neaps 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +157 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +367 -0
- package/dist/index.d.ts +367 -0
- package/dist/index.js +122 -0
- package/dist/index.js.map +1 -0
- package/package.json +34 -0
- package/src/index.ts +185 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
13
|
+
__defProp(to, key, {
|
|
14
|
+
get: ((k) => from[k]).bind(null, key),
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
23
|
+
value: mod,
|
|
24
|
+
enumerable: true
|
|
25
|
+
}) : target, mod));
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
let geolib = require("geolib");
|
|
29
|
+
let _neaps_tide_database = require("@neaps/tide-database");
|
|
30
|
+
_neaps_tide_database = __toESM(_neaps_tide_database);
|
|
31
|
+
let _neaps_tide_predictor = require("@neaps/tide-predictor");
|
|
32
|
+
_neaps_tide_predictor = __toESM(_neaps_tide_predictor);
|
|
33
|
+
|
|
34
|
+
//#region src/index.ts
|
|
35
|
+
/**
|
|
36
|
+
* Get extremes prediction using the nearest station to the given position.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* import { getExtremesPrediction } from 'neaps'
|
|
41
|
+
*
|
|
42
|
+
* const prediction = getExtremesPrediction({
|
|
43
|
+
* latitude: 26.7, // or `lat`
|
|
44
|
+
* longitude: -80.05, // or `lng` or `lon`
|
|
45
|
+
* start: new Date('2025-12-17'),
|
|
46
|
+
* end: new Date('2025-12-18'),
|
|
47
|
+
* datum: 'MLLW', // optional, defaults to MLLW if available
|
|
48
|
+
* })
|
|
49
|
+
*/
|
|
50
|
+
function getExtremesPrediction(options) {
|
|
51
|
+
return nearestStation(options).getExtremesPrediction(options);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get timeline prediction using the nearest station to the given position.
|
|
55
|
+
*/
|
|
56
|
+
function getTimelinePrediction(options) {
|
|
57
|
+
return nearestStation(options).getTimelinePrediction(options);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get water level at a specific time using the nearest station to the given position.
|
|
61
|
+
*/
|
|
62
|
+
function getWaterLevelAtTime(options) {
|
|
63
|
+
return nearestStation(options).getWaterLevelAtTime(options);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Find the nearest station to the given position.
|
|
67
|
+
*/
|
|
68
|
+
function nearestStation(position) {
|
|
69
|
+
return stationsNear(position, 1)[0];
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Find stations near the given position.
|
|
73
|
+
* @param limit Maximum number of stations to return (default: 10)
|
|
74
|
+
*/
|
|
75
|
+
function stationsNear(position, limit = 10) {
|
|
76
|
+
return _neaps_tide_database.default.map((station) => ({
|
|
77
|
+
station,
|
|
78
|
+
distance: (0, geolib.getDistance)(position, station)
|
|
79
|
+
})).sort((a, b) => a.distance - b.distance).slice(0, limit).map(({ station, distance }) => useStation(station, distance));
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Find a specific station by its ID or source ID.
|
|
83
|
+
*/
|
|
84
|
+
function findStation(query) {
|
|
85
|
+
const searches = [(s) => s.id === query, (s) => s.source.id === query];
|
|
86
|
+
let found = void 0;
|
|
87
|
+
for (const search of searches) {
|
|
88
|
+
found = _neaps_tide_database.default.find(search);
|
|
89
|
+
if (found) break;
|
|
90
|
+
}
|
|
91
|
+
if (!found) throw new Error(`Station not found: ${query}`);
|
|
92
|
+
return useStation(found);
|
|
93
|
+
}
|
|
94
|
+
function useStation(station, distance) {
|
|
95
|
+
let reference = station;
|
|
96
|
+
if (station.type === "subordinate") reference = findStation(station.offsets?.reference || "");
|
|
97
|
+
const { datums, harmonic_constituents } = reference;
|
|
98
|
+
const defaultDatum = "MLLW" in datums ? "MLLW" : void 0;
|
|
99
|
+
function getPredictor({ datum = defaultDatum } = {}) {
|
|
100
|
+
let offset = 0;
|
|
101
|
+
if (datum) {
|
|
102
|
+
const datumOffset = datums?.[datum];
|
|
103
|
+
const mslOffset = datums?.["MSL"];
|
|
104
|
+
if (typeof datumOffset !== "number") throw new Error(`Station ${station.id} missing ${datum} datum. Available datums: ${Object.keys(datums || {}).join(", ")}`);
|
|
105
|
+
if (typeof mslOffset !== "number") throw new Error(`Station ${station.id} missing MSL datum, so predictions can't be given in ${datum}.`);
|
|
106
|
+
offset = mslOffset - datumOffset;
|
|
107
|
+
}
|
|
108
|
+
return (0, _neaps_tide_predictor.default)(harmonic_constituents, {
|
|
109
|
+
phaseKey: "phase_UTC",
|
|
110
|
+
offset
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
...station,
|
|
115
|
+
distance,
|
|
116
|
+
datums,
|
|
117
|
+
harmonic_constituents,
|
|
118
|
+
defaultDatum,
|
|
119
|
+
getExtremesPrediction({ datum = defaultDatum, ...input }) {
|
|
120
|
+
return {
|
|
121
|
+
datum,
|
|
122
|
+
distance,
|
|
123
|
+
station,
|
|
124
|
+
extremes: getPredictor({ datum }).getExtremesPrediction({
|
|
125
|
+
...input,
|
|
126
|
+
offsets: station.offsets
|
|
127
|
+
})
|
|
128
|
+
};
|
|
129
|
+
},
|
|
130
|
+
getTimelinePrediction({ datum = defaultDatum, ...params }) {
|
|
131
|
+
if (station.type === "subordinate") throw new Error(`Timeline predictions are not supported for subordinate stations.`);
|
|
132
|
+
return {
|
|
133
|
+
datum,
|
|
134
|
+
station,
|
|
135
|
+
timeline: getPredictor({ datum }).getTimelinePrediction(params)
|
|
136
|
+
};
|
|
137
|
+
},
|
|
138
|
+
getWaterLevelAtTime({ time, datum = defaultDatum }) {
|
|
139
|
+
if (station.type === "subordinate") throw new Error(`Water level predictions are not supported for subordinate stations.`);
|
|
140
|
+
return {
|
|
141
|
+
datum,
|
|
142
|
+
station,
|
|
143
|
+
...getPredictor({ datum }).getWaterLevelAtTime({ time })
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
//#endregion
|
|
150
|
+
exports.findStation = findStation;
|
|
151
|
+
exports.getExtremesPrediction = getExtremesPrediction;
|
|
152
|
+
exports.getTimelinePrediction = getTimelinePrediction;
|
|
153
|
+
exports.getWaterLevelAtTime = getWaterLevelAtTime;
|
|
154
|
+
exports.nearestStation = nearestStation;
|
|
155
|
+
exports.stationsNear = stationsNear;
|
|
156
|
+
exports.useStation = useStation;
|
|
157
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["stations","found: Station | undefined"],"sources":["../src/index.ts"],"sourcesContent":["import { getDistance } from 'geolib'\nimport stations, { type Station } from '@neaps/tide-database'\nimport tidePredictor, {\n type TimeSpan,\n type ExtremesInput\n} from '@neaps/tide-predictor'\nimport type { GeolibInputCoordinates } from 'geolib/es/types'\n\ntype DatumOption = {\n /** Datum to return predictions in. Defaults to 'MLLW' if available for the nearest station. */\n datum?: string\n}\n\nexport type ExtremesOptions = ExtremesInput & DatumOption\nexport type TimelineOptions = TimeSpan & DatumOption\nexport type WaterLevelOptions = { time: Date } & DatumOption\n\n/**\n * Get extremes prediction using the nearest station to the given position.\n *\n * @example\n * ```ts\n * import { getExtremesPrediction } from 'neaps'\n *\n * const prediction = getExtremesPrediction({\n * latitude: 26.7, // or `lat`\n * longitude: -80.05, // or `lng` or `lon`\n * start: new Date('2025-12-17'),\n * end: new Date('2025-12-18'),\n * datum: 'MLLW', // optional, defaults to MLLW if available\n * })\n */\nexport function getExtremesPrediction(\n options: GeolibInputCoordinates & ExtremesOptions\n) {\n return nearestStation(options).getExtremesPrediction(options)\n}\n\n/**\n * Get timeline prediction using the nearest station to the given position.\n */\nexport function getTimelinePrediction(\n options: GeolibInputCoordinates & TimelineOptions\n) {\n return nearestStation(options).getTimelinePrediction(options)\n}\n\n/**\n * Get water level at a specific time using the nearest station to the given position.\n */\nexport function getWaterLevelAtTime(\n options: GeolibInputCoordinates & WaterLevelOptions\n) {\n return nearestStation(options).getWaterLevelAtTime(options)\n}\n\n/**\n * Find the nearest station to the given position.\n */\nexport function nearestStation(position: GeolibInputCoordinates) {\n return stationsNear(position, 1)[0]\n}\n\n/**\n * Find stations near the given position.\n * @param limit Maximum number of stations to return (default: 10)\n */\nexport function stationsNear(position: GeolibInputCoordinates, limit = 10) {\n return stations\n .map((station) => ({ station, distance: getDistance(position, station) }))\n .sort((a, b) => a.distance - b.distance)\n .slice(0, limit)\n .map(({ station, distance }) => useStation(station, distance))\n}\n\n/**\n * Find a specific station by its ID or source ID.\n */\nexport function findStation(query: string) {\n const searches = [\n (s: Station) => s.id === query,\n (s: Station) => s.source.id === query\n ]\n\n let found: Station | undefined = undefined\n\n for (const search of searches) {\n found = stations.find(search)\n if (found) break\n }\n\n if (!found) throw new Error(`Station not found: ${query}`)\n\n return useStation(found)\n}\n\nexport function useStation(station: Station, distance?: number) {\n // If subordinate station, use the reference station for datums and constituents\n let reference = station\n if (station.type === 'subordinate') {\n reference = findStation(station.offsets?.reference || '')\n }\n const { datums, harmonic_constituents } = reference\n\n // Use MLLW as the default datum if available\n const defaultDatum = 'MLLW' in datums ? 'MLLW' : undefined\n\n function getPredictor({ datum = defaultDatum }: DatumOption = {}) {\n let offset = 0\n\n if (datum) {\n const datumOffset = datums?.[datum]\n const mslOffset = datums?.['MSL']\n\n if (typeof datumOffset !== 'number') {\n throw new Error(\n `Station ${station.id} missing ${datum} datum. Available datums: ${Object.keys(datums || {}).join(', ')}`\n )\n }\n\n if (typeof mslOffset !== 'number') {\n throw new Error(\n `Station ${station.id} missing MSL datum, so predictions can't be given in ${datum}.`\n )\n }\n\n offset = mslOffset - datumOffset\n }\n\n return tidePredictor(harmonic_constituents, {\n phaseKey: 'phase_UTC',\n offset\n })\n }\n\n return {\n ...station,\n distance,\n datums,\n harmonic_constituents,\n defaultDatum,\n getExtremesPrediction({ datum = defaultDatum, ...input }: ExtremesOptions) {\n return {\n datum,\n distance,\n station,\n extremes: getPredictor({ datum }).getExtremesPrediction({\n ...input,\n offsets: station.offsets\n })\n }\n },\n\n getTimelinePrediction({\n datum = defaultDatum,\n ...params\n }: TimelineOptions) {\n if (station.type === 'subordinate') {\n throw new Error(\n `Timeline predictions are not supported for subordinate stations.`\n )\n }\n\n return {\n datum,\n station,\n timeline: getPredictor({ datum }).getTimelinePrediction(params)\n }\n },\n\n getWaterLevelAtTime({ time, datum = defaultDatum }: WaterLevelOptions) {\n if (station.type === 'subordinate') {\n throw new Error(\n `Water level predictions are not supported for subordinate stations.`\n )\n }\n\n return {\n datum,\n station,\n ...getPredictor({ datum }).getWaterLevelAtTime({ time })\n }\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,SAAgB,sBACd,SACA;AACA,QAAO,eAAe,QAAQ,CAAC,sBAAsB,QAAQ;;;;;AAM/D,SAAgB,sBACd,SACA;AACA,QAAO,eAAe,QAAQ,CAAC,sBAAsB,QAAQ;;;;;AAM/D,SAAgB,oBACd,SACA;AACA,QAAO,eAAe,QAAQ,CAAC,oBAAoB,QAAQ;;;;;AAM7D,SAAgB,eAAe,UAAkC;AAC/D,QAAO,aAAa,UAAU,EAAE,CAAC;;;;;;AAOnC,SAAgB,aAAa,UAAkC,QAAQ,IAAI;AACzE,QAAOA,6BACJ,KAAK,aAAa;EAAE;EAAS,kCAAsB,UAAU,QAAQ;EAAE,EAAE,CACzE,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,SAAS,CACvC,MAAM,GAAG,MAAM,CACf,KAAK,EAAE,SAAS,eAAe,WAAW,SAAS,SAAS,CAAC;;;;;AAMlE,SAAgB,YAAY,OAAe;CACzC,MAAM,WAAW,EACd,MAAe,EAAE,OAAO,QACxB,MAAe,EAAE,OAAO,OAAO,MACjC;CAED,IAAIC,QAA6B;AAEjC,MAAK,MAAM,UAAU,UAAU;AAC7B,UAAQD,6BAAS,KAAK,OAAO;AAC7B,MAAI,MAAO;;AAGb,KAAI,CAAC,MAAO,OAAM,IAAI,MAAM,sBAAsB,QAAQ;AAE1D,QAAO,WAAW,MAAM;;AAG1B,SAAgB,WAAW,SAAkB,UAAmB;CAE9D,IAAI,YAAY;AAChB,KAAI,QAAQ,SAAS,cACnB,aAAY,YAAY,QAAQ,SAAS,aAAa,GAAG;CAE3D,MAAM,EAAE,QAAQ,0BAA0B;CAG1C,MAAM,eAAe,UAAU,SAAS,SAAS;CAEjD,SAAS,aAAa,EAAE,QAAQ,iBAA8B,EAAE,EAAE;EAChE,IAAI,SAAS;AAEb,MAAI,OAAO;GACT,MAAM,cAAc,SAAS;GAC7B,MAAM,YAAY,SAAS;AAE3B,OAAI,OAAO,gBAAgB,SACzB,OAAM,IAAI,MACR,WAAW,QAAQ,GAAG,WAAW,MAAM,4BAA4B,OAAO,KAAK,UAAU,EAAE,CAAC,CAAC,KAAK,KAAK,GACxG;AAGH,OAAI,OAAO,cAAc,SACvB,OAAM,IAAI,MACR,WAAW,QAAQ,GAAG,uDAAuD,MAAM,GACpF;AAGH,YAAS,YAAY;;AAGvB,4CAAqB,uBAAuB;GAC1C,UAAU;GACV;GACD,CAAC;;AAGJ,QAAO;EACL,GAAG;EACH;EACA;EACA;EACA;EACA,sBAAsB,EAAE,QAAQ,cAAc,GAAG,SAA0B;AACzE,UAAO;IACL;IACA;IACA;IACA,UAAU,aAAa,EAAE,OAAO,CAAC,CAAC,sBAAsB;KACtD,GAAG;KACH,SAAS,QAAQ;KAClB,CAAC;IACH;;EAGH,sBAAsB,EACpB,QAAQ,cACR,GAAG,UACe;AAClB,OAAI,QAAQ,SAAS,cACnB,OAAM,IAAI,MACR,mEACD;AAGH,UAAO;IACL;IACA;IACA,UAAU,aAAa,EAAE,OAAO,CAAC,CAAC,sBAAsB,OAAO;IAChE;;EAGH,oBAAoB,EAAE,MAAM,QAAQ,gBAAmC;AACrE,OAAI,QAAQ,SAAS,cACnB,OAAM,IAAI,MACR,sEACD;AAGH,UAAO;IACL;IACA;IACA,GAAG,aAAa,EAAE,OAAO,CAAC,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACzD;;EAEJ"}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
import * as _neaps_tide_predictor0 from "@neaps/tide-predictor";
|
|
2
|
+
import { ExtremesInput, TimeSpan } from "@neaps/tide-predictor";
|
|
3
|
+
import { Station } from "@neaps/tide-database";
|
|
4
|
+
import { GeolibInputCoordinates } from "geolib/es/types";
|
|
5
|
+
|
|
6
|
+
//#region src/index.d.ts
|
|
7
|
+
type DatumOption = {
|
|
8
|
+
/** Datum to return predictions in. Defaults to 'MLLW' if available for the nearest station. */
|
|
9
|
+
datum?: string;
|
|
10
|
+
};
|
|
11
|
+
type ExtremesOptions = ExtremesInput & DatumOption;
|
|
12
|
+
type TimelineOptions = TimeSpan & DatumOption;
|
|
13
|
+
type WaterLevelOptions = {
|
|
14
|
+
time: Date;
|
|
15
|
+
} & DatumOption;
|
|
16
|
+
/**
|
|
17
|
+
* Get extremes prediction using the nearest station to the given position.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { getExtremesPrediction } from 'neaps'
|
|
22
|
+
*
|
|
23
|
+
* const prediction = getExtremesPrediction({
|
|
24
|
+
* latitude: 26.7, // or `lat`
|
|
25
|
+
* longitude: -80.05, // or `lng` or `lon`
|
|
26
|
+
* start: new Date('2025-12-17'),
|
|
27
|
+
* end: new Date('2025-12-18'),
|
|
28
|
+
* datum: 'MLLW', // optional, defaults to MLLW if available
|
|
29
|
+
* })
|
|
30
|
+
*/
|
|
31
|
+
declare function getExtremesPrediction(options: GeolibInputCoordinates & ExtremesOptions): {
|
|
32
|
+
datum: string | undefined;
|
|
33
|
+
distance: number | undefined;
|
|
34
|
+
station: Station;
|
|
35
|
+
extremes: _neaps_tide_predictor0.Extreme[];
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Get timeline prediction using the nearest station to the given position.
|
|
39
|
+
*/
|
|
40
|
+
declare function getTimelinePrediction(options: GeolibInputCoordinates & TimelineOptions): {
|
|
41
|
+
datum: string | undefined;
|
|
42
|
+
station: Station;
|
|
43
|
+
timeline: _neaps_tide_predictor0.TimelinePoint[];
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Get water level at a specific time using the nearest station to the given position.
|
|
47
|
+
*/
|
|
48
|
+
declare function getWaterLevelAtTime(options: GeolibInputCoordinates & WaterLevelOptions): {
|
|
49
|
+
time: Date;
|
|
50
|
+
hour: number;
|
|
51
|
+
level: number;
|
|
52
|
+
datum: string | undefined;
|
|
53
|
+
station: Station;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Find the nearest station to the given position.
|
|
57
|
+
*/
|
|
58
|
+
declare function nearestStation(position: GeolibInputCoordinates): {
|
|
59
|
+
distance: number | undefined;
|
|
60
|
+
datums: Record<string, number>;
|
|
61
|
+
harmonic_constituents: {
|
|
62
|
+
name: string;
|
|
63
|
+
description?: string;
|
|
64
|
+
amplitude: number;
|
|
65
|
+
phase_UTC: number;
|
|
66
|
+
phase_local: number;
|
|
67
|
+
speed?: number;
|
|
68
|
+
}[];
|
|
69
|
+
defaultDatum: string | undefined;
|
|
70
|
+
getExtremesPrediction({
|
|
71
|
+
datum,
|
|
72
|
+
...input
|
|
73
|
+
}: ExtremesOptions): {
|
|
74
|
+
datum: string | undefined;
|
|
75
|
+
distance: number | undefined;
|
|
76
|
+
station: Station;
|
|
77
|
+
extremes: _neaps_tide_predictor0.Extreme[];
|
|
78
|
+
};
|
|
79
|
+
getTimelinePrediction({
|
|
80
|
+
datum,
|
|
81
|
+
...params
|
|
82
|
+
}: TimelineOptions): {
|
|
83
|
+
datum: string | undefined;
|
|
84
|
+
station: Station;
|
|
85
|
+
timeline: _neaps_tide_predictor0.TimelinePoint[];
|
|
86
|
+
};
|
|
87
|
+
getWaterLevelAtTime({
|
|
88
|
+
time,
|
|
89
|
+
datum
|
|
90
|
+
}: WaterLevelOptions): {
|
|
91
|
+
time: Date;
|
|
92
|
+
hour: number;
|
|
93
|
+
level: number;
|
|
94
|
+
datum: string | undefined;
|
|
95
|
+
station: Station;
|
|
96
|
+
};
|
|
97
|
+
id: string;
|
|
98
|
+
name: string;
|
|
99
|
+
continent: string;
|
|
100
|
+
country: string;
|
|
101
|
+
region: string;
|
|
102
|
+
timezone: string;
|
|
103
|
+
disclaimers: string;
|
|
104
|
+
type: "reference" | "subordinate";
|
|
105
|
+
latitude: number;
|
|
106
|
+
longitude: number;
|
|
107
|
+
source: {
|
|
108
|
+
name: string;
|
|
109
|
+
id: string;
|
|
110
|
+
published_harmonics: boolean;
|
|
111
|
+
url: string;
|
|
112
|
+
source_url: string;
|
|
113
|
+
};
|
|
114
|
+
license: {
|
|
115
|
+
type: string;
|
|
116
|
+
commercial_use: boolean;
|
|
117
|
+
url: string;
|
|
118
|
+
notes?: string;
|
|
119
|
+
};
|
|
120
|
+
offsets?: {
|
|
121
|
+
reference: string;
|
|
122
|
+
height: {
|
|
123
|
+
high: number;
|
|
124
|
+
low: number;
|
|
125
|
+
type: "ratio" | "fixed";
|
|
126
|
+
};
|
|
127
|
+
time: {
|
|
128
|
+
high: number;
|
|
129
|
+
low: number;
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Find stations near the given position.
|
|
135
|
+
* @param limit Maximum number of stations to return (default: 10)
|
|
136
|
+
*/
|
|
137
|
+
declare function stationsNear(position: GeolibInputCoordinates, limit?: number): {
|
|
138
|
+
distance: number | undefined;
|
|
139
|
+
datums: Record<string, number>;
|
|
140
|
+
harmonic_constituents: {
|
|
141
|
+
name: string;
|
|
142
|
+
description?: string;
|
|
143
|
+
amplitude: number;
|
|
144
|
+
phase_UTC: number;
|
|
145
|
+
phase_local: number;
|
|
146
|
+
speed?: number;
|
|
147
|
+
}[];
|
|
148
|
+
defaultDatum: string | undefined;
|
|
149
|
+
getExtremesPrediction({
|
|
150
|
+
datum,
|
|
151
|
+
...input
|
|
152
|
+
}: ExtremesOptions): {
|
|
153
|
+
datum: string | undefined;
|
|
154
|
+
distance: number | undefined;
|
|
155
|
+
station: Station;
|
|
156
|
+
extremes: _neaps_tide_predictor0.Extreme[];
|
|
157
|
+
};
|
|
158
|
+
getTimelinePrediction({
|
|
159
|
+
datum,
|
|
160
|
+
...params
|
|
161
|
+
}: TimelineOptions): {
|
|
162
|
+
datum: string | undefined;
|
|
163
|
+
station: Station;
|
|
164
|
+
timeline: _neaps_tide_predictor0.TimelinePoint[];
|
|
165
|
+
};
|
|
166
|
+
getWaterLevelAtTime({
|
|
167
|
+
time,
|
|
168
|
+
datum
|
|
169
|
+
}: WaterLevelOptions): {
|
|
170
|
+
time: Date;
|
|
171
|
+
hour: number;
|
|
172
|
+
level: number;
|
|
173
|
+
datum: string | undefined;
|
|
174
|
+
station: Station;
|
|
175
|
+
};
|
|
176
|
+
id: string;
|
|
177
|
+
name: string;
|
|
178
|
+
continent: string;
|
|
179
|
+
country: string;
|
|
180
|
+
region: string;
|
|
181
|
+
timezone: string;
|
|
182
|
+
disclaimers: string;
|
|
183
|
+
type: "reference" | "subordinate";
|
|
184
|
+
latitude: number;
|
|
185
|
+
longitude: number;
|
|
186
|
+
source: {
|
|
187
|
+
name: string;
|
|
188
|
+
id: string;
|
|
189
|
+
published_harmonics: boolean;
|
|
190
|
+
url: string;
|
|
191
|
+
source_url: string;
|
|
192
|
+
};
|
|
193
|
+
license: {
|
|
194
|
+
type: string;
|
|
195
|
+
commercial_use: boolean;
|
|
196
|
+
url: string;
|
|
197
|
+
notes?: string;
|
|
198
|
+
};
|
|
199
|
+
offsets?: {
|
|
200
|
+
reference: string;
|
|
201
|
+
height: {
|
|
202
|
+
high: number;
|
|
203
|
+
low: number;
|
|
204
|
+
type: "ratio" | "fixed";
|
|
205
|
+
};
|
|
206
|
+
time: {
|
|
207
|
+
high: number;
|
|
208
|
+
low: number;
|
|
209
|
+
};
|
|
210
|
+
};
|
|
211
|
+
}[];
|
|
212
|
+
/**
|
|
213
|
+
* Find a specific station by its ID or source ID.
|
|
214
|
+
*/
|
|
215
|
+
declare function findStation(query: string): {
|
|
216
|
+
distance: number | undefined;
|
|
217
|
+
datums: Record<string, number>;
|
|
218
|
+
harmonic_constituents: {
|
|
219
|
+
name: string;
|
|
220
|
+
description?: string;
|
|
221
|
+
amplitude: number;
|
|
222
|
+
phase_UTC: number;
|
|
223
|
+
phase_local: number;
|
|
224
|
+
speed?: number;
|
|
225
|
+
}[];
|
|
226
|
+
defaultDatum: string | undefined;
|
|
227
|
+
getExtremesPrediction({
|
|
228
|
+
datum,
|
|
229
|
+
...input
|
|
230
|
+
}: ExtremesOptions): {
|
|
231
|
+
datum: string | undefined;
|
|
232
|
+
distance: number | undefined;
|
|
233
|
+
station: Station;
|
|
234
|
+
extremes: _neaps_tide_predictor0.Extreme[];
|
|
235
|
+
};
|
|
236
|
+
getTimelinePrediction({
|
|
237
|
+
datum,
|
|
238
|
+
...params
|
|
239
|
+
}: TimelineOptions): {
|
|
240
|
+
datum: string | undefined;
|
|
241
|
+
station: Station;
|
|
242
|
+
timeline: _neaps_tide_predictor0.TimelinePoint[];
|
|
243
|
+
};
|
|
244
|
+
getWaterLevelAtTime({
|
|
245
|
+
time,
|
|
246
|
+
datum
|
|
247
|
+
}: WaterLevelOptions): {
|
|
248
|
+
time: Date;
|
|
249
|
+
hour: number;
|
|
250
|
+
level: number;
|
|
251
|
+
datum: string | undefined;
|
|
252
|
+
station: Station;
|
|
253
|
+
};
|
|
254
|
+
id: string;
|
|
255
|
+
name: string;
|
|
256
|
+
continent: string;
|
|
257
|
+
country: string;
|
|
258
|
+
region: string;
|
|
259
|
+
timezone: string;
|
|
260
|
+
disclaimers: string;
|
|
261
|
+
type: "reference" | "subordinate";
|
|
262
|
+
latitude: number;
|
|
263
|
+
longitude: number;
|
|
264
|
+
source: {
|
|
265
|
+
name: string;
|
|
266
|
+
id: string;
|
|
267
|
+
published_harmonics: boolean;
|
|
268
|
+
url: string;
|
|
269
|
+
source_url: string;
|
|
270
|
+
};
|
|
271
|
+
license: {
|
|
272
|
+
type: string;
|
|
273
|
+
commercial_use: boolean;
|
|
274
|
+
url: string;
|
|
275
|
+
notes?: string;
|
|
276
|
+
};
|
|
277
|
+
offsets?: {
|
|
278
|
+
reference: string;
|
|
279
|
+
height: {
|
|
280
|
+
high: number;
|
|
281
|
+
low: number;
|
|
282
|
+
type: "ratio" | "fixed";
|
|
283
|
+
};
|
|
284
|
+
time: {
|
|
285
|
+
high: number;
|
|
286
|
+
low: number;
|
|
287
|
+
};
|
|
288
|
+
};
|
|
289
|
+
};
|
|
290
|
+
declare function useStation(station: Station, distance?: number): {
|
|
291
|
+
distance: number | undefined;
|
|
292
|
+
datums: Record<string, number>;
|
|
293
|
+
harmonic_constituents: {
|
|
294
|
+
name: string;
|
|
295
|
+
description?: string;
|
|
296
|
+
amplitude: number;
|
|
297
|
+
phase_UTC: number;
|
|
298
|
+
phase_local: number;
|
|
299
|
+
speed?: number;
|
|
300
|
+
}[];
|
|
301
|
+
defaultDatum: string | undefined;
|
|
302
|
+
getExtremesPrediction({
|
|
303
|
+
datum,
|
|
304
|
+
...input
|
|
305
|
+
}: ExtremesOptions): {
|
|
306
|
+
datum: string | undefined;
|
|
307
|
+
distance: number | undefined;
|
|
308
|
+
station: Station;
|
|
309
|
+
extremes: _neaps_tide_predictor0.Extreme[];
|
|
310
|
+
};
|
|
311
|
+
getTimelinePrediction({
|
|
312
|
+
datum,
|
|
313
|
+
...params
|
|
314
|
+
}: TimelineOptions): {
|
|
315
|
+
datum: string | undefined;
|
|
316
|
+
station: Station;
|
|
317
|
+
timeline: _neaps_tide_predictor0.TimelinePoint[];
|
|
318
|
+
};
|
|
319
|
+
getWaterLevelAtTime({
|
|
320
|
+
time,
|
|
321
|
+
datum
|
|
322
|
+
}: WaterLevelOptions): {
|
|
323
|
+
time: Date;
|
|
324
|
+
hour: number;
|
|
325
|
+
level: number;
|
|
326
|
+
datum: string | undefined;
|
|
327
|
+
station: Station;
|
|
328
|
+
};
|
|
329
|
+
id: string;
|
|
330
|
+
name: string;
|
|
331
|
+
continent: string;
|
|
332
|
+
country: string;
|
|
333
|
+
region: string;
|
|
334
|
+
timezone: string;
|
|
335
|
+
disclaimers: string;
|
|
336
|
+
type: "reference" | "subordinate";
|
|
337
|
+
latitude: number;
|
|
338
|
+
longitude: number;
|
|
339
|
+
source: {
|
|
340
|
+
name: string;
|
|
341
|
+
id: string;
|
|
342
|
+
published_harmonics: boolean;
|
|
343
|
+
url: string;
|
|
344
|
+
source_url: string;
|
|
345
|
+
};
|
|
346
|
+
license: {
|
|
347
|
+
type: string;
|
|
348
|
+
commercial_use: boolean;
|
|
349
|
+
url: string;
|
|
350
|
+
notes?: string;
|
|
351
|
+
};
|
|
352
|
+
offsets?: {
|
|
353
|
+
reference: string;
|
|
354
|
+
height: {
|
|
355
|
+
high: number;
|
|
356
|
+
low: number;
|
|
357
|
+
type: "ratio" | "fixed";
|
|
358
|
+
};
|
|
359
|
+
time: {
|
|
360
|
+
high: number;
|
|
361
|
+
low: number;
|
|
362
|
+
};
|
|
363
|
+
};
|
|
364
|
+
};
|
|
365
|
+
//#endregion
|
|
366
|
+
export { ExtremesOptions, TimelineOptions, WaterLevelOptions, findStation, getExtremesPrediction, getTimelinePrediction, getWaterLevelAtTime, nearestStation, stationsNear, useStation };
|
|
367
|
+
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
import { Station } from "@neaps/tide-database";
|
|
2
|
+
import * as _neaps_tide_predictor0 from "@neaps/tide-predictor";
|
|
3
|
+
import { ExtremesInput, TimeSpan } from "@neaps/tide-predictor";
|
|
4
|
+
import { GeolibInputCoordinates } from "geolib/es/types";
|
|
5
|
+
|
|
6
|
+
//#region src/index.d.ts
|
|
7
|
+
type DatumOption = {
|
|
8
|
+
/** Datum to return predictions in. Defaults to 'MLLW' if available for the nearest station. */
|
|
9
|
+
datum?: string;
|
|
10
|
+
};
|
|
11
|
+
type ExtremesOptions = ExtremesInput & DatumOption;
|
|
12
|
+
type TimelineOptions = TimeSpan & DatumOption;
|
|
13
|
+
type WaterLevelOptions = {
|
|
14
|
+
time: Date;
|
|
15
|
+
} & DatumOption;
|
|
16
|
+
/**
|
|
17
|
+
* Get extremes prediction using the nearest station to the given position.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { getExtremesPrediction } from 'neaps'
|
|
22
|
+
*
|
|
23
|
+
* const prediction = getExtremesPrediction({
|
|
24
|
+
* latitude: 26.7, // or `lat`
|
|
25
|
+
* longitude: -80.05, // or `lng` or `lon`
|
|
26
|
+
* start: new Date('2025-12-17'),
|
|
27
|
+
* end: new Date('2025-12-18'),
|
|
28
|
+
* datum: 'MLLW', // optional, defaults to MLLW if available
|
|
29
|
+
* })
|
|
30
|
+
*/
|
|
31
|
+
declare function getExtremesPrediction(options: GeolibInputCoordinates & ExtremesOptions): {
|
|
32
|
+
datum: string | undefined;
|
|
33
|
+
distance: number | undefined;
|
|
34
|
+
station: Station;
|
|
35
|
+
extremes: _neaps_tide_predictor0.Extreme[];
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Get timeline prediction using the nearest station to the given position.
|
|
39
|
+
*/
|
|
40
|
+
declare function getTimelinePrediction(options: GeolibInputCoordinates & TimelineOptions): {
|
|
41
|
+
datum: string | undefined;
|
|
42
|
+
station: Station;
|
|
43
|
+
timeline: _neaps_tide_predictor0.TimelinePoint[];
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Get water level at a specific time using the nearest station to the given position.
|
|
47
|
+
*/
|
|
48
|
+
declare function getWaterLevelAtTime(options: GeolibInputCoordinates & WaterLevelOptions): {
|
|
49
|
+
time: Date;
|
|
50
|
+
hour: number;
|
|
51
|
+
level: number;
|
|
52
|
+
datum: string | undefined;
|
|
53
|
+
station: Station;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Find the nearest station to the given position.
|
|
57
|
+
*/
|
|
58
|
+
declare function nearestStation(position: GeolibInputCoordinates): {
|
|
59
|
+
distance: number | undefined;
|
|
60
|
+
datums: Record<string, number>;
|
|
61
|
+
harmonic_constituents: {
|
|
62
|
+
name: string;
|
|
63
|
+
description?: string;
|
|
64
|
+
amplitude: number;
|
|
65
|
+
phase_UTC: number;
|
|
66
|
+
phase_local: number;
|
|
67
|
+
speed?: number;
|
|
68
|
+
}[];
|
|
69
|
+
defaultDatum: string | undefined;
|
|
70
|
+
getExtremesPrediction({
|
|
71
|
+
datum,
|
|
72
|
+
...input
|
|
73
|
+
}: ExtremesOptions): {
|
|
74
|
+
datum: string | undefined;
|
|
75
|
+
distance: number | undefined;
|
|
76
|
+
station: Station;
|
|
77
|
+
extremes: _neaps_tide_predictor0.Extreme[];
|
|
78
|
+
};
|
|
79
|
+
getTimelinePrediction({
|
|
80
|
+
datum,
|
|
81
|
+
...params
|
|
82
|
+
}: TimelineOptions): {
|
|
83
|
+
datum: string | undefined;
|
|
84
|
+
station: Station;
|
|
85
|
+
timeline: _neaps_tide_predictor0.TimelinePoint[];
|
|
86
|
+
};
|
|
87
|
+
getWaterLevelAtTime({
|
|
88
|
+
time,
|
|
89
|
+
datum
|
|
90
|
+
}: WaterLevelOptions): {
|
|
91
|
+
time: Date;
|
|
92
|
+
hour: number;
|
|
93
|
+
level: number;
|
|
94
|
+
datum: string | undefined;
|
|
95
|
+
station: Station;
|
|
96
|
+
};
|
|
97
|
+
id: string;
|
|
98
|
+
name: string;
|
|
99
|
+
continent: string;
|
|
100
|
+
country: string;
|
|
101
|
+
region: string;
|
|
102
|
+
timezone: string;
|
|
103
|
+
disclaimers: string;
|
|
104
|
+
type: "reference" | "subordinate";
|
|
105
|
+
latitude: number;
|
|
106
|
+
longitude: number;
|
|
107
|
+
source: {
|
|
108
|
+
name: string;
|
|
109
|
+
id: string;
|
|
110
|
+
published_harmonics: boolean;
|
|
111
|
+
url: string;
|
|
112
|
+
source_url: string;
|
|
113
|
+
};
|
|
114
|
+
license: {
|
|
115
|
+
type: string;
|
|
116
|
+
commercial_use: boolean;
|
|
117
|
+
url: string;
|
|
118
|
+
notes?: string;
|
|
119
|
+
};
|
|
120
|
+
offsets?: {
|
|
121
|
+
reference: string;
|
|
122
|
+
height: {
|
|
123
|
+
high: number;
|
|
124
|
+
low: number;
|
|
125
|
+
type: "ratio" | "fixed";
|
|
126
|
+
};
|
|
127
|
+
time: {
|
|
128
|
+
high: number;
|
|
129
|
+
low: number;
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Find stations near the given position.
|
|
135
|
+
* @param limit Maximum number of stations to return (default: 10)
|
|
136
|
+
*/
|
|
137
|
+
declare function stationsNear(position: GeolibInputCoordinates, limit?: number): {
|
|
138
|
+
distance: number | undefined;
|
|
139
|
+
datums: Record<string, number>;
|
|
140
|
+
harmonic_constituents: {
|
|
141
|
+
name: string;
|
|
142
|
+
description?: string;
|
|
143
|
+
amplitude: number;
|
|
144
|
+
phase_UTC: number;
|
|
145
|
+
phase_local: number;
|
|
146
|
+
speed?: number;
|
|
147
|
+
}[];
|
|
148
|
+
defaultDatum: string | undefined;
|
|
149
|
+
getExtremesPrediction({
|
|
150
|
+
datum,
|
|
151
|
+
...input
|
|
152
|
+
}: ExtremesOptions): {
|
|
153
|
+
datum: string | undefined;
|
|
154
|
+
distance: number | undefined;
|
|
155
|
+
station: Station;
|
|
156
|
+
extremes: _neaps_tide_predictor0.Extreme[];
|
|
157
|
+
};
|
|
158
|
+
getTimelinePrediction({
|
|
159
|
+
datum,
|
|
160
|
+
...params
|
|
161
|
+
}: TimelineOptions): {
|
|
162
|
+
datum: string | undefined;
|
|
163
|
+
station: Station;
|
|
164
|
+
timeline: _neaps_tide_predictor0.TimelinePoint[];
|
|
165
|
+
};
|
|
166
|
+
getWaterLevelAtTime({
|
|
167
|
+
time,
|
|
168
|
+
datum
|
|
169
|
+
}: WaterLevelOptions): {
|
|
170
|
+
time: Date;
|
|
171
|
+
hour: number;
|
|
172
|
+
level: number;
|
|
173
|
+
datum: string | undefined;
|
|
174
|
+
station: Station;
|
|
175
|
+
};
|
|
176
|
+
id: string;
|
|
177
|
+
name: string;
|
|
178
|
+
continent: string;
|
|
179
|
+
country: string;
|
|
180
|
+
region: string;
|
|
181
|
+
timezone: string;
|
|
182
|
+
disclaimers: string;
|
|
183
|
+
type: "reference" | "subordinate";
|
|
184
|
+
latitude: number;
|
|
185
|
+
longitude: number;
|
|
186
|
+
source: {
|
|
187
|
+
name: string;
|
|
188
|
+
id: string;
|
|
189
|
+
published_harmonics: boolean;
|
|
190
|
+
url: string;
|
|
191
|
+
source_url: string;
|
|
192
|
+
};
|
|
193
|
+
license: {
|
|
194
|
+
type: string;
|
|
195
|
+
commercial_use: boolean;
|
|
196
|
+
url: string;
|
|
197
|
+
notes?: string;
|
|
198
|
+
};
|
|
199
|
+
offsets?: {
|
|
200
|
+
reference: string;
|
|
201
|
+
height: {
|
|
202
|
+
high: number;
|
|
203
|
+
low: number;
|
|
204
|
+
type: "ratio" | "fixed";
|
|
205
|
+
};
|
|
206
|
+
time: {
|
|
207
|
+
high: number;
|
|
208
|
+
low: number;
|
|
209
|
+
};
|
|
210
|
+
};
|
|
211
|
+
}[];
|
|
212
|
+
/**
|
|
213
|
+
* Find a specific station by its ID or source ID.
|
|
214
|
+
*/
|
|
215
|
+
declare function findStation(query: string): {
|
|
216
|
+
distance: number | undefined;
|
|
217
|
+
datums: Record<string, number>;
|
|
218
|
+
harmonic_constituents: {
|
|
219
|
+
name: string;
|
|
220
|
+
description?: string;
|
|
221
|
+
amplitude: number;
|
|
222
|
+
phase_UTC: number;
|
|
223
|
+
phase_local: number;
|
|
224
|
+
speed?: number;
|
|
225
|
+
}[];
|
|
226
|
+
defaultDatum: string | undefined;
|
|
227
|
+
getExtremesPrediction({
|
|
228
|
+
datum,
|
|
229
|
+
...input
|
|
230
|
+
}: ExtremesOptions): {
|
|
231
|
+
datum: string | undefined;
|
|
232
|
+
distance: number | undefined;
|
|
233
|
+
station: Station;
|
|
234
|
+
extremes: _neaps_tide_predictor0.Extreme[];
|
|
235
|
+
};
|
|
236
|
+
getTimelinePrediction({
|
|
237
|
+
datum,
|
|
238
|
+
...params
|
|
239
|
+
}: TimelineOptions): {
|
|
240
|
+
datum: string | undefined;
|
|
241
|
+
station: Station;
|
|
242
|
+
timeline: _neaps_tide_predictor0.TimelinePoint[];
|
|
243
|
+
};
|
|
244
|
+
getWaterLevelAtTime({
|
|
245
|
+
time,
|
|
246
|
+
datum
|
|
247
|
+
}: WaterLevelOptions): {
|
|
248
|
+
time: Date;
|
|
249
|
+
hour: number;
|
|
250
|
+
level: number;
|
|
251
|
+
datum: string | undefined;
|
|
252
|
+
station: Station;
|
|
253
|
+
};
|
|
254
|
+
id: string;
|
|
255
|
+
name: string;
|
|
256
|
+
continent: string;
|
|
257
|
+
country: string;
|
|
258
|
+
region: string;
|
|
259
|
+
timezone: string;
|
|
260
|
+
disclaimers: string;
|
|
261
|
+
type: "reference" | "subordinate";
|
|
262
|
+
latitude: number;
|
|
263
|
+
longitude: number;
|
|
264
|
+
source: {
|
|
265
|
+
name: string;
|
|
266
|
+
id: string;
|
|
267
|
+
published_harmonics: boolean;
|
|
268
|
+
url: string;
|
|
269
|
+
source_url: string;
|
|
270
|
+
};
|
|
271
|
+
license: {
|
|
272
|
+
type: string;
|
|
273
|
+
commercial_use: boolean;
|
|
274
|
+
url: string;
|
|
275
|
+
notes?: string;
|
|
276
|
+
};
|
|
277
|
+
offsets?: {
|
|
278
|
+
reference: string;
|
|
279
|
+
height: {
|
|
280
|
+
high: number;
|
|
281
|
+
low: number;
|
|
282
|
+
type: "ratio" | "fixed";
|
|
283
|
+
};
|
|
284
|
+
time: {
|
|
285
|
+
high: number;
|
|
286
|
+
low: number;
|
|
287
|
+
};
|
|
288
|
+
};
|
|
289
|
+
};
|
|
290
|
+
declare function useStation(station: Station, distance?: number): {
|
|
291
|
+
distance: number | undefined;
|
|
292
|
+
datums: Record<string, number>;
|
|
293
|
+
harmonic_constituents: {
|
|
294
|
+
name: string;
|
|
295
|
+
description?: string;
|
|
296
|
+
amplitude: number;
|
|
297
|
+
phase_UTC: number;
|
|
298
|
+
phase_local: number;
|
|
299
|
+
speed?: number;
|
|
300
|
+
}[];
|
|
301
|
+
defaultDatum: string | undefined;
|
|
302
|
+
getExtremesPrediction({
|
|
303
|
+
datum,
|
|
304
|
+
...input
|
|
305
|
+
}: ExtremesOptions): {
|
|
306
|
+
datum: string | undefined;
|
|
307
|
+
distance: number | undefined;
|
|
308
|
+
station: Station;
|
|
309
|
+
extremes: _neaps_tide_predictor0.Extreme[];
|
|
310
|
+
};
|
|
311
|
+
getTimelinePrediction({
|
|
312
|
+
datum,
|
|
313
|
+
...params
|
|
314
|
+
}: TimelineOptions): {
|
|
315
|
+
datum: string | undefined;
|
|
316
|
+
station: Station;
|
|
317
|
+
timeline: _neaps_tide_predictor0.TimelinePoint[];
|
|
318
|
+
};
|
|
319
|
+
getWaterLevelAtTime({
|
|
320
|
+
time,
|
|
321
|
+
datum
|
|
322
|
+
}: WaterLevelOptions): {
|
|
323
|
+
time: Date;
|
|
324
|
+
hour: number;
|
|
325
|
+
level: number;
|
|
326
|
+
datum: string | undefined;
|
|
327
|
+
station: Station;
|
|
328
|
+
};
|
|
329
|
+
id: string;
|
|
330
|
+
name: string;
|
|
331
|
+
continent: string;
|
|
332
|
+
country: string;
|
|
333
|
+
region: string;
|
|
334
|
+
timezone: string;
|
|
335
|
+
disclaimers: string;
|
|
336
|
+
type: "reference" | "subordinate";
|
|
337
|
+
latitude: number;
|
|
338
|
+
longitude: number;
|
|
339
|
+
source: {
|
|
340
|
+
name: string;
|
|
341
|
+
id: string;
|
|
342
|
+
published_harmonics: boolean;
|
|
343
|
+
url: string;
|
|
344
|
+
source_url: string;
|
|
345
|
+
};
|
|
346
|
+
license: {
|
|
347
|
+
type: string;
|
|
348
|
+
commercial_use: boolean;
|
|
349
|
+
url: string;
|
|
350
|
+
notes?: string;
|
|
351
|
+
};
|
|
352
|
+
offsets?: {
|
|
353
|
+
reference: string;
|
|
354
|
+
height: {
|
|
355
|
+
high: number;
|
|
356
|
+
low: number;
|
|
357
|
+
type: "ratio" | "fixed";
|
|
358
|
+
};
|
|
359
|
+
time: {
|
|
360
|
+
high: number;
|
|
361
|
+
low: number;
|
|
362
|
+
};
|
|
363
|
+
};
|
|
364
|
+
};
|
|
365
|
+
//#endregion
|
|
366
|
+
export { ExtremesOptions, TimelineOptions, WaterLevelOptions, findStation, getExtremesPrediction, getTimelinePrediction, getWaterLevelAtTime, nearestStation, stationsNear, useStation };
|
|
367
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { getDistance } from "geolib";
|
|
2
|
+
import stations from "@neaps/tide-database";
|
|
3
|
+
import tidePredictor from "@neaps/tide-predictor";
|
|
4
|
+
|
|
5
|
+
//#region src/index.ts
|
|
6
|
+
/**
|
|
7
|
+
* Get extremes prediction using the nearest station to the given position.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { getExtremesPrediction } from 'neaps'
|
|
12
|
+
*
|
|
13
|
+
* const prediction = getExtremesPrediction({
|
|
14
|
+
* latitude: 26.7, // or `lat`
|
|
15
|
+
* longitude: -80.05, // or `lng` or `lon`
|
|
16
|
+
* start: new Date('2025-12-17'),
|
|
17
|
+
* end: new Date('2025-12-18'),
|
|
18
|
+
* datum: 'MLLW', // optional, defaults to MLLW if available
|
|
19
|
+
* })
|
|
20
|
+
*/
|
|
21
|
+
function getExtremesPrediction(options) {
|
|
22
|
+
return nearestStation(options).getExtremesPrediction(options);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Get timeline prediction using the nearest station to the given position.
|
|
26
|
+
*/
|
|
27
|
+
function getTimelinePrediction(options) {
|
|
28
|
+
return nearestStation(options).getTimelinePrediction(options);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Get water level at a specific time using the nearest station to the given position.
|
|
32
|
+
*/
|
|
33
|
+
function getWaterLevelAtTime(options) {
|
|
34
|
+
return nearestStation(options).getWaterLevelAtTime(options);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Find the nearest station to the given position.
|
|
38
|
+
*/
|
|
39
|
+
function nearestStation(position) {
|
|
40
|
+
return stationsNear(position, 1)[0];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Find stations near the given position.
|
|
44
|
+
* @param limit Maximum number of stations to return (default: 10)
|
|
45
|
+
*/
|
|
46
|
+
function stationsNear(position, limit = 10) {
|
|
47
|
+
return stations.map((station) => ({
|
|
48
|
+
station,
|
|
49
|
+
distance: getDistance(position, station)
|
|
50
|
+
})).sort((a, b) => a.distance - b.distance).slice(0, limit).map(({ station, distance }) => useStation(station, distance));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Find a specific station by its ID or source ID.
|
|
54
|
+
*/
|
|
55
|
+
function findStation(query) {
|
|
56
|
+
const searches = [(s) => s.id === query, (s) => s.source.id === query];
|
|
57
|
+
let found = void 0;
|
|
58
|
+
for (const search of searches) {
|
|
59
|
+
found = stations.find(search);
|
|
60
|
+
if (found) break;
|
|
61
|
+
}
|
|
62
|
+
if (!found) throw new Error(`Station not found: ${query}`);
|
|
63
|
+
return useStation(found);
|
|
64
|
+
}
|
|
65
|
+
function useStation(station, distance) {
|
|
66
|
+
let reference = station;
|
|
67
|
+
if (station.type === "subordinate") reference = findStation(station.offsets?.reference || "");
|
|
68
|
+
const { datums, harmonic_constituents } = reference;
|
|
69
|
+
const defaultDatum = "MLLW" in datums ? "MLLW" : void 0;
|
|
70
|
+
function getPredictor({ datum = defaultDatum } = {}) {
|
|
71
|
+
let offset = 0;
|
|
72
|
+
if (datum) {
|
|
73
|
+
const datumOffset = datums?.[datum];
|
|
74
|
+
const mslOffset = datums?.["MSL"];
|
|
75
|
+
if (typeof datumOffset !== "number") throw new Error(`Station ${station.id} missing ${datum} datum. Available datums: ${Object.keys(datums || {}).join(", ")}`);
|
|
76
|
+
if (typeof mslOffset !== "number") throw new Error(`Station ${station.id} missing MSL datum, so predictions can't be given in ${datum}.`);
|
|
77
|
+
offset = mslOffset - datumOffset;
|
|
78
|
+
}
|
|
79
|
+
return tidePredictor(harmonic_constituents, {
|
|
80
|
+
phaseKey: "phase_UTC",
|
|
81
|
+
offset
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
...station,
|
|
86
|
+
distance,
|
|
87
|
+
datums,
|
|
88
|
+
harmonic_constituents,
|
|
89
|
+
defaultDatum,
|
|
90
|
+
getExtremesPrediction({ datum = defaultDatum, ...input }) {
|
|
91
|
+
return {
|
|
92
|
+
datum,
|
|
93
|
+
distance,
|
|
94
|
+
station,
|
|
95
|
+
extremes: getPredictor({ datum }).getExtremesPrediction({
|
|
96
|
+
...input,
|
|
97
|
+
offsets: station.offsets
|
|
98
|
+
})
|
|
99
|
+
};
|
|
100
|
+
},
|
|
101
|
+
getTimelinePrediction({ datum = defaultDatum, ...params }) {
|
|
102
|
+
if (station.type === "subordinate") throw new Error(`Timeline predictions are not supported for subordinate stations.`);
|
|
103
|
+
return {
|
|
104
|
+
datum,
|
|
105
|
+
station,
|
|
106
|
+
timeline: getPredictor({ datum }).getTimelinePrediction(params)
|
|
107
|
+
};
|
|
108
|
+
},
|
|
109
|
+
getWaterLevelAtTime({ time, datum = defaultDatum }) {
|
|
110
|
+
if (station.type === "subordinate") throw new Error(`Water level predictions are not supported for subordinate stations.`);
|
|
111
|
+
return {
|
|
112
|
+
datum,
|
|
113
|
+
station,
|
|
114
|
+
...getPredictor({ datum }).getWaterLevelAtTime({ time })
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
//#endregion
|
|
121
|
+
export { findStation, getExtremesPrediction, getTimelinePrediction, getWaterLevelAtTime, nearestStation, stationsNear, useStation };
|
|
122
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["found: Station | undefined"],"sources":["../src/index.ts"],"sourcesContent":["import { getDistance } from 'geolib'\nimport stations, { type Station } from '@neaps/tide-database'\nimport tidePredictor, {\n type TimeSpan,\n type ExtremesInput\n} from '@neaps/tide-predictor'\nimport type { GeolibInputCoordinates } from 'geolib/es/types'\n\ntype DatumOption = {\n /** Datum to return predictions in. Defaults to 'MLLW' if available for the nearest station. */\n datum?: string\n}\n\nexport type ExtremesOptions = ExtremesInput & DatumOption\nexport type TimelineOptions = TimeSpan & DatumOption\nexport type WaterLevelOptions = { time: Date } & DatumOption\n\n/**\n * Get extremes prediction using the nearest station to the given position.\n *\n * @example\n * ```ts\n * import { getExtremesPrediction } from 'neaps'\n *\n * const prediction = getExtremesPrediction({\n * latitude: 26.7, // or `lat`\n * longitude: -80.05, // or `lng` or `lon`\n * start: new Date('2025-12-17'),\n * end: new Date('2025-12-18'),\n * datum: 'MLLW', // optional, defaults to MLLW if available\n * })\n */\nexport function getExtremesPrediction(\n options: GeolibInputCoordinates & ExtremesOptions\n) {\n return nearestStation(options).getExtremesPrediction(options)\n}\n\n/**\n * Get timeline prediction using the nearest station to the given position.\n */\nexport function getTimelinePrediction(\n options: GeolibInputCoordinates & TimelineOptions\n) {\n return nearestStation(options).getTimelinePrediction(options)\n}\n\n/**\n * Get water level at a specific time using the nearest station to the given position.\n */\nexport function getWaterLevelAtTime(\n options: GeolibInputCoordinates & WaterLevelOptions\n) {\n return nearestStation(options).getWaterLevelAtTime(options)\n}\n\n/**\n * Find the nearest station to the given position.\n */\nexport function nearestStation(position: GeolibInputCoordinates) {\n return stationsNear(position, 1)[0]\n}\n\n/**\n * Find stations near the given position.\n * @param limit Maximum number of stations to return (default: 10)\n */\nexport function stationsNear(position: GeolibInputCoordinates, limit = 10) {\n return stations\n .map((station) => ({ station, distance: getDistance(position, station) }))\n .sort((a, b) => a.distance - b.distance)\n .slice(0, limit)\n .map(({ station, distance }) => useStation(station, distance))\n}\n\n/**\n * Find a specific station by its ID or source ID.\n */\nexport function findStation(query: string) {\n const searches = [\n (s: Station) => s.id === query,\n (s: Station) => s.source.id === query\n ]\n\n let found: Station | undefined = undefined\n\n for (const search of searches) {\n found = stations.find(search)\n if (found) break\n }\n\n if (!found) throw new Error(`Station not found: ${query}`)\n\n return useStation(found)\n}\n\nexport function useStation(station: Station, distance?: number) {\n // If subordinate station, use the reference station for datums and constituents\n let reference = station\n if (station.type === 'subordinate') {\n reference = findStation(station.offsets?.reference || '')\n }\n const { datums, harmonic_constituents } = reference\n\n // Use MLLW as the default datum if available\n const defaultDatum = 'MLLW' in datums ? 'MLLW' : undefined\n\n function getPredictor({ datum = defaultDatum }: DatumOption = {}) {\n let offset = 0\n\n if (datum) {\n const datumOffset = datums?.[datum]\n const mslOffset = datums?.['MSL']\n\n if (typeof datumOffset !== 'number') {\n throw new Error(\n `Station ${station.id} missing ${datum} datum. Available datums: ${Object.keys(datums || {}).join(', ')}`\n )\n }\n\n if (typeof mslOffset !== 'number') {\n throw new Error(\n `Station ${station.id} missing MSL datum, so predictions can't be given in ${datum}.`\n )\n }\n\n offset = mslOffset - datumOffset\n }\n\n return tidePredictor(harmonic_constituents, {\n phaseKey: 'phase_UTC',\n offset\n })\n }\n\n return {\n ...station,\n distance,\n datums,\n harmonic_constituents,\n defaultDatum,\n getExtremesPrediction({ datum = defaultDatum, ...input }: ExtremesOptions) {\n return {\n datum,\n distance,\n station,\n extremes: getPredictor({ datum }).getExtremesPrediction({\n ...input,\n offsets: station.offsets\n })\n }\n },\n\n getTimelinePrediction({\n datum = defaultDatum,\n ...params\n }: TimelineOptions) {\n if (station.type === 'subordinate') {\n throw new Error(\n `Timeline predictions are not supported for subordinate stations.`\n )\n }\n\n return {\n datum,\n station,\n timeline: getPredictor({ datum }).getTimelinePrediction(params)\n }\n },\n\n getWaterLevelAtTime({ time, datum = defaultDatum }: WaterLevelOptions) {\n if (station.type === 'subordinate') {\n throw new Error(\n `Water level predictions are not supported for subordinate stations.`\n )\n }\n\n return {\n datum,\n station,\n ...getPredictor({ datum }).getWaterLevelAtTime({ time })\n }\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAgCA,SAAgB,sBACd,SACA;AACA,QAAO,eAAe,QAAQ,CAAC,sBAAsB,QAAQ;;;;;AAM/D,SAAgB,sBACd,SACA;AACA,QAAO,eAAe,QAAQ,CAAC,sBAAsB,QAAQ;;;;;AAM/D,SAAgB,oBACd,SACA;AACA,QAAO,eAAe,QAAQ,CAAC,oBAAoB,QAAQ;;;;;AAM7D,SAAgB,eAAe,UAAkC;AAC/D,QAAO,aAAa,UAAU,EAAE,CAAC;;;;;;AAOnC,SAAgB,aAAa,UAAkC,QAAQ,IAAI;AACzE,QAAO,SACJ,KAAK,aAAa;EAAE;EAAS,UAAU,YAAY,UAAU,QAAQ;EAAE,EAAE,CACzE,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,SAAS,CACvC,MAAM,GAAG,MAAM,CACf,KAAK,EAAE,SAAS,eAAe,WAAW,SAAS,SAAS,CAAC;;;;;AAMlE,SAAgB,YAAY,OAAe;CACzC,MAAM,WAAW,EACd,MAAe,EAAE,OAAO,QACxB,MAAe,EAAE,OAAO,OAAO,MACjC;CAED,IAAIA,QAA6B;AAEjC,MAAK,MAAM,UAAU,UAAU;AAC7B,UAAQ,SAAS,KAAK,OAAO;AAC7B,MAAI,MAAO;;AAGb,KAAI,CAAC,MAAO,OAAM,IAAI,MAAM,sBAAsB,QAAQ;AAE1D,QAAO,WAAW,MAAM;;AAG1B,SAAgB,WAAW,SAAkB,UAAmB;CAE9D,IAAI,YAAY;AAChB,KAAI,QAAQ,SAAS,cACnB,aAAY,YAAY,QAAQ,SAAS,aAAa,GAAG;CAE3D,MAAM,EAAE,QAAQ,0BAA0B;CAG1C,MAAM,eAAe,UAAU,SAAS,SAAS;CAEjD,SAAS,aAAa,EAAE,QAAQ,iBAA8B,EAAE,EAAE;EAChE,IAAI,SAAS;AAEb,MAAI,OAAO;GACT,MAAM,cAAc,SAAS;GAC7B,MAAM,YAAY,SAAS;AAE3B,OAAI,OAAO,gBAAgB,SACzB,OAAM,IAAI,MACR,WAAW,QAAQ,GAAG,WAAW,MAAM,4BAA4B,OAAO,KAAK,UAAU,EAAE,CAAC,CAAC,KAAK,KAAK,GACxG;AAGH,OAAI,OAAO,cAAc,SACvB,OAAM,IAAI,MACR,WAAW,QAAQ,GAAG,uDAAuD,MAAM,GACpF;AAGH,YAAS,YAAY;;AAGvB,SAAO,cAAc,uBAAuB;GAC1C,UAAU;GACV;GACD,CAAC;;AAGJ,QAAO;EACL,GAAG;EACH;EACA;EACA;EACA;EACA,sBAAsB,EAAE,QAAQ,cAAc,GAAG,SAA0B;AACzE,UAAO;IACL;IACA;IACA;IACA,UAAU,aAAa,EAAE,OAAO,CAAC,CAAC,sBAAsB;KACtD,GAAG;KACH,SAAS,QAAQ;KAClB,CAAC;IACH;;EAGH,sBAAsB,EACpB,QAAQ,cACR,GAAG,UACe;AAClB,OAAI,QAAQ,SAAS,cACnB,OAAM,IAAI,MACR,mEACD;AAGH,UAAO;IACL;IACA;IACA,UAAU,aAAa,EAAE,OAAO,CAAC,CAAC,sBAAsB,OAAO;IAChE;;EAGH,oBAAoB,EAAE,MAAM,QAAQ,gBAAmC;AACrE,OAAI,QAAQ,SAAS,cACnB,OAAM,IAAI,MACR,sEACD;AAGH,UAAO;IACL;IACA;IACA,GAAG,aAAa,EAAE,OAAO,CAAC,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACzD;;EAEJ"}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "neaps",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Tide predictions",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"tides",
|
|
7
|
+
"harmonics"
|
|
8
|
+
],
|
|
9
|
+
"homepage": "https://github.com/neaps/neaps#readme",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/neaps/neaps/issues"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/neaps/neaps.git",
|
|
16
|
+
"directory": "packages/neaps"
|
|
17
|
+
},
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"author": "Brandon Keepers <brandon@openwaters.io>",
|
|
20
|
+
"type": "module",
|
|
21
|
+
"main": "src/index.ts",
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsdown",
|
|
24
|
+
"prepack": "npm run build"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist"
|
|
28
|
+
],
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@neaps/tide-predictor": "^0.2.0",
|
|
31
|
+
"@neaps/tide-database": "^0.0",
|
|
32
|
+
"geolib": "^3.3.4"
|
|
33
|
+
}
|
|
34
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { getDistance } from 'geolib'
|
|
2
|
+
import stations, { type Station } from '@neaps/tide-database'
|
|
3
|
+
import tidePredictor, {
|
|
4
|
+
type TimeSpan,
|
|
5
|
+
type ExtremesInput
|
|
6
|
+
} from '@neaps/tide-predictor'
|
|
7
|
+
import type { GeolibInputCoordinates } from 'geolib/es/types'
|
|
8
|
+
|
|
9
|
+
type DatumOption = {
|
|
10
|
+
/** Datum to return predictions in. Defaults to 'MLLW' if available for the nearest station. */
|
|
11
|
+
datum?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type ExtremesOptions = ExtremesInput & DatumOption
|
|
15
|
+
export type TimelineOptions = TimeSpan & DatumOption
|
|
16
|
+
export type WaterLevelOptions = { time: Date } & DatumOption
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Get extremes prediction using the nearest station to the given position.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* import { getExtremesPrediction } from 'neaps'
|
|
24
|
+
*
|
|
25
|
+
* const prediction = getExtremesPrediction({
|
|
26
|
+
* latitude: 26.7, // or `lat`
|
|
27
|
+
* longitude: -80.05, // or `lng` or `lon`
|
|
28
|
+
* start: new Date('2025-12-17'),
|
|
29
|
+
* end: new Date('2025-12-18'),
|
|
30
|
+
* datum: 'MLLW', // optional, defaults to MLLW if available
|
|
31
|
+
* })
|
|
32
|
+
*/
|
|
33
|
+
export function getExtremesPrediction(
|
|
34
|
+
options: GeolibInputCoordinates & ExtremesOptions
|
|
35
|
+
) {
|
|
36
|
+
return nearestStation(options).getExtremesPrediction(options)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get timeline prediction using the nearest station to the given position.
|
|
41
|
+
*/
|
|
42
|
+
export function getTimelinePrediction(
|
|
43
|
+
options: GeolibInputCoordinates & TimelineOptions
|
|
44
|
+
) {
|
|
45
|
+
return nearestStation(options).getTimelinePrediction(options)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get water level at a specific time using the nearest station to the given position.
|
|
50
|
+
*/
|
|
51
|
+
export function getWaterLevelAtTime(
|
|
52
|
+
options: GeolibInputCoordinates & WaterLevelOptions
|
|
53
|
+
) {
|
|
54
|
+
return nearestStation(options).getWaterLevelAtTime(options)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Find the nearest station to the given position.
|
|
59
|
+
*/
|
|
60
|
+
export function nearestStation(position: GeolibInputCoordinates) {
|
|
61
|
+
return stationsNear(position, 1)[0]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Find stations near the given position.
|
|
66
|
+
* @param limit Maximum number of stations to return (default: 10)
|
|
67
|
+
*/
|
|
68
|
+
export function stationsNear(position: GeolibInputCoordinates, limit = 10) {
|
|
69
|
+
return stations
|
|
70
|
+
.map((station) => ({ station, distance: getDistance(position, station) }))
|
|
71
|
+
.sort((a, b) => a.distance - b.distance)
|
|
72
|
+
.slice(0, limit)
|
|
73
|
+
.map(({ station, distance }) => useStation(station, distance))
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Find a specific station by its ID or source ID.
|
|
78
|
+
*/
|
|
79
|
+
export function findStation(query: string) {
|
|
80
|
+
const searches = [
|
|
81
|
+
(s: Station) => s.id === query,
|
|
82
|
+
(s: Station) => s.source.id === query
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
let found: Station | undefined = undefined
|
|
86
|
+
|
|
87
|
+
for (const search of searches) {
|
|
88
|
+
found = stations.find(search)
|
|
89
|
+
if (found) break
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (!found) throw new Error(`Station not found: ${query}`)
|
|
93
|
+
|
|
94
|
+
return useStation(found)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function useStation(station: Station, distance?: number) {
|
|
98
|
+
// If subordinate station, use the reference station for datums and constituents
|
|
99
|
+
let reference = station
|
|
100
|
+
if (station.type === 'subordinate') {
|
|
101
|
+
reference = findStation(station.offsets?.reference || '')
|
|
102
|
+
}
|
|
103
|
+
const { datums, harmonic_constituents } = reference
|
|
104
|
+
|
|
105
|
+
// Use MLLW as the default datum if available
|
|
106
|
+
const defaultDatum = 'MLLW' in datums ? 'MLLW' : undefined
|
|
107
|
+
|
|
108
|
+
function getPredictor({ datum = defaultDatum }: DatumOption = {}) {
|
|
109
|
+
let offset = 0
|
|
110
|
+
|
|
111
|
+
if (datum) {
|
|
112
|
+
const datumOffset = datums?.[datum]
|
|
113
|
+
const mslOffset = datums?.['MSL']
|
|
114
|
+
|
|
115
|
+
if (typeof datumOffset !== 'number') {
|
|
116
|
+
throw new Error(
|
|
117
|
+
`Station ${station.id} missing ${datum} datum. Available datums: ${Object.keys(datums || {}).join(', ')}`
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (typeof mslOffset !== 'number') {
|
|
122
|
+
throw new Error(
|
|
123
|
+
`Station ${station.id} missing MSL datum, so predictions can't be given in ${datum}.`
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
offset = mslOffset - datumOffset
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return tidePredictor(harmonic_constituents, {
|
|
131
|
+
phaseKey: 'phase_UTC',
|
|
132
|
+
offset
|
|
133
|
+
})
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
...station,
|
|
138
|
+
distance,
|
|
139
|
+
datums,
|
|
140
|
+
harmonic_constituents,
|
|
141
|
+
defaultDatum,
|
|
142
|
+
getExtremesPrediction({ datum = defaultDatum, ...input }: ExtremesOptions) {
|
|
143
|
+
return {
|
|
144
|
+
datum,
|
|
145
|
+
distance,
|
|
146
|
+
station,
|
|
147
|
+
extremes: getPredictor({ datum }).getExtremesPrediction({
|
|
148
|
+
...input,
|
|
149
|
+
offsets: station.offsets
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
getTimelinePrediction({
|
|
155
|
+
datum = defaultDatum,
|
|
156
|
+
...params
|
|
157
|
+
}: TimelineOptions) {
|
|
158
|
+
if (station.type === 'subordinate') {
|
|
159
|
+
throw new Error(
|
|
160
|
+
`Timeline predictions are not supported for subordinate stations.`
|
|
161
|
+
)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
datum,
|
|
166
|
+
station,
|
|
167
|
+
timeline: getPredictor({ datum }).getTimelinePrediction(params)
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
getWaterLevelAtTime({ time, datum = defaultDatum }: WaterLevelOptions) {
|
|
172
|
+
if (station.type === 'subordinate') {
|
|
173
|
+
throw new Error(
|
|
174
|
+
`Water level predictions are not supported for subordinate stations.`
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
datum,
|
|
180
|
+
station,
|
|
181
|
+
...getPredictor({ datum }).getWaterLevelAtTime({ time })
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|