edytor 1.0.0-rc.1 → 1.0.0-rc.3
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 +1 -1
- package/dist/block/block.svelte.js +20 -4
- package/dist/clipboard/htmlFlow.d.ts +6 -1
- package/dist/clipboard/htmlFlow.js +19 -6
- package/dist/cloudflare/DocumentRoom.d.ts +27 -60
- package/dist/cloudflare/DocumentRoom.js +13 -75
- package/dist/cloudflare/history.d.ts +2 -2
- package/dist/cloudflare/history.js +2 -2
- package/dist/cloudflare/index.d.ts +1 -1
- package/dist/cloudflare/index.js +1 -1
- package/dist/cloudflare/room/access.js +1 -1
- package/dist/cloudflare/room/admission.js +1 -1
- package/dist/cloudflare/room/comments.d.ts +1 -1
- package/dist/cloudflare/room/comments.js +1 -1
- package/dist/cloudflare/room/context.d.ts +2 -1
- package/dist/cloudflare/room/context.js +1 -1
- package/dist/cloudflare/room/history.d.ts +1 -1
- package/dist/cloudflare/room/history.js +1 -1
- package/dist/cloudflare/room/moves.js +1 -1
- package/dist/cloudflare/room/presence.d.ts +1 -1
- package/dist/cloudflare/room/presence.js +1 -1
- package/dist/cloudflare/room/purge.js +1 -1
- package/dist/cloudflare/room/replicas.d.ts +1 -1
- package/dist/cloudflare/room/replicas.js +1 -1
- package/dist/cloudflare/room/scheduler.d.ts +1 -1
- package/dist/cloudflare/room/scheduler.js +2 -2
- package/dist/cloudflare/room/shared.d.ts +60 -0
- package/dist/cloudflare/room/shared.js +79 -0
- package/dist/cloudflare/room/storage.d.ts +9 -1
- package/dist/cloudflare/room/storage.js +25 -2
- package/dist/cloudflare/room/updates.js +1 -1
- package/dist/cloudflare/room/validation.d.ts +1 -1
- package/dist/cloudflare/room/validation.js +1 -1
- package/dist/cloudflare/routeDocumentSocket.js +1 -1
- package/dist/collaboration/history/HistoryPanel.svelte +49 -20
- package/dist/collaboration/history/index.d.ts +1 -1
- package/dist/collaboration/history/panel.d.ts +18 -0
- package/dist/components/Block.svelte +155 -98
- package/dist/components/Block.svelte.d.ts +4 -1
- package/dist/components/Content.svelte +90 -39
- package/dist/components/CustomMark.svelte +46 -0
- package/dist/components/CustomMark.svelte.d.ts +11 -0
- package/dist/components/Edytor.svelte +31 -3
- package/dist/components/InlineBlock.svelte +4 -9
- package/dist/components/Mark.svelte +46 -35
- package/dist/components/Mark.svelte.d.ts +7 -0
- package/dist/components/Text.svelte +51 -14
- package/dist/crdt/document.d.ts +0 -6
- package/dist/crdt/document.js +8 -16
- package/dist/crdt/protocols/envelope.d.ts +2 -2
- package/dist/crdt/providers/container.d.ts +2 -2
- package/dist/{plugins/blockHandles → dnd}/autoScroll.d.ts +2 -1
- package/dist/{plugins/blockHandles → dnd}/autoScroll.js +3 -2
- package/dist/edytor.svelte.js +5 -3
- package/dist/events/beforeInputCommands.js +4 -3
- package/dist/events/onBeforeInput.js +1 -1
- package/dist/events/onDrop.d.ts +6 -0
- package/dist/events/onDrop.js +7 -4
- package/dist/events/onFocus.js +52 -10
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/labels.d.ts +18 -2
- package/dist/labels.js +13 -1
- package/dist/plugins/blockHandles/BlockHandle.svelte +5 -2
- package/dist/plugins/blockHandles/BlockHandleController.svelte.d.ts +43 -61
- package/dist/plugins/blockHandles/BlockHandleController.svelte.js +110 -332
- package/dist/plugins/blockHandles/BlockHandles.svelte +19 -12
- package/dist/plugins/blockHandles/blockHandlesPlugin.d.ts +23 -3
- package/dist/plugins/blockHandles/blockHandlesPlugin.js +33 -9
- package/dist/plugins/blockHandles/dragPreview.js +2 -1
- package/dist/plugins/blockHandles/dropIndicator.d.ts +37 -0
- package/dist/plugins/blockHandles/dropIndicator.js +252 -0
- package/dist/plugins/blockHandles/geometry.d.ts +72 -0
- package/dist/plugins/blockHandles/geometry.js +85 -0
- package/dist/plugins/blockMenu/BlockMenu.svelte +16 -128
- package/dist/plugins/blockMenu/BlockMenuController.svelte.d.ts +43 -2
- package/dist/plugins/blockMenu/BlockMenuController.svelte.js +142 -0
- package/dist/plugins/chrome.d.ts +72 -0
- package/dist/plugins/chrome.js +64 -0
- package/dist/plugins/code/CodeHeader.svelte +40 -54
- package/dist/plugins/code/CodeHeader.svelte.d.ts +1 -0
- package/dist/plugins/code/CodePlugin.svelte +42 -20
- package/dist/plugins/code/LanguageMenu.svelte +134 -0
- package/dist/plugins/code/LanguageMenu.svelte.d.ts +8 -0
- package/dist/plugins/code/code.css +37 -20
- package/dist/plugins/code/header.svelte.d.ts +56 -0
- package/dist/plugins/code/header.svelte.js +168 -0
- package/dist/plugins/code/languageMenu.svelte.d.ts +104 -0
- package/dist/plugins/code/languageMenu.svelte.js +329 -0
- package/dist/plugins/code/languages.d.ts +21 -0
- package/dist/plugins/comments/CommentsSidebar.svelte +3 -2
- package/dist/plugins/comments/CommentsSidebar.svelte.d.ts +3 -6
- package/dist/plugins/comments/commentsPlugin.d.ts +10 -5
- package/dist/plugins/equation/EquationEditor.svelte +31 -28
- package/dist/plugins/equation/EquationEditor.svelte.d.ts +2 -0
- package/dist/plugins/equation/EquationPlugin.svelte +15 -4
- package/dist/plugins/equation/EquationPlugin.svelte.d.ts +5 -3
- package/dist/plugins/equation/equation.svelte.d.ts +43 -18
- package/dist/plugins/equation/equation.svelte.js +90 -8
- package/dist/plugins/equation/importUrl.d.ts +6 -0
- package/dist/plugins/equation/importUrl.js +6 -0
- package/dist/plugins/equation/katex.d.ts +8 -0
- package/dist/plugins/equation/katex.js +80 -0
- package/dist/plugins/image/ImageChrome.svelte +27 -12
- package/dist/plugins/image/ImageChrome.svelte.d.ts +2 -0
- package/dist/plugins/image/ImageEmpty.svelte +25 -48
- package/dist/plugins/image/ImageEmpty.svelte.d.ts +3 -0
- package/dist/plugins/image/ImagePlugin.svelte +27 -6
- package/dist/plugins/image/ImagePlugin.svelte.d.ts +18 -0
- package/dist/plugins/image/controls.svelte.d.ts +14 -35
- package/dist/plugins/image/controls.svelte.js +56 -10
- package/dist/plugins/image/empty.svelte.d.ts +56 -0
- package/dist/plugins/image/empty.svelte.js +83 -0
- package/dist/plugins/index.d.ts +14 -4
- package/dist/plugins/index.js +3 -2
- package/dist/plugins/marquee/MarqueeBox.svelte +32 -0
- package/dist/plugins/marquee/MarqueeBox.svelte.d.ts +9 -0
- package/dist/plugins/marquee/MarqueeController.svelte.d.ts +48 -0
- package/dist/plugins/marquee/MarqueeController.svelte.js +246 -0
- package/dist/plugins/marquee/marquee.d.ts +33 -0
- package/dist/plugins/marquee/marquee.js +106 -0
- package/dist/plugins/marquee/marqueePlugin.d.ts +31 -0
- package/dist/plugins/marquee/marqueePlugin.js +67 -0
- package/dist/plugins/media/AudioPlugin.svelte +2 -0
- package/dist/plugins/media/BookmarkPlugin.svelte +22 -3
- package/dist/plugins/media/BookmarkPlugin.svelte.d.ts +18 -0
- package/dist/plugins/media/EmbedPlugin.svelte +22 -2
- package/dist/plugins/media/EmbedPlugin.svelte.d.ts +18 -0
- package/dist/plugins/media/FilePlugin.svelte +2 -0
- package/dist/plugins/media/MediaEmpty.svelte +35 -53
- package/dist/plugins/media/UrlPasteMenu.svelte +16 -7
- package/dist/plugins/media/UrlPasteMenu.svelte.d.ts +2 -0
- package/dist/plugins/media/VideoPlugin.svelte +2 -0
- package/dist/plugins/media/empty.svelte.d.ts +77 -0
- package/dist/plugins/media/empty.svelte.js +115 -0
- package/dist/plugins/media/media.d.ts +17 -0
- package/dist/plugins/media/media.js +15 -0
- package/dist/plugins/media/urlPaste.svelte.d.ts +22 -14
- package/dist/plugins/media/urlPaste.svelte.js +48 -7
- package/dist/plugins/mention/MentionPlugin.svelte +11 -7
- package/dist/plugins/mention/MentionPlugin.svelte.d.ts +7 -0
- package/dist/plugins/pageLink/PageLinkPlugin.svelte +11 -7
- package/dist/plugins/pageLink/PageLinkPlugin.svelte.d.ts +7 -0
- package/dist/plugins/richtext/CalloutIcon.svelte +38 -0
- package/dist/plugins/richtext/CalloutIcon.svelte.d.ts +9 -0
- package/dist/plugins/richtext/CalloutIconMenu.svelte +98 -0
- package/dist/plugins/richtext/CalloutIconMenu.svelte.d.ts +9 -0
- package/dist/plugins/richtext/EmptyBody.svelte +32 -0
- package/dist/plugins/richtext/EmptyBody.svelte.d.ts +8 -0
- package/dist/plugins/richtext/RichTextPlugin.svelte +201 -61
- package/dist/plugins/richtext/RichTextPlugin.svelte.d.ts +21 -1
- package/dist/plugins/richtext/TodoCheckbox.svelte +2 -2
- package/dist/plugins/richtext/body.d.ts +9 -0
- package/dist/plugins/richtext/body.js +16 -0
- package/dist/plugins/richtext/calloutIcons.svelte.d.ts +102 -0
- package/dist/plugins/richtext/calloutIcons.svelte.js +302 -0
- package/dist/plugins/richtext/labels.d.ts +6 -2
- package/dist/plugins/richtext/labels.js +6 -2
- package/dist/plugins/slashMenu/SlashMenu.svelte +25 -109
- package/dist/plugins/slashMenu/SlashMenuController.svelte.d.ts +19 -0
- package/dist/plugins/slashMenu/SlashMenuController.svelte.js +95 -0
- package/dist/plugins/slashMenu/slashMenuPlugin.d.ts +15 -11
- package/dist/plugins/suggestions/SuggestionBars.svelte +6 -1
- package/dist/plugins/suggestions/suggestionsPlugin.d.ts +3 -1
- package/dist/plugins/table/TableChrome.svelte +174 -121
- package/dist/plugins/table/TableChrome.svelte.d.ts +5 -1
- package/dist/plugins/table/TablePlugin.svelte +16 -9
- package/dist/plugins/table/chrome.svelte.d.ts +190 -94
- package/dist/plugins/table/chrome.svelte.js +658 -54
- package/dist/plugins/table/dragPreview.d.ts +29 -0
- package/dist/plugins/table/dragPreview.js +103 -0
- package/dist/plugins/table/table.css +59 -2
- package/dist/plugins/table/table.d.ts +18 -0
- package/dist/plugins/table/table.js +1 -33
- package/dist/plugins/toolbar/LinkCard.svelte +6 -2
- package/dist/plugins/toolbar/LinkCard.svelte.d.ts +2 -0
- package/dist/plugins/toolbar/Toolbar.svelte +10 -61
- package/dist/plugins/toolbar/ToolbarController.svelte.d.ts +27 -0
- package/dist/plugins/toolbar/ToolbarController.svelte.js +101 -0
- package/dist/plugins/toolbar/toolbarPlugin.d.ts +14 -3
- package/dist/plugins/toolbar/toolbarPlugin.js +1 -1
- package/dist/plugins/triggers/TriggerController.svelte.d.ts +25 -0
- package/dist/plugins/triggers/TriggerController.svelte.js +36 -0
- package/dist/plugins/triggers/TriggerMenu.svelte +27 -36
- package/dist/plugins.d.ts +25 -13
- package/dist/selection/pointer.svelte.d.ts +36 -0
- package/dist/selection/pointer.svelte.js +440 -0
- package/dist/selection/selection.svelte.d.ts +0 -8
- package/dist/selection/selection.svelte.js +61 -289
- package/dist/selection/visibility.d.ts +8 -0
- package/dist/selection/visibility.js +16 -3
- package/dist/session/attempt.js +4 -2
- package/dist/session/navigation.d.ts +15 -1
- package/dist/session/navigation.js +83 -1
- package/dist/session/ports.d.ts +12 -0
- package/dist/session/selection.js +3 -0
- package/dist/session/suggestions.svelte.js +22 -0
- package/dist/surface/lines.d.ts +32 -0
- package/dist/surface/lines.js +43 -0
- package/dist/surface/observer.svelte.js +20 -4
- package/dist/surface/overlay.d.ts +8 -4
- package/dist/surface/overlay.js +64 -9
- package/dist/themes/notion.css +53 -21
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
Edytor aims to be for Svelte what Slate.js is for React: a heavily customizable editor with an API to build any kind of collaborative rich text editor.
|
|
19
19
|
|
|
20
|
-
> **Release candidate.** Edytor `1.0.0-rc.
|
|
20
|
+
> **Release candidate.** Edytor `1.0.0-rc.3` is the 1.0 release candidate (`edytor` on npm): its API is frozen, and a change to it before 1.0 is a listed breaking change. It has no production track record yet: read the [limitations](https://edytor.dev/docs/reference/limitations) before you build on it. Issues and PRs are welcome: when you report a bug, include the document's JSON value.
|
|
21
21
|
|
|
22
22
|
## Features
|
|
23
23
|
|
|
@@ -117,10 +117,10 @@ export class Block {
|
|
|
117
117
|
this.patchData({ ops: [{ path: [], value: data }] });
|
|
118
118
|
};
|
|
119
119
|
get selected() {
|
|
120
|
-
return this.edytor.selection.
|
|
120
|
+
return this.edytor.selection.isSelected(this);
|
|
121
121
|
}
|
|
122
122
|
get focused() {
|
|
123
|
-
return this.edytor.selection.
|
|
123
|
+
return this.edytor.selection.isFocused(this) && !this.selected;
|
|
124
124
|
}
|
|
125
125
|
/** May this block move at all: `canPlace` without a destination (drag handles). */
|
|
126
126
|
get movable() {
|
|
@@ -195,10 +195,24 @@ export class Block {
|
|
|
195
195
|
return this.edytor.facade.isVisibleBlock(this.id);
|
|
196
196
|
}
|
|
197
197
|
get nextBlock() {
|
|
198
|
-
return this
|
|
198
|
+
return this.#sibling(1);
|
|
199
199
|
}
|
|
200
200
|
get previousBlock() {
|
|
201
|
-
return this
|
|
201
|
+
return this.#sibling(-1);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* The sibling `step` places away (none past either end): one id read, no
|
|
205
|
+
* handle for every sibling (a top-level block's are the whole page's).
|
|
206
|
+
* Tracks what `parent` and `index` track: this block's cell and its
|
|
207
|
+
* parent's child list.
|
|
208
|
+
*/
|
|
209
|
+
#sibling(step) {
|
|
210
|
+
const parent = this.parent;
|
|
211
|
+
if (!parent)
|
|
212
|
+
return null;
|
|
213
|
+
const ids = this.edytor.facade.childrenIds(parent.isRoot ? null : parent.id);
|
|
214
|
+
const id = ids[this.index + step];
|
|
215
|
+
return id === undefined ? null : this.edytor.idToBlock.block(id);
|
|
202
216
|
}
|
|
203
217
|
get closestPreviousBlock() {
|
|
204
218
|
return this.edytor.blockBefore(this);
|
|
@@ -422,6 +436,8 @@ export class Block {
|
|
|
422
436
|
node.setAttribute(name, value);
|
|
423
437
|
this.node = node;
|
|
424
438
|
const release = this.edytor.surface.register(node, 'block', this.id);
|
|
439
|
+
// Its attributes follow its own selected and focused membership.
|
|
440
|
+
this.edytor.selection.keep(this);
|
|
425
441
|
// A block laid out again with no commit moves the chrome beside it (the overlay measures).
|
|
426
442
|
const unobserve = this.edytor.overlay.observe(node);
|
|
427
443
|
const onDestroy = this.edytor.plugins.flatMap((plugin) => {
|
|
@@ -7,7 +7,12 @@ export type ImportKinds = Pick<Edytor, 'blocks' | 'marks'> & Partial<Pick<Edytor
|
|
|
7
7
|
document: Pick<Edytor['document'], 'defaultChild'>;
|
|
8
8
|
};
|
|
9
9
|
type Values = Record<string, SerializableContent>;
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* The tag a kind writes for `data`: its export form's first tag, else its
|
|
12
|
+
* element's, else its content element's. A generic one (`div`, `span`) is
|
|
13
|
+
* none: an export form written as one (a callout's `<div data-edytor-callout>`)
|
|
14
|
+
* is found by its `parse` hook only.
|
|
15
|
+
*/
|
|
11
16
|
export declare const tagOf: (type: string, kind: BlockDefinition, data: Values) => string | undefined;
|
|
12
17
|
/**
|
|
13
18
|
* External HTML as a flow: the browser parses (inert: no script
|
|
@@ -33,14 +33,21 @@ const isGlyph = (node) => {
|
|
|
33
33
|
};
|
|
34
34
|
/** Tags that carry no meaning of their own: a kind rendering one is not found by it. */
|
|
35
35
|
const GENERIC = /^(div|span)$/;
|
|
36
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* The tag a kind writes for `data`: its export form's first tag, else its
|
|
38
|
+
* element's, else its content element's. A generic one (`div`, `span`) is
|
|
39
|
+
* none: an export form written as one (a callout's `<div data-edytor-callout>`)
|
|
40
|
+
* is found by its `parse` hook only.
|
|
41
|
+
*/
|
|
37
42
|
export const tagOf = (type, kind, data) => {
|
|
38
43
|
const { html, element, contentElement } = kind;
|
|
39
44
|
if (typeof html === 'string')
|
|
40
45
|
return html;
|
|
41
46
|
try {
|
|
42
|
-
if (html)
|
|
43
|
-
|
|
47
|
+
if (html) {
|
|
48
|
+
const tag = /^<([a-z][\w-]*)/i.exec(html({ type, data }, '', ''))?.[1]?.toLowerCase();
|
|
49
|
+
return tag && !GENERIC.test(tag) ? tag : undefined;
|
|
50
|
+
}
|
|
44
51
|
}
|
|
45
52
|
catch {
|
|
46
53
|
return undefined;
|
|
@@ -251,18 +258,24 @@ export const flowOfHtml = (kinds, html) => {
|
|
|
251
258
|
texts.add(current);
|
|
252
259
|
}
|
|
253
260
|
};
|
|
261
|
+
/** Whether a leading paragraph gave the element its text: one only, empty or not. */
|
|
262
|
+
let led = false;
|
|
254
263
|
for (const node of element.childNodes)
|
|
255
264
|
if (isVoid(node))
|
|
256
265
|
at.apart(node);
|
|
257
266
|
else if (!isBlock(node))
|
|
258
267
|
inline(node, at, {}, pre);
|
|
259
|
-
// A leading plain paragraph is the element's own text (`<li><p>Item</p></li
|
|
260
|
-
|
|
268
|
+
// A leading plain paragraph is the element's own text (`<li><p>Item</p></li>`,
|
|
269
|
+
// a callout's title): an empty one too, so the paragraph after it is a child.
|
|
270
|
+
else if (!led &&
|
|
271
|
+
!current.content.length &&
|
|
261
272
|
!current.children?.length &&
|
|
262
273
|
!kindOf(node) &&
|
|
263
|
-
!wraps(node))
|
|
274
|
+
!wraps(node)) {
|
|
275
|
+
led = true;
|
|
264
276
|
for (const child of node.childNodes)
|
|
265
277
|
inline(child, at, {}, pre);
|
|
278
|
+
}
|
|
266
279
|
else
|
|
267
280
|
(current.children ??= []).push(...blockOf(node, childType));
|
|
268
281
|
for (const part of texts)
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
* replace: those deletes wait with them, in memory); compaction keeps
|
|
48
48
|
* the pending records apart, and rewrites them as the deletes still
|
|
49
49
|
* waiting; a frame that discards a forged stamp drops them. At most
|
|
50
|
-
*
|
|
50
|
+
* `MAX_WAITING_DELETES` ranges wait, stored or in memory: a frame
|
|
51
51
|
* that would pass it has its waiting deletes dropped (refusal `waiting`,
|
|
52
52
|
* left out of the ack), the rest applied. Compaction reclaims the
|
|
53
53
|
* waiting deletes of client ids no user registered and no socket holds;
|
|
@@ -112,6 +112,7 @@ import type { CommitResult, ExportedBlocks, ImportReceipt, ImportRequest, LateEd
|
|
|
112
112
|
import type { AwarenessEntry } from '../crdt/protocol.js';
|
|
113
113
|
import type { DocumentSemanticsConfig, DocumentOperations, JSONBlock, JSONDoc, YDoc } from '../crdt/index.js';
|
|
114
114
|
import type { CommentActor, CommentChange, CommentOutcome, CommentRequest, CommentSnapshot } from '../crdt/protocols/comments.js';
|
|
115
|
+
export { closedSocket, COMMENTS_HEADER, DEFAULT_MAX_COMMENT_BYTES, DEFAULT_MAX_COMMENT_REQUESTS_PER_SECOND, HISTORY_HEADER, HISTORY_KEY_HEADER, IDENTITY_HEADERS, MAX_REFUSALS, MAX_WAITING_DELETES, noTimers, PROBE_HEADER, PURGE_ORIGIN, RESTORE_ORIGIN, ROOM_ORIGIN, SOCKET_TAG } from './room/shared.js';
|
|
115
116
|
/** Under SQLite-backed Durable Objects' 2 MB row cap, with room for the other columns. */
|
|
116
117
|
export declare const DEFAULT_MAX_ROW_BYTES: number;
|
|
117
118
|
/** Update records before the rows are merged into one snapshot. */
|
|
@@ -127,6 +128,8 @@ export declare const DEFAULT_SAVE_AFTER = 2000;
|
|
|
127
128
|
* about 100 MB at worst. Raise it for documents of long text.
|
|
128
129
|
*/
|
|
129
130
|
export declare const DEFAULT_MAX_DOCUMENT_BYTES: number;
|
|
131
|
+
/** The share of the document quota past which the room logs its size, by default. */
|
|
132
|
+
export declare const DEFAULT_DOCUMENT_WARNING = 0.8;
|
|
130
133
|
/**
|
|
131
134
|
* The largest frame a socket may send, reassembled from chunks: room for a
|
|
132
135
|
* whole document at the default quota (a client seeding an empty room).
|
|
@@ -166,14 +169,6 @@ export declare const DEFAULT_MAX_PRESENCE_PER_SECOND = 50;
|
|
|
166
169
|
* would send 50,000 frames a second.
|
|
167
170
|
*/
|
|
168
171
|
export declare const DEFAULT_MAX_PRESENCE_FANOUT = 2000;
|
|
169
|
-
/**
|
|
170
|
-
* Delete ranges the room keeps waiting for items it does not hold (a
|
|
171
|
-
* relayer's delete of an author's edit a restore lost). Every update the
|
|
172
|
-
* engine applies re-reads them, so they are capped.
|
|
173
|
-
*/
|
|
174
|
-
export declare const MAX_WAITING_DELETES = 1024;
|
|
175
|
-
/** Refusals kept in `refusals` (the newest); `refusalCounts` counts every one. */
|
|
176
|
-
export declare const MAX_REFUSALS = 100;
|
|
177
172
|
/**
|
|
178
173
|
* A client id and the user who owns it (the room's replica registry). An
|
|
179
174
|
* empty `user` marks an id a restore without a registry left unowned: its
|
|
@@ -208,33 +203,6 @@ export type SavedDocument = {
|
|
|
208
203
|
};
|
|
209
204
|
/** What `onLoad` may return: JSON, a bare v14 update, or `{ update, replicas }` (a `SavedDocument`). */
|
|
210
205
|
export type LoadedDocument = JSONDoc | Uint8Array | Pick<SavedDocument, 'update' | 'replicas'>;
|
|
211
|
-
/** The header `routeDocumentSocket` sets on an authorized probe: `lastUpdated` or `snapshot`. */
|
|
212
|
-
export declare const PROBE_HEADER = "X-Edytor-Probe";
|
|
213
|
-
/** The transaction origin of the room's own edits (`transact`, `onLoad` seeds). */
|
|
214
|
-
export declare const ROOM_ORIGIN: unique symbol;
|
|
215
|
-
/** The transaction origin of a history restore: the room's restore history tracks it. */
|
|
216
|
-
export declare const RESTORE_ORIGIN: unique symbol;
|
|
217
|
-
/** The transaction origin of the room's purge: tracked by no history. */
|
|
218
|
-
export declare const PURGE_ORIGIN: unique symbol;
|
|
219
|
-
/** The header `routeDocumentHistory` sets on an authorized history request. */
|
|
220
|
-
export declare const HISTORY_HEADER = "X-Edytor-History";
|
|
221
|
-
/** The version key of a history `read` or `restore` request. */
|
|
222
|
-
export declare const HISTORY_KEY_HEADER = "X-Edytor-History-Key";
|
|
223
|
-
/** The header `routeDocumentComments` sets on an authorized comments request: `list` or `post`. */
|
|
224
|
-
export declare const COMMENTS_HEADER = "X-Edytor-Comments";
|
|
225
|
-
/**
|
|
226
|
-
* Headers carrying the identity `routeDocumentSocket` verified — never the
|
|
227
|
-
* client's. The user id is percent-encoded (`encodeURIComponent`): a header
|
|
228
|
-
* value is trimmed and cannot carry every character, and a user id is any
|
|
229
|
-
* string.
|
|
230
|
-
*/
|
|
231
|
-
export declare const IDENTITY_HEADERS: {
|
|
232
|
-
readonly user: "X-Edytor-User";
|
|
233
|
-
readonly replica: "X-Edytor-Replica";
|
|
234
|
-
readonly access: "X-Edytor-Access";
|
|
235
|
-
/** When the credential expires, ms since the epoch (absent: never). */
|
|
236
|
-
readonly expires: "X-Edytor-Expires";
|
|
237
|
-
};
|
|
238
206
|
/**
|
|
239
207
|
* Optional knobs (strings, as `vars` arrive): row size, outgoing frame
|
|
240
208
|
* limit and compaction threshold. The defaults are the platform limits.
|
|
@@ -245,6 +213,8 @@ export type DocumentRoomEnv = {
|
|
|
245
213
|
EDYTOR_COMPACT_AFTER?: string | number;
|
|
246
214
|
EDYTOR_SAVE_AFTER?: string | number;
|
|
247
215
|
EDYTOR_MAX_DOCUMENT_BYTES?: string | number;
|
|
216
|
+
/** The share of the document quota past which the room logs its size (`documentWarning`). */
|
|
217
|
+
EDYTOR_DOCUMENT_WARNING?: string | number;
|
|
248
218
|
EDYTOR_MAX_INBOUND_FRAME_BYTES?: string | number;
|
|
249
219
|
EDYTOR_MAX_BUFFERED_BYTES?: string | number;
|
|
250
220
|
EDYTOR_MAX_UPDATES_PER_SECOND?: string | number;
|
|
@@ -324,6 +294,8 @@ export type Timing = {
|
|
|
324
294
|
export type RoomMetrics = {
|
|
325
295
|
/** The document's size as the document quota measures it: its records, uncompressed. */
|
|
326
296
|
documentBytes: number;
|
|
297
|
+
/** The document quota (`maxDocumentBytes`): writes past it are refused (`4413`). */
|
|
298
|
+
documentLimit: number;
|
|
327
299
|
/** What its rows take in storage (a snapshot compressed). */
|
|
328
300
|
storedBytes: number;
|
|
329
301
|
/** Logical records stored (the generation record included), and their rows. */
|
|
@@ -400,6 +372,11 @@ export type RoomLogEntry = {
|
|
|
400
372
|
edytor: 'quota';
|
|
401
373
|
user: string;
|
|
402
374
|
quota: string;
|
|
375
|
+
} | {
|
|
376
|
+
edytor: 'size';
|
|
377
|
+
bytes: number;
|
|
378
|
+
limit: number;
|
|
379
|
+
share: number;
|
|
403
380
|
} | {
|
|
404
381
|
edytor: 'denied';
|
|
405
382
|
user: string;
|
|
@@ -434,15 +411,6 @@ export type RoomLogEntry = {
|
|
|
434
411
|
};
|
|
435
412
|
/** `pending`: deletes of items the room does not hold yet (they wait for them). */
|
|
436
413
|
type RowKind = 'generation' | 'update' | 'snapshot' | 'pending';
|
|
437
|
-
/**
|
|
438
|
-
* An upgrade accepted and closed at once, so the client reads `code`: a
|
|
439
|
-
* browser sees an HTTP error at the upgrade only as `1006`, which a
|
|
440
|
-
* provider cannot tell from a network failure. Refuse a dial your Worker
|
|
441
|
-
* turns away itself with it: the provider stops at `1008` or `4xxx`
|
|
442
|
-
* (except `4401`, redialed), and redials after anything else (`CLOSE`,
|
|
443
|
-
* `isRefusal` in `crdt/providers/room.ts`).
|
|
444
|
-
*/
|
|
445
|
-
export declare const closedSocket: (code: number, reason: string) => Response;
|
|
446
414
|
/** A stored record, reassembled: its kind, record number, bytes, and whether they are v2 (a v2 container's snapshot). */
|
|
447
415
|
export type StoredRecord = {
|
|
448
416
|
kind: RowKind;
|
|
@@ -450,8 +418,6 @@ export type StoredRecord = {
|
|
|
450
418
|
bytes: Uint8Array<ArrayBuffer>;
|
|
451
419
|
v2: boolean;
|
|
452
420
|
};
|
|
453
|
-
/** Run an entry point with timers forbidden — a pending timer keeps a Durable Object from hibernating. */
|
|
454
|
-
export declare const noTimers: <T>(fn: () => T) => T;
|
|
455
421
|
/** A block as `validate` reads it, before or after a frame. */
|
|
456
422
|
export type ValidatedBlock = {
|
|
457
423
|
id: string;
|
|
@@ -496,24 +462,20 @@ export type CommentOptions = {
|
|
|
496
462
|
maxLength?: number;
|
|
497
463
|
/**
|
|
498
464
|
* The bytes the room's comments may hold (default
|
|
499
|
-
*
|
|
465
|
+
* `DEFAULT_MAX_COMMENT_BYTES`, 4 MiB): each body and quote in UTF-8
|
|
500
466
|
* plus 128 a comment. A thread or reply past it is refused `413`; a
|
|
501
467
|
* delete frees its bytes.
|
|
502
468
|
*/
|
|
503
469
|
maxBytes?: number;
|
|
504
470
|
/**
|
|
505
471
|
* Comment requests per second (default
|
|
506
|
-
*
|
|
472
|
+
* `DEFAULT_MAX_COMMENT_REQUESTS_PER_SECOND`, a ten-second burst):
|
|
507
473
|
* over HTTP per verified user (past it, `429`), and a socket's comment
|
|
508
474
|
* messages per socket (past it, dropped). RPC calls are the host's own and
|
|
509
475
|
* are not counted.
|
|
510
476
|
*/
|
|
511
477
|
maxRequestsPerSecond?: number;
|
|
512
478
|
};
|
|
513
|
-
/** The bytes a room's comments hold at most, by default (4 MiB). */
|
|
514
|
-
export declare const DEFAULT_MAX_COMMENT_BYTES: number;
|
|
515
|
-
/** Comment requests per second and user (or socket), by default. */
|
|
516
|
-
export declare const DEFAULT_MAX_COMMENT_REQUESTS_PER_SECOND = 2;
|
|
517
479
|
/** What {@link attachRoom} (and `DocumentRoom`) takes. */
|
|
518
480
|
export type AttachRoomOptions = {
|
|
519
481
|
/**
|
|
@@ -544,6 +506,12 @@ export type AttachRoomOptions = {
|
|
|
544
506
|
tablePrefix?: string;
|
|
545
507
|
/** Largest document, in stored bytes (default {@link DEFAULT_MAX_DOCUMENT_BYTES}). */
|
|
546
508
|
maxDocumentBytes?: number;
|
|
509
|
+
/**
|
|
510
|
+
* The share of `maxDocumentBytes` past which the room logs the
|
|
511
|
+
* document's size (`size`, once per crossing), above 0 and at most 1
|
|
512
|
+
* (default {@link DEFAULT_DOCUMENT_WARNING}, 0.8).
|
|
513
|
+
*/
|
|
514
|
+
documentWarning?: number;
|
|
547
515
|
/** Largest frame a socket may send, reassembled (default {@link DEFAULT_MAX_INBOUND_FRAME_BYTES}). */
|
|
548
516
|
maxInboundFrameBytes?: number;
|
|
549
517
|
/**
|
|
@@ -599,7 +567,8 @@ export type AttachRoomOptions = {
|
|
|
599
567
|
*/
|
|
600
568
|
semantics?: DocumentSemanticsConfig;
|
|
601
569
|
/**
|
|
602
|
-
* Version history in
|
|
570
|
+
* Version history, in the store `HistoryOptions.store` names (a KV namespace, an R2 bucket or
|
|
571
|
+
* the room's own storage): the room writes its
|
|
603
572
|
* state twice a day — the morning's at local noon, the evening's at
|
|
604
573
|
* midnight, in `timeZone` — when it changed, for `retentionDays`; read
|
|
605
574
|
* and restore them with `listHistory`, `readHistory`, `restoreHistory`
|
|
@@ -622,8 +591,6 @@ export type AttachRoomOptions = {
|
|
|
622
591
|
*/
|
|
623
592
|
comments?: CommentOptions | false;
|
|
624
593
|
};
|
|
625
|
-
/** The tag of the document's sockets: other sockets of the object are left to you. */
|
|
626
|
-
export declare const SOCKET_TAG = "edytor";
|
|
627
594
|
/**
|
|
628
595
|
* One edytor document living in a Durable Object's storage: the room
|
|
629
596
|
* logic, independent of the class that hosts it. Create it with
|
|
@@ -638,6 +605,7 @@ export declare class AttachedDocument {
|
|
|
638
605
|
readonly compactAfter: number;
|
|
639
606
|
readonly saveAfter: number;
|
|
640
607
|
readonly maxDocumentBytes: number;
|
|
608
|
+
readonly documentWarning: number;
|
|
641
609
|
readonly maxInboundFrameBytes: number;
|
|
642
610
|
readonly maxBufferedBytes: number;
|
|
643
611
|
readonly maxUpdatesPerSecond: number;
|
|
@@ -648,7 +616,7 @@ export declare class AttachedDocument {
|
|
|
648
616
|
failure: Error | null;
|
|
649
617
|
/** Latest presence entry per replica, for join snapshots (memory: refills after a wake). */
|
|
650
618
|
presence: Map<number, E.AwarenessEntry>;
|
|
651
|
-
/** The newest
|
|
619
|
+
/** The newest `MAX_REFUSALS` refusals since this instance started (diagnostics; memory only). */
|
|
652
620
|
refusals: Refusal[];
|
|
653
621
|
/** Every refusal since this instance started, by reason. */
|
|
654
622
|
refusalCounts: Partial<Record<Refusal['reason'], number>>;
|
|
@@ -746,7 +714,7 @@ export declare class AttachedDocument {
|
|
|
746
714
|
};
|
|
747
715
|
/**
|
|
748
716
|
* When the room last stored a change (ms since the epoch), or `null`
|
|
749
|
-
* for a room that stored none since
|
|
717
|
+
* for a room that stored none since it records the time. Cheap: one
|
|
750
718
|
* row, no document. `routeDocumentSocket` answers it over HTTP
|
|
751
719
|
* (`GET <room>?lastUpdated`), also over RPC.
|
|
752
720
|
*/
|
|
@@ -857,7 +825,7 @@ export declare class AttachedDocument {
|
|
|
857
825
|
metrics(): RoomMetrics;
|
|
858
826
|
/**
|
|
859
827
|
* Drop every waiting delete, stored or in memory (callable over RPC):
|
|
860
|
-
* the way out when a writer filled
|
|
828
|
+
* the way out when a writer filled `MAX_WAITING_DELETES` with
|
|
861
829
|
* deletes of registered ids' items, which compaction keeps. A dropped
|
|
862
830
|
* delete's item shows if it ever arrives — but for an entry a waiting
|
|
863
831
|
* rewrite replaces, which that rewrite deletes should it integrate.
|
|
@@ -1056,4 +1024,3 @@ export declare class DocumentRoom<Env = DocumentRoomEnv> extends DurableObject<E
|
|
|
1056
1024
|
get origin(): AttachedDocument['origin'];
|
|
1057
1025
|
records(): ReturnType<AttachedDocument['records']>;
|
|
1058
1026
|
}
|
|
1059
|
-
export {};
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
* replace: those deletes wait with them, in memory); compaction keeps
|
|
48
48
|
* the pending records apart, and rewrites them as the deletes still
|
|
49
49
|
* waiting; a frame that discards a forged stamp drops them. At most
|
|
50
|
-
*
|
|
50
|
+
* `MAX_WAITING_DELETES` ranges wait, stored or in memory: a frame
|
|
51
51
|
* that would pass it has its waiting deletes dropped (refusal `waiting`,
|
|
52
52
|
* left out of the ack), the rest applied. Compaction reclaims the
|
|
53
53
|
* waiting deletes of client ids no user registered and no socket holds;
|
|
@@ -120,6 +120,8 @@ import { ReplicaRegistry } from './room/replicas.js';
|
|
|
120
120
|
import { Scheduler } from './room/scheduler.js';
|
|
121
121
|
import { RoomStorage } from './room/storage.js';
|
|
122
122
|
import { RoomValidation } from './room/validation.js';
|
|
123
|
+
import { noTimers, SOCKET_TAG } from './room/shared.js';
|
|
124
|
+
export { closedSocket, COMMENTS_HEADER, DEFAULT_MAX_COMMENT_BYTES, DEFAULT_MAX_COMMENT_REQUESTS_PER_SECOND, HISTORY_HEADER, HISTORY_KEY_HEADER, IDENTITY_HEADERS, MAX_REFUSALS, MAX_WAITING_DELETES, noTimers, PROBE_HEADER, PURGE_ORIGIN, RESTORE_ORIGIN, ROOM_ORIGIN, SOCKET_TAG } from './room/shared.js';
|
|
123
125
|
/** Under SQLite-backed Durable Objects' 2 MB row cap, with room for the other columns. */
|
|
124
126
|
export const DEFAULT_MAX_ROW_BYTES = 2_000_000 - 4096;
|
|
125
127
|
/** Update records before the rows are merged into one snapshot. */
|
|
@@ -135,6 +137,8 @@ export const DEFAULT_SAVE_AFTER = 2000;
|
|
|
135
137
|
* about 100 MB at worst. Raise it for documents of long text.
|
|
136
138
|
*/
|
|
137
139
|
export const DEFAULT_MAX_DOCUMENT_BYTES = 2 * 1024 * 1024;
|
|
140
|
+
/** The share of the document quota past which the room logs its size, by default. */
|
|
141
|
+
export const DEFAULT_DOCUMENT_WARNING = 0.8;
|
|
138
142
|
/**
|
|
139
143
|
* The largest frame a socket may send, reassembled from chunks: room for a
|
|
140
144
|
* whole document at the default quota (a client seeding an empty room).
|
|
@@ -177,75 +181,6 @@ export const DEFAULT_MAX_PRESENCE_FANOUT = 2000;
|
|
|
177
181
|
/** Seconds of the update rate a socket may spend at once. */
|
|
178
182
|
/** The ceiling of a quota knob (a host may raise the defaults up to it). */
|
|
179
183
|
const QUOTA_CEILING = 2 ** 40;
|
|
180
|
-
/**
|
|
181
|
-
* Delete ranges the room keeps waiting for items it does not hold (a
|
|
182
|
-
* relayer's delete of an author's edit a restore lost). Every update the
|
|
183
|
-
* engine applies re-reads them, so they are capped.
|
|
184
|
-
*/
|
|
185
|
-
export const MAX_WAITING_DELETES = 1024;
|
|
186
|
-
/** Refusals kept in `refusals` (the newest); `refusalCounts` counts every one. */
|
|
187
|
-
export const MAX_REFUSALS = 100;
|
|
188
|
-
/** The header `routeDocumentSocket` sets on an authorized probe: `lastUpdated` or `snapshot`. */
|
|
189
|
-
export const PROBE_HEADER = 'X-Edytor-Probe';
|
|
190
|
-
/** The transaction origin of the room's own edits (`transact`, `onLoad` seeds). */
|
|
191
|
-
export const ROOM_ORIGIN = Symbol('edytor-room');
|
|
192
|
-
/** The transaction origin of a history restore: the room's restore history tracks it. */
|
|
193
|
-
export const RESTORE_ORIGIN = Symbol('edytor-restore');
|
|
194
|
-
/** The transaction origin of the room's purge: tracked by no history. */
|
|
195
|
-
export const PURGE_ORIGIN = Symbol('edytor-purge');
|
|
196
|
-
/** The header `routeDocumentHistory` sets on an authorized history request. */
|
|
197
|
-
export const HISTORY_HEADER = 'X-Edytor-History';
|
|
198
|
-
/** The version key of a history `read` or `restore` request. */
|
|
199
|
-
export const HISTORY_KEY_HEADER = 'X-Edytor-History-Key';
|
|
200
|
-
/** The header `routeDocumentComments` sets on an authorized comments request: `list` or `post`. */
|
|
201
|
-
export const COMMENTS_HEADER = 'X-Edytor-Comments';
|
|
202
|
-
/**
|
|
203
|
-
* Headers carrying the identity `routeDocumentSocket` verified — never the
|
|
204
|
-
* client's. The user id is percent-encoded (`encodeURIComponent`): a header
|
|
205
|
-
* value is trimmed and cannot carry every character, and a user id is any
|
|
206
|
-
* string.
|
|
207
|
-
*/
|
|
208
|
-
export const IDENTITY_HEADERS = {
|
|
209
|
-
user: 'X-Edytor-User',
|
|
210
|
-
replica: 'X-Edytor-Replica',
|
|
211
|
-
access: 'X-Edytor-Access',
|
|
212
|
-
/** When the credential expires, ms since the epoch (absent: never). */
|
|
213
|
-
expires: 'X-Edytor-Expires'
|
|
214
|
-
};
|
|
215
|
-
/**
|
|
216
|
-
* An upgrade accepted and closed at once, so the client reads `code`: a
|
|
217
|
-
* browser sees an HTTP error at the upgrade only as `1006`, which a
|
|
218
|
-
* provider cannot tell from a network failure. Refuse a dial your Worker
|
|
219
|
-
* turns away itself with it: the provider stops at `1008` or `4xxx`
|
|
220
|
-
* (except `4401`, redialed), and redials after anything else (`CLOSE`,
|
|
221
|
-
* `isRefusal` in `crdt/providers/room.ts`).
|
|
222
|
-
*/
|
|
223
|
-
export const closedSocket = (code, reason) => {
|
|
224
|
-
const [client, server] = Object.values(new WebSocketPair());
|
|
225
|
-
server.accept();
|
|
226
|
-
server.close(code, reason);
|
|
227
|
-
return new Response(null, { status: 101, webSocket: client });
|
|
228
|
-
};
|
|
229
|
-
/** Run an entry point with timers forbidden — a pending timer keeps a Durable Object from hibernating. */
|
|
230
|
-
export const noTimers = (fn) => {
|
|
231
|
-
const g = globalThis;
|
|
232
|
-
const saved = [g.setTimeout, g.setInterval];
|
|
233
|
-
const forbidden = () => {
|
|
234
|
-
throw new Error('room scheduled a timer (a Durable Object could not hibernate)');
|
|
235
|
-
};
|
|
236
|
-
g.setTimeout = forbidden;
|
|
237
|
-
g.setInterval = forbidden;
|
|
238
|
-
try {
|
|
239
|
-
return fn();
|
|
240
|
-
}
|
|
241
|
-
finally {
|
|
242
|
-
[g.setTimeout, g.setInterval] = saved;
|
|
243
|
-
}
|
|
244
|
-
};
|
|
245
|
-
/** The bytes a room's comments hold at most, by default (4 MiB). */
|
|
246
|
-
export const DEFAULT_MAX_COMMENT_BYTES = 4 * 1024 * 1024;
|
|
247
|
-
/** Comment requests per second and user (or socket), by default. */
|
|
248
|
-
export const DEFAULT_MAX_COMMENT_REQUESTS_PER_SECOND = 2;
|
|
249
184
|
/** `EDYTOR_PURGE_AFTER_DAYS`: `off` (or `false`) never purges; a number of days; anything else the default. */
|
|
250
185
|
const purgeAfterDays = (value) => {
|
|
251
186
|
if (value === 'off' || value === 'false' || value === false)
|
|
@@ -253,8 +188,6 @@ const purgeAfterDays = (value) => {
|
|
|
253
188
|
const n = Number(value);
|
|
254
189
|
return Number.isInteger(n) && n > 0 ? n : undefined;
|
|
255
190
|
};
|
|
256
|
-
/** The tag of the document's sockets: other sockets of the object are left to you. */
|
|
257
|
-
export const SOCKET_TAG = 'edytor';
|
|
258
191
|
/**
|
|
259
192
|
* One edytor document living in a Durable Object's storage: the room
|
|
260
193
|
* logic, independent of the class that hosts it. Create it with
|
|
@@ -269,6 +202,7 @@ export class AttachedDocument {
|
|
|
269
202
|
compactAfter;
|
|
270
203
|
saveAfter;
|
|
271
204
|
maxDocumentBytes;
|
|
205
|
+
documentWarning;
|
|
272
206
|
maxInboundFrameBytes;
|
|
273
207
|
maxBufferedBytes;
|
|
274
208
|
maxUpdatesPerSecond;
|
|
@@ -279,7 +213,7 @@ export class AttachedDocument {
|
|
|
279
213
|
failure = null;
|
|
280
214
|
/** Latest presence entry per replica, for join snapshots (memory: refills after a wake). */
|
|
281
215
|
presence = new Map();
|
|
282
|
-
/** The newest
|
|
216
|
+
/** The newest `MAX_REFUSALS` refusals since this instance started (diagnostics; memory only). */
|
|
283
217
|
refusals = [];
|
|
284
218
|
/** Every refusal since this instance started, by reason. */
|
|
285
219
|
refusalCounts = {};
|
|
@@ -294,6 +228,8 @@ export class AttachedDocument {
|
|
|
294
228
|
this.compactAfter = knob(options.compactAfter, DEFAULT_COMPACT_AFTER, 1e9);
|
|
295
229
|
this.saveAfter = knob(options.saveAfter, DEFAULT_SAVE_AFTER, 1e9);
|
|
296
230
|
this.maxDocumentBytes = knob(options.maxDocumentBytes, DEFAULT_MAX_DOCUMENT_BYTES, QUOTA_CEILING);
|
|
231
|
+
const warning = Number(options.documentWarning);
|
|
232
|
+
this.documentWarning = warning > 0 && warning <= 1 ? warning : DEFAULT_DOCUMENT_WARNING;
|
|
297
233
|
this.maxInboundFrameBytes = knob(options.maxInboundFrameBytes, DEFAULT_MAX_INBOUND_FRAME_BYTES, QUOTA_CEILING);
|
|
298
234
|
this.maxBufferedBytes = Math.max(this.maxInboundFrameBytes, knob(options.maxBufferedBytes, 2 * this.maxInboundFrameBytes, QUOTA_CEILING));
|
|
299
235
|
this.maxUpdatesPerSecond = knob(options.maxUpdatesPerSecond, DEFAULT_MAX_UPDATES_PER_SECOND, QUOTA_CEILING);
|
|
@@ -427,7 +363,7 @@ export class AttachedDocument {
|
|
|
427
363
|
}
|
|
428
364
|
/**
|
|
429
365
|
* When the room last stored a change (ms since the epoch), or `null`
|
|
430
|
-
* for a room that stored none since
|
|
366
|
+
* for a room that stored none since it records the time. Cheap: one
|
|
431
367
|
* row, no document. `routeDocumentSocket` answers it over HTTP
|
|
432
368
|
* (`GET <room>?lastUpdated`), also over RPC.
|
|
433
369
|
*/
|
|
@@ -561,6 +497,7 @@ export class AttachedDocument {
|
|
|
561
497
|
const { counters } = room;
|
|
562
498
|
return {
|
|
563
499
|
documentBytes: room.storage.documentBytes,
|
|
500
|
+
documentLimit: room.limits.maxDocumentBytes,
|
|
564
501
|
storedBytes: stored?.bytes ?? 0,
|
|
565
502
|
records: stored?.records ?? 0,
|
|
566
503
|
rows: stored?.rows ?? 0,
|
|
@@ -582,7 +519,7 @@ export class AttachedDocument {
|
|
|
582
519
|
}
|
|
583
520
|
/**
|
|
584
521
|
* Drop every waiting delete, stored or in memory (callable over RPC):
|
|
585
|
-
* the way out when a writer filled
|
|
522
|
+
* the way out when a writer filled `MAX_WAITING_DELETES` with
|
|
586
523
|
* deletes of registered ids' items, which compaction keeps. A dropped
|
|
587
524
|
* delete's item shows if it ever arrives — but for an entry a waiting
|
|
588
525
|
* rewrite replaces, which that rewrite deletes should it integrate.
|
|
@@ -718,6 +655,7 @@ export class DocumentRoom extends DurableObject {
|
|
|
718
655
|
compactAfter: Number(knobs.EDYTOR_COMPACT_AFTER),
|
|
719
656
|
saveAfter: Number(knobs.EDYTOR_SAVE_AFTER),
|
|
720
657
|
maxDocumentBytes: Number(knobs.EDYTOR_MAX_DOCUMENT_BYTES),
|
|
658
|
+
documentWarning: Number(knobs.EDYTOR_DOCUMENT_WARNING),
|
|
721
659
|
maxInboundFrameBytes: Number(knobs.EDYTOR_MAX_INBOUND_FRAME_BYTES),
|
|
722
660
|
maxBufferedBytes: Number(knobs.EDYTOR_MAX_BUFFERED_BYTES),
|
|
723
661
|
maxUpdatesPerSecond: Number(knobs.EDYTOR_MAX_UPDATES_PER_SECOND),
|
|
@@ -200,8 +200,8 @@ export declare const historyEntry: (room: string, name: string, metadata: unknow
|
|
|
200
200
|
* Versions in a Workers KV namespace (the room history's first store): KV's
|
|
201
201
|
* TTL expires them (`nativeTtl`, `expirationTtl` = the retention, at least
|
|
202
202
|
* KV's 60 s), its listing's `expiration` is each one's `expiresAt`, its
|
|
203
|
-
* metadata the room's. Values up to KV's 25 MiB. Versions written by
|
|
204
|
-
*
|
|
203
|
+
* metadata the room's. Values up to KV's 25 MiB. Versions written by the
|
|
204
|
+
* pre-releases that took a bare namespace as the store read as they are.
|
|
205
205
|
*/
|
|
206
206
|
export declare const kvHistory: (namespace: KVLike) => HistoryStore;
|
|
207
207
|
/**
|
|
@@ -145,8 +145,8 @@ const finite = (value) => {
|
|
|
145
145
|
* Versions in a Workers KV namespace (the room history's first store): KV's
|
|
146
146
|
* TTL expires them (`nativeTtl`, `expirationTtl` = the retention, at least
|
|
147
147
|
* KV's 60 s), its listing's `expiration` is each one's `expiresAt`, its
|
|
148
|
-
* metadata the room's. Values up to KV's 25 MiB. Versions written by
|
|
149
|
-
*
|
|
148
|
+
* metadata the room's. Values up to KV's 25 MiB. Versions written by the
|
|
149
|
+
* pre-releases that took a bare namespace as the store read as they are.
|
|
150
150
|
*/
|
|
151
151
|
export const kvHistory = (namespace) => ({
|
|
152
152
|
maxValueBytes: HISTORY_MAX_VALUE_BYTES,
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* `cloudflare:workers`); built on the Worker-safe CRDT entry. Documented in
|
|
5
5
|
* the site's `server/` section (room, authorization, extending, protocol).
|
|
6
6
|
*/
|
|
7
|
-
export { DocumentRoom, AttachedDocument, attachRoom, SOCKET_TAG, closedSocket, type AttachRoomOptions, type CommentOptions, DEFAULT_COMPACT_AFTER, DEFAULT_MAX_ROW_BYTES, DEFAULT_SAVE_AFTER, DEFAULT_MAX_DOCUMENT_BYTES, DEFAULT_MAX_INBOUND_FRAME_BYTES, DEFAULT_MAX_BUFFERED_BYTES, DEFAULT_MAX_UPDATES_PER_SECOND, DEFAULT_MAX_PRESENCE_BYTES, DEFAULT_MAX_PRESENCE_PER_SECOND, DEFAULT_MAX_PRESENCE_FANOUT, DEFAULT_MAX_COMMENT_BYTES, DEFAULT_MAX_COMMENT_REQUESTS_PER_SECOND, MAX_REFUSALS, MAX_WAITING_DELETES, ROOM_ORIGIN, RESTORE_ORIGIN, PURGE_ORIGIN, IDENTITY_HEADERS, PROBE_HEADER, noTimers, type Attachment, type DocumentRoomEnv, type LoadedDocument, type Refusal, type ReplicaOwner, type SavedDocument, type SocketIdentity, type StoredRecord, type FrameValidation, type ValidatedBlock, type RoomMetrics, type RoomLogEntry, type RestoreResult, type Timing } from './DocumentRoom.js';
|
|
7
|
+
export { DocumentRoom, AttachedDocument, attachRoom, SOCKET_TAG, closedSocket, type AttachRoomOptions, type CommentOptions, DEFAULT_COMPACT_AFTER, DEFAULT_MAX_ROW_BYTES, DEFAULT_SAVE_AFTER, DEFAULT_MAX_DOCUMENT_BYTES, DEFAULT_DOCUMENT_WARNING, DEFAULT_MAX_INBOUND_FRAME_BYTES, DEFAULT_MAX_BUFFERED_BYTES, DEFAULT_MAX_UPDATES_PER_SECOND, DEFAULT_MAX_PRESENCE_BYTES, DEFAULT_MAX_PRESENCE_PER_SECOND, DEFAULT_MAX_PRESENCE_FANOUT, DEFAULT_MAX_COMMENT_BYTES, DEFAULT_MAX_COMMENT_REQUESTS_PER_SECOND, MAX_REFUSALS, MAX_WAITING_DELETES, ROOM_ORIGIN, RESTORE_ORIGIN, PURGE_ORIGIN, IDENTITY_HEADERS, PROBE_HEADER, noTimers, type Attachment, type DocumentRoomEnv, type LoadedDocument, type Refusal, type ReplicaOwner, type SavedDocument, type SocketIdentity, type StoredRecord, type FrameValidation, type ValidatedBlock, type RoomMetrics, type RoomLogEntry, type RestoreResult, type Timing } from './DocumentRoom.js';
|
|
8
8
|
export { DEFAULT_RETENTION_DAYS, HISTORY_MAX_VALUE_BYTES, R2_HISTORY_MAX_VALUE_BYTES, ROOM_HISTORY_MAX_BYTES, ROOM_HISTORY_MAX_VALUE_BYTES, kvHistory, r2History, roomHistory, type HistoryEntry, type HistoryMetadata, type HistoryOptions, type HistoryRoomStorage, type HistoryStore, type HistoryStoreFactory, type HistoryStoreRecord, type KVLike, type R2BucketLike } from './history.js';
|
|
9
9
|
export { type PurgeReport } from '../crdt/purge.js';
|
|
10
10
|
export { COMMENT_ROW_BYTES, COMMENT_STATUS, MAX_COMMENT_LENGTH, MAX_COMMENTS_PER_THREAD, MAX_THREADS, commentAnchors, commentBytes, decideComment, type ThreadComment, type CommentActor, type CommentChange, type CommentOutcome, type CommentRefusal, type CommentRequest, type CommentRun, type CommentSnapshot, type CommentThread } from '../crdt/protocols/comments.js';
|
package/dist/cloudflare/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* `cloudflare:workers`); built on the Worker-safe CRDT entry. Documented in
|
|
5
5
|
* the site's `server/` section (room, authorization, extending, protocol).
|
|
6
6
|
*/
|
|
7
|
-
export { DocumentRoom, AttachedDocument, attachRoom, SOCKET_TAG, closedSocket, DEFAULT_COMPACT_AFTER, DEFAULT_MAX_ROW_BYTES, DEFAULT_SAVE_AFTER, DEFAULT_MAX_DOCUMENT_BYTES, DEFAULT_MAX_INBOUND_FRAME_BYTES, DEFAULT_MAX_BUFFERED_BYTES, DEFAULT_MAX_UPDATES_PER_SECOND, DEFAULT_MAX_PRESENCE_BYTES, DEFAULT_MAX_PRESENCE_PER_SECOND, DEFAULT_MAX_PRESENCE_FANOUT, DEFAULT_MAX_COMMENT_BYTES, DEFAULT_MAX_COMMENT_REQUESTS_PER_SECOND, MAX_REFUSALS, MAX_WAITING_DELETES, ROOM_ORIGIN, RESTORE_ORIGIN, PURGE_ORIGIN, IDENTITY_HEADERS, PROBE_HEADER, noTimers } from './DocumentRoom.js';
|
|
7
|
+
export { DocumentRoom, AttachedDocument, attachRoom, SOCKET_TAG, closedSocket, DEFAULT_COMPACT_AFTER, DEFAULT_MAX_ROW_BYTES, DEFAULT_SAVE_AFTER, DEFAULT_MAX_DOCUMENT_BYTES, DEFAULT_DOCUMENT_WARNING, DEFAULT_MAX_INBOUND_FRAME_BYTES, DEFAULT_MAX_BUFFERED_BYTES, DEFAULT_MAX_UPDATES_PER_SECOND, DEFAULT_MAX_PRESENCE_BYTES, DEFAULT_MAX_PRESENCE_PER_SECOND, DEFAULT_MAX_PRESENCE_FANOUT, DEFAULT_MAX_COMMENT_BYTES, DEFAULT_MAX_COMMENT_REQUESTS_PER_SECOND, MAX_REFUSALS, MAX_WAITING_DELETES, ROOM_ORIGIN, RESTORE_ORIGIN, PURGE_ORIGIN, IDENTITY_HEADERS, PROBE_HEADER, noTimers } from './DocumentRoom.js';
|
|
8
8
|
export { DEFAULT_RETENTION_DAYS, HISTORY_MAX_VALUE_BYTES, R2_HISTORY_MAX_VALUE_BYTES, ROOM_HISTORY_MAX_BYTES, ROOM_HISTORY_MAX_VALUE_BYTES, kvHistory, r2History, roomHistory } from './history.js';
|
|
9
9
|
export {} from '../crdt/purge.js';
|
|
10
10
|
export { COMMENT_ROW_BYTES, COMMENT_STATUS, MAX_COMMENT_LENGTH, MAX_COMMENTS_PER_THREAD, MAX_THREADS, commentAnchors, commentBytes, decideComment } from '../crdt/protocols/comments.js';
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* revocation, a changed access, an expired credential.
|
|
7
7
|
*/
|
|
8
8
|
import { CLOSE } from '../../crdt/providers/room.js';
|
|
9
|
-
import { COMMENTS_HEADER, HISTORY_HEADER, HISTORY_KEY_HEADER, IDENTITY_HEADERS, PROBE_HEADER, SOCKET_TAG, closedSocket, noTimers } from '
|
|
9
|
+
import { COMMENTS_HEADER, HISTORY_HEADER, HISTORY_KEY_HEADER, IDENTITY_HEADERS, PROBE_HEADER, SOCKET_TAG, closedSocket, noTimers } from './shared.js';
|
|
10
10
|
import { STORAGE_FAILURE } from './context.js';
|
|
11
11
|
import { readOnlyFrame, step1Frame } from './frames.js';
|
|
12
12
|
import { StorageFault } from './replicas.js';
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import { Y } from '../../crdt/engine.js';
|
|
13
13
|
import * as E from '../../crdt/protocol.js';
|
|
14
14
|
import { ChunkLimitError, ChunkSequenceError, CLOSE } from '../../crdt/providers/room.js';
|
|
15
|
-
import { MAX_WAITING_DELETES, noTimers } from '
|
|
15
|
+
import { MAX_WAITING_DELETES, noTimers } from './shared.js';
|
|
16
16
|
import { STORAGE_FAILURE, now, sync, tally } from './context.js';
|
|
17
17
|
import { attributionWrites, BINDING_PREFIX, forgedAttributionDeletes, forgedDeletes, forgedWriters } from './forged.js';
|
|
18
18
|
import { MalformedFrame, decode, readOnlyDenialFrame, savedFrame, step1Frame, storedStep2, updateFrame } from './frames.js';
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import * as E from '../../crdt/protocol.js';
|
|
10
10
|
import { type CommentActor, type CommentOutcome, type CommentRequest, type CommentSnapshot } from '../../crdt/protocols/comments.js';
|
|
11
|
-
import {
|
|
11
|
+
import type { Attachment, SocketIdentity } from '../DocumentRoom.js';
|
|
12
12
|
import { type RoomContext } from './context.js';
|
|
13
13
|
/** The largest request body `routeDocumentComments` forwards, in bytes. */
|
|
14
14
|
export declare const MAX_COMMENT_REQUEST_BYTES: number;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import * as E from '../../crdt/protocol.js';
|
|
10
10
|
import { COMMENT_MARK, COMMENT_ROW_BYTES, COMMENT_STATUS, commentAnchors, decideComment, OVER_BYTE_QUOTA, parseCommentRequest, validCommentId } from '../../crdt/protocols/comments.js';
|
|
11
|
-
import { DEFAULT_MAX_COMMENT_BYTES, DEFAULT_MAX_COMMENT_REQUESTS_PER_SECOND, SOCKET_TAG, noTimers } from '
|
|
11
|
+
import { DEFAULT_MAX_COMMENT_BYTES, DEFAULT_MAX_COMMENT_REQUESTS_PER_SECOND, SOCKET_TAG, noTimers } from './shared.js';
|
|
12
12
|
import { allowance } from './admission.js';
|
|
13
13
|
import { knob } from './context.js';
|
|
14
14
|
import { decode } from './frames.js';
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { Y } from '../../crdt/engine.js';
|
|
11
11
|
import * as E from '../../crdt/protocol.js';
|
|
12
12
|
import type { DocumentSemanticsConfig, EdytorDoc, JSONDoc, YDoc } from '../../crdt/index.js';
|
|
13
|
-
import {
|
|
13
|
+
import type { AttachRoomOptions, AttachedDocument, Refusal, RoomLogEntry, Timing } from '../DocumentRoom.js';
|
|
14
14
|
import type { RoomAccess } from './access.js';
|
|
15
15
|
import type { Admission } from './admission.js';
|
|
16
16
|
import type { RoomComments } from './comments.js';
|
|
@@ -685,6 +685,7 @@ export type RoomLimits = Readonly<{
|
|
|
685
685
|
compactAfter: number;
|
|
686
686
|
saveAfter: number;
|
|
687
687
|
maxDocumentBytes: number;
|
|
688
|
+
documentWarning: number;
|
|
688
689
|
maxInboundFrameBytes: number;
|
|
689
690
|
maxBufferedBytes: number;
|
|
690
691
|
maxUpdatesPerSecond: number;
|
|
@@ -12,7 +12,7 @@ import * as E from '../../crdt/protocol.js';
|
|
|
12
12
|
import { CLOSE } from '../../crdt/providers/room.js';
|
|
13
13
|
import { asEngineDoc } from '../../crdt/structs.js';
|
|
14
14
|
import { defaultSemantics, facadeConfigOf, semanticsDigest } from '../../crdt/semantics.js';
|
|
15
|
-
import { MAX_REFUSALS, ROOM_ORIGIN, SOCKET_TAG, noTimers } from '
|
|
15
|
+
import { MAX_REFUSALS, ROOM_ORIGIN, SOCKET_TAG, noTimers } from './shared.js';
|
|
16
16
|
/** The engine API the room is built on (the Worker-safe CRDT entry). */
|
|
17
17
|
export const crdt = E.bindCrdt(Y);
|
|
18
18
|
export const sync = crdt.sync;
|