neaps 0.3.0 → 0.4.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
@@ -1,33 +1,6 @@
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
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
28
2
  let _neaps_tide_database = require("@neaps/tide-database");
29
3
  let _neaps_tide_predictor = require("@neaps/tide-predictor");
30
- _neaps_tide_predictor = __toESM(_neaps_tide_predictor);
31
4
 
32
5
  //#region src/index.ts
33
6
  const feetPerMeter = 3.2808399;
@@ -95,7 +68,7 @@ function useStation(station, distance) {
95
68
  if (station.type === "subordinate" && station.offsets?.reference) reference = findStation(station.offsets?.reference);
96
69
  const { datums, harmonic_constituents } = reference;
97
70
  const defaultDatum = "MLLW" in datums ? "MLLW" : void 0;
98
- function getPredictor({ datum = defaultDatum } = {}) {
71
+ function getPredictor({ datum = defaultDatum, nodeCorrections } = {}) {
99
72
  let offset = 0;
100
73
  if (datum) {
101
74
  const datumOffset = datums?.[datum];
@@ -104,7 +77,10 @@ function useStation(station, distance) {
104
77
  if (typeof mslOffset !== "number") throw new Error(`Station ${station.id} missing MSL datum, so predictions can't be given in ${datum}.`);
105
78
  offset = mslOffset - datumOffset;
106
79
  }
107
- return (0, _neaps_tide_predictor.default)(harmonic_constituents, { offset });
80
+ return (0, _neaps_tide_predictor.createTidePredictor)(harmonic_constituents, {
81
+ offset,
82
+ nodeCorrections
83
+ });
108
84
  }
109
85
  return {
110
86
  ...station,
@@ -112,36 +88,45 @@ function useStation(station, distance) {
112
88
  datums,
113
89
  harmonic_constituents,
114
90
  defaultDatum,
115
- getExtremesPrediction({ datum = defaultDatum, units = defaultUnits, ...options }) {
91
+ getExtremesPrediction({ datum = defaultDatum, units = defaultUnits, nodeCorrections, ...options }) {
116
92
  return {
117
93
  datum,
118
94
  units,
119
95
  station,
120
96
  distance,
121
- extremes: getPredictor({ datum }).getExtremesPrediction({
97
+ extremes: getPredictor({
98
+ datum,
99
+ nodeCorrections
100
+ }).getExtremesPrediction({
122
101
  ...options,
123
102
  offsets: station.offsets
124
103
  }).map((e) => toPreferredUnits(e, units))
125
104
  };
126
105
  },
127
- getTimelinePrediction({ datum = defaultDatum, units = defaultUnits, ...options }) {
106
+ getTimelinePrediction({ datum = defaultDatum, units = defaultUnits, nodeCorrections, ...options }) {
128
107
  if (station.type === "subordinate") throw new Error(`Timeline predictions are not supported for subordinate stations.`);
129
108
  return {
130
109
  datum,
131
110
  units,
132
111
  station,
133
112
  distance,
134
- timeline: getPredictor({ datum }).getTimelinePrediction(options).map((e) => toPreferredUnits(e, units))
113
+ timeline: getPredictor({
114
+ datum,
115
+ nodeCorrections
116
+ }).getTimelinePrediction(options).map((e) => toPreferredUnits(e, units))
135
117
  };
136
118
  },
137
- getWaterLevelAtTime({ time, datum = defaultDatum, units = defaultUnits }) {
119
+ getWaterLevelAtTime({ time, datum = defaultDatum, units = defaultUnits, nodeCorrections }) {
138
120
  if (station.type === "subordinate") throw new Error(`Water level predictions are not supported for subordinate stations.`);
139
121
  return {
140
122
  datum,
141
123
  units,
142
124
  station,
143
125
  distance,
144
- ...toPreferredUnits(getPredictor({ datum }).getWaterLevelAtTime({ time }), units)
126
+ ...toPreferredUnits(getPredictor({
127
+ datum,
128
+ nodeCorrections
129
+ }).getWaterLevelAtTime({ time }), units)
145
130
  };
146
131
  }
147
132
  };
@@ -1 +1 @@
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":"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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 { createTidePredictor, 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 /** Nodal correction fundamentals. Defaults to 'iho'. */\n nodeCorrections?: \"iho\" | \"schureman\";\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, nodeCorrections }: 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 createTidePredictor(harmonic_constituents, { offset, nodeCorrections });\n }\n\n return {\n ...station,\n distance,\n datums,\n harmonic_constituents,\n defaultDatum,\n getExtremesPrediction({\n datum = defaultDatum,\n units = defaultUnits,\n nodeCorrections,\n ...options\n }: ExtremesOptions) {\n const extremes = getPredictor({ datum, nodeCorrections })\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 nodeCorrections,\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, nodeCorrections })\n .getTimelinePrediction(options)\n .map((e) => toPreferredUnits(e, units));\n\n return { datum, units, station, distance, timeline };\n },\n\n getWaterLevelAtTime({\n time,\n datum = defaultDatum,\n units = defaultUnits,\n nodeCorrections,\n }: 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, nodeCorrections }).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/dist/index.d.cts CHANGED
@@ -6,7 +6,8 @@ import { ExtremesInput, TimeSpan } from "@neaps/tide-predictor";
6
6
  type Units = "meters" | "feet";
7
7
  type PredictionOptions = {
8
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'. */
9
- units?: Units;
9
+ units?: Units; /** Nodal correction fundamentals. Defaults to 'iho'. */
10
+ nodeCorrections?: "iho" | "schureman";
10
11
  };
11
12
  type ExtremesOptions = ExtremesInput & PredictionOptions;
12
13
  type TimelineOptions = TimeSpan & PredictionOptions;
@@ -60,6 +61,7 @@ declare function nearestStation(options: NearestOptions): {
60
61
  getExtremesPrediction({
61
62
  datum,
62
63
  units,
64
+ nodeCorrections,
63
65
  ...options
64
66
  }: ExtremesOptions): {
65
67
  datum: any;
@@ -71,6 +73,7 @@ declare function nearestStation(options: NearestOptions): {
71
73
  getTimelinePrediction({
72
74
  datum,
73
75
  units,
76
+ nodeCorrections,
74
77
  ...options
75
78
  }: TimelineOptions): {
76
79
  datum: any;
@@ -82,7 +85,8 @@ declare function nearestStation(options: NearestOptions): {
82
85
  getWaterLevelAtTime({
83
86
  time,
84
87
  datum,
85
- units
88
+ units,
89
+ nodeCorrections
86
90
  }: WaterLevelOptions): any;
87
91
  id: string;
88
92
  name: string;
@@ -131,6 +135,7 @@ declare function stationsNear(options: NearOptions): {
131
135
  getExtremesPrediction({
132
136
  datum,
133
137
  units,
138
+ nodeCorrections,
134
139
  ...options
135
140
  }: ExtremesOptions): {
136
141
  datum: any;
@@ -142,6 +147,7 @@ declare function stationsNear(options: NearOptions): {
142
147
  getTimelinePrediction({
143
148
  datum,
144
149
  units,
150
+ nodeCorrections,
145
151
  ...options
146
152
  }: TimelineOptions): {
147
153
  datum: any;
@@ -153,7 +159,8 @@ declare function stationsNear(options: NearOptions): {
153
159
  getWaterLevelAtTime({
154
160
  time,
155
161
  datum,
156
- units
162
+ units,
163
+ nodeCorrections
157
164
  }: WaterLevelOptions): any;
158
165
  id: string;
159
166
  name: string;
@@ -201,6 +208,7 @@ declare function findStation(query: string): {
201
208
  getExtremesPrediction({
202
209
  datum,
203
210
  units,
211
+ nodeCorrections,
204
212
  ...options
205
213
  }: ExtremesOptions): {
206
214
  datum: any;
@@ -212,6 +220,7 @@ declare function findStation(query: string): {
212
220
  getTimelinePrediction({
213
221
  datum,
214
222
  units,
223
+ nodeCorrections,
215
224
  ...options
216
225
  }: TimelineOptions): {
217
226
  datum: any;
@@ -223,7 +232,8 @@ declare function findStation(query: string): {
223
232
  getWaterLevelAtTime({
224
233
  time,
225
234
  datum,
226
- units
235
+ units,
236
+ nodeCorrections
227
237
  }: WaterLevelOptions): any;
228
238
  id: string;
229
239
  name: string;
@@ -268,6 +278,7 @@ declare function useStation(station: Station, distance?: number): {
268
278
  getExtremesPrediction({
269
279
  datum,
270
280
  units,
281
+ nodeCorrections,
271
282
  ...options
272
283
  }: ExtremesOptions): {
273
284
  datum: any;
@@ -279,6 +290,7 @@ declare function useStation(station: Station, distance?: number): {
279
290
  getTimelinePrediction({
280
291
  datum,
281
292
  units,
293
+ nodeCorrections,
282
294
  ...options
283
295
  }: TimelineOptions): {
284
296
  datum: any;
@@ -290,7 +302,8 @@ declare function useStation(station: Station, distance?: number): {
290
302
  getWaterLevelAtTime({
291
303
  time,
292
304
  datum,
293
- units
305
+ units,
306
+ nodeCorrections
294
307
  }: WaterLevelOptions): any;
295
308
  id: string;
296
309
  name: string;
package/dist/index.d.ts CHANGED
@@ -6,7 +6,8 @@ import { ExtremesInput, TimeSpan } from "@neaps/tide-predictor";
6
6
  type Units = "meters" | "feet";
7
7
  type PredictionOptions = {
8
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'. */
9
- units?: Units;
9
+ units?: Units; /** Nodal correction fundamentals. Defaults to 'iho'. */
10
+ nodeCorrections?: "iho" | "schureman";
10
11
  };
11
12
  type ExtremesOptions = ExtremesInput & PredictionOptions;
12
13
  type TimelineOptions = TimeSpan & PredictionOptions;
@@ -60,6 +61,7 @@ declare function nearestStation(options: NearestOptions): {
60
61
  getExtremesPrediction({
61
62
  datum,
62
63
  units,
64
+ nodeCorrections,
63
65
  ...options
64
66
  }: ExtremesOptions): {
65
67
  datum: any;
@@ -71,6 +73,7 @@ declare function nearestStation(options: NearestOptions): {
71
73
  getTimelinePrediction({
72
74
  datum,
73
75
  units,
76
+ nodeCorrections,
74
77
  ...options
75
78
  }: TimelineOptions): {
76
79
  datum: any;
@@ -82,7 +85,8 @@ declare function nearestStation(options: NearestOptions): {
82
85
  getWaterLevelAtTime({
83
86
  time,
84
87
  datum,
85
- units
88
+ units,
89
+ nodeCorrections
86
90
  }: WaterLevelOptions): any;
87
91
  id: string;
88
92
  name: string;
@@ -131,6 +135,7 @@ declare function stationsNear(options: NearOptions): {
131
135
  getExtremesPrediction({
132
136
  datum,
133
137
  units,
138
+ nodeCorrections,
134
139
  ...options
135
140
  }: ExtremesOptions): {
136
141
  datum: any;
@@ -142,6 +147,7 @@ declare function stationsNear(options: NearOptions): {
142
147
  getTimelinePrediction({
143
148
  datum,
144
149
  units,
150
+ nodeCorrections,
145
151
  ...options
146
152
  }: TimelineOptions): {
147
153
  datum: any;
@@ -153,7 +159,8 @@ declare function stationsNear(options: NearOptions): {
153
159
  getWaterLevelAtTime({
154
160
  time,
155
161
  datum,
156
- units
162
+ units,
163
+ nodeCorrections
157
164
  }: WaterLevelOptions): any;
158
165
  id: string;
159
166
  name: string;
@@ -201,6 +208,7 @@ declare function findStation(query: string): {
201
208
  getExtremesPrediction({
202
209
  datum,
203
210
  units,
211
+ nodeCorrections,
204
212
  ...options
205
213
  }: ExtremesOptions): {
206
214
  datum: any;
@@ -212,6 +220,7 @@ declare function findStation(query: string): {
212
220
  getTimelinePrediction({
213
221
  datum,
214
222
  units,
223
+ nodeCorrections,
215
224
  ...options
216
225
  }: TimelineOptions): {
217
226
  datum: any;
@@ -223,7 +232,8 @@ declare function findStation(query: string): {
223
232
  getWaterLevelAtTime({
224
233
  time,
225
234
  datum,
226
- units
235
+ units,
236
+ nodeCorrections
227
237
  }: WaterLevelOptions): any;
228
238
  id: string;
229
239
  name: string;
@@ -268,6 +278,7 @@ declare function useStation(station: Station, distance?: number): {
268
278
  getExtremesPrediction({
269
279
  datum,
270
280
  units,
281
+ nodeCorrections,
271
282
  ...options
272
283
  }: ExtremesOptions): {
273
284
  datum: any;
@@ -279,6 +290,7 @@ declare function useStation(station: Station, distance?: number): {
279
290
  getTimelinePrediction({
280
291
  datum,
281
292
  units,
293
+ nodeCorrections,
282
294
  ...options
283
295
  }: TimelineOptions): {
284
296
  datum: any;
@@ -290,7 +302,8 @@ declare function useStation(station: Station, distance?: number): {
290
302
  getWaterLevelAtTime({
291
303
  time,
292
304
  datum,
293
- units
305
+ units,
306
+ nodeCorrections
294
307
  }: WaterLevelOptions): any;
295
308
  id: string;
296
309
  name: string;
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { near, nearest, stations } from "@neaps/tide-database";
2
- import tidePredictor from "@neaps/tide-predictor";
2
+ import { createTidePredictor } from "@neaps/tide-predictor";
3
3
 
4
4
  //#region src/index.ts
5
5
  const feetPerMeter = 3.2808399;
@@ -67,7 +67,7 @@ function useStation(station, distance) {
67
67
  if (station.type === "subordinate" && station.offsets?.reference) reference = findStation(station.offsets?.reference);
68
68
  const { datums, harmonic_constituents } = reference;
69
69
  const defaultDatum = "MLLW" in datums ? "MLLW" : void 0;
70
- function getPredictor({ datum = defaultDatum } = {}) {
70
+ function getPredictor({ datum = defaultDatum, nodeCorrections } = {}) {
71
71
  let offset = 0;
72
72
  if (datum) {
73
73
  const datumOffset = datums?.[datum];
@@ -76,7 +76,10 @@ function useStation(station, distance) {
76
76
  if (typeof mslOffset !== "number") throw new Error(`Station ${station.id} missing MSL datum, so predictions can't be given in ${datum}.`);
77
77
  offset = mslOffset - datumOffset;
78
78
  }
79
- return tidePredictor(harmonic_constituents, { offset });
79
+ return createTidePredictor(harmonic_constituents, {
80
+ offset,
81
+ nodeCorrections
82
+ });
80
83
  }
81
84
  return {
82
85
  ...station,
@@ -84,36 +87,45 @@ function useStation(station, distance) {
84
87
  datums,
85
88
  harmonic_constituents,
86
89
  defaultDatum,
87
- getExtremesPrediction({ datum = defaultDatum, units = defaultUnits, ...options }) {
90
+ getExtremesPrediction({ datum = defaultDatum, units = defaultUnits, nodeCorrections, ...options }) {
88
91
  return {
89
92
  datum,
90
93
  units,
91
94
  station,
92
95
  distance,
93
- extremes: getPredictor({ datum }).getExtremesPrediction({
96
+ extremes: getPredictor({
97
+ datum,
98
+ nodeCorrections
99
+ }).getExtremesPrediction({
94
100
  ...options,
95
101
  offsets: station.offsets
96
102
  }).map((e) => toPreferredUnits(e, units))
97
103
  };
98
104
  },
99
- getTimelinePrediction({ datum = defaultDatum, units = defaultUnits, ...options }) {
105
+ getTimelinePrediction({ datum = defaultDatum, units = defaultUnits, nodeCorrections, ...options }) {
100
106
  if (station.type === "subordinate") throw new Error(`Timeline predictions are not supported for subordinate stations.`);
101
107
  return {
102
108
  datum,
103
109
  units,
104
110
  station,
105
111
  distance,
106
- timeline: getPredictor({ datum }).getTimelinePrediction(options).map((e) => toPreferredUnits(e, units))
112
+ timeline: getPredictor({
113
+ datum,
114
+ nodeCorrections
115
+ }).getTimelinePrediction(options).map((e) => toPreferredUnits(e, units))
107
116
  };
108
117
  },
109
- getWaterLevelAtTime({ time, datum = defaultDatum, units = defaultUnits }) {
118
+ getWaterLevelAtTime({ time, datum = defaultDatum, units = defaultUnits, nodeCorrections }) {
110
119
  if (station.type === "subordinate") throw new Error(`Water level predictions are not supported for subordinate stations.`);
111
120
  return {
112
121
  datum,
113
122
  units,
114
123
  station,
115
124
  distance,
116
- ...toPreferredUnits(getPredictor({ datum }).getWaterLevelAtTime({ time }), units)
125
+ ...toPreferredUnits(getPredictor({
126
+ datum,
127
+ nodeCorrections
128
+ }).getWaterLevelAtTime({ time }), units)
117
129
  };
118
130
  }
119
131
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
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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"}
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 { createTidePredictor, 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 /** Nodal correction fundamentals. Defaults to 'iho'. */\n nodeCorrections?: \"iho\" | \"schureman\";\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, nodeCorrections }: 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 createTidePredictor(harmonic_constituents, { offset, nodeCorrections });\n }\n\n return {\n ...station,\n distance,\n datums,\n harmonic_constituents,\n defaultDatum,\n getExtremesPrediction({\n datum = defaultDatum,\n units = defaultUnits,\n nodeCorrections,\n ...options\n }: ExtremesOptions) {\n const extremes = getPredictor({ datum, nodeCorrections })\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 nodeCorrections,\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, nodeCorrections })\n .getTimelinePrediction(options)\n .map((e) => toPreferredUnits(e, units));\n\n return { datum, units, station, distance, timeline };\n },\n\n getWaterLevelAtTime({\n time,\n datum = defaultDatum,\n units = defaultUnits,\n nodeCorrections,\n }: 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, nodeCorrections }).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,18 +1,18 @@
1
1
  {
2
2
  "name": "neaps",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Tide predictions",
5
5
  "keywords": [
6
6
  "tides",
7
7
  "harmonics"
8
8
  ],
9
- "homepage": "https://github.com/neaps/neaps#readme",
9
+ "homepage": "https://openwaters.io/tides/neaps",
10
10
  "bugs": {
11
- "url": "https://github.com/neaps/neaps/issues"
11
+ "url": "https://github.com/openwatersio/neaps/issues"
12
12
  },
13
13
  "repository": {
14
14
  "type": "git",
15
- "url": "git+https://github.com/neaps/neaps.git",
15
+ "url": "git+https://github.com/openwatersio/neaps.git",
16
16
  "directory": "packages/neaps"
17
17
  },
18
18
  "license": "MIT",
@@ -34,7 +34,7 @@
34
34
  "prepack": "npm run build"
35
35
  },
36
36
  "dependencies": {
37
- "@neaps/tide-database": "0.3",
38
- "@neaps/tide-predictor": "^0.5.0"
37
+ "@neaps/tide-database": "0.4",
38
+ "@neaps/tide-predictor": "^0.6.0"
39
39
  }
40
40
  }