signalk-charts-provider-simple 2.7.1 → 2.8.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.
Files changed (77) hide show
  1. package/README.md +11 -2
  2. package/dist/catalog/build-merged-catalog.d.ts +85 -0
  3. package/dist/catalog/build-merged-catalog.d.ts.map +1 -0
  4. package/dist/catalog/build-merged-catalog.js +210 -0
  5. package/dist/catalog/build-merged-catalog.js.map +1 -0
  6. package/dist/catalog/chartcatalogs-xml.d.ts +17 -0
  7. package/dist/catalog/chartcatalogs-xml.d.ts.map +1 -0
  8. package/dist/catalog/chartcatalogs-xml.js +53 -0
  9. package/dist/catalog/chartcatalogs-xml.js.map +1 -0
  10. package/dist/catalog/merged-catalog-schema.d.ts +321 -0
  11. package/dist/catalog/merged-catalog-schema.d.ts.map +1 -0
  12. package/dist/catalog/merged-catalog-schema.js +336 -0
  13. package/dist/catalog/merged-catalog-schema.js.map +1 -0
  14. package/dist/charts-loader.d.ts +6 -1
  15. package/dist/charts-loader.d.ts.map +1 -1
  16. package/dist/charts-loader.js +30 -5
  17. package/dist/charts-loader.js.map +1 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +332 -62
  20. package/dist/index.js.map +1 -1
  21. package/dist/types.d.ts +34 -8
  22. package/dist/types.d.ts.map +1 -1
  23. package/dist/utils/catalog-manager.d.ts +60 -5
  24. package/dist/utils/catalog-manager.d.ts.map +1 -1
  25. package/dist/utils/catalog-manager.js +324 -348
  26. package/dist/utils/catalog-manager.js.map +1 -1
  27. package/dist/utils/catalog-schemas.d.ts +7 -24
  28. package/dist/utils/catalog-schemas.d.ts.map +1 -1
  29. package/dist/utils/catalog-schemas.js +7 -22
  30. package/dist/utils/catalog-schemas.js.map +1 -1
  31. package/dist/utils/file-scanner.d.ts.map +1 -1
  32. package/dist/utils/file-scanner.js +20 -0
  33. package/dist/utils/file-scanner.js.map +1 -1
  34. package/dist/utils/mbtiles-reader.d.ts +31 -0
  35. package/dist/utils/mbtiles-reader.d.ts.map +1 -1
  36. package/dist/utils/mbtiles-reader.js +94 -3
  37. package/dist/utils/mbtiles-reader.js.map +1 -1
  38. package/dist/utils/online-charts.d.ts +63 -0
  39. package/dist/utils/online-charts.d.ts.map +1 -0
  40. package/dist/utils/online-charts.js +209 -0
  41. package/dist/utils/online-charts.js.map +1 -0
  42. package/dist/utils/raster-compose.d.ts +34 -0
  43. package/dist/utils/raster-compose.d.ts.map +1 -0
  44. package/dist/utils/raster-compose.js +126 -0
  45. package/dist/utils/raster-compose.js.map +1 -0
  46. package/dist/utils/raster-overzoom-worker.d.ts +10 -0
  47. package/dist/utils/raster-overzoom-worker.d.ts.map +1 -0
  48. package/dist/utils/raster-overzoom-worker.js +15 -0
  49. package/dist/utils/raster-overzoom-worker.js.map +1 -0
  50. package/dist/utils/raster-overzoom.d.ts +31 -0
  51. package/dist/utils/raster-overzoom.d.ts.map +1 -0
  52. package/dist/utils/raster-overzoom.js +155 -0
  53. package/dist/utils/raster-overzoom.js.map +1 -0
  54. package/dist/utils/tile-overzoom.d.ts +9 -0
  55. package/dist/utils/tile-overzoom.d.ts.map +1 -1
  56. package/dist/utils/tile-overzoom.js +1 -1
  57. package/dist/utils/tile-overzoom.js.map +1 -1
  58. package/dist/utils/time-dimension.d.ts +82 -0
  59. package/dist/utils/time-dimension.d.ts.map +1 -0
  60. package/dist/utils/time-dimension.js +240 -0
  61. package/dist/utils/time-dimension.js.map +1 -0
  62. package/dist/utils/time-poller.d.ts +54 -0
  63. package/dist/utils/time-poller.d.ts.map +1 -0
  64. package/dist/utils/time-poller.js +170 -0
  65. package/dist/utils/time-poller.js.map +1 -0
  66. package/dist/utils/vessel-position.d.ts +13 -0
  67. package/dist/utils/vessel-position.d.ts.map +1 -0
  68. package/dist/utils/vessel-position.js +22 -0
  69. package/dist/utils/vessel-position.js.map +1 -0
  70. package/package.json +8 -2
  71. package/public/css/chart-catalog.css +120 -11
  72. package/public/css/manage-charts.css +17 -0
  73. package/public/js/chart-catalog.js +551 -102
  74. package/public/js/chart-catalog.ts +695 -114
  75. package/public/js/globals.d.ts +1 -1
  76. package/public/js/manage-charts-enhanced.js +79 -13
  77. package/public/js/manage-charts-enhanced.ts +95 -13
package/README.md CHANGED
@@ -8,6 +8,7 @@ A lightweight Signal K server plugin for managing local nautical charts, written
8
8
  - **Folder Groups**: Enable/disable whole chart folders at once (OpenCPN-style groups, including nested folders); clients like Freeboard-SK see the change live via `resources.charts` deltas
9
9
  - **Download Manager**: Built-in download queue with progress tracking and ZIP extraction
10
10
  - **Chart Catalog**: Browse and download charts from [chartcatalogs.github.io](https://chartcatalogs.github.io/) with automatic update notifications
11
+ - **Online Charts**: Add weather radar and satellite, online nautical charts, depth layers and base maps from the Chart Catalog with one click — no download, no conversion
11
12
  - **NOAA Charts**: Draw a coverage region on a map from NOAA band-4 chart footprints; the plugin bundles the overlapping band-3/4/5 ENCs and converts them into a single vector MBTiles named after your chart set
12
13
  - **S-57 ENC Conversion**: Convert IENC/ENC charts to vector MBTiles with full S-52 symbology in Freeboard-SK
13
14
  - **BSB Raster Conversion**: Convert BSB/KAP raster charts and Pilot Charts to raster MBTiles
@@ -88,11 +89,13 @@ The interface provides five tabs:
88
89
  - Live conversion progress with log viewer
89
90
 
90
91
  4. **Chart Catalog**:
91
- - Dynamic catalog from [chartcatalogs.github.io](https://chartcatalogs.github.io/)
92
+ - Downloadable charts from [chartcatalogs.github.io](https://chartcatalogs.github.io/) and a curated list of online charts, in one list, sectioned by what the charts show, with **Near me** narrowing each section to where you are
93
+ - **Online charts** (weather radar and satellite, online nautical charts, depths, base maps): press **Add** and the chart appears in Manage Charts and in your chart plotter. They stream from their provider, so they need an internet connection to display. They go into an "Online Charts" folder by default, so you can switch them all off at once when you're offline
94
+ - Live weather layers (radar, satellite, forecasts) keep their recent images or forecast steps up to date, so chart plotters with a time slider (Freeboard-SK) can play them back
92
95
  - One-click download for MBTiles charts (NOAA)
93
96
  - Download & convert for S-57 ENC, BSB raster, Pilot Charts, and basemaps
94
97
  - Automatic update notifications (Signal K delta + tab badge)
95
- - Category filtering (MBTiles / RNC / IENC / General)
98
+ - Filters: **Download** (works offline) or **Stream** (needs internet); what the chart shows (Navigation, Weather, Depth & Seabed, Base maps, Overlays); chart type under "More filters"; and **Near me**, using the boat's position
96
99
 
97
100
  5. **NOAA Charts**:
98
101
  - Build a named **chart set** of NOAA ENC coverage by clicking band-4 footprints on a map (Leaflet + OpenSeaMap)
@@ -186,6 +189,12 @@ Inspired by [Signal K Charts Plugin](https://github.com/SignalK/charts-plugin) b
186
189
 
187
190
  Contributions are welcome! Please feel free to submit a Pull Request.
188
191
 
192
+ **Online charts in the Chart Catalog** are curated in this repository. To add or fix one, see
193
+ [Maintaining the catalog](docs/chart-catalog.md#maintaining-the-catalog). If you know a good
194
+ free service but don't want to write the entry yourself, open a
195
+ [Suggest an online chart](https://github.com/dirkwa/signalk-charts-provider-simple/issues/new?template=suggest-online-chart.yml)
196
+ issue.
197
+
189
198
  ## Support
190
199
 
191
200
  For issues and feature requests:
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Pure assembly of the merged chart catalog. File and network access live
3
+ * in `publish-catalog-cli.ts`; everything here is deterministic so it can be
4
+ * unit-tested and so an unchanged input always yields the same content hash.
5
+ */
6
+ import type { ParsedChartcatalogsXml } from './chartcatalogs-xml.js';
7
+ import { type ChartcatalogsIndex, type MergedCatalog, type MergedChartcatalogsCatalog, type OnlineChartsSourceFile } from './merged-catalog-schema.js';
8
+ export declare const CHARTCATALOGS_HOMEPAGE = "https://chartcatalogs.github.io/";
9
+ export declare const CHARTCATALOGS_ISSUES = "https://github.com/chartcatalogs/catalogs/issues";
10
+ export interface ChartcatalogsFile {
11
+ file: string;
12
+ /** `null` when the file exists upstream but could not be parsed. */
13
+ parsed: ParsedChartcatalogsXml | null;
14
+ }
15
+ export interface BuildInputs {
16
+ chartcatalogs: ChartcatalogsFile[];
17
+ chartcatalogsCommit?: string;
18
+ index: ChartcatalogsIndex;
19
+ online: OnlineChartsSourceFile;
20
+ /** `owner/name` of the repo publishing the catalog; issue links point here. */
21
+ repo: string;
22
+ /** chartcatalogs entries from the catalog currently published, by file. */
23
+ previous?: Map<string, MergedChartcatalogsCatalog>;
24
+ now: Date;
25
+ }
26
+ export interface BuildResult {
27
+ catalog: MergedCatalog;
28
+ /** chartcatalogs files with no entry in the index yet. */
29
+ unindexed: string[];
30
+ /** Index entries whose file chartcatalogs no longer has. */
31
+ staleIndexEntries: string[];
32
+ /** Files that failed to parse or came back empty, kept from the published catalog. */
33
+ carriedForward: string[];
34
+ /** Files that failed to parse and had nothing published to fall back on. */
35
+ skipped: string[];
36
+ /** Charts dropped because their download location is not an http(s) URL. */
37
+ droppedCharts: string[];
38
+ /**
39
+ * Published catalogs whose file chartcatalogs no longer has. They leave
40
+ * the catalog (the file may really have been withdrawn), but the drop
41
+ * guard tolerates a few, so each one is reported.
42
+ */
43
+ removedUpstream: string[];
44
+ }
45
+ /**
46
+ * Hash of what a user would actually see. chartcatalogs re-commits every
47
+ * hour just to refresh its header dates, so those dates, the upstream
48
+ * commit id and our own `generatedAt` are excluded by name; anything else,
49
+ * including fields added later, is hashed.
50
+ */
51
+ export declare function computeContentHash(catalog: Omit<MergedCatalog, 'contentHash'>): string;
52
+ export declare function buildMergedCatalog(inputs: BuildInputs): BuildResult;
53
+ /** What the drop guard and change detection need to know about the live catalog. */
54
+ export interface PublishedState {
55
+ contentHash: string | null;
56
+ catalogCount: number;
57
+ chartCount: number;
58
+ /** chartcatalogs entries that still validate, for carrying forward. */
59
+ chartcatalogs: Map<string, MergedChartcatalogsCatalog>;
60
+ /** The published `catalog.schema.json` text, or null if absent. */
61
+ schemaText: string | null;
62
+ }
63
+ /**
64
+ * Read the published catalog loosely. It may predate the current schema
65
+ * (that is exactly when a build change is riskiest), so the counts the drop
66
+ * guard relies on are taken from the raw arrays rather than a full parse.
67
+ */
68
+ export declare function readPublishedState(raw: unknown, schemaText: string | null): PublishedState;
69
+ /**
70
+ * Reasons not to replace the published catalog with `next`. Per-file
71
+ * breakage is absorbed by carrying entries forward; these thresholds catch
72
+ * whole-source failures such as a truncated clone.
73
+ */
74
+ export declare function publishBlockers(next: MergedCatalog, published: PublishedState | null): string[];
75
+ export interface PublishDecision {
76
+ publish: boolean;
77
+ blockers: string[];
78
+ }
79
+ /**
80
+ * Whether to deploy. The site also carries the JSON Schema, so a schema
81
+ * change with identical content must still deploy, or third parties would
82
+ * keep validating against a stale schema.
83
+ */
84
+ export declare function decidePublish(next: MergedCatalog, published: PublishedState | null, schemaText: string, force: boolean): PublishDecision;
85
+ //# sourceMappingURL=build-merged-catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-merged-catalog.d.ts","sourceRoot":"","sources":["../../src/catalog/build-merged-catalog.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAQL,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAElB,KAAK,0BAA0B,EAE/B,KAAK,sBAAsB,EAC5B,MAAM,4BAA4B,CAAC;AAEpC,eAAO,MAAM,sBAAsB,qCAAqC,CAAC;AACzE,eAAO,MAAM,oBAAoB,qDAAqD,CAAC;AAEvF,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,MAAM,EAAE,sBAAsB,GAAG,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,iBAAiB,EAAE,CAAC;IACnC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,KAAK,EAAE,kBAAkB,CAAC;IAC1B,MAAM,EAAE,sBAAsB,CAAC;IAC/B,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAC;IACnD,GAAG,EAAE,IAAI,CAAC;CACX;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,aAAa,CAAC;IACvB,0DAA0D;IAC1D,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,4DAA4D;IAC5D,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,sFAAsF;IACtF,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,4EAA4E;IAC5E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,4EAA4E;IAC5E,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB;;;;OAIG;IACH,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAkED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,aAAa,CAAC,GAAG,MAAM,CAYtF;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,CAoEnE;AAED,oFAAoF;AACpF,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAC;IACvD,mEAAmE;IACnE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,cAAc,CAmB1F;AAMD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,cAAc,GAAG,IAAI,GAAG,MAAM,EAAE,CAuB/F;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,aAAa,EACnB,SAAS,EAAE,cAAc,GAAG,IAAI,EAChC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,OAAO,GACb,eAAe,CAKjB"}
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Pure assembly of the merged chart catalog. File and network access live
3
+ * in `publish-catalog-cli.ts`; everything here is deterministic so it can be
4
+ * unit-tested and so an unchanged input always yields the same content hash.
5
+ */
6
+ import { createHash } from 'node:crypto';
7
+ import { Value } from '@sinclair/typebox/value';
8
+ import { MERGED_CATALOG_SCHEMA_VERSION, MergedCatalogSchema, MergedChartcatalogsCatalogSchema, checkChartcatalogsIndex, checkOnlineChartEntry, formatForChartType, schemaErrors } from './merged-catalog-schema.js';
9
+ export const CHARTCATALOGS_HOMEPAGE = 'https://chartcatalogs.github.io/';
10
+ export const CHARTCATALOGS_ISSUES = 'https://github.com/chartcatalogs/catalogs/issues';
11
+ function compareStrings(a, b) {
12
+ return a < b ? -1 : a > b ? 1 : 0;
13
+ }
14
+ function mergeChartcatalogsFile(file, parsed, index, droppedCharts) {
15
+ const id = file.replace(/\.xml$/i, '');
16
+ // One odd upstream URL must not fail the whole build (the schema would
17
+ // reject the catalog), so bad charts are dropped here and reported.
18
+ const charts = parsed.charts.filter((chart) => {
19
+ const ok = /^https?:\/\//.test(chart.zipfile_location);
20
+ if (!ok) {
21
+ droppedCharts.push(`${file} ${chart.number}`);
22
+ }
23
+ return ok;
24
+ });
25
+ const base = { id, file, use: 'download', header: parsed.header, charts };
26
+ const facets = index[file];
27
+ if (facets) {
28
+ return { ...base, ...facets, indexed: true };
29
+ }
30
+ // Nearly every chartcatalogs catalog is a navigation chart set, so that is
31
+ // the safest default until someone adds the file to the index.
32
+ return { ...base, label: parsed.header.title || id, category: 'navigation', indexed: false };
33
+ }
34
+ function mergeOnlineCharts(online) {
35
+ const problems = [];
36
+ const seen = new Set();
37
+ for (const entry of online.charts) {
38
+ if (seen.has(entry.id)) {
39
+ problems.push(`${entry.id}: duplicate id`);
40
+ }
41
+ seen.add(entry.id);
42
+ problems.push(...checkOnlineChartEntry(entry));
43
+ }
44
+ if (problems.length > 0) {
45
+ throw new Error(`Invalid online chart entries:\n ${problems.join('\n ')}`);
46
+ }
47
+ return online.charts.map((entry) => ({
48
+ ...entry,
49
+ use: 'stream',
50
+ format: formatForChartType(entry.chart.type)
51
+ }));
52
+ }
53
+ /** JSON with object keys sorted, so key order never changes the hash. */
54
+ function canonicalJson(value) {
55
+ if (Array.isArray(value)) {
56
+ return `[${value.map(canonicalJson).join(',')}]`;
57
+ }
58
+ if (value !== null && typeof value === 'object') {
59
+ const entries = Object.entries(value)
60
+ .filter(([, v]) => v !== undefined)
61
+ .sort(([a], [b]) => compareStrings(a, b));
62
+ return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${canonicalJson(v)}`).join(',')}}`;
63
+ }
64
+ return JSON.stringify(value);
65
+ }
66
+ /**
67
+ * Hash of what a user would actually see. chartcatalogs re-commits every
68
+ * hour just to refresh its header dates, so those dates, the upstream
69
+ * commit id and our own `generatedAt` are excluded by name; anything else,
70
+ * including fields added later, is hashed.
71
+ */
72
+ export function computeContentHash(catalog) {
73
+ const { generatedAt: _generatedAt, ...content } = catalog;
74
+ const { commit: _commit, ...chartcatalogsSource } = content.sources.chartcatalogs;
75
+ const hashed = {
76
+ ...content,
77
+ sources: { ...content.sources, chartcatalogs: chartcatalogsSource },
78
+ chartcatalogs: content.chartcatalogs.map((c) => {
79
+ const { dateCreated: _created, dateValid: _valid, ...header } = c.header;
80
+ return { ...c, header };
81
+ })
82
+ };
83
+ return createHash('sha256').update(canonicalJson(hashed)).digest('hex');
84
+ }
85
+ export function buildMergedCatalog(inputs) {
86
+ const indexProblems = checkChartcatalogsIndex(inputs.index);
87
+ if (indexProblems.length > 0) {
88
+ throw new Error(`Invalid chartcatalogs index:\n ${indexProblems.join('\n ')}`);
89
+ }
90
+ const files = [...inputs.chartcatalogs].sort((a, b) => compareStrings(a.file, b.file));
91
+ const carriedForward = [];
92
+ const skipped = [];
93
+ const droppedCharts = [];
94
+ const chartcatalogs = [];
95
+ for (const { file, parsed } of files) {
96
+ const previous = inputs.previous?.get(file);
97
+ // A file that still exists upstream but is broken or suddenly empty is
98
+ // far more likely an upstream mistake than a withdrawn catalog, so keep
99
+ // what users can see today rather than wiping it from every plugin.
100
+ if (previous && (!parsed || parsed.charts.length === 0)) {
101
+ const facets = inputs.index[file];
102
+ chartcatalogs.push(facets ? { ...previous, ...facets, indexed: true } : previous);
103
+ carriedForward.push(file);
104
+ continue;
105
+ }
106
+ if (!parsed) {
107
+ skipped.push(file);
108
+ continue;
109
+ }
110
+ chartcatalogs.push(mergeChartcatalogsFile(file, parsed, inputs.index, droppedCharts));
111
+ }
112
+ const fileNames = new Set(files.map((f) => f.file));
113
+ const withoutHash = {
114
+ schemaVersion: MERGED_CATALOG_SCHEMA_VERSION,
115
+ generatedAt: inputs.now.toISOString(),
116
+ sources: {
117
+ chartcatalogs: {
118
+ homepage: CHARTCATALOGS_HOMEPAGE,
119
+ issues: CHARTCATALOGS_ISSUES,
120
+ license: 'CC0-1.0',
121
+ ...(inputs.chartcatalogsCommit ? { commit: inputs.chartcatalogsCommit } : {})
122
+ },
123
+ online: {
124
+ homepage: `https://github.com/${inputs.repo}`,
125
+ issues: `https://github.com/${inputs.repo}/issues/new?template=catalog-problem.yml`
126
+ }
127
+ },
128
+ chartcatalogs,
129
+ online: mergeOnlineCharts(inputs.online)
130
+ };
131
+ const catalog = { ...withoutHash, contentHash: computeContentHash(withoutHash) };
132
+ if (!Value.Check(MergedCatalogSchema, catalog)) {
133
+ throw new Error(`Merged catalog failed validation:\n ${schemaErrors(MergedCatalogSchema, catalog).join('\n ')}`);
134
+ }
135
+ return {
136
+ catalog,
137
+ unindexed: chartcatalogs.filter((c) => !c.indexed).map((c) => c.file),
138
+ staleIndexEntries: Object.keys(inputs.index).filter((f) => !fileNames.has(f)),
139
+ carriedForward,
140
+ skipped,
141
+ droppedCharts,
142
+ removedUpstream: [...(inputs.previous?.keys() ?? [])]
143
+ .filter((f) => !fileNames.has(f))
144
+ .sort(compareStrings)
145
+ };
146
+ }
147
+ /**
148
+ * Read the published catalog loosely. It may predate the current schema
149
+ * (that is exactly when a build change is riskiest), so the counts the drop
150
+ * guard relies on are taken from the raw arrays rather than a full parse.
151
+ */
152
+ export function readPublishedState(raw, schemaText) {
153
+ const obj = raw !== null && typeof raw === 'object' ? raw : {};
154
+ const rawCatalogs = Array.isArray(obj.chartcatalogs) ? obj.chartcatalogs : [];
155
+ const chartcatalogs = new Map();
156
+ let chartCount = 0;
157
+ for (const entry of rawCatalogs) {
158
+ const charts = entry?.charts;
159
+ chartCount += Array.isArray(charts) ? charts.length : 0;
160
+ if (Value.Check(MergedChartcatalogsCatalogSchema, entry)) {
161
+ chartcatalogs.set(entry.file, entry);
162
+ }
163
+ }
164
+ return {
165
+ contentHash: typeof obj.contentHash === 'string' ? obj.contentHash : null,
166
+ catalogCount: rawCatalogs.length,
167
+ chartCount,
168
+ chartcatalogs,
169
+ schemaText
170
+ };
171
+ }
172
+ function chartCount(catalog) {
173
+ return catalog.chartcatalogs.reduce((n, c) => n + c.charts.length, 0);
174
+ }
175
+ /**
176
+ * Reasons not to replace the published catalog with `next`. Per-file
177
+ * breakage is absorbed by carrying entries forward; these thresholds catch
178
+ * whole-source failures such as a truncated clone.
179
+ */
180
+ export function publishBlockers(next, published) {
181
+ const blockers = [];
182
+ if (next.chartcatalogs.length === 0) {
183
+ blockers.push('no chartcatalogs catalogs were read');
184
+ }
185
+ if (next.online.length === 0) {
186
+ blockers.push('the online chart list is empty');
187
+ }
188
+ if (published) {
189
+ const after = next.chartcatalogs.length;
190
+ if (after < Math.floor(published.catalogCount * 0.8)) {
191
+ blockers.push(`chartcatalogs catalogs dropped from ${String(published.catalogCount)} to ${String(after)}`);
192
+ }
193
+ const chartsAfter = chartCount(next);
194
+ if (chartsAfter < Math.floor(published.chartCount * 0.5)) {
195
+ blockers.push(`chartcatalogs charts dropped from ${String(published.chartCount)} to ${String(chartsAfter)}`);
196
+ }
197
+ }
198
+ return blockers;
199
+ }
200
+ /**
201
+ * Whether to deploy. The site also carries the JSON Schema, so a schema
202
+ * change with identical content must still deploy, or third parties would
203
+ * keep validating against a stale schema.
204
+ */
205
+ export function decidePublish(next, published, schemaText, force) {
206
+ const blockers = publishBlockers(next, published);
207
+ const changed = !published || published.contentHash !== next.contentHash || published.schemaText !== schemaText;
208
+ return { publish: force || (changed && blockers.length === 0), blockers };
209
+ }
210
+ //# sourceMappingURL=build-merged-catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-merged-catalog.js","sourceRoot":"","sources":["../../src/catalog/build-merged-catalog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Parser for chartcatalogs.github.io catalog XML (the NOAA RNC product
3
+ * catalog subset used by OpenCPN). Shared by the plugin's catalog manager
4
+ * and the merged-catalog build so both read the files identically.
5
+ */
6
+ import type { CatalogChart, CatalogHeader } from '../utils/catalog-schemas.js';
7
+ export interface ParsedChartcatalogsXml {
8
+ header: CatalogHeader;
9
+ charts: CatalogChart[];
10
+ }
11
+ /**
12
+ * Parse one catalog file. Entries without a chart number or download
13
+ * location are dropped: they cannot be installed or tracked for updates.
14
+ * Throws when the document is not a chartcatalogs catalog at all.
15
+ */
16
+ export declare function parseChartcatalogsXml(xmlData: string): Promise<ParsedChartcatalogsXml>;
17
+ //# sourceMappingURL=chartcatalogs-xml.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chartcatalogs-xml.d.ts","sourceRoot":"","sources":["../../src/catalog/chartcatalogs-xml.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE/E,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB;AAeD;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAmC5F"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Parser for chartcatalogs.github.io catalog XML (the NOAA RNC product
3
+ * catalog subset used by OpenCPN). Shared by the plugin's catalog manager
4
+ * and the merged-catalog build so both read the files identically.
5
+ */
6
+ import { parseStringPromise } from 'xml2js';
7
+ // xml2js keeps element text verbatim, and some catalogs wrap values on
8
+ // their own lines (ACE_BUOY's zip URL is surrounded by newlines), which
9
+ // would otherwise reach the downloader as an invalid URL.
10
+ function text(node, ...names) {
11
+ for (const name of names) {
12
+ const value = node[name]?.[0];
13
+ if (typeof value === 'string') {
14
+ return value.trim();
15
+ }
16
+ }
17
+ return '';
18
+ }
19
+ /**
20
+ * Parse one catalog file. Entries without a chart number or download
21
+ * location are dropped: they cannot be installed or tracked for updates.
22
+ * Throws when the document is not a chartcatalogs catalog at all.
23
+ */
24
+ export async function parseChartcatalogsXml(xmlData) {
25
+ const result = await parseStringPromise(xmlData);
26
+ if (typeof result !== 'object' || result === null) {
27
+ throw new Error('Invalid XML parse result');
28
+ }
29
+ const parsed = result;
30
+ const root = (parsed.RncProductCatalogChartCatalogs ?? parsed.EncProductCatalogcellCatalogs);
31
+ if (!root) {
32
+ throw new Error('Unexpected XML root element');
33
+ }
34
+ const headerArr = root.Header;
35
+ const headerNode = headerArr?.[0] ?? {};
36
+ const header = {
37
+ title: text(headerNode, 'title'),
38
+ dateCreated: text(headerNode, 'date_created'),
39
+ dateValid: text(headerNode, 'date_valid')
40
+ };
41
+ const chartNodes = (root.chart ?? root.cell ?? []);
42
+ const charts = chartNodes
43
+ .map((node) => ({
44
+ number: text(node, 'number', 'name'),
45
+ title: text(node, 'title', 'lname'),
46
+ format: text(node, 'format'),
47
+ zipfile_location: text(node, 'zipfile_location'),
48
+ zipfile_datetime_iso8601: text(node, 'zipfile_datetime_iso8601')
49
+ }))
50
+ .filter((c) => c.number !== '' && c.zipfile_location !== '');
51
+ return { header, charts };
52
+ }
53
+ //# sourceMappingURL=chartcatalogs-xml.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chartcatalogs-xml.js","sourceRoot":"","sources":["../../src/catalog/chartcatalogs-xml.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAQ5C,uEAAuE;AACvE,wEAAwE;AACxE,0DAA0D;AAC1D,SAAS,IAAI,CAAC,IAA0C,EAAE,GAAG,KAAe;IAC1E,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9B,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;QACtB,CAAC;IACH,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,OAAe;IACzD,MAAM,MAAM,GAAY,MAAM,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAE1D,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,MAAM,GAAG,MAAiC,CAAC;IACjD,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,8BAA8B,IAAI,MAAM,CAAC,6BAA6B,CACtD,CAAC;IAEtC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACjD,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,MAA4D,CAAC;IACpF,MAAM,UAAU,GAAG,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACxC,MAAM,MAAM,GAAkB;QAC5B,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC;QAChC,WAAW,EAAE,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC;QAC7C,SAAS,EAAE,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC;KAC1C,CAAC;IAEF,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAA2C,CAAC;IAC7F,MAAM,MAAM,GAAmB,UAAU;SACtC,GAAG,CAAC,CAAC,IAAI,EAAgB,EAAE,CAAC,CAAC;QAC5B,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC;QACpC,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC;QACnC,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC;QAC5B,gBAAgB,EAAE,IAAI,CAAC,IAAI,EAAE,kBAAkB,CAAC;QAChD,wBAAwB,EAAE,IAAI,CAAC,IAAI,EAAE,0BAA0B,CAAC;KACjE,CAAC,CAAC;SACF,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,EAAE,IAAI,CAAC,CAAC,gBAAgB,KAAK,EAAE,CAAC,CAAC;IAE/D,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC5B,CAAC"}