@sayue_ltr/fleq 1.50.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/CHANGELOG.md +174 -0
  2. package/README.md +42 -6
  3. package/dist/config.js +37 -4
  4. package/dist/dmdata/rest-client.js +58 -3
  5. package/dist/dmdata/telegram-parser.js +115 -64
  6. package/dist/dmdata/ws-client.js +49 -18
  7. package/dist/engine/cli/cli-run.js +88 -3
  8. package/dist/engine/cli/cli.js +12 -0
  9. package/dist/engine/eew/eew-tracker.js +41 -15
  10. package/dist/engine/filter/compile-filter.js +21 -0
  11. package/dist/engine/filter/compiler.js +188 -0
  12. package/dist/engine/filter/errors.js +41 -0
  13. package/dist/engine/filter/field-registry.js +78 -0
  14. package/dist/engine/filter/index.js +15 -0
  15. package/dist/engine/filter/parser.js +137 -0
  16. package/dist/engine/filter/rank-maps.js +34 -0
  17. package/dist/engine/filter/tokenizer.js +121 -0
  18. package/dist/engine/filter/type-checker.js +104 -0
  19. package/dist/engine/filter/types.js +2 -0
  20. package/dist/engine/filter-template/pipeline-controller.js +73 -0
  21. package/dist/engine/filter-template/pipeline.js +16 -0
  22. package/dist/engine/messages/display-callbacks.js +7 -0
  23. package/dist/engine/messages/message-router.js +114 -182
  24. package/dist/engine/messages/summary-tracker.js +106 -0
  25. package/dist/engine/messages/telegram-stats.js +103 -0
  26. package/dist/engine/messages/volcano-route-handler.js +122 -0
  27. package/dist/engine/monitor/monitor.js +52 -4
  28. package/dist/engine/monitor/shutdown.js +1 -0
  29. package/dist/engine/notification/notifier.js +21 -4
  30. package/dist/engine/notification/sound-player.js +398 -36
  31. package/dist/engine/presentation/diff-store.js +158 -0
  32. package/dist/engine/presentation/diff-types.js +2 -0
  33. package/dist/engine/presentation/events/from-earthquake.js +53 -0
  34. package/dist/engine/presentation/events/from-eew.js +72 -0
  35. package/dist/engine/presentation/events/from-lg-observation.js +58 -0
  36. package/dist/engine/presentation/events/from-nankai-trough.js +39 -0
  37. package/dist/engine/presentation/events/from-raw.js +35 -0
  38. package/dist/engine/presentation/events/from-seismic-text.js +37 -0
  39. package/dist/engine/presentation/events/from-tsunami.js +51 -0
  40. package/dist/engine/presentation/events/from-volcano.js +88 -0
  41. package/dist/engine/presentation/events/to-presentation-event.js +32 -0
  42. package/dist/engine/presentation/level-helpers.js +118 -0
  43. package/dist/engine/presentation/processors/process-earthquake.js +36 -0
  44. package/dist/engine/presentation/processors/process-eew.js +105 -0
  45. package/dist/engine/presentation/processors/process-lg-observation.js +30 -0
  46. package/dist/engine/presentation/processors/process-message.js +53 -0
  47. package/dist/engine/presentation/processors/process-nankai-trough.js +30 -0
  48. package/dist/engine/presentation/processors/process-raw.js +22 -0
  49. package/dist/engine/presentation/processors/process-seismic-text.js +30 -0
  50. package/dist/engine/presentation/processors/process-tsunami.js +42 -0
  51. package/dist/engine/presentation/processors/process-volcano.js +41 -0
  52. package/dist/engine/presentation/types.js +2 -0
  53. package/dist/engine/startup/config-resolver.js +2 -0
  54. package/dist/engine/template/compile-template.js +18 -0
  55. package/dist/engine/template/compiler.js +105 -0
  56. package/dist/engine/template/field-accessor.js +31 -0
  57. package/dist/engine/template/filters.js +100 -0
  58. package/dist/engine/template/index.js +5 -0
  59. package/dist/engine/template/parser.js +185 -0
  60. package/dist/engine/template/tokenizer.js +96 -0
  61. package/dist/engine/template/types.js +2 -0
  62. package/dist/types.js +3 -2
  63. package/dist/ui/display-adapter.js +60 -0
  64. package/dist/ui/earthquake-formatter.js +22 -5
  65. package/dist/ui/eew-formatter.js +25 -10
  66. package/dist/ui/formatter.js +116 -32
  67. package/dist/ui/minimap/grid-layout.js +91 -0
  68. package/dist/ui/minimap/index.js +16 -0
  69. package/dist/ui/minimap/minimap-renderer.js +277 -0
  70. package/dist/ui/minimap/pref-mapping.js +82 -0
  71. package/dist/ui/minimap/types.js +2 -0
  72. package/dist/ui/night-overlay.js +56 -0
  73. package/dist/ui/repl-handlers/command-definitions.js +327 -0
  74. package/dist/ui/repl-handlers/index.js +11 -0
  75. package/dist/ui/repl-handlers/info-handlers.js +633 -0
  76. package/dist/ui/repl-handlers/operation-handlers.js +233 -0
  77. package/dist/ui/repl-handlers/settings-handlers.js +927 -0
  78. package/dist/ui/repl-handlers/types.js +10 -0
  79. package/dist/ui/repl.js +81 -1752
  80. package/dist/ui/statistics-formatter.js +258 -0
  81. package/dist/ui/status-line.js +80 -0
  82. package/dist/ui/summary/index.js +5 -0
  83. package/dist/ui/summary/summary-line.js +18 -0
  84. package/dist/ui/summary/summary-model.js +31 -0
  85. package/dist/ui/summary/token-builders.js +317 -0
  86. package/dist/ui/summary/types.js +2 -0
  87. package/dist/ui/summary/width-fit.js +41 -0
  88. package/dist/ui/summary-interval-formatter.js +72 -0
  89. package/dist/ui/test-samples.js +6 -0
  90. package/dist/ui/theme.js +43 -5
  91. package/dist/ui/tip-shuffler.js +81 -0
  92. package/dist/ui/volcano-formatter.js +15 -13
  93. package/dist/ui/waiting-tips-eew.js +63 -0
  94. package/dist/ui/waiting-tips-info-systems.js +81 -0
  95. package/dist/ui/waiting-tips-seismology.js +97 -0
  96. package/dist/ui/waiting-tips-tsunami.js +72 -0
  97. package/dist/ui/waiting-tips-weather.js +189 -0
  98. package/dist/ui/waiting-tips.js +420 -249
  99. package/package.json +1 -1
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PresentationDiffStore = void 0;
4
+ /** TTL のデフォルト値 (30分) */
5
+ const DEFAULT_TTL_MS = 30 * 60 * 1000;
6
+ /** プルーニング実行間隔 (apply 呼び出し回数) */
7
+ const PRUNE_INTERVAL = 50;
8
+ /**
9
+ * PresentationEvent の差分を検出・保持するストア。
10
+ *
11
+ * apply() は PresentationEvent を受け取り、同一 diffKey を持つ直前のイベントとの
12
+ * 差分を検出して diff プロパティを付与して返す。
13
+ *
14
+ * TTL ベースの自動クリーンアップにより、長時間稼働時のメモリ蓄積を防止する。
15
+ */
16
+ class PresentationDiffStore {
17
+ previous = new Map();
18
+ ttlMs;
19
+ applyCount = 0;
20
+ constructor(ttlMs) {
21
+ this.ttlMs = ttlMs ?? DEFAULT_TTL_MS;
22
+ }
23
+ /**
24
+ * イベントを受け取り、差分を検出する。
25
+ * - 初回 (同一 diffKey で初めて) → diff なし
26
+ * - 2回目以降 → diff あり (changed フラグ + summary + fields)
27
+ * - diffKey が解決できないドメイン → diff なし (対象外)
28
+ */
29
+ apply(event) {
30
+ this.applyCount++;
31
+ if (this.applyCount % PRUNE_INTERVAL === 0) {
32
+ this.prune();
33
+ }
34
+ const diffKey = this.resolveDiffKey(event);
35
+ if (diffKey == null)
36
+ return event;
37
+ const entry = this.previous.get(diffKey);
38
+ const diff = entry ? this.computeDiff(entry.event, event) : undefined;
39
+ this.previous.set(diffKey, { event, updatedAt: Date.now() });
40
+ return diff ? { ...event, diff } : event;
41
+ }
42
+ /** 指定した diffKey のエントリを削除する */
43
+ remove(diffKey) {
44
+ this.previous.delete(diffKey);
45
+ }
46
+ /** テスト用: ストアをクリアする */
47
+ clear() {
48
+ this.previous.clear();
49
+ }
50
+ /** TTL を超過した古いエントリを削除する */
51
+ prune() {
52
+ const now = Date.now();
53
+ for (const [key, entry] of this.previous) {
54
+ if (now - entry.updatedAt > this.ttlMs) {
55
+ this.previous.delete(key);
56
+ }
57
+ }
58
+ }
59
+ // ── diffKey 解決 ──
60
+ resolveDiffKey(event) {
61
+ switch (event.domain) {
62
+ case "eew":
63
+ return event.eventId ? `eew:${event.eventId}` : null;
64
+ case "tsunami":
65
+ return event.type === "VTSE41" ? "tsunami:vtse41" : null;
66
+ case "volcano":
67
+ return event.type === "VFVO50" && event.volcanoCode
68
+ ? `volcano:${event.volcanoCode}`
69
+ : null;
70
+ default:
71
+ return null;
72
+ }
73
+ }
74
+ // ── diff 算出 ──
75
+ computeDiff(prev, curr) {
76
+ const fields = [];
77
+ const summary = [];
78
+ switch (curr.domain) {
79
+ case "eew":
80
+ this.compareEew(prev, curr, fields, summary);
81
+ break;
82
+ case "tsunami":
83
+ this.compareTsunami(prev, curr, fields, summary);
84
+ break;
85
+ case "volcano":
86
+ this.compareVolcano(prev, curr, fields, summary);
87
+ break;
88
+ }
89
+ return {
90
+ changed: fields.length > 0,
91
+ summary,
92
+ fields,
93
+ };
94
+ }
95
+ compareEew(prev, curr, fields, summary) {
96
+ // magnitude
97
+ if (prev.magnitude !== curr.magnitude) {
98
+ fields.push({
99
+ key: "magnitude",
100
+ previous: prev.magnitude ?? null,
101
+ current: curr.magnitude ?? null,
102
+ significance: "major",
103
+ });
104
+ if (prev.magnitude != null && curr.magnitude != null) {
105
+ summary.push(`M${prev.magnitude}→${curr.magnitude}`);
106
+ }
107
+ }
108
+ // maxInt (forecastMaxInt for EEW)
109
+ const prevInt = prev.forecastMaxInt ?? prev.maxInt;
110
+ const currInt = curr.forecastMaxInt ?? curr.maxInt;
111
+ if (prevInt !== currInt) {
112
+ fields.push({
113
+ key: "maxInt",
114
+ previous: prevInt ?? null,
115
+ current: currInt ?? null,
116
+ significance: "major",
117
+ });
118
+ if (prevInt != null && currInt != null) {
119
+ summary.push(`${prevInt}→${currInt}`);
120
+ }
121
+ }
122
+ // hypocenterName
123
+ if (prev.hypocenterName !== curr.hypocenterName) {
124
+ fields.push({
125
+ key: "hypocenterName",
126
+ previous: prev.hypocenterName ?? null,
127
+ current: curr.hypocenterName ?? null,
128
+ significance: "minor",
129
+ });
130
+ summary.push("震源変更");
131
+ }
132
+ }
133
+ compareTsunami(prev, curr, fields, summary) {
134
+ if (prev.areaCount !== curr.areaCount) {
135
+ fields.push({
136
+ key: "areaCount",
137
+ previous: prev.areaCount,
138
+ current: curr.areaCount,
139
+ significance: "major",
140
+ });
141
+ summary.push(`${prev.areaCount}区域→${curr.areaCount}区域`);
142
+ }
143
+ }
144
+ compareVolcano(prev, curr, fields, summary) {
145
+ if (prev.alertLevel !== curr.alertLevel) {
146
+ fields.push({
147
+ key: "alertLevel",
148
+ previous: prev.alertLevel ?? null,
149
+ current: curr.alertLevel ?? null,
150
+ significance: "major",
151
+ });
152
+ if (prev.alertLevel != null && curr.alertLevel != null) {
153
+ summary.push(`Lv${prev.alertLevel}→${curr.alertLevel}`);
154
+ }
155
+ }
156
+ }
157
+ }
158
+ exports.PresentationDiffStore = PresentationDiffStore;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fromEarthquakeOutcome = fromEarthquakeOutcome;
4
+ const intensity_1 = require("../../../utils/intensity");
5
+ /** EarthquakeOutcome → PresentationEvent */
6
+ function fromEarthquakeOutcome(outcome) {
7
+ const xmlReport = outcome.msg.xmlReport;
8
+ const info = outcome.parsed;
9
+ const maxInt = info.intensity?.maxInt ?? null;
10
+ const maxIntRank = maxInt != null ? (0, intensity_1.intensityToRank)(maxInt) : null;
11
+ const areas = info.intensity?.areas ?? [];
12
+ const areaNames = areas.map((a) => a.name);
13
+ const areaItems = areas.map((a) => ({
14
+ name: a.name,
15
+ maxInt: a.intensity,
16
+ }));
17
+ return {
18
+ id: outcome.msg.id,
19
+ classification: outcome.msg.classification,
20
+ domain: outcome.domain,
21
+ type: outcome.headType,
22
+ infoType: xmlReport?.head.infoType ?? "不明",
23
+ title: xmlReport?.head.title ?? outcome.headType,
24
+ headline: xmlReport?.head.headline ?? null,
25
+ reportDateTime: xmlReport?.head.reportDateTime ?? outcome.msg.head.time,
26
+ publishingOffice: xmlReport?.control.publishingOffice ?? outcome.msg.head.author,
27
+ isTest: outcome.msg.head.test,
28
+ frameLevel: outcome.presentation.frameLevel,
29
+ soundLevel: outcome.presentation.soundLevel,
30
+ notifyCategory: outcome.presentation.notifyCategory,
31
+ isCancellation: info.infoType === "取消",
32
+ eventId: xmlReport?.head.eventId ?? null,
33
+ serial: xmlReport?.head.serial ?? null,
34
+ originTime: info.earthquake?.originTime ?? null,
35
+ hypocenterName: info.earthquake?.hypocenterName ?? null,
36
+ latitude: info.earthquake?.latitude ?? null,
37
+ longitude: info.earthquake?.longitude ?? null,
38
+ depth: info.earthquake?.depth ?? null,
39
+ magnitude: info.earthquake?.magnitude ?? null,
40
+ maxInt,
41
+ maxIntRank,
42
+ areaNames,
43
+ forecastAreaNames: [],
44
+ municipalityNames: [],
45
+ observationNames: [],
46
+ areaCount: areaNames.length,
47
+ forecastAreaCount: 0,
48
+ municipalityCount: 0,
49
+ observationCount: 0,
50
+ areaItems,
51
+ raw: outcome.parsed,
52
+ };
53
+ }
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fromEewOutcome = fromEewOutcome;
4
+ const intensity_1 = require("../../../utils/intensity");
5
+ /** EewOutcome → PresentationEvent */
6
+ function fromEewOutcome(outcome) {
7
+ const xmlReport = outcome.msg.xmlReport;
8
+ const info = outcome.parsed;
9
+ // 予測地域から最大予測震度を算出
10
+ const forecastAreas = info.forecastIntensity?.areas ?? [];
11
+ let forecastMaxInt = null;
12
+ let forecastMaxIntRank = null;
13
+ for (const area of forecastAreas) {
14
+ const rank = (0, intensity_1.intensityToRank)(area.intensity);
15
+ if (forecastMaxIntRank == null || rank > forecastMaxIntRank) {
16
+ forecastMaxIntRank = rank;
17
+ forecastMaxInt = area.intensity;
18
+ }
19
+ }
20
+ const areaNames = forecastAreas.map((a) => a.name);
21
+ const areaItems = forecastAreas.map((a) => ({
22
+ name: a.name,
23
+ kind: "forecast",
24
+ maxInt: a.intensity,
25
+ }));
26
+ return {
27
+ id: outcome.msg.id,
28
+ classification: outcome.msg.classification,
29
+ domain: outcome.domain,
30
+ type: outcome.headType,
31
+ infoType: xmlReport?.head.infoType ?? "不明",
32
+ title: xmlReport?.head.title ?? outcome.headType,
33
+ headline: xmlReport?.head.headline ?? null,
34
+ reportDateTime: xmlReport?.head.reportDateTime ?? outcome.msg.head.time,
35
+ publishingOffice: xmlReport?.control.publishingOffice ?? outcome.msg.head.author,
36
+ isTest: outcome.msg.head.test,
37
+ frameLevel: outcome.presentation.frameLevel,
38
+ soundLevel: outcome.presentation.soundLevel,
39
+ notifyCategory: outcome.presentation.notifyCategory,
40
+ isCancellation: info.infoType === "取消",
41
+ eventId: info.eventId ?? xmlReport?.head.eventId ?? null,
42
+ serial: info.serial ?? xmlReport?.head.serial ?? null,
43
+ isWarning: info.isWarning,
44
+ isFinal: info.nextAdvisory != null,
45
+ isAssumedHypocenter: info.isAssumedHypocenter,
46
+ hypocenterName: info.earthquake?.hypocenterName ?? null,
47
+ latitude: info.earthquake?.latitude ?? null,
48
+ longitude: info.earthquake?.longitude ?? null,
49
+ depth: info.earthquake?.depth ?? null,
50
+ magnitude: info.earthquake?.magnitude ?? null,
51
+ forecastMaxInt: forecastMaxInt,
52
+ forecastMaxIntRank: forecastMaxIntRank,
53
+ nextAdvisory: info.nextAdvisory ?? null,
54
+ areaNames,
55
+ forecastAreaNames: areaNames,
56
+ municipalityNames: [],
57
+ observationNames: [],
58
+ areaCount: areaNames.length,
59
+ forecastAreaCount: areaNames.length,
60
+ municipalityCount: 0,
61
+ observationCount: 0,
62
+ areaItems,
63
+ stateSnapshot: {
64
+ kind: "eew",
65
+ activeCount: outcome.state.activeCount,
66
+ colorIndex: outcome.state.colorIndex,
67
+ isCancelled: outcome.state.isCancelled,
68
+ diff: outcome.state.diff,
69
+ },
70
+ raw: outcome.parsed,
71
+ };
72
+ }
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fromLgObservationOutcome = fromLgObservationOutcome;
4
+ const intensity_1 = require("../../../utils/intensity");
5
+ /** LgObservationOutcome → PresentationEvent */
6
+ function fromLgObservationOutcome(outcome) {
7
+ const xmlReport = outcome.msg.xmlReport;
8
+ const info = outcome.parsed;
9
+ const maxLgInt = info.maxLgInt ?? null;
10
+ const maxLgIntRank = maxLgInt != null ? Number(maxLgInt) || null : null;
11
+ const observations = info.areas ?? [];
12
+ const observationNames = observations.map((o) => o.name);
13
+ const areaItems = observations.map((o) => ({
14
+ name: o.name,
15
+ maxInt: o.maxInt,
16
+ maxLgInt: o.maxLgInt,
17
+ }));
18
+ const maxInt = info.maxInt ?? null;
19
+ const maxIntRank = maxInt != null ? (0, intensity_1.intensityToRank)(maxInt) : null;
20
+ return {
21
+ id: outcome.msg.id,
22
+ classification: outcome.msg.classification,
23
+ domain: outcome.domain,
24
+ type: outcome.headType,
25
+ infoType: xmlReport?.head.infoType ?? "不明",
26
+ title: xmlReport?.head.title ?? outcome.headType,
27
+ headline: xmlReport?.head.headline ?? null,
28
+ reportDateTime: xmlReport?.head.reportDateTime ?? outcome.msg.head.time,
29
+ publishingOffice: xmlReport?.control.publishingOffice ?? outcome.msg.head.author,
30
+ isTest: outcome.msg.head.test,
31
+ frameLevel: outcome.presentation.frameLevel,
32
+ soundLevel: outcome.presentation.soundLevel,
33
+ notifyCategory: outcome.presentation.notifyCategory,
34
+ isCancellation: info.infoType === "取消",
35
+ eventId: xmlReport?.head.eventId ?? null,
36
+ serial: xmlReport?.head.serial ?? null,
37
+ originTime: info.earthquake?.originTime ?? null,
38
+ hypocenterName: info.earthquake?.hypocenterName ?? null,
39
+ latitude: info.earthquake?.latitude ?? null,
40
+ longitude: info.earthquake?.longitude ?? null,
41
+ depth: info.earthquake?.depth ?? null,
42
+ magnitude: info.earthquake?.magnitude ?? null,
43
+ maxInt,
44
+ maxIntRank,
45
+ maxLgInt,
46
+ maxLgIntRank,
47
+ areaNames: [],
48
+ forecastAreaNames: [],
49
+ municipalityNames: [],
50
+ observationNames,
51
+ areaCount: 0,
52
+ forecastAreaCount: 0,
53
+ municipalityCount: 0,
54
+ observationCount: observationNames.length,
55
+ areaItems,
56
+ raw: outcome.parsed,
57
+ };
58
+ }
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fromNankaiTroughOutcome = fromNankaiTroughOutcome;
4
+ /** NankaiTroughOutcome → PresentationEvent */
5
+ function fromNankaiTroughOutcome(outcome) {
6
+ const xmlReport = outcome.msg.xmlReport;
7
+ const info = outcome.parsed;
8
+ return {
9
+ id: outcome.msg.id,
10
+ classification: outcome.msg.classification,
11
+ domain: outcome.domain,
12
+ type: outcome.headType,
13
+ infoType: xmlReport?.head.infoType ?? "不明",
14
+ title: xmlReport?.head.title ?? outcome.headType,
15
+ headline: xmlReport?.head.headline ?? null,
16
+ reportDateTime: xmlReport?.head.reportDateTime ?? outcome.msg.head.time,
17
+ publishingOffice: xmlReport?.control.publishingOffice ?? outcome.msg.head.author,
18
+ isTest: outcome.msg.head.test,
19
+ frameLevel: outcome.presentation.frameLevel,
20
+ soundLevel: outcome.presentation.soundLevel,
21
+ notifyCategory: outcome.presentation.notifyCategory,
22
+ isCancellation: info.infoType === "取消",
23
+ eventId: xmlReport?.head.eventId ?? null,
24
+ serial: xmlReport?.head.serial ?? null,
25
+ infoSerialCode: info.infoSerial?.code ?? null,
26
+ bodyText: info.bodyText,
27
+ nextAdvisory: info.nextAdvisory ?? null,
28
+ areaNames: [],
29
+ forecastAreaNames: [],
30
+ municipalityNames: [],
31
+ observationNames: [],
32
+ areaCount: 0,
33
+ forecastAreaCount: 0,
34
+ municipalityCount: 0,
35
+ observationCount: 0,
36
+ areaItems: [],
37
+ raw: outcome.parsed,
38
+ };
39
+ }
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fromRawOutcome = fromRawOutcome;
4
+ /** RawOutcome → PresentationEvent (フォールバック用の最小変換) */
5
+ function fromRawOutcome(outcome) {
6
+ const xmlReport = outcome.msg.xmlReport;
7
+ return {
8
+ id: outcome.msg.id,
9
+ classification: outcome.msg.classification,
10
+ domain: outcome.domain,
11
+ type: outcome.headType,
12
+ infoType: xmlReport?.head.infoType ?? "不明",
13
+ title: xmlReport?.head.title ?? outcome.headType,
14
+ headline: xmlReport?.head.headline ?? null,
15
+ reportDateTime: xmlReport?.head.reportDateTime ?? outcome.msg.head.time,
16
+ publishingOffice: xmlReport?.control.publishingOffice ?? outcome.msg.head.author,
17
+ isTest: outcome.msg.head.test,
18
+ frameLevel: outcome.presentation.frameLevel,
19
+ soundLevel: outcome.presentation.soundLevel,
20
+ notifyCategory: outcome.presentation.notifyCategory,
21
+ isCancellation: false,
22
+ eventId: xmlReport?.head.eventId ?? null,
23
+ serial: xmlReport?.head.serial ?? null,
24
+ areaNames: [],
25
+ forecastAreaNames: [],
26
+ municipalityNames: [],
27
+ observationNames: [],
28
+ areaCount: 0,
29
+ forecastAreaCount: 0,
30
+ municipalityCount: 0,
31
+ observationCount: 0,
32
+ areaItems: [],
33
+ raw: null,
34
+ };
35
+ }
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fromSeismicTextOutcome = fromSeismicTextOutcome;
4
+ /** SeismicTextOutcome → PresentationEvent */
5
+ function fromSeismicTextOutcome(outcome) {
6
+ const xmlReport = outcome.msg.xmlReport;
7
+ const info = outcome.parsed;
8
+ return {
9
+ id: outcome.msg.id,
10
+ classification: outcome.msg.classification,
11
+ domain: outcome.domain,
12
+ type: outcome.headType,
13
+ infoType: xmlReport?.head.infoType ?? "不明",
14
+ title: xmlReport?.head.title ?? outcome.headType,
15
+ headline: xmlReport?.head.headline ?? null,
16
+ reportDateTime: xmlReport?.head.reportDateTime ?? outcome.msg.head.time,
17
+ publishingOffice: xmlReport?.control.publishingOffice ?? outcome.msg.head.author,
18
+ isTest: outcome.msg.head.test,
19
+ frameLevel: outcome.presentation.frameLevel,
20
+ soundLevel: outcome.presentation.soundLevel,
21
+ notifyCategory: outcome.presentation.notifyCategory,
22
+ isCancellation: info.infoType === "取消",
23
+ eventId: xmlReport?.head.eventId ?? null,
24
+ serial: xmlReport?.head.serial ?? null,
25
+ bodyText: info.bodyText,
26
+ areaNames: [],
27
+ forecastAreaNames: [],
28
+ municipalityNames: [],
29
+ observationNames: [],
30
+ areaCount: 0,
31
+ forecastAreaCount: 0,
32
+ municipalityCount: 0,
33
+ observationCount: 0,
34
+ areaItems: [],
35
+ raw: outcome.parsed,
36
+ };
37
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fromTsunamiOutcome = fromTsunamiOutcome;
4
+ /** TsunamiOutcome → PresentationEvent */
5
+ function fromTsunamiOutcome(outcome) {
6
+ const xmlReport = outcome.msg.xmlReport;
7
+ const info = outcome.parsed;
8
+ const forecastItems = info.forecast ?? [];
9
+ const forecastAreaNames = forecastItems.map((f) => f.areaName);
10
+ const tsunamiKinds = forecastItems.map((f) => f.kind);
11
+ const areaItems = forecastItems.map((f) => ({
12
+ name: f.areaName,
13
+ kind: f.kind,
14
+ }));
15
+ return {
16
+ id: outcome.msg.id,
17
+ classification: outcome.msg.classification,
18
+ domain: outcome.domain,
19
+ type: outcome.headType,
20
+ infoType: xmlReport?.head.infoType ?? "不明",
21
+ title: xmlReport?.head.title ?? outcome.headType,
22
+ headline: xmlReport?.head.headline ?? null,
23
+ reportDateTime: xmlReport?.head.reportDateTime ?? outcome.msg.head.time,
24
+ publishingOffice: xmlReport?.control.publishingOffice ?? outcome.msg.head.author,
25
+ isTest: outcome.msg.head.test,
26
+ frameLevel: outcome.presentation.frameLevel,
27
+ soundLevel: outcome.presentation.soundLevel,
28
+ notifyCategory: outcome.presentation.notifyCategory,
29
+ isCancellation: info.infoType === "取消",
30
+ eventId: xmlReport?.head.eventId ?? null,
31
+ serial: xmlReport?.head.serial ?? null,
32
+ warningComment: info.warningComment || null,
33
+ tsunamiKinds,
34
+ areaNames: [],
35
+ forecastAreaNames,
36
+ municipalityNames: [],
37
+ observationNames: [],
38
+ areaCount: 0,
39
+ forecastAreaCount: forecastAreaNames.length,
40
+ municipalityCount: 0,
41
+ observationCount: 0,
42
+ areaItems,
43
+ stateSnapshot: {
44
+ kind: "tsunami",
45
+ levelBefore: outcome.state.levelBefore,
46
+ levelAfter: outcome.state.levelAfter,
47
+ changed: outcome.state.changed,
48
+ },
49
+ raw: outcome.parsed,
50
+ };
51
+ }
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fromVolcanoOutcome = fromVolcanoOutcome;
4
+ /** VolcanoOutcome | VolcanoBatchOutcome → PresentationEvent */
5
+ function fromVolcanoOutcome(outcome) {
6
+ if ("isBatch" in outcome && outcome.isBatch) {
7
+ return fromVolcanoBatchOutcome(outcome);
8
+ }
9
+ return fromSingleVolcanoOutcome(outcome);
10
+ }
11
+ function fromSingleVolcanoOutcome(outcome) {
12
+ const xmlReport = outcome.msg.xmlReport;
13
+ const info = outcome.parsed;
14
+ const alertLevel = info.kind === "alert" ? info.alertLevel : null;
15
+ return {
16
+ id: outcome.msg.id,
17
+ classification: outcome.msg.classification,
18
+ domain: outcome.domain,
19
+ type: outcome.headType,
20
+ infoType: xmlReport?.head.infoType ?? "不明",
21
+ title: xmlReport?.head.title ?? outcome.headType,
22
+ headline: xmlReport?.head.headline ?? null,
23
+ reportDateTime: xmlReport?.head.reportDateTime ?? outcome.msg.head.time,
24
+ publishingOffice: xmlReport?.control.publishingOffice ?? outcome.msg.head.author,
25
+ isTest: outcome.msg.head.test,
26
+ frameLevel: outcome.presentation.frameLevel,
27
+ soundLevel: outcome.presentation.soundLevel,
28
+ notifyCategory: outcome.presentation.notifyCategory,
29
+ isCancellation: info.infoType === "取消",
30
+ isRenotification: outcome.state.isRenotification,
31
+ eventId: xmlReport?.head.eventId ?? null,
32
+ serial: xmlReport?.head.serial ?? null,
33
+ volcanoCode: info.volcanoCode,
34
+ volcanoName: info.volcanoName,
35
+ alertLevel,
36
+ areaNames: [],
37
+ forecastAreaNames: [],
38
+ municipalityNames: [],
39
+ observationNames: [],
40
+ areaCount: 0,
41
+ forecastAreaCount: 0,
42
+ municipalityCount: 0,
43
+ observationCount: 0,
44
+ areaItems: [],
45
+ stateSnapshot: {
46
+ kind: "volcano",
47
+ isRenotification: outcome.state.isRenotification,
48
+ },
49
+ raw: outcome.parsed,
50
+ };
51
+ }
52
+ function fromVolcanoBatchOutcome(outcome) {
53
+ const xmlReport = outcome.msg.xmlReport;
54
+ const firstItem = outcome.parsed[0];
55
+ const volcanoName = firstItem?.volcanoName ?? null;
56
+ const volcanoCode = firstItem?.volcanoCode ?? null;
57
+ return {
58
+ id: outcome.msg.id,
59
+ classification: outcome.msg.classification,
60
+ domain: outcome.domain,
61
+ type: outcome.headType,
62
+ subType: "ashfallBatch",
63
+ infoType: xmlReport?.head.infoType ?? "不明",
64
+ title: xmlReport?.head.title ?? outcome.headType,
65
+ headline: xmlReport?.head.headline ?? null,
66
+ reportDateTime: outcome.batchReportDateTime,
67
+ publishingOffice: xmlReport?.control.publishingOffice ?? outcome.msg.head.author,
68
+ isTest: outcome.batchIsTest,
69
+ frameLevel: outcome.presentation.frameLevel,
70
+ soundLevel: outcome.presentation.soundLevel,
71
+ notifyCategory: outcome.presentation.notifyCategory,
72
+ isCancellation: false,
73
+ eventId: xmlReport?.head.eventId ?? null,
74
+ serial: xmlReport?.head.serial ?? null,
75
+ volcanoCode,
76
+ volcanoName,
77
+ areaNames: [],
78
+ forecastAreaNames: [],
79
+ municipalityNames: [],
80
+ observationNames: [],
81
+ areaCount: 0,
82
+ forecastAreaCount: 0,
83
+ municipalityCount: 0,
84
+ observationCount: 0,
85
+ areaItems: [],
86
+ raw: outcome.parsed,
87
+ };
88
+ }
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toPresentationEvent = toPresentationEvent;
4
+ const from_eew_1 = require("./from-eew");
5
+ const from_earthquake_1 = require("./from-earthquake");
6
+ const from_seismic_text_1 = require("./from-seismic-text");
7
+ const from_lg_observation_1 = require("./from-lg-observation");
8
+ const from_tsunami_1 = require("./from-tsunami");
9
+ const from_volcano_1 = require("./from-volcano");
10
+ const from_nankai_trough_1 = require("./from-nankai-trough");
11
+ const from_raw_1 = require("./from-raw");
12
+ /** ProcessOutcome → PresentationEvent に変換する */
13
+ function toPresentationEvent(outcome) {
14
+ switch (outcome.domain) {
15
+ case "eew":
16
+ return (0, from_eew_1.fromEewOutcome)(outcome);
17
+ case "earthquake":
18
+ return (0, from_earthquake_1.fromEarthquakeOutcome)(outcome);
19
+ case "seismicText":
20
+ return (0, from_seismic_text_1.fromSeismicTextOutcome)(outcome);
21
+ case "lgObservation":
22
+ return (0, from_lg_observation_1.fromLgObservationOutcome)(outcome);
23
+ case "tsunami":
24
+ return (0, from_tsunami_1.fromTsunamiOutcome)(outcome);
25
+ case "volcano":
26
+ return (0, from_volcano_1.fromVolcanoOutcome)(outcome);
27
+ case "nankaiTrough":
28
+ return (0, from_nankai_trough_1.fromNankaiTroughOutcome)(outcome);
29
+ case "raw":
30
+ return (0, from_raw_1.fromRawOutcome)(outcome);
31
+ }
32
+ }