@anvilkit/plugin-asset-manager 0.1.7 → 0.1.9

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 (141) hide show
  1. package/README.md +4 -4
  2. package/dist/adapters/data-url.d.cts +13 -0
  3. package/dist/adapters/data-url.d.cts.map +1 -1
  4. package/dist/adapters/data-url.d.ts +13 -0
  5. package/dist/adapters/data-url.d.ts.map +1 -1
  6. package/dist/adapters/in-memory.d.cts +8 -1
  7. package/dist/adapters/in-memory.d.cts.map +1 -1
  8. package/dist/adapters/in-memory.d.ts +8 -1
  9. package/dist/adapters/in-memory.d.ts.map +1 -1
  10. package/dist/i18n/entry.cjs +75 -0
  11. package/dist/i18n/entry.d.cts +15 -0
  12. package/dist/i18n/entry.d.cts.map +1 -0
  13. package/dist/i18n/entry.d.ts +15 -0
  14. package/dist/i18n/entry.d.ts.map +1 -0
  15. package/dist/i18n/entry.js +29 -0
  16. package/dist/i18n/provider.cjs +49 -0
  17. package/dist/i18n/provider.d.cts +20 -0
  18. package/dist/i18n/provider.d.cts.map +1 -0
  19. package/dist/i18n/provider.d.ts +20 -0
  20. package/dist/i18n/provider.d.ts.map +1 -0
  21. package/dist/i18n/provider.js +11 -0
  22. package/dist/plugin.cjs +3 -1
  23. package/dist/plugin.d.cts.map +1 -1
  24. package/dist/plugin.d.ts.map +1 -1
  25. package/dist/plugin.js +3 -1
  26. package/dist/sources/composite-source.cjs +4 -3
  27. package/dist/sources/composite-source.d.cts.map +1 -1
  28. package/dist/sources/composite-source.d.ts.map +1 -1
  29. package/dist/sources/composite-source.js +4 -3
  30. package/dist/sources/federated-search.cjs +16 -6
  31. package/dist/sources/federated-search.d.cts.map +1 -1
  32. package/dist/sources/federated-search.d.ts.map +1 -1
  33. package/dist/sources/federated-search.js +16 -6
  34. package/dist/sources/unsplash/index.cjs +6 -4
  35. package/dist/sources/unsplash/index.d.cts.map +1 -1
  36. package/dist/sources/unsplash/index.d.ts.map +1 -1
  37. package/dist/sources/unsplash/index.js +6 -4
  38. package/dist/types/types.d.cts +7 -1
  39. package/dist/types/types.d.cts.map +1 -1
  40. package/dist/types/types.d.ts +7 -1
  41. package/dist/types/types.d.ts.map +1 -1
  42. package/dist/ui/AssetBrowser.cjs +175 -134
  43. package/dist/ui/AssetBrowser.d.cts.map +1 -1
  44. package/dist/ui/AssetBrowser.d.ts.map +1 -1
  45. package/dist/ui/AssetBrowser.js +175 -134
  46. package/dist/ui/AssetCommandPalette.cjs +20 -18
  47. package/dist/ui/AssetCommandPalette.d.cts.map +1 -1
  48. package/dist/ui/AssetCommandPalette.d.ts.map +1 -1
  49. package/dist/ui/AssetCommandPalette.js +20 -18
  50. package/dist/ui/AssetManagerUI.cjs +23 -15
  51. package/dist/ui/AssetManagerUI.d.cts.map +1 -1
  52. package/dist/ui/AssetManagerUI.d.ts.map +1 -1
  53. package/dist/ui/AssetManagerUI.js +23 -15
  54. package/dist/ui/DeleteAssetDialog.cjs +5 -3
  55. package/dist/ui/DeleteAssetDialog.d.cts.map +1 -1
  56. package/dist/ui/DeleteAssetDialog.d.ts.map +1 -1
  57. package/dist/ui/DeleteAssetDialog.js +5 -3
  58. package/dist/ui/DeleteFolderDialog.cjs +6 -4
  59. package/dist/ui/DeleteFolderDialog.d.cts.map +1 -1
  60. package/dist/ui/DeleteFolderDialog.d.ts.map +1 -1
  61. package/dist/ui/DeleteFolderDialog.js +6 -4
  62. package/dist/ui/EmptyFolderState.cjs +6 -3
  63. package/dist/ui/EmptyFolderState.d.cts +1 -1
  64. package/dist/ui/EmptyFolderState.d.cts.map +1 -1
  65. package/dist/ui/EmptyFolderState.d.ts +1 -1
  66. package/dist/ui/EmptyFolderState.d.ts.map +1 -1
  67. package/dist/ui/EmptyFolderState.js +6 -3
  68. package/dist/ui/FolderBreadcrumb.cjs +7 -4
  69. package/dist/ui/FolderBreadcrumb.d.cts.map +1 -1
  70. package/dist/ui/FolderBreadcrumb.d.ts.map +1 -1
  71. package/dist/ui/FolderBreadcrumb.js +7 -4
  72. package/dist/ui/FolderNameDialog.cjs +19 -12
  73. package/dist/ui/FolderNameDialog.d.cts.map +1 -1
  74. package/dist/ui/FolderNameDialog.d.ts.map +1 -1
  75. package/dist/ui/FolderNameDialog.js +19 -12
  76. package/dist/ui/FolderTree.cjs +4 -2
  77. package/dist/ui/FolderTree.d.cts.map +1 -1
  78. package/dist/ui/FolderTree.d.ts.map +1 -1
  79. package/dist/ui/FolderTree.js +4 -2
  80. package/dist/ui/MetadataPanel.cjs +16 -13
  81. package/dist/ui/MetadataPanel.d.cts.map +1 -1
  82. package/dist/ui/MetadataPanel.d.ts.map +1 -1
  83. package/dist/ui/MetadataPanel.js +16 -13
  84. package/dist/ui/MoveTargetPicker.cjs +7 -4
  85. package/dist/ui/MoveTargetPicker.d.cts.map +1 -1
  86. package/dist/ui/MoveTargetPicker.d.ts.map +1 -1
  87. package/dist/ui/MoveTargetPicker.js +7 -4
  88. package/dist/ui/ReplaceAssetDialog.cjs +19 -17
  89. package/dist/ui/ReplaceAssetDialog.d.cts.map +1 -1
  90. package/dist/ui/ReplaceAssetDialog.d.ts.map +1 -1
  91. package/dist/ui/ReplaceAssetDialog.js +19 -17
  92. package/dist/ui/UnsplashPanel.cjs +15 -12
  93. package/dist/ui/UnsplashPanel.d.cts.map +1 -1
  94. package/dist/ui/UnsplashPanel.d.ts.map +1 -1
  95. package/dist/ui/UnsplashPanel.js +15 -12
  96. package/dist/ui/UploadButton.cjs +11 -8
  97. package/dist/ui/UploadButton.d.cts.map +1 -1
  98. package/dist/ui/UploadButton.d.ts.map +1 -1
  99. package/dist/ui/UploadButton.js +11 -8
  100. package/dist/ui/index.cjs +4 -0
  101. package/dist/ui/index.d.cts +1 -0
  102. package/dist/ui/index.d.cts.map +1 -1
  103. package/dist/ui/index.d.ts +1 -0
  104. package/dist/ui/index.d.ts.map +1 -1
  105. package/dist/ui/index.js +1 -0
  106. package/dist/utils/data-source.cjs +18 -5
  107. package/dist/utils/data-source.d.cts.map +1 -1
  108. package/dist/utils/data-source.d.ts.map +1 -1
  109. package/dist/utils/data-source.js +19 -6
  110. package/dist/utils/folders.cjs +107 -33
  111. package/dist/utils/folders.d.cts +7 -2
  112. package/dist/utils/folders.d.cts.map +1 -1
  113. package/dist/utils/folders.d.ts +7 -2
  114. package/dist/utils/folders.d.ts.map +1 -1
  115. package/dist/utils/folders.js +107 -33
  116. package/dist/utils/header-action.cjs +1 -1
  117. package/dist/utils/header-action.d.cts.map +1 -1
  118. package/dist/utils/header-action.d.ts.map +1 -1
  119. package/dist/utils/header-action.js +1 -1
  120. package/dist/utils/registry.cjs +23 -12
  121. package/dist/utils/registry.d.cts +16 -8
  122. package/dist/utils/registry.d.cts.map +1 -1
  123. package/dist/utils/registry.d.ts +16 -8
  124. package/dist/utils/registry.d.ts.map +1 -1
  125. package/dist/utils/registry.js +19 -8
  126. package/dist/utils/resolver.cjs +5 -4
  127. package/dist/utils/resolver.d.cts.map +1 -1
  128. package/dist/utils/resolver.d.ts.map +1 -1
  129. package/dist/utils/resolver.js +5 -4
  130. package/dist/utils/studio-asset-source.cjs +8 -2
  131. package/dist/utils/studio-asset-source.js +8 -2
  132. package/dist/version.cjs +1 -1
  133. package/dist/version.d.cts +1 -1
  134. package/dist/version.d.ts +1 -1
  135. package/dist/version.js +1 -1
  136. package/i18n/messages/en.json +99 -0
  137. package/i18n/messages/ja.json +99 -0
  138. package/i18n/messages/ko.json +99 -0
  139. package/i18n/messages/zh.json +99 -0
  140. package/meta/config.json +1 -1
  141. package/package.json +11 -10
@@ -38,6 +38,8 @@ function createFolderStore(options = {}) {
38
38
  const assetFolder = new Map();
39
39
  const listeners = new Set();
40
40
  let seq = 0;
41
+ const childrenByParent = new Map();
42
+ const folderAssets = new Map();
41
43
  const notify = ()=>{
42
44
  for (const listener of listeners)listener();
43
45
  };
@@ -46,16 +48,47 @@ function createFolderStore(options = {}) {
46
48
  if (void 0 === rec) throw new external_errors_cjs_namespaceObject.AssetSourceError("FOLDER_NOT_FOUND", `Unknown folder "${id}".`);
47
49
  return rec;
48
50
  };
49
- const childFolderCount = (id)=>{
50
- let n = 0;
51
- for (const rec of records.values())if (rec.parentId === id) n += 1;
52
- return n;
51
+ const linkChild = (parentId, childId)=>{
52
+ let set = childrenByParent.get(parentId);
53
+ if (void 0 === set) {
54
+ set = new Set();
55
+ childrenByParent.set(parentId, set);
56
+ }
57
+ set.add(childId);
58
+ };
59
+ const unlinkChild = (parentId, childId)=>{
60
+ const set = childrenByParent.get(parentId);
61
+ if (void 0 === set) return;
62
+ set.delete(childId);
63
+ if (0 === set.size) childrenByParent.delete(parentId);
64
+ };
65
+ const detachAsset = (assetId, folderId)=>{
66
+ const set = folderAssets.get(folderId);
67
+ if (void 0 === set) return;
68
+ set.delete(assetId);
69
+ if (0 === set.size) folderAssets.delete(folderId);
70
+ };
71
+ const setMembership = (assetId, folderId)=>{
72
+ const prev = assetFolder.get(assetId);
73
+ if (prev === folderId) return;
74
+ if (void 0 !== prev) detachAsset(assetId, prev);
75
+ assetFolder.set(assetId, folderId);
76
+ let set = folderAssets.get(folderId);
77
+ if (void 0 === set) {
78
+ set = new Set();
79
+ folderAssets.set(folderId, set);
80
+ }
81
+ set.add(assetId);
53
82
  };
54
- const directAssetCount = (id)=>{
55
- let n = 0;
56
- for (const folderId of assetFolder.values())if (folderId === id) n += 1;
57
- return n;
83
+ const clearMembership = (assetId)=>{
84
+ const prev = assetFolder.get(assetId);
85
+ if (void 0 === prev) return false;
86
+ assetFolder.delete(assetId);
87
+ detachAsset(assetId, prev);
88
+ return true;
58
89
  };
90
+ const childFolderCount = (id)=>childrenByParent.get(id)?.size ?? 0;
91
+ const directAssetCount = (id)=>folderAssets.get(id)?.size ?? 0;
59
92
  const project = (rec)=>Object.freeze({
60
93
  id: rec.id,
61
94
  name: rec.name,
@@ -82,12 +115,17 @@ function createFolderStore(options = {}) {
82
115
  const out = new Set([
83
116
  id
84
117
  ]);
85
- let added = true;
86
- while(added){
87
- added = false;
88
- for (const rec of records.values())if (null !== rec.parentId && out.has(rec.parentId) && !out.has(rec.id)) {
89
- out.add(rec.id);
90
- added = true;
118
+ const stack = [
119
+ id
120
+ ];
121
+ while(stack.length > 0){
122
+ const current = stack.pop();
123
+ if (void 0 === current) continue;
124
+ const kids = childrenByParent.get(current);
125
+ if (void 0 === kids) continue;
126
+ for (const kid of kids)if (!out.has(kid)) {
127
+ out.add(kid);
128
+ stack.push(kid);
91
129
  }
92
130
  }
93
131
  return out;
@@ -103,10 +141,12 @@ function createFolderStore(options = {}) {
103
141
  };
104
142
  const assertNameFree = (parentId, name, exceptId)=>{
105
143
  const lowered = name.toLowerCase();
106
- for (const rec of records.values())if (rec.parentId === parentId) {
107
- if (rec.id !== exceptId) {
108
- if (rec.name.toLowerCase() === lowered) throw new external_errors_cjs_namespaceObject.AssetSourceError("FOLDER_NAME_CONFLICT", `A folder named "${name}" already exists here.`);
109
- }
144
+ const siblings = childrenByParent.get(parentId);
145
+ if (void 0 === siblings) return;
146
+ for (const sibId of siblings){
147
+ if (sibId === exceptId) continue;
148
+ const rec = records.get(sibId);
149
+ if (void 0 !== rec && rec.name.toLowerCase() === lowered) throw new external_errors_cjs_namespaceObject.AssetSourceError("FOLDER_NAME_CONFLICT", `A folder named "${name}" already exists here.`);
110
150
  }
111
151
  };
112
152
  const normalizeName = (name)=>{
@@ -121,8 +161,13 @@ function createFolderStore(options = {}) {
121
161
  return {
122
162
  listChildren (parentId) {
123
163
  const target = (0, folders_cjs_namespaceObject.resolveFolderId)(parentId);
164
+ const ids = childrenByParent.get(target);
165
+ if (void 0 === ids) return Object.freeze([]);
124
166
  const out = [];
125
- for (const rec of records.values())if (rec.parentId === target) out.push(project(rec));
167
+ for (const id of ids){
168
+ const rec = records.get(id);
169
+ if (void 0 !== rec) out.push(project(rec));
170
+ }
126
171
  return Object.freeze(out);
127
172
  },
128
173
  listAll () {
@@ -165,6 +210,7 @@ function createFolderStore(options = {}) {
165
210
  updatedAt: ts
166
211
  };
167
212
  records.set(rec.id, rec);
213
+ linkChild(target, rec.id);
168
214
  notify();
169
215
  return project(rec);
170
216
  },
@@ -188,8 +234,10 @@ function createFolderStore(options = {}) {
188
234
  if (rec.parentId === target) return project(rec);
189
235
  assertNameFree(target, rec.name, id);
190
236
  assertDepthOk(depthOf(target), heightOf(id), maxDepth);
237
+ unlinkChild(rec.parentId, id);
191
238
  rec.parentId = target;
192
239
  rec.updatedAt = now();
240
+ linkChild(target, id);
193
241
  notify();
194
242
  return project(rec);
195
243
  },
@@ -198,23 +246,43 @@ function createFolderStore(options = {}) {
198
246
  if (opts?.cascade) {
199
247
  const ids = subtree(id);
200
248
  const removedAssetIds = [];
201
- for (const [assetId, folderId] of assetFolder)if (ids.has(folderId)) {
202
- removedAssetIds.push(assetId);
203
- assetFolder.delete(assetId);
249
+ for (const fid of ids){
250
+ const assetsHere = folderAssets.get(fid);
251
+ if (void 0 !== assetsHere) {
252
+ for (const assetId of assetsHere){
253
+ removedAssetIds.push(assetId);
254
+ assetFolder.delete(assetId);
255
+ }
256
+ folderAssets.delete(fid);
257
+ }
258
+ childrenByParent.delete(fid);
259
+ records.delete(fid);
204
260
  }
205
- for (const fid of ids)records.delete(fid);
261
+ unlinkChild(rec.parentId, id);
206
262
  notify();
207
263
  return {
208
264
  removedAssetIds: Object.freeze(removedAssetIds)
209
265
  };
210
266
  }
211
267
  const newParent = rec.parentId;
212
- for (const child of records.values())if (child.parentId === id) {
213
- child.parentId = newParent;
214
- child.updatedAt = now();
268
+ const childIds = [
269
+ ...childrenByParent.get(id) ?? []
270
+ ];
271
+ for (const childId of childIds){
272
+ const child = records.get(childId);
273
+ if (void 0 !== child) {
274
+ child.parentId = newParent;
275
+ child.updatedAt = now();
276
+ linkChild(newParent, childId);
277
+ }
215
278
  }
216
- for (const [assetId, folderId] of assetFolder)if (folderId === id) if (null === newParent) assetFolder.delete(assetId);
217
- else assetFolder.set(assetId, newParent);
279
+ childrenByParent.delete(id);
280
+ const assetIds = [
281
+ ...folderAssets.get(id) ?? []
282
+ ];
283
+ for (const assetId of assetIds)if (null === newParent) clearMembership(assetId);
284
+ else setMembership(assetId, newParent);
285
+ unlinkChild(newParent, id);
218
286
  records.delete(id);
219
287
  notify();
220
288
  return {
@@ -227,23 +295,29 @@ function createFolderStore(options = {}) {
227
295
  moveAsset (assetId, folderId) {
228
296
  const target = (0, folders_cjs_namespaceObject.resolveFolderId)(folderId);
229
297
  if (null !== target) requireRecord(target);
230
- if (null === target) assetFolder.delete(assetId);
231
- else assetFolder.set(assetId, target);
298
+ if (null === target) clearMembership(assetId);
299
+ else setMembership(assetId, target);
232
300
  notify();
233
301
  },
234
302
  moveAssets (assetIds, folderId) {
235
303
  const target = (0, folders_cjs_namespaceObject.resolveFolderId)(folderId);
236
304
  if (null !== target) requireRecord(target);
237
- for (const assetId of assetIds)if (null === target) assetFolder.delete(assetId);
238
- else assetFolder.set(assetId, target);
305
+ for (const assetId of assetIds)if (null === target) clearMembership(assetId);
306
+ else setMembership(assetId, target);
239
307
  notify();
240
308
  },
241
309
  removeAsset (assetId) {
242
- if (assetFolder.delete(assetId)) notify();
310
+ if (clearMembership(assetId)) notify();
243
311
  },
244
312
  subtreeIds (id) {
245
313
  return subtree(id);
246
314
  },
315
+ directAssetIds (id) {
316
+ const set = folderAssets.get(id);
317
+ return void 0 === set ? Object.freeze([]) : Object.freeze([
318
+ ...set
319
+ ]);
320
+ },
247
321
  subscribe (listener) {
248
322
  listeners.add(listener);
249
323
  return ()=>{
@@ -5,8 +5,11 @@
5
5
  * Owns the folder tree (records) and the asset→folder side-index. Membership is
6
6
  * stored ONLY for non-root assets (absence ⇒ root), so `UploadResult` is never
7
7
  * extended and the registry's freeze reconstructor can't strip a folder field.
8
- * `AssetFolder.counts` is computed fresh on read (never denormalized) so it can
9
- * never drift from the side-index.
8
+ * `AssetFolder.counts` is served from two reverse indexes `childrenByParent`
9
+ * (parent child folder ids) and `folderAssets` (folder → direct asset ids) —
10
+ * kept in lockstep with the authoritative maps via centralized mutation helpers,
11
+ * so projection, `listChildren`, and subtree walks are O(result size) instead of
12
+ * O(every record), and the counts still cannot drift from the side-index.
10
13
  */
11
14
  import type { AssetFolder, FolderId } from "../types/folders.js";
12
15
  export interface CreateFolderStoreOptions {
@@ -43,6 +46,8 @@ export interface FolderStore {
43
46
  removeAsset(assetId: string): void;
44
47
  /** Folder id + every descendant folder id (for recursive listing). */
45
48
  subtreeIds(id: FolderId): ReadonlySet<FolderId>;
49
+ /** Asset ids directly contained by `id` (membership only; no descendants). */
50
+ directAssetIds(id: FolderId): readonly string[];
46
51
  subscribe(listener: () => void): () => void;
47
52
  }
48
53
  export declare function createFolderStore(options?: CreateFolderStoreOptions): FolderStore;
@@ -1 +1 @@
1
- {"version":3,"file":"folders.d.cts","sourceRoot":"","sources":["../../src/utils/folders.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAYjE,MAAM,WAAW,wBAAwB;IACxC,sFAAsF;IACtF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC3B,+EAA+E;IAC/E,YAAY,CAAC,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,SAAS,WAAW,EAAE,CAAC;IACjE,yBAAyB;IACzB,OAAO,IAAI,SAAS,WAAW,EAAE,CAAC;IAClC,GAAG,CAAC,EAAE,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;IAC3C,4DAA4D;IAC5D,IAAI,CAAC,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,SAAS,WAAW,EAAE,CAAC;IAEnD,YAAY,CACX,QAAQ,EAAE,QAAQ,GAAG,IAAI,EACzB,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,GACf,WAAW,CAAC;IACf,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IACtD,UAAU,CACT,EAAE,EAAE,QAAQ,EACZ,QAAQ,EAAE,QAAQ,GAAG,IAAI,EACzB,QAAQ,CAAC,EAAE,MAAM,GACf,WAAW,CAAC;IACf;;;;OAIG;IACH,YAAY,CACX,EAAE,EAAE,QAAQ,EACZ,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GACnC;QAAE,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAC;IAEnD,iDAAiD;IACjD,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IAC3C,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC;IAC5D,+EAA+E;IAC/E,UAAU,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC;IACzE,qFAAqF;IACrF,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAEnC,sEAAsE;IACtE,UAAU,CAAC,EAAE,EAAE,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IAEhD,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;CAC5C;AAED,wBAAgB,iBAAiB,CAChC,OAAO,GAAE,wBAA6B,GACpC,WAAW,CAsSb"}
1
+ {"version":3,"file":"folders.d.cts","sourceRoot":"","sources":["../../src/utils/folders.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAYjE,MAAM,WAAW,wBAAwB;IACxC,sFAAsF;IACtF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC3B,+EAA+E;IAC/E,YAAY,CAAC,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,SAAS,WAAW,EAAE,CAAC;IACjE,yBAAyB;IACzB,OAAO,IAAI,SAAS,WAAW,EAAE,CAAC;IAClC,GAAG,CAAC,EAAE,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;IAC3C,4DAA4D;IAC5D,IAAI,CAAC,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,SAAS,WAAW,EAAE,CAAC;IAEnD,YAAY,CACX,QAAQ,EAAE,QAAQ,GAAG,IAAI,EACzB,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,GACf,WAAW,CAAC;IACf,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IACtD,UAAU,CACT,EAAE,EAAE,QAAQ,EACZ,QAAQ,EAAE,QAAQ,GAAG,IAAI,EACzB,QAAQ,CAAC,EAAE,MAAM,GACf,WAAW,CAAC;IACf;;;;OAIG;IACH,YAAY,CACX,EAAE,EAAE,QAAQ,EACZ,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GACnC;QAAE,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAC;IAEnD,iDAAiD;IACjD,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IAC3C,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC;IAC5D,+EAA+E;IAC/E,UAAU,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC;IACzE,qFAAqF;IACrF,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAEnC,sEAAsE;IACtE,UAAU,CAAC,EAAE,EAAE,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IAEhD,8EAA8E;IAC9E,cAAc,CAAC,EAAE,EAAE,QAAQ,GAAG,SAAS,MAAM,EAAE,CAAC;IAEhD,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;CAC5C;AAED,wBAAgB,iBAAiB,CAChC,OAAO,GAAE,wBAA6B,GACpC,WAAW,CA4Wb"}
@@ -5,8 +5,11 @@
5
5
  * Owns the folder tree (records) and the asset→folder side-index. Membership is
6
6
  * stored ONLY for non-root assets (absence ⇒ root), so `UploadResult` is never
7
7
  * extended and the registry's freeze reconstructor can't strip a folder field.
8
- * `AssetFolder.counts` is computed fresh on read (never denormalized) so it can
9
- * never drift from the side-index.
8
+ * `AssetFolder.counts` is served from two reverse indexes `childrenByParent`
9
+ * (parent child folder ids) and `folderAssets` (folder → direct asset ids) —
10
+ * kept in lockstep with the authoritative maps via centralized mutation helpers,
11
+ * so projection, `listChildren`, and subtree walks are O(result size) instead of
12
+ * O(every record), and the counts still cannot drift from the side-index.
10
13
  */
11
14
  import type { AssetFolder, FolderId } from "../types/folders.js";
12
15
  export interface CreateFolderStoreOptions {
@@ -43,6 +46,8 @@ export interface FolderStore {
43
46
  removeAsset(assetId: string): void;
44
47
  /** Folder id + every descendant folder id (for recursive listing). */
45
48
  subtreeIds(id: FolderId): ReadonlySet<FolderId>;
49
+ /** Asset ids directly contained by `id` (membership only; no descendants). */
50
+ directAssetIds(id: FolderId): readonly string[];
46
51
  subscribe(listener: () => void): () => void;
47
52
  }
48
53
  export declare function createFolderStore(options?: CreateFolderStoreOptions): FolderStore;
@@ -1 +1 @@
1
- {"version":3,"file":"folders.d.ts","sourceRoot":"","sources":["../../src/utils/folders.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAYjE,MAAM,WAAW,wBAAwB;IACxC,sFAAsF;IACtF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC3B,+EAA+E;IAC/E,YAAY,CAAC,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,SAAS,WAAW,EAAE,CAAC;IACjE,yBAAyB;IACzB,OAAO,IAAI,SAAS,WAAW,EAAE,CAAC;IAClC,GAAG,CAAC,EAAE,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;IAC3C,4DAA4D;IAC5D,IAAI,CAAC,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,SAAS,WAAW,EAAE,CAAC;IAEnD,YAAY,CACX,QAAQ,EAAE,QAAQ,GAAG,IAAI,EACzB,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,GACf,WAAW,CAAC;IACf,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IACtD,UAAU,CACT,EAAE,EAAE,QAAQ,EACZ,QAAQ,EAAE,QAAQ,GAAG,IAAI,EACzB,QAAQ,CAAC,EAAE,MAAM,GACf,WAAW,CAAC;IACf;;;;OAIG;IACH,YAAY,CACX,EAAE,EAAE,QAAQ,EACZ,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GACnC;QAAE,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAC;IAEnD,iDAAiD;IACjD,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IAC3C,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC;IAC5D,+EAA+E;IAC/E,UAAU,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC;IACzE,qFAAqF;IACrF,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAEnC,sEAAsE;IACtE,UAAU,CAAC,EAAE,EAAE,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IAEhD,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;CAC5C;AAED,wBAAgB,iBAAiB,CAChC,OAAO,GAAE,wBAA6B,GACpC,WAAW,CAsSb"}
1
+ {"version":3,"file":"folders.d.ts","sourceRoot":"","sources":["../../src/utils/folders.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAYjE,MAAM,WAAW,wBAAwB;IACxC,sFAAsF;IACtF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC3B,+EAA+E;IAC/E,YAAY,CAAC,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,SAAS,WAAW,EAAE,CAAC;IACjE,yBAAyB;IACzB,OAAO,IAAI,SAAS,WAAW,EAAE,CAAC;IAClC,GAAG,CAAC,EAAE,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;IAC3C,4DAA4D;IAC5D,IAAI,CAAC,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,SAAS,WAAW,EAAE,CAAC;IAEnD,YAAY,CACX,QAAQ,EAAE,QAAQ,GAAG,IAAI,EACzB,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,GACf,WAAW,CAAC;IACf,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IACtD,UAAU,CACT,EAAE,EAAE,QAAQ,EACZ,QAAQ,EAAE,QAAQ,GAAG,IAAI,EACzB,QAAQ,CAAC,EAAE,MAAM,GACf,WAAW,CAAC;IACf;;;;OAIG;IACH,YAAY,CACX,EAAE,EAAE,QAAQ,EACZ,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GACnC;QAAE,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAC;IAEnD,iDAAiD;IACjD,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IAC3C,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC;IAC5D,+EAA+E;IAC/E,UAAU,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC;IACzE,qFAAqF;IACrF,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAEnC,sEAAsE;IACtE,UAAU,CAAC,EAAE,EAAE,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IAEhD,8EAA8E;IAC9E,cAAc,CAAC,EAAE,EAAE,QAAQ,GAAG,SAAS,MAAM,EAAE,CAAC;IAEhD,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;CAC5C;AAED,wBAAgB,iBAAiB,CAChC,OAAO,GAAE,wBAA6B,GACpC,WAAW,CA4Wb"}
@@ -6,6 +6,8 @@ function createFolderStore(options = {}) {
6
6
  const assetFolder = new Map();
7
7
  const listeners = new Set();
8
8
  let seq = 0;
9
+ const childrenByParent = new Map();
10
+ const folderAssets = new Map();
9
11
  const notify = ()=>{
10
12
  for (const listener of listeners)listener();
11
13
  };
@@ -14,16 +16,47 @@ function createFolderStore(options = {}) {
14
16
  if (void 0 === rec) throw new AssetSourceError("FOLDER_NOT_FOUND", `Unknown folder "${id}".`);
15
17
  return rec;
16
18
  };
17
- const childFolderCount = (id)=>{
18
- let n = 0;
19
- for (const rec of records.values())if (rec.parentId === id) n += 1;
20
- return n;
19
+ const linkChild = (parentId, childId)=>{
20
+ let set = childrenByParent.get(parentId);
21
+ if (void 0 === set) {
22
+ set = new Set();
23
+ childrenByParent.set(parentId, set);
24
+ }
25
+ set.add(childId);
26
+ };
27
+ const unlinkChild = (parentId, childId)=>{
28
+ const set = childrenByParent.get(parentId);
29
+ if (void 0 === set) return;
30
+ set.delete(childId);
31
+ if (0 === set.size) childrenByParent.delete(parentId);
32
+ };
33
+ const detachAsset = (assetId, folderId)=>{
34
+ const set = folderAssets.get(folderId);
35
+ if (void 0 === set) return;
36
+ set.delete(assetId);
37
+ if (0 === set.size) folderAssets.delete(folderId);
38
+ };
39
+ const setMembership = (assetId, folderId)=>{
40
+ const prev = assetFolder.get(assetId);
41
+ if (prev === folderId) return;
42
+ if (void 0 !== prev) detachAsset(assetId, prev);
43
+ assetFolder.set(assetId, folderId);
44
+ let set = folderAssets.get(folderId);
45
+ if (void 0 === set) {
46
+ set = new Set();
47
+ folderAssets.set(folderId, set);
48
+ }
49
+ set.add(assetId);
21
50
  };
22
- const directAssetCount = (id)=>{
23
- let n = 0;
24
- for (const folderId of assetFolder.values())if (folderId === id) n += 1;
25
- return n;
51
+ const clearMembership = (assetId)=>{
52
+ const prev = assetFolder.get(assetId);
53
+ if (void 0 === prev) return false;
54
+ assetFolder.delete(assetId);
55
+ detachAsset(assetId, prev);
56
+ return true;
26
57
  };
58
+ const childFolderCount = (id)=>childrenByParent.get(id)?.size ?? 0;
59
+ const directAssetCount = (id)=>folderAssets.get(id)?.size ?? 0;
27
60
  const project = (rec)=>Object.freeze({
28
61
  id: rec.id,
29
62
  name: rec.name,
@@ -50,12 +83,17 @@ function createFolderStore(options = {}) {
50
83
  const out = new Set([
51
84
  id
52
85
  ]);
53
- let added = true;
54
- while(added){
55
- added = false;
56
- for (const rec of records.values())if (null !== rec.parentId && out.has(rec.parentId) && !out.has(rec.id)) {
57
- out.add(rec.id);
58
- added = true;
86
+ const stack = [
87
+ id
88
+ ];
89
+ while(stack.length > 0){
90
+ const current = stack.pop();
91
+ if (void 0 === current) continue;
92
+ const kids = childrenByParent.get(current);
93
+ if (void 0 === kids) continue;
94
+ for (const kid of kids)if (!out.has(kid)) {
95
+ out.add(kid);
96
+ stack.push(kid);
59
97
  }
60
98
  }
61
99
  return out;
@@ -71,10 +109,12 @@ function createFolderStore(options = {}) {
71
109
  };
72
110
  const assertNameFree = (parentId, name, exceptId)=>{
73
111
  const lowered = name.toLowerCase();
74
- for (const rec of records.values())if (rec.parentId === parentId) {
75
- if (rec.id !== exceptId) {
76
- if (rec.name.toLowerCase() === lowered) throw new AssetSourceError("FOLDER_NAME_CONFLICT", `A folder named "${name}" already exists here.`);
77
- }
112
+ const siblings = childrenByParent.get(parentId);
113
+ if (void 0 === siblings) return;
114
+ for (const sibId of siblings){
115
+ if (sibId === exceptId) continue;
116
+ const rec = records.get(sibId);
117
+ if (void 0 !== rec && rec.name.toLowerCase() === lowered) throw new AssetSourceError("FOLDER_NAME_CONFLICT", `A folder named "${name}" already exists here.`);
78
118
  }
79
119
  };
80
120
  const normalizeName = (name)=>{
@@ -89,8 +129,13 @@ function createFolderStore(options = {}) {
89
129
  return {
90
130
  listChildren (parentId) {
91
131
  const target = resolveFolderId(parentId);
132
+ const ids = childrenByParent.get(target);
133
+ if (void 0 === ids) return Object.freeze([]);
92
134
  const out = [];
93
- for (const rec of records.values())if (rec.parentId === target) out.push(project(rec));
135
+ for (const id of ids){
136
+ const rec = records.get(id);
137
+ if (void 0 !== rec) out.push(project(rec));
138
+ }
94
139
  return Object.freeze(out);
95
140
  },
96
141
  listAll () {
@@ -133,6 +178,7 @@ function createFolderStore(options = {}) {
133
178
  updatedAt: ts
134
179
  };
135
180
  records.set(rec.id, rec);
181
+ linkChild(target, rec.id);
136
182
  notify();
137
183
  return project(rec);
138
184
  },
@@ -156,8 +202,10 @@ function createFolderStore(options = {}) {
156
202
  if (rec.parentId === target) return project(rec);
157
203
  assertNameFree(target, rec.name, id);
158
204
  assertDepthOk(depthOf(target), heightOf(id), maxDepth);
205
+ unlinkChild(rec.parentId, id);
159
206
  rec.parentId = target;
160
207
  rec.updatedAt = now();
208
+ linkChild(target, id);
161
209
  notify();
162
210
  return project(rec);
163
211
  },
@@ -166,23 +214,43 @@ function createFolderStore(options = {}) {
166
214
  if (opts?.cascade) {
167
215
  const ids = subtree(id);
168
216
  const removedAssetIds = [];
169
- for (const [assetId, folderId] of assetFolder)if (ids.has(folderId)) {
170
- removedAssetIds.push(assetId);
171
- assetFolder.delete(assetId);
217
+ for (const fid of ids){
218
+ const assetsHere = folderAssets.get(fid);
219
+ if (void 0 !== assetsHere) {
220
+ for (const assetId of assetsHere){
221
+ removedAssetIds.push(assetId);
222
+ assetFolder.delete(assetId);
223
+ }
224
+ folderAssets.delete(fid);
225
+ }
226
+ childrenByParent.delete(fid);
227
+ records.delete(fid);
172
228
  }
173
- for (const fid of ids)records.delete(fid);
229
+ unlinkChild(rec.parentId, id);
174
230
  notify();
175
231
  return {
176
232
  removedAssetIds: Object.freeze(removedAssetIds)
177
233
  };
178
234
  }
179
235
  const newParent = rec.parentId;
180
- for (const child of records.values())if (child.parentId === id) {
181
- child.parentId = newParent;
182
- child.updatedAt = now();
236
+ const childIds = [
237
+ ...childrenByParent.get(id) ?? []
238
+ ];
239
+ for (const childId of childIds){
240
+ const child = records.get(childId);
241
+ if (void 0 !== child) {
242
+ child.parentId = newParent;
243
+ child.updatedAt = now();
244
+ linkChild(newParent, childId);
245
+ }
183
246
  }
184
- for (const [assetId, folderId] of assetFolder)if (folderId === id) if (null === newParent) assetFolder.delete(assetId);
185
- else assetFolder.set(assetId, newParent);
247
+ childrenByParent.delete(id);
248
+ const assetIds = [
249
+ ...folderAssets.get(id) ?? []
250
+ ];
251
+ for (const assetId of assetIds)if (null === newParent) clearMembership(assetId);
252
+ else setMembership(assetId, newParent);
253
+ unlinkChild(newParent, id);
186
254
  records.delete(id);
187
255
  notify();
188
256
  return {
@@ -195,23 +263,29 @@ function createFolderStore(options = {}) {
195
263
  moveAsset (assetId, folderId) {
196
264
  const target = resolveFolderId(folderId);
197
265
  if (null !== target) requireRecord(target);
198
- if (null === target) assetFolder.delete(assetId);
199
- else assetFolder.set(assetId, target);
266
+ if (null === target) clearMembership(assetId);
267
+ else setMembership(assetId, target);
200
268
  notify();
201
269
  },
202
270
  moveAssets (assetIds, folderId) {
203
271
  const target = resolveFolderId(folderId);
204
272
  if (null !== target) requireRecord(target);
205
- for (const assetId of assetIds)if (null === target) assetFolder.delete(assetId);
206
- else assetFolder.set(assetId, target);
273
+ for (const assetId of assetIds)if (null === target) clearMembership(assetId);
274
+ else setMembership(assetId, target);
207
275
  notify();
208
276
  },
209
277
  removeAsset (assetId) {
210
- if (assetFolder.delete(assetId)) notify();
278
+ if (clearMembership(assetId)) notify();
211
279
  },
212
280
  subtreeIds (id) {
213
281
  return subtree(id);
214
282
  },
283
+ directAssetIds (id) {
284
+ const set = folderAssets.get(id);
285
+ return void 0 === set ? Object.freeze([]) : Object.freeze([
286
+ ...set
287
+ ]);
288
+ },
215
289
  subscribe (listener) {
216
290
  listeners.add(listener);
217
291
  return ()=>{
@@ -29,7 +29,7 @@ var __webpack_exports__ = {};
29
29
  __webpack_require__.r(__webpack_exports__);
30
30
  const uploadAssetAction = {
31
31
  id: "asset-manager:upload",
32
- label: "Upload asset",
32
+ labelKey: "assetManager.action.upload",
33
33
  icon: "upload",
34
34
  group: "secondary",
35
35
  onClick (ctx) {
@@ -1 +1 @@
1
- {"version":3,"file":"header-action.d.cts","sourceRoot":"","sources":["../../src/utils/header-action.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE/D,eAAO,MAAM,iBAAiB,EAAE,kBAQ/B,CAAC"}
1
+ {"version":3,"file":"header-action.d.cts","sourceRoot":"","sources":["../../src/utils/header-action.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE/D,eAAO,MAAM,iBAAiB,EAAE,kBAW/B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"header-action.d.ts","sourceRoot":"","sources":["../../src/utils/header-action.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE/D,eAAO,MAAM,iBAAiB,EAAE,kBAQ/B,CAAC"}
1
+ {"version":3,"file":"header-action.d.ts","sourceRoot":"","sources":["../../src/utils/header-action.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE/D,eAAO,MAAM,iBAAiB,EAAE,kBAW/B,CAAC"}
@@ -1,6 +1,6 @@
1
1
  const uploadAssetAction = {
2
2
  id: "asset-manager:upload",
3
- label: "Upload asset",
3
+ labelKey: "assetManager.action.upload",
4
4
  icon: "upload",
5
5
  group: "secondary",
6
6
  onClick (ctx) {
@@ -28,9 +28,9 @@ var __webpack_require__ = {};
28
28
  var __webpack_exports__ = {};
29
29
  __webpack_require__.r(__webpack_exports__);
30
30
  __webpack_require__.d(__webpack_exports__, {
31
- assetMatchesSearch: ()=>assetMatchesSearch,
32
31
  createAssetRegistry: ()=>createAssetRegistry,
33
- paginateMatches: ()=>paginateMatches
32
+ paginateMatches: ()=>paginateMatches,
33
+ prepareAssetMatcher: ()=>prepareAssetMatcher
34
34
  });
35
35
  const external_infer_kind_cjs_namespaceObject = require("./infer-kind.cjs");
36
36
  const DEFAULT_SEARCH_LIMIT = 50;
@@ -156,15 +156,25 @@ function normalizeTags(tags) {
156
156
  }
157
157
  return out;
158
158
  }
159
- function assetMatchesSearch(entry, options) {
159
+ function prepareAssetMatcher(options) {
160
160
  const query = options.query?.trim().toLowerCase() ?? "";
161
- if (!matchesQuery(entry, query)) return false;
162
- if (options.kinds && options.kinds.length > 0 && !options.kinds.includes((0, external_infer_kind_cjs_namespaceObject.inferAssetKind)(entry))) return false;
163
- if (options.tags && options.tags.length > 0) {
164
- const tagFilter = options.tags.map((t)=>t.trim().toLowerCase()).filter((t)=>"" !== t);
161
+ const kindSet = options.kinds && options.kinds.length > 0 ? new Set(options.kinds) : null;
162
+ const tagFilter = normalizeTagFilter(options.tags);
163
+ return (entry)=>{
164
+ if (!matchesQuery(entry, query)) return false;
165
+ if (null !== kindSet && !kindSet.has((0, external_infer_kind_cjs_namespaceObject.inferAssetKind)(entry))) return false;
165
166
  if (tagFilter.length > 0 && !matchesAllTags(entry, tagFilter)) return false;
167
+ return true;
168
+ };
169
+ }
170
+ function normalizeTagFilter(tags) {
171
+ if (void 0 === tags || 0 === tags.length) return [];
172
+ const out = [];
173
+ for (const raw of tags){
174
+ const tag = raw.trim().toLowerCase();
175
+ if ("" !== tag) out.push(tag);
166
176
  }
167
- return true;
177
+ return out;
168
178
  }
169
179
  function paginateMatches(matches, options) {
170
180
  const total = matches.length;
@@ -181,7 +191,8 @@ function paginateMatches(matches, options) {
181
191
  }
182
192
  function runSearch(assetsById, options) {
183
193
  const matches = [];
184
- for (const entry of assetsById.values())if (assetMatchesSearch(entry, options)) matches.push(entry);
194
+ const matcher = prepareAssetMatcher(options);
195
+ for (const entry of assetsById.values())if (matcher(entry)) matches.push(entry);
185
196
  return paginateMatches(matches, options);
186
197
  }
187
198
  function matchesQuery(entry, query) {
@@ -204,13 +215,13 @@ function parseCursor(cursor) {
204
215
  if (!Number.isFinite(value) || value < 0) return 0;
205
216
  return value;
206
217
  }
207
- exports.assetMatchesSearch = __webpack_exports__.assetMatchesSearch;
208
218
  exports.createAssetRegistry = __webpack_exports__.createAssetRegistry;
209
219
  exports.paginateMatches = __webpack_exports__.paginateMatches;
220
+ exports.prepareAssetMatcher = __webpack_exports__.prepareAssetMatcher;
210
221
  for(var __rspack_i in __webpack_exports__)if (-1 === [
211
- "assetMatchesSearch",
212
222
  "createAssetRegistry",
213
- "paginateMatches"
223
+ "paginateMatches",
224
+ "prepareAssetMatcher"
214
225
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
215
226
  Object.defineProperty(exports, '__esModule', {
216
227
  value: true
@@ -1,16 +1,24 @@
1
1
  import type { AssetKind, AssetRegistry, AssetSearchPage, UploadResult } from "../types/types.js";
2
2
  export declare function createAssetRegistry(): AssetRegistry;
3
- /**
4
- * Pure predicate: does `entry` satisfy the query / kind / tag filters? Exported
5
- * so the in-memory data-source compose layer applies the EXACT same matching
6
- * before adding its folder clause (PRD 0002 §9.2 — single source of truth for
7
- * search semantics).
8
- */
9
- export declare function assetMatchesSearch(entry: UploadResult, options: {
3
+ /** Query / kind / tag filter shared by the registry and the data-source path. */
4
+ export interface AssetMatchFilter {
10
5
  readonly query?: string;
11
6
  readonly kinds?: readonly AssetKind[];
12
7
  readonly tags?: readonly string[];
13
- }): boolean;
8
+ }
9
+ /**
10
+ * Compile a search filter into a reusable predicate. The query string and tag
11
+ * filter are trimmed + lowercased ONCE here, not once per candidate, so a scan
12
+ * over N assets normalizes the filter a single time instead of N times. This is
13
+ * the registry's search hot path — `AssetCommandPalette` re-runs a free-text
14
+ * query on every keystroke — so build the matcher once, then apply it across the
15
+ * list (see `runSearch`).
16
+ *
17
+ * Exported so the in-memory data-source compose layer applies the EXACT same
18
+ * matching before adding its folder clause (PRD 0002 §9.2 — single source of
19
+ * truth for search semantics).
20
+ */
21
+ export declare function prepareAssetMatcher(options: AssetMatchFilter): (entry: UploadResult) => boolean;
14
22
  /**
15
23
  * Pure offset-cursor pagination over a pre-filtered match list. Shared by
16
24
  * `runSearch` and the folder-scoped data-source path so the cursor contract is