@myapihq/cli 2.11.1 → 2.12.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.
|
@@ -6,5 +6,6 @@ export declare const SCHEMA: FlagSchema;
|
|
|
6
6
|
export declare function list(flags: Flags): Promise<void>;
|
|
7
7
|
export declare function create(bodyArg: string | undefined, flags: Flags): Promise<void>;
|
|
8
8
|
export declare function resolve(id: string, flags: Flags): Promise<void>;
|
|
9
|
+
export declare function del(id: string | undefined, flags: Flags): Promise<void>;
|
|
9
10
|
export declare function widget(sub: string | undefined, arg: string | undefined, flags: Flags): Promise<void>;
|
|
10
11
|
export declare function run(subcommand: string | undefined, args: string[], flags: Flags): Promise<void>;
|
|
@@ -13,6 +13,7 @@ export const EXPOSES = [
|
|
|
13
13
|
'GET /feedback/orgs/{org_id}/items',
|
|
14
14
|
'POST /feedback/orgs/{org_id}/items',
|
|
15
15
|
'POST /feedback/orgs/{org_id}/items/{id}/resolve',
|
|
16
|
+
'DELETE /feedback/orgs/{org_id}/items/{id}',
|
|
16
17
|
'POST /feedback/orgs/{org_id}/widgets',
|
|
17
18
|
'DELETE /feedback/orgs/{org_id}/widgets/{id}',
|
|
18
19
|
];
|
|
@@ -92,6 +93,18 @@ export async function resolve(id, flags) {
|
|
|
92
93
|
success(`Resolved ${id}`);
|
|
93
94
|
info('(An unknown id answers the same way, so this is not confirmation the item existed.)');
|
|
94
95
|
}
|
|
96
|
+
export async function del(id, flags) {
|
|
97
|
+
const usage = 'myapi feedback delete <id> [--yes] [--org <id>]';
|
|
98
|
+
const config = requireConfig();
|
|
99
|
+
const orgId = requireOrg(flags, config, usage);
|
|
100
|
+
requireArg(id, 'id', usage);
|
|
101
|
+
// Erases rather than closes. `resolve` is the reversible one; this is not,
|
|
102
|
+
// so it takes the same confirmation every destructive verb here takes.
|
|
103
|
+
await confirmDestructive(flags, `permanently delete feedback ${id} (resolve keeps it; this erases it)`, usage);
|
|
104
|
+
await sdkFeedback.deleteFeedback(config.api_key, orgId, id);
|
|
105
|
+
success(`Deleted ${id}`);
|
|
106
|
+
info('(Idempotent — an unknown id answers the same way, so this is not confirmation the item existed.)');
|
|
107
|
+
}
|
|
95
108
|
export async function widget(sub, arg, flags) {
|
|
96
109
|
const config = requireConfig();
|
|
97
110
|
const orgId = requireOrg(flags, config, 'myapi feedback widget create <name> | revoke <id>');
|
|
@@ -128,6 +141,11 @@ export async function widget(sub, arg, flags) {
|
|
|
128
141
|
error('Usage: myapi feedback widget create <name> [--origins <list>]\n myapi feedback widget revoke <id>');
|
|
129
142
|
}
|
|
130
143
|
const SUBCOMMAND_USAGE = {
|
|
144
|
+
'delete': `myapi feedback delete <id> [--yes] [--org <id>]
|
|
145
|
+
|
|
146
|
+
Erases an item. \`resolve\` closes one and keeps it; this removes it — for spam,
|
|
147
|
+
or a report where somebody typed personal details into the box. Idempotent, and
|
|
148
|
+
an unknown id answers the same way.`,
|
|
131
149
|
'list': `myapi feedback list [--kind bug|issue|suggestion] [--status open|resolved]
|
|
132
150
|
[--limit N] [--offset N] [--org <id>] [--json]
|
|
133
151
|
|
|
@@ -151,6 +169,7 @@ page submit without a credential; you list, filter and resolve the results.
|
|
|
151
169
|
|
|
152
170
|
Subcommands:
|
|
153
171
|
create "<text>" Record one piece of feedback (--kind bug|issue|suggestion)
|
|
172
|
+
delete <id> Erase an item (resolve keeps it; this does not)
|
|
154
173
|
list List feedback, newest first (--kind, --status, --limit, --offset)
|
|
155
174
|
resolve <id> Close a piece of feedback
|
|
156
175
|
widget create <name> Mint a PUBLIC widget key for a site (--origins to restrict)
|
|
@@ -167,6 +186,7 @@ All commands accept --org <id> (or set default: myapi config set-org <id>).`);
|
|
|
167
186
|
switch (subcommand) {
|
|
168
187
|
case 'create': return create(args[0], flags);
|
|
169
188
|
case 'list': return list(flags);
|
|
189
|
+
case 'delete': return del(args[0], flags);
|
|
170
190
|
case 'resolve': return resolve(args[0], flags);
|
|
171
191
|
case 'widget': return widget(args[0], args[1], flags);
|
|
172
192
|
default: error(`Unknown subcommand: ${subcommand}. Run "myapi feedback --help" for a list of valid subcommands.`);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: my-feedback-api
|
|
3
|
-
version: 1.
|
|
3
|
+
version: 1.2.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-199fba185e85ccc91a6858bce4a60e20167a6591dee28cbc475606c72cb8d787
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# MyFeedbackAPI
|
|
@@ -33,12 +33,44 @@ myapi feedback widget create site --origins app.example.com,example.com
|
|
|
33
33
|
Revoke with `myapi feedback widget revoke <id>`. Submissions stop immediately;
|
|
34
34
|
feedback already collected is kept.
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
### Embedding it: one script tag
|
|
37
|
+
|
|
38
|
+
The platform hosts the widget, compiled per key with that widget's routes and
|
|
39
|
+
theme baked in. This is the intended way in — you do not build a UI:
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<script src="https://api.myapihq.com/feedback/in/<widget_key>/widget.js" async></script>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
It renders a button, shows itself only on the routes the widget is configured
|
|
46
|
+
for, and lets the person point at an element or drag a region. It sends `kind`,
|
|
47
|
+
`body`, `page_url`, `route`, `viewport`, plus **either** `target_selector` (they
|
|
48
|
+
clicked something) **or** `target_region` `{x,y,w,h}` (they dragged a box).
|
|
49
|
+
|
|
50
|
+
A wrong key does not break the page: the response is `application/javascript`
|
|
51
|
+
carrying a JS comment that names the fix, so a typo cannot throw a syntax error
|
|
52
|
+
in your app.
|
|
53
|
+
|
|
54
|
+
**No screenshots.** The submit body takes no image and there is no multipart
|
|
55
|
+
form — `target_selector` / `target_region` are the platform's answer to "where
|
|
56
|
+
were they pointing". Do not build a capture step expecting somewhere to put it.
|
|
57
|
+
|
|
58
|
+
### Submitting by hand (only if you cannot use the script)
|
|
59
|
+
|
|
60
|
+
`POST https://api.myapihq.com/feedback/in/<widget_key>` — no auth, no SDK.
|
|
61
|
+
Same fields the widget sends:
|
|
62
|
+
|
|
63
|
+
```js
|
|
64
|
+
await fetch(`https://api.myapihq.com/feedback/in/${WIDGET_KEY}`, {
|
|
65
|
+
method: 'POST',
|
|
66
|
+
headers: { 'Content-Type': 'application/json' },
|
|
67
|
+
body: JSON.stringify({ kind: 'bug', body: text, page_url: location.href }),
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Errors: `WIDGET_NOT_FOUND` (a revoked key reads like an invented one, so keys
|
|
72
|
+
cannot be probed), `ORIGIN_NOT_ALLOWED`, `RATE_LIMITED`, `INVALID_KIND`,
|
|
73
|
+
`BODY_REQUIRED`, `BODY_TOO_LONG`. The key only ever writes.
|
|
42
74
|
|
|
43
75
|
### Kind is a claim, not a guess
|
|
44
76
|
|
|
@@ -69,7 +101,8 @@ that is deliberate, so ids cannot be probed across orgs.
|
|
|
69
101
|
|---|---|
|
|
70
102
|
| `myapi feedback create "<text>" --kind <k>` | Record one item (`--page-url`, `--route` for context) |
|
|
71
103
|
| `myapi feedback list [--kind bug\|issue\|suggestion] [--status open\|resolved] [--limit N] [--offset N]` | List feedback, newest first |
|
|
72
|
-
| `myapi feedback resolve <id>` | Close an item |
|
|
104
|
+
| `myapi feedback resolve <id>` | Close an item, keeping it |
|
|
105
|
+
| `myapi feedback delete <id>` | Erase an item — for spam, or personal details typed into the box |
|
|
73
106
|
| `myapi feedback widget create <name> [--origins a.com,b.com]` | Mint a PUBLIC widget key for a site |
|
|
74
107
|
| `myapi feedback widget revoke <id>` | Revoke a key; collected feedback is kept |
|
|
75
108
|
<!-- generated:end -->
|
|
@@ -99,6 +132,9 @@ myapi feedback resolve <id>
|
|
|
99
132
|
- The widget key is public by design — restrict it with `--origins` rather than hiding it.
|
|
100
133
|
- `resolve` is idempotent and deliberately indistinguishable from an unknown id.
|
|
101
134
|
- Feedback survives widget revocation.
|
|
135
|
+
- **`resolve` keeps, `delete` erases.** A public inbox collects spam and the
|
|
136
|
+
occasional report with personal details in it; `delete` is how those leave.
|
|
137
|
+
Both are idempotent and answer the same for an unknown id.
|
|
102
138
|
|
|
103
139
|
## HTTP (from deployed code)
|
|
104
140
|
|
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.12.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.12.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@types/node": "^25.6.0",
|