bruce-models 7.1.120 → 7.1.122

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 (33) hide show
  1. package/README.md +26 -0
  2. package/dist/bruce-models.es5.js +257 -47
  3. package/dist/bruce-models.es5.js.map +1 -1
  4. package/dist/bruce-models.umd.js +254 -46
  5. package/dist/bruce-models.umd.js.map +1 -1
  6. package/dist/lib/account/account-concept.js +2 -0
  7. package/dist/lib/account/account-concept.js.map +1 -1
  8. package/dist/lib/ann-document/ann-document.js +12 -0
  9. package/dist/lib/ann-document/ann-document.js.map +1 -1
  10. package/dist/lib/api/api.js +1 -0
  11. package/dist/lib/api/api.js.map +1 -1
  12. package/dist/lib/bruce-models.js +2 -1
  13. package/dist/lib/bruce-models.js.map +1 -1
  14. package/dist/lib/client-file/client-file-folder.js +109 -0
  15. package/dist/lib/client-file/client-file-folder.js.map +1 -0
  16. package/dist/lib/client-file/client-file.js +119 -42
  17. package/dist/lib/client-file/client-file.js.map +1 -1
  18. package/dist/lib/data-lab/data-lab.js.map +1 -1
  19. package/dist/lib/entity/entity-historic-data.js +13 -3
  20. package/dist/lib/entity/entity-historic-data.js.map +1 -1
  21. package/dist/lib/internal/uploader.js +12 -0
  22. package/dist/lib/internal/uploader.js.map +1 -1
  23. package/dist/lib/server/record-change-feed.js +2 -0
  24. package/dist/lib/server/record-change-feed.js.map +1 -1
  25. package/dist/types/account/account-concept.d.ts +1 -0
  26. package/dist/types/ann-document/ann-document.d.ts +9 -0
  27. package/dist/types/api/api.d.ts +1 -0
  28. package/dist/types/bruce-models.d.ts +2 -1
  29. package/dist/types/client-file/client-file-folder.d.ts +55 -0
  30. package/dist/types/client-file/client-file.d.ts +68 -5
  31. package/dist/types/data-lab/data-lab.d.ts +15 -1
  32. package/dist/types/entity/entity-historic-data.d.ts +1 -0
  33. package/package.json +1 -1
package/README.md CHANGED
@@ -48,6 +48,32 @@ parameters. Both filters accept a single value or an array. Use
48
48
 
49
49
  <br>
50
50
 
51
+ ### Client File folders
52
+
53
+ `ClientFileFolder` manages virtual folders through `Get`, `GetList`, `Create`, `Update`, and `Delete`.
54
+ Deleting a folder moves its files and immediate subfolders into its parent, or the top level; it preserves file data.
55
+
56
+ ```ts
57
+ const { folder } = await ClientFileFolder.Create({ api, folder: { Name: "Plans" } });
58
+ await ClientFile.Upload({ api, file, folderId: folder.ID, purpose: "Import" });
59
+ await ClientFile.Update({ api, fileId, folderId: folder.ID });
60
+ const { clientFiles } = await ClientFile.GetList({
61
+ api, filter: { "ClientFileFolder.ID": folder.ID, Purpose: "Import" }
62
+ });
63
+ const { folders } = await ClientFileFolder.GetList({ api, parentFolderId: folder.ID });
64
+ ```
65
+
66
+ Omit the folder filter to include all folders; use `0` (or `null` in JSON filters) for top-level files.
67
+ Folder filters combine with the existing criteria and layer permissions. `ClientFile.GetListByQuery`
68
+ wraps `GET files` and also returns `nextPage` and `nextPageUrl`. Existing `GetList` callers keep using
69
+ `POST files/filtered` without changes.
70
+
71
+ `ClientFile.Update`, `UpdateList`, `ReplaceContent`, and `Upload` support folder membership. On updates,
72
+ omit the field to preserve it; set `null` or `0` to clear it. Upload metadata is carried on every multipart request.
73
+ All four `GetCounts*` methods accept `folderId`, with separate caches for each folder and the unfiltered result.
74
+ Pass bigint IDs outside JavaScript's safe integer range as decimal strings when supplying IDs to these methods.
75
+ Folder permissions and record-change events use the `clff` concept code.
76
+
51
77
  ### Local build
52
78
 
53
79
  - `npm i`
@@ -48,6 +48,7 @@ var Api;
48
48
  ECacheKey["ProjectViewBookmark"] = "pvbookmark";
49
49
  ECacheKey["Tileset"] = "tileset";
50
50
  ECacheKey["ClientFile"] = "clientfile";
51
+ ECacheKey["ClientFileFolder"] = "clientfilefolder";
51
52
  ECacheKey["ClientFileCountsPurpose"] = "clientfilecountspurpose";
52
53
  ECacheKey["ClientFileCountsExtension"] = "clientfilecountsextensions";
53
54
  ECacheKey["ClientFileCountsMIMEType"] = "clientfilecountsmimetypes";
@@ -340,6 +341,7 @@ var AccountConcept;
340
341
  EConcept["ATTACHMENT_TYPE"] = "at";
341
342
  EConcept["CHANGE_SET"] = "cs";
342
343
  EConcept["CLIENT_FILE"] = "clf";
344
+ EConcept["CLIENT_FILE_FOLDER"] = "clff";
343
345
  EConcept["COMMENT"] = "cm";
344
346
  EConcept["CUSTOM_FORM"] = "csf";
345
347
  EConcept["DATA_FEED"] = "df";
@@ -416,6 +418,7 @@ var AccountConcept;
416
418
  { concept: EConcept.ATTACHMENT_TYPE, label: "Attachment Type", description: undefined },
417
419
  { concept: EConcept.CHANGE_SET, label: "Change Set", description: undefined },
418
420
  { concept: EConcept.CLIENT_FILE, label: "Client File", description: undefined },
421
+ { concept: EConcept.CLIENT_FILE_FOLDER, label: "Client File Folder", description: "Virtual folders for Client Files" },
419
422
  { concept: EConcept.CUSTOM_FORM, label: "Custom Form", description: undefined },
420
423
  { concept: EConcept.DATA_FEED, label: "Data Feed", description: undefined },
421
424
  { concept: EConcept.DATA_LAB_QUERY, label: "DataLab Query", description: undefined },
@@ -666,6 +669,8 @@ var RecordChangeFeed;
666
669
  return [Api.ECacheKey.Assembly];
667
670
  case AccountConcept.EConcept.ATTACHMENT_TYPE:
668
671
  return [Api.ECacheKey.AttachmentType];
672
+ case AccountConcept.EConcept.CLIENT_FILE_FOLDER:
673
+ return [Api.ECacheKey.ClientFileFolder, ...RecordChangeFeed.getConceptCacheKeys(AccountConcept.EConcept.CLIENT_FILE)];
669
674
  case AccountConcept.EConcept.CLIENT_FILE:
670
675
  return [
671
676
  Api.ECacheKey.ClientFile,
@@ -4139,6 +4144,18 @@ var AnnDocument;
4139
4144
  });
4140
4145
  }
4141
4146
  AnnDocument.UploadPDF = UploadPDF;
4147
+ /** Renders every page of an existing PDF without saving a Document View. */
4148
+ function ImportPages(params) {
4149
+ return __awaiter(this, void 0, void 0, function* () {
4150
+ const { fileId, req } = params;
4151
+ if (!fileId || !fileId.trim()) {
4152
+ throw new Error("File ID is required.");
4153
+ }
4154
+ const api = params.api || ENVIRONMENT.Api().GetBruceApi();
4155
+ return api.POST("documentView/importPages", { "ClientFile.ID": fileId }, Api.PrepReqParams(req));
4156
+ });
4157
+ }
4158
+ AnnDocument.ImportPages = ImportPages;
4142
4159
  /**
4143
4160
  * Returns an annotated document by ID.
4144
4161
  * @param params
@@ -5608,7 +5625,8 @@ var EntityHistoricData;
5608
5625
  location: bruce.Location,
5609
5626
  transform: bruce.Transform,
5610
5627
  boundaries: bruce.Boundaries,
5611
- geometry: bruce.VectorGeometry
5628
+ geometry: bruce.VectorGeometry,
5629
+ assemblyPosition: bruce.AssemblyPosition
5612
5630
  };
5613
5631
  }
5614
5632
  EntityHistoricData.ToDataRecord = ToDataRecord;
@@ -5623,9 +5641,18 @@ var EntityHistoricData;
5623
5641
  if (!(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length) && !entityTypeId) {
5624
5642
  return { recordsByIds: {}, sample: 0 };
5625
5643
  }
5626
- const page = yield GetPage(Object.assign(Object.assign({}, params), { pageSize: params.sample > 0 ? undefined : (params.pageSize || 1000) }));
5644
+ // A page counts records across every Entity asked about, so the first page alone can stop partway
5645
+ // through the range. Read to its end, unless the caller asked for a page or a sample.
5646
+ const readAll = !(params.sample > 0) && params.pageIndex == null && params.pageSize == null;
5647
+ const items = [];
5648
+ let page = yield GetPage(Object.assign(Object.assign({}, params), { pageSize: params.sample > 0 ? undefined : (params.pageSize || 1000) }));
5649
+ items.push(...page.items);
5650
+ while (readAll && !(page.sample > 0) && page.pageSize > 0 && page.items.length >= page.pageSize) {
5651
+ page = yield GetPage(Object.assign(Object.assign({}, params), { pageIndex: page.pageIndex + 1, pageSize: page.pageSize }));
5652
+ items.push(...page.items);
5653
+ }
5627
5654
  const recordsByIds = {};
5628
- for (const item of page.items) {
5655
+ for (const item of items) {
5629
5656
  const record = ToDataRecord(item);
5630
5657
  if (!record.entityId) {
5631
5658
  continue;
@@ -9150,6 +9177,18 @@ var Uploader;
9150
9177
  const blob = file.slice(fileOffset, fileOffset + partSize);
9151
9178
  const partialFile = new File([blob], file.name, { type: file.type });
9152
9179
  const formData = new FormData();
9180
+ // Keep custom metadata on every part, including retries. Core transport fields are controlled below.
9181
+ const appendField = (key, value) => {
9182
+ if (!["file", "token", "count", "part", "originalfilename"].includes(key.toLowerCase())) {
9183
+ formData.append(key, value);
9184
+ }
9185
+ };
9186
+ if (typeof FormData !== "undefined" && (req === null || req === void 0 ? void 0 : req.formData) instanceof FormData) {
9187
+ req.formData.forEach((value, key) => appendField(key, value));
9188
+ }
9189
+ else if (req === null || req === void 0 ? void 0 : req.formData) {
9190
+ Object.keys(req.formData).forEach(key => appendField(key, req.formData[key]));
9191
+ }
9153
9192
  formData.append("originalFileName", file.name);
9154
9193
  formData.append("token", uploadToken);
9155
9194
  formData.append("count", "" + filePartsCount);
@@ -9215,6 +9254,101 @@ var Uploader;
9215
9254
  Uploader.DoMultiPartUpload = DoMultiPartUpload;
9216
9255
  })(Uploader || (Uploader = {}));
9217
9256
 
9257
+ /** Virtual folders organize Client Files without changing their storage paths or versions. */
9258
+ var ClientFileFolder;
9259
+ (function (ClientFileFolder) {
9260
+ /** Validate and normalize an ID for routes, queries and cache keys without rounding it. */
9261
+ function NormalizeId(id, allowZero = false) {
9262
+ if (typeof id === "number" && (!Number.isSafeInteger(id) || id < 0)) {
9263
+ throw new Error("Folder ID must be a safe integer, or a decimal string for a larger bigint ID.");
9264
+ }
9265
+ if ((typeof id !== "string" && typeof id !== "number") || !/^\d+$/.test(String(id))) {
9266
+ throw new Error("Folder ID must be a non-negative decimal integer.");
9267
+ }
9268
+ const value = String(id).replace(/^0+(?=\d)/, "");
9269
+ if ((!allowZero && value === "0") || value.length > 19 ||
9270
+ (value.length === 19 && value > "9223372036854775807")) {
9271
+ throw new Error("Folder ID must be a positive signed 64-bit integer (0 is allowed only for the top level or creation).");
9272
+ }
9273
+ return value;
9274
+ }
9275
+ ClientFileFolder.NormalizeId = NormalizeId;
9276
+ function Get(params) {
9277
+ return __awaiter(this, void 0, void 0, function* () {
9278
+ const id = NormalizeId(params.folderId);
9279
+ const api = params.api || ENVIRONMENT.Api().GetBruceApi();
9280
+ const key = GetCacheKey(id);
9281
+ const cache = api.GetCacheItem(key, params.req);
9282
+ if (cache === null || cache === void 0 ? void 0 : cache.found)
9283
+ return cache.data;
9284
+ const promise = api.GET(`clientFileFolder/${id}`, Api.PrepReqParams(params.req))
9285
+ .then(folder => ({ folder }));
9286
+ api.SetCacheItem({ key, value: promise, req: params.req });
9287
+ return promise;
9288
+ });
9289
+ }
9290
+ ClientFileFolder.Get = Get;
9291
+ /** Omit parentFolderId for all folders. Null or 0 selects only top-level folders. */
9292
+ function GetList(params = {}) {
9293
+ return __awaiter(this, void 0, void 0, function* () {
9294
+ const api = params.api || ENVIRONMENT.Api().GetBruceApi();
9295
+ const parent = params.parentFolderId === undefined ? undefined : NormalizeId(params.parentFolderId == null ? 0 : params.parentFolderId, true);
9296
+ const key = GetListCacheKey(parent);
9297
+ const cache = api.GetCacheItem(key, params.req);
9298
+ if (cache === null || cache === void 0 ? void 0 : cache.found)
9299
+ return cache.data;
9300
+ const url = "clientFileFolders" + (parent === undefined ? "" : `?parent_folder_id=${parent}`);
9301
+ const promise = api.GET(url, Api.PrepReqParams(params.req))
9302
+ .then(data => ({ folders: (data === null || data === void 0 ? void 0 : data.Items) || [] }));
9303
+ api.SetCacheItem({ key, value: promise, req: params.req });
9304
+ return promise;
9305
+ });
9306
+ }
9307
+ ClientFileFolder.GetList = GetList;
9308
+ /** Create when folderId and folder.ID are omitted or 0; otherwise update only supplied fields. */
9309
+ function Update(params) {
9310
+ return __awaiter(this, void 0, void 0, function* () {
9311
+ if (!params.folder)
9312
+ throw new Error("Folder data is required.");
9313
+ const folder = Object.assign({}, params.folder);
9314
+ const id = NormalizeId(params.folderId !== undefined ? params.folderId : folder.ID == null ? 0 : folder.ID, true);
9315
+ if (folder["Parent.ClientFileFolder.ID"] != null)
9316
+ NormalizeId(folder["Parent.ClientFileFolder.ID"], true);
9317
+ const api = params.api || ENVIRONMENT.Api().GetBruceApi();
9318
+ const result = yield api.POST(`clientFileFolder/${id}`, folder, Api.PrepReqParams(params.req));
9319
+ api.Cache.RemoveByStartsWith(Api.ECacheKey.ClientFileFolder);
9320
+ return { folder: result };
9321
+ });
9322
+ }
9323
+ ClientFileFolder.Update = Update;
9324
+ function Create(params) {
9325
+ return __awaiter(this, void 0, void 0, function* () {
9326
+ return Update(Object.assign(Object.assign({}, params), { folderId: 0 }));
9327
+ });
9328
+ }
9329
+ ClientFileFolder.Create = Create;
9330
+ /** Contents move into the deleted folder's parent (or the top level); files are preserved. */
9331
+ function Delete(params) {
9332
+ return __awaiter(this, void 0, void 0, function* () {
9333
+ const id = NormalizeId(params.folderId);
9334
+ const api = params.api || ENVIRONMENT.Api().GetBruceApi();
9335
+ yield api.DELETE(`clientFileFolder/${id}`, Api.PrepReqParams(params.req));
9336
+ // This prefix also covers folder records and all scoped file-count caches.
9337
+ api.Cache.RemoveByStartsWith(Api.ECacheKey.ClientFile);
9338
+ });
9339
+ }
9340
+ ClientFileFolder.Delete = Delete;
9341
+ function GetCacheKey(folderId) {
9342
+ return `${Api.ECacheKey.ClientFileFolder}${Api.ECacheKey.Id}${NormalizeId(folderId)}`;
9343
+ }
9344
+ ClientFileFolder.GetCacheKey = GetCacheKey;
9345
+ function GetListCacheKey(parentFolderId) {
9346
+ const parent = parentFolderId === undefined ? "all" : NormalizeId(parentFolderId == null ? 0 : parentFolderId, true);
9347
+ return `${Api.ECacheKey.ClientFileFolder}${Api.ECacheKey.ListId}${parent}`;
9348
+ }
9349
+ ClientFileFolder.GetListCacheKey = GetListCacheKey;
9350
+ })(ClientFileFolder || (ClientFileFolder = {}));
9351
+
9218
9352
  /**
9219
9353
  * Describes the "Client File" concept within Nextspace.
9220
9354
  * A client file is a record of a file uploaded to Bruce.
@@ -9331,10 +9465,7 @@ var ClientFile;
9331
9465
  Items: fileIds
9332
9466
  };
9333
9467
  yield api.POST("deleteFiles", data, Api.PrepReqParams(reqParams));
9334
- for (let i = 0; i < fileIds.length; i++) {
9335
- const key = GetCacheKey(fileIds[i]);
9336
- api.Cache.Remove(key);
9337
- }
9468
+ api.Cache.RemoveByStartsWith(Api.ECacheKey.ClientFile);
9338
9469
  });
9339
9470
  }
9340
9471
  ClientFile.Delete = Delete;
@@ -9345,7 +9476,7 @@ var ClientFile;
9345
9476
  */
9346
9477
  function Upload(params) {
9347
9478
  return __awaiter(this, void 0, void 0, function* () {
9348
- let { api, file, purpose, req, onProgress } = params;
9479
+ let { api, file, purpose, folderId, req, onProgress } = params;
9349
9480
  if (!api) {
9350
9481
  api = ENVIRONMENT.Api().GetBruceApi();
9351
9482
  }
@@ -9357,6 +9488,7 @@ var ClientFile;
9357
9488
  throw ("You cannot upload a 0byte sized file.");
9358
9489
  }
9359
9490
  req = Api.PrepReqParams(req);
9491
+ req = PrepareUploadMetadata(req, folderId, purpose);
9360
9492
  let clientFile;
9361
9493
  if (size > Uploader.MIN_LARGE_FILE_SIZE) {
9362
9494
  clientFile = yield Uploader.DoMultiPartUpload({
@@ -9366,15 +9498,6 @@ var ClientFile;
9366
9498
  req,
9367
9499
  onProgress
9368
9500
  });
9369
- // TODO: Check if we can add it to the request like the small file upload.
9370
- if ((clientFile === null || clientFile === void 0 ? void 0 : clientFile.ID) && purpose) {
9371
- yield ClientFile.UpdatePurpose({
9372
- api,
9373
- fileId: clientFile.ID,
9374
- purpose,
9375
- req
9376
- });
9377
- }
9378
9501
  }
9379
9502
  else {
9380
9503
  req.onProgress = (progress) => {
@@ -9384,17 +9507,13 @@ var ClientFile;
9384
9507
  uploaded: false
9385
9508
  });
9386
9509
  };
9387
- if (purpose) {
9388
- req.formData = {
9389
- Purpose: purpose
9390
- };
9391
- }
9392
9510
  clientFile = yield api.UPLOAD("file/uploadNew", file, req);
9393
9511
  }
9394
9512
  onProgress === null || onProgress === void 0 ? void 0 : onProgress({
9395
9513
  percent: 100,
9396
9514
  uploaded: true
9397
9515
  });
9516
+ api.Cache.RemoveByStartsWith(Api.ECacheKey.ClientFile);
9398
9517
  return {
9399
9518
  clientFile
9400
9519
  };
@@ -9407,11 +9526,18 @@ var ClientFile;
9407
9526
  */
9408
9527
  function Update(params) {
9409
9528
  return __awaiter(this, void 0, void 0, function* () {
9410
- let { api, fileId, purpose, layerIds, req: reqParams, dataEntityId } = params;
9529
+ let { api, fileId, purpose, layerIds, folderId, req: reqParams, dataEntityId } = params;
9530
+ if (!fileId)
9531
+ throw new Error("File ID is required.");
9411
9532
  if (!api) {
9412
9533
  api = ENVIRONMENT.Api().GetBruceApi();
9413
9534
  }
9414
9535
  const data = {};
9536
+ if (folderId !== undefined) {
9537
+ if (folderId !== null)
9538
+ ClientFileFolder.NormalizeId(folderId, true);
9539
+ data["ClientFileFolder.ID"] = folderId;
9540
+ }
9415
9541
  if (layerIds != null) {
9416
9542
  data["Layer.ID"] = layerIds;
9417
9543
  }
@@ -9422,8 +9548,7 @@ var ClientFile;
9422
9548
  data["Data.Entity.ID"] = dataEntityId ? dataEntityId : "";
9423
9549
  }
9424
9550
  yield api.POST(`file/${fileId}/details`, data, Api.PrepReqParams(reqParams));
9425
- const cacheKey = GetCacheKey(fileId);
9426
- api.Cache.RemoveByContains(cacheKey);
9551
+ api.Cache.RemoveByStartsWith(Api.ECacheKey.ClientFile);
9427
9552
  });
9428
9553
  }
9429
9554
  ClientFile.Update = Update;
@@ -9491,19 +9616,19 @@ var ClientFile;
9491
9616
  */
9492
9617
  function GetCountsPurpose(params) {
9493
9618
  return __awaiter(this, void 0, void 0, function* () {
9494
- let { api, req: reqParams } = params;
9619
+ let { api, folderId, req: reqParams } = params;
9495
9620
  if (!api) {
9496
9621
  api = ENVIRONMENT.Api().GetBruceApi();
9497
9622
  }
9498
9623
  reqParams = Api.PrepReqParams(reqParams);
9499
- const key = GetCountsPurposeCacheKey();
9624
+ const key = GetCountsPurposeCacheKey(folderId);
9500
9625
  const cache = api.GetCacheItem(key, reqParams);
9501
9626
  if (cache === null || cache === void 0 ? void 0 : cache.found) {
9502
9627
  return cache.data;
9503
9628
  }
9504
9629
  const prom = new Promise((res, rej) => __awaiter(this, void 0, void 0, function* () {
9505
9630
  try {
9506
- const data = yield api.GET("file/purpose/counts", Api.PrepReqParams(reqParams));
9631
+ const data = yield api.GET(FolderQuery("file/purpose/counts", folderId), Api.PrepReqParams(reqParams));
9507
9632
  res({
9508
9633
  counts: data
9509
9634
  });
@@ -9530,19 +9655,19 @@ var ClientFile;
9530
9655
  */
9531
9656
  function GetCountsExtension(params) {
9532
9657
  return __awaiter(this, void 0, void 0, function* () {
9533
- let { api, req: reqParams } = params;
9658
+ let { api, folderId, req: reqParams } = params;
9534
9659
  if (!api) {
9535
9660
  api = ENVIRONMENT.Api().GetBruceApi();
9536
9661
  }
9537
9662
  reqParams = Api.PrepReqParams(reqParams);
9538
- const key = GetCountsExtensionCacheKey();
9663
+ const key = GetCountsExtensionCacheKey(folderId);
9539
9664
  const cache = api.GetCacheItem(key, reqParams);
9540
9665
  if (cache === null || cache === void 0 ? void 0 : cache.found) {
9541
9666
  return cache.data;
9542
9667
  }
9543
9668
  const prom = new Promise((res, rej) => __awaiter(this, void 0, void 0, function* () {
9544
9669
  try {
9545
- const data = yield api.GET("file/extension/counts", Api.PrepReqParams(reqParams));
9670
+ const data = yield api.GET(FolderQuery("file/extension/counts", folderId), Api.PrepReqParams(reqParams));
9546
9671
  res({
9547
9672
  counts: data
9548
9673
  });
@@ -9569,19 +9694,19 @@ var ClientFile;
9569
9694
  */
9570
9695
  function GetCountsMIMEType(params) {
9571
9696
  return __awaiter(this, void 0, void 0, function* () {
9572
- let { api, req: reqParams } = params;
9697
+ let { api, folderId, req: reqParams } = params;
9573
9698
  if (!api) {
9574
9699
  api = ENVIRONMENT.Api().GetBruceApi();
9575
9700
  }
9576
9701
  reqParams = Api.PrepReqParams(reqParams);
9577
- const key = GetCountsMIMETypeCacheKey();
9702
+ const key = GetCountsMIMETypeCacheKey(folderId);
9578
9703
  const cache = api.GetCacheItem(key, reqParams);
9579
9704
  if (cache === null || cache === void 0 ? void 0 : cache.found) {
9580
9705
  return cache.data;
9581
9706
  }
9582
9707
  const prom = new Promise((res, rej) => __awaiter(this, void 0, void 0, function* () {
9583
9708
  try {
9584
- const data = yield api.GET("file/mimetype/counts", Api.PrepReqParams(reqParams));
9709
+ const data = yield api.GET(FolderQuery("file/mimetype/counts", folderId), Api.PrepReqParams(reqParams));
9585
9710
  res({
9586
9711
  counts: data
9587
9712
  });
@@ -9608,19 +9733,19 @@ var ClientFile;
9608
9733
  */
9609
9734
  function GetCountsUser(params) {
9610
9735
  return __awaiter(this, void 0, void 0, function* () {
9611
- let { api, req: reqParams } = params;
9736
+ let { api, folderId, req: reqParams } = params;
9612
9737
  if (!api) {
9613
9738
  api = ENVIRONMENT.Api().GetBruceApi();
9614
9739
  }
9615
9740
  reqParams = Api.PrepReqParams(reqParams);
9616
- const key = GetCountsUserCacheKey();
9741
+ const key = GetCountsUserCacheKey(folderId);
9617
9742
  const cache = api.GetCacheItem(key, reqParams);
9618
9743
  if (cache === null || cache === void 0 ? void 0 : cache.found) {
9619
9744
  return cache.data;
9620
9745
  }
9621
9746
  const prom = new Promise((res, rej) => __awaiter(this, void 0, void 0, function* () {
9622
9747
  try {
9623
- const data = yield api.GET("file/user/counts", Api.PrepReqParams(reqParams));
9748
+ const data = yield api.GET(FolderQuery("file/user/counts", folderId), Api.PrepReqParams(reqParams));
9624
9749
  res({
9625
9750
  counts: data
9626
9751
  });
@@ -9655,6 +9780,8 @@ var ClientFile;
9655
9780
  EColumn["User"] = "user";
9656
9781
  EColumn["Extension"] = "extension";
9657
9782
  EColumn["Data"] = "data";
9783
+ // Exact folder equality only. Use 0 for top-level files.
9784
+ EColumn["Folder"] = "ClientFileFolder.ID";
9658
9785
  })(EColumn = Filter.EColumn || (Filter.EColumn = {}));
9659
9786
  let ESortOrder;
9660
9787
  (function (ESortOrder) {
@@ -9678,6 +9805,7 @@ var ClientFile;
9678
9805
  if (!api) {
9679
9806
  api = ENVIRONMENT.Api().GetBruceApi();
9680
9807
  }
9808
+ ValidateFolderFilter(filter);
9681
9809
  const data = yield api.POST("files/filtered", filter, Api.PrepReqParams(reqParams));
9682
9810
  return {
9683
9811
  clientFiles: data.Items,
@@ -9696,6 +9824,7 @@ var ClientFile;
9696
9824
  if (!api) {
9697
9825
  api = ENVIRONMENT.Api().GetBruceApi();
9698
9826
  }
9827
+ ValidateFolderFilter(filter);
9699
9828
  const res = yield api.POST("files/filtered/delete", filter, Api.PrepReqParams(reqParams));
9700
9829
  // We'll clear cache if at least one file was deleted.
9701
9830
  if ((res === null || res === void 0 ? void 0 : res.OK) && (res === null || res === void 0 ? void 0 : res.DeleteFilesCount) > 0) {
@@ -9708,6 +9837,87 @@ var ClientFile;
9708
9837
  });
9709
9838
  }
9710
9839
  ClientFile.DeleteList = DeleteList;
9840
+ function UpdateList(params) {
9841
+ return __awaiter(this, void 0, void 0, function* () {
9842
+ if (!params.items || params.items.some(item => !(item === null || item === void 0 ? void 0 : item.ID)))
9843
+ throw new Error("File ID is required for every update.");
9844
+ params.items.forEach(item => ValidateFolderFilter(item));
9845
+ const api = params.api || ENVIRONMENT.Api().GetBruceApi();
9846
+ const result = yield api.POST("file/details", { Items: params.items }, Api.PrepReqParams(params.req));
9847
+ api.Cache.RemoveByStartsWith(Api.ECacheKey.ClientFile);
9848
+ return { clientFiles: (result === null || result === void 0 ? void 0 : result.Items) || [], errors: (result === null || result === void 0 ? void 0 : result.Error) || [] };
9849
+ });
9850
+ }
9851
+ ClientFile.UpdateList = UpdateList;
9852
+ /** Modern list endpoint. GetList keeps using the legacy JSON filter for existing callers. */
9853
+ function GetListByQuery(params) {
9854
+ return __awaiter(this, void 0, void 0, function* () {
9855
+ const api = params.api || ENVIRONMENT.Api().GetBruceApi();
9856
+ const query = new URLSearchParams();
9857
+ Object.keys(params.filter || {}).forEach(key => {
9858
+ const value = params.filter[key];
9859
+ if (value === undefined)
9860
+ return;
9861
+ if (key === "ClientFileFolder.ID") {
9862
+ query.append(key, ClientFileFolder.NormalizeId(value == null ? 0 : value, true));
9863
+ }
9864
+ else if (value != null) {
9865
+ (Array.isArray(value) ? value : [value]).forEach(item => query.append(key, String(item)));
9866
+ }
9867
+ });
9868
+ const url = "files" + (query.toString() ? "?" + query.toString() : "");
9869
+ const result = yield api.GET(url, Api.PrepReqParams(params.req));
9870
+ return { clientFiles: (result === null || result === void 0 ? void 0 : result.Items) || [], totalCount: result === null || result === void 0 ? void 0 : result.TotalCount,
9871
+ nextPage: result === null || result === void 0 ? void 0 : result.NextPage, nextPageUrl: result === null || result === void 0 ? void 0 : result.NextPageURL };
9872
+ });
9873
+ }
9874
+ ClientFile.GetListByQuery = GetListByQuery;
9875
+ /** Replace file content through the existing update route, preserving membership when omitted. */
9876
+ function ReplaceContent(params) {
9877
+ return __awaiter(this, void 0, void 0, function* () {
9878
+ if (!params.fileId)
9879
+ throw new Error("File ID is required.");
9880
+ if (!params.file)
9881
+ throw new Error("File is required.");
9882
+ const api = params.api || ENVIRONMENT.Api().GetBruceApi();
9883
+ const req = PrepareUploadMetadata(params.req, params.folderId);
9884
+ const clientFile = yield api.UPLOAD(`file/update/${encodeURIComponent(params.fileId)}`, params.file, req);
9885
+ api.Cache.RemoveByStartsWith(Api.ECacheKey.ClientFile);
9886
+ return { clientFile };
9887
+ });
9888
+ }
9889
+ ClientFile.ReplaceContent = ReplaceContent;
9890
+ function ValidateFolderFilter(filter) {
9891
+ const folderId = filter === null || filter === void 0 ? void 0 : filter["ClientFileFolder.ID"];
9892
+ if (folderId != null)
9893
+ ClientFileFolder.NormalizeId(folderId, true);
9894
+ }
9895
+ function FolderQuery(url, folderId) {
9896
+ return folderId === undefined ? url : `${url}?ClientFileFolder.ID=${ClientFileFolder.NormalizeId(folderId == null ? 0 : folderId, true)}`;
9897
+ }
9898
+ function FolderCacheSuffix(folderId) {
9899
+ return folderId === undefined ? "" : `:folder:${ClientFileFolder.NormalizeId(folderId == null ? 0 : folderId, true)}`;
9900
+ }
9901
+ function PrepareUploadMetadata(base, folderId, purpose) {
9902
+ const req = Api.PrepReqParams(base);
9903
+ if (folderId === undefined && purpose === undefined)
9904
+ return req;
9905
+ const values = {};
9906
+ if (folderId !== undefined)
9907
+ values["ClientFileFolder.ID"] = ClientFileFolder.NormalizeId(folderId == null ? 0 : folderId, true);
9908
+ if (purpose !== undefined)
9909
+ values.Purpose = purpose;
9910
+ if (typeof FormData !== "undefined" && req.formData instanceof FormData) {
9911
+ const form = new FormData();
9912
+ req.formData.forEach((value, key) => form.append(key, value));
9913
+ Object.keys(values).forEach(key => form.set(key, values[key]));
9914
+ req.formData = form;
9915
+ }
9916
+ else {
9917
+ req.formData = Object.assign(Object.assign({}, req.formData), values);
9918
+ }
9919
+ return req;
9920
+ }
9711
9921
  /**
9712
9922
  * Utility for processing client files.
9713
9923
  * Commonly used to convert a file to a different format. Eg: FBX to GLB.
@@ -9759,20 +9969,20 @@ var ClientFile;
9759
9969
  return `${Api.ECacheKey.ClientFile}${Api.ECacheKey.Id}${fileId}`;
9760
9970
  }
9761
9971
  ClientFile.GetCacheKey = GetCacheKey;
9762
- function GetCountsPurposeCacheKey() {
9763
- return `${Api.ECacheKey.ClientFile}${Api.ECacheKey.ClientFileCountsPurpose}`;
9972
+ function GetCountsPurposeCacheKey(folderId) {
9973
+ return `${Api.ECacheKey.ClientFile}${Api.ECacheKey.ClientFileCountsPurpose}${FolderCacheSuffix(folderId)}`;
9764
9974
  }
9765
9975
  ClientFile.GetCountsPurposeCacheKey = GetCountsPurposeCacheKey;
9766
- function GetCountsExtensionCacheKey() {
9767
- return `${Api.ECacheKey.ClientFile}${Api.ECacheKey.ClientFileCountsExtension}`;
9976
+ function GetCountsExtensionCacheKey(folderId) {
9977
+ return `${Api.ECacheKey.ClientFile}${Api.ECacheKey.ClientFileCountsExtension}${FolderCacheSuffix(folderId)}`;
9768
9978
  }
9769
9979
  ClientFile.GetCountsExtensionCacheKey = GetCountsExtensionCacheKey;
9770
- function GetCountsMIMETypeCacheKey() {
9771
- return `${Api.ECacheKey.ClientFile}${Api.ECacheKey.ClientFileCountsMIMEType}`;
9980
+ function GetCountsMIMETypeCacheKey(folderId) {
9981
+ return `${Api.ECacheKey.ClientFile}${Api.ECacheKey.ClientFileCountsMIMEType}${FolderCacheSuffix(folderId)}`;
9772
9982
  }
9773
9983
  ClientFile.GetCountsMIMETypeCacheKey = GetCountsMIMETypeCacheKey;
9774
- function GetCountsUserCacheKey() {
9775
- return `${Api.ECacheKey.ClientFile}${Api.ECacheKey.ClientFileCountsUser}`;
9984
+ function GetCountsUserCacheKey(folderId) {
9985
+ return `${Api.ECacheKey.ClientFile}${Api.ECacheKey.ClientFileCountsUser}${FolderCacheSuffix(folderId)}`;
9776
9986
  }
9777
9987
  ClientFile.GetCountsUserCacheKey = GetCountsUserCacheKey;
9778
9988
  })(ClientFile || (ClientFile = {}));
@@ -25388,7 +25598,7 @@ function getFirstWrappedArray(data, wrapperKeys) {
25388
25598
  }
25389
25599
 
25390
25600
  // This is updated with the package.json version on build.
25391
- const VERSION = "7.1.120";
25601
+ const VERSION = "7.1.122";
25392
25602
 
25393
- export { VERSION, Account, AccountAudit, AccountConcept, AccountFeatures, AccountInvite, AccountLimits, AccountTemplate, AccountType, AnnDocument, AbstractApi, Api, ApiGetters, BruceApi, GlobalApi, GuardianApi, Assembly, Calculator, ChangeSet, ClientFile, ClientFileValueMap, Bounds, BruceEvent, BruceVariable, CacheControl, Camera, Cartes, Carto, Color, DelayQueue, RequestLane, GeoJson, Geometry, LRUCache, UTC, CustomForm, DashboardView, DataFeed, DataLab, DataLabGroup, DataSource, DataTransform, Comment, Entity, EntityAttachment, EntityAttachmentType, EntityAttribute, EntityComment, EntityCoords, EntityHistoricData, EntityLink, EntityLod, EntityLodCategory, EntityRelation, EntityRelationType, EntitySource, EntityTableView, EntityTag, EntityType, EntityTypeRelation, EntityTypeSource, EntityTypeTrigger, Ontology, OntologyDocument, ENVIRONMENT, ExportBrz, ExportCsv, ExportNsx, ExportUsd, Hexbin, ImportAssembly, ImportCad, ImportCsv, ImportGeoJson, ImportJson, ImportKml, ImportLcc, ImportTif, ImportedFile, Uploader, Markup, UIMarkup, NAVIGATOR_CHAT_EVENT_ENTITY_HIGHLIGHT_APPLIED, NAVIGATOR_CHAT_EVENT_SCENE_CONTEXT_PREFETCHED, NavigatorChatClient, NavigatorMcpWebSocketClient, Plugin, PluginAiTool, ProgramKey, MenuItem, ProjectView, ProjectViewBookmark, ProjectViewBookmarkGroup, ProjectViewLegacy, ProjectViewLegacyBookmark, ProjectViewLegacyTile, ProjectViewTile, ZoomControl, Scenario, HostingLocation, MessageBroker, PendingAction, RecordChangeFeed, Style, Tileset, Tracking, Permission, Session, User, UserGroup, UserMfaMethod, EncryptUtils, MathUtils, ObjectUtils, PathUtils, UrlUtils, WorkflowItem, WorkflowSchedule, WorkflowType, WorkflowItemType };
25603
+ export { VERSION, Account, AccountAudit, AccountConcept, AccountFeatures, AccountInvite, AccountLimits, AccountTemplate, AccountType, AnnDocument, AbstractApi, Api, ApiGetters, BruceApi, GlobalApi, GuardianApi, Assembly, Calculator, ChangeSet, ClientFile, ClientFileFolder, ClientFileValueMap, Bounds, BruceEvent, BruceVariable, CacheControl, Camera, Cartes, Carto, Color, DelayQueue, RequestLane, GeoJson, Geometry, LRUCache, UTC, CustomForm, DashboardView, DataFeed, DataLab, DataLabGroup, DataSource, DataTransform, Comment, Entity, EntityAttachment, EntityAttachmentType, EntityAttribute, EntityComment, EntityCoords, EntityHistoricData, EntityLink, EntityLod, EntityLodCategory, EntityRelation, EntityRelationType, EntitySource, EntityTableView, EntityTag, EntityType, EntityTypeRelation, EntityTypeSource, EntityTypeTrigger, Ontology, OntologyDocument, ENVIRONMENT, ExportBrz, ExportCsv, ExportNsx, ExportUsd, Hexbin, ImportAssembly, ImportCad, ImportCsv, ImportGeoJson, ImportJson, ImportKml, ImportLcc, ImportTif, ImportedFile, Uploader, Markup, UIMarkup, NAVIGATOR_CHAT_EVENT_ENTITY_HIGHLIGHT_APPLIED, NAVIGATOR_CHAT_EVENT_SCENE_CONTEXT_PREFETCHED, NavigatorChatClient, NavigatorMcpWebSocketClient, Plugin, PluginAiTool, ProgramKey, MenuItem, ProjectView, ProjectViewBookmark, ProjectViewBookmarkGroup, ProjectViewLegacy, ProjectViewLegacyBookmark, ProjectViewLegacyTile, ProjectViewTile, ZoomControl, Scenario, HostingLocation, MessageBroker, PendingAction, RecordChangeFeed, Style, Tileset, Tracking, Permission, Session, User, UserGroup, UserMfaMethod, EncryptUtils, MathUtils, ObjectUtils, PathUtils, UrlUtils, WorkflowItem, WorkflowSchedule, WorkflowType, WorkflowItemType };
25394
25604
  //# sourceMappingURL=bruce-models.es5.js.map