@tx5dr/plugin-api 1.7.12 → 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.
- package/README.md +475 -17
- package/dist/__tests__/adif.test.js +107 -0
- package/dist/__tests__/adif.test.js.map +1 -1
- package/dist/__tests__/capability-context.test.d.ts +2 -0
- package/dist/__tests__/capability-context.test.d.ts.map +1 -0
- package/dist/__tests__/capability-context.test.js +99 -0
- package/dist/__tests__/capability-context.test.js.map +1 -0
- package/dist/__tests__/testing-utils.test.js +234 -15
- package/dist/__tests__/testing-utils.test.js.map +1 -1
- package/dist/capabilities.d.ts +38 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +50 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/compatibility.d.ts +15 -0
- package/dist/compatibility.d.ts.map +1 -0
- package/dist/compatibility.js +71 -0
- package/dist/compatibility.js.map +1 -0
- package/dist/contest-logbook-ui/assets/contest-log.css +1 -0
- package/dist/contest-logbook-ui/assets/contest-log.js +40 -0
- package/dist/contest-logbook-ui/contest-log.html +13 -0
- package/dist/context.d.ts +125 -54
- package/dist/context.d.ts.map +1 -1
- package/dist/definition.d.ts +98 -21
- package/dist/definition.d.ts.map +1 -1
- package/dist/definition.js +8 -1
- package/dist/definition.js.map +1 -1
- package/dist/ft8/StandardQSOPluginRuntime.d.ts +142 -0
- package/dist/ft8/StandardQSOPluginRuntime.d.ts.map +1 -0
- package/dist/ft8/StandardQSOPluginRuntime.js +1592 -0
- package/dist/ft8/StandardQSOPluginRuntime.js.map +1 -0
- package/dist/ft8/index.d.ts +22 -0
- package/dist/ft8/index.d.ts.map +1 -0
- package/dist/ft8/index.js +176 -0
- package/dist/ft8/index.js.map +1 -0
- package/dist/helpers.d.ts +417 -132
- package/dist/helpers.d.ts.map +1 -1
- package/dist/hooks.d.ts +56 -34
- package/dist/hooks.d.ts.map +1 -1
- package/dist/host-dependencies.d.ts +101 -0
- package/dist/host-dependencies.d.ts.map +1 -1
- package/dist/index.d.ts +20 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -1
- package/dist/index.js.map +1 -1
- package/dist/runtime.d.ts +539 -13
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +9 -1
- package/dist/runtime.js.map +1 -1
- package/dist/settings.d.ts +31 -0
- package/dist/settings.d.ts.map +1 -1
- package/dist/simulation.d.ts +60 -0
- package/dist/simulation.d.ts.map +1 -0
- package/dist/simulation.js +2 -0
- package/dist/simulation.js.map +1 -0
- package/dist/sync.d.ts +98 -6
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +6 -0
- package/dist/sync.js.map +1 -1
- package/dist/testing/index.d.ts +74 -12
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +372 -105
- package/dist/testing/index.js.map +1 -1
- package/dist/toolkit/contest/CabrilloBuilder.d.ts +7 -0
- package/dist/toolkit/contest/CabrilloBuilder.d.ts.map +1 -0
- package/dist/toolkit/contest/CabrilloBuilder.js +11 -0
- package/dist/toolkit/contest/CabrilloBuilder.js.map +1 -0
- package/dist/toolkit/contest/ContestCategorySchema.d.ts +11 -0
- package/dist/toolkit/contest/ContestCategorySchema.d.ts.map +1 -0
- package/dist/toolkit/contest/ContestCategorySchema.js +6 -0
- package/dist/toolkit/contest/ContestCategorySchema.js.map +1 -0
- package/dist/toolkit/contest/ContestLogbook.d.ts +223 -0
- package/dist/toolkit/contest/ContestLogbook.d.ts.map +1 -0
- package/dist/toolkit/contest/ContestLogbook.js +845 -0
- package/dist/toolkit/contest/ContestLogbook.js.map +1 -0
- package/dist/toolkit/contest/ContestQsoEnvelopeAdapter.d.ts +28 -0
- package/dist/toolkit/contest/ContestQsoEnvelopeAdapter.d.ts.map +1 -0
- package/dist/toolkit/contest/ContestQsoEnvelopeAdapter.js +79 -0
- package/dist/toolkit/contest/ContestQsoEnvelopeAdapter.js.map +1 -0
- package/dist/toolkit/contest/ContestQsoProjector.d.ts +12 -0
- package/dist/toolkit/contest/ContestQsoProjector.d.ts.map +1 -0
- package/dist/toolkit/contest/ContestQsoProjector.js +13 -0
- package/dist/toolkit/contest/ContestQsoProjector.js.map +1 -0
- package/dist/toolkit/contest/ContestSessionNotifier.d.ts +9 -0
- package/dist/toolkit/contest/ContestSessionNotifier.d.ts.map +1 -0
- package/dist/toolkit/contest/ContestSessionNotifier.js +13 -0
- package/dist/toolkit/contest/ContestSessionNotifier.js.map +1 -0
- package/dist/toolkit/contest/ContestSessionRepository.d.ts +21 -0
- package/dist/toolkit/contest/ContestSessionRepository.d.ts.map +1 -0
- package/dist/toolkit/contest/ContestSessionRepository.js +27 -0
- package/dist/toolkit/contest/ContestSessionRepository.js.map +1 -0
- package/dist/toolkit/contest/DefaultContestSession.d.ts +105 -0
- package/dist/toolkit/contest/DefaultContestSession.d.ts.map +1 -0
- package/dist/toolkit/contest/DefaultContestSession.js +387 -0
- package/dist/toolkit/contest/DefaultContestSession.js.map +1 -0
- package/dist/toolkit/contest/DefaultContestWorkbench.d.ts +100 -0
- package/dist/toolkit/contest/DefaultContestWorkbench.d.ts.map +1 -0
- package/dist/toolkit/contest/DefaultContestWorkbench.js +33 -0
- package/dist/toolkit/contest/DefaultContestWorkbench.js.map +1 -0
- package/dist/toolkit/contest/FT8ContestDefinition.d.ts +83 -0
- package/dist/toolkit/contest/FT8ContestDefinition.d.ts.map +1 -0
- package/dist/toolkit/contest/FT8ContestDefinition.js +167 -0
- package/dist/toolkit/contest/FT8ContestDefinition.js.map +1 -0
- package/dist/toolkit/contest/FT8ContestModules.d.ts +178 -0
- package/dist/toolkit/contest/FT8ContestModules.d.ts.map +1 -0
- package/dist/toolkit/contest/FT8ContestModules.js +247 -0
- package/dist/toolkit/contest/FT8ContestModules.js.map +1 -0
- package/dist/toolkit/contest/FT8ContestPlugin.d.ts +55 -0
- package/dist/toolkit/contest/FT8ContestPlugin.d.ts.map +1 -0
- package/dist/toolkit/contest/FT8ContestPlugin.js +322 -0
- package/dist/toolkit/contest/FT8ContestPlugin.js.map +1 -0
- package/dist/toolkit/contest/FT8ContestTestKit.d.ts +12 -0
- package/dist/toolkit/contest/FT8ContestTestKit.d.ts.map +1 -0
- package/dist/toolkit/contest/FT8ContestTestKit.js +60 -0
- package/dist/toolkit/contest/FT8ContestTestKit.js.map +1 -0
- package/dist/toolkit/contest/contest-toolkit.test.d.ts +2 -0
- package/dist/toolkit/contest/contest-toolkit.test.d.ts.map +1 -0
- package/dist/toolkit/contest/contest-toolkit.test.js +1196 -0
- package/dist/toolkit/contest/contest-toolkit.test.js.map +1 -0
- package/dist/toolkit/contest/index.d.ts +14 -0
- package/dist/toolkit/contest/index.d.ts.map +1 -0
- package/dist/toolkit/contest/index.js +14 -0
- package/dist/toolkit/contest/index.js.map +1 -0
- package/dist/toolkit/index.d.ts +3 -0
- package/dist/toolkit/index.d.ts.map +1 -0
- package/dist/toolkit/index.js +3 -0
- package/dist/toolkit/index.js.map +1 -0
- package/dist/toolkit/parallel-qso/AuthorizationLease.d.ts +15 -0
- package/dist/toolkit/parallel-qso/AuthorizationLease.d.ts.map +1 -0
- package/dist/toolkit/parallel-qso/AuthorizationLease.js +25 -0
- package/dist/toolkit/parallel-qso/AuthorizationLease.js.map +1 -0
- package/dist/toolkit/parallel-qso/BoundedCallSessionController.d.ts +40 -0
- package/dist/toolkit/parallel-qso/BoundedCallSessionController.d.ts.map +1 -0
- package/dist/toolkit/parallel-qso/BoundedCallSessionController.js +81 -0
- package/dist/toolkit/parallel-qso/BoundedCallSessionController.js.map +1 -0
- package/dist/toolkit/parallel-qso/BoundedCallSessionController.test.d.ts +2 -0
- package/dist/toolkit/parallel-qso/BoundedCallSessionController.test.d.ts.map +1 -0
- package/dist/toolkit/parallel-qso/BoundedCallSessionController.test.js +31 -0
- package/dist/toolkit/parallel-qso/BoundedCallSessionController.test.js.map +1 -0
- package/dist/toolkit/parallel-qso/CompletionTracker.d.ts +20 -0
- package/dist/toolkit/parallel-qso/CompletionTracker.d.ts.map +1 -0
- package/dist/toolkit/parallel-qso/CompletionTracker.js +20 -0
- package/dist/toolkit/parallel-qso/CompletionTracker.js.map +1 -0
- package/dist/toolkit/parallel-qso/LaneFrequencyController.d.ts +19 -0
- package/dist/toolkit/parallel-qso/LaneFrequencyController.d.ts.map +1 -0
- package/dist/toolkit/parallel-qso/LaneFrequencyController.js +23 -0
- package/dist/toolkit/parallel-qso/LaneFrequencyController.js.map +1 -0
- package/dist/toolkit/parallel-qso/ParallelQSOCoordinator.d.ts +134 -0
- package/dist/toolkit/parallel-qso/ParallelQSOCoordinator.d.ts.map +1 -0
- package/dist/toolkit/parallel-qso/ParallelQSOCoordinator.js +554 -0
- package/dist/toolkit/parallel-qso/ParallelQSOCoordinator.js.map +1 -0
- package/dist/toolkit/parallel-qso/ParallelQSOCoordinator.test.d.ts +2 -0
- package/dist/toolkit/parallel-qso/ParallelQSOCoordinator.test.d.ts.map +1 -0
- package/dist/toolkit/parallel-qso/ParallelQSOCoordinator.test.js +470 -0
- package/dist/toolkit/parallel-qso/ParallelQSOCoordinator.test.js.map +1 -0
- package/dist/toolkit/parallel-qso/PostCompletionRecoveryLease.d.ts +20 -0
- package/dist/toolkit/parallel-qso/PostCompletionRecoveryLease.d.ts.map +1 -0
- package/dist/toolkit/parallel-qso/PostCompletionRecoveryLease.js +29 -0
- package/dist/toolkit/parallel-qso/PostCompletionRecoveryLease.js.map +1 -0
- package/dist/toolkit/parallel-qso/ProtocolLane.d.ts +50 -0
- package/dist/toolkit/parallel-qso/ProtocolLane.d.ts.map +1 -0
- package/dist/toolkit/parallel-qso/ProtocolLane.js +2 -0
- package/dist/toolkit/parallel-qso/ProtocolLane.js.map +1 -0
- package/dist/toolkit/parallel-qso/controllers.test.d.ts +2 -0
- package/dist/toolkit/parallel-qso/controllers.test.d.ts.map +1 -0
- package/dist/toolkit/parallel-qso/controllers.test.js +36 -0
- package/dist/toolkit/parallel-qso/controllers.test.js.map +1 -0
- package/dist/toolkit/parallel-qso/index.d.ts +8 -0
- package/dist/toolkit/parallel-qso/index.d.ts.map +1 -0
- package/dist/toolkit/parallel-qso/index.js +8 -0
- package/dist/toolkit/parallel-qso/index.js.map +1 -0
- package/dist/utils/adif.d.ts +1 -1
- package/dist/utils/adif.d.ts.map +1 -1
- package/dist/utils/adif.js +96 -51
- package/dist/utils/adif.js.map +1 -1
- package/dist/utils/qso-text-fields.d.ts +7 -1
- package/dist/utils/qso-text-fields.d.ts.map +1 -1
- package/dist/utils/qso-text-fields.js +74 -6
- package/dist/utils/qso-text-fields.js.map +1 -1
- package/package.json +28 -6
- package/src/bridge.d.ts +3 -0
- package/tokens.css +51 -0
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
import { ContestSessionRepository } from './ContestSessionRepository.js';
|
|
2
|
+
export const CONTEST_SESSION_PERMISSIONS = [
|
|
3
|
+
'logbook:session',
|
|
4
|
+
'plugin:event-bus',
|
|
5
|
+
];
|
|
6
|
+
function cloneHealth(health) {
|
|
7
|
+
return { ...health };
|
|
8
|
+
}
|
|
9
|
+
function errorMessage(error) {
|
|
10
|
+
return error instanceof Error ? error.message : String(error);
|
|
11
|
+
}
|
|
12
|
+
function isRevisionConflict(error) {
|
|
13
|
+
return error?.code === 'LOGBOOK_REVISION_CONFLICT';
|
|
14
|
+
}
|
|
15
|
+
function validateAttempts(value) {
|
|
16
|
+
if (!Number.isInteger(value) || value < 1 || value > 10) {
|
|
17
|
+
throw new Error('contest_session_invalid_transaction_attempts');
|
|
18
|
+
}
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
function encodeIdentitySegment(value) {
|
|
22
|
+
return [...new TextEncoder().encode(value)].map((byte) => {
|
|
23
|
+
const character = String.fromCharCode(byte);
|
|
24
|
+
if (/^[A-Za-z0-9.-]$/.test(character))
|
|
25
|
+
return character;
|
|
26
|
+
if (character === '_')
|
|
27
|
+
return '__';
|
|
28
|
+
return `_${byte.toString(16).padStart(2, '0')}`;
|
|
29
|
+
}).join('');
|
|
30
|
+
}
|
|
31
|
+
function defaultSessionKey(contest) {
|
|
32
|
+
const key = [
|
|
33
|
+
'contest',
|
|
34
|
+
encodeIdentitySegment(contest.id),
|
|
35
|
+
encodeIdentitySegment(contest.edition.id),
|
|
36
|
+
encodeIdentitySegment(contest.rulesetVersion),
|
|
37
|
+
].join(':');
|
|
38
|
+
if (key.length > 128)
|
|
39
|
+
throw new Error('contest_session_identity_too_long');
|
|
40
|
+
return key;
|
|
41
|
+
}
|
|
42
|
+
function ownedChangeTopic(contest, owner) {
|
|
43
|
+
return [
|
|
44
|
+
'tx5dr.contest',
|
|
45
|
+
encodeIdentitySegment(owner.pluginName),
|
|
46
|
+
encodeIdentitySegment(owner.stationCallsign),
|
|
47
|
+
encodeIdentitySegment(contest.id),
|
|
48
|
+
encodeIdentitySegment(contest.edition.id),
|
|
49
|
+
encodeIdentitySegment(contest.rulesetVersion),
|
|
50
|
+
'session-changed',
|
|
51
|
+
].join(':');
|
|
52
|
+
}
|
|
53
|
+
function isChangeEvent(value) {
|
|
54
|
+
if (!value || typeof value !== 'object')
|
|
55
|
+
return false;
|
|
56
|
+
const event = value;
|
|
57
|
+
const reasons = ['transaction', 'import', 'review', 'manual'];
|
|
58
|
+
return typeof event.pluginName === 'string'
|
|
59
|
+
&& typeof event.stationCallsign === 'string'
|
|
60
|
+
&& typeof event.contestId === 'string'
|
|
61
|
+
&& typeof event.editionId === 'string'
|
|
62
|
+
&& typeof event.rulesetVersion === 'string'
|
|
63
|
+
&& typeof event.operatorId === 'string'
|
|
64
|
+
&& reasons.includes(event.reason)
|
|
65
|
+
&& typeof event.timestamp === 'number'
|
|
66
|
+
&& Number.isFinite(event.timestamp);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Contest application facade backed by Host plugin-sessions and a small KV state store.
|
|
70
|
+
* It hides session keys, event topics, raw handles and revision-conflict retry loops.
|
|
71
|
+
*/
|
|
72
|
+
export function defaultContestSession(options) {
|
|
73
|
+
if (options.retention === 'runtime') {
|
|
74
|
+
throw new Error('contest_session_runtime_retention_not_supported');
|
|
75
|
+
}
|
|
76
|
+
const repositories = new Map();
|
|
77
|
+
const contests = new Map();
|
|
78
|
+
const owners = new Map();
|
|
79
|
+
const sessionKeys = new Map();
|
|
80
|
+
const health = new Map();
|
|
81
|
+
const subscriptions = new Map();
|
|
82
|
+
const defaultAttempts = validateAttempts(options.maxTransactionAttempts ?? 3);
|
|
83
|
+
function setHealth(operatorId, patch) {
|
|
84
|
+
const current = health.get(operatorId);
|
|
85
|
+
const next = {
|
|
86
|
+
...current,
|
|
87
|
+
...patch,
|
|
88
|
+
state: patch.state,
|
|
89
|
+
readable: patch.readable ?? (patch.state === 'healthy' ? true : current?.readable ?? false),
|
|
90
|
+
writable: patch.writable ?? (patch.state === 'healthy' ? true : current?.writable ?? false),
|
|
91
|
+
updatedAt: Date.now(),
|
|
92
|
+
error: patch.error ?? (patch.state === 'healthy' ? undefined : current?.error),
|
|
93
|
+
};
|
|
94
|
+
health.set(operatorId, next);
|
|
95
|
+
return next;
|
|
96
|
+
}
|
|
97
|
+
function requireContest(operatorId) {
|
|
98
|
+
const contest = contests.get(operatorId);
|
|
99
|
+
if (!contest)
|
|
100
|
+
throw new Error('contest_session_not_open');
|
|
101
|
+
return contest;
|
|
102
|
+
}
|
|
103
|
+
function requireOwner(operatorId) {
|
|
104
|
+
const owner = owners.get(operatorId);
|
|
105
|
+
if (!owner)
|
|
106
|
+
throw new Error('contest_session_not_open');
|
|
107
|
+
return owner;
|
|
108
|
+
}
|
|
109
|
+
async function openHostSession(contest, context, owner) {
|
|
110
|
+
const access = await context.logbook.sessions.open({
|
|
111
|
+
sessionKey: options.sessionKey?.(contest, context) ?? defaultSessionKey(contest),
|
|
112
|
+
stationCallsign: owner.stationCallsign,
|
|
113
|
+
title: options.title?.(contest, context)
|
|
114
|
+
?? `${contest.id} ${contest.edition.id} - ${owner.stationCallsign}`,
|
|
115
|
+
});
|
|
116
|
+
await access.awaitReady();
|
|
117
|
+
return access;
|
|
118
|
+
}
|
|
119
|
+
async function publishChange(contest, context, owner, reason, revision, hostAccess) {
|
|
120
|
+
const access = hostAccess ?? await openHostSession(contest, context, owner);
|
|
121
|
+
await access.notifyUpdated(context.operator.id);
|
|
122
|
+
context.eventBus.publish(ownedChangeTopic(contest, owner), {
|
|
123
|
+
pluginName: owner.pluginName,
|
|
124
|
+
stationCallsign: owner.stationCallsign,
|
|
125
|
+
contestId: contest.id,
|
|
126
|
+
editionId: contest.edition.id,
|
|
127
|
+
rulesetVersion: contest.rulesetVersion,
|
|
128
|
+
operatorId: context.operator.id,
|
|
129
|
+
reason,
|
|
130
|
+
revision,
|
|
131
|
+
timestamp: Date.now(),
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
id: 'default-contest-session',
|
|
136
|
+
forOperator(operatorId) {
|
|
137
|
+
const repository = repositories.get(operatorId);
|
|
138
|
+
if (!repository)
|
|
139
|
+
throw new Error('contest_session_not_open');
|
|
140
|
+
return repository;
|
|
141
|
+
},
|
|
142
|
+
getHealth(operatorId) {
|
|
143
|
+
return cloneHealth(health.get(operatorId) ?? {
|
|
144
|
+
state: 'closed',
|
|
145
|
+
readable: false,
|
|
146
|
+
writable: false,
|
|
147
|
+
updatedAt: Date.now(),
|
|
148
|
+
});
|
|
149
|
+
},
|
|
150
|
+
getDestination(operatorId) {
|
|
151
|
+
const key = sessionKeys.get(operatorId);
|
|
152
|
+
if (!key)
|
|
153
|
+
throw new Error('contest_session_not_open');
|
|
154
|
+
return { kind: 'plugin-session-key', sessionKey: key };
|
|
155
|
+
},
|
|
156
|
+
async rebind(operatorId, contest, context) {
|
|
157
|
+
const currentRepository = repositories.get(operatorId);
|
|
158
|
+
const owner = owners.get(operatorId);
|
|
159
|
+
if (!currentRepository || !owner)
|
|
160
|
+
throw new Error('contest_session_not_open');
|
|
161
|
+
for (const unsubscribe of subscriptions.get(operatorId) ?? [])
|
|
162
|
+
unsubscribe();
|
|
163
|
+
subscriptions.delete(operatorId);
|
|
164
|
+
await currentRepository.flush();
|
|
165
|
+
const store = options.stateScope === 'global' ? context.store.global : context.store.operator;
|
|
166
|
+
const durableKey = options.sessionKey?.(contest, context) ?? defaultSessionKey(contest);
|
|
167
|
+
const repository = new ContestSessionRepository(store, options.stateKey?.(contest, context) ?? durableKey, () => options.create(contest, context));
|
|
168
|
+
repositories.set(operatorId, repository);
|
|
169
|
+
contests.set(operatorId, contest);
|
|
170
|
+
sessionKeys.set(operatorId, durableKey);
|
|
171
|
+
setHealth(operatorId, { state: 'opening', readable: false, writable: false });
|
|
172
|
+
try {
|
|
173
|
+
const access = await openHostSession(contest, context, owner);
|
|
174
|
+
const snapshot = await access.readQsoSnapshot();
|
|
175
|
+
setHealth(operatorId, {
|
|
176
|
+
state: 'healthy',
|
|
177
|
+
revision: snapshot.revision,
|
|
178
|
+
qsoCount: snapshot.records.length,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
setHealth(operatorId, {
|
|
183
|
+
state: 'degraded',
|
|
184
|
+
readable: false,
|
|
185
|
+
writable: false,
|
|
186
|
+
error: errorMessage(error),
|
|
187
|
+
});
|
|
188
|
+
throw error;
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
access(context) {
|
|
192
|
+
const operatorId = context.operator.id;
|
|
193
|
+
const contest = requireContest(operatorId);
|
|
194
|
+
const owner = requireOwner(operatorId);
|
|
195
|
+
return {
|
|
196
|
+
getHealth: () => cloneHealth(health.get(operatorId) ?? setHealth(operatorId, {
|
|
197
|
+
state: 'closed',
|
|
198
|
+
readable: false,
|
|
199
|
+
writable: false,
|
|
200
|
+
})),
|
|
201
|
+
async query(filter = {}) {
|
|
202
|
+
try {
|
|
203
|
+
const access = await openHostSession(contest, context, owner);
|
|
204
|
+
const records = await access.queryQSOs(filter);
|
|
205
|
+
setHealth(operatorId, { state: 'healthy' });
|
|
206
|
+
return records;
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
setHealth(operatorId, {
|
|
210
|
+
state: 'degraded',
|
|
211
|
+
readable: false,
|
|
212
|
+
writable: false,
|
|
213
|
+
error: errorMessage(error),
|
|
214
|
+
});
|
|
215
|
+
throw error;
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
async snapshot(filter = {}) {
|
|
219
|
+
try {
|
|
220
|
+
const access = await openHostSession(contest, context, owner);
|
|
221
|
+
const snapshot = await access.readQsoSnapshot(filter);
|
|
222
|
+
setHealth(operatorId, {
|
|
223
|
+
state: 'healthy',
|
|
224
|
+
revision: snapshot.revision,
|
|
225
|
+
qsoCount: snapshot.records.length,
|
|
226
|
+
});
|
|
227
|
+
return snapshot;
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
setHealth(operatorId, {
|
|
231
|
+
state: 'degraded',
|
|
232
|
+
readable: false,
|
|
233
|
+
writable: false,
|
|
234
|
+
error: errorMessage(error),
|
|
235
|
+
});
|
|
236
|
+
throw error;
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
async transact(planner, transactionOptions = {}) {
|
|
240
|
+
const maxAttempts = validateAttempts(transactionOptions.maxAttempts ?? defaultAttempts);
|
|
241
|
+
let access;
|
|
242
|
+
try {
|
|
243
|
+
access = await openHostSession(contest, context, owner);
|
|
244
|
+
}
|
|
245
|
+
catch (error) {
|
|
246
|
+
setHealth(operatorId, {
|
|
247
|
+
state: 'degraded',
|
|
248
|
+
readable: false,
|
|
249
|
+
writable: false,
|
|
250
|
+
error: errorMessage(error),
|
|
251
|
+
});
|
|
252
|
+
throw error;
|
|
253
|
+
}
|
|
254
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
255
|
+
let snapshot;
|
|
256
|
+
try {
|
|
257
|
+
snapshot = await access.readQsoSnapshot();
|
|
258
|
+
const mutations = await planner(structuredClone(snapshot));
|
|
259
|
+
const batch = await access.applyQsoBatch(mutations, {
|
|
260
|
+
expectedRevision: snapshot.revision,
|
|
261
|
+
});
|
|
262
|
+
const added = batch.outcomes.filter((outcome) => outcome.status === 'added').length;
|
|
263
|
+
setHealth(operatorId, {
|
|
264
|
+
state: 'healthy',
|
|
265
|
+
revision: batch.revision,
|
|
266
|
+
qsoCount: snapshot.records.length + added,
|
|
267
|
+
});
|
|
268
|
+
let notificationError;
|
|
269
|
+
if (transactionOptions.notify !== false) {
|
|
270
|
+
try {
|
|
271
|
+
await publishChange(contest, context, owner, transactionOptions.reason ?? 'transaction', batch.revision, access);
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
notificationError = errorMessage(error);
|
|
275
|
+
setHealth(operatorId, {
|
|
276
|
+
state: 'degraded',
|
|
277
|
+
readable: true,
|
|
278
|
+
writable: true,
|
|
279
|
+
revision: batch.revision,
|
|
280
|
+
qsoCount: snapshot.records.length + added,
|
|
281
|
+
error: notificationError,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return { attempts: attempt, snapshot, batch, notificationError };
|
|
286
|
+
}
|
|
287
|
+
catch (error) {
|
|
288
|
+
if (isRevisionConflict(error) && attempt < maxAttempts)
|
|
289
|
+
continue;
|
|
290
|
+
setHealth(operatorId, {
|
|
291
|
+
state: 'degraded',
|
|
292
|
+
readable: snapshot !== undefined,
|
|
293
|
+
writable: false,
|
|
294
|
+
revision: snapshot?.revision,
|
|
295
|
+
qsoCount: snapshot?.records.length,
|
|
296
|
+
error: errorMessage(error),
|
|
297
|
+
});
|
|
298
|
+
throw error;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
throw new Error('contest_session_transaction_exhausted');
|
|
302
|
+
},
|
|
303
|
+
notify(reason = 'manual', revision) {
|
|
304
|
+
return publishChange(contest, context, owner, reason, revision);
|
|
305
|
+
},
|
|
306
|
+
subscribe(handler) {
|
|
307
|
+
const unsubscribe = context.eventBus.subscribe(ownedChangeTopic(contest, owner), (message) => {
|
|
308
|
+
if (!isChangeEvent(message.payload))
|
|
309
|
+
return;
|
|
310
|
+
if (message.publisher.pluginName !== owner.pluginName
|
|
311
|
+
|| message.payload.pluginName !== owner.pluginName
|
|
312
|
+
|| message.payload.stationCallsign !== owner.stationCallsign
|
|
313
|
+
|| message.payload.contestId !== contest.id
|
|
314
|
+
|| message.payload.editionId !== contest.edition.id
|
|
315
|
+
|| message.payload.rulesetVersion !== contest.rulesetVersion)
|
|
316
|
+
return;
|
|
317
|
+
return handler(message.payload);
|
|
318
|
+
});
|
|
319
|
+
const operatorSubscriptions = subscriptions.get(operatorId) ?? new Set();
|
|
320
|
+
operatorSubscriptions.add(unsubscribe);
|
|
321
|
+
subscriptions.set(operatorId, operatorSubscriptions);
|
|
322
|
+
return () => {
|
|
323
|
+
operatorSubscriptions.delete(unsubscribe);
|
|
324
|
+
unsubscribe();
|
|
325
|
+
};
|
|
326
|
+
},
|
|
327
|
+
};
|
|
328
|
+
},
|
|
329
|
+
async setup({ contest, context, pluginName }) {
|
|
330
|
+
const operatorId = context.operator.id;
|
|
331
|
+
if (repositories.has(operatorId))
|
|
332
|
+
throw new Error('contest_session_already_open');
|
|
333
|
+
const owner = {
|
|
334
|
+
pluginName: pluginName.trim(),
|
|
335
|
+
stationCallsign: context.operator.callsign.trim().toUpperCase(),
|
|
336
|
+
};
|
|
337
|
+
if (!owner.pluginName || !owner.stationCallsign)
|
|
338
|
+
throw new Error('contest_session_owner_invalid');
|
|
339
|
+
const store = options.stateScope === 'global' ? context.store.global : context.store.operator;
|
|
340
|
+
const durableKey = options.sessionKey?.(contest, context) ?? defaultSessionKey(contest);
|
|
341
|
+
const repository = new ContestSessionRepository(store, options.stateKey?.(contest, context) ?? durableKey, () => options.create(contest, context));
|
|
342
|
+
repositories.set(operatorId, repository);
|
|
343
|
+
contests.set(operatorId, contest);
|
|
344
|
+
owners.set(operatorId, owner);
|
|
345
|
+
sessionKeys.set(operatorId, durableKey);
|
|
346
|
+
setHealth(operatorId, { state: 'opening', readable: false, writable: false });
|
|
347
|
+
try {
|
|
348
|
+
const access = await openHostSession(contest, context, owner);
|
|
349
|
+
const snapshot = await access.readQsoSnapshot();
|
|
350
|
+
setHealth(operatorId, {
|
|
351
|
+
state: 'healthy',
|
|
352
|
+
revision: snapshot.revision,
|
|
353
|
+
qsoCount: snapshot.records.length,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
catch (error) {
|
|
357
|
+
setHealth(operatorId, {
|
|
358
|
+
state: 'degraded',
|
|
359
|
+
readable: false,
|
|
360
|
+
writable: false,
|
|
361
|
+
error: errorMessage(error),
|
|
362
|
+
});
|
|
363
|
+
repositories.delete(operatorId);
|
|
364
|
+
contests.delete(operatorId);
|
|
365
|
+
owners.delete(operatorId);
|
|
366
|
+
sessionKeys.delete(operatorId);
|
|
367
|
+
throw error;
|
|
368
|
+
}
|
|
369
|
+
return async () => {
|
|
370
|
+
try {
|
|
371
|
+
for (const unsubscribe of subscriptions.get(operatorId) ?? [])
|
|
372
|
+
unsubscribe();
|
|
373
|
+
subscriptions.delete(operatorId);
|
|
374
|
+
await (repositories.get(operatorId) ?? repository).flush();
|
|
375
|
+
}
|
|
376
|
+
finally {
|
|
377
|
+
repositories.delete(operatorId);
|
|
378
|
+
contests.delete(operatorId);
|
|
379
|
+
owners.delete(operatorId);
|
|
380
|
+
sessionKeys.delete(operatorId);
|
|
381
|
+
setHealth(operatorId, { state: 'closed', readable: false, writable: false });
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
},
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
//# sourceMappingURL=DefaultContestSession.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DefaultContestSession.js","sourceRoot":"","sources":["../../../src/toolkit/contest/DefaultContestSession.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { PluginPermission } from '@tx5dr/contracts';
|
|
2
|
+
import type { PluginContextFor } from '../../context.js';
|
|
3
|
+
import type { PluginUIRequestContext } from '../../helpers.js';
|
|
4
|
+
import type { ContestSessionHealth } from './DefaultContestSession.js';
|
|
5
|
+
import type { ContestWorkbenchModule } from './FT8ContestPlugin.js';
|
|
6
|
+
export declare const CONTEST_WORKBENCH_ACTIONS: {
|
|
7
|
+
readonly getState: "get-state";
|
|
8
|
+
readonly saveSettings: "save-settings";
|
|
9
|
+
readonly setQsoStatus: "set-qso-status";
|
|
10
|
+
readonly previewImport: "preview-import";
|
|
11
|
+
readonly commitImport: "commit-import";
|
|
12
|
+
readonly export: "export";
|
|
13
|
+
};
|
|
14
|
+
export type ContestWorkbenchAction = typeof CONTEST_WORKBENCH_ACTIONS[keyof typeof CONTEST_WORKBENCH_ACTIONS];
|
|
15
|
+
export type ContestWorkbenchQsoStatus = 'included' | 'review' | 'excluded' | 'x-qso';
|
|
16
|
+
export interface ContestWorkbenchSettingsView<TSettings = unknown> {
|
|
17
|
+
value: TSettings;
|
|
18
|
+
valid: boolean;
|
|
19
|
+
issues: readonly string[];
|
|
20
|
+
}
|
|
21
|
+
export interface ContestWorkbenchScoreView<TDetails = unknown> {
|
|
22
|
+
claimedScore: number;
|
|
23
|
+
qsoPoints: number;
|
|
24
|
+
multiplierCount: number;
|
|
25
|
+
details?: TDetails;
|
|
26
|
+
}
|
|
27
|
+
export interface ContestWorkbenchQsoRow<TFields = Readonly<Record<string, unknown>>> {
|
|
28
|
+
id: string;
|
|
29
|
+
callsign: string;
|
|
30
|
+
band: string;
|
|
31
|
+
mode: 'FT8' | 'FT4';
|
|
32
|
+
time: number;
|
|
33
|
+
status: ContestWorkbenchQsoStatus;
|
|
34
|
+
fields: TFields;
|
|
35
|
+
}
|
|
36
|
+
export interface ContestWorkbenchReviewView<TIssue = unknown> {
|
|
37
|
+
pendingCount: number;
|
|
38
|
+
issues: readonly TIssue[];
|
|
39
|
+
}
|
|
40
|
+
export interface ContestWorkbenchImportView<TPreview = unknown> {
|
|
41
|
+
state: 'idle' | 'preview' | 'committing' | 'complete' | 'error';
|
|
42
|
+
token?: string;
|
|
43
|
+
preview?: TPreview;
|
|
44
|
+
error?: string;
|
|
45
|
+
}
|
|
46
|
+
export interface ContestWorkbenchExportFormat {
|
|
47
|
+
id: string;
|
|
48
|
+
label: string;
|
|
49
|
+
extension: string;
|
|
50
|
+
enabled: boolean;
|
|
51
|
+
}
|
|
52
|
+
/** Stable outer page state; plugins own the contest-specific generic fields. */
|
|
53
|
+
export interface ContestWorkbenchViewModel<TSettings = unknown, TScoreDetails = unknown, TQsoFields = Readonly<Record<string, unknown>>, TReviewIssue = unknown, TImportPreview = unknown> {
|
|
54
|
+
schemaVersion: 1;
|
|
55
|
+
contest: {
|
|
56
|
+
id: string;
|
|
57
|
+
editionId: string;
|
|
58
|
+
rulesetVersion: string;
|
|
59
|
+
};
|
|
60
|
+
health: ContestSessionHealth;
|
|
61
|
+
settings: ContestWorkbenchSettingsView<TSettings>;
|
|
62
|
+
score: ContestWorkbenchScoreView<TScoreDetails>;
|
|
63
|
+
qsos: readonly ContestWorkbenchQsoRow<TQsoFields>[];
|
|
64
|
+
review: ContestWorkbenchReviewView<TReviewIssue>;
|
|
65
|
+
import: ContestWorkbenchImportView<TImportPreview>;
|
|
66
|
+
export: {
|
|
67
|
+
formats: readonly ContestWorkbenchExportFormat[];
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export interface ContestWorkbenchRequest<TAction extends string = string, TPayload = unknown> {
|
|
71
|
+
action: TAction;
|
|
72
|
+
payload: TPayload;
|
|
73
|
+
}
|
|
74
|
+
/** Shared command names; parsers still validate each contest-specific payload. */
|
|
75
|
+
export type ContestWorkbenchCommand<TSettings = unknown, TImportSource = unknown> = ContestWorkbenchRequest<typeof CONTEST_WORKBENCH_ACTIONS.saveSettings, TSettings> | ContestWorkbenchRequest<typeof CONTEST_WORKBENCH_ACTIONS.setQsoStatus, {
|
|
76
|
+
qsoId: string;
|
|
77
|
+
status: ContestWorkbenchQsoStatus;
|
|
78
|
+
}> | ContestWorkbenchRequest<typeof CONTEST_WORKBENCH_ACTIONS.previewImport, TImportSource> | ContestWorkbenchRequest<typeof CONTEST_WORKBENCH_ACTIONS.commitImport, {
|
|
79
|
+
token: string;
|
|
80
|
+
}> | ContestWorkbenchRequest<typeof CONTEST_WORKBENCH_ACTIONS.export, {
|
|
81
|
+
formatId: string;
|
|
82
|
+
}>;
|
|
83
|
+
export interface ContestWorkbenchHandlerContext<TContest, Permissions extends readonly PluginPermission[]> {
|
|
84
|
+
contest: TContest;
|
|
85
|
+
context: PluginContextFor<Permissions>;
|
|
86
|
+
request: PluginUIRequestContext;
|
|
87
|
+
}
|
|
88
|
+
export interface DefaultContestWorkbenchOptions<TContest, TState extends ContestWorkbenchViewModel, TRequest extends ContestWorkbenchRequest, TResult, Permissions extends readonly PluginPermission[] = readonly []> {
|
|
89
|
+
pageId: string;
|
|
90
|
+
getState(context: ContestWorkbenchHandlerContext<TContest, Permissions>): TState | Promise<TState>;
|
|
91
|
+
/** Validates untrusted iframe data and returns a typed request union. */
|
|
92
|
+
decode(action: string, data: unknown): TRequest;
|
|
93
|
+
handle(request: TRequest, context: ContestWorkbenchHandlerContext<TContest, Permissions>): TResult | Promise<TResult>;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Registers one narrow page protocol: `get-state` plus plugin-decoded commands.
|
|
97
|
+
* Rendering, fields and contest-specific actions remain owned by the plugin.
|
|
98
|
+
*/
|
|
99
|
+
export declare function defaultContestWorkbench<TContest, TState extends ContestWorkbenchViewModel, TRequest extends ContestWorkbenchRequest, TResult, Permissions extends readonly PluginPermission[] = readonly []>(options: DefaultContestWorkbenchOptions<TContest, TState, TRequest, TResult, Permissions>): ContestWorkbenchModule<TContest, Permissions>;
|
|
100
|
+
//# sourceMappingURL=DefaultContestWorkbench.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DefaultContestWorkbench.d.ts","sourceRoot":"","sources":["../../../src/toolkit/contest/DefaultContestWorkbench.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export const CONTEST_WORKBENCH_ACTIONS = {
|
|
2
|
+
getState: 'get-state',
|
|
3
|
+
saveSettings: 'save-settings',
|
|
4
|
+
setQsoStatus: 'set-qso-status',
|
|
5
|
+
previewImport: 'preview-import',
|
|
6
|
+
commitImport: 'commit-import',
|
|
7
|
+
export: 'export',
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Registers one narrow page protocol: `get-state` plus plugin-decoded commands.
|
|
11
|
+
* Rendering, fields and contest-specific actions remain owned by the plugin.
|
|
12
|
+
*/
|
|
13
|
+
export function defaultContestWorkbench(options) {
|
|
14
|
+
return {
|
|
15
|
+
id: 'default-contest-workbench',
|
|
16
|
+
setup({ contest, context }) {
|
|
17
|
+
context.ui.registerPageHandler({
|
|
18
|
+
async onMessage(pageId, action, data, request) {
|
|
19
|
+
if (pageId !== options.pageId)
|
|
20
|
+
throw new Error('contest_workbench_page_mismatch');
|
|
21
|
+
const handlerContext = { contest, context, request };
|
|
22
|
+
if (action === CONTEST_WORKBENCH_ACTIONS.getState)
|
|
23
|
+
return options.getState(handlerContext);
|
|
24
|
+
const decoded = options.decode(action, data);
|
|
25
|
+
if (decoded.action !== action)
|
|
26
|
+
throw new Error('contest_workbench_action_mismatch');
|
|
27
|
+
return options.handle(decoded, handlerContext);
|
|
28
|
+
},
|
|
29
|
+
}, { pageIds: [options.pageId] });
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=DefaultContestWorkbench.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DefaultContestWorkbench.js","sourceRoot":"","sources":["../../../src/toolkit/contest/DefaultContestWorkbench.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,QAAQ,EAAE,WAAW;IACrB,YAAY,EAAE,eAAe;IAC7B,YAAY,EAAE,gBAAgB;IAC9B,aAAa,EAAE,gBAAgB;IAC/B,YAAY,EAAE,eAAe;IAC7B,MAAM,EAAE,QAAQ;CACR,CAAC;AAoHX;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAOrC,OAAyF;IAEzF,OAAO;QACL,EAAE,EAAE,2BAA2B;QAC/B,KAAK,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE;YACxB,OAAO,CAAC,EAAE,CAAC,mBAAmB,CAAC;gBAC7B,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO;oBAC3C,IAAI,MAAM,KAAK,OAAO,CAAC,MAAM;wBAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;oBAClF,MAAM,cAAc,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;oBACrD,IAAI,MAAM,KAAK,yBAAyB,CAAC,QAAQ;wBAAE,OAAO,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;oBAC3F,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;oBAC7C,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM;wBAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;oBACpF,OAAO,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;gBACjD,CAAC;aACF,EAAE,EAAE,OAAO,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACpC,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { CompletionModule, DupeModule, FT8ContestMode, FT8ContestQso, FT8ExchangeModule, ScoringModule, ContestScoreSummary, SubmissionModule } from './FT8ContestModules.js';
|
|
2
|
+
export interface ContestRuleSource {
|
|
3
|
+
readonly url: string;
|
|
4
|
+
readonly confirmedAt?: string;
|
|
5
|
+
}
|
|
6
|
+
/** Operator-facing rule summary kept separate from the authoritative rule URL. */
|
|
7
|
+
export interface ContestRulePresentation {
|
|
8
|
+
readonly title?: string;
|
|
9
|
+
readonly summary: string;
|
|
10
|
+
readonly scoring?: string;
|
|
11
|
+
readonly exchange?: string;
|
|
12
|
+
}
|
|
13
|
+
/** Immutable identity and time boundary for one contest occurrence. */
|
|
14
|
+
export interface ContestEditionDefinition {
|
|
15
|
+
readonly id: string;
|
|
16
|
+
readonly startAt: string;
|
|
17
|
+
readonly endAt: string;
|
|
18
|
+
readonly source?: ContestRuleSource;
|
|
19
|
+
}
|
|
20
|
+
export interface FixedWeekendEditionInput {
|
|
21
|
+
id: string;
|
|
22
|
+
startAt: string | Date;
|
|
23
|
+
endAt: string | Date;
|
|
24
|
+
source?: ContestRuleSource;
|
|
25
|
+
}
|
|
26
|
+
/** Defines one fixed contest occurrence; the name reflects the common weekend format. */
|
|
27
|
+
export declare function fixedWeekendEdition(input: FixedWeekendEditionInput): ContestEditionDefinition;
|
|
28
|
+
export interface FT8OperatingPolicy {
|
|
29
|
+
humanInitiation: 'required' | 'optional';
|
|
30
|
+
maxConcurrentQsos: number;
|
|
31
|
+
maxSimultaneousSignals: number;
|
|
32
|
+
cycleRelation: 'single' | 'same' | 'opposite' | 'any';
|
|
33
|
+
}
|
|
34
|
+
export interface FT8ContestDefinition<TExchange, TQso extends FT8ContestQso<TExchange>, TSubmissionOptions = void> {
|
|
35
|
+
readonly id: string;
|
|
36
|
+
readonly rulesetVersion: string;
|
|
37
|
+
readonly edition: ContestEditionDefinition;
|
|
38
|
+
readonly modes: readonly FT8ContestMode[];
|
|
39
|
+
readonly bands: readonly string[];
|
|
40
|
+
readonly exchange: FT8ExchangeModule<TExchange>;
|
|
41
|
+
readonly completion: CompletionModule<TExchange>;
|
|
42
|
+
readonly dupe: DupeModule<TQso>;
|
|
43
|
+
readonly scoring: ScoringModule<TQso>;
|
|
44
|
+
readonly submission: SubmissionModule<TQso, TSubmissionOptions>;
|
|
45
|
+
readonly operating: Readonly<FT8OperatingPolicy>;
|
|
46
|
+
readonly presentation?: ContestRulePresentation;
|
|
47
|
+
}
|
|
48
|
+
export interface FT8ContestDefinitionInput<TExchange, TQso extends FT8ContestQso<TExchange>, TSubmissionOptions = void> {
|
|
49
|
+
id: string;
|
|
50
|
+
rulesetVersion: string;
|
|
51
|
+
edition: ContestEditionDefinition;
|
|
52
|
+
modes?: readonly FT8ContestMode[];
|
|
53
|
+
bands: readonly string[];
|
|
54
|
+
exchange: FT8ExchangeModule<TExchange>;
|
|
55
|
+
/** Completion stays explicit because it participates in RF fail-closed behavior. */
|
|
56
|
+
completion: CompletionModule<TExchange>;
|
|
57
|
+
dupe?: DupeModule<TQso>;
|
|
58
|
+
scoring: ScoringModule<TQso>;
|
|
59
|
+
submission: SubmissionModule<TQso, TSubmissionOptions>;
|
|
60
|
+
operating?: Partial<FT8OperatingPolicy>;
|
|
61
|
+
presentation?: ContestRulePresentation;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Composes public rule modules into a normalized FT8/FT4 contest definition.
|
|
65
|
+
* It performs no Host registration and every supplied module remains replaceable.
|
|
66
|
+
*/
|
|
67
|
+
export declare function defineFT8Contest<TExchange, TQso extends FT8ContestQso<TExchange> = FT8ContestQso<TExchange>, TSubmissionOptions = void>(input: FT8ContestDefinitionInput<TExchange, TQso, TSubmissionOptions>): FT8ContestDefinition<TExchange, TQso, TSubmissionOptions>;
|
|
68
|
+
export type AnyFT8ContestDefinition = FT8ContestDefinition<unknown, FT8ContestQso<unknown>, unknown>;
|
|
69
|
+
export type FT8ContestProjectionIssue = 'outside_edition' | 'unsupported_mode' | 'unsupported_band' | 'review' | 'excluded' | 'x_qso' | 'dupe';
|
|
70
|
+
export interface FT8ContestProjectionRow<TQso> {
|
|
71
|
+
qso: TQso;
|
|
72
|
+
/** Backwards-friendly alias for scoreEligible. */
|
|
73
|
+
eligible: boolean;
|
|
74
|
+
scoreEligible: boolean;
|
|
75
|
+
submissionEligible: boolean;
|
|
76
|
+
dupe: boolean;
|
|
77
|
+
issues: readonly FT8ContestProjectionIssue[];
|
|
78
|
+
}
|
|
79
|
+
/** Applies the common edition/mode/band/status/dupe envelope once for score and export. */
|
|
80
|
+
export declare function projectFT8ContestQsos<TExchange, TQso extends FT8ContestQso<TExchange>, TSubmissionOptions>(contest: FT8ContestDefinition<TExchange, TQso, TSubmissionOptions>, records: readonly TQso[]): FT8ContestProjectionRow<TQso>[];
|
|
81
|
+
export declare function scoreFT8ContestQsos<TExchange, TQso extends FT8ContestQso<TExchange>, TSubmissionOptions>(contest: FT8ContestDefinition<TExchange, TQso, TSubmissionOptions>, records: readonly TQso[]): ContestScoreSummary;
|
|
82
|
+
export declare function formatFT8ContestSubmission<TExchange, TQso extends FT8ContestQso<TExchange>, TSubmissionOptions>(contest: FT8ContestDefinition<TExchange, TQso, TSubmissionOptions>, records: readonly TQso[], options: TSubmissionOptions): string;
|
|
83
|
+
//# sourceMappingURL=FT8ContestDefinition.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FT8ContestDefinition.d.ts","sourceRoot":"","sources":["../../../src/toolkit/contest/FT8ContestDefinition.ts"],"names":[],"mappings":"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"}
|