@twinfinity/twin 6.0.1 → 6.0.2-ci.29168

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 (84) hide show
  1. package/dist/BuildInfo.js +3 -3
  2. package/dist/TwinClient.d.ts +159 -0
  3. package/dist/TwinClient.d.ts.map +1 -1
  4. package/dist/TwinClient.js +323 -28
  5. package/dist/TwinClient.js.map +1 -1
  6. package/dist/errors.d.ts +114 -3
  7. package/dist/errors.d.ts.map +1 -1
  8. package/dist/errors.js +142 -0
  9. package/dist/errors.js.map +1 -1
  10. package/dist/tsconfig.tsbuildinfo +1 -1
  11. package/dist/types/asset-types-api.d.ts +76 -0
  12. package/dist/types/asset-types-api.d.ts.map +1 -0
  13. package/dist/types/asset-types-api.js +5 -0
  14. package/dist/types/asset-types-api.js.map +1 -0
  15. package/dist/types/index.d.ts +2 -0
  16. package/dist/types/index.d.ts.map +1 -1
  17. package/dist/types/index.js +2 -0
  18. package/dist/types/index.js.map +1 -1
  19. package/dist/types/twin-permissions-api.d.ts +20 -0
  20. package/dist/types/twin-permissions-api.d.ts.map +1 -0
  21. package/dist/types/twin-permissions-api.js +2 -0
  22. package/dist/types/twin-permissions-api.js.map +1 -0
  23. package/docs/assets/hierarchy.js +1 -1
  24. package/docs/assets/navigation.js +1 -1
  25. package/docs/assets/search.js +1 -1
  26. package/docs/classes/AssetBatchError.html +1 -1
  27. package/docs/classes/AssetCatalogTooLargeError.html +16 -0
  28. package/docs/classes/AssetCategoryConflictError.html +3 -0
  29. package/docs/classes/AssetCategoryForbiddenError.html +2 -0
  30. package/docs/classes/AssetCategoryNotFoundError.html +2 -0
  31. package/docs/classes/AssetCategoryValidationError.html +3 -0
  32. package/docs/classes/AssetConflictError.html +1 -1
  33. package/docs/classes/AssetForbiddenError.html +1 -1
  34. package/docs/classes/AssetNotFoundError.html +1 -1
  35. package/docs/classes/AssetTypeConflictError.html +3 -0
  36. package/docs/classes/AssetTypeForbiddenError.html +2 -0
  37. package/docs/classes/AssetTypeNotFoundError.html +2 -0
  38. package/docs/classes/AssetTypeValidationError.html +3 -0
  39. package/docs/classes/AssetValidationError.html +1 -1
  40. package/docs/classes/ProcessorNotFoundError.html +1 -1
  41. package/docs/classes/TwinClient.html +114 -41
  42. package/docs/classes/TwinConflictError.html +1 -1
  43. package/docs/classes/TwinFileConflictError.html +1 -1
  44. package/docs/classes/TwinFileNotFoundError.html +1 -1
  45. package/docs/classes/TwinFileValidationError.html +1 -1
  46. package/docs/classes/TwinNotFoundError.html +1 -1
  47. package/docs/classes/TwinUnauthenticatedError.html +6 -0
  48. package/docs/classes/TwinValidationError.html +1 -1
  49. package/docs/functions/isAssetCatalogTooLargeErrorBody.html +6 -0
  50. package/docs/functions/readErrorBody.html +10 -0
  51. package/docs/hierarchy.html +1 -1
  52. package/docs/interfaces/AssetCatalogCategory.html +7 -0
  53. package/docs/interfaces/AssetCatalogResponse.html +6 -0
  54. package/docs/interfaces/AssetCatalogTooLargeErrorBody.html +15 -0
  55. package/docs/interfaces/AssetCategoryDelete.html +2 -0
  56. package/docs/interfaces/AssetCategoryGet.html +14 -0
  57. package/docs/interfaces/AssetCategoryPut.html +7 -0
  58. package/docs/interfaces/AssetTypeDelete.html +2 -0
  59. package/docs/interfaces/AssetTypeGet.html +16 -0
  60. package/docs/interfaces/AssetTypePut.html +9 -0
  61. package/docs/interfaces/ITwinClient.html +115 -42
  62. package/docs/interfaces/MyPermissions.html +7 -0
  63. package/docs/interfaces/TwinErrorBody.html +2 -2
  64. package/docs/interfaces/TwinSpecification.html +1 -1
  65. package/docs/modules.html +1 -1
  66. package/docs/types/TwinCapability.html +6 -0
  67. package/docs/types/TwinErrorCause.html +8 -0
  68. package/docs/types/TwinErrorItemKind.html +4 -0
  69. package/package.json +3 -3
  70. package/src/BuildInfo.ts +41 -41
  71. package/src/TwinClient.ts +2010 -1496
  72. package/src/errors.ts +360 -117
  73. package/src/index.ts +3 -3
  74. package/src/types/Twin.ts +7 -7
  75. package/src/types/TwinGeometryInfo.ts +7 -7
  76. package/src/types/asset-api.ts +60 -60
  77. package/src/types/asset-batch-api.ts +88 -88
  78. package/src/types/asset-types-api.ts +86 -0
  79. package/src/types/common.ts +10 -10
  80. package/src/types/generated.ts +574 -574
  81. package/src/types/index.ts +8 -6
  82. package/src/types/twin-api.ts +99 -99
  83. package/src/types/twin-file-api.ts +67 -67
  84. package/src/types/twin-permissions-api.ts +20 -0
@@ -1,12 +1,15 @@
1
1
  import { HttpMethod } from '@twinfinity/authentication';
2
2
  import { readT8ClientModelWithFactories, readT8ClientModelWithGeometry, readT8GIModelWithFactories, T8EntityType, T8GIMeshDescriptor, T8GIStyle, T8GIRegion, T8Product, T8Project, T8Unit } from '@twinfinity/t8-client-model';
3
- import { TwinValidationError, TwinConflictError, TwinNotFoundError, ProcessorNotFoundError, AssetValidationError, AssetForbiddenError, AssetConflictError, AssetNotFoundError, AssetBatchError, TwinFileValidationError, TwinFileConflictError, TwinFileNotFoundError } from './errors';
3
+ import { TwinValidationError, TwinConflictError, TwinNotFoundError, ProcessorNotFoundError, AssetValidationError, AssetForbiddenError, AssetConflictError, AssetNotFoundError, AssetBatchError, TwinFileValidationError, TwinFileConflictError, TwinFileNotFoundError, AssetCategoryValidationError, AssetCategoryConflictError, AssetCategoryNotFoundError, AssetCategoryForbiddenError, AssetTypeValidationError, AssetTypeConflictError, AssetTypeNotFoundError, AssetTypeForbiddenError, AssetCatalogTooLargeError, isAssetCatalogTooLargeErrorBody, TwinUnauthenticatedError, readErrorBody } from './errors';
4
4
  export class TwinClient {
5
5
  _httpClient;
6
6
  _baseUrl;
7
+ _assetTypeCatalogUrl;
7
8
  constructor(baseUrl, _httpClient) {
8
9
  this._httpClient = _httpClient;
9
- this._baseUrl = `${baseUrl}/_ps/twins`;
10
+ const base = String(baseUrl).replace(/\/+$/, '');
11
+ this._baseUrl = `${base}/_ps/twins`;
12
+ this._assetTypeCatalogUrl = `${base}/_ps/asset-type-catalog`;
10
13
  }
11
14
  async listTwins(relatedTo, page = undefined, limit = 100, signal) {
12
15
  const params = new URLSearchParams();
@@ -18,14 +21,14 @@ export class TwinClient {
18
21
  params.set('limit', limit.toString());
19
22
  const url = params.toString() ? `${this._baseUrl}?${params}` : this._baseUrl;
20
23
  const response = await this._httpClient.fetch(HttpMethod.Get, url, {
21
- headers: { 'Content-Type': 'application/json' },
24
+ headers: { Accept: 'application/json' },
22
25
  signal
23
26
  });
24
27
  if (response.ok) {
25
28
  return (await response.json());
26
29
  }
27
30
  if (response.status === 400) {
28
- const errorBody = await response.json();
31
+ const errorBody = await readErrorBody(response);
29
32
  throw new TwinValidationError(`Twin listing validation failed: ${errorBody.detail}`, errorBody);
30
33
  }
31
34
  const errorText = await response.text();
@@ -50,7 +53,7 @@ export class TwinClient {
50
53
  const twinId = typeof twin === 'string' ? twin : twin.id;
51
54
  const specifiedVersion = typeof twin === 'string' ? undefined : twin.version;
52
55
  const response = await this._httpClient.fetch(HttpMethod.Get, `${this._baseUrl}/${twinId}${specifiedVersion !== undefined ? `/versions/${specifiedVersion}` : ''}`, {
53
- headers: { 'Content-Type': 'application/json' },
56
+ headers: { Accept: 'application/json' },
54
57
  signal
55
58
  });
56
59
  if (response.ok) {
@@ -72,14 +75,14 @@ export class TwinClient {
72
75
  params.set('includeDeleted', 'true');
73
76
  const url = `${this._baseUrl}/${id}/versions${params.toString() ? `?${params}` : ''}`;
74
77
  const response = await this._httpClient.fetch(HttpMethod.Get, url, {
75
- headers: { 'Content-Type': 'application/json' },
78
+ headers: { Accept: 'application/json' },
76
79
  signal
77
80
  });
78
81
  if (response.ok) {
79
82
  return (await response.json());
80
83
  }
81
84
  if (response.status === 400) {
82
- const errorBody = await response.json();
85
+ const errorBody = await readErrorBody(response);
83
86
  throw new TwinValidationError(`Twin listing validation failed: ${errorBody.detail}`, errorBody);
84
87
  }
85
88
  const errorText = await response.text();
@@ -243,7 +246,7 @@ export class TwinClient {
243
246
  return (await response.json());
244
247
  }
245
248
  if (response.status === 400) {
246
- const errorBody = await response.json();
249
+ const errorBody = await readErrorBody(response);
247
250
  throw new TwinValidationError(`Twin validation failed: ${errorBody.detail}`, errorBody);
248
251
  }
249
252
  if (response.status === 409) {
@@ -295,7 +298,7 @@ export class TwinClient {
295
298
  throw new Error(`Failed to restore twin: ${response.status} ${response.statusText} - ${errorText}`);
296
299
  }
297
300
  async getTwinVersionContent(twinId, twinVersion, signal) {
298
- const response = await this._httpClient.fetch(HttpMethod.Get, `${this._baseUrl}/${twinId}/versions/${twinVersion}/contents`, { headers: { 'Content-Type': 'application/json' }, signal });
301
+ const response = await this._httpClient.fetch(HttpMethod.Get, `${this._baseUrl}/${twinId}/versions/${twinVersion}/contents`, { headers: { Accept: 'application/json' }, signal });
299
302
  if (response.ok) {
300
303
  return (await response.json());
301
304
  }
@@ -307,7 +310,7 @@ export class TwinClient {
307
310
  }
308
311
  async getTwinContent(twinId, signal) {
309
312
  const response = await this._httpClient.fetch(HttpMethod.Get, `${this._baseUrl}/${twinId}/contents`, {
310
- headers: { 'Content-Type': 'application/json' },
313
+ headers: { Accept: 'application/json' },
311
314
  signal
312
315
  });
313
316
  if (response.ok) {
@@ -321,7 +324,7 @@ export class TwinClient {
321
324
  }
322
325
  async getTwinDiagnostics(twinId, signal) {
323
326
  const response = await this._httpClient.fetch(HttpMethod.Get, `${this._baseUrl}/${twinId}/diagnostics`, {
324
- headers: { 'Content-Type': 'application/json' },
327
+ headers: { Accept: 'application/json' },
325
328
  signal
326
329
  });
327
330
  if (response.ok) {
@@ -334,7 +337,7 @@ export class TwinClient {
334
337
  throw new Error(`Failed to get twin diagnostics: ${response.status} ${response.statusText} - ${errorText}`);
335
338
  }
336
339
  async getTwinVersionDiagnostics(twinId, twinVersion, signal) {
337
- const response = await this._httpClient.fetch(HttpMethod.Get, `${this._baseUrl}/${twinId}/versions/${twinVersion}/diagnostics`, { headers: { 'Content-Type': 'application/json' }, signal });
340
+ const response = await this._httpClient.fetch(HttpMethod.Get, `${this._baseUrl}/${twinId}/versions/${twinVersion}/diagnostics`, { headers: { Accept: 'application/json' }, signal });
338
341
  if (response.ok) {
339
342
  return (await response.json());
340
343
  }
@@ -347,14 +350,14 @@ export class TwinClient {
347
350
  async getTwinVersionEvents(twinId, twinVersion, offset = 0, limit = 100, signal) {
348
351
  const url = `${this._baseUrl}/${twinId}/versions/${twinVersion}/events?offset=${offset}&limit=${limit}`;
349
352
  const response = await this._httpClient.fetch(HttpMethod.Get, url, {
350
- headers: { 'Content-Type': 'application/json' },
353
+ headers: { Accept: 'application/json' },
351
354
  signal
352
355
  });
353
356
  if (response.ok) {
354
357
  return (await response.json());
355
358
  }
356
359
  if (response.status === 400) {
357
- const errorBody = await response.json();
360
+ const errorBody = await readErrorBody(response);
358
361
  throw new TwinValidationError(`Twin events validation failed: ${errorBody.detail}`, errorBody);
359
362
  }
360
363
  if (response.status === 404) {
@@ -366,14 +369,14 @@ export class TwinClient {
366
369
  async getProcessorEvents(twinId, twinVersion, processorId, offset = 0, limit = 100, signal) {
367
370
  const url = `${this._baseUrl}/${twinId}/versions/${twinVersion}/processors/${processorId}/events?offset=${offset}&limit=${limit}`;
368
371
  const response = await this._httpClient.fetch(HttpMethod.Get, url, {
369
- headers: { 'Content-Type': 'application/json' },
372
+ headers: { Accept: 'application/json' },
370
373
  signal
371
374
  });
372
375
  if (response.ok) {
373
376
  return (await response.json());
374
377
  }
375
378
  if (response.status === 400) {
376
- const errorBody = await response.json();
379
+ const errorBody = await readErrorBody(response);
377
380
  throw new TwinValidationError(`Processor events validation failed: ${errorBody.detail}`, errorBody);
378
381
  }
379
382
  if (response.status === 404) {
@@ -386,14 +389,14 @@ export class TwinClient {
386
389
  const includeDeleted = options?.includeDeleted ?? false;
387
390
  const params = `offset=${offset}&limit=${limit}${includeDeleted ? '&includeDeleted=true' : ''}`;
388
391
  const response = await this._httpClient.fetch(HttpMethod.Get, `${this._baseUrl}/${twinId}/assets?${params}`, {
389
- headers: { 'Content-Type': 'application/json' },
392
+ headers: { Accept: 'application/json' },
390
393
  signal
391
394
  });
392
395
  if (response.ok) {
393
396
  return (await response.json());
394
397
  }
395
398
  if (response.status === 400) {
396
- const errorBody = await response.json();
399
+ const errorBody = await readErrorBody(response);
397
400
  throw new AssetValidationError(`Asset listing validation failed: ${errorBody.detail}`, errorBody);
398
401
  }
399
402
  if (response.status === 404) {
@@ -404,7 +407,7 @@ export class TwinClient {
404
407
  }
405
408
  async getAsset(twinId, assetId, signal) {
406
409
  const response = await this._httpClient.fetch(HttpMethod.Get, `${this._baseUrl}/${twinId}/assets/${assetId}`, {
407
- headers: { 'Content-Type': 'application/json' },
410
+ headers: { Accept: 'application/json' },
408
411
  signal
409
412
  });
410
413
  if (response.ok) {
@@ -426,7 +429,7 @@ export class TwinClient {
426
429
  return (await response.json());
427
430
  }
428
431
  if (response.status === 400) {
429
- const errorBody = await response.json();
432
+ const errorBody = await readErrorBody(response);
430
433
  throw new AssetValidationError(`Asset validation failed: ${errorBody.detail}`, errorBody);
431
434
  }
432
435
  const errorText = await response.text();
@@ -446,7 +449,7 @@ export class TwinClient {
446
449
  throw new AssetConflictError('Asset has been modified by another user', conflictedAsset);
447
450
  }
448
451
  if (response.status === 400) {
449
- const errorBody = await response.json();
452
+ const errorBody = await readErrorBody(response);
450
453
  throw new AssetValidationError(`Asset validation failed: ${errorBody.detail}`, errorBody);
451
454
  }
452
455
  const errorText = await response.text();
@@ -499,7 +502,7 @@ export class TwinClient {
499
502
  return (await response.json());
500
503
  }
501
504
  if (response.status === 400) {
502
- const errorBody = await response.json();
505
+ const errorBody = await readErrorBody(response);
503
506
  throw new AssetValidationError(`Asset batch validation failed: ${errorBody.detail}`, errorBody);
504
507
  }
505
508
  if (response.status === 403) {
@@ -523,7 +526,7 @@ export class TwinClient {
523
526
  return (await response.json());
524
527
  }
525
528
  if (response.status === 400) {
526
- const errorBody = await response.json();
529
+ const errorBody = await readErrorBody(response);
527
530
  throw new AssetValidationError(`Asset batch-get validation failed: ${errorBody.detail}`, errorBody);
528
531
  }
529
532
  const errorText = await response.text();
@@ -549,14 +552,14 @@ export class TwinClient {
549
552
  ? `${this._baseUrl}/${twinId}/files?${params}`
550
553
  : `${this._baseUrl}/${twinId}/files`;
551
554
  const response = await this._httpClient.fetch(HttpMethod.Get, url, {
552
- headers: { 'Content-Type': 'application/json' },
555
+ headers: { Accept: 'application/json' },
553
556
  signal
554
557
  });
555
558
  if (response.ok) {
556
559
  return (await response.json());
557
560
  }
558
561
  if (response.status === 400) {
559
- const errorBody = await response.json();
562
+ const errorBody = await readErrorBody(response);
560
563
  throw new TwinFileValidationError(`Twin file listing validation failed: ${errorBody.detail}`, errorBody);
561
564
  }
562
565
  const errorText = await response.text();
@@ -564,7 +567,7 @@ export class TwinClient {
564
567
  }
565
568
  async getTwinFile(twinId, fileId, signal) {
566
569
  const response = await this._httpClient.fetch(HttpMethod.Get, `${this._baseUrl}/${twinId}/files/${fileId}`, {
567
- headers: { 'Content-Type': 'application/json' },
570
+ headers: { Accept: 'application/json' },
568
571
  signal
569
572
  });
570
573
  if (response.ok) {
@@ -590,7 +593,7 @@ export class TwinClient {
590
593
  return (await response.json());
591
594
  }
592
595
  if (response.status === 400) {
593
- const errorBody = await response.json();
596
+ const errorBody = await readErrorBody(response);
594
597
  throw new TwinFileValidationError(`Twin file validation failed`, errorBody);
595
598
  }
596
599
  if (response.status === 409) {
@@ -681,7 +684,7 @@ export class TwinClient {
681
684
  return (await response.json());
682
685
  }
683
686
  if (response.status === 400) {
684
- const errorBody = await response.json();
687
+ const errorBody = await readErrorBody(response);
685
688
  throw new TwinFileValidationError(`Twin file version listing validation failed: ${errorBody.detail}`, errorBody);
686
689
  }
687
690
  const errorText = await response.text();
@@ -712,5 +715,297 @@ export class TwinClient {
712
715
  signal
713
716
  });
714
717
  }
718
+ // ---------- Asset categories ----------
719
+ async getMyPermissions(signal) {
720
+ const url = `${this._baseUrl}/permissions/me`;
721
+ const response = await this._httpClient.fetch(HttpMethod.Get, url, {
722
+ headers: { Accept: 'application/json' },
723
+ signal
724
+ });
725
+ if (response.ok) {
726
+ return (await response.json());
727
+ }
728
+ // 401: no valid auth context. Throw so consumers can redirect to
729
+ // login / refresh tokens rather than mistake an expired session for
730
+ // "logged-in user with no grants."
731
+ if (response.status === 401) {
732
+ throw new TwinUnauthenticatedError('Not authenticated');
733
+ }
734
+ // 403: authenticated but no Twin-service capabilities. Surface as an
735
+ // empty array so consumers can treat it like a logged-in user with
736
+ // zero grants.
737
+ if (response.status === 403) {
738
+ return { permissions: [] };
739
+ }
740
+ throw new Error(`Failed to fetch permissions: ${response.status} ${response.statusText}`);
741
+ }
742
+ async getAssetTypeMetaSchema(signal) {
743
+ const url = `${this._assetTypeCatalogUrl}/meta-schema`;
744
+ const response = await this._httpClient.fetch(HttpMethod.Get, url, {
745
+ headers: { Accept: 'application/schema+json, application/json' },
746
+ signal
747
+ });
748
+ if (!response.ok) {
749
+ throw new Error(`Failed to fetch meta-schema: ${response.status} ${response.statusText}`);
750
+ }
751
+ return (await response.json());
752
+ }
753
+ async listAssetCategories(options, signal) {
754
+ const params = new URLSearchParams();
755
+ if (options?.page !== undefined)
756
+ params.set('page', options.page);
757
+ if (options?.limit !== undefined)
758
+ params.set('limit', options.limit.toString());
759
+ if (options?.includeDeleted)
760
+ params.set('includeDeleted', 'true');
761
+ const url = params.toString()
762
+ ? `${this._assetTypeCatalogUrl}/categories?${params}`
763
+ : `${this._assetTypeCatalogUrl}/categories`;
764
+ const response = await this._httpClient.fetch(HttpMethod.Get, url, {
765
+ headers: { Accept: 'application/json' },
766
+ signal
767
+ });
768
+ if (response.ok)
769
+ return (await response.json());
770
+ if (response.status === 403)
771
+ throw new AssetCategoryForbiddenError('Asset category listing forbidden');
772
+ if (response.status === 400) {
773
+ const errorBody = await readErrorBody(response);
774
+ throw new AssetCategoryValidationError(`Asset category listing failed: ${errorBody.detail}`, errorBody);
775
+ }
776
+ throw new Error(`Failed to list asset categories: ${response.status} ${response.statusText}`);
777
+ }
778
+ async getAssetCategory(categoryId, signal) {
779
+ const response = await this._httpClient.fetch(HttpMethod.Get, `${this._assetTypeCatalogUrl}/categories/${categoryId}`, {
780
+ headers: { Accept: 'application/json' },
781
+ signal
782
+ });
783
+ if (response.ok)
784
+ return (await response.json());
785
+ if (response.status === 403)
786
+ throw new AssetCategoryForbiddenError(`Asset category ${categoryId} read forbidden`);
787
+ if (response.status === 404)
788
+ throw new AssetCategoryNotFoundError(`Asset category ${categoryId} not found`);
789
+ throw new Error(`Failed to get asset category: ${response.status} ${response.statusText}`);
790
+ }
791
+ async putAssetCategory(categoryId, body, signal) {
792
+ const response = await this._httpClient.fetch(HttpMethod.Put, `${this._assetTypeCatalogUrl}/categories/${categoryId}`, {
793
+ headers: { 'Content-Type': 'application/json' },
794
+ body: JSON.stringify(body),
795
+ signal
796
+ });
797
+ if (response.ok)
798
+ return (await response.json());
799
+ if (response.status === 403)
800
+ throw new AssetCategoryForbiddenError('Asset category upsert forbidden');
801
+ if (response.status === 409) {
802
+ const current = (await response.json());
803
+ throw new AssetCategoryConflictError('Asset category was modified by another user', current);
804
+ }
805
+ if (response.status === 400) {
806
+ const errorBody = await readErrorBody(response);
807
+ throw new AssetCategoryValidationError(`Asset category validation failed: ${errorBody.detail}`, errorBody);
808
+ }
809
+ const errorText = await response.text();
810
+ throw new Error(`Failed to upsert asset category: ${response.status} ${response.statusText} - ${errorText}`);
811
+ }
812
+ async deleteAssetCategory(categoryId, etag, signal) {
813
+ return this._categoryDeleteOrRestore(categoryId, etag, /*isRestore*/ false, signal);
814
+ }
815
+ async restoreAssetCategory(categoryId, etag, signal) {
816
+ return this._categoryDeleteOrRestore(categoryId, etag, /*isRestore*/ true, signal);
817
+ }
818
+ async _categoryDeleteOrRestore(categoryId, etag, isRestore, signal) {
819
+ const url = isRestore
820
+ ? `${this._assetTypeCatalogUrl}/categories/${categoryId}/restore`
821
+ : `${this._assetTypeCatalogUrl}/categories/${categoryId}`;
822
+ const method = isRestore ? HttpMethod.Put : HttpMethod.Delete;
823
+ const response = await this._httpClient.fetch(method, url, {
824
+ headers: { 'Content-Type': 'application/json' },
825
+ body: JSON.stringify({ etag }),
826
+ signal
827
+ });
828
+ if (response.ok)
829
+ return (await response.json());
830
+ if (response.status === 403) {
831
+ const op = isRestore ? 'restore' : 'delete';
832
+ throw new AssetCategoryForbiddenError(`Asset category ${op} forbidden`);
833
+ }
834
+ if (response.status === 409) {
835
+ const current = (await response.json());
836
+ throw new AssetCategoryConflictError('Asset category was modified by another user', current);
837
+ }
838
+ if (response.status === 404)
839
+ throw new AssetCategoryNotFoundError(`Asset category ${categoryId} not found`);
840
+ const errorText = await response.text();
841
+ const op = isRestore ? 'restore' : 'delete';
842
+ throw new Error(`Failed to ${op} asset category: ${response.status} ${response.statusText} - ${errorText}`);
843
+ }
844
+ async listAssetCategoryVersions(categoryId, options, signal) {
845
+ const params = new URLSearchParams();
846
+ if (options?.page !== undefined)
847
+ params.set('page', options.page);
848
+ if (options?.limit !== undefined)
849
+ params.set('limit', options.limit.toString());
850
+ if (options?.includeDeleted)
851
+ params.set('includeDeleted', 'true');
852
+ const baseUrl = `${this._assetTypeCatalogUrl}/categories/${categoryId}/versions`;
853
+ const url = params.toString() ? `${baseUrl}?${params}` : baseUrl;
854
+ const response = await this._httpClient.fetch(HttpMethod.Get, url, {
855
+ headers: { Accept: 'application/json' },
856
+ signal
857
+ });
858
+ if (response.ok)
859
+ return (await response.json());
860
+ if (response.status === 403)
861
+ throw new AssetCategoryForbiddenError('Asset category version listing forbidden');
862
+ if (response.status === 400) {
863
+ const errorBody = await readErrorBody(response);
864
+ throw new AssetCategoryValidationError(`Asset category version listing failed: ${errorBody.detail}`, errorBody);
865
+ }
866
+ if (response.status === 404)
867
+ throw new AssetCategoryNotFoundError(`Asset category ${categoryId} not found`);
868
+ throw new Error(`Failed to list asset category versions: ${response.status} ${response.statusText}`);
869
+ }
870
+ // ---------- Asset types ----------
871
+ async listAssetTypes(categoryId, options, signal) {
872
+ const params = new URLSearchParams();
873
+ if (options?.page !== undefined)
874
+ params.set('page', options.page);
875
+ if (options?.limit !== undefined)
876
+ params.set('limit', options.limit.toString());
877
+ if (options?.includeDeleted)
878
+ params.set('includeDeleted', 'true');
879
+ const baseUrl = `${this._assetTypeCatalogUrl}/categories/${categoryId}/types`;
880
+ const url = params.toString() ? `${baseUrl}?${params}` : baseUrl;
881
+ const response = await this._httpClient.fetch(HttpMethod.Get, url, {
882
+ headers: { Accept: 'application/json' },
883
+ signal
884
+ });
885
+ if (response.ok)
886
+ return (await response.json());
887
+ if (response.status === 403)
888
+ throw new AssetTypeForbiddenError('Asset type listing forbidden');
889
+ if (response.status === 400) {
890
+ const errorBody = await readErrorBody(response);
891
+ throw new AssetTypeValidationError(`Asset type listing failed: ${errorBody.detail}`, errorBody);
892
+ }
893
+ throw new Error(`Failed to list asset types: ${response.status} ${response.statusText}`);
894
+ }
895
+ async getAssetType(categoryId, typeId, signal) {
896
+ const response = await this._httpClient.fetch(HttpMethod.Get, `${this._assetTypeCatalogUrl}/categories/${categoryId}/types/${typeId}`, { headers: { Accept: 'application/json' }, signal });
897
+ if (response.ok)
898
+ return (await response.json());
899
+ if (response.status === 403)
900
+ throw new AssetTypeForbiddenError(`Asset type ${typeId} read forbidden`);
901
+ if (response.status === 404)
902
+ throw new AssetTypeNotFoundError(`Asset type ${typeId} not found`);
903
+ throw new Error(`Failed to get asset type: ${response.status} ${response.statusText}`);
904
+ }
905
+ async listAssetTypeVersions(categoryId, typeId, options, signal) {
906
+ const params = new URLSearchParams();
907
+ if (options?.page !== undefined)
908
+ params.set('page', options.page);
909
+ if (options?.limit !== undefined)
910
+ params.set('limit', options.limit.toString());
911
+ if (options?.includeDeleted)
912
+ params.set('includeDeleted', 'true');
913
+ const baseUrl = `${this._assetTypeCatalogUrl}/categories/${categoryId}/types/${typeId}/versions`;
914
+ const url = params.toString() ? `${baseUrl}?${params}` : baseUrl;
915
+ const response = await this._httpClient.fetch(HttpMethod.Get, url, {
916
+ headers: { Accept: 'application/json' },
917
+ signal
918
+ });
919
+ if (response.ok)
920
+ return (await response.json());
921
+ if (response.status === 403)
922
+ throw new AssetTypeForbiddenError('Asset type version listing forbidden');
923
+ if (response.status === 400) {
924
+ const errorBody = await readErrorBody(response);
925
+ throw new AssetTypeValidationError(`Asset type version listing failed: ${errorBody.detail}`, errorBody);
926
+ }
927
+ if (response.status === 404)
928
+ throw new AssetTypeNotFoundError(`Asset type ${typeId} not found`);
929
+ throw new Error(`Failed to list asset type versions: ${response.status} ${response.statusText}`);
930
+ }
931
+ async putAssetType(categoryId, typeId, body, signal) {
932
+ const response = await this._httpClient.fetch(HttpMethod.Put, `${this._assetTypeCatalogUrl}/categories/${categoryId}/types/${typeId}`, {
933
+ headers: { 'Content-Type': 'application/json' },
934
+ body: JSON.stringify(body),
935
+ signal
936
+ });
937
+ if (response.ok)
938
+ return (await response.json());
939
+ if (response.status === 403)
940
+ throw new AssetTypeForbiddenError('Asset type upsert forbidden');
941
+ if (response.status === 409) {
942
+ const current = (await response.json());
943
+ throw new AssetTypeConflictError('Asset type was modified by another user', current);
944
+ }
945
+ if (response.status === 400) {
946
+ const errorBody = await readErrorBody(response);
947
+ throw new AssetTypeValidationError(`Asset type validation failed: ${errorBody.detail}`, errorBody);
948
+ }
949
+ const errorText = await response.text();
950
+ throw new Error(`Failed to upsert asset type: ${response.status} ${response.statusText} - ${errorText}`);
951
+ }
952
+ async deleteAssetType(categoryId, typeId, etag, signal) {
953
+ return this._typeDeleteOrRestore(categoryId, typeId, etag, /*isRestore*/ false, signal);
954
+ }
955
+ async restoreAssetType(categoryId, typeId, etag, signal) {
956
+ return this._typeDeleteOrRestore(categoryId, typeId, etag, /*isRestore*/ true, signal);
957
+ }
958
+ async _typeDeleteOrRestore(categoryId, typeId, etag, isRestore, signal) {
959
+ const url = isRestore
960
+ ? `${this._assetTypeCatalogUrl}/categories/${categoryId}/types/${typeId}/restore`
961
+ : `${this._assetTypeCatalogUrl}/categories/${categoryId}/types/${typeId}`;
962
+ const method = isRestore ? HttpMethod.Put : HttpMethod.Delete;
963
+ const response = await this._httpClient.fetch(method, url, {
964
+ headers: { 'Content-Type': 'application/json' },
965
+ body: JSON.stringify({ etag }),
966
+ signal
967
+ });
968
+ if (response.ok)
969
+ return (await response.json());
970
+ if (response.status === 403) {
971
+ const op = isRestore ? 'restore' : 'delete';
972
+ throw new AssetTypeForbiddenError(`Asset type ${op} forbidden`);
973
+ }
974
+ if (response.status === 409) {
975
+ const current = (await response.json());
976
+ throw new AssetTypeConflictError('Asset type was modified by another user', current);
977
+ }
978
+ if (response.status === 404)
979
+ throw new AssetTypeNotFoundError(`Asset type ${typeId} not found`);
980
+ const errorText = await response.text();
981
+ const op = isRestore ? 'restore' : 'delete';
982
+ throw new Error(`Failed to ${op} asset type: ${response.status} ${response.statusText} - ${errorText}`);
983
+ }
984
+ async getAssetTypeCatalog(signal) {
985
+ const response = await this._httpClient.fetch(HttpMethod.Get, this._assetTypeCatalogUrl, {
986
+ headers: { Accept: 'application/json' },
987
+ signal
988
+ });
989
+ if (response.ok)
990
+ return (await response.json());
991
+ if (response.status === 403)
992
+ throw new AssetCategoryForbiddenError('Asset type catalog read forbidden');
993
+ if (response.status === 400) {
994
+ // The server emits a single structured 400 here today —
995
+ // `cause: 'CatalogTooLarge'` — to flag a tenant whose catalog
996
+ // overflows the per-customer cap. Surface as a typed error so
997
+ // picker UIs can render "use search" instead of crashing on
998
+ // missing rows. Any other 400 (malformed CatalogTooLarge body,
999
+ // future cause) falls through to the generic error below so the
1000
+ // caller still sees the raw response.
1001
+ const errorBody = await readErrorBody(response);
1002
+ if (isAssetCatalogTooLargeErrorBody(errorBody)) {
1003
+ throw new AssetCatalogTooLargeError(`Asset type catalog too large: ${errorBody.detail}`, errorBody);
1004
+ }
1005
+ throw new Error(`Failed to get asset-type catalog: ${response.status} ${response.statusText} - ${errorBody.detail}`);
1006
+ }
1007
+ const errorText = await response.text();
1008
+ throw new Error(`Failed to get asset-type catalog: ${response.status} ${response.statusText} - ${errorText}`);
1009
+ }
715
1010
  }
716
1011
  //# sourceMappingURL=TwinClient.js.map