@tx5dr/plugin-api 2.0.0 → 2.5.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 (163) hide show
  1. package/README.md +201 -0
  2. package/dist/__tests__/adif.test.js +67 -0
  3. package/dist/__tests__/adif.test.js.map +1 -1
  4. package/dist/__tests__/testing-utils.test.js +17 -0
  5. package/dist/__tests__/testing-utils.test.js.map +1 -1
  6. package/dist/capabilities.d.ts +2 -1
  7. package/dist/capabilities.d.ts.map +1 -1
  8. package/dist/capabilities.js +2 -0
  9. package/dist/capabilities.js.map +1 -1
  10. package/dist/compatibility.d.ts +15 -0
  11. package/dist/compatibility.d.ts.map +1 -0
  12. package/dist/compatibility.js +71 -0
  13. package/dist/compatibility.js.map +1 -0
  14. package/dist/contest-logbook-ui/assets/contest-log.css +1 -0
  15. package/dist/contest-logbook-ui/assets/contest-log.js +40 -0
  16. package/dist/contest-logbook-ui/contest-log.html +13 -0
  17. package/dist/context.d.ts +39 -7
  18. package/dist/context.d.ts.map +1 -1
  19. package/dist/definition.d.ts +25 -1
  20. package/dist/definition.d.ts.map +1 -1
  21. package/dist/definition.js.map +1 -1
  22. package/dist/ft8/StandardQSOPluginRuntime.d.ts +142 -0
  23. package/dist/ft8/StandardQSOPluginRuntime.d.ts.map +1 -0
  24. package/dist/ft8/StandardQSOPluginRuntime.js +1592 -0
  25. package/dist/ft8/StandardQSOPluginRuntime.js.map +1 -0
  26. package/dist/ft8/index.d.ts +22 -0
  27. package/dist/ft8/index.d.ts.map +1 -0
  28. package/dist/ft8/index.js +176 -0
  29. package/dist/ft8/index.js.map +1 -0
  30. package/dist/helpers.d.ts +95 -3
  31. package/dist/helpers.d.ts.map +1 -1
  32. package/dist/hooks.d.ts +2 -0
  33. package/dist/hooks.d.ts.map +1 -1
  34. package/dist/index.d.ts +13 -3
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +7 -0
  37. package/dist/index.js.map +1 -1
  38. package/dist/runtime.d.ts +377 -6
  39. package/dist/runtime.d.ts.map +1 -1
  40. package/dist/runtime.js.map +1 -1
  41. package/dist/simulation.d.ts +60 -0
  42. package/dist/simulation.d.ts.map +1 -0
  43. package/dist/simulation.js +2 -0
  44. package/dist/simulation.js.map +1 -0
  45. package/dist/testing/index.d.ts +5 -1
  46. package/dist/testing/index.d.ts.map +1 -1
  47. package/dist/testing/index.js +67 -2
  48. package/dist/testing/index.js.map +1 -1
  49. package/dist/toolkit/contest/CabrilloBuilder.d.ts +7 -0
  50. package/dist/toolkit/contest/CabrilloBuilder.d.ts.map +1 -0
  51. package/dist/toolkit/contest/CabrilloBuilder.js +11 -0
  52. package/dist/toolkit/contest/CabrilloBuilder.js.map +1 -0
  53. package/dist/toolkit/contest/ContestCategorySchema.d.ts +11 -0
  54. package/dist/toolkit/contest/ContestCategorySchema.d.ts.map +1 -0
  55. package/dist/toolkit/contest/ContestCategorySchema.js +6 -0
  56. package/dist/toolkit/contest/ContestCategorySchema.js.map +1 -0
  57. package/dist/toolkit/contest/ContestLogbook.d.ts +223 -0
  58. package/dist/toolkit/contest/ContestLogbook.d.ts.map +1 -0
  59. package/dist/toolkit/contest/ContestLogbook.js +845 -0
  60. package/dist/toolkit/contest/ContestLogbook.js.map +1 -0
  61. package/dist/toolkit/contest/ContestQsoEnvelopeAdapter.d.ts +28 -0
  62. package/dist/toolkit/contest/ContestQsoEnvelopeAdapter.d.ts.map +1 -0
  63. package/dist/toolkit/contest/ContestQsoEnvelopeAdapter.js +79 -0
  64. package/dist/toolkit/contest/ContestQsoEnvelopeAdapter.js.map +1 -0
  65. package/dist/toolkit/contest/ContestQsoProjector.d.ts +12 -0
  66. package/dist/toolkit/contest/ContestQsoProjector.d.ts.map +1 -0
  67. package/dist/toolkit/contest/ContestQsoProjector.js +13 -0
  68. package/dist/toolkit/contest/ContestQsoProjector.js.map +1 -0
  69. package/dist/toolkit/contest/ContestSessionNotifier.d.ts +9 -0
  70. package/dist/toolkit/contest/ContestSessionNotifier.d.ts.map +1 -0
  71. package/dist/toolkit/contest/ContestSessionNotifier.js +13 -0
  72. package/dist/toolkit/contest/ContestSessionNotifier.js.map +1 -0
  73. package/dist/toolkit/contest/ContestSessionRepository.d.ts +21 -0
  74. package/dist/toolkit/contest/ContestSessionRepository.d.ts.map +1 -0
  75. package/dist/toolkit/contest/ContestSessionRepository.js +27 -0
  76. package/dist/toolkit/contest/ContestSessionRepository.js.map +1 -0
  77. package/dist/toolkit/contest/DefaultContestSession.d.ts +105 -0
  78. package/dist/toolkit/contest/DefaultContestSession.d.ts.map +1 -0
  79. package/dist/toolkit/contest/DefaultContestSession.js +387 -0
  80. package/dist/toolkit/contest/DefaultContestSession.js.map +1 -0
  81. package/dist/toolkit/contest/DefaultContestWorkbench.d.ts +100 -0
  82. package/dist/toolkit/contest/DefaultContestWorkbench.d.ts.map +1 -0
  83. package/dist/toolkit/contest/DefaultContestWorkbench.js +33 -0
  84. package/dist/toolkit/contest/DefaultContestWorkbench.js.map +1 -0
  85. package/dist/toolkit/contest/FT8ContestDefinition.d.ts +83 -0
  86. package/dist/toolkit/contest/FT8ContestDefinition.d.ts.map +1 -0
  87. package/dist/toolkit/contest/FT8ContestDefinition.js +167 -0
  88. package/dist/toolkit/contest/FT8ContestDefinition.js.map +1 -0
  89. package/dist/toolkit/contest/FT8ContestModules.d.ts +178 -0
  90. package/dist/toolkit/contest/FT8ContestModules.d.ts.map +1 -0
  91. package/dist/toolkit/contest/FT8ContestModules.js +247 -0
  92. package/dist/toolkit/contest/FT8ContestModules.js.map +1 -0
  93. package/dist/toolkit/contest/FT8ContestPlugin.d.ts +55 -0
  94. package/dist/toolkit/contest/FT8ContestPlugin.d.ts.map +1 -0
  95. package/dist/toolkit/contest/FT8ContestPlugin.js +322 -0
  96. package/dist/toolkit/contest/FT8ContestPlugin.js.map +1 -0
  97. package/dist/toolkit/contest/FT8ContestTestKit.d.ts +12 -0
  98. package/dist/toolkit/contest/FT8ContestTestKit.d.ts.map +1 -0
  99. package/dist/toolkit/contest/FT8ContestTestKit.js +60 -0
  100. package/dist/toolkit/contest/FT8ContestTestKit.js.map +1 -0
  101. package/dist/toolkit/contest/contest-toolkit.test.d.ts +2 -0
  102. package/dist/toolkit/contest/contest-toolkit.test.d.ts.map +1 -0
  103. package/dist/toolkit/contest/contest-toolkit.test.js +1196 -0
  104. package/dist/toolkit/contest/contest-toolkit.test.js.map +1 -0
  105. package/dist/toolkit/contest/index.d.ts +14 -0
  106. package/dist/toolkit/contest/index.d.ts.map +1 -0
  107. package/dist/toolkit/contest/index.js +14 -0
  108. package/dist/toolkit/contest/index.js.map +1 -0
  109. package/dist/toolkit/index.d.ts +3 -0
  110. package/dist/toolkit/index.d.ts.map +1 -0
  111. package/dist/toolkit/index.js +3 -0
  112. package/dist/toolkit/index.js.map +1 -0
  113. package/dist/toolkit/parallel-qso/AuthorizationLease.d.ts +15 -0
  114. package/dist/toolkit/parallel-qso/AuthorizationLease.d.ts.map +1 -0
  115. package/dist/toolkit/parallel-qso/AuthorizationLease.js +25 -0
  116. package/dist/toolkit/parallel-qso/AuthorizationLease.js.map +1 -0
  117. package/dist/toolkit/parallel-qso/BoundedCallSessionController.d.ts +40 -0
  118. package/dist/toolkit/parallel-qso/BoundedCallSessionController.d.ts.map +1 -0
  119. package/dist/toolkit/parallel-qso/BoundedCallSessionController.js +81 -0
  120. package/dist/toolkit/parallel-qso/BoundedCallSessionController.js.map +1 -0
  121. package/dist/toolkit/parallel-qso/BoundedCallSessionController.test.d.ts +2 -0
  122. package/dist/toolkit/parallel-qso/BoundedCallSessionController.test.d.ts.map +1 -0
  123. package/dist/toolkit/parallel-qso/BoundedCallSessionController.test.js +31 -0
  124. package/dist/toolkit/parallel-qso/BoundedCallSessionController.test.js.map +1 -0
  125. package/dist/toolkit/parallel-qso/CompletionTracker.d.ts +20 -0
  126. package/dist/toolkit/parallel-qso/CompletionTracker.d.ts.map +1 -0
  127. package/dist/toolkit/parallel-qso/CompletionTracker.js +20 -0
  128. package/dist/toolkit/parallel-qso/CompletionTracker.js.map +1 -0
  129. package/dist/toolkit/parallel-qso/LaneFrequencyController.d.ts +19 -0
  130. package/dist/toolkit/parallel-qso/LaneFrequencyController.d.ts.map +1 -0
  131. package/dist/toolkit/parallel-qso/LaneFrequencyController.js +23 -0
  132. package/dist/toolkit/parallel-qso/LaneFrequencyController.js.map +1 -0
  133. package/dist/toolkit/parallel-qso/ParallelQSOCoordinator.d.ts +134 -0
  134. package/dist/toolkit/parallel-qso/ParallelQSOCoordinator.d.ts.map +1 -0
  135. package/dist/toolkit/parallel-qso/ParallelQSOCoordinator.js +554 -0
  136. package/dist/toolkit/parallel-qso/ParallelQSOCoordinator.js.map +1 -0
  137. package/dist/toolkit/parallel-qso/ParallelQSOCoordinator.test.d.ts +2 -0
  138. package/dist/toolkit/parallel-qso/ParallelQSOCoordinator.test.d.ts.map +1 -0
  139. package/dist/toolkit/parallel-qso/ParallelQSOCoordinator.test.js +470 -0
  140. package/dist/toolkit/parallel-qso/ParallelQSOCoordinator.test.js.map +1 -0
  141. package/dist/toolkit/parallel-qso/PostCompletionRecoveryLease.d.ts +20 -0
  142. package/dist/toolkit/parallel-qso/PostCompletionRecoveryLease.d.ts.map +1 -0
  143. package/dist/toolkit/parallel-qso/PostCompletionRecoveryLease.js +29 -0
  144. package/dist/toolkit/parallel-qso/PostCompletionRecoveryLease.js.map +1 -0
  145. package/dist/toolkit/parallel-qso/ProtocolLane.d.ts +50 -0
  146. package/dist/toolkit/parallel-qso/ProtocolLane.d.ts.map +1 -0
  147. package/dist/toolkit/parallel-qso/ProtocolLane.js +2 -0
  148. package/dist/toolkit/parallel-qso/ProtocolLane.js.map +1 -0
  149. package/dist/toolkit/parallel-qso/controllers.test.d.ts +2 -0
  150. package/dist/toolkit/parallel-qso/controllers.test.d.ts.map +1 -0
  151. package/dist/toolkit/parallel-qso/controllers.test.js +36 -0
  152. package/dist/toolkit/parallel-qso/controllers.test.js.map +1 -0
  153. package/dist/toolkit/parallel-qso/index.d.ts +8 -0
  154. package/dist/toolkit/parallel-qso/index.d.ts.map +1 -0
  155. package/dist/toolkit/parallel-qso/index.js +8 -0
  156. package/dist/toolkit/parallel-qso/index.js.map +1 -0
  157. package/dist/utils/adif.d.ts +1 -1
  158. package/dist/utils/adif.d.ts.map +1 -1
  159. package/dist/utils/adif.js +91 -50
  160. package/dist/utils/adif.js.map +1 -1
  161. package/package.json +27 -5
  162. package/src/bridge.d.ts +3 -0
  163. package/tokens.css +51 -0
@@ -0,0 +1,167 @@
1
+ import { oncePerBand } from './FT8ContestModules.js';
2
+ function toIso(value, field) {
3
+ const date = value instanceof Date ? value : new Date(value);
4
+ if (!Number.isFinite(date.getTime()))
5
+ throw new Error(`contest_edition_invalid_${field}`);
6
+ return date.toISOString();
7
+ }
8
+ /** Defines one fixed contest occurrence; the name reflects the common weekend format. */
9
+ export function fixedWeekendEdition(input) {
10
+ const startAt = toIso(input.startAt, 'start');
11
+ const endAt = toIso(input.endAt, 'end');
12
+ if (new Date(endAt).getTime() <= new Date(startAt).getTime()) {
13
+ throw new Error('contest_edition_invalid_range');
14
+ }
15
+ if (!input.id.trim())
16
+ throw new Error('contest_edition_id_required');
17
+ return Object.freeze({
18
+ id: input.id.trim(),
19
+ startAt,
20
+ endAt,
21
+ source: input.source ? Object.freeze({ ...input.source }) : undefined,
22
+ });
23
+ }
24
+ const SAFE_OPERATING_DEFAULTS = {
25
+ humanInitiation: 'required',
26
+ maxConcurrentQsos: 1,
27
+ maxSimultaneousSignals: 1,
28
+ cycleRelation: 'single',
29
+ };
30
+ const HOST_MAX_CONTEST_STREAMS = 5;
31
+ function snapshotExchangeModule(module) {
32
+ return Object.freeze({
33
+ id: module.id,
34
+ decode: module.decode.bind(module),
35
+ encode: module.encode.bind(module),
36
+ validate: module.validate.bind(module),
37
+ });
38
+ }
39
+ function snapshotCompletionModule(module) {
40
+ return Object.freeze({ id: module.id, evaluate: module.evaluate.bind(module) });
41
+ }
42
+ function snapshotDupeModule(module) {
43
+ return Object.freeze({ id: module.id, scope: module.scope, key: module.key.bind(module) });
44
+ }
45
+ function snapshotScoringModule(module) {
46
+ return Object.freeze({
47
+ id: module.id,
48
+ score: module.score.bind(module),
49
+ aggregate: module.aggregate.bind(module),
50
+ });
51
+ }
52
+ function snapshotSubmissionModule(module) {
53
+ return Object.freeze({
54
+ id: module.id,
55
+ mediaType: module.mediaType,
56
+ extension: module.extension,
57
+ format: module.format.bind(module),
58
+ });
59
+ }
60
+ /**
61
+ * Composes public rule modules into a normalized FT8/FT4 contest definition.
62
+ * It performs no Host registration and every supplied module remains replaceable.
63
+ */
64
+ export function defineFT8Contest(input) {
65
+ const id = input.id.trim();
66
+ const rulesetVersion = input.rulesetVersion.trim();
67
+ if (!id)
68
+ throw new Error('contest_id_required');
69
+ if (!rulesetVersion)
70
+ throw new Error('contest_ruleset_version_required');
71
+ const edition = fixedWeekendEdition(input.edition);
72
+ const modes = [...new Set(input.modes ?? ['FT8'])];
73
+ const bands = [...new Set(input.bands.map((band) => band.trim().toUpperCase()).filter(Boolean))];
74
+ if (modes.length === 0)
75
+ throw new Error('contest_modes_required');
76
+ if (bands.length === 0)
77
+ throw new Error('contest_bands_required');
78
+ const operating = { ...SAFE_OPERATING_DEFAULTS, ...input.operating };
79
+ if (!Number.isInteger(operating.maxConcurrentQsos)
80
+ || operating.maxConcurrentQsos < 1
81
+ || operating.maxConcurrentQsos > HOST_MAX_CONTEST_STREAMS) {
82
+ throw new Error('contest_operating_invalid_concurrent_qsos');
83
+ }
84
+ if (!Number.isInteger(operating.maxSimultaneousSignals)
85
+ || operating.maxSimultaneousSignals < 1
86
+ || operating.maxSimultaneousSignals > HOST_MAX_CONTEST_STREAMS
87
+ || operating.maxSimultaneousSignals > operating.maxConcurrentQsos) {
88
+ throw new Error('contest_operating_invalid_simultaneous_signals');
89
+ }
90
+ return Object.freeze({
91
+ ...input,
92
+ id,
93
+ rulesetVersion,
94
+ edition,
95
+ modes: Object.freeze(modes),
96
+ bands: Object.freeze(bands),
97
+ exchange: snapshotExchangeModule(input.exchange),
98
+ completion: snapshotCompletionModule(input.completion),
99
+ dupe: snapshotDupeModule(input.dupe ?? oncePerBand()),
100
+ scoring: snapshotScoringModule(input.scoring),
101
+ submission: snapshotSubmissionModule(input.submission),
102
+ operating: Object.freeze(operating),
103
+ });
104
+ }
105
+ /** Applies the common edition/mode/band/status/dupe envelope once for score and export. */
106
+ export function projectFT8ContestQsos(contest, records) {
107
+ const start = Date.parse(contest.edition.startAt);
108
+ const end = Date.parse(contest.edition.endAt);
109
+ const modes = new Set(contest.modes);
110
+ const bands = new Set(contest.bands.map((band) => band.toUpperCase()));
111
+ const worked = new Set();
112
+ return records
113
+ .map((qso, index) => ({ qso, index }))
114
+ .sort((left, right) => left.qso.startTime - right.qso.startTime || left.index - right.index)
115
+ .map(({ qso }) => {
116
+ const issues = [];
117
+ const band = qso.band.trim().toUpperCase();
118
+ const baseEligible = Number.isFinite(qso.startTime)
119
+ && qso.startTime >= start
120
+ && qso.startTime < end
121
+ && modes.has(qso.mode)
122
+ && bands.has(band);
123
+ if (!Number.isFinite(qso.startTime) || qso.startTime < start || qso.startTime >= end) {
124
+ issues.push('outside_edition');
125
+ }
126
+ if (!modes.has(qso.mode))
127
+ issues.push('unsupported_mode');
128
+ if (!bands.has(band))
129
+ issues.push('unsupported_band');
130
+ const status = qso.status ?? 'included';
131
+ if (status === 'review')
132
+ issues.push('review');
133
+ if (status === 'excluded')
134
+ issues.push('excluded');
135
+ if (status === 'x-qso')
136
+ issues.push('x_qso');
137
+ const key = contest.dupe.key(qso);
138
+ const countsAsWorked = baseEligible && (status === 'included' || status === 'review');
139
+ const dupe = countsAsWorked && worked.has(key);
140
+ if (dupe)
141
+ issues.push('dupe');
142
+ if (countsAsWorked)
143
+ worked.add(key);
144
+ const scoreEligible = baseEligible && status === 'included' && !dupe;
145
+ return {
146
+ qso,
147
+ dupe,
148
+ issues,
149
+ eligible: scoreEligible,
150
+ scoreEligible,
151
+ submissionEligible: baseEligible && (status === 'included' || status === 'x-qso'),
152
+ };
153
+ });
154
+ }
155
+ export function scoreFT8ContestQsos(contest, records) {
156
+ const scores = projectFT8ContestQsos(contest, records)
157
+ .filter((row) => row.scoreEligible)
158
+ .map((row) => contest.scoring.score(row.qso));
159
+ return contest.scoring.aggregate(scores);
160
+ }
161
+ export function formatFT8ContestSubmission(contest, records, options) {
162
+ const eligible = projectFT8ContestQsos(contest, records)
163
+ .filter((row) => row.submissionEligible)
164
+ .map((row) => row.qso);
165
+ return contest.submission.format(eligible, options);
166
+ }
167
+ //# sourceMappingURL=FT8ContestDefinition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FT8ContestDefinition.js","sourceRoot":"","sources":["../../../src/toolkit/contest/FT8ContestDefinition.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,178 @@
1
+ import { type CabrilloDocumentInput } from './CabrilloBuilder.js';
2
+ /** Modes currently covered by the FT8 contest composition API. */
3
+ export type FT8ContestMode = 'FT8' | 'FT4';
4
+ /** Flat exchange fields suitable for a contest QSO envelope or submission adapter. */
5
+ export type ContestExchangeFields = Readonly<Record<string, string>>;
6
+ export interface ContestValidationIssue {
7
+ code: string;
8
+ field?: string;
9
+ message?: string;
10
+ }
11
+ export type FT8ExchangeDecodeResult<TExchange> = {
12
+ ok: true;
13
+ value: TExchange;
14
+ } | {
15
+ ok: false;
16
+ issues: readonly ContestValidationIssue[];
17
+ };
18
+ /** Converts between typed contest exchange data and flat persisted fields. */
19
+ export interface FT8ExchangeModule<TExchange> {
20
+ readonly id: string;
21
+ decode(fields: ContestExchangeFields): FT8ExchangeDecodeResult<TExchange>;
22
+ encode(exchange: TExchange): ContestExchangeFields;
23
+ validate(exchange: TExchange): readonly ContestValidationIssue[];
24
+ }
25
+ export declare function defineFT8ExchangeModule<TExchange>(module: FT8ExchangeModule<TExchange>): FT8ExchangeModule<TExchange>;
26
+ export interface GridExchange {
27
+ grid: string;
28
+ }
29
+ export interface GridAndSnrExchange extends GridExchange {
30
+ snr: number;
31
+ }
32
+ export interface GridExchangeOptions {
33
+ /** Value used when an imported exchange has no grid. Omit to reject it. */
34
+ missingGrid?: string;
35
+ }
36
+ /** Common four-character Maidenhead exchange. */
37
+ export declare function gridExchange(options?: GridExchangeOptions): FT8ExchangeModule<GridExchange>;
38
+ /** Four-character Maidenhead plus an integer signal report. */
39
+ export declare function gridAndSnrExchange(options?: GridExchangeOptions): FT8ExchangeModule<GridAndSnrExchange>;
40
+ export interface CompletionEvidence<TExchange> {
41
+ sentExchange?: TExchange;
42
+ receivedExchange?: TExchange;
43
+ sentFinalAck?: boolean;
44
+ receivedFinalAck?: boolean;
45
+ }
46
+ export interface CompletionEvaluation {
47
+ complete: boolean;
48
+ missing: readonly string[];
49
+ }
50
+ /** Pure completion policy. It never keys the radio or mutates Host state. */
51
+ export interface CompletionModule<TExchange> {
52
+ readonly id: string;
53
+ evaluate(evidence: CompletionEvidence<TExchange>): CompletionEvaluation;
54
+ }
55
+ export declare function defineCompletionModule<TExchange>(module: CompletionModule<TExchange>): CompletionModule<TExchange>;
56
+ export interface ExchangeAndFinalAckOptions {
57
+ exchange?: 'received' | 'both';
58
+ finalAck?: 'sent' | 'received' | 'either' | 'both';
59
+ }
60
+ /** Requires exchange evidence and an explicit final acknowledgement. */
61
+ export declare function requireExchangeAndFinalAck<TExchange>(options?: ExchangeAndFinalAckOptions): CompletionModule<TExchange>;
62
+ /** Minimal QSO shape used by common FT8 contest modules. Plugins may extend it. */
63
+ export interface FT8ContestQso<TExchange = unknown> {
64
+ callsign: string;
65
+ band: string;
66
+ mode: FT8ContestMode;
67
+ /** QSO start time used for edition eligibility. */
68
+ startTime: number;
69
+ /** Review/excluded records remain visible but are not scored or submitted. */
70
+ status?: 'included' | 'review' | 'excluded' | 'x-qso';
71
+ sentExchange?: TExchange;
72
+ receivedExchange?: TExchange;
73
+ distanceKm?: number;
74
+ }
75
+ /** Center-to-center Maidenhead distance shared by FT8 distance-scoring rules. */
76
+ export declare function maidenheadDistanceKm(fromGrid: string, toGrid: string): number | undefined;
77
+ export interface ContestSerialOptions<TRecord> {
78
+ serial(record: TRecord): string | number | undefined;
79
+ startAt?: number;
80
+ width?: number;
81
+ }
82
+ /**
83
+ * Allocates the next serial from a current QSO snapshot. Call this inside
84
+ * `ContestApplicationSessionFacade.transact()` so revision retries re-plan it.
85
+ */
86
+ export declare function nextContestSerial<TRecord>(records: readonly TRecord[], options: ContestSerialOptions<TRecord>): string;
87
+ export type DupeScope = 'band' | 'mode' | 'session' | 'contest';
88
+ export interface DupeModule<TQso> {
89
+ readonly id: string;
90
+ readonly scope: DupeScope;
91
+ key(qso: TQso): string;
92
+ }
93
+ export declare function defineDupeModule<TQso>(module: DupeModule<TQso>): DupeModule<TQso>;
94
+ export interface OncePerBandOptions {
95
+ /** Set true only when FT4 and FT8 are separate duplicate scopes. */
96
+ includeMode?: boolean;
97
+ }
98
+ /** Default FT contest duplicate policy: normalized callsign once per band. */
99
+ export declare function oncePerBand<TQso extends Pick<FT8ContestQso, 'callsign' | 'band' | 'mode'>>(options?: OncePerBandOptions): DupeModule<TQso>;
100
+ export interface ContestQsoScore {
101
+ points: number;
102
+ multiplierKeys: readonly string[];
103
+ eligible: boolean;
104
+ }
105
+ export interface ContestScoreSummary {
106
+ qsoCount: number;
107
+ qsoPoints: number;
108
+ multiplierCount: number;
109
+ total: number;
110
+ }
111
+ export interface ScoringModule<TQso> {
112
+ readonly id: string;
113
+ score(qso: TQso): ContestQsoScore;
114
+ aggregate(scores: readonly ContestQsoScore[]): ContestScoreSummary;
115
+ }
116
+ export declare function defineScoringModule<TQso>(module: ScoringModule<TQso>): ScoringModule<TQso>;
117
+ export interface ScoreByOptions<TQso> {
118
+ id: string;
119
+ points(qso: TQso): number;
120
+ eligible?(qso: TQso, points: number): boolean;
121
+ multiplierKeys?(qso: TQso): readonly string[];
122
+ aggregate?(scores: readonly ContestQsoScore[]): ContestScoreSummary;
123
+ }
124
+ /**
125
+ * Builds a scoring module from a point function and optional multiplier key extractor.
126
+ * Use this for contest families whose score is not covered by the canned distance helper.
127
+ */
128
+ export declare function scoreBy<TQso>(options: ScoreByOptions<TQso>): ScoringModule<TQso>;
129
+ export interface FixedPointsOptions<TQso> {
130
+ eligible?(qso: TQso): boolean;
131
+ multiplierKeys?(qso: TQso): readonly string[];
132
+ }
133
+ /** Convenience wrapper for contests that award a fixed number of points per QSO. */
134
+ export declare function fixedPoints<TQso>(points: number, options?: FixedPointsOptions<TQso>): ScoringModule<TQso>;
135
+ export interface DistancePointsOptions<TQso> {
136
+ stepKm: number;
137
+ rounding?: 'floor' | 'ceil';
138
+ basePoints?: number;
139
+ /** Minimum number of distance steps, used by rules that award one step for any valid QSO. */
140
+ minimumDistanceSteps?: number;
141
+ missingDistancePoints?: number;
142
+ distanceKm?: (qso: TQso) => number | undefined;
143
+ multiplierKeys?: (qso: TQso) => readonly string[];
144
+ }
145
+ /** Common distance-step scoring with optional multiplier aggregation. */
146
+ export declare function distancePoints<TQso extends {
147
+ distanceKm?: number;
148
+ } = FT8ContestQso>(options: DistancePointsOptions<TQso>): ScoringModule<TQso>;
149
+ export interface MultiplierKeysFromOptions<TQso> {
150
+ key(qso: TQso): string | undefined;
151
+ band?: (qso: TQso) => string | undefined;
152
+ normalize?(key: string): string;
153
+ }
154
+ /**
155
+ * Builds multiplier keys from one normalized field. Scope the key by band when
156
+ * the contest counts per-band multipliers; omit band to count once per contest.
157
+ */
158
+ export declare function multiplierKeysFrom<TQso>(options: MultiplierKeysFromOptions<TQso>): (qso: TQso) => readonly string[];
159
+ export interface GridFieldMultiplierOptions<TQso> {
160
+ grid(qso: TQso): string | undefined;
161
+ band?: (qso: TQso) => string | undefined;
162
+ }
163
+ /** Builds multiplier keys from the first two characters of a valid grid. */
164
+ export declare function gridFieldMultiplier<TQso>(options: GridFieldMultiplierOptions<TQso>): (qso: TQso) => readonly string[];
165
+ export interface SubmissionModule<TQso, TOptions = void> {
166
+ readonly id: string;
167
+ readonly mediaType: string;
168
+ readonly extension: string;
169
+ format(records: readonly TQso[], options: TOptions): string;
170
+ }
171
+ export declare function defineSubmissionModule<TQso, TOptions = void>(module: SubmissionModule<TQso, TOptions>): SubmissionModule<TQso, TOptions>;
172
+ export interface CabrilloSubmissionOptions<TQso, TOptions> {
173
+ headers(options: TOptions): CabrilloDocumentInput['headers'];
174
+ qsoLine(qso: TQso, options: TOptions): string;
175
+ }
176
+ /** Cabrillo adapter that leaves every contest-specific column with the plugin. */
177
+ export declare function cabrilloSubmission<TQso = FT8ContestQso, TOptions = void>(options: CabrilloSubmissionOptions<TQso, TOptions>): SubmissionModule<TQso, TOptions>;
178
+ //# sourceMappingURL=FT8ContestModules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FT8ContestModules.d.ts","sourceRoot":"","sources":["../../../src/toolkit/contest/FT8ContestModules.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,247 @@
1
+ import { normalizeCallsign } from '../../utils/callsign.js';
2
+ import { calculateGridDistance } from '@tx5dr/core';
3
+ import { buildCabrilloDocument } from './CabrilloBuilder.js';
4
+ export function defineFT8ExchangeModule(module) {
5
+ return module;
6
+ }
7
+ function normalizeGrid(grid) {
8
+ return grid.trim().toUpperCase();
9
+ }
10
+ function validateGrid(grid, allowedMissingGrid) {
11
+ const normalized = normalizeGrid(grid);
12
+ if (allowedMissingGrid && normalized === normalizeGrid(allowedMissingGrid))
13
+ return [];
14
+ if (!/^[A-R]{2}[0-9]{2}$/.test(normalized)) {
15
+ return [{ code: 'invalid_grid', field: 'grid' }];
16
+ }
17
+ return [];
18
+ }
19
+ /** Common four-character Maidenhead exchange. */
20
+ export function gridExchange(options = {}) {
21
+ return defineFT8ExchangeModule({
22
+ id: 'grid-4',
23
+ decode(fields) {
24
+ const grid = normalizeGrid(fields.grid ?? options.missingGrid ?? '');
25
+ const issues = validateGrid(grid, options.missingGrid);
26
+ return issues.length > 0 ? { ok: false, issues } : { ok: true, value: { grid } };
27
+ },
28
+ encode(exchange) {
29
+ return { grid: normalizeGrid(exchange.grid) };
30
+ },
31
+ validate(exchange) {
32
+ return validateGrid(exchange.grid, options.missingGrid);
33
+ },
34
+ });
35
+ }
36
+ /** Four-character Maidenhead plus an integer signal report. */
37
+ export function gridAndSnrExchange(options = {}) {
38
+ return defineFT8ExchangeModule({
39
+ id: 'grid-4-and-snr',
40
+ decode(fields) {
41
+ const grid = normalizeGrid(fields.grid ?? options.missingGrid ?? '');
42
+ const snrText = fields.snr?.trim() ?? '';
43
+ const snr = Number(snrText);
44
+ const issues = validateGrid(grid, options.missingGrid);
45
+ if (snrText === '' || !Number.isInteger(snr)) {
46
+ issues.push({ code: 'invalid_snr', field: 'snr' });
47
+ }
48
+ return issues.length > 0 ? { ok: false, issues } : { ok: true, value: { grid, snr } };
49
+ },
50
+ encode(exchange) {
51
+ return { grid: normalizeGrid(exchange.grid), snr: String(exchange.snr) };
52
+ },
53
+ validate(exchange) {
54
+ const issues = validateGrid(exchange.grid, options.missingGrid);
55
+ if (!Number.isInteger(exchange.snr))
56
+ issues.push({ code: 'invalid_snr', field: 'snr' });
57
+ return issues;
58
+ },
59
+ });
60
+ }
61
+ export function defineCompletionModule(module) {
62
+ return module;
63
+ }
64
+ /** Requires exchange evidence and an explicit final acknowledgement. */
65
+ export function requireExchangeAndFinalAck(options = {}) {
66
+ const exchange = options.exchange ?? 'both';
67
+ const finalAck = options.finalAck ?? 'either';
68
+ return {
69
+ id: `exchange-${exchange}-final-ack-${finalAck}`,
70
+ evaluate(evidence) {
71
+ const missing = [];
72
+ if (!evidence.receivedExchange)
73
+ missing.push('received_exchange');
74
+ if (exchange === 'both' && !evidence.sentExchange)
75
+ missing.push('sent_exchange');
76
+ if (finalAck === 'sent' && !evidence.sentFinalAck)
77
+ missing.push('sent_final_ack');
78
+ if (finalAck === 'received' && !evidence.receivedFinalAck)
79
+ missing.push('received_final_ack');
80
+ if (finalAck === 'either' && !evidence.sentFinalAck && !evidence.receivedFinalAck) {
81
+ missing.push('final_ack');
82
+ }
83
+ if (finalAck === 'both') {
84
+ if (!evidence.sentFinalAck)
85
+ missing.push('sent_final_ack');
86
+ if (!evidence.receivedFinalAck)
87
+ missing.push('received_final_ack');
88
+ }
89
+ return { complete: missing.length === 0, missing };
90
+ },
91
+ };
92
+ }
93
+ /** Center-to-center Maidenhead distance shared by FT8 distance-scoring rules. */
94
+ export function maidenheadDistanceKm(fromGrid, toGrid) {
95
+ return calculateGridDistance(fromGrid, toGrid) ?? undefined;
96
+ }
97
+ /**
98
+ * Allocates the next serial from a current QSO snapshot. Call this inside
99
+ * `ContestApplicationSessionFacade.transact()` so revision retries re-plan it.
100
+ */
101
+ export function nextContestSerial(records, options) {
102
+ const startAt = options.startAt ?? 1;
103
+ const width = options.width ?? 3;
104
+ if (!Number.isInteger(startAt) || startAt < 1 || !Number.isInteger(width) || width < 1 || width > 9) {
105
+ throw new Error('contest_serial_invalid_options');
106
+ }
107
+ let maximum = startAt - 1;
108
+ for (const record of records) {
109
+ const value = options.serial(record);
110
+ const text = typeof value === 'number' ? String(value) : value?.trim();
111
+ if (!text || !/^\d+$/.test(text))
112
+ continue;
113
+ const serial = Number(text);
114
+ if (Number.isSafeInteger(serial) && serial >= startAt)
115
+ maximum = Math.max(maximum, serial);
116
+ }
117
+ return String(maximum + 1).padStart(width, '0');
118
+ }
119
+ export function defineDupeModule(module) {
120
+ return module;
121
+ }
122
+ /** Default FT contest duplicate policy: normalized callsign once per band. */
123
+ export function oncePerBand(options = {}) {
124
+ return defineDupeModule({
125
+ id: options.includeMode ? 'callsign-band-mode' : 'callsign-band',
126
+ scope: options.includeMode ? 'mode' : 'band',
127
+ key(qso) {
128
+ const parts = [normalizeCallsign(qso.callsign), qso.band.trim().toUpperCase()];
129
+ if (options.includeMode)
130
+ parts.push(qso.mode);
131
+ return parts.join(':');
132
+ },
133
+ });
134
+ }
135
+ export function defineScoringModule(module) {
136
+ return module;
137
+ }
138
+ function aggregateContestScores(scores) {
139
+ const eligible = scores.filter((score) => score.eligible);
140
+ const qsoPoints = eligible.reduce((sum, score) => sum + score.points, 0);
141
+ const multiplierCount = new Set(eligible.flatMap((score) => score.multiplierKeys)).size;
142
+ return {
143
+ qsoCount: eligible.length,
144
+ qsoPoints,
145
+ multiplierCount,
146
+ total: multiplierCount > 0 ? qsoPoints * multiplierCount : qsoPoints,
147
+ };
148
+ }
149
+ /**
150
+ * Builds a scoring module from a point function and optional multiplier key extractor.
151
+ * Use this for contest families whose score is not covered by the canned distance helper.
152
+ */
153
+ export function scoreBy(options) {
154
+ const aggregate = options.aggregate ?? aggregateContestScores;
155
+ return defineScoringModule({
156
+ id: options.id.trim(),
157
+ score(qso) {
158
+ const points = options.points(qso);
159
+ return {
160
+ points,
161
+ multiplierKeys: options.multiplierKeys?.(qso) ?? [],
162
+ eligible: options.eligible?.(qso, points) ?? points > 0,
163
+ };
164
+ },
165
+ aggregate,
166
+ });
167
+ }
168
+ /** Convenience wrapper for contests that award a fixed number of points per QSO. */
169
+ export function fixedPoints(points, options = {}) {
170
+ if (!Number.isFinite(points))
171
+ throw new Error('contest_scoring_invalid_points');
172
+ return scoreBy({
173
+ id: `fixed-${points}`,
174
+ points: () => points,
175
+ eligible: options.eligible ?? (() => true),
176
+ multiplierKeys: options.multiplierKeys,
177
+ });
178
+ }
179
+ /** Common distance-step scoring with optional multiplier aggregation. */
180
+ export function distancePoints(options) {
181
+ if (!Number.isFinite(options.stepKm) || options.stepKm <= 0) {
182
+ throw new Error('contest_scoring_invalid_step_km');
183
+ }
184
+ const basePoints = options.basePoints ?? 1;
185
+ const minimumDistanceSteps = options.minimumDistanceSteps ?? 0;
186
+ if (!Number.isInteger(minimumDistanceSteps) || minimumDistanceSteps < 0) {
187
+ throw new Error('contest_scoring_invalid_minimum_distance_steps');
188
+ }
189
+ const rounding = options.rounding ?? 'floor';
190
+ const round = rounding === 'ceil' ? Math.ceil : Math.floor;
191
+ return scoreBy({
192
+ id: `distance-${rounding}-${options.stepKm}`,
193
+ points(qso) {
194
+ const distanceKm = options.distanceKm?.(qso) ?? qso.distanceKm;
195
+ return distanceKm === undefined || !Number.isFinite(distanceKm) || distanceKm < 0
196
+ ? options.missingDistancePoints ?? 0
197
+ : basePoints + Math.max(minimumDistanceSteps, round(distanceKm / options.stepKm));
198
+ },
199
+ eligible(_qso, points) {
200
+ return points > 0;
201
+ },
202
+ multiplierKeys: options.multiplierKeys,
203
+ });
204
+ }
205
+ /**
206
+ * Builds multiplier keys from one normalized field. Scope the key by band when
207
+ * the contest counts per-band multipliers; omit band to count once per contest.
208
+ */
209
+ export function multiplierKeysFrom(options) {
210
+ return (qso) => {
211
+ const raw = options.key(qso)?.trim();
212
+ if (!raw)
213
+ return [];
214
+ const key = (options.normalize ?? ((value) => value.toUpperCase()))(raw);
215
+ const band = options.band?.(qso)?.trim().toUpperCase();
216
+ return [band ? `${band}:${key}` : key];
217
+ };
218
+ }
219
+ /** Builds multiplier keys from the first two characters of a valid grid. */
220
+ export function gridFieldMultiplier(options) {
221
+ return multiplierKeysFrom({
222
+ key(qso) {
223
+ const grid = normalizeGrid(options.grid(qso) ?? '');
224
+ return /^[A-R]{2}[0-9]{2}$/.test(grid) ? grid.slice(0, 2) : undefined;
225
+ },
226
+ band: options.band,
227
+ normalize: (value) => value.toUpperCase(),
228
+ });
229
+ }
230
+ export function defineSubmissionModule(module) {
231
+ return module;
232
+ }
233
+ /** Cabrillo adapter that leaves every contest-specific column with the plugin. */
234
+ export function cabrilloSubmission(options) {
235
+ return defineSubmissionModule({
236
+ id: 'cabrillo-3',
237
+ mediaType: 'text/plain',
238
+ extension: '.log',
239
+ format(records, formatOptions) {
240
+ return buildCabrilloDocument({
241
+ headers: options.headers(formatOptions),
242
+ qsoLines: records.map((record) => options.qsoLine(record, formatOptions)),
243
+ });
244
+ },
245
+ });
246
+ }
247
+ //# sourceMappingURL=FT8ContestModules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FT8ContestModules.js","sourceRoot":"","sources":["../../../src/toolkit/contest/FT8ContestModules.ts"],"names":[],"mappings":"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"}