tci-client-node 0.1.2 → 0.2.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 (41) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +32 -6
  3. package/dist/audio/index.cjs +41 -11
  4. package/dist/audio/index.cjs.map +1 -1
  5. package/dist/audio/index.d.cts +16 -3
  6. package/dist/audio/index.d.ts +16 -3
  7. package/dist/audio/index.js +41 -11
  8. package/dist/audio/index.js.map +1 -1
  9. package/dist/dialect/index.cjs +331 -0
  10. package/dist/dialect/index.cjs.map +1 -0
  11. package/dist/dialect/index.d.cts +29 -0
  12. package/dist/dialect/index.d.ts +29 -0
  13. package/dist/dialect/index.js +292 -0
  14. package/dist/dialect/index.js.map +1 -0
  15. package/dist/{index-CK3XdXP3.d.cts → index-lbK6NGY4.d.cts} +1 -1
  16. package/dist/{index-Dfmrk2MR.d.ts → index-paj1AOJY.d.ts} +1 -1
  17. package/dist/index.cjs +854 -215
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +53 -12
  20. package/dist/index.d.ts +53 -12
  21. package/dist/index.js +840 -215
  22. package/dist/index.js.map +1 -1
  23. package/dist/protocol/index.cjs.map +1 -1
  24. package/dist/protocol/index.d.cts +1 -1
  25. package/dist/protocol/index.d.ts +1 -1
  26. package/dist/protocol/index.js.map +1 -1
  27. package/dist/testing/index.cjs +53 -14
  28. package/dist/testing/index.cjs.map +1 -1
  29. package/dist/testing/index.d.cts +2 -0
  30. package/dist/testing/index.d.ts +2 -0
  31. package/dist/testing/index.js +53 -14
  32. package/dist/testing/index.js.map +1 -1
  33. package/dist/transport/index.cjs +175 -0
  34. package/dist/transport/index.cjs.map +1 -0
  35. package/dist/transport/index.d.cts +37 -0
  36. package/dist/transport/index.d.ts +37 -0
  37. package/dist/transport/index.js +138 -0
  38. package/dist/transport/index.js.map +1 -0
  39. package/dist/types-9seY9Th-.d.ts +63 -0
  40. package/dist/types-xRotf9gW.d.cts +63 -0
  41. package/package.json +15 -1
@@ -0,0 +1,292 @@
1
+ // src/dialect/builtins.ts
2
+ var StandardTciDialect = class {
3
+ id;
4
+ label;
5
+ streamLengthSemantics;
6
+ supportsStreamChannels;
7
+ supportsTxAudioSource;
8
+ driveHasTrx;
9
+ detector;
10
+ resolver;
11
+ constructor(options) {
12
+ this.id = options.id;
13
+ this.label = options.label;
14
+ this.streamLengthSemantics = options.streamLengthSemantics;
15
+ this.supportsStreamChannels = options.supportsStreamChannels;
16
+ this.supportsTxAudioSource = options.supportsTxAudioSource;
17
+ this.driveHasTrx = options.driveHasTrx;
18
+ this.detector = options.detect;
19
+ this.resolver = options.resolve;
20
+ }
21
+ detect(context) {
22
+ return this.detector(context);
23
+ }
24
+ resolve(context) {
25
+ return this.resolver?.(context) ?? this;
26
+ }
27
+ buildDriveSetArgs(trx, value) {
28
+ return this.driveHasTrx ? [trx, value] : [value];
29
+ }
30
+ buildDriveReadArgs(trx) {
31
+ return this.driveHasTrx ? [trx] : [];
32
+ }
33
+ parseDrive(args, defaultTrx) {
34
+ return parseDriveState(args, defaultTrx, this.driveHasTrx);
35
+ }
36
+ buildTuneDriveSetArgs(trx, value) {
37
+ return this.driveHasTrx ? [trx, value] : [value];
38
+ }
39
+ buildTuneDriveReadArgs(trx) {
40
+ return this.driveHasTrx ? [trx] : [];
41
+ }
42
+ parseTuneDrive(args, defaultTrx) {
43
+ return parseDriveState(args, defaultTrx, this.driveHasTrx);
44
+ }
45
+ };
46
+ function parseDriveState(args, defaultTrx, hasTrx) {
47
+ const trx = hasTrx ? Number(args[0]) : defaultTrx;
48
+ const value = Number(args[hasTrx ? 1 : 0]);
49
+ if (!Number.isInteger(trx) || !Number.isFinite(value)) return void 0;
50
+ return { trx, value };
51
+ }
52
+ function version(context) {
53
+ return parseTciVersion(context.identity.protocolVersion);
54
+ }
55
+ function programIncludes(context, value) {
56
+ return context.identity.programName?.toLowerCase().includes(value) ?? false;
57
+ }
58
+ var expertSdr14Dialect = new StandardTciDialect({
59
+ id: "expertsdr-1.4",
60
+ label: "ExpertSDR / TCI 1.4",
61
+ streamLengthSemantics: "per-channel",
62
+ supportsStreamChannels: false,
63
+ supportsTxAudioSource: false,
64
+ driveHasTrx: false,
65
+ detect: (context) => {
66
+ const parsed = version(context);
67
+ if (!parsed || compareTciVersion(parsed, [1, 4]) > 0) return { score: 0, evidence: [] };
68
+ return { score: 80 + (programIncludes(context, "expert") ? 10 : 0), evidence: [`protocol ${formatVersion(parsed)} <= 1.4`] };
69
+ }
70
+ });
71
+ var expertSdrLegacyDialect = new StandardTciDialect({
72
+ id: "expertsdr-1.5-1.8",
73
+ label: "ExpertSDR / TCI 1.5-1.8",
74
+ streamLengthSemantics: "per-channel",
75
+ supportsStreamChannels: false,
76
+ supportsTxAudioSource: false,
77
+ driveHasTrx: true,
78
+ detect: (context) => {
79
+ const parsed = version(context);
80
+ if (!parsed || compareTciVersion(parsed, [1, 5]) < 0 || compareTciVersion(parsed, [1, 9]) >= 0) return { score: 0, evidence: [] };
81
+ return { score: 80 + (programIncludes(context, "expert") ? 10 : 0), evidence: [`protocol ${formatVersion(parsed)} is in 1.5-1.8`] };
82
+ }
83
+ });
84
+ var expertSdrModernDialect = new StandardTciDialect({
85
+ id: "expertsdr-1.9-2.0",
86
+ label: "ExpertSDR / TCI 1.9-2.0",
87
+ streamLengthSemantics: "scalar",
88
+ supportsStreamChannels: true,
89
+ supportsTxAudioSource: true,
90
+ driveHasTrx: true,
91
+ detect: (context) => {
92
+ const parsed = version(context);
93
+ if (!parsed || compareTciVersion(parsed, [1, 9]) < 0) return { score: 0, evidence: [] };
94
+ const future = compareTciVersion(parsed, [2, 0]) > 0;
95
+ return {
96
+ score: 70 + (programIncludes(context, "expert") ? 15 : 0),
97
+ evidence: [`protocol ${formatVersion(parsed)} uses modern stream negotiation`],
98
+ warnings: future ? [`Unknown future TCI version ${formatVersion(parsed)}; using the modern dialect`] : []
99
+ };
100
+ }
101
+ });
102
+ var thetisDialect = new StandardTciDialect({
103
+ id: "thetis-2.0",
104
+ label: "Thetis / TCI 2.0",
105
+ streamLengthSemantics: "scalar",
106
+ supportsStreamChannels: true,
107
+ supportsTxAudioSource: true,
108
+ driveHasTrx: true,
109
+ detect: (context) => {
110
+ const evidence = [];
111
+ let score = 0;
112
+ if (programIncludes(context, "thetis")) {
113
+ score += 120;
114
+ evidence.push("PROTOCOL program is Thetis");
115
+ }
116
+ const observed = ["tx_frequency_ex", "tx_profiles_ex", "tx_profile_ex", "calibration_ex"].filter((name) => context.commandNames.has(name));
117
+ if (observed.length > 0) {
118
+ score += 100;
119
+ evidence.push(`Thetis extension commands: ${observed.join(", ")}`);
120
+ }
121
+ if (/anan|hermes|orion|saturn/i.test(context.identity.device ?? "")) {
122
+ score += 30;
123
+ evidence.push(`Thetis-family device: ${context.identity.device}`);
124
+ }
125
+ return { score, evidence };
126
+ }
127
+ });
128
+ var aetherSdrDialect = new StandardTciDialect({
129
+ id: "aethersdr-1.5",
130
+ label: "AetherSDR / TCI 1.5 hybrid",
131
+ streamLengthSemantics: "scalar",
132
+ supportsStreamChannels: true,
133
+ supportsTxAudioSource: true,
134
+ driveHasTrx: true,
135
+ detect: (context) => {
136
+ if (!/^aethersdr$/i.test(context.identity.device ?? "")) return { score: 0, evidence: [] };
137
+ const evidence = [`AetherSDR device identity: ${context.identity.device}`];
138
+ const modernAudioCommands = ["audio_stream_sample_type", "audio_stream_channels", "audio_stream_samples"].filter((name) => context.commandNames.has(name));
139
+ if (modernAudioCommands.length > 0) evidence.push(`Modern audio negotiation: ${modernAudioCommands.join(", ")}`);
140
+ return {
141
+ score: 150,
142
+ evidence,
143
+ warnings: context.identity.protocolVersion === "1.5" ? ["AetherSDR reports TCI 1.5 but uses modern scalar audio stream semantics"] : []
144
+ };
145
+ }
146
+ });
147
+ var genericObservedDialect = new StandardTciDialect({
148
+ id: "generic-observed",
149
+ label: "Generic observed TCI",
150
+ streamLengthSemantics: "auto",
151
+ supportsStreamChannels: true,
152
+ supportsTxAudioSource: true,
153
+ driveHasTrx: true,
154
+ detect: (context) => ({
155
+ score: context.commandNames.has("ready") ? 10 : 0,
156
+ evidence: ["No vendor-specific match; using observed command shapes"],
157
+ warnings: ["Dialect identity is uncertain"]
158
+ }),
159
+ resolve: (context) => {
160
+ const drive = [...context.commands].reverse().find((command) => command.name === "drive");
161
+ const driveHasTrx = (drive?.args.length ?? 0) >= 2;
162
+ return new StandardTciDialect({
163
+ id: "generic-observed",
164
+ label: "Generic observed TCI",
165
+ streamLengthSemantics: "auto",
166
+ supportsStreamChannels: context.commandNames.has("audio_stream_channels"),
167
+ supportsTxAudioSource: compareTciVersion(version(context) ?? [0], [2, 0]) >= 0,
168
+ driveHasTrx,
169
+ detect: genericObservedDialect.detect.bind(genericObservedDialect)
170
+ });
171
+ }
172
+ });
173
+ var builtInDialects = [
174
+ aetherSdrDialect,
175
+ thetisDialect,
176
+ expertSdr14Dialect,
177
+ expertSdrLegacyDialect,
178
+ expertSdrModernDialect,
179
+ genericObservedDialect
180
+ ];
181
+ function parseTciVersion(value) {
182
+ if (!value) return void 0;
183
+ const match = value.trim().match(/^(\d+)(?:\.(\d+))?(?:\.(\d+))?/);
184
+ if (!match) return void 0;
185
+ return match.slice(1).filter((part) => part !== void 0).map(Number);
186
+ }
187
+ function compareTciVersion(left, right) {
188
+ const length = Math.max(left.length, right.length);
189
+ for (let index = 0; index < length; index += 1) {
190
+ const difference = (left[index] ?? 0) - (right[index] ?? 0);
191
+ if (difference !== 0) return difference;
192
+ }
193
+ return 0;
194
+ }
195
+ function formatVersion(value) {
196
+ return value.join(".");
197
+ }
198
+
199
+ // src/errors.ts
200
+ var TciError = class extends Error {
201
+ code;
202
+ details;
203
+ constructor(code, message, details) {
204
+ super(message);
205
+ this.name = "TciError";
206
+ this.code = code;
207
+ this.details = details;
208
+ }
209
+ };
210
+
211
+ // src/dialect/registry.ts
212
+ var TciDialectRegistry = class {
213
+ dialects = /* @__PURE__ */ new Map();
214
+ constructor(dialects = builtInDialects) {
215
+ for (const dialect of dialects) this.register(dialect);
216
+ }
217
+ register(dialect) {
218
+ this.dialects.set(dialect.id, dialect);
219
+ }
220
+ get(id) {
221
+ return this.dialects.get(id);
222
+ }
223
+ list() {
224
+ return [...this.dialects.values()];
225
+ }
226
+ select(context, selection = "auto") {
227
+ if (typeof selection === "object") {
228
+ return { dialect: selection, confidence: "manual", evidence: ["Custom dialect supplied by caller"], warnings: [] };
229
+ }
230
+ if (selection !== "auto") {
231
+ const dialect = this.get(selection);
232
+ if (!dialect) throw new TciError("unknown-dialect", `Unknown TCI dialect: ${selection}`);
233
+ return { dialect: dialect.resolve?.(context) ?? dialect, confidence: "manual", evidence: [`Dialect ${selection} selected by caller`], warnings: [] };
234
+ }
235
+ const candidates = this.list().map((dialect) => ({ dialect, result: dialect.detect(context) })).sort((left, right) => right.result.score - left.result.score);
236
+ const selected = candidates[0];
237
+ if (!selected || selected.result.score <= 0) {
238
+ throw new TciError("unknown-dialect", "Unable to identify the TCI server dialect");
239
+ }
240
+ return {
241
+ dialect: selected.dialect.resolve?.(context) ?? selected.dialect,
242
+ confidence: selected.result.score >= 100 ? "high" : selected.result.score >= 70 ? "medium" : "low",
243
+ evidence: selected.result.evidence,
244
+ warnings: selected.result.warnings ?? []
245
+ };
246
+ }
247
+ };
248
+ var defaultTciDialectRegistry = new TciDialectRegistry();
249
+
250
+ // src/dialect/handshake.ts
251
+ var IDENTITY_COMMANDS = /* @__PURE__ */ new Set(["protocol", "device", "trx_count", "channels_count", "channel_count"]);
252
+ var STATE_COMMANDS = /* @__PURE__ */ new Set(["vfo", "modulation", "modulations_list", "trx", "drive"]);
253
+ function parseProtocolIdentity(commands) {
254
+ const protocol = [...commands].reverse().find((command) => command.name === "protocol");
255
+ const device = [...commands].reverse().find((command) => command.name === "device");
256
+ const rawProtocolArgs = protocol?.args ?? [];
257
+ const firstLooksLikeVersion = /^\d+(?:\.\d+){0,2}/.test(rawProtocolArgs[0] ?? "");
258
+ return {
259
+ programName: firstLooksLikeVersion ? void 0 : rawProtocolArgs[0],
260
+ protocolVersion: firstLooksLikeVersion ? rawProtocolArgs[0] : rawProtocolArgs[1],
261
+ rawProtocolArgs: [...rawProtocolArgs],
262
+ device: device?.args.join(",")
263
+ };
264
+ }
265
+ function assertValidTciHandshake(commands) {
266
+ const names = new Set(commands.map((command) => command.name));
267
+ if (!names.has("ready")) throw new TciError("handshake-timeout", "TCI READY was not received");
268
+ const categories = [
269
+ [...IDENTITY_COMMANDS].some((name) => names.has(name)),
270
+ [...STATE_COMMANDS].some((name) => names.has(name))
271
+ ].filter(Boolean).length;
272
+ const identitySignals = [...IDENTITY_COMMANDS].filter((name) => names.has(name)).length;
273
+ if (categories < 2 && identitySignals < 2) {
274
+ throw new TciError("invalid-handshake", "WebSocket opened but did not provide enough TCI initialization evidence");
275
+ }
276
+ }
277
+ export {
278
+ TciDialectRegistry,
279
+ aetherSdrDialect,
280
+ assertValidTciHandshake,
281
+ builtInDialects,
282
+ compareTciVersion,
283
+ defaultTciDialectRegistry,
284
+ expertSdr14Dialect,
285
+ expertSdrLegacyDialect,
286
+ expertSdrModernDialect,
287
+ genericObservedDialect,
288
+ parseProtocolIdentity,
289
+ parseTciVersion,
290
+ thetisDialect
291
+ };
292
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/dialect/builtins.ts","../../src/errors.ts","../../src/dialect/registry.ts","../../src/dialect/handshake.ts"],"sourcesContent":["import type {\n TciDialect,\n TciDialectDetectionContext,\n TciDialectScore,\n TciDriveState,\n TciStreamLengthSemantics,\n} from './types.js';\n\ntype VersionTuple = readonly number[];\n\ninterface StandardDialectOptions {\n id: TciDialect['id'];\n label: string;\n streamLengthSemantics: TciStreamLengthSemantics;\n supportsStreamChannels: boolean;\n supportsTxAudioSource: boolean;\n driveHasTrx: boolean;\n detect: (context: TciDialectDetectionContext) => TciDialectScore;\n resolve?: (context: TciDialectDetectionContext) => TciDialect;\n}\n\nclass StandardTciDialect implements TciDialect {\n readonly id: TciDialect['id'];\n readonly label: string;\n readonly streamLengthSemantics: TciStreamLengthSemantics;\n readonly supportsStreamChannels: boolean;\n readonly supportsTxAudioSource: boolean;\n private readonly driveHasTrx: boolean;\n private readonly detector: StandardDialectOptions['detect'];\n private readonly resolver?: StandardDialectOptions['resolve'];\n\n constructor(options: StandardDialectOptions) {\n this.id = options.id;\n this.label = options.label;\n this.streamLengthSemantics = options.streamLengthSemantics;\n this.supportsStreamChannels = options.supportsStreamChannels;\n this.supportsTxAudioSource = options.supportsTxAudioSource;\n this.driveHasTrx = options.driveHasTrx;\n this.detector = options.detect;\n this.resolver = options.resolve;\n }\n\n detect(context: TciDialectDetectionContext): TciDialectScore {\n return this.detector(context);\n }\n\n resolve(context: TciDialectDetectionContext): TciDialect {\n return this.resolver?.(context) ?? this;\n }\n\n buildDriveSetArgs(trx: number, value: number): readonly unknown[] {\n return this.driveHasTrx ? [trx, value] : [value];\n }\n\n buildDriveReadArgs(trx: number): readonly unknown[] {\n return this.driveHasTrx ? [trx] : [];\n }\n\n parseDrive(args: readonly string[], defaultTrx: number): TciDriveState | undefined {\n return parseDriveState(args, defaultTrx, this.driveHasTrx);\n }\n\n buildTuneDriveSetArgs(trx: number, value: number): readonly unknown[] {\n return this.driveHasTrx ? [trx, value] : [value];\n }\n\n buildTuneDriveReadArgs(trx: number): readonly unknown[] {\n return this.driveHasTrx ? [trx] : [];\n }\n\n parseTuneDrive(args: readonly string[], defaultTrx: number): TciDriveState | undefined {\n return parseDriveState(args, defaultTrx, this.driveHasTrx);\n }\n}\n\nfunction parseDriveState(args: readonly string[], defaultTrx: number, hasTrx: boolean): TciDriveState | undefined {\n const trx = hasTrx ? Number(args[0]) : defaultTrx;\n const value = Number(args[hasTrx ? 1 : 0]);\n if (!Number.isInteger(trx) || !Number.isFinite(value)) return undefined;\n return { trx, value };\n}\n\nfunction version(context: TciDialectDetectionContext): VersionTuple | undefined {\n return parseTciVersion(context.identity.protocolVersion);\n}\n\nfunction programIncludes(context: TciDialectDetectionContext, value: string): boolean {\n return context.identity.programName?.toLowerCase().includes(value) ?? false;\n}\n\nexport const expertSdr14Dialect: TciDialect = new StandardTciDialect({\n id: 'expertsdr-1.4', label: 'ExpertSDR / TCI 1.4', streamLengthSemantics: 'per-channel',\n supportsStreamChannels: false, supportsTxAudioSource: false, driveHasTrx: false,\n detect: (context) => {\n const parsed = version(context);\n if (!parsed || compareTciVersion(parsed, [1, 4]) > 0) return { score: 0, evidence: [] };\n return { score: 80 + (programIncludes(context, 'expert') ? 10 : 0), evidence: [`protocol ${formatVersion(parsed)} <= 1.4`] };\n },\n});\n\nexport const expertSdrLegacyDialect: TciDialect = new StandardTciDialect({\n id: 'expertsdr-1.5-1.8', label: 'ExpertSDR / TCI 1.5-1.8', streamLengthSemantics: 'per-channel',\n supportsStreamChannels: false, supportsTxAudioSource: false, driveHasTrx: true,\n detect: (context) => {\n const parsed = version(context);\n if (!parsed || compareTciVersion(parsed, [1, 5]) < 0 || compareTciVersion(parsed, [1, 9]) >= 0) return { score: 0, evidence: [] };\n return { score: 80 + (programIncludes(context, 'expert') ? 10 : 0), evidence: [`protocol ${formatVersion(parsed)} is in 1.5-1.8`] };\n },\n});\n\nexport const expertSdrModernDialect: TciDialect = new StandardTciDialect({\n id: 'expertsdr-1.9-2.0', label: 'ExpertSDR / TCI 1.9-2.0', streamLengthSemantics: 'scalar',\n supportsStreamChannels: true, supportsTxAudioSource: true, driveHasTrx: true,\n detect: (context) => {\n const parsed = version(context);\n if (!parsed || compareTciVersion(parsed, [1, 9]) < 0) return { score: 0, evidence: [] };\n const future = compareTciVersion(parsed, [2, 0]) > 0;\n return {\n score: 70 + (programIncludes(context, 'expert') ? 15 : 0),\n evidence: [`protocol ${formatVersion(parsed)} uses modern stream negotiation`],\n warnings: future ? [`Unknown future TCI version ${formatVersion(parsed)}; using the modern dialect`] : [],\n };\n },\n});\n\nexport const thetisDialect: TciDialect = new StandardTciDialect({\n id: 'thetis-2.0', label: 'Thetis / TCI 2.0', streamLengthSemantics: 'scalar',\n supportsStreamChannels: true, supportsTxAudioSource: true, driveHasTrx: true,\n detect: (context) => {\n const evidence: string[] = [];\n let score = 0;\n if (programIncludes(context, 'thetis')) { score += 120; evidence.push('PROTOCOL program is Thetis'); }\n const observed = ['tx_frequency_ex', 'tx_profiles_ex', 'tx_profile_ex', 'calibration_ex']\n .filter((name) => context.commandNames.has(name));\n if (observed.length > 0) { score += 100; evidence.push(`Thetis extension commands: ${observed.join(', ')}`); }\n if (/anan|hermes|orion|saturn/i.test(context.identity.device ?? '')) {\n score += 30;\n evidence.push(`Thetis-family device: ${context.identity.device}`);\n }\n return { score, evidence };\n },\n});\n\nexport const aetherSdrDialect: TciDialect = new StandardTciDialect({\n id: 'aethersdr-1.5', label: 'AetherSDR / TCI 1.5 hybrid', streamLengthSemantics: 'scalar',\n supportsStreamChannels: true, supportsTxAudioSource: true, driveHasTrx: true,\n detect: (context) => {\n if (!/^aethersdr$/i.test(context.identity.device ?? '')) return { score: 0, evidence: [] };\n const evidence = [`AetherSDR device identity: ${context.identity.device}`];\n const modernAudioCommands = ['audio_stream_sample_type', 'audio_stream_channels', 'audio_stream_samples']\n .filter((name) => context.commandNames.has(name));\n if (modernAudioCommands.length > 0) evidence.push(`Modern audio negotiation: ${modernAudioCommands.join(', ')}`);\n return {\n score: 150,\n evidence,\n warnings: context.identity.protocolVersion === '1.5'\n ? ['AetherSDR reports TCI 1.5 but uses modern scalar audio stream semantics']\n : [],\n };\n },\n});\n\nexport const genericObservedDialect: TciDialect = new StandardTciDialect({\n id: 'generic-observed', label: 'Generic observed TCI', streamLengthSemantics: 'auto',\n supportsStreamChannels: true, supportsTxAudioSource: true, driveHasTrx: true,\n detect: (context) => ({\n score: context.commandNames.has('ready') ? 10 : 0,\n evidence: ['No vendor-specific match; using observed command shapes'],\n warnings: ['Dialect identity is uncertain'],\n }),\n resolve: (context) => {\n const drive = [...context.commands].reverse().find((command) => command.name === 'drive');\n const driveHasTrx = (drive?.args.length ?? 0) >= 2;\n return new StandardTciDialect({\n id: 'generic-observed',\n label: 'Generic observed TCI',\n streamLengthSemantics: 'auto',\n supportsStreamChannels: context.commandNames.has('audio_stream_channels'),\n supportsTxAudioSource: compareTciVersion(version(context) ?? [0], [2, 0]) >= 0,\n driveHasTrx,\n detect: genericObservedDialect.detect.bind(genericObservedDialect),\n });\n },\n});\n\nexport const builtInDialects: readonly TciDialect[] = [\n aetherSdrDialect, thetisDialect, expertSdr14Dialect, expertSdrLegacyDialect, expertSdrModernDialect, genericObservedDialect,\n];\n\nexport function parseTciVersion(value: string | undefined): VersionTuple | undefined {\n if (!value) return undefined;\n const match = value.trim().match(/^(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?/);\n if (!match) return undefined;\n return match.slice(1).filter((part): part is string => part !== undefined).map(Number);\n}\n\nexport function compareTciVersion(left: VersionTuple, right: VersionTuple): number {\n const length = Math.max(left.length, right.length);\n for (let index = 0; index < length; index += 1) {\n const difference = (left[index] ?? 0) - (right[index] ?? 0);\n if (difference !== 0) return difference;\n }\n return 0;\n}\n\nfunction formatVersion(value: VersionTuple): string { return value.join('.'); }\n","export type TciErrorCode =\n | 'connect-timeout'\n | 'handshake-timeout'\n | 'invalid-handshake'\n | 'unknown-dialect'\n | 'command-timeout'\n | 'not-connected'\n | 'disconnected'\n | 'protocol-error'\n | 'invalid-frame'\n | 'cancelled';\n\nexport class TciError extends Error {\n readonly code: TciErrorCode;\n readonly details?: unknown;\n\n constructor(code: TciErrorCode, message: string, details?: unknown) {\n super(message);\n this.name = 'TciError';\n this.code = code;\n this.details = details;\n }\n}\n\nexport function toTciError(error: unknown, fallbackCode: TciErrorCode = 'protocol-error'): TciError {\n if (error instanceof TciError) {\n return error;\n }\n if (error instanceof Error) {\n return new TciError(fallbackCode, error.message, error);\n }\n return new TciError(fallbackCode, String(error), error);\n}\n","import { TciError } from '../errors.js';\nimport { builtInDialects } from './builtins.js';\nimport type {\n TciDialect,\n TciDialectDetection,\n TciDialectDetectionContext,\n TciDialectId,\n TciDialectSelection,\n} from './types.js';\n\nexport class TciDialectRegistry {\n private readonly dialects = new Map<TciDialectId, TciDialect>();\n\n constructor(dialects: readonly TciDialect[] = builtInDialects) {\n for (const dialect of dialects) this.register(dialect);\n }\n\n register(dialect: TciDialect): void { this.dialects.set(dialect.id, dialect); }\n get(id: TciDialectId): TciDialect | undefined { return this.dialects.get(id); }\n list(): TciDialect[] { return [...this.dialects.values()]; }\n\n select(context: TciDialectDetectionContext, selection: TciDialectSelection = 'auto'): TciDialectDetection {\n if (typeof selection === 'object') {\n return { dialect: selection, confidence: 'manual', evidence: ['Custom dialect supplied by caller'], warnings: [] };\n }\n if (selection !== 'auto') {\n const dialect = this.get(selection);\n if (!dialect) throw new TciError('unknown-dialect', `Unknown TCI dialect: ${selection}`);\n return { dialect: dialect.resolve?.(context) ?? dialect, confidence: 'manual', evidence: [`Dialect ${selection} selected by caller`], warnings: [] };\n }\n\n const candidates = this.list()\n .map((dialect) => ({ dialect, result: dialect.detect(context) }))\n .sort((left, right) => right.result.score - left.result.score);\n const selected = candidates[0];\n if (!selected || selected.result.score <= 0) {\n throw new TciError('unknown-dialect', 'Unable to identify the TCI server dialect');\n }\n return {\n dialect: selected.dialect.resolve?.(context) ?? selected.dialect,\n confidence: selected.result.score >= 100 ? 'high' : selected.result.score >= 70 ? 'medium' : 'low',\n evidence: selected.result.evidence,\n warnings: selected.result.warnings ?? [],\n };\n }\n}\n\nexport const defaultTciDialectRegistry = new TciDialectRegistry();\n","import { TciError } from '../errors.js';\nimport type { TciCommand } from '../protocol/text.js';\nimport type { TciProtocolIdentity } from './types.js';\n\nconst IDENTITY_COMMANDS = new Set(['protocol', 'device', 'trx_count', 'channels_count', 'channel_count']);\nconst STATE_COMMANDS = new Set(['vfo', 'modulation', 'modulations_list', 'trx', 'drive']);\n\nexport function parseProtocolIdentity(commands: readonly TciCommand[]): TciProtocolIdentity {\n const protocol = [...commands].reverse().find((command) => command.name === 'protocol');\n const device = [...commands].reverse().find((command) => command.name === 'device');\n const rawProtocolArgs = protocol?.args ?? [];\n const firstLooksLikeVersion = /^\\d+(?:\\.\\d+){0,2}/.test(rawProtocolArgs[0] ?? '');\n return {\n programName: firstLooksLikeVersion ? undefined : rawProtocolArgs[0],\n protocolVersion: firstLooksLikeVersion ? rawProtocolArgs[0] : rawProtocolArgs[1],\n rawProtocolArgs: [...rawProtocolArgs],\n device: device?.args.join(','),\n };\n}\n\nexport function assertValidTciHandshake(commands: readonly TciCommand[]): void {\n const names = new Set(commands.map((command) => command.name));\n if (!names.has('ready')) throw new TciError('handshake-timeout', 'TCI READY was not received');\n const categories = [\n [...IDENTITY_COMMANDS].some((name) => names.has(name)),\n [...STATE_COMMANDS].some((name) => names.has(name)),\n ].filter(Boolean).length;\n const identitySignals = [...IDENTITY_COMMANDS].filter((name) => names.has(name)).length;\n if (categories < 2 && identitySignals < 2) {\n throw new TciError('invalid-handshake', 'WebSocket opened but did not provide enough TCI initialization evidence');\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  import { T as TciCommand, a as TciCommandInput } from './text-BwCWY1k1.cjs';
2
2
 
3
- type TciErrorCode = 'connect-timeout' | 'command-timeout' | 'not-connected' | 'disconnected' | 'protocol-error' | 'invalid-frame' | 'cancelled';
3
+ type TciErrorCode = 'connect-timeout' | 'handshake-timeout' | 'invalid-handshake' | 'unknown-dialect' | 'command-timeout' | 'not-connected' | 'disconnected' | 'protocol-error' | 'invalid-frame' | 'cancelled';
4
4
  declare class TciError extends Error {
5
5
  readonly code: TciErrorCode;
6
6
  readonly details?: unknown;
@@ -1,6 +1,6 @@
1
1
  import { T as TciCommand, a as TciCommandInput } from './text-BwCWY1k1.js';
2
2
 
3
- type TciErrorCode = 'connect-timeout' | 'command-timeout' | 'not-connected' | 'disconnected' | 'protocol-error' | 'invalid-frame' | 'cancelled';
3
+ type TciErrorCode = 'connect-timeout' | 'handshake-timeout' | 'invalid-handshake' | 'unknown-dialect' | 'command-timeout' | 'not-connected' | 'disconnected' | 'protocol-error' | 'invalid-frame' | 'cancelled';
4
4
  declare class TciError extends Error {
5
5
  readonly code: TciErrorCode;
6
6
  readonly details?: unknown;