@kuzuma/colwork 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,11 +1,36 @@
1
+ import { Awareness } from 'y-protocols/awareness';
2
+ import * as Y from 'yjs';
3
+
1
4
  export declare type AwarenessSelection = {
2
5
  anchor?: CellPosition;
3
6
  focus?: CellPosition;
4
7
  mode?: SelectionMode_2;
5
8
  };
6
9
 
10
+ export declare type BuiltInCollaborationOptions = CommonOptions & {
11
+ room: string;
12
+ transport?: 'webrtc' | 'websocket';
13
+ collaboration?: never;
14
+ signalingUrl?: string;
15
+ websocketUrl?: string;
16
+ peerOpts?: Record<string, unknown>;
17
+ initializeAfterSync?: boolean;
18
+ rows?: string[][];
19
+ snapshot?: Uint8Array;
20
+ updates?: Uint8Array[];
21
+ };
22
+
23
+ export declare type CellBorder = {
24
+ top?: boolean;
25
+ right?: boolean;
26
+ bottom?: boolean;
27
+ left?: boolean;
28
+ };
29
+
7
30
  export declare function cellKey(position: CellPosition): string;
8
31
 
32
+ export declare type CellLock = '1' | PasswordLock;
33
+
9
34
  export declare type CellPosition = {
10
35
  row: number;
11
36
  column: number;
@@ -16,16 +41,49 @@ export declare type CellRange = {
16
41
  end: CellPosition;
17
42
  };
18
43
 
44
+ export declare type CellStyle = {
45
+ bold?: boolean;
46
+ italic?: boolean;
47
+ underline?: boolean;
48
+ strike?: boolean;
49
+ wrap?: boolean;
50
+ border?: CellBorder;
51
+ fontSize?: number;
52
+ color?: string;
53
+ background?: string;
54
+ align?: 'left' | 'center' | 'right';
55
+ format?: 'general' | 'number' | 'date' | 'percent';
56
+ };
57
+
58
+ export declare const COLWORK_MAP_NAMES: Readonly<{
59
+ readonly cells: "cells";
60
+ readonly styles: "styles";
61
+ readonly rowHeights: "rowHeights";
62
+ readonly columnWidths: "columnWidths";
63
+ readonly merges: "merges";
64
+ readonly locks: "locks";
65
+ readonly metadata: "colwork-metadata";
66
+ }>;
67
+
68
+ /** The existing version-one wire format. Missing metadata is valid legacy data. */
69
+ export declare const COLWORK_SCHEMA_VERSION: 1;
70
+
19
71
  export declare class ColworkTable {
72
+ private readonly session;
20
73
  private readonly doc;
74
+ private readonly sheet;
21
75
  private readonly cells;
22
76
  private readonly styles;
23
77
  private readonly rowHeights;
24
78
  private readonly columnWidths;
25
79
  private readonly locks;
26
- private messageDialog?;
27
- private passwordDialog?;
80
+ private readonly pointer;
81
+ private readonly clipboard;
82
+ private readonly selection;
83
+ private readonly formatting;
84
+ private readonly dialogs;
28
85
  private destroyed;
86
+ private editEpoch;
29
87
  private frozenRows;
30
88
  private frozenColumns;
31
89
  private readonly merges;
@@ -34,27 +92,21 @@ export declare class ColworkTable {
34
92
  private readonly awareness;
35
93
  private readonly root;
36
94
  private readonly options;
95
+ private readonly toolbar;
37
96
  private readonly table;
38
97
  private readonly viewportResizeObserver;
39
98
  private readonly viewport;
40
99
  private readonly frozenBoundaryLayer;
41
100
  private protectionMenuButton?;
42
- private contextMenu?;
43
- private pendingCellContext?;
44
- private rightButtonReleased;
45
- private rightMouseUpPoint?;
46
- private rightDrag?;
101
+ private readonly menu;
47
102
  private undoButton?;
48
103
  private redoButton?;
49
- private rowCountValue;
50
- private columnCountValue;
104
+ private readonly dimensions;
51
105
  private zoomRatio;
52
106
  private showGridLines;
53
107
  private bandedRows;
54
- private readonly readOnly;
55
- private documentRevision;
56
- private updateSequence;
57
- private readonly updateLog;
108
+ private readOnly;
109
+ private readonly archive;
58
110
  private resizing?;
59
111
  private readonly onCellsChange;
60
112
  private readonly onStylesChange;
@@ -72,42 +124,26 @@ export declare class ColworkTable {
72
124
  private readonly onWindowBlur;
73
125
  private readonly onWindowMouseMove;
74
126
  private readonly onHistoryChange;
75
- private editor?;
76
- private editingKey?;
77
- private editingOriginal;
78
- private selectedKey?;
79
- private selectionAnchor?;
80
- private selectionFocus?;
81
- private selectionMode?;
82
- private selecting;
83
- private headerSelecting?;
84
- private pendingAwarenessCursor?;
85
- private readonly loggedPeers;
86
- private readonly loggedSignals;
87
- private readonly onDocUpdate;
88
- private readonly onAwarenessUpdate;
127
+ private readonly editing;
89
128
  constructor(root: HTMLElement, options: ColworkTableOptions);
90
129
  private log;
91
130
  private undo;
92
131
  private redo;
93
132
  private refreshHistoryButtons;
133
+ /** Changes local editing affordances. Hosts enforce actual document permissions. */
134
+ setReadOnly(readOnly: boolean): void;
135
+ /** Explicitly commits the active cell draft before a host publishes or exports. */
136
+ commitEditing(): void;
137
+ /** Discards an active draft while preserving the current shared document value. */
138
+ cancelEditing(): void;
94
139
  getYjsSnapshot(): YjsSnapshotFile;
95
140
  getYjsUpdateLog(): YjsUpdateLogFile;
96
- /** Freeze a leading prefix of rows/columns in this client only. */
141
+ /** Freeze a leading prefix in this local view. */
97
142
  setFrozenPanes(rows: number, columns: number): boolean;
98
- private hasPartialMerge;
99
143
  private crossesFrozenBoundary;
100
144
  private freezeSelection;
101
- private rangeHasLocks;
102
- private isCellLocked;
103
- private isCellPasswordLocked;
104
145
  private selectionHasLocks;
105
- private isAxisLocked;
106
- /** Passwords are optional for legacy/plain locks; protected locks require verification. */
107
146
  setSelectionLocked(locked: boolean, password?: string): Promise<void>;
108
- private requestSelectionLock;
109
- private closeLockMessage;
110
- private showLockMessage;
111
147
  private get rowCount();
112
148
  private get columnCount();
113
149
  private get rowHeaderWidth();
@@ -116,100 +152,145 @@ export declare class ColworkTable {
116
152
  private getColumnWidth;
117
153
  private beginResize;
118
154
  private addResizeHandle;
119
- private selectRange;
120
- private hideContextMenu;
121
- private showContextMenu;
122
- private protectionActions;
123
- private hasHeaderSelection;
124
- private openRowContextMenu;
125
- private openColumnContextMenu;
126
- private mergeKey;
127
- private parseMergeKey;
128
- private getMergeRanges;
129
- private expandSelectionToMerges;
130
- private getMergeStartingAt;
131
- private isMergeCovered;
132
155
  private mergeSelection;
133
156
  private unmergeSelection;
134
157
  private modifyAxis;
135
158
  private deleteRows;
136
159
  private deleteColumns;
137
- private selectHeaderRange;
138
- private selectHeaderSpan;
139
- private addHeaderSelection;
140
160
  private expandLogicalSpace;
141
- private publishSelection;
142
- private updateAwareness;
143
161
  private expandForRemoteSelections;
144
- private getSelectionBounds;
145
- private selectCell;
146
- private isPositionSelected;
147
- private selectionToClipboard;
148
- private selectionToText;
149
- private copySelection;
150
162
  private clearSelectionContents;
151
- private showCellContextMenu;
152
- private openCellContextMenu;
153
- private sendAwareness;
154
- private onCopy;
155
- private onPaste;
156
- private logChunk;
157
- private inspectConnections;
158
- private seed;
159
- private seedDemoFormatting;
160
163
  private expandLogicalSizeFromDocument;
161
164
  private render;
162
- private refreshFrozenBoundaries;
163
165
  private refreshValues;
164
166
  private refreshSelection;
165
167
  private refreshCursors;
166
- private addSelectionOverlay;
167
- private addCursorLabel;
168
- private startEdit;
169
- private readStyle;
170
- private applyStyle;
171
- private displayValue;
172
- private toggleFormat;
173
- private clearFormatting;
174
- private toggleBorder;
175
- private setStyle;
176
168
  private refreshStyles;
177
- private finishEdit;
169
+ private refreshView;
178
170
  destroy(): void;
179
171
  }
180
172
 
181
- export declare type ColworkTableOptions = {
182
- room: string;
183
- signalingUrl?: string;
173
+ export declare type ColworkTableOptions = ExternalCollaborationOptions | BuiltInCollaborationOptions;
174
+
175
+ declare type CommonOptions = {
184
176
  user: string;
185
- rows?: string[][];
177
+ userColor?: string;
186
178
  rowCount?: number;
187
179
  columnCount?: number;
188
180
  onLog?: (message: string) => void;
189
- userColor?: string;
190
- peerOpts?: Record<string, unknown>;
191
- transport?: 'webrtc' | 'websocket';
192
- websocketUrl?: string;
193
- initializeAfterSync?: boolean;
194
181
  readOnly?: boolean;
195
- snapshot?: Uint8Array;
196
- updates?: Uint8Array[];
182
+ onEditingChange?: (state: EditingState) => void;
197
183
  };
198
184
 
199
185
  export declare function containsPosition(range: CellRange, position: CellPosition): boolean;
200
186
 
187
+ export declare type EditingState = {
188
+ editing: boolean;
189
+ dirty: boolean;
190
+ };
191
+
192
+ export declare function exportYjsSnapshot(document: Y.Doc, options?: {
193
+ room?: string;
194
+ sequence?: number;
195
+ }): YjsSnapshotFile;
196
+
197
+ export declare type ExternalCollaborationOptions = CommonOptions & {
198
+ transport: 'external';
199
+ collaboration: {
200
+ document: Y.Doc;
201
+ awareness: Awareness;
202
+ };
203
+ room?: string;
204
+ rows?: never;
205
+ snapshot?: never;
206
+ updates?: never;
207
+ initializeAfterSync?: false;
208
+ signalingUrl?: never;
209
+ websocketUrl?: never;
210
+ peerOpts?: never;
211
+ };
212
+
213
+ /** Materializes named Y.Map roots, preserving the version-one encoding. */
214
+ export declare function getSheetMaps(document: Y.Doc): SheetMaps;
215
+
216
+ /** Initializes an empty document without demo cells, headers, styles, or network access. */
217
+ export declare function initializeBlankSheet(document: Y.Doc): void;
218
+
219
+ export declare function mergeKey(range: CellRange): string;
220
+
201
221
  export declare function normalizeRange(start: CellPosition, end: CellPosition): CellRange;
202
222
 
223
+ export declare function parseCellKey(key: string): {
224
+ row: number;
225
+ column: number;
226
+ } | undefined;
227
+
228
+ export declare function parseMergeKey(key: string): CellRange | undefined;
229
+
230
+ export declare type PasswordLock = {
231
+ version: 1;
232
+ algorithm: 'PBKDF2-SHA-256';
233
+ iterations: 600000;
234
+ salt: string;
235
+ verifier: string;
236
+ };
237
+
203
238
  export declare function rangeSize(range: CellRange): {
204
239
  rows: number;
205
240
  columns: number;
206
241
  };
207
242
 
243
+ /** Reads a deterministic sparse sheet without loading a renderer, browser globals, or CSS. */
244
+ export declare function readSheetSnapshot(document: Y.Doc, limits?: SheetValidationLimits): SheetSnapshot;
245
+
246
+ /** Decodes a Yjs state update and releases its temporary document after export. */
247
+ export declare function readSheetSnapshotUpdate(update: Uint8Array, limits?: SheetValidationLimits): SheetSnapshot;
248
+
208
249
  export declare function rebuildYjsSnapshot(snapshotText?: string, updateLogText?: string): YjsSnapshotFile;
209
250
 
210
251
  declare type SelectionMode_2 = 'row' | 'column' | 'all';
211
252
  export { SelectionMode_2 as SelectionMode }
212
253
 
254
+ export declare type SheetMaps = {
255
+ cells: Y.Map<string>;
256
+ styles: Y.Map<string>;
257
+ rowHeights: Y.Map<number>;
258
+ columnWidths: Y.Map<number>;
259
+ merges: Y.Map<string>;
260
+ locks: Y.Map<string>;
261
+ };
262
+
263
+ /** Sparse, JSON-serializable logical sheet. Dimensions are derived from stored data. */
264
+ export declare type SheetSnapshot = {
265
+ schemaVersion: typeof COLWORK_SCHEMA_VERSION;
266
+ rowCount: number;
267
+ columnCount: number;
268
+ cells: Record<string, string>;
269
+ styles: Record<string, CellStyle>;
270
+ rowHeights: Record<string, number>;
271
+ columnWidths: Record<string, number>;
272
+ merges: CellRange[];
273
+ locks: Record<string, CellLock>;
274
+ };
275
+
276
+ export declare type SheetValidationIssue = {
277
+ path: string;
278
+ message: string;
279
+ };
280
+
281
+ /** Optional host policy. Omitted numeric limits impose no application-specific cap. */
282
+ export declare type SheetValidationLimits = {
283
+ maxRows?: number;
284
+ maxColumns?: number;
285
+ maxEntries?: number;
286
+ maxStringLength?: number;
287
+ maxMergeArea?: number;
288
+ maxMerges?: number;
289
+ allowUnknownRoots?: boolean;
290
+ };
291
+
292
+ export declare function validateSheetDocument(document: Y.Doc, limits?: SheetValidationLimits): SheetValidationIssue[];
293
+
213
294
  export declare type YjsArchiveFile = {
214
295
  format: 'colwork.archive';
215
296
  version: 1;
@@ -0,0 +1,3 @@
1
+ import { CellRange } from './range.cjs';
2
+ /** Sweep rectangles across rows with a range-add tree over compressed columns. */
3
+ export declare function hasOverlappingMerges(merges: CellRange[]): boolean;
@@ -0,0 +1,3 @@
1
+ import { CellRange } from './range.js';
2
+ /** Sweep rectangles across rows with a range-add tree over compressed columns. */
3
+ export declare function hasOverlappingMerges(merges: CellRange[]): boolean;
@@ -0,0 +1,80 @@
1
+ import { CellRange } from './range.cjs';
2
+ import type * as Y from 'yjs';
3
+ /** The existing version-one wire format. Missing metadata is valid legacy data. */
4
+ export declare const COLWORK_SCHEMA_VERSION: 1;
5
+ export declare const COLWORK_MAP_NAMES: Readonly<{
6
+ readonly cells: "cells";
7
+ readonly styles: "styles";
8
+ readonly rowHeights: "rowHeights";
9
+ readonly columnWidths: "columnWidths";
10
+ readonly merges: "merges";
11
+ readonly locks: "locks";
12
+ readonly metadata: "colwork-metadata";
13
+ }>;
14
+ export type CellBorder = {
15
+ top?: boolean;
16
+ right?: boolean;
17
+ bottom?: boolean;
18
+ left?: boolean;
19
+ };
20
+ export type CellStyle = {
21
+ bold?: boolean;
22
+ italic?: boolean;
23
+ underline?: boolean;
24
+ strike?: boolean;
25
+ wrap?: boolean;
26
+ border?: CellBorder;
27
+ fontSize?: number;
28
+ color?: string;
29
+ background?: string;
30
+ align?: 'left' | 'center' | 'right';
31
+ format?: 'general' | 'number' | 'date' | 'percent';
32
+ };
33
+ export type PasswordLock = {
34
+ version: 1;
35
+ algorithm: 'PBKDF2-SHA-256';
36
+ iterations: 600000;
37
+ salt: string;
38
+ verifier: string;
39
+ };
40
+ export type CellLock = '1' | PasswordLock;
41
+ export type SheetMaps = {
42
+ cells: Y.Map<string>;
43
+ styles: Y.Map<string>;
44
+ rowHeights: Y.Map<number>;
45
+ columnWidths: Y.Map<number>;
46
+ merges: Y.Map<string>;
47
+ locks: Y.Map<string>;
48
+ };
49
+ /** Sparse, JSON-serializable logical sheet. Dimensions are derived from stored data. */
50
+ export type SheetSnapshot = {
51
+ schemaVersion: typeof COLWORK_SCHEMA_VERSION;
52
+ rowCount: number;
53
+ columnCount: number;
54
+ cells: Record<string, string>;
55
+ styles: Record<string, CellStyle>;
56
+ rowHeights: Record<string, number>;
57
+ columnWidths: Record<string, number>;
58
+ merges: CellRange[];
59
+ locks: Record<string, CellLock>;
60
+ };
61
+ export type SheetValidationIssue = {
62
+ path: string;
63
+ message: string;
64
+ };
65
+ export declare function parseCellKey(key: string): {
66
+ row: number;
67
+ column: number;
68
+ } | undefined;
69
+ export declare function mergeKey(range: CellRange): string;
70
+ export declare function parseMergeKey(key: string): CellRange | undefined;
71
+ /** Optional host policy. Omitted numeric limits impose no application-specific cap. */
72
+ export type SheetValidationLimits = {
73
+ maxRows?: number;
74
+ maxColumns?: number;
75
+ maxEntries?: number;
76
+ maxStringLength?: number;
77
+ maxMergeArea?: number;
78
+ maxMerges?: number;
79
+ allowUnknownRoots?: boolean;
80
+ };
@@ -0,0 +1,80 @@
1
+ import { CellRange } from './range.js';
2
+ import type * as Y from 'yjs';
3
+ /** The existing version-one wire format. Missing metadata is valid legacy data. */
4
+ export declare const COLWORK_SCHEMA_VERSION: 1;
5
+ export declare const COLWORK_MAP_NAMES: Readonly<{
6
+ readonly cells: "cells";
7
+ readonly styles: "styles";
8
+ readonly rowHeights: "rowHeights";
9
+ readonly columnWidths: "columnWidths";
10
+ readonly merges: "merges";
11
+ readonly locks: "locks";
12
+ readonly metadata: "colwork-metadata";
13
+ }>;
14
+ export type CellBorder = {
15
+ top?: boolean;
16
+ right?: boolean;
17
+ bottom?: boolean;
18
+ left?: boolean;
19
+ };
20
+ export type CellStyle = {
21
+ bold?: boolean;
22
+ italic?: boolean;
23
+ underline?: boolean;
24
+ strike?: boolean;
25
+ wrap?: boolean;
26
+ border?: CellBorder;
27
+ fontSize?: number;
28
+ color?: string;
29
+ background?: string;
30
+ align?: 'left' | 'center' | 'right';
31
+ format?: 'general' | 'number' | 'date' | 'percent';
32
+ };
33
+ export type PasswordLock = {
34
+ version: 1;
35
+ algorithm: 'PBKDF2-SHA-256';
36
+ iterations: 600000;
37
+ salt: string;
38
+ verifier: string;
39
+ };
40
+ export type CellLock = '1' | PasswordLock;
41
+ export type SheetMaps = {
42
+ cells: Y.Map<string>;
43
+ styles: Y.Map<string>;
44
+ rowHeights: Y.Map<number>;
45
+ columnWidths: Y.Map<number>;
46
+ merges: Y.Map<string>;
47
+ locks: Y.Map<string>;
48
+ };
49
+ /** Sparse, JSON-serializable logical sheet. Dimensions are derived from stored data. */
50
+ export type SheetSnapshot = {
51
+ schemaVersion: typeof COLWORK_SCHEMA_VERSION;
52
+ rowCount: number;
53
+ columnCount: number;
54
+ cells: Record<string, string>;
55
+ styles: Record<string, CellStyle>;
56
+ rowHeights: Record<string, number>;
57
+ columnWidths: Record<string, number>;
58
+ merges: CellRange[];
59
+ locks: Record<string, CellLock>;
60
+ };
61
+ export type SheetValidationIssue = {
62
+ path: string;
63
+ message: string;
64
+ };
65
+ export declare function parseCellKey(key: string): {
66
+ row: number;
67
+ column: number;
68
+ } | undefined;
69
+ export declare function mergeKey(range: CellRange): string;
70
+ export declare function parseMergeKey(key: string): CellRange | undefined;
71
+ /** Optional host policy. Omitted numeric limits impose no application-specific cap. */
72
+ export type SheetValidationLimits = {
73
+ maxRows?: number;
74
+ maxColumns?: number;
75
+ maxEntries?: number;
76
+ maxStringLength?: number;
77
+ maxMergeArea?: number;
78
+ maxMerges?: number;
79
+ allowUnknownRoots?: boolean;
80
+ };
@@ -0,0 +1,7 @@
1
+ import { CellStyle, PasswordLock, SheetMaps, SheetValidationIssue, SheetValidationLimits } from './model-schema.cjs';
2
+ import * as Y from 'yjs';
3
+ export declare function isPasswordLock(value: unknown): value is PasswordLock;
4
+ export declare function isCellStyle(value: unknown): value is CellStyle;
5
+ /** Materializes named Y.Map roots, preserving the version-one encoding. */
6
+ export declare function getSheetMaps(document: Y.Doc): SheetMaps;
7
+ export declare function validateSheetDocument(document: Y.Doc, limits?: SheetValidationLimits): SheetValidationIssue[];
@@ -0,0 +1,7 @@
1
+ import { CellStyle, PasswordLock, SheetMaps, SheetValidationIssue, SheetValidationLimits } from './model-schema.js';
2
+ import * as Y from 'yjs';
3
+ export declare function isPasswordLock(value: unknown): value is PasswordLock;
4
+ export declare function isCellStyle(value: unknown): value is CellStyle;
5
+ /** Materializes named Y.Map roots, preserving the version-one encoding. */
6
+ export declare function getSheetMaps(document: Y.Doc): SheetMaps;
7
+ export declare function validateSheetDocument(document: Y.Doc, limits?: SheetValidationLimits): SheetValidationIssue[];
package/dist/model.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const I=require("yjs");function _(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const r in e)if(r!=="default"){const n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:()=>e[r]})}}return t.default=e,Object.freeze(t)}const g=_(I),y=1,p=Object.freeze({cells:"cells",styles:"styles",rowHeights:"rowHeights",columnWidths:"columnWidths",merges:"merges",locks:"locks",metadata:"colwork-metadata"});function S(e){if(!/^(0|[1-9]\d*):(0|[1-9]\d*)$/.test(e))return;const[t,r]=e.split(":").map(Number);return Number.isSafeInteger(t)&&Number.isSafeInteger(r)?{row:t,column:r}:void 0}function R(e){return`${e.start.row}:${e.start.column}-${e.end.row}:${e.end.column}`}function E(e){const t=e.split("-");if(t.length!==2)return;const r=S(t[0]),n=S(t[1]);if(!(!r||!n||r.row>n.row||r.column>n.column))return{start:r,end:n}}function z(e){for(const t of e){const r=t.codePointAt(0);if(r>=55296&&r<=57343)return!1}return!0}function U(e){if(e.length<2)return!1;const t=[...new Set(e.flatMap(i=>[i.start.column,i.end.column+1]))].sort((i,m)=>i-m),r=new Map(t.map((i,m)=>[i,m])),n=e.flatMap(i=>[{row:i.start.row,left:r.get(i.start.column),right:r.get(i.end.column+1)-1,delta:1},{row:i.end.row+1,left:r.get(i.start.column),right:r.get(i.end.column+1)-1,delta:-1}]).sort((i,m)=>i.row-m.row||i.delta-m.delta),f=new Int32Array(t.length*4),d=new Int32Array(t.length*4),u=(i,m,c,l,o,s)=>{if(l<=m&&c<=o){f[i]+=s,d[i]+=s;return}const a=Math.floor((m+c)/2);l<=a&&u(i*2,m,a,l,o,s),o>a&&u(i*2+1,a+1,c,l,o,s),f[i]=d[i]+Math.max(f[i*2],f[i*2+1])};for(const i of n)if(u(1,0,t.length-2,i.left,i.right,i.delta),f[1]>1)return!0;return!1}const x=e=>!!e&&typeof e=="object"&&!Array.isArray(e)&&Object.getPrototypeOf(e)===Object.prototype,k=(e,t)=>Object.keys(e).every(r=>t.includes(r));function q(e){return x(e)&&k(e,["version","algorithm","iterations","salt","verifier"])&&e.version===1&&e.algorithm==="PBKDF2-SHA-256"&&e.iterations===6e5&&typeof e.salt=="string"&&/^[0-9a-f]{32}$/.test(e.salt)&&typeof e.verifier=="string"&&/^[0-9a-f]{64}$/.test(e.verifier)}function K(e){if(!x(e)||!k(e,["bold","italic","underline","strike","wrap","border","fontSize","color","background","align","format"]))return!1;for(const t of["bold","italic","underline","strike","wrap"])if(t in e&&typeof e[t]!="boolean")return!1;for(const t of["color","background"])if(t in e&&(typeof e[t]!="string"||!z(e[t])))return!1;if("fontSize"in e&&(typeof e.fontSize!="number"||!Number.isFinite(e.fontSize)||e.fontSize<=0)||"align"in e&&(typeof e.align!="string"||!["left","center","right"].includes(e.align))||"format"in e&&(typeof e.format!="string"||!["general","number","date","percent"].includes(e.format)))return!1;if("border"in e){if(!x(e.border)||!k(e.border,["top","right","bottom","left"]))return!1;for(const t of Object.keys(e.border))if(typeof e.border[t]!="boolean")return!1}return!0}function M(e){return{cells:e.getMap(p.cells),styles:e.getMap(p.styles),rowHeights:e.getMap(p.rowHeights),columnWidths:e.getMap(p.columnWidths),merges:e.getMap(p.merges),locks:e.getMap(p.locks)}}function O(e,t={}){for(const o of["maxRows","maxColumns","maxEntries","maxStringLength","maxMergeArea","maxMerges"]){const s=t[o];if(s!==void 0&&(!Number.isSafeInteger(s)||s<0))throw new RangeError(`${o} must be a non-negative safe integer`)}const r=[];(e.store.pendingStructs!==null||e.store.pendingDs!==null)&&r.push({path:"$",message:"Document contains unresolved Yjs update dependencies"});const n=(o,s)=>{r.push({path:o,message:s})};if(!t.allowUnknownRoots)for(const o of e.share.keys())Object.values(p).includes(o)||n(o,"Unknown document root");let f,d;try{f=M(e),d=e.getMap(p.metadata)}catch{return[...r,{path:"$",message:"Sheet roots must be Y.Map values"}]}for(const[o,s]of[...Object.entries(f),["metadata",d]])(!(s instanceof g.Map)||s._start!==null)&&n(o,"Expected map entries without sequence content");const u=Object.values(f).reduce((o,s)=>o+s.size,d.size);t.maxEntries!==void 0&&u>t.maxEntries&&n("$","Document exceeds maxEntries");const i=(o,s)=>o<Number.MAX_SAFE_INTEGER&&s<Number.MAX_SAFE_INTEGER&&(t.maxRows===void 0||o<t.maxRows)&&(t.maxColumns===void 0||s<t.maxColumns),m=(o,s)=>{if(typeof o!="string")return!1;try{return s(JSON.parse(o))}catch{return!1}},c=(o,s,a)=>{typeof a=="string"&&t.maxStringLength!==void 0&&a.length>t.maxStringLength&&n(`${o}.${s}`,"String exceeds maxStringLength")};for(const o of["cells","styles","locks"])f[o].forEach((s,a)=>{const h=S(a);(!h||!i(h.row,h.column))&&n(`${o}.${a}`,"Invalid or out-of-bounds row:column key"),c(o,a,s),o==="cells"&&(typeof s!="string"||!z(s))&&n(`${o}.${a}`,"Cell values must be strings"),o==="styles"&&!m(s,K)&&n(`${o}.${a}`,"Expected a JSON CellStyle object"),o==="locks"&&s!=="1"&&!m(s,q)&&n(`${o}.${a}`,"Expected a plain lock or version-one password verifier")});for(const o of["rowHeights","columnWidths"])f[o].forEach((s,a)=>{const h=Number(a),N=o==="rowHeights"?t.maxRows:t.maxColumns;(!/^(0|[1-9]\d*)$/.test(a)||!Number.isSafeInteger(h)||h>=Number.MAX_SAFE_INTEGER||N!==void 0&&h>=N)&&n(`${o}.${a}`,"Invalid or out-of-bounds index"),(typeof s!="number"||!Number.isFinite(s)||s<=0)&&n(`${o}.${a}`,"Sizes must be finite positive numbers")});t.maxMerges!==void 0&&f.merges.size>t.maxMerges&&n("merges","Document exceeds maxMerges");const l=[];return f.merges.forEach((o,s)=>{const a=E(s);!a||o!=="1"||!i(a.end.row,a.end.column)?n(`merges.${s}`,"Invalid or out-of-bounds merge range"):(t.maxMergeArea!==void 0&&a.end.row-a.start.row+1>t.maxMergeArea/(a.end.column-a.start.column+1)&&n(`merges.${s}`,"Merge exceeds maxMergeArea"),l.push(a))}),U(l)&&n("merges","Merge ranges must not overlap"),d.forEach((o,s)=>{s==="schemaVersion"?o!==y&&n("metadata.schemaVersion","Unsupported schema version"):s==="initialized"?typeof o!="boolean"&&n("metadata.initialized","Expected a boolean"):n(`metadata.${s}`,"Unknown metadata field")}),r}function w(e){let t="";for(let n=0;n<e.length;n+=32768)t+=String.fromCharCode(...e.subarray(n,n+32768));return btoa(t)}function $(e){const t=atob(e);return Uint8Array.from(t,r=>r.charCodeAt(0))}function j(e){if(e!=null&&e.trim())return JSON.parse(e)}function V(e){if(!(!e||e.format==="colwork.update-log"))return e.format==="colwork.archive"?e.snapshot:e}function A(e){return!e||e.format==="colwork.snapshot"?[]:e.updates??[]}function H(e,t){const r=j(e),n=j(t),f=V(r),d=[...A(r),...A(n)],u=new g.Doc;try{f!=null&&f.snapshot&&g.applyUpdate(u,$(f.snapshot));const i=Number((f==null?void 0:f.sequence)??0),m=new Set,c=new Set;let l=i;for(const o of d.sort((s,a)=>Number(s.seq)-Number(a.seq))){const s=Number(o.seq);!Number.isInteger(s)||typeof o.update!="string"||s<=i||m.has(s)||c.has(o.update)||(g.applyUpdate(u,$(o.update)),m.add(s),c.add(o.update),l=Math.max(l,s))}return{format:"colwork.snapshot",version:1,room:f==null?void 0:f.room,sequence:l,snapshot:w(g.encodeStateAsUpdate(u)),stateVector:w(g.encodeStateVector(u))}}finally{u.destroy()}}function W(e,t){const r=e.split(":").map(Number),n=t.split(":").map(Number);return r[0]-n[0]||(r[1]??0)-(n[1]??0)}function b(e){return[...e].sort(([t],[r])=>W(t,r))}function D(e){const t={};for(const r of["bold","italic","underline","strike","wrap","fontSize","color","background","align","format"])e[r]!==void 0&&(t[r]=e[r]);if(e.border!==void 0){const r={};for(const n of["top","right","bottom","left"])e.border[n]!==void 0&&(r[n]=e.border[n]);t.border=r}return t}function C(e,t){const r=O(e,t);if(r.length)throw new TypeError(`Invalid Colwork document at ${r[0].path}: ${r[0].message}`);const n=M(e),f=Object.fromEntries(b(n.styles).map(([c,l])=>[c,D(JSON.parse(l))])),d=Object.fromEntries(b(n.locks).map(([c,l])=>{if(l==="1")return[c,"1"];const o=JSON.parse(l);return[c,{version:o.version,algorithm:o.algorithm,iterations:o.iterations,salt:o.salt,verifier:o.verifier}]})),u=[...n.merges.keys()].map(c=>E(c)).sort((c,l)=>c.start.row-l.start.row||c.start.column-l.start.column||c.end.row-l.end.row||c.end.column-l.end.column);let i=1,m=1;for(const c of[...n.cells.keys(),...n.styles.keys(),...n.locks.keys()]){const l=S(c);i=Math.max(i,l.row+1),m=Math.max(m,l.column+1)}for(const c of u)i=Math.max(i,c.end.row+1),m=Math.max(m,c.end.column+1);for(const c of n.rowHeights.keys())i=Math.max(i,Number(c)+1);for(const c of n.columnWidths.keys())m=Math.max(m,Number(c)+1);return{schemaVersion:y,rowCount:i,columnCount:m,cells:Object.fromEntries(b(n.cells)),styles:f,rowHeights:Object.fromEntries(b(n.rowHeights)),columnWidths:Object.fromEntries(b(n.columnWidths)),merges:u,locks:d}}function L(e){const t=O(e);if(t.length)throw new TypeError(`Invalid Colwork document at ${t[0].path}: ${t[0].message}`);if(Object.values(M(e)).some(n=>n.size>0))throw new Error("Blank initialization requires an empty sheet");const r=e.getMap(p.metadata);e.transact(()=>{r.set("schemaVersion",y),r.set("initialized",!0)})}function P(e,t={}){const r=t.sequence??0;if(!Number.isSafeInteger(r)||r<0)throw new RangeError("sequence must be a non-negative safe integer");return{format:"colwork.snapshot",version:1,room:t.room,sequence:r,snapshot:w(g.encodeStateAsUpdate(e)),stateVector:w(g.encodeStateVector(e))}}function T(e,t){const r=new g.Doc;try{return g.applyUpdate(r,e),C(r,t)}finally{r.destroy()}}exports.COLWORK_MAP_NAMES=p;exports.COLWORK_SCHEMA_VERSION=y;exports.exportYjsSnapshot=P;exports.getSheetMaps=M;exports.initializeBlankSheet=L;exports.mergeKey=R;exports.parseCellKey=S;exports.parseMergeKey=E;exports.readSheetSnapshot=C;exports.readSheetSnapshotUpdate=T;exports.rebuildYjsSnapshot=H;exports.validateSheetDocument=O;
@@ -0,0 +1,18 @@
1
+ import { SheetSnapshot, SheetValidationLimits } from './model-schema.cjs';
2
+ import { YjsSnapshotFile } from './yjsArchive.cjs';
3
+ import * as Y from 'yjs';
4
+ export * from './model-schema.cjs';
5
+ export type { CellPosition, CellRange } from './range.cjs';
6
+ export { getSheetMaps, validateSheetDocument } from './model-validation.cjs';
7
+ export { rebuildYjsSnapshot } from './yjsRebuild.cjs';
8
+ export type { YjsArchiveFile, YjsSnapshotFile, YjsUpdateLogFile, YjsUpdateRecord } from './yjsArchive.cjs';
9
+ /** Reads a deterministic sparse sheet without loading a renderer, browser globals, or CSS. */
10
+ export declare function readSheetSnapshot(document: Y.Doc, limits?: SheetValidationLimits): SheetSnapshot;
11
+ /** Initializes an empty document without demo cells, headers, styles, or network access. */
12
+ export declare function initializeBlankSheet(document: Y.Doc): void;
13
+ export declare function exportYjsSnapshot(document: Y.Doc, options?: {
14
+ room?: string;
15
+ sequence?: number;
16
+ }): YjsSnapshotFile;
17
+ /** Decodes a Yjs state update and releases its temporary document after export. */
18
+ export declare function readSheetSnapshotUpdate(update: Uint8Array, limits?: SheetValidationLimits): SheetSnapshot;
@@ -0,0 +1,18 @@
1
+ import { SheetSnapshot, SheetValidationLimits } from './model-schema.js';
2
+ import { YjsSnapshotFile } from './yjsArchive.js';
3
+ import * as Y from 'yjs';
4
+ export * from './model-schema.js';
5
+ export type { CellPosition, CellRange } from './range.js';
6
+ export { getSheetMaps, validateSheetDocument } from './model-validation.js';
7
+ export { rebuildYjsSnapshot } from './yjsRebuild.js';
8
+ export type { YjsArchiveFile, YjsSnapshotFile, YjsUpdateLogFile, YjsUpdateRecord } from './yjsArchive.js';
9
+ /** Reads a deterministic sparse sheet without loading a renderer, browser globals, or CSS. */
10
+ export declare function readSheetSnapshot(document: Y.Doc, limits?: SheetValidationLimits): SheetSnapshot;
11
+ /** Initializes an empty document without demo cells, headers, styles, or network access. */
12
+ export declare function initializeBlankSheet(document: Y.Doc): void;
13
+ export declare function exportYjsSnapshot(document: Y.Doc, options?: {
14
+ room?: string;
15
+ sequence?: number;
16
+ }): YjsSnapshotFile;
17
+ /** Decodes a Yjs state update and releases its temporary document after export. */
18
+ export declare function readSheetSnapshotUpdate(update: Uint8Array, limits?: SheetValidationLimits): SheetSnapshot;