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.
Files changed (204) hide show
  1. package/README.md +1 -1
  2. package/dist/block/block.svelte.js +20 -4
  3. package/dist/clipboard/htmlFlow.d.ts +6 -1
  4. package/dist/clipboard/htmlFlow.js +19 -6
  5. package/dist/cloudflare/DocumentRoom.d.ts +27 -60
  6. package/dist/cloudflare/DocumentRoom.js +13 -75
  7. package/dist/cloudflare/history.d.ts +2 -2
  8. package/dist/cloudflare/history.js +2 -2
  9. package/dist/cloudflare/index.d.ts +1 -1
  10. package/dist/cloudflare/index.js +1 -1
  11. package/dist/cloudflare/room/access.js +1 -1
  12. package/dist/cloudflare/room/admission.js +1 -1
  13. package/dist/cloudflare/room/comments.d.ts +1 -1
  14. package/dist/cloudflare/room/comments.js +1 -1
  15. package/dist/cloudflare/room/context.d.ts +2 -1
  16. package/dist/cloudflare/room/context.js +1 -1
  17. package/dist/cloudflare/room/history.d.ts +1 -1
  18. package/dist/cloudflare/room/history.js +1 -1
  19. package/dist/cloudflare/room/moves.js +1 -1
  20. package/dist/cloudflare/room/presence.d.ts +1 -1
  21. package/dist/cloudflare/room/presence.js +1 -1
  22. package/dist/cloudflare/room/purge.js +1 -1
  23. package/dist/cloudflare/room/replicas.d.ts +1 -1
  24. package/dist/cloudflare/room/replicas.js +1 -1
  25. package/dist/cloudflare/room/scheduler.d.ts +1 -1
  26. package/dist/cloudflare/room/scheduler.js +2 -2
  27. package/dist/cloudflare/room/shared.d.ts +60 -0
  28. package/dist/cloudflare/room/shared.js +79 -0
  29. package/dist/cloudflare/room/storage.d.ts +9 -1
  30. package/dist/cloudflare/room/storage.js +25 -2
  31. package/dist/cloudflare/room/updates.js +1 -1
  32. package/dist/cloudflare/room/validation.d.ts +1 -1
  33. package/dist/cloudflare/room/validation.js +1 -1
  34. package/dist/cloudflare/routeDocumentSocket.js +1 -1
  35. package/dist/collaboration/history/HistoryPanel.svelte +49 -20
  36. package/dist/collaboration/history/index.d.ts +1 -1
  37. package/dist/collaboration/history/panel.d.ts +18 -0
  38. package/dist/components/Block.svelte +155 -98
  39. package/dist/components/Block.svelte.d.ts +4 -1
  40. package/dist/components/Content.svelte +90 -39
  41. package/dist/components/CustomMark.svelte +46 -0
  42. package/dist/components/CustomMark.svelte.d.ts +11 -0
  43. package/dist/components/Edytor.svelte +31 -3
  44. package/dist/components/InlineBlock.svelte +4 -9
  45. package/dist/components/Mark.svelte +46 -35
  46. package/dist/components/Mark.svelte.d.ts +7 -0
  47. package/dist/components/Text.svelte +51 -14
  48. package/dist/crdt/document.d.ts +0 -6
  49. package/dist/crdt/document.js +8 -16
  50. package/dist/crdt/protocols/envelope.d.ts +2 -2
  51. package/dist/crdt/providers/container.d.ts +2 -2
  52. package/dist/{plugins/blockHandles → dnd}/autoScroll.d.ts +2 -1
  53. package/dist/{plugins/blockHandles → dnd}/autoScroll.js +3 -2
  54. package/dist/edytor.svelte.js +5 -3
  55. package/dist/events/beforeInputCommands.js +4 -3
  56. package/dist/events/onBeforeInput.js +1 -1
  57. package/dist/events/onDrop.d.ts +6 -0
  58. package/dist/events/onDrop.js +7 -4
  59. package/dist/events/onFocus.js +52 -10
  60. package/dist/index.d.ts +2 -1
  61. package/dist/index.js +1 -1
  62. package/dist/labels.d.ts +18 -2
  63. package/dist/labels.js +13 -1
  64. package/dist/plugins/blockHandles/BlockHandle.svelte +5 -2
  65. package/dist/plugins/blockHandles/BlockHandleController.svelte.d.ts +43 -61
  66. package/dist/plugins/blockHandles/BlockHandleController.svelte.js +110 -332
  67. package/dist/plugins/blockHandles/BlockHandles.svelte +19 -12
  68. package/dist/plugins/blockHandles/blockHandlesPlugin.d.ts +23 -3
  69. package/dist/plugins/blockHandles/blockHandlesPlugin.js +33 -9
  70. package/dist/plugins/blockHandles/dragPreview.js +2 -1
  71. package/dist/plugins/blockHandles/dropIndicator.d.ts +37 -0
  72. package/dist/plugins/blockHandles/dropIndicator.js +252 -0
  73. package/dist/plugins/blockHandles/geometry.d.ts +72 -0
  74. package/dist/plugins/blockHandles/geometry.js +85 -0
  75. package/dist/plugins/blockMenu/BlockMenu.svelte +16 -128
  76. package/dist/plugins/blockMenu/BlockMenuController.svelte.d.ts +43 -2
  77. package/dist/plugins/blockMenu/BlockMenuController.svelte.js +142 -0
  78. package/dist/plugins/chrome.d.ts +72 -0
  79. package/dist/plugins/chrome.js +64 -0
  80. package/dist/plugins/code/CodeHeader.svelte +40 -54
  81. package/dist/plugins/code/CodeHeader.svelte.d.ts +1 -0
  82. package/dist/plugins/code/CodePlugin.svelte +42 -20
  83. package/dist/plugins/code/LanguageMenu.svelte +134 -0
  84. package/dist/plugins/code/LanguageMenu.svelte.d.ts +8 -0
  85. package/dist/plugins/code/code.css +37 -20
  86. package/dist/plugins/code/header.svelte.d.ts +56 -0
  87. package/dist/plugins/code/header.svelte.js +168 -0
  88. package/dist/plugins/code/languageMenu.svelte.d.ts +104 -0
  89. package/dist/plugins/code/languageMenu.svelte.js +329 -0
  90. package/dist/plugins/code/languages.d.ts +21 -0
  91. package/dist/plugins/comments/CommentsSidebar.svelte +3 -2
  92. package/dist/plugins/comments/CommentsSidebar.svelte.d.ts +3 -6
  93. package/dist/plugins/comments/commentsPlugin.d.ts +10 -5
  94. package/dist/plugins/equation/EquationEditor.svelte +31 -28
  95. package/dist/plugins/equation/EquationEditor.svelte.d.ts +2 -0
  96. package/dist/plugins/equation/EquationPlugin.svelte +15 -4
  97. package/dist/plugins/equation/EquationPlugin.svelte.d.ts +5 -3
  98. package/dist/plugins/equation/equation.svelte.d.ts +43 -18
  99. package/dist/plugins/equation/equation.svelte.js +90 -8
  100. package/dist/plugins/equation/importUrl.d.ts +6 -0
  101. package/dist/plugins/equation/importUrl.js +6 -0
  102. package/dist/plugins/equation/katex.d.ts +8 -0
  103. package/dist/plugins/equation/katex.js +80 -0
  104. package/dist/plugins/image/ImageChrome.svelte +27 -12
  105. package/dist/plugins/image/ImageChrome.svelte.d.ts +2 -0
  106. package/dist/plugins/image/ImageEmpty.svelte +25 -48
  107. package/dist/plugins/image/ImageEmpty.svelte.d.ts +3 -0
  108. package/dist/plugins/image/ImagePlugin.svelte +27 -6
  109. package/dist/plugins/image/ImagePlugin.svelte.d.ts +18 -0
  110. package/dist/plugins/image/controls.svelte.d.ts +14 -35
  111. package/dist/plugins/image/controls.svelte.js +56 -10
  112. package/dist/plugins/image/empty.svelte.d.ts +56 -0
  113. package/dist/plugins/image/empty.svelte.js +83 -0
  114. package/dist/plugins/index.d.ts +14 -4
  115. package/dist/plugins/index.js +3 -2
  116. package/dist/plugins/marquee/MarqueeBox.svelte +32 -0
  117. package/dist/plugins/marquee/MarqueeBox.svelte.d.ts +9 -0
  118. package/dist/plugins/marquee/MarqueeController.svelte.d.ts +48 -0
  119. package/dist/plugins/marquee/MarqueeController.svelte.js +246 -0
  120. package/dist/plugins/marquee/marquee.d.ts +33 -0
  121. package/dist/plugins/marquee/marquee.js +106 -0
  122. package/dist/plugins/marquee/marqueePlugin.d.ts +31 -0
  123. package/dist/plugins/marquee/marqueePlugin.js +67 -0
  124. package/dist/plugins/media/AudioPlugin.svelte +2 -0
  125. package/dist/plugins/media/BookmarkPlugin.svelte +22 -3
  126. package/dist/plugins/media/BookmarkPlugin.svelte.d.ts +18 -0
  127. package/dist/plugins/media/EmbedPlugin.svelte +22 -2
  128. package/dist/plugins/media/EmbedPlugin.svelte.d.ts +18 -0
  129. package/dist/plugins/media/FilePlugin.svelte +2 -0
  130. package/dist/plugins/media/MediaEmpty.svelte +35 -53
  131. package/dist/plugins/media/UrlPasteMenu.svelte +16 -7
  132. package/dist/plugins/media/UrlPasteMenu.svelte.d.ts +2 -0
  133. package/dist/plugins/media/VideoPlugin.svelte +2 -0
  134. package/dist/plugins/media/empty.svelte.d.ts +77 -0
  135. package/dist/plugins/media/empty.svelte.js +115 -0
  136. package/dist/plugins/media/media.d.ts +17 -0
  137. package/dist/plugins/media/media.js +15 -0
  138. package/dist/plugins/media/urlPaste.svelte.d.ts +22 -14
  139. package/dist/plugins/media/urlPaste.svelte.js +48 -7
  140. package/dist/plugins/mention/MentionPlugin.svelte +11 -7
  141. package/dist/plugins/mention/MentionPlugin.svelte.d.ts +7 -0
  142. package/dist/plugins/pageLink/PageLinkPlugin.svelte +11 -7
  143. package/dist/plugins/pageLink/PageLinkPlugin.svelte.d.ts +7 -0
  144. package/dist/plugins/richtext/CalloutIcon.svelte +38 -0
  145. package/dist/plugins/richtext/CalloutIcon.svelte.d.ts +9 -0
  146. package/dist/plugins/richtext/CalloutIconMenu.svelte +98 -0
  147. package/dist/plugins/richtext/CalloutIconMenu.svelte.d.ts +9 -0
  148. package/dist/plugins/richtext/EmptyBody.svelte +32 -0
  149. package/dist/plugins/richtext/EmptyBody.svelte.d.ts +8 -0
  150. package/dist/plugins/richtext/RichTextPlugin.svelte +201 -61
  151. package/dist/plugins/richtext/RichTextPlugin.svelte.d.ts +21 -1
  152. package/dist/plugins/richtext/TodoCheckbox.svelte +2 -2
  153. package/dist/plugins/richtext/body.d.ts +9 -0
  154. package/dist/plugins/richtext/body.js +16 -0
  155. package/dist/plugins/richtext/calloutIcons.svelte.d.ts +102 -0
  156. package/dist/plugins/richtext/calloutIcons.svelte.js +302 -0
  157. package/dist/plugins/richtext/labels.d.ts +6 -2
  158. package/dist/plugins/richtext/labels.js +6 -2
  159. package/dist/plugins/slashMenu/SlashMenu.svelte +25 -109
  160. package/dist/plugins/slashMenu/SlashMenuController.svelte.d.ts +19 -0
  161. package/dist/plugins/slashMenu/SlashMenuController.svelte.js +95 -0
  162. package/dist/plugins/slashMenu/slashMenuPlugin.d.ts +15 -11
  163. package/dist/plugins/suggestions/SuggestionBars.svelte +6 -1
  164. package/dist/plugins/suggestions/suggestionsPlugin.d.ts +3 -1
  165. package/dist/plugins/table/TableChrome.svelte +174 -121
  166. package/dist/plugins/table/TableChrome.svelte.d.ts +5 -1
  167. package/dist/plugins/table/TablePlugin.svelte +16 -9
  168. package/dist/plugins/table/chrome.svelte.d.ts +190 -94
  169. package/dist/plugins/table/chrome.svelte.js +658 -54
  170. package/dist/plugins/table/dragPreview.d.ts +29 -0
  171. package/dist/plugins/table/dragPreview.js +103 -0
  172. package/dist/plugins/table/table.css +59 -2
  173. package/dist/plugins/table/table.d.ts +18 -0
  174. package/dist/plugins/table/table.js +1 -33
  175. package/dist/plugins/toolbar/LinkCard.svelte +6 -2
  176. package/dist/plugins/toolbar/LinkCard.svelte.d.ts +2 -0
  177. package/dist/plugins/toolbar/Toolbar.svelte +10 -61
  178. package/dist/plugins/toolbar/ToolbarController.svelte.d.ts +27 -0
  179. package/dist/plugins/toolbar/ToolbarController.svelte.js +101 -0
  180. package/dist/plugins/toolbar/toolbarPlugin.d.ts +14 -3
  181. package/dist/plugins/toolbar/toolbarPlugin.js +1 -1
  182. package/dist/plugins/triggers/TriggerController.svelte.d.ts +25 -0
  183. package/dist/plugins/triggers/TriggerController.svelte.js +36 -0
  184. package/dist/plugins/triggers/TriggerMenu.svelte +27 -36
  185. package/dist/plugins.d.ts +25 -13
  186. package/dist/selection/pointer.svelte.d.ts +36 -0
  187. package/dist/selection/pointer.svelte.js +440 -0
  188. package/dist/selection/selection.svelte.d.ts +0 -8
  189. package/dist/selection/selection.svelte.js +61 -289
  190. package/dist/selection/visibility.d.ts +8 -0
  191. package/dist/selection/visibility.js +16 -3
  192. package/dist/session/attempt.js +4 -2
  193. package/dist/session/navigation.d.ts +15 -1
  194. package/dist/session/navigation.js +83 -1
  195. package/dist/session/ports.d.ts +12 -0
  196. package/dist/session/selection.js +3 -0
  197. package/dist/session/suggestions.svelte.js +22 -0
  198. package/dist/surface/lines.d.ts +32 -0
  199. package/dist/surface/lines.js +43 -0
  200. package/dist/surface/observer.svelte.js +20 -4
  201. package/dist/surface/overlay.d.ts +8 -4
  202. package/dist/surface/overlay.js +64 -9
  203. package/dist/themes/notion.css +53 -21
  204. 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.1` 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.
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.selectedBlocks.has(this);
120
+ return this.edytor.selection.isSelected(this);
121
121
  }
122
122
  get focused() {
123
- return this.edytor.selection.focusedBlocks.has(this) && !this.selected;
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.parent ? this.parent.children[this.index + 1] : null;
198
+ return this.#sibling(1);
199
199
  }
200
200
  get previousBlock() {
201
- return this.parent ? this.parent.children[this.index - 1] : null;
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
- /** The tag a kind writes for `data`: its export form's first tag, else its element's, else its content element's. */
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
- /** The tag a kind writes for `data`: its export form's first tag, else its element's, else its content element's. */
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
- return /^<([a-z][\w-]*)/i.exec(html({ type, data }, '', ''))?.[1]?.toLowerCase();
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
- else if (!current.content.length &&
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
- * {@link MAX_WAITING_DELETES} ranges wait, stored or in memory: a frame
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
- * {@link DEFAULT_MAX_COMMENT_BYTES}, 4 MiB): each body and quote in UTF-8
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
- * {@link DEFAULT_MAX_COMMENT_REQUESTS_PER_SECOND}, a ten-second burst):
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 KV (`room.history.*`): the room writes its
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 {@link MAX_REFUSALS} refusals since this instance started (diagnostics; memory only). */
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 0.1.0-next.23. Cheap: one
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 {@link MAX_WAITING_DELETES} with
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
- * {@link MAX_WAITING_DELETES} ranges wait, stored or in memory: a frame
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 {@link MAX_REFUSALS} refusals since this instance started (diagnostics; memory only). */
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 0.1.0-next.23. Cheap: one
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 {@link MAX_WAITING_DELETES} with
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
- * 0.1.0-next.24 and next.25 (a bare namespace as the store) read as they are.
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
- * 0.1.0-next.24 and next.25 (a bare namespace as the store) read as they are.
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';
@@ -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 '../DocumentRoom.js';
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 '../DocumentRoom.js';
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 { type Attachment, type SocketIdentity } from '../DocumentRoom.js';
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 '../DocumentRoom.js';
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 { type AttachRoomOptions, type AttachedDocument, type Refusal, type RoomLogEntry, type Timing } from '../DocumentRoom.js';
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 '../DocumentRoom.js';
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;