@ham2k/extension-sdk 0.5.2 → 0.5.4

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/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- // @ham2k/extension-sdk 0.5.2
1
+ // @ham2k/extension-sdk 0.5.4
2
2
  /** Experimental v1 scene contract. All coordinates are in the scene's viewBox. */
3
3
  export interface SvgScene {
4
4
  version: 1;
@@ -231,7 +231,26 @@ export interface HookContext {
231
231
  getOperation?(uuid: string): Promise<Record<string, JSONValue> | null>;
232
232
  getQsos?(operationUuid: string): Promise<Record<string, JSONValue>[] | null>;
233
233
  getSpotsForCall?(call: string, maxAgeMinutes?: number): Promise<Spot[]>;
234
- getHistoryForCall?(call: string): Promise<Record<string, JSONValue>[]>;
234
+ getHistoryForCall?(call: string, options?: HistoryForCallOptions): Promise<Record<string, JSONValue>[]>;
235
+ }
236
+ export interface HistoryForCallOptions {
237
+ refType?: string | string[];
238
+ refPrefix?: string | string[];
239
+ operation?: string | string[];
240
+ excludeOperation?: string | string[];
241
+ fromDate?: string;
242
+ toDate?: string;
243
+ fromDateMillis?: number;
244
+ toDateMillis?: number;
245
+ fromTime?: string;
246
+ toTime?: string;
247
+ fromTimeMillis?: number;
248
+ toTimeMillis?: number;
249
+ band?: string | string[];
250
+ excludeBand?: string | string[];
251
+ mode?: string | string[];
252
+ excludeMode?: string | string[];
253
+ limit?: number;
235
254
  }
236
255
  export type LookupResult = (CallInfoLookup & {
237
256
  locAccuracy?: number;
@@ -393,6 +393,71 @@ as a constant inside the extension that uses it, because these bundles are
393
393
  served to anyone who asks and a `.h2kext` is a zip. An installed extension
394
394
  sees no build secret, whatever key it claims and wherever it came from.
395
395
 
396
+ ### The upgrade to catalog extensions
397
+
398
+ An install that has been running the app's own extensions is offered the move
399
+ at start, and again the moment the catalog experiment is switched on: that
400
+ switch is the operator asking for catalog extensions, and being made to
401
+ relaunch before anything is offered reads as nothing having happened. The
402
+ switch withdraws nothing by itself; only a taken upgrade does, and the offer
403
+ may be deferred either way. A catalog that cannot be reached says so in the
404
+ footer when the operator asked, and says nothing at a launch nobody was
405
+ watching.
406
+
407
+ Accepting installs the pre-loads, then fetches the catalog's twin of every
408
+ other built-in the operator had switched on — `wca` becomes `ham2k-wca` —
409
+ carrying its settings and credentials the same way. Nothing is withdrawn until
410
+ that finishes; a download that fails puts the app's own extensions back in use
411
+ and the offer returns next launch. Twins that did arrive stay on disk, unused
412
+ until an upgrade completes — the built-in each one supersedes is what runs
413
+ meanwhile.
414
+
415
+ A bundle the engine will not evaluate takes the whole runtime with it, so the
416
+ upgrade puts that one aside — the boot names the bundle it died on — and
417
+ restarts once more. What boots then is the upgrade minus that extension, named
418
+ in the dialog in a sentence of its own. Refused rather than
419
+ withdrawn: the panel still lists it, badged, because the row is where an
420
+ operator sees that something they installed is doing nothing, and updating it
421
+ there is what lifts the refusal. Keyed by the VERSION that failed, so a fixed
422
+ release arrives as an ordinary update and clears it. Only an INSTALLED
423
+ extension is ever put aside; a built-in that
424
+ will not evaluate is a defect in the app, and skipping it would ship an
425
+ install quietly missing part of itself.
426
+
427
+ A refusal is kept even when putting the bundle aside did not get a runtime
428
+ back: it still will not evaluate, and an extension with no built-in behind it
429
+ is in the reverted set too, so re-admitting it there would kill the boot that
430
+ was about to give the operator everything back. Every dialog, and the notice
431
+ that stands in for one, names what stayed out — except a downloaded copy the
432
+ revert superseded, whose built-in is running again. Uninstalling clears the
433
+ record, so a reinstall of the same bytes gets its chance.
434
+
435
+ A refused extension is treated like a revoked one in everything else: it
436
+ keeps its switch, and its downloaded data expires on the same clock as any
437
+ extension the app is not loading.
438
+
439
+ What this does NOT cover is a failure that names no bundle. Only a bundle
440
+ that fails while it is being EVALUATED names itself: a kernel that will not
441
+ load, or an extension that throws while ACTIVATING, takes the generation down
442
+ under a name that is not a key. Those revert the whole upgrade as before, and
443
+ it is offered again at the next launch.
444
+
445
+ The upgrade restarts the extension runtime, which takes the footer items of
446
+ the generation going down with it: a data file's import raises an error rather
447
+ than returning into a torn-down runtime, so its progress line is cleared and
448
+ the file is left unstamped for the next sweep instead of recorded as fresh
449
+ with nothing imported.
450
+
451
+ A few built-ins have no twin on purpose — `qp`, which the catalog carries as
452
+ one extension per party instead — and the app names them itself
453
+ (`kBuiltInsWithoutTwin`). Those are withdrawn without asking the catalog, and
454
+ the dialog that reports the upgrade finished names each one the operator had
455
+ switched on, since it is where they learn it is gone. Any other twin missing
456
+ from the listing fails the upgrade and is asked for again next launch: a
457
+ listing lacks a key the same way whether the catalog will never serve it or has
458
+ not published it yet, and only the app knows which. A built-in retired from the
459
+ catalog on purpose joins that list in the same change.
460
+
396
461
  ### Installing from the catalog
397
462
 
398
463
  **Settings → Extensions → Catalog** lists what [catalog.ham2k.net](https://catalog.ham2k.net)
package/docs/hooks.md CHANGED
@@ -51,8 +51,9 @@ hook method receives `(args, ctx)` where `ctx: HookContext` is:
51
51
  reads above it is cheap enough for the lookup path; it resolves `[]`
52
52
  whenever the cache is cold or the host keeps no spots. Used by
53
53
  `spot-history` to pull a hunted park or summit into the QSO being logged.
54
- * `getHistoryForCall?(call)` — every non-deleted QSO ever logged with `call`,
55
- across every operation, most recent first, as raw QSON — the one log read
54
+ * `getHistoryForCall?(call, options?)` — the most recent non-deleted contacts
55
+ logged with `call` (five unless `limit` says otherwise, never more than
56
+ 50), across every operation, newest first, as raw QSON — the one log read
56
57
  that is cross-operation rather than scoped to a single one, since it
57
58
  answers "who is this station" from the whole log rather than "what's in
58
59
  this operation". Resolves `[]` for no match or no log access; unlike
@@ -60,6 +61,25 @@ hook method receives `(args, ctx)` where `ctx: HookContext` is:
60
61
  Used by `call-history` to fold the most recent past QSO's fields into a
61
62
  lookup result.
62
63
 
64
+ `options` (`HistoryForCallOptions` in `types.ts`) narrow the history
65
+ before it is ordered and limited, so `{ refType: 'cwt' }` finds last
66
+ month's CWT exchange behind a week of POTA contacts. The filters are
67
+ `refType` (a ref in the QSO's own `refs`), `refPrefix` (a ref whose `ref`
68
+ starts with it, ignoring ASCII case; with `refType`, the same ref must pass
69
+ both, so `{ refType: 'potaActivation', refPrefix: 'FR-' }` finds French
70
+ parks), `operation`/`excludeOperation`,
71
+ `band`/`excludeBand`, `mode`/`excludeMode` (`SSB` also matches its
72
+ sidebands, and `CW`/`PHONE`/`DATA` match their whole family), whole UTC
73
+ days through `fromDate`/`toDate` or `fromDateMillis`/`toDateMillis`, and
74
+ exact instants through `fromTime`/`toTime` or
75
+ `fromTimeMillis`/`toTimeMillis`. All the bounds are inclusive. A malformed
76
+ option, an unknown one, or an include option given no values
77
+ (`operation: []`) rejects the call instead of answering an unfiltered
78
+ history. Hosts older than these options ignore them and answer the latest
79
+ five contacts unfiltered, so a caller re-checks on the results whatever it
80
+ relies on — and an empty answer there means "none among the latest five",
81
+ not "none at all".
82
+
63
83
  Status legend: ✅ implemented · 🔜 planned (design in DESIGN.md §4).
64
84
 
65
85
  ---
@@ -1206,6 +1226,14 @@ permission (pending challenge code for an email, immediately-active for an
1206
1226
  already-permitted account, or a blank permission for QR-code linking) and
1207
1227
  returns server rejections as `{ error, error_status }` data.
1208
1228
 
1229
+ `linkClient` must NOT mail anything. The core shows the challenge code on
1230
+ screen and offers the email as a separate choice, so a transport that mails
1231
+ here sends a confirmation nobody asked for — and one more on every renewal,
1232
+ since an expiring code re-requests through this same call.
1233
+ `linkClientWithEmail` is the call the operator reaches by choosing the
1234
+ email over the code, and the only one in this seam that mails. A server
1235
+ that mails by default (LoFi does) has to be told not to.
1236
+
1209
1237
  The account-management methods are all optional and all follow that same
1210
1238
  "a rejection is data, not a throw" convention, because every one of them
1211
1239
  reports to an operator in the middle of an action: `setAccountEmail` /
@@ -1256,7 +1284,7 @@ numeric value patches; local-only controls and animation frames make no bridge
1256
1284
  calls. Controls with `continuous: true` send `change` events during dragging and a
1257
1285
  final `commit` on release; pending movements are coalesced to the newest value.
1258
1286
  Numeric text supports `scale`, `truncate`, `modulo`, and `minIntegerDigits`
1259
- for local numeric formatting. The Radio Panel Example uses these for its Modern
1287
+ for local numeric formatting. KI2D’s Radio Panel uses these for its Modern
1260
1288
  frequency groups; its settings offer Modern/LCD styles and radio selection. Local sliders may use `hover` and `discrete` hourly buckets. Text `samples`
1261
1289
  may hold numbers or preformatted strings; control `valueLabels` supplies accessible
1262
1290
  value descriptions. Transform/opacity bindings may also supply numeric `samples`,
@@ -1302,12 +1330,12 @@ Button controls can supply `menu: [{label, event}]` to open a native dropdown.
1302
1330
  Selecting an item emits its `event` as the action with the original control ID;
1303
1331
  dismissing the menu emits nothing.
1304
1332
 
1305
- The `svg-weather`, `svg-solar`, and `svg-radio` reference panels live in
1333
+ The `ki2d-weather-panel`, `ki2d-solar-panel` and `ki2d-radio-panel` reference
1334
+ panels live in
1306
1335
  [ham2k/extensions](https://github.com/ham2k/extensions/tree/main/extensions/dashboard).
1307
1336
  They use public host APIs and ship as `.h2kext` packages, not app assets.
1308
- Install the packages, then add their panels through Edit Layout. Their original
1309
- extension and panel keys are retained so existing placements and settings survive.
1310
- See that repository’s dashboard README for building against the unreleased SDK.
1337
+ Install the packages, then add their panels through Edit Layout. See that
1338
+ repository's dashboard README for building them.
1311
1339
 
1312
1340
  The radio host calls are manifest capabilities, refused unless declared — the
1313
1341
  same shape as `requiresLocation`, and shown to the operator at install:
@@ -1315,8 +1343,16 @@ same shape as `requiresLocation`, and shown to the operator at install:
1315
1343
  `"requiresRadioWrite": true` allows `host.tuneRadio()` and
1316
1344
  `host.setRadioConnection()`, and implies read, since a command answers with the
1317
1345
  radio's state. An undeclared call rejects rather than answering null.
1346
+ A capability belongs to the bundle that declared it, and to the sub-extensions
1347
+ that bundle defines under its own key. A separately installed bundle never
1348
+ inherits one through its name: `rigpanel-themes` gets nothing from `rigpanel`.
1349
+
1350
+ An `onEvent` that cannot read its panel's config is refused rather than run
1351
+ with an empty one, since a config is where a panel keeps which radio it
1352
+ commands. The host allows an event up to about ten seconds in all (config, then
1353
+ the hook); the control shows its pending value until the outcome is known.
1318
1354
 
1319
- **Radio Panel Example** is the CAT reference extension. `host.listRadios()` lists configured
1355
+ **KI2D’s Radio Panel** is the CAT reference extension. `host.listRadios()` lists configured
1320
1356
  local transceivers. `host.readRadio(id?)` returns
1321
1357
  a **local** radio's reported frequency (Hz), mode, connection state,
1322
1358
  power, TX state and fresh telemetry, or null on hosts without this API.
package/docs/templates.md CHANGED
@@ -227,8 +227,9 @@ will jump rather than count. Show HH:MM.
227
227
  | CW messages | Radio settings `cwMessage1..8`, keyed on F1-F8 through the radio (docs/design/cat.md § CW keying) — rendered by the `template` hook (hooks.md) | by the operator, in the Station dialog's Messages… dialog |
228
228
 
229
229
  NOTES and COMMENT default to QSO notes and are withheld when private data
230
- is off. QSLMSG defaults to empty for program exports, and to the operation’s
231
- references for the whole-log ADIF. Custom QSL messages may use contact values.
230
+ is off. QSLMSG defaults to empty for program exports, and for the whole-log
231
+ ADIF to the operation’s references as `refLabels | sentence` names them —
232
+ “POTA US-0001 & WWFF KFF-0002”. Custom QSL messages may use contact values.
232
233
  Templates receive no withheld private or lookup values. File titles obey the
233
234
  private-data choice; filename templates are labels for the operator’s files.
234
235
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ham2k/extension-sdk",
3
- "version": "0.5.2",
3
+ "version": "0.5.4",
4
4
  "description": "Write extensions for the Ham2K Logger: typed hook contracts and the host API",
5
5
  "keywords": [
6
6
  "ham2k",
@@ -19,6 +19,6 @@ node build.mjs
19
19
  node ../../tools/h2kext-pack.mjs build -o /tmp/k2hrc-svg-scenes.h2kext
20
20
  ```
21
21
 
22
- For the standalone Flutter preview and migration plan, see
23
- `docs/design/svg-scenes.md` in the logger repository. This is an API experiment,
22
+ For the contract and migration plan, see `docs/design/svg-scenes.md` in the
23
+ logger repository. This is an API experiment,
24
24
  not a replacement for the production weather/solar panels yet.