@fin.cx/opendata 4.7.0 → 4.9.0

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 (89) hide show
  1. package/.smartconfig.json +6 -2
  2. package/dist_ts/00_commitinfo_data.js +3 -3
  3. package/dist_ts/financialstatements/amounts.d.ts +58 -0
  4. package/dist_ts/financialstatements/amounts.js +130 -0
  5. package/dist_ts/financialstatements/classes.financialstatementerror.d.ts +24 -0
  6. package/dist_ts/financialstatements/classes.financialstatementerror.js +10 -0
  7. package/dist_ts/financialstatements/constants.d.ts +16 -0
  8. package/dist_ts/financialstatements/constants.js +20 -0
  9. package/dist_ts/financialstatements/dates.d.ts +16 -0
  10. package/dist_ts/financialstatements/dates.js +72 -0
  11. package/dist_ts/financialstatements/html.d.ts +21 -0
  12. package/dist_ts/financialstatements/html.js +92 -0
  13. package/dist_ts/financialstatements/index.d.ts +6 -0
  14. package/dist_ts/financialstatements/index.js +11 -0
  15. package/dist_ts/financialstatements/interfaces.d.ts +258 -0
  16. package/dist_ts/financialstatements/interfaces.js +2 -0
  17. package/dist_ts/financialstatements/layout.d.ts +20 -0
  18. package/dist_ts/financialstatements/layout.html.d.ts +8 -0
  19. package/dist_ts/financialstatements/layout.html.js +125 -0
  20. package/dist_ts/financialstatements/layout.js +2 -0
  21. package/dist_ts/financialstatements/layout.pdf.d.ts +6 -0
  22. package/dist_ts/financialstatements/layout.pdf.js +229 -0
  23. package/dist_ts/financialstatements/mediatypes.d.ts +3 -0
  24. package/dist_ts/financialstatements/mediatypes.js +11 -0
  25. package/dist_ts/financialstatements/outline.d.ts +22 -0
  26. package/dist_ts/financialstatements/outline.js +26 -0
  27. package/dist_ts/financialstatements/parse.esef.d.ts +13 -0
  28. package/dist_ts/financialstatements/parse.esef.js +349 -0
  29. package/dist_ts/financialstatements/parse.hgb.d.ts +9 -0
  30. package/dist_ts/financialstatements/parse.hgb.js +1014 -0
  31. package/dist_ts/financialstatements/parse.statement.d.ts +8 -0
  32. package/dist_ts/financialstatements/parse.statement.js +25 -0
  33. package/dist_ts/financialstatements/plugins.d.ts +10 -0
  34. package/dist_ts/financialstatements/plugins.js +15 -0
  35. package/dist_ts/financialstatements/read.d.ts +10 -0
  36. package/dist_ts/financialstatements/read.js +113 -0
  37. package/dist_ts/gleif/classes.gleifclient.d.ts +26 -0
  38. package/dist_ts/gleif/classes.gleifclient.js +214 -0
  39. package/dist_ts/gleif/classes.gleiferror.d.ts +6 -0
  40. package/dist_ts/gleif/classes.gleiferror.js +11 -0
  41. package/dist_ts/gleif/crosswalk.d.ts +7 -0
  42. package/dist_ts/gleif/crosswalk.js +25 -0
  43. package/dist_ts/gleif/csv.d.ts +2 -0
  44. package/dist_ts/gleif/csv.js +75 -0
  45. package/dist_ts/gleif/data.crosswalk.d.ts +12 -0
  46. package/dist_ts/gleif/data.crosswalk.js +1265 -0
  47. package/dist_ts/gleif/index.d.ts +6 -0
  48. package/dist_ts/gleif/index.js +7 -0
  49. package/dist_ts/gleif/interfaces.d.ts +101 -0
  50. package/dist_ts/gleif/interfaces.js +2 -0
  51. package/dist_ts/gleif/plugins.d.ts +1 -0
  52. package/dist_ts/gleif/plugins.js +3 -0
  53. package/dist_ts/gleif/records.d.ts +6 -0
  54. package/dist_ts/gleif/records.js +107 -0
  55. package/dist_ts/gleif/stream.zip.d.ts +2 -0
  56. package/dist_ts/gleif/stream.zip.js +54 -0
  57. package/dist_ts/plugins.d.ts +2 -0
  58. package/dist_ts/plugins.js +4 -1
  59. package/package.json +20 -5
  60. package/readme.md +156 -5
  61. package/ts/00_commitinfo_data.ts +2 -2
  62. package/ts/financialstatements/amounts.ts +181 -0
  63. package/ts/financialstatements/classes.financialstatementerror.ts +35 -0
  64. package/ts/financialstatements/constants.ts +24 -0
  65. package/ts/financialstatements/dates.ts +89 -0
  66. package/ts/financialstatements/html.ts +107 -0
  67. package/ts/financialstatements/index.ts +17 -0
  68. package/ts/financialstatements/interfaces.ts +268 -0
  69. package/ts/financialstatements/layout.html.ts +130 -0
  70. package/ts/financialstatements/layout.pdf.ts +268 -0
  71. package/ts/financialstatements/layout.ts +16 -0
  72. package/ts/financialstatements/mediatypes.ts +14 -0
  73. package/ts/financialstatements/outline.ts +44 -0
  74. package/ts/financialstatements/parse.esef.ts +394 -0
  75. package/ts/financialstatements/parse.hgb.ts +1235 -0
  76. package/ts/financialstatements/parse.statement.ts +26 -0
  77. package/ts/financialstatements/plugins.ts +29 -0
  78. package/ts/financialstatements/read.ts +135 -0
  79. package/ts/gleif/classes.gleifclient.ts +170 -0
  80. package/ts/gleif/classes.gleiferror.ts +8 -0
  81. package/ts/gleif/crosswalk.ts +29 -0
  82. package/ts/gleif/csv.ts +60 -0
  83. package/ts/gleif/data.crosswalk.ts +1271 -0
  84. package/ts/gleif/index.ts +6 -0
  85. package/ts/gleif/interfaces.ts +107 -0
  86. package/ts/gleif/plugins.ts +2 -0
  87. package/ts/gleif/records.ts +104 -0
  88. package/ts/gleif/stream.zip.ts +43 -0
  89. package/ts/plugins.ts +4 -0
@@ -0,0 +1,6 @@
1
+ export * from './interfaces.js';
2
+ export { GleifClient, gleifDeltaKinds, gleifGoldenCopyBaseUrl, gleifRestBaseUrl } from './classes.gleifclient.js';
3
+ export { GleifError, type TGleifErrorCode } from './classes.gleiferror.js';
4
+ export { parseGleifRestRecord } from './records.js';
5
+ export { courtFromRegistrationAuthority, registrationAuthorityFromCourt, parseRegistrationAuthorityEntityId, registerReferenceFromRegistrationAuthority } from './crosswalk.js';
6
+ export { germanRegistrationAuthorities, gleifUnmappedCourts, gleifRegistrationAuthoritiesSource } from './data.crosswalk.js';
@@ -0,0 +1,107 @@
1
+ import type { TRegisterType } from '../handelsregister/interfaces.js';
2
+
3
+ export interface IGleifName {
4
+ name: string;
5
+ language?: string;
6
+ /** The published other-name type; absent for the legal name. */
7
+ type?: string;
8
+ }
9
+
10
+ export interface IGleifAddress {
11
+ addressLines: string[];
12
+ city: string;
13
+ country: string;
14
+ language?: string;
15
+ region?: string;
16
+ postalCode?: string;
17
+ addressNumber?: string;
18
+ addressNumberWithinBuilding?: string;
19
+ mailRouting?: string;
20
+ }
21
+
22
+ /** Level 1 reference data, with source strings and ISO 8601 dates preserved. No persistence. */
23
+ export interface IGleifRecord {
24
+ lei: string;
25
+ legalName: IGleifName;
26
+ otherNames: IGleifName[];
27
+ transliteratedOtherNames: IGleifName[];
28
+ legalForm?: { elfCode?: string; other?: string };
29
+ legalAddress: IGleifAddress;
30
+ headquartersAddress: IGleifAddress;
31
+ jurisdiction?: string;
32
+ entityStatus: string;
33
+ entityCategory?: string;
34
+ registrationAuthority?: { id?: string; otherId?: string; entityId?: string };
35
+ registrationStatus: string;
36
+ initialRegistrationDate: string;
37
+ lastUpdateDate: string;
38
+ }
39
+
40
+ export type TGleifDelta = 'IntraDay' | 'LastDay' | 'LastWeek' | 'LastMonth';
41
+ export type TGleifFileKind = 'GoldenCopy' | TGleifDelta;
42
+
43
+ /** The API's LEI-CDF 3.1 ZIP/CSV descriptor. `size` is compressed bytes. */
44
+ export interface IGleifGoldenCopyFile {
45
+ url: string;
46
+ format: 'csv';
47
+ cdfVersion: 'LEI_3.1';
48
+ kind: TGleifFileKind;
49
+ recordCount: number;
50
+ size: number;
51
+ }
52
+
53
+ export interface IGleifPublish {
54
+ /** UTC publication label exactly as returned, `YYYY-MM-DD HH:mm:ss`. */
55
+ publishDate: string;
56
+ fullFile: IGleifGoldenCopyFile;
57
+ deltaFiles: Record<TGleifDelta, IGleifGoldenCopyFile>;
58
+ }
59
+
60
+ export type TGleifFetch = (input: string, init: RequestInit) => Promise<Response>;
61
+
62
+ export interface IGleifClientOptions {
63
+ fetch?: TGleifFetch;
64
+ /** Default: https://goldencopy.gleif.org/api/v2 */
65
+ goldenCopyBaseUrl?: string;
66
+ /** Default: https://api.gleif.org/api/v1 */
67
+ restBaseUrl?: string;
68
+ userAgent?: string;
69
+ /** Per request, including streaming and consumer time; default 30 minutes. */
70
+ timeoutMs?: number;
71
+ }
72
+
73
+ export interface IGleifReadOptions {
74
+ /** ISO 3166-1 alpha-2; compares the legal address's country, not the headquarters. */
75
+ country?: string;
76
+ /** Exact legal jurisdiction, e.g. DE or US-DE. Both filters, if given, must match. */
77
+ jurisdiction?: string;
78
+ signal?: AbortSignal;
79
+ /** Maximum CSV row size in Unicode code points, including the header; default 1,048,576. */
80
+ maxRowChars?: number;
81
+ }
82
+
83
+ export interface IGleifStreamOptions extends IGleifReadOptions {
84
+ /** Default GoldenCopy; deltas overlap and are current records, not event histories. */
85
+ kind?: TGleifFileKind;
86
+ }
87
+
88
+ export interface IGleifRegisterNumber {
89
+ type: TRegisterType;
90
+ number: string;
91
+ }
92
+
93
+ export interface IGleifRegistrationAuthority {
94
+ raCode: string;
95
+ name: string;
96
+ jurisdiction: string;
97
+ registerName: string;
98
+ courtCode?: string;
99
+ /** Present exactly when this German RA has no court in opendata's list. */
100
+ unmappedReason?: string;
101
+ }
102
+
103
+ export interface IGleifUnmappedCourt {
104
+ courtCode: string;
105
+ name: string;
106
+ reason: string;
107
+ }
@@ -0,0 +1,2 @@
1
+ // External dependencies for this subpath only; no portal client or storage imports.
2
+ export { fflate } from '../plugins.js';
@@ -0,0 +1,104 @@
1
+ import { GleifError } from './classes.gleiferror.js';
2
+ import type { IGleifAddress, IGleifName, IGleifRecord } from './interfaces.js';
3
+
4
+ const bad = (labelArg: string): never => { throw new GleifError('unexpected_answer', `Missing or invalid GLEIF ${labelArg}.`); };
5
+ const object = (valueArg: unknown, labelArg: string): Record<string, unknown> =>
6
+ valueArg && typeof valueArg === 'object' && !Array.isArray(valueArg) ? valueArg as Record<string, unknown> : bad(labelArg);
7
+ const optional = (valueArg: unknown): string | undefined => {
8
+ if (valueArg === undefined || valueArg === null || valueArg === '') return undefined;
9
+ return typeof valueArg === 'string' ? valueArg : bad('string');
10
+ };
11
+ const required = (valueArg: unknown, labelArg: string): string => optional(valueArg) ?? bad(labelArg);
12
+ const date = (valueArg: unknown, labelArg: string): string => {
13
+ const value = required(valueArg, labelArg);
14
+ if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/.test(value) || !Number.isFinite(Date.parse(value))) bad(labelArg);
15
+ return value;
16
+ };
17
+ const compact = <TArg extends object>(valueArg: TArg): TArg => Object.fromEntries(Object.entries(valueArg).filter(([, valueArg]) => valueArg !== undefined)) as TArg;
18
+ const name = (valueArg: unknown): IGleifName => {
19
+ const value = object(valueArg, 'name');
20
+ return compact({ name: required(value.name, 'name'), language: optional(value.language), type: optional(value.type) });
21
+ };
22
+ const names = (valueArg: unknown): IGleifName[] => {
23
+ if (valueArg === undefined || valueArg === null) return [];
24
+ if (!Array.isArray(valueArg)) bad('names');
25
+ return (valueArg as unknown[]).map(name);
26
+ };
27
+ const address = (valueArg: unknown): IGleifAddress => {
28
+ const value = object(valueArg, 'address');
29
+ if (!Array.isArray(value.addressLines) || value.addressLines.length < 1) bad('address lines');
30
+ return compact({
31
+ addressLines: (value.addressLines as unknown[]).map((lineArg) => required(lineArg, 'address line')),
32
+ city: required(value.city, 'city'), country: required(value.country, 'country'),
33
+ language: optional(value.language), region: optional(value.region), postalCode: optional(value.postalCode),
34
+ addressNumber: optional(value.addressNumber), addressNumberWithinBuilding: optional(value.addressNumberWithinBuilding), mailRouting: optional(value.mailRouting),
35
+ });
36
+ };
37
+
38
+ /** Maps the documented JSON:API attributes, not the differently shaped Golden Copy JSON. */
39
+ export const parseGleifRestRecord = (valueArg: unknown): IGleifRecord => {
40
+ const data = object(object(valueArg, 'response').data, 'data');
41
+ if (data.type !== 'lei-records') bad('resource type');
42
+ const attributes = object(data.attributes, 'attributes');
43
+ const entity = object(attributes.entity, 'entity');
44
+ const registration = object(attributes.registration, 'registration');
45
+ const lei = required(attributes.lei, 'LEI');
46
+ if (!/^[A-Z0-9]{18}\d{2}$/.test(lei) || data.id !== lei) bad('LEI');
47
+ const legalForm = entity.legalForm === undefined || entity.legalForm === null ? undefined : object(entity.legalForm, 'legal form');
48
+ const registeredAt = entity.registeredAt === undefined || entity.registeredAt === null ? undefined : object(entity.registeredAt, 'registration authority');
49
+ const form = legalForm ? compact({ elfCode: optional(legalForm.id), other: optional(legalForm.other) }) : undefined;
50
+ const authority = compact({ id: optional(registeredAt?.id), otherId: optional(registeredAt?.other), entityId: optional(entity.registeredAs) });
51
+ return compact({
52
+ lei, legalName: name(entity.legalName), otherNames: names(entity.otherNames), transliteratedOtherNames: names(entity.transliteratedOtherNames),
53
+ legalForm: form && Object.keys(form).length ? form : undefined,
54
+ legalAddress: address(entity.legalAddress), headquartersAddress: address(entity.headquartersAddress),
55
+ jurisdiction: optional(entity.jurisdiction), entityStatus: required(entity.status, 'entity status'), entityCategory: optional(entity.category),
56
+ registrationAuthority: Object.keys(authority).length ? authority : undefined,
57
+ registrationStatus: required(registration.status, 'registration status'),
58
+ initialRegistrationDate: date(registration.initialRegistrationDate, 'initial registration date'), lastUpdateDate: date(registration.lastUpdateDate, 'last update date'),
59
+ });
60
+ };
61
+
62
+ /** Column names verified against the published LEI-CDF 3.1 CSV (the optional values may be empty). */
63
+ export const gleifCsvColumns = [
64
+ 'LEI', 'Entity.LegalName', 'Entity.LegalName.xmllang', 'Entity.LegalJurisdiction', 'Entity.EntityStatus', 'Entity.EntityCategory',
65
+ 'Entity.LegalForm.EntityLegalFormCode', 'Entity.LegalForm.OtherLegalForm',
66
+ 'Entity.RegistrationAuthority.RegistrationAuthorityID', 'Entity.RegistrationAuthority.OtherRegistrationAuthorityID', 'Entity.RegistrationAuthority.RegistrationAuthorityEntityID',
67
+ 'Registration.RegistrationStatus', 'Registration.InitialRegistrationDate', 'Registration.LastUpdateDate',
68
+ ...['Entity.LegalAddress', 'Entity.HeadquartersAddress'].flatMap((prefixArg) => ['FirstAddressLine', 'City', 'Country'].map((fieldArg) => `${prefixArg}.${fieldArg}`)),
69
+ ] as const;
70
+
71
+ export const csvRecordMapper = (headerArg: string[]): ((rowArg: string[]) => IGleifRecord) => {
72
+ if (new Set(headerArg).size !== headerArg.length || gleifCsvColumns.some((columnArg) => !headerArg.includes(columnArg))) {
73
+ throw new GleifError('invalid_csv', 'Missing or duplicate LEI-CDF 3.1 columns.');
74
+ }
75
+ const indices = new Map(headerArg.map((columnArg, indexArg) => [columnArg, indexArg]));
76
+ const nameColumns = (prefixArg: string): string[] => headerArg.filter((columnArg) => new RegExp(`^${prefixArg.replaceAll('.', '\\.') }\\.\\d+$`).test(columnArg));
77
+ const otherColumns = nameColumns('Entity.OtherEntityNames.OtherEntityName');
78
+ const transliteratedColumns = nameColumns('Entity.TransliteratedOtherEntityNames.TransliteratedOtherEntityName');
79
+ return (rowArg) => {
80
+ if (rowArg.length !== headerArg.length) throw new GleifError('invalid_csv', 'LEI-CDF CSV row has a different column count from its header.');
81
+ const get = (columnArg: string): string | undefined => {
82
+ const index = indices.get(columnArg);
83
+ return index === undefined ? undefined : rowArg[index];
84
+ };
85
+ const nameOf = (prefixArg: string) => ({ name: get(prefixArg), language: get(`${prefixArg}.xmllang`), type: get(`${prefixArg}.type`) });
86
+ const addressOf = (prefixArg: string) => ({
87
+ addressLines: [get(`${prefixArg}.FirstAddressLine`), ...[1, 2, 3].map((indexArg) => get(`${prefixArg}.AdditionalAddressLine.${indexArg}`))].filter(Boolean),
88
+ city: get(`${prefixArg}.City`), country: get(`${prefixArg}.Country`), language: get(`${prefixArg}.xmllang`), region: get(`${prefixArg}.Region`), postalCode: get(`${prefixArg}.PostalCode`),
89
+ addressNumber: get(`${prefixArg}.AddressNumber`), addressNumberWithinBuilding: get(`${prefixArg}.AddressNumberWithinBuilding`), mailRouting: get(`${prefixArg}.MailRouting`),
90
+ });
91
+ const lei = get('LEI');
92
+ return parseGleifRestRecord({ data: { type: 'lei-records', id: lei, attributes: { lei, entity: {
93
+ legalName: nameOf('Entity.LegalName'), otherNames: otherColumns.filter((columnArg) => get(columnArg)).map(nameOf),
94
+ transliteratedOtherNames: transliteratedColumns.filter((columnArg) => get(columnArg)).map(nameOf),
95
+ legalForm: { id: get('Entity.LegalForm.EntityLegalFormCode'), other: get('Entity.LegalForm.OtherLegalForm') },
96
+ legalAddress: addressOf('Entity.LegalAddress'), headquartersAddress: addressOf('Entity.HeadquartersAddress'),
97
+ jurisdiction: get('Entity.LegalJurisdiction'), status: get('Entity.EntityStatus'), category: get('Entity.EntityCategory'),
98
+ registeredAt: { id: get('Entity.RegistrationAuthority.RegistrationAuthorityID'), other: get('Entity.RegistrationAuthority.OtherRegistrationAuthorityID') },
99
+ registeredAs: get('Entity.RegistrationAuthority.RegistrationAuthorityEntityID'),
100
+ }, registration: {
101
+ status: get('Registration.RegistrationStatus'), initialRegistrationDate: get('Registration.InitialRegistrationDate'), lastUpdateDate: get('Registration.LastUpdateDate'),
102
+ } } } });
103
+ };
104
+ };
@@ -0,0 +1,43 @@
1
+ import * as plugins from './plugins.js';
2
+ import { GleifError } from './classes.gleiferror.js';
3
+
4
+ /** One CSV member, incrementally inflated. Input slices bound each synchronous output batch. */
5
+ export async function* unzipCsv(sourceArg: AsyncIterable<Uint8Array>): AsyncGenerator<Uint8Array> {
6
+ let member: plugins.fflate.UnzipFile | undefined;
7
+ let complete = false;
8
+ let failure: Error | undefined;
9
+ let output: Uint8Array[] = [];
10
+ const unzipper = new plugins.fflate.Unzip((fileArg) => {
11
+ if (member || !fileArg.name.toLowerCase().endsWith('.csv')) {
12
+ throw new GleifError('invalid_archive', 'Expected exactly one CSV member in the Golden Copy ZIP.');
13
+ }
14
+ member = fileArg;
15
+ fileArg.ondata = (errorArg, dataArg, finalArg) => {
16
+ if (errorArg) failure = errorArg;
17
+ else if (dataArg.length) output.push(dataArg);
18
+ if (finalArg) complete = true;
19
+ };
20
+ fileArg.start();
21
+ });
22
+ unzipper.register(plugins.fflate.UnzipInflate);
23
+ try {
24
+ for await (const chunk of sourceArg) {
25
+ for (let offset = 0; offset < chunk.length; offset += 1024) {
26
+ unzipper.push(chunk.subarray(offset, offset + 1024));
27
+ if (failure) throw failure;
28
+ const ready = output;
29
+ output = [];
30
+ for (const data of ready) yield data;
31
+ }
32
+ }
33
+ unzipper.push(new Uint8Array(), true);
34
+ if (failure) throw failure;
35
+ for (const data of output) yield data;
36
+ if (!member || !complete) throw new GleifError('invalid_archive', 'Missing or truncated CSV member in Golden Copy ZIP.');
37
+ } catch (error) {
38
+ if (error instanceof GleifError) throw error;
39
+ throw new GleifError('invalid_archive', 'Could not stream the Golden Copy ZIP.', undefined, { cause: error });
40
+ } finally {
41
+ member?.terminate();
42
+ }
43
+ }
package/ts/plugins.ts CHANGED
@@ -24,3 +24,7 @@ export {
24
24
  smartpromise,
25
25
  smartrequest,
26
26
  }
27
+
28
+ // third-party scope
29
+ import * as fflate from 'fflate';
30
+ export { fflate };