@fileverse-dev/dsheet 4.1.23-stabilise-package-1 → 4.1.23-stabilise-package-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 (29) hide show
  1. package/README.md +10 -0
  2. package/dist/editor/contexts/editor-context.d.ts +2 -0
  3. package/dist/editor/hooks/use-editor-data.d.ts +1 -0
  4. package/dist/editor/types.d.ts +14 -3
  5. package/dist/editor/utils/after-update-cell.d.ts +4 -0
  6. package/dist/editor/utils/format-gate.d.ts +8 -4
  7. package/dist/editor/utils/legacy-on-change.d.ts +20 -0
  8. package/dist/editor/utils/legacy-on-change.test.d.ts +1 -0
  9. package/dist/editor/utils/rebuild-indexeddb-store.d.ts +8 -1
  10. package/dist/editor/utils/remote-apply-guard.d.ts +25 -3
  11. package/dist/editor/utils/wait-for-sync.d.ts +35 -0
  12. package/dist/editor/utils/wait-for-sync.test.d.ts +1 -0
  13. package/dist/{executeStringFunction-DKA5MuP0.js → executeStringFunction-D5BTPrXL.js} +9414 -9324
  14. package/dist/formula.js +1 -1
  15. package/dist/{index-ypRdpDnX.js → index-BXNWi7s5.js} +12266 -12081
  16. package/dist/index.es.js +29 -29
  17. package/dist/sheet-engine/core/api/sheet-flowdata-lifecycle.d.ts +1 -0
  18. package/dist/sheet-engine/core/api/sheet-flowdata-lifecycle.test.d.ts +1 -0
  19. package/dist/sheet-engine/core/modules/formula.d.ts +9 -0
  20. package/dist/sheet-engine/core/modules/history-calc-chain.d.ts +6 -0
  21. package/dist/sheet-engine/core/modules/history-grid-size.d.ts +16 -0
  22. package/dist/sheet-engine/core/modules/history-grid-size.test.d.ts +1 -0
  23. package/dist/sheet-engine/core/settings.d.ts +9 -1
  24. package/dist/sheet-engine/core/utils/ydoc-celldata-changes.d.ts +14 -3
  25. package/dist/{use-xlsx-import-impl-DQ3tpIAe.js → use-xlsx-import-impl-gsG9w9qV.js} +4 -4
  26. package/dist/{xlsx-defined-names-CVVLxbe-.js → xlsx-defined-names-dZveijsB.js} +2 -2
  27. package/dist/{xlsx-export-impl-ghSoFZBz.js → xlsx-export-impl-B10lK_L2.js} +4 -4
  28. package/dist/{xlsx-hyperlink-inline-DXj7AkSf.js → xlsx-hyperlink-inline-BFbPe75M.js} +2 -2
  29. package/package.json +1 -1
package/README.md CHANGED
@@ -86,6 +86,7 @@ function App() {
86
86
  | `isCollaborative` | `boolean` | `false` | Enable collaborative features |
87
87
  | `enableWebrtc` | `boolean` | `true` | Enable WebRTC for P2P collaboration |
88
88
  | `enableIndexeddbSync` | `boolean` | `true` | Enable local IndexedDB persistence |
89
+ | `onIndexedDbError` | `(error: Error) => void` | - | Called when local persistence fails, or when the first read of the local store does not finish within 15 s. The editor continues with the in-memory document; call `rebuildLocalStore()` to recreate the store |
89
90
  | `isTemplateOpen` | `boolean` | - | Template sidebar state |
90
91
  | `selectedTemplate` | `string` | - | Selected template identifier |
91
92
  | `onboardingComplete` | `boolean` | - | Onboarding completion status |
@@ -115,6 +116,15 @@ function App() {
115
116
  | `setInputFetchURLDataBlock` | `Dispatch<SetStateAction<string>>` | URL input state setter |
116
117
  | `setForceSheetRender` | `Dispatch<SetStateAction<number>>` | Force re-render trigger |
117
118
 
119
+ ### Editor handle methods
120
+
121
+ `sheetEditorRef` is a `DSheetEditorHandle`: the workbook instance plus these methods.
122
+
123
+ | Method | Description |
124
+ |--------|-------------|
125
+ | `rebuildLocalStore()` | `Promise<void>`. Deletes this sheet's IndexedDB database and rewrites it from the live document, so local edits are kept. A no-op when read-only or when `enableIndexeddbSync` is off. Rejects if the rebuild fails, the new store does not sync within 15 s, or a refresh or unmount supersedes it. Concurrent calls share one rebuild. |
126
+ | `getContentFingerprint()` | `string \| null`. Changes on every document change, deletes included; compare with `===` only. `null` until local persistence has synced. |
127
+
118
128
  ## Examples
119
129
 
120
130
  ### Read-Only Viewer
@@ -43,6 +43,8 @@ export interface EditorContextType {
43
43
  setSheetData: React.Dispatch<React.SetStateAction<Sheet[]>>;
44
44
  currentDataRef: React.MutableRefObject<Sheet[]>;
45
45
  remoteUpdateRef: React.MutableRefObject<boolean>;
46
+ /** True while a peer's structural edit waits to remount the grid. */
47
+ structuralRemountPendingRef: React.MutableRefObject<boolean>;
46
48
  handleChange: (data: Sheet[]) => void;
47
49
  initialiseLiveQueryData: (data: Sheet[]) => void;
48
50
  loading: boolean;
@@ -21,6 +21,7 @@ export declare const useEditorData: (ydocRef: React.MutableRefObject<Y.Doc | nul
21
21
  setSheetData: import('react').Dispatch<import('react').SetStateAction<Sheet[]>>;
22
22
  currentDataRef: import('react').MutableRefObject<Sheet[]>;
23
23
  remoteUpdateRef: import('react').MutableRefObject<boolean>;
24
+ structuralRemountPendingRef: import('react').MutableRefObject<boolean>;
24
25
  isDataLoaded: boolean;
25
26
  setIsDataLoaded: import('react').Dispatch<import('react').SetStateAction<boolean>>;
26
27
  handleChange: (_data: Sheet[]) => void;
@@ -33,7 +33,13 @@ export type DSheetEditorHandle = WorkbookInstance & {
33
33
  * document (same Y.Doc, never replaced), so local edits are kept. Resolves
34
34
  * once the new store has synced. Resolves as a no-op when the editor is
35
35
  * read-only, local persistence is disabled or there is no sheet id. Rejects
36
- * if the rebuild fails or a refresh/unmount supersedes it. Concurrent calls share one rebuild.
36
+ * if the rebuild fails, if the new store does not sync within 15 s, or if a
37
+ * refresh/unmount supersedes it. Concurrent calls share one rebuild.
38
+ *
39
+ * A bootstrap that is still waiting on an unreadable store (the case this
40
+ * heals) is abandoned after 3 s: the rebuild then finishes the bootstrap
41
+ * itself, merging the published content into the document, so the editor
42
+ * leaves "syncing" once the rebuild resolves.
37
43
  */
38
44
  rebuildLocalStore: () => Promise<void>;
39
45
  terminateSession: () => void;
@@ -111,12 +117,17 @@ export interface DsheetProps {
111
117
  /**
112
118
  * @deprecated Encodes the whole Y.Doc and rebuilds a plain workbook per
113
119
  * call. Use `onContentChange` and read full state on demand. Called at most
114
- * once per second (trailing), flushed only on unload and unmount.
120
+ * once per second (trailing), flushed only on unload and unmount. The latest
121
+ * `onChange` you pass is the one called, so an inline function is safe: a new
122
+ * identity does not cancel a pending call.
115
123
  */
116
124
  onChange?: (updateData: SheetUpdateData, encodedUpdate?: string) => void;
117
125
  collaboration?: CollaborationProps;
118
126
  /** Called when local IndexedDB persistence fails. The editor and durable
119
- * collaboration continue using the in-memory Y.Doc, matching dDoc. */
127
+ * collaboration continue using the in-memory Y.Doc, matching dDoc. Also
128
+ * called when the first read of the local store does not finish within 15 s
129
+ * (the editor then continues without local persistence, and
130
+ * `rebuildLocalStore()` can recreate the store). */
120
131
  onIndexedDbError?: (error: Error) => void;
121
132
  username?: string;
122
133
  portalContent?: string;
@@ -50,9 +50,13 @@ interface AfterUpdateCellParams {
50
50
  collabEnabled?: boolean;
51
51
  collabIsOwner?: boolean;
52
52
  remoteUpdateRef?: React.MutableRefObject<boolean>;
53
+ /** True while a peer's structural edit waits to remount the grid. */
54
+ structuralRemountPendingRef?: React.MutableRefObject<boolean>;
53
55
  localUserEditRef?: React.MutableRefObject<boolean>;
54
56
  /** Sheet that held the cell at commit time; falls back to the current sheet. */
55
57
  sheetId?: string;
58
+ /** The caller writes the cell to Yjs itself (paste and fill batch writes). */
59
+ skipPersist?: boolean;
56
60
  }
57
61
  /** True when data-block formulas (API / smart contract) should run for this edit. */
58
62
  export declare const shouldExecuteDataBlocks: (params: {
@@ -15,9 +15,13 @@ export declare function readFormatVersion(doc: Y.Doc, dsheetId: string): number;
15
15
  */
16
16
  export declare function isFormatLocked(doc: Y.Doc | null | undefined, dsheetId?: string): boolean;
17
17
  /**
18
- * Checks `meta.format` now and while the sheet is open. On the first value
19
- * above SUPPORTED_FORMAT the sheet is locked (write helpers return early) and
20
- * `onLocked` runs once per watcher with that value, even if the sheet was
21
- * already locked by an earlier watcher. Returns an unsubscribe function.
18
+ * Make the grid read-only in the same tick the lock is seen. The Yjs writers
19
+ * stop at once (isFormatLocked), but the grid became read-only only after the
20
+ * workbook data changed identity and the Workbook init effect ran: a commit in
21
+ * between showed in the grid, never reached Yjs, and was gone on reload.
22
+ * The Workbook init effect sets the same flag from the prop afterwards.
22
23
  */
24
+ export declare function lockWorkbookReadOnly(workbook: {
25
+ getWorkbookSetContext?: () => unknown;
26
+ } | null | undefined): boolean;
23
27
  export declare function watchFormatGate(doc: Y.Doc, dsheetId: string, onLocked: (format: number) => void): () => void;
@@ -0,0 +1,20 @@
1
+ /** The legacy `onChange` argument pair: plain sheet data and the encoded doc. */
2
+ export type LegacyOnChangeArgs = {
3
+ data: unknown;
4
+ update: string;
5
+ };
6
+ export declare const LEGACY_ON_CHANGE_WAIT_MS = 1000;
7
+ /**
8
+ * Trailing-only throttle for the host's legacy `onChange`.
9
+ *
10
+ * The host's handler is read when the throttle fires, not when it is created.
11
+ * A host that passes a new inline `onChange` on every render must not rebuild
12
+ * this throttle: rebuilding cancels the pending call, so an edit followed
13
+ * within the wait by a re-render never reached the host's save.
14
+ * `buildArgs` runs only when there is a handler, because it encodes the whole
15
+ * document.
16
+ */
17
+ export declare function createLegacyOnChangeThrottle<TData>(getOnChange: () => ((data: TData, update: string) => void) | undefined, buildArgs: () => {
18
+ data: TData;
19
+ update: string;
20
+ } | null, waitMs?: number): any;
@@ -0,0 +1 @@
1
+ export {};
@@ -8,5 +8,12 @@ import type * as Y from 'yjs';
8
8
  * fresh row. `onCreated` runs right after the new provider is constructed,
9
9
  * before it has synced, so the caller can track it and attach listeners. The Y.Doc is never replaced or cleared. Unlike delete-and-reopen
10
10
  * (heal), edits that exist only in the live doc are kept.
11
+ *
12
+ * The wait for the new provider is bounded: `whenSynced` never rejects, and a
13
+ * provider destroyed before its first read (a bootstrap restarting meanwhile)
14
+ * never syncs. It rejects on `timeoutMs` or once `isCurrent()` is false.
11
15
  */
12
- export declare function rebuildIndexedDbStore(dsheetId: string, doc: Y.Doc, current: IndexeddbPersistence | null, onCreated?: (provider: IndexeddbPersistence) => void): Promise<IndexeddbPersistence>;
16
+ export declare function rebuildIndexedDbStore(dsheetId: string, doc: Y.Doc, current: IndexeddbPersistence | null, onCreated?: (provider: IndexeddbPersistence) => void, syncOptions?: {
17
+ timeoutMs?: number;
18
+ isCurrent?: () => boolean;
19
+ }): Promise<IndexeddbPersistence>;
@@ -11,6 +11,18 @@ export type RemoteApplyGuardRefs = {
11
11
  remoteApplyDepthRef: MutableRefObject<number>;
12
12
  remoteUpdateRef: MutableRefObject<boolean>;
13
13
  };
14
+ /**
15
+ * True when an engine → Yjs echo hook (calcChain, conditional formats, ...)
16
+ * must stay quiet: a remote apply is running, or a structural remount is
17
+ * pending. While one is pending the engine still has the grid from before the
18
+ * peer's insert or delete, so a diff of its metadata against Yjs would write
19
+ * the old coordinates over the peer's (and delete the peer's calcChain
20
+ * entries). Cell commits are not echo hooks and are not held back by this.
21
+ */
22
+ export declare function shouldSkipEchoWrite(refs: {
23
+ remoteUpdateRef: MutableRefObject<boolean>;
24
+ structuralRemountPendingRef?: MutableRefObject<boolean>;
25
+ }): boolean;
14
26
  export declare function syncRemoteUpdateFlag(refs: RemoteApplyGuardRefs): void;
15
27
  export declare function beginRemoteApply(refs: RemoteApplyGuardRefs): void;
16
28
  export declare function endRemoteApply(refs: RemoteApplyGuardRefs): void;
@@ -25,9 +37,12 @@ export type StructuralRemountRefs = RemoteApplyGuardRefs & {
25
37
  * The guard is begun once, right before `run`, and ended after paint, so each
26
38
  * remount owns exactly one begin and one end. It is NOT held while the timer
27
39
  * is merely pending or deferred by a cell edit: `remoteUpdateRef` makes
28
- * handleChange, guardRemoteEcho and afterUpdateCell drop local writes, so
29
- * holding it across an edit would drop the user's commit. Events that land
30
- * while one is pending only re-arm its timer.
40
+ * handleChange and the data-block work in afterUpdateCell drop local work, so
41
+ * holding it across an edit would drop the user's typed edit. (The cell write
42
+ * in afterUpdateCell and the commit-time write do not check it.) What must not
43
+ * run while a remount is pending is the engine → Yjs echo hooks, which diff
44
+ * the old grid against Yjs: they check `shouldSkipEchoWrite`. Events that
45
+ * land while one is pending only re-arm its timer.
31
46
  *
32
47
  * While `isEditing()` is true at fire time the timer re-arms (250 ms) and the
33
48
  * pending flag is kept; the remount runs once the edit ends.
@@ -41,5 +56,12 @@ export declare const STRUCTURAL_REMOUNT_EDIT_RETRY_MS = 250;
41
56
  * to release here.
42
57
  */
43
58
  export declare function cancelStructuralRemount(refs: StructuralRemountRefs): void;
59
+ /**
60
+ * Run `fn` under the guard and keep it until paint (a remount follows). If
61
+ * `fn` throws, the guard is ended at once and the error is rethrown: a begin
62
+ * with no matching end leaves the depth above zero, and `handleChange` then
63
+ * drops every local write until reload.
64
+ */
65
+ export declare function runRemoteApplyUntilPaint<T>(refs: RemoteApplyGuardRefs, fn: () => T): T;
44
66
  /** End after Workbook remount hooks have flushed (2 rAF ≈ one paint). */
45
67
  export declare function endRemoteApplyAfterPaint(refs: RemoteApplyGuardRefs): void;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Waits for a y-indexeddb provider without trusting it to finish.
3
+ *
4
+ * In y-indexeddb 9.0.12 `whenSynced` resolves only on 'synced'. It has no
5
+ * reject path, and a provider that is destroyed before its first read, or whose
6
+ * first read never completes, never syncs. Awaiting it directly hangs the
7
+ * bootstrap, and a rebuild that waits for the bootstrap hangs with it.
8
+ */
9
+ export declare const INDEXEDDB_SYNC_TIMEOUT_MS = 15000;
10
+ /** How long a rebuild waits for a running bootstrap before it abandons it. */
11
+ export declare const REBUILD_BOOTSTRAP_WAIT_MS = 3000;
12
+ export declare class PersistenceSyncTimeoutError extends Error {
13
+ constructor(ms: number);
14
+ }
15
+ export declare class PersistenceSupersededError extends Error {
16
+ constructor();
17
+ }
18
+ /**
19
+ * Resolves when `whenSynced` does. Rejects with PersistenceSyncTimeoutError
20
+ * after `timeoutMs`, or with PersistenceSupersededError as soon as
21
+ * `isCurrent()` turns false (checked every 100 ms): a newer bootstrap or an
22
+ * unmount owns the provider then, and it may already be destroyed.
23
+ */
24
+ export declare function waitForPersistenceSynced(persistence: {
25
+ whenSynced: Promise<unknown>;
26
+ }, options?: {
27
+ timeoutMs?: number;
28
+ isCurrent?: () => boolean;
29
+ }): Promise<void>;
30
+ /**
31
+ * Waits for a running bootstrap for at most `ms`. 'stuck' means it has not
32
+ * settled; the caller then abandons it (bumps the generation) instead of
33
+ * waiting for a provider that may never sync.
34
+ */
35
+ export declare function waitForBootstrapOrAbandon(bootstrap: Promise<unknown>, ms?: number): Promise<'settled' | 'stuck'>;
@@ -0,0 +1 @@
1
+ export {};