@stephenov/feedbackwidget 0.1.0 → 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.
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +211 -0
- package/dist/cli.mjs +188 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +14 -6
package/dist/cli.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
// src/cli.ts
|
|
27
|
+
var import_http = __toESM(require("http"));
|
|
28
|
+
var import_open = __toESM(require("open"));
|
|
29
|
+
var import_crypto = require("crypto");
|
|
30
|
+
var import_fs = __toESM(require("fs"));
|
|
31
|
+
var import_path = __toESM(require("path"));
|
|
32
|
+
var API_BASE = "https://feedbackwidget-api.vercel.app";
|
|
33
|
+
var CLI_PORT = 9876;
|
|
34
|
+
async function main() {
|
|
35
|
+
const args = process.argv.slice(2);
|
|
36
|
+
const command = args[0];
|
|
37
|
+
if (command === "init") {
|
|
38
|
+
await initProject();
|
|
39
|
+
} else if (command === "whoami") {
|
|
40
|
+
await whoami();
|
|
41
|
+
} else {
|
|
42
|
+
showHelp();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async function initProject() {
|
|
46
|
+
console.log("\n\u{1F3A4} feedbackwidget - Voice-first feedback for your app\n");
|
|
47
|
+
const existingKey = getStoredApiKey();
|
|
48
|
+
if (existingKey) {
|
|
49
|
+
console.log("\u2705 Already configured!");
|
|
50
|
+
console.log(` API Key: ${existingKey.slice(0, 20)}...`);
|
|
51
|
+
console.log("\n To reconfigure, delete .feedbackwidgetrc and run again.\n");
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const state = (0, import_crypto.randomBytes)(16).toString("hex");
|
|
55
|
+
const apiKey = await new Promise((resolve, reject) => {
|
|
56
|
+
const server = import_http.default.createServer((req, res) => {
|
|
57
|
+
const url = new URL(req.url, `http://localhost:${CLI_PORT}`);
|
|
58
|
+
if (url.pathname === "/callback") {
|
|
59
|
+
const receivedState = url.searchParams.get("state");
|
|
60
|
+
const key = url.searchParams.get("key");
|
|
61
|
+
const error = url.searchParams.get("error");
|
|
62
|
+
if (error) {
|
|
63
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
64
|
+
res.end(errorPage(error));
|
|
65
|
+
server.close();
|
|
66
|
+
reject(new Error(error));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (receivedState !== state) {
|
|
70
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
71
|
+
res.end(errorPage("Invalid state - possible CSRF attack"));
|
|
72
|
+
server.close();
|
|
73
|
+
reject(new Error("Invalid state"));
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (key) {
|
|
77
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
78
|
+
res.end(successPage());
|
|
79
|
+
server.close();
|
|
80
|
+
resolve(key);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
server.listen(CLI_PORT, () => {
|
|
85
|
+
const authUrl = `${API_BASE}/cli/auth?state=${state}&port=${CLI_PORT}`;
|
|
86
|
+
console.log("Opening browser to authenticate...\n");
|
|
87
|
+
console.log(` If browser doesn't open, visit:
|
|
88
|
+
${authUrl}
|
|
89
|
+
`);
|
|
90
|
+
(0, import_open.default)(authUrl);
|
|
91
|
+
});
|
|
92
|
+
setTimeout(() => {
|
|
93
|
+
server.close();
|
|
94
|
+
reject(new Error("Authentication timed out"));
|
|
95
|
+
}, 5 * 60 * 1e3);
|
|
96
|
+
});
|
|
97
|
+
saveApiKey(apiKey);
|
|
98
|
+
console.log("\u2705 Authenticated successfully!\n");
|
|
99
|
+
console.log(` API Key: ${apiKey.slice(0, 20)}...`);
|
|
100
|
+
console.log(" Saved to .feedbackwidgetrc\n");
|
|
101
|
+
console.log(" Add to your app:\n");
|
|
102
|
+
console.log(' import { FeedbackWidget } from "@stephenov/feedbackwidget"');
|
|
103
|
+
console.log(` <FeedbackWidget apiKey="${apiKey}" />
|
|
104
|
+
`);
|
|
105
|
+
}
|
|
106
|
+
async function whoami() {
|
|
107
|
+
const apiKey = getStoredApiKey();
|
|
108
|
+
if (!apiKey) {
|
|
109
|
+
console.log("\nNot logged in. Run: npx @stephenov/feedbackwidget init\n");
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
const res = await fetch(`${API_BASE}/api/v1/validate`, {
|
|
114
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
115
|
+
});
|
|
116
|
+
const data = await res.json();
|
|
117
|
+
if (data.valid) {
|
|
118
|
+
console.log(`
|
|
119
|
+
Logged in as: ${data.project?.name || "Unknown"}`);
|
|
120
|
+
console.log(`Plan: ${data.limits?.submissions || 100} submissions/month
|
|
121
|
+
`);
|
|
122
|
+
} else {
|
|
123
|
+
console.log("\nInvalid API key. Run: npx @stephenov/feedbackwidget init\n");
|
|
124
|
+
}
|
|
125
|
+
} catch {
|
|
126
|
+
console.log("\nCouldn't verify API key. Check your connection.\n");
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function showHelp() {
|
|
130
|
+
console.log(`
|
|
131
|
+
\u{1F3A4} feedbackwidget CLI
|
|
132
|
+
|
|
133
|
+
Commands:
|
|
134
|
+
init Authenticate and get your API key
|
|
135
|
+
whoami Show current project info
|
|
136
|
+
|
|
137
|
+
Usage:
|
|
138
|
+
npx @stephenov/feedbackwidget init
|
|
139
|
+
npx @stephenov/feedbackwidget whoami
|
|
140
|
+
`);
|
|
141
|
+
}
|
|
142
|
+
function getStoredApiKey() {
|
|
143
|
+
const rcPath = import_path.default.join(process.cwd(), ".feedbackwidgetrc");
|
|
144
|
+
try {
|
|
145
|
+
const content = import_fs.default.readFileSync(rcPath, "utf-8");
|
|
146
|
+
const match = content.match(/FEEDBACKWIDGET_API_KEY=(.+)/);
|
|
147
|
+
return match ? match[1].trim() : null;
|
|
148
|
+
} catch {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function saveApiKey(apiKey) {
|
|
153
|
+
const rcPath = import_path.default.join(process.cwd(), ".feedbackwidgetrc");
|
|
154
|
+
import_fs.default.writeFileSync(rcPath, `FEEDBACKWIDGET_API_KEY=${apiKey}
|
|
155
|
+
`);
|
|
156
|
+
const gitignorePath = import_path.default.join(process.cwd(), ".gitignore");
|
|
157
|
+
try {
|
|
158
|
+
const gitignore = import_fs.default.readFileSync(gitignorePath, "utf-8");
|
|
159
|
+
if (!gitignore.includes(".feedbackwidgetrc")) {
|
|
160
|
+
import_fs.default.appendFileSync(gitignorePath, "\n.feedbackwidgetrc\n");
|
|
161
|
+
}
|
|
162
|
+
} catch {
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function successPage() {
|
|
166
|
+
return `
|
|
167
|
+
<!DOCTYPE html>
|
|
168
|
+
<html>
|
|
169
|
+
<head>
|
|
170
|
+
<title>feedbackwidget - Authenticated</title>
|
|
171
|
+
<style>
|
|
172
|
+
body { font-family: -apple-system, sans-serif; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; background: #f5f5f5; }
|
|
173
|
+
.card { background: white; padding: 48px; border-radius: 16px; text-align: center; box-shadow: 0 4px 20px rgba(0,0,0,0.1); }
|
|
174
|
+
h1 { font-size: 24px; margin: 0 0 16px; }
|
|
175
|
+
p { color: #666; margin: 0; }
|
|
176
|
+
.emoji { font-size: 48px; margin-bottom: 24px; }
|
|
177
|
+
</style>
|
|
178
|
+
</head>
|
|
179
|
+
<body>
|
|
180
|
+
<div class="card">
|
|
181
|
+
<div class="emoji">\u2705</div>
|
|
182
|
+
<h1>Authenticated!</h1>
|
|
183
|
+
<p>You can close this window and return to your terminal.</p>
|
|
184
|
+
</div>
|
|
185
|
+
</body>
|
|
186
|
+
</html>`;
|
|
187
|
+
}
|
|
188
|
+
function errorPage(error) {
|
|
189
|
+
return `
|
|
190
|
+
<!DOCTYPE html>
|
|
191
|
+
<html>
|
|
192
|
+
<head>
|
|
193
|
+
<title>feedbackwidget - Error</title>
|
|
194
|
+
<style>
|
|
195
|
+
body { font-family: -apple-system, sans-serif; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; background: #f5f5f5; }
|
|
196
|
+
.card { background: white; padding: 48px; border-radius: 16px; text-align: center; box-shadow: 0 4px 20px rgba(0,0,0,0.1); }
|
|
197
|
+
h1 { font-size: 24px; margin: 0 0 16px; color: #e00; }
|
|
198
|
+
p { color: #666; margin: 0; }
|
|
199
|
+
.emoji { font-size: 48px; margin-bottom: 24px; }
|
|
200
|
+
</style>
|
|
201
|
+
</head>
|
|
202
|
+
<body>
|
|
203
|
+
<div class="card">
|
|
204
|
+
<div class="emoji">\u274C</div>
|
|
205
|
+
<h1>Authentication Failed</h1>
|
|
206
|
+
<p>${error}</p>
|
|
207
|
+
</div>
|
|
208
|
+
</body>
|
|
209
|
+
</html>`;
|
|
210
|
+
}
|
|
211
|
+
main().catch(console.error);
|
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import http from "http";
|
|
5
|
+
import open from "open";
|
|
6
|
+
import { randomBytes } from "crypto";
|
|
7
|
+
import fs from "fs";
|
|
8
|
+
import path from "path";
|
|
9
|
+
var API_BASE = "https://feedbackwidget-api.vercel.app";
|
|
10
|
+
var CLI_PORT = 9876;
|
|
11
|
+
async function main() {
|
|
12
|
+
const args = process.argv.slice(2);
|
|
13
|
+
const command = args[0];
|
|
14
|
+
if (command === "init") {
|
|
15
|
+
await initProject();
|
|
16
|
+
} else if (command === "whoami") {
|
|
17
|
+
await whoami();
|
|
18
|
+
} else {
|
|
19
|
+
showHelp();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async function initProject() {
|
|
23
|
+
console.log("\n\u{1F3A4} feedbackwidget - Voice-first feedback for your app\n");
|
|
24
|
+
const existingKey = getStoredApiKey();
|
|
25
|
+
if (existingKey) {
|
|
26
|
+
console.log("\u2705 Already configured!");
|
|
27
|
+
console.log(` API Key: ${existingKey.slice(0, 20)}...`);
|
|
28
|
+
console.log("\n To reconfigure, delete .feedbackwidgetrc and run again.\n");
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const state = randomBytes(16).toString("hex");
|
|
32
|
+
const apiKey = await new Promise((resolve, reject) => {
|
|
33
|
+
const server = http.createServer((req, res) => {
|
|
34
|
+
const url = new URL(req.url, `http://localhost:${CLI_PORT}`);
|
|
35
|
+
if (url.pathname === "/callback") {
|
|
36
|
+
const receivedState = url.searchParams.get("state");
|
|
37
|
+
const key = url.searchParams.get("key");
|
|
38
|
+
const error = url.searchParams.get("error");
|
|
39
|
+
if (error) {
|
|
40
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
41
|
+
res.end(errorPage(error));
|
|
42
|
+
server.close();
|
|
43
|
+
reject(new Error(error));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (receivedState !== state) {
|
|
47
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
48
|
+
res.end(errorPage("Invalid state - possible CSRF attack"));
|
|
49
|
+
server.close();
|
|
50
|
+
reject(new Error("Invalid state"));
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (key) {
|
|
54
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
55
|
+
res.end(successPage());
|
|
56
|
+
server.close();
|
|
57
|
+
resolve(key);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
server.listen(CLI_PORT, () => {
|
|
62
|
+
const authUrl = `${API_BASE}/cli/auth?state=${state}&port=${CLI_PORT}`;
|
|
63
|
+
console.log("Opening browser to authenticate...\n");
|
|
64
|
+
console.log(` If browser doesn't open, visit:
|
|
65
|
+
${authUrl}
|
|
66
|
+
`);
|
|
67
|
+
open(authUrl);
|
|
68
|
+
});
|
|
69
|
+
setTimeout(() => {
|
|
70
|
+
server.close();
|
|
71
|
+
reject(new Error("Authentication timed out"));
|
|
72
|
+
}, 5 * 60 * 1e3);
|
|
73
|
+
});
|
|
74
|
+
saveApiKey(apiKey);
|
|
75
|
+
console.log("\u2705 Authenticated successfully!\n");
|
|
76
|
+
console.log(` API Key: ${apiKey.slice(0, 20)}...`);
|
|
77
|
+
console.log(" Saved to .feedbackwidgetrc\n");
|
|
78
|
+
console.log(" Add to your app:\n");
|
|
79
|
+
console.log(' import { FeedbackWidget } from "@stephenov/feedbackwidget"');
|
|
80
|
+
console.log(` <FeedbackWidget apiKey="${apiKey}" />
|
|
81
|
+
`);
|
|
82
|
+
}
|
|
83
|
+
async function whoami() {
|
|
84
|
+
const apiKey = getStoredApiKey();
|
|
85
|
+
if (!apiKey) {
|
|
86
|
+
console.log("\nNot logged in. Run: npx @stephenov/feedbackwidget init\n");
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
const res = await fetch(`${API_BASE}/api/v1/validate`, {
|
|
91
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
92
|
+
});
|
|
93
|
+
const data = await res.json();
|
|
94
|
+
if (data.valid) {
|
|
95
|
+
console.log(`
|
|
96
|
+
Logged in as: ${data.project?.name || "Unknown"}`);
|
|
97
|
+
console.log(`Plan: ${data.limits?.submissions || 100} submissions/month
|
|
98
|
+
`);
|
|
99
|
+
} else {
|
|
100
|
+
console.log("\nInvalid API key. Run: npx @stephenov/feedbackwidget init\n");
|
|
101
|
+
}
|
|
102
|
+
} catch {
|
|
103
|
+
console.log("\nCouldn't verify API key. Check your connection.\n");
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function showHelp() {
|
|
107
|
+
console.log(`
|
|
108
|
+
\u{1F3A4} feedbackwidget CLI
|
|
109
|
+
|
|
110
|
+
Commands:
|
|
111
|
+
init Authenticate and get your API key
|
|
112
|
+
whoami Show current project info
|
|
113
|
+
|
|
114
|
+
Usage:
|
|
115
|
+
npx @stephenov/feedbackwidget init
|
|
116
|
+
npx @stephenov/feedbackwidget whoami
|
|
117
|
+
`);
|
|
118
|
+
}
|
|
119
|
+
function getStoredApiKey() {
|
|
120
|
+
const rcPath = path.join(process.cwd(), ".feedbackwidgetrc");
|
|
121
|
+
try {
|
|
122
|
+
const content = fs.readFileSync(rcPath, "utf-8");
|
|
123
|
+
const match = content.match(/FEEDBACKWIDGET_API_KEY=(.+)/);
|
|
124
|
+
return match ? match[1].trim() : null;
|
|
125
|
+
} catch {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function saveApiKey(apiKey) {
|
|
130
|
+
const rcPath = path.join(process.cwd(), ".feedbackwidgetrc");
|
|
131
|
+
fs.writeFileSync(rcPath, `FEEDBACKWIDGET_API_KEY=${apiKey}
|
|
132
|
+
`);
|
|
133
|
+
const gitignorePath = path.join(process.cwd(), ".gitignore");
|
|
134
|
+
try {
|
|
135
|
+
const gitignore = fs.readFileSync(gitignorePath, "utf-8");
|
|
136
|
+
if (!gitignore.includes(".feedbackwidgetrc")) {
|
|
137
|
+
fs.appendFileSync(gitignorePath, "\n.feedbackwidgetrc\n");
|
|
138
|
+
}
|
|
139
|
+
} catch {
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function successPage() {
|
|
143
|
+
return `
|
|
144
|
+
<!DOCTYPE html>
|
|
145
|
+
<html>
|
|
146
|
+
<head>
|
|
147
|
+
<title>feedbackwidget - Authenticated</title>
|
|
148
|
+
<style>
|
|
149
|
+
body { font-family: -apple-system, sans-serif; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; background: #f5f5f5; }
|
|
150
|
+
.card { background: white; padding: 48px; border-radius: 16px; text-align: center; box-shadow: 0 4px 20px rgba(0,0,0,0.1); }
|
|
151
|
+
h1 { font-size: 24px; margin: 0 0 16px; }
|
|
152
|
+
p { color: #666; margin: 0; }
|
|
153
|
+
.emoji { font-size: 48px; margin-bottom: 24px; }
|
|
154
|
+
</style>
|
|
155
|
+
</head>
|
|
156
|
+
<body>
|
|
157
|
+
<div class="card">
|
|
158
|
+
<div class="emoji">\u2705</div>
|
|
159
|
+
<h1>Authenticated!</h1>
|
|
160
|
+
<p>You can close this window and return to your terminal.</p>
|
|
161
|
+
</div>
|
|
162
|
+
</body>
|
|
163
|
+
</html>`;
|
|
164
|
+
}
|
|
165
|
+
function errorPage(error) {
|
|
166
|
+
return `
|
|
167
|
+
<!DOCTYPE html>
|
|
168
|
+
<html>
|
|
169
|
+
<head>
|
|
170
|
+
<title>feedbackwidget - Error</title>
|
|
171
|
+
<style>
|
|
172
|
+
body { font-family: -apple-system, sans-serif; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; background: #f5f5f5; }
|
|
173
|
+
.card { background: white; padding: 48px; border-radius: 16px; text-align: center; box-shadow: 0 4px 20px rgba(0,0,0,0.1); }
|
|
174
|
+
h1 { font-size: 24px; margin: 0 0 16px; color: #e00; }
|
|
175
|
+
p { color: #666; margin: 0; }
|
|
176
|
+
.emoji { font-size: 48px; margin-bottom: 24px; }
|
|
177
|
+
</style>
|
|
178
|
+
</head>
|
|
179
|
+
<body>
|
|
180
|
+
<div class="card">
|
|
181
|
+
<div class="emoji">\u274C</div>
|
|
182
|
+
<h1>Authentication Failed</h1>
|
|
183
|
+
<p>${error}</p>
|
|
184
|
+
</div>
|
|
185
|
+
</body>
|
|
186
|
+
</html>`;
|
|
187
|
+
}
|
|
188
|
+
main().catch(console.error);
|
package/dist/index.js
CHANGED
|
@@ -632,7 +632,7 @@ function VoiceRecorder({
|
|
|
632
632
|
}
|
|
633
633
|
|
|
634
634
|
// src/api/client.ts
|
|
635
|
-
var API_BASE = "https://api.
|
|
635
|
+
var API_BASE = "https://feedbackwidget-api.vercel.app/api/v1";
|
|
636
636
|
var FeedbackApiClient = class {
|
|
637
637
|
constructor(apiKey, baseUrl) {
|
|
638
638
|
this.apiKey = apiKey;
|
package/dist/index.mjs
CHANGED
|
@@ -587,7 +587,7 @@ function VoiceRecorder({
|
|
|
587
587
|
}
|
|
588
588
|
|
|
589
589
|
// src/api/client.ts
|
|
590
|
-
var API_BASE = "https://api.
|
|
590
|
+
var API_BASE = "https://feedbackwidget-api.vercel.app/api/v1";
|
|
591
591
|
var FeedbackApiClient = class {
|
|
592
592
|
constructor(apiKey, baseUrl) {
|
|
593
593
|
this.apiKey = apiKey;
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stephenov/feedbackwidget",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Voice-first feedback widget with AI analysis, GitHub, and Slack integration",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"feedbackwidget": "./dist/cli.js"
|
|
10
|
+
},
|
|
8
11
|
"exports": {
|
|
9
12
|
".": {
|
|
10
13
|
"types": "./dist/index.d.ts",
|
|
@@ -17,8 +20,8 @@
|
|
|
17
20
|
"dist"
|
|
18
21
|
],
|
|
19
22
|
"scripts": {
|
|
20
|
-
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
21
|
-
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
23
|
+
"build": "tsup src/index.ts src/cli.ts --format cjs,esm --dts --clean",
|
|
24
|
+
"dev": "tsup src/index.ts src/cli.ts --format cjs,esm --dts --watch",
|
|
22
25
|
"lint": "eslint src/",
|
|
23
26
|
"clean": "rm -rf dist"
|
|
24
27
|
},
|
|
@@ -26,7 +29,11 @@
|
|
|
26
29
|
"react": ">=18.0.0",
|
|
27
30
|
"react-dom": ">=18.0.0"
|
|
28
31
|
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"open": "^10.0.0"
|
|
34
|
+
},
|
|
29
35
|
"devDependencies": {
|
|
36
|
+
"@types/node": "^20.0.0",
|
|
30
37
|
"@types/react": "^18.2.0",
|
|
31
38
|
"@types/react-dom": "^18.2.0",
|
|
32
39
|
"react": "^18.2.0",
|
|
@@ -42,12 +49,13 @@
|
|
|
42
49
|
"react",
|
|
43
50
|
"github",
|
|
44
51
|
"slack",
|
|
45
|
-
"ai"
|
|
52
|
+
"ai",
|
|
53
|
+
"cli"
|
|
46
54
|
],
|
|
47
55
|
"license": "MIT",
|
|
48
56
|
"repository": {
|
|
49
57
|
"type": "git",
|
|
50
|
-
"url": "https://github.com/
|
|
58
|
+
"url": "https://github.com/stephennewman/feedbackwidget"
|
|
51
59
|
},
|
|
52
|
-
"homepage": "https://feedbackwidget.
|
|
60
|
+
"homepage": "https://feedbackwidget-api.vercel.app"
|
|
53
61
|
}
|