@emailmaker/filemanager 0.10.93 → 0.10.95

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- export{O as DEFAULT_FILE_MANAGER_CACHE_TTL_MS,R as DataSourceProxyBase,L as FailedRequestCache,A as FileContent,G as FileManagerApiError,z as FileManagerApp,t as FileManagerAppWithContext,B as FileModals,C as FolderSidebar,M as MutationRegistry,S as PathAwareStorageAdapter,P as PixieOnlyApp,T as TreeCache,V as ViewCacheManager,I as buildAssetsPath,y as default,Q as defaultIsFolderNotFoundError,U as fetchRemoteImageBlobByUrl,K as getAssetsBase,q as init,x as initFileManager,v as initPixieEditor,D as installResizeObserverErrorHandler,J as joinUrls,H as mapHttpStatusToErrorCode,E as uninstallResizeObserverErrorHandler,s as unmount,w as unmountPixieEditor}from"./file-manager-index-6WE8OVI9.js";import"react/jsx-runtime";import"react";import"react-dom/client";import"antd";import"@ant-design/icons";import"@ant-design/cssinjs";import"react-dom";import"@untitledui/icons";import"browser-image-compression";import"pixie";
1
+ export{$ as DEFAULT_FILE_MANAGER_CACHE_TTL_MS,a1 as DataSourceProxyBase,L as FailedRequestCache,A as FileContent,G as FileManagerApiError,z as FileManagerApp,t as FileManagerAppWithContext,B as FileModals,C as FolderSidebar,M as MutationRegistry,a2 as PathAwareStorageAdapter,P as PixieOnlyApp,V as TRASH_FOLDER_ID,Z as TreeCache,_ as ViewCacheManager,I as buildAssetsPath,O as compareFileSystemItems,W as createSystemFolderByPathResolver,y as default,Q as defaultChildrenViewFilterMatch,R as defaultFileSystemItemComparator,a0 as defaultIsFolderNotFoundError,a3 as fetchRemoteImageBlobByUrl,K as getAssetsBase,X as getTrashFolderLookupCandidates,q as init,x as initFileManager,v as initPixieEditor,D as installResizeObserverErrorHandler,J as joinUrls,H as mapHttpStatusToErrorCode,S as matchesChildrenViewFilter,Y as normalizeSystemFolderPath,T as resolveSortParams,U as resolveViewStrategyOptions,E as uninstallResizeObserverErrorHandler,s as unmount,w as unmountPixieEditor}from"./file-manager-index-Bi21dmKL.js";import"react/jsx-runtime";import"react";import"react-dom/client";import"antd";import"@ant-design/icons";import"@ant-design/cssinjs";import"react-dom";import"@untitledui/icons";import"browser-image-compression";import"pixie";
2
2
  //# sourceMappingURL=file-manager.esm.js.map
package/file-manager.js CHANGED
@@ -32451,7 +32451,7 @@ __webpack_require__.d(__webpack_exports__, {
32451
32451
  "default": () => (/* binding */ src)
32452
32452
  });
32453
32453
 
32454
- // UNUSED EXPORTS: DEFAULT_FILE_MANAGER_CACHE_TTL_MS, DataSourceProxyBase, FailedRequestCache, FileContent, FileManagerApiError, FileManagerApp, FileManagerAppWithContext, FileModals, FolderSidebar, MutationRegistry, PathAwareStorageAdapter, PixieOnlyApp, TreeCache, ViewCacheManager, buildAssetsPath, defaultIsFolderNotFoundError, fetchRemoteImageBlobByUrl, getAssetsBase, init, initFileManager, initPixieEditor, installResizeObserverErrorHandler, joinUrls, mapHttpStatusToErrorCode, uninstallResizeObserverErrorHandler, unmount, unmountPixieEditor
32454
+ // UNUSED EXPORTS: DEFAULT_FILE_MANAGER_CACHE_TTL_MS, DataSourceProxyBase, FailedRequestCache, FileContent, FileManagerApiError, FileManagerApp, FileManagerAppWithContext, FileModals, FolderSidebar, MutationRegistry, PathAwareStorageAdapter, PixieOnlyApp, TRASH_FOLDER_ID, TreeCache, ViewCacheManager, buildAssetsPath, compareFileSystemItems, createSystemFolderByPathResolver, defaultChildrenViewFilterMatch, defaultFileSystemItemComparator, defaultIsFolderNotFoundError, fetchRemoteImageBlobByUrl, getAssetsBase, getTrashFolderLookupCandidates, init, initFileManager, initPixieEditor, installResizeObserverErrorHandler, joinUrls, mapHttpStatusToErrorCode, matchesChildrenViewFilter, normalizeSystemFolderPath, resolveSortParams, resolveViewStrategyOptions, uninstallResizeObserverErrorHandler, unmount, unmountPixieEditor
32455
32455
 
32456
32456
  // EXTERNAL MODULE: ./node_modules/react/jsx-runtime.js
32457
32457
  var jsx_runtime = __webpack_require__(4848);
@@ -39888,6 +39888,7 @@ var TreeCache_rest = (undefined && undefined.__rest) || function (s, e) {
39888
39888
  return t;
39889
39889
  };
39890
39890
 
39891
+
39891
39892
  const ROOT_KEY = '';
39892
39893
  /** When `fileManager.cacheStrategy.ttl` is unset: success/error cache and notification dedupe fallback (30 min). */
39893
39894
  const DEFAULT_FILE_MANAGER_CACHE_TTL_MS = (/* unused pure expression or super */ null && (30 * 60 * 1000));
@@ -40344,14 +40345,15 @@ class ViewCacheManager {
40344
40345
  this.views = new Map();
40345
40346
  // Защита от переполнения
40346
40347
  this.maxViewsPerParent = 50;
40348
+ const resolved = resolveViewStrategyOptions(options);
40347
40349
  this.strategy = {
40348
- allowSortedInsert: (_a = options.allowSortedInsert) !== null && _a !== void 0 ? _a : true,
40349
- allowSearchInsert: (_b = options.allowSearchInsert) !== null && _b !== void 0 ? _b : true,
40350
- invalidateOnPaginationFull: (_c = options.invalidateOnPaginationFull) !== null && _c !== void 0 ? _c : true,
40351
- preloadPagesBefore: (_d = options.preloadPagesBefore) !== null && _d !== void 0 ? _d : 0,
40352
- preloadPagesAfter: (_e = options.preloadPagesAfter) !== null && _e !== void 0 ? _e : 1,
40353
- comparator: options.comparator,
40354
- filterMatch: options.filterMatch,
40350
+ allowSortedInsert: (_a = resolved.allowSortedInsert) !== null && _a !== void 0 ? _a : true,
40351
+ allowSearchInsert: (_b = resolved.allowSearchInsert) !== null && _b !== void 0 ? _b : true,
40352
+ invalidateOnPaginationFull: (_c = resolved.invalidateOnPaginationFull) !== null && _c !== void 0 ? _c : true,
40353
+ preloadPagesBefore: (_d = resolved.preloadPagesBefore) !== null && _d !== void 0 ? _d : 0,
40354
+ preloadPagesAfter: (_e = resolved.preloadPagesAfter) !== null && _e !== void 0 ? _e : 1,
40355
+ comparator: resolved.comparator,
40356
+ filterMatch: resolved.filterMatch,
40355
40357
  };
40356
40358
  this.ttl = ttl;
40357
40359
  this.errorTtl = errorTtl !== null && errorTtl !== void 0 ? errorTtl : ttl;
@@ -40393,6 +40395,17 @@ class ViewCacheManager {
40393
40395
  return true;
40394
40396
  return false;
40395
40397
  }
40398
+ /** Mark cached view as stale and cancel any in-flight load for this record. */
40399
+ markViewStaleForReload(rec) {
40400
+ var _a;
40401
+ rec.view.meta = Object.assign(Object.assign({}, ((_a = rec.view.meta) !== null && _a !== void 0 ? _a : {})), { stale: true });
40402
+ rec.view.updatedAt = this.now();
40403
+ rec.view.loadId = generateId();
40404
+ if (rec.view.abortController) {
40405
+ rec.view.abortController.abort();
40406
+ rec.view.abortController = undefined;
40407
+ }
40408
+ }
40396
40409
  cleanupOldViews(bucket) {
40397
40410
  if (bucket.size <= this.maxViewsPerParent)
40398
40411
  return;
@@ -40669,14 +40682,6 @@ class ViewCacheManager {
40669
40682
  }
40670
40683
  }
40671
40684
  }
40672
- // Если задан comparator — считаем клиентскую сортировку авторитетной
40673
- canSafelyModifySortedView(baseParams) {
40674
- if (!baseParams.sortBy && !baseParams.sortOrder)
40675
- return true;
40676
- if (this.strategy.comparator)
40677
- return true;
40678
- return false;
40679
- }
40680
40685
  cascadeShiftPages(bucket, startPageRec, startPageNum, pageSize, totalPages, entitiesManager, baseParams) {
40681
40686
  var _a, _b, _c;
40682
40687
  let currentPageRec = startPageRec;
@@ -40793,7 +40798,7 @@ class ViewCacheManager {
40793
40798
  return wasNewPageCreated;
40794
40799
  }
40795
40800
  tryInsertSorted(rec, entity, entitiesManager) {
40796
- var _a;
40801
+ var _a, _b;
40797
40802
  const comparator = this.strategy.comparator;
40798
40803
  if (!comparator)
40799
40804
  return false;
@@ -40805,6 +40810,21 @@ class ViewCacheManager {
40805
40810
  const currentEntities = rec.view.value.map((id) => entitiesManager.getEntity(id));
40806
40811
  if (currentEntities.some((e) => !e))
40807
40812
  return false;
40813
+ if (currentEntities.length === 0) {
40814
+ const params = (_b = rec.params) !== null && _b !== void 0 ? _b : {};
40815
+ if (params.sortBy || params.sortOrder) {
40816
+ const probe = comparator(entity, entity, rec.params);
40817
+ if (typeof probe !== 'number' || Number.isNaN(probe))
40818
+ return false;
40819
+ }
40820
+ if (rec.view.value.includes(entity.id)) {
40821
+ rec.view.updatedAt = this.now();
40822
+ return true;
40823
+ }
40824
+ rec.view.value = [entity.id];
40825
+ rec.view.updatedAt = this.now();
40826
+ return true;
40827
+ }
40808
40828
  let lo = 0;
40809
40829
  let hi = currentEntities.length;
40810
40830
  while (lo < hi) {
@@ -40823,9 +40843,6 @@ class ViewCacheManager {
40823
40843
  }
40824
40844
  rec.view.value = [...rec.view.value.slice(0, lo), entity.id, ...rec.view.value.slice(lo)];
40825
40845
  rec.view.updatedAt = this.now();
40826
- if (rec.view.meta && typeof rec.view.meta.total === 'number') {
40827
- rec.view.meta.total = Number(rec.view.meta.total) + 1;
40828
- }
40829
40846
  return true;
40830
40847
  }
40831
40848
  updateChildrenCountForOperation(operation, entity, prevParentId, entitiesManager) {
@@ -40860,7 +40877,7 @@ class ViewCacheManager {
40860
40877
  }
40861
40878
  // Разделили smartInvalidate на хелперы
40862
40879
  smartInvalidateChildrenViews(parentId, entity, operation, entitiesManager, prevParentId, prevEntity) {
40863
- var _a, _b, _c, _d;
40880
+ var _a, _b, _c;
40864
40881
  if (!entity)
40865
40882
  return;
40866
40883
  // Всегда обновляем childrenCount (entitiesManager обязателен)
@@ -40885,7 +40902,7 @@ class ViewCacheManager {
40885
40902
  if (rec.view.meta && typeof rec.view.meta.total === 'number') {
40886
40903
  rec.view.meta.total = Math.max(0, rec.view.meta.total - 1);
40887
40904
  }
40888
- rec.view.updatedAt = Date.now();
40905
+ this.markViewStaleForReload(rec);
40889
40906
  }
40890
40907
  continue;
40891
40908
  }
@@ -40903,13 +40920,7 @@ class ViewCacheManager {
40903
40920
  const entityInView = rec.view.value.includes(entity.id);
40904
40921
  const shouldInvalidateCompletely = this.shouldInvalidateCompletely(rec, operation, entity, hasSort, isPaginated, page);
40905
40922
  if (shouldInvalidateCompletely) {
40906
- rec.view.meta = Object.assign(Object.assign({}, ((_d = rec.view.meta) !== null && _d !== void 0 ? _d : {})), { stale: true });
40907
- rec.view.loadId = generateId();
40908
- // Отменяем старый AbortController если был
40909
- if (rec.view.abortController) {
40910
- rec.view.abortController.abort();
40911
- rec.view.abortController = undefined;
40912
- }
40923
+ this.markViewStaleForReload(rec);
40913
40924
  continue;
40914
40925
  }
40915
40926
  switch (operation) {
@@ -40929,13 +40940,10 @@ class ViewCacheManager {
40929
40940
  }
40930
40941
  }
40931
40942
  }
40932
- shouldInvalidateCompletely(rec, operation, entity, hasSort, isPaginated, page) {
40943
+ shouldInvalidateCompletely(rec, operation, _entity, _hasSort, isPaginated, page) {
40933
40944
  if (isPaginated && page > 1 && (operation === 'insert' || operation === 'delete' || operation === 'move')) {
40934
40945
  return true;
40935
40946
  }
40936
- if (hasSort && !this.strategy.comparator && (operation === 'insert' || operation === 'move')) {
40937
- return true;
40938
- }
40939
40947
  if (this.isExpired(rec.view.updatedAt)) {
40940
40948
  return true;
40941
40949
  }
@@ -40946,16 +40954,13 @@ class ViewCacheManager {
40946
40954
  const itemType = ((_a = rec.params) === null || _a === void 0 ? void 0 : _a.itemType) || 'all';
40947
40955
  if (!this.isEntityTypeCompatible(entity, itemType))
40948
40956
  return false;
40949
- if (this.strategy.comparator && this.strategy.filterMatch) {
40950
- if (!this.strategy.filterMatch(entity, rec.params))
40951
- return false;
40952
- const inserted = this.tryInsertSorted(rec, entity, entitiesManager);
40953
- if (inserted)
40954
- return true;
40955
- }
40956
40957
  const params = (_b = rec.params) !== null && _b !== void 0 ? _b : {};
40957
- const hasSort = !!(params.sortBy || params.sortOrder);
40958
- if (hasSort && !this.canSafelyModifySortedView(params))
40958
+ if (!this.strategy.filterMatch(entity, params))
40959
+ return false;
40960
+ const inserted = this.tryInsertSorted(rec, entity, entitiesManager);
40961
+ if (inserted)
40962
+ return true;
40963
+ if (params.sortBy || params.sortOrder)
40959
40964
  return false;
40960
40965
  if (!isPaginated || rec.view.value.length < pageSize) {
40961
40966
  rec.view.value.push(entity.id);
@@ -41000,31 +41005,37 @@ class ViewCacheManager {
41000
41005
  }
41001
41006
  // helper: вставка
41002
41007
  handleInsert(bucket, rec, page, pageSize, isPaginated, hasSort, entity, entitiesManager) {
41003
- var _a, _b, _c, _d;
41008
+ var _a, _b, _c;
41004
41009
  if (rec.view.value.includes(entity.id))
41005
41010
  return;
41006
41011
  if (hasSort && this.strategy.allowSortedInsert && this.strategy.comparator && entitiesManager) {
41007
41012
  const inserted = this.tryInsertSorted(rec, entity, entitiesManager);
41008
- if (inserted && rec.view.meta && typeof rec.view.meta.total === 'number') {
41009
- rec.view.meta.total += 1;
41010
- if (isPaginated && Number.isFinite(pageSize)) {
41011
- const finitePageSize = pageSize;
41012
- if (finitePageSize > 0) {
41013
- rec.view.meta.totalPages = Math.max(1, Math.ceil(rec.view.meta.total / finitePageSize));
41013
+ if (inserted) {
41014
+ if (rec.view.meta && typeof rec.view.meta.total === 'number') {
41015
+ rec.view.meta.total += 1;
41016
+ if (isPaginated && Number.isFinite(pageSize)) {
41017
+ const finitePageSize = pageSize;
41018
+ if (finitePageSize > 0) {
41019
+ rec.view.meta.totalPages = Math.max(1, Math.ceil(rec.view.meta.total / finitePageSize));
41020
+ }
41014
41021
  }
41022
+ this.syncTotalsInSameViews(bucket, rec);
41015
41023
  }
41016
- this.syncTotalsInSameViews(bucket, rec);
41017
- }
41018
- if (isPaginated && ((_b = (_a = rec.view.value) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > pageSize && entitiesManager) {
41019
- const meta = rec.view.meta;
41020
- const totalPages = meta && typeof meta.totalPages === 'number' ? meta.totalPages : 1;
41021
- const wasNewPageCreated = this.cascadeShiftToNextPage(bucket, rec, page, pageSize, totalPages, entitiesManager, (_c = rec.params) !== null && _c !== void 0 ? _c : {});
41022
- if (wasNewPageCreated && rec.view.meta && typeof rec.view.meta.totalPages === 'number') {
41023
- const newTotalPages = rec.view.meta.totalPages + 1;
41024
- rec.view.meta.totalPages = newTotalPages;
41025
- this.updateTotalPagesForAllViews(bucket, newTotalPages);
41024
+ rec.view.updatedAt = Date.now();
41025
+ if (isPaginated && ((_b = (_a = rec.view.value) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > pageSize && entitiesManager) {
41026
+ const meta = rec.view.meta;
41027
+ const totalPages = meta && typeof meta.totalPages === 'number' ? meta.totalPages : 1;
41028
+ const wasNewPageCreated = this.cascadeShiftToNextPage(bucket, rec, page, pageSize, totalPages, entitiesManager, (_c = rec.params) !== null && _c !== void 0 ? _c : {});
41029
+ if (wasNewPageCreated && rec.view.meta && typeof rec.view.meta.totalPages === 'number') {
41030
+ const newTotalPages = rec.view.meta.totalPages + 1;
41031
+ rec.view.meta.totalPages = newTotalPages;
41032
+ this.updateTotalPagesForAllViews(bucket, newTotalPages);
41033
+ }
41026
41034
  }
41027
41035
  }
41036
+ else {
41037
+ this.markViewStaleForReload(rec);
41038
+ }
41028
41039
  }
41029
41040
  else {
41030
41041
  if (!isPaginated || rec.view.value.length < pageSize) {
@@ -41042,7 +41053,7 @@ class ViewCacheManager {
41042
41053
  rec.view.updatedAt = Date.now();
41043
41054
  }
41044
41055
  else {
41045
- rec.view.meta = Object.assign(Object.assign({}, ((_d = rec.view.meta) !== null && _d !== void 0 ? _d : {})), { stale: true });
41056
+ this.markViewStaleForReload(rec);
41046
41057
  }
41047
41058
  }
41048
41059
  rec.view.loadId = generateId();
@@ -41054,7 +41065,7 @@ class ViewCacheManager {
41054
41065
  }
41055
41066
  // helper: update
41056
41067
  handleUpdate(bucket, rec, page, pageSize, isPaginated, hasSort, hasSearch, entity, entitiesManager) {
41057
- var _a, _b, _c, _d;
41068
+ var _a, _b;
41058
41069
  const entityInView = rec.view.value.includes(entity.id);
41059
41070
  const stillCompatible = this.isEntityTypeCompatible(entity, ((_a = rec.params) === null || _a === void 0 ? void 0 : _a.itemType) || 'all');
41060
41071
  if (entityInView && !stillCompatible) {
@@ -41091,46 +41102,16 @@ class ViewCacheManager {
41091
41102
  rec.view.value = rec.view.value.filter((id) => id !== entity.id);
41092
41103
  const reinserted = this.tryReinsertEntity(rec, entity, entitiesManager, isPaginated, pageSize);
41093
41104
  if (!reinserted) {
41094
- if (rec.view.meta && typeof rec.view.meta.total === 'number') {
41095
- rec.view.meta.total = Math.max(0, rec.view.meta.total - 1);
41096
- if (isPaginated && Number.isFinite(pageSize) && typeof rec.view.meta.total === 'number') {
41097
- const finitePageSize = pageSize;
41098
- if (finitePageSize > 0) {
41099
- rec.view.meta.totalPages = Math.max(1, Math.ceil(rec.view.meta.total / finitePageSize));
41100
- }
41101
- }
41102
- this.syncTotalsInSameViews(bucket, rec);
41103
- }
41104
- if (isPaginated && rec.view.value.length < pageSize && entitiesManager) {
41105
- const meta = rec.view.meta;
41106
- const totalPages = meta && typeof meta.totalPages === 'number' ? meta.totalPages : 1;
41107
- const wasEmptyPageRemoved = this.cascadeShiftPages(bucket, rec, page, pageSize, totalPages, entitiesManager, (_c = rec.params) !== null && _c !== void 0 ? _c : {});
41108
- if (wasEmptyPageRemoved && rec.view.meta && typeof rec.view.meta.totalPages === 'number') {
41109
- const newTotalPages = Math.max(1, rec.view.meta.totalPages - 1);
41110
- rec.view.meta.totalPages = newTotalPages;
41111
- this.updateTotalPagesForAllViews(bucket, newTotalPages);
41112
- }
41113
- }
41105
+ this.markViewStaleForReload(rec);
41114
41106
  }
41115
41107
  else {
41116
- if (rec.view.meta && typeof rec.view.meta.total === 'number') {
41117
- rec.view.meta.total += 1;
41118
- if (isPaginated && Number.isFinite(pageSize)) {
41119
- const finitePageSize = pageSize;
41120
- if (finitePageSize > 0) {
41121
- rec.view.meta.totalPages = Math.max(1, Math.ceil(rec.view.meta.total / finitePageSize));
41122
- }
41123
- }
41124
- this.syncTotalsInSameViews(bucket, rec);
41108
+ rec.view.updatedAt = Date.now();
41109
+ rec.view.loadId = generateId();
41110
+ if (rec.view.abortController) {
41111
+ rec.view.abortController.abort();
41112
+ rec.view.abortController = undefined;
41125
41113
  }
41126
41114
  }
41127
- rec.view.updatedAt = Date.now();
41128
- rec.view.loadId = generateId();
41129
- // Отменяем старый AbortController если был
41130
- if (rec.view.abortController) {
41131
- rec.view.abortController.abort();
41132
- rec.view.abortController = undefined;
41133
- }
41134
41115
  return;
41135
41116
  }
41136
41117
  if (entityInView) {
@@ -41146,15 +41127,21 @@ class ViewCacheManager {
41146
41127
  if (stillCompatible && !hasSearch) {
41147
41128
  if (hasSort && this.strategy.allowSortedInsert && this.strategy.comparator && entitiesManager) {
41148
41129
  const inserted = this.tryInsertSorted(rec, entity, entitiesManager);
41149
- if (inserted && rec.view.meta && typeof rec.view.meta.total === 'number') {
41150
- rec.view.meta.total += 1;
41151
- if (isPaginated && Number.isFinite(pageSize)) {
41152
- const finitePageSize = pageSize;
41153
- if (finitePageSize > 0) {
41154
- rec.view.meta.totalPages = Math.max(1, Math.ceil(rec.view.meta.total / finitePageSize));
41130
+ if (inserted) {
41131
+ if (rec.view.meta && typeof rec.view.meta.total === 'number') {
41132
+ rec.view.meta.total += 1;
41133
+ if (isPaginated && Number.isFinite(pageSize)) {
41134
+ const finitePageSize = pageSize;
41135
+ if (finitePageSize > 0) {
41136
+ rec.view.meta.totalPages = Math.max(1, Math.ceil(rec.view.meta.total / finitePageSize));
41137
+ }
41155
41138
  }
41139
+ this.syncTotalsInSameViews(bucket, rec);
41156
41140
  }
41157
- this.syncTotalsInSameViews(bucket, rec);
41141
+ rec.view.updatedAt = Date.now();
41142
+ }
41143
+ else {
41144
+ this.markViewStaleForReload(rec);
41158
41145
  }
41159
41146
  }
41160
41147
  else if (!isPaginated || rec.view.value.length < pageSize) {
@@ -41172,7 +41159,7 @@ class ViewCacheManager {
41172
41159
  rec.view.updatedAt = Date.now();
41173
41160
  }
41174
41161
  else {
41175
- rec.view.meta = Object.assign(Object.assign({}, ((_d = rec.view.meta) !== null && _d !== void 0 ? _d : {})), { stale: true });
41162
+ this.markViewStaleForReload(rec);
41176
41163
  }
41177
41164
  rec.view.loadId = generateId();
41178
41165
  // Отменяем старый AbortController если был
@@ -41504,6 +41491,10 @@ class TreeCache_TreeCache {
41504
41491
  this.invalidateChildrenCountCache(folderId);
41505
41492
  }
41506
41493
  }
41494
+ /** Сбрасывает закэшированные листинги папки, даже если entity папки ещё нет в графе. */
41495
+ invalidateListingViews(folderId) {
41496
+ this.views.forceInvalidateChildrenViews(folderId !== null && folderId !== void 0 ? folderId : null);
41497
+ }
41507
41498
  getChildrenIds(parentId) {
41508
41499
  return this.entities.getChildrenIds(parentId);
41509
41500
  }
@@ -41578,14 +41569,15 @@ class TreeCache_TreeCache {
41578
41569
  });
41579
41570
  // Применяем viewOptions к ViewCacheManager после создания
41580
41571
  if (viewOptions) {
41572
+ const resolved = resolveViewStrategyOptions(viewOptions);
41581
41573
  v.strategy = {
41582
- allowSortedInsert: (_g = viewOptions.allowSortedInsert) !== null && _g !== void 0 ? _g : true,
41583
- allowSearchInsert: (_h = viewOptions.allowSearchInsert) !== null && _h !== void 0 ? _h : true,
41584
- invalidateOnPaginationFull: (_j = viewOptions.invalidateOnPaginationFull) !== null && _j !== void 0 ? _j : true,
41585
- preloadPagesBefore: (_k = viewOptions.preloadPagesBefore) !== null && _k !== void 0 ? _k : 0,
41586
- preloadPagesAfter: (_l = viewOptions.preloadPagesAfter) !== null && _l !== void 0 ? _l : 1,
41587
- comparator: viewOptions.comparator,
41588
- filterMatch: viewOptions.filterMatch,
41574
+ allowSortedInsert: (_g = resolved.allowSortedInsert) !== null && _g !== void 0 ? _g : true,
41575
+ allowSearchInsert: (_h = resolved.allowSearchInsert) !== null && _h !== void 0 ? _h : true,
41576
+ invalidateOnPaginationFull: (_j = resolved.invalidateOnPaginationFull) !== null && _j !== void 0 ? _j : true,
41577
+ preloadPagesBefore: (_k = resolved.preloadPagesBefore) !== null && _k !== void 0 ? _k : 0,
41578
+ preloadPagesAfter: (_l = resolved.preloadPagesAfter) !== null && _l !== void 0 ? _l : 1,
41579
+ comparator: resolved.comparator,
41580
+ filterMatch: resolved.filterMatch,
41589
41581
  };
41590
41582
  }
41591
41583
  tc.entities = ent;
@@ -41635,6 +41627,8 @@ var DataSourceProxyBase_rest = (undefined && undefined.__rest) || function (s, e
41635
41627
 
41636
41628
 
41637
41629
 
41630
+
41631
+
41638
41632
  // Константы для стандартных идентификаторов
41639
41633
  const DEFAULT_ROOT_ID = '';
41640
41634
  const DEFAULT_TRASH_PATH = 'Trash';
@@ -41690,12 +41684,62 @@ function parseFilePath(filePath) {
41690
41684
  * Extend this class in a consumer app to add backend-specific logic.
41691
41685
  */
41692
41686
  class DataSourceProxyBase {
41687
+ _getTrashPath() {
41688
+ return this._pathOptions.trashPath || DEFAULT_TRASH_PATH;
41689
+ }
41690
+ _getPathLookupCandidates(path) {
41691
+ return getTrashFolderLookupCandidates(path, this._getTrashPath(), TRASH_FOLDER_ID);
41692
+ }
41693
+ _folderFromResolvedPath(resolved, lookupPath) {
41694
+ var _a;
41695
+ if (resolved.isFolder !== true) {
41696
+ const message = resolved.isFolder === false ?
41697
+ "Path '%s' resolves to a file, not a folder".replace('%s', lookupPath)
41698
+ : "Path '%s' resolved to an item that is not marked as a folder".replace('%s', lookupPath);
41699
+ throw new FileManagerApiError(message, 'ValidationError');
41700
+ }
41701
+ if (!resolved.id) {
41702
+ const message = "Path '%s' resolved to a folder without id".replace('%s', lookupPath);
41703
+ throw new FileManagerApiError(message, 'ValidationError');
41704
+ }
41705
+ const folder = {
41706
+ id: resolved.id,
41707
+ name: resolved.name || resolved.id,
41708
+ parentId: resolved.folderId,
41709
+ };
41710
+ // Synthetic system folders (e.g. backend-managed trash) must exist in the entity
41711
+ // graph so forceInvalidate(trash.id) can invalidate children views.
41712
+ this._cache.upsertEntity(normalizeFileSystemItem({
41713
+ id: folder.id,
41714
+ name: folder.name,
41715
+ folderId: (_a = folder.parentId) !== null && _a !== void 0 ? _a : null,
41716
+ isFolder: true,
41717
+ }));
41718
+ return folder;
41719
+ }
41720
+ async _resolveFolderByPath(path) {
41721
+ if (typeof this._dataProvider.findItemByPath !== 'function') {
41722
+ return undefined;
41723
+ }
41724
+ for (const lookupPath of this._getPathLookupCandidates(path)) {
41725
+ const resolved = await this._dataProvider.findItemByPath(lookupPath);
41726
+ if (!resolved) {
41727
+ continue;
41728
+ }
41729
+ return this._folderFromResolvedPath(resolved, lookupPath);
41730
+ }
41731
+ return undefined;
41732
+ }
41693
41733
  async _findOrCreateFolderByPath(path) {
41694
41734
  const parts = parseFilePath(path);
41695
41735
  if (parts.length > MAX_PATH_DEPTH) {
41696
41736
  const message = 'Path depth exceeds maximum limit of %s'.replace('%s', String(MAX_PATH_DEPTH));
41697
41737
  throw new FileManagerApiError(message, 'ValidationError');
41698
41738
  }
41739
+ const resolvedFolder = await this._resolveFolderByPath(path);
41740
+ if (resolvedFolder) {
41741
+ return resolvedFolder;
41742
+ }
41699
41743
  let current = undefined;
41700
41744
  for (const part of parts) {
41701
41745
  const { files } = await this.getFiles({ folderId: (current === null || current === void 0 ? void 0 : current.id) || '', itemType: 'folder' });
@@ -41716,8 +41760,13 @@ class DataSourceProxyBase {
41716
41760
  }
41717
41761
  return current;
41718
41762
  }
41719
- getTrashFolder() {
41720
- return this._findOrCreateFolderByPath(this._pathOptions.trashPath || DEFAULT_TRASH_PATH);
41763
+ async getTrashFolder() {
41764
+ const folder = await this._findOrCreateFolderByPath(this._getTrashPath());
41765
+ if (!folder) {
41766
+ const message = "Trash folder path '%s' could not be resolved".replace('%s', this._getTrashPath());
41767
+ throw new FileManagerApiError(message, 'FolderNotFound');
41768
+ }
41769
+ return folder;
41721
41770
  }
41722
41771
  async getTempFolder() {
41723
41772
  var _a;
@@ -41765,7 +41814,7 @@ class DataSourceProxyBase {
41765
41814
  this._rootId = this._pathOptions.rootId || DEFAULT_ROOT_ID;
41766
41815
  this._enableTrash = this._options.enableTrash === undefined ? true : this._options.enableTrash;
41767
41816
  this._validateDuplicates = this._dataProvider.validateDuplicates;
41768
- // Инициализация кэша с переданными настройками
41817
+ // ViewCacheManager applies resolveViewStrategyOptions in its constructor.
41769
41818
  this._cache = new TreeCache(_options.cacheStrategy || {}, (_a = _options.cacheStrategy) === null || _a === void 0 ? void 0 : _a.ttl, (_b = _options.cacheStrategy) === null || _b === void 0 ? void 0 : _b.errorTtl);
41770
41819
  // if (!this._dataProvider.deleteItems) {
41771
41820
  // this.deleteItems = undefined;
@@ -41784,9 +41833,6 @@ class DataSourceProxyBase {
41784
41833
  return this._cache.getEntity(itemId);
41785
41834
  },
41786
41835
  });
41787
- if (typeof this._dataProvider.clearCache !== 'function') {
41788
- this.clearCache = undefined;
41789
- }
41790
41836
  // Bind all prototype methods to this instance (replaces @BindMethods decorator)
41791
41837
  const proto = Object.getPrototypeOf(this);
41792
41838
  for (const name of Object.getOwnPropertyNames(proto)) {
@@ -41803,11 +41849,13 @@ class DataSourceProxyBase {
41803
41849
  }
41804
41850
  }
41805
41851
  async clearCache(pathFolder) {
41806
- if (typeof this._dataProvider.clearCache !== 'function') {
41807
- throw new FileManagerApiError('Clear cache is not supported by data provider', 'UnsupportedOperation');
41852
+ const folderId = pathFolder !== null && pathFolder !== void 0 ? pathFolder : this._rootId;
41853
+ this._cache.forceInvalidate(folderId);
41854
+ // Корневой листинг может жить в views без entity в графе (пустой ответ при indexing).
41855
+ this._cache.invalidateListingViews(folderId);
41856
+ if (typeof this._dataProvider.clearCache === 'function') {
41857
+ await this._dataProvider.clearCache(pathFolder);
41808
41858
  }
41809
- this._cache.forceInvalidate(this._rootId);
41810
- await this._dataProvider.clearCache(pathFolder);
41811
41859
  }
41812
41860
  /**
41813
41861
  * After save/overwrite, the next `getFileData` for this file id will use `forceReload` (HTTP no-store).
@@ -42181,23 +42229,7 @@ class DataSourceProxyBase {
42181
42229
  * Стандартная клиентская сортировка файлов
42182
42230
  */
42183
42231
  _defaultClientSideSort(files, sortBy, sortOrder) {
42184
- return files.sort((a, b) => {
42185
- let compareResult = 0;
42186
- switch (sortBy) {
42187
- case 'name':
42188
- compareResult = (a.name || '').localeCompare(b.name || '');
42189
- break;
42190
- case 'date':
42191
- compareResult = new Date(a.date || 0).getTime() - new Date(b.date || 0).getTime();
42192
- break;
42193
- case 'size':
42194
- compareResult = (Number(a.size) || 0) - (Number(b.size) || 0);
42195
- break;
42196
- default:
42197
- compareResult = (a.name || '').localeCompare(b.name || '');
42198
- }
42199
- return sortOrder === 'desc' ? -compareResult : compareResult;
42200
- });
42232
+ return files.sort((a, b) => compareFileSystemItems(a, b, { sortBy, sortOrder }));
42201
42233
  }
42202
42234
  async getFileData(fileOrId, options) {
42203
42235
  var _a;
@@ -43022,11 +43054,11 @@ var PathAwareStorageAdapter_rest = (undefined && undefined.__rest) || function (
43022
43054
  // @ts-nocheck
43023
43055
 
43024
43056
 
43057
+
43025
43058
  const PathAwareStorageAdapter_DEFAULT_ROOT_ID = '';
43026
43059
  const PathAwareStorageAdapter_DEFAULT_TRASH_PATH = 'Trash';
43027
- const DEFAULT_TRASH_ID = 'Trash';
43028
43060
  class PathAwareStorageAdapter {
43029
- constructor(_inner, rootPath = PathAwareStorageAdapter_DEFAULT_ROOT_ID, trashId = DEFAULT_TRASH_ID, trashPath = PathAwareStorageAdapter_DEFAULT_TRASH_PATH, ensureFolderTrailingSlash = true) {
43061
+ constructor(_inner, rootPath = PathAwareStorageAdapter_DEFAULT_ROOT_ID, trashId = TRASH_FOLDER_ID, trashPath = PathAwareStorageAdapter_DEFAULT_TRASH_PATH, ensureFolderTrailingSlash = true) {
43030
43062
  var _a;
43031
43063
  this._inner = _inner;
43032
43064
  this.rootPath = rootPath;
@@ -43100,11 +43132,46 @@ class PathAwareStorageAdapter {
43100
43132
  return;
43101
43133
  return this._inner.clearCache(pathFolder);
43102
43134
  }
43135
+ findItemByPath(path) {
43136
+ if (typeof this._inner.findItemByPath !== 'function') {
43137
+ return undefined;
43138
+ }
43139
+ const mapResolved = (resolved, lookupPath, requestPath) => {
43140
+ if (!resolved) {
43141
+ return undefined;
43142
+ }
43143
+ if (resolved.isFolder !== true) {
43144
+ return resolved;
43145
+ }
43146
+ const requestPathClean = normalizeSystemFolderPath(requestPath);
43147
+ const trashPathClean = normalizeSystemFolderPath(this.trashPath);
43148
+ const idPath = requestPathClean === trashPathClean ? this.trashPath : lookupPath;
43149
+ const cleanedIdPath = normalizeSystemFolderPath(idPath);
43150
+ const parentPath = resolved.folderId != null && resolved.folderId !== '' ?
43151
+ normalizeSystemFolderPath(resolved.folderId)
43152
+ : this.rootPath;
43153
+ return Object.assign(Object.assign({}, resolved), { id: this._getOrGenerateId(cleanedIdPath), name: resolved.name, folderId: parentPath === normalizeSystemFolderPath(this.rootPath) ?
43154
+ this.rootPath || ''
43155
+ : this._getOrGenerateId(parentPath), isFolder: true });
43156
+ };
43157
+ const lookupPaths = getTrashFolderLookupCandidates(path, this.trashPath, this.trashId);
43158
+ const resolveCandidates = async () => {
43159
+ for (const lookupPath of lookupPaths) {
43160
+ const resolved = await Promise.resolve(this._inner.findItemByPath(lookupPath));
43161
+ const mapped = mapResolved(resolved, lookupPath, path);
43162
+ if (mapped) {
43163
+ return mapped;
43164
+ }
43165
+ }
43166
+ return undefined;
43167
+ };
43168
+ return resolveCandidates();
43169
+ }
43103
43170
  _getOrGenerateId(path) {
43104
43171
  if (path === this.rootPath)
43105
43172
  return '';
43106
- const cleanedPath = path.replaceAll(/^\/+|\/+$/g, '');
43107
- if (cleanedPath === this.trashPath.replaceAll(/^\/+|\/+$/g, ''))
43173
+ const cleanedPath = normalizeSystemFolderPath(path);
43174
+ if (cleanedPath === normalizeSystemFolderPath(this.trashPath))
43108
43175
  return this.trashId;
43109
43176
  if (this._pathToId.has(cleanedPath))
43110
43177
  return this._pathToId.get(cleanedPath);
@@ -43584,6 +43651,8 @@ var remoteFileFetchPipeline = __webpack_require__(5597);
43584
43651
 
43585
43652
 
43586
43653
 
43654
+
43655
+
43587
43656
  })();
43588
43657
 
43589
43658
  __webpack_exports__ = __webpack_exports__["default"];
package/index.d.ts CHANGED
@@ -23,6 +23,8 @@ export { mapHttpStatusToErrorCode } from './shared/mapHttpStatusToErrorCode';
23
23
  export { buildAssetsPath, joinUrls, getAssetsBase } from './helpers/urls';
24
24
  export { FailedRequestCache } from './adapters/FailedRequestCache';
25
25
  export { MutationRegistry } from './adapters/MutationRegistry';
26
+ export { compareFileSystemItems, defaultChildrenViewFilterMatch, defaultFileSystemItemComparator, matchesChildrenViewFilter, resolveSortParams, resolveViewStrategyOptions, } from './adapters/cacheViewStrategy';
27
+ export { TRASH_FOLDER_ID, createSystemFolderByPathResolver, getTrashFolderLookupCandidates, normalizeSystemFolderPath, type SystemFolderDefinition, } from './adapters/systemFolderPath';
26
28
  export { TreeCache, ViewCacheManager, DEFAULT_FILE_MANAGER_CACHE_TTL_MS, defaultIsFolderNotFoundError, type TreeCacheConfig, type QueryResult, type ChildrenQueryParams, type ViewStrategyOptions, } from './adapters/TreeCache';
27
29
  export { DataSourceProxyBase, type DataSourceProxyConfig, type DataSourceProxyOptions, type FileManagerProxyOptions, } from './adapters/DataSourceProxyBase';
28
30
  export { PathAwareStorageAdapter } from './adapters/PathAwareStorageAdapter';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emailmaker/filemanager",
3
- "version": "0.10.93",
3
+ "version": "0.10.95",
4
4
  "main": "./file-manager.js",
5
5
  "module": "./file-manager.esm.js",
6
6
  "types": "./index.d.ts",