@ham2k/extension-sdk 0.11.0 → 0.12.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.
- package/dist/dxcc.js +8 -1
- package/dist/exportSettings.js +3 -2
- package/dist/index.d.ts +5 -1
- package/dist/referenceActivity.js +9 -1
- package/docs/hooks.md +53 -7
- package/package.json +1 -1
package/dist/dxcc.js
CHANGED
|
@@ -3,7 +3,14 @@ import { annotateFromCountryFile, useBuiltinCountryFile } from "@ham2k/lib-count
|
|
|
3
3
|
import { DXCC_BY_CODE } from "@ham2k/lib-dxcc-data";
|
|
4
4
|
useBuiltinCountryFile();
|
|
5
5
|
function annotateCallAgainstCountryFile(call, options) {
|
|
6
|
-
|
|
6
|
+
const annotated = annotateFromCountryFile(parseCallsign(call), options);
|
|
7
|
+
return annotated.tz ? { ...annotated, tz: ordinarySignTz(annotated.tz) } : annotated;
|
|
8
|
+
}
|
|
9
|
+
function ordinarySignTz(tz) {
|
|
10
|
+
const match = /^GMT([+-]?\d+(?:\.\d+)?)$/.exec(tz);
|
|
11
|
+
if (!match) return tz;
|
|
12
|
+
const offset = -Number(match[1]);
|
|
13
|
+
return offset > 0 ? `GMT+${offset}` : `GMT${offset === 0 ? 0 : offset}`;
|
|
7
14
|
}
|
|
8
15
|
function entityPrefixForCall(call) {
|
|
9
16
|
if (!call) return void 0;
|
package/dist/exportSettings.js
CHANGED
|
@@ -76,6 +76,7 @@ function resolveExportSettings(definition, global = {}, overrides = {}) {
|
|
|
76
76
|
}
|
|
77
77
|
return resolved;
|
|
78
78
|
}
|
|
79
|
+
const PRIVATE_STATION_FIELDS = ["name", "city", "street", "postal", "email", "qslVia", "url", "notes", "lat", "lon", "multiIdentifier"];
|
|
79
80
|
function exportQso(qso, settings) {
|
|
80
81
|
const copy = { ...qso };
|
|
81
82
|
for (const side of ["their", "our"]) {
|
|
@@ -83,11 +84,11 @@ function exportQso(qso, settings) {
|
|
|
83
84
|
const station = { ...copy[side] };
|
|
84
85
|
if (settings.includeLookupData === false) delete station.guess;
|
|
85
86
|
if (settings.includePrivateData === false) {
|
|
86
|
-
for (const key of
|
|
87
|
+
for (const key of PRIVATE_STATION_FIELDS) delete station[key];
|
|
87
88
|
if (typeof station.grid === "string") station.grid = station.grid.slice(0, 6);
|
|
88
89
|
if (station.guess && typeof station.guess === "object") {
|
|
89
90
|
const guess = { ...station.guess };
|
|
90
|
-
for (const key of
|
|
91
|
+
for (const key of PRIVATE_STATION_FIELDS) delete guess[key];
|
|
91
92
|
if (typeof guess.grid === "string") guess.grid = guess.grid.slice(0, 6);
|
|
92
93
|
station.guess = guess;
|
|
93
94
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// @ham2k/extension-sdk 0.
|
|
1
|
+
// @ham2k/extension-sdk 0.12.2
|
|
2
2
|
/** Experimental v1 panel scene contract. All coordinates are in the scene's viewBox. */
|
|
3
3
|
export interface PanelScene {
|
|
4
4
|
version: 1;
|
|
@@ -490,6 +490,8 @@ export interface Ref {
|
|
|
490
490
|
lon?: number;
|
|
491
491
|
location?: string;
|
|
492
492
|
program?: string;
|
|
493
|
+
activationRadiusInMeters?: number;
|
|
494
|
+
activationRadiusInFeet?: number;
|
|
493
495
|
retired?: boolean;
|
|
494
496
|
for?: "operation" | "qso";
|
|
495
497
|
[key: string]: JSONValue | undefined;
|
|
@@ -1874,7 +1876,9 @@ export interface ReferenceActivityConfig {
|
|
|
1874
1876
|
linkUrl?: (reference: string) => string;
|
|
1875
1877
|
transforms?: RefTransform[];
|
|
1876
1878
|
refInput?: (args: RefInputArgs, ctx: HookContext) => Promise<RefInputExtras> | RefInputExtras;
|
|
1879
|
+
activationRadius?: ActivationRadius | ((row: LookupRow) => ActivationRadius | undefined);
|
|
1877
1880
|
}
|
|
1881
|
+
export type ActivationRadius = Pick<Ref, "activationRadiusInMeters" | "activationRadiusInFeet">;
|
|
1878
1882
|
export interface RefInputArgs {
|
|
1879
1883
|
operation: Record<string, JSONValue>;
|
|
1880
1884
|
qso?: Record<string, JSONValue>;
|
|
@@ -58,6 +58,10 @@ function referenceActivity(config) {
|
|
|
58
58
|
const category = config.category ?? config.key;
|
|
59
59
|
const program = config.adifProgram ?? config.label;
|
|
60
60
|
const allowsMultiple = config.allowsMultiple ?? false;
|
|
61
|
+
function radiusFor(row) {
|
|
62
|
+
const radius = row ? typeof config.activationRadius === "function" ? config.activationRadius(row) : config.activationRadius : void 0;
|
|
63
|
+
return { activationRadiusInMeters: radius?.activationRadiusInMeters, activationRadiusInFeet: radius?.activationRadiusInFeet };
|
|
64
|
+
}
|
|
61
65
|
async function lookupReference(ref) {
|
|
62
66
|
const host = await hostApi();
|
|
63
67
|
try {
|
|
@@ -78,7 +82,8 @@ function referenceActivity(config) {
|
|
|
78
82
|
grid: void 0,
|
|
79
83
|
lat: void 0,
|
|
80
84
|
lon: void 0,
|
|
81
|
-
location: void 0
|
|
85
|
+
location: void 0,
|
|
86
|
+
...radiusFor(null)
|
|
82
87
|
};
|
|
83
88
|
}
|
|
84
89
|
function decorate(ref, reference, row, unknown) {
|
|
@@ -91,6 +96,7 @@ function referenceActivity(config) {
|
|
|
91
96
|
grid: data.grid,
|
|
92
97
|
lat: row.lat,
|
|
93
98
|
lon: row.lon,
|
|
99
|
+
...radiusFor(row),
|
|
94
100
|
location: data.location,
|
|
95
101
|
program,
|
|
96
102
|
label: `${config.label} ${reference}: ${row.name}`,
|
|
@@ -206,6 +212,7 @@ function referenceActivity(config) {
|
|
|
206
212
|
grid: data.grid,
|
|
207
213
|
lat: row.lat,
|
|
208
214
|
lon: row.lon,
|
|
215
|
+
...radiusFor(row),
|
|
209
216
|
location: data.location,
|
|
210
217
|
program,
|
|
211
218
|
label: `${config.label} ${row.key}: ${row.name ?? ""}`,
|
|
@@ -230,6 +237,7 @@ function referenceActivity(config) {
|
|
|
230
237
|
grid: data.grid,
|
|
231
238
|
lat: row?.lat,
|
|
232
239
|
lon: row?.lon,
|
|
240
|
+
...radiusFor(row),
|
|
233
241
|
location: data.location,
|
|
234
242
|
program,
|
|
235
243
|
label: `${config.label} ${typed}: ${name}`,
|
package/docs/hooks.md
CHANGED
|
@@ -209,9 +209,11 @@ interface LookupServiceHook {
|
|
|
209
209
|
**locationScope merge rules** (`CallInfo.locationScope`, ranked
|
|
210
210
|
`qth < prefixed < portable`, most general to most specific):
|
|
211
211
|
- A result whose `locationScope` is strictly more specific than the current
|
|
212
|
-
guess's clears all location fields (`locSource, lat, lon, grid,
|
|
213
|
-
state, county, country`) before merging the result in, and
|
|
214
|
-
adopts the more specific scope.
|
|
212
|
+
guess's clears all location fields (`locSource, lat, lon, grid, street,
|
|
213
|
+
city, state, postal, county, country`) before merging the result in, and
|
|
214
|
+
the guess adopts the more specific scope. `street` and `postal` are the
|
|
215
|
+
mailing address's own lines, grouped with the town they complete so an
|
|
216
|
+
address never puts one source's street on another source's town.
|
|
215
217
|
- Otherwise, priority order applies as usual: a field already present in the
|
|
216
218
|
guess is never overwritten by a later (lower-priority) result. A
|
|
217
219
|
location field additionally requires the result's own scope to be at
|
|
@@ -231,13 +233,22 @@ interface LookupServiceHook {
|
|
|
231
233
|
- Grid/lat-lon reconciliation, scoped to fields the result actually set:
|
|
232
234
|
grid-only → lat/lon computed from the grid; lat/lon-only → a 6-digit grid
|
|
233
235
|
computed from them; both given → taken verbatim. Setting grid/lat/lon
|
|
234
|
-
clears city/state/country/county unless the *same* result
|
|
235
|
-
them. The converse clause — a town write clearing grid/lat/lon — can only
|
|
236
|
+
clears street/city/state/postal/country/county unless the *same* result
|
|
237
|
+
also supplies them. The converse clause — a town write clearing grid/lat/lon — can only
|
|
236
238
|
sweep a leftover half lat/lon pair: the group rule above blocks a town
|
|
237
239
|
from landing at all where a full pin already stands.
|
|
238
240
|
- `notes`/`history` are per-`CallInfoLookup` fields, not part of the merged
|
|
239
241
|
`guess` — they simply accumulate, unconditionally, in the returned
|
|
240
242
|
`lookups[]` array.
|
|
243
|
+
- **`cqZone`, `ituZone` and `tz` are the exception to first-answer-wins.** The
|
|
244
|
+
pre-step can only answer them for a whole entity or call area (a W6 call
|
|
245
|
+
reads CQ zone 3 wherever the station lives), so once every hook has run,
|
|
246
|
+
a value the pre-step still holds goes to the first hook result that
|
|
247
|
+
carried one (`preferStationValues`) — only while the guess's scope is
|
|
248
|
+
`qth`, since on a portable or prefixed contact a source describes the
|
|
249
|
+
home QTH. `tz` is a UTC offset with its ordinary sign, `"GMT-5"` being
|
|
250
|
+
five hours behind; the SDK's `annotateCallAgainstCountryFile` flips the
|
|
251
|
+
country file's west-positive offsets to match.
|
|
241
252
|
- **`locSource: 'prefix'` is reserved**, and a `lat`/`lon` merged under it is
|
|
242
253
|
never read as a coordinate (`locationFromGuess`, halo_core). It marks
|
|
243
254
|
lib-country-files' DXCC entity centroid, whose longitude follows cty.dat's
|
|
@@ -429,7 +440,8 @@ interface RefHandlerHook {
|
|
|
429
440
|
linkForRef?(args: { ref: Ref }, ctx): Promise<RefLink | null> // {url, label?}
|
|
430
441
|
geojsonUrlForRef?(args: { ref: Ref }, ctx): Promise<RefGeojson | null>
|
|
431
442
|
}
|
|
432
|
-
// Ref: {type, ref?, name?, label?, shortLabel?, grid?, location?, program?,
|
|
443
|
+
// Ref: {type, ref?, name?, label?, shortLabel?, grid?, lat?, lon?, location?, program?,
|
|
444
|
+
// activationRadiusInMeters?, activationRadiusInFeet?, ...}
|
|
433
445
|
// TitleSuggestion: {title?, for?, at?, subtitle?, priority?} — a fragment of
|
|
434
446
|
// the operation's title/subtitle sentence (ham2k/halo-dist#174). Only
|
|
435
447
|
// return one for the ref type that means "this operation is happening AT/FOR
|
|
@@ -517,6 +529,35 @@ SOTLAS's `az.sotl.as`, used with the operators' permission) and `pota` (both
|
|
|
517
529
|
types, via `services.ham2k.net/lookups/outlines/pota/`, which links parks to
|
|
518
530
|
OpenStreetMap shapes; a park not yet linked answers 404).
|
|
519
531
|
|
|
532
|
+
**POTA is the one exception, and the core makes it, not the hook.** For a
|
|
533
|
+
POTA suggestion's dashed outline the core skips `geojsonUrlForRef` and reads
|
|
534
|
+
`services.ham2k.net`'s grid bundles instead — every outlined park touching a
|
|
535
|
+
Maidenhead cell, simplified and clipped to it, one cached document per cell
|
|
536
|
+
(500 m blocks below GL zoom 9, 10 m squares from 9). A long trail's whole
|
|
537
|
+
outline runs to megabytes; its pieces in a cell, to kilobytes. The same
|
|
538
|
+
bundles add to `suggest`'s answers the parks whose outline, not just whose
|
|
539
|
+
point, is near: within 5 km for the nearby list, touching the view for a pan
|
|
540
|
+
close in (from about GL zoom 10; see `suggest` below). An open card's POTA suggestion is drawn solid from the
|
|
541
|
+
same pieces; the operation's own references still come from
|
|
542
|
+
`geojsonUrlForRef`.
|
|
543
|
+
|
|
544
|
+
**An activation radius is a circle, drawn the same way.** A reference that
|
|
545
|
+
carries `activationRadiusInMeters` or `activationRadiusInFeet` — how far from
|
|
546
|
+
its point the program lets an activator be — is circled on both maps, in the
|
|
547
|
+
same color and under the same rules as an outline: solid for the operation's
|
|
548
|
+
own references and the open card, dashed for the other suggestions once
|
|
549
|
+
zoomed in. It is set on the reference itself, by `suggest` and `decorateRef`,
|
|
550
|
+
because some programs set different distances by region or by kind of
|
|
551
|
+
reference; a suggestion is stored on the operation verbatim, so the Map tab
|
|
552
|
+
draws it too. Give whichever unit the rules are written in; meters win when
|
|
553
|
+
both are set. It is drawn only around `lat`/`lon`, never around a `grid`,
|
|
554
|
+
whose centre can sit further from the reference than the whole radius
|
|
555
|
+
(docs/design/locations.md). A reference with an outline AND a radius draws
|
|
556
|
+
both. A circle has no source, so it adds nothing to the map's outline credits
|
|
557
|
+
and is not offered for an outline report. Programs built on the SDK's
|
|
558
|
+
`referenceActivity` factory get this from one `activationRadius` config line —
|
|
559
|
+
a value, or a function of the list row for rules that vary.
|
|
560
|
+
|
|
520
561
|
`suggestOperationTitle` lets an activity build a natural-language operation
|
|
521
562
|
title/subtitle from its refs — "at Yosemite NP" (POTA), "for Field Day"
|
|
522
563
|
(contest programs, when ported) — mirroring app-polo's
|
|
@@ -647,7 +688,12 @@ an app that sends `bounds` answers that call, so an extension that calls it
|
|
|
647
688
|
only then runs on older apps unchanged, and one that predates `bounds` answers
|
|
648
689
|
with what is nearest the view's centre. Measure `distance` from the `location`
|
|
649
690
|
given either way; the core re-measures a panned answer from the operation's own
|
|
650
|
-
place before any card shows it.
|
|
691
|
+
place before any card shows it. For POTA only, the core also adds the parks
|
|
692
|
+
whose OUTLINE is near (from the grid bundles above) to the nearby list and to a
|
|
693
|
+
pan, labelled by POTA's own `decorateRef`, and gives a park POTA already
|
|
694
|
+
suggested the nearer of its point's and its outline's distance — so `pota`'s
|
|
695
|
+
`suggest` keeps answering by point, and a trail whose point is a state away
|
|
696
|
+
still reaches an operator standing on it. Called with no
|
|
651
697
|
`searchTerm` for nearby suggestions, or with one for name/code search — an
|
|
652
698
|
extension may honor either, both, or neither (returning `[]`). `scoped` is
|
|
653
699
|
true when THIS extension alone was asked — the operator tapped its "Activity
|