@synod-ai/extension-feedback 0.1.1
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 +308 -0
- package/dist/index.d.cts +253 -0
- package/dist/index.d.ts +253 -0
- package/dist/index.js +3213 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +3160 -0
- package/dist/index.mjs.map +1 -0
- package/dist/react.d.cts +24 -0
- package/dist/react.d.ts +24 -0
- package/dist/react.js +86 -0
- package/dist/react.js.map +1 -0
- package/dist/react.mjs +58 -0
- package/dist/react.mjs.map +1 -0
- package/package.json +57 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
type FindingSeverity = 'low' | 'medium' | 'high';
|
|
2
|
+
interface FindingContextJson {
|
|
3
|
+
url?: string;
|
|
4
|
+
/** SPA route or pathname (best-effort). Helps the agent know which "screen" the user was on. */
|
|
5
|
+
route?: string;
|
|
6
|
+
/** Document title — gives the agent a human-readable label for the page. */
|
|
7
|
+
page_title?: string;
|
|
8
|
+
element_text?: string;
|
|
9
|
+
/** outerHTML of the selected element, truncated at ~1500 chars. */
|
|
10
|
+
element_html?: string;
|
|
11
|
+
/** Filtered attribute map of the selected element. */
|
|
12
|
+
element_attributes?: Record<string, string>;
|
|
13
|
+
/**
|
|
14
|
+
* Root-first parent chain, filtered to ancestors with an id or class.
|
|
15
|
+
* Generic wrappers are skipped on the client. Each entry is
|
|
16
|
+
* {tag, id?, className?}.
|
|
17
|
+
*/
|
|
18
|
+
parent_chain?: Array<{
|
|
19
|
+
tag: string;
|
|
20
|
+
id?: string;
|
|
21
|
+
className?: string;
|
|
22
|
+
}>;
|
|
23
|
+
viewport?: {
|
|
24
|
+
width: number;
|
|
25
|
+
height: number;
|
|
26
|
+
};
|
|
27
|
+
user_agent?: string;
|
|
28
|
+
screenshot_data_url?: string;
|
|
29
|
+
batch_id?: string;
|
|
30
|
+
extension_version?: string;
|
|
31
|
+
}
|
|
32
|
+
interface FindingPayload {
|
|
33
|
+
title: string;
|
|
34
|
+
description: string;
|
|
35
|
+
severity: FindingSeverity;
|
|
36
|
+
suggested_action?: 'create_story';
|
|
37
|
+
context_json: FindingContextJson;
|
|
38
|
+
}
|
|
39
|
+
interface ExternalFindingsRequest {
|
|
40
|
+
project_id: string;
|
|
41
|
+
findings: FindingPayload[];
|
|
42
|
+
}
|
|
43
|
+
interface CreatedFinding {
|
|
44
|
+
id: string;
|
|
45
|
+
title: string;
|
|
46
|
+
severity: FindingSeverity;
|
|
47
|
+
}
|
|
48
|
+
interface FindingError {
|
|
49
|
+
index: number;
|
|
50
|
+
error: string;
|
|
51
|
+
}
|
|
52
|
+
interface BatchResponse {
|
|
53
|
+
created: CreatedFinding[];
|
|
54
|
+
errors: FindingError[];
|
|
55
|
+
}
|
|
56
|
+
interface BatchResult {
|
|
57
|
+
created: CreatedFinding[];
|
|
58
|
+
errors: FindingError[];
|
|
59
|
+
}
|
|
60
|
+
type ClientErrorCode = 'AUTH_ERROR' | 'RATE_LIMITED' | 'NETWORK_ERROR' | 'TIMEOUT' | 'SERVER_ERROR' | 'CLIENT_ERROR' | 'CONTEXT_TOO_LARGE';
|
|
61
|
+
interface ClientError extends Error {
|
|
62
|
+
code: ClientErrorCode;
|
|
63
|
+
statusCode?: number;
|
|
64
|
+
retryable: boolean;
|
|
65
|
+
}
|
|
66
|
+
interface FeedbackConfig {
|
|
67
|
+
gatewayUrl: string;
|
|
68
|
+
projectId: string;
|
|
69
|
+
token: string;
|
|
70
|
+
keyCombo?: string;
|
|
71
|
+
timeout?: number;
|
|
72
|
+
maxRetries?: number;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
declare class SynodFeedbackClient {
|
|
76
|
+
private readonly config;
|
|
77
|
+
private _queue;
|
|
78
|
+
private _abortControllers;
|
|
79
|
+
constructor(config: FeedbackConfig);
|
|
80
|
+
/**
|
|
81
|
+
* Add a finding to the local batch queue.
|
|
82
|
+
* Pre-validates context_json size to prevent oversized payloads.
|
|
83
|
+
*/
|
|
84
|
+
queue(finding: FindingPayload): void;
|
|
85
|
+
/**
|
|
86
|
+
* Get the current queue length.
|
|
87
|
+
*/
|
|
88
|
+
get queueLength(): number;
|
|
89
|
+
/**
|
|
90
|
+
* Get a shallow copy of the current queue.
|
|
91
|
+
*/
|
|
92
|
+
getQueueSnapshot(): FindingPayload[];
|
|
93
|
+
/**
|
|
94
|
+
* Clear all items from the queue.
|
|
95
|
+
*/
|
|
96
|
+
clearQueue(): void;
|
|
97
|
+
/**
|
|
98
|
+
* Send all queued findings as a batch to the gateway.
|
|
99
|
+
* On success (201): created items are dequeued; errored items remain.
|
|
100
|
+
* On full failure (after retries): entire batch remains in queue.
|
|
101
|
+
*
|
|
102
|
+
* @returns BatchResult with created and errors arrays
|
|
103
|
+
* @throws ClientError on full failure after retries, or on non-retryable error
|
|
104
|
+
*/
|
|
105
|
+
sendBatch(): Promise<BatchResult>;
|
|
106
|
+
/**
|
|
107
|
+
* POST to the gateway with retry/backoff logic.
|
|
108
|
+
* Retries up to maxRetries times on retryable failures (5xx, 429, network, timeout).
|
|
109
|
+
* Does NOT retry on 401 or other 4xx (except 429).
|
|
110
|
+
*
|
|
111
|
+
* Worst-case wall time: ~1s + timeout + 2s + timeout + 4s + timeout.
|
|
112
|
+
*/
|
|
113
|
+
private postWithRetry;
|
|
114
|
+
/**
|
|
115
|
+
* Process the gateway response: dequeue created items, retain errored items.
|
|
116
|
+
* Findings are matched by their position in the original sent batch.
|
|
117
|
+
*/
|
|
118
|
+
private processResponse;
|
|
119
|
+
/**
|
|
120
|
+
* Remove successfully sent items from the live queue.
|
|
121
|
+
*
|
|
122
|
+
* The sentFindings were a snapshot of the queue at send time. We need to remove
|
|
123
|
+
* the successful ones while keeping the failed ones. Since they were all at the
|
|
124
|
+
* front of the queue (in order), we rebuild: remove createdIndices from [0..sentCount-1].
|
|
125
|
+
*/
|
|
126
|
+
private dequeueByIndices;
|
|
127
|
+
private classifyHttpError;
|
|
128
|
+
private classifyTransportError;
|
|
129
|
+
/**
|
|
130
|
+
* Abort all in-flight requests.
|
|
131
|
+
*/
|
|
132
|
+
destroy(): void;
|
|
133
|
+
private sleep;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
type EnableHandler = () => void;
|
|
137
|
+
type DisableHandler = () => void;
|
|
138
|
+
/**
|
|
139
|
+
* Singleton lifecycle manager for the feedback extension.
|
|
140
|
+
*
|
|
141
|
+
* State machine:
|
|
142
|
+
* uninitialized → (init) → initialized (enabled=false)
|
|
143
|
+
* ↕ enable() / disable()
|
|
144
|
+
* initialized (enabled=true/false)
|
|
145
|
+
*
|
|
146
|
+
* The client and queue are ALWAYS available regardless of `enabled` state —
|
|
147
|
+
* `enabled` is a semantic signal for the interaction layer (SDG-294), not a gate on transport.
|
|
148
|
+
*/
|
|
149
|
+
declare class FeedbackManager {
|
|
150
|
+
private _initialized;
|
|
151
|
+
private _enabled;
|
|
152
|
+
private _client;
|
|
153
|
+
private _config;
|
|
154
|
+
private _enableHandlers;
|
|
155
|
+
private _disableHandlers;
|
|
156
|
+
get initialized(): boolean;
|
|
157
|
+
get enabled(): boolean;
|
|
158
|
+
/** The active client instance, or null if not initialized. */
|
|
159
|
+
get client(): SynodFeedbackClient | null;
|
|
160
|
+
/** The validated config, or null if not initialized. */
|
|
161
|
+
get config(): FeedbackConfig | null;
|
|
162
|
+
/**
|
|
163
|
+
* Initialize the feedback system with configuration.
|
|
164
|
+
* Creates the singleton client instance. Re-init replaces existing state.
|
|
165
|
+
*/
|
|
166
|
+
init(config: FeedbackConfig): void;
|
|
167
|
+
/**
|
|
168
|
+
* Enable the feedback system. Fires all registered onEnable handlers.
|
|
169
|
+
*/
|
|
170
|
+
enable(): void;
|
|
171
|
+
/**
|
|
172
|
+
* Disable the feedback system. Fires all registered onDisable handlers.
|
|
173
|
+
*/
|
|
174
|
+
disable(): void;
|
|
175
|
+
/**
|
|
176
|
+
* Register a handler to be called when enable() is invoked.
|
|
177
|
+
* If already enabled, the handler fires immediately.
|
|
178
|
+
* @returns unregister function
|
|
179
|
+
*/
|
|
180
|
+
onEnable(handler: EnableHandler): () => void;
|
|
181
|
+
/**
|
|
182
|
+
* Register a handler to be called when disable() is invoked.
|
|
183
|
+
* @returns unregister function
|
|
184
|
+
*/
|
|
185
|
+
onDisable(handler: DisableHandler): () => void;
|
|
186
|
+
queue(finding: FindingPayload): void;
|
|
187
|
+
sendBatch(): Promise<BatchResult>;
|
|
188
|
+
get queueLength(): number;
|
|
189
|
+
getQueueSnapshot(): FindingPayload[];
|
|
190
|
+
/**
|
|
191
|
+
* Clear all items from the queue.
|
|
192
|
+
*/
|
|
193
|
+
clearQueue(): void;
|
|
194
|
+
/**
|
|
195
|
+
* Replace the entire queue with the given items.
|
|
196
|
+
* Used by the interaction layer for remove/edit operations.
|
|
197
|
+
*/
|
|
198
|
+
replaceQueue(items: FindingPayload[]): void;
|
|
199
|
+
/**
|
|
200
|
+
* Reset the manager to uninitialized state.
|
|
201
|
+
* Destroys client, clears handlers.
|
|
202
|
+
*/
|
|
203
|
+
destroy(): void;
|
|
204
|
+
private requireClient;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Encode an array of findings into the clipboard transfer format.
|
|
209
|
+
* Screenshots are stripped from every finding's context_json.
|
|
210
|
+
*
|
|
211
|
+
* Empty arrays still encode (returns the prefix + empty-list base64)
|
|
212
|
+
* so consumers can distinguish "Synod clipboard blob with no items" from
|
|
213
|
+
* "not a Synod clipboard blob at all".
|
|
214
|
+
*/
|
|
215
|
+
declare function encodeFindingsToClipboard(findings: FindingPayload[]): string;
|
|
216
|
+
/**
|
|
217
|
+
* Decode a clipboard string back into findings.
|
|
218
|
+
*
|
|
219
|
+
* Returns `{ ok: true, findings }` on success, or `{ ok: false, error }`
|
|
220
|
+
* if the input is not a Synod findings blob, the JSON is malformed, the
|
|
221
|
+
* version is unsupported, or any finding has an invalid shape.
|
|
222
|
+
*
|
|
223
|
+
* On any decode error the consumer should fall back to plain-text paste
|
|
224
|
+
* behaviour (or just show an "invalid clipboard" toast).
|
|
225
|
+
*/
|
|
226
|
+
declare function decodeFindingsFromClipboard(raw: string): {
|
|
227
|
+
ok: true;
|
|
228
|
+
findings: FindingPayload[];
|
|
229
|
+
} | {
|
|
230
|
+
ok: false;
|
|
231
|
+
error: string;
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
declare function init(config: FeedbackConfig): void;
|
|
235
|
+
declare function enable(): void;
|
|
236
|
+
declare function disable(): void;
|
|
237
|
+
declare function onEnable(handler: () => void): () => void;
|
|
238
|
+
declare function onDisable(handler: () => void): () => void;
|
|
239
|
+
declare function sendBatch(): Promise<BatchResult>;
|
|
240
|
+
declare function queue(finding: FindingPayload): void;
|
|
241
|
+
declare function clearQueue(): void;
|
|
242
|
+
declare function replaceQueue(items: FindingPayload[]): void;
|
|
243
|
+
declare function isEnabled(): boolean;
|
|
244
|
+
declare function getQueueSnapshot(): FindingPayload[];
|
|
245
|
+
declare function getQueueLength(): number;
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* @internal Reset singleton state. Intended for test isolation only.
|
|
249
|
+
* Creates a fresh manager and re-registers interaction layer hooks.
|
|
250
|
+
*/
|
|
251
|
+
declare function __resetForTesting(): void;
|
|
252
|
+
|
|
253
|
+
export { type BatchResponse, type BatchResult, type ClientError, type ClientErrorCode, type CreatedFinding, type ExternalFindingsRequest, type FeedbackConfig, FeedbackManager, type FindingContextJson, type FindingError, type FindingPayload, type FindingSeverity, SynodFeedbackClient, __resetForTesting, clearQueue, decodeFindingsFromClipboard, disable, enable, encodeFindingsToClipboard, getQueueLength, getQueueSnapshot, init, isEnabled, onDisable, onEnable, queue, replaceQueue, sendBatch };
|