@updog/data-editor 0.1.80 → 0.1.82

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/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
 
3
3
  declare var export_default = {
4
4
  ui: {
@@ -448,24 +448,6 @@ declare var export_default = {
448
448
  text: "Your subscription is no longer active. Please renew to continue.",
449
449
  },
450
450
  },
451
- scale: {
452
- bootstrap_failed: {
453
- title: "Couldn't connect to the server",
454
- text: "The server returned an error. Please refresh the page or contact support.",
455
- },
456
- workspace_lost: {
457
- title: "Connection lost",
458
- text: "The session ended unexpectedly. Refresh the page to reconnect.",
459
- },
460
- unreachable: {
461
- title: "Server unreachable",
462
- text: "Check your connection and refresh the page.",
463
- },
464
- server_error: {
465
- title: "Server error",
466
- text: "The server returned an error. Please refresh the page or contact support.",
467
- },
468
- },
469
451
  },
470
452
  uploader: {
471
453
  steps: {
@@ -646,11 +628,12 @@ type SortState = {
646
628
  columnId: string;
647
629
  direction: SortDirection;
648
630
  } | null;
631
+ type ErrorFilter = "all" | string[] | null;
649
632
  type Filters = {
650
633
  search: string;
651
634
  matchCase: boolean;
652
635
  matchEntireCell: boolean;
653
- errorMessageFilters: string[];
636
+ errorFilter: ErrorFilter;
654
637
  showOnlyNewRows: boolean;
655
638
  showOnlyEditedRows: boolean;
656
639
  showOnlyEmptyCells: boolean;
@@ -673,104 +656,6 @@ type Filters = {
673
656
  }>;
674
657
  };
675
658
 
676
- /**
677
- * A built-in declarative validator. Mode-symmetric: the SDK ships a TS
678
- * interpreter, the Updog Scale Go binary ships a Go interpreter, and both
679
- * agree on pass/fail outcomes per `api/validators.json`.
680
- */
681
- type BuiltInValidator = {
682
- type: "required";
683
- message?: string;
684
- } | {
685
- type: "regex";
686
- pattern: string;
687
- flags?: string;
688
- message?: string;
689
- } | {
690
- type: "oneOf";
691
- values: string[];
692
- message?: string;
693
- } | {
694
- type: "range";
695
- min?: number;
696
- max?: number;
697
- message?: string;
698
- } | {
699
- type: "email";
700
- message?: string;
701
- } | {
702
- type: "date";
703
- format?: "YYYY-MM-DD" | "DD/MM/YYYY";
704
- message?: string;
705
- } | {
706
- type: "numeric";
707
- message?: string;
708
- } | {
709
- type: "unique";
710
- message?: string;
711
- fn?: UniqueRemoteFn;
712
- };
713
- /** One cell in an asyncFunction batch. Row is passed by reference. */
714
- type AsyncValidatorCell = {
715
- /** Value of the validated column for this cell. */
716
- value: unknown;
717
- /** The full row — for row-dependent checks. */
718
- row: DataEditorRow;
719
- };
720
- /**
721
- * Remote existence check for `{ type: "unique" }`. Called once per sweep
722
- * with all distinct candidate values; report the subset that already exists —
723
- * return it and/or stream it via onChunk (results are unioned). `signal`
724
- * fires only when results can no longer be used. Client-mode only.
725
- */
726
- type UniqueRemoteFn = (values: unknown[], onChunk: (existing: unknown[]) => void, signal: AbortSignal) => Promise<unknown[] | void>;
727
- type AsyncFunctionValidator = {
728
- type: "asyncFunction";
729
- /**
730
- * Called once per column per operation with every affected cell. Report
731
- * failures by `index` into `cells`: return an array aligned with the input
732
- * (null = valid) and/or stream sparse failures via onChunk (unioned, any
733
- * order). `signal` fires only when results can no longer be used.
734
- * Client-mode only. For uniqueness use `unique.fn`, not this.
735
- */
736
- fn: (cells: AsyncValidatorCell[], onChunk: (failures: {
737
- index: number;
738
- error: ValidationError;
739
- }[]) => void, signal: AbortSignal) => Promise<(ValidationError | null)[] | void>;
740
- };
741
- /**
742
- * Server-mode-only escape hatch: an expression evaluated by the Go binary
743
- * via expr-lang. Skipped at runtime in client mode (warned at mount).
744
- */
745
- type ExpressionValidator = {
746
- type: "expression";
747
- expr: string;
748
- message?: string;
749
- };
750
- /**
751
- * Client-mode-only escape hatch: a JS predicate run inline. Dropped (with
752
- * one warn per column) when the SDK serializes the schema for server mode.
753
- */
754
- type FunctionValidator = {
755
- type: "function";
756
- fn: CellValidator;
757
- };
758
- /**
759
- * The validator-rule union accepted by `DataEditorColumn.validators`.
760
- * - Built-ins and `expression` are declarative objects (cross the wire).
761
- * - `function` wraps a `CellValidator`; client-mode-only, dropped+warned in server mode.
762
- *
763
- * Named `ValidatorRule` (not `Validator`) so it doesn't clash with the
764
- * runtime `Validator` class in `core/Validator.ts`.
765
- */
766
- type ValidatorRule = BuiltInValidator | ExpressionValidator | FunctionValidator | AsyncFunctionValidator;
767
- /**
768
- * Async-check state of a cell, orthogonal to errors/misplaced: "pending"
769
- * while a verdict is awaited, "unverified" when the check failed or timed
770
- * out. Idle cells carry no entry.
771
- */
772
- type CellAsyncState = "pending" | "unverified";
773
-
774
659
  /**
775
660
  * Severity level for a validation message.
776
661
  * - `"error"` — a validation failure: marks the row invalid, counts as an error.
@@ -915,10 +800,8 @@ type DataEditorColumn = {
915
800
  /**
916
801
  * One or more validators run on every edit. Accepts:
917
802
  * - Built-in object literals: `{ type: "required" | "email" | "regex" | "range" | "oneOf" | "date" | "numeric" | "unique", ... }`.
918
- * - `{ type: "expression", expr }` — server-mode only. Warned in client mode.
919
- * - `{ type: "function", fn }` — client-mode only. Dropped+warned in server mode.
920
- *
921
- * See `_specs/VALIDATIONS.md` §4.5 for the per-mode support matrix.
803
+ * - `{ type: "function", fn }` — a JS predicate run inline.
804
+ * - `{ type: "asyncFunction", fn }` — batched remote checks.
922
805
  */
923
806
  validators?: ValidatorRule[];
924
807
  /**
@@ -955,360 +838,90 @@ type DataEditorColumn = {
955
838
  locked?: boolean | ColumnLockMode;
956
839
  };
957
840
 
958
- /** Params passed to `findAndReplace.onFind` when the user types a search query. */
959
- type FindParams = {
960
- /** The search string. */
961
- search: string;
962
- /** When `true`, matching is case-sensitive. */
963
- matchCase?: boolean;
964
- /** When `true`, the entire cell value must equal the search string. */
965
- matchEntireCell?: boolean;
966
- /** Restrict search to these columns. `null` or omitted = all columns. */
967
- columnIds?: string[] | null;
968
- /** Current view filters so the server can scope matches to the active filter set. */
969
- filters?: QueryFilters;
970
- /** Current sort state so match ordering follows the visual row order. */
971
- sort?: SortState;
972
- };
973
- /** A single match location returned by the server. */
974
- type FindMatch = {
975
- /** Row position in the current filtered+sorted view (for grid scrolling). */
976
- rowIndex: number;
977
- /** Column ID where the match occurs. */
978
- columnId: string;
979
- /** Character offset within the cell value (for inline highlight). */
980
- startIndex: number;
981
- /** 0-based position in the ordered match list (for counter display). */
982
- matchIndex: number;
983
- };
984
- /** Response from `findAndReplace.onFind`. */
985
- type FindResponse = {
986
- /** Total number of matches across all rows. */
987
- totalCount: number;
988
- /** The first match. Omit when `totalCount` is 0. */
989
- current?: FindMatch;
990
- };
991
- /** Params passed to `findAndReplace.onNavigate` when the user clicks prev/next. */
992
- type FindNavigateParams = FindParams & {
993
- /** Navigation direction. */
994
- direction: "next" | "prev";
995
- /** Current match position so the server knows where to navigate from. */
996
- currentMatchIndex: number;
997
- };
998
- /** Params passed to `findAndReplace.onReplace`. */
999
- type ReplaceParams = FindParams & {
1000
- /** The replacement text. */
1001
- replacement: string;
1002
- /** When `true`, replace all matches. When omitted or `false`, replace only `target`. */
1003
- all?: boolean;
1004
- /** The specific match to replace. Required when `all` is not `true`. */
1005
- target?: FindMatch;
1006
- };
1007
- /** Response from `findAndReplace.onReplace`. */
1008
- type ReplaceResponse = {
1009
- /** Remaining match count after replacement. */
1010
- totalCount: number;
1011
- /** Next match to navigate to after replacement. Omit when none left. */
1012
- current?: FindMatch;
1013
- };
1014
- /** Server-side find and replace configuration. */
1015
- type FindAndReplaceConfig = {
1016
- /** Called when the user types a search query. Returns total count and first match. */
1017
- onFind: (params: FindParams) => Promise<FindResponse>;
1018
- /** Called when the user clicks prev/next arrows. Returns the target match. */
1019
- onNavigate: (params: FindNavigateParams) => Promise<FindMatch>;
1020
- /** Called when the user clicks Replace or Replace All. */
1021
- onReplace: (params: ReplaceParams) => Promise<ReplaceResponse>;
1022
- };
1023
- type StoreMode = "client" | "server";
1024
- type ServerRowId = string | number;
1025
- /** Row-level status flags returned by the server. Drive row filters and sidebar counts. */
1026
- type ServerRowStatus = {
1027
- edited?: boolean;
1028
- new?: boolean;
1029
- deleted?: boolean;
1030
- hasErrors?: boolean;
1031
- hasEmptyCells?: boolean;
1032
- };
1033
- /** Server-reported change for a single cell. The current value lives in `fields`. */
1034
- type ServerCellChange = {
1035
- original: unknown;
1036
- };
1037
- /** Server-reported validation error for a single cell. */
1038
- type ServerCellError = {
1039
- message: string;
1040
- code?: number | string;
1041
- };
1042
- /** Per-row metadata returned by the server in server-delegated mode. */
1043
- type ServerRowMeta = {
1044
- /** Row-level status flags — drive row filters and sidebar counts. */
1045
- status?: ServerRowStatus;
1046
- /** Cell-level change tracking. Key = field name. */
1047
- changes?: Record<string, ServerCellChange>;
1048
- /** Cell-level validation errors. Key = field name. */
1049
- errors?: Record<string, ServerCellError[]>;
1050
- };
1051
- /** Per-source row count returned by the server. Drives the Data Sources sidebar. */
1052
- type ServerSourceCount = {
1053
- id: string;
1054
- name: string;
1055
- count: number;
1056
- };
1057
- /** Aggregate row counts returned alongside a query page. Drive sidebar indicators. */
1058
- type ServerQueryCounts = {
1059
- edited?: number;
1060
- new?: number;
1061
- deleted?: number;
1062
- errors?: number;
1063
- emptyCells?: number;
1064
- sources?: ServerSourceCount[];
1065
- };
1066
- type ServerRow<T extends DataEditorRow = DataEditorRow> = {
1067
- id: ServerRowId;
1068
- fields: T;
1069
- meta?: ServerRowMeta;
1070
- };
1071
- type ServerResponse<T> = {
1072
- data: T;
1073
- meta?: Record<string, unknown>;
1074
- };
1075
- type QueryFilters<F = Record<string, unknown>> = Partial<Filters> & F;
1076
- type QueryParams<F = Record<string, unknown>> = {
1077
- filters?: QueryFilters<F>;
1078
- sort?: SortState;
1079
- /** When present, only rows belonging to these source IDs are returned. Omit to include all sources. */
1080
- sources?: string[];
1081
- offset?: number;
1082
- limit: number;
1083
- signal?: AbortSignal;
1084
- };
1085
- type QueryResponse<T extends DataEditorRow = DataEditorRow> = ServerResponse<{
1086
- rows: ServerRow<T>[];
1087
- totalCount: number;
1088
- filteredCount?: number;
1089
- counts?: ServerQueryCounts;
1090
- }>;
1091
841
  /**
1092
- * Filter options returned by `onFilterOptions` for populating sidebar filter controls in server mode.
1093
- * Keys are column IDs. Only include columns that have a `filter` configured.
842
+ * A built-in declarative validator a declarative object the SDK interprets,
843
+ * per `api/validators.json`.
1094
844
  */
1095
- type FilterOptionsResponse = {
1096
- [columnId: string]: {
1097
- /** Values for `"select"` filters. Raw display strings — no formatter is applied. */
1098
- options?: string[];
1099
- /** Bounds for `"number-range"` filters. */
1100
- range?: {
1101
- min: number;
1102
- max: number;
1103
- };
1104
- /** Bounds for `"date-range"` filters. Values are ISO date strings (YYYY-MM-DD). */
1105
- dateRange?: {
1106
- min: string;
1107
- max: string;
1108
- };
1109
- };
845
+ type BuiltInValidator = {
846
+ type: "required";
847
+ message?: string;
848
+ } | {
849
+ type: "regex";
850
+ pattern: string;
851
+ flags?: string;
852
+ message?: string;
853
+ } | {
854
+ type: "oneOf";
855
+ values: string[];
856
+ message?: string;
857
+ } | {
858
+ type: "range";
859
+ min?: number;
860
+ max?: number;
861
+ message?: string;
862
+ } | {
863
+ type: "email";
864
+ message?: string;
865
+ } | {
866
+ type: "date";
867
+ format?: "YYYY-MM-DD" | "DD/MM/YYYY";
868
+ message?: string;
869
+ } | {
870
+ type: "numeric";
871
+ message?: string;
872
+ } | {
873
+ type: "unique";
874
+ message?: string;
875
+ fn?: UniqueRemoteFn;
1110
876
  };
1111
- type ServerCallOptions = {
1112
- signal: AbortSignal;
877
+ /** One cell in an asyncFunction batch. Row is passed by reference. */
878
+ type AsyncValidatorCell = {
879
+ /** Value of the validated column for this cell. */
880
+ value: unknown;
881
+ /** The full row — for row-dependent checks. */
882
+ row: DataEditorRow;
1113
883
  };
1114
884
  /**
1115
- * Coordinate rectangle within the server's data view.
1116
- * Uses ServerRowId (primary key) for rows and column ID strings for columns.
1117
- *
1118
- * Convention:
1119
- * - Both row fields omitted → all rows.
1120
- * - Both column fields omitted → all columns.
1121
- * - Single row: `fromRow` AND `toRow` both set, `toRow === fromRow`.
1122
- * - Single column: `fromColumn` AND `toColumn` both set, `toColumn === fromColumn`.
1123
- * - Range: both `from` and `to` set, `to !== from`.
1124
- * - `allSelected: true` → all rows and all columns.
1125
- * - Empty `{}` → used only for insert operations.
1126
- *
1127
- * INVALID: `from` present without `to`, or vice versa.
885
+ * Remote existence check for `{ type: "unique" }`. Called once per sweep
886
+ * with all distinct candidate values; report the subset that already exists
887
+ * return it and/or stream it via onChunk (results are unioned). `signal`
888
+ * fires only when results can no longer be used. Client-mode only.
1128
889
  */
1129
- type Region = {
1130
- fromRow?: ServerRowId;
1131
- toRow?: ServerRowId;
1132
- fromColumn?: string;
1133
- toColumn?: string;
1134
- allSelected?: boolean;
1135
- };
1136
- /** Describes where and how to insert a new row. */
1137
- type InsertParams = {
1138
- /** Existing row to anchor the insert relative to. Omitted when appending to the end. */
1139
- anchorRow?: ServerRowId;
1140
- /** Insert before or after the anchor row. */
1141
- position: "above" | "below";
1142
- /** Column IDs matching the order of `values` entries. */
1143
- columns: string[];
890
+ type UniqueRemoteFn = (values: unknown[], onChunk: (existing: unknown[]) => void, signal: AbortSignal) => Promise<unknown[] | void>;
891
+ type AsyncFunctionValidator = {
892
+ type: "asyncFunction";
893
+ /**
894
+ * Called once per column per operation with every affected cell. Report
895
+ * failures by `index` into `cells`: return an array aligned with the input
896
+ * (null = valid) and/or stream sparse failures via onChunk (unioned, any
897
+ * order). `signal` fires only when results can no longer be used.
898
+ * Client-mode only. For uniqueness use `unique.fn`, not this.
899
+ */
900
+ fn: (cells: AsyncValidatorCell[], onChunk: (failures: {
901
+ index: number;
902
+ error: ValidationError;
903
+ }[]) => void, signal: AbortSignal) => Promise<(ValidationError | null)[] | void>;
1144
904
  };
1145
905
  /**
1146
- * Unified edit params for all data mutations in server-delegated mode.
1147
- *
1148
- * The combination of fields determines the operation:
1149
- * - `target` + `values` → cell edit, clear, or external paste
1150
- * - `target` + `source` → internal paste (+ `cut` for cut-paste)
1151
- * - `target` + `source` (fill) → fill handle
1152
- * - `target` + `transform` → transform / revert
1153
- * - `target` + `delete: true` → mark rows for deletion
1154
- * - `target` + `delete: false` → restore rows (unmark deletion)
1155
- * - `insert` + `values` → create a new row
1156
- *
1157
- * `values` is always a 2D array. For a single cell edit: `[["newValue"]]`.
1158
- * For clearing: `[[""]]`. The server interprets dimensions relative to `target`:
1159
- * a 1×1 `values` applied to a multi-cell target means "fill all cells with this value".
1160
- *
1161
- * `filters` and `sort` provide the view context so the server can resolve
1162
- * which rows fall between `fromRow` and `toRow` in the current view.
1163
- * Omitted for single-cell edits where `fromRow` is a direct row ID.
906
+ * Escape hatch: a JS predicate run inline against the cell value and its row.
1164
907
  */
1165
- type EditParams = {
1166
- target: Region[];
1167
- source?: Region[];
1168
- values?: unknown[][];
1169
- transform?: TransformParams;
1170
- cut?: boolean;
1171
- delete?: boolean;
1172
- insert?: InsertParams;
1173
- undo?: boolean;
1174
- filters?: QueryFilters;
1175
- sort?: SortState;
1176
- lockedColumns?: Array<{
1177
- columnId: string;
1178
- mode: "all" | "default";
1179
- }>;
1180
- };
1181
- type ExportParams$1<F = Record<string, unknown>> = {
1182
- format: "csv" | "tsv" | "xlsx" | "json" | "xml";
1183
- allRows: boolean;
1184
- rtl?: boolean;
1185
- filters?: QueryFilters<F>;
1186
- sort?: SortState;
1187
- signal?: AbortSignal;
1188
- };
1189
- /** Transform operation descriptor. `type` identifies the operation, optional fields carry parameters. */
1190
- type TransformParams = {
1191
- type: string;
1192
- separator?: string;
1193
- /** When `true`, the server should delete the dynamic source columns after applying the transform. */
1194
- deleteSource?: boolean;
1195
- };
1196
- /** Params passed to `onColumnDelete` when the user deletes a dynamic column. */
1197
- type ColumnDeleteParams = {
1198
- /** ID of the dynamic column to delete. */
1199
- columnId: string;
1200
- /** `true` when the server should reverse this operation (undo). Omitted on initial call and redo. */
1201
- undo?: boolean;
1202
- };
1203
- /** Params passed to `onColumnEdit` when the user renames a dynamic column. */
1204
- type ColumnEditParams = {
1205
- /** ID of the dynamic column being edited. */
1206
- columnId: string;
1207
- /** New title for the column. */
1208
- title: string;
1209
- /** `true` when the server should reverse this operation (undo). Omitted on initial call and redo. */
1210
- undo?: boolean;
1211
- };
1212
- /** Server's response after applying a mutation. */
1213
- type EditResponse = {
1214
- counts?: ServerQueryCounts;
1215
- /** Business-logic rejection. SDK reverts the optimistic update and shows `reason` in a toast. */
1216
- rejected?: boolean;
1217
- /** Why the server rejected. Shown to the user as-is. */
1218
- reason?: string;
1219
- /** The full row created by the server. Returned for insert operations. */
1220
- row?: ServerRow;
1221
- /** Updated column list. When present, the SDK replaces its columns with this list. */
1222
- columns?: Array<{
1223
- id: string;
1224
- title: string;
1225
- }>;
908
+ type FunctionValidator = {
909
+ type: "function";
910
+ fn: CellValidator;
1226
911
  };
1227
912
  /**
1228
- * Every decision the user made during the import wizard, packed into one object.
1229
- * You get the raw file and the full mapping config. Parse it however you want —
1230
- * stream it, bulk-load it, hand it to a background job. Your call.
913
+ * The validator-rule union accepted by `DataEditorColumn.validators`.
914
+ *
915
+ * Named `ValidatorRule` (not `Validator`) so it doesn't clash with the
916
+ * runtime `Validator` class in `core/Validator.ts`.
1231
917
  */
1232
- type ImportMappings = {
1233
- /** CSV header → column ID. Headers the user left unmatched are `undefined`. */
1234
- columnMapping: Record<string, string | undefined>;
1235
- /**
1236
- * Value substitutions for select columns.
1237
- * Outer key = column ID, inner key = imported value, inner value = target option.
1238
- * Only present when at least one select column was matched.
1239
- */
1240
- valueMapping: Record<string, Record<string, string | undefined>>;
1241
- /** Column ID used to match imported rows against existing data. Same value as `DataEditorProps.primaryKey`. */
1242
- primaryKey: string;
1243
- /** Sheet name the user selected. Only present for multi-sheet XLSX files. */
1244
- selectedSheet?: string;
1245
- /** Zero-based index of the row the SDK detected as the header row. */
1246
- headerRowIndex: number;
1247
- /** Number format detected from the file contents. Affects how `"1.234,56"` vs `"1,234.56"` is read. */
1248
- numberFormat: "EU" | "US";
1249
- /**
1250
- * Date order detected from the file's date columns. `"EU"` = day-first,
1251
- * `"US"` = month-first. One verdict for the file, since date order follows
1252
- * the source locale; ISO values are parsed regardless of this.
1253
- */
1254
- dateFormat: "EU" | "US";
1255
- /**
1256
- * Columns the user created during import for unmatched headers.
1257
- * These don't exist in your schema yet — you decide whether to persist them.
1258
- */
1259
- newColumns: DataEditorColumn[];
1260
- };
1261
- /** Params passed to `onFileImport`. The original file, unchanged, plus everything the wizard collected. */
1262
- type FileImportParams = {
1263
- /** The original file. Same bytes the user dropped into the browser. */
1264
- file: File;
1265
- /** All mapping decisions from the import wizard. */
1266
- mappings: ImportMappings;
1267
- /** Display name for this import source. Typically the file name. */
1268
- sourceName: string;
1269
- /** Fires when the user cancels the import. */
1270
- signal?: AbortSignal;
1271
- };
918
+ type ValidatorRule = BuiltInValidator | FunctionValidator | AsyncFunctionValidator;
1272
919
  /**
1273
- * Params passed to `onRowsImport` once per chunk.
1274
- * The SDK already parsed the file, applied column mappings, normalized dates
1275
- * and numbers, and resolved value mappings. You get clean, schema-conformant rows.
920
+ * Async-check state of a cell, orthogonal to errors/misplaced: "pending"
921
+ * while a verdict is awaited, "unverified" when the check failed or timed
922
+ * out. Idle cells carry no entry.
1276
923
  */
1277
- type RowsImportParams = {
1278
- /** Stable ID for this import session. Use it for idempotency or correlation. */
1279
- importId: string;
1280
- /** Display name for this import source. Typically the file name. */
1281
- sourceName: string;
1282
- /** Zero-based chunk index. Together with `importId`, uniquely identifies each chunk. */
1283
- chunkIndex: number;
1284
- /** `true` on the last chunk. Safe to finalize, run post-import hooks, or trigger validation. */
1285
- isLastChunk: boolean;
1286
- /** Transformed rows, keyed by column ID. Ready to store. */
1287
- rows: Record<string, unknown>[];
1288
- /** Columns the user created during import. Only present on the first chunk (`chunkIndex === 0`). */
1289
- newColumns?: DataEditorColumn[];
1290
- /** Column ID used to match imported rows against existing data. */
1291
- primaryKey: string;
1292
- /** Fires when the user cancels mid-import. Clean up any partial state. */
1293
- signal?: AbortSignal;
1294
- };
1295
- /** Your response after processing a chunk. */
1296
- type RowsImportResponse = {
1297
- /** How many rows you accepted from this chunk. Drives progress reporting. */
1298
- accepted: number;
1299
- /** Per-row errors. `rowIndex` is relative to the chunk (0-based). Surfaced in the UI after import. */
1300
- errors?: Array<{
1301
- rowIndex: number;
1302
- message: string;
1303
- }>;
1304
- };
1305
- /** Params passed to `onSourceRemove` when the user deletes a data source. */
1306
- type SourceRemoveParams = {
1307
- /** The source ID to remove. Matches the `id` from `ServerQueryCounts.sources`. */
1308
- sourceId: string;
1309
- /** Fires when the user cancels. */
1310
- signal?: AbortSignal;
1311
- };
924
+ type CellAsyncState = "pending" | "unverified";
1312
925
 
1313
926
  /**
1314
927
  * ChunkedProcessor — Generic utility for processing items in prioritized chunks
@@ -1353,33 +966,10 @@ declare class ChunkedProcessor<T> {
1353
966
  private _pendingChunkFn;
1354
967
  constructor(chunkSize?: number);
1355
968
  get isRunning(): boolean;
1356
- get chunkSize(): number;
1357
969
  run(params: ChunkedProcessorCallbacks<T>): void;
1358
970
  cancel(): void;
1359
971
  }
1360
972
 
1361
- /**
1362
- * Internal contract: the surface a Scale client exposes to the SDK's data
1363
- * layer. Implemented by `ScaleClient`. Not part of the public SDK API —
1364
- * customers configure server mode via `server: { url }` and never see this
1365
- * type.
1366
- */
1367
- type ScaleClientApi<TRow extends DataEditorRow = DataEditorRow, TFilters = Record<string, unknown>> = {
1368
- onQuery: (params: QueryParams<TFilters>) => Promise<QueryResponse<TRow>>;
1369
- onFilterOptions?: () => Promise<FilterOptionsResponse>;
1370
- onExport?: (params: ExportParams$1<TFilters>) => Promise<void>;
1371
- onEdit: (params: EditParams, options?: ServerCallOptions) => Promise<EditResponse | void>;
1372
- onFileImport?: (params: FileImportParams) => Promise<void>;
1373
- onRowsImport?: (params: RowsImportParams) => Promise<RowsImportResponse | void>;
1374
- importChunkSize?: number;
1375
- onSourceRemove?: (params: SourceRemoveParams) => Promise<void>;
1376
- onColumnDelete?: (params: ColumnDeleteParams) => Promise<EditResponse | void>;
1377
- onColumnEdit?: (params: ColumnEditParams) => Promise<EditResponse | void>;
1378
- findAndReplace?: FindAndReplaceConfig;
1379
- pageSize?: number;
1380
- scrollSensitivity?: number;
1381
- };
1382
-
1383
973
  /**
1384
974
  * A single operation the LLM wants to apply to rows in the current filtered view.
1385
975
  *
@@ -1520,12 +1110,10 @@ type DataEditorChat<TRow extends DataEditorRow = DataEditorRow> = {
1520
1110
 
1521
1111
  /**
1522
1112
  * Categories of internal errors surfaced through the `onError` callback.
1523
- *
1524
- * Existing categories cover client-side failures. `scale.*` codes cover
1525
- * server-mode (Updog Scale) failures. `license.*` codes cover license
1526
- * validation failures (previously a separate `LicenseErrorCode` enum).
1113
+ * `license.*` codes cover license validation failures (previously a separate
1114
+ * `LicenseErrorCode` enum).
1527
1115
  */
1528
- type UpdogErrorCode = "PARSE_ERROR" | "RENDER_ERROR" | "TRANSFORM_ERROR" | "VALIDATION_ERROR" | "WORKER_ERROR" | "COMMAND_ERROR" | "OPERATION_ERROR" | "license.invalid" | "license.missing" | "license.domain_not_allowed" | "license.subscription_inactive" | "license.trial_expired" | "scale.bootstrap_failed" | "scale.workspace_lost" | "scale.unreachable" | "scale.server_error";
1116
+ type UpdogErrorCode = "PARSE_ERROR" | "RENDER_ERROR" | "TRANSFORM_ERROR" | "VALIDATION_ERROR" | "WORKER_ERROR" | "COMMAND_ERROR" | "OPERATION_ERROR" | "license.invalid" | "license.missing" | "license.domain_not_allowed" | "license.subscription_inactive" | "license.trial_expired";
1529
1117
  /**
1530
1118
  * An internal error caught by the SDK and passed to `onError`. The SDK
1531
1119
  * recovers gracefully where possible — `onError` is for your logging and
@@ -1657,261 +1245,6 @@ type NormalizedColumn = DataEditorColumn & {
1657
1245
 
1658
1246
  type PrimaryKeyInput = string | readonly string[];
1659
1247
 
1660
- type RegisterSourceOptions = {
1661
- name: string;
1662
- id?: DataSourceId;
1663
- isDeletable?: boolean;
1664
- isInitialData?: boolean;
1665
- };
1666
- type MergeEntry<TRow> = {
1667
- row: TRow;
1668
- sourceId: DataSourceId;
1669
- isNew: boolean;
1670
- isEdited: boolean;
1671
- /** Diff basis the row carried before the merge. Present only when isEdited. */
1672
- originalRow?: TRow;
1673
- };
1674
- type RemovalPlan<TRow> = {
1675
- rowsToDelete: Set<TRowId>;
1676
- rowsToRestore: Array<{
1677
- rowId: TRowId;
1678
- row: TRow;
1679
- originalSourceId: DataSourceId;
1680
- isNew: boolean;
1681
- isEdited: boolean;
1682
- originalRow?: TRow;
1683
- }>;
1684
- };
1685
- type ExtendedRemovalPlan<TRow> = RemovalPlan<TRow> & {
1686
- sourceId: DataSourceId;
1687
- repairedEntries: Array<{
1688
- sourceId: DataSourceId;
1689
- rowId: TRowId;
1690
- before: MergeEntry<TRow>;
1691
- after: MergeEntry<TRow> | null;
1692
- }>;
1693
- };
1694
- declare class SourceManager<TRow extends DataEditorRow = DataEditorRow> {
1695
- private readonly _defaultSourceId;
1696
- private readonly overrides;
1697
- private readonly sources;
1698
- private readonly mergedRows;
1699
- getSourceId(rowId: TRowId): DataSourceId;
1700
- setSourceId(rowId: TRowId, sourceId: DataSourceId): void;
1701
- deleteSourceId(rowId: TRowId): void;
1702
- getOverrides(): ReadonlyMap<TRowId, DataSourceId>;
1703
- register(options: RegisterSourceOptions): DataSourceId;
1704
- /**
1705
- * Re-insert a source using a full captured state, preserving
1706
- * isVisible, isLoading, rowCount, etc. Used by SourceLifecycle.restore.
1707
- * If the source already exists, overwrites its state.
1708
- */
1709
- restoreState(state: DataSourceState): void;
1710
- has(sourceId: DataSourceId): boolean;
1711
- get(sourceId: DataSourceId): DataSourceState | undefined;
1712
- delete(sourceId: DataSourceId): void;
1713
- setLoading(sourceId: DataSourceId, isLoading: boolean): void;
1714
- finalizeAllSources(): void;
1715
- values(): IterableIterator<DataSourceState>;
1716
- getHiddenSourceIds(): Set<DataSourceId>;
1717
- saveMergeSnapshot(sourceId: DataSourceId, rowId: TRowId, existingRow: TRow, previousSourceId: DataSourceId, isNew: boolean, isEdited: boolean, originalRow?: TRow): void;
1718
- /**
1719
- * Public so commands can re-install merge entries during undo of a remove.
1720
- */
1721
- restoreMergeEntry(sourceId: DataSourceId, rowId: TRowId, entry: MergeEntry<TRow>): void;
1722
- /**
1723
- * Pure — computes the full removal plan without mutating any state.
1724
- * Callers run applyRemovalPlan(plan) to commit.
1725
- */
1726
- planRemoval(sourceId: DataSourceId): ExtendedRemovalPlan<TRow> | null;
1727
- /**
1728
- * Mutates internal state per plan produced by planRemoval.
1729
- */
1730
- applyRemovalPlan(plan: ExtendedRemovalPlan<TRow>): void;
1731
- clear(): void;
1732
- private getUniqueName;
1733
- }
1734
-
1735
- type ServerDataManagerDeps<TRow extends DataEditorRow = DataEditorRow> = {
1736
- clear(): void;
1737
- setLoading(isLoading: boolean): void;
1738
- registerSource(options: RegisterSourceOptions): DataSourceId;
1739
- setSourceLoading(sourceId: DataSourceId, isLoading: boolean): void;
1740
- getLocalRowCount(): number;
1741
- replaceServerRows(sourceId: DataSourceId, rows: ServerRow<TRow>[], offset: number, counts?: ServerQueryCounts): void;
1742
- appendServerRows(rows: ServerRow<TRow>[], counts?: ServerQueryCounts): void;
1743
- prependServerRows(rows: ServerRow<TRow>[], offset: number, counts?: ServerQueryCounts): void;
1744
- applyServerRowMeta(rows: ServerRow<TRow>[], counts?: ServerQueryCounts): void;
1745
- };
1746
- type FetchDirection = "forward" | "backward" | "jump";
1747
- declare class ServerDataManager<TRow extends DataEditorRow = DataEditorRow> {
1748
- private _offset;
1749
- private _totalCount;
1750
- private _isFetching;
1751
- private readonly _pageSize;
1752
- private readonly _maxBufferRows;
1753
- private _filters;
1754
- private _sources;
1755
- private _sort;
1756
- private _filterOptions;
1757
- private _filterOptionsFetched;
1758
- private _abortController;
1759
- private _syncAbort;
1760
- private _lastVisibleStart;
1761
- private _debouncedFetch;
1762
- private readonly _config;
1763
- private readonly _dataStoreRef;
1764
- private readonly _sourceLabel;
1765
- private _onChanged;
1766
- constructor(config: ScaleClientApi<TRow>, dataStoreRef: ServerDataManagerDeps<TRow>, sourceLabel: string);
1767
- get offset(): number;
1768
- get totalCount(): number | null;
1769
- get isFetching(): boolean;
1770
- get pageSize(): number;
1771
- get maxBufferRows(): number;
1772
- setOnChanged(callback: () => void): void;
1773
- setOffset(offset: number): void;
1774
- setTotalCount(count: number): void;
1775
- private setFetching;
1776
- getExcess(currentCount: number, newCount: number): number;
1777
- shouldFetch(visibleStart: number, visibleEnd: number, loadedCount: number): FetchDirection | null;
1778
- /**
1779
- * Full reload — abort in-flight, clear store, fetch first page.
1780
- * Called on initial load, search/filter/sort changes, and resetFilters.
1781
- */
1782
- reload(): void;
1783
- /**
1784
- * Scroll-driven pagination with velocity-based debouncing.
1785
- * Called from CanvasGrid on every scroll event.
1786
- */
1787
- handleScroll(visibleStart: number, visibleEnd: number): void;
1788
- /**
1789
- * Fetch a single page based on scroll position and current window state.
1790
- */
1791
- private fetchPage;
1792
- /**
1793
- * Re-query the current viewport and replace row data, metadata, and counts.
1794
- * Called after successful edits and find-and-replace mutations.
1795
- * Each call aborts the previous in-flight sync.
1796
- */
1797
- syncCurrentView(): void;
1798
- /**
1799
- * Merge filter keys into server filter state and reload.
1800
- * Called by DataStore.setFilters() in server mode and by filter components.
1801
- */
1802
- setFilters(filters: Partial<Filters>): void;
1803
- /**
1804
- * Set sort state and reload.
1805
- */
1806
- setSort(sort: SortState): void;
1807
- /**
1808
- * Restrict query to visible sources and reload.
1809
- * Pass `undefined` to include all sources.
1810
- */
1811
- setSources(sources: string[] | undefined): void;
1812
- /**
1813
- * Clear all filters and sort, then reload.
1814
- */
1815
- resetFilters(): void;
1816
- /**
1817
- * One-time fetch of filter option dictionaries for sidebar filter controls.
1818
- */
1819
- fetchFilterOptions(): void;
1820
- getFilterOptions(): FilterOptionsResponse | null;
1821
- get onEdit(): (params: EditParams, options?: ServerCallOptions) => Promise<EditResponse | void>;
1822
- get filters(): Record<string, unknown>;
1823
- get sort(): SortState;
1824
- get sources(): string[] | undefined;
1825
- get onSourceRemove(): ((params: SourceRemoveParams) => Promise<void>) | undefined;
1826
- get onColumnDelete(): ((params: ColumnDeleteParams) => Promise<EditResponse | void>) | undefined;
1827
- get onColumnEdit(): ((params: ColumnEditParams) => Promise<EditResponse | void>) | undefined;
1828
- get hasExport(): boolean;
1829
- private _exportAbortController;
1830
- export(format: DataEditorFormat, allRows: boolean, rtl: boolean): Promise<void>;
1831
- clear(): void;
1832
- destroy(): void;
1833
- }
1834
-
1835
- /**
1836
- * A post-resolution selection rectangle in stable coordinate space.
1837
- * Produced by grid-layer resolvers from CellRange[] in grid-index space.
1838
- * Consumed by DataStore operations and server sync.
1839
- */
1840
- type SelectionRect = {
1841
- readonly fields: readonly string[];
1842
- readonly rowIds: readonly TRowId[];
1843
- };
1844
-
1845
- /**
1846
- * ServerEditBuilder — Stateless coordinate translator for server-delegated edits.
1847
- *
1848
- * Converts frontend coordinates (TRowId, column index, grid ranges) into
1849
- * `EditParams` with `Region[]` that the server can interpret.
1850
- *
1851
- * Does NOT call `onEdit`. Only builds params.
1852
- * DataStore calls the builder, then sends the result to the server.
1853
- *
1854
- * Responsibilities:
1855
- * - TRowId → ServerRowId translation via primaryKey
1856
- * - Grid index → column ID translation via columns array
1857
- * - Filter/sort context attachment from ServerDataManager
1858
- */
1859
-
1860
- type ServerEditDeps<TRow extends DataEditorRow = DataEditorRow> = {
1861
- getPrimaryKey: () => string;
1862
- getRowById: (id: TRowId) => TRow | undefined;
1863
- getColumnIds: () => string[];
1864
- getFilters: () => Record<string, unknown>;
1865
- getSort: () => SortState;
1866
- getLockedColumns: () => ReadonlyMap<string, ColumnLockMode>;
1867
- };
1868
- declare class ServerEditBuilder<TRow extends DataEditorRow = DataEditorRow> {
1869
- private readonly _deps;
1870
- constructor(deps: ServerEditDeps<TRow>);
1871
- resolveServerRowId(rowId: TRowId): ServerRowId | undefined;
1872
- buildRegion(rowIds: TRowId[], columnIds: string[]): Region;
1873
- /**
1874
- * Collapse rowIds × columnIds into minimal Region[].
1875
- * - All columns → omit column fields (row-only regions).
1876
- * - Contiguous columns in schema order → single fromColumn/toColumn span.
1877
- * - Non-contiguous → one region per contiguous column group.
1878
- * Rows are expressed as fromRow/toRow using first/last of the provided array.
1879
- */
1880
- buildRegions(rowIds: TRowId[], columnIds: string[]): Region[];
1881
- /**
1882
- * Collapse columnIds into minimal column-only Region[] (all rows implied).
1883
- * - All columns → `{ allSelected: true }`.
1884
- * - Contiguous in schema order → single `{ fromColumn, toColumn }`.
1885
- * - Non-contiguous → one region per contiguous group.
1886
- */
1887
- buildColumnRegions(columnIds: string[]): Region[];
1888
- /**
1889
- * Build minimal Region[] from multiple selection rectangles.
1890
- * Each rect is collapsed independently, preserving disjoint selections.
1891
- */
1892
- buildRegionsFromRects(rects: SelectionRect[]): Region[];
1893
- buildAllSelectedRegion(): Region;
1894
- buildColumnRegion(columnId: string): Region;
1895
- buildRowRegion(fromRowId: TRowId, toRowId: TRowId): Region;
1896
- cellEdit(rowId: TRowId, field: string, value: unknown): EditParams;
1897
- clear(target: Region[]): EditParams;
1898
- paste(source: Region[], target: Region[], cut?: boolean): EditParams;
1899
- pasteExternal(target: Region[], values: unknown[][]): EditParams;
1900
- fill(source: Region[], target: Region[]): EditParams;
1901
- transform(target: Region[], transform: TransformParams): EditParams;
1902
- deleteRows(rowRanges: [TRowId, TRowId][]): EditParams;
1903
- restoreRows(rowRanges: [TRowId, TRowId][]): EditParams;
1904
- deleteAllRows(): EditParams;
1905
- restoreAllRows(): EditParams;
1906
- insertRow(anchorRowId: TRowId | undefined, position: InsertParams["position"], values: unknown[][], columnIds: string[]): EditParams;
1907
- /**
1908
- * Returns null when all columns are selected (caller decides representation).
1909
- * Otherwise returns contiguous column spans as `{ fromColumn, toColumn }` regions.
1910
- */
1911
- private collapseColumns;
1912
- private viewContext;
1913
- }
1914
-
1915
1248
  /**
1916
1249
  * DirtyTracker — Change classification and revert detection for rows.
1917
1250
  *
@@ -1998,7 +1331,6 @@ type IFilterEngine<TRow extends DataEditorRow = DataEditorRow> = {
1998
1331
  getWordsPerRow(): number;
1999
1332
  getShowOnlyDeletedRows(): boolean;
2000
1333
  getSortState(): SortState;
2001
- setReaders(rowReader: FilterRowReader<TRow>, flagReader: FlagReader): void;
2002
1334
  setColumns(columns: DataEditorColumn[]): void;
2003
1335
  setFilters(filters: Partial<Filters>): void;
2004
1336
  setSortState(state: SortState, sortType?: SortType, locales?: string[]): Promise<void>;
@@ -2130,12 +1462,6 @@ interface SnapshotStateReader {
2130
1462
  getSortState(): SortState;
2131
1463
  getShowOnlyDeletedRows(): boolean;
2132
1464
  getPendingValidationCount(): number;
2133
- /** Server-provided aggregate counts. Present only in server mode. */
2134
- getServerEditedCount?(): number;
2135
- getServerNewCount?(): number;
2136
- getServerErrorCount?(): number;
2137
- getServerEmptyCount?(): number;
2138
- getServerDeletedCount?(): number;
2139
1465
  }
2140
1466
  declare class SnapshotManager {
2141
1467
  private _visibleNewCount;
@@ -2181,6 +1507,81 @@ declare class SnapshotManager {
2181
1507
  private recomputeFilteredCounts;
2182
1508
  }
2183
1509
 
1510
+ type RegisterSourceOptions = {
1511
+ name: string;
1512
+ id?: DataSourceId;
1513
+ isDeletable?: boolean;
1514
+ isInitialData?: boolean;
1515
+ };
1516
+ type MergeEntry<TRow> = {
1517
+ row: TRow;
1518
+ sourceId: DataSourceId;
1519
+ isNew: boolean;
1520
+ isEdited: boolean;
1521
+ /** Diff basis the row carried before the merge. Present only when isEdited. */
1522
+ originalRow?: TRow;
1523
+ };
1524
+ type RemovalPlan<TRow> = {
1525
+ rowsToDelete: Set<TRowId>;
1526
+ rowsToRestore: Array<{
1527
+ rowId: TRowId;
1528
+ row: TRow;
1529
+ originalSourceId: DataSourceId;
1530
+ isNew: boolean;
1531
+ isEdited: boolean;
1532
+ originalRow?: TRow;
1533
+ }>;
1534
+ };
1535
+ type ExtendedRemovalPlan<TRow> = RemovalPlan<TRow> & {
1536
+ sourceId: DataSourceId;
1537
+ repairedEntries: Array<{
1538
+ sourceId: DataSourceId;
1539
+ rowId: TRowId;
1540
+ before: MergeEntry<TRow>;
1541
+ after: MergeEntry<TRow> | null;
1542
+ }>;
1543
+ };
1544
+ declare class SourceManager<TRow extends DataEditorRow = DataEditorRow> {
1545
+ private readonly _defaultSourceId;
1546
+ private readonly overrides;
1547
+ private readonly sources;
1548
+ private readonly mergedRows;
1549
+ getSourceId(rowId: TRowId): DataSourceId;
1550
+ setSourceId(rowId: TRowId, sourceId: DataSourceId): void;
1551
+ deleteSourceId(rowId: TRowId): void;
1552
+ getOverrides(): ReadonlyMap<TRowId, DataSourceId>;
1553
+ register(options: RegisterSourceOptions): DataSourceId;
1554
+ /**
1555
+ * Re-insert a source using a full captured state, preserving
1556
+ * isVisible, isLoading, rowCount, etc. Used by SourceLifecycle.restore.
1557
+ * If the source already exists, overwrites its state.
1558
+ */
1559
+ restoreState(state: DataSourceState): void;
1560
+ has(sourceId: DataSourceId): boolean;
1561
+ get(sourceId: DataSourceId): DataSourceState | undefined;
1562
+ delete(sourceId: DataSourceId): void;
1563
+ setLoading(sourceId: DataSourceId, isLoading: boolean): void;
1564
+ finalizeAllSources(): void;
1565
+ values(): IterableIterator<DataSourceState>;
1566
+ getHiddenSourceIds(): Set<DataSourceId>;
1567
+ saveMergeSnapshot(sourceId: DataSourceId, rowId: TRowId, existingRow: TRow, previousSourceId: DataSourceId, isNew: boolean, isEdited: boolean, originalRow?: TRow): void;
1568
+ /**
1569
+ * Public so commands can re-install merge entries during undo of a remove.
1570
+ */
1571
+ restoreMergeEntry(sourceId: DataSourceId, rowId: TRowId, entry: MergeEntry<TRow>): void;
1572
+ /**
1573
+ * Pure — computes the full removal plan without mutating any state.
1574
+ * Callers run applyRemovalPlan(plan) to commit.
1575
+ */
1576
+ planRemoval(sourceId: DataSourceId): ExtendedRemovalPlan<TRow> | null;
1577
+ /**
1578
+ * Mutates internal state per plan produced by planRemoval.
1579
+ */
1580
+ applyRemovalPlan(plan: ExtendedRemovalPlan<TRow>): void;
1581
+ clear(): void;
1582
+ private getUniqueName;
1583
+ }
1584
+
2184
1585
  /**
2185
1586
  * ValidationStore — Cell-level validation state with incremental count tracking.
2186
1587
  *
@@ -2227,6 +1628,26 @@ type IValidationStore = {
2227
1628
  clear(): void;
2228
1629
  };
2229
1630
 
1631
+ type IValueIndex<TRow extends DataEditorRow = DataEditorRow> = {
1632
+ setTrackedFields(fields: Set<string>): void;
1633
+ addRow(row: TRow): void;
1634
+ removeRow(row: TRow): void;
1635
+ updateField(field: string, oldValue: unknown, newValue: unknown): void;
1636
+ rebuild(rows: Iterable<TRow>): void;
1637
+ getValues(field: string): ReadonlyMap<string, number>;
1638
+ getVersion(): number;
1639
+ isTracked(field: string): boolean;
1640
+ getMinMax(field: string): {
1641
+ min: number;
1642
+ max: number;
1643
+ } | null;
1644
+ getDateMinMax(field: string): {
1645
+ min: string;
1646
+ max: string;
1647
+ } | null;
1648
+ bumpVersion(): void;
1649
+ };
1650
+
2230
1651
  /**
2231
1652
  * AsyncValidationScheduler — facade over the async annotation channel.
2232
1653
  *
@@ -2275,26 +1696,6 @@ type IValidator<TRow extends DataEditorRow = DataEditorRow> = {
2275
1696
  destroy(): void;
2276
1697
  };
2277
1698
 
2278
- type IValueIndex<TRow extends DataEditorRow = DataEditorRow> = {
2279
- setTrackedFields(fields: Set<string>): void;
2280
- addRow(row: TRow): void;
2281
- removeRow(row: TRow): void;
2282
- updateField(field: string, oldValue: unknown, newValue: unknown): void;
2283
- rebuild(rows: Iterable<TRow>): void;
2284
- getValues(field: string): ReadonlyMap<string, number>;
2285
- getVersion(): number;
2286
- isTracked(field: string): boolean;
2287
- getMinMax(field: string): {
2288
- min: number;
2289
- max: number;
2290
- } | null;
2291
- getDateMinMax(field: string): {
2292
- min: string;
2293
- max: string;
2294
- } | null;
2295
- bumpVersion(): void;
2296
- };
2297
-
2298
1699
  type RowEntry<TRow extends DataEditorRow> = {
2299
1700
  rowId: TRowId;
2300
1701
  row: TRow;
@@ -2316,10 +1717,9 @@ type SourceSnapshot<TRow extends DataEditorRow> = {
2316
1717
  plan: ExtendedRemovalPlan<TRow>;
2317
1718
  };
2318
1719
  type SourceLifecycleHost<TRow extends DataEditorRow> = {
2319
- getValidator: () => IValidator<TRow> | null;
1720
+ getValidator: () => IValidator<TRow>;
2320
1721
  pushCommand: (cmd: Command<TRow>, cost?: number) => number;
2321
1722
  notify: () => void;
2322
- isServerStrategy: () => boolean;
2323
1723
  checkRowEmptyCells: (rowId: TRowId) => void;
2324
1724
  clearRowValidations: (rowId: TRowId) => void;
2325
1725
  };
@@ -2350,28 +1750,19 @@ declare class SourceLifecycle<TRow extends DataEditorRow = DataEditorRow> {
2350
1750
  }
2351
1751
 
2352
1752
  /**
2353
- * Fill-level delta computations.
2354
- *
2355
- * Pure functions that compute ColumnDelta[] for fill handle operations.
2356
- * Zero side effects — take a spec + row reader, return deltas.
2357
- *
2358
- * buildFillSpec() — reads source values once, builds tiling index
2359
- * computeFillDeltas() — processes a chunk of target rows against the spec
2360
- *
2361
- * Fill uses a tiling pattern: source values repeat cyclically.
2362
- * For row r in fill range: srcRow = r % sourceHeight.
2363
- * For col c in fill range: srcCol = c % sourceWidth.
1753
+ * A post-resolution selection rectangle in stable coordinate space.
1754
+ * Produced by grid-layer resolvers from CellRange[] in grid-index space.
1755
+ * Consumed by DataStore operations and server sync.
2364
1756
  */
1757
+ type SelectionRect = {
1758
+ readonly fields: readonly string[];
1759
+ readonly rowIds: readonly TRowId[];
1760
+ };
2365
1761
 
2366
- type FillSpec = {
2367
- /** 2D source grid: sourceValues[row][col]. Read once — source region is always small. */
2368
- sourceValues: unknown[][];
2369
- sourceHeight: number;
2370
- sourceWidth: number;
2371
- /** Column IDs for the fill target columns. */
2372
- fields: string[];
2373
- /** Target rowId → position within the fill range, for tiling modulo. */
2374
- rowIdToFillIndex: ReadonlyMap<TRowId, number>;
1762
+ type MultiSelectEditorConfig = {
1763
+ options: string[];
1764
+ delimiter?: string;
1765
+ enableCustomValue?: boolean;
2375
1766
  };
2376
1767
 
2377
1768
  /**
@@ -2389,15 +1780,47 @@ type FillSpec = {
2389
1780
  * - Large datasets: orchestrator calls computePasteDeltas() per chunk
2390
1781
  */
2391
1782
 
1783
+ type MultiSelectTarget = {
1784
+ delimiter: string;
1785
+ editor: MultiSelectEditorConfig;
1786
+ };
2392
1787
  type PasteSpec = {
2393
1788
  sourceColumnIds: string[];
2394
1789
  targetColumnIds: string[];
2395
1790
  targetToSource: ReadonlyMap<TRowId, TRowId>;
2396
1791
  selectOptionsMap: ReadonlyMap<string, ReadonlySet<string>>;
1792
+ multiSelectTargets: ReadonlyMap<string, MultiSelectTarget>;
2397
1793
  skipColumnIndices: ReadonlySet<number>;
2398
1794
  isCut: boolean;
2399
1795
  };
2400
1796
 
1797
+ /**
1798
+ * Fill-level delta computations.
1799
+ *
1800
+ * Pure functions that compute ColumnDelta[] for fill handle operations.
1801
+ * Zero side effects — take a spec + row reader, return deltas.
1802
+ *
1803
+ * buildFillSpec() — reads source values once, builds tiling index
1804
+ * computeFillDeltas() — processes a chunk of target rows against the spec
1805
+ *
1806
+ * Fill uses a tiling pattern: source values repeat cyclically.
1807
+ * For row r in fill range: srcRow = r % sourceHeight.
1808
+ * For col c in fill range: srcCol = c % sourceWidth.
1809
+ */
1810
+
1811
+ type FillSpec = {
1812
+ /** 2D source grid: sourceValues[row][col]. Read once — source region is always small. */
1813
+ sourceValues: unknown[][];
1814
+ sourceHeight: number;
1815
+ sourceWidth: number;
1816
+ /** Column IDs for the fill target columns. */
1817
+ fields: string[];
1818
+ /** Target rowId → position within the fill range, for tiling modulo. */
1819
+ rowIdToFillIndex: ReadonlyMap<TRowId, number>;
1820
+ /** Multiselect target fields with the delimiter resolved from the source grid. */
1821
+ multiSelectTargets: ReadonlyMap<string, MultiSelectTarget>;
1822
+ };
1823
+
2401
1824
  type ApplyFormulaOptions = {
2402
1825
  /**
2403
1826
  * Column IDs to delete AFTER the formula has been applied.
@@ -2414,9 +1837,6 @@ type UpsertOptions = {
2414
1837
  skipRowValidation?: boolean;
2415
1838
  };
2416
1839
  declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
2417
- private readonly _mode;
2418
- isServer(): boolean;
2419
- isClient(): boolean;
2420
1840
  private rowStore;
2421
1841
  readonly formulaRegistry: FormulaRegistry;
2422
1842
  private _isLoading;
@@ -2430,8 +1850,6 @@ declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
2430
1850
  private history;
2431
1851
  private validator;
2432
1852
  private valueIndex;
2433
- private serverCounts;
2434
- private editBuilder;
2435
1853
  private isUndoRedoing;
2436
1854
  private anchorMapCache;
2437
1855
  private pendingBatchCommands;
@@ -2439,7 +1857,6 @@ declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
2439
1857
  private _skipNotify;
2440
1858
  private _bulkMode;
2441
1859
  private _editedCells;
2442
- private _primaryKeyFields;
2443
1860
  /** Columns that are currently locked (pre-locked from schema + user-locked at runtime). */
2444
1861
  private _lockedColumns;
2445
1862
  /** Columns locked via schema definition — user cannot unlock these. */
@@ -2447,12 +1864,8 @@ declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
2447
1864
  /** Last-known visible row range reported by the canvas scroll handler. */
2448
1865
  private _viewportStart;
2449
1866
  private _viewportEnd;
2450
- private pendingMutations;
2451
- private editParamsHistory;
2452
1867
  readonly errorHandler: ErrorHandler;
2453
- readonly server: ServerDataManager<TRow> | null;
2454
1868
  private readonly strategy;
2455
- private readonly serverStrategy;
2456
1869
  private snapshotReader;
2457
1870
  private flagReader;
2458
1871
  private buildErrorBitmask;
@@ -2467,16 +1880,10 @@ declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
2467
1880
  private filterRowReader;
2468
1881
  private bulkMutationHost;
2469
1882
  private orchestrator;
2470
- constructor(mode?: StoreMode, serverInit?: {
2471
- config: ScaleClientApi<TRow>;
2472
- sourceLabel: string;
2473
- }, errorHandler?: ErrorHandler);
2474
- get mode(): StoreMode;
2475
- getEditBuilder(): ServerEditBuilder<TRow> | null;
1883
+ constructor(errorHandler?: ErrorHandler);
2476
1884
  getRowId(index: number): TRowId | undefined;
2477
1885
  getLocalRowCount(): number;
2478
1886
  setValidator(validator: IValidator<TRow>): void;
2479
- setPrimaryKey(key: PrimaryKeyInput): void;
2480
1887
  isColumnLocked(field: string): boolean;
2481
1888
  isColumnPreLocked(field: string): boolean;
2482
1889
  lockColumn(field: string, mode?: ColumnLockMode): void;
@@ -2558,35 +1965,19 @@ declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
2558
1965
  * Flag rows as deleted. Pushes a command for undo/redo.
2559
1966
  * Rows stay in all stores — they are just excluded from alive-mode filters.
2560
1967
  */
2561
- deleteRows(rowIds: TRowId[], rowRanges?: [TRowId, TRowId][]): Promise<void>;
1968
+ deleteRows(rowIds: TRowId[]): Promise<void>;
2562
1969
  /**
2563
- * Delete all visible rows at once. In server mode sends { allSelected: true }
2564
- * instead of enumerating every row. Locally marks all loaded rows as deleted
2565
- * and clears the RowStore display list.
1970
+ * Delete all visible rows at once. Marks all loaded rows as deleted.
2566
1971
  */
2567
1972
  deleteAllRows(): Promise<void>;
2568
- /**
2569
- * Optimistic bulk delete for server mode. Marks all locally loaded rows
2570
- * as deleted, clears the RowStore, and adjusts counts.
2571
- */
2572
- private deleteAllServer;
2573
1973
  /**
2574
1974
  * Unflag rows (restore from deletion). Pushes a command for undo/redo.
2575
1975
  */
2576
- restoreRows(rowIds: TRowId[], rowRanges?: [TRowId, TRowId][]): Promise<void>;
1976
+ restoreRows(rowIds: TRowId[]): Promise<void>;
2577
1977
  /**
2578
- * Restore all deleted rows at once. In server mode sends { allSelected: true }
2579
- * instead of enumerating every row. Locally clears all deleted flags and
2580
- * empties the RowStore display list (bin view becomes empty).
1978
+ * Restore all deleted rows at once. Clears every deleted flag.
2581
1979
  */
2582
1980
  restoreAllRows(): Promise<void>;
2583
- /**
2584
- * Optimistic bulk restore for server mode. Clears all locally known deleted
2585
- * flags and empties the RowStore display list (we are in deleted-only view,
2586
- * so every visible row is being restored out). Server-provided counts will
2587
- * be authoritative after the sync response arrives.
2588
- */
2589
- private restoreAllDeletedServer;
2590
1981
  /**
2591
1982
  * Apply delete flags directly without cost-gating. Called by commands
2592
1983
  * (DeleteRowCommand.redo/undo, restore inline commands) where runHeavy
@@ -2601,17 +1992,6 @@ declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
2601
1992
  getRealRowPosition(rowId: TRowId): number;
2602
1993
  insertRow(sourceId: DataSourceId, row: TRow, position: number): Promise<TRowId>;
2603
1994
  insertRowDirect(rowId: TRowId, row: TRow, sourceId: DataSourceId, position: number): void;
2604
- /**
2605
- * Ingest a single ServerRow at a specific local position.
2606
- * Used after the server confirms an insert and returns the full row.
2607
- * Source counts come from the server via counts.sources — no local source tracking.
2608
- */
2609
- insertServerRow(serverRow: ServerRow<TRow>, position: number): TRowId;
2610
- /**
2611
- * Server-mode insert: send insert request to server, wait for response,
2612
- * then ingest the returned row locally. Non-optimistic.
2613
- */
2614
- insertRowServer(row: TRow, localPosition: number, anchorRowId: TRowId | undefined, insertPosition: "above" | "below", columnIds: string[]): Promise<TRowId>;
2615
1995
  appendRows(sourceId: DataSourceId, newRows: TRow[], rowIdMap?: Map<number, TRowId>): TRowId[];
2616
1996
  seedInitialChanges(assignedRowIds: TRowId[], currentRows: TRow[], changes: InitialRowChange<TRow>[]): void;
2617
1997
  upsertRows(sourceId: DataSourceId, newRows: TRow[], options?: UpsertOptions): UpsertResult<TRow>;
@@ -2627,7 +2007,8 @@ declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
2627
2007
  * Called by the orchestrator after all chunks complete, before validation.
2628
2008
  * Deferred per-row work from updateColumnDirect is flushed here in bulk:
2629
2009
  * - rowTextCache cleared once instead of per-row
2630
- * - checkRevert run for each affected row
2010
+ * - checkRevert and checkRowEmptyCells run for each affected row
2011
+ * - the filter worker gets every affected row's text in one batch
2631
2012
  * - _editedCells populated for FindReplace incremental matching
2632
2013
  */
2633
2014
  flushBulkMode(deltas: ColumnDelta[]): void;
@@ -2640,30 +2021,12 @@ declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
2640
2021
  */
2641
2022
  getViewportRowIds(): TRowId[];
2642
2023
  getAllFilteredRowIds(): TRowId[];
2643
- replaceServerRows(sourceId: DataSourceId, serverRows: ServerRow<TRow>[], offset: number, counts?: ServerQueryCounts): void;
2644
- appendServerRows(serverRows: ServerRow<TRow>[], counts?: ServerQueryCounts): void;
2645
- prependServerRows(serverRows: ServerRow<TRow>[], newOffset: number, counts?: ServerQueryCounts): void;
2646
- /**
2647
- * Seeds DirtyTracker from server-provided row metadata.
2648
- * For rows with `meta.status.edited`, builds a synthetic original row
2649
- * from `meta.changes` so that `isCellDirty()` and `getOriginalCellValue()`
2650
- * work through the existing DirtyTracker comparison logic.
2651
- */
2652
- private hydrateServerMeta;
2653
- private hydrateRowMeta;
2654
- applyServerRowMeta(serverRows: ServerRow<TRow>[], counts?: ServerQueryCounts): void;
2655
2024
  clear(): void;
2656
2025
  destroy(): void;
2657
2026
  setFilters(filters: Partial<Filters>): void;
2658
2027
  getFilters(): Filters;
2659
2028
  setSort(sortState: SortState, sortType?: SortType, locales?: string[]): Promise<void>;
2660
- handleServerScroll(visibleStart: number, visibleEnd: number): void;
2661
- reloadServerData(): void;
2662
2029
  resetFilters(): void;
2663
- fetchFilterOptions(): void;
2664
- getFilterOptions(): FilterOptionsResponse | null;
2665
- get hasServerExport(): boolean;
2666
- serverExport(format: DataEditorFormat, allRows: boolean, rtl: boolean): Promise<void>;
2667
2030
  syncWorkerFlags(): void;
2668
2031
  setCellValidation(rowId: TRowId, field: string, result: ValidationResult): void;
2669
2032
  getCellValidation(rowId: TRowId, field: string): ValidationResult;
@@ -2694,14 +2057,6 @@ declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
2694
2057
  undo(): Promise<UndoRedoResult>;
2695
2058
  private _undoSync;
2696
2059
  pushCommand(cmd: Command<TRow>, cost?: number): number;
2697
- removeCommandById(id: number): void;
2698
- /**
2699
- * Delegate to ServerStrategy. Called by ActionsDispatcher and ClipboardManager
2700
- * for non-cell edits (clear, paste, fill, transform).
2701
- */
2702
- syncServerEdit(params: EditParams, cmdId: number, revertFn: () => void): void;
2703
- fireServerEditParams(params: EditParams): void;
2704
- syncColumnEdit(params: ColumnEditParams, cmdId: number, revertFn: () => void): void;
2705
2060
  redo(): Promise<UndoRedoResult>;
2706
2061
  private _redoSync;
2707
2062
  getOriginalCellValue(rowId: TRowId, field: string): unknown | undefined;
@@ -2732,7 +2087,6 @@ declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
2732
2087
  private _runFormulaOperation;
2733
2088
  private captureDeleteColumnSnapshots;
2734
2089
  private applyDeleteColumnSnapshots;
2735
- private syncFormulaToServer;
2736
2090
  private transformWorker;
2737
2091
  private initTransformWorker;
2738
2092
  private buildChatOpsCommand;
@@ -2744,21 +2098,17 @@ declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
2744
2098
  private _applyChatOpsSync;
2745
2099
  private _commitChatOps;
2746
2100
  applyChatRows(incomingRows: Record<string, unknown>[], primaryKey: PrimaryKeyInput): Promise<void>;
2747
- private syncChatTransformToServer;
2748
2101
  private get revertRowReader();
2749
2102
  revertColumns(fields: string[]): Promise<void>;
2750
2103
  revertRange(rects: SelectionRect[]): Promise<void>;
2751
2104
  private _revertInternal;
2752
2105
  private _buildRevertCommand;
2753
- private syncRevertToServer;
2754
2106
  clearColumn(field: string): Promise<void>;
2755
2107
  clearColumns(fields: string[]): Promise<void>;
2756
- private syncClearToServer;
2757
2108
  purgeField(columnId: string, rowIds?: TRowId[]): void;
2758
2109
  deleteColumn(columnId: string): Promise<void>;
2759
2110
  deleteColumns(columnIds: readonly string[]): Promise<void>;
2760
2111
  clearRange(rects: SelectionRect[]): Promise<void>;
2761
- private syncRangeClearToServer;
2762
2112
  pasteChunked(spec: PasteSpec, targetRowIds: TRowId[], targetCell: {
2763
2113
  rowId: TRowId;
2764
2114
  field: string;
@@ -2798,7 +2148,7 @@ declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
2798
2148
  * Each command knows how to apply and revert its changes.
2799
2149
  */
2800
2150
  interface Command<TRow extends DataEditorRow = DataEditorRow> {
2801
- /** Assigned by CommandHistory.push(). Used by removeById() to target specific commands. */
2151
+ /** Assigned by CommandHistory.push() and handed back as its return value. */
2802
2152
  id?: number;
2803
2153
  redo(store: DataStore<TRow>, validator: IValidator<TRow>): void;
2804
2154
  undo(store: DataStore<TRow>, validator: IValidator<TRow>): void;
@@ -2827,10 +2177,6 @@ type ColumnDelta = {
2827
2177
  newValues: Map<TRowId, unknown>;
2828
2178
  };
2829
2179
 
2830
- type ScaleServerConfig = {
2831
- url: string;
2832
- };
2833
-
2834
2180
  /** Numeric row identifier. V8 stores small integers (Smi) inline — no heap allocation. */
2835
2181
  type TRowId = number;
2836
2182
  type SortType = "text" | "number" | "date";
@@ -3125,10 +2471,24 @@ type CustomImportFormat = {
3125
2471
  * Returns rows, named tables, or a `File` in a format the SDK already reads.
3126
2472
  * Throw to fail the import; the thrown message is shown to the user.
3127
2473
  */
3128
- handle: (file: File, ctx: {
3129
- signal: AbortSignal;
3130
- }) => Promise<File | Record<string, unknown>[] | CustomImportTable[]>;
2474
+ handle: FileHandler;
3131
2475
  };
2476
+ /**
2477
+ * What client code may hand back for a file the SDK will not read itself: rows,
2478
+ * named tables, or a `File` in a format the SDK already reads.
2479
+ */
2480
+ type FileHandlerResult = File | Record<string, unknown>[] | CustomImportTable[];
2481
+ /** Claims a file by extension and turns it into tables the SDK can stage. */
2482
+ type FileHandler = (file: File, ctx: {
2483
+ signal: AbortSignal;
2484
+ }) => Promise<FileHandlerResult>;
2485
+ /**
2486
+ * Takes over a readable file that holds no single table. `null` declines the
2487
+ * file, leaving it to be staged the ordinary way.
2488
+ */
2489
+ type UnstructuredFileHandler = (file: File, ctx: {
2490
+ signal: AbortSignal;
2491
+ }) => Promise<FileHandlerResult | null>;
3132
2492
  /**
3133
2493
  * Controls the initial view when the editor opens.
3134
2494
  *
@@ -3249,6 +2609,17 @@ type DataEditorBaseProps<TRow extends DataEditorRow = DataEditorRow> = {
3249
2609
  * the file and stages whatever `handle()` returns.
3250
2610
  */
3251
2611
  customFormats?: CustomImportFormat[];
2612
+ /**
2613
+ * Called when a file the SDK can read turns out to hold no single table —
2614
+ * a report with a banner, several tables on one sheet, a sheet that is really
2615
+ * a document. You get the `File` and return tables, exactly as a
2616
+ * `customFormats` handler does.
2617
+ *
2618
+ * Return `null`, throw, or take longer than 30 seconds and the file is staged
2619
+ * the ordinary way, as if this prop were absent. Nothing about the file
2620
+ * reaches Updog.
2621
+ */
2622
+ onUnstructuredFile?: UnstructuredFileHandler;
3252
2623
  /**
3253
2624
  * Which file formats the user can export to. `undefined` allows all
3254
2625
  * formats, `false` disables export entirely.
@@ -3359,11 +2730,6 @@ type DataEditorMode = "modal" | "inline";
3359
2730
  type DataEditorCommonProps<TRow extends DataEditorRow = DataEditorRow> = DataEditorBaseProps<TRow> & {
3360
2731
  /** Your Updog license key. Validated on each open. */
3361
2732
  apiKey: string;
3362
- /**
3363
- * @internal
3364
- * Reserved for future server-delegated mode. Not part of the public API.
3365
- */
3366
- __server?: ScaleServerConfig;
3367
2733
  /**
3368
2734
  * Controls what the editor stores in `localStorage`. Set to `false` to
3369
2735
  * disable all local storage usage.
@@ -3491,7 +2857,7 @@ declare function exportDataEditor<TRow extends DataEditorRow>(params: ExportPara
3491
2857
  * />
3492
2858
  * ```
3493
2859
  */
3494
- declare function DataEditor<TRow extends DataEditorRow = DataEditorRow>(allProps: DataEditorProps<TRow>): react_jsx_runtime.JSX.Element;
2860
+ declare function DataEditor<TRow extends DataEditorRow = DataEditorRow>(allProps: DataEditorProps<TRow>): react.JSX.Element;
3495
2861
 
3496
2862
  export { DataEditor, downloadExampleFile, exportDataEditor };
3497
2863
  export type { CellValidator, ChatContext, ChatErrorSummary, ChatResponseChunk, ChatRow, ChatRowStatus, ChunkSourceOptions, CustomImportFormat, CustomImportTable, DataEditorChat, DataEditorColumn, DataEditorFormat, DataEditorInlineProps, DataEditorLocalStorage, DataEditorModalProps, DataEditorMode, DataEditorProps, DataEditorResult, DataEditorRow, DataEditorSourceResult, DataEditorTranslations, DataEditorVariant, InitialRowChange, RemoteSource, ResultRow, UpdogError, UpdogErrorCode, ValidationError, ValueMatchInput, ValueMatchOutput };