riksdagsmonitor 0.8.60 → 0.8.65
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.
- package/README.md +366 -972
- package/SECURITY.md +57 -4
- package/dist/lib/cia/csv-utils.d.ts +75 -0
- package/dist/lib/cia/csv-utils.d.ts.map +1 -0
- package/dist/lib/cia/csv-utils.js +122 -0
- package/dist/lib/cia/csv-utils.js.map +1 -0
- package/dist/lib/cia/dashboard-init.d.ts +1 -1
- package/dist/lib/cia/dashboard-init.d.ts.map +1 -1
- package/dist/lib/cia/dashboard-init.js +7 -6
- package/dist/lib/cia/dashboard-init.js.map +1 -1
- package/dist/lib/cia/data-loader.d.ts +38 -348
- package/dist/lib/cia/data-loader.d.ts.map +1 -1
- package/dist/lib/cia/data-loader.js +54 -766
- package/dist/lib/cia/data-loader.js.map +1 -1
- package/dist/lib/cia/election-predictions.d.ts +1 -1
- package/dist/lib/cia/election-predictions.d.ts.map +1 -1
- package/dist/lib/cia/loaders/committees.d.ts +25 -0
- package/dist/lib/cia/loaders/committees.d.ts.map +1 -0
- package/dist/lib/cia/loaders/committees.js +110 -0
- package/dist/lib/cia/loaders/committees.js.map +1 -0
- package/dist/lib/cia/loaders/demographics.d.ts +22 -0
- package/dist/lib/cia/loaders/demographics.d.ts.map +1 -0
- package/dist/lib/cia/loaders/demographics.js +48 -0
- package/dist/lib/cia/loaders/demographics.js.map +1 -0
- package/dist/lib/cia/loaders/documents.d.ts +22 -0
- package/dist/lib/cia/loaders/documents.d.ts.map +1 -0
- package/dist/lib/cia/loaders/documents.js +51 -0
- package/dist/lib/cia/loaders/documents.js.map +1 -0
- package/dist/lib/cia/loaders/election.d.ts +24 -0
- package/dist/lib/cia/loaders/election.d.ts.map +1 -0
- package/dist/lib/cia/loaders/election.js +111 -0
- package/dist/lib/cia/loaders/election.js.map +1 -0
- package/dist/lib/cia/loaders/index.d.ts +26 -0
- package/dist/lib/cia/loaders/index.d.ts.map +1 -0
- package/dist/lib/cia/loaders/index.js +26 -0
- package/dist/lib/cia/loaders/index.js.map +1 -0
- package/dist/lib/cia/loaders/ministries.d.ts +22 -0
- package/dist/lib/cia/loaders/ministries.d.ts.map +1 -0
- package/dist/lib/cia/loaders/ministries.js +41 -0
- package/dist/lib/cia/loaders/ministries.js.map +1 -0
- package/dist/lib/cia/loaders/overview.d.ts +24 -0
- package/dist/lib/cia/loaders/overview.d.ts.map +1 -0
- package/dist/lib/cia/loaders/overview.js +96 -0
- package/dist/lib/cia/loaders/overview.js.map +1 -0
- package/dist/lib/cia/loaders/parties.d.ts +24 -0
- package/dist/lib/cia/loaders/parties.d.ts.map +1 -0
- package/dist/lib/cia/loaders/parties.js +92 -0
- package/dist/lib/cia/loaders/parties.js.map +1 -0
- package/dist/lib/cia/loaders/risk.d.ts +22 -0
- package/dist/lib/cia/loaders/risk.d.ts.map +1 -0
- package/dist/lib/cia/loaders/risk.js +38 -0
- package/dist/lib/cia/loaders/risk.js.map +1 -0
- package/dist/lib/cia/loaders/top10.d.ts +24 -0
- package/dist/lib/cia/loaders/top10.d.ts.map +1 -0
- package/dist/lib/cia/loaders/top10.js +68 -0
- package/dist/lib/cia/loaders/top10.js.map +1 -0
- package/dist/lib/cia/loaders/voting.d.ts +27 -0
- package/dist/lib/cia/loaders/voting.d.ts.map +1 -0
- package/dist/lib/cia/loaders/voting.js +108 -0
- package/dist/lib/cia/loaders/voting.js.map +1 -0
- package/dist/lib/cia/sources.d.ts +29 -0
- package/dist/lib/cia/sources.d.ts.map +1 -0
- package/dist/lib/cia/sources.js +162 -0
- package/dist/lib/cia/sources.js.map +1 -0
- package/dist/lib/cia/types.d.ts +324 -0
- package/dist/lib/cia/types.d.ts.map +1 -0
- package/dist/lib/cia/types.js +24 -0
- package/dist/lib/cia/types.js.map +1 -0
- package/dist/lib/cia/visualizations.d.ts +1 -1
- package/dist/lib/cia/visualizations.d.ts.map +1 -1
- package/dist/lib/shared/register-globals.d.ts +1 -1
- package/dist/lib/shared/register-globals.d.ts.map +1 -1
- package/dist/lib/shared/register-globals.js +6 -4
- package/dist/lib/shared/register-globals.js.map +1 -1
- package/package.json +7 -6
package/SECURITY.md
CHANGED
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
12
|
<p align="center">
|
|
13
|
-
<
|
|
14
|
-
<
|
|
15
|
-
<
|
|
16
|
-
<
|
|
13
|
+
<img src="https://img.shields.io/badge/Owner-CEO-0A66C2?style=for-the-badge" alt="Owner"/>
|
|
14
|
+
<img src="https://img.shields.io/badge/Version-1.0-555?style=for-the-badge" alt="Version"/>
|
|
15
|
+
<img src="https://img.shields.io/badge/Effective-2026--02--20-success?style=for-the-badge" alt="Effective Date"/>
|
|
16
|
+
<img src="https://img.shields.io/badge/Review-Quarterly-orange?style=for-the-badge" alt="Review Cycle"/>
|
|
17
17
|
</p>
|
|
18
18
|
|
|
19
19
|
**📋 Document Owner:** CEO | **📄 Version:** 1.0 | **📅 Last Updated:** 2026-02-20 (UTC)
|
|
@@ -198,3 +198,56 @@ If you discover a vulnerability in our IMF integration (e.g., cache integrity by
|
|
|
198
198
|
**Egress hosts** (allow-list): `www.imf.org` (Datamapper REST · WEO/FM), `sdmxcentral.imf.org` (SDMX 3.0 REST · IFS/BOP/DOTS/GFS/PCPS/ER/MFS_IR/MFS_PR). Both HTTPS-only, anonymous, public — no credentials required.
|
|
199
199
|
|
|
200
200
|
**Canonical rule.** Every economic claim in a Riksdagsmonitor article cites an IMF dataflow first; World Bank citations are reserved for governance, environment and social residue (the classes IMF does not publish). SCB is the Swedish-specific ground truth layer. See `ECONOMIC_DATA_CONTRACT.md` v2.1 for the banned-phrase list and vintage discipline (>6 mo → annotation).
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## 🔗 Hack23 Ecosystem
|
|
205
|
+
|
|
206
|
+
<table>
|
|
207
|
+
<tr>
|
|
208
|
+
<th width="33%">🌐 Platforms</th>
|
|
209
|
+
<th width="33%">📦 Open-Source Projects</th>
|
|
210
|
+
<th width="33%">🛡️ Governance & Standards</th>
|
|
211
|
+
</tr>
|
|
212
|
+
<tr>
|
|
213
|
+
<td valign="top">
|
|
214
|
+
🗳️ <a href="https://riksdagsmonitor.com">Riksdagsmonitor</a> — Swedish Parliament intelligence<br>
|
|
215
|
+
🇪🇺 <a href="https://www.euparliamentmonitor.com">EU Parliament Monitor</a> — European coverage<br>
|
|
216
|
+
🕵️ <a href="https://www.hack23.com/cia">Citizen Intelligence Agency</a> — political-data engine<br>
|
|
217
|
+
🌐 <a href="https://www.hack23.com">Hack23 AB</a> — corporate site<br>
|
|
218
|
+
📰 <a href="https://hack23.com/blog.html">Hack23 Blog</a> — engineering & policy<br>
|
|
219
|
+
💼 <a href="https://www.linkedin.com/company/hack23/">Hack23 on LinkedIn</a>
|
|
220
|
+
</td>
|
|
221
|
+
<td valign="top">
|
|
222
|
+
🗳️ <a href="https://github.com/Hack23/riksdagsmonitor">Hack23/riksdagsmonitor</a><br>
|
|
223
|
+
🕵️ <a href="https://github.com/Hack23/cia">Hack23/cia</a><br>
|
|
224
|
+
🇪🇺 <a href="https://github.com/Hack23/euparliamentmonitor">Hack23/euparliamentmonitor</a><br>
|
|
225
|
+
🔌 <a href="https://github.com/Hack23/european-parliament-mcp">Hack23/european-parliament-mcp</a><br>
|
|
226
|
+
✅ <a href="https://github.com/Hack23/cia-compliance-manager">Hack23/cia-compliance-manager</a><br>
|
|
227
|
+
🥋 <a href="https://github.com/Hack23/black-trigram">Hack23/black-trigram</a><br>
|
|
228
|
+
🏠 <a href="https://github.com/Hack23/homepage">Hack23/homepage</a>
|
|
229
|
+
</td>
|
|
230
|
+
<td valign="top">
|
|
231
|
+
🛡️ <a href="https://github.com/Hack23/ISMS-PUBLIC">Hack23 ISMS-PUBLIC</a> — public ISMS<br>
|
|
232
|
+
🔒 <a href="https://github.com/Hack23/ISMS-PUBLIC/blob/main/Information_Security_Policy.md">Information Security Policy</a><br>
|
|
233
|
+
🤖 <a href="https://github.com/Hack23/ISMS-PUBLIC/blob/main/AI_Policy.md">AI Policy</a><br>
|
|
234
|
+
🧪 <a href="https://github.com/Hack23/ISMS-PUBLIC/blob/main/Secure_Development_Policy.md">Secure Development Policy</a><br>
|
|
235
|
+
🎯 <a href="https://github.com/Hack23/ISMS-PUBLIC/blob/main/Threat_Modeling.md">Threat Modeling Policy</a><br>
|
|
236
|
+
⚠️ <a href="https://github.com/Hack23/ISMS-PUBLIC/blob/main/Vulnerability_Management.md">Vulnerability Management</a><br>
|
|
237
|
+
🏷️ <a href="https://github.com/Hack23/ISMS-PUBLIC/blob/main/CLASSIFICATION.md">Classification Framework</a>
|
|
238
|
+
</td>
|
|
239
|
+
</tr>
|
|
240
|
+
</table>
|
|
241
|
+
|
|
242
|
+
<p align="center">
|
|
243
|
+
<a href="https://www.bestpractices.dev/projects/12069"><img src="https://www.bestpractices.dev/projects/12069/badge" alt="OpenSSF Best Practices"/></a>
|
|
244
|
+
<a href="https://scorecard.dev/viewer/?uri=github.com/Hack23/riksdagsmonitor"><img src="https://api.securityscorecards.dev/projects/github.com/Hack23/riksdagsmonitor/badge" alt="OpenSSF Scorecard"/></a>
|
|
245
|
+
<a href="https://github.com/Hack23/ISMS-PUBLIC"><img src="https://img.shields.io/badge/ISO_27001-2022-blue?style=flat-square&logo=iso&logoColor=white" alt="ISO 27001:2022"/></a>
|
|
246
|
+
<a href="https://github.com/Hack23/ISMS-PUBLIC"><img src="https://img.shields.io/badge/NIST_CSF-2.0-green?style=flat-square&logo=nist&logoColor=white" alt="NIST CSF 2.0"/></a>
|
|
247
|
+
<a href="https://github.com/Hack23/ISMS-PUBLIC"><img src="https://img.shields.io/badge/CIS_Controls-v8.1-orange?style=flat-square&logo=cisecurity&logoColor=white" alt="CIS Controls v8.1"/></a>
|
|
248
|
+
<a href="https://www.apache.org/licenses/LICENSE-2.0"><img src="https://img.shields.io/badge/License-Apache_2.0-blue?style=flat-square" alt="Apache 2.0"/></a>
|
|
249
|
+
</p>
|
|
250
|
+
|
|
251
|
+
<p align="center"><em>🗳️ Empower citizens · 🔍 Strengthen democratic accountability · 🕵️ Illuminate the political process</em></p>
|
|
252
|
+
|
|
253
|
+
<p align="center"><sub>© 2008–2026 <a href="https://www.hack23.com">Hack23 AB</a> (Org.nr 559534-7807) · Maintainer: <a href="https://www.linkedin.com/in/jamessorling/">James Pether Sörling, CISSP CISM</a></sub></p>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module CIA/CSVUtils
|
|
3
|
+
* @category Intelligence Platform - Data Acquisition & Pipeline Management
|
|
4
|
+
*
|
|
5
|
+
* @description
|
|
6
|
+
* CSV parsing and HTTP loading helpers for the CIA data pipeline.
|
|
7
|
+
*
|
|
8
|
+
* Originally lived as private/public methods on `CIADataLoader`; extracted as
|
|
9
|
+
* free functions so each per-domain loader (`loaders/*.ts`) can use them
|
|
10
|
+
* directly without instantiating the orchestrator class. Mockable in tests
|
|
11
|
+
* by stubbing `globalThis.fetch`.
|
|
12
|
+
*
|
|
13
|
+
* @author Hack23 AB - Data Pipeline Engineering
|
|
14
|
+
* @license Apache-2.0
|
|
15
|
+
* @since 2026
|
|
16
|
+
*/
|
|
17
|
+
import type { CSVRow } from './types.js';
|
|
18
|
+
/** Signature used by per-domain loaders to fetch and parse a single CSV. */
|
|
19
|
+
export type LoadCSV = (localPath: string, fallbackPath?: string) => Promise<CSVRow[]>;
|
|
20
|
+
/**
|
|
21
|
+
* Parse CSV text into an array of header-keyed rows with auto-typed values.
|
|
22
|
+
*
|
|
23
|
+
* Handles basic quoting (`"value, with, commas"`) and converts numeric strings
|
|
24
|
+
* to numbers. Empty cells are kept as the empty string. Returns `[]` for
|
|
25
|
+
* inputs without at least a header and one data row.
|
|
26
|
+
*
|
|
27
|
+
* @param csvText - Raw CSV text
|
|
28
|
+
* @returns Parsed rows (empty array if header-only or empty)
|
|
29
|
+
*/
|
|
30
|
+
export declare function parseCSV(csvText: string): CSVRow[];
|
|
31
|
+
/**
|
|
32
|
+
* Join a base URL with a relative path using exactly one slash between them.
|
|
33
|
+
*
|
|
34
|
+
* Tolerant of base URLs that omit the trailing slash and of paths that include
|
|
35
|
+
* a leading slash — both common foot-guns when callers concatenate URL strings
|
|
36
|
+
* by hand. Empty inputs are passed through: an empty `base` returns `path`
|
|
37
|
+
* unchanged, and an empty `path` returns `base` unchanged (useful for directory
|
|
38
|
+
* listings or when the path is computed conditionally).
|
|
39
|
+
*
|
|
40
|
+
* @param base - Base URL (with or without trailing slash); empty string returns `path` as-is
|
|
41
|
+
* @param path - Relative path (with or without leading slash); empty string returns `base` as-is
|
|
42
|
+
* @returns The two segments joined by exactly one `/`, or whichever input is non-empty when one is empty
|
|
43
|
+
*/
|
|
44
|
+
export declare function joinURL(base: string, path: string): string;
|
|
45
|
+
/**
|
|
46
|
+
* Load a CSV with local-first fallback.
|
|
47
|
+
*
|
|
48
|
+
* Tries `joinURL(csvBaseURL, localPath)` first. If the response is non-OK or
|
|
49
|
+
* yields zero rows, falls back to `joinURL(fallbackURL, fallbackPath ?? localPath)`
|
|
50
|
+
* when a `fallbackURL` is provided. Network errors are logged as warnings
|
|
51
|
+
* rather than thrown so the page can degrade gracefully when offline.
|
|
52
|
+
*
|
|
53
|
+
* URL joining is tolerant of missing trailing slashes on the base URL and
|
|
54
|
+
* leading slashes on the path; callers do not need to worry about the slash
|
|
55
|
+
* boundary.
|
|
56
|
+
*
|
|
57
|
+
* @param csvBaseURL - Base URL for the local-first CSV directory
|
|
58
|
+
* @param fallbackURL - Optional remote fallback URL (e.g. raw.githubusercontent.com mirror); empty string disables fallback
|
|
59
|
+
* @param localPath - Path relative to `csvBaseURL`
|
|
60
|
+
* @param fallbackPath - Optional path on the fallback host (defaults to `localPath`)
|
|
61
|
+
* @returns Parsed CSV rows; `[]` when no source returned data
|
|
62
|
+
*/
|
|
63
|
+
export declare function loadCSV(csvBaseURL: string, fallbackURL: string, localPath: string, fallbackPath?: string): Promise<CSVRow[]>;
|
|
64
|
+
/**
|
|
65
|
+
* Build a `LoadCSV` closure bound to a `csvBaseURL` / `fallbackURL` pair.
|
|
66
|
+
*
|
|
67
|
+
* Per-domain loaders accept this closure so they can be unit-tested without
|
|
68
|
+
* any reference to the URL configuration of a specific environment.
|
|
69
|
+
*
|
|
70
|
+
* @param csvBaseURL - Base URL for the local-first CSV directory
|
|
71
|
+
* @param fallbackURL - Optional remote fallback URL (empty string disables fallback)
|
|
72
|
+
* @returns A `LoadCSV` function bound to those URLs
|
|
73
|
+
*/
|
|
74
|
+
export declare function createLoadCSV(csvBaseURL: string, fallbackURL?: string): LoadCSV;
|
|
75
|
+
//# sourceMappingURL=csv-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csv-utils.d.ts","sourceRoot":"","sources":["../../../src/browser/cia/csv-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAGzC,4EAA4E;AAC5E,MAAM,MAAM,OAAO,GAAG,CACpB,SAAS,EAAE,MAAM,EACjB,YAAY,CAAC,EAAE,MAAM,KAClB,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;AAEvB;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAqBlD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,OAAO,CAC3B,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,EAAE,CAAC,CAqBnB;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,SAAK,GAAG,OAAO,CAG3E"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module CIA/CSVUtils
|
|
3
|
+
* @category Intelligence Platform - Data Acquisition & Pipeline Management
|
|
4
|
+
*
|
|
5
|
+
* @description
|
|
6
|
+
* CSV parsing and HTTP loading helpers for the CIA data pipeline.
|
|
7
|
+
*
|
|
8
|
+
* Originally lived as private/public methods on `CIADataLoader`; extracted as
|
|
9
|
+
* free functions so each per-domain loader (`loaders/*.ts`) can use them
|
|
10
|
+
* directly without instantiating the orchestrator class. Mockable in tests
|
|
11
|
+
* by stubbing `globalThis.fetch`.
|
|
12
|
+
*
|
|
13
|
+
* @author Hack23 AB - Data Pipeline Engineering
|
|
14
|
+
* @license Apache-2.0
|
|
15
|
+
* @since 2026
|
|
16
|
+
*/
|
|
17
|
+
import Papa from 'papaparse';
|
|
18
|
+
/**
|
|
19
|
+
* Parse CSV text into an array of header-keyed rows with auto-typed values.
|
|
20
|
+
*
|
|
21
|
+
* Handles basic quoting (`"value, with, commas"`) and converts numeric strings
|
|
22
|
+
* to numbers. Empty cells are kept as the empty string. Returns `[]` for
|
|
23
|
+
* inputs without at least a header and one data row.
|
|
24
|
+
*
|
|
25
|
+
* @param csvText - Raw CSV text
|
|
26
|
+
* @returns Parsed rows (empty array if header-only or empty)
|
|
27
|
+
*/
|
|
28
|
+
export function parseCSV(csvText) {
|
|
29
|
+
const trimmed = csvText.trim();
|
|
30
|
+
if (!trimmed || !trimmed.includes('\n'))
|
|
31
|
+
return [];
|
|
32
|
+
const parsed = Papa.parse(trimmed, {
|
|
33
|
+
header: true,
|
|
34
|
+
dynamicTyping: true,
|
|
35
|
+
skipEmptyLines: true,
|
|
36
|
+
transformHeader: header => header.trim().replace(/^"|"$/g, ''),
|
|
37
|
+
});
|
|
38
|
+
if (parsed.errors.length > 0) {
|
|
39
|
+
const errorSummary = parsed.errors
|
|
40
|
+
.map(error => `${error.code} at row ${error.row ?? 'unknown'}: ${error.message}`)
|
|
41
|
+
.join('; ');
|
|
42
|
+
throw new Error(`CSV parse error: ${errorSummary}`);
|
|
43
|
+
}
|
|
44
|
+
return parsed.data.filter(row => Object.values(row).some(value => value !== null && value !== undefined && value !== ''));
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Join a base URL with a relative path using exactly one slash between them.
|
|
48
|
+
*
|
|
49
|
+
* Tolerant of base URLs that omit the trailing slash and of paths that include
|
|
50
|
+
* a leading slash — both common foot-guns when callers concatenate URL strings
|
|
51
|
+
* by hand. Empty inputs are passed through: an empty `base` returns `path`
|
|
52
|
+
* unchanged, and an empty `path` returns `base` unchanged (useful for directory
|
|
53
|
+
* listings or when the path is computed conditionally).
|
|
54
|
+
*
|
|
55
|
+
* @param base - Base URL (with or without trailing slash); empty string returns `path` as-is
|
|
56
|
+
* @param path - Relative path (with or without leading slash); empty string returns `base` as-is
|
|
57
|
+
* @returns The two segments joined by exactly one `/`, or whichever input is non-empty when one is empty
|
|
58
|
+
*/
|
|
59
|
+
export function joinURL(base, path) {
|
|
60
|
+
if (!base)
|
|
61
|
+
return path;
|
|
62
|
+
if (!path)
|
|
63
|
+
return base;
|
|
64
|
+
const trimmedBase = base.replace(/\/+$/, '');
|
|
65
|
+
const trimmedPath = path.replace(/^\/+/, '');
|
|
66
|
+
return `${trimmedBase}/${trimmedPath}`;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Load a CSV with local-first fallback.
|
|
70
|
+
*
|
|
71
|
+
* Tries `joinURL(csvBaseURL, localPath)` first. If the response is non-OK or
|
|
72
|
+
* yields zero rows, falls back to `joinURL(fallbackURL, fallbackPath ?? localPath)`
|
|
73
|
+
* when a `fallbackURL` is provided. Network errors are logged as warnings
|
|
74
|
+
* rather than thrown so the page can degrade gracefully when offline.
|
|
75
|
+
*
|
|
76
|
+
* URL joining is tolerant of missing trailing slashes on the base URL and
|
|
77
|
+
* leading slashes on the path; callers do not need to worry about the slash
|
|
78
|
+
* boundary.
|
|
79
|
+
*
|
|
80
|
+
* @param csvBaseURL - Base URL for the local-first CSV directory
|
|
81
|
+
* @param fallbackURL - Optional remote fallback URL (e.g. raw.githubusercontent.com mirror); empty string disables fallback
|
|
82
|
+
* @param localPath - Path relative to `csvBaseURL`
|
|
83
|
+
* @param fallbackPath - Optional path on the fallback host (defaults to `localPath`)
|
|
84
|
+
* @returns Parsed CSV rows; `[]` when no source returned data
|
|
85
|
+
*/
|
|
86
|
+
export async function loadCSV(csvBaseURL, fallbackURL, localPath, fallbackPath) {
|
|
87
|
+
const urls = [joinURL(csvBaseURL, localPath)];
|
|
88
|
+
if (fallbackURL) {
|
|
89
|
+
urls.push(joinURL(fallbackURL, fallbackPath ?? localPath));
|
|
90
|
+
}
|
|
91
|
+
for (const url of urls) {
|
|
92
|
+
try {
|
|
93
|
+
const response = await fetch(url);
|
|
94
|
+
if (!response.ok)
|
|
95
|
+
continue;
|
|
96
|
+
const text = await response.text();
|
|
97
|
+
const rows = parseCSV(text);
|
|
98
|
+
if (rows.length > 0)
|
|
99
|
+
return rows;
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
103
|
+
console.warn(`Failed to load CSV from ${url}:`, message);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
console.warn(`No data loaded for ${localPath}`);
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Build a `LoadCSV` closure bound to a `csvBaseURL` / `fallbackURL` pair.
|
|
111
|
+
*
|
|
112
|
+
* Per-domain loaders accept this closure so they can be unit-tested without
|
|
113
|
+
* any reference to the URL configuration of a specific environment.
|
|
114
|
+
*
|
|
115
|
+
* @param csvBaseURL - Base URL for the local-first CSV directory
|
|
116
|
+
* @param fallbackURL - Optional remote fallback URL (empty string disables fallback)
|
|
117
|
+
* @returns A `LoadCSV` function bound to those URLs
|
|
118
|
+
*/
|
|
119
|
+
export function createLoadCSV(csvBaseURL, fallbackURL = '') {
|
|
120
|
+
return (localPath, fallbackPath) => loadCSV(csvBaseURL, fallbackURL, localPath, fallbackPath);
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=csv-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csv-utils.js","sourceRoot":"","sources":["../../../src/browser/cia/csv-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -22,5 +22,5 @@
|
|
|
22
22
|
*
|
|
23
23
|
* @marketing First-load experience quality — dashboard initialization speed and reliability determine first-impression quality for new users. Time to Interactive (< 3s target) is critical for conversion from landing page visitor to engaged user. Loading state UX affects bounce rate.
|
|
24
24
|
* */
|
|
25
|
-
export
|
|
25
|
+
export declare function startDashboard(): void;
|
|
26
26
|
//# sourceMappingURL=dashboard-init.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashboard-init.d.ts","sourceRoot":"","sources":["../../../src/browser/cia/dashboard-init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;KAuBK"}
|
|
1
|
+
{"version":3,"file":"dashboard-init.d.ts","sourceRoot":"","sources":["../../../src/browser/cia/dashboard-init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;KAuBK;AAwFL,wBAAgB,cAAc,IAAI,IAAI,CAMrC"}
|
|
@@ -98,11 +98,12 @@ async function initDashboard() {
|
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
|
-
|
|
102
|
-
if (document.readyState === 'loading') {
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
|
|
101
|
+
export function startDashboard() {
|
|
102
|
+
if (document.readyState === 'loading') {
|
|
103
|
+
document.addEventListener('DOMContentLoaded', () => void initDashboard());
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
void initDashboard();
|
|
107
|
+
}
|
|
107
108
|
}
|
|
108
109
|
//# sourceMappingURL=dashboard-init.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashboard-init.js","sourceRoot":"","sources":["../../../src/browser/cia/dashboard-init.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"dashboard-init.js","sourceRoot":"","sources":["../../../src/browser/cia/dashboard-init.ts"],"names":[],"mappings":"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"}
|