@robosystems/client 0.3.38 → 0.3.40

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.
@@ -1,6 +1,6 @@
1
1
  import type { AssociationResponse, AutoMapElementsOperation, CreateAgentRequest, CreateEventBlockRequest, CreateEventHandlerRequest, CreateInformationBlockRequest, CreateMappingAssociationOperation, CreateTaxonomyBlockRequest, CreateViewRequest, DeleteInformationBlockRequest, DeleteInformationBlockResponse, DeleteMappingAssociationOperation, DeleteResult, DeleteTaxonomyBlockRequest, DeleteTaxonomyBlockResponse, EntityTaxonomyResponse, EvaluateRulesRequest, EvaluateRulesResponse, EventBlockEnvelope, EventHandlerResponse, FinancialStatementAnalysisRequest, InformationBlockEnvelope, JournalEntryResponse, LedgerAgentResponse, LinkEntityTaxonomyRequest, LiveFinancialStatementRequest, OperationEnvelope, PreviewEventBlockResponse, PublishListMemberResponse, PublishListResponse, ReportResponse, ShareReportResponse, TaxonomyBlockEnvelope, UpdateAgentRequest, UpdateEntityRequest, UpdateEventBlockRequest, UpdateEventHandlerRequest, UpdateInformationBlockRequest, UpdateJournalEntryRequest, UpdateTaxonomyBlockRequest } from '../types.gen';
2
2
  import type { TokenProvider } from './graphql/client';
3
- import { type GetInformationBlockQuery, type GetLedgerAccountRollupsQuery, type GetLedgerAccountTreeQuery, type GetLedgerAgentQuery, type GetLedgerClosingBookStructuresQuery, type GetLedgerEntityQuery, type GetLedgerEventBlockQuery, type GetLedgerFiscalCalendarQuery, type GetLedgerMappedTrialBalanceQuery, type GetLedgerMappingCoverageQuery, type GetLedgerMappingQuery, type GetLedgerPeriodCloseStatusQuery, type GetLedgerPeriodDraftsQuery, type GetLedgerPublishListQuery, type GetLedgerReportingTaxonomyQuery, type GetLedgerReportPackageQuery, type GetLedgerReportQuery, type GetLedgerStatementQuery, type GetLedgerSummaryQuery, type GetLedgerTransactionQuery, type GetLedgerTrialBalanceQuery, type ListInformationBlocksQuery, type ListLedgerAccountsQuery, type ListLedgerAgentsQuery, type ListLedgerElementsQuery, type ListLedgerEntitiesQuery, type ListLedgerEventBlocksQuery, type ListLedgerMappingsQuery, type ListLedgerPublishListsQuery, type ListLedgerReportsQuery, type ListLedgerStructuresQuery, type ListLedgerTaxonomiesQuery, type ListLedgerTransactionsQuery, type ListLedgerUnmappedElementsQuery, type MappingCandidatesQuery } from './graphql/generated/graphql';
3
+ import { type GetInformationBlockQuery, type GetLedgerAccountRollupsQuery, type GetLedgerAccountTreeQuery, type GetLedgerAgentQuery, type GetLedgerClosingBookStructuresQuery, type GetLedgerEntityQuery, type GetLedgerEventBlockQuery, type GetLedgerFiscalCalendarQuery, type GetLedgerMappedTrialBalanceQuery, type GetLedgerMappingCoverageQuery, type GetLedgerMappingQuery, type GetLedgerPeriodCloseStatusQuery, type GetLedgerPeriodDraftsQuery, type GetLedgerPublishListQuery, type GetLedgerReportingTaxonomyQuery, type GetLedgerReportPackageQuery, type GetLedgerReportQuery, type GetLedgerStatementQuery, type GetLedgerSummaryQuery, type GetLedgerTransactionQuery, type GetLedgerTrialBalanceQuery, type ListInformationBlocksQuery, type ListLedgerAccountsQuery, type ListLedgerAgentsQuery, type ListLedgerElementsQuery, type ListLedgerEntitiesQuery, type ListLedgerEventBlocksQuery, type ListLedgerMappingsQuery, type ListLedgerPublishListsQuery, type ListLedgerReportsQuery, type ListLedgerStructuresQuery, type ListLedgerTaxonomiesQuery, type ListLedgerTransactionsQuery, type ListLedgerUnmappedElementsQuery, type MappingCandidatesQuery, type ReportDownloadFormat } from './graphql/generated/graphql';
4
4
  export type LedgerEntity = NonNullable<GetLedgerEntityQuery['entity']>;
5
5
  export type LedgerEntitySummary = ListLedgerEntitiesQuery['entities'][number];
6
6
  export type LedgerSummary = NonNullable<GetLedgerSummaryQuery['summary']>;
@@ -56,7 +56,7 @@ export type PublishListMember = PublishListDetail['members'][number];
56
56
  /**
57
57
  * Presigned-URL response for a Report bundle download.
58
58
  *
59
- * Returned by ``LedgerClient.getReportBundleDownloadUrl`` — the
59
+ * Returned by ``LedgerClient.getReportDownloadUrl`` — the
60
60
  * ``downloadUrl`` is a time-limited URL that streams the
61
61
  * serialization artifact directly from object storage. Browser
62
62
  * callers typically follow the URL via ``window.location.href`` or
@@ -69,7 +69,7 @@ export interface ReportBundleDownloadResponse {
69
69
  expiresAt: string;
70
70
  /** MIME type of the artifact behind the URL. */
71
71
  contentType: string;
72
- /** Serialization flavor — ``jsonld`` is the Phase 1a default. */
72
+ /** Serialization flavor — ``jsonld`` or ``xbrl-2.1``. */
73
73
  format: string;
74
74
  /** Bundle generation number stamped on the Report. */
75
75
  generationCount: number;
@@ -587,51 +587,29 @@ export declare class LedgerClient {
587
587
  * Get a short-lived presigned URL for downloading a published
588
588
  * Report's serialization bundle.
589
589
  *
590
- * Phase 1a only resolves the JSON-LD flavor; reserved RDF and XBRL
591
- * flavors return HTTP 400 until their producers ship. Reports
592
- * published before the serialization feature shipped will resolve
593
- * to a 404 those Reports have no stamped bundle_url and must be
594
- * regenerated to produce one.
590
+ * A download is a read, so this resolves through GraphQL
591
+ * (`reportDownloadUrl`) the retired `GET .../reports/{id}/download`
592
+ * REST resource is gone. Every flavor resolves to a presigned S3 URL:
593
+ * JSON-LD is stamped at publish time; XBRL is materialized + cached
594
+ * on first request. The returned `downloadUrl` is valid for
595
+ * `expiresIn` seconds (default 300, max 3600); browser callers
596
+ * navigate to it via `window.location.href` (or an `<a href>` click)
597
+ * to trigger the download — the server-set Content-Disposition forces
598
+ * "attachment" with a versioned filename.
595
599
  *
596
- * The returned ``downloadUrl`` is a presigned S3 URL valid for
597
- * ``expiresIn`` seconds (default 300, max 3600). Browser callers
598
- * typically navigate to it via ``window.location.href`` (or assign
599
- * to an `<a href>` and click) to trigger the file download; the
600
- * server-set Content-Disposition forces "attachment" with a
601
- * versioned filename.
600
+ * Returns `null` when the report doesn't exist. A report that has
601
+ * never been published surfaces a `REPORT_BUNDLE_NOT_AVAILABLE`
602
+ * GraphQL error (regenerate it to produce a bundle).
602
603
  *
603
604
  * @param graphId Graph identifier owning the Report.
604
605
  * @param reportId Report identifier (rpt_-prefixed ULID).
605
- * @param options.format Serialization flavor — defaults to ``'jsonld'``.
606
+ * @param options.format Serialization flavor — `JSONLD` (default) or `XBRL_2_1`.
606
607
  * @param options.expiresIn Presigned URL lifetime, in seconds.
607
608
  */
608
- getReportBundleDownloadUrl(graphId: string, reportId: string, options?: {
609
- format?: string;
609
+ getReportDownloadUrl(graphId: string, reportId: string, options?: {
610
+ format?: ReportDownloadFormat;
610
611
  expiresIn?: number;
611
- }): Promise<ReportBundleDownloadResponse>;
612
- /**
613
- * Download the Report's serialization bundle as an XBRL 2.1 zip.
614
- *
615
- * Rebuilds the bundle on the server and streams the zip body
616
- * directly — no S3 presigned URL is involved (XBRL is on-demand
617
- * emit, per the serialization spec). The returned ``Blob`` can be
618
- * saved via URL.createObjectURL + a temporary anchor click to
619
- * trigger the browser download dialog.
620
- *
621
- * The zip contains five files: ``instance.xml``, ``report.xsd``,
622
- * ``report-pre.xml``, ``report-cal.xml``, ``report-def.xml``.
623
- *
624
- * @param graphId Graph identifier owning the Report.
625
- * @param reportId Report identifier (rpt_-prefixed ULID).
626
- * @param options.flavor XBRL flavor (default ``'xbrl-2.1'``).
627
- */
628
- getReportBundleXbrlZip(graphId: string, reportId: string, options?: {
629
- flavor?: string;
630
- }): Promise<{
631
- blob: Blob;
632
- filename: string;
633
- generationCount: number | null;
634
- }>;
612
+ }): Promise<ReportBundleDownloadResponse | null>;
635
613
  /**
636
614
  * Share a published report to every member of a publish list. Each
637
615
  * target graph receives a snapshot copy of the report's facts.
@@ -768,115 +768,42 @@ class LedgerClient {
768
768
  * Get a short-lived presigned URL for downloading a published
769
769
  * Report's serialization bundle.
770
770
  *
771
- * Phase 1a only resolves the JSON-LD flavor; reserved RDF and XBRL
772
- * flavors return HTTP 400 until their producers ship. Reports
773
- * published before the serialization feature shipped will resolve
774
- * to a 404 those Reports have no stamped bundle_url and must be
775
- * regenerated to produce one.
771
+ * A download is a read, so this resolves through GraphQL
772
+ * (`reportDownloadUrl`) the retired `GET .../reports/{id}/download`
773
+ * REST resource is gone. Every flavor resolves to a presigned S3 URL:
774
+ * JSON-LD is stamped at publish time; XBRL is materialized + cached
775
+ * on first request. The returned `downloadUrl` is valid for
776
+ * `expiresIn` seconds (default 300, max 3600); browser callers
777
+ * navigate to it via `window.location.href` (or an `<a href>` click)
778
+ * to trigger the download — the server-set Content-Disposition forces
779
+ * "attachment" with a versioned filename.
776
780
  *
777
- * The returned ``downloadUrl`` is a presigned S3 URL valid for
778
- * ``expiresIn`` seconds (default 300, max 3600). Browser callers
779
- * typically navigate to it via ``window.location.href`` (or assign
780
- * to an `<a href>` and click) to trigger the file download; the
781
- * server-set Content-Disposition forces "attachment" with a
782
- * versioned filename.
781
+ * Returns `null` when the report doesn't exist. A report that has
782
+ * never been published surfaces a `REPORT_BUNDLE_NOT_AVAILABLE`
783
+ * GraphQL error (regenerate it to produce a bundle).
783
784
  *
784
785
  * @param graphId Graph identifier owning the Report.
785
786
  * @param reportId Report identifier (rpt_-prefixed ULID).
786
- * @param options.format Serialization flavor — defaults to ``'jsonld'``.
787
+ * @param options.format Serialization flavor — `JSONLD` (default) or `XBRL_2_1`.
787
788
  * @param options.expiresIn Presigned URL lifetime, in seconds.
788
789
  */
789
- async getReportBundleDownloadUrl(graphId, reportId, options = {}) {
790
- const format = options.format ?? 'jsonld';
791
- const expiresIn = options.expiresIn ?? 300;
792
- const url = `${this.config.baseUrl.replace(/\/$/, '')}` +
793
- `/extensions/roboledger/${encodeURIComponent(graphId)}` +
794
- `/reports/${encodeURIComponent(reportId)}/download` +
795
- `?format=${encodeURIComponent(format)}&expires_in=${expiresIn}`;
796
- const headers = new Headers({ Accept: 'application/json', ...(this.config.headers ?? {}) });
797
- const token = await this.resolveToken();
798
- if (token) {
799
- // ``rfs…`` long-lived keys go in X-API-Key; everything else is
800
- // a short-lived JWT. Mirrors the GraphQL client behaviour at
801
- // ``clients/graphql/client.ts``.
802
- if (token.startsWith('rfs')) {
803
- headers.set('X-API-Key', token);
804
- }
805
- else {
806
- headers.set('Authorization', `Bearer ${token}`);
807
- }
808
- }
809
- const response = await fetch(url, {
810
- method: 'GET',
811
- headers,
812
- credentials: this.config.credentials,
813
- });
814
- if (!response.ok) {
815
- const body = await response.text();
816
- throw new Error(`Get report bundle download URL failed (${response.status}): ${body}`);
817
- }
818
- const raw = (await response.json());
819
- return {
820
- downloadUrl: raw.download_url,
821
- expiresAt: raw.expires_at,
822
- contentType: raw.content_type,
823
- format: raw.format,
824
- generationCount: raw.generation_count,
825
- };
826
- }
827
- /**
828
- * Download the Report's serialization bundle as an XBRL 2.1 zip.
829
- *
830
- * Rebuilds the bundle on the server and streams the zip body
831
- * directly — no S3 presigned URL is involved (XBRL is on-demand
832
- * emit, per the serialization spec). The returned ``Blob`` can be
833
- * saved via URL.createObjectURL + a temporary anchor click to
834
- * trigger the browser download dialog.
835
- *
836
- * The zip contains five files: ``instance.xml``, ``report.xsd``,
837
- * ``report-pre.xml``, ``report-cal.xml``, ``report-def.xml``.
838
- *
839
- * @param graphId Graph identifier owning the Report.
840
- * @param reportId Report identifier (rpt_-prefixed ULID).
841
- * @param options.flavor XBRL flavor (default ``'xbrl-2.1'``).
842
- */
843
- async getReportBundleXbrlZip(graphId, reportId, options = {}) {
844
- const flavor = options.flavor ?? 'xbrl-2.1';
845
- const url = `${this.config.baseUrl.replace(/\/$/, '')}` +
846
- `/extensions/roboledger/${encodeURIComponent(graphId)}` +
847
- `/reports/${encodeURIComponent(reportId)}/download` +
848
- `?format=${encodeURIComponent(flavor)}`;
849
- const headers = new Headers({
850
- Accept: 'application/zip',
851
- ...(this.config.headers ?? {}),
852
- });
853
- const token = await this.resolveToken();
854
- if (token) {
855
- if (token.startsWith('rfs')) {
856
- headers.set('X-API-Key', token);
857
- }
858
- else {
859
- headers.set('Authorization', `Bearer ${token}`);
860
- }
861
- }
862
- const response = await fetch(url, {
863
- method: 'GET',
864
- headers,
865
- credentials: this.config.credentials,
790
+ async getReportDownloadUrl(graphId, reportId, options = {}) {
791
+ return this.gqlQuery(graphId, graphql_1.GetLedgerReportDownloadUrlDocument, {
792
+ reportId,
793
+ format: options.format ?? 'JSONLD',
794
+ expiresIn: options.expiresIn ?? 300,
795
+ }, 'Get report download URL', (data) => {
796
+ const node = data.reportDownloadUrl;
797
+ if (!node)
798
+ return null;
799
+ return {
800
+ downloadUrl: node.downloadUrl,
801
+ expiresAt: node.expiresAt,
802
+ contentType: node.contentType,
803
+ format: node.format,
804
+ generationCount: node.generationCount,
805
+ };
866
806
  });
867
- if (!response.ok) {
868
- const body = await response.text();
869
- throw new Error(`Get report bundle XBRL zip failed (${response.status}): ${body}`);
870
- }
871
- const blob = await response.blob();
872
- // Parse Content-Disposition for the server-suggested filename;
873
- // fall back to a sensible default if absent.
874
- const disposition = response.headers.get('Content-Disposition') ?? '';
875
- const filenameMatch = disposition.match(/filename="?([^";]+)"?/i);
876
- const filename = filenameMatch ? filenameMatch[1] : `${reportId}.zip`;
877
- const generationHeader = response.headers.get('X-Bundle-Generation');
878
- const generationCount = generationHeader ? Number.parseInt(generationHeader, 10) : null;
879
- return { blob, filename, generationCount };
880
807
  }
881
808
  /**
882
809
  * Share a published report to every member of a publish list. Each
@@ -136,6 +136,7 @@ import {
136
136
  GetLedgerPeriodDraftsDocument,
137
137
  GetLedgerPublishListDocument,
138
138
  GetLedgerReportDocument,
139
+ GetLedgerReportDownloadUrlDocument,
139
140
  GetLedgerReportingTaxonomyDocument,
140
141
  GetLedgerReportPackageDocument,
141
142
  GetLedgerStatementDocument,
@@ -191,6 +192,7 @@ import {
191
192
  type ListLedgerTransactionsQuery,
192
193
  type ListLedgerUnmappedElementsQuery,
193
194
  type MappingCandidatesQuery,
195
+ type ReportDownloadFormat,
194
196
  } from './graphql/generated/graphql'
195
197
 
196
198
  // ── Friendly types derived from GraphQL codegen ────────────────────────
@@ -283,7 +285,7 @@ export type PublishListMember = PublishListDetail['members'][number]
283
285
  /**
284
286
  * Presigned-URL response for a Report bundle download.
285
287
  *
286
- * Returned by ``LedgerClient.getReportBundleDownloadUrl`` — the
288
+ * Returned by ``LedgerClient.getReportDownloadUrl`` — the
287
289
  * ``downloadUrl`` is a time-limited URL that streams the
288
290
  * serialization artifact directly from object storage. Browser
289
291
  * callers typically follow the URL via ``window.location.href`` or
@@ -296,20 +298,12 @@ export interface ReportBundleDownloadResponse {
296
298
  expiresAt: string
297
299
  /** MIME type of the artifact behind the URL. */
298
300
  contentType: string
299
- /** Serialization flavor — ``jsonld`` is the Phase 1a default. */
301
+ /** Serialization flavor — ``jsonld`` or ``xbrl-2.1``. */
300
302
  format: string
301
303
  /** Bundle generation number stamped on the Report. */
302
304
  generationCount: number
303
305
  }
304
306
 
305
- interface RawReportBundleDownloadResponse {
306
- download_url: string
307
- expires_at: string
308
- content_type: string
309
- format: string
310
- generation_count: number
311
- }
312
-
313
307
  export interface PeriodSpecInput {
314
308
  start: string
315
309
  end: string
@@ -1903,124 +1897,51 @@ export class LedgerClient {
1903
1897
  * Get a short-lived presigned URL for downloading a published
1904
1898
  * Report's serialization bundle.
1905
1899
  *
1906
- * Phase 1a only resolves the JSON-LD flavor; reserved RDF and XBRL
1907
- * flavors return HTTP 400 until their producers ship. Reports
1908
- * published before the serialization feature shipped will resolve
1909
- * to a 404 those Reports have no stamped bundle_url and must be
1910
- * regenerated to produce one.
1900
+ * A download is a read, so this resolves through GraphQL
1901
+ * (`reportDownloadUrl`) the retired `GET .../reports/{id}/download`
1902
+ * REST resource is gone. Every flavor resolves to a presigned S3 URL:
1903
+ * JSON-LD is stamped at publish time; XBRL is materialized + cached
1904
+ * on first request. The returned `downloadUrl` is valid for
1905
+ * `expiresIn` seconds (default 300, max 3600); browser callers
1906
+ * navigate to it via `window.location.href` (or an `<a href>` click)
1907
+ * to trigger the download — the server-set Content-Disposition forces
1908
+ * "attachment" with a versioned filename.
1911
1909
  *
1912
- * The returned ``downloadUrl`` is a presigned S3 URL valid for
1913
- * ``expiresIn`` seconds (default 300, max 3600). Browser callers
1914
- * typically navigate to it via ``window.location.href`` (or assign
1915
- * to an `<a href>` and click) to trigger the file download; the
1916
- * server-set Content-Disposition forces "attachment" with a
1917
- * versioned filename.
1910
+ * Returns `null` when the report doesn't exist. A report that has
1911
+ * never been published surfaces a `REPORT_BUNDLE_NOT_AVAILABLE`
1912
+ * GraphQL error (regenerate it to produce a bundle).
1918
1913
  *
1919
1914
  * @param graphId Graph identifier owning the Report.
1920
1915
  * @param reportId Report identifier (rpt_-prefixed ULID).
1921
- * @param options.format Serialization flavor — defaults to ``'jsonld'``.
1916
+ * @param options.format Serialization flavor — `JSONLD` (default) or `XBRL_2_1`.
1922
1917
  * @param options.expiresIn Presigned URL lifetime, in seconds.
1923
1918
  */
1924
- async getReportBundleDownloadUrl(
1925
- graphId: string,
1926
- reportId: string,
1927
- options: { format?: string; expiresIn?: number } = {}
1928
- ): Promise<ReportBundleDownloadResponse> {
1929
- const format = options.format ?? 'jsonld'
1930
- const expiresIn = options.expiresIn ?? 300
1931
- const url =
1932
- `${this.config.baseUrl.replace(/\/$/, '')}` +
1933
- `/extensions/roboledger/${encodeURIComponent(graphId)}` +
1934
- `/reports/${encodeURIComponent(reportId)}/download` +
1935
- `?format=${encodeURIComponent(format)}&expires_in=${expiresIn}`
1936
- const headers = new Headers({ Accept: 'application/json', ...(this.config.headers ?? {}) })
1937
- const token = await this.resolveToken()
1938
- if (token) {
1939
- // ``rfs…`` long-lived keys go in X-API-Key; everything else is
1940
- // a short-lived JWT. Mirrors the GraphQL client behaviour at
1941
- // ``clients/graphql/client.ts``.
1942
- if (token.startsWith('rfs')) {
1943
- headers.set('X-API-Key', token)
1944
- } else {
1945
- headers.set('Authorization', `Bearer ${token}`)
1946
- }
1947
- }
1948
- const response = await fetch(url, {
1949
- method: 'GET',
1950
- headers,
1951
- credentials: this.config.credentials,
1952
- })
1953
- if (!response.ok) {
1954
- const body = await response.text()
1955
- throw new Error(`Get report bundle download URL failed (${response.status}): ${body}`)
1956
- }
1957
- const raw = (await response.json()) as RawReportBundleDownloadResponse
1958
- return {
1959
- downloadUrl: raw.download_url,
1960
- expiresAt: raw.expires_at,
1961
- contentType: raw.content_type,
1962
- format: raw.format,
1963
- generationCount: raw.generation_count,
1964
- }
1965
- }
1966
-
1967
- /**
1968
- * Download the Report's serialization bundle as an XBRL 2.1 zip.
1969
- *
1970
- * Rebuilds the bundle on the server and streams the zip body
1971
- * directly — no S3 presigned URL is involved (XBRL is on-demand
1972
- * emit, per the serialization spec). The returned ``Blob`` can be
1973
- * saved via URL.createObjectURL + a temporary anchor click to
1974
- * trigger the browser download dialog.
1975
- *
1976
- * The zip contains five files: ``instance.xml``, ``report.xsd``,
1977
- * ``report-pre.xml``, ``report-cal.xml``, ``report-def.xml``.
1978
- *
1979
- * @param graphId Graph identifier owning the Report.
1980
- * @param reportId Report identifier (rpt_-prefixed ULID).
1981
- * @param options.flavor XBRL flavor (default ``'xbrl-2.1'``).
1982
- */
1983
- async getReportBundleXbrlZip(
1919
+ async getReportDownloadUrl(
1984
1920
  graphId: string,
1985
1921
  reportId: string,
1986
- options: { flavor?: string } = {}
1987
- ): Promise<{ blob: Blob; filename: string; generationCount: number | null }> {
1988
- const flavor = options.flavor ?? 'xbrl-2.1'
1989
- const url =
1990
- `${this.config.baseUrl.replace(/\/$/, '')}` +
1991
- `/extensions/roboledger/${encodeURIComponent(graphId)}` +
1992
- `/reports/${encodeURIComponent(reportId)}/download` +
1993
- `?format=${encodeURIComponent(flavor)}`
1994
- const headers = new Headers({
1995
- Accept: 'application/zip',
1996
- ...(this.config.headers ?? {}),
1997
- })
1998
- const token = await this.resolveToken()
1999
- if (token) {
2000
- if (token.startsWith('rfs')) {
2001
- headers.set('X-API-Key', token)
2002
- } else {
2003
- headers.set('Authorization', `Bearer ${token}`)
1922
+ options: { format?: ReportDownloadFormat; expiresIn?: number } = {}
1923
+ ): Promise<ReportBundleDownloadResponse | null> {
1924
+ return this.gqlQuery(
1925
+ graphId,
1926
+ GetLedgerReportDownloadUrlDocument,
1927
+ {
1928
+ reportId,
1929
+ format: options.format ?? 'JSONLD',
1930
+ expiresIn: options.expiresIn ?? 300,
1931
+ },
1932
+ 'Get report download URL',
1933
+ (data) => {
1934
+ const node = data.reportDownloadUrl
1935
+ if (!node) return null
1936
+ return {
1937
+ downloadUrl: node.downloadUrl,
1938
+ expiresAt: node.expiresAt,
1939
+ contentType: node.contentType,
1940
+ format: node.format,
1941
+ generationCount: node.generationCount,
1942
+ }
2004
1943
  }
2005
- }
2006
- const response = await fetch(url, {
2007
- method: 'GET',
2008
- headers,
2009
- credentials: this.config.credentials,
2010
- })
2011
- if (!response.ok) {
2012
- const body = await response.text()
2013
- throw new Error(`Get report bundle XBRL zip failed (${response.status}): ${body}`)
2014
- }
2015
- const blob = await response.blob()
2016
- // Parse Content-Disposition for the server-suggested filename;
2017
- // fall back to a sensible default if absent.
2018
- const disposition = response.headers.get('Content-Disposition') ?? ''
2019
- const filenameMatch = disposition.match(/filename="?([^";]+)"?/i)
2020
- const filename = filenameMatch ? filenameMatch[1] : `${reportId}.zip`
2021
- const generationHeader = response.headers.get('X-Bundle-Generation')
2022
- const generationCount = generationHeader ? Number.parseInt(generationHeader, 10) : null
2023
- return { blob, filename, generationCount }
1944
+ )
2024
1945
  }
2025
1946
 
2026
1947
  /**
@@ -1,5 +1,5 @@
1
1
  import type { TokenProvider } from './graphql/client';
2
- import { type GetLibraryElementArcsQuery, type GetLibraryElementClassificationsQuery, type GetLibraryElementEquivalentsQuery, type GetLibraryElementQuery, type GetLibraryTaxonomyQuery, type ListLibraryElementsQuery, type ListLibraryTaxonomiesQuery, type ListLibraryTaxonomyArcsQuery, type SearchLibraryElementsQuery } from './graphql/generated/graphql';
2
+ import { type GetLibraryElementArcsQuery, type GetLibraryElementClassificationsQuery, type GetLibraryElementEquivalentsQuery, type GetLibraryElementQuery, type GetLibraryTaxonomyQuery, type ListLibraryElementsQuery, type ListLibraryStructuresQuery, type ListLibraryTaxonomiesQuery, type ListLibraryTaxonomyArcsQuery, type SearchLibraryElementsQuery } from './graphql/generated/graphql';
3
3
  export type LibraryTaxonomy = ListLibraryTaxonomiesQuery['libraryTaxonomies'][number];
4
4
  export type LibraryTaxonomyDetail = NonNullable<GetLibraryTaxonomyQuery['libraryTaxonomy']>;
5
5
  export type LibraryElement = ListLibraryElementsQuery['libraryElements'][number];
@@ -8,6 +8,7 @@ export type LibrarySearchResult = SearchLibraryElementsQuery['searchLibraryEleme
8
8
  export type LibraryLabel = LibraryElementDetail['labels'][number];
9
9
  export type LibraryReference = LibraryElementDetail['references'][number];
10
10
  export type LibraryArc = ListLibraryTaxonomyArcsQuery['libraryTaxonomyArcs'][number];
11
+ export type LibraryStructure = ListLibraryStructuresQuery['libraryStructures'][number];
11
12
  export type LibraryElementArc = GetLibraryElementArcsQuery['libraryElementArcs'][number];
12
13
  export type LibraryElementClassification = GetLibraryElementClassificationsQuery['libraryElementClassifications'][number];
13
14
  export type LibraryEquivalence = NonNullable<GetLibraryElementEquivalentsQuery['libraryElementEquivalents']>;
@@ -32,6 +33,8 @@ export interface SearchLibraryElementsOptions {
32
33
  }
33
34
  export interface ListLibraryTaxonomyArcsOptions {
34
35
  associationType?: string;
36
+ /** Scope to a single structure (one presentation/calculation hierarchy). */
37
+ structureId?: string;
35
38
  limit?: number;
36
39
  offset?: number;
37
40
  }
@@ -39,6 +42,11 @@ export interface ListLibraryTaxonomyArcsResult {
39
42
  arcs: LibraryArc[];
40
43
  count: number;
41
44
  }
45
+ export interface ListLibraryStructuresOptions {
46
+ taxonomyId?: string;
47
+ /** Filter to one statement kind (balance_sheet | income_statement | …). */
48
+ blockType?: string;
49
+ }
42
50
  export interface GetLibraryElementIdentifier {
43
51
  id?: string;
44
52
  qname?: string;
@@ -102,6 +110,15 @@ export declare class LibraryClient {
102
110
  * type-subtype) this is the primary browse view.
103
111
  */
104
112
  listLibraryTaxonomyArcs(graphId: string, taxonomyId: string, options?: ListLibraryTaxonomyArcsOptions): Promise<ListLibraryTaxonomyArcsResult>;
113
+ /**
114
+ * List the structures (extended link roles) a taxonomy contributes —
115
+ * the named presentation/calculation hierarchies (BS-classified,
116
+ * IS-multistep, the calc DAG roots, …). Pair a structure's `id` with
117
+ * `listLibraryTaxonomyArcs({ structureId })` to load just that
118
+ * hierarchy's arcs — the hierarchy view uses this to scope a tree to
119
+ * one role at a time.
120
+ */
121
+ listLibraryStructures(graphId: string, options?: ListLibraryStructuresOptions): Promise<LibraryStructure[]>;
105
122
  /**
106
123
  * All mapping arcs where this element is source or target. Covers
107
124
  * every `taxonomy_type='mapping'` bridge — equivalence,
@@ -87,6 +87,7 @@ class LibraryClient {
87
87
  return this.gqlQuery(graphId, graphql_1.ListLibraryTaxonomyArcsDocument, {
88
88
  taxonomyId,
89
89
  associationType: options?.associationType ?? null,
90
+ structureId: options?.structureId ?? null,
90
91
  limit: options?.limit ?? 200,
91
92
  offset: options?.offset ?? 0,
92
93
  }, 'List library taxonomy arcs', (data) => ({
@@ -94,6 +95,21 @@ class LibraryClient {
94
95
  count: data.libraryTaxonomyArcCount,
95
96
  }));
96
97
  }
98
+ // ── Structures ───────────────────────────────────────────────────────
99
+ /**
100
+ * List the structures (extended link roles) a taxonomy contributes —
101
+ * the named presentation/calculation hierarchies (BS-classified,
102
+ * IS-multistep, the calc DAG roots, …). Pair a structure's `id` with
103
+ * `listLibraryTaxonomyArcs({ structureId })` to load just that
104
+ * hierarchy's arcs — the hierarchy view uses this to scope a tree to
105
+ * one role at a time.
106
+ */
107
+ async listLibraryStructures(graphId, options) {
108
+ return this.gqlQuery(graphId, graphql_1.ListLibraryStructuresDocument, {
109
+ taxonomyId: options?.taxonomyId ?? null,
110
+ blockType: options?.blockType ?? null,
111
+ }, 'List library structures', (data) => data.libraryStructures);
112
+ }
97
113
  /**
98
114
  * All mapping arcs where this element is source or target. Covers
99
115
  * every `taxonomy_type='mapping'` bridge — equivalence,
@@ -37,6 +37,7 @@ import {
37
37
  GetLibraryElementEquivalentsDocument,
38
38
  GetLibraryTaxonomyDocument,
39
39
  ListLibraryElementsDocument,
40
+ ListLibraryStructuresDocument,
40
41
  ListLibraryTaxonomiesDocument,
41
42
  ListLibraryTaxonomyArcsDocument,
42
43
  SearchLibraryElementsDocument,
@@ -46,6 +47,7 @@ import {
46
47
  type GetLibraryElementQuery,
47
48
  type GetLibraryTaxonomyQuery,
48
49
  type ListLibraryElementsQuery,
50
+ type ListLibraryStructuresQuery,
49
51
  type ListLibraryTaxonomiesQuery,
50
52
  type ListLibraryTaxonomyArcsQuery,
51
53
  type SearchLibraryElementsQuery,
@@ -67,6 +69,7 @@ export type LibraryLabel = LibraryElementDetail['labels'][number]
67
69
  export type LibraryReference = LibraryElementDetail['references'][number]
68
70
 
69
71
  export type LibraryArc = ListLibraryTaxonomyArcsQuery['libraryTaxonomyArcs'][number]
72
+ export type LibraryStructure = ListLibraryStructuresQuery['libraryStructures'][number]
70
73
  export type LibraryElementArc = GetLibraryElementArcsQuery['libraryElementArcs'][number]
71
74
  export type LibraryElementClassification =
72
75
  GetLibraryElementClassificationsQuery['libraryElementClassifications'][number]
@@ -99,6 +102,8 @@ export interface SearchLibraryElementsOptions {
99
102
 
100
103
  export interface ListLibraryTaxonomyArcsOptions {
101
104
  associationType?: string
105
+ /** Scope to a single structure (one presentation/calculation hierarchy). */
106
+ structureId?: string
102
107
  limit?: number
103
108
  offset?: number
104
109
  }
@@ -108,6 +113,12 @@ export interface ListLibraryTaxonomyArcsResult {
108
113
  count: number
109
114
  }
110
115
 
116
+ export interface ListLibraryStructuresOptions {
117
+ taxonomyId?: string
118
+ /** Filter to one statement kind (balance_sheet | income_statement | …). */
119
+ blockType?: string
120
+ }
121
+
111
122
  export interface GetLibraryElementIdentifier {
112
123
  id?: string
113
124
  qname?: string
@@ -276,6 +287,7 @@ export class LibraryClient {
276
287
  {
277
288
  taxonomyId,
278
289
  associationType: options?.associationType ?? null,
290
+ structureId: options?.structureId ?? null,
279
291
  limit: options?.limit ?? 200,
280
292
  offset: options?.offset ?? 0,
281
293
  },
@@ -287,6 +299,32 @@ export class LibraryClient {
287
299
  )
288
300
  }
289
301
 
302
+ // ── Structures ───────────────────────────────────────────────────────
303
+
304
+ /**
305
+ * List the structures (extended link roles) a taxonomy contributes —
306
+ * the named presentation/calculation hierarchies (BS-classified,
307
+ * IS-multistep, the calc DAG roots, …). Pair a structure's `id` with
308
+ * `listLibraryTaxonomyArcs({ structureId })` to load just that
309
+ * hierarchy's arcs — the hierarchy view uses this to scope a tree to
310
+ * one role at a time.
311
+ */
312
+ async listLibraryStructures(
313
+ graphId: string,
314
+ options?: ListLibraryStructuresOptions
315
+ ): Promise<LibraryStructure[]> {
316
+ return this.gqlQuery(
317
+ graphId,
318
+ ListLibraryStructuresDocument,
319
+ {
320
+ taxonomyId: options?.taxonomyId ?? null,
321
+ blockType: options?.blockType ?? null,
322
+ },
323
+ 'List library structures',
324
+ (data) => data.libraryStructures
325
+ )
326
+ }
327
+
290
328
  /**
291
329
  * All mapping arcs where this element is source or target. Covers
292
330
  * every `taxonomy_type='mapping'` bridge — equivalence,