neaps 0.2.0 → 0.3.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 CHANGED
@@ -25,7 +25,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
25
25
  }) : target, mod));
26
26
 
27
27
  //#endregion
28
- let geolib = require("geolib");
29
28
  let _neaps_tide_database = require("@neaps/tide-database");
30
29
  let _neaps_tide_predictor = require("@neaps/tide-predictor");
31
30
  _neaps_tide_predictor = __toESM(_neaps_tide_predictor);
@@ -66,18 +65,17 @@ function getWaterLevelAtTime(options) {
66
65
  /**
67
66
  * Find the nearest station to the given position.
68
67
  */
69
- function nearestStation(position) {
70
- return stationsNear(position, 1)[0];
68
+ function nearestStation(options) {
69
+ const data = (0, _neaps_tide_database.nearest)(options);
70
+ if (!data) throw new Error(`No stations found with options: ${JSON.stringify(options)}`);
71
+ return useStation(...data);
71
72
  }
72
73
  /**
73
74
  * Find stations near the given position.
74
75
  * @param limit Maximum number of stations to return (default: 10)
75
76
  */
76
- function stationsNear(position, limit = 10) {
77
- return _neaps_tide_database.stations.map((station) => ({
78
- station,
79
- distance: (0, geolib.getDistance)(position, station)
80
- })).sort((a, b) => a.distance - b.distance).slice(0, limit).map(({ station, distance }) => useStation(station, distance));
77
+ function stationsNear(options) {
78
+ return (0, _neaps_tide_database.near)(options).map(([station, distance]) => useStation(station, distance));
81
79
  }
82
80
  /**
83
81
  * Find a specific station by its ID or source ID.
@@ -94,7 +92,7 @@ function findStation(query) {
94
92
  }
95
93
  function useStation(station, distance) {
96
94
  let reference = station;
97
- if (station.type === "subordinate") reference = findStation(station.offsets?.reference || "");
95
+ if (station.type === "subordinate" && station.offsets?.reference) reference = findStation(station.offsets?.reference);
98
96
  const { datums, harmonic_constituents } = reference;
99
97
  const defaultDatum = "MLLW" in datums ? "MLLW" : void 0;
100
98
  function getPredictor({ datum = defaultDatum } = {}) {
@@ -102,7 +100,7 @@ function useStation(station, distance) {
102
100
  if (datum) {
103
101
  const datumOffset = datums?.[datum];
104
102
  const mslOffset = datums?.["MSL"];
105
- if (typeof datumOffset !== "number") throw new Error(`Station ${station.id} missing ${datum} datum. Available datums: ${Object.keys(datums || {}).join(", ")}`);
103
+ if (typeof datumOffset !== "number") throw new Error(`Station ${station.id} missing ${datum} datum. Available datums: ${Object.keys(datums).join(", ")}`);
106
104
  if (typeof mslOffset !== "number") throw new Error(`Station ${station.id} missing MSL datum, so predictions can't be given in ${datum}.`);
107
105
  offset = mslOffset - datumOffset;
108
106
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["defaultUnits: Units","stations","found: Station | undefined"],"sources":["../src/index.ts"],"sourcesContent":["import { getDistance } from \"geolib\";\nimport { stations, type Station } from \"@neaps/tide-database\";\nimport tidePredictor, { type TimeSpan, type ExtremesInput } from \"@neaps/tide-predictor\";\nimport type { GeolibInputCoordinates } from \"geolib/es/types\";\n\ntype Units = \"meters\" | \"feet\";\ntype PredictionOptions = {\n /** Datum to return predictions in. Defaults to 'MLLW' if available for the nearest station. */\n datum?: string;\n\n /** Units for returned water levels. Defaults to 'meters'. */\n units?: Units;\n};\n\nexport type ExtremesOptions = ExtremesInput & PredictionOptions;\nexport type TimelineOptions = TimeSpan & PredictionOptions;\nexport type WaterLevelOptions = { time: Date } & PredictionOptions;\n\nconst feetPerMeter = 3.2808399;\nconst defaultUnits: Units = \"meters\";\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(options: GeolibInputCoordinates & ExtremesOptions) {\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(options: GeolibInputCoordinates & TimelineOptions) {\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(options: GeolibInputCoordinates & WaterLevelOptions) {\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 = [(s: Station) => s.id === query, (s: Station) => s.source.id === query];\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 }: PredictionOptions = {}) {\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, { offset });\n }\n\n return {\n ...station,\n distance,\n datums,\n harmonic_constituents,\n defaultDatum,\n getExtremesPrediction({\n datum = defaultDatum,\n units = defaultUnits,\n ...options\n }: ExtremesOptions) {\n const extremes = getPredictor({ datum })\n .getExtremesPrediction({ ...options, offsets: station.offsets })\n .map((e) => toPreferredUnits(e, units));\n\n return { datum, units, station, distance, extremes };\n },\n\n getTimelinePrediction({\n datum = defaultDatum,\n units = defaultUnits,\n ...options\n }: TimelineOptions) {\n if (station.type === \"subordinate\") {\n throw new Error(`Timeline predictions are not supported for subordinate stations.`);\n }\n const timeline = getPredictor({ datum })\n .getTimelinePrediction(options)\n .map((e) => toPreferredUnits(e, units));\n\n return { datum, units, station, distance, timeline };\n },\n\n getWaterLevelAtTime({ time, datum = defaultDatum, units = defaultUnits }: WaterLevelOptions) {\n if (station.type === \"subordinate\") {\n throw new Error(`Water level predictions are not supported for subordinate stations.`);\n }\n\n const prediction = toPreferredUnits(\n getPredictor({ datum }).getWaterLevelAtTime({ time }),\n units,\n );\n\n return { datum, units, station, distance, ...prediction };\n },\n };\n}\n\nfunction toPreferredUnits<T extends { level: number }>(prediction: T, units: Units): T {\n let { level } = prediction;\n if (units === \"feet\") level *= feetPerMeter;\n else if (units !== \"meters\") throw new Error(`Unsupported units: ${units}`);\n return { ...prediction, level };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["stations"],"sources":["../src/index.ts"],"sourcesContent":["import {\n stations,\n near,\n nearest,\n type Station,\n type NearOptions,\n type NearestOptions,\n} from \"@neaps/tide-database\";\nimport tidePredictor, { type TimeSpan, type ExtremesInput } from \"@neaps/tide-predictor\";\n\ntype Units = \"meters\" | \"feet\";\ntype PredictionOptions = {\n /** Datum to return predictions in. Defaults to 'MLLW' if available for the nearest station. */\n datum?: string;\n\n /** Units for returned water levels. Defaults to 'meters'. */\n units?: Units;\n};\n\nexport type ExtremesOptions = ExtremesInput & PredictionOptions;\nexport type TimelineOptions = TimeSpan & PredictionOptions;\nexport type WaterLevelOptions = { time: Date } & PredictionOptions;\n\nconst feetPerMeter = 3.2808399;\nconst defaultUnits: Units = \"meters\";\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(options: NearestOptions & ExtremesOptions) {\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(options: NearestOptions & TimelineOptions) {\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(options: NearestOptions & WaterLevelOptions) {\n return nearestStation(options).getWaterLevelAtTime(options);\n}\n\n/**\n * Find the nearest station to the given position.\n */\nexport function nearestStation(options: NearestOptions) {\n const data = nearest(options);\n if (!data) throw new Error(`No stations found with options: ${JSON.stringify(options)}`);\n return useStation(...data);\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(options: NearOptions) {\n return near(options).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 = [(s: Station) => s.id === query, (s: Station) => s.source.id === query];\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\" && station.offsets?.reference) {\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 }: PredictionOptions = {}) {\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, { offset });\n }\n\n return {\n ...station,\n distance,\n datums,\n harmonic_constituents,\n defaultDatum,\n getExtremesPrediction({\n datum = defaultDatum,\n units = defaultUnits,\n ...options\n }: ExtremesOptions) {\n const extremes = getPredictor({ datum })\n .getExtremesPrediction({ ...options, offsets: station.offsets })\n .map((e) => toPreferredUnits(e, units));\n\n return { datum, units, station, distance, extremes };\n },\n\n getTimelinePrediction({\n datum = defaultDatum,\n units = defaultUnits,\n ...options\n }: TimelineOptions) {\n if (station.type === \"subordinate\") {\n throw new Error(`Timeline predictions are not supported for subordinate stations.`);\n }\n const timeline = getPredictor({ datum })\n .getTimelinePrediction(options)\n .map((e) => toPreferredUnits(e, units));\n\n return { datum, units, station, distance, timeline };\n },\n\n getWaterLevelAtTime({ time, datum = defaultDatum, units = defaultUnits }: WaterLevelOptions) {\n if (station.type === \"subordinate\") {\n throw new Error(`Water level predictions are not supported for subordinate stations.`);\n }\n\n const prediction = toPreferredUnits(\n getPredictor({ datum }).getWaterLevelAtTime({ time }),\n units,\n );\n\n return { datum, units, station, distance, ...prediction };\n },\n };\n}\n\nfunction toPreferredUnits<T extends { level: number }>(prediction: T, units: Units): T {\n let { level } = prediction;\n if (units === \"feet\") level *= feetPerMeter;\n else if (units !== \"meters\") throw new Error(`Unsupported units: ${units}`);\n return { ...prediction, level };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuBA,MAAM,eAAe;AACrB,MAAM,eAAsB;;;;;;;;;;;;;;;;AAiB5B,SAAgB,sBAAsB,SAA2C;AAC/E,QAAO,eAAe,QAAQ,CAAC,sBAAsB,QAAQ;;;;;AAM/D,SAAgB,sBAAsB,SAA2C;AAC/E,QAAO,eAAe,QAAQ,CAAC,sBAAsB,QAAQ;;;;;AAM/D,SAAgB,oBAAoB,SAA6C;AAC/E,QAAO,eAAe,QAAQ,CAAC,oBAAoB,QAAQ;;;;;AAM7D,SAAgB,eAAe,SAAyB;CACtD,MAAM,yCAAe,QAAQ;AAC7B,KAAI,CAAC,KAAM,OAAM,IAAI,MAAM,mCAAmC,KAAK,UAAU,QAAQ,GAAG;AACxF,QAAO,WAAW,GAAG,KAAK;;;;;;AAO5B,SAAgB,aAAa,SAAsB;AACjD,uCAAY,QAAQ,CAAC,KAAK,CAAC,SAAS,cAAc,WAAW,SAAS,SAAS,CAAC;;;;;AAMlF,SAAgB,YAAY,OAAe;CACzC,MAAM,WAAW,EAAE,MAAe,EAAE,OAAO,QAAQ,MAAe,EAAE,OAAO,OAAO,MAAM;CAExF,IAAI,QAA6B;AAEjC,MAAK,MAAM,UAAU,UAAU;AAC7B,UAAQA,8BAAS,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,iBAAiB,QAAQ,SAAS,UACrD,aAAY,YAAY,QAAQ,SAAS,UAAU;CAErD,MAAM,EAAE,QAAQ,0BAA0B;CAG1C,MAAM,eAAe,UAAU,SAAS,SAAS;CAEjD,SAAS,aAAa,EAAE,QAAQ,iBAAoC,EAAE,EAAE;EACtE,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,OAAO,CAAC,KAAK,KAAK,GAClG;AAGH,OAAI,OAAO,cAAc,SACvB,OAAM,IAAI,MACR,WAAW,QAAQ,GAAG,uDAAuD,MAAM,GACpF;AAGH,YAAS,YAAY;;AAGvB,4CAAqB,uBAAuB,EAAE,QAAQ,CAAC;;AAGzD,QAAO;EACL,GAAG;EACH;EACA;EACA;EACA;EACA,sBAAsB,EACpB,QAAQ,cACR,QAAQ,cACR,GAAG,WACe;AAKlB,UAAO;IAAE;IAAO;IAAO;IAAS;IAAU,UAJzB,aAAa,EAAE,OAAO,CAAC,CACrC,sBAAsB;KAAE,GAAG;KAAS,SAAS,QAAQ;KAAS,CAAC,CAC/D,KAAK,MAAM,iBAAiB,GAAG,MAAM,CAAC;IAEW;;EAGtD,sBAAsB,EACpB,QAAQ,cACR,QAAQ,cACR,GAAG,WACe;AAClB,OAAI,QAAQ,SAAS,cACnB,OAAM,IAAI,MAAM,mEAAmE;AAMrF,UAAO;IAAE;IAAO;IAAO;IAAS;IAAU,UAJzB,aAAa,EAAE,OAAO,CAAC,CACrC,sBAAsB,QAAQ,CAC9B,KAAK,MAAM,iBAAiB,GAAG,MAAM,CAAC;IAEW;;EAGtD,oBAAoB,EAAE,MAAM,QAAQ,cAAc,QAAQ,gBAAmC;AAC3F,OAAI,QAAQ,SAAS,cACnB,OAAM,IAAI,MAAM,sEAAsE;AAQxF,UAAO;IAAE;IAAO;IAAO;IAAS;IAAU,GALvB,iBACjB,aAAa,EAAE,OAAO,CAAC,CAAC,oBAAoB,EAAE,MAAM,CAAC,EACrD,MACD;IAEwD;;EAE5D;;AAGH,SAAS,iBAA8C,YAAe,OAAiB;CACrF,IAAI,EAAE,UAAU;AAChB,KAAI,UAAU,OAAQ,UAAS;UACtB,UAAU,SAAU,OAAM,IAAI,MAAM,sBAAsB,QAAQ;AAC3E,QAAO;EAAE,GAAG;EAAY;EAAO"}
package/dist/index.d.cts CHANGED
@@ -1,15 +1,11 @@
1
- import * as _neaps_tide_predictor0 from "@neaps/tide-predictor";
2
- import { ExtremesInput, TimeSpan } from "@neaps/tide-predictor";
3
1
  import * as _neaps_tide_database0 from "@neaps/tide-database";
4
- import { Station } from "@neaps/tide-database";
5
- import { GeolibInputCoordinates } from "geolib/es/types";
2
+ import { NearOptions, NearestOptions, Station } from "@neaps/tide-database";
3
+ import { ExtremesInput, TimeSpan } from "@neaps/tide-predictor";
6
4
 
7
5
  //#region src/index.d.ts
8
6
  type Units = "meters" | "feet";
9
7
  type PredictionOptions = {
10
- /** Datum to return predictions in. Defaults to 'MLLW' if available for the nearest station. */
11
- datum?: string;
12
- /** Units for returned water levels. Defaults to 'meters'. */
8
+ /** Datum to return predictions in. Defaults to 'MLLW' if available for the nearest station. */datum?: string; /** Units for returned water levels. Defaults to 'meters'. */
13
9
  units?: Units;
14
10
  };
15
11
  type ExtremesOptions = ExtremesInput & PredictionOptions;
@@ -32,39 +28,31 @@ type WaterLevelOptions = {
32
28
  * datum: 'MLLW', // optional, defaults to MLLW if available
33
29
  * })
34
30
  */
35
- declare function getExtremesPrediction(options: GeolibInputCoordinates & ExtremesOptions): {
36
- datum: string | undefined;
37
- units: Units;
31
+ declare function getExtremesPrediction(options: NearestOptions & ExtremesOptions): {
32
+ datum: any;
33
+ units: any;
38
34
  station: Station;
39
35
  distance: number | undefined;
40
- extremes: _neaps_tide_predictor0.Extreme[];
36
+ extremes: any;
41
37
  };
42
38
  /**
43
39
  * Get timeline prediction using the nearest station to the given position.
44
40
  */
45
- declare function getTimelinePrediction(options: GeolibInputCoordinates & TimelineOptions): {
46
- datum: string | undefined;
47
- units: Units;
41
+ declare function getTimelinePrediction(options: NearestOptions & TimelineOptions): {
42
+ datum: any;
43
+ units: any;
48
44
  station: Station;
49
45
  distance: number | undefined;
50
- timeline: _neaps_tide_predictor0.TimelinePoint[];
46
+ timeline: any;
51
47
  };
52
48
  /**
53
49
  * Get water level at a specific time using the nearest station to the given position.
54
50
  */
55
- declare function getWaterLevelAtTime(options: GeolibInputCoordinates & WaterLevelOptions): {
56
- time: Date;
57
- hour: number;
58
- level: number;
59
- datum: string | undefined;
60
- units: Units;
61
- station: Station;
62
- distance: number | undefined;
63
- };
51
+ declare function getWaterLevelAtTime(options: NearestOptions & WaterLevelOptions): any;
64
52
  /**
65
53
  * Find the nearest station to the given position.
66
54
  */
67
- declare function nearestStation(position: GeolibInputCoordinates): {
55
+ declare function nearestStation(options: NearestOptions): {
68
56
  distance: number | undefined;
69
57
  datums: Record<string, number>;
70
58
  harmonic_constituents: _neaps_tide_database0.HarmonicConstituent[];
@@ -74,36 +62,28 @@ declare function nearestStation(position: GeolibInputCoordinates): {
74
62
  units,
75
63
  ...options
76
64
  }: ExtremesOptions): {
77
- datum: string | undefined;
78
- units: Units;
65
+ datum: any;
66
+ units: any;
79
67
  station: Station;
80
68
  distance: number | undefined;
81
- extremes: _neaps_tide_predictor0.Extreme[];
69
+ extremes: any;
82
70
  };
83
71
  getTimelinePrediction({
84
72
  datum,
85
73
  units,
86
74
  ...options
87
75
  }: TimelineOptions): {
88
- datum: string | undefined;
89
- units: Units;
76
+ datum: any;
77
+ units: any;
90
78
  station: Station;
91
79
  distance: number | undefined;
92
- timeline: _neaps_tide_predictor0.TimelinePoint[];
80
+ timeline: any;
93
81
  };
94
82
  getWaterLevelAtTime({
95
83
  time,
96
84
  datum,
97
85
  units
98
- }: WaterLevelOptions): {
99
- time: Date;
100
- hour: number;
101
- level: number;
102
- datum: string | undefined;
103
- units: Units;
104
- station: Station;
105
- distance: number | undefined;
106
- };
86
+ }: WaterLevelOptions): any;
107
87
  id: string;
108
88
  name: string;
109
89
  continent: string;
@@ -143,7 +123,7 @@ declare function nearestStation(position: GeolibInputCoordinates): {
143
123
  * Find stations near the given position.
144
124
  * @param limit Maximum number of stations to return (default: 10)
145
125
  */
146
- declare function stationsNear(position: GeolibInputCoordinates, limit?: number): {
126
+ declare function stationsNear(options: NearOptions): {
147
127
  distance: number | undefined;
148
128
  datums: Record<string, number>;
149
129
  harmonic_constituents: _neaps_tide_database0.HarmonicConstituent[];
@@ -153,36 +133,28 @@ declare function stationsNear(position: GeolibInputCoordinates, limit?: number):
153
133
  units,
154
134
  ...options
155
135
  }: ExtremesOptions): {
156
- datum: string | undefined;
157
- units: Units;
136
+ datum: any;
137
+ units: any;
158
138
  station: Station;
159
139
  distance: number | undefined;
160
- extremes: _neaps_tide_predictor0.Extreme[];
140
+ extremes: any;
161
141
  };
162
142
  getTimelinePrediction({
163
143
  datum,
164
144
  units,
165
145
  ...options
166
146
  }: TimelineOptions): {
167
- datum: string | undefined;
168
- units: Units;
147
+ datum: any;
148
+ units: any;
169
149
  station: Station;
170
150
  distance: number | undefined;
171
- timeline: _neaps_tide_predictor0.TimelinePoint[];
151
+ timeline: any;
172
152
  };
173
153
  getWaterLevelAtTime({
174
154
  time,
175
155
  datum,
176
156
  units
177
- }: WaterLevelOptions): {
178
- time: Date;
179
- hour: number;
180
- level: number;
181
- datum: string | undefined;
182
- units: Units;
183
- station: Station;
184
- distance: number | undefined;
185
- };
157
+ }: WaterLevelOptions): any;
186
158
  id: string;
187
159
  name: string;
188
160
  continent: string;
@@ -231,36 +203,28 @@ declare function findStation(query: string): {
231
203
  units,
232
204
  ...options
233
205
  }: ExtremesOptions): {
234
- datum: string | undefined;
235
- units: Units;
206
+ datum: any;
207
+ units: any;
236
208
  station: Station;
237
209
  distance: number | undefined;
238
- extremes: _neaps_tide_predictor0.Extreme[];
210
+ extremes: any;
239
211
  };
240
212
  getTimelinePrediction({
241
213
  datum,
242
214
  units,
243
215
  ...options
244
216
  }: TimelineOptions): {
245
- datum: string | undefined;
246
- units: Units;
217
+ datum: any;
218
+ units: any;
247
219
  station: Station;
248
220
  distance: number | undefined;
249
- timeline: _neaps_tide_predictor0.TimelinePoint[];
221
+ timeline: any;
250
222
  };
251
223
  getWaterLevelAtTime({
252
224
  time,
253
225
  datum,
254
226
  units
255
- }: WaterLevelOptions): {
256
- time: Date;
257
- hour: number;
258
- level: number;
259
- datum: string | undefined;
260
- units: Units;
261
- station: Station;
262
- distance: number | undefined;
263
- };
227
+ }: WaterLevelOptions): any;
264
228
  id: string;
265
229
  name: string;
266
230
  continent: string;
@@ -306,36 +270,28 @@ declare function useStation(station: Station, distance?: number): {
306
270
  units,
307
271
  ...options
308
272
  }: ExtremesOptions): {
309
- datum: string | undefined;
310
- units: Units;
273
+ datum: any;
274
+ units: any;
311
275
  station: Station;
312
276
  distance: number | undefined;
313
- extremes: _neaps_tide_predictor0.Extreme[];
277
+ extremes: any;
314
278
  };
315
279
  getTimelinePrediction({
316
280
  datum,
317
281
  units,
318
282
  ...options
319
283
  }: TimelineOptions): {
320
- datum: string | undefined;
321
- units: Units;
284
+ datum: any;
285
+ units: any;
322
286
  station: Station;
323
287
  distance: number | undefined;
324
- timeline: _neaps_tide_predictor0.TimelinePoint[];
288
+ timeline: any;
325
289
  };
326
290
  getWaterLevelAtTime({
327
291
  time,
328
292
  datum,
329
293
  units
330
- }: WaterLevelOptions): {
331
- time: Date;
332
- hour: number;
333
- level: number;
334
- datum: string | undefined;
335
- units: Units;
336
- station: Station;
337
- distance: number | undefined;
338
- };
294
+ }: WaterLevelOptions): any;
339
295
  id: string;
340
296
  name: string;
341
297
  continent: string;
package/dist/index.d.ts CHANGED
@@ -1,15 +1,11 @@
1
1
  import * as _neaps_tide_database0 from "@neaps/tide-database";
2
- import { Station } from "@neaps/tide-database";
3
- import * as _neaps_tide_predictor0 from "@neaps/tide-predictor";
2
+ import { NearOptions, NearestOptions, Station } from "@neaps/tide-database";
4
3
  import { ExtremesInput, TimeSpan } from "@neaps/tide-predictor";
5
- import { GeolibInputCoordinates } from "geolib/es/types";
6
4
 
7
5
  //#region src/index.d.ts
8
6
  type Units = "meters" | "feet";
9
7
  type PredictionOptions = {
10
- /** Datum to return predictions in. Defaults to 'MLLW' if available for the nearest station. */
11
- datum?: string;
12
- /** Units for returned water levels. Defaults to 'meters'. */
8
+ /** Datum to return predictions in. Defaults to 'MLLW' if available for the nearest station. */datum?: string; /** Units for returned water levels. Defaults to 'meters'. */
13
9
  units?: Units;
14
10
  };
15
11
  type ExtremesOptions = ExtremesInput & PredictionOptions;
@@ -32,39 +28,31 @@ type WaterLevelOptions = {
32
28
  * datum: 'MLLW', // optional, defaults to MLLW if available
33
29
  * })
34
30
  */
35
- declare function getExtremesPrediction(options: GeolibInputCoordinates & ExtremesOptions): {
36
- datum: string | undefined;
37
- units: Units;
31
+ declare function getExtremesPrediction(options: NearestOptions & ExtremesOptions): {
32
+ datum: any;
33
+ units: any;
38
34
  station: Station;
39
35
  distance: number | undefined;
40
- extremes: _neaps_tide_predictor0.Extreme[];
36
+ extremes: any;
41
37
  };
42
38
  /**
43
39
  * Get timeline prediction using the nearest station to the given position.
44
40
  */
45
- declare function getTimelinePrediction(options: GeolibInputCoordinates & TimelineOptions): {
46
- datum: string | undefined;
47
- units: Units;
41
+ declare function getTimelinePrediction(options: NearestOptions & TimelineOptions): {
42
+ datum: any;
43
+ units: any;
48
44
  station: Station;
49
45
  distance: number | undefined;
50
- timeline: _neaps_tide_predictor0.TimelinePoint[];
46
+ timeline: any;
51
47
  };
52
48
  /**
53
49
  * Get water level at a specific time using the nearest station to the given position.
54
50
  */
55
- declare function getWaterLevelAtTime(options: GeolibInputCoordinates & WaterLevelOptions): {
56
- time: Date;
57
- hour: number;
58
- level: number;
59
- datum: string | undefined;
60
- units: Units;
61
- station: Station;
62
- distance: number | undefined;
63
- };
51
+ declare function getWaterLevelAtTime(options: NearestOptions & WaterLevelOptions): any;
64
52
  /**
65
53
  * Find the nearest station to the given position.
66
54
  */
67
- declare function nearestStation(position: GeolibInputCoordinates): {
55
+ declare function nearestStation(options: NearestOptions): {
68
56
  distance: number | undefined;
69
57
  datums: Record<string, number>;
70
58
  harmonic_constituents: _neaps_tide_database0.HarmonicConstituent[];
@@ -74,36 +62,28 @@ declare function nearestStation(position: GeolibInputCoordinates): {
74
62
  units,
75
63
  ...options
76
64
  }: ExtremesOptions): {
77
- datum: string | undefined;
78
- units: Units;
65
+ datum: any;
66
+ units: any;
79
67
  station: Station;
80
68
  distance: number | undefined;
81
- extremes: _neaps_tide_predictor0.Extreme[];
69
+ extremes: any;
82
70
  };
83
71
  getTimelinePrediction({
84
72
  datum,
85
73
  units,
86
74
  ...options
87
75
  }: TimelineOptions): {
88
- datum: string | undefined;
89
- units: Units;
76
+ datum: any;
77
+ units: any;
90
78
  station: Station;
91
79
  distance: number | undefined;
92
- timeline: _neaps_tide_predictor0.TimelinePoint[];
80
+ timeline: any;
93
81
  };
94
82
  getWaterLevelAtTime({
95
83
  time,
96
84
  datum,
97
85
  units
98
- }: WaterLevelOptions): {
99
- time: Date;
100
- hour: number;
101
- level: number;
102
- datum: string | undefined;
103
- units: Units;
104
- station: Station;
105
- distance: number | undefined;
106
- };
86
+ }: WaterLevelOptions): any;
107
87
  id: string;
108
88
  name: string;
109
89
  continent: string;
@@ -143,7 +123,7 @@ declare function nearestStation(position: GeolibInputCoordinates): {
143
123
  * Find stations near the given position.
144
124
  * @param limit Maximum number of stations to return (default: 10)
145
125
  */
146
- declare function stationsNear(position: GeolibInputCoordinates, limit?: number): {
126
+ declare function stationsNear(options: NearOptions): {
147
127
  distance: number | undefined;
148
128
  datums: Record<string, number>;
149
129
  harmonic_constituents: _neaps_tide_database0.HarmonicConstituent[];
@@ -153,36 +133,28 @@ declare function stationsNear(position: GeolibInputCoordinates, limit?: number):
153
133
  units,
154
134
  ...options
155
135
  }: ExtremesOptions): {
156
- datum: string | undefined;
157
- units: Units;
136
+ datum: any;
137
+ units: any;
158
138
  station: Station;
159
139
  distance: number | undefined;
160
- extremes: _neaps_tide_predictor0.Extreme[];
140
+ extremes: any;
161
141
  };
162
142
  getTimelinePrediction({
163
143
  datum,
164
144
  units,
165
145
  ...options
166
146
  }: TimelineOptions): {
167
- datum: string | undefined;
168
- units: Units;
147
+ datum: any;
148
+ units: any;
169
149
  station: Station;
170
150
  distance: number | undefined;
171
- timeline: _neaps_tide_predictor0.TimelinePoint[];
151
+ timeline: any;
172
152
  };
173
153
  getWaterLevelAtTime({
174
154
  time,
175
155
  datum,
176
156
  units
177
- }: WaterLevelOptions): {
178
- time: Date;
179
- hour: number;
180
- level: number;
181
- datum: string | undefined;
182
- units: Units;
183
- station: Station;
184
- distance: number | undefined;
185
- };
157
+ }: WaterLevelOptions): any;
186
158
  id: string;
187
159
  name: string;
188
160
  continent: string;
@@ -231,36 +203,28 @@ declare function findStation(query: string): {
231
203
  units,
232
204
  ...options
233
205
  }: ExtremesOptions): {
234
- datum: string | undefined;
235
- units: Units;
206
+ datum: any;
207
+ units: any;
236
208
  station: Station;
237
209
  distance: number | undefined;
238
- extremes: _neaps_tide_predictor0.Extreme[];
210
+ extremes: any;
239
211
  };
240
212
  getTimelinePrediction({
241
213
  datum,
242
214
  units,
243
215
  ...options
244
216
  }: TimelineOptions): {
245
- datum: string | undefined;
246
- units: Units;
217
+ datum: any;
218
+ units: any;
247
219
  station: Station;
248
220
  distance: number | undefined;
249
- timeline: _neaps_tide_predictor0.TimelinePoint[];
221
+ timeline: any;
250
222
  };
251
223
  getWaterLevelAtTime({
252
224
  time,
253
225
  datum,
254
226
  units
255
- }: WaterLevelOptions): {
256
- time: Date;
257
- hour: number;
258
- level: number;
259
- datum: string | undefined;
260
- units: Units;
261
- station: Station;
262
- distance: number | undefined;
263
- };
227
+ }: WaterLevelOptions): any;
264
228
  id: string;
265
229
  name: string;
266
230
  continent: string;
@@ -306,36 +270,28 @@ declare function useStation(station: Station, distance?: number): {
306
270
  units,
307
271
  ...options
308
272
  }: ExtremesOptions): {
309
- datum: string | undefined;
310
- units: Units;
273
+ datum: any;
274
+ units: any;
311
275
  station: Station;
312
276
  distance: number | undefined;
313
- extremes: _neaps_tide_predictor0.Extreme[];
277
+ extremes: any;
314
278
  };
315
279
  getTimelinePrediction({
316
280
  datum,
317
281
  units,
318
282
  ...options
319
283
  }: TimelineOptions): {
320
- datum: string | undefined;
321
- units: Units;
284
+ datum: any;
285
+ units: any;
322
286
  station: Station;
323
287
  distance: number | undefined;
324
- timeline: _neaps_tide_predictor0.TimelinePoint[];
288
+ timeline: any;
325
289
  };
326
290
  getWaterLevelAtTime({
327
291
  time,
328
292
  datum,
329
293
  units
330
- }: WaterLevelOptions): {
331
- time: Date;
332
- hour: number;
333
- level: number;
334
- datum: string | undefined;
335
- units: Units;
336
- station: Station;
337
- distance: number | undefined;
338
- };
294
+ }: WaterLevelOptions): any;
339
295
  id: string;
340
296
  name: string;
341
297
  continent: string;
package/dist/index.js CHANGED
@@ -1,5 +1,4 @@
1
- import { getDistance } from "geolib";
2
- import { stations } from "@neaps/tide-database";
1
+ import { near, nearest, stations } from "@neaps/tide-database";
3
2
  import tidePredictor from "@neaps/tide-predictor";
4
3
 
5
4
  //#region src/index.ts
@@ -38,18 +37,17 @@ function getWaterLevelAtTime(options) {
38
37
  /**
39
38
  * Find the nearest station to the given position.
40
39
  */
41
- function nearestStation(position) {
42
- return stationsNear(position, 1)[0];
40
+ function nearestStation(options) {
41
+ const data = nearest(options);
42
+ if (!data) throw new Error(`No stations found with options: ${JSON.stringify(options)}`);
43
+ return useStation(...data);
43
44
  }
44
45
  /**
45
46
  * Find stations near the given position.
46
47
  * @param limit Maximum number of stations to return (default: 10)
47
48
  */
48
- function stationsNear(position, limit = 10) {
49
- return stations.map((station) => ({
50
- station,
51
- distance: getDistance(position, station)
52
- })).sort((a, b) => a.distance - b.distance).slice(0, limit).map(({ station, distance }) => useStation(station, distance));
49
+ function stationsNear(options) {
50
+ return near(options).map(([station, distance]) => useStation(station, distance));
53
51
  }
54
52
  /**
55
53
  * Find a specific station by its ID or source ID.
@@ -66,7 +64,7 @@ function findStation(query) {
66
64
  }
67
65
  function useStation(station, distance) {
68
66
  let reference = station;
69
- if (station.type === "subordinate") reference = findStation(station.offsets?.reference || "");
67
+ if (station.type === "subordinate" && station.offsets?.reference) reference = findStation(station.offsets?.reference);
70
68
  const { datums, harmonic_constituents } = reference;
71
69
  const defaultDatum = "MLLW" in datums ? "MLLW" : void 0;
72
70
  function getPredictor({ datum = defaultDatum } = {}) {
@@ -74,7 +72,7 @@ function useStation(station, distance) {
74
72
  if (datum) {
75
73
  const datumOffset = datums?.[datum];
76
74
  const mslOffset = datums?.["MSL"];
77
- if (typeof datumOffset !== "number") throw new Error(`Station ${station.id} missing ${datum} datum. Available datums: ${Object.keys(datums || {}).join(", ")}`);
75
+ if (typeof datumOffset !== "number") throw new Error(`Station ${station.id} missing ${datum} datum. Available datums: ${Object.keys(datums).join(", ")}`);
78
76
  if (typeof mslOffset !== "number") throw new Error(`Station ${station.id} missing MSL datum, so predictions can't be given in ${datum}.`);
79
77
  offset = mslOffset - datumOffset;
80
78
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["defaultUnits: Units","found: Station | undefined"],"sources":["../src/index.ts"],"sourcesContent":["import { getDistance } from \"geolib\";\nimport { stations, type Station } from \"@neaps/tide-database\";\nimport tidePredictor, { type TimeSpan, type ExtremesInput } from \"@neaps/tide-predictor\";\nimport type { GeolibInputCoordinates } from \"geolib/es/types\";\n\ntype Units = \"meters\" | \"feet\";\ntype PredictionOptions = {\n /** Datum to return predictions in. Defaults to 'MLLW' if available for the nearest station. */\n datum?: string;\n\n /** Units for returned water levels. Defaults to 'meters'. */\n units?: Units;\n};\n\nexport type ExtremesOptions = ExtremesInput & PredictionOptions;\nexport type TimelineOptions = TimeSpan & PredictionOptions;\nexport type WaterLevelOptions = { time: Date } & PredictionOptions;\n\nconst feetPerMeter = 3.2808399;\nconst defaultUnits: Units = \"meters\";\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(options: GeolibInputCoordinates & ExtremesOptions) {\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(options: GeolibInputCoordinates & TimelineOptions) {\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(options: GeolibInputCoordinates & WaterLevelOptions) {\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 = [(s: Station) => s.id === query, (s: Station) => s.source.id === query];\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 }: PredictionOptions = {}) {\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, { offset });\n }\n\n return {\n ...station,\n distance,\n datums,\n harmonic_constituents,\n defaultDatum,\n getExtremesPrediction({\n datum = defaultDatum,\n units = defaultUnits,\n ...options\n }: ExtremesOptions) {\n const extremes = getPredictor({ datum })\n .getExtremesPrediction({ ...options, offsets: station.offsets })\n .map((e) => toPreferredUnits(e, units));\n\n return { datum, units, station, distance, extremes };\n },\n\n getTimelinePrediction({\n datum = defaultDatum,\n units = defaultUnits,\n ...options\n }: TimelineOptions) {\n if (station.type === \"subordinate\") {\n throw new Error(`Timeline predictions are not supported for subordinate stations.`);\n }\n const timeline = getPredictor({ datum })\n .getTimelinePrediction(options)\n .map((e) => toPreferredUnits(e, units));\n\n return { datum, units, station, distance, timeline };\n },\n\n getWaterLevelAtTime({ time, datum = defaultDatum, units = defaultUnits }: WaterLevelOptions) {\n if (station.type === \"subordinate\") {\n throw new Error(`Water level predictions are not supported for subordinate stations.`);\n }\n\n const prediction = toPreferredUnits(\n getPredictor({ datum }).getWaterLevelAtTime({ time }),\n units,\n );\n\n return { datum, units, station, distance, ...prediction };\n },\n };\n}\n\nfunction toPreferredUnits<T extends { level: number }>(prediction: T, units: Units): T {\n let { level } = prediction;\n if (units === \"feet\") level *= feetPerMeter;\n else if (units !== \"meters\") throw new Error(`Unsupported units: ${units}`);\n return { ...prediction, level };\n}\n"],"mappings":";;;;;AAkBA,MAAM,eAAe;AACrB,MAAMA,eAAsB;;;;;;;;;;;;;;;;AAiB5B,SAAgB,sBAAsB,SAAmD;AACvF,QAAO,eAAe,QAAQ,CAAC,sBAAsB,QAAQ;;;;;AAM/D,SAAgB,sBAAsB,SAAmD;AACvF,QAAO,eAAe,QAAQ,CAAC,sBAAsB,QAAQ;;;;;AAM/D,SAAgB,oBAAoB,SAAqD;AACvF,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,EAAE,MAAe,EAAE,OAAO,QAAQ,MAAe,EAAE,OAAO,OAAO,MAAM;CAExF,IAAIC,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,iBAAoC,EAAE,EAAE;EACtE,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,EAAE,QAAQ,CAAC;;AAGzD,QAAO;EACL,GAAG;EACH;EACA;EACA;EACA;EACA,sBAAsB,EACpB,QAAQ,cACR,QAAQ,cACR,GAAG,WACe;AAKlB,UAAO;IAAE;IAAO;IAAO;IAAS;IAAU,UAJzB,aAAa,EAAE,OAAO,CAAC,CACrC,sBAAsB;KAAE,GAAG;KAAS,SAAS,QAAQ;KAAS,CAAC,CAC/D,KAAK,MAAM,iBAAiB,GAAG,MAAM,CAAC;IAEW;;EAGtD,sBAAsB,EACpB,QAAQ,cACR,QAAQ,cACR,GAAG,WACe;AAClB,OAAI,QAAQ,SAAS,cACnB,OAAM,IAAI,MAAM,mEAAmE;AAMrF,UAAO;IAAE;IAAO;IAAO;IAAS;IAAU,UAJzB,aAAa,EAAE,OAAO,CAAC,CACrC,sBAAsB,QAAQ,CAC9B,KAAK,MAAM,iBAAiB,GAAG,MAAM,CAAC;IAEW;;EAGtD,oBAAoB,EAAE,MAAM,QAAQ,cAAc,QAAQ,gBAAmC;AAC3F,OAAI,QAAQ,SAAS,cACnB,OAAM,IAAI,MAAM,sEAAsE;AAQxF,UAAO;IAAE;IAAO;IAAO;IAAS;IAAU,GALvB,iBACjB,aAAa,EAAE,OAAO,CAAC,CAAC,oBAAoB,EAAE,MAAM,CAAC,EACrD,MACD;IAEwD;;EAE5D;;AAGH,SAAS,iBAA8C,YAAe,OAAiB;CACrF,IAAI,EAAE,UAAU;AAChB,KAAI,UAAU,OAAQ,UAAS;UACtB,UAAU,SAAU,OAAM,IAAI,MAAM,sBAAsB,QAAQ;AAC3E,QAAO;EAAE,GAAG;EAAY;EAAO"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import {\n stations,\n near,\n nearest,\n type Station,\n type NearOptions,\n type NearestOptions,\n} from \"@neaps/tide-database\";\nimport tidePredictor, { type TimeSpan, type ExtremesInput } from \"@neaps/tide-predictor\";\n\ntype Units = \"meters\" | \"feet\";\ntype PredictionOptions = {\n /** Datum to return predictions in. Defaults to 'MLLW' if available for the nearest station. */\n datum?: string;\n\n /** Units for returned water levels. Defaults to 'meters'. */\n units?: Units;\n};\n\nexport type ExtremesOptions = ExtremesInput & PredictionOptions;\nexport type TimelineOptions = TimeSpan & PredictionOptions;\nexport type WaterLevelOptions = { time: Date } & PredictionOptions;\n\nconst feetPerMeter = 3.2808399;\nconst defaultUnits: Units = \"meters\";\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(options: NearestOptions & ExtremesOptions) {\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(options: NearestOptions & TimelineOptions) {\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(options: NearestOptions & WaterLevelOptions) {\n return nearestStation(options).getWaterLevelAtTime(options);\n}\n\n/**\n * Find the nearest station to the given position.\n */\nexport function nearestStation(options: NearestOptions) {\n const data = nearest(options);\n if (!data) throw new Error(`No stations found with options: ${JSON.stringify(options)}`);\n return useStation(...data);\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(options: NearOptions) {\n return near(options).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 = [(s: Station) => s.id === query, (s: Station) => s.source.id === query];\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\" && station.offsets?.reference) {\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 }: PredictionOptions = {}) {\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, { offset });\n }\n\n return {\n ...station,\n distance,\n datums,\n harmonic_constituents,\n defaultDatum,\n getExtremesPrediction({\n datum = defaultDatum,\n units = defaultUnits,\n ...options\n }: ExtremesOptions) {\n const extremes = getPredictor({ datum })\n .getExtremesPrediction({ ...options, offsets: station.offsets })\n .map((e) => toPreferredUnits(e, units));\n\n return { datum, units, station, distance, extremes };\n },\n\n getTimelinePrediction({\n datum = defaultDatum,\n units = defaultUnits,\n ...options\n }: TimelineOptions) {\n if (station.type === \"subordinate\") {\n throw new Error(`Timeline predictions are not supported for subordinate stations.`);\n }\n const timeline = getPredictor({ datum })\n .getTimelinePrediction(options)\n .map((e) => toPreferredUnits(e, units));\n\n return { datum, units, station, distance, timeline };\n },\n\n getWaterLevelAtTime({ time, datum = defaultDatum, units = defaultUnits }: WaterLevelOptions) {\n if (station.type === \"subordinate\") {\n throw new Error(`Water level predictions are not supported for subordinate stations.`);\n }\n\n const prediction = toPreferredUnits(\n getPredictor({ datum }).getWaterLevelAtTime({ time }),\n units,\n );\n\n return { datum, units, station, distance, ...prediction };\n },\n };\n}\n\nfunction toPreferredUnits<T extends { level: number }>(prediction: T, units: Units): T {\n let { level } = prediction;\n if (units === \"feet\") level *= feetPerMeter;\n else if (units !== \"meters\") throw new Error(`Unsupported units: ${units}`);\n return { ...prediction, level };\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neaps",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Tide predictions",
5
5
  "keywords": [
6
6
  "tides",
@@ -34,8 +34,7 @@
34
34
  "prepack": "npm run build"
35
35
  },
36
36
  "dependencies": {
37
- "@neaps/tide-database": "0.2",
38
- "@neaps/tide-predictor": "^0.3.0",
39
- "geolib": "^3.3.4"
37
+ "@neaps/tide-database": "0.3",
38
+ "@neaps/tide-predictor": "^0.5.0"
40
39
  }
41
40
  }