react-threat-map 0.1.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.
- package/DECISIONS.md +275 -0
- package/LICENSE +21 -0
- package/README.md +645 -0
- package/dist/chunk-43FECBAY.js +202 -0
- package/dist/chunk-PM2OVFS5.js +9 -0
- package/dist/chunk-S6KRDFNO.cjs +13 -0
- package/dist/chunk-Y7WYSA4G.cjs +208 -0
- package/dist/countries-F7ATTG3H.cjs +20 -0
- package/dist/countries-NSR2XH7C.js +11 -0
- package/dist/geo.cjs +69 -0
- package/dist/geo.d.cts +56 -0
- package/dist/geo.d.ts +56 -0
- package/dist/geo.js +47 -0
- package/dist/index.cjs +1351 -0
- package/dist/index.d.cts +301 -0
- package/dist/index.d.ts +301 -0
- package/dist/index.js +1321 -0
- package/dist/regions-neHSPgtu.d.cts +765 -0
- package/dist/regions-neHSPgtu.d.ts +765 -0
- package/dist/small-countries-6O4AI3HD.js +8 -0
- package/dist/small-countries-D4QUXHH3.cjs +14 -0
- package/dist/states-DZ3SOMAC.js +11 -0
- package/dist/states-H54VC3H5.cjs +20 -0
- package/package.json +91 -0
|
@@ -0,0 +1,765 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public data types for `react-threat-map`.
|
|
3
|
+
*
|
|
4
|
+
* Everything a consumer touches is declared here: the attack input shape, the
|
|
5
|
+
* region/location model, theme and configuration objects, and the render hooks.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* A raw geographic coordinate in degrees (WGS84).
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* const paris: LatLng = { lat: 48.8566, lng: 2.3522 };
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
interface LatLng {
|
|
18
|
+
/** Latitude in degrees, -90 (south pole) to 90 (north pole). */
|
|
19
|
+
readonly lat: number;
|
|
20
|
+
/** Longitude in degrees, -180 (west) to 180 (east). */
|
|
21
|
+
readonly lng: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A string identifier for a region the library can resolve to a coordinate.
|
|
25
|
+
*
|
|
26
|
+
* Accepted forms, matched case-insensitively:
|
|
27
|
+
*
|
|
28
|
+
* - ISO 3166-1 alpha-2 country code — `"FR"`, `"US"`, `"CN"`
|
|
29
|
+
* - ISO 3166-1 alpha-3 country code — `"FRA"`, `"USA"`, `"CHN"`
|
|
30
|
+
* - ISO 3166-2 US state code — `"US-CA"`, `"US-TX"`
|
|
31
|
+
* - Bare USPS state code — `"CA"`, `"TX"` (see the ambiguity note below)
|
|
32
|
+
*
|
|
33
|
+
* Note on bare two-letter codes: a handful collide between country and US state
|
|
34
|
+
* codes (`"CA"` is both Canada and California; also `"AL"`, `"CO"`, `"DE"`,
|
|
35
|
+
* `"GA"`, `"IN"`, `"LA"`, `"MD"`, `"MO"`, `"MS"`, `"MT"`, `"NE"`, `"PA"`, `"SC"`,
|
|
36
|
+
* `"SD"`, `"VA"`). Bare codes always resolve to the **country** — `"CA"` is
|
|
37
|
+
* Canada. Use the unambiguous `"US-CA"` form for states. Resolution never
|
|
38
|
+
* guesses; an unresolvable identifier is reported through `onError` rather than
|
|
39
|
+
* silently dropped.
|
|
40
|
+
*
|
|
41
|
+
* The type is `string` rather than a literal union on purpose: a closed union of
|
|
42
|
+
* ~300 codes produces unreadable IDE errors and breaks consumers whose data is
|
|
43
|
+
* typed as `string` from an API. Validation happens at resolution time, where a
|
|
44
|
+
* useful error message is possible.
|
|
45
|
+
*/
|
|
46
|
+
type RegionCode = string;
|
|
47
|
+
/**
|
|
48
|
+
* Where an attack starts or ends.
|
|
49
|
+
*
|
|
50
|
+
* Three interchangeable forms, so you can pass whatever your data already has:
|
|
51
|
+
*
|
|
52
|
+
* 1. A {@link RegionCode} string — `"FR"`, `"US-CA"`. Resolved to that region's
|
|
53
|
+
* anchor coordinate. Cheapest option: no geometry needed, and aggregation
|
|
54
|
+
* knows the region without a reverse lookup.
|
|
55
|
+
* 2. A {@link LatLng} — exact coordinates. Aggregation reverse-resolves the
|
|
56
|
+
* region via point-in-polygon once the geo data has loaded.
|
|
57
|
+
* 3. A {@link LatLng} **with** a `region` — exact coordinates *and* an explicit
|
|
58
|
+
* aggregation key. Best of both: pixel-accurate placement, zero-cost grouping.
|
|
59
|
+
* Use this when your feed already carries geo-IP region data.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* const a: AttackLocation = 'US-CA';
|
|
64
|
+
* const b: AttackLocation = { lat: 34.05, lng: -118.24 };
|
|
65
|
+
* const c: AttackLocation = { lat: 34.05, lng: -118.24, region: 'US-CA' };
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
type AttackLocation = RegionCode | LatLng | (LatLng & {
|
|
69
|
+
readonly region?: RegionCode;
|
|
70
|
+
});
|
|
71
|
+
/**
|
|
72
|
+
* How specific a resolved region is.
|
|
73
|
+
*
|
|
74
|
+
* - `'country'` — resolved to a country (e.g. France).
|
|
75
|
+
* - `'state'` — resolved to a US state (e.g. California).
|
|
76
|
+
* - `'unknown'` — coordinates that fall outside all known boundaries (ocean,
|
|
77
|
+
* Antarctica, disputed areas), or a region code that could not be resolved.
|
|
78
|
+
*/
|
|
79
|
+
type RegionKind = 'country' | 'state' | 'unknown';
|
|
80
|
+
/**
|
|
81
|
+
* A region resolved from an {@link AttackLocation}, as produced by the geo layer
|
|
82
|
+
* and handed to aggregation key functions and render hooks.
|
|
83
|
+
*/
|
|
84
|
+
interface ResolvedRegion {
|
|
85
|
+
/**
|
|
86
|
+
* Canonical, stable identifier. Countries use ISO alpha-2 (`"FR"`); US states
|
|
87
|
+
* use ISO 3166-2 (`"US-CA"`). Unknown regions use `"??"`.
|
|
88
|
+
*
|
|
89
|
+
* This — not the display name — is what aggregation groups on.
|
|
90
|
+
*/
|
|
91
|
+
readonly id: string;
|
|
92
|
+
/** Human-readable name, e.g. `"France"` or `"California"`. */
|
|
93
|
+
readonly name: string;
|
|
94
|
+
/** Granularity of this resolution. */
|
|
95
|
+
readonly kind: RegionKind;
|
|
96
|
+
/** ISO alpha-2 of the containing country. For `"US-CA"` this is `"US"`. */
|
|
97
|
+
readonly countryCode: string;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Severity of an attack. Drives the threat's color via {@link ThreatMapTheme.severityColors}
|
|
101
|
+
* and its baseline visual weight.
|
|
102
|
+
*
|
|
103
|
+
* Custom severity strings are permitted — supply a matching entry in
|
|
104
|
+
* `theme.severityColors` and it will be used. Unrecognized values fall back to
|
|
105
|
+
* `theme.severityColors.medium`.
|
|
106
|
+
*/
|
|
107
|
+
type Severity = 'low' | 'medium' | 'high' | 'critical' | (string & {});
|
|
108
|
+
/**
|
|
109
|
+
* A single cyberattack: the library's input unit.
|
|
110
|
+
*
|
|
111
|
+
* Only `from` and `to` are required. Everything else is metadata that
|
|
112
|
+
* influences styling, grouping, or your own render hooks.
|
|
113
|
+
*
|
|
114
|
+
* @example Minimal
|
|
115
|
+
* ```ts
|
|
116
|
+
* const attacks: Attack[] = [{ from: 'CN', to: 'US-CA' }];
|
|
117
|
+
* ```
|
|
118
|
+
*
|
|
119
|
+
* @example Realistic feed row
|
|
120
|
+
* ```ts
|
|
121
|
+
* const attack: Attack = {
|
|
122
|
+
* id: 'evt-84321',
|
|
123
|
+
* from: { lat: 39.9, lng: 116.4, region: 'CN' },
|
|
124
|
+
* to: 'US-CA',
|
|
125
|
+
* timestamp: Date.now(),
|
|
126
|
+
* type: 'ssh-bruteforce',
|
|
127
|
+
* severity: 'high',
|
|
128
|
+
* meta: { targetPort: 22, attempts: 1_204 },
|
|
129
|
+
* };
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
interface Attack<TMeta = unknown> {
|
|
133
|
+
/**
|
|
134
|
+
* Stable unique identifier.
|
|
135
|
+
*
|
|
136
|
+
* Strongly recommended for streaming feeds: it is how the renderer keeps an
|
|
137
|
+
* in-flight animation attached to the right attack across re-renders. Without
|
|
138
|
+
* one, a fallback key is derived from `from`/`to`/`timestamp`, and attacks
|
|
139
|
+
* that collide on all three are treated as the same threat.
|
|
140
|
+
*/
|
|
141
|
+
readonly id?: string;
|
|
142
|
+
/** Where the attack originates. */
|
|
143
|
+
readonly from: AttackLocation;
|
|
144
|
+
/** Where the attack is directed. */
|
|
145
|
+
readonly to: AttackLocation;
|
|
146
|
+
/** Epoch milliseconds. Used for time-window filtering and as a fallback key input. */
|
|
147
|
+
readonly timestamp?: number;
|
|
148
|
+
/** Free-form classification, e.g. `"ddos"`, `"phishing"`. Available to hooks; not interpreted by the library. */
|
|
149
|
+
readonly type?: string;
|
|
150
|
+
/** Severity band. Defaults to `'medium'` when omitted. */
|
|
151
|
+
readonly severity?: Severity;
|
|
152
|
+
/**
|
|
153
|
+
* Relative importance, default `1`. Aggregation sums weights rather than
|
|
154
|
+
* counting rows, so one row representing 500 blocked packets can carry
|
|
155
|
+
* `weight: 500` and size the line accordingly.
|
|
156
|
+
*/
|
|
157
|
+
readonly weight?: number;
|
|
158
|
+
/** Your own payload. Passed through untouched to hooks and event handlers. */
|
|
159
|
+
readonly meta?: TMeta;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* A renderable line, produced by the aggregation stage from one or more
|
|
163
|
+
* {@link Attack}s. This is what actually gets drawn, and what render hooks and
|
|
164
|
+
* event handlers receive.
|
|
165
|
+
*
|
|
166
|
+
* When aggregation is disabled, exactly one threat is produced per attack, with
|
|
167
|
+
* `count === 1` and `attacks.length === 1`.
|
|
168
|
+
*/
|
|
169
|
+
interface Threat<TMeta = unknown> {
|
|
170
|
+
/** Stable identity across frames — the aggregation group key, or the attack id when ungrouped. */
|
|
171
|
+
readonly id: string;
|
|
172
|
+
/** Resolved origin coordinate, in degrees. */
|
|
173
|
+
readonly from: LatLng;
|
|
174
|
+
/** Resolved destination coordinate, in degrees. */
|
|
175
|
+
readonly to: LatLng;
|
|
176
|
+
/** Origin region. `kind: 'unknown'` if it could not be resolved. */
|
|
177
|
+
readonly fromRegion: ResolvedRegion;
|
|
178
|
+
/** Destination region. */
|
|
179
|
+
readonly toRegion: ResolvedRegion;
|
|
180
|
+
/** Number of underlying attacks. `1` when unaggregated. */
|
|
181
|
+
readonly count: number;
|
|
182
|
+
/** Sum of the underlying attacks' `weight` values (each defaulting to `1`). */
|
|
183
|
+
readonly totalWeight: number;
|
|
184
|
+
/** Effective severity. By default the **max** severity across members — see {@link AggregationConfig.severity}. */
|
|
185
|
+
readonly severity: Severity;
|
|
186
|
+
/**
|
|
187
|
+
* Visual weight multiplier derived from `count` via {@link AggregationConfig.scale}.
|
|
188
|
+
* `1` means baseline thickness; `2` means twice as heavy. Applied to line
|
|
189
|
+
* width, glow radius, and head size.
|
|
190
|
+
*/
|
|
191
|
+
readonly intensity: number;
|
|
192
|
+
/** The attacks that were folded into this threat. Always at least one. */
|
|
193
|
+
readonly attacks: readonly Attack<TMeta>[];
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* How finely origins are grouped.
|
|
197
|
+
*
|
|
198
|
+
* - `'auto'` *(default)* — US origins group by **state**, everything else by
|
|
199
|
+
* **country**. This is what makes California and Texas distinct aggregates
|
|
200
|
+
* while keeping the rest of the world at country level.
|
|
201
|
+
* - `'state'` — always prefer state granularity where known (currently US only);
|
|
202
|
+
* elsewhere behaves like `'country'`.
|
|
203
|
+
* - `'country'` — always country level. California and Texas both become `"US"`.
|
|
204
|
+
*/
|
|
205
|
+
type AggregationGranularity = 'auto' | 'state' | 'country';
|
|
206
|
+
/**
|
|
207
|
+
* What constitutes "the same threat".
|
|
208
|
+
*
|
|
209
|
+
* - `'origin-destination'` *(default)* — one line per origin→destination region
|
|
210
|
+
* pair. France→US and France→Japan stay separate, because they are visually
|
|
211
|
+
* distinct lines and collapsing them has no meaningful endpoint.
|
|
212
|
+
* - `'origin'` — one line per origin region, regardless of destination. The
|
|
213
|
+
* destination becomes the origin's most frequent target region. Use when you
|
|
214
|
+
* want strictly one line per attacking region.
|
|
215
|
+
*/
|
|
216
|
+
type AggregationGroupBy = 'origin-destination' | 'origin';
|
|
217
|
+
/**
|
|
218
|
+
* Maps an aggregate's attack count to a visual weight multiplier.
|
|
219
|
+
*
|
|
220
|
+
* @param count - Number of attacks in the group (>= 1).
|
|
221
|
+
* @param totalWeight - Sum of member `weight` values.
|
|
222
|
+
* @returns Multiplier applied to line width/glow/head size. `1` is baseline.
|
|
223
|
+
*/
|
|
224
|
+
type IntensityScale = (count: number, totalWeight: number) => number;
|
|
225
|
+
/**
|
|
226
|
+
* Derives a grouping key for an attack. Attacks yielding the same key merge into
|
|
227
|
+
* one threat.
|
|
228
|
+
*
|
|
229
|
+
* @param attack - The original attack.
|
|
230
|
+
* @param from - Its resolved origin region.
|
|
231
|
+
* @param to - Its resolved destination region.
|
|
232
|
+
* @returns A group key, or `null` to exclude this attack from aggregation and
|
|
233
|
+
* render it on its own.
|
|
234
|
+
*
|
|
235
|
+
* @example Group by origin country and attack type together
|
|
236
|
+
* ```ts
|
|
237
|
+
* const key: AggregationKeyFn = (attack, from) => `${from.id}:${attack.type ?? 'unknown'}`;
|
|
238
|
+
* ```
|
|
239
|
+
*/
|
|
240
|
+
type AggregationKeyFn<TMeta = unknown> = (attack: Attack<TMeta>, from: ResolvedRegion, to: ResolvedRegion) => string | null;
|
|
241
|
+
/**
|
|
242
|
+
* Picks the severity for an aggregate from its members' severities.
|
|
243
|
+
*
|
|
244
|
+
* @param severities - Every member's severity, in input order. Never empty.
|
|
245
|
+
* @returns The severity the aggregated threat should render as.
|
|
246
|
+
*/
|
|
247
|
+
type AggregationSeverityFn = (severities: readonly Severity[]) => Severity;
|
|
248
|
+
/**
|
|
249
|
+
* Controls how attacks sharing an origin collapse into single, heavier threats.
|
|
250
|
+
*
|
|
251
|
+
* Pass `aggregation={false}` on {@link ThreatMapProps} to disable entirely and
|
|
252
|
+
* render one line per attack.
|
|
253
|
+
*
|
|
254
|
+
* @example Group at country level only, and require 3 attacks before merging
|
|
255
|
+
* ```tsx
|
|
256
|
+
* <ThreatMap
|
|
257
|
+
* attacks={attacks}
|
|
258
|
+
* aggregation={{ granularity: 'country', minCount: 3 }}
|
|
259
|
+
* />
|
|
260
|
+
* ```
|
|
261
|
+
*/
|
|
262
|
+
interface AggregationConfig<TMeta = unknown> {
|
|
263
|
+
/** Master switch. Default `true`. Equivalent to passing `aggregation={false}`. */
|
|
264
|
+
readonly enabled?: boolean;
|
|
265
|
+
/** Origin granularity. Default `'auto'` (US → state, elsewhere → country). */
|
|
266
|
+
readonly granularity?: AggregationGranularity;
|
|
267
|
+
/** What counts as the same threat. Default `'origin-destination'`. */
|
|
268
|
+
readonly groupBy?: AggregationGroupBy;
|
|
269
|
+
/**
|
|
270
|
+
* Full override of the grouping key. When provided, `granularity` and
|
|
271
|
+
* `groupBy` are ignored. Returning `null` renders that attack individually.
|
|
272
|
+
*/
|
|
273
|
+
readonly key?: AggregationKeyFn<TMeta>;
|
|
274
|
+
/**
|
|
275
|
+
* Minimum group size to merge. Groups smaller than this are emitted as
|
|
276
|
+
* individual threats instead. Default `2` — a "group" of one is just an attack.
|
|
277
|
+
*/
|
|
278
|
+
readonly minCount?: number;
|
|
279
|
+
/**
|
|
280
|
+
* Cap on rendered threats, keeping the heaviest groups by `totalWeight`.
|
|
281
|
+
* Unlimited by default. A backstop for feeds that can spike unboundedly.
|
|
282
|
+
*/
|
|
283
|
+
readonly maxGroups?: number;
|
|
284
|
+
/**
|
|
285
|
+
* count → visual weight multiplier. Default is a logarithmic ramp
|
|
286
|
+
* (`1 + log2(count) * 0.5`), clamped to `[1, 6]`: it keeps a 500-attack group
|
|
287
|
+
* visibly heavier than a 5-attack one without rendering a line 500× thick.
|
|
288
|
+
*/
|
|
289
|
+
readonly scale?: IntensityScale;
|
|
290
|
+
/** How an aggregate picks its severity. Default: the **max** severity among members. */
|
|
291
|
+
readonly severity?: AggregationSeverityFn;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Any CSS color string the Canvas 2D context accepts — `"#0af"`,
|
|
295
|
+
* `"rgb(0 170 255)"`, `"hsl(200 100% 50% / 0.5)"`, `"tomato"`.
|
|
296
|
+
*/
|
|
297
|
+
type Color = string;
|
|
298
|
+
/**
|
|
299
|
+
* Colors for the map and the threats drawn over it.
|
|
300
|
+
*
|
|
301
|
+
* Every field is optional in {@link ThreatMapProps.theme}: what you pass is
|
|
302
|
+
* merged over {@link defaultTheme}, so you can restyle one color without
|
|
303
|
+
* restating the rest.
|
|
304
|
+
*
|
|
305
|
+
* @example Light theme
|
|
306
|
+
* ```tsx
|
|
307
|
+
* <ThreatMap attacks={attacks} theme={{ ocean: '#eef2f6', land: '#d6dee8', border: '#fff' }} />
|
|
308
|
+
* ```
|
|
309
|
+
*/
|
|
310
|
+
interface ThreatMapTheme {
|
|
311
|
+
/** Background behind the landmasses. */
|
|
312
|
+
readonly ocean: Color;
|
|
313
|
+
/** Country/state fill. */
|
|
314
|
+
readonly land: Color;
|
|
315
|
+
/** Country border stroke. */
|
|
316
|
+
readonly border: Color;
|
|
317
|
+
/** Country border width in CSS pixels. */
|
|
318
|
+
readonly borderWidth: number;
|
|
319
|
+
/** US state border stroke, when `regions.showStates` is on. */
|
|
320
|
+
readonly stateBorder: Color;
|
|
321
|
+
/** US state border width in CSS pixels. */
|
|
322
|
+
readonly stateBorderWidth: number;
|
|
323
|
+
/**
|
|
324
|
+
* Threat line color per severity. Extra keys are allowed for custom severity
|
|
325
|
+
* strings; a severity with no entry falls back to `medium`.
|
|
326
|
+
*/
|
|
327
|
+
readonly severityColors: Readonly<Record<string, Color>>;
|
|
328
|
+
/** Color of the dot travelling along the path. Defaults to the threat's severity color when `null`. */
|
|
329
|
+
readonly headColor: Color | null;
|
|
330
|
+
/** Origin marker color. Applies when `line.showOrigin` is on. */
|
|
331
|
+
readonly originColor: Color;
|
|
332
|
+
/** Impact ripple color at the destination. Applies when `line.showImpact` is on. */
|
|
333
|
+
readonly impactColor: Color;
|
|
334
|
+
}
|
|
335
|
+
/** Geometry and styling of the threat arcs. */
|
|
336
|
+
interface LineStyleConfig {
|
|
337
|
+
/**
|
|
338
|
+
* Arc height as a fraction of the chord length. `0` draws a straight geodesic;
|
|
339
|
+
* `0.3` bows noticeably. Default `0.22`. Negative values arc the other way.
|
|
340
|
+
*/
|
|
341
|
+
readonly curvature: number;
|
|
342
|
+
/** Baseline stroke width in CSS pixels, before `intensity` scaling. Default `1.2`. */
|
|
343
|
+
readonly width: number;
|
|
344
|
+
/** Opacity of the full arc that sits behind the animated head, `0`–`1`. Default `0.28`. */
|
|
345
|
+
readonly trackOpacity: number;
|
|
346
|
+
/** Opacity of the lit trail behind the head, `0`–`1`. Default `0.95`. */
|
|
347
|
+
readonly trailOpacity: number;
|
|
348
|
+
/** Trail length as a fraction of the path, `0`–`1`. Default `0.18`. */
|
|
349
|
+
readonly trailLength: number;
|
|
350
|
+
/** Glow strength, `0` (off) to `1`. Rendered as a cheap wide/narrow double-stroke. Default `0.5`. */
|
|
351
|
+
readonly glow: number;
|
|
352
|
+
/** Radius of the travelling head dot in CSS pixels, before `intensity` scaling. Default `2`. */
|
|
353
|
+
readonly headRadius: number;
|
|
354
|
+
/** Draw a static marker at each origin. Default `true`. */
|
|
355
|
+
readonly showOrigin: boolean;
|
|
356
|
+
/** Draw an expanding ripple where a head lands. Default `true`. */
|
|
357
|
+
readonly showImpact: boolean;
|
|
358
|
+
/**
|
|
359
|
+
* Number of straight segments each arc is flattened into. Higher is smoother
|
|
360
|
+
* and costlier to precompute (not to draw). Default `48`.
|
|
361
|
+
*/
|
|
362
|
+
readonly segments: number;
|
|
363
|
+
}
|
|
364
|
+
/** Named easing curves for the head's travel along the path. */
|
|
365
|
+
type EasingName = 'linear' | 'easeInQuad' | 'easeOutQuad' | 'easeInOutQuad' | 'easeInOutCubic';
|
|
366
|
+
/** Controls the animation loop. */
|
|
367
|
+
interface AnimationConfig {
|
|
368
|
+
/**
|
|
369
|
+
* Master switch. Default `true`. When `false` no `requestAnimationFrame` loop
|
|
370
|
+
* runs at all — arcs render statically and the component costs nothing per
|
|
371
|
+
* frame. Also respects `prefers-reduced-motion` unless
|
|
372
|
+
* {@link AnimationConfig.respectReducedMotion} is `false`.
|
|
373
|
+
*/
|
|
374
|
+
readonly enabled: boolean;
|
|
375
|
+
/** Full path traversals per second. Default `0.5` (one trip every 2s). */
|
|
376
|
+
readonly speed: number;
|
|
377
|
+
/** Easing for head position. Name or your own `(t: 0..1) => 0..1`. Default `'easeInOutQuad'`. */
|
|
378
|
+
readonly easing: EasingName | ((t: number) => number);
|
|
379
|
+
/**
|
|
380
|
+
* Randomized phase offset spread, `0`–`1`. At `0` every threat launches in
|
|
381
|
+
* lockstep; at `1` phases are fully scattered. Default `1`.
|
|
382
|
+
*/
|
|
383
|
+
readonly stagger: number;
|
|
384
|
+
/** Restart on completion. Default `true`. When `false` each threat animates once and holds. */
|
|
385
|
+
readonly loop: boolean;
|
|
386
|
+
/** Fade-in duration in ms for newly appearing threats. Default `400`. */
|
|
387
|
+
readonly fadeIn: number;
|
|
388
|
+
/** Fade-out duration in ms when a threat leaves `attacks`. Default `600`. */
|
|
389
|
+
readonly fadeOut: number;
|
|
390
|
+
/** Honor the `prefers-reduced-motion` media query. Default `true`. */
|
|
391
|
+
readonly respectReducedMotion: boolean;
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Map projection.
|
|
395
|
+
*
|
|
396
|
+
* - `'naturalEarth1'` *(default)* — compromise projection; the usual choice for
|
|
397
|
+
* world maps. Balanced distortion, pleasant shape.
|
|
398
|
+
* - `'equirectangular'` — plate carrée. Lat/lng map linearly to x/y.
|
|
399
|
+
* - `'mercator'` — familiar from web maps; badly inflates high latitudes.
|
|
400
|
+
* - `'orthographic'` — globe view. Half the world is not visible.
|
|
401
|
+
*
|
|
402
|
+
* You may also pass any [d3-geo](https://github.com/d3/d3-geo) projection
|
|
403
|
+
* instance for full control; the library will fit it to the viewport.
|
|
404
|
+
*/
|
|
405
|
+
type ProjectionName = 'naturalEarth1' | 'equirectangular' | 'mercator' | 'orthographic';
|
|
406
|
+
/** A projection name, or a d3-geo projection object. */
|
|
407
|
+
type ProjectionSpec = ProjectionName | GeoProjectionLike;
|
|
408
|
+
/**
|
|
409
|
+
* The slice of d3-geo's `GeoProjection` this library depends on. Structural, so
|
|
410
|
+
* any d3-geo projection satisfies it without importing d3's types.
|
|
411
|
+
*/
|
|
412
|
+
interface GeoProjectionLike {
|
|
413
|
+
/** Project `[lng, lat]` degrees to `[x, y]` pixels, or `null` if unprojectable. */
|
|
414
|
+
(point: [number, number]): [number, number] | null;
|
|
415
|
+
/** Inverse-project pixels back to `[lng, lat]`. Optional — not all projections have one. */
|
|
416
|
+
invert?: (point: [number, number]) => [number, number] | null;
|
|
417
|
+
/** Scale the projection to fit `extent` around `object`. */
|
|
418
|
+
fitExtent?: (extent: [[number, number], [number, number]], object: unknown) => GeoProjectionLike;
|
|
419
|
+
/** Get/set the projection scale. */
|
|
420
|
+
scale?: {
|
|
421
|
+
(): number;
|
|
422
|
+
(scale: number): GeoProjectionLike;
|
|
423
|
+
};
|
|
424
|
+
/** Get/set the projection translation. */
|
|
425
|
+
translate?: {
|
|
426
|
+
(): [number, number];
|
|
427
|
+
(translate: [number, number]): GeoProjectionLike;
|
|
428
|
+
};
|
|
429
|
+
/** Get/set the projection rotation. */
|
|
430
|
+
rotate?: {
|
|
431
|
+
(): number[];
|
|
432
|
+
(angles: number[]): GeoProjectionLike;
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
/** Which boundaries to draw. */
|
|
436
|
+
interface RegionsConfig {
|
|
437
|
+
/** Draw country boundaries. Default `true`. */
|
|
438
|
+
readonly showCountries: boolean;
|
|
439
|
+
/**
|
|
440
|
+
* Draw US state boundaries. Default `false` — it costs a separate ~40 kB
|
|
441
|
+
* lazy chunk. Turn on when US-state-level origins matter visually.
|
|
442
|
+
*
|
|
443
|
+
* Independent of aggregation: `granularity: 'auto'` groups by state whether or
|
|
444
|
+
* not state borders are drawn.
|
|
445
|
+
*/
|
|
446
|
+
readonly showStates: boolean;
|
|
447
|
+
/** Draw the graticule (lat/lng grid). Default `false`. */
|
|
448
|
+
readonly showGraticule: boolean;
|
|
449
|
+
/** Graticule stroke color. Default a low-alpha white. */
|
|
450
|
+
readonly graticuleColor: Color;
|
|
451
|
+
/** Draw the sphere outline around the projected globe. Default `true`. */
|
|
452
|
+
readonly showSphere: boolean;
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Everything a custom threat renderer needs, handed to it per threat per frame.
|
|
456
|
+
*/
|
|
457
|
+
interface ThreatRenderContext<TMeta = unknown> {
|
|
458
|
+
/** The threat being drawn, including its `count` and `intensity`. */
|
|
459
|
+
readonly threat: Threat<TMeta>;
|
|
460
|
+
/**
|
|
461
|
+
* The precomputed arc in screen pixels, flattened to `line.segments + 1`
|
|
462
|
+
* points as a flat `[x0, y0, x1, y1, ...]` array. Already projected, arced,
|
|
463
|
+
* and split at the antimeridian.
|
|
464
|
+
*/
|
|
465
|
+
readonly points: Float32Array;
|
|
466
|
+
/** Animation progress of the head along the path, `0`–`1`, easing already applied. */
|
|
467
|
+
readonly progress: number;
|
|
468
|
+
/** Overall opacity `0`–`1`, accounting for fade-in/fade-out. Multiply your alpha by this. */
|
|
469
|
+
readonly alpha: number;
|
|
470
|
+
/** Resolved theme, with defaults filled in. */
|
|
471
|
+
readonly theme: ThreatMapTheme;
|
|
472
|
+
/** Resolved line config, with defaults filled in. */
|
|
473
|
+
readonly line: LineStyleConfig;
|
|
474
|
+
/** Device pixel ratio the canvas is scaled to. The context is already transformed; you rarely need this. */
|
|
475
|
+
readonly pixelRatio: number;
|
|
476
|
+
/** Milliseconds since the animation loop started. Useful for your own time-based effects. */
|
|
477
|
+
readonly elapsed: number;
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Draws a single threat, replacing the built-in renderer for it.
|
|
481
|
+
*
|
|
482
|
+
* The context is pre-transformed for device pixel ratio, so draw in CSS pixels.
|
|
483
|
+
* Save/restore is handled around your call; you may mutate context state freely.
|
|
484
|
+
*
|
|
485
|
+
* Returning `false` falls through to the built-in renderer for that threat —
|
|
486
|
+
* useful for customizing only some threats.
|
|
487
|
+
*
|
|
488
|
+
* Note: opting into this hook opts that threat out of style batching, so it
|
|
489
|
+
* costs a draw call of its own. Fine for tens of threats; if you need custom
|
|
490
|
+
* drawing on hundreds, prefer restyling via `theme`/`line`.
|
|
491
|
+
*
|
|
492
|
+
* @example Label the heaviest aggregates
|
|
493
|
+
* ```tsx
|
|
494
|
+
* const renderThreat: ThreatRenderer = (ctx, { threat, points, alpha }) => {
|
|
495
|
+
* if (threat.count < 50) return false; // built-in renderer handles the rest
|
|
496
|
+
* ctx.globalAlpha = alpha;
|
|
497
|
+
* ctx.fillStyle = '#fff';
|
|
498
|
+
* ctx.fillText(`${threat.count}`, points[0], points[1] - 6);
|
|
499
|
+
* return false; // still draw the normal line underneath
|
|
500
|
+
* };
|
|
501
|
+
* ```
|
|
502
|
+
*/
|
|
503
|
+
type ThreatRenderer<TMeta = unknown> = (ctx: CanvasRenderingContext2D, info: ThreatRenderContext<TMeta>) => void | boolean;
|
|
504
|
+
/** Everything a custom region renderer needs. */
|
|
505
|
+
interface RegionRenderContext {
|
|
506
|
+
/** The region's GeoJSON feature. */
|
|
507
|
+
readonly feature: GeoFeature;
|
|
508
|
+
/** Canonical region id — `"FR"`, `"US-CA"`. */
|
|
509
|
+
readonly id: string;
|
|
510
|
+
/** Granularity of this feature. */
|
|
511
|
+
readonly kind: Exclude<RegionKind, 'unknown'>;
|
|
512
|
+
/**
|
|
513
|
+
* A d3-geo path generator already bound to this canvas context and the active
|
|
514
|
+
* projection. Call `path(feature)` to lay down the outline, then fill/stroke.
|
|
515
|
+
*/
|
|
516
|
+
readonly path: (feature: GeoFeature) => void;
|
|
517
|
+
/** Resolved theme. */
|
|
518
|
+
readonly theme: ThreatMapTheme;
|
|
519
|
+
/** Total attack weight originating in this region this frame — handy for choropleths. */
|
|
520
|
+
readonly weight: number;
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Draws a single map region, replacing the built-in fill/stroke for it.
|
|
524
|
+
*
|
|
525
|
+
* Runs only when the base map is (re)rasterized — on mount, resize, and
|
|
526
|
+
* theme/projection change — not per animation frame.
|
|
527
|
+
*
|
|
528
|
+
* Returning `false` falls through to the built-in renderer.
|
|
529
|
+
*
|
|
530
|
+
* @example Heat-shade countries by attack volume
|
|
531
|
+
* ```tsx
|
|
532
|
+
* const renderRegion: RegionRenderer = (ctx, { feature, path, weight, theme }) => {
|
|
533
|
+
* ctx.beginPath();
|
|
534
|
+
* path(feature);
|
|
535
|
+
* ctx.fillStyle = weight > 0 ? `hsl(0 80% ${20 + Math.min(weight, 40)}%)` : theme.land;
|
|
536
|
+
* ctx.fill();
|
|
537
|
+
* return true; // we handled it
|
|
538
|
+
* };
|
|
539
|
+
* ```
|
|
540
|
+
*/
|
|
541
|
+
type RegionRenderer = (ctx: CanvasRenderingContext2D, info: RegionRenderContext) => void | boolean;
|
|
542
|
+
/** A minimal GeoJSON geometry, narrowed to what this library draws. */
|
|
543
|
+
type GeoGeometry = {
|
|
544
|
+
readonly type: 'Polygon';
|
|
545
|
+
readonly coordinates: number[][][];
|
|
546
|
+
} | {
|
|
547
|
+
readonly type: 'MultiPolygon';
|
|
548
|
+
readonly coordinates: number[][][][];
|
|
549
|
+
};
|
|
550
|
+
/** A GeoJSON feature for one country or US state. */
|
|
551
|
+
interface GeoFeature {
|
|
552
|
+
readonly type: 'Feature';
|
|
553
|
+
/** Canonical region id — ISO alpha-2 for countries, ISO 3166-2 for states. */
|
|
554
|
+
readonly id: string;
|
|
555
|
+
readonly properties: {
|
|
556
|
+
/** Display name. */
|
|
557
|
+
readonly name: string;
|
|
558
|
+
/** Granularity. */
|
|
559
|
+
readonly kind: 'country' | 'state';
|
|
560
|
+
/** ISO alpha-2 of the containing country. */
|
|
561
|
+
readonly countryCode: string;
|
|
562
|
+
};
|
|
563
|
+
readonly geometry: GeoGeometry;
|
|
564
|
+
}
|
|
565
|
+
/** A GeoJSON feature collection of regions. */
|
|
566
|
+
interface GeoFeatureCollection {
|
|
567
|
+
readonly type: 'FeatureCollection';
|
|
568
|
+
readonly features: readonly GeoFeature[];
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* The boundary geometry the map draws and reverse region lookup tests against.
|
|
572
|
+
*
|
|
573
|
+
* Loaded lazily by default. Pass your own via {@link ThreatMapProps.geo} to
|
|
574
|
+
* self-host, preload, or substitute different boundaries.
|
|
575
|
+
*/
|
|
576
|
+
interface GeoData {
|
|
577
|
+
/** Country boundaries. */
|
|
578
|
+
readonly countries: GeoFeatureCollection;
|
|
579
|
+
/** US state boundaries. Omit if you never enable states or state aggregation. */
|
|
580
|
+
readonly states?: GeoFeatureCollection;
|
|
581
|
+
}
|
|
582
|
+
/** An error the library recovered from, surfaced via {@link ThreatMapProps.onError}. */
|
|
583
|
+
interface ThreatMapError {
|
|
584
|
+
/**
|
|
585
|
+
* - `'geo-load'` — the geo data chunk failed to load. The map stays blank; threats with
|
|
586
|
+
* explicit region codes or coordinates still render.
|
|
587
|
+
* - `'resolve'` — an attack's `from`/`to` could not be resolved to a coordinate. That
|
|
588
|
+
* attack is skipped.
|
|
589
|
+
* - `'render'` — a `renderThreat`/`renderRegion` hook threw. The hook is disabled for
|
|
590
|
+
* the rest of the frame and the built-in renderer takes over.
|
|
591
|
+
*/
|
|
592
|
+
readonly kind: 'geo-load' | 'resolve' | 'render';
|
|
593
|
+
/** Human-readable description. */
|
|
594
|
+
readonly message: string;
|
|
595
|
+
/** The underlying error, when there was one. */
|
|
596
|
+
readonly cause?: unknown;
|
|
597
|
+
/** The attack involved, for `'resolve'` errors. */
|
|
598
|
+
readonly attack?: Attack<unknown>;
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* Props for {@link ThreatMap}.
|
|
602
|
+
*
|
|
603
|
+
* Only `attacks` is required. Every config object is deeply merged over the
|
|
604
|
+
* defaults, so partial overrides are safe and stable.
|
|
605
|
+
*/
|
|
606
|
+
interface ThreatMapProps<TMeta = unknown> {
|
|
607
|
+
/**
|
|
608
|
+
* The attacks to display. Treated as the complete current set: attacks that
|
|
609
|
+
* disappear from this array fade out.
|
|
610
|
+
*
|
|
611
|
+
* For streaming feeds, keep this array referentially stable between updates —
|
|
612
|
+
* a new array identity re-runs resolution and aggregation. Resolution is
|
|
613
|
+
* memoized per attack `id`, so appending to a growing array is cheap.
|
|
614
|
+
*/
|
|
615
|
+
readonly attacks: readonly Attack<TMeta>[];
|
|
616
|
+
/** Width in CSS pixels. Omit to fill the container width and track it via `ResizeObserver`. */
|
|
617
|
+
readonly width?: number;
|
|
618
|
+
/** Height in CSS pixels. Omit to derive from width and the projection's aspect ratio. */
|
|
619
|
+
readonly height?: number;
|
|
620
|
+
/** Projection name or a d3-geo projection instance. Default `'naturalEarth1'`. */
|
|
621
|
+
readonly projection?: ProjectionSpec;
|
|
622
|
+
/** Color overrides, merged over {@link defaultTheme}. */
|
|
623
|
+
readonly theme?: Partial<ThreatMapTheme>;
|
|
624
|
+
/** Arc geometry/styling overrides, merged over {@link defaultLineStyle}. */
|
|
625
|
+
readonly line?: Partial<LineStyleConfig>;
|
|
626
|
+
/** Animation overrides, merged over {@link defaultAnimation}. */
|
|
627
|
+
readonly animation?: Partial<AnimationConfig>;
|
|
628
|
+
/** Boundary-drawing overrides, merged over {@link defaultRegions}. */
|
|
629
|
+
readonly regions?: Partial<RegionsConfig>;
|
|
630
|
+
/**
|
|
631
|
+
* Aggregation overrides, merged over {@link defaultAggregation}. Pass `false`
|
|
632
|
+
* to render one line per attack.
|
|
633
|
+
*/
|
|
634
|
+
readonly aggregation?: Partial<AggregationConfig<TMeta>> | false;
|
|
635
|
+
/** Override how a threat is drawn. See {@link ThreatRenderer}. */
|
|
636
|
+
readonly renderThreat?: ThreatRenderer<TMeta>;
|
|
637
|
+
/** Override how a region is drawn. See {@link RegionRenderer}. */
|
|
638
|
+
readonly renderRegion?: RegionRenderer;
|
|
639
|
+
/**
|
|
640
|
+
* Supply geo data instead of lazy-loading it. Accepts the data directly or a
|
|
641
|
+
* loader function. Use to self-host the JSON, preload during app boot, or swap
|
|
642
|
+
* in different boundaries.
|
|
643
|
+
*/
|
|
644
|
+
readonly geo?: GeoData | (() => Promise<GeoData>);
|
|
645
|
+
/** Called when a threat is clicked. Hit testing uses the arc, within a few pixels. */
|
|
646
|
+
readonly onThreatClick?: (threat: Threat<TMeta>, event: MouseEvent) => void;
|
|
647
|
+
/** Called when the pointer enters/leaves a threat. `null` on leave. */
|
|
648
|
+
readonly onThreatHover?: (threat: Threat<TMeta> | null, event: MouseEvent) => void;
|
|
649
|
+
/** Called for recoverable errors. Without a handler these are logged in dev and swallowed in prod. */
|
|
650
|
+
readonly onError?: (error: ThreatMapError) => void;
|
|
651
|
+
/** Applied to the wrapper element. */
|
|
652
|
+
readonly className?: string;
|
|
653
|
+
/** Applied to the wrapper element. The canvases fill it. */
|
|
654
|
+
readonly style?: React.CSSProperties;
|
|
655
|
+
/** Accessible label for the map. Default `"Cyberattack threat map"`. */
|
|
656
|
+
readonly ariaLabel?: string;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Reverse geo lookup: a raw `{lat, lng}` → the region that contains it.
|
|
661
|
+
*
|
|
662
|
+
* Only needed when a consumer supplies bare coordinates and wants aggregation.
|
|
663
|
+
* Attacks carrying an explicit region code skip this entirely — which is why
|
|
664
|
+
* `{ lat, lng, region }` is the recommended shape for high-volume feeds.
|
|
665
|
+
*
|
|
666
|
+
* @packageDocumentation
|
|
667
|
+
*/
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* Point-in-region index over a {@link GeoData} set.
|
|
671
|
+
*
|
|
672
|
+
* Naive point-in-polygon against ~230 features costs ~230 polygon walks per
|
|
673
|
+
* query, and a 500-attack feed re-resolving on every update makes that the
|
|
674
|
+
* dominant cost in the whole pipeline. Three things fix it:
|
|
675
|
+
*
|
|
676
|
+
* 1. **Bounding-box rejection.** Four float compares eliminate ~99% of
|
|
677
|
+
* candidates before any polygon walk. Boxes are computed once at construction.
|
|
678
|
+
* 2. **States before countries.** A point inside California is also inside the
|
|
679
|
+
* US; testing states first means `'auto'` granularity gets the specific answer
|
|
680
|
+
* without testing twice.
|
|
681
|
+
* 3. **Memoization on a rounded key.** Attack feeds repeat origins heavily
|
|
682
|
+
* (the same datacenter, over and over), so a cache keyed on coordinates
|
|
683
|
+
* rounded to ~1 km turns the common case into a Map hit.
|
|
684
|
+
*/
|
|
685
|
+
declare class RegionIndex {
|
|
686
|
+
#private;
|
|
687
|
+
constructor(geo: GeoData);
|
|
688
|
+
/** Whether US state geometry is present, and so whether state resolution can succeed. */
|
|
689
|
+
get hasStates(): boolean;
|
|
690
|
+
/**
|
|
691
|
+
* Find the region containing a point.
|
|
692
|
+
*
|
|
693
|
+
* @param point - Coordinates in degrees.
|
|
694
|
+
* @param preferStates - When `true`, return the US state if the point is in one.
|
|
695
|
+
* When `false`, always return the country. Maps to aggregation granularity.
|
|
696
|
+
* @returns The containing region, or {@link UNKNOWN_REGION} for points in the
|
|
697
|
+
* ocean or outside all known boundaries.
|
|
698
|
+
*/
|
|
699
|
+
resolve(point: LatLng, preferStates: boolean): ResolvedRegion;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* The inline region table: canonical codes and anchor coordinates for every
|
|
704
|
+
* country and US state.
|
|
705
|
+
*
|
|
706
|
+
* This is the one piece of geo data that is **not** lazy-loaded. It is small
|
|
707
|
+
* (~20 kB raw, ~6 kB gzipped) and it must be synchronous, because resolving
|
|
708
|
+
* `"US-CA"` to a coordinate is what lets aggregation stay a pure function with
|
|
709
|
+
* no async and no fetch. Boundary geometry — 100× larger and only needed to
|
|
710
|
+
* *draw* — is loaded separately. See DECISIONS.md §3.
|
|
711
|
+
*
|
|
712
|
+
* @packageDocumentation
|
|
713
|
+
*/
|
|
714
|
+
|
|
715
|
+
/** A region entry with its anchor coordinate. */
|
|
716
|
+
interface RegionEntry extends ResolvedRegion {
|
|
717
|
+
/** The region's anchor point — see DECISIONS.md §3 on why this is not a true centroid. */
|
|
718
|
+
readonly anchor: LatLng;
|
|
719
|
+
/** ISO alpha-3 code. `null` for US states. */
|
|
720
|
+
readonly alpha3: string | null;
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* The sentinel region used when a location cannot be resolved. Never throws —
|
|
724
|
+
* unresolvable input degrades to this so one bad row cannot blank the map.
|
|
725
|
+
*/
|
|
726
|
+
declare const UNKNOWN_REGION: ResolvedRegion;
|
|
727
|
+
/**
|
|
728
|
+
* Look up a region by its canonical id.
|
|
729
|
+
*
|
|
730
|
+
* @param id - `"FR"` or `"US-CA"`. Case-sensitive; use {@link lookupRegionCode} for user input.
|
|
731
|
+
* @returns The region, or `undefined`.
|
|
732
|
+
*/
|
|
733
|
+
declare function getRegionById(id: string): RegionEntry | undefined;
|
|
734
|
+
/**
|
|
735
|
+
* Resolve a user-supplied region code to a region.
|
|
736
|
+
*
|
|
737
|
+
* Matching order — see {@link RegionCode} for the full contract:
|
|
738
|
+
* 1. Hyphenated (`"US-CA"`) → US state, exact.
|
|
739
|
+
* 2. Two letters (`"FR"`) → country first, then falling back to a US state.
|
|
740
|
+
* This is why `"CA"` is Canada and `"TX"` is Texas: `CA` is a real country
|
|
741
|
+
* code and `TX` is not.
|
|
742
|
+
* 3. Three letters (`"FRA"`) → country by alpha-3.
|
|
743
|
+
*
|
|
744
|
+
* @param code - The identifier. Leading/trailing space and case are ignored.
|
|
745
|
+
* @returns The matching region, or `undefined` if nothing matched.
|
|
746
|
+
*
|
|
747
|
+
* @example
|
|
748
|
+
* ```ts
|
|
749
|
+
* lookupRegionCode('us-ca')?.name; // 'California'
|
|
750
|
+
* lookupRegionCode('CA')?.name; // 'Canada' (country wins)
|
|
751
|
+
* lookupRegionCode('TX')?.name; // 'Texas' (no country 'TX')
|
|
752
|
+
* lookupRegionCode('FRA')?.name; // 'France'
|
|
753
|
+
* ```
|
|
754
|
+
*/
|
|
755
|
+
declare function lookupRegionCode(code: string): RegionEntry | undefined;
|
|
756
|
+
/**
|
|
757
|
+
* Every region the library knows about, countries and US states.
|
|
758
|
+
*
|
|
759
|
+
* Useful for building region pickers or validating a feed before rendering.
|
|
760
|
+
*
|
|
761
|
+
* @returns A new array; the underlying entries are frozen and shared.
|
|
762
|
+
*/
|
|
763
|
+
declare function listRegions(): RegionEntry[];
|
|
764
|
+
|
|
765
|
+
export { type AnimationConfig as A, type ThreatRenderContext as B, type Color as C, type ThreatRenderer as D, type EasingName as E, type GeoData as G, type IntensityScale as I, type LineStyleConfig as L, type ProjectionName as P, type RegionEntry as R, type Severity as S, type ThreatMapProps as T, UNKNOWN_REGION as U, RegionIndex as a, lookupRegionCode as b, type RegionsConfig as c, type ThreatMapTheme as d, type AggregationConfig as e, type Attack as f, getRegionById as g, type Threat as h, type ResolvedRegion as i, type AggregationGranularity as j, type LatLng as k, listRegions as l, type AttackLocation as m, type AggregationGroupBy as n, type AggregationKeyFn as o, type AggregationSeverityFn as p, type GeoFeature as q, type GeoFeatureCollection as r, type GeoGeometry as s, type GeoProjectionLike as t, type ProjectionSpec as u, type RegionCode as v, type RegionKind as w, type RegionRenderContext as x, type RegionRenderer as y, type ThreatMapError as z };
|