bruce-models 7.1.119 → 7.1.121

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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
@@ -6821,7 +6838,7 @@ var Entity;
6821
6838
  const prom = new Promise((res, rej) => __awaiter(this, void 0, void 0, function* () {
6822
6839
  try {
6823
6840
  const urlParams = new URLSearchParams();
6824
- let expand;
6841
+ let expand = "";
6825
6842
  if (expandLocation) {
6826
6843
  expand = "location";
6827
6844
  }
@@ -9150,6 +9167,18 @@ var Uploader;
9150
9167
  const blob = file.slice(fileOffset, fileOffset + partSize);
9151
9168
  const partialFile = new File([blob], file.name, { type: file.type });
9152
9169
  const formData = new FormData();
9170
+ // Keep custom metadata on every part, including retries. Core transport fields are controlled below.
9171
+ const appendField = (key, value) => {
9172
+ if (!["file", "token", "count", "part", "originalfilename"].includes(key.toLowerCase())) {
9173
+ formData.append(key, value);
9174
+ }
9175
+ };
9176
+ if (typeof FormData !== "undefined" && (req === null || req === void 0 ? void 0 : req.formData) instanceof FormData) {
9177
+ req.formData.forEach((value, key) => appendField(key, value));
9178
+ }
9179
+ else if (req === null || req === void 0 ? void 0 : req.formData) {
9180
+ Object.keys(req.formData).forEach(key => appendField(key, req.formData[key]));
9181
+ }
9153
9182
  formData.append("originalFileName", file.name);
9154
9183
  formData.append("token", uploadToken);
9155
9184
  formData.append("count", "" + filePartsCount);
@@ -9215,6 +9244,101 @@ var Uploader;
9215
9244
  Uploader.DoMultiPartUpload = DoMultiPartUpload;
9216
9245
  })(Uploader || (Uploader = {}));
9217
9246
 
9247
+ /** Virtual folders organize Client Files without changing their storage paths or versions. */
9248
+ var ClientFileFolder;
9249
+ (function (ClientFileFolder) {
9250
+ /** Validate and normalize an ID for routes, queries and cache keys without rounding it. */
9251
+ function NormalizeId(id, allowZero = false) {
9252
+ if (typeof id === "number" && (!Number.isSafeInteger(id) || id < 0)) {
9253
+ throw new Error("Folder ID must be a safe integer, or a decimal string for a larger bigint ID.");
9254
+ }
9255
+ if ((typeof id !== "string" && typeof id !== "number") || !/^\d+$/.test(String(id))) {
9256
+ throw new Error("Folder ID must be a non-negative decimal integer.");
9257
+ }
9258
+ const value = String(id).replace(/^0+(?=\d)/, "");
9259
+ if ((!allowZero && value === "0") || value.length > 19 ||
9260
+ (value.length === 19 && value > "9223372036854775807")) {
9261
+ throw new Error("Folder ID must be a positive signed 64-bit integer (0 is allowed only for the top level or creation).");
9262
+ }
9263
+ return value;
9264
+ }
9265
+ ClientFileFolder.NormalizeId = NormalizeId;
9266
+ function Get(params) {
9267
+ return __awaiter(this, void 0, void 0, function* () {
9268
+ const id = NormalizeId(params.folderId);
9269
+ const api = params.api || ENVIRONMENT.Api().GetBruceApi();
9270
+ const key = GetCacheKey(id);
9271
+ const cache = api.GetCacheItem(key, params.req);
9272
+ if (cache === null || cache === void 0 ? void 0 : cache.found)
9273
+ return cache.data;
9274
+ const promise = api.GET(`clientFileFolder/${id}`, Api.PrepReqParams(params.req))
9275
+ .then(folder => ({ folder }));
9276
+ api.SetCacheItem({ key, value: promise, req: params.req });
9277
+ return promise;
9278
+ });
9279
+ }
9280
+ ClientFileFolder.Get = Get;
9281
+ /** Omit parentFolderId for all folders. Null or 0 selects only top-level folders. */
9282
+ function GetList(params = {}) {
9283
+ return __awaiter(this, void 0, void 0, function* () {
9284
+ const api = params.api || ENVIRONMENT.Api().GetBruceApi();
9285
+ const parent = params.parentFolderId === undefined ? undefined : NormalizeId(params.parentFolderId == null ? 0 : params.parentFolderId, true);
9286
+ const key = GetListCacheKey(parent);
9287
+ const cache = api.GetCacheItem(key, params.req);
9288
+ if (cache === null || cache === void 0 ? void 0 : cache.found)
9289
+ return cache.data;
9290
+ const url = "clientFileFolders" + (parent === undefined ? "" : `?parent_folder_id=${parent}`);
9291
+ const promise = api.GET(url, Api.PrepReqParams(params.req))
9292
+ .then(data => ({ folders: (data === null || data === void 0 ? void 0 : data.Items) || [] }));
9293
+ api.SetCacheItem({ key, value: promise, req: params.req });
9294
+ return promise;
9295
+ });
9296
+ }
9297
+ ClientFileFolder.GetList = GetList;
9298
+ /** Create when folderId and folder.ID are omitted or 0; otherwise update only supplied fields. */
9299
+ function Update(params) {
9300
+ return __awaiter(this, void 0, void 0, function* () {
9301
+ if (!params.folder)
9302
+ throw new Error("Folder data is required.");
9303
+ const folder = Object.assign({}, params.folder);
9304
+ const id = NormalizeId(params.folderId !== undefined ? params.folderId : folder.ID == null ? 0 : folder.ID, true);
9305
+ if (folder["Parent.ClientFileFolder.ID"] != null)
9306
+ NormalizeId(folder["Parent.ClientFileFolder.ID"], true);
9307
+ const api = params.api || ENVIRONMENT.Api().GetBruceApi();
9308
+ const result = yield api.POST(`clientFileFolder/${id}`, folder, Api.PrepReqParams(params.req));
9309
+ api.Cache.RemoveByStartsWith(Api.ECacheKey.ClientFileFolder);
9310
+ return { folder: result };
9311
+ });
9312
+ }
9313
+ ClientFileFolder.Update = Update;
9314
+ function Create(params) {
9315
+ return __awaiter(this, void 0, void 0, function* () {
9316
+ return Update(Object.assign(Object.assign({}, params), { folderId: 0 }));
9317
+ });
9318
+ }
9319
+ ClientFileFolder.Create = Create;
9320
+ /** Contents move into the deleted folder's parent (or the top level); files are preserved. */
9321
+ function Delete(params) {
9322
+ return __awaiter(this, void 0, void 0, function* () {
9323
+ const id = NormalizeId(params.folderId);
9324
+ const api = params.api || ENVIRONMENT.Api().GetBruceApi();
9325
+ yield api.DELETE(`clientFileFolder/${id}`, Api.PrepReqParams(params.req));
9326
+ // This prefix also covers folder records and all scoped file-count caches.
9327
+ api.Cache.RemoveByStartsWith(Api.ECacheKey.ClientFile);
9328
+ });
9329
+ }
9330
+ ClientFileFolder.Delete = Delete;
9331
+ function GetCacheKey(folderId) {
9332
+ return `${Api.ECacheKey.ClientFileFolder}${Api.ECacheKey.Id}${NormalizeId(folderId)}`;
9333
+ }
9334
+ ClientFileFolder.GetCacheKey = GetCacheKey;
9335
+ function GetListCacheKey(parentFolderId) {
9336
+ const parent = parentFolderId === undefined ? "all" : NormalizeId(parentFolderId == null ? 0 : parentFolderId, true);
9337
+ return `${Api.ECacheKey.ClientFileFolder}${Api.ECacheKey.ListId}${parent}`;
9338
+ }
9339
+ ClientFileFolder.GetListCacheKey = GetListCacheKey;
9340
+ })(ClientFileFolder || (ClientFileFolder = {}));
9341
+
9218
9342
  /**
9219
9343
  * Describes the "Client File" concept within Nextspace.
9220
9344
  * A client file is a record of a file uploaded to Bruce.
@@ -9331,10 +9455,7 @@ var ClientFile;
9331
9455
  Items: fileIds
9332
9456
  };
9333
9457
  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
- }
9458
+ api.Cache.RemoveByStartsWith(Api.ECacheKey.ClientFile);
9338
9459
  });
9339
9460
  }
9340
9461
  ClientFile.Delete = Delete;
@@ -9345,7 +9466,7 @@ var ClientFile;
9345
9466
  */
9346
9467
  function Upload(params) {
9347
9468
  return __awaiter(this, void 0, void 0, function* () {
9348
- let { api, file, purpose, req, onProgress } = params;
9469
+ let { api, file, purpose, folderId, req, onProgress } = params;
9349
9470
  if (!api) {
9350
9471
  api = ENVIRONMENT.Api().GetBruceApi();
9351
9472
  }
@@ -9357,6 +9478,7 @@ var ClientFile;
9357
9478
  throw ("You cannot upload a 0byte sized file.");
9358
9479
  }
9359
9480
  req = Api.PrepReqParams(req);
9481
+ req = PrepareUploadMetadata(req, folderId, purpose);
9360
9482
  let clientFile;
9361
9483
  if (size > Uploader.MIN_LARGE_FILE_SIZE) {
9362
9484
  clientFile = yield Uploader.DoMultiPartUpload({
@@ -9366,15 +9488,6 @@ var ClientFile;
9366
9488
  req,
9367
9489
  onProgress
9368
9490
  });
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
9491
  }
9379
9492
  else {
9380
9493
  req.onProgress = (progress) => {
@@ -9384,17 +9497,13 @@ var ClientFile;
9384
9497
  uploaded: false
9385
9498
  });
9386
9499
  };
9387
- if (purpose) {
9388
- req.formData = {
9389
- Purpose: purpose
9390
- };
9391
- }
9392
9500
  clientFile = yield api.UPLOAD("file/uploadNew", file, req);
9393
9501
  }
9394
9502
  onProgress === null || onProgress === void 0 ? void 0 : onProgress({
9395
9503
  percent: 100,
9396
9504
  uploaded: true
9397
9505
  });
9506
+ api.Cache.RemoveByStartsWith(Api.ECacheKey.ClientFile);
9398
9507
  return {
9399
9508
  clientFile
9400
9509
  };
@@ -9407,11 +9516,18 @@ var ClientFile;
9407
9516
  */
9408
9517
  function Update(params) {
9409
9518
  return __awaiter(this, void 0, void 0, function* () {
9410
- let { api, fileId, purpose, layerIds, req: reqParams, dataEntityId } = params;
9519
+ let { api, fileId, purpose, layerIds, folderId, req: reqParams, dataEntityId } = params;
9520
+ if (!fileId)
9521
+ throw new Error("File ID is required.");
9411
9522
  if (!api) {
9412
9523
  api = ENVIRONMENT.Api().GetBruceApi();
9413
9524
  }
9414
9525
  const data = {};
9526
+ if (folderId !== undefined) {
9527
+ if (folderId !== null)
9528
+ ClientFileFolder.NormalizeId(folderId, true);
9529
+ data["ClientFileFolder.ID"] = folderId;
9530
+ }
9415
9531
  if (layerIds != null) {
9416
9532
  data["Layer.ID"] = layerIds;
9417
9533
  }
@@ -9422,8 +9538,7 @@ var ClientFile;
9422
9538
  data["Data.Entity.ID"] = dataEntityId ? dataEntityId : "";
9423
9539
  }
9424
9540
  yield api.POST(`file/${fileId}/details`, data, Api.PrepReqParams(reqParams));
9425
- const cacheKey = GetCacheKey(fileId);
9426
- api.Cache.RemoveByContains(cacheKey);
9541
+ api.Cache.RemoveByStartsWith(Api.ECacheKey.ClientFile);
9427
9542
  });
9428
9543
  }
9429
9544
  ClientFile.Update = Update;
@@ -9491,19 +9606,19 @@ var ClientFile;
9491
9606
  */
9492
9607
  function GetCountsPurpose(params) {
9493
9608
  return __awaiter(this, void 0, void 0, function* () {
9494
- let { api, req: reqParams } = params;
9609
+ let { api, folderId, req: reqParams } = params;
9495
9610
  if (!api) {
9496
9611
  api = ENVIRONMENT.Api().GetBruceApi();
9497
9612
  }
9498
9613
  reqParams = Api.PrepReqParams(reqParams);
9499
- const key = GetCountsPurposeCacheKey();
9614
+ const key = GetCountsPurposeCacheKey(folderId);
9500
9615
  const cache = api.GetCacheItem(key, reqParams);
9501
9616
  if (cache === null || cache === void 0 ? void 0 : cache.found) {
9502
9617
  return cache.data;
9503
9618
  }
9504
9619
  const prom = new Promise((res, rej) => __awaiter(this, void 0, void 0, function* () {
9505
9620
  try {
9506
- const data = yield api.GET("file/purpose/counts", Api.PrepReqParams(reqParams));
9621
+ const data = yield api.GET(FolderQuery("file/purpose/counts", folderId), Api.PrepReqParams(reqParams));
9507
9622
  res({
9508
9623
  counts: data
9509
9624
  });
@@ -9530,19 +9645,19 @@ var ClientFile;
9530
9645
  */
9531
9646
  function GetCountsExtension(params) {
9532
9647
  return __awaiter(this, void 0, void 0, function* () {
9533
- let { api, req: reqParams } = params;
9648
+ let { api, folderId, req: reqParams } = params;
9534
9649
  if (!api) {
9535
9650
  api = ENVIRONMENT.Api().GetBruceApi();
9536
9651
  }
9537
9652
  reqParams = Api.PrepReqParams(reqParams);
9538
- const key = GetCountsExtensionCacheKey();
9653
+ const key = GetCountsExtensionCacheKey(folderId);
9539
9654
  const cache = api.GetCacheItem(key, reqParams);
9540
9655
  if (cache === null || cache === void 0 ? void 0 : cache.found) {
9541
9656
  return cache.data;
9542
9657
  }
9543
9658
  const prom = new Promise((res, rej) => __awaiter(this, void 0, void 0, function* () {
9544
9659
  try {
9545
- const data = yield api.GET("file/extension/counts", Api.PrepReqParams(reqParams));
9660
+ const data = yield api.GET(FolderQuery("file/extension/counts", folderId), Api.PrepReqParams(reqParams));
9546
9661
  res({
9547
9662
  counts: data
9548
9663
  });
@@ -9569,19 +9684,19 @@ var ClientFile;
9569
9684
  */
9570
9685
  function GetCountsMIMEType(params) {
9571
9686
  return __awaiter(this, void 0, void 0, function* () {
9572
- let { api, req: reqParams } = params;
9687
+ let { api, folderId, req: reqParams } = params;
9573
9688
  if (!api) {
9574
9689
  api = ENVIRONMENT.Api().GetBruceApi();
9575
9690
  }
9576
9691
  reqParams = Api.PrepReqParams(reqParams);
9577
- const key = GetCountsMIMETypeCacheKey();
9692
+ const key = GetCountsMIMETypeCacheKey(folderId);
9578
9693
  const cache = api.GetCacheItem(key, reqParams);
9579
9694
  if (cache === null || cache === void 0 ? void 0 : cache.found) {
9580
9695
  return cache.data;
9581
9696
  }
9582
9697
  const prom = new Promise((res, rej) => __awaiter(this, void 0, void 0, function* () {
9583
9698
  try {
9584
- const data = yield api.GET("file/mimetype/counts", Api.PrepReqParams(reqParams));
9699
+ const data = yield api.GET(FolderQuery("file/mimetype/counts", folderId), Api.PrepReqParams(reqParams));
9585
9700
  res({
9586
9701
  counts: data
9587
9702
  });
@@ -9608,19 +9723,19 @@ var ClientFile;
9608
9723
  */
9609
9724
  function GetCountsUser(params) {
9610
9725
  return __awaiter(this, void 0, void 0, function* () {
9611
- let { api, req: reqParams } = params;
9726
+ let { api, folderId, req: reqParams } = params;
9612
9727
  if (!api) {
9613
9728
  api = ENVIRONMENT.Api().GetBruceApi();
9614
9729
  }
9615
9730
  reqParams = Api.PrepReqParams(reqParams);
9616
- const key = GetCountsUserCacheKey();
9731
+ const key = GetCountsUserCacheKey(folderId);
9617
9732
  const cache = api.GetCacheItem(key, reqParams);
9618
9733
  if (cache === null || cache === void 0 ? void 0 : cache.found) {
9619
9734
  return cache.data;
9620
9735
  }
9621
9736
  const prom = new Promise((res, rej) => __awaiter(this, void 0, void 0, function* () {
9622
9737
  try {
9623
- const data = yield api.GET("file/user/counts", Api.PrepReqParams(reqParams));
9738
+ const data = yield api.GET(FolderQuery("file/user/counts", folderId), Api.PrepReqParams(reqParams));
9624
9739
  res({
9625
9740
  counts: data
9626
9741
  });
@@ -9655,6 +9770,8 @@ var ClientFile;
9655
9770
  EColumn["User"] = "user";
9656
9771
  EColumn["Extension"] = "extension";
9657
9772
  EColumn["Data"] = "data";
9773
+ // Exact folder equality only. Use 0 for top-level files.
9774
+ EColumn["Folder"] = "ClientFileFolder.ID";
9658
9775
  })(EColumn = Filter.EColumn || (Filter.EColumn = {}));
9659
9776
  let ESortOrder;
9660
9777
  (function (ESortOrder) {
@@ -9678,6 +9795,7 @@ var ClientFile;
9678
9795
  if (!api) {
9679
9796
  api = ENVIRONMENT.Api().GetBruceApi();
9680
9797
  }
9798
+ ValidateFolderFilter(filter);
9681
9799
  const data = yield api.POST("files/filtered", filter, Api.PrepReqParams(reqParams));
9682
9800
  return {
9683
9801
  clientFiles: data.Items,
@@ -9696,6 +9814,7 @@ var ClientFile;
9696
9814
  if (!api) {
9697
9815
  api = ENVIRONMENT.Api().GetBruceApi();
9698
9816
  }
9817
+ ValidateFolderFilter(filter);
9699
9818
  const res = yield api.POST("files/filtered/delete", filter, Api.PrepReqParams(reqParams));
9700
9819
  // We'll clear cache if at least one file was deleted.
9701
9820
  if ((res === null || res === void 0 ? void 0 : res.OK) && (res === null || res === void 0 ? void 0 : res.DeleteFilesCount) > 0) {
@@ -9708,6 +9827,87 @@ var ClientFile;
9708
9827
  });
9709
9828
  }
9710
9829
  ClientFile.DeleteList = DeleteList;
9830
+ function UpdateList(params) {
9831
+ return __awaiter(this, void 0, void 0, function* () {
9832
+ if (!params.items || params.items.some(item => !(item === null || item === void 0 ? void 0 : item.ID)))
9833
+ throw new Error("File ID is required for every update.");
9834
+ params.items.forEach(item => ValidateFolderFilter(item));
9835
+ const api = params.api || ENVIRONMENT.Api().GetBruceApi();
9836
+ const result = yield api.POST("file/details", { Items: params.items }, Api.PrepReqParams(params.req));
9837
+ api.Cache.RemoveByStartsWith(Api.ECacheKey.ClientFile);
9838
+ return { clientFiles: (result === null || result === void 0 ? void 0 : result.Items) || [], errors: (result === null || result === void 0 ? void 0 : result.Error) || [] };
9839
+ });
9840
+ }
9841
+ ClientFile.UpdateList = UpdateList;
9842
+ /** Modern list endpoint. GetList keeps using the legacy JSON filter for existing callers. */
9843
+ function GetListByQuery(params) {
9844
+ return __awaiter(this, void 0, void 0, function* () {
9845
+ const api = params.api || ENVIRONMENT.Api().GetBruceApi();
9846
+ const query = new URLSearchParams();
9847
+ Object.keys(params.filter || {}).forEach(key => {
9848
+ const value = params.filter[key];
9849
+ if (value === undefined)
9850
+ return;
9851
+ if (key === "ClientFileFolder.ID") {
9852
+ query.append(key, ClientFileFolder.NormalizeId(value == null ? 0 : value, true));
9853
+ }
9854
+ else if (value != null) {
9855
+ (Array.isArray(value) ? value : [value]).forEach(item => query.append(key, String(item)));
9856
+ }
9857
+ });
9858
+ const url = "files" + (query.toString() ? "?" + query.toString() : "");
9859
+ const result = yield api.GET(url, Api.PrepReqParams(params.req));
9860
+ return { clientFiles: (result === null || result === void 0 ? void 0 : result.Items) || [], totalCount: result === null || result === void 0 ? void 0 : result.TotalCount,
9861
+ nextPage: result === null || result === void 0 ? void 0 : result.NextPage, nextPageUrl: result === null || result === void 0 ? void 0 : result.NextPageURL };
9862
+ });
9863
+ }
9864
+ ClientFile.GetListByQuery = GetListByQuery;
9865
+ /** Replace file content through the existing update route, preserving membership when omitted. */
9866
+ function ReplaceContent(params) {
9867
+ return __awaiter(this, void 0, void 0, function* () {
9868
+ if (!params.fileId)
9869
+ throw new Error("File ID is required.");
9870
+ if (!params.file)
9871
+ throw new Error("File is required.");
9872
+ const api = params.api || ENVIRONMENT.Api().GetBruceApi();
9873
+ const req = PrepareUploadMetadata(params.req, params.folderId);
9874
+ const clientFile = yield api.UPLOAD(`file/update/${encodeURIComponent(params.fileId)}`, params.file, req);
9875
+ api.Cache.RemoveByStartsWith(Api.ECacheKey.ClientFile);
9876
+ return { clientFile };
9877
+ });
9878
+ }
9879
+ ClientFile.ReplaceContent = ReplaceContent;
9880
+ function ValidateFolderFilter(filter) {
9881
+ const folderId = filter === null || filter === void 0 ? void 0 : filter["ClientFileFolder.ID"];
9882
+ if (folderId != null)
9883
+ ClientFileFolder.NormalizeId(folderId, true);
9884
+ }
9885
+ function FolderQuery(url, folderId) {
9886
+ return folderId === undefined ? url : `${url}?ClientFileFolder.ID=${ClientFileFolder.NormalizeId(folderId == null ? 0 : folderId, true)}`;
9887
+ }
9888
+ function FolderCacheSuffix(folderId) {
9889
+ return folderId === undefined ? "" : `:folder:${ClientFileFolder.NormalizeId(folderId == null ? 0 : folderId, true)}`;
9890
+ }
9891
+ function PrepareUploadMetadata(base, folderId, purpose) {
9892
+ const req = Api.PrepReqParams(base);
9893
+ if (folderId === undefined && purpose === undefined)
9894
+ return req;
9895
+ const values = {};
9896
+ if (folderId !== undefined)
9897
+ values["ClientFileFolder.ID"] = ClientFileFolder.NormalizeId(folderId == null ? 0 : folderId, true);
9898
+ if (purpose !== undefined)
9899
+ values.Purpose = purpose;
9900
+ if (typeof FormData !== "undefined" && req.formData instanceof FormData) {
9901
+ const form = new FormData();
9902
+ req.formData.forEach((value, key) => form.append(key, value));
9903
+ Object.keys(values).forEach(key => form.set(key, values[key]));
9904
+ req.formData = form;
9905
+ }
9906
+ else {
9907
+ req.formData = Object.assign(Object.assign({}, req.formData), values);
9908
+ }
9909
+ return req;
9910
+ }
9711
9911
  /**
9712
9912
  * Utility for processing client files.
9713
9913
  * Commonly used to convert a file to a different format. Eg: FBX to GLB.
@@ -9759,20 +9959,20 @@ var ClientFile;
9759
9959
  return `${Api.ECacheKey.ClientFile}${Api.ECacheKey.Id}${fileId}`;
9760
9960
  }
9761
9961
  ClientFile.GetCacheKey = GetCacheKey;
9762
- function GetCountsPurposeCacheKey() {
9763
- return `${Api.ECacheKey.ClientFile}${Api.ECacheKey.ClientFileCountsPurpose}`;
9962
+ function GetCountsPurposeCacheKey(folderId) {
9963
+ return `${Api.ECacheKey.ClientFile}${Api.ECacheKey.ClientFileCountsPurpose}${FolderCacheSuffix(folderId)}`;
9764
9964
  }
9765
9965
  ClientFile.GetCountsPurposeCacheKey = GetCountsPurposeCacheKey;
9766
- function GetCountsExtensionCacheKey() {
9767
- return `${Api.ECacheKey.ClientFile}${Api.ECacheKey.ClientFileCountsExtension}`;
9966
+ function GetCountsExtensionCacheKey(folderId) {
9967
+ return `${Api.ECacheKey.ClientFile}${Api.ECacheKey.ClientFileCountsExtension}${FolderCacheSuffix(folderId)}`;
9768
9968
  }
9769
9969
  ClientFile.GetCountsExtensionCacheKey = GetCountsExtensionCacheKey;
9770
- function GetCountsMIMETypeCacheKey() {
9771
- return `${Api.ECacheKey.ClientFile}${Api.ECacheKey.ClientFileCountsMIMEType}`;
9970
+ function GetCountsMIMETypeCacheKey(folderId) {
9971
+ return `${Api.ECacheKey.ClientFile}${Api.ECacheKey.ClientFileCountsMIMEType}${FolderCacheSuffix(folderId)}`;
9772
9972
  }
9773
9973
  ClientFile.GetCountsMIMETypeCacheKey = GetCountsMIMETypeCacheKey;
9774
- function GetCountsUserCacheKey() {
9775
- return `${Api.ECacheKey.ClientFile}${Api.ECacheKey.ClientFileCountsUser}`;
9974
+ function GetCountsUserCacheKey(folderId) {
9975
+ return `${Api.ECacheKey.ClientFile}${Api.ECacheKey.ClientFileCountsUser}${FolderCacheSuffix(folderId)}`;
9776
9976
  }
9777
9977
  ClientFile.GetCountsUserCacheKey = GetCountsUserCacheKey;
9778
9978
  })(ClientFile || (ClientFile = {}));
@@ -25388,7 +25588,7 @@ function getFirstWrappedArray(data, wrapperKeys) {
25388
25588
  }
25389
25589
 
25390
25590
  // This is updated with the package.json version on build.
25391
- const VERSION = "7.1.119";
25591
+ const VERSION = "7.1.121";
25392
25592
 
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 };
25593
+ 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
25594
  //# sourceMappingURL=bruce-models.es5.js.map