neaps 0.4.0 → 0.5.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.
@@ -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 { 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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"}
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 ExtremesInput, type TimelineInput } 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 = TimelineInput & 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
@@ -1,6 +1,6 @@
1
1
  import * as _neaps_tide_database0 from "@neaps/tide-database";
2
2
  import { NearOptions, NearestOptions, Station } from "@neaps/tide-database";
3
- import { ExtremesInput, TimeSpan } from "@neaps/tide-predictor";
3
+ import { ExtremesInput, TimelineInput } from "@neaps/tide-predictor";
4
4
 
5
5
  //#region src/index.d.ts
6
6
  type Units = "meters" | "feet";
@@ -10,7 +10,7 @@ type PredictionOptions = {
10
10
  nodeCorrections?: "iho" | "schureman";
11
11
  };
12
12
  type ExtremesOptions = ExtremesInput & PredictionOptions;
13
- type TimelineOptions = TimeSpan & PredictionOptions;
13
+ type TimelineOptions = TimelineInput & PredictionOptions;
14
14
  type WaterLevelOptions = {
15
15
  time: Date;
16
16
  } & PredictionOptions;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as _neaps_tide_database0 from "@neaps/tide-database";
2
2
  import { NearOptions, NearestOptions, Station } from "@neaps/tide-database";
3
- import { ExtremesInput, TimeSpan } from "@neaps/tide-predictor";
3
+ import { ExtremesInput, TimelineInput } from "@neaps/tide-predictor";
4
4
 
5
5
  //#region src/index.d.ts
6
6
  type Units = "meters" | "feet";
@@ -10,7 +10,7 @@ type PredictionOptions = {
10
10
  nodeCorrections?: "iho" | "schureman";
11
11
  };
12
12
  type ExtremesOptions = ExtremesInput & PredictionOptions;
13
- type TimelineOptions = TimeSpan & PredictionOptions;
13
+ type TimelineOptions = TimelineInput & PredictionOptions;
14
14
  type WaterLevelOptions = {
15
15
  time: Date;
16
16
  } & PredictionOptions;
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 { 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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"}
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 ExtremesInput, type TimelineInput } 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 = TimelineInput & 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,6 +1,6 @@
1
1
  {
2
2
  "name": "neaps",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Tide predictions",
5
5
  "keywords": [
6
6
  "tides",
@@ -35,6 +35,6 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@neaps/tide-database": "0.4",
38
- "@neaps/tide-predictor": "^0.6.0"
38
+ "@neaps/tide-predictor": "^0.7.0"
39
39
  }
40
40
  }