@tx5dr/plugin-api 1.0.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/dist/__tests__/ft8-message-type.test.d.ts +2 -0
  2. package/dist/__tests__/ft8-message-type.test.d.ts.map +1 -0
  3. package/dist/__tests__/ft8-message-type.test.js +9 -0
  4. package/dist/__tests__/ft8-message-type.test.js.map +1 -0
  5. package/dist/__tests__/testing-utils.test.d.ts +2 -0
  6. package/dist/__tests__/testing-utils.test.d.ts.map +1 -0
  7. package/dist/__tests__/testing-utils.test.js +151 -0
  8. package/dist/__tests__/testing-utils.test.js.map +1 -0
  9. package/dist/context.d.ts +82 -0
  10. package/dist/context.d.ts.map +1 -0
  11. package/dist/context.js +2 -0
  12. package/dist/context.js.map +1 -0
  13. package/dist/definition.d.ts +181 -0
  14. package/dist/definition.d.ts.map +1 -0
  15. package/dist/definition.js +2 -0
  16. package/dist/definition.js.map +1 -0
  17. package/dist/ft8-message-type.d.ts +21 -0
  18. package/dist/ft8-message-type.d.ts.map +1 -0
  19. package/dist/ft8-message-type.js +21 -0
  20. package/dist/ft8-message-type.js.map +1 -0
  21. package/dist/helpers.d.ts +223 -0
  22. package/dist/helpers.d.ts.map +1 -0
  23. package/dist/helpers.js +2 -0
  24. package/dist/helpers.js.map +1 -0
  25. package/dist/hooks.d.ts +204 -0
  26. package/dist/hooks.d.ts.map +1 -0
  27. package/dist/hooks.js +2 -0
  28. package/dist/hooks.js.map +1 -0
  29. package/dist/index.d.ts +33 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +24 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/runtime.d.ts +116 -0
  34. package/dist/runtime.d.ts.map +1 -0
  35. package/dist/runtime.js +2 -0
  36. package/dist/runtime.js.map +1 -0
  37. package/dist/testing/index.d.ts +83 -0
  38. package/dist/testing/index.d.ts.map +1 -0
  39. package/dist/testing/index.js +190 -0
  40. package/dist/testing/index.js.map +1 -0
  41. package/package.json +48 -0
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ft8-message-type.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ft8-message-type.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/ft8-message-type.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { FT8MessageType as InlinedType } from '../ft8-message-type.js';
3
+ import { FT8MessageType as ContractsType } from '@tx5dr/contracts';
4
+ describe('FT8MessageType inlining', () => {
5
+ it('must match the contracts source of truth', () => {
6
+ expect(InlinedType).toStrictEqual(ContractsType);
7
+ });
8
+ });
9
+ //# sourceMappingURL=ft8-message-type.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ft8-message-type.test.js","sourceRoot":"","sources":["../../src/__tests__/ft8-message-type.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,cAAc,IAAI,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,EAAE,cAAc,IAAI,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEnE,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,CAAC,WAAW,CAAC,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=testing-utils.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing-utils.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/testing-utils.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,151 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { createMockKVStore, createMockLogger, createMockTimers, createMockUIBridge, createMockContext, createMockSlotInfo, createMockParsedMessage, createMockOperatorControl, createMockRadioControl, createMockLogbookAccess, createMockBandAccess, } from '../testing/index.js';
3
+ describe('plugin-api testing utilities', () => {
4
+ describe('createMockKVStore', () => {
5
+ it('supports get/set/delete/getAll', () => {
6
+ const store = createMockKVStore({ key1: 'value1' });
7
+ expect(store.get('key1')).toBe('value1');
8
+ expect(store.get('missing', 'default')).toBe('default');
9
+ store.set('key2', 42);
10
+ expect(store._data.get('key2')).toBe(42);
11
+ store.delete('key1');
12
+ expect(store.getAll()).toEqual({ key2: 42 });
13
+ });
14
+ });
15
+ describe('createMockLogger', () => {
16
+ it('records all log calls', () => {
17
+ const log = createMockLogger();
18
+ log.debug('d', { a: 1 });
19
+ log.info('i');
20
+ log.warn('w');
21
+ log.error('e', new Error('test'));
22
+ expect(log._calls).toHaveLength(4);
23
+ expect(log._calls[0]).toEqual({ level: 'debug', message: 'd', data: { a: 1 } });
24
+ expect(log._calls[1]).toEqual({ level: 'info', message: 'i', data: undefined });
25
+ });
26
+ });
27
+ describe('createMockTimers', () => {
28
+ it('tracks active timers', () => {
29
+ const timers = createMockTimers();
30
+ timers.set('poll', 5000);
31
+ expect(timers._active.get('poll')).toBe(5000);
32
+ timers.clear('poll');
33
+ expect(timers._active.size).toBe(0);
34
+ });
35
+ it('clearAll removes all timers', () => {
36
+ const timers = createMockTimers();
37
+ timers.set('a', 100);
38
+ timers.set('b', 200);
39
+ timers.clearAll();
40
+ expect(timers._active.size).toBe(0);
41
+ });
42
+ });
43
+ describe('createMockUIBridge', () => {
44
+ it('captures sent panel data', () => {
45
+ const ui = createMockUIBridge();
46
+ ui.send('my-panel', { count: 1 });
47
+ ui.send('my-panel', { count: 2 });
48
+ expect(ui._sentData.get('my-panel')).toEqual([{ count: 1 }, { count: 2 }]);
49
+ });
50
+ });
51
+ describe('createMockContext', () => {
52
+ it('creates a full context with defaults', () => {
53
+ const ctx = createMockContext();
54
+ expect(ctx.operator.callsign).toBe('W1AW');
55
+ expect(ctx.operator.grid).toBe('FN31');
56
+ expect(ctx.radio.isConnected).toBe(true);
57
+ expect(ctx.config).toEqual({});
58
+ });
59
+ it('accepts overrides', () => {
60
+ const ctx = createMockContext({
61
+ callsign: 'JA1ABC',
62
+ grid: 'PM95',
63
+ config: { watchNewDxcc: true },
64
+ radio: { band: '40m', frequency: 7074000 },
65
+ });
66
+ expect(ctx.operator.callsign).toBe('JA1ABC');
67
+ expect(ctx.operator.grid).toBe('PM95');
68
+ expect(ctx.config).toEqual({ watchNewDxcc: true });
69
+ expect(ctx.radio.band).toBe('40m');
70
+ });
71
+ it('provides typed access to sub-mocks', () => {
72
+ const ctx = createMockContext();
73
+ ctx.store.global.set('k', 'v');
74
+ expect(ctx.store.global._data.get('k')).toBe('v');
75
+ ctx.log.info('test');
76
+ expect(ctx.log._calls).toHaveLength(1);
77
+ });
78
+ });
79
+ describe('createMockOperatorControl', () => {
80
+ it('has reasonable defaults', () => {
81
+ const op = createMockOperatorControl();
82
+ expect(op.isTransmitting).toBe(false);
83
+ expect(op.mode.name).toBe('FT8');
84
+ });
85
+ it('supports partial overrides', () => {
86
+ const op = createMockOperatorControl({ isTransmitting: true, callsign: 'K1ABC' });
87
+ expect(op.isTransmitting).toBe(true);
88
+ expect(op.callsign).toBe('K1ABC');
89
+ });
90
+ });
91
+ describe('createMockRadioControl', () => {
92
+ it('provides connected radio by default', () => {
93
+ const radio = createMockRadioControl();
94
+ expect(radio.isConnected).toBe(true);
95
+ expect(radio.frequency).toBe(14074000);
96
+ });
97
+ });
98
+ describe('createMockLogbookAccess', () => {
99
+ it('returns false by default for all queries', async () => {
100
+ const logbook = createMockLogbookAccess();
101
+ expect(await logbook.hasWorked('W1AW')).toBe(false);
102
+ expect(await logbook.hasWorkedDXCC('US')).toBe(false);
103
+ expect(await logbook.hasWorkedGrid('FN31')).toBe(false);
104
+ });
105
+ it('accepts custom implementations', async () => {
106
+ const worked = new Set(['W1AW']);
107
+ const logbook = createMockLogbookAccess({
108
+ hasWorked: async (cs) => worked.has(cs),
109
+ });
110
+ expect(await logbook.hasWorked('W1AW')).toBe(true);
111
+ expect(await logbook.hasWorked('K2ABC')).toBe(false);
112
+ });
113
+ });
114
+ describe('createMockBandAccess', () => {
115
+ it('returns empty/null defaults', () => {
116
+ const band = createMockBandAccess();
117
+ expect(band.getActiveCallers()).toEqual([]);
118
+ expect(band.getLatestSlotPack()).toBeNull();
119
+ expect(band.findIdleTransmitFrequency()).toBeNull();
120
+ });
121
+ });
122
+ describe('createMockSlotInfo', () => {
123
+ it('provides FT8 defaults', () => {
124
+ const slot = createMockSlotInfo();
125
+ expect(slot.mode).toBe('FT8');
126
+ expect(slot.id).toBe('slot-0');
127
+ });
128
+ it('accepts overrides', () => {
129
+ const slot = createMockSlotInfo({ id: 'slot-42', cycleNumber: 5 });
130
+ expect(slot.id).toBe('slot-42');
131
+ expect(slot.cycleNumber).toBe(5);
132
+ });
133
+ });
134
+ describe('createMockParsedMessage', () => {
135
+ it('creates a CQ message by default', () => {
136
+ const msg = createMockParsedMessage();
137
+ expect(msg.message.type).toBe('cq');
138
+ expect(msg.rawMessage).toBe('CQ TEST W1AW FN31');
139
+ });
140
+ it('accepts overrides', () => {
141
+ const msg = createMockParsedMessage({
142
+ snr: 5,
143
+ rawMessage: 'CQ DX JA1ABC PM95',
144
+ message: { type: 'cq', senderCallsign: 'JA1ABC', grid: 'PM95' },
145
+ });
146
+ expect(msg.snr).toBe(5);
147
+ expect(msg.rawMessage).toBe('CQ DX JA1ABC PM95');
148
+ });
149
+ });
150
+ });
151
+ //# sourceMappingURL=testing-utils.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing-utils.test.js","sourceRoot":"","sources":["../../src/__tests__/testing-utils.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ import type { KVStore, PluginLogger, PluginTimers, OperatorControl, RadioControl, LogbookAccess, BandAccess, UIBridge } from './helpers.js';
2
+ /**
3
+ * Runtime services exposed to a plugin instance.
4
+ *
5
+ * The host creates a {@link PluginContext} for each loaded plugin/operator
6
+ * combination. It is the main entry point for everything that a plugin can do
7
+ * at runtime: read resolved settings, persist state, control the operator,
8
+ * interact with the radio, publish UI updates and, when permitted, perform HTTP
9
+ * requests.
10
+ *
11
+ * The context is intentionally capability-oriented. If a method is not exposed
12
+ * here, plugin code should treat it as unavailable rather than reaching into
13
+ * TX-5DR internals.
14
+ */
15
+ export interface PluginContext {
16
+ /**
17
+ * Resolved plugin configuration values.
18
+ *
19
+ * The host validates and persists settings, then injects the final values into
20
+ * this readonly map before invoking hooks or lifecycle methods. Use
21
+ * {@link PluginHooks.onConfigChange} to react to updates.
22
+ */
23
+ readonly config: Readonly<Record<string, unknown>>;
24
+ /**
25
+ * Persistent key-value stores provisioned for the plugin.
26
+ *
27
+ * Each scope is isolated by plugin identity. Use `global` for shared plugin
28
+ * data and `operator` for values that should not leak across operators.
29
+ */
30
+ readonly store: {
31
+ /**
32
+ * Storage shared by all operators and all sessions of this plugin.
33
+ */
34
+ readonly global: KVStore;
35
+ /**
36
+ * Storage isolated to the current operator instance.
37
+ */
38
+ readonly operator: KVStore;
39
+ };
40
+ /**
41
+ * Structured logger scoped to the plugin.
42
+ *
43
+ * Messages typically appear in backend logs and, when applicable, in frontend
44
+ * plugin log views.
45
+ */
46
+ readonly log: PluginLogger;
47
+ /**
48
+ * Named timer manager owned by the host.
49
+ *
50
+ * Timers created here are automatically cleaned up when the plugin unloads, so
51
+ * prefer this over raw `setInterval` calls inside plugin code.
52
+ */
53
+ readonly timers: PluginTimers;
54
+ /**
55
+ * Control surface for the current operator.
56
+ */
57
+ readonly operator: OperatorControl;
58
+ /**
59
+ * Access to the physical radio state and tuning controls.
60
+ */
61
+ readonly radio: RadioControl;
62
+ /**
63
+ * Read-only access to logbook-derived history.
64
+ */
65
+ readonly logbook: LogbookAccess;
66
+ /**
67
+ * Read-only access to current-band and slot decode data.
68
+ */
69
+ readonly band: BandAccess;
70
+ /**
71
+ * Bridge for pushing structured data into declarative plugin panels.
72
+ */
73
+ readonly ui: UIBridge;
74
+ /**
75
+ * Permission-gated HTTP client.
76
+ *
77
+ * This method is only available when the plugin declares the corresponding
78
+ * network permission. Treat it as optional and feature-detect before calling.
79
+ */
80
+ readonly fetch?: (url: string, init?: RequestInit) => Promise<Response>;
81
+ }
82
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,aAAa,EACb,UAAU,EACV,QAAQ,EACT,MAAM,cAAc,CAAC;AAEtB;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;;OAMG;IACH,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAEnD;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE;QACd;;WAEG;QACH,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;QAEzB;;WAEG;QACH,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;KAC5B,CAAC;IAEF;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;IAE3B;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAE9B;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IAEnC;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAE7B;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAEhC;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAE1B;;OAEG;IACH,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IAEtB;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CACzE"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":""}
@@ -0,0 +1,181 @@
1
+ import type { PluginSettingDescriptor, PluginQuickAction, PluginQuickSetting, PluginPanelDescriptor, PluginPermission, PluginType } from '@tx5dr/contracts';
2
+ import type { PluginContext } from './context.js';
3
+ import type { PluginHooks } from './hooks.js';
4
+ import type { StrategyRuntime } from './runtime.js';
5
+ /**
6
+ * Describes a TX-5DR plugin module.
7
+ *
8
+ * The default export of a plugin package or entry file must satisfy this
9
+ * interface. It combines declarative metadata, optional UI descriptors and the
10
+ * runtime callbacks that the host invokes after the plugin is loaded.
11
+ *
12
+ * A plugin can be one of two categories:
13
+ * - `strategy`: owns the operator automation state machine and is mutually
14
+ * exclusive per operator.
15
+ * - `utility`: augments the pipeline or UI and can run alongside other utility
16
+ * plugins.
17
+ *
18
+ * The TX-5DR host reads this definition once during load, validates the static
19
+ * fields and then wires the lifecycle callbacks and hooks into the plugin
20
+ * subsystem.
21
+ *
22
+ * @example
23
+ * ```js
24
+ * /** @type {import('@tx5dr/plugin-api').PluginDefinition} *\/
25
+ * export default {
26
+ * name: 'my-plugin',
27
+ * version: '1.0.0',
28
+ * type: 'utility',
29
+ * description: 'Annotates interesting decoded stations.',
30
+ * hooks: {
31
+ * onDecode(messages, ctx) {
32
+ * ctx.log.info('decoded', { count: messages.length });
33
+ * },
34
+ * },
35
+ * };
36
+ * ```
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * import type { PluginDefinition } from '@tx5dr/plugin-api';
41
+ *
42
+ * const plugin: PluginDefinition = {
43
+ * name: 'my-strategy',
44
+ * version: '1.0.0',
45
+ * type: 'strategy',
46
+ * createStrategyRuntime(ctx) {
47
+ * return {
48
+ * decide() {
49
+ * return { stop: false };
50
+ * },
51
+ * getTransmitText() {
52
+ * return null;
53
+ * },
54
+ * requestCall() {},
55
+ * getSnapshot() {
56
+ * return { currentState: 'idle' };
57
+ * },
58
+ * patchContext() {},
59
+ * setState() {},
60
+ * setSlotContent() {},
61
+ * reset() {},
62
+ * };
63
+ * },
64
+ * };
65
+ *
66
+ * export default plugin;
67
+ * ```
68
+ */
69
+ export interface PluginDefinition {
70
+ /**
71
+ * Stable machine-readable plugin identifier.
72
+ *
73
+ * This value is used as the plugin's identity in manifests, persisted
74
+ * configuration, log records and runtime lookups. Treat it as an immutable ID
75
+ * once the plugin is released.
76
+ */
77
+ name: string;
78
+ /**
79
+ * Semantic version of the plugin implementation.
80
+ *
81
+ * The host does not currently enforce a compatibility policy, but publishing a
82
+ * valid semver string makes diagnostics and upgrades much easier.
83
+ */
84
+ version: string;
85
+ /**
86
+ * Declares how the host should schedule and combine this plugin.
87
+ *
88
+ * - `strategy` plugins provide a {@link StrategyRuntime} and are selected as
89
+ * the active automation implementation for an operator.
90
+ * - `utility` plugins participate in filters, scoring, monitoring and UI, but
91
+ * do not own the core automation state machine.
92
+ */
93
+ type: PluginType;
94
+ /**
95
+ * Human-readable summary shown in plugin management UIs.
96
+ *
97
+ * Keep this short and product-oriented so operators can quickly understand the
98
+ * plugin's purpose.
99
+ */
100
+ description?: string;
101
+ /**
102
+ * Explicitly declares privileged capabilities required by the plugin.
103
+ *
104
+ * Permissions allow the host to gate sensitive features such as network
105
+ * access. Always declare the smallest set that the plugin truly needs.
106
+ */
107
+ permissions?: PluginPermission[];
108
+ /**
109
+ * Declarative settings schema for generated configuration forms.
110
+ *
111
+ * Each key becomes a persisted config entry. The host validates and stores the
112
+ * values, then exposes the resolved runtime config through
113
+ * {@link PluginContext.config}. Use this for durable, user-facing settings
114
+ * rather than ephemeral runtime state.
115
+ */
116
+ settings?: Record<string, PluginSettingDescriptor>;
117
+ /**
118
+ * Lightweight button actions shown in operator-facing quick action areas.
119
+ *
120
+ * These are intended for one-shot commands such as reset, clear or manual
121
+ * trigger operations. When clicked, the host invokes
122
+ * {@link PluginHooks.onUserAction} with the configured action id.
123
+ */
124
+ quickActions?: PluginQuickAction[];
125
+ /**
126
+ * Quick settings surfaced in compact operator-facing automation panels.
127
+ *
128
+ * Use these for high-frequency adjustments that operators may need to tweak
129
+ * during operation, such as a threshold, target list or enable flag.
130
+ */
131
+ quickSettings?: PluginQuickSetting[];
132
+ /**
133
+ * Panel descriptors used to render plugin-owned UI sections.
134
+ *
135
+ * Panels are declarative containers. Plugins push live data into them through
136
+ * {@link PluginContext.ui} rather than rendering custom frontend code.
137
+ */
138
+ panels?: PluginPanelDescriptor[];
139
+ /**
140
+ * Declares which persistent storage scopes should be provisioned.
141
+ *
142
+ * Request `global` storage for data shared by the whole station, and
143
+ * `operator` storage for per-operator state. The corresponding stores are then
144
+ * available via {@link PluginContext.store}.
145
+ */
146
+ storage?: {
147
+ scopes: ('global' | 'operator')[];
148
+ };
149
+ /**
150
+ * Creates the strategy runtime for a `strategy` plugin.
151
+ *
152
+ * This method is required when {@link PluginDefinition.type} is `strategy` and
153
+ * should be omitted for utility plugins. The returned runtime becomes the
154
+ * operator's active automation controller.
155
+ */
156
+ createStrategyRuntime?(ctx: PluginContext): StrategyRuntime;
157
+ /**
158
+ * Runs after the plugin instance has been loaded and the context is ready.
159
+ *
160
+ * Use this for startup work such as warming caches, scheduling timers or
161
+ * sending initial panel data. Keep it fast; long-running work should be
162
+ * deferred or done asynchronously.
163
+ */
164
+ onLoad?(ctx: PluginContext): void | Promise<void>;
165
+ /**
166
+ * Runs before the plugin instance is unloaded.
167
+ *
168
+ * Use this to release external resources or flush state that is not already
169
+ * handled through the host abstractions. Any timers created via
170
+ * {@link PluginContext.timers} are cleared automatically by the host.
171
+ */
172
+ onUnload?(ctx: PluginContext): void | Promise<void>;
173
+ /**
174
+ * Event and pipeline hooks implemented by the plugin.
175
+ *
176
+ * Hooks let utility plugins observe or transform the message flow, and let the
177
+ * active strategy participate in decision making.
178
+ */
179
+ hooks?: PluginHooks;
180
+ }
181
+ //# sourceMappingURL=definition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../src/definition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EACvB,iBAAiB,EACjB,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,EAChB,UAAU,EACX,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;OAMG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;;;;;;OAOG;IACH,IAAI,EAAE,UAAU,CAAC;IAEjB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAEjC;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;IAEnD;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAEnC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAErC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,qBAAqB,EAAE,CAAC;IAEjC;;;;;;OAMG;IACH,OAAO,CAAC,EAAE;QAAE,MAAM,EAAE,CAAC,QAAQ,GAAG,UAAU,CAAC,EAAE,CAAA;KAAE,CAAC;IAEhD;;;;;;OAMG;IACH,qBAAqB,CAAC,CAAC,GAAG,EAAE,aAAa,GAAG,eAAe,CAAC;IAE5D;;;;;;OAMG;IACH,MAAM,CAAC,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAElD;;;;;;OAMG;IACH,QAAQ,CAAC,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpD;;;;;OAKG;IACH,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=definition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definition.js","sourceRoot":"","sources":["../src/definition.ts"],"names":[],"mappings":""}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * FT8 message type discriminator values.
3
+ *
4
+ * Inlined from `@tx5dr/contracts` to keep `@tx5dr/plugin-api` free of runtime
5
+ * dependencies. The values MUST remain identical to those in
6
+ * `packages/contracts/src/schema/ft8.schema.ts`.
7
+ *
8
+ * A cross-check test in this package verifies they stay in sync.
9
+ */
10
+ export declare const FT8MessageType: {
11
+ readonly CQ: "cq";
12
+ readonly CALL: "call";
13
+ readonly SIGNAL_REPORT: "signal_report";
14
+ readonly ROGER_REPORT: "roger_report";
15
+ readonly RRR: "rrr";
16
+ readonly SEVENTY_THREE: "73";
17
+ readonly FOX_RR73: "fox_rr73";
18
+ readonly CUSTOM: "custom";
19
+ readonly UNKNOWN: "unknown";
20
+ };
21
+ //# sourceMappingURL=ft8-message-type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ft8-message-type.d.ts","sourceRoot":"","sources":["../src/ft8-message-type.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;CAUjB,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * FT8 message type discriminator values.
3
+ *
4
+ * Inlined from `@tx5dr/contracts` to keep `@tx5dr/plugin-api` free of runtime
5
+ * dependencies. The values MUST remain identical to those in
6
+ * `packages/contracts/src/schema/ft8.schema.ts`.
7
+ *
8
+ * A cross-check test in this package verifies they stay in sync.
9
+ */
10
+ export const FT8MessageType = {
11
+ CQ: 'cq',
12
+ CALL: 'call',
13
+ SIGNAL_REPORT: 'signal_report',
14
+ ROGER_REPORT: 'roger_report',
15
+ RRR: 'rrr',
16
+ SEVENTY_THREE: '73',
17
+ FOX_RR73: 'fox_rr73',
18
+ CUSTOM: 'custom',
19
+ UNKNOWN: 'unknown',
20
+ };
21
+ //# sourceMappingURL=ft8-message-type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ft8-message-type.js","sourceRoot":"","sources":["../src/ft8-message-type.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,EAAE,EAAE,IAAI;IACR,IAAI,EAAE,MAAM;IACZ,aAAa,EAAE,eAAe;IAC9B,YAAY,EAAE,cAAc;IAC5B,GAAG,EAAE,KAAK;IACV,aAAa,EAAE,IAAI;IACnB,QAAQ,EAAE,UAAU;IACpB,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,SAAS;CACV,CAAC"}