neaps 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +12 -5
- package/src/index.ts +0 -185
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neaps",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Tide predictions",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tides",
|
|
@@ -18,14 +18,21 @@
|
|
|
18
18
|
"license": "MIT",
|
|
19
19
|
"author": "Brandon Keepers <brandon@openwaters.io>",
|
|
20
20
|
"type": "module",
|
|
21
|
-
"main": "
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
|
|
21
|
+
"main": "dist/index.cjs",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"import": "./dist/index.js",
|
|
26
|
+
"require": "./dist/index.cjs"
|
|
27
|
+
}
|
|
25
28
|
},
|
|
26
29
|
"files": [
|
|
27
30
|
"dist"
|
|
28
31
|
],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsdown",
|
|
34
|
+
"prepack": "npm run build"
|
|
35
|
+
},
|
|
29
36
|
"dependencies": {
|
|
30
37
|
"@neaps/tide-predictor": "^0.2.0",
|
|
31
38
|
"@neaps/tide-database": "^0.0",
|
package/src/index.ts
DELETED
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import { getDistance } from 'geolib'
|
|
2
|
-
import stations, { type Station } from '@neaps/tide-database'
|
|
3
|
-
import tidePredictor, {
|
|
4
|
-
type TimeSpan,
|
|
5
|
-
type ExtremesInput
|
|
6
|
-
} from '@neaps/tide-predictor'
|
|
7
|
-
import type { GeolibInputCoordinates } from 'geolib/es/types'
|
|
8
|
-
|
|
9
|
-
type DatumOption = {
|
|
10
|
-
/** Datum to return predictions in. Defaults to 'MLLW' if available for the nearest station. */
|
|
11
|
-
datum?: string
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export type ExtremesOptions = ExtremesInput & DatumOption
|
|
15
|
-
export type TimelineOptions = TimeSpan & DatumOption
|
|
16
|
-
export type WaterLevelOptions = { time: Date } & DatumOption
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Get extremes prediction using the nearest station to the given position.
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* ```ts
|
|
23
|
-
* import { getExtremesPrediction } from 'neaps'
|
|
24
|
-
*
|
|
25
|
-
* const prediction = getExtremesPrediction({
|
|
26
|
-
* latitude: 26.7, // or `lat`
|
|
27
|
-
* longitude: -80.05, // or `lng` or `lon`
|
|
28
|
-
* start: new Date('2025-12-17'),
|
|
29
|
-
* end: new Date('2025-12-18'),
|
|
30
|
-
* datum: 'MLLW', // optional, defaults to MLLW if available
|
|
31
|
-
* })
|
|
32
|
-
*/
|
|
33
|
-
export function getExtremesPrediction(
|
|
34
|
-
options: GeolibInputCoordinates & ExtremesOptions
|
|
35
|
-
) {
|
|
36
|
-
return nearestStation(options).getExtremesPrediction(options)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Get timeline prediction using the nearest station to the given position.
|
|
41
|
-
*/
|
|
42
|
-
export function getTimelinePrediction(
|
|
43
|
-
options: GeolibInputCoordinates & TimelineOptions
|
|
44
|
-
) {
|
|
45
|
-
return nearestStation(options).getTimelinePrediction(options)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Get water level at a specific time using the nearest station to the given position.
|
|
50
|
-
*/
|
|
51
|
-
export function getWaterLevelAtTime(
|
|
52
|
-
options: GeolibInputCoordinates & WaterLevelOptions
|
|
53
|
-
) {
|
|
54
|
-
return nearestStation(options).getWaterLevelAtTime(options)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Find the nearest station to the given position.
|
|
59
|
-
*/
|
|
60
|
-
export function nearestStation(position: GeolibInputCoordinates) {
|
|
61
|
-
return stationsNear(position, 1)[0]
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Find stations near the given position.
|
|
66
|
-
* @param limit Maximum number of stations to return (default: 10)
|
|
67
|
-
*/
|
|
68
|
-
export function stationsNear(position: GeolibInputCoordinates, limit = 10) {
|
|
69
|
-
return stations
|
|
70
|
-
.map((station) => ({ station, distance: getDistance(position, station) }))
|
|
71
|
-
.sort((a, b) => a.distance - b.distance)
|
|
72
|
-
.slice(0, limit)
|
|
73
|
-
.map(({ station, distance }) => useStation(station, distance))
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Find a specific station by its ID or source ID.
|
|
78
|
-
*/
|
|
79
|
-
export function findStation(query: string) {
|
|
80
|
-
const searches = [
|
|
81
|
-
(s: Station) => s.id === query,
|
|
82
|
-
(s: Station) => s.source.id === query
|
|
83
|
-
]
|
|
84
|
-
|
|
85
|
-
let found: Station | undefined = undefined
|
|
86
|
-
|
|
87
|
-
for (const search of searches) {
|
|
88
|
-
found = stations.find(search)
|
|
89
|
-
if (found) break
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (!found) throw new Error(`Station not found: ${query}`)
|
|
93
|
-
|
|
94
|
-
return useStation(found)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export function useStation(station: Station, distance?: number) {
|
|
98
|
-
// If subordinate station, use the reference station for datums and constituents
|
|
99
|
-
let reference = station
|
|
100
|
-
if (station.type === 'subordinate') {
|
|
101
|
-
reference = findStation(station.offsets?.reference || '')
|
|
102
|
-
}
|
|
103
|
-
const { datums, harmonic_constituents } = reference
|
|
104
|
-
|
|
105
|
-
// Use MLLW as the default datum if available
|
|
106
|
-
const defaultDatum = 'MLLW' in datums ? 'MLLW' : undefined
|
|
107
|
-
|
|
108
|
-
function getPredictor({ datum = defaultDatum }: DatumOption = {}) {
|
|
109
|
-
let offset = 0
|
|
110
|
-
|
|
111
|
-
if (datum) {
|
|
112
|
-
const datumOffset = datums?.[datum]
|
|
113
|
-
const mslOffset = datums?.['MSL']
|
|
114
|
-
|
|
115
|
-
if (typeof datumOffset !== 'number') {
|
|
116
|
-
throw new Error(
|
|
117
|
-
`Station ${station.id} missing ${datum} datum. Available datums: ${Object.keys(datums || {}).join(', ')}`
|
|
118
|
-
)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (typeof mslOffset !== 'number') {
|
|
122
|
-
throw new Error(
|
|
123
|
-
`Station ${station.id} missing MSL datum, so predictions can't be given in ${datum}.`
|
|
124
|
-
)
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
offset = mslOffset - datumOffset
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return tidePredictor(harmonic_constituents, {
|
|
131
|
-
phaseKey: 'phase_UTC',
|
|
132
|
-
offset
|
|
133
|
-
})
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return {
|
|
137
|
-
...station,
|
|
138
|
-
distance,
|
|
139
|
-
datums,
|
|
140
|
-
harmonic_constituents,
|
|
141
|
-
defaultDatum,
|
|
142
|
-
getExtremesPrediction({ datum = defaultDatum, ...input }: ExtremesOptions) {
|
|
143
|
-
return {
|
|
144
|
-
datum,
|
|
145
|
-
distance,
|
|
146
|
-
station,
|
|
147
|
-
extremes: getPredictor({ datum }).getExtremesPrediction({
|
|
148
|
-
...input,
|
|
149
|
-
offsets: station.offsets
|
|
150
|
-
})
|
|
151
|
-
}
|
|
152
|
-
},
|
|
153
|
-
|
|
154
|
-
getTimelinePrediction({
|
|
155
|
-
datum = defaultDatum,
|
|
156
|
-
...params
|
|
157
|
-
}: TimelineOptions) {
|
|
158
|
-
if (station.type === 'subordinate') {
|
|
159
|
-
throw new Error(
|
|
160
|
-
`Timeline predictions are not supported for subordinate stations.`
|
|
161
|
-
)
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return {
|
|
165
|
-
datum,
|
|
166
|
-
station,
|
|
167
|
-
timeline: getPredictor({ datum }).getTimelinePrediction(params)
|
|
168
|
-
}
|
|
169
|
-
},
|
|
170
|
-
|
|
171
|
-
getWaterLevelAtTime({ time, datum = defaultDatum }: WaterLevelOptions) {
|
|
172
|
-
if (station.type === 'subordinate') {
|
|
173
|
-
throw new Error(
|
|
174
|
-
`Water level predictions are not supported for subordinate stations.`
|
|
175
|
-
)
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return {
|
|
179
|
-
datum,
|
|
180
|
-
station,
|
|
181
|
-
...getPredictor({ datum }).getWaterLevelAtTime({ time })
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|