@fileverse-dev/ddoc 4.1.11 → 4.1.12-durability-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { k as Ql, b as Zl, s as eh } from "./index-BhAjJb8w.mjs";
1
+ import { k as Ql, b as Zl, s as eh } from "./index-CTR-epIo.mjs";
2
2
  let An = [], Xr = [];
3
3
  (() => {
4
4
  let s = "lc,34,7n,7,7b,19,,,,2,,2,,,20,b,1c,l,g,,2t,7,2,6,2,2,,4,z,,u,r,2j,b,1m,9,9,,o,4,,9,,3,,5,17,3,3b,f,,w,1j,,,,4,8,4,,3,7,a,2,t,,1m,,,,2,4,8,,9,,a,2,q,,2,2,1l,,4,2,4,2,2,3,3,,u,2,3,,b,2,1l,,4,5,,2,4,,k,2,m,6,,,1m,,,2,,4,8,,7,3,a,2,u,,1n,,,,c,,9,,14,,3,,1l,3,5,3,,4,7,2,b,2,t,,1m,,2,,2,,3,,5,2,7,2,b,2,s,2,1l,2,,,2,4,8,,9,,a,2,t,,20,,4,,2,3,,,8,,29,,2,7,c,8,2q,,2,9,b,6,22,2,r,,,,,,1j,e,,5,,2,5,b,,10,9,,2u,4,,6,,2,2,2,p,2,4,3,g,4,d,,2,2,6,,f,,jj,3,qa,3,t,3,t,2,u,2,1s,2,,7,8,,2,b,9,,19,3,3b,2,y,,3a,3,4,2,9,,6,3,63,2,2,,1m,,,7,,,,,2,8,6,a,2,,1c,h,1r,4,1c,7,,,5,,14,9,c,2,w,4,2,2,,3,1k,,,2,3,,,3,1m,8,2,2,48,3,,d,,7,4,,6,,3,2,5i,1m,,5,ek,,5f,x,2da,3,3x,,2o,w,fe,6,2x,2,n9w,4,,a,w,2,28,2,7k,,3,,4,,p,2,5,,47,2,q,i,d,,12,8,p,b,1a,3,1c,,2,4,2,2,13,,1v,6,2,2,2,2,c,,8,,1b,,1f,,,3,2,2,5,2,,,16,2,8,,6m,,2,,4,,fn4,,kh,g,g,g,a6,2,gt,,6a,,45,5,1ae,3,,2,5,4,14,3,4,,4l,2,fx,4,ar,2,49,b,4w,,1i,f,1k,3,1d,4,2,2,1x,3,10,5,,8,1q,,c,2,1g,9,a,4,2,,2n,3,2,,,2,6,,4g,,3,8,l,2,1l,2,,,,,m,,e,7,3,5,5f,8,2,3,,,n,,29,,2,6,,,2,,,2,,2,6j,,2,4,6,2,,2,r,2,2d,8,2,,,2,2y,,,,2,6,,,2t,3,2,4,,5,77,9,,2,6t,,a,2,,,4,,40,4,2,2,4,,w,a,14,6,2,4,8,,9,6,2,3,1a,d,,2,ba,7,,6,,,2a,m,2,7,,2,,2,3e,6,3,,,2,,7,,,20,2,3,,,,9n,2,f0b,5,1n,7,t4,,1r,4,29,,f5k,2,43q,,,3,4,5,8,8,2,7,u,4,44,3,1iz,1j,4,1e,8,,e,,m,5,,f,11s,7,,h,2,7,,2,,5,79,7,c5,4,15s,7,31,7,240,5,gx7k,2o,3k,6o".split(",").map((e) => e ? parseInt(e, 36) : 1);
package/dist/index.d.ts CHANGED
@@ -5,6 +5,8 @@ export { DdocExportModal } from './package/components/export-modal';
5
5
  export { useHeadlessEditor } from './package/hooks/use-headless-editor';
6
6
  export { useExportHeadlessEditorContent } from './package/hooks/use-export-headless-editor-content';
7
7
  export { mergeTabAwareYjsUpdates } from './package/components/tabs/utils/tab-utils';
8
+ export { validateCustomCss, sanitizeCustomCss, } from './package/utils/sanitize-css';
9
+ export type { CssDiagnostic, CssValidationResult, } from './package/utils/sanitize-css';
8
10
  export { buildVersionDiffSnapshot } from './package/components/tabs/utils/version-diff-snapshot';
9
11
  export type { DdocExportModalProps, ExportFormatOption, ExportTabOption, } from './package/components/export-modal';
10
12
  export type { VersionTabSnapshot } from './package/components/tabs/utils/version-diff-snapshot';
package/dist/index.es.js CHANGED
@@ -1,12 +1,14 @@
1
- import { D as e, a as o, E as d, P as t, d as r, h as i, m as n, c as E, u as l } from "./index-BhAjJb8w.mjs";
1
+ import { D as e, a as o, E as t, P as d, e as r, h as i, m as n, d as E, c as l, u, v as C } from "./index-CTR-epIo.mjs";
2
2
  export {
3
3
  e as DdocEditor,
4
4
  o as DdocExportModal,
5
- d as Editor,
6
- t as PreviewDdocEditor,
5
+ t as Editor,
6
+ d as PreviewDdocEditor,
7
7
  r as buildVersionDiffSnapshot,
8
8
  i as handleContentPrint,
9
9
  n as mergeTabAwareYjsUpdates,
10
- E as useExportHeadlessEditorContent,
11
- l as useHeadlessEditor
10
+ E as sanitizeCustomCss,
11
+ l as useExportHeadlessEditorContent,
12
+ u as useHeadlessEditor,
13
+ C as validateCustomCss
12
14
  };
@@ -1,9 +1,9 @@
1
1
  var Vr = Object.defineProperty;
2
2
  var Wr = (t, e, O) => e in t ? Vr(t, e, { enumerable: !0, configurable: !0, writable: !0, value: O }) : t[e] = O;
3
3
  var gt = (t, e, O) => Wr(t, typeof e != "symbol" ? e + "" : e, O);
4
- import { j as Cr } from "./index-BhAjJb8w.mjs";
4
+ import { j as Cr } from "./index-CTR-epIo.mjs";
5
5
  import { useRef as pe, useEffect as St } from "react";
6
- import { s as y, A as pO, T as dO, a as Gr, S as et, b as Lr, P as fO, E as j, i as QO, c as _, D as le, k as tt, F as Ar, M as Pt, W as Er, R as Ur, d as mO, N as oe, e as V, f as Mr, g as Ot, h as ce, p as $O, j as Y, t as h, l as Ir, I as rt, L as at, m as ye, n as ue, o as Qe, q as gO, r as te, u as SO, v as Br, w as Nr, x as PO, y as kO, z as Dr, B as Fr, C as Kr, G as Oe, H as ZO, J as Jr, K as kt, O as Hr, Q as ea, U as ta, V as Oa, X as ra, Y as aa, Z as ia, _ as sa, $ as na, a0 as la, a1 as oa, a2 as ca } from "./index-rpz9D-nF.mjs";
6
+ import { s as y, A as pO, T as dO, a as Gr, S as et, b as Lr, P as fO, E as j, i as QO, c as _, D as le, k as tt, F as Ar, M as Pt, W as Er, R as Ur, d as mO, N as oe, e as V, f as Mr, g as Ot, h as ce, p as $O, j as Y, t as h, l as Ir, I as rt, L as at, m as ye, n as ue, o as Qe, q as gO, r as te, u as SO, v as Br, w as Nr, x as PO, y as kO, z as Dr, B as Fr, C as Kr, G as Oe, H as ZO, J as Jr, K as kt, O as Hr, Q as ea, U as ta, V as Oa, X as ra, Y as aa, Z as ia, _ as sa, $ as na, a0 as la, a1 as oa, a2 as ca } from "./index-DOdUt7ap.mjs";
7
7
  class ua {
8
8
  /**
9
9
  Create a new completion context. (Mostly useful for testing
@@ -0,0 +1,13 @@
1
+ interface SplitViewCssAccordionProps {
2
+ /** The document's custom CSS (raw author selectors). */
3
+ customCSS?: string;
4
+ }
5
+ /**
6
+ * Split View LEFT pane: a collapsible, READ-ONLY view of the document's custom
7
+ * CSS, shown above the markdown source. Custom CSS is edited in the styling
8
+ * palette (the single source of truth), not in the markdown pane — this is a
9
+ * transparency affordance so the author can see what CSS is applied while in
10
+ * markdown mode. Renders nothing when there is no custom CSS.
11
+ */
12
+ export declare const SplitViewCssAccordion: ({ customCSS, }: SplitViewCssAccordionProps) => import("react/jsx-runtime").JSX.Element | null;
13
+ export {};
@@ -6,6 +6,8 @@ interface SplitViewMarkdownPaneProps {
6
6
  /** Same uploader the editor uses — for the markdown toolbar's Image button. */
7
7
  ipfsImageUploadFn?: (file: File) => Promise<IpfsImageUploadResponse>;
8
8
  onError?: (error: string) => void;
9
+ /** Document custom CSS — shown read-only in a collapsible accordion. */
10
+ customCSS?: string;
9
11
  /** Sizing for the resizable split (flex-grow set by the draggable splitter). */
10
12
  style?: React.CSSProperties;
11
13
  }
@@ -15,5 +17,5 @@ interface SplitViewMarkdownPaneProps {
15
17
  * real ddoc editor itself — see ddoc-editor.tsx, which keeps that editor mounted
16
18
  * in place (never a second <EditorContent>) so its React node views survive.
17
19
  */
18
- export declare const SplitViewMarkdownPane: ({ markdown, onMarkdownChange, ipfsImageUploadFn, onError, style, }: SplitViewMarkdownPaneProps) => import("react/jsx-runtime").JSX.Element;
20
+ export declare const SplitViewMarkdownPane: ({ markdown, onMarkdownChange, ipfsImageUploadFn, onError, customCSS, style, }: SplitViewMarkdownPaneProps) => import("react/jsx-runtime").JSX.Element;
19
21
  export {};
@@ -7,6 +7,11 @@ export declare const turndownService: TurndownService;
7
7
  export declare const setMarkdownInlineStyles: (enabled: boolean) => void;
8
8
  export declare const setResolveColorVars: (enabled: boolean) => void;
9
9
  declare module '@tiptap/core' {
10
+ interface Storage {
11
+ markdownPasteHandler: {
12
+ customCSS: string;
13
+ };
14
+ }
10
15
  interface Commands {
11
16
  uploadMarkdownFile: {
12
17
  uploadMarkdownFile: (ipfsImageUploadFn?: (file: File) => Promise<IpfsImageUploadResponse>, onError?: (error: string) => void) => any;
@@ -17,7 +17,6 @@ interface UseTabEditorArgs {
17
17
  initialContent: DdocProps['initialContent'];
18
18
  collaboration?: CollaborationProps;
19
19
  isReady?: boolean;
20
- isSyncing?: boolean;
21
20
  awareness?: any;
22
21
  disableInlineComment?: boolean;
23
22
  isFocusMode?: boolean;
@@ -45,6 +44,8 @@ interface UseTabEditorArgs {
45
44
  ignoreCorruptedData?: boolean;
46
45
  onCollaboratorChange?: DdocProps['onCollaboratorChange'];
47
46
  onConnect: (connectConfig: CollabConnectionConfig) => void;
47
+ onDisconnect: () => void;
48
+ isIndexeddbSynced: boolean;
48
49
  hasCollabContentInitialised?: boolean;
49
50
  initialiseYjsIndexedDbProvider: () => Promise<void>;
50
51
  externalExtensions?: Record<string, AnyExtension>;
@@ -56,7 +57,7 @@ interface UseTabEditorArgs {
56
57
  initialCommentAnchors?: SerializedCommentAnchor[];
57
58
  dBlockRuntimeStateRef?: DBlockRuntimeStateRef;
58
59
  }
59
- export declare const useTabEditor: ({ ydoc, isVersionMode, hasTabState, versionId, isPreviewMode, viewerMode, initialContent, collaboration, isReady, isSyncing, awareness, disableInlineComment, isFocusMode, onCommentInteraction, onError, ipfsImageUploadFn, metadataProxyUrl, onCopyHeadingLink, ipfsImageFetchFn, fetchV1ImageFn, isConnected, activeModel, maxTokens, isAIAgentEnabled, setCharacterCount, setWordCount, setSelectedWordCount, setPageCount, setIsContentLoading, setIsCollabContentLoading, unFocused, zoomLevel, isPresentationMode, onInvalidContentError, ignoreCorruptedData, onCollaboratorChange, onConnect, hasCollabContentInitialised, initialiseYjsIndexedDbProvider, externalExtensions, isContentLoading, activeTabId, tabIds, theme, editorRef, initialCommentAnchors, dBlockRuntimeStateRef, }: UseTabEditorArgs) => {
60
+ export declare const useTabEditor: ({ ydoc, isVersionMode, hasTabState, versionId, isPreviewMode, viewerMode, initialContent, collaboration, isReady, awareness, disableInlineComment, isFocusMode, onCommentInteraction, onError, ipfsImageUploadFn, metadataProxyUrl, onCopyHeadingLink, ipfsImageFetchFn, fetchV1ImageFn, isConnected, activeModel, maxTokens, isAIAgentEnabled, setCharacterCount, setWordCount, setSelectedWordCount, setPageCount, setIsContentLoading, setIsCollabContentLoading, unFocused, zoomLevel, isPresentationMode, onInvalidContentError, ignoreCorruptedData, onCollaboratorChange, onConnect, onDisconnect, isIndexeddbSynced, hasCollabContentInitialised, initialiseYjsIndexedDbProvider, externalExtensions, isContentLoading, activeTabId, tabIds, theme, editorRef, initialCommentAnchors, dBlockRuntimeStateRef, }: UseTabEditorArgs) => {
60
61
  editor: Editor | null;
61
62
  cachedEditorEntries: import('./use-tab-editor-cache').CachedTabEditorRenderEntry[];
62
63
  ref: import('react').RefObject<HTMLDivElement>;
@@ -11,6 +11,7 @@ interface UseYjsSetupArgs {
11
11
  export declare const useYjsSetup: ({ onChange, enableIndexeddbSync, ddocId, collaboration, onIndexedDbError, }: UseYjsSetupArgs) => {
12
12
  ydoc: Y.Doc;
13
13
  onConnect: (connectConfig: import('../types').CollabConnectionConfig) => void;
14
+ onDisconnect: () => void;
14
15
  isReady: boolean;
15
16
  isSyncing: boolean;
16
17
  terminateSession: () => void;
@@ -11,21 +11,23 @@ export declare class SyncManager {
11
11
  private roomKeyBytes;
12
12
  private isOwner;
13
13
  private updateQueue;
14
- private uncommittedUpdatesIdList;
15
14
  private contentTobeAppliedQueue;
16
15
  private isProcessing;
17
16
  private syncId;
17
+ private floor;
18
+ private updatesSinceSnapshot;
19
+ private isAuthoringSnapshot;
20
+ private readonly SNAPSHOT_THRESHOLD;
18
21
  private flushTimer;
19
22
  private readonly FLUSH_INTERVAL_MS;
20
23
  private readonly MAX_QUEUE_SIZE;
21
24
  private _awarenessUpdateHandler;
22
25
  private ydoc;
23
- private servicesRef;
24
26
  private callbacksRef;
25
27
  private onLocalUpdate?;
26
28
  constructor(config: SyncManagerConfig, onCollabStateChange: (state: CollabState) => void);
27
29
  /** Called by useSyncManager on every render to keep refs fresh */
28
- updateRefs(services: CollabServices | undefined, callbacks: CollabCallbacks | undefined, onLocalUpdate?: (updatedDocContent: string, updateChunk: string) => void): void;
30
+ updateRefs(_services: CollabServices | undefined, callbacks: CollabCallbacks | undefined, onLocalUpdate?: (updatedDocContent: string, updateChunk: string) => void): void;
29
31
  get isConnected(): boolean;
30
32
  get isReady(): boolean;
31
33
  get awareness(): Awareness | null;
@@ -46,21 +48,23 @@ export declare class SyncManager {
46
48
  * Fire-and-forget: merge all queued updates, encrypt, and emit via Socket.IO
47
49
  * without awaiting the server ACK. The server broadcasts to peers immediately
48
50
  * (before MongoDB write), so content reaches observers in near-real-time.
49
- * ACK callback handles updateId tracking and auto-commit asynchronously.
50
51
  */
51
52
  private sendUpdateBatch;
53
+ buildPendingBeaconPayload(): string | null;
54
+ fireBeacon(): void;
52
55
  forceCleanup(): void;
53
56
  private handleConnectionError;
54
57
  private handleReconnection;
55
58
  private connectSocket;
56
- private syncLatestCommit;
59
+ private decodeInto;
60
+ private catchUpFloor;
61
+ private authorSnapshot;
62
+ private hydrate;
57
63
  private initializeAwareness;
58
64
  private cleanupAwareness;
59
- private commitLocalContents;
60
65
  private broadcastLocalContents;
61
66
  private processUpdateQueue;
62
67
  private processNextUpdate;
63
- private processCommit;
64
68
  private handleRemoteContentUpdate;
65
69
  private applyRemoteYjsUpdate;
66
70
  private applyQueuedRemoteContents;
@@ -0,0 +1,6 @@
1
+ export declare function advanceFloor(floor: number, pageSeqsAscending: number[]): number;
2
+ export declare function shouldAuthorSnapshot(p: {
3
+ isOwner: boolean;
4
+ updatesSinceLastSnapshot: number;
5
+ threshold: number;
6
+ }): boolean;
@@ -1,4 +1,4 @@
1
- import { ISocketInitConfig, RoomMember, SocketStatusEnum, SendUpdateResponse, CommitResponse, AckResponse } from './types';
1
+ import { ISocketInitConfig, RoomMember, SocketStatusEnum, SendUpdateResponse, HydrationResponse, SnapshotResponse, AckResponse } from './types';
2
2
  import { Awareness } from 'y-protocols/awareness.js';
3
3
 
4
4
  interface ISocketClientConfig {
@@ -8,6 +8,9 @@ interface ISocketClientConfig {
8
8
  ownerEdSecret?: string;
9
9
  contractAddress?: string;
10
10
  ownerAddress?: string;
11
+ ownerIdentityDid?: string;
12
+ editLock?: string;
13
+ encryptedTitle?: string;
11
14
  onHandshakeData?: (response: {
12
15
  data: AckResponse;
13
16
  roomKey: string;
@@ -20,6 +23,8 @@ interface ISocketClientConfig {
20
23
  }
21
24
  export declare class SocketClient {
22
25
  private _socketUrl;
26
+ private _restBase;
27
+ private _lastSessionToken;
23
28
  private _socket;
24
29
  private _webSocketStatus;
25
30
  private _isIntentionalDisconnect;
@@ -34,6 +39,9 @@ export declare class SocketClient {
34
39
  private ownerUcan?;
35
40
  private collaborationUcan?;
36
41
  private ownerAddress?;
42
+ private ownerIdentityDid?;
43
+ private editLock?;
44
+ private encryptedTitle?;
37
45
  private roomKey;
38
46
  private roomInfo?;
39
47
  private awareness;
@@ -46,15 +54,17 @@ export declare class SocketClient {
46
54
  sendUpdate({ update }: {
47
55
  update: string;
48
56
  }): Promise<SendUpdateResponse>;
49
- commitUpdates({ updates, cid }: {
50
- updates: string[];
51
- cid: string;
52
- }): Promise<CommitResponse>;
53
- fetchLatestCommit(): Promise<AckResponse<any>>;
54
- getUncommittedChanges(): Promise<AckResponse<any>>;
57
+ fetchHydrationRange(sinceSeq?: number): Promise<HydrationResponse>;
58
+ sendSnapshot({ data, floorSeq, publishedMarker, }: {
59
+ data: string;
60
+ floorSeq: number;
61
+ publishedMarker?: string | null;
62
+ }): Promise<SnapshotResponse>;
63
+ setDocumentMeta(): Promise<void>;
55
64
  broadcastAwareness(awarenessUpdate: string): Promise<void>;
56
65
  disconnect: () => void;
57
66
  terminateSession: () => Promise<void>;
67
+ flushBeacon(mergedUpdate: string): void;
58
68
  private getCollaborationKeyPair;
59
69
  private isUcanValid;
60
70
  private getOwnerToken;
@@ -7,6 +7,16 @@ export interface CollabConnectionConfig {
7
7
  roomId: string;
8
8
  wsUrl: string;
9
9
  isOwner: boolean;
10
+ /** Host signal: doc is in an active live-collaboration context (shared / peers present). Keeps the socket connected. */
11
+ livePresence?: boolean;
12
+ /** Host signal: connect once on open to initialise durability even without an edit. */
13
+ connectOnOpen?: boolean;
14
+ /** Host signal (owner-only): the owner identity signingKey DID. Recorded by the durable server on the first owner /auth as the R3 owner binding. */
15
+ ownerIdentityDid?: string;
16
+ /** Host signal (owner-only): wrapped roomKey bytes (owner-lock construction), uploaded as the server editLock recovery artifact. Opaque to the package. */
17
+ editLock?: string;
18
+ /** Host signal (owner-only): the document title encrypted with the roomKey, uploaded as the server title recovery artifact. Opaque to the package. */
19
+ encryptedTitle?: string;
10
20
  ownerEdSecret?: string;
11
21
  contractAddress?: string;
12
22
  ownerAddress?: string;
@@ -21,11 +31,7 @@ export interface CollabSessionMeta {
21
31
  username: string;
22
32
  isEns?: boolean;
23
33
  }
24
- /** Storage integrations the sync engine depends on */
25
- export interface CollabServices {
26
- commitToStorage?: (file: File) => Promise<string>;
27
- fetchFromStorage?: (cid: string) => Promise<any>;
28
- }
34
+ export type CollabServices = Record<string, never>;
29
35
  export type CollabErrorCode = 'CONNECTION_FAILED' | 'AUTH_FAILED' | 'SYNC_FAILED' | 'TIMEOUT' | 'UNKNOWN';
30
36
  export type CollabError = {
31
37
  code: CollabErrorCode;
@@ -145,11 +151,30 @@ export interface SendUpdateResponse extends AckResponse<{
145
151
  createdAt: number;
146
152
  }> {
147
153
  }
148
- export interface CommitResponse extends AckResponse<{
149
- cid: string;
150
- createdAt: number;
154
+ export interface HydrationRow {
155
+ id: string;
151
156
  documentId: string;
152
- updates: string[];
157
+ seq: number;
158
+ data: string;
159
+ updateType: string;
160
+ committed?: boolean;
161
+ commitCid?: string | null;
162
+ createdAt?: number;
163
+ sessionDid?: string;
164
+ publishedMarker?: string | null;
165
+ floorSeq?: number | null;
166
+ }
167
+ export interface HydrationResponse extends AckResponse<{
168
+ history: HydrationRow[];
169
+ total: number;
170
+ snapshot: HydrationRow | null;
171
+ nextSeq: number | null;
172
+ hasMore: boolean;
173
+ }> {
174
+ }
175
+ export interface SnapshotResponse extends AckResponse<{
176
+ id: string;
177
+ seq: number;
153
178
  }> {
154
179
  }
155
180
  export interface ISocketInitConfig {
@@ -196,4 +221,5 @@ export interface IAuthArgs {
196
221
  contractAddress?: string;
197
222
  sessionDid?: string;
198
223
  roomInfo?: string;
224
+ ownerIdentityDid?: string;
199
225
  }
@@ -103,6 +103,17 @@ export interface DocumentStyling {
103
103
  * @example "portrait" | "landscape"
104
104
  */
105
105
  orientation?: 'portrait' | 'landscape';
106
+ /**
107
+ * Custom CSS
108
+ * @description The author's escape hatch for styling the document beyond the
109
+ * structured options above. Write BARE selectors (`h1 { … }`, `p { … }`,
110
+ * `blockquote { … }`) — they are auto-scoped to the document content, so rules
111
+ * can't leak into the toolbar or the host app. Bare top-level declarations
112
+ * (e.g. `background`, `font-family`) style the document surface itself.
113
+ * Applies live in the editor, in preview, and in exports (Markdown/HTML).
114
+ * @example "h1 { letter-spacing: -0.02em } p { line-height: 1.8 }"
115
+ */
116
+ customCSS?: string;
106
117
  }
107
118
  export interface DdocProps extends CommentAccountProps {
108
119
  /**
@@ -28,6 +28,7 @@ export declare const useDdocEditor: ({ isPreviewMode, viewerMode, initialContent
28
28
  duplicateTab: (tabId: string) => string | undefined;
29
29
  orderTab: (destinationTabId: string, movedTabId: string) => void;
30
30
  onConnect: (connectConfig: import('./types').CollabConnectionConfig) => void;
31
+ onDisconnect: () => void;
31
32
  isReady: boolean;
32
33
  isSyncing: boolean;
33
34
  hasCollabContentInitialised: boolean;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Sanitize + scope + validate author-supplied custom CSS before it is injected
3
+ * into the document.
4
+ *
5
+ * Authors write **normal, full-page CSS** — `body { … }`, `html body h1 { … }`,
6
+ * `h1 { … }`, `* { … }` — the way they'd style any web page. We transparently
7
+ * scope every rule to the document so it can't leak into the app, AND we map the
8
+ * page-root selectors (`html`, `body`, `:root`) onto the document root so that
9
+ * `body { background: … }` styles the doc surface and `html body h1 { … }`
10
+ * styles the doc's headings. No `.ProseMirror` prefix, no learning curve.
11
+ *
12
+ * Because the raw string reaches VIEWERS of a published doc, it is untrusted.
13
+ * Every selector is force-scoped (so a `}` breakout is neutralised — the escaped
14
+ * rule is simply scoped too), and dangerous declarations are stripped:
15
+ * - external resource loads / exfiltration: `url(…)`, `@import`;
16
+ * - clickjacking / UI redressing: `position: fixed | sticky`;
17
+ * - legacy script vectors: `expression()`, `-moz-binding`, `behavior:`.
18
+ *
19
+ * We parse with the browser's own CSS engine (no dependency), rewrite each
20
+ * selector, strip dangerous declarations at every nesting level, and let the
21
+ * engine re-serialise — so the output is always a valid, balanced stylesheet.
22
+ *
23
+ * The sanitizer knows exactly what it removed, so it returns non-blocking
24
+ * `diagnostics`; the editing UI surfaces them (CSS is forgiving — we warn,
25
+ * never block).
26
+ */
27
+ export interface CssDiagnostic {
28
+ level: 'warning' | 'error';
29
+ message: string;
30
+ }
31
+ export interface CssValidationResult {
32
+ /** Sanitized, scoped CSS, safe to inject. '' when nothing survives. */
33
+ css: string;
34
+ /** What was stripped/ignored, deduped. Empty when the CSS was fully clean. */
35
+ diagnostics: CssDiagnostic[];
36
+ }
37
+ /**
38
+ * Sanitize + scope AND report. Use this from the editing UI for diagnostics.
39
+ */
40
+ export declare const validateCustomCss: (raw: string | undefined | null, scope?: string) => CssValidationResult;
41
+ /**
42
+ * Sanitized + scoped CSS only — used at injection/export sinks that just need
43
+ * the safe string. Diagnostics are surfaced separately via validateCustomCss.
44
+ */
45
+ export declare const sanitizeCustomCss: (raw: string | undefined | null, scope?: string) => string;
@@ -1,7 +1,7 @@
1
- import { j as d } from "./index-BhAjJb8w.mjs";
1
+ import { j as d } from "./index-CTR-epIo.mjs";
2
2
  import { useRef as I, useState as N, useEffect as D } from "react";
3
3
  import { DynamicDropdown as E, Tooltip as R, IconButton as O } from "@fileverse/ui";
4
- import { a3 as A, a4 as P, c as y } from "./index-rpz9D-nF.mjs";
4
+ import { a3 as A, a4 as P, c as y } from "./index-DOdUt7ap.mjs";
5
5
  const p = (e, t, o = t) => {
6
6
  const { state: s } = e, l = s.changeByRange((n) => {
7
7
  const u = s.sliceDoc(n.from, n.to), r = s.sliceDoc(