tinybase 7.3.5 → 8.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/@types/index.d.ts +1 -0
  2. package/@types/middleware/index.d.ts +1064 -0
  3. package/@types/middleware/with-schemas/index.d.ts +1355 -0
  4. package/@types/omni/index.d.ts +1 -0
  5. package/@types/omni/with-schemas/index.d.ts +1 -0
  6. package/@types/store/index.d.ts +0 -1
  7. package/@types/with-schemas/index.d.ts +1 -0
  8. package/agents.md +33 -11
  9. package/checkpoints/index.js +8 -9
  10. package/checkpoints/with-schemas/index.js +8 -9
  11. package/index.js +484 -153
  12. package/mergeable-store/index.js +371 -135
  13. package/mergeable-store/with-schemas/index.js +371 -135
  14. package/middleware/index.js +130 -0
  15. package/middleware/with-schemas/index.js +130 -0
  16. package/min/checkpoints/index.js +1 -1
  17. package/min/checkpoints/index.js.gz +0 -0
  18. package/min/checkpoints/with-schemas/index.js +1 -1
  19. package/min/checkpoints/with-schemas/index.js.gz +0 -0
  20. package/min/index.js +1 -1
  21. package/min/index.js.gz +0 -0
  22. package/min/mergeable-store/index.js +1 -1
  23. package/min/mergeable-store/index.js.gz +0 -0
  24. package/min/mergeable-store/with-schemas/index.js +1 -1
  25. package/min/mergeable-store/with-schemas/index.js.gz +0 -0
  26. package/min/middleware/index.js +1 -0
  27. package/min/middleware/index.js.gz +0 -0
  28. package/min/middleware/with-schemas/index.js +1 -0
  29. package/min/middleware/with-schemas/index.js.gz +0 -0
  30. package/min/omni/index.js +1 -1
  31. package/min/omni/index.js.gz +0 -0
  32. package/min/omni/with-schemas/index.js +1 -1
  33. package/min/omni/with-schemas/index.js.gz +0 -0
  34. package/min/queries/index.js +1 -1
  35. package/min/queries/index.js.gz +0 -0
  36. package/min/queries/with-schemas/index.js +1 -1
  37. package/min/queries/with-schemas/index.js.gz +0 -0
  38. package/min/store/index.js +1 -1
  39. package/min/store/index.js.gz +0 -0
  40. package/min/store/with-schemas/index.js +1 -1
  41. package/min/store/with-schemas/index.js.gz +0 -0
  42. package/min/ui-react-inspector/index.js +1 -1
  43. package/min/ui-react-inspector/index.js.gz +0 -0
  44. package/min/ui-react-inspector/with-schemas/index.js +1 -1
  45. package/min/ui-react-inspector/with-schemas/index.js.gz +0 -0
  46. package/min/with-schemas/index.js +1 -1
  47. package/min/with-schemas/index.js.gz +0 -0
  48. package/omni/index.js +492 -161
  49. package/omni/with-schemas/index.js +492 -161
  50. package/package.json +37 -1
  51. package/queries/index.js +1 -6
  52. package/queries/with-schemas/index.js +1 -6
  53. package/readme.md +14 -14
  54. package/releases.md +41 -41
  55. package/store/index.js +370 -134
  56. package/store/with-schemas/index.js +370 -134
  57. package/ui-react-inspector/index.js +349 -134
  58. package/ui-react-inspector/with-schemas/index.js +349 -134
  59. package/with-schemas/index.js +484 -153
@@ -53,6 +53,7 @@ const slice = (arrayOrString, start, end) => arrayOrString.slice(start, end);
53
53
  const size = (arrayOrString) => arrayOrString.length;
54
54
  const test = (regex, subject) => regex.test(subject);
55
55
  const noop = () => {};
56
+ const structuredClone = GLOBAL.structuredClone;
56
57
  const tryCatch = async (action, then1, then2) => {
57
58
  try {
58
59
  return await action();
@@ -74,12 +75,6 @@ const getCellOrValueType = (cellOrValue) => {
74
75
  };
75
76
  const isCellOrValueOrUndefined = (cellOrValue) =>
76
77
  isUndefined(cellOrValue) || !isUndefined(getCellOrValueType(cellOrValue));
77
- const setOrDelCell = (store, tableId, rowId, cellId, cell) =>
78
- isUndefined(cell)
79
- ? store.delCell(tableId, rowId, cellId, true)
80
- : store.setCell(tableId, rowId, cellId, cell);
81
- const setOrDelValue = (store, valueId, value) =>
82
- isUndefined(value) ? store.delValue(valueId) : store.setValue(valueId, value);
83
78
 
84
79
  const arrayHas = (array, value) => array.includes(value);
85
80
  const arrayEvery = (array, cb) => array.every(cb);
@@ -137,6 +132,26 @@ const objMap = (obj, cb) =>
137
132
  objNew(objToArray(obj, (value, id) => [id, cb(value, id)]));
138
133
  const objSize = (obj) => size(objIds(obj));
139
134
  const objIsEmpty = (obj) => isObject(obj) && objSize(obj) == 0;
135
+
136
+ /* istanbul ignore next */
137
+ const objIsEqual = (
138
+ obj1,
139
+ obj2,
140
+ isEqual = (value1, value2) => value1 === value2,
141
+ ) => {
142
+ const entries1 = objEntries(obj1);
143
+ return (
144
+ size(entries1) === objSize(obj2) &&
145
+ arrayEvery(entries1, ([index, value1]) =>
146
+ isObject(value1)
147
+ ? /* istanbul ignore next */
148
+ isObject(obj2[index])
149
+ ? objIsEqual(obj2[index], value1)
150
+ : false
151
+ : isEqual(value1, obj2[index]),
152
+ )
153
+ );
154
+ };
140
155
  const objEnsure = (obj, id, getDefaultValue) => {
141
156
  if (!objHas(obj, id)) {
142
157
  obj[id] = getDefaultValue();
@@ -504,12 +519,15 @@ const idsChanged = (changedIds, id2, addedOrRemoved) =>
504
519
  id2,
505
520
  mapGet(changedIds, id2) == -addedOrRemoved ? void 0 : addedOrRemoved,
506
521
  );
522
+ const contentOrChangesIsEqual = ([tables1, values1], [tables2, values2]) =>
523
+ objIsEqual(tables1, tables2) && objIsEqual(values1, values2);
507
524
  const createStore = () => {
508
525
  let hasTablesSchema;
509
526
  let hasValuesSchema;
510
527
  let hadTables = false;
511
528
  let hadValues = false;
512
529
  let transactions = 0;
530
+ let middleware = [];
513
531
  let internalListeners = [];
514
532
  let mutating = 0;
515
533
  const changedTableIds = mapNew();
@@ -557,6 +575,19 @@ const createStore = () => {
557
575
  const finishTransactionListeners = pairNewMap();
558
576
  const [addListener, callListeners, delListenerImpl, callListenerImpl] =
559
577
  getListenerFunctions(() => store);
578
+ const whileMutating = (action) => {
579
+ const wasMutating = mutating;
580
+ mutating = 1;
581
+ const result = action();
582
+ mutating = wasMutating;
583
+ return result;
584
+ };
585
+ const ifTransformed = (snapshot, getResult, then, isEqual = Object.is) =>
586
+ ifNotUndefined(getResult(), (result) =>
587
+ snapshot === result || isEqual(snapshot, result)
588
+ ? then(result)
589
+ : whileMutating(() => then(result)),
590
+ );
560
591
  const validateTablesSchema = (tableSchema) =>
561
592
  objValidate(tableSchema, (tableSchema2) =>
562
593
  objValidate(tableSchema2, validateCellOrValueSchema),
@@ -744,82 +775,194 @@ const createStore = () => {
744
775
  );
745
776
  const setOrDelTables = (tables) =>
746
777
  objIsEmpty(tables) ? delTables() : setTables(tables);
747
- const setValidContent = ([tables, values]) => {
748
- (objIsEmpty(tables) ? delTables : setTables)(tables);
749
- (objIsEmpty(values) ? delValues : setValues)(values);
750
- };
751
- const setValidTables = (tables) =>
752
- mapMatch(
753
- tablesMap,
778
+ const setOrDelCell = (tableId, rowId, cellId, cell, skipMiddleware) =>
779
+ isUndefined(cell)
780
+ ? delCell(tableId, rowId, cellId, true, skipMiddleware)
781
+ : setCell(tableId, rowId, cellId, cell, skipMiddleware);
782
+ const setOrDelValues = (values) =>
783
+ objIsEmpty(values) ? delValues() : setValues(values);
784
+ const setOrDelValue = (valueId, value, skipMiddleware) =>
785
+ isUndefined(value)
786
+ ? delValue(valueId, skipMiddleware)
787
+ : setValue(valueId, value, skipMiddleware);
788
+ const setValidContent = (content) =>
789
+ ifTransformed(
790
+ content,
791
+ () =>
792
+ ifNotUndefined(
793
+ middleware[0],
794
+ (willSetContent) =>
795
+ whileMutating(() => willSetContent(structuredClone(content))),
796
+ () => content,
797
+ ),
798
+ ([tables, values]) => {
799
+ (objIsEmpty(tables) ? delTables : setTables)(tables);
800
+ (objIsEmpty(values) ? delValues : setValues)(values);
801
+ },
802
+ contentOrChangesIsEqual,
803
+ );
804
+ const setValidTables = (tables, forceDel) =>
805
+ ifTransformed(
754
806
  tables,
755
- (_tables, tableId, table) => setValidTable(tableId, table),
756
- (_tables, tableId) => delValidTable(tableId),
807
+ () =>
808
+ forceDel
809
+ ? tables
810
+ : ifNotUndefined(
811
+ middleware[1],
812
+ (willSetTables) =>
813
+ whileMutating(() => willSetTables(structuredClone(tables))),
814
+ () => tables,
815
+ ),
816
+ (validTables) =>
817
+ mapMatch(
818
+ tablesMap,
819
+ validTables,
820
+ (_tables, tableId, table) => setValidTable(tableId, table),
821
+ (_tables, tableId) => delValidTable(tableId),
822
+ ),
823
+ objIsEqual,
757
824
  );
758
- const setValidTable = (tableId, table) =>
759
- mapMatch(
760
- mapEnsure(tablesMap, tableId, () => {
761
- tableIdsChanged(tableId, 1);
762
- mapSet(tablePoolFunctions, tableId, getPoolFunctions());
763
- mapSet(tableCellIds, tableId, mapNew());
764
- return mapNew();
765
- }),
825
+ const setValidTable = (tableId, table, forceDel) =>
826
+ ifTransformed(
766
827
  table,
767
- (tableMap, rowId, row) => setValidRow(tableId, tableMap, rowId, row),
768
- (tableMap, rowId) => delValidRow(tableId, tableMap, rowId),
828
+ () =>
829
+ forceDel
830
+ ? table
831
+ : ifNotUndefined(
832
+ middleware[2],
833
+ (willSetTable) =>
834
+ whileMutating(() =>
835
+ willSetTable(tableId, structuredClone(table)),
836
+ ),
837
+ () => table,
838
+ ),
839
+ (validTable) =>
840
+ mapMatch(
841
+ mapEnsure(tablesMap, tableId, () => {
842
+ tableIdsChanged(tableId, 1);
843
+ mapSet(tablePoolFunctions, tableId, getPoolFunctions());
844
+ mapSet(tableCellIds, tableId, mapNew());
845
+ return mapNew();
846
+ }),
847
+ validTable,
848
+ (tableMap, rowId, row) => setValidRow(tableId, tableMap, rowId, row),
849
+ (tableMap, rowId) => delValidRow(tableId, tableMap, rowId),
850
+ ),
851
+ objIsEqual,
769
852
  );
770
853
  const setValidRow = (tableId, tableMap, rowId, row, forceDel) =>
771
- mapMatch(
772
- mapEnsure(tableMap, rowId, () => {
773
- rowIdsChanged(tableId, rowId, 1);
774
- return mapNew();
775
- }),
854
+ ifTransformed(
776
855
  row,
777
- (rowMap, cellId, cell) =>
778
- setValidCell(tableId, rowId, rowMap, cellId, cell),
779
- (rowMap, cellId) =>
780
- delValidCell(tableId, tableMap, rowId, rowMap, cellId, forceDel),
856
+ () =>
857
+ forceDel
858
+ ? row
859
+ : ifNotUndefined(
860
+ middleware[3],
861
+ (willSetRow) =>
862
+ whileMutating(() =>
863
+ willSetRow(tableId, rowId, structuredClone(row)),
864
+ ),
865
+ () => row,
866
+ ),
867
+ (validRow) =>
868
+ mapMatch(
869
+ mapEnsure(tableMap, rowId, () => {
870
+ rowIdsChanged(tableId, rowId, 1);
871
+ return mapNew();
872
+ }),
873
+ validRow,
874
+ (rowMap, cellId, cell) =>
875
+ setValidCell(tableId, rowId, rowMap, cellId, cell),
876
+ (rowMap, cellId) =>
877
+ delValidCell(tableId, tableMap, rowId, rowMap, cellId, forceDel),
878
+ ),
879
+ objIsEqual,
781
880
  );
782
- const setValidCell = (tableId, rowId, rowMap, cellId, cell) => {
783
- if (!collHas(rowMap, cellId)) {
784
- cellIdsChanged(tableId, rowId, cellId, 1);
785
- }
786
- const oldCell = mapGet(rowMap, cellId);
787
- if (cell !== oldCell) {
788
- cellChanged(tableId, rowId, cellId, oldCell, cell);
789
- mapSet(rowMap, cellId, cell);
790
- }
791
- };
792
- const setCellIntoDefaultRow = (tableId, tableMap, rowId, cellId, validCell) =>
881
+ const setValidCell = (tableId, rowId, rowMap, cellId, cell, skipMiddleware) =>
882
+ ifTransformed(
883
+ cell,
884
+ () =>
885
+ ifNotUndefined(
886
+ skipMiddleware ? void 0 : middleware[4],
887
+ (willSetCell) =>
888
+ whileMutating(() => willSetCell(tableId, rowId, cellId, cell)),
889
+ () => cell,
890
+ ),
891
+ (cell2) => {
892
+ if (!collHas(rowMap, cellId)) {
893
+ cellIdsChanged(tableId, rowId, cellId, 1);
894
+ }
895
+ const oldCell = mapGet(rowMap, cellId);
896
+ if (cell2 !== oldCell) {
897
+ cellChanged(tableId, rowId, cellId, oldCell, cell2);
898
+ mapSet(rowMap, cellId, cell2);
899
+ }
900
+ },
901
+ );
902
+ const setCellIntoNewRow = (
903
+ tableId,
904
+ tableMap,
905
+ rowId,
906
+ cellId,
907
+ validCell,
908
+ skipMiddleware,
909
+ ) =>
793
910
  ifNotUndefined(
794
911
  mapGet(tableMap, rowId),
795
- (rowMap) => setValidCell(tableId, rowId, rowMap, cellId, validCell),
796
- () =>
797
- setValidRow(
798
- tableId,
799
- tableMap,
800
- rowId,
912
+ (rowMap) =>
913
+ setValidCell(tableId, rowId, rowMap, cellId, validCell, skipMiddleware),
914
+ () => {
915
+ const rowMap = mapNew();
916
+ mapSet(tableMap, rowId, rowMap);
917
+ rowIdsChanged(tableId, rowId, 1);
918
+ objMap(
801
919
  addDefaultsToRow({[cellId]: validCell}, tableId, rowId),
802
- ),
920
+ (cell, cellId2) =>
921
+ setValidCell(tableId, rowId, rowMap, cellId2, cell, skipMiddleware),
922
+ );
923
+ },
803
924
  );
804
- const setOrDelValues = (values) =>
805
- objIsEmpty(values) ? delValues() : setValues(values);
806
- const setValidValues = (values) =>
807
- mapMatch(
808
- valuesMap,
925
+ const setValidValues = (values, forceDel) =>
926
+ ifTransformed(
809
927
  values,
810
- (_valuesMap, valueId, value) => setValidValue(valueId, value),
811
- (_valuesMap, valueId) => delValidValue(valueId),
928
+ () =>
929
+ forceDel
930
+ ? values
931
+ : ifNotUndefined(
932
+ middleware[5],
933
+ (willSetValues) =>
934
+ whileMutating(() => willSetValues(structuredClone(values))),
935
+ () => values,
936
+ ),
937
+ (validValues) =>
938
+ mapMatch(
939
+ valuesMap,
940
+ validValues,
941
+ (_valuesMap, valueId, value) => setValidValue(valueId, value),
942
+ (_valuesMap, valueId) => delValidValue(valueId),
943
+ ),
944
+ objIsEqual,
945
+ );
946
+ const setValidValue = (valueId, value, skipMiddleware) =>
947
+ ifTransformed(
948
+ value,
949
+ () =>
950
+ ifNotUndefined(
951
+ skipMiddleware ? void 0 : middleware[6],
952
+ (willSetValue) => whileMutating(() => willSetValue(valueId, value)),
953
+ () => value,
954
+ ),
955
+ (value2) => {
956
+ if (!collHas(valuesMap, valueId)) {
957
+ valueIdsChanged(valueId, 1);
958
+ }
959
+ const oldValue = mapGet(valuesMap, valueId);
960
+ if (value2 !== oldValue) {
961
+ valueChanged(valueId, oldValue, value2);
962
+ mapSet(valuesMap, valueId, value2);
963
+ }
964
+ },
812
965
  );
813
- const setValidValue = (valueId, value) => {
814
- if (!collHas(valuesMap, valueId)) {
815
- valueIdsChanged(valueId, 1);
816
- }
817
- const oldValue = mapGet(valuesMap, valueId);
818
- if (value !== oldValue) {
819
- valueChanged(valueId, oldValue, value);
820
- mapSet(valuesMap, valueId, value);
821
- }
822
- };
823
966
  const getNewRowId = (tableId, reuse) => {
824
967
  const [getId] = mapGet(tablePoolFunctions, tableId);
825
968
  let rowId;
@@ -829,14 +972,34 @@ const createStore = () => {
829
972
  return rowId;
830
973
  };
831
974
  const getOrCreateTable = (tableId) =>
832
- mapGet(tablesMap, tableId) ?? setValidTable(tableId, {});
833
- const delValidTable = (tableId) => setValidTable(tableId, {});
975
+ mapEnsure(tablesMap, tableId, () => {
976
+ tableIdsChanged(tableId, 1);
977
+ mapSet(tablePoolFunctions, tableId, getPoolFunctions());
978
+ mapSet(tableCellIds, tableId, mapNew());
979
+ return mapNew();
980
+ });
981
+ const delValidTable = (tableId) => {
982
+ if (whileMutating(() => middleware[8]?.(tableId)) ?? true) {
983
+ return setValidTable(tableId, {}, true);
984
+ }
985
+ return mapGet(tablesMap, tableId);
986
+ };
834
987
  const delValidRow = (tableId, tableMap, rowId) => {
835
- const [, releaseId] = mapGet(tablePoolFunctions, tableId);
836
- releaseId(rowId);
837
- setValidRow(tableId, tableMap, rowId, {}, true);
988
+ if (whileMutating(() => middleware[9]?.(tableId, rowId)) ?? true) {
989
+ const [, releaseId] = mapGet(tablePoolFunctions, tableId);
990
+ releaseId(rowId);
991
+ setValidRow(tableId, tableMap, rowId, {}, true);
992
+ }
838
993
  };
839
- const delValidCell = (tableId, table, rowId, row, cellId, forceDel) => {
994
+ const delValidCell = (
995
+ tableId,
996
+ table,
997
+ rowId,
998
+ row,
999
+ cellId,
1000
+ forceDel,
1001
+ skipMiddleware,
1002
+ ) => {
840
1003
  const defaultCell = mapGet(
841
1004
  mapGet(tablesSchemaRowCache, tableId)?.[0],
842
1005
  cellId,
@@ -844,34 +1007,44 @@ const createStore = () => {
844
1007
  if (!isUndefined(defaultCell) && !forceDel) {
845
1008
  return setValidCell(tableId, rowId, row, cellId, defaultCell);
846
1009
  }
847
- const delCell2 = (cellId2) => {
848
- cellChanged(tableId, rowId, cellId2, mapGet(row, cellId2));
849
- cellIdsChanged(tableId, rowId, cellId2, -1);
850
- mapSet(row, cellId2);
851
- };
852
- if (isUndefined(defaultCell)) {
853
- delCell2(cellId);
854
- } else {
855
- mapForEach(row, delCell2);
856
- }
857
- if (collIsEmpty(row)) {
858
- rowIdsChanged(tableId, rowId, -1);
859
- if (collIsEmpty(mapSet(table, rowId))) {
860
- tableIdsChanged(tableId, -1);
861
- mapSet(tablesMap, tableId);
862
- mapSet(tablePoolFunctions, tableId);
863
- mapSet(tableCellIds, tableId);
1010
+ if (
1011
+ skipMiddleware ||
1012
+ (whileMutating(() => middleware[10]?.(tableId, rowId, cellId)) ?? true)
1013
+ ) {
1014
+ const delCell2 = (cellId2) => {
1015
+ cellChanged(tableId, rowId, cellId2, mapGet(row, cellId2));
1016
+ cellIdsChanged(tableId, rowId, cellId2, -1);
1017
+ mapSet(row, cellId2);
1018
+ };
1019
+ if (isUndefined(defaultCell)) {
1020
+ delCell2(cellId);
1021
+ } else {
1022
+ mapForEach(row, delCell2);
1023
+ }
1024
+ if (collIsEmpty(row)) {
1025
+ rowIdsChanged(tableId, rowId, -1);
1026
+ if (collIsEmpty(mapSet(table, rowId))) {
1027
+ tableIdsChanged(tableId, -1);
1028
+ mapSet(tablesMap, tableId);
1029
+ mapSet(tablePoolFunctions, tableId);
1030
+ mapSet(tableCellIds, tableId);
1031
+ }
864
1032
  }
865
1033
  }
866
1034
  };
867
- const delValidValue = (valueId) => {
1035
+ const delValidValue = (valueId, skipMiddleware) => {
868
1036
  const defaultValue = mapGet(valuesDefaulted, valueId);
869
1037
  if (!isUndefined(defaultValue)) {
870
1038
  return setValidValue(valueId, defaultValue);
871
1039
  }
872
- valueChanged(valueId, mapGet(valuesMap, valueId));
873
- valueIdsChanged(valueId, -1);
874
- mapSet(valuesMap, valueId);
1040
+ if (
1041
+ skipMiddleware ||
1042
+ (whileMutating(() => middleware[12]?.(valueId)) ?? true)
1043
+ ) {
1044
+ valueChanged(valueId, mapGet(valuesMap, valueId));
1045
+ valueIdsChanged(valueId, -1);
1046
+ mapSet(valuesMap, valueId);
1047
+ }
875
1048
  };
876
1049
  const tableIdsChanged = (tableId, addedOrRemoved) =>
877
1050
  idsChanged(changedTableIds, tableId, addedOrRemoved);
@@ -1330,14 +1503,14 @@ const createStore = () => {
1330
1503
  if (validateRow(tableId2, rowId2, partialRow, 1)) {
1331
1504
  const table = getOrCreateTable(tableId2);
1332
1505
  objMap(partialRow, (cell, cellId) =>
1333
- setCellIntoDefaultRow(tableId2, table, rowId2, cellId, cell),
1506
+ setCellIntoNewRow(tableId2, table, rowId2, cellId, cell),
1334
1507
  );
1335
1508
  }
1336
1509
  },
1337
1510
  tableId,
1338
1511
  rowId,
1339
1512
  );
1340
- const setCell = (tableId, rowId, cellId, cell) =>
1513
+ const setCell = (tableId, rowId, cellId, cell, skipMiddleware) =>
1341
1514
  fluentTransaction(
1342
1515
  (tableId2, rowId2, cellId2) =>
1343
1516
  ifNotUndefined(
@@ -1348,12 +1521,13 @@ const createStore = () => {
1348
1521
  isFunction(cell) ? cell(getCell(tableId2, rowId2, cellId2)) : cell,
1349
1522
  ),
1350
1523
  (validCell) =>
1351
- setCellIntoDefaultRow(
1524
+ setCellIntoNewRow(
1352
1525
  tableId2,
1353
1526
  getOrCreateTable(tableId2),
1354
1527
  rowId2,
1355
1528
  cellId2,
1356
1529
  validCell,
1530
+ skipMiddleware,
1357
1531
  ),
1358
1532
  ),
1359
1533
  tableId,
@@ -1372,7 +1546,7 @@ const createStore = () => {
1372
1546
  )
1373
1547
  : 0,
1374
1548
  );
1375
- const setValue = (valueId, value) =>
1549
+ const setValue = (valueId, value, skipMiddleware) =>
1376
1550
  fluentTransaction(
1377
1551
  (valueId2) =>
1378
1552
  ifNotUndefined(
@@ -1380,27 +1554,40 @@ const createStore = () => {
1380
1554
  valueId2,
1381
1555
  isFunction(value) ? value(getValue(valueId2)) : value,
1382
1556
  ),
1383
- (validValue) => setValidValue(valueId2, validValue),
1557
+ (validValue) => setValidValue(valueId2, validValue, skipMiddleware),
1384
1558
  ),
1385
1559
  valueId,
1386
1560
  );
1387
1561
  const applyChanges = (changes) =>
1388
- fluentTransaction(() => {
1389
- objMap(changes[0], (table, tableId) =>
1390
- isUndefined(table)
1391
- ? delTable(tableId)
1392
- : objMap(table, (row, rowId) =>
1393
- isUndefined(row)
1394
- ? delRow(tableId, rowId)
1395
- : objMap(row, (cell, cellId) =>
1396
- setOrDelCell(store, tableId, rowId, cellId, cell),
1397
- ),
1398
- ),
1399
- );
1400
- objMap(changes[1], (value, valueId) =>
1401
- setOrDelValue(store, valueId, value),
1402
- );
1403
- });
1562
+ fluentTransaction(() =>
1563
+ ifTransformed(
1564
+ changes,
1565
+ () =>
1566
+ ifNotUndefined(
1567
+ middleware[13],
1568
+ (willApplyChanges) =>
1569
+ whileMutating(() => willApplyChanges(structuredClone(changes))),
1570
+ () => changes,
1571
+ ),
1572
+ (changes2) => {
1573
+ objMap(changes2[0], (table, tableId) =>
1574
+ isUndefined(table)
1575
+ ? delTable(tableId)
1576
+ : objMap(table, (row, rowId) =>
1577
+ isUndefined(row)
1578
+ ? delRow(tableId, rowId)
1579
+ : objMap(row, (cell, cellId) =>
1580
+ setOrDelCell(tableId, rowId, cellId, cell),
1581
+ ),
1582
+ ),
1583
+ );
1584
+ objMap(changes2[1], (value, valueId) =>
1585
+ setOrDelValue(valueId, value),
1586
+ );
1587
+ },
1588
+ contentOrChangesIsEqual,
1589
+ ),
1590
+ );
1404
1591
  const setTablesJson = (tablesJson) => {
1405
1592
  tryCatch(() => setOrDelTables(jsonParse(tablesJson)));
1406
1593
  return store;
@@ -1447,7 +1634,12 @@ const createStore = () => {
1447
1634
  setTablesSchema(tablesSchema);
1448
1635
  setValuesSchema(valuesSchema);
1449
1636
  });
1450
- const delTables = () => fluentTransaction(() => setValidTables({}));
1637
+ const delTables = () =>
1638
+ fluentTransaction(() =>
1639
+ (whileMutating(() => middleware[7]?.()) ?? true)
1640
+ ? setValidTables({}, true)
1641
+ : 0,
1642
+ );
1451
1643
  const delTable = (tableId) =>
1452
1644
  fluentTransaction(
1453
1645
  (tableId2) =>
@@ -1465,7 +1657,7 @@ const createStore = () => {
1465
1657
  tableId,
1466
1658
  rowId,
1467
1659
  );
1468
- const delCell = (tableId, rowId, cellId, forceDel) =>
1660
+ const delCell = (tableId, rowId, cellId, forceDel, skipMiddleware) =>
1469
1661
  fluentTransaction(
1470
1662
  (tableId2, rowId2, cellId2) =>
1471
1663
  ifNotUndefined(mapGet(tablesMap, tableId2), (tableMap) =>
@@ -1478,6 +1670,7 @@ const createStore = () => {
1478
1670
  rowMap,
1479
1671
  cellId2,
1480
1672
  forceDel,
1673
+ skipMiddleware,
1481
1674
  )
1482
1675
  : 0,
1483
1676
  ),
@@ -1486,11 +1679,18 @@ const createStore = () => {
1486
1679
  rowId,
1487
1680
  cellId,
1488
1681
  );
1489
- const delValues = () => fluentTransaction(() => setValidValues({}));
1490
- const delValue = (valueId) =>
1682
+ const delValues = () =>
1683
+ fluentTransaction(() =>
1684
+ (whileMutating(() => middleware[11]?.()) ?? true)
1685
+ ? setValidValues({}, true)
1686
+ : 0,
1687
+ );
1688
+ const delValue = (valueId, skipMiddleware) =>
1491
1689
  fluentTransaction(
1492
1690
  (valueId2) =>
1493
- collHas(valuesMap, valueId2) ? delValidValue(valueId2) : 0,
1691
+ collHas(valuesMap, valueId2)
1692
+ ? delValidValue(valueId2, skipMiddleware)
1693
+ : 0,
1494
1694
  valueId,
1495
1695
  );
1496
1696
  const delTablesSchema = () =>
@@ -1572,27 +1772,27 @@ const createStore = () => {
1572
1772
  transactions--;
1573
1773
  if (transactions == 0) {
1574
1774
  transactions = 1;
1575
- mutating = 1;
1576
- callInvalidCellListeners(1);
1577
- if (!collIsEmpty(changedCells)) {
1578
- callTabularListenersForChanges(1);
1579
- }
1580
- callInvalidValueListeners(1);
1581
- if (!collIsEmpty(changedValues)) {
1582
- callValuesListenersForChanges(1);
1583
- }
1584
- mutating = 0;
1775
+ whileMutating(() => {
1776
+ callInvalidCellListeners(1);
1777
+ if (!collIsEmpty(changedCells)) {
1778
+ callTabularListenersForChanges(1);
1779
+ }
1780
+ callInvalidValueListeners(1);
1781
+ if (!collIsEmpty(changedValues)) {
1782
+ callValuesListenersForChanges(1);
1783
+ }
1784
+ });
1585
1785
  if (doRollback?.(store)) {
1586
1786
  collForEach(changedCells, (table, tableId) =>
1587
1787
  collForEach(table, (row, rowId) =>
1588
1788
  collForEach(row, ([oldCell], cellId) =>
1589
- setOrDelCell(store, tableId, rowId, cellId, oldCell),
1789
+ setOrDelCell(tableId, rowId, cellId, oldCell, true),
1590
1790
  ),
1591
1791
  ),
1592
1792
  );
1593
1793
  collClear(changedCells);
1594
1794
  collForEach(changedValues, ([oldValue], valueId) =>
1595
- setOrDelValue(store, valueId, oldValue),
1795
+ setOrDelValue(valueId, oldValue, true),
1596
1796
  );
1597
1797
  collClear(changedValues);
1598
1798
  }
@@ -1719,6 +1919,38 @@ const createStore = () => {
1719
1919
  collSize2(startTransactionListeners) +
1720
1920
  pairCollSize2(finishTransactionListeners),
1721
1921
  });
1922
+ const setMiddleware = (
1923
+ willSetContent,
1924
+ willSetTables,
1925
+ willSetTable,
1926
+ willSetRow,
1927
+ willSetCell,
1928
+ willSetValues,
1929
+ willSetValue,
1930
+ willDelTables,
1931
+ willDelTable,
1932
+ willDelRow,
1933
+ willDelCell,
1934
+ willDelValues,
1935
+ willDelValue,
1936
+ willApplyChanges,
1937
+ ) =>
1938
+ (middleware = [
1939
+ willSetContent,
1940
+ willSetTables,
1941
+ willSetTable,
1942
+ willSetRow,
1943
+ willSetCell,
1944
+ willSetValues,
1945
+ willSetValue,
1946
+ willDelTables,
1947
+ willDelTable,
1948
+ willDelRow,
1949
+ willDelCell,
1950
+ willDelValues,
1951
+ willDelValue,
1952
+ willApplyChanges,
1953
+ ]);
1722
1954
  const setInternalListeners = (
1723
1955
  preStartTransaction,
1724
1956
  preFinishTransaction,
@@ -1812,6 +2044,9 @@ const createStore = () => {
1812
2044
  addListener,
1813
2045
  callListeners,
1814
2046
  setInternalListeners,
2047
+ setMiddleware,
2048
+ setOrDelCell,
2049
+ setOrDelValue,
1815
2050
  };
1816
2051
  objMap(
1817
2052
  {
@@ -2368,7 +2603,8 @@ const createMergeableStore = (uniqueId, getNow) => {
2368
2603
  strStartsWith(name, DEL) ||
2369
2604
  strStartsWith(name, 'apply') ||
2370
2605
  strEndsWith(name, TRANSACTION) ||
2371
- name == 'call' + LISTENER
2606
+ name == 'call' + LISTENER ||
2607
+ name == 'use'
2372
2608
  ? (...args) => {
2373
2609
  method(...args);
2374
2610
  return mergeableStore;