@sayue_ltr/fleq 1.49.2

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.
Files changed (52) hide show
  1. package/CHANGELOG.md +898 -0
  2. package/LICENSE +21 -0
  3. package/README.md +535 -0
  4. package/assets/icons/.gitkeep +0 -0
  5. package/assets/sounds/.gitkeep +0 -0
  6. package/assets/sounds/cancel.mp3 +0 -0
  7. package/assets/sounds/critical.mp3 +0 -0
  8. package/assets/sounds/info.mp3 +0 -0
  9. package/assets/sounds/normal.mp3 +0 -0
  10. package/assets/sounds/warning.mp3 +0 -0
  11. package/dist/config.js +638 -0
  12. package/dist/dmdata/connection-manager.js +2 -0
  13. package/dist/dmdata/endpoint-selector.js +185 -0
  14. package/dist/dmdata/multi-connection-manager.js +158 -0
  15. package/dist/dmdata/rest-client.js +281 -0
  16. package/dist/dmdata/telegram-parser.js +704 -0
  17. package/dist/dmdata/volcano-parser.js +647 -0
  18. package/dist/dmdata/ws-client.js +336 -0
  19. package/dist/engine/cli/cli-init.js +266 -0
  20. package/dist/engine/cli/cli-run.js +121 -0
  21. package/dist/engine/cli/cli.js +121 -0
  22. package/dist/engine/eew/eew-logger.js +355 -0
  23. package/dist/engine/eew/eew-tracker.js +229 -0
  24. package/dist/engine/messages/message-router.js +261 -0
  25. package/dist/engine/messages/tsunami-state.js +96 -0
  26. package/dist/engine/messages/volcano-state.js +131 -0
  27. package/dist/engine/messages/volcano-vfvo53-aggregator.js +173 -0
  28. package/dist/engine/monitor/monitor.js +118 -0
  29. package/dist/engine/monitor/repl-coordinator.js +63 -0
  30. package/dist/engine/monitor/shutdown.js +114 -0
  31. package/dist/engine/notification/node-notifier-loader.js +19 -0
  32. package/dist/engine/notification/notifier.js +338 -0
  33. package/dist/engine/notification/sound-player.js +230 -0
  34. package/dist/engine/notification/volcano-presentation.js +166 -0
  35. package/dist/engine/startup/config-resolver.js +139 -0
  36. package/dist/engine/startup/tsunami-initializer.js +91 -0
  37. package/dist/engine/startup/update-checker.js +229 -0
  38. package/dist/engine/startup/volcano-initializer.js +89 -0
  39. package/dist/index.js +24 -0
  40. package/dist/logger.js +95 -0
  41. package/dist/types.js +61 -0
  42. package/dist/ui/earthquake-formatter.js +871 -0
  43. package/dist/ui/eew-formatter.js +335 -0
  44. package/dist/ui/formatter.js +689 -0
  45. package/dist/ui/repl.js +2059 -0
  46. package/dist/ui/test-samples.js +880 -0
  47. package/dist/ui/theme.js +516 -0
  48. package/dist/ui/volcano-formatter.js +667 -0
  49. package/dist/ui/waiting-tips.js +227 -0
  50. package/dist/utils/intensity.js +13 -0
  51. package/dist/utils/secrets.js +14 -0
  52. package/package.json +69 -0
@@ -0,0 +1,335 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.eewFrameLevel = eewFrameLevel;
40
+ exports.displayEewInfo = displayEewInfo;
41
+ const chalk_1 = __importDefault(require("chalk"));
42
+ const theme = __importStar(require("./theme"));
43
+ const formatter_1 = require("./formatter");
44
+ // ── EEW バナーパレット ──
45
+ /**
46
+ * EEW バナー色パレット (遅延生成: chalk.level が確定した後に呼ぶ)
47
+ * chalk v4 では bgRgb() 呼び出し時点の level で ANSI コードが確定するため、
48
+ * モジュールレベル定数ではなく関数で都度生成する。
49
+ */
50
+ function getWarningBannerPalette() {
51
+ return [
52
+ theme.getRoleChalk("eewWarningBanner"),
53
+ theme.getRoleChalk("eewWarningBanner1"),
54
+ theme.getRoleChalk("eewWarningBanner2"),
55
+ theme.getRoleChalk("eewWarningBanner3"),
56
+ theme.getRoleChalk("eewWarningBanner4"),
57
+ ];
58
+ }
59
+ function getForecastBannerPalette() {
60
+ return [
61
+ theme.getRoleChalk("eewForecastBanner"),
62
+ theme.getRoleChalk("eewForecastBanner1"),
63
+ theme.getRoleChalk("eewForecastBanner2"),
64
+ theme.getRoleChalk("eewForecastBanner3"),
65
+ theme.getRoleChalk("eewForecastBanner4"),
66
+ ];
67
+ }
68
+ /** colorIndex からバナースタイルを取得 */
69
+ function getEewBannerStyle(isWarning, colorIndex) {
70
+ const palette = isWarning ? getWarningBannerPalette() : getForecastBannerPalette();
71
+ return palette[colorIndex % palette.length];
72
+ }
73
+ /** PLUM法バナーの装飾行スタイル (1行目・3行目用) */
74
+ function getPlumDecorStyle(isWarning) {
75
+ return isWarning
76
+ ? theme.getRoleChalk("plumDecorWarning")
77
+ : theme.getRoleChalk("plumDecorForecast");
78
+ }
79
+ /** EEW のフレームレベルを決定 */
80
+ function eewFrameLevel(info) {
81
+ if (info.infoType === "取消")
82
+ return "cancel";
83
+ if (info.isWarning)
84
+ return "critical";
85
+ return "warning";
86
+ }
87
+ /** EEW情報を整形して表示 */
88
+ function displayEewInfo(info, context) {
89
+ const isCancelled = info.infoType === "取消";
90
+ const level = eewFrameLevel(info);
91
+ const diff = context?.diff;
92
+ const width = (0, formatter_1.getFrameWidth)();
93
+ // コンパクトモード: 1行サマリー
94
+ if ((0, formatter_1.getDisplayMode)() === "compact") {
95
+ const parts = [];
96
+ parts.push(formatter_1.SEVERITY_LABELS[level]);
97
+ const typeTag = isCancelled ? "EEW取消" : info.isWarning ? "EEW警報" : "EEW予報";
98
+ parts.push(typeTag);
99
+ if (info.serial)
100
+ parts.push(`#${info.serial}`);
101
+ if (info.earthquake)
102
+ parts.push(info.earthquake.hypocenterName);
103
+ if (info.forecastIntensity?.areas.length) {
104
+ const maxInt = info.forecastIntensity.areas.reduce((best, area) => (0, formatter_1.intensityToNumeric)(area.intensity) > (0, formatter_1.intensityToNumeric)(best) ? area.intensity : best, info.forecastIntensity.areas[0].intensity);
105
+ parts.push(`震度${maxInt}`);
106
+ }
107
+ if (info.earthquake?.magnitude && !info.isAssumedHypocenter) {
108
+ parts.push(`M${info.earthquake.magnitude}`);
109
+ }
110
+ const color = (0, formatter_1.frameColor)(level);
111
+ console.log(color(parts.join(" ")));
112
+ return;
113
+ }
114
+ const buf = (0, formatter_1.createRenderBuffer)();
115
+ buf.pushEmpty();
116
+ // バナー (警報/予報/取消のヘッダー)
117
+ const bannerWidth = width;
118
+ const serialTag = info.serial ? ` #${info.serial}` : "";
119
+ const hypocenterTag = info.earthquake?.hypocenterName ? ` ${info.earthquake.hypocenterName}` : "";
120
+ const colorIndex = context?.colorIndex ?? 0;
121
+ if (isCancelled) {
122
+ const bannerText = ` 緊急地震速報 取消${serialTag}${hypocenterTag}`;
123
+ const cancelBanner = theme.getRoleChalk("eewCancelBanner");
124
+ buf.push(cancelBanner(" ".repeat(bannerWidth)));
125
+ buf.push(cancelBanner((0, formatter_1.visualPadEnd)(bannerText, bannerWidth)));
126
+ buf.push(cancelBanner(" ".repeat(bannerWidth)));
127
+ }
128
+ else {
129
+ const bannerStyle = getEewBannerStyle(info.isWarning, colorIndex);
130
+ const typeLbl = info.isWarning ? "警報" : "予報";
131
+ const bannerText = ` 緊急地震速報(${typeLbl})${serialTag}${hypocenterTag}`;
132
+ const decorStyle = info.isAssumedHypocenter ? getPlumDecorStyle(info.isWarning) : bannerStyle;
133
+ buf.push(decorStyle(" ".repeat(bannerWidth)));
134
+ buf.push(bannerStyle((0, formatter_1.visualPadEnd)(bannerText, bannerWidth)));
135
+ buf.push(decorStyle(" ".repeat(bannerWidth)));
136
+ }
137
+ // フレーム開始 (テスト電文/PLUM法ラベルがある場合のみ先にframeTopを出す)
138
+ const hasPreContent = info.isTest || info.maxIntChangeReason === 9;
139
+ if (hasPreContent) {
140
+ buf.push((0, formatter_1.frameTop)(level, width));
141
+ }
142
+ // テスト電文
143
+ if (info.isTest) {
144
+ buf.push((0, formatter_1.frameLine)(level, theme.getRoleChalk("testBadge")(" テスト電文 "), width));
145
+ }
146
+ // PLUM法ラベル (MaxIntChangeReason=9)
147
+ if (info.maxIntChangeReason === 9) {
148
+ buf.push((0, formatter_1.frameLine)(level, theme.getRoleChalk("plumLabel")("PLUM法") + chalk_1.default.gray(" による予測震度変化"), width));
149
+ }
150
+ // カード1行目: infoType + 最重要項目
151
+ const activeCount = context?.activeCount ?? 0;
152
+ if (!isCancelled) {
153
+ buf.push(hasPreContent ? (0, formatter_1.frameDivider)(level, width) : (0, formatter_1.frameTop)(level, width));
154
+ const cardParts = [];
155
+ // infoType (+ 同時発生注記)
156
+ if (activeCount >= 2 && info.eventId) {
157
+ cardParts.push(theme.getRoleChalk("concurrent")(`同時${activeCount}件発生中`) + chalk_1.default.gray(` ${info.infoType}`));
158
+ }
159
+ else {
160
+ cardParts.push(chalk_1.default.gray(info.infoType));
161
+ }
162
+ if (info.forecastIntensity?.areas.length) {
163
+ const areas = info.forecastIntensity.areas;
164
+ const maxInt = areas.reduce((best, area) => (0, formatter_1.intensityToNumeric)(area.intensity) > (0, formatter_1.intensityToNumeric)(best) ? area.intensity : best, areas[0].intensity);
165
+ const ic = (0, formatter_1.intensityColor)(maxInt);
166
+ let intLabel;
167
+ if (diff?.previousMaxInt) {
168
+ intLabel = chalk_1.default.white("最大予測震度 ") + chalk_1.default.gray(diff.previousMaxInt) + chalk_1.default.white(" → ") + ic.bold(maxInt);
169
+ }
170
+ else {
171
+ intLabel = chalk_1.default.white("最大予測震度 ") + ic.bold(maxInt);
172
+ }
173
+ cardParts.push(intLabel);
174
+ // 最大予測長周期地震動階級
175
+ const maxLgInt = info.forecastIntensity.maxLgInt;
176
+ if (maxLgInt && (0, formatter_1.lgIntToNumeric)(maxLgInt) >= 1) {
177
+ const lc = (0, formatter_1.lgIntensityColor)(maxLgInt);
178
+ cardParts.push(chalk_1.default.white("長周期階級 ") + lc.bold(maxLgInt));
179
+ }
180
+ }
181
+ if (info.earthquake?.magnitude && !info.isAssumedHypocenter) {
182
+ cardParts.push((0, formatter_1.colorMagnitude)(info.earthquake.magnitude));
183
+ }
184
+ if (info.earthquake?.depth && !info.isAssumedHypocenter) {
185
+ cardParts.push(chalk_1.default.white("深さ ") + chalk_1.default.white(info.earthquake.depth));
186
+ }
187
+ buf.pushCard((0, formatter_1.frameLine)(level, cardParts.join(chalk_1.default.gray(" │ ")), width));
188
+ }
189
+ else {
190
+ // 取消時はinfoTypeのみ
191
+ if (!hasPreContent) {
192
+ buf.push((0, formatter_1.frameTop)(level, width));
193
+ }
194
+ if (activeCount >= 2 && info.eventId) {
195
+ buf.push((0, formatter_1.frameLine)(level, theme.getRoleChalk("concurrent")(`同時${activeCount}件発生中`) +
196
+ chalk_1.default.gray(` ${info.infoType}`), width));
197
+ }
198
+ else {
199
+ buf.push((0, formatter_1.frameLine)(level, chalk_1.default.gray(info.infoType), width));
200
+ }
201
+ }
202
+ // ヘッドライン
203
+ if (info.headline) {
204
+ buf.push((0, formatter_1.frameDivider)(level, width));
205
+ const headlineWrapped = (0, formatter_1.wrapFrameLines)(level, chalk_1.default.bold.white(info.headline), width);
206
+ for (let i = 0; i < headlineWrapped.length; i++) {
207
+ if (i === 0) {
208
+ buf.pushHeadline(headlineWrapped[i]);
209
+ }
210
+ else {
211
+ buf.push(headlineWrapped[i]);
212
+ }
213
+ }
214
+ }
215
+ // 震源詳細
216
+ if (info.earthquake) {
217
+ const eq = info.earthquake;
218
+ buf.push((0, formatter_1.frameDivider)(level, width));
219
+ if (info.isAssumedHypocenter) {
220
+ buf.push((0, formatter_1.frameLine)(level, theme.getRoleChalk("plumLabel")("仮定震源要素") + chalk_1.default.gray(" (震源未確定・PLUM法による推定)"), width));
221
+ }
222
+ if (info.isAssumedHypocenter) {
223
+ // 仮定震源要素: 震源・発生時刻・位置をグレーアウト
224
+ buf.push((0, formatter_1.frameLine)(level, chalk_1.default.gray("震源地: ") + chalk_1.default.gray(eq.hypocenterName), width));
225
+ if (eq.originTime) {
226
+ buf.push((0, formatter_1.frameLine)(level, chalk_1.default.gray("発生: ") + chalk_1.default.gray((0, formatter_1.formatTimestamp)(eq.originTime)), width));
227
+ }
228
+ if (eq.latitude && eq.longitude) {
229
+ buf.push((0, formatter_1.frameLine)(level, chalk_1.default.gray("位置: ") + chalk_1.default.gray(`${eq.latitude} ${eq.longitude}`), width));
230
+ }
231
+ }
232
+ else {
233
+ const hypoContent = diff?.hypocenterChange
234
+ ? chalk_1.default.white("震源地: ") + theme.getRoleChalk("hypocenter")(eq.hypocenterName) + theme.getRoleChalk("nextAdvisory")(" (変更)")
235
+ : chalk_1.default.white("震源地: ") + theme.getRoleChalk("hypocenter")(eq.hypocenterName);
236
+ buf.push((0, formatter_1.frameLine)(level, hypoContent, width));
237
+ if (eq.originTime) {
238
+ buf.push((0, formatter_1.frameLine)(level, chalk_1.default.white("発生: ") + chalk_1.default.white((0, formatter_1.formatTimestamp)(eq.originTime)), width));
239
+ }
240
+ if (eq.latitude && eq.longitude) {
241
+ buf.push((0, formatter_1.frameLine)(level, chalk_1.default.white("位置: ") + chalk_1.default.white(`${eq.latitude} ${eq.longitude}`), width));
242
+ }
243
+ }
244
+ if (eq.magnitude && !info.isAssumedHypocenter) {
245
+ let magLine;
246
+ if (diff?.previousMagnitude) {
247
+ magLine = chalk_1.default.white("規模: ") + chalk_1.default.gray(`M${diff.previousMagnitude}`) + chalk_1.default.white(" → ") + chalk_1.default.bold((0, formatter_1.colorMagnitude)(eq.magnitude));
248
+ }
249
+ else {
250
+ magLine = chalk_1.default.white("規模: ") + (0, formatter_1.colorMagnitude)(eq.magnitude);
251
+ }
252
+ buf.push((0, formatter_1.frameLine)(level, magLine, width));
253
+ }
254
+ if (eq.depth && !info.isAssumedHypocenter) {
255
+ let depthLine;
256
+ if (diff?.previousDepth) {
257
+ depthLine = chalk_1.default.white("深さ: ") + chalk_1.default.gray(diff.previousDepth) + chalk_1.default.white(" → ") + chalk_1.default.bold.white(eq.depth);
258
+ }
259
+ else {
260
+ depthLine = chalk_1.default.white("深さ: ") + chalk_1.default.white(eq.depth);
261
+ }
262
+ buf.push((0, formatter_1.frameLine)(level, depthLine, width));
263
+ }
264
+ }
265
+ if (isCancelled) {
266
+ buf.push((0, formatter_1.frameDivider)(level, width));
267
+ buf.push((0, formatter_1.frameLine)(level, theme.getRoleChalk("cancelText")("この地震についての緊急地震速報は取り消されました。"), width));
268
+ if (info.eventId) {
269
+ buf.push((0, formatter_1.frameDivider)(level, width));
270
+ buf.push((0, formatter_1.frameLine)(level, chalk_1.default.gray(`EventID: ${info.eventId}`), width));
271
+ }
272
+ (0, formatter_1.renderFooter)(level, info.type, info.reportDateTime, info.publishingOffice, width, buf);
273
+ buf.push((0, formatter_1.frameBottom)(level, width));
274
+ buf.pushEmpty();
275
+ (0, formatter_1.flushWithRecap)(buf, level, width);
276
+ return;
277
+ }
278
+ // 予測震度一覧
279
+ if (info.forecastIntensity && info.forecastIntensity.areas.length > 0) {
280
+ buf.push((0, formatter_1.frameDivider)(level, width));
281
+ const maxObs = (0, formatter_1.getMaxObservations)();
282
+ const allAreas = info.forecastIntensity.areas;
283
+ const displayAreas = maxObs != null ? allAreas.slice(0, maxObs) : allAreas;
284
+ const hiddenCount = allAreas.length - displayAreas.length;
285
+ for (const area of displayAreas) {
286
+ const color = (0, formatter_1.intensityColor)(area.intensity);
287
+ let areaText = chalk_1.default.white(area.name);
288
+ if (area.isPlum) {
289
+ areaText += theme.getRoleChalk("plumLabel")(" [PLUM]");
290
+ }
291
+ if (area.hasArrived) {
292
+ areaText += theme.getRoleChalk("arrivedLabel")(" [到達]");
293
+ }
294
+ if (area.lgIntensity && (0, formatter_1.lgIntToNumeric)(area.lgIntensity) >= 1) {
295
+ const lc = (0, formatter_1.lgIntensityColor)(area.lgIntensity);
296
+ areaText += lc(` [長周期${area.lgIntensity}]`);
297
+ }
298
+ for (const wl of (0, formatter_1.wrapFrameLines)(level, color(`震度${area.intensity}: `) + areaText, width)) {
299
+ buf.push(wl);
300
+ }
301
+ }
302
+ if (hiddenCount > 0) {
303
+ buf.push((0, formatter_1.frameLine)(level, chalk_1.default.gray(`... 他 ${hiddenCount} 地点`), width));
304
+ }
305
+ }
306
+ // 主要動到達と推測される地域
307
+ if (info.forecastIntensity) {
308
+ const arrivedAreas = info.forecastIntensity.areas.filter((a) => a.hasArrived);
309
+ if (arrivedAreas.length > 0) {
310
+ buf.push((0, formatter_1.frameDivider)(level, width));
311
+ buf.push((0, formatter_1.frameLine)(level, theme.getRoleChalk("arrivedLabel")("既に主要動到達と推測:"), width));
312
+ const names = arrivedAreas.map((a) => a.name).join("、");
313
+ for (const line of (0, formatter_1.wrapFrameLines)(level, theme.getRoleChalk("arrivedLabel")(names), width)) {
314
+ buf.push(line);
315
+ }
316
+ }
317
+ }
318
+ // 最終報
319
+ if (info.nextAdvisory) {
320
+ buf.push((0, formatter_1.frameDivider)(level, width));
321
+ for (const wl of (0, formatter_1.wrapFrameLines)(level, theme.getRoleChalk("nextAdvisory")(info.nextAdvisory), width)) {
322
+ buf.push(wl);
323
+ }
324
+ }
325
+ // EventID
326
+ if (info.eventId) {
327
+ buf.push((0, formatter_1.frameDivider)(level, width));
328
+ buf.push((0, formatter_1.frameLine)(level, chalk_1.default.gray(`EventID: ${info.eventId}`), width));
329
+ }
330
+ // フッター
331
+ (0, formatter_1.renderFooter)(level, info.type, info.reportDateTime, info.publishingOffice, width, buf);
332
+ buf.push((0, formatter_1.frameBottom)(level, width));
333
+ buf.pushEmpty();
334
+ (0, formatter_1.flushWithRecap)(buf, level, width);
335
+ }