@meshmakers/octo-services 3.5.100 → 3.5.110

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.
@@ -7,8 +7,8 @@ import { CombinedGraphQLErrors } from '@apollo/client';
7
7
  import * as i1 from 'apollo-angular';
8
8
  import { gql } from 'apollo-angular';
9
9
  import { map, catchError, finalize } from 'rxjs/operators';
10
- import { of, firstValueFrom, map as map$1, Subject, throwError, from, filter } from 'rxjs';
11
- import { HttpClient, HttpParams, HttpErrorResponse, HttpContext, HttpHeaders } from '@angular/common/http';
10
+ import { of, firstValueFrom, map as map$1, Subject, throwError, from, switchMap, takeUntil, filter, fromEvent } from 'rxjs';
11
+ import { HttpClient, HttpParams, HttpErrorResponse, HttpContext, HttpHeaders, HttpEventType } from '@angular/common/http';
12
12
  import { Upload } from 'tus-js-client';
13
13
  import { AuthorizeService } from '@meshmakers/shared-auth';
14
14
 
@@ -6592,6 +6592,626 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
6592
6592
  }]
6593
6593
  }] });
6594
6594
 
6595
+ /** Thrown when a reference can be turned into no download URL (no `downloadUri`, no `binaryId`, or no tenant). */
6596
+ class BinaryDownloadUnavailableError extends Error {
6597
+ constructor(message) {
6598
+ super(message);
6599
+ this.name = 'BinaryDownloadUnavailableError';
6600
+ }
6601
+ }
6602
+ const DEFAULT_FILE_NAME = 'download';
6603
+ /**
6604
+ * Reads the file name from a `Content-Disposition` header (RFC 6266). The RFC 5987 form
6605
+ * `filename*=UTF-8''…` wins over the plain `filename=` parameter, as browsers do.
6606
+ * Returns `null` when the header is absent or names no file.
6607
+ *
6608
+ * Note: a cross-origin response exposes `Content-Disposition` to script only when the server lists
6609
+ * it in `Access-Control-Expose-Headers`; otherwise this sees `null` and the caller's fallback applies.
6610
+ */
6611
+ function parseContentDispositionFileName(header) {
6612
+ if (!header) {
6613
+ return null;
6614
+ }
6615
+ const extended = /filename\*\s*=\s*([^;]+)/i.exec(header);
6616
+ if (extended) {
6617
+ const raw = extended[1].trim().replace(/^"(.*)"$/, '$1');
6618
+ // charset'language'percent-encoded-value
6619
+ const parts = /^([^']*)'[^']*'(.*)$/.exec(raw);
6620
+ const encoded = parts ? parts[2] : raw;
6621
+ try {
6622
+ const decoded = decodeURIComponent(encoded);
6623
+ const name = decoded ? sanitizeFileName(decoded) : null;
6624
+ if (name) {
6625
+ return name;
6626
+ }
6627
+ }
6628
+ catch {
6629
+ // Malformed percent-encoding: fall through to the plain parameter.
6630
+ }
6631
+ }
6632
+ const plain = /(?:^|;)\s*filename\s*=\s*("((?:[^"\\]|\\.)*)"|[^;]+)/i.exec(header);
6633
+ if (plain) {
6634
+ const value = plain[2] !== undefined ? plain[2].replace(/\\(.)/g, '$1') : plain[1].trim();
6635
+ if (value) {
6636
+ return sanitizeFileName(value);
6637
+ }
6638
+ }
6639
+ return null;
6640
+ }
6641
+ /**
6642
+ * Strips any path a server might send along with the name; the browser would refuse it anyway. An empty name,
6643
+ * `.` or `..` is no file name: `null`, so the caller falls back to the reference's own name.
6644
+ */
6645
+ function sanitizeFileName(name) {
6646
+ const base = (name.split(/[\\/]/).pop() ?? name).trim();
6647
+ return base === '' || base === '.' || base === '..' ? null : base;
6648
+ }
6649
+ /**
6650
+ * Authenticated file downloads for the browser (AB#6171 decision D9).
6651
+ *
6652
+ * Binaries live behind the asset repository's `GET {tenant}/v1/largeBinaries`, which needs a bearer
6653
+ * token with an API scope. Opening the URL in a new tab (`window.open`) sends no token — the service
6654
+ * then signs the tab in through its own login without that scope and answers 403 (AB#5268), and a
6655
+ * popup blocker may swallow the tab anyway because the click is over by the time a URL is known.
6656
+ *
6657
+ * This service therefore fetches the file through `HttpClient`, so the host's `authorizeInterceptor`
6658
+ * attaches the bearer (it covers every URL under the configured service URIs, i.e.
6659
+ * `config.assetServices`), receives a `Blob`, and saves it through a temporary anchor under the real
6660
+ * file name — from `Content-Disposition` when the server sends one, else from the binary's stored
6661
+ * file name. It is owner-agnostic: any `BINARY_LINKED` value works, whichever CK type holds it.
6662
+ *
6663
+ * @example
6664
+ * ```typescript
6665
+ * const downloads = inject(FileDownloadService);
6666
+ * // generic attribute value { binaryId, filename, contentType, size }
6667
+ * await downloads.downloadBinary(attributeValue);
6668
+ * // any authenticated URL
6669
+ * await downloads.downloadUrl(`${assetServices}${tenantId}/v1/files/Files/Reports/report.pdf`, 'report.pdf');
6670
+ * ```
6671
+ */
6672
+ class FileDownloadService {
6673
+ httpClient = inject(HttpClient);
6674
+ configurationService = inject(CONFIGURATION_SERVICE, { optional: true });
6675
+ tenantIdProvider = inject(TENANT_ID_PROVIDER, { optional: true });
6676
+ /**
6677
+ * Builds the asset repository download URL for a large binary:
6678
+ * `{assetServices}{tenantId}/v1/largeBinaries?largeBinaryId={binaryId}`.
6679
+ * Returns `null` when the asset service URL or the tenant is unknown.
6680
+ */
6681
+ async buildLargeBinaryUri(binaryId, tenantId) {
6682
+ const assetServices = this.configurationService?.config?.assetServices;
6683
+ const tenant = tenantId ?? (this.tenantIdProvider ? await this.tenantIdProvider() : null);
6684
+ if (!assetServices || !tenant) {
6685
+ return null;
6686
+ }
6687
+ const base = assetServices.endsWith('/') ? assetServices : `${assetServices}/`;
6688
+ return `${base}${encodeURIComponent(tenant)}/v1/largeBinaries?largeBinaryId=${encodeURIComponent(binaryId)}`;
6689
+ }
6690
+ /**
6691
+ * Downloads a binary reference (a `BINARY_LINKED` value or `LargeBinaryInfo`) with the user's
6692
+ * bearer token and saves it. Uses `downloadUri` when present, else builds the URL from `binaryId`.
6693
+ *
6694
+ * @throws BinaryDownloadUnavailableError when no download URL can be determined.
6695
+ * @throws HttpErrorResponse when the server refuses or fails the download.
6696
+ */
6697
+ async downloadBinary(reference, options) {
6698
+ let url = reference.downloadUri || null;
6699
+ if (!url && reference.binaryId) {
6700
+ url = await this.buildLargeBinaryUri(reference.binaryId, options?.tenantId);
6701
+ }
6702
+ if (!url) {
6703
+ throw new BinaryDownloadUnavailableError(reference.binaryId
6704
+ ? 'Cannot build a download URL: asset service URL or tenant unknown'
6705
+ : 'The binary reference carries neither downloadUri nor binaryId');
6706
+ }
6707
+ await this.downloadUrl(url, reference.filename || options?.fallbackFileName, reference.contentType);
6708
+ }
6709
+ /**
6710
+ * Fetches any authenticated URL as a blob and saves it. The file name comes from
6711
+ * `Content-Disposition` when exposed, else from `fallbackFileName`, else `download`.
6712
+ * `context` is passed to the request (see {@link fetchBlob}).
6713
+ */
6714
+ async downloadUrl(url, fallbackFileName, contentType, context) {
6715
+ const response = await this.fetchBlob(url, context);
6716
+ const blob = this.withContentType(response.body ?? new Blob(), contentType);
6717
+ const fileName = parseContentDispositionFileName(response.headers.get('Content-Disposition'))
6718
+ || fallbackFileName
6719
+ || DEFAULT_FILE_NAME;
6720
+ this.saveBlob(blob, fileName);
6721
+ }
6722
+ /**
6723
+ * Fetches an authenticated URL as a blob response, e.g. for an inline preview.
6724
+ * The bearer is attached by the host's `authorizeInterceptor`. `context` lets the caller mark
6725
+ * statuses it handles itself (`MM_CALLER_HANDLED_STATUSES`), so no global error toast shows.
6726
+ */
6727
+ fetchBlob(url, context) {
6728
+ return firstValueFrom(this.httpClient.get(url, { responseType: 'blob', observe: 'response', context }));
6729
+ }
6730
+ /**
6731
+ * Hands a blob to the browser as a file download through a temporary anchor — not `window.open`,
6732
+ * which a popup blocker would swallow once the click is over.
6733
+ */
6734
+ saveBlob(blob, fileName) {
6735
+ const objectUrl = URL.createObjectURL(blob);
6736
+ try {
6737
+ const anchor = document.createElement('a');
6738
+ anchor.href = objectUrl;
6739
+ anchor.download = fileName;
6740
+ anchor.rel = 'noopener';
6741
+ anchor.style.display = 'none';
6742
+ document.body.appendChild(anchor);
6743
+ anchor.click();
6744
+ anchor.remove();
6745
+ }
6746
+ finally {
6747
+ // Safari needs the URL to outlive the click, so it is released on the next macrotask.
6748
+ setTimeout(() => URL.revokeObjectURL(objectUrl));
6749
+ }
6750
+ }
6751
+ /** Re-types a blob the server sent as generic octet-stream when the stored type is more specific. */
6752
+ withContentType(blob, contentType) {
6753
+ if (contentType && (!blob.type || blob.type === 'application/octet-stream') && contentType !== blob.type) {
6754
+ return new Blob([blob], { type: contentType });
6755
+ }
6756
+ return blob;
6757
+ }
6758
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: FileDownloadService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
6759
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: FileDownloadService, providedIn: 'root' });
6760
+ }
6761
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: FileDownloadService, decorators: [{
6762
+ type: Injectable,
6763
+ args: [{
6764
+ providedIn: 'root'
6765
+ }]
6766
+ }] });
6767
+
6768
+ /*
6769
+ * Asset-repo file bytes API (epic AB#6171: S2 AB#6174, zip AB#6225; client S13 AB#6230).
6770
+ *
6771
+ * Only the BYTES of files go through REST (`{assetServices}{tenant}/v1/files`); metadata — roots, folder
6772
+ * listings, create folder, rename, move, delete (recursive on the server), linked entities — goes through
6773
+ * the generic tenant GraphQL API against `System.Files` (decision Q1, 2026-10-09).
6774
+ *
6775
+ * | Method | Path | Notes |
6776
+ * |---|---|---|
6777
+ * | GET | `capabilities` | {@link FilesCapabilities} |
6778
+ * | PUT | `{root}/{path…}` | raw body upload, `?conflict=fail\|replace\|keepBoth&createFolders=true`; 201 new / 200 replaced |
6779
+ * | GET | `{root}/{path…}` | download, `?inline=true` for previews |
6780
+ * | POST | `items/{rtId}/content?name=&conflict=` | upload into the folder or root `rtId` |
6781
+ * | PUT | `items/{rtId}/content` | new content for the existing file `rtId` (rtId and links stay) |
6782
+ * | GET | `items/{rtId}/content` | download by rtId, `?inline=true` for previews |
6783
+ * | GET | `stats?root=&path=`, `items/{rtId}/stats` | {@link FolderStats} |
6784
+ * | POST | `zip` | `{ items, rtIds?, fileName? }` → streamed `application/zip` |
6785
+ * | POST | `linked-counts` | `{ rtIds }` (≤ 500) → `{ counts: { rtId: n } }` |
6786
+ *
6787
+ * Path segments are URL-encoded one by one; `root` is the folder root's well-known name. Errors are
6788
+ * problem details `{ status, title, detail, code }` (see {@link parseFilesProblem}).
6789
+ */
6790
+ /** Well-known names a folder root cannot use because they are routes of the file API. */
6791
+ const FILES_RESERVED_ROOT_NAMES = ['capabilities', 'items', 'linked-counts', 'stats', 'zip'];
6792
+ /** How long a "not available" answer of the capabilities is reused before asking again (ms). */
6793
+ const FILES_UNAVAILABLE_TTL_MS = 60_000;
6794
+ /** Most rtIds one `POST linked-counts` request may carry (server limit). */
6795
+ const FILES_LINKED_COUNTS_MAX = 500;
6796
+ /** Statuses the callers of this client handle themselves (no global error toast). */
6797
+ const CALLER_HANDLED = [400, 403, 404, 409, 413];
6798
+ /**
6799
+ * Bytes client of the platform file system (AB#6178, AB#6230): upload with progress (by path, into a
6800
+ * folder by rtId, new content by rtId), download and preview content (by path or rtId) with the user's
6801
+ * bearer under the real file name (decision D9, via {@link FileDownloadService}), the server-side zip,
6802
+ * deep folder statistics and capability detection.
6803
+ *
6804
+ * - The bearer is attached by the host's `authorizeInterceptor` (all URLs under `assetServices`).
6805
+ * - Statuses the caller handles (400, 403, 404, 409, 413) are excluded from the global HTTP error toast
6806
+ * via `MM_CALLER_HANDLED_STATUSES`; read the reason with {@link parseFilesProblem} and show it where it
6807
+ * belongs. Blob requests (download, preview, zip) rethrow their error with the parsed problem as body.
6808
+ * - {@link detectCapabilities} asks `GET /capabilities` once per tenant; a 404/405/501 (file API not
6809
+ * deployed) or 403 (token without the API scope) answers `{ available: false }` silently, so hosts can
6810
+ * probe safely.
6811
+ * - Downloads, previews and zips are in-memory blobs (D9); respect `previewMaxBytes` / `zipMaxBytes`.
6812
+ *
6813
+ * @example
6814
+ * ```typescript
6815
+ * const files = inject(FilesClientService);
6816
+ * if ((await files.detectCapabilities()).available) {
6817
+ * files.upload('Files', 'Receipts 2026', file, { conflict: 'keepBoth', createFolders: true }).subscribe(e => …);
6818
+ * await files.download('Files', 'Receipts 2026/a.pdf');
6819
+ * const stats = await files.folderStats('Files', 'Receipts 2026');
6820
+ * }
6821
+ * ```
6822
+ */
6823
+ class FilesClientService {
6824
+ http = inject(HttpClient);
6825
+ configuration = inject(CONFIGURATION_SERVICE, { optional: true });
6826
+ tenantIdProvider = inject(TENANT_ID_PROVIDER, { optional: true });
6827
+ downloads = inject(FileDownloadService);
6828
+ capabilityCache = new Map();
6829
+ // ---------------------------------------------------------------------------------- capabilities
6830
+ /**
6831
+ * Whether the file API exists for the tenant, plus the server's limits and features. Cached per tenant;
6832
+ * transient failures (network, 5xx) are not cached, so a later call asks again.
6833
+ */
6834
+ async detectCapabilities(tenantId) {
6835
+ const tenant = await this.tenant(tenantId);
6836
+ if (!tenant || !this.configuration?.config?.assetServices) {
6837
+ return { available: false };
6838
+ }
6839
+ let cached = this.capabilityCache.get(tenant);
6840
+ if (!cached) {
6841
+ const answer = this.fetchCapabilities(tenant);
6842
+ cached = { answer, at: Date.now() };
6843
+ this.capabilityCache.set(tenant, cached);
6844
+ answer.catch(() => this.capabilityCache.delete(tenant));
6845
+ }
6846
+ let result;
6847
+ try {
6848
+ result = await cached.answer;
6849
+ }
6850
+ catch {
6851
+ return { available: false };
6852
+ }
6853
+ // "Not available" is kept only briefly: the file API may be deployed or System.Files imported
6854
+ // meanwhile (tenant setup), so a later call after the TTL asks again.
6855
+ if (!result.available && Date.now() - cached.at > FILES_UNAVAILABLE_TTL_MS && this.capabilityCache.get(tenant) === cached) {
6856
+ this.capabilityCache.delete(tenant);
6857
+ return this.detectCapabilities(tenant);
6858
+ }
6859
+ return result;
6860
+ }
6861
+ /** Forgets the detected capabilities (tests, tenant switch). */
6862
+ resetCapabilities() {
6863
+ this.capabilityCache.clear();
6864
+ }
6865
+ // ---------------------------------------------------------------------------------- uploads
6866
+ /**
6867
+ * Uploads one file into a folder addressed by path: `PUT {root}/{folderPath…}/{name}` with progress
6868
+ * events (`reportProgress`). Unsubscribing cancels the request. `conflict` may be a mode (legacy form)
6869
+ * or {@link FilesUploadOptions}. Errors are `HttpErrorResponse` (404 PATH_NOT_FOUND without
6870
+ * `createFolders`, 409 NAME_CONFLICT / AMBIGUOUS_PATH, 413 LIMIT_EXCEEDED, 403 FORBIDDEN).
6871
+ */
6872
+ upload(root, folderPath, file, conflict = {}, tenantId) {
6873
+ const options = typeof conflict === 'string' ? { conflict } : conflict;
6874
+ if (options.name !== undefined && (!options.name || options.name.includes('/'))) {
6875
+ return throwError(() => new FilesPathError(`Invalid file name: ${options.name}`));
6876
+ }
6877
+ let params = new HttpParams().set('conflict', options.conflict ?? 'fail');
6878
+ if (options.createFolders) {
6879
+ params = params.set('createFolders', 'true');
6880
+ }
6881
+ return from(this.itemUrl(root, joinSegments(folderPath, options.name ?? file.name), tenantId)).pipe(switchMap((url) => this.sendUpload('PUT', url, file, params)));
6882
+ }
6883
+ /**
6884
+ * Uploads one file into the folder or root `folderRtId`: `POST items/{rtId}/content?name=&conflict=`.
6885
+ * Same events, cancellation and errors as {@link upload} (409 NOT_A_FOLDER for a file rtId).
6886
+ */
6887
+ uploadToFolder(folderRtId, file, options = {}) {
6888
+ const params = new HttpParams().set('name', options.name ?? file.name).set('conflict', options.conflict ?? 'fail');
6889
+ return from(this.itemContentUrl(folderRtId, options.tenantId)).pipe(switchMap((url) => this.sendUpload('POST', url, file, params)));
6890
+ }
6891
+ /**
6892
+ * Replaces the content of the existing file `fileRtId`: `PUT items/{rtId}/content`. The rtId, the name
6893
+ * and all links stay. Same events and cancellation as {@link upload} (409 NOT_A_FILE for a folder).
6894
+ */
6895
+ replaceContent(fileRtId, file, tenantId) {
6896
+ return from(this.itemContentUrl(fileRtId, tenantId)).pipe(switchMap((url) => this.sendUpload('PUT', url, file, new HttpParams())));
6897
+ }
6898
+ // ---------------------------------------------------------------------------------- downloads
6899
+ /** Downloads a file by path with the user's bearer and saves it under its real name (D9). */
6900
+ async download(root, path, fileName, contentType, tenantId) {
6901
+ const url = await this.itemUrl(root, path, tenantId);
6902
+ await withProblemBody(this.downloads.downloadUrl(url, fileName, contentType, callerHandled()));
6903
+ }
6904
+ /** Downloads a file by rtId (`GET items/{rtId}/content`) and saves it under its real name. */
6905
+ async downloadById(rtId, fileName, contentType, tenantId) {
6906
+ const url = await this.itemContentUrl(rtId, tenantId);
6907
+ await withProblemBody(this.downloads.downloadUrl(url, fileName, contentType, callerHandled()));
6908
+ }
6909
+ /**
6910
+ * Fetches a file's content by path as a blob for an inline preview (`?inline=true`). Inline delivery is
6911
+ * an allow-list on the server (images except SVG, audio, video, PDF, text/plain, CSV, JSON); everything
6912
+ * else stays an attachment with a sandbox CSP. The whole file is held in memory — check
6913
+ * `previewMaxBytes` before previewing large files.
6914
+ */
6915
+ async fetchContent(root, path, tenantId) {
6916
+ return this.fetchBlob(`${await this.itemUrl(root, path, tenantId)}?inline=true`);
6917
+ }
6918
+ /** Fetches a file's content by rtId as a blob for an inline preview (`?inline=true`). */
6919
+ async fetchContentById(rtId, tenantId) {
6920
+ return this.fetchBlob(`${await this.itemContentUrl(rtId, tenantId)}?inline=true`);
6921
+ }
6922
+ /**
6923
+ * Server-side streamed zip (AB#6225) of entries by path and/or rtId; folders are included recursively.
6924
+ * Body `{ items, rtIds?, fileName? }`. Saved under the server's `Content-Disposition` name, else
6925
+ * `fileName`, else `files.zip`. Limits are checked before the first byte (413 LIMIT_EXCEEDED); a
6926
+ * selected entry that is missing or hidden answers 404. The zip is received as an in-memory blob before
6927
+ * it is saved (D9: bearer download, no `window.open`), so the UI must respect `zipMaxBytes`.
6928
+ */
6929
+ async downloadZip(selection, fileName, tenantId) {
6930
+ const { items = [], rtIds = [] } = Array.isArray(selection) ? { items: selection } : selection;
6931
+ const body = { items };
6932
+ if (rtIds.length > 0) {
6933
+ body.rtIds = rtIds;
6934
+ }
6935
+ if (fileName) {
6936
+ body.fileName = fileName;
6937
+ }
6938
+ const url = await this.url(tenantId, 'zip');
6939
+ const response = await withProblemBody(firstValueFrom(this.http.post(url, body, { responseType: 'blob', observe: 'response', context: callerHandled() })));
6940
+ const name = parseContentDispositionFileName(response.headers.get('Content-Disposition')) || fileName || 'files.zip';
6941
+ this.downloads.saveBlob(response.body ?? new Blob(), name);
6942
+ }
6943
+ // ---------------------------------------------------------------------------------- statistics
6944
+ /**
6945
+ * Deep statistics of a root (`path` empty) or folder by path: `GET stats?root=&path=`. Use it instead of
6946
+ * walking the tree on the client (delete confirmation, folder info).
6947
+ */
6948
+ async folderStats(root, path, tenantId) {
6949
+ if (!root) {
6950
+ throw new FilesPathError('Invalid folder: empty root');
6951
+ }
6952
+ let params = new HttpParams().set('root', root);
6953
+ const folderPath = joinSegments(path ?? '');
6954
+ if (folderPath) {
6955
+ params = params.set('path', folderPath);
6956
+ }
6957
+ const url = await this.url(tenantId, 'stats');
6958
+ return normalizeStats(await firstValueFrom(this.http.get(url, { params, context: callerHandled() })));
6959
+ }
6960
+ /**
6961
+ * Deep statistics of a root or folder by rtId: `GET items/{rtId}/stats`. An aborted `signal` cancels
6962
+ * the request (the walk on the server is expensive) and rejects with an `AbortError`.
6963
+ */
6964
+ async folderStatsById(rtId, tenantId, signal) {
6965
+ signal?.throwIfAborted();
6966
+ const url = await this.url(tenantId, 'items', checkRtId(rtId), 'stats');
6967
+ const request = this.http.get(url, { context: callerHandled() });
6968
+ return normalizeStats(await firstValueFrom(signal ? request.pipe(takeUntil(abortOf(signal))) : request, { defaultValue: null })
6969
+ .then((body) => {
6970
+ signal?.throwIfAborted();
6971
+ return body;
6972
+ }));
6973
+ }
6974
+ /**
6975
+ * Links per entry (every association except the folder tree, any role, any direction):
6976
+ * `POST linked-counts { rtIds }` → `{ counts }`. Sends at most {@link FILES_LINKED_COUNTS_MAX} rtIds per
6977
+ * request (more are split). Entries the caller cannot see are omitted from the answer. Only call it
6978
+ * when the capabilities report `linkedCounts`.
6979
+ */
6980
+ async linkedCounts(rtIds, tenantId) {
6981
+ const unique = [...new Set(rtIds.filter((id) => !!id))];
6982
+ const counts = {};
6983
+ if (unique.length === 0) {
6984
+ return counts;
6985
+ }
6986
+ const url = await this.url(tenantId, 'linked-counts');
6987
+ for (let i = 0; i < unique.length; i += FILES_LINKED_COUNTS_MAX) {
6988
+ const chunk = unique.slice(i, i + FILES_LINKED_COUNTS_MAX);
6989
+ const body = await firstValueFrom(this.http.post(url, { rtIds: chunk }, { context: callerHandled() }));
6990
+ Object.assign(counts, body?.counts ?? {});
6991
+ }
6992
+ return counts;
6993
+ }
6994
+ // ---------------------------------------------------------------------------------- URLs
6995
+ /**
6996
+ * `{assetServices}{tenant}/v1/files/{root}/{seg}/…` with every segment URL-encoded.
6997
+ *
6998
+ * @throws FilesPathError for an empty root or a `.` / `..` segment (browsers and proxies resolve
6999
+ * dot segments even when percent-encoded, so such a URL would address a different resource), and for
7000
+ * a root named like a route of the file API (`capabilities`, `items`, `stats`, `zip`, case-insensitive).
7001
+ */
7002
+ async itemUrl(root, path, tenantId) {
7003
+ const segments = path.split('/').filter((s) => s.length > 0);
7004
+ if (!root || [root, ...segments].some(isDotSegment)) {
7005
+ throw new FilesPathError(`Invalid file path: ${root}/${path}`);
7006
+ }
7007
+ if (FILES_RESERVED_ROOT_NAMES.includes(root.toLowerCase())) {
7008
+ throw new FilesPathError(`Reserved root name: ${root}`);
7009
+ }
7010
+ return this.url(tenantId, root, ...segments);
7011
+ }
7012
+ /** `{assetServices}{tenant}/v1/files/items/{rtId}/content`. */
7013
+ async itemContentUrl(rtId, tenantId) {
7014
+ return this.url(tenantId, 'items', checkRtId(rtId), 'content');
7015
+ }
7016
+ // ---------------------------------------------------------------------------------- internals
7017
+ sendUpload(method, url, file, params) {
7018
+ return this.http.request(method, url, {
7019
+ body: file,
7020
+ params,
7021
+ headers: { 'Content-Type': file.type || 'application/octet-stream' },
7022
+ reportProgress: true,
7023
+ observe: 'events',
7024
+ context: callerHandled(),
7025
+ }).pipe(filter((event) => event.type === HttpEventType.UploadProgress || event.type === HttpEventType.Response), map$1((event) => {
7026
+ if (event.type === HttpEventType.UploadProgress) {
7027
+ return { type: 'progress', loaded: event.loaded, total: event.total ?? file.size };
7028
+ }
7029
+ return { type: 'done', item: event.body };
7030
+ }));
7031
+ }
7032
+ async fetchBlob(url) {
7033
+ const response = await withProblemBody(this.downloads.fetchBlob(url, callerHandled()));
7034
+ return response.body ?? new Blob();
7035
+ }
7036
+ async fetchCapabilities(tenant) {
7037
+ const url = await this.url(tenant, 'capabilities');
7038
+ try {
7039
+ const body = await firstValueFrom(this.http.get(url, { context: callerHandled([403, 404, 405, 501]) }));
7040
+ return normalizeCapabilities(body);
7041
+ }
7042
+ catch (error) {
7043
+ const status = error?.status;
7044
+ if (status === 403 || status === 404 || status === 405 || status === 501) {
7045
+ return { available: false };
7046
+ }
7047
+ throw error;
7048
+ }
7049
+ }
7050
+ async url(tenantId, ...segments) {
7051
+ // Without both a tenant and the asset service address the URL would point at the wrong resource (a
7052
+ // tenant-less path, or the host origin); fail with a clear client error instead of a misleading 404.
7053
+ const assetServices = this.configuration?.config?.assetServices;
7054
+ if (!assetServices) {
7055
+ throw new Error('FilesClientService: assetServices is not configured (CONFIGURATION_SERVICE)');
7056
+ }
7057
+ const tenant = await this.tenant(tenantId);
7058
+ if (!tenant) {
7059
+ throw new Error('FilesClientService: no tenant (pass tenantId or provide TENANT_ID_PROVIDER)');
7060
+ }
7061
+ const base = assetServices.endsWith('/') ? assetServices : `${assetServices}/`;
7062
+ return `${base}${encodeURIComponent(tenant)}/v1/files/${segments.map(encodeURIComponent).join('/')}`;
7063
+ }
7064
+ async tenant(tenantId) {
7065
+ return tenantId ?? (this.tenantIdProvider ? await this.tenantIdProvider() : null);
7066
+ }
7067
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: FilesClientService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
7068
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: FilesClientService, providedIn: 'root' });
7069
+ }
7070
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: FilesClientService, decorators: [{
7071
+ type: Injectable,
7072
+ args: [{ providedIn: 'root' }]
7073
+ }] });
7074
+ /** Thrown for a path or rtId the bytes API cannot address (empty root, `.` or `..` segments, empty rtId). */
7075
+ class FilesPathError extends Error {
7076
+ constructor(message) {
7077
+ super(message);
7078
+ this.name = 'FilesPathError';
7079
+ }
7080
+ }
7081
+ /**
7082
+ * Reads the file API problem details from an error of {@link FilesClientService} (`HttpErrorResponse`
7083
+ * with a JSON object or JSON string body). Returns `null` for anything that is no HTTP error.
7084
+ * A bare 403 / 413 without a code (e.g. nginx's body limit) maps to `FORBIDDEN` / `LIMIT_EXCEEDED`.
7085
+ */
7086
+ function parseFilesProblem(error) {
7087
+ if (!(error instanceof HttpErrorResponse)) {
7088
+ return null;
7089
+ }
7090
+ let body = error.error;
7091
+ if (typeof body === 'string') {
7092
+ try {
7093
+ body = JSON.parse(body);
7094
+ }
7095
+ catch {
7096
+ body = null;
7097
+ }
7098
+ }
7099
+ const problem = body && typeof body === 'object' ? body : {};
7100
+ let code = typeof problem.code === 'string' && problem.code ? problem.code : null;
7101
+ if (!code && typeof problem.title === 'string' && /^[A-Z][A-Z_]+$/.test(problem.title)) {
7102
+ code = problem.title;
7103
+ }
7104
+ if (!code && error.status === 403) {
7105
+ code = 'FORBIDDEN';
7106
+ }
7107
+ if (!code && error.status === 413) {
7108
+ code = 'LIMIT_EXCEEDED';
7109
+ }
7110
+ return { status: error.status, code, detail: typeof problem.detail === 'string' ? problem.detail : null };
7111
+ }
7112
+ /**
7113
+ * Reads the file system code (`extensions.code`, e.g. NAME_CONFLICT, PROTECTED_ROOT, RESERVED_NAME,
7114
+ * MOVE_INTO_ITSELF, FORBIDDEN) from a GraphQL error of a `System.Files` mutation (Apollo 4
7115
+ * `CombinedGraphQLErrors.errors`, or a raw `graphQLErrors` / `errors` array). `null` when none is found.
7116
+ */
7117
+ function filesGraphQlErrorCode(error) {
7118
+ if (!error || typeof error !== 'object') {
7119
+ return null;
7120
+ }
7121
+ const candidate = error;
7122
+ const list = Array.isArray(candidate.errors) ? candidate.errors : Array.isArray(candidate.graphQLErrors) ? candidate.graphQLErrors : [];
7123
+ for (const entry of list) {
7124
+ const code = entry?.extensions?.code;
7125
+ if (typeof code === 'string' && code) {
7126
+ return code;
7127
+ }
7128
+ }
7129
+ return null;
7130
+ }
7131
+ function normalizeCapabilities(body) {
7132
+ const b = body ?? {};
7133
+ return {
7134
+ ...b,
7135
+ // A tenant-aware server may answer available:false (+ reason) with 200; keep it.
7136
+ available: b.available !== false,
7137
+ apiVersion: typeof b.apiVersion === 'number' ? b.apiVersion : 1,
7138
+ zipDownload: b.zipDownload === true,
7139
+ recursiveDelete: b.recursiveDelete === true,
7140
+ folderStats: b.folderStats === true,
7141
+ linkedCounts: b.linkedCounts === true,
7142
+ reservedRootNames: (Array.isArray(b.reservedRootNames) && b.reservedRootNames.length > 0 ? b.reservedRootNames : FILES_RESERVED_ROOT_NAMES)
7143
+ .map((n) => n.toLowerCase()),
7144
+ };
7145
+ }
7146
+ function normalizeStats(body) {
7147
+ const b = body ?? {};
7148
+ return {
7149
+ folders: b.folders ?? 0,
7150
+ files: b.files ?? 0,
7151
+ bytes: b.bytes ?? 0,
7152
+ linkedFiles: b.linkedFiles ?? 0,
7153
+ hiddenEntries: b.hiddenEntries ?? 0,
7154
+ complete: b.complete !== false,
7155
+ linkedSamples: (b.linkedSamples ?? []).map((s) => ({ ...s, entities: s.entities ?? [] })),
7156
+ };
7157
+ }
7158
+ /**
7159
+ * Blob requests deliver their error body as a `Blob`; this rethrows the error with the parsed problem
7160
+ * details (or the text) as body, so {@link parseFilesProblem} works for downloads as well.
7161
+ */
7162
+ async function withProblemBody(request) {
7163
+ try {
7164
+ return await request;
7165
+ }
7166
+ catch (error) {
7167
+ if (error instanceof HttpErrorResponse && error.error instanceof Blob) {
7168
+ const body = await readBlobBody(error.error);
7169
+ throw new HttpErrorResponse({
7170
+ error: body,
7171
+ headers: error.headers,
7172
+ status: error.status,
7173
+ statusText: error.statusText,
7174
+ url: error.url ?? undefined,
7175
+ });
7176
+ }
7177
+ throw error;
7178
+ }
7179
+ }
7180
+ async function readBlobBody(blob) {
7181
+ let text;
7182
+ try {
7183
+ text = await blob.text();
7184
+ }
7185
+ catch {
7186
+ return null;
7187
+ }
7188
+ try {
7189
+ return JSON.parse(text);
7190
+ }
7191
+ catch {
7192
+ return text;
7193
+ }
7194
+ }
7195
+ /** Emits once the signal aborts (also when it is already aborted). */
7196
+ function abortOf(signal) {
7197
+ return signal.aborted ? from([true]) : fromEvent(signal, 'abort');
7198
+ }
7199
+ function checkRtId(rtId) {
7200
+ if (!rtId || isDotSegment(rtId) || rtId.includes('/')) {
7201
+ throw new FilesPathError(`Invalid rtId: ${rtId}`);
7202
+ }
7203
+ return rtId;
7204
+ }
7205
+ function isDotSegment(segment) {
7206
+ return segment === '.' || segment === '..';
7207
+ }
7208
+ function callerHandled(statuses = CALLER_HANDLED) {
7209
+ return new HttpContext().set(MM_CALLER_HANDLED_STATUSES, statuses);
7210
+ }
7211
+ function joinSegments(...parts) {
7212
+ return parts.flatMap((p) => p.split('/')).filter((p) => p.length > 0).join('/');
7213
+ }
7214
+
6595
7215
  /**
6596
7216
  * Service for communication controller operations.
6597
7217
  * Handles adapter deployment, pipeline execution, and debugging.
@@ -7849,5 +8469,5 @@ function provideOctoServices(octoServiceOptions) {
7849
8469
  * Generated bundle index. Do not edit.
7850
8470
  */
7851
8471
 
7852
- export { AggregationInputTypesDto, AggregationTypeDto, AggregationTypesDto, AiService, ArchiveStorageHealthDto, AssetRepoGraphQlDataSource, AssetRepoService, AssociationModOptionsDto, AttributeOwnershipDto, AttributeSelectorService, AttributeValueTypeDto, BasicEnergyCarrierTypeDto, BasicEnergyDataQualityDto, BasicEnergyFacilityTypeDto, BasicEnergyProductionTypeDto, BasicEnergyStateDto, BasicLegalEntityTypeDto, BasicSalutationDto, BasicTypeOfTelephoneBasicDto, BasicTypeOfTelephoneEnhancedDto, BasicUnitOfMeasureDto, BlueprintConflictResolutionDto, BlueprintUpdateModeDto, BotSecretsService, BotService, BucketAlignmentDto, BucketAlignmentInputDto, CONFIGURATION_SERVICE, CREDENTIAL_ATTRIBUTE_NAME_SUFFIXES, CkExtensionUpdateOperationsDto, CkModelCatalogService, CkModelService, CkRollupFunctionDto, CkTypeAttributeService, CkTypeMetaData, CkTypeSelectorService, CommunicationService, DEFAULT_SECRET_STATUS_LABELS, DeepGraphDirectionDto, DeleteStrategiesDto, DeploymentState, EnergyCommunityBillingCycleDto, EnergyCommunityBillingDocumentStateDto, EnergyCommunityBillingTypeDto, EnergyCommunityTaxProcedureCreditNoteDto, EnvironmentCarbonScopeDto, EnvironmentComplianceCategoryDto, EnvironmentComplianceStatusDto, EnvironmentEnergySourceDto, EnvironmentGoalStateDto, FieldFilterOperatorsDto, FormulaResultTypeDto, GetCkModelByIdDocumentDto, GetCkModelByIdDtoGQL, GetCkRecordAttributesDocumentDto, GetCkRecordAttributesDtoGQL, GetCkTypeAttributesDocumentDto, GetCkTypeAttributesDtoGQL, GetCkTypeAvailableQueryColumnsDocumentDto, GetCkTypeAvailableQueryColumnsDtoGQL, GetCkTypesDocumentDto, GetCkTypesDtoGQL, GetDerivedCkTypesDocumentDto, GetDerivedCkTypesDtoGQL, GetEntitiesByCkTypeDocumentDto, GetEntitiesByCkTypeDtoGQL, GraphDirectionDto, GraphQL, GraphQLCloneIgnoredProperties, GraphQLCommonIgnoredProperties, GraphQlDataSource, HealthService, HealthStatus, IDENTITY_PROVIDER_TYPE_LABELS, IdentityProviderType, IdentityService, ImportStrategyDto, IndustryBasicAlarmPriorityDto, IndustryBasicAlarmSourceTypeDto, IndustryBasicAlarmStateDto, IndustryBasicAlarmTypeDto, IndustryBasicIecDataTypeDto, IndustryBasicMachineCapabilitiesDto, IndustryBasicMachineStateDto, IndustryEnergyDemandResponseMarketDto, IndustryEnergyDemandResponseStatusDto, IndustryEnergyTariffTypeDto, IndustryMaintenanceAggregationTypeDto, IndustryMaintenanceCostCategoryDto, IndustryMaintenanceEnergyBalanceGroupDto, IndustryMaintenanceEnergyBalanceProductDto, IndustryMaintenanceEnergyBalanceUnitDto, IndustryMaintenanceOrderPriorityDto, IndustryMaintenanceOrderStateDto, IndustryMaintenanceOrderTypeDto, IndustryMaintenanceServiceTypeDto, IndustryManufacturingFeedbackSyncStateDto, IndustryManufacturingProductionOrderItemStateDto, IndustryManufacturingProductionOrderStateDto, JobManagementService, LevelMetaData, LoggerSeverity, ModelStateDto, MultiplicitiesDto, NavigationFilterModeDto, OCTO_SILENT_ERRORS, OctoErrorLink, OctoGraphQLServiceBase, OctoSdkDemoCustomerStatusDto, OctoSdkDemoNetworkOperatorDto, OctoSdkDemoOperatingStatusDto, OctoServiceOptions, OctoServicesModule, PagedGraphResultDto, ProgressValue, ProgressWindowService, QueryModeDto, ReportingService, RtAssociationMetaData, RuntimeEntityDialogDataSource, RuntimeEntitySelectDataSource, SECRET_DUMP_RESTORE_ERROR_DUMP_DELETED, SECRET_DUMP_RESTORE_ERROR_DUMP_KEY_MISSING, SECRET_LEGACY_V1_KEY_ID, SECRET_STATUS_WARNING_DUMP_KEY_MISSING, SECRET_STATUS_WARNING_NO_KEY_RING, SECRET_STATUS_WARNING_NO_LEGACY_V1_KEY, SECRET_VALUE_TYPE, SearchFilterTypesDto, SecretStorageFormDto, SecretUsageMatchDto, SeriesComparisonPolicyDto, SeriesResolutionSignalDto, SortOrdersDto, SystemAggregationTypesDto, SystemAiApprovalModeDto, SystemAiApprovalReasonDto, SystemAiApprovalStatusDto, SystemAiAuthModeDto, SystemAiConflictModeDto, SystemAiCredentialKindDto, SystemAiJobKindDto, SystemAiJobStatusDto, SystemAiKnowledgeKindDto, SystemAiLeaseStatusDto, SystemAiModelTierDto, SystemAiRiskLevelDto, SystemAiSessionEventKindDto, SystemAiSessionStatusDto, SystemAiSubscriptionScopeDto, SystemAiTicketScopeDto, SystemAiTicketStatusDto, SystemAiWorkspaceModeDto, SystemCommunicationAdapterSharingModeDto, SystemCommunicationCommunicationStateDto, SystemCommunicationConfigurationStateDto, SystemCommunicationDeploymentStateDto, SystemCommunicationEnvironmentDto, SystemCommunicationHelmChannelDto, SystemCommunicationHelmRepositoryPurposeDto, SystemCommunicationLifecycleModeDto, SystemCommunicationLifecycleStateDto, SystemCommunicationPipelineExecutionClassDto, SystemCommunicationPipelineExecutionStatusDto, SystemCommunicationPipelineTriggerTypeDto, SystemCommunicationPoolScaleUpPolicyDto, SystemCommunicationSignalRegistrationActionDto, SystemCommunicationSignalRegistrationStateDto, SystemEnvironmentModesDto, SystemFieldFilterOperatorDto, SystemIdentityDataPolicyEnforcementModeDto, SystemIdentityDataPolicyScopeDto, SystemIdentityIdentifierKindDto, SystemIdentityIdentifierSourceDto, SystemIdentityTokenExpirationDto, SystemIdentityTokenTypeDto, SystemIdentityTokenUsageDto, SystemIdentityTrustLevelDto, SystemMaintenanceLevelsDto, SystemNavigationFilterModesDto, SystemNotificationEventLevelsDto, SystemNotificationEventSourcesDto, SystemNotificationEventStatesDto, SystemNotificationNotificationTypesDto, SystemNotificationRenderingTypesDto, SystemQueryTypesDto, SystemSortOrdersDto, SystemStreamDataBucketAlignmentDto, SystemStreamDataCkArchiveStatusDto, SystemStreamDataCkComputedColumnResultTypeDto, SystemStreamDataCkComputedColumnStateDto, SystemStreamDataCkConflictKeyOrderDto, SystemStreamDataCkRecomputeChangeKindDto, SystemStreamDataCkRecomputeChangeSourceDto, SystemStreamDataCkRecomputeJobStateDto, SystemStreamDataCkRecomputeTriggerDto, SystemStreamDataCkRollupFunctionDto, TENANT_ID_PROVIDER, TusUploadService, UpdateTypeDto, buildTusEndpoint, formatSecretStatus, isCredentialLikeAttributeName, isSecretAttributeCandidate, isSecretPresent, isSecretQueryColumn, isSecretStateObject, isSecretValueType, isTextualValueType, octoDataIdFromObject, result as possibleTypes, provideOctoServices, secretInputValue, secretStateFromAttribute, secretStatusOf, toAttributeNameFilter, toCamelCaseAttributeName, toSecretState, toUniqueCamelCaseNames };
8472
+ export { AggregationInputTypesDto, AggregationTypeDto, AggregationTypesDto, AiService, ArchiveStorageHealthDto, AssetRepoGraphQlDataSource, AssetRepoService, AssociationModOptionsDto, AttributeOwnershipDto, AttributeSelectorService, AttributeValueTypeDto, BasicEnergyCarrierTypeDto, BasicEnergyDataQualityDto, BasicEnergyFacilityTypeDto, BasicEnergyProductionTypeDto, BasicEnergyStateDto, BasicLegalEntityTypeDto, BasicSalutationDto, BasicTypeOfTelephoneBasicDto, BasicTypeOfTelephoneEnhancedDto, BasicUnitOfMeasureDto, BinaryDownloadUnavailableError, BlueprintConflictResolutionDto, BlueprintUpdateModeDto, BotSecretsService, BotService, BucketAlignmentDto, BucketAlignmentInputDto, CONFIGURATION_SERVICE, CREDENTIAL_ATTRIBUTE_NAME_SUFFIXES, CkExtensionUpdateOperationsDto, CkModelCatalogService, CkModelService, CkRollupFunctionDto, CkTypeAttributeService, CkTypeMetaData, CkTypeSelectorService, CommunicationService, DEFAULT_SECRET_STATUS_LABELS, DeepGraphDirectionDto, DeleteStrategiesDto, DeploymentState, EnergyCommunityBillingCycleDto, EnergyCommunityBillingDocumentStateDto, EnergyCommunityBillingTypeDto, EnergyCommunityTaxProcedureCreditNoteDto, EnvironmentCarbonScopeDto, EnvironmentComplianceCategoryDto, EnvironmentComplianceStatusDto, EnvironmentEnergySourceDto, EnvironmentGoalStateDto, FILES_LINKED_COUNTS_MAX, FILES_RESERVED_ROOT_NAMES, FILES_UNAVAILABLE_TTL_MS, FieldFilterOperatorsDto, FileDownloadService, FilesClientService, FilesPathError, FormulaResultTypeDto, GetCkModelByIdDocumentDto, GetCkModelByIdDtoGQL, GetCkRecordAttributesDocumentDto, GetCkRecordAttributesDtoGQL, GetCkTypeAttributesDocumentDto, GetCkTypeAttributesDtoGQL, GetCkTypeAvailableQueryColumnsDocumentDto, GetCkTypeAvailableQueryColumnsDtoGQL, GetCkTypesDocumentDto, GetCkTypesDtoGQL, GetDerivedCkTypesDocumentDto, GetDerivedCkTypesDtoGQL, GetEntitiesByCkTypeDocumentDto, GetEntitiesByCkTypeDtoGQL, GraphDirectionDto, GraphQL, GraphQLCloneIgnoredProperties, GraphQLCommonIgnoredProperties, GraphQlDataSource, HealthService, HealthStatus, IDENTITY_PROVIDER_TYPE_LABELS, IdentityProviderType, IdentityService, ImportStrategyDto, IndustryBasicAlarmPriorityDto, IndustryBasicAlarmSourceTypeDto, IndustryBasicAlarmStateDto, IndustryBasicAlarmTypeDto, IndustryBasicIecDataTypeDto, IndustryBasicMachineCapabilitiesDto, IndustryBasicMachineStateDto, IndustryEnergyDemandResponseMarketDto, IndustryEnergyDemandResponseStatusDto, IndustryEnergyTariffTypeDto, IndustryMaintenanceAggregationTypeDto, IndustryMaintenanceCostCategoryDto, IndustryMaintenanceEnergyBalanceGroupDto, IndustryMaintenanceEnergyBalanceProductDto, IndustryMaintenanceEnergyBalanceUnitDto, IndustryMaintenanceOrderPriorityDto, IndustryMaintenanceOrderStateDto, IndustryMaintenanceOrderTypeDto, IndustryMaintenanceServiceTypeDto, IndustryManufacturingFeedbackSyncStateDto, IndustryManufacturingProductionOrderItemStateDto, IndustryManufacturingProductionOrderStateDto, JobManagementService, LevelMetaData, LoggerSeverity, ModelStateDto, MultiplicitiesDto, NavigationFilterModeDto, OCTO_SILENT_ERRORS, OctoErrorLink, OctoGraphQLServiceBase, OctoSdkDemoCustomerStatusDto, OctoSdkDemoNetworkOperatorDto, OctoSdkDemoOperatingStatusDto, OctoServiceOptions, OctoServicesModule, PagedGraphResultDto, ProgressValue, ProgressWindowService, QueryModeDto, ReportingService, RtAssociationMetaData, RuntimeEntityDialogDataSource, RuntimeEntitySelectDataSource, SECRET_DUMP_RESTORE_ERROR_DUMP_DELETED, SECRET_DUMP_RESTORE_ERROR_DUMP_KEY_MISSING, SECRET_LEGACY_V1_KEY_ID, SECRET_STATUS_WARNING_DUMP_KEY_MISSING, SECRET_STATUS_WARNING_NO_KEY_RING, SECRET_STATUS_WARNING_NO_LEGACY_V1_KEY, SECRET_VALUE_TYPE, SearchFilterTypesDto, SecretStorageFormDto, SecretUsageMatchDto, SeriesComparisonPolicyDto, SeriesResolutionSignalDto, SortOrdersDto, SystemAggregationTypesDto, SystemAiApprovalModeDto, SystemAiApprovalReasonDto, SystemAiApprovalStatusDto, SystemAiAuthModeDto, SystemAiConflictModeDto, SystemAiCredentialKindDto, SystemAiJobKindDto, SystemAiJobStatusDto, SystemAiKnowledgeKindDto, SystemAiLeaseStatusDto, SystemAiModelTierDto, SystemAiRiskLevelDto, SystemAiSessionEventKindDto, SystemAiSessionStatusDto, SystemAiSubscriptionScopeDto, SystemAiTicketScopeDto, SystemAiTicketStatusDto, SystemAiWorkspaceModeDto, SystemCommunicationAdapterSharingModeDto, SystemCommunicationCommunicationStateDto, SystemCommunicationConfigurationStateDto, SystemCommunicationDeploymentStateDto, SystemCommunicationEnvironmentDto, SystemCommunicationHelmChannelDto, SystemCommunicationHelmRepositoryPurposeDto, SystemCommunicationLifecycleModeDto, SystemCommunicationLifecycleStateDto, SystemCommunicationPipelineExecutionClassDto, SystemCommunicationPipelineExecutionStatusDto, SystemCommunicationPipelineTriggerTypeDto, SystemCommunicationPoolScaleUpPolicyDto, SystemCommunicationSignalRegistrationActionDto, SystemCommunicationSignalRegistrationStateDto, SystemEnvironmentModesDto, SystemFieldFilterOperatorDto, SystemIdentityDataPolicyEnforcementModeDto, SystemIdentityDataPolicyScopeDto, SystemIdentityIdentifierKindDto, SystemIdentityIdentifierSourceDto, SystemIdentityTokenExpirationDto, SystemIdentityTokenTypeDto, SystemIdentityTokenUsageDto, SystemIdentityTrustLevelDto, SystemMaintenanceLevelsDto, SystemNavigationFilterModesDto, SystemNotificationEventLevelsDto, SystemNotificationEventSourcesDto, SystemNotificationEventStatesDto, SystemNotificationNotificationTypesDto, SystemNotificationRenderingTypesDto, SystemQueryTypesDto, SystemSortOrdersDto, SystemStreamDataBucketAlignmentDto, SystemStreamDataCkArchiveStatusDto, SystemStreamDataCkComputedColumnResultTypeDto, SystemStreamDataCkComputedColumnStateDto, SystemStreamDataCkConflictKeyOrderDto, SystemStreamDataCkRecomputeChangeKindDto, SystemStreamDataCkRecomputeChangeSourceDto, SystemStreamDataCkRecomputeJobStateDto, SystemStreamDataCkRecomputeTriggerDto, SystemStreamDataCkRollupFunctionDto, TENANT_ID_PROVIDER, TusUploadService, UpdateTypeDto, buildTusEndpoint, filesGraphQlErrorCode, formatSecretStatus, isCredentialLikeAttributeName, isSecretAttributeCandidate, isSecretPresent, isSecretQueryColumn, isSecretStateObject, isSecretValueType, isTextualValueType, octoDataIdFromObject, parseContentDispositionFileName, parseFilesProblem, result as possibleTypes, provideOctoServices, secretInputValue, secretStateFromAttribute, secretStatusOf, toAttributeNameFilter, toCamelCaseAttributeName, toSecretState, toUniqueCamelCaseNames };
7853
8473
  //# sourceMappingURL=meshmakers-octo-services.mjs.map