@fin.cx/opendata 1.5.4 → 1.6.1

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.
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@fin.cx/opendata',
6
- version: '1.5.3',
7
- description: 'A comprehensive TypeScript library that manages open business data for German companies by integrating MongoDB, processing JSONL bulk data, and automating browser interactions for Handelsregister data retrieval.'
6
+ version: '1.6.1',
7
+ description: 'A comprehensive TypeScript library for accessing business data and real-time financial information. Features include German company data management with MongoDB integration, JSONL bulk processing, automated Handelsregister interactions, and real-time stock market data from multiple providers.'
8
8
  };
9
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSxrQkFBa0I7SUFDeEIsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLHFOQUFxTjtDQUNuTyxDQUFBIn0=
9
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSxrQkFBa0I7SUFDeEIsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLHVTQUF1UztDQUNyVCxDQUFBIn0=
@@ -1,2 +1,2 @@
1
- export {};
2
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RvY2twcmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL3N0b2Nrcy9pbnRlcmZhY2VzL3N0b2NrcHJpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiJ9
1
+ import * as plugins from '../../plugins.js';
2
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RvY2twcmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL3N0b2Nrcy9pbnRlcmZhY2VzL3N0b2NrcHJpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxrQkFBa0IsQ0FBQyJ9
@@ -16,13 +16,14 @@ export class YahooFinanceProvider {
16
16
  async fetchPrice(request) {
17
17
  try {
18
18
  const url = `${this.baseUrl}/v8/finance/chart/${request.ticker}`;
19
- const response = await plugins.smartrequest.getJson(url, {
20
- headers: {
21
- 'User-Agent': this.userAgent
22
- },
23
- timeout: this.config?.timeout || 10000
24
- });
25
- const responseData = response.body;
19
+ const response = await plugins.smartrequest.SmartRequest.create()
20
+ .url(url)
21
+ .headers({
22
+ 'User-Agent': this.userAgent
23
+ })
24
+ .timeout(this.config?.timeout || 10000)
25
+ .get();
26
+ const responseData = await response.json();
26
27
  if (!responseData?.chart?.result?.[0]) {
27
28
  throw new Error(`No data found for ticker ${request.ticker}`);
28
29
  }
@@ -55,13 +56,14 @@ export class YahooFinanceProvider {
55
56
  try {
56
57
  const symbols = request.tickers.join(',');
57
58
  const url = `${this.baseUrl}/v8/finance/spark?symbols=${symbols}&range=1d&interval=5m`;
58
- const response = await plugins.smartrequest.getJson(url, {
59
- headers: {
60
- 'User-Agent': this.userAgent
61
- },
62
- timeout: this.config?.timeout || 15000
63
- });
64
- const responseData = response.body;
59
+ const response = await plugins.smartrequest.SmartRequest.create()
60
+ .url(url)
61
+ .headers({
62
+ 'User-Agent': this.userAgent
63
+ })
64
+ .timeout(this.config?.timeout || 15000)
65
+ .get();
66
+ const responseData = await response.json();
65
67
  const prices = [];
66
68
  for (const [ticker, data] of Object.entries(responseData)) {
67
69
  if (!data || typeof data !== 'object')
@@ -136,4 +138,4 @@ export class YahooFinanceProvider {
136
138
  }
137
139
  }
138
140
  }
139
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdmlkZXIueWFob28uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9zdG9ja3MvcHJvdmlkZXJzL3Byb3ZpZGVyLnlhaG9vLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFJNUMsTUFBTSxPQUFPLG9CQUFvQjtJQWEvQixZQUFvQixNQUF3QjtRQUF4QixXQUFNLEdBQU4sTUFBTSxDQUFrQjtRQVpyQyxTQUFJLEdBQUcsZUFBZSxDQUFDO1FBQ3ZCLGFBQVEsR0FBRyxHQUFHLENBQUM7UUFDTixpQkFBWSxHQUFHLEtBQUssQ0FBQztRQUNyQixjQUFTLEdBQUc7WUFDMUIsaUJBQWlCLEVBQUUsR0FBRyxFQUFFLHdCQUF3QjtZQUNoRCxjQUFjLEVBQUUsU0FBUztTQUMxQixDQUFDO1FBRU0sV0FBTSxHQUFHLE9BQU8sQ0FBQztRQUNqQixZQUFPLEdBQUcsa0NBQWtDLENBQUM7UUFDN0MsY0FBUyxHQUFHLGlIQUFpSCxDQUFDO0lBRXZGLENBQUM7SUFFekMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxPQUEyQjtRQUNqRCxJQUFJLENBQUM7WUFDSCxNQUFNLEdBQUcsR0FBRyxHQUFHLElBQUksQ0FBQyxPQUFPLHFCQUFxQixPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDakUsTUFBTSxRQUFRLEdBQUcsTUFBTSxPQUFPLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUU7Z0JBQ3ZELE9BQU8sRUFBRTtvQkFDUCxZQUFZLEVBQUUsSUFBSSxDQUFDLFNBQVM7aUJBQzdCO2dCQUNELE9BQU8sRUFBRSxJQUFJLENBQUMsTUFBTSxFQUFFLE9BQU8sSUFBSSxLQUFLO2FBQ3ZDLENBQUMsQ0FBQztZQUVILE1BQU0sWUFBWSxHQUFHLFFBQVEsQ0FBQyxJQUFXLENBQUM7WUFFMUMsSUFBSSxDQUFDLFlBQVksRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FB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
141
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdmlkZXIueWFob28uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9zdG9ja3MvcHJvdmlkZXJzL3Byb3ZpZGVyLnlhaG9vLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFJNUMsTUFBTSxPQUFPLG9CQUFvQjtJQWEvQixZQUFvQixNQUF3QjtRQUF4QixXQUFNLEdBQU4sTUFBTSxDQUFrQjtRQVpyQyxTQUFJLEdBQUcsZUFBZSxDQUFDO1FBQ3ZCLGFBQVEsR0FBRyxHQUFHLENBQUM7UUFDTixpQkFBWSxHQUFHLEtBQUssQ0FBQztRQUNyQixjQUFTLEdBQUc7WUFDMUIsaUJBQWlCLEVBQUUsR0FBRyxFQUFFLHdCQUF3QjtZQUNoRCxjQUFjLEVBQUUsU0FBUztTQUMxQixDQUFDO1FBRU0sV0FBTSxHQUFHLE9BQU8sQ0FBQztRQUNqQixZQUFPLEdBQUcsa0NBQWtDLENBQUM7UUFDN0MsY0FBUyxHQUFHLGlIQUFpSCxDQUFDO0lBRXZGLENBQUM7SUFFekMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxPQUEyQjtRQUNqRCxJQUFJLENBQUM7WUFDSCxNQUFNLEdBQUcsR0FBRyxHQUFHLElBQUksQ0FBQyxPQUFPLHFCQUFxQixPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDakUsTUFBTSxRQUFRLEdBQUcsTUFBTSxPQUFPLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FBQyxNQUFNLEVBQUU7aUJBQzlELEdBQUcsQ0FBQyxHQUFHLENBQUM7aUJBQ1IsT0FBTyxDQUFDO2dCQUNQLFlBQVksRUFBRSxJQUFJLENBQUMsU0FBUzthQUM3QixDQUFDO2lCQUNELE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLE9BQU8sSUFBSSxLQUFLLENBQUM7aUJBQ3RDLEdBQUcsRUFBRSxDQUFDO1lBRVQsTUFBTSxZQUFZLEdBQUcsTUFBTSxRQUFRLENBQUMsSUFBSSxFQUFTLENBQUM7WUFFbEQsSUFBSSxDQUFDLFlBQVksRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztnQkFDdEMsTUFBTSxJQUFJLEtBQUssQ0FBQyw0QkFBNEIsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUM7WUFDaEUsQ0FBQztZQUVELE1BQU0sSUFBSSxHQUFHLFlBQVksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzFDLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUM7WUFFdkIsSUFBSSxDQUFDLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO2dCQUM3QixNQUFNLElBQUksS0FBSyxDQUFDLCtCQUErQixPQUFPLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztZQUNuRSxDQUFDO1lBRUQsTUFBTSxVQUFVLEdBQWdCO2dCQUM5QixNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxXQUFXLEVBQUU7Z0JBQ3BDLEtBQUssRUFBRSxJQUFJLENBQUMsa0JBQWtCO2dCQUM5QixRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQVEsSUFBSSxLQUFLO2dCQUNoQyxNQUFNLEVBQUUsSUFBSSxDQUFDLGtCQUFrQixHQUFHLElBQUksQ0FBQyxhQUFhO2dCQUNwRCxhQUFhLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLEdBQUc7Z0JBQzFGLGFBQWEsRUFBRSxJQUFJLENBQUMsYUFBYTtnQkFDakMsU0FBUyxFQUFFLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLENBQUM7Z0JBQ2xELFFBQVEsRUFBRSxJQUFJLENBQUMsSUFBSTtnQkFDbkIsV0FBVyxFQUFFLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLENBQUM7Z0JBQzVDLFFBQVEsRUFBRSxJQUFJLENBQUMsUUFBUTtnQkFDdkIsWUFBWSxFQUFFLElBQUksQ0FBQyxZQUFZO2FBQ2hDLENBQUM7WUFFRixPQUFPLFVBQVUsQ0FBQztRQUNwQixDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE9BQU8sQ0FBQyxLQUFLLENBQUMsNkJBQTZCLE9BQU8sQ0FBQyxNQUFNLEdBQUcsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNyRSxNQUFNLElBQUksS0FBSyxDQUFDLDRDQUE0QyxPQUFPLENBQUMsTUFBTSxLQUFLLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBQ2xHLENBQUM7SUFDSCxDQUFDO0lBRU0sS0FBSyxDQUFDLFdBQVcsQ0FBQyxPQUFnQztRQUN2RCxJQUFJLENBQUM7WUFDSCxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUMxQyxNQUFNLEdBQUcsR0FBRyxHQUFHLElBQUksQ0FBQyxPQUFPLDZCQUE2QixPQUFPLHVCQUF1QixDQUFDO1lBRXZGLE1BQU0sUUFBUSxHQUFHLE1BQU0sT0FBTyxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUMsTUFBTSxFQUFFO2lCQUM5RCxHQUFHLENBQUMsR0FBRyxDQUFDO2lCQUNSLE9BQU8sQ0FBQztnQkFDUCxZQUFZLEVBQUUsSUFBSSxDQUFDLFNBQVM7YUFDN0IsQ0FBQztpQkFDRCxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxPQUFPLElBQUksS0FBSyxDQUFDO2lCQUN0QyxHQUFHLEVBQUUsQ0FBQztZQUVULE1BQU0sWUFBWSxHQUFHLE1BQU0sUUFBUSxDQUFDLElBQUksRUFBUyxDQUFDO1lBQ2xELE1BQU0sTUFBTSxHQUFrQixFQUFFLENBQUM7WUFFakMsS0FBSyxNQUFNLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDLEVBQUUsQ0FBQztnQkFDMUQsSUFBSSxDQUFDLElBQUksSUFBSSxPQUFPLElBQUksS0FBSyxRQUFRO29CQUFFLFNBQVM7Z0JBRWhELE1BQU0sU0FBUyxHQUFHLElBQVcsQ0FBQztnQkFDOUIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxhQUFhLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxDQUFDO29CQUN6RCxPQUFPLENBQUMsSUFBSSxDQUFDLHVCQUF1QixNQUFNLFlBQVksQ0FBQyxDQUFDO29CQUN4RCxTQUFTO2dCQUNYLENBQUM7Z0JBRUQsTUFBTSxZQUFZLEdBQUcsU0FBUyxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQztnQkFDakUsTUFBTSxTQUFTLEdBQUcsU0FBUyxDQUFDLFNBQVMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDO2dCQUV4RSxNQUFNLENBQUMsSUFBSSxDQUFDO29CQUNWLE1BQU0sRUFBRSxNQUFNLENBQUMsV0FBVyxFQUFFO29CQUM1QixLQUFLLEVBQUUsWUFBWTtvQkFDbkIsUUFBUSxFQUFFLFNBQVMsQ0FBQyxRQUFRLElBQUksS0FBSztvQkFDckMsTUFBTSxFQUFFLFlBQVksR0FBRyxTQUFTLENBQUMsYUFBYTtvQkFDOUMsYUFBYSxFQUFFLENBQUMsQ0FBQyxZQUFZLEdBQUcsU0FBUyxDQUFDLGFBQWEsQ0FBQyxHQUFHLFNBQVMsQ0FBQyxhQUFhLENBQUMsR0FBRyxHQUFHO29CQUN6RixhQUFhLEVBQUUsU0FBUyxDQUFDLGFBQWE7b0JBQ3RDLFNBQVMsRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDLElBQUksSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFJLEVBQUU7b0JBQzlELFFBQVEsRUFBRSxJQUFJLENBQUMsSUFBSTtvQkFDbkIsV0FBVyxFQUFFLFNBQVMsQ0FBQyxXQUFXLElBQUksU0FBUztvQkFDL0MsUUFBUSxFQUFFLFNBQVMsQ0FBQyxRQUFRO29CQUM1QixZQUFZLEVBQUUsU0FBUyxDQUFDLFlBQVk7aUJBQ3JDLENBQUMsQ0FBQztZQUNMLENBQUM7WUFFRCxJQUFJLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7Z0JBQ3hCLE1BQU0sSUFBSSxLQUFLLENBQUMsaURBQWlELENBQUMsQ0FBQztZQUNyRSxDQUFDO1lBRUQsT0FBTyxNQUFNLENBQUM7UUFDaEIsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixPQUFPLENBQUMsS0FBSyxDQUFDLCtCQUErQixFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ3RELE1BQU0sSUFBSSxLQUFLLENBQUMsZ0RBQWdELEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBQ25GLENBQUM7SUFDSCxDQUFDO0lBRU0sS0FBSyxDQUFDLFdBQVc7UUFDdEIsSUFBSSxDQUFDO1lBQ0gsZ0NBQWdDO1lBQ2hDLE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDO1lBQzFDLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixPQUFPLENBQUMsSUFBSSxDQUFDLDBDQUEwQyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ2hFLE9BQU8sS0FBSyxDQUFDO1FBQ2YsQ0FBQztJQUNILENBQUM7SUFFTSxjQUFjLENBQUMsTUFBYztRQUNsQyw0Q0FBNEM7UUFDNUMsTUFBTSxnQkFBZ0IsR0FBRyxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDaEYsT0FBTyxnQkFBZ0IsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUM7SUFDekQsQ0FBQztJQUVNLGNBQWMsQ0FBQyxNQUFjO1FBQ2xDLGlEQUFpRDtRQUNqRCxPQUFPLHNCQUFzQixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQztJQUMzRCxDQUFDO0lBRU8sb0JBQW9CLENBQUMsSUFBUztRQUNwQyxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsV0FBVyxFQUFFLFdBQVcsRUFBRSxDQUFDO1FBRXBELFFBQVEsV0FBVyxFQUFFLENBQUM7WUFDcEIsS0FBSyxLQUFLO2dCQUNSLE9BQU8sS0FBSyxDQUFDO1lBQ2YsS0FBSyxNQUFNO2dCQUNULE9BQU8sTUFBTSxDQUFDO1lBQ2hCLEtBQUssU0FBUztnQkFDWixPQUFPLFNBQVMsQ0FBQztZQUNuQjtnQkFDRSx3REFBd0Q7Z0JBQ3hELE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7Z0JBQzlCLE1BQU0saUJBQWlCLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDO2dCQUNqRCxNQUFNLFFBQVEsR0FBRyxHQUFHLEdBQUcsaUJBQWlCLENBQUM7Z0JBRXpDLG1FQUFtRTtnQkFDbkUsT0FBTyxRQUFRLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztRQUNsRCxDQUFDO0lBQ0gsQ0FBQztDQUNGIn0=
package/package.json CHANGED
@@ -1,37 +1,37 @@
1
1
  {
2
2
  "name": "@fin.cx/opendata",
3
- "version": "1.5.4",
3
+ "version": "1.6.1",
4
4
  "private": false,
5
- "description": "A comprehensive TypeScript library that manages open business data for German companies by integrating MongoDB, processing JSONL bulk data, and automating browser interactions for Handelsregister data retrieval.",
5
+ "description": "A comprehensive TypeScript library for accessing business data and real-time financial information. Features include German company data management with MongoDB integration, JSONL bulk processing, automated Handelsregister interactions, and real-time stock market data from multiple providers.",
6
6
  "main": "dist_ts/index.js",
7
7
  "typings": "dist_ts/index.d.ts",
8
8
  "type": "module",
9
9
  "author": "Task Venture Capital GmbH",
10
10
  "license": "MIT",
11
11
  "devDependencies": {
12
- "@git.zone/tsbuild": "^2.6.4",
12
+ "@git.zone/tsbuild": "^2.6.8",
13
13
  "@git.zone/tsbundle": "^2.5.1",
14
14
  "@git.zone/tsrun": "^1.3.3",
15
- "@git.zone/tstest": "^2.3.1",
15
+ "@git.zone/tstest": "^2.3.8",
16
16
  "@types/node": "^22.14.0"
17
17
  },
18
18
  "dependencies": {
19
19
  "@push.rocks/lik": "^6.2.2",
20
- "@push.rocks/qenv": "^6.1.0",
21
- "@push.rocks/smartarchive": "^4.0.39",
20
+ "@push.rocks/qenv": "^6.1.3",
21
+ "@push.rocks/smartarchive": "^4.2.2",
22
22
  "@push.rocks/smartarray": "^1.1.0",
23
23
  "@push.rocks/smartbrowser": "^2.0.8",
24
- "@push.rocks/smartdata": "^5.15.1",
24
+ "@push.rocks/smartdata": "^5.16.4",
25
25
  "@push.rocks/smartdelay": "^3.0.5",
26
- "@push.rocks/smartfile": "^11.2.5",
27
- "@push.rocks/smartlog": "^3.1.8",
28
- "@push.rocks/smartpath": "^5.0.18",
26
+ "@push.rocks/smartfile": "^11.2.7",
27
+ "@push.rocks/smartlog": "^3.1.10",
28
+ "@push.rocks/smartpath": "^6.0.0",
29
29
  "@push.rocks/smartpromise": "^4.2.3",
30
- "@push.rocks/smartrequest": "^2.1.0",
30
+ "@push.rocks/smartrequest": "^4.3.1",
31
31
  "@push.rocks/smartstream": "^3.2.5",
32
32
  "@push.rocks/smartunique": "^3.0.9",
33
33
  "@push.rocks/smartxml": "^1.1.1",
34
- "@tsclass/tsclass": "^9.2.0"
34
+ "@tsclass/tsclass": "^9.3.0"
35
35
  },
36
36
  "repository": {
37
37
  "type": "git",
package/readme.md CHANGED
@@ -1,649 +1,298 @@
1
1
  # @fin.cx/opendata
2
- A TypeScript library for accessing, managing, and updating open business data, focused on German companies and integrating with MongoDB.
2
+ 🚀 **Real-time financial data and German business intelligence in one powerful TypeScript library**
3
3
 
4
- ## Install
4
+ Access live stock prices, cryptocurrencies, forex, commodities AND comprehensive German company data - all through a single, unified API.
5
5
 
6
- To install the @fin.cx/opendata package, you can use npm or yarn as your package manager. The installation process is simple and straightforward.
7
-
8
- Using npm:
9
-
10
- npm install @fin.cx/opendata
11
-
12
- Using yarn:
13
-
14
- yarn add @fin.cx/opendata
15
-
16
- ## Usage
17
-
18
- The @fin.cx/opendata library is a versatile tool that empowers developers to integrate comprehensive open business data into their systems. This library is particularly tailored for German companies, offering functionalities that include creating, retrieving, updating, and deleting business records as well as processing large volumes of JSONL data from external sources. In addition to core database operations via MongoDB, the library provides integration with web-based services, primarily through a hands-on Handelsregister processor that utilizes browser automation for searching and downloading documents.
19
-
20
- In this section, we will extensively detail multiple usage scenarios, ensuring that every feature the module offers is thoroughly explored. All examples in this documentation employ ECMAScript Module (ESM) syntax and TypeScript, highlighting proper asynchronous handling, error management, and advanced integration with other dependencies. We will walk you through environment setup, initializing the package, managing business records, processing bulk JSONL data, interacting with the Handelsregister for on-demand document retrieval, and much more. Each example is constructed to expose every nuance of the module's behavior and usage.
21
-
22
- For clarity, we will split this section into multiple parts:
23
-
24
- 1. Environment Setup and Initializing the Library
25
- 2. Managing Business Records (CRUD Operations)
26
- 3. Bulk Data Processing and Importing via JSONL Streams
27
- 4. Integrating with the Handelsregister: Detailed Demonstrations
28
- 5. Advanced Examples: Combined Operations and Edge Cases
29
- 6. Error Handling and Data Validation
30
- 7. Testing and Automated Workflows
31
-
32
- Throughout these examples, we will examine how each class and method interacts with the underlying MongoDB database and the system's file structure. We assume you have a running MongoDB instance and that your environment is configured with the necessary variables.
33
-
34
- ────────────────────────────────────────────
35
- ### 1. Environment Setup and Initializing the Library
36
-
37
- Before diving into any operations, ensure that your development environment is properly configured. The @fin.cx/opendata library mandates several environment variables for connecting to your MongoDB instance. For a smooth experience, it is advisable to use a .env file or any secure secrets management tool that suits your workflow. The required environment variables include:
38
-
39
- • MONGODB_URL – The connection string URL for your MongoDB instance.
40
- • MONGODB_NAME – The name of the database that the module will interact with.
41
- • MONGODB_USER – MongoDB username required for authentication.
42
- • MONGODB_PASS – The password for the MongoDB user.
43
-
44
- Below is an example .env file for local development:
6
+ ## Installation
45
7
 
46
- ```
47
- MONGODB_URL=mongodb://localhost:27017
48
- MONGODB_NAME=opendataDB
49
- MONGODB_USER=myUser
50
- MONGODB_PASS=myPass
8
+ ```bash
9
+ npm install @fin.cx/opendata
10
+ # or
11
+ yarn add @fin.cx/opendata
51
12
  ```
52
13
 
53
- Once these variables are set, the library can fetch them using the integrated qenv tool. The following code snippet demonstrates how to import and initialize the library:
14
+ ## Quick Start
54
15
 
55
- ```typescript
56
- import { OpenData } from '@fin.cx/opendata';
16
+ ### 📈 Real-Time Stock Data
57
17
 
58
- const startOpenDataInstance = async () => {
59
- const openData = new OpenData();
60
-
61
- try {
62
- console.log('Starting OpenData instance...');
63
- await openData.start();
64
- console.log('OpenData instance started successfully.');
65
-
66
- // Invoke sample operations:
67
- await demonstrateBusinessRecordsOperations(openData);
68
- await demonstrateBulkDataProcessing(openData);
69
- await demonstrateHandelsregisterOperations(openData);
70
-
71
- } catch (error) {
72
- console.error('Error during initialization:', error);
73
- } finally {
74
- console.log('Stopping OpenData instance...');
75
- await openData.stop();
76
- console.log('OpenData instance stopped.');
77
- }
78
- };
79
-
80
- startOpenDataInstance();
81
- ```
82
-
83
- In this snippet, we import the OpenData class from the module and execute its start and stop routines to ensure that the MongoDB connection is properly initialized and terminated. Notice that we move on to different demonstration functions that showcase individual features.
84
-
85
- ────────────────────────────────────────────
86
- ### 2. Managing Business Records (CRUD Operations)
87
-
88
- Central to the @fin.cx/opendata library is the management of business records. The BusinessRecord class encapsulates data pertaining to companies, allowing you to create new records, retrieve existing ones, update information, and delete entries when necessary. The following examples illustrate each operation within a robust context.
89
-
90
- #### a) Creating a Business Record
91
-
92
- Creating a new business record in the openData instance is straightforward. You instantiate a new record and populate its data properties with relevant details such as company name, address, registration number, managing directors, and much more. The sample below uses the embedded CBusinessRecord manager to generate a new record:
18
+ Get live market data in seconds:
93
19
 
94
20
  ```typescript
95
- import { OpenData } from '@fin.cx/opendata';
21
+ import { StockPriceService, YahooFinanceProvider } from '@fin.cx/opendata';
96
22
 
97
- export const createBusinessRecordExample = async (openData: OpenData) => {
98
- const businessRecord = new openData.CBusinessRecord();
99
-
100
- businessRecord.data = {
101
- name: "Innovative Solutions GmbH",
102
- address: "Musterstraße 1",
103
- postalCode: "10115",
104
- city: "Berlin",
105
- country: "Germany",
106
- phone: "+49 30 123456",
107
- email: "contact@innovativesolutions.de",
108
- website: "https://innovativesolutions.de",
109
- businessType: "GmbH",
110
- registrationId: "District court Berlin HRB 987654",
111
- legalForm: "GmbH",
112
- managingDirectors: ["Max Mustermann", "Erika Musterfrau"],
113
- foundingDate: new Date("2018-05-10").toISOString(),
114
- capital: "250,000 EUR",
115
- purpose: "Technology development and consulting services",
116
- lastUpdate: new Date().toISOString()
117
- };
23
+ // Initialize the service
24
+ const stockService = new StockPriceService();
25
+ stockService.register(new YahooFinanceProvider());
118
26
 
119
- try {
120
- await businessRecord.save();
121
- console.log('BusinessRecord created successfully:', businessRecord);
122
- } catch (error) {
123
- console.error('Error creating business record:', error);
124
- }
125
- };
126
- ```
27
+ // Get single stock price
28
+ const apple = await stockService.getPrice({ ticker: 'AAPL' });
29
+ console.log(`Apple: $${apple.price} (${apple.changePercent.toFixed(2)}%)`);
127
30
 
128
- In this example, after setting the business record fields, the record is saved to the MongoDB collection using the save method. The system ensures that the newly created record receives a unique identifier by generating a new ID when saving the document.
129
-
130
- #### b) Retrieving Business Records
131
-
132
- To retrieve business records, you can search by various fields such as city, business name, or registration details. The system utilizes MongoDB queries to filter and return relevant documents. Below is a sample function that retrieves all records for companies based in a particular city:
133
-
134
- ```typescript
135
- import { OpenData } from '@fin.cx/opendata';
136
- import type { BusinessRecord } from '@fin.cx/opendata';
31
+ // Get multiple prices at once
32
+ const prices = await stockService.getPrices({
33
+ tickers: ['AAPL', 'MSFT', 'GOOGL', 'BTC-USD', 'ETH-USD']
34
+ });
137
35
 
138
- export const retrieveRecordsByCity = async (openData: OpenData, city: string) => {
139
- try {
140
- const records = await openData.db
141
- .collection<BusinessRecord>('businessrecords')
142
- .find({ city })
143
- .toArray();
144
-
145
- console.log(`Retrieved ${records.length} records for city ${city}.`);
146
- console.log(records);
147
- return records;
148
- } catch (error) {
149
- console.error('Error retrieving business records:', error);
150
- }
151
- };
36
+ // Market indices, crypto, forex, commodities - all supported!
37
+ const marketData = await stockService.getPrices({
38
+ tickers: ['^GSPC', '^DJI', 'BTC-USD', 'EURUSD=X', 'GC=F']
39
+ });
152
40
  ```
153
41
 
154
- This method queries the "businessrecords" collection using a simple filter and converts the cursor into an array of records. You can extend the query to filter by more sophisticated criteria as needed.
155
-
156
- #### c) Updating an Existing Business Record
42
+ ### 🏢 German Business Data
157
43
 
158
- Modifying the details of an exisiting record is a common operation. First, you need to retrieve the record from the database. Once the record is loaded, you can make changes to its properties and then save the updated record back to the database. The following example demonstrates this with a change to the company’s phone number and last update timestamp:
44
+ Access comprehensive data on German companies:
159
45
 
160
46
  ```typescript
161
47
  import { OpenData } from '@fin.cx/opendata';
162
48
 
163
- export const updateBusinessRecordExample = async (openData: OpenData, recordId: string) => {
164
- try {
165
- // Retrieve the record by its id using the manager’s helper
166
- const businessRecord = await openData.CBusinessRecord.getInstance(recordId);
167
- if (!businessRecord) {
168
- console.log(`No business record found with id: ${recordId}`);
169
- return;
170
- }
49
+ const openData = new OpenData();
50
+ await openData.start();
171
51
 
172
- // Update some fields
173
- businessRecord.data.phone = "+49 30 654321";
174
- businessRecord.data.lastUpdate = new Date().toISOString();
175
-
176
- // Save the updated record into the database
177
- await businessRecord.save();
178
- console.log("Business record updated successfully:", businessRecord);
179
- } catch (error) {
180
- console.error('Error updating business record:', error);
181
- }
52
+ // Create a business record
53
+ const company = new openData.CBusinessRecord();
54
+ company.data = {
55
+ name: "TechStart GmbH",
56
+ city: "Berlin",
57
+ registrationId: "HRB 123456",
58
+ // ... more fields
182
59
  };
183
- ```
60
+ await company.save();
184
61
 
185
- This code snippet presents a robust pattern where errors are caught and logged, ensuring that any update issues can be diagnosed easily.
62
+ // Search companies by city
63
+ const berlinCompanies = await openData.db
64
+ .collection('businessrecords')
65
+ .find({ city: "Berlin" })
66
+ .toArray();
186
67
 
187
- #### d) Deleting a Business Record
188
-
189
- The deletion of a record is as vital as its creation and modification. The library provides a delete method that removes the specified record from the database. Below is a simple function to delete a business record by its identifier:
190
-
191
- ```typescript
192
- import { OpenData } from '@fin.cx/opendata';
193
-
194
- export const deleteBusinessRecordExample = async (openData: OpenData, recordId: string) => {
195
- try {
196
- const businessRecord = await openData.CBusinessRecord.getInstance(recordId);
197
- if (businessRecord) {
198
- await businessRecord.delete();
199
- console.log(`Successfully deleted business record with id: ${recordId}`);
200
- } else {
201
- console.log(`No business record found with id: ${recordId}`);
202
- }
203
- } catch (error) {
204
- console.error('Error deleting business record:', error);
205
- }
206
- };
68
+ // Import bulk data from official sources
69
+ await openData.buildInitialDb();
207
70
  ```
208
71
 
209
- Through this example, you can integrate safe deletion practices in your application, removing outdated or incorrect records without compromising database integrity.
210
-
211
- ────────────────────────────────────────────
212
- ### 3. Bulk Data Processing and Importing via JSONL Streams
72
+ ## Features
213
73
 
214
- One of the powerful features of the @fin.cx/opendata module is its ability to process large datasets provided in the JSON Lines (JSONL) format. The JsonlDataProcessor class is designed to handle streaming data, processing each record concurrently, and efficiently updating the database.
74
+ ### 🎯 Stock Market Module
215
75
 
216
- This bulk data ingestion mechanism is particularly useful when dealing with large-scale datasets such as the German companies' open data that the module fetches from official data portals. The process involves decompressing, streaming, and parsing data by leveraging pipelines of smart streams and concurrent processors.
76
+ - **Real-time prices** for stocks, ETFs, indices, crypto, forex, and commodities
77
+ - **Batch operations** - fetch 100+ symbols in one request
78
+ - **Smart caching** - configurable TTL, automatic invalidation
79
+ - **Provider system** - easily extensible for new data sources
80
+ - **Automatic retries** and fallback mechanisms
81
+ - **Type-safe** - full TypeScript support with detailed interfaces
217
82
 
218
- Below is an extended example demonstrating how to process a JSONL data file from a given URL:
219
-
220
- ```typescript
221
- import { OpenData } from '@fin.cx/opendata';
83
+ ### 🇩🇪 German Business Intelligence
222
84
 
223
- // This function demonstrates bulk data processing using the JSONL data processor.
224
- // The dataUrl parameter is optional and, if not provided, defaults to the official open data URL.
225
- export const demonstrateBulkDataProcessing = async (openData: OpenData, dataUrl?: string) => {
226
- try {
227
- console.log('Starting bulk data processing...');
228
- await openData.jsonLDataProcessor.processDataFromUrl(dataUrl);
229
- console.log('Bulk data processing completed successfully.');
230
- } catch (error) {
231
- console.error('Error during bulk data processing:', error);
232
- }
233
- };
234
- ```
85
+ - **MongoDB integration** for scalable data storage
86
+ - **Bulk JSONL import** from official German data sources
87
+ - **Handelsregister automation** - automated document retrieval
88
+ - **CRUD operations** with validation
89
+ - **Streaming processing** for multi-GB datasets
235
90
 
236
- In the processDataFromUrl implementation, the library uses a pipeline of smart streams. After downloading the compressed file, it decompresses it and splits the content into discrete JSON lines. The processor then concurrently applies a handler function to each JSON entry. This function extracts relevant company details, instantiates a new BusinessRecord, associates parsed data (for example, registration attributes from German registers), and saves the record to MongoDB.
91
+ ## Advanced Examples
237
92
 
238
- A deeper dive into the processing mechanism:
239
- • The JSONL data is received as a binary (Buffer) stream.
240
- • The stream is piped into a duplex stream that splits the text by newline characters.
241
- • Each line is parsed into a JSON object and passed into an asynchronous processing function.
242
- • This function creates a new business record and sets properties such as the company name and its registration details, derived from the JSON entry.
243
- • As the processor moves through the stream, it logs progress every 10,000 records to give feedback on its bulk processing status.
93
+ ### Market Dashboard
244
94
 
245
- By supporting concurrency (with a configurable concurrency limit, e.g., 1000 simultaneous operations), the library ensures that even gigabytes of data are processed efficiently without hitting memory bottlenecks.
246
-
247
- ────────────────────────────────────────────
248
- ### 4. Integrating with the Handelsregister: Detailed Demonstrations
249
-
250
- In addition to CRUD operations and bulk processing, the module includes an integrated Handelsregister system. This sophisticated component leverages a headless browser (via the smartbrowser instance) to interact with the official Handelsregister website. Through this integration, you can search for companies, navigate to specific pages, trigger file downloads (such as PDF or XML data), and parse the downloaded content for further processing.
251
-
252
- #### a) Starting the Handelsregister
253
-
254
- Before executing any search or download operations, the Handelsregister system must be started. The start method initializes required resources including starting a headless browser, ensuring download directories are created, and preparing asynchronous stacks for exclusive execution.
95
+ Create a real-time market overview:
255
96
 
256
97
  ```typescript
257
- import { OpenData } from '@fin.cx/opendata';
258
-
259
- export const demonstrateHandelsregisterStart = async (openData: OpenData) => {
260
- try {
261
- console.log('Starting Handelsregister services...');
262
- await openData.handelsregister.start();
263
- console.log('Handelsregister ready.');
264
- } catch (error) {
265
- console.error('Error starting Handelsregister service:', error);
266
- }
267
- };
268
- ```
269
-
270
- #### b) Searching for a Company Using the Handelsregister
271
-
272
- A common use case is to search for a company by its name. The Handelsregister system creates a dedicated browser page, enters the search criteria into the input fields, selects the appropriate options (such as radio buttons for search type), and clicks the “Find” button. The following function demonstrates how to incorporate these actions:
98
+ const indicators = [
99
+ // Indices
100
+ { ticker: '^GSPC', name: 'S&P 500' },
101
+ { ticker: '^IXIC', name: 'NASDAQ' },
102
+
103
+ // Tech Giants
104
+ { ticker: 'AAPL', name: 'Apple' },
105
+ { ticker: 'MSFT', name: 'Microsoft' },
106
+
107
+ // Crypto
108
+ { ticker: 'BTC-USD', name: 'Bitcoin' },
109
+ { ticker: 'ETH-USD', name: 'Ethereum' },
110
+
111
+ // Commodities
112
+ { ticker: 'GC=F', name: 'Gold' },
113
+ { ticker: 'CL=F', name: 'Oil' }
114
+ ];
273
115
 
274
- ```typescript
275
- import { OpenData } from '@fin.cx/opendata';
116
+ const prices = await stockService.getPrices({
117
+ tickers: indicators.map(i => i.ticker)
118
+ });
276
119
 
277
- export const searchCompanyExample = async (openData: OpenData, companyName: string, limit: number = 100) => {
278
- try {
279
- console.log(`Searching for company with name "${companyName}"...`);
280
- const records = await openData.handelsregister.searchCompany(companyName, limit);
281
- console.log(`Found ${records.length} matching records for "${companyName}".`);
282
- console.log('Records:', records);
283
- return records;
284
- } catch (error) {
285
- console.error('Error searching for company:', error);
286
- }
287
- };
120
+ // Display with color-coded changes
121
+ prices.forEach(price => {
122
+ const indicator = indicators.find(i => i.ticker === price.ticker);
123
+ const arrow = price.change >= 0 ? '↑' : '↓';
124
+ const color = price.change >= 0 ? '\x1b[32m' : '\x1b[31m';
125
+
126
+ console.log(
127
+ `${indicator.name.padEnd(15)} ${price.price.toFixed(2).padStart(10)} ` +
128
+ `${color}${arrow} ${price.changePercent.toFixed(2)}%\x1b[0m`
129
+ );
130
+ });
288
131
  ```
289
132
 
290
- In this scenario, the Handelsregister component uses internal helper functions:
291
- • getNewPage – to create a new browser page with file download behavior enabled.
292
- • navigateToPage – which navigates to the “Normal search” page.
293
- • Input events – to simulate typing in search criteria.
294
- • UI interactions – to select options and trigger the search.
295
-
296
- #### c) Retrieving Detailed Data and Triggering Downloads
297
-
298
- After obtaining general search results, you may wish to retrieve more detailed information about a specific company. Provided you have the parsed registration data (which typically includes the registration court, type, and number), you can instruct the system to navigate to a detailed view and trigger file downloads. These files might include the company’s official registry entry (as an XML file) and additional documents (such as a PDF summary).
133
+ ### Handelsregister Integration
299
134
 
300
- The example below details how to use the Handelsregister functionality to focus on a specific company by leveraging its registration details, then download both SI and AD files:
135
+ Automate German company data retrieval:
301
136
 
302
137
  ```typescript
303
- import { OpenData } from '@fin.cx/opendata';
138
+ // Search for a company
139
+ const results = await openData.handelsregister.searchCompany("Siemens AG");
140
+
141
+ // Get detailed information and documents
142
+ const details = await openData.handelsregister.getSpecificCompany({
143
+ court: "Munich",
144
+ type: "HRB",
145
+ number: "6684"
146
+ });
304
147
 
305
- export const getDetailedCompanyData = async (openData: OpenData, registrationData: { court?: string; type?: 'HRA' | 'HRB' | 'GnR' | 'PR' | 'VR' | 'GsR'; number?: string; }) => {
306
- try {
307
- console.log('Retrieving detailed company data...');
308
- const result = await openData.handelsregister.getSpecificCompany(registrationData);
309
- console.log('Retrieved detailed company data.');
310
- console.log('Business Records:', result.businessRecords);
311
- console.log('Downloaded Files:', result.files);
312
- return result;
313
- } catch (error) {
314
- console.error('Error retrieving detailed company data:', error);
315
- }
316
- };
148
+ // Downloaded files include:
149
+ // - XML data (SI files)
150
+ // - PDF documents (AD files)
151
+ for (const file of details.files) {
152
+ await file.writeToDir('./downloads');
153
+ }
317
154
  ```
318
155
 
319
- In the above example:
320
- • The getSpecificCompany method triggers navigation through various UI elements:
321
- – Selecting the register type via a dropdown.
322
- – Inputting the register number.
323
- – Choosing the appropriate register court.
324
- • Then, after clicking the “Find” button, the system waits for the results, verifies the visual components on the page, and initiates file downloads.
325
- • The downloaded files are renamed according to their type (SI for XML and AD for PDF) and are returned for further processing or storage.
326
-
327
- #### d) Downloading and Processing Files
328
-
329
- The Handelsregister component not only triggers file downloads but also includes utility functions that wait for downloads to complete, clear temporary directories, and output the file objects. You may want to use these file objects to persist data locally, parse file content, or send the data downstream for further analysis.
156
+ ### Combined Data Analysis
330
157
 
331
- Below is an example that covers downloading and saving the files into a custom directory for post-download analysis:
158
+ Merge financial and business data:
332
159
 
333
160
  ```typescript
334
- import { OpenData } from '@fin.cx/opendata';
335
- import * as path from 'path';
336
-
337
- export const downloadAndSaveFilesExample = async (openData: OpenData, registrationData: { court?: string; type?: 'HRA' | 'HRB' | 'GnR' | 'PR' | 'VR' | 'GsR'; number?: string; }) => {
161
+ // Find all public German companies (AG)
162
+ const publicCompanies = await openData.db
163
+ .collection('businessrecords')
164
+ .find({ legalForm: 'AG' })
165
+ .toArray();
166
+
167
+ // Enrich with stock data
168
+ for (const company of publicCompanies) {
338
169
  try {
339
- console.log('Initiating specific company download...');
340
- const result = await openData.handelsregister.getSpecificCompany(registrationData);
341
- const saveDirectory = path.join(process.cwd(), 'downloaded_files');
342
-
343
- // Save each downloaded file to the specified directory
344
- for (const file of result.files) {
345
- await file.writeToDir(saveDirectory);
346
- console.log(`File saved: ${file.path}`);
170
+ // Map company to ticker (custom logic needed)
171
+ const ticker = mapCompanyToTicker(company.data.name);
172
+
173
+ if (ticker) {
174
+ const stock = await stockService.getPrice({ ticker });
175
+
176
+ // Add financial metrics
177
+ company.data.stockPrice = stock.price;
178
+ company.data.marketCap = stock.price * getSharesOutstanding(ticker);
179
+ company.data.priceChange = stock.changePercent;
180
+
181
+ await company.save();
347
182
  }
348
183
  } catch (error) {
349
- console.error('Error during file download and save process:', error);
184
+ // Handle missing tickers gracefully
350
185
  }
351
- };
186
+ }
352
187
  ```
353
188
 
354
- This function demonstrates a complete flow from launching the Handelsregister detailed company search to saving the downloaded files to disk. This example is particularly useful in scenarios where the downloaded documents need to be processed further, such as converting XML to JSON or extracting text from PDFs.
355
-
356
- ────────────────────────────────────────────
357
- ### 5. Advanced Examples: Combined Operations and Edge Cases
358
-
359
- Given the numerous functionalities offered by the library, you can combine various operations to create more complex workflows. One such example is an end-to-end pipeline that:
360
- 1. Initializes the open data instance.
361
- 2. Processes an initial bulk data import.
362
- 3. Searches for key business records that match specific criteria.
363
- 4. Updates individual records based on additional data retrieved from the Handelsregister.
364
- 5. Handles error conditions and retries processes where necessary.
189
+ ## Configuration
365
190
 
366
- The following advanced example integrates these steps:
191
+ ### Stock Service Options
367
192
 
368
193
  ```typescript
369
- import { OpenData } from '@fin.cx/opendata';
370
-
371
- const advancedWorkflowExample = async () => {
372
- const openData = new OpenData();
373
-
374
- try {
375
- console.log('Starting advanced workflow...');
376
- await openData.start();
377
-
378
- // Step 1: Bulk data import from external JSONL source
379
- console.log('Building initial database from bulk import...');
380
- await openData.buildInitialDb();
381
-
382
- // Step 2: Search for companies in a selected area (for instance, Munich)
383
- console.log('Retrieving companies located in Munich...');
384
- const munichRecords = await openData.db
385
- .collection('businessrecords')
386
- .find({ city: "Munich" })
387
- .toArray();
388
- console.log(`Found ${munichRecords.length} companies in Munich.`);
389
-
390
- // Step 3: For each record, perform an update operation based on new file downloads
391
- for (const record of munichRecords) {
392
- try {
393
- console.log(`Updating record for company: ${record.data.name}`);
394
- // Assuming the record contains parsed registration info
395
- if (record.data.germanParsedRegistration) {
396
- const detailedData = await openData.handelsregister.getSpecificCompany(record.data.germanParsedRegistration);
397
- // Update business record with new information (e.g., registration files or updated details)
398
- record.data.lastUpdate = new Date().toISOString();
399
- // You might want to add additional fields based on the downloaded file data
400
- await record.save();
401
- console.log(`Updated record for ${record.data.name}.`);
402
- } else {
403
- console.log(`No registration data available for ${record.data.name}; skipping update.`);
404
- }
405
- } catch (innerError) {
406
- console.error(`Error updating record for ${record.data.name}:`, innerError);
407
- }
408
- }
409
-
410
- // Step 4: Demonstrate retrieval and deletion
411
- const recordToDeleteId = munichRecords.length > 0 ? munichRecords[0].id : null;
412
- if (recordToDeleteId) {
413
- console.log(`Deleting record with id: ${recordToDeleteId}`);
414
- const recordToDelete = await openData.CBusinessRecord.getInstance(recordToDeleteId);
415
- if (recordToDelete) {
416
- await recordToDelete.delete();
417
- console.log(`Record ${recordToDeleteId} deleted successfully.`);
418
- }
419
- }
420
-
421
- } catch (error) {
422
- console.error('Advanced workflow encountered an error:', error);
423
- } finally {
424
- console.log('Ending advanced workflow and stopping OpenData instance.');
425
- await openData.stop();
426
- }
427
- };
194
+ const stockService = new StockPriceService({
195
+ ttl: 60000, // Cache for 1 minute
196
+ maxEntries: 1000 // Max cached symbols
197
+ });
428
198
 
429
- advancedWorkflowExample();
199
+ // Provider configuration
200
+ stockService.register(new YahooFinanceProvider(), {
201
+ enabled: true,
202
+ priority: 100,
203
+ timeout: 10000,
204
+ retryAttempts: 3,
205
+ retryDelay: 1000
206
+ });
430
207
  ```
431
208
 
432
- This advanced workflow not only illustrates the coordinated use of bulk data import, search, update, and delete operations but also demonstrates the integration of browser automation for fetching detailed data. The error handling at each step ensures that even if a particular operation fails, the workflow continues in a controlled fashion.
433
-
434
- ────────────────────────────────────────────
435
- ### 6. Error Handling and Data Validation
436
-
437
- Robust systems must gracefully handle errors and ensure data consistency. The @fin.cx/opendata library has built-in error handling for asynchronous operations, whether connecting to MongoDB, processing JSON streams, or interacting with web pages. In addition, each BusinessRecord instance provides a validate method that performs basic checks (for instance, ensuring that a company name is present) before a record is saved into the database.
209
+ ### MongoDB Setup
438
210
 
439
- The snippet below shows how to wrap operations in try/catch blocks and use the validate method:
440
-
441
- ```typescript
442
- import { OpenData } from '@fin.cx/opendata';
211
+ Set environment variables:
443
212
 
444
- export const validateAndSaveRecord = async (openData: OpenData) => {
445
- const record = new openData.CBusinessRecord();
446
- record.data = {
447
- name: "Validation Test Corp",
448
- address: "Teststraße 99",
449
- postalCode: "12345",
450
- city: "Teststadt",
451
- country: "Germany",
452
- phone: "+49 123 456789",
453
- email: "test@testcorp.de",
454
- businessType: "AG",
455
- registrationId: "District court Teststadt HRB 111111",
456
- legalForm: "AG",
457
- managingDirectors: ["Test Director"],
458
- foundingDate: new Date().toISOString(),
459
- capital: "1,000,000 EUR",
460
- purpose: "Testing for data validation",
461
- lastUpdate: new Date().toISOString()
462
- };
463
-
464
- try {
465
- // Validate record data before saving.
466
- await record.validate();
467
- await record.save();
468
- console.log("Record validated and saved successfully.");
469
- } catch (error) {
470
- console.error("Error validating or saving record:", error);
471
- }
472
- };
213
+ ```env
214
+ MONGODB_URL=mongodb://localhost:27017
215
+ MONGODB_NAME=opendata
216
+ MONGODB_USER=myuser
217
+ MONGODB_PASS=mypass
473
218
  ```
474
219
 
475
- Using proper error handling ensures that the entire system remains reliable, and any data validation issues are caught early during development or in production.
476
-
477
- ────────────────────────────────────────────
478
- ### 7. Testing and Automated Workflows
479
-
480
- To support continuous integration and adherence to best practices, the @fin.cx/opendata module includes tests written with @push.rocks/tapbundle. You should consider incorporating these tests in your development workflow. The tests verify all main functionalities including instance initialization, bulk data import, Handelsregister operations, and CRUD operations for BusinessRecords.
220
+ ## API Reference
481
221
 
482
- Below is an example of a simple test written in TypeScript using ESM that makes use of the module:
222
+ ### Stock Types
483
223
 
484
224
  ```typescript
485
- import { expect, tap } from '@push.rocks/tapbundle';
486
- import { OpenData } from '@fin.cx/opendata';
487
-
488
- let testOpenDataInstance: OpenData;
489
-
490
- tap.test('Instance creation', async () => {
491
- testOpenDataInstance = new OpenData();
492
- expect(testOpenDataInstance).toBeInstanceOf(OpenData);
493
- });
494
-
495
- tap.test('Start instance', async () => {
496
- await testOpenDataInstance.start();
497
- });
498
-
499
- tap.test('Perform bulk import', async () => {
500
- await testOpenDataInstance.buildInitialDb();
501
- });
502
-
503
- tap.test('Stop instance', async () => {
504
- await testOpenDataInstance.stop();
505
- });
506
-
507
- tap.start();
225
+ interface IStockPrice {
226
+ ticker: string;
227
+ price: number;
228
+ currency: string;
229
+ change: number;
230
+ changePercent: number;
231
+ previousClose: number;
232
+ timestamp: Date;
233
+ provider: string;
234
+ marketState: 'PRE' | 'REGULAR' | 'POST' | 'CLOSED';
235
+ exchange?: string;
236
+ exchangeName?: string;
237
+ }
508
238
  ```
509
239
 
510
- This test code is designed to verify that the OpenData instance is successfully created, started, performs the critical bulk import operation, and is properly shutdown. Integration tests for the Handelsregister functionality follow a similar pattern and ensure that the browser automation routines and file download processes complete without errors.
240
+ ### Key Methods
511
241
 
512
- ────────────────────────────────────────────
513
- ### Comprehensive Example: Full Cycle from Initialization to Cleanup
242
+ **StockPriceService**
243
+ - `getPrice(request)` - Single stock price
244
+ - `getPrices(request)` - Batch prices
245
+ - `register(provider)` - Add data provider
246
+ - `clearCache()` - Clear price cache
514
247
 
515
- To better illustrate how one might combine several aspects of the module in a production scenario, here's a comprehensive example that ties together initialization, CRUD operations, bulk processing, and Handelsregister interactions. This full-cycle example is written in TypeScript using ESM syntax and demonstrates how to build a production-grade data update and management pipeline.
248
+ **OpenData**
249
+ - `start()` - Initialize MongoDB connection
250
+ - `buildInitialDb()` - Import bulk data
251
+ - `CBusinessRecord` - Business record class
252
+ - `handelsregister` - Registry automation
516
253
 
517
- ```typescript
518
- import { OpenData } from '@fin.cx/opendata';
254
+ ## Performance
519
255
 
520
- const runFullCyclePipeline = async () => {
521
- const openData = new OpenData();
256
+ - **Batch fetching**: Get 100+ prices in <500ms
257
+ - **Caching**: Instant repeated queries
258
+ - **Concurrent processing**: Handle 1000+ records/second
259
+ - **Streaming**: Process GB-sized datasets without memory issues
522
260
 
523
- try {
524
- // Initialize the module and connect to MongoDB
525
- console.log('Initializing the OpenData module...');
526
- await openData.start();
527
-
528
- // Step 1: Bulk Import - Build the initial database from downloaded open data
529
- console.log('Starting bulk data import from JSONL source...');
530
- await openData.buildInitialDb();
531
-
532
- // Step 2: Business Record Management - Create a sample business record
533
- console.log('Creating a new business record...');
534
- const sampleRecord = new openData.CBusinessRecord();
535
- sampleRecord.data = {
536
- name: "Sample Enterprise GmbH",
537
- address: "Innovation Avenue 101",
538
- postalCode: "80807",
539
- city: "Munich",
540
- country: "Germany",
541
- phone: "+49 89 111222",
542
- email: "info@sampleenterprise.de",
543
- website: "https://sampleenterprise.de",
544
- businessType: "GmbH",
545
- registrationId: "District court Munich HRB 555555",
546
- legalForm: "GmbH",
547
- managingDirectors: ["Director A", "Director B"],
548
- foundingDate: new Date("2015-06-15").toISOString(),
549
- capital: "500,000 EUR",
550
- purpose: "Holistic business solutions and data processing",
551
- lastUpdate: new Date().toISOString()
552
- };
553
-
554
- await sampleRecord.save();
555
- console.log('Sample business record created with id:', sampleRecord.id);
556
-
557
- // Step 3: Retrieve business records for a specific location
558
- console.log('Retrieving business records for Munich...');
559
- const munichRecords = await openData.db
560
- .collection('businessrecords')
561
- .find({ city: "Munich" })
562
- .toArray();
563
- console.log(`Found ${munichRecords.length} records for Munich.`);
564
-
565
- // Step 4: Update an existing record
566
- if (munichRecords.length > 0) {
567
- const recordToUpdateId = munichRecords[0].id;
568
- console.log(`Updating business record with id: ${recordToUpdateId}`);
569
- const recordToUpdate = await openData.CBusinessRecord.getInstance(recordToUpdateId);
570
- if (recordToUpdate) {
571
- recordToUpdate.data.phone = "+49 89 999888";
572
- recordToUpdate.data.lastUpdate = new Date().toISOString();
573
- await recordToUpdate.save();
574
- console.log('Business record updated:', recordToUpdate);
575
- }
576
- }
261
+ ## Extensibility
577
262
 
578
- // Step 5: Use Handelsregister to search for a specific company
579
- console.log('Using Handelsregister to search for a specific company...');
580
- const searchResults = await openData.handelsregister.searchCompany("Step Beyond GmbH", 20);
581
- if (searchResults && searchResults.length > 0) {
582
- const registrationData = searchResults[0].germanParsedRegistration;
583
- console.log('Retrieved registration data:', registrationData);
584
-
585
- // Step 6: Retrieve detailed info and download files for the specific company
586
- console.log('Fetching detailed data for the identified company...');
587
- const detailedInfo = await openData.handelsregister.getSpecificCompany(registrationData);
588
- console.log('Detailed company data received:', detailedInfo);
589
-
590
- // Optionally, save the downloaded files to a designated directory
591
- for (const downloadedFile of detailedInfo.files) {
592
- await downloadedFile.writeToDir('./output_files');
593
- console.log(`Downloaded file saved at: ${downloadedFile.path}`);
594
- }
595
- } else {
596
- console.log('No matching records found for detailed company data retrieval.');
597
- }
263
+ The provider architecture makes it easy to add new data sources:
598
264
 
599
- // Step 7: Validate and save a record to demonstrate error handling and validation
600
- console.log('Validating and saving a new test record...');
601
- await validateAndSaveRecord(openData);
602
-
603
- } catch (error) {
604
- console.error('An error occurred during the full cycle pipeline operation:', error);
605
- } finally {
606
- // Final cleanup: Stop the OpenData module and release all resources
607
- console.log('Finalizing: stopping the OpenData module...');
608
- await openData.stop();
609
- console.log('Pipeline completed and all resources have been cleaned up.');
265
+ ```typescript
266
+ class MyCustomProvider implements IStockProvider {
267
+ name = 'My Provider';
268
+
269
+ async fetchPrice(request: IStockQuoteRequest): Promise<IStockPrice> {
270
+ // Your implementation
610
271
  }
611
- };
272
+
273
+ // ... other required methods
274
+ }
612
275
 
613
- runFullCyclePipeline();
276
+ stockService.register(new MyCustomProvider());
614
277
  ```
615
278
 
616
- In this example, the entire processing cycle is constructed to mimic a realistic scenario. The pipeline:
617
- • Starts by connecting to your database.
618
- • Imports extensive JSONL open data.
619
- • Creates, retrieves, updates, and deletes business records.
620
- • Interacts with the Handelsregister for advanced company-specific operations.
621
- • Implements robust error handling and validation routines, ensuring that each step is verifiable.
622
- • Finally, ensures that resources such as MongoDB connections and headless browser sessions are responsibly closed.
623
-
624
- ────────────────────────────────────────────
625
- ### Final Thoughts on Module Integration
279
+ ## Testing
626
280
 
627
- The @fin.cx/opendata library is designed to cater to a wide range of business data management needs. Whether you are an enterprise looking to integrate updated open data for decision-making or a developer looking to build data-rich applications with a focus on German companies, this library provides the tools and abstractions necessary to build robust solutions.
281
+ Run the comprehensive test suite:
628
282
 
629
- Every component—from the smart data management for business records to the advanced streaming and concurrent processing of JSONL files—is built with scalability and ease of use in mind. Integration with the Handelsregister via browser automation further extends its reach, providing dynamic access to official data sources in real-time.
630
-
631
- As demonstrated in the examples above, each sub-component of the library is independent yet harmoniously integrated into a cohesive user experience. The use of ESM syntax throughout the module and the strict adherence to TypeScript definitions enhances reliability, maintainability, and the overall developer experience.
632
-
633
- By following the usage scenarios provided in this documentation, you should now have a deep understanding of how to:
634
- • Set up your environment and initialize the OpenData instance.
635
- • Perform CRUD operations on business records.
636
- • Efficiently process thousands of records from external JSONL sources.
637
- • Integrate and automate Handelsregister interactions for detailed company data retrieval.
638
- • Combine all building blocks into advanced automated workflows that support large-scale enterprise applications.
639
-
640
- Feel free to explore, extend, and customize these examples to suit your project’s unique requirements. The library is designed with extensibility in mind, and additional utility functions or integrations can be added based on your needs.
283
+ ```bash
284
+ npm test
285
+ ```
641
286
 
642
- We encourage you to integrate these practices into your development processes, run the provided tests, and contribute to further enhancements that can benefit the entire community of developers working on open data management systems.
287
+ View live market data:
643
288
 
644
- Happy coding and data integrating!
289
+ ```bash
290
+ npm test -- --grep "market indicators"
291
+ ```
645
292
 
293
+ ## Contributing
646
294
 
295
+ We welcome contributions! Please see our contributing guidelines for details.
647
296
 
648
297
  ## License and Legal Information
649
298
 
@@ -662,4 +311,4 @@ Registered at District court Bremen HRB 35230 HB, Germany
662
311
 
663
312
  For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
664
313
 
665
- By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
314
+ By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@fin.cx/opendata',
6
- version: '1.5.3',
7
- description: 'A comprehensive TypeScript library that manages open business data for German companies by integrating MongoDB, processing JSONL bulk data, and automating browser interactions for Handelsregister data retrieval.'
6
+ version: '1.6.1',
7
+ description: 'A comprehensive TypeScript library for accessing business data and real-time financial information. Features include German company data management with MongoDB integration, JSONL bulk processing, automated Handelsregister interactions, and real-time stock market data from multiple providers.'
8
8
  }
@@ -1,3 +1,5 @@
1
+ import * as plugins from '../../plugins.js';
2
+
1
3
  export interface IStockPrice {
2
4
  ticker: string;
3
5
  price: number;
@@ -11,6 +13,10 @@ export interface IStockPrice {
11
13
  exchange?: string;
12
14
  exchangeName?: string;
13
15
  }
16
+ type CheckStockPrice = plugins.tsclass.typeFest.IsEqual<
17
+ IStockPrice,
18
+ plugins.tsclass.finance.IStockPrice
19
+ >;
14
20
 
15
21
  export interface IStockPriceError {
16
22
  ticker: string;
@@ -27,4 +33,4 @@ export interface IStockQuoteRequest {
27
33
  export interface IStockBatchQuoteRequest {
28
34
  tickers: string[];
29
35
  includeExtendedHours?: boolean;
30
- }
36
+ }
@@ -20,14 +20,15 @@ export class YahooFinanceProvider implements IStockProvider {
20
20
  public async fetchPrice(request: IStockQuoteRequest): Promise<IStockPrice> {
21
21
  try {
22
22
  const url = `${this.baseUrl}/v8/finance/chart/${request.ticker}`;
23
- const response = await plugins.smartrequest.getJson(url, {
24
- headers: {
23
+ const response = await plugins.smartrequest.SmartRequest.create()
24
+ .url(url)
25
+ .headers({
25
26
  'User-Agent': this.userAgent
26
- },
27
- timeout: this.config?.timeout || 10000
28
- });
27
+ })
28
+ .timeout(this.config?.timeout || 10000)
29
+ .get();
29
30
 
30
- const responseData = response.body as any;
31
+ const responseData = await response.json() as any;
31
32
 
32
33
  if (!responseData?.chart?.result?.[0]) {
33
34
  throw new Error(`No data found for ticker ${request.ticker}`);
@@ -66,14 +67,15 @@ export class YahooFinanceProvider implements IStockProvider {
66
67
  const symbols = request.tickers.join(',');
67
68
  const url = `${this.baseUrl}/v8/finance/spark?symbols=${symbols}&range=1d&interval=5m`;
68
69
 
69
- const response = await plugins.smartrequest.getJson(url, {
70
- headers: {
70
+ const response = await plugins.smartrequest.SmartRequest.create()
71
+ .url(url)
72
+ .headers({
71
73
  'User-Agent': this.userAgent
72
- },
73
- timeout: this.config?.timeout || 15000
74
- });
74
+ })
75
+ .timeout(this.config?.timeout || 15000)
76
+ .get();
75
77
 
76
- const responseData = response.body as any;
78
+ const responseData = await response.json() as any;
77
79
  const prices: IStockPrice[] = [];
78
80
 
79
81
  for (const [ticker, data] of Object.entries(responseData)) {