@myapihq/cli 2.19.2 → 2.20.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.
|
@@ -14,6 +14,21 @@ export declare function _captureFrom(flags: Flags): sdkFeedback.WidgetCapture |
|
|
|
14
14
|
export declare function list(flags: Flags): Promise<void>;
|
|
15
15
|
export declare function create(bodyArg: string | undefined, flags: Flags): Promise<void>;
|
|
16
16
|
export declare function resolve(id: string, flags: Flags): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Turn a report into a Playwright spec.
|
|
19
|
+
*
|
|
20
|
+
* A report that carries a route, an element and an ordered trace of clicks,
|
|
21
|
+
* console errors and failed requests already IS a test — someone hit the bug
|
|
22
|
+
* and recorded the steps. The inversion that makes it a test rather than a
|
|
23
|
+
* replay: the errors in the trace are the reported failure, so the generated
|
|
24
|
+
* assertions are that those errors do NOT happen. It fails on the reported
|
|
25
|
+
* state and passes once the bug is fixed.
|
|
26
|
+
*
|
|
27
|
+
* Prints the spec to stdout so it can be redirected, and takes `--out` for the
|
|
28
|
+
* common case of wanting it on disk. Nothing else is printed to stdout, or a
|
|
29
|
+
* redirect would capture the chatter along with the code.
|
|
30
|
+
*/
|
|
31
|
+
export declare function test(id: string | undefined, flags: Flags): Promise<void>;
|
|
17
32
|
export declare function del(id: string | undefined, flags: Flags): Promise<void>;
|
|
18
33
|
export declare function widget(sub: string | undefined, arg: string | undefined, flags: Flags): Promise<void>;
|
|
19
34
|
export declare const SUBCOMMAND_USAGE: Record<string, string>;
|
|
@@ -8,11 +8,13 @@ import { feedback as sdkFeedback } from '@myapihq/sdk';
|
|
|
8
8
|
import { requireConfig } from '../config.js';
|
|
9
9
|
import { success, error, info, printJson, banner } from '../output.js';
|
|
10
10
|
import { formatDate } from '../utils.js';
|
|
11
|
+
import * as fs from 'node:fs';
|
|
11
12
|
import { requireOrg, requireArg, confirmDestructive } from '../helpers.js';
|
|
12
13
|
export const EXPOSES = [
|
|
13
14
|
'GET /feedback/orgs/{org_id}/items',
|
|
14
15
|
'POST /feedback/orgs/{org_id}/items',
|
|
15
16
|
'POST /feedback/orgs/{org_id}/items/{id}/resolve',
|
|
17
|
+
'GET /feedback/orgs/{org_id}/items/{id}/test',
|
|
16
18
|
'DELETE /feedback/orgs/{org_id}/items/{id}',
|
|
17
19
|
'GET /feedback/orgs/{org_id}/widgets',
|
|
18
20
|
'PATCH /feedback/orgs/{org_id}/widgets/{id}',
|
|
@@ -34,6 +36,8 @@ export const SCHEMA = {
|
|
|
34
36
|
status: 'string',
|
|
35
37
|
body: 'string',
|
|
36
38
|
'page-url': 'string',
|
|
39
|
+
base: 'string',
|
|
40
|
+
out: 'string',
|
|
37
41
|
route: 'string',
|
|
38
42
|
origins: 'string',
|
|
39
43
|
// Capture controls. Paired --x / --no-x rather than --x=true|false so that
|
|
@@ -217,6 +221,39 @@ export async function resolve(id, flags) {
|
|
|
217
221
|
success(`Resolved ${id}`);
|
|
218
222
|
info('(An unknown id answers the same way, so this is not confirmation the item existed.)');
|
|
219
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Turn a report into a Playwright spec.
|
|
226
|
+
*
|
|
227
|
+
* A report that carries a route, an element and an ordered trace of clicks,
|
|
228
|
+
* console errors and failed requests already IS a test — someone hit the bug
|
|
229
|
+
* and recorded the steps. The inversion that makes it a test rather than a
|
|
230
|
+
* replay: the errors in the trace are the reported failure, so the generated
|
|
231
|
+
* assertions are that those errors do NOT happen. It fails on the reported
|
|
232
|
+
* state and passes once the bug is fixed.
|
|
233
|
+
*
|
|
234
|
+
* Prints the spec to stdout so it can be redirected, and takes `--out` for the
|
|
235
|
+
* common case of wanting it on disk. Nothing else is printed to stdout, or a
|
|
236
|
+
* redirect would capture the chatter along with the code.
|
|
237
|
+
*/
|
|
238
|
+
export async function test(id, flags) {
|
|
239
|
+
const usage = 'myapi feedback test <id> [--base https://staging.example.com] [--out <path>]';
|
|
240
|
+
const config = requireConfig();
|
|
241
|
+
const orgId = requireOrg(flags, config, usage);
|
|
242
|
+
requireArg(id, 'id', usage);
|
|
243
|
+
const base = typeof flags.base === 'string' ? flags.base : undefined;
|
|
244
|
+
const spec = await sdkFeedback.getItemTest(config.api_key, orgId, id, base);
|
|
245
|
+
const out = typeof flags.out === 'string' ? flags.out : undefined;
|
|
246
|
+
if (!out) {
|
|
247
|
+
// stdout, unadorned: `myapi feedback test <id> > tests/bug.spec.ts`.
|
|
248
|
+
process.stdout.write(spec.endsWith('\n') ? spec : `${spec}\n`);
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
fs.writeFileSync(out, spec.endsWith('\n') ? spec : `${spec}\n`);
|
|
252
|
+
success(`Wrote ${out}`);
|
|
253
|
+
// It asserts the reported errors do NOT happen, so a red run here is the bug
|
|
254
|
+
// reproducing — not a broken test. Worth saying before someone "fixes" it.
|
|
255
|
+
info('It should FAIL until the bug is fixed — the assertions are that the reported errors stop happening.');
|
|
256
|
+
}
|
|
220
257
|
export async function del(id, flags) {
|
|
221
258
|
const usage = 'myapi feedback delete <id> [--yes] [--org <id>]';
|
|
222
259
|
const config = requireConfig();
|
|
@@ -308,34 +345,18 @@ export async function widget(sub, arg, flags) {
|
|
|
308
345
|
}
|
|
309
346
|
if (Object.keys(theme).length)
|
|
310
347
|
patch.theme = theme;
|
|
311
|
-
//
|
|
312
|
-
//
|
|
313
|
-
//
|
|
314
|
-
// back TRUE. Only the capture object behaves this way — a name-only PATCH
|
|
315
|
-
// leaves it untouched — so the request as a whole merges and this field
|
|
316
|
-
// does not.
|
|
348
|
+
// Only the fields the operator named. The backend merges them into the
|
|
349
|
+
// stored value (myapi-hq#137, live 2026-08-20), so the one they did not
|
|
350
|
+
// mention keeps whatever it was.
|
|
317
351
|
//
|
|
318
|
-
//
|
|
319
|
-
//
|
|
320
|
-
//
|
|
321
|
-
//
|
|
322
|
-
//
|
|
323
|
-
// Remove once the backend merges (cross-repo prompt, 2026-08-20): then
|
|
324
|
-
// `patch.capture = capture` stands alone and the extra read disappears.
|
|
352
|
+
// Until that shipped this had to read the widget first and send the
|
|
353
|
+
// resolved object, because `capture` replaced rather than merged and
|
|
354
|
+
// `--no-text` would switch screenshots back ON. The read is gone; the
|
|
355
|
+
// guarantee is the server's now, which also closes the race two concurrent
|
|
356
|
+
// updates had.
|
|
325
357
|
const capture = _captureFrom(flags);
|
|
326
|
-
if (capture)
|
|
358
|
+
if (capture)
|
|
327
359
|
patch.capture = capture;
|
|
328
|
-
try {
|
|
329
|
-
const current = (await sdkFeedback.listWidgets(config.api_key, orgId)).find(x => x.id === arg);
|
|
330
|
-
if (current?.capture)
|
|
331
|
-
patch.capture = { ...current.capture, ...capture };
|
|
332
|
-
}
|
|
333
|
-
catch {
|
|
334
|
-
// A failed read must not block the change that was asked for. The
|
|
335
|
-
// operator still gets what they typed, and the resolved state printed
|
|
336
|
-
// after the call is the truth either way.
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
360
|
if (Object.keys(patch).length === 0) {
|
|
340
361
|
error('Nothing to change. Pass at least one of --routes, --origins, --name, --accent, --position, --label, --screenshot/--no-screenshot, --text/--no-text.');
|
|
341
362
|
}
|
|
@@ -365,6 +386,19 @@ export async function widget(sub, arg, flags) {
|
|
|
365
386
|
error('Usage: myapi feedback widget create <name> [--origins <list>] [--no-screenshot] [--no-text]\n myapi feedback widget list\n myapi feedback widget update <id> [--routes <list>] [--origins <list>] [--no-screenshot] [--no-text]\n myapi feedback widget revoke <id>');
|
|
366
387
|
}
|
|
367
388
|
export const SUBCOMMAND_USAGE = {
|
|
389
|
+
'test': `myapi feedback test <id> [--base https://staging.example.com] [--out <path>]
|
|
390
|
+
|
|
391
|
+
Render a report as a Playwright spec. A report carrying a route, an element and
|
|
392
|
+
an ordered trace of clicks, console errors and failed requests already IS a
|
|
393
|
+
test; this transcribes it.
|
|
394
|
+
|
|
395
|
+
The assertions are that the reported errors do NOT happen, so it FAILS on the
|
|
396
|
+
reported state and passes once the bug is fixed — the guard arrives with the
|
|
397
|
+
bug. Prints to stdout so it can be redirected; --out writes it instead.
|
|
398
|
+
|
|
399
|
+
--base overrides where the test runs. Without it the report's own page_url is
|
|
400
|
+
used, and a report filed without one answers 422 BASE_URL_REQUIRED rather than
|
|
401
|
+
guessing a host and producing a spec that tests nothing.`,
|
|
368
402
|
'delete': `myapi feedback delete <id> [--yes] [--org <id>]
|
|
369
403
|
|
|
370
404
|
Erases an item. \`resolve\` closes one and keeps it; this removes it — for spam,
|
|
@@ -411,6 +445,7 @@ Subcommands:
|
|
|
411
445
|
delete <id> Erase an item (resolve keeps it; this does not)
|
|
412
446
|
list List feedback, newest first (--kind, --status, --limit, --offset)
|
|
413
447
|
resolve <id> Close a piece of feedback
|
|
448
|
+
test <id> Render the report as a Playwright spec (--base, --out)
|
|
414
449
|
widget create <name> Mint a PUBLIC widget key for a site (--origins to restrict)
|
|
415
450
|
widget list List widgets with the script tag to paste
|
|
416
451
|
widget revoke <id> Revoke a widget key; collected feedback is kept
|
|
@@ -429,6 +464,7 @@ All commands accept --org <id> (or set default: myapi config set-org <id>).`);
|
|
|
429
464
|
case 'list': return list(flags);
|
|
430
465
|
case 'delete': return del(args[0], flags);
|
|
431
466
|
case 'resolve': return resolve(args[0], flags);
|
|
467
|
+
case 'test': return test(args[0], flags);
|
|
432
468
|
case 'widget': return widget(args[0], args[1], flags);
|
|
433
469
|
default: error(`Unknown subcommand: ${subcommand}. Run "myapi feedback --help" for a list of valid subcommands.`);
|
|
434
470
|
}
|
package/dist/completion.js
CHANGED
|
@@ -61,7 +61,7 @@ export const SUBCOMMANDS = {
|
|
|
61
61
|
payments: ['connect', 'status', 'charge', 'list', 'get', 'refund'],
|
|
62
62
|
container: ['create', 'deploy', 'list', 'get', 'logs', 'domain', 'delete'],
|
|
63
63
|
git: ['create', 'list', 'get', 'delete', 'refs', 'log', 'show', 'tree', 'blob', 'diff', 'commit', 'create-branch', 'delete-branch', 'tag', 'merge', 'repack'],
|
|
64
|
-
feedback: ['create', 'list', 'resolve', 'widget'],
|
|
64
|
+
feedback: ['create', 'list', 'resolve', 'test', 'widget'],
|
|
65
65
|
queue: ['create', 'list', 'get', 'delete', 'enqueue', 'jobs', 'job'],
|
|
66
66
|
task: ['create', 'list', 'get', 'claim', 'extend', 'resolve', 'fail', 'cancel'],
|
|
67
67
|
completion: ['install', 'uninstall'],
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: my-feedback-api
|
|
3
|
-
version: 1.
|
|
3
|
+
version: 1.7.0
|
|
4
4
|
description: >
|
|
5
5
|
Collect feedback from the people using what you built. A public widget key lets a page submit without a credential; you list, filter and resolve the results. Kind is chosen by the person reporting, not inferred from their wording.
|
|
6
6
|
triggers: [feedback, bug report, user feedback, feature request, widget, support, complaints, praise]
|
|
7
|
-
checksum: sha256-
|
|
7
|
+
checksum: sha256-a76c44ae06a9693ec4874132f52675d0344dfdbb174fff668cb602b16dca59b7
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# MyFeedbackAPI
|
|
@@ -19,34 +19,32 @@ Two halves: a **widget key** a page embeds, and the **items** it produces.
|
|
|
19
19
|
### The widget key is public, and that is the point
|
|
20
20
|
|
|
21
21
|
`widget create <name>` mints a key that ships in your page source. It is **not a
|
|
22
|
-
secret
|
|
23
|
-
authenticates nobody.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
work. It needs `--origins`, so another site cannot post through it:
|
|
22
|
+
secret**: it names your org so a visitor can submit without signing in, and
|
|
23
|
+
authenticates nobody. Treating it as a credential is the mistake — people hide
|
|
24
|
+
it and the widget stops working. It needs `--origins`, so another site cannot
|
|
25
|
+
post through it:
|
|
27
26
|
|
|
28
27
|
```bash
|
|
29
28
|
myapi feedback widget create site --origins app.example.com,example.com
|
|
30
29
|
```
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
collected feedback is kept.
|
|
31
|
+
`widget revoke <id>`: submissions stop immediately, collected feedback is kept.
|
|
34
32
|
|
|
35
33
|
### Embedding it: one script tag
|
|
36
34
|
|
|
37
35
|
The platform hosts the widget, compiled per key with its routes and theme baked
|
|
38
|
-
in. The intended way in —
|
|
36
|
+
in. The intended way in — no UI to build:
|
|
39
37
|
|
|
40
38
|
```html
|
|
41
39
|
<script src="https://api.myapihq.com/feedback/in/<widget_key>/widget.js" async></script>
|
|
42
40
|
```
|
|
43
41
|
|
|
44
|
-
It shows only on the widget's routes —
|
|
45
|
-
|
|
42
|
+
It shows only on the widget's routes — `widget update <id> --routes
|
|
43
|
+
/app,/app/**`; live in ~5 min, no redeploy.
|
|
46
44
|
|
|
47
|
-
The person points at an element or drags a region; it sends
|
|
45
|
+
The person points at an element or drags a region; it sends `kind`, `body`,
|
|
46
|
+
`page_url`, `route`, `viewport`, plus:
|
|
48
47
|
|
|
49
|
-
- `kind`, `body`, `page_url`, `route`, `viewport`
|
|
50
48
|
- `target_selector` and `target_region` `{x,y,w,h}` — on **every** report: the
|
|
51
49
|
element's bounding box for a click, the dragged box for a drag
|
|
52
50
|
- `target_context` — what the element *was*: text, role, the heading above it
|
|
@@ -55,32 +53,30 @@ The person points at an element or drags a region; it sends:
|
|
|
55
53
|
A wrong key cannot break the page: the response is `application/javascript`
|
|
56
54
|
with a comment naming the fix, so a typo throws no syntax error.
|
|
57
55
|
|
|
58
|
-
**Screenshots are automatic
|
|
59
|
-
|
|
60
|
-
to render never costs the report.
|
|
56
|
+
**Screenshots are automatic.** The widget attaches the picture as a second call
|
|
57
|
+
after the report is saved, so an image that fails to render never costs it.
|
|
61
58
|
|
|
62
59
|
The image is **private in your org's assets**; listing returns a **signed link
|
|
63
|
-
good for ~an hour** (`screenshot_url`) — re-list rather than persisting it.
|
|
64
|
-
|
|
60
|
+
good for ~an hour** (`screenshot_url`) — re-list rather than persisting it. Up
|
|
61
|
+
to 3 MB; over that the report is kept without it.
|
|
65
62
|
|
|
66
63
|
### Submitting by hand (only if you cannot use the script)
|
|
67
64
|
|
|
68
65
|
`POST https://api.myapihq.com/feedback/in/<widget_key>` — no auth, no SDK, same
|
|
69
|
-
fields the widget sends (`kind`, `body`, `page_url`, …).
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
`
|
|
74
|
-
an oversized `trace`). Nothing is saved; the key only writes.
|
|
66
|
+
fields the widget sends (`kind`, `body`, `page_url`, …). Errors:
|
|
67
|
+
`WIDGET_NOT_FOUND` (a revoked key reads like an invented one, so keys cannot be
|
|
68
|
+
probed), `ORIGIN_NOT_ALLOWED`, `RATE_LIMITED`, `INVALID_KIND`, `BODY_REQUIRED`,
|
|
69
|
+
`BODY_TOO_LONG` (>8000), `BODY_TOO_LARGE` (>64 KB, usually an oversized
|
|
70
|
+
`trace`). Nothing is saved; the key only writes.
|
|
75
71
|
|
|
76
72
|
### Kind is a claim, not a guess
|
|
77
73
|
|
|
78
74
|
`--kind` is one of `bug`, `issue`, `suggestion`, and it is **what the reporter
|
|
79
|
-
says it is**. A `bug` means they believe the product is broken —
|
|
80
|
-
|
|
75
|
+
says it is**. A `bug` means they believe the product is broken — more urgent
|
|
76
|
+
than a wish for something new. Do not re-classify from the wording.
|
|
81
77
|
|
|
82
78
|
Classification and duplicate-grouping are designed but not built, so treat
|
|
83
|
-
`kind` as the person's
|
|
79
|
+
`kind` as the person's label, not a processed signal.
|
|
84
80
|
|
|
85
81
|
### Controlling what a report contains
|
|
86
82
|
|
|
@@ -94,7 +90,7 @@ myapi feedback widget update <id> --no-text # keep SHAPE, drop words
|
|
|
94
90
|
|
|
95
91
|
`--no-text` keeps tag, role, id and `data-feedback-id`: on a table row, "row, id
|
|
96
92
|
`row-8`" not the tenant's name. `--screenshot` / `--text` turn one back on.
|
|
97
|
-
Omitted flags are left alone
|
|
93
|
+
Omitted flags are left alone. Live in ~5 min.
|
|
98
94
|
|
|
99
95
|
**In your page**, two levers only you control:
|
|
100
96
|
|
|
@@ -104,8 +100,8 @@ window.__myapiFeedback.identify(); // on sign-out
|
|
|
104
100
|
```
|
|
105
101
|
|
|
106
102
|
Callable any time, even long after load. Your id for your user — opaque to us,
|
|
107
|
-
never resolved, posted to a public endpoint: a label, not
|
|
108
|
-
|
|
103
|
+
never resolved, posted to a public endpoint: a label, not auth. Shows as `from`
|
|
104
|
+
in `feedback list`.
|
|
109
105
|
|
|
110
106
|
Mark an element `data-feedback-ignore` to skip it in the context AND black it out
|
|
111
107
|
in the screenshot.
|
|
@@ -118,19 +114,23 @@ in the screenshot.
|
|
|
118
114
|
| Different rules per page | two widgets, two route sets |
|
|
119
115
|
|
|
120
116
|
The last row is usually right: capture off on record-bearing routes, on
|
|
121
|
-
elsewhere
|
|
117
|
+
elsewhere.
|
|
122
118
|
|
|
123
119
|
### Reading it back
|
|
124
120
|
|
|
125
121
|
Each item carries what was pointed at, how they got there, and a picture.
|
|
126
122
|
`list` summarises it — the element's own text rather than its CSS selector,
|
|
127
123
|
counts of steps/errors/failed requests, whether a screenshot exists, and `from`
|
|
128
|
-
when the page called `identify()`. `--trace` expands
|
|
129
|
-
|
|
124
|
+
when the page called `identify()`. `--trace` expands events; `--json` passes all.
|
|
125
|
+
|
|
126
|
+
Two not to misread: **`trace[].t` is ms since page load**, not clock time. And
|
|
127
|
+
**`target_context.filled` says an input had a value, never what**.
|
|
130
128
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
129
|
+
`feedback test <id>` renders a report as a Playwright spec — a report with a
|
|
130
|
+
route, an element and a trace of clicks and errors already IS a test. It asserts
|
|
131
|
+
the reported errors do NOT happen, so it fails now and passes once fixed.
|
|
132
|
+
`--base` says where to run it; without one the report's `page_url` is used, and
|
|
133
|
+
a report lacking that answers 422 `BASE_URL_REQUIRED`.
|
|
134
134
|
|
|
135
135
|
`delete` removes the screenshot with the report — what matters is somebody
|
|
136
136
|
erasing a report because of what is in the picture.
|
|
@@ -140,7 +140,7 @@ erasing a report because of what is in the picture.
|
|
|
140
140
|
truncation — both describe the whole match set.
|
|
141
141
|
|
|
142
142
|
`resolve <id>` closes an item. An unknown id answers like an already-resolved
|
|
143
|
-
one, so success is not proof it existed —
|
|
143
|
+
one, so success is not proof it existed — so ids cannot be probed.
|
|
144
144
|
<!-- llm:end -->
|
|
145
145
|
|
|
146
146
|
## Commands
|
|
@@ -150,6 +150,7 @@ one, so success is not proof it existed — deliberate, so ids cannot be probed.
|
|
|
150
150
|
| `myapi feedback create "<text>" --kind <k>` | Record one item (`--page-url`, `--route` for context) |
|
|
151
151
|
| `myapi feedback list [--kind bug\|issue\|suggestion] [--status open\|resolved] [--limit N] [--offset N] [--trace]` | List feedback, newest first. Each report summarises what was pointed at, what happened before, and whether a screenshot exists; `--trace` expands the events |
|
|
152
152
|
| `myapi feedback resolve <id>` | Close an item, keeping it |
|
|
153
|
+
| `myapi feedback test <id> [--base <url>] [--out <p>]` | Render the report as a Playwright spec (stdout, or `--out`) |
|
|
153
154
|
| `myapi feedback delete <id>` | Erase an item — for spam, or personal details typed into the box |
|
|
154
155
|
| `myapi feedback widget create <name> [--origins a.com,b.com]` | Mint a PUBLIC widget key for a site |
|
|
155
156
|
| `myapi feedback widget list` | List widgets, each with the script tag to paste |
|
|
@@ -160,25 +161,19 @@ one, so success is not proof it existed — deliberate, so ids cannot be probed.
|
|
|
160
161
|
## Examples
|
|
161
162
|
<!-- llm:start -->
|
|
162
163
|
```bash
|
|
163
|
-
#
|
|
164
|
+
# Mint a key for your site, restrict the origins, paste the tag it prints
|
|
164
165
|
myapi feedback widget create marketing --origins example.com,www.example.com
|
|
165
|
-
# → prints a PUBLIC key to embed in the page
|
|
166
|
-
|
|
167
|
-
# 2. See your widgets and the exact tag to paste
|
|
168
166
|
myapi feedback widget list
|
|
169
167
|
|
|
170
|
-
#
|
|
168
|
+
# Where it appears, and what it may collect — same key either way
|
|
171
169
|
myapi feedback widget update <id> --routes /app,/app/**
|
|
172
170
|
myapi feedback widget update <id> --no-screenshot --no-text # record-bearing routes
|
|
173
171
|
|
|
174
|
-
#
|
|
175
|
-
myapi feedback list --status open
|
|
176
|
-
myapi feedback list --kind bug --limit 20
|
|
177
|
-
|
|
178
|
-
# 5. Record something yourself (support call, your own testing)
|
|
179
|
-
myapi feedback create "checkout 500s on retry" --kind bug --route /checkout
|
|
172
|
+
# Read what came back (`from` shows when the page called identify())
|
|
173
|
+
myapi feedback list --status open --kind bug
|
|
180
174
|
|
|
181
|
-
#
|
|
175
|
+
# Turn a report into a failing Playwright spec, then close or erase it
|
|
176
|
+
myapi feedback test <id> --out tests/regression.spec.ts
|
|
182
177
|
myapi feedback resolve <id>
|
|
183
178
|
myapi feedback delete <id> --yes
|
|
184
179
|
```
|
|
@@ -186,11 +181,10 @@ myapi feedback delete <id> --yes
|
|
|
186
181
|
|
|
187
182
|
## Notes
|
|
188
183
|
|
|
189
|
-
- The
|
|
184
|
+
- The key is public by design — restrict with `--origins`, don't hide it.
|
|
190
185
|
- Feedback survives widget revocation.
|
|
191
186
|
- **`resolve` keeps, `delete` erases.** A public inbox collects spam and the odd
|
|
192
|
-
report with personal details
|
|
193
|
-
idempotent and answer the same for an unknown id, so ids cannot be probed.
|
|
187
|
+
report with personal details; `delete` is how those leave. Both idempotent.
|
|
194
188
|
|
|
195
189
|
## HTTP (from deployed code)
|
|
196
190
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@myapihq/cli",
|
|
3
3
|
"license": "Apache-2.0",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.20.0",
|
|
5
5
|
"description": "MyAPI command-line interface",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"lint:skills:strict": "node scripts/copy-skills.js && node scripts/lint-skills.js --strict"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@myapihq/sdk": "^2.
|
|
49
|
+
"@myapihq/sdk": "^2.20.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@types/node": "^25.6.0",
|