+15
-2
.github/workflows/test.yml
+15
-2
.github/workflows/test.yml
···
14
14
timeout-minutes: 20
15
15
strategy:
16
16
fail-fast: true
17
+
matrix:
18
+
nodever:
19
+
[
20
+
'latest',
21
+
'lts/*',
22
+
'lts/hydrogen'
23
+
]
17
24
permissions:
18
25
contents: read
19
26
···
23
30
24
31
- name: Setup nodejs
25
32
uses: https://github.com/actions/setup-node@v4
33
+
with:
34
+
node-version: "${{ matrix.nodever }}"
35
+
check-latest: true
26
36
27
37
- name: Install dependencies
28
38
run: npm ci
39
+
40
+
- name: Build
41
+
run: npm run build
29
42
30
-
- run: npm test
31
-
name: Run tests
43
+
- name: Run tests
44
+
run: npm test
+2
.gitignore
+2
.gitignore
+18
.tangled/workflows/audit.yml
+18
.tangled/workflows/audit.yml
+24
.tangled/workflows/test.yml
+24
.tangled/workflows/test.yml
···
1
+
when:
2
+
- event: ["push"]
3
+
branch: ["master"]
4
+
5
+
engine: "nixery"
6
+
7
+
dependencies:
8
+
nixpkgs:
9
+
- nodejs
10
+
11
+
steps:
12
+
- name: "Install dependencies"
13
+
command: "npm ci"
14
+
15
+
- name: "tsc"
16
+
command: "npm run build && echo 'done.'"
17
+
18
+
- name: "tests"
19
+
command: "npm test"
20
+
21
+
clone:
22
+
skip: false
23
+
depth: 3
24
+
submodules: false
+22
.vscode/launch.json
+22
.vscode/launch.json
···
1
+
{
2
+
// Use IntelliSense to learn about possible attributes.
3
+
// Hover to view descriptions of existing attributes.
4
+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
+
"version": "0.2.0",
6
+
"configurations": [
7
+
8
+
{
9
+
"type": "node",
10
+
"request": "launch",
11
+
"name": "Launch Program",
12
+
"skipFiles": [
13
+
"<node_internals>/**"
14
+
],
15
+
"program": "${workspaceFolder}/src/index.ts",
16
+
"preLaunchTask": "tsc: build - tsconfig.json",
17
+
"outFiles": [
18
+
"${workspaceFolder}/distribution/**/*.js"
19
+
]
20
+
}
21
+
]
22
+
}
+4
-4
config/config.example.json5
+4
-4
config/config.example.json5
···
49
49
"hilo 1": {
50
50
"tracks": [
51
51
"audio/hi_01.flac",
52
-
"%cory hi",
52
+
"%cory weather.temp.max",
53
53
"audio/lo_01.flac",
54
-
"%cory lo"
54
+
"%cory weather.temp.min"
55
55
]
56
56
},
57
57
"hilo 2": {
58
58
"tracks": [
59
59
"audio/hi_02.flac",
60
-
"%cory hi",
60
+
"%cory weather.temp.max",
61
61
"audio/lo_02.flac",
62
-
"%cory lo"
62
+
"%cory weather.temp.min"
63
63
]
64
64
},
65
65
"rain 1": {
+300
-311
package-lock.json
+300
-311
package-lock.json
···
1
1
{
2
2
"name": "morning-report",
3
-
"version": "0.0.1",
3
+
"version": "0.0.5",
4
4
"lockfileVersion": 3,
5
5
"requires": true,
6
6
"packages": {
7
7
"": {
8
8
"name": "morning-report",
9
-
"version": "0.0.1",
9
+
"version": "0.0.5",
10
10
"license": "MIT",
11
11
"dependencies": {
12
12
"json5": "2.2.3",
13
-
"openweathermap-ts": "1.2.10"
13
+
"openweather-api-node": "3.1.5"
14
+
},
15
+
"bin": {
16
+
"morning-report": "distribution/src/index.js"
14
17
},
15
18
"devDependencies": {
16
-
"@types/node": "24.3.0",
19
+
"@types/node": "24.10.1",
17
20
"@vitest/coverage-v8": "3.2.4",
18
-
"typescript": "5.9.2",
21
+
"typescript": "5.9.3",
19
22
"vitest": "3.2.4"
20
23
}
21
24
},
···
44
47
}
45
48
},
46
49
"node_modules/@babel/helper-validator-identifier": {
47
-
"version": "7.27.1",
48
-
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
49
-
"integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
50
+
"version": "7.28.5",
51
+
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
52
+
"integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
50
53
"dev": true,
51
54
"license": "MIT",
52
55
"engines": {
···
54
57
}
55
58
},
56
59
"node_modules/@babel/parser": {
57
-
"version": "7.28.3",
58
-
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.3.tgz",
59
-
"integrity": "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==",
60
+
"version": "7.28.5",
61
+
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz",
62
+
"integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==",
60
63
"dev": true,
61
64
"license": "MIT",
62
65
"dependencies": {
63
-
"@babel/types": "^7.28.2"
66
+
"@babel/types": "^7.28.5"
64
67
},
65
68
"bin": {
66
69
"parser": "bin/babel-parser.js"
···
70
73
}
71
74
},
72
75
"node_modules/@babel/types": {
73
-
"version": "7.28.2",
74
-
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz",
75
-
"integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==",
76
+
"version": "7.28.5",
77
+
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz",
78
+
"integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==",
76
79
"dev": true,
77
80
"license": "MIT",
78
81
"dependencies": {
79
82
"@babel/helper-string-parser": "^7.27.1",
80
-
"@babel/helper-validator-identifier": "^7.27.1"
83
+
"@babel/helper-validator-identifier": "^7.28.5"
81
84
},
82
85
"engines": {
83
86
"node": ">=6.9.0"
···
94
97
}
95
98
},
96
99
"node_modules/@esbuild/aix-ppc64": {
97
-
"version": "0.25.9",
98
-
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz",
99
-
"integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==",
100
+
"version": "0.25.12",
101
+
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
102
+
"integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
100
103
"cpu": [
101
104
"ppc64"
102
105
],
···
111
114
}
112
115
},
113
116
"node_modules/@esbuild/android-arm": {
114
-
"version": "0.25.9",
115
-
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz",
116
-
"integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==",
117
+
"version": "0.25.12",
118
+
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
119
+
"integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
117
120
"cpu": [
118
121
"arm"
119
122
],
···
128
131
}
129
132
},
130
133
"node_modules/@esbuild/android-arm64": {
131
-
"version": "0.25.9",
132
-
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz",
133
-
"integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==",
134
+
"version": "0.25.12",
135
+
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
136
+
"integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
134
137
"cpu": [
135
138
"arm64"
136
139
],
···
145
148
}
146
149
},
147
150
"node_modules/@esbuild/android-x64": {
148
-
"version": "0.25.9",
149
-
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz",
150
-
"integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==",
151
+
"version": "0.25.12",
152
+
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
153
+
"integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
151
154
"cpu": [
152
155
"x64"
153
156
],
···
162
165
}
163
166
},
164
167
"node_modules/@esbuild/darwin-arm64": {
165
-
"version": "0.25.9",
166
-
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz",
167
-
"integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==",
168
+
"version": "0.25.12",
169
+
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
170
+
"integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
168
171
"cpu": [
169
172
"arm64"
170
173
],
···
179
182
}
180
183
},
181
184
"node_modules/@esbuild/darwin-x64": {
182
-
"version": "0.25.9",
183
-
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz",
184
-
"integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==",
185
+
"version": "0.25.12",
186
+
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
187
+
"integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
185
188
"cpu": [
186
189
"x64"
187
190
],
···
196
199
}
197
200
},
198
201
"node_modules/@esbuild/freebsd-arm64": {
199
-
"version": "0.25.9",
200
-
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz",
201
-
"integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==",
202
+
"version": "0.25.12",
203
+
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
204
+
"integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
202
205
"cpu": [
203
206
"arm64"
204
207
],
···
213
216
}
214
217
},
215
218
"node_modules/@esbuild/freebsd-x64": {
216
-
"version": "0.25.9",
217
-
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz",
218
-
"integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==",
219
+
"version": "0.25.12",
220
+
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
221
+
"integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
219
222
"cpu": [
220
223
"x64"
221
224
],
···
230
233
}
231
234
},
232
235
"node_modules/@esbuild/linux-arm": {
233
-
"version": "0.25.9",
234
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz",
235
-
"integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==",
236
+
"version": "0.25.12",
237
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
238
+
"integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
236
239
"cpu": [
237
240
"arm"
238
241
],
···
247
250
}
248
251
},
249
252
"node_modules/@esbuild/linux-arm64": {
250
-
"version": "0.25.9",
251
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz",
252
-
"integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==",
253
+
"version": "0.25.12",
254
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
255
+
"integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
253
256
"cpu": [
254
257
"arm64"
255
258
],
···
264
267
}
265
268
},
266
269
"node_modules/@esbuild/linux-ia32": {
267
-
"version": "0.25.9",
268
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz",
269
-
"integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==",
270
+
"version": "0.25.12",
271
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
272
+
"integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
270
273
"cpu": [
271
274
"ia32"
272
275
],
···
281
284
}
282
285
},
283
286
"node_modules/@esbuild/linux-loong64": {
284
-
"version": "0.25.9",
285
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz",
286
-
"integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==",
287
+
"version": "0.25.12",
288
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
289
+
"integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
287
290
"cpu": [
288
291
"loong64"
289
292
],
···
298
301
}
299
302
},
300
303
"node_modules/@esbuild/linux-mips64el": {
301
-
"version": "0.25.9",
302
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz",
303
-
"integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==",
304
+
"version": "0.25.12",
305
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
306
+
"integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
304
307
"cpu": [
305
308
"mips64el"
306
309
],
···
315
318
}
316
319
},
317
320
"node_modules/@esbuild/linux-ppc64": {
318
-
"version": "0.25.9",
319
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz",
320
-
"integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==",
321
+
"version": "0.25.12",
322
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
323
+
"integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
321
324
"cpu": [
322
325
"ppc64"
323
326
],
···
332
335
}
333
336
},
334
337
"node_modules/@esbuild/linux-riscv64": {
335
-
"version": "0.25.9",
336
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz",
337
-
"integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==",
338
+
"version": "0.25.12",
339
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
340
+
"integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
338
341
"cpu": [
339
342
"riscv64"
340
343
],
···
349
352
}
350
353
},
351
354
"node_modules/@esbuild/linux-s390x": {
352
-
"version": "0.25.9",
353
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz",
354
-
"integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==",
355
+
"version": "0.25.12",
356
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
357
+
"integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
355
358
"cpu": [
356
359
"s390x"
357
360
],
···
366
369
}
367
370
},
368
371
"node_modules/@esbuild/linux-x64": {
369
-
"version": "0.25.9",
370
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz",
371
-
"integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==",
372
+
"version": "0.25.12",
373
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
374
+
"integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
372
375
"cpu": [
373
376
"x64"
374
377
],
···
383
386
}
384
387
},
385
388
"node_modules/@esbuild/netbsd-arm64": {
386
-
"version": "0.25.9",
387
-
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz",
388
-
"integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==",
389
+
"version": "0.25.12",
390
+
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
391
+
"integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
389
392
"cpu": [
390
393
"arm64"
391
394
],
···
400
403
}
401
404
},
402
405
"node_modules/@esbuild/netbsd-x64": {
403
-
"version": "0.25.9",
404
-
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz",
405
-
"integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==",
406
+
"version": "0.25.12",
407
+
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
408
+
"integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
406
409
"cpu": [
407
410
"x64"
408
411
],
···
417
420
}
418
421
},
419
422
"node_modules/@esbuild/openbsd-arm64": {
420
-
"version": "0.25.9",
421
-
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz",
422
-
"integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==",
423
+
"version": "0.25.12",
424
+
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
425
+
"integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
423
426
"cpu": [
424
427
"arm64"
425
428
],
···
434
437
}
435
438
},
436
439
"node_modules/@esbuild/openbsd-x64": {
437
-
"version": "0.25.9",
438
-
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz",
439
-
"integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==",
440
+
"version": "0.25.12",
441
+
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
442
+
"integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
440
443
"cpu": [
441
444
"x64"
442
445
],
···
451
454
}
452
455
},
453
456
"node_modules/@esbuild/openharmony-arm64": {
454
-
"version": "0.25.9",
455
-
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz",
456
-
"integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==",
457
+
"version": "0.25.12",
458
+
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
459
+
"integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
457
460
"cpu": [
458
461
"arm64"
459
462
],
···
468
471
}
469
472
},
470
473
"node_modules/@esbuild/sunos-x64": {
471
-
"version": "0.25.9",
472
-
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz",
473
-
"integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==",
474
+
"version": "0.25.12",
475
+
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
476
+
"integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
474
477
"cpu": [
475
478
"x64"
476
479
],
···
485
488
}
486
489
},
487
490
"node_modules/@esbuild/win32-arm64": {
488
-
"version": "0.25.9",
489
-
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz",
490
-
"integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==",
491
+
"version": "0.25.12",
492
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
493
+
"integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
491
494
"cpu": [
492
495
"arm64"
493
496
],
···
502
505
}
503
506
},
504
507
"node_modules/@esbuild/win32-ia32": {
505
-
"version": "0.25.9",
506
-
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz",
507
-
"integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==",
508
+
"version": "0.25.12",
509
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
510
+
"integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
508
511
"cpu": [
509
512
"ia32"
510
513
],
···
519
522
}
520
523
},
521
524
"node_modules/@esbuild/win32-x64": {
522
-
"version": "0.25.9",
523
-
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz",
524
-
"integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==",
525
+
"version": "0.25.12",
526
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
527
+
"integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
525
528
"cpu": [
526
529
"x64"
527
530
],
···
592
595
"license": "MIT"
593
596
},
594
597
"node_modules/@jridgewell/trace-mapping": {
595
-
"version": "0.3.30",
596
-
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz",
597
-
"integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==",
598
+
"version": "0.3.31",
599
+
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
600
+
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
598
601
"dev": true,
599
602
"license": "MIT",
600
603
"dependencies": {
···
614
617
}
615
618
},
616
619
"node_modules/@rollup/rollup-android-arm-eabi": {
617
-
"version": "4.48.0",
618
-
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.48.0.tgz",
619
-
"integrity": "sha512-aVzKH922ogVAWkKiyKXorjYymz2084zrhrZRXtLrA5eEx5SO8Dj0c/4FpCHZyn7MKzhW2pW4tK28vVr+5oQ2xw==",
620
+
"version": "4.53.3",
621
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz",
622
+
"integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==",
620
623
"cpu": [
621
624
"arm"
622
625
],
···
628
631
]
629
632
},
630
633
"node_modules/@rollup/rollup-android-arm64": {
631
-
"version": "4.48.0",
632
-
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.48.0.tgz",
633
-
"integrity": "sha512-diOdQuw43xTa1RddAFbhIA8toirSzFMcnIg8kvlzRbK26xqEnKJ/vqQnghTAajy2Dcy42v+GMPMo6jq67od+Dw==",
634
+
"version": "4.53.3",
635
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz",
636
+
"integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==",
634
637
"cpu": [
635
638
"arm64"
636
639
],
···
642
645
]
643
646
},
644
647
"node_modules/@rollup/rollup-darwin-arm64": {
645
-
"version": "4.48.0",
646
-
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.48.0.tgz",
647
-
"integrity": "sha512-QhR2KA18fPlJWFefySJPDYZELaVqIUVnYgAOdtJ+B/uH96CFg2l1TQpX19XpUMWUqMyIiyY45wje8K6F4w4/CA==",
648
+
"version": "4.53.3",
649
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz",
650
+
"integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==",
648
651
"cpu": [
649
652
"arm64"
650
653
],
···
656
659
]
657
660
},
658
661
"node_modules/@rollup/rollup-darwin-x64": {
659
-
"version": "4.48.0",
660
-
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.48.0.tgz",
661
-
"integrity": "sha512-Q9RMXnQVJ5S1SYpNSTwXDpoQLgJ/fbInWOyjbCnnqTElEyeNvLAB3QvG5xmMQMhFN74bB5ZZJYkKaFPcOG8sGg==",
662
+
"version": "4.53.3",
663
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz",
664
+
"integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==",
662
665
"cpu": [
663
666
"x64"
664
667
],
···
670
673
]
671
674
},
672
675
"node_modules/@rollup/rollup-freebsd-arm64": {
673
-
"version": "4.48.0",
674
-
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.48.0.tgz",
675
-
"integrity": "sha512-3jzOhHWM8O8PSfyft+ghXZfBkZawQA0PUGtadKYxFqpcYlOYjTi06WsnYBsbMHLawr+4uWirLlbhcYLHDXR16w==",
676
+
"version": "4.53.3",
677
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz",
678
+
"integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==",
676
679
"cpu": [
677
680
"arm64"
678
681
],
···
684
687
]
685
688
},
686
689
"node_modules/@rollup/rollup-freebsd-x64": {
687
-
"version": "4.48.0",
688
-
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.48.0.tgz",
689
-
"integrity": "sha512-NcD5uVUmE73C/TPJqf78hInZmiSBsDpz3iD5MF/BuB+qzm4ooF2S1HfeTChj5K4AV3y19FFPgxonsxiEpy8v/A==",
690
+
"version": "4.53.3",
691
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz",
692
+
"integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==",
690
693
"cpu": [
691
694
"x64"
692
695
],
···
698
701
]
699
702
},
700
703
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
701
-
"version": "4.48.0",
702
-
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.48.0.tgz",
703
-
"integrity": "sha512-JWnrj8qZgLWRNHr7NbpdnrQ8kcg09EBBq8jVOjmtlB3c8C6IrynAJSMhMVGME4YfTJzIkJqvSUSVJRqkDnu/aA==",
704
+
"version": "4.53.3",
705
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz",
706
+
"integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==",
704
707
"cpu": [
705
708
"arm"
706
709
],
···
712
715
]
713
716
},
714
717
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
715
-
"version": "4.48.0",
716
-
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.48.0.tgz",
717
-
"integrity": "sha512-9xu92F0TxuMH0tD6tG3+GtngwdgSf8Bnz+YcsPG91/r5Vgh5LNofO48jV55priA95p3c92FLmPM7CvsVlnSbGQ==",
718
+
"version": "4.53.3",
719
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz",
720
+
"integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==",
718
721
"cpu": [
719
722
"arm"
720
723
],
···
726
729
]
727
730
},
728
731
"node_modules/@rollup/rollup-linux-arm64-gnu": {
729
-
"version": "4.48.0",
730
-
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.48.0.tgz",
731
-
"integrity": "sha512-NLtvJB5YpWn7jlp1rJiY0s+G1Z1IVmkDuiywiqUhh96MIraC0n7XQc2SZ1CZz14shqkM+XN2UrfIo7JB6UufOA==",
732
+
"version": "4.53.3",
733
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz",
734
+
"integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==",
732
735
"cpu": [
733
736
"arm64"
734
737
],
···
740
743
]
741
744
},
742
745
"node_modules/@rollup/rollup-linux-arm64-musl": {
743
-
"version": "4.48.0",
744
-
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.48.0.tgz",
745
-
"integrity": "sha512-QJ4hCOnz2SXgCh+HmpvZkM+0NSGcZACyYS8DGbWn2PbmA0e5xUk4bIP8eqJyNXLtyB4gZ3/XyvKtQ1IFH671vQ==",
746
+
"version": "4.53.3",
747
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz",
748
+
"integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==",
746
749
"cpu": [
747
750
"arm64"
748
751
],
···
753
756
"linux"
754
757
]
755
758
},
756
-
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
757
-
"version": "4.48.0",
758
-
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.48.0.tgz",
759
-
"integrity": "sha512-Pk0qlGJnhILdIC5zSKQnprFjrGmjfDM7TPZ0FKJxRkoo+kgMRAg4ps1VlTZf8u2vohSicLg7NP+cA5qE96PaFg==",
759
+
"node_modules/@rollup/rollup-linux-loong64-gnu": {
760
+
"version": "4.53.3",
761
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz",
762
+
"integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==",
760
763
"cpu": [
761
764
"loong64"
762
765
],
···
768
771
]
769
772
},
770
773
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
771
-
"version": "4.48.0",
772
-
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.48.0.tgz",
773
-
"integrity": "sha512-/dNFc6rTpoOzgp5GKoYjT6uLo8okR/Chi2ECOmCZiS4oqh3mc95pThWma7Bgyk6/WTEvjDINpiBCuecPLOgBLQ==",
774
+
"version": "4.53.3",
775
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz",
776
+
"integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==",
774
777
"cpu": [
775
778
"ppc64"
776
779
],
···
782
785
]
783
786
},
784
787
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
785
-
"version": "4.48.0",
786
-
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.48.0.tgz",
787
-
"integrity": "sha512-YBwXsvsFI8CVA4ej+bJF2d9uAeIiSkqKSPQNn0Wyh4eMDY4wxuSp71BauPjQNCKK2tD2/ksJ7uhJ8X/PVY9bHQ==",
788
+
"version": "4.53.3",
789
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz",
790
+
"integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==",
788
791
"cpu": [
789
792
"riscv64"
790
793
],
···
796
799
]
797
800
},
798
801
"node_modules/@rollup/rollup-linux-riscv64-musl": {
799
-
"version": "4.48.0",
800
-
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.48.0.tgz",
801
-
"integrity": "sha512-FI3Rr2aGAtl1aHzbkBIamsQyuauYtTF9SDUJ8n2wMXuuxwchC3QkumZa1TEXYIv/1AUp1a25Kwy6ONArvnyeVQ==",
802
+
"version": "4.53.3",
803
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz",
804
+
"integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==",
802
805
"cpu": [
803
806
"riscv64"
804
807
],
···
810
813
]
811
814
},
812
815
"node_modules/@rollup/rollup-linux-s390x-gnu": {
813
-
"version": "4.48.0",
814
-
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.48.0.tgz",
815
-
"integrity": "sha512-Dx7qH0/rvNNFmCcIRe1pyQ9/H0XO4v/f0SDoafwRYwc2J7bJZ5N4CHL/cdjamISZ5Cgnon6iazAVRFlxSoHQnQ==",
816
+
"version": "4.53.3",
817
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz",
818
+
"integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==",
816
819
"cpu": [
817
820
"s390x"
818
821
],
···
824
827
]
825
828
},
826
829
"node_modules/@rollup/rollup-linux-x64-gnu": {
827
-
"version": "4.48.0",
828
-
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.48.0.tgz",
829
-
"integrity": "sha512-GUdZKTeKBq9WmEBzvFYuC88yk26vT66lQV8D5+9TgkfbewhLaTHRNATyzpQwwbHIfJvDJ3N9WJ90wK/uR3cy3Q==",
830
+
"version": "4.53.3",
831
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz",
832
+
"integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==",
830
833
"cpu": [
831
834
"x64"
832
835
],
···
838
841
]
839
842
},
840
843
"node_modules/@rollup/rollup-linux-x64-musl": {
841
-
"version": "4.48.0",
842
-
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.48.0.tgz",
843
-
"integrity": "sha512-ao58Adz/v14MWpQgYAb4a4h3fdw73DrDGtaiF7Opds5wNyEQwtO6M9dBh89nke0yoZzzaegq6J/EXs7eBebG8A==",
844
+
"version": "4.53.3",
845
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz",
846
+
"integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==",
844
847
"cpu": [
845
848
"x64"
846
849
],
···
851
854
"linux"
852
855
]
853
856
},
857
+
"node_modules/@rollup/rollup-openharmony-arm64": {
858
+
"version": "4.53.3",
859
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz",
860
+
"integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==",
861
+
"cpu": [
862
+
"arm64"
863
+
],
864
+
"dev": true,
865
+
"license": "MIT",
866
+
"optional": true,
867
+
"os": [
868
+
"openharmony"
869
+
]
870
+
},
854
871
"node_modules/@rollup/rollup-win32-arm64-msvc": {
855
-
"version": "4.48.0",
856
-
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.48.0.tgz",
857
-
"integrity": "sha512-kpFno46bHtjZVdRIOxqaGeiABiToo2J+st7Yce+aiAoo1H0xPi2keyQIP04n2JjDVuxBN6bSz9R6RdTK5hIppw==",
872
+
"version": "4.53.3",
873
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz",
874
+
"integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==",
858
875
"cpu": [
859
876
"arm64"
860
877
],
···
866
883
]
867
884
},
868
885
"node_modules/@rollup/rollup-win32-ia32-msvc": {
869
-
"version": "4.48.0",
870
-
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.48.0.tgz",
871
-
"integrity": "sha512-rFYrk4lLk9YUTIeihnQMiwMr6gDhGGSbWThPEDfBoU/HdAtOzPXeexKi7yU8jO+LWRKnmqPN9NviHQf6GDwBcQ==",
886
+
"version": "4.53.3",
887
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz",
888
+
"integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==",
872
889
"cpu": [
873
890
"ia32"
874
891
],
···
879
896
"win32"
880
897
]
881
898
},
899
+
"node_modules/@rollup/rollup-win32-x64-gnu": {
900
+
"version": "4.53.3",
901
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz",
902
+
"integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==",
903
+
"cpu": [
904
+
"x64"
905
+
],
906
+
"dev": true,
907
+
"license": "MIT",
908
+
"optional": true,
909
+
"os": [
910
+
"win32"
911
+
]
912
+
},
882
913
"node_modules/@rollup/rollup-win32-x64-msvc": {
883
-
"version": "4.48.0",
884
-
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.48.0.tgz",
885
-
"integrity": "sha512-sq0hHLTgdtwOPDB5SJOuaoHyiP1qSwg+71TQWk8iDS04bW1wIE0oQ6otPiRj2ZvLYNASLMaTp8QRGUVZ+5OL5A==",
914
+
"version": "4.53.3",
915
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz",
916
+
"integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==",
886
917
"cpu": [
887
918
"x64"
888
919
],
···
894
925
]
895
926
},
896
927
"node_modules/@types/chai": {
897
-
"version": "5.2.2",
898
-
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz",
899
-
"integrity": "sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==",
928
+
"version": "5.2.3",
929
+
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz",
930
+
"integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==",
900
931
"dev": true,
901
932
"license": "MIT",
902
933
"dependencies": {
903
-
"@types/deep-eql": "*"
934
+
"@types/deep-eql": "*",
935
+
"assertion-error": "^2.0.1"
904
936
}
905
937
},
906
938
"node_modules/@types/deep-eql": {
···
918
950
"license": "MIT"
919
951
},
920
952
"node_modules/@types/node": {
921
-
"version": "24.3.0",
922
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz",
923
-
"integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==",
953
+
"version": "24.10.1",
954
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
955
+
"integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
924
956
"dev": true,
925
957
"license": "MIT",
926
958
"dependencies": {
927
-
"undici-types": "~7.10.0"
959
+
"undici-types": "~7.16.0"
928
960
}
929
961
},
930
962
"node_modules/@vitest/coverage-v8": {
···
1077
1109
}
1078
1110
},
1079
1111
"node_modules/ansi-regex": {
1080
-
"version": "6.2.0",
1081
-
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.0.tgz",
1082
-
"integrity": "sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==",
1112
+
"version": "6.2.2",
1113
+
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
1114
+
"integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
1083
1115
"dev": true,
1084
1116
"license": "MIT",
1085
1117
"engines": {
···
1090
1122
}
1091
1123
},
1092
1124
"node_modules/ansi-styles": {
1093
-
"version": "6.2.1",
1094
-
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
1095
-
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
1125
+
"version": "6.2.3",
1126
+
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
1127
+
"integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
1096
1128
"dev": true,
1097
1129
"license": "MIT",
1098
1130
"engines": {
···
1113
1145
}
1114
1146
},
1115
1147
"node_modules/ast-v8-to-istanbul": {
1116
-
"version": "0.3.4",
1117
-
"resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.4.tgz",
1118
-
"integrity": "sha512-cxrAnZNLBnQwBPByK4CeDaw5sWZtMilJE/Q3iDA0aamgaIVNDF9T6K2/8DfYDZEejZ2jNnDrG9m8MY72HFd0KA==",
1148
+
"version": "0.3.8",
1149
+
"resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.8.tgz",
1150
+
"integrity": "sha512-szgSZqUxI5T8mLKvS7WTjF9is+MVbOeLADU73IseOcrqhxr/VAvy6wfoVE39KnKzA7JRhjF5eUagNlHwvZPlKQ==",
1119
1151
"dev": true,
1120
1152
"license": "MIT",
1121
1153
"dependencies": {
1122
-
"@jridgewell/trace-mapping": "^0.3.29",
1154
+
"@jridgewell/trace-mapping": "^0.3.31",
1123
1155
"estree-walker": "^3.0.3",
1124
1156
"js-tokens": "^9.0.1"
1125
1157
}
···
1263
1295
"license": "MIT"
1264
1296
},
1265
1297
"node_modules/esbuild": {
1266
-
"version": "0.25.9",
1267
-
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz",
1268
-
"integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==",
1298
+
"version": "0.25.12",
1299
+
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
1300
+
"integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
1269
1301
"dev": true,
1270
1302
"hasInstallScript": true,
1271
1303
"license": "MIT",
···
1276
1308
"node": ">=18"
1277
1309
},
1278
1310
"optionalDependencies": {
1279
-
"@esbuild/aix-ppc64": "0.25.9",
1280
-
"@esbuild/android-arm": "0.25.9",
1281
-
"@esbuild/android-arm64": "0.25.9",
1282
-
"@esbuild/android-x64": "0.25.9",
1283
-
"@esbuild/darwin-arm64": "0.25.9",
1284
-
"@esbuild/darwin-x64": "0.25.9",
1285
-
"@esbuild/freebsd-arm64": "0.25.9",
1286
-
"@esbuild/freebsd-x64": "0.25.9",
1287
-
"@esbuild/linux-arm": "0.25.9",
1288
-
"@esbuild/linux-arm64": "0.25.9",
1289
-
"@esbuild/linux-ia32": "0.25.9",
1290
-
"@esbuild/linux-loong64": "0.25.9",
1291
-
"@esbuild/linux-mips64el": "0.25.9",
1292
-
"@esbuild/linux-ppc64": "0.25.9",
1293
-
"@esbuild/linux-riscv64": "0.25.9",
1294
-
"@esbuild/linux-s390x": "0.25.9",
1295
-
"@esbuild/linux-x64": "0.25.9",
1296
-
"@esbuild/netbsd-arm64": "0.25.9",
1297
-
"@esbuild/netbsd-x64": "0.25.9",
1298
-
"@esbuild/openbsd-arm64": "0.25.9",
1299
-
"@esbuild/openbsd-x64": "0.25.9",
1300
-
"@esbuild/openharmony-arm64": "0.25.9",
1301
-
"@esbuild/sunos-x64": "0.25.9",
1302
-
"@esbuild/win32-arm64": "0.25.9",
1303
-
"@esbuild/win32-ia32": "0.25.9",
1304
-
"@esbuild/win32-x64": "0.25.9"
1311
+
"@esbuild/aix-ppc64": "0.25.12",
1312
+
"@esbuild/android-arm": "0.25.12",
1313
+
"@esbuild/android-arm64": "0.25.12",
1314
+
"@esbuild/android-x64": "0.25.12",
1315
+
"@esbuild/darwin-arm64": "0.25.12",
1316
+
"@esbuild/darwin-x64": "0.25.12",
1317
+
"@esbuild/freebsd-arm64": "0.25.12",
1318
+
"@esbuild/freebsd-x64": "0.25.12",
1319
+
"@esbuild/linux-arm": "0.25.12",
1320
+
"@esbuild/linux-arm64": "0.25.12",
1321
+
"@esbuild/linux-ia32": "0.25.12",
1322
+
"@esbuild/linux-loong64": "0.25.12",
1323
+
"@esbuild/linux-mips64el": "0.25.12",
1324
+
"@esbuild/linux-ppc64": "0.25.12",
1325
+
"@esbuild/linux-riscv64": "0.25.12",
1326
+
"@esbuild/linux-s390x": "0.25.12",
1327
+
"@esbuild/linux-x64": "0.25.12",
1328
+
"@esbuild/netbsd-arm64": "0.25.12",
1329
+
"@esbuild/netbsd-x64": "0.25.12",
1330
+
"@esbuild/openbsd-arm64": "0.25.12",
1331
+
"@esbuild/openbsd-x64": "0.25.12",
1332
+
"@esbuild/openharmony-arm64": "0.25.12",
1333
+
"@esbuild/sunos-x64": "0.25.12",
1334
+
"@esbuild/win32-arm64": "0.25.12",
1335
+
"@esbuild/win32-ia32": "0.25.12",
1336
+
"@esbuild/win32-x64": "0.25.12"
1305
1337
}
1306
1338
},
1307
1339
"node_modules/estree-walker": {
···
1375
1407
}
1376
1408
},
1377
1409
"node_modules/glob": {
1378
-
"version": "10.4.5",
1379
-
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
1380
-
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
1410
+
"version": "10.5.0",
1411
+
"resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
1412
+
"integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
1381
1413
"dev": true,
1382
1414
"license": "ISC",
1383
1415
"dependencies": {
···
1533
1565
"license": "ISC"
1534
1566
},
1535
1567
"node_modules/magic-string": {
1536
-
"version": "0.30.18",
1537
-
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.18.tgz",
1538
-
"integrity": "sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==",
1568
+
"version": "0.30.21",
1569
+
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
1570
+
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
1539
1571
"dev": true,
1540
1572
"license": "MIT",
1541
1573
"dependencies": {
···
1622
1654
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
1623
1655
}
1624
1656
},
1625
-
"node_modules/node-fetch": {
1626
-
"version": "2.7.0",
1627
-
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
1628
-
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
1629
-
"license": "MIT",
1630
-
"dependencies": {
1631
-
"whatwg-url": "^5.0.0"
1632
-
},
1633
-
"engines": {
1634
-
"node": "4.x || >=6.0.0"
1635
-
},
1636
-
"peerDependencies": {
1637
-
"encoding": "^0.1.0"
1638
-
},
1639
-
"peerDependenciesMeta": {
1640
-
"encoding": {
1641
-
"optional": true
1642
-
}
1643
-
}
1644
-
},
1645
-
"node_modules/openweathermap-ts": {
1646
-
"version": "1.2.10",
1647
-
"resolved": "https://registry.npmjs.org/openweathermap-ts/-/openweathermap-ts-1.2.10.tgz",
1648
-
"integrity": "sha512-Zckv2aXN8ENSeAeroces2jJciLWb6aLNXEmvG6pmF+BcIMw2kwRo6++/AKUNoU5suOp47UWA6lllDV0TNm//OA==",
1649
-
"license": "MIT",
1650
-
"dependencies": {
1651
-
"node-fetch": "^2.6.0"
1652
-
}
1657
+
"node_modules/openweather-api-node": {
1658
+
"version": "3.1.5",
1659
+
"resolved": "https://registry.npmjs.org/openweather-api-node/-/openweather-api-node-3.1.5.tgz",
1660
+
"integrity": "sha512-FGLE0bWOTvp4XHaswmzMfisYMMEtwEwOEJR0vaS07L31OUcutV/UUO5/vRuktkRPoqfk3KZOoqddsRTGTxT7Aw==",
1661
+
"license": "MIT"
1653
1662
},
1654
1663
"node_modules/package-json-from-dist": {
1655
1664
"version": "1.0.1",
···
1752
1761
}
1753
1762
},
1754
1763
"node_modules/rollup": {
1755
-
"version": "4.48.0",
1756
-
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.48.0.tgz",
1757
-
"integrity": "sha512-BXHRqK1vyt9XVSEHZ9y7xdYtuYbwVod2mLwOMFP7t/Eqoc1pHRlG/WdV2qNeNvZHRQdLedaFycljaYYM96RqJQ==",
1764
+
"version": "4.53.3",
1765
+
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz",
1766
+
"integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==",
1758
1767
"dev": true,
1759
1768
"license": "MIT",
1760
1769
"dependencies": {
···
1768
1777
"npm": ">=8.0.0"
1769
1778
},
1770
1779
"optionalDependencies": {
1771
-
"@rollup/rollup-android-arm-eabi": "4.48.0",
1772
-
"@rollup/rollup-android-arm64": "4.48.0",
1773
-
"@rollup/rollup-darwin-arm64": "4.48.0",
1774
-
"@rollup/rollup-darwin-x64": "4.48.0",
1775
-
"@rollup/rollup-freebsd-arm64": "4.48.0",
1776
-
"@rollup/rollup-freebsd-x64": "4.48.0",
1777
-
"@rollup/rollup-linux-arm-gnueabihf": "4.48.0",
1778
-
"@rollup/rollup-linux-arm-musleabihf": "4.48.0",
1779
-
"@rollup/rollup-linux-arm64-gnu": "4.48.0",
1780
-
"@rollup/rollup-linux-arm64-musl": "4.48.0",
1781
-
"@rollup/rollup-linux-loongarch64-gnu": "4.48.0",
1782
-
"@rollup/rollup-linux-ppc64-gnu": "4.48.0",
1783
-
"@rollup/rollup-linux-riscv64-gnu": "4.48.0",
1784
-
"@rollup/rollup-linux-riscv64-musl": "4.48.0",
1785
-
"@rollup/rollup-linux-s390x-gnu": "4.48.0",
1786
-
"@rollup/rollup-linux-x64-gnu": "4.48.0",
1787
-
"@rollup/rollup-linux-x64-musl": "4.48.0",
1788
-
"@rollup/rollup-win32-arm64-msvc": "4.48.0",
1789
-
"@rollup/rollup-win32-ia32-msvc": "4.48.0",
1790
-
"@rollup/rollup-win32-x64-msvc": "4.48.0",
1780
+
"@rollup/rollup-android-arm-eabi": "4.53.3",
1781
+
"@rollup/rollup-android-arm64": "4.53.3",
1782
+
"@rollup/rollup-darwin-arm64": "4.53.3",
1783
+
"@rollup/rollup-darwin-x64": "4.53.3",
1784
+
"@rollup/rollup-freebsd-arm64": "4.53.3",
1785
+
"@rollup/rollup-freebsd-x64": "4.53.3",
1786
+
"@rollup/rollup-linux-arm-gnueabihf": "4.53.3",
1787
+
"@rollup/rollup-linux-arm-musleabihf": "4.53.3",
1788
+
"@rollup/rollup-linux-arm64-gnu": "4.53.3",
1789
+
"@rollup/rollup-linux-arm64-musl": "4.53.3",
1790
+
"@rollup/rollup-linux-loong64-gnu": "4.53.3",
1791
+
"@rollup/rollup-linux-ppc64-gnu": "4.53.3",
1792
+
"@rollup/rollup-linux-riscv64-gnu": "4.53.3",
1793
+
"@rollup/rollup-linux-riscv64-musl": "4.53.3",
1794
+
"@rollup/rollup-linux-s390x-gnu": "4.53.3",
1795
+
"@rollup/rollup-linux-x64-gnu": "4.53.3",
1796
+
"@rollup/rollup-linux-x64-musl": "4.53.3",
1797
+
"@rollup/rollup-openharmony-arm64": "4.53.3",
1798
+
"@rollup/rollup-win32-arm64-msvc": "4.53.3",
1799
+
"@rollup/rollup-win32-ia32-msvc": "4.53.3",
1800
+
"@rollup/rollup-win32-x64-gnu": "4.53.3",
1801
+
"@rollup/rollup-win32-x64-msvc": "4.53.3",
1791
1802
"fsevents": "~2.3.2"
1792
1803
}
1793
1804
},
···
1865
1876
"license": "MIT"
1866
1877
},
1867
1878
"node_modules/std-env": {
1868
-
"version": "3.9.0",
1869
-
"resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz",
1870
-
"integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==",
1879
+
"version": "3.10.0",
1880
+
"resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz",
1881
+
"integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==",
1871
1882
"dev": true,
1872
1883
"license": "MIT"
1873
1884
},
···
1936
1947
}
1937
1948
},
1938
1949
"node_modules/strip-ansi": {
1939
-
"version": "7.1.0",
1940
-
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
1941
-
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
1950
+
"version": "7.1.2",
1951
+
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
1952
+
"integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
1942
1953
"dev": true,
1943
1954
"license": "MIT",
1944
1955
"dependencies": {
···
1976
1987
}
1977
1988
},
1978
1989
"node_modules/strip-literal": {
1979
-
"version": "3.0.0",
1980
-
"resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.0.0.tgz",
1981
-
"integrity": "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==",
1990
+
"version": "3.1.0",
1991
+
"resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz",
1992
+
"integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==",
1982
1993
"dev": true,
1983
1994
"license": "MIT",
1984
1995
"dependencies": {
···
2031
2042
"license": "MIT"
2032
2043
},
2033
2044
"node_modules/tinyglobby": {
2034
-
"version": "0.2.14",
2035
-
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz",
2036
-
"integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==",
2045
+
"version": "0.2.15",
2046
+
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
2047
+
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
2037
2048
"dev": true,
2038
2049
"license": "MIT",
2039
2050
"dependencies": {
2040
-
"fdir": "^6.4.4",
2041
-
"picomatch": "^4.0.2"
2051
+
"fdir": "^6.5.0",
2052
+
"picomatch": "^4.0.3"
2042
2053
},
2043
2054
"engines": {
2044
2055
"node": ">=12.0.0"
···
2068
2079
}
2069
2080
},
2070
2081
"node_modules/tinyspy": {
2071
-
"version": "4.0.3",
2072
-
"resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.3.tgz",
2073
-
"integrity": "sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==",
2082
+
"version": "4.0.4",
2083
+
"resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz",
2084
+
"integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==",
2074
2085
"dev": true,
2075
2086
"license": "MIT",
2076
2087
"engines": {
2077
2088
"node": ">=14.0.0"
2078
2089
}
2079
2090
},
2080
-
"node_modules/tr46": {
2081
-
"version": "0.0.3",
2082
-
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
2083
-
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
2084
-
"license": "MIT"
2085
-
},
2086
2091
"node_modules/typescript": {
2087
-
"version": "5.9.2",
2088
-
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
2089
-
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
2092
+
"version": "5.9.3",
2093
+
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
2094
+
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
2090
2095
"dev": true,
2091
2096
"license": "Apache-2.0",
2092
2097
"bin": {
···
2098
2103
}
2099
2104
},
2100
2105
"node_modules/undici-types": {
2101
-
"version": "7.10.0",
2102
-
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz",
2103
-
"integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==",
2106
+
"version": "7.16.0",
2107
+
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
2108
+
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
2104
2109
"dev": true,
2105
2110
"license": "MIT"
2106
2111
},
2107
2112
"node_modules/vite": {
2108
-
"version": "7.1.3",
2109
-
"resolved": "https://registry.npmjs.org/vite/-/vite-7.1.3.tgz",
2110
-
"integrity": "sha512-OOUi5zjkDxYrKhTV3V7iKsoS37VUM7v40+HuwEmcrsf11Cdx9y3DIr2Px6liIcZFwt3XSRpQvFpL3WVy7ApkGw==",
2113
+
"version": "7.2.6",
2114
+
"resolved": "https://registry.npmjs.org/vite/-/vite-7.2.6.tgz",
2115
+
"integrity": "sha512-tI2l/nFHC5rLh7+5+o7QjKjSR04ivXDF4jcgV0f/bTQ+OJiITy5S6gaynVsEM+7RqzufMnVbIon6Sr5x1SDYaQ==",
2111
2116
"dev": true,
2112
2117
"license": "MIT",
2113
2118
"dependencies": {
···
2116
2121
"picomatch": "^4.0.3",
2117
2122
"postcss": "^8.5.6",
2118
2123
"rollup": "^4.43.0",
2119
-
"tinyglobby": "^0.2.14"
2124
+
"tinyglobby": "^0.2.15"
2120
2125
},
2121
2126
"bin": {
2122
2127
"vite": "bin/vite.js"
···
2273
2278
"jsdom": {
2274
2279
"optional": true
2275
2280
}
2276
-
}
2277
-
},
2278
-
"node_modules/webidl-conversions": {
2279
-
"version": "3.0.1",
2280
-
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
2281
-
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
2282
-
"license": "BSD-2-Clause"
2283
-
},
2284
-
"node_modules/whatwg-url": {
2285
-
"version": "5.0.0",
2286
-
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
2287
-
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
2288
-
"license": "MIT",
2289
-
"dependencies": {
2290
-
"tr46": "~0.0.3",
2291
-
"webidl-conversions": "^3.0.0"
2292
2281
}
2293
2282
},
2294
2283
"node_modules/which": {
+11
-5
package.json
+11
-5
package.json
···
1
1
{
2
2
"name": "morning-report",
3
-
"version": "0.0.1",
3
+
"version": "0.0.5",
4
4
"description": "Procedurally generates a radio weather report",
5
5
"keywords": [
6
6
"weather",
···
19
19
},
20
20
"type": "module",
21
21
"main": "distribution/index.js",
22
+
"bin": {
23
+
"morning-report": "./distribution/src/index.js"
24
+
},
25
+
"files": [
26
+
"distribution"
27
+
],
22
28
"scripts": {
23
29
"build": "tsc",
24
-
"start": "node distribution/index.js",
30
+
"start": "node distribution/src/index.js",
25
31
"test": "vitest"
26
32
},
27
33
"dependencies": {
28
34
"json5": "2.2.3",
29
-
"openweathermap-ts": "1.2.10"
35
+
"openweather-api-node": "3.1.5"
30
36
},
31
37
"devDependencies": {
32
-
"typescript": "5.9.2",
33
-
"@types/node": "24.3.0",
38
+
"typescript": "5.9.3",
39
+
"@types/node": "24.10.1",
34
40
"vitest": "3.2.4",
35
41
"@vitest/coverage-v8": "3.2.4"
36
42
}
+6
-4
src/index.ts
+6
-4
src/index.ts
···
1
+
#!/usr/bin/env node
1
2
import path from 'path';
2
3
import fsp from 'fs/promises';
3
4
import json5 from 'json5';
4
5
import Sequencer from './sequencer.js';
6
+
import { Stitcher } from './stitcher.js';
5
7
import type {Programs, Segments, Sequences} from './sequencer.js';
6
8
import type { Voices } from './voice.js';
7
-
import type { WeatherConfig } from './weather.js';
9
+
import type { Options } from 'openweather-api-node';
8
10
9
11
10
12
interface Config {
···
12
14
segments: Segments,
13
15
sequences: Sequences,
14
16
voices: Voices,
15
-
weather: WeatherConfig
17
+
weather: Options
16
18
}
17
19
18
20
console.log('morning-report\nCory Sanin 2025\n');
19
21
20
22
const config: Config = json5.parse(await fsp.readFile(process.env['CONFIG'] || path.join('config', 'config.json5'), { encoding: 'utf-8' }));
21
-
const sequence = Sequencer(config);
23
+
const sequence = await Sequencer(config);
22
24
console.log(sequence.join('\n'));
23
-
25
+
await Stitcher(sequence);
24
26
25
27
export type { Config };
+72
-14
src/sequencer.ts
+72
-14
src/sequencer.ts
···
1
+
import { OpenWeatherAPI, type DailyWeather } from 'openweather-api-node';
2
+
import { voiceLines } from './voice.js';
1
3
import type { Config } from './index.js';
4
+
import type { Voice } from './voice.js';
5
+
import crypto from 'crypto';
2
6
3
7
type SegmentName = string;
4
8
type SequenceName = string;
5
9
type Programs = SegmentName[][];
6
10
type Segments = { [segment: SegmentName]: SequenceName[] };
7
11
type Sequence = {
8
-
condition?: string;
12
+
conditions?: string[];
9
13
tracks: string[];
10
14
}
11
15
type Sequences = { [sequence: SequenceName]: Sequence };
···
13
17
let config: Config = null;
14
18
15
19
function selectOne<T>(arr: T[]): T {
16
-
return arr[Math.floor(Math.random() * arr.length)];
20
+
return arr[crypto.randomInt(0, arr.length)];
21
+
}
22
+
23
+
function resolveSide(side: string, currentWeather: DailyWeather) {
24
+
if (!side.startsWith('weather')) {
25
+
return side.includes('.') ? parseFloat(side) : parseInt(side);
26
+
}
27
+
28
+
const tokens = side.split('.');
29
+
let w = currentWeather;
30
+
tokens.forEach(t => w = w[t]);
31
+
return typeof w === 'object' ? JSON.stringify(w) : w as (string | number);
32
+
}
33
+
34
+
function notNotANumber(something: number | string, defaultVal: string) {
35
+
if (typeof something === 'string' || !isNaN(something)) {
36
+
return something;
37
+
}
38
+
return defaultVal;
17
39
}
18
40
19
-
function conditionIsMet(condition: string | undefined = undefined): boolean {
41
+
function conditionIsMet(condition: string | undefined, currentWeather: DailyWeather): boolean {
20
42
if (typeof condition !== 'string') {
21
43
return true;
22
44
}
23
-
// TODO: parse condition, return bool
24
-
return false;
45
+
const [lhs, relational, rhs] = condition.split(' ');
46
+
if (lhs === undefined || relational === undefined || rhs === undefined) {
47
+
throw new Error(`Condition "${condition}" is not in the correct format`);
48
+
}
49
+
const lhsResolved = notNotANumber(resolveSide(lhs, currentWeather), lhs);
50
+
const rhsResolved = notNotANumber(resolveSide(rhs, currentWeather), rhs);
51
+
switch (relational) {
52
+
case '=':
53
+
case '==':
54
+
return lhsResolved == rhsResolved;
55
+
case '!=':
56
+
return lhsResolved != rhsResolved;
57
+
case '<':
58
+
return lhsResolved < rhsResolved;
59
+
case '<=':
60
+
return lhsResolved <= rhsResolved;
61
+
case '>':
62
+
return lhsResolved > rhsResolved;
63
+
case '>=':
64
+
return lhsResolved >= rhsResolved;
65
+
default:
66
+
throw new Error(`Unsupported relational operator: ${relational}`);
67
+
}
25
68
}
26
69
27
-
function processSequence(sequence: Sequence): string[] {
70
+
function resolveMacro(str: string, currentWeather: DailyWeather): string[] {
71
+
if (str.startsWith('%')) {
72
+
const [profile, subject] = str.substring(1).split(' ', 2);
73
+
const voiceProfile: Voice = config.voices[profile];
74
+
let resolvedSubject: any = currentWeather;
75
+
subject.split('.').forEach(t => resolvedSubject = resolvedSubject[t]);
76
+
return voiceLines(voiceProfile, resolvedSubject);
77
+
}
78
+
return [str];
79
+
}
80
+
81
+
function processSequence(sequence: Sequence, currentWeather: DailyWeather): string[] {
28
82
const tracks = sequence.tracks;
29
-
// TODO: process voice macros
30
-
return tracks;
83
+
return tracks.map(t => resolveMacro(t, currentWeather)).flat().filter(t => t !== null);
31
84
}
32
85
33
-
function processSegment(segment: SegmentName): string[] {
86
+
function processSegment(segment: SegmentName, currentWeather: DailyWeather): string[] {
34
87
if (!(segment in config.segments)) {
35
-
return processSequence(config.sequences[segment]);
88
+
return (config.sequences[segment].conditions || []).every(c => conditionIsMet(c, currentWeather)) ? processSequence(config.sequences[segment], currentWeather) : [];
36
89
}
37
-
const potentialSequences: SequenceName[] = config.segments[segment].filter(s => conditionIsMet(config.sequences[s].condition));
90
+
const potentialSequences: SequenceName[] = config.segments[segment].filter(s => (config.sequences[s].conditions || []).every(c => conditionIsMet(c, currentWeather)));
38
91
if (potentialSequences.length === 0) {
39
92
return [];
40
93
}
41
-
return processSequence(config.sequences[selectOne(potentialSequences)]);
94
+
return processSequence(config.sequences[selectOne(potentialSequences)], currentWeather);
42
95
}
43
96
44
-
function Sequencer(conf: Config): string[] {
97
+
async function Sequencer(conf: Config): Promise<string[]> {
45
98
config = conf;
99
+
const weather = new OpenWeatherAPI(conf.weather);
100
+
const currentWeather = await weather.getToday();
46
101
const sequence: string[] = [];
47
102
const program: SegmentName[] = selectOne(conf.programs);
48
-
program.forEach(segment => sequence.push(...processSegment(segment)));
103
+
for (let i = 0; i < program.length; i++) {
104
+
const segment = program[i];
105
+
sequence.push(...(processSegment(segment, currentWeather)));
106
+
}
49
107
return sequence;
50
108
}
51
109
+34
src/stitcher.ts
+34
src/stitcher.ts
···
1
+
import { spawn } from 'child_process';
2
+
3
+
const ENCTOOL = process.env['ENCTOOL'] || 'ffmpeg';
4
+
5
+
function ffmpeg(args: string[], files: number): Promise<void> {
6
+
return new Promise((resolve, reject) => {
7
+
console.log(`${ENCTOOL} ${args.join(' ')}`);
8
+
const process = spawn(ENCTOOL, args);
9
+
const to = setTimeout(async () => {
10
+
process.kill();
11
+
reject(new Error('timed out'));
12
+
}, 5000 * files);
13
+
process.on('exit', async (code) => {
14
+
clearTimeout(to);
15
+
if (code !== 0) {
16
+
reject(new Error(`exited with ${code}`));
17
+
}
18
+
else {
19
+
resolve();
20
+
}
21
+
});
22
+
});
23
+
}
24
+
25
+
async function Stitcher(files: string[]) {
26
+
const args: string[] = [];
27
+
files.forEach(f => args.push('-i', f));
28
+
args.push('-filter_complex', `[0:a][1:a][2:a]concat=n=${files.length}:v=0:a=1[out]`);
29
+
args.push('-map', '[out]', '-ar', '44100', '-ac', '2', '-c:a', 'pcm_s16le', 'output.wav', '-y');
30
+
await ffmpeg(args, files.length);
31
+
}
32
+
33
+
export default Stitcher;
34
+
export { Stitcher };
-101
src/weather.ts
-101
src/weather.ts
···
1
-
import OpenWeatherMap from 'openweathermap-ts';
2
-
import type { ThreeHourResponse, CurrentResponse, CountryCode } from 'openweathermap-ts/dist/types/index.js';
3
-
4
-
interface CityName {
5
-
cityName: string;
6
-
state: string;
7
-
countryCode: CountryCode;
8
-
}
9
-
10
-
interface WeatherConfig {
11
-
key: string;
12
-
lang?: string;
13
-
coordinates?: number[] | string;
14
-
zip?: number;
15
-
country?: CountryCode;
16
-
cityid?: number;
17
-
city?: CityName;
18
-
}
19
-
20
-
type LocationType = 'coordinates' | 'zip' | 'cityid' | 'city' | null;
21
-
22
-
function parseCoords(coords: number[] | string): number[] {
23
-
if (typeof coords == 'string') {
24
-
return coords.replace(/\s/g, '').split(',').map(Number.parseFloat);
25
-
}
26
-
return coords;
27
-
}
28
-
29
-
30
-
class Weather {
31
-
private openWeather: OpenWeatherMap.default;
32
-
private locationType: LocationType;
33
-
private current: CurrentResponse;
34
-
private threeDay: ThreeHourResponse;
35
-
36
-
constructor(options: WeatherConfig) {
37
-
this.locationType = this.current = this.threeDay = null;
38
-
this.openWeather = new OpenWeatherMap.default({
39
-
apiKey: options.key
40
-
});
41
-
if ('city' in options && 'cityName' in options.city && 'state' in options.city && 'countryCode' in options.city) {
42
-
this.openWeather.setCityName(options.city);
43
-
this.locationType = 'city';
44
-
}
45
-
if ('cityid' in options) {
46
-
this.openWeather.setCityId(options.cityid);
47
-
this.locationType = 'cityid';
48
-
}
49
-
if ('zip' in options && 'country' in options) {
50
-
this.openWeather.setZipCode(options.zip, options.country)
51
-
this.locationType = 'zip';
52
-
}
53
-
if ('coordinates' in options) {
54
-
const coords = parseCoords(options.coordinates);
55
-
if (coords.length >= 2) {
56
-
this.openWeather.setGeoCoordinates(coords[0], coords[1]);
57
-
this.locationType = 'coordinates';
58
-
}
59
-
}
60
-
}
61
-
62
-
async getCurrentWeather(): Promise<CurrentResponse> {
63
-
if (this.current) {
64
-
return this.current;
65
-
}
66
-
switch (this.locationType) {
67
-
case 'city':
68
-
return this.current = await this.openWeather.getCurrentWeatherByCityName();
69
-
case 'cityid':
70
-
return this.current = await this.openWeather.getCurrentWeatherByCityId();
71
-
case 'zip':
72
-
return this.current = await this.openWeather.getCurrentWeatherByZipcode();
73
-
case 'coordinates':
74
-
return this.current = await this.openWeather.getCurrentWeatherByGeoCoordinates();
75
-
default:
76
-
throw new Error(`Can't fetch weather for location type '${this.locationType}'`);
77
-
}
78
-
}
79
-
80
-
async getThreeHourForecast(): Promise<ThreeHourResponse> {
81
-
if (this.threeDay) {
82
-
return this.threeDay;
83
-
}
84
-
switch (this.locationType) {
85
-
case 'city':
86
-
return this.threeDay = await this.openWeather.getThreeHourForecastByCityName();
87
-
case 'cityid':
88
-
return this.threeDay = await this.openWeather.getThreeHourForecastByCityId();
89
-
case 'zip':
90
-
return this.threeDay = await this.openWeather.getThreeHourForecastByZipcode();
91
-
case 'coordinates':
92
-
return this.threeDay = await this.openWeather.getThreeHourForecastByGeoCoordinates();
93
-
default:
94
-
throw new Error(`Can't fetch weather for location type '${this.locationType}'`);
95
-
}
96
-
}
97
-
}
98
-
99
-
export default Weather;
100
-
export { Weather };
101
-
export type { WeatherConfig, CityName, CurrentResponse, ThreeHourResponse };
+189
test/sequencer.test.ts
+189
test/sequencer.test.ts
···
1
+
import { describe, expect, it, vi } from 'vitest';
2
+
import { type Options } from 'openweather-api-node';
3
+
import { Sequencer } from '../src/sequencer.js';
4
+
5
+
const dummyWeather: Options = { key: 'dummy' };
6
+
7
+
vi.mock('openweather-api-node', () => {
8
+
return {
9
+
OpenWeatherAPI: vi.fn().mockImplementation((_) => {
10
+
return {
11
+
getToday: vi.fn(() => {
12
+
return {
13
+
"lat": 43.0748,
14
+
"lon": -89.3838,
15
+
"dt": "2025-08-29T06:31:05.000Z",
16
+
"dtRaw": 1756449065,
17
+
"timezoneOffset": -18000,
18
+
"astronomical": {
19
+
"sunrise": "2025-08-29T11:19:05.000Z",
20
+
"sunriseRaw": 1756466345,
21
+
"sunset": "2025-08-30T00:38:08.000Z",
22
+
"sunsetRaw": 1756514288
23
+
},
24
+
"weather": {
25
+
"temp": {
26
+
"cur": 55.85,
27
+
"min": 52.99,
28
+
"max": 58.01
29
+
},
30
+
"feelsLike": {
31
+
"cur": 55.31
32
+
},
33
+
"pressure": 1022,
34
+
"humidity": 89,
35
+
"clouds": 0,
36
+
"visibility": 10000,
37
+
"wind": {
38
+
"deg": 140,
39
+
"speed": 5.75
40
+
},
41
+
"rain": 0,
42
+
"snow": 0,
43
+
"conditionId": 800,
44
+
"main": "Clear",
45
+
"description": "clear sky",
46
+
"icon": {
47
+
"url": "http://openweathermap.org/img/wn/01n@2x.png",
48
+
"raw": "01n"
49
+
}
50
+
}
51
+
}
52
+
})
53
+
}
54
+
})
55
+
}
56
+
});
57
+
58
+
describe('sequencer', () => {
59
+
it('can generate a list from a static config', async () => {
60
+
expect(await Sequencer({
61
+
programs: [['sequence 1', 'segment 1', 'segment 2']],
62
+
segments: {
63
+
'segment 1': ['sequence 1'],
64
+
'segment 2': ['sequence 2']
65
+
},
66
+
sequences: {
67
+
'sequence 1': {
68
+
'tracks': [
69
+
'seq1.flac'
70
+
]
71
+
},
72
+
'sequence 2': {
73
+
'tracks': [
74
+
'seq2.flac'
75
+
]
76
+
}
77
+
},
78
+
voices: {},
79
+
weather: dummyWeather
80
+
})).to.include.ordered.members(['seq1.flac', 'seq1.flac', 'seq2.flac']);
81
+
});
82
+
83
+
it('can include tracks conditionally', async () => {
84
+
expect(await Sequencer({
85
+
programs: [['segment 1', 'sequence 1', 'segment 2', 'sequence 2']],
86
+
segments: {
87
+
'segment 1': ['sequence 1'],
88
+
'segment 2': ['sequence 2']
89
+
},
90
+
sequences: {
91
+
'sequence 1': {
92
+
'conditions': ['1 = 1', '1.1 > 1', '2 >= 1', '1 < 2', '1 <= 1', '-1 != 0', undefined],
93
+
'tracks': [
94
+
'seq1.flac'
95
+
]
96
+
},
97
+
'sequence 2': {
98
+
'conditions': ['weather.lat = -500'],
99
+
'tracks': [
100
+
'seq2.flac'
101
+
]
102
+
}
103
+
},
104
+
voices: {},
105
+
weather: dummyWeather
106
+
})).to.be.ordered.members(['seq1.flac', 'seq1.flac']);
107
+
});
108
+
109
+
it('throws an error on invalid conditions', async () => {
110
+
await expect(Sequencer({
111
+
programs: [['sequence 1']],
112
+
segments: {
113
+
},
114
+
sequences: {
115
+
'sequence 1': {
116
+
'conditions': ['100'],
117
+
'tracks': [
118
+
'seq1.flac'
119
+
]
120
+
}
121
+
},
122
+
voices: {},
123
+
weather: dummyWeather
124
+
})).rejects.toThrow(/not in the correct format/);
125
+
126
+
await expect(Sequencer({
127
+
programs: [['sequence 1']],
128
+
segments: {
129
+
},
130
+
sequences: {
131
+
'sequence 1': {
132
+
'conditions': ['1 ~ 2'],
133
+
'tracks': [
134
+
'seq1.flac'
135
+
]
136
+
}
137
+
},
138
+
voices: {},
139
+
weather: dummyWeather
140
+
})).rejects.toThrow(/Unsupported relational operator/);
141
+
});
142
+
143
+
it('can stringify conditions', async () => {
144
+
expect(await Sequencer({
145
+
programs: [['sequence 1']],
146
+
segments: {
147
+
},
148
+
sequences: {
149
+
'sequence 1': {
150
+
'conditions': ['weather.feelsLike = {"cur":55.31}'],
151
+
'tracks': [
152
+
'seq1.flac'
153
+
]
154
+
}
155
+
},
156
+
voices: {},
157
+
weather: dummyWeather
158
+
})).to.be.ordered.members(['seq1.flac']);
159
+
});
160
+
161
+
it('can parse voice macros', async () => {
162
+
expect(await Sequencer({
163
+
programs: [['sequence 1']],
164
+
segments: {
165
+
},
166
+
sequences: {
167
+
'sequence 1': {
168
+
'tracks': [
169
+
'%alice weather.temp.max'
170
+
]
171
+
}
172
+
},
173
+
voices: {
174
+
"alice": {
175
+
"directory": "alice/",
176
+
"extension": "flac"
177
+
}
178
+
},
179
+
weather: dummyWeather
180
+
})).to.be.ordered.members([
181
+
'alice/fifty.flac',
182
+
'alice/eight.flac',
183
+
'alice/point.flac',
184
+
'alice/zero.flac',
185
+
'alice/one.flac'
186
+
]);
187
+
});
188
+
});
189
+
+90
test/stitcher.test.ts
+90
test/stitcher.test.ts
···
1
+
import { Stitcher } from '../src/stitcher.js';
2
+
import { describe, expect, it, vi, beforeEach } from 'vitest';
3
+
import { EventEmitter } from 'events';
4
+
import { spawn } from 'child_process';
5
+
6
+
const mockChildProcess = new (class MockChildProcess
7
+
extends EventEmitter {
8
+
kill = vi.fn(() => {
9
+
return true;
10
+
});
11
+
})();
12
+
13
+
vi.mock('child_process', () => {
14
+
return {
15
+
spawn: vi.fn(() => mockChildProcess)
16
+
}
17
+
});
18
+
19
+
describe('stitcher', () => {
20
+
21
+
beforeEach(() => {
22
+
vi.clearAllMocks();
23
+
});
24
+
25
+
it('passes the correct arguments to ffmpeg', async () => {
26
+
const p = Stitcher(['1.flac', 'dir/2.flac']);
27
+
mockChildProcess.emit('exit', 0, null);
28
+
await p;
29
+
expect(spawn).toBeCalledWith('ffmpeg', [
30
+
"-i",
31
+
'1.flac',
32
+
'-i',
33
+
'dir/2.flac',
34
+
'-filter_complex',
35
+
'[0:a][1:a][2:a]concat=n=2:v=0:a=1[out]',
36
+
'-map',
37
+
'[out]',
38
+
'-ar',
39
+
'44100',
40
+
'-ac',
41
+
'2',
42
+
'-c:a',
43
+
'pcm_s16le',
44
+
'output.wav',
45
+
'-y'
46
+
]);
47
+
});
48
+
49
+
it('throws an error when ffmpeg fails', async () => {
50
+
const p = Stitcher(['sound.mp3']);
51
+
mockChildProcess.emit('exit', 1, null);
52
+
await expect(p).rejects.toThrow('exited with 1');
53
+
expect(spawn).toBeCalledWith('ffmpeg', [
54
+
"-i",
55
+
'sound.mp3',
56
+
'-filter_complex',
57
+
'[0:a][1:a][2:a]concat=n=1:v=0:a=1[out]',
58
+
'-map',
59
+
'[out]',
60
+
'-ar',
61
+
'44100',
62
+
'-ac',
63
+
'2',
64
+
'-c:a',
65
+
'pcm_s16le',
66
+
'output.wav',
67
+
'-y'
68
+
]);
69
+
});
70
+
71
+
it('throws an error when ffmpeg takes longer than expected', { timeout: 6000 }, async () => {
72
+
await expect(Stitcher(['in.wav'])).rejects.toThrow('timed out');
73
+
expect(spawn).toBeCalledWith('ffmpeg', [
74
+
"-i",
75
+
'in.wav',
76
+
'-filter_complex',
77
+
'[0:a][1:a][2:a]concat=n=1:v=0:a=1[out]',
78
+
'-map',
79
+
'[out]',
80
+
'-ar',
81
+
'44100',
82
+
'-ac',
83
+
'2',
84
+
'-c:a',
85
+
'pcm_s16le',
86
+
'output.wav',
87
+
'-y'
88
+
]);
89
+
});
90
+
});
+15
-15
test/voice.test.ts
+15
-15
test/voice.test.ts
···
10
10
11
11
describe('voiceLines', () => {
12
12
it('handles integers', () => {
13
-
expect(voiceLines(dummyVoice, 16549872)).to.include.ordered.members(
13
+
expect(voiceLines(dummyVoice, 16549872)).to.be.ordered.members(
14
14
[
15
15
LINES.SIX, LINES.TEEN, LINES.MILLION, LINES.FIVE, LINES.HUNDRED, LINES.FORTY,
16
16
LINES.NINE, LINES.THOUSAND, LINES.EIGHT, LINES.HUNDRED, LINES.SEVENTY, LINES.TWO
···
19
19
});
20
20
21
21
it('handles floating point', () => {
22
-
expect(voiceLines(dummyVoice, 672.09435)).to.include.ordered.members(
22
+
expect(voiceLines(dummyVoice, 672.09435)).to.be.ordered.members(
23
23
[
24
24
LINES.SIX, LINES.HUNDRED, LINES.SEVENTY, LINES.TWO, LINES.POINT, LINES.ZERO,
25
25
LINES.NINE, LINES.FOUR, LINES.THREE, LINES.FIVE
···
28
28
});
29
29
30
30
it('handles the negative', () => {
31
-
expect(voiceLines(dummyVoice, -672.09435)).to.include.ordered.members(
31
+
expect(voiceLines(dummyVoice, -672.09435)).to.be.ordered.members(
32
32
[
33
33
LINES.NEGATIVE, LINES.SIX, LINES.HUNDRED, LINES.SEVENTY, LINES.TWO, LINES.POINT, LINES.ZERO,
34
34
LINES.NINE, LINES.FOUR, LINES.THREE, LINES.FIVE
···
37
37
});
38
38
39
39
it('handles zero', () => {
40
-
expect(voiceLines(dummyVoice, 0)).to.include.ordered.members(
40
+
expect(voiceLines(dummyVoice, 0)).to.be.ordered.members(
41
41
[
42
42
LINES.ZERO
43
43
]
···
45
45
});
46
46
47
47
it('handles large numbers with many zeroes', () => {
48
-
expect(voiceLines(dummyVoice, 700000000000001)).to.include.ordered.members(
48
+
expect(voiceLines(dummyVoice, 700000000000001)).to.be.ordered.members(
49
49
[
50
50
LINES.SEVEN, LINES.HUNDRED, LINES.TRILLION, LINES.ONE
51
51
]
52
52
);
53
53
54
-
expect(voiceLines(dummyVoice, 1000001)).to.include.ordered.members(
54
+
expect(voiceLines(dummyVoice, 1000001)).to.be.ordered.members(
55
55
[
56
56
LINES.ONE, LINES.MILLION, LINES.ONE
57
57
]
58
58
);
59
59
60
-
expect(voiceLines(dummyVoice, 9000000001000)).to.include.ordered.members(
60
+
expect(voiceLines(dummyVoice, 9000000001000)).to.be.ordered.members(
61
61
[
62
62
LINES.NINE, LINES.TRILLION, LINES.ONE, LINES.THOUSAND
63
63
]
64
64
);
65
65
66
-
expect(voiceLines(dummyVoice, 60002000000000.12)).to.include.ordered.members(
66
+
expect(voiceLines(dummyVoice, 60002000000000.12)).to.be.ordered.members(
67
67
[
68
68
LINES.SIXTY, LINES.TRILLION, LINES.TWO, LINES.BILLION, LINES.POINT, LINES.ONE, LINES.TWO
69
69
]
70
70
);
71
71
72
-
expect(voiceLines(dummyVoice, 100010001)).to.include.ordered.members(
72
+
expect(voiceLines(dummyVoice, 100010001)).to.be.ordered.members(
73
73
[
74
74
LINES.ONE, LINES.HUNDRED, LINES.MILLION, LINES.TEN, LINES.THOUSAND, LINES.ONE
75
75
]
···
77
77
});
78
78
79
79
it('handles irregularly named numbers', () => {
80
-
expect(voiceLines(dummyVoice, 210)).to.include.ordered.members(
80
+
expect(voiceLines(dummyVoice, 210)).to.be.ordered.members(
81
81
[
82
82
LINES.TWO, LINES.HUNDRED, LINES.TEN
83
83
]
84
84
);
85
85
86
-
expect(voiceLines(dummyVoice, 311)).to.include.ordered.members(
86
+
expect(voiceLines(dummyVoice, 311)).to.be.ordered.members(
87
87
[
88
88
LINES.THREE, LINES.HUNDRED, LINES.ELEVEN
89
89
]
90
90
);
91
91
92
-
expect(voiceLines(dummyVoice, 412)).to.include.ordered.members(
92
+
expect(voiceLines(dummyVoice, 412)).to.be.ordered.members(
93
93
[
94
94
LINES.FOUR, LINES.HUNDRED, LINES.TWELVE
95
95
]
96
96
);
97
97
98
-
expect(voiceLines(dummyVoice, 513)).to.include.ordered.members(
98
+
expect(voiceLines(dummyVoice, 513)).to.be.ordered.members(
99
99
[
100
100
LINES.FIVE, LINES.HUNDRED, LINES.THIRTEEN
101
101
]
102
102
);
103
103
104
-
expect(voiceLines(dummyVoice, 615)).to.include.ordered.members(
104
+
expect(voiceLines(dummyVoice, 615)).to.be.ordered.members(
105
105
[
106
106
LINES.SIX, LINES.HUNDRED, LINES.FIFTEEN
107
107
]
···
121
121
directory,
122
122
extension: 'flac'
123
123
}
124
-
expect(voiceLines(v, 29)).to.include.ordered.members([
124
+
expect(voiceLines(v, 29)).to.be.ordered.members([
125
125
path.join(directory, `twenty.flac`),
126
126
path.join(directory, `nine.flac`),
127
127
]);
-338
test/weather.test.ts
-338
test/weather.test.ts
···
1
-
import OpenWeatherMap from 'openweathermap-ts';
2
-
import { describe, expect, it, vi, beforeEach, type Mocked } from 'vitest';
3
-
import { Weather } from '../src/weather.js';
4
-
import type { CurrentResponse, ThreeHourResponse } from '../src/weather.js';
5
-
6
-
// #region mock API responses
7
-
const current: CurrentResponse = {
8
-
"coord": {
9
-
"lon": 7.367,
10
-
"lat": 45.133
11
-
},
12
-
"weather": [
13
-
{
14
-
"id": 501,
15
-
"main": "Rain",
16
-
"description": "moderate rain",
17
-
"icon": "10d"
18
-
}
19
-
],
20
-
"base": "stations",
21
-
"main": {
22
-
"temp": 284.2,
23
-
"feels_like": 282.93,
24
-
"temp_min": 283.06,
25
-
"temp_max": 286.82,
26
-
"pressure": 1021,
27
-
"humidity": 60,
28
-
"sea_level": 1021,
29
-
"grnd_level": 910
30
-
},
31
-
"visibility": 10000,
32
-
"wind": {
33
-
"speed": 4.09,
34
-
"deg": 121,
35
-
"gust": 3.47
36
-
},
37
-
"rain": {
38
-
"1h": 2.73
39
-
},
40
-
"clouds": {
41
-
"all": 83
42
-
},
43
-
"dt": 1726660758,
44
-
"sys": {
45
-
"type": 1,
46
-
"id": 6736,
47
-
"country": "IT",
48
-
"sunrise": 1726636384,
49
-
"sunset": 1726680975
50
-
},
51
-
"timezone": 7200,
52
-
"id": 3165523,
53
-
"name": "Province of Turin",
54
-
"cod": 200
55
-
};
56
-
57
-
const threeHour: ThreeHourResponse = {
58
-
"cod": "200",
59
-
"message": 0,
60
-
"cnt": 96,
61
-
"list": [
62
-
{
63
-
"dt": 1661875200,
64
-
"main": {
65
-
"temp": 296.34,
66
-
"temp_min": 296.34,
67
-
"temp_max": 298.24,
68
-
"pressure": 1015,
69
-
"sea_level": 1015,
70
-
"grnd_level": 933,
71
-
"humidity": 50,
72
-
"temp_kf": -1.9
73
-
},
74
-
"weather": [
75
-
{
76
-
"id": 500,
77
-
"main": "Rain",
78
-
"description": "light rain",
79
-
"icon": "10d"
80
-
}
81
-
],
82
-
"clouds": {
83
-
"all": 97
84
-
},
85
-
"wind": {
86
-
"speed": 1.06,
87
-
"deg": 66
88
-
},
89
-
"rain": {
90
-
"3h": 1
91
-
},
92
-
"sys": {
93
-
"pod": "d"
94
-
},
95
-
"dt_txt": "2022-08-30 16:00:00"
96
-
},
97
-
{
98
-
"dt": 1661878800,
99
-
"main": {
100
-
"temp": 296.31,
101
-
"temp_min": 296.2,
102
-
"temp_max": 296.31,
103
-
"pressure": 1015,
104
-
"sea_level": 1015,
105
-
"grnd_level": 932,
106
-
"humidity": 53,
107
-
"temp_kf": 0.11
108
-
},
109
-
"weather": [
110
-
{
111
-
"id": 500,
112
-
"main": "Rain",
113
-
"description": "light rain",
114
-
"icon": "10d"
115
-
}
116
-
],
117
-
"clouds": {
118
-
"all": 95
119
-
},
120
-
"wind": {
121
-
"speed": 1.58,
122
-
"deg": 103
123
-
},
124
-
"rain": {
125
-
"3h": 0.24
126
-
},
127
-
"sys": {
128
-
"pod": "d"
129
-
},
130
-
"dt_txt": "2022-08-30 17:00:00"
131
-
},
132
-
{
133
-
"dt": 1661882400,
134
-
"main": {
135
-
"temp": 294.94,
136
-
"temp_min": 292.84,
137
-
"temp_max": 294.94,
138
-
"pressure": 1015,
139
-
"sea_level": 1015,
140
-
"grnd_level": 931,
141
-
"humidity": 60,
142
-
"temp_kf": 2.1
143
-
},
144
-
"weather": [
145
-
{
146
-
"id": 500,
147
-
"main": "Rain",
148
-
"description": "light rain",
149
-
"icon": "10n"
150
-
}
151
-
],
152
-
"clouds": {
153
-
"all": 93
154
-
},
155
-
"wind": {
156
-
"speed": 1.97,
157
-
"deg": 157
158
-
},
159
-
"rain": {
160
-
"3h": 0.2
161
-
},
162
-
"sys": {
163
-
"pod": "n"
164
-
},
165
-
"dt_txt": "2022-08-30 18:00:00"
166
-
},
167
-
{
168
-
"dt": 1662217200,
169
-
"main": {
170
-
"temp": 294.14,
171
-
"temp_min": 294.14,
172
-
"temp_max": 294.14,
173
-
"pressure": 1014,
174
-
"sea_level": 1014,
175
-
"grnd_level": 931,
176
-
"humidity": 65,
177
-
"temp_kf": 0
178
-
},
179
-
"weather": [
180
-
{
181
-
"id": 804,
182
-
"main": "Clouds",
183
-
"description": "overcast clouds",
184
-
"icon": "04d"
185
-
}
186
-
],
187
-
"clouds": {
188
-
"all": 100
189
-
},
190
-
"wind": {
191
-
"speed": 0.91,
192
-
"deg": 104
193
-
},
194
-
"sys": {
195
-
"pod": "d"
196
-
},
197
-
"dt_txt": "2022-09-03 15:00:00"
198
-
}
199
-
],
200
-
"city": {
201
-
"id": 3163858,
202
-
"name": "Zocca",
203
-
"coord": {
204
-
"lat": 44.34,
205
-
"lon": 10.99
206
-
},
207
-
"country": "IT"
208
-
}
209
-
}
210
-
// #endregion
211
-
212
-
vi.mock('openweathermap-ts', () => {
213
-
return {
214
-
default: {
215
-
default: vi.fn().mockImplementation((_) => {
216
-
return {
217
-
setCityName: vi.fn(() => undefined),
218
-
setCityId: vi.fn(() => undefined),
219
-
setZipCode: vi.fn(() => undefined),
220
-
setGeoCoordinates: vi.fn(() => undefined),
221
-
getCurrentWeatherByCityName: vi.fn(async () => current),
222
-
getCurrentWeatherByCityId: vi.fn(async () => current),
223
-
getCurrentWeatherByZipcode: vi.fn(async () => current),
224
-
getCurrentWeatherByGeoCoordinates: vi.fn(async () => current),
225
-
getThreeHourForecastByCityName: vi.fn(async () => threeHour),
226
-
getThreeHourForecastByCityId: vi.fn(async () => threeHour),
227
-
getThreeHourForecastByZipcode: vi.fn(async () => threeHour),
228
-
getThreeHourForecastByGeoCoordinates: vi.fn(async () => threeHour),
229
-
}
230
-
})
231
-
}
232
-
}
233
-
});
234
-
235
-
let weather: Weather = null;
236
-
237
-
describe.for(
238
-
[
239
-
{
240
-
weatherFactory: () => new Weather({
241
-
key: 'api-key',
242
-
city: {
243
-
cityName: 'Madison',
244
-
state: 'Wisconsin',
245
-
countryCode: 'US'
246
-
}
247
-
}),
248
-
by: 'CityName'
249
-
},
250
-
{
251
-
weatherFactory: () => new Weather({
252
-
key: 'api-key',
253
-
cityid: 1
254
-
}),
255
-
by: 'CityId'
256
-
},
257
-
{
258
-
weatherFactory: () => new Weather({
259
-
key: 'api-key',
260
-
zip: 53702,
261
-
country: 'US'
262
-
}),
263
-
by: 'Zipcode'
264
-
},
265
-
{
266
-
weatherFactory: () => new Weather({
267
-
key: 'api-key',
268
-
coordinates: [0, 0]
269
-
}),
270
-
by: 'GeoCoordinates'
271
-
},
272
-
{
273
-
weatherFactory: () => new Weather({
274
-
key: 'api-key',
275
-
coordinates: '1000 , 1000'
276
-
}),
277
-
by: 'GeoCoordinates'
278
-
}
279
-
])('weather API using city name', ({ weatherFactory, by }) => {
280
-
beforeEach(() => {
281
-
vi.clearAllMocks();
282
-
weather = weatherFactory();
283
-
});
284
-
285
-
it('gets current weather', async () => {
286
-
expect(await weather.getCurrentWeather()).to.deep.equal(current);
287
-
expect(OpenWeatherMap.default).toBeCalledWith({
288
-
apiKey: 'api-key'
289
-
});
290
-
const MockedOpenWeather = vi.mocked(OpenWeatherMap.default);
291
-
const openWeather = MockedOpenWeather.mock.results[0].value;
292
-
expect(openWeather[`getCurrentWeatherBy${by}`]).toBeCalledTimes(1);
293
-
});
294
-
295
-
it('gets the 3h forecast', async () => {
296
-
expect(await weather.getThreeHourForecast()).to.deep.equal(threeHour);
297
-
expect(OpenWeatherMap.default).toBeCalledWith({
298
-
apiKey: 'api-key'
299
-
});
300
-
const MockedOpenWeather = vi.mocked(OpenWeatherMap.default);
301
-
const openWeather = MockedOpenWeather.mock.results[0].value;
302
-
expect(openWeather[`getThreeHourForecastBy${by}`]).toBeCalledTimes(1);
303
-
});
304
-
305
-
it('only calls the api once', async () => {
306
-
expect(await weather.getCurrentWeather()).to.deep.equal(current);
307
-
expect(await weather.getCurrentWeather()).to.deep.equal(current);
308
-
expect(await weather.getThreeHourForecast()).to.deep.equal(threeHour);
309
-
expect(await weather.getThreeHourForecast()).to.deep.equal(threeHour);
310
-
expect(OpenWeatherMap.default).toBeCalledWith({
311
-
apiKey: 'api-key'
312
-
});
313
-
const MockedOpenWeather = vi.mocked(OpenWeatherMap.default);
314
-
const openWeather = MockedOpenWeather.mock.results[0].value;
315
-
expect(openWeather[`getCurrentWeatherBy${by}`]).toBeCalledTimes(1);
316
-
expect(openWeather[`getThreeHourForecastBy${by}`]).toBeCalledTimes(1);
317
-
});
318
-
}
319
-
);
320
-
321
-
describe('invalid weather object', () => {
322
-
beforeEach(() => {
323
-
vi.clearAllMocks();
324
-
weather = new Weather({
325
-
key: 'api-key',
326
-
cityid: 1
327
-
});
328
-
weather['locationType'] = null;
329
-
});
330
-
331
-
it('throws an exception when getCurrentWeather is called', async () => {
332
-
await expect(weather.getCurrentWeather()).rejects.toThrow(/location type/);
333
-
});
334
-
335
-
it('throws an exception when getThreeHourForecast is called', async () => {
336
-
await expect(weather.getThreeHourForecast()).rejects.toThrow(/location type/);
337
-
});
338
-
});