@feedhog/js 0.1.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/README.md +215 -0
- package/dist/index.cjs +426 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +338 -0
- package/dist/index.d.ts +338 -0
- package/dist/index.js +398 -0
- package/dist/index.js.map +1 -0
- package/dist/index.min.js +2 -0
- package/package.json +52 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
// src/utils.ts
|
|
2
|
+
var STORAGE_KEY = "feedhog_user";
|
|
3
|
+
function storeUser(user) {
|
|
4
|
+
if (typeof window === "undefined" || !window.localStorage) return;
|
|
5
|
+
try {
|
|
6
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify(user));
|
|
7
|
+
} catch {
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function getStoredUser() {
|
|
11
|
+
if (typeof window === "undefined" || !window.localStorage) return null;
|
|
12
|
+
try {
|
|
13
|
+
const stored = localStorage.getItem(STORAGE_KEY);
|
|
14
|
+
if (!stored) return null;
|
|
15
|
+
return JSON.parse(stored);
|
|
16
|
+
} catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function clearStoredUser() {
|
|
21
|
+
if (typeof window === "undefined" || !window.localStorage) return;
|
|
22
|
+
try {
|
|
23
|
+
localStorage.removeItem(STORAGE_KEY);
|
|
24
|
+
} catch {
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function buildUrl(baseUrl, path, params) {
|
|
28
|
+
const url = new URL(path, baseUrl);
|
|
29
|
+
if (params) {
|
|
30
|
+
for (const [key, value] of Object.entries(params)) {
|
|
31
|
+
if (value === void 0) continue;
|
|
32
|
+
if (Array.isArray(value)) {
|
|
33
|
+
url.searchParams.set(key, value.join(","));
|
|
34
|
+
} else {
|
|
35
|
+
url.searchParams.set(key, String(value));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return url.toString();
|
|
40
|
+
}
|
|
41
|
+
function isBrowser() {
|
|
42
|
+
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
43
|
+
}
|
|
44
|
+
var EventEmitter = class {
|
|
45
|
+
constructor() {
|
|
46
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
47
|
+
}
|
|
48
|
+
on(event, callback) {
|
|
49
|
+
if (!this.listeners.has(event)) {
|
|
50
|
+
this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
51
|
+
}
|
|
52
|
+
this.listeners.get(event).add(callback);
|
|
53
|
+
return () => {
|
|
54
|
+
this.listeners.get(event)?.delete(callback);
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
emit(event, data) {
|
|
58
|
+
this.listeners.get(event)?.forEach((callback) => callback(data));
|
|
59
|
+
}
|
|
60
|
+
off(event, callback) {
|
|
61
|
+
this.listeners.get(event)?.delete(callback);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// src/client.ts
|
|
66
|
+
var DEFAULT_BASE_URL = "https://feedhog.com";
|
|
67
|
+
var FeedhogClient = class {
|
|
68
|
+
constructor(config) {
|
|
69
|
+
if (!config.apiKey) {
|
|
70
|
+
throw new Error("Feedhog: apiKey is required");
|
|
71
|
+
}
|
|
72
|
+
this.apiKey = config.apiKey;
|
|
73
|
+
this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Make an authenticated API request
|
|
77
|
+
*/
|
|
78
|
+
async request(method, path, options) {
|
|
79
|
+
const url = options?.params ? buildUrl(this.baseUrl, path, options.params) : `${this.baseUrl}${path}`;
|
|
80
|
+
const response = await fetch(url, {
|
|
81
|
+
method,
|
|
82
|
+
headers: {
|
|
83
|
+
"Content-Type": "application/json",
|
|
84
|
+
"x-api-key": this.apiKey
|
|
85
|
+
},
|
|
86
|
+
body: options?.body ? JSON.stringify(options.body) : void 0
|
|
87
|
+
});
|
|
88
|
+
const data = await response.json();
|
|
89
|
+
if (!response.ok) {
|
|
90
|
+
const error = data;
|
|
91
|
+
throw new FeedhogApiError(
|
|
92
|
+
error.error || "Unknown error",
|
|
93
|
+
response.status,
|
|
94
|
+
error.details
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
return data;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Identify or create an end user
|
|
101
|
+
*/
|
|
102
|
+
async identify(user) {
|
|
103
|
+
const response = await this.request(
|
|
104
|
+
"POST",
|
|
105
|
+
"/api/v1/identify",
|
|
106
|
+
{ body: user }
|
|
107
|
+
);
|
|
108
|
+
return response.user;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Submit new feedback
|
|
112
|
+
*/
|
|
113
|
+
async submit(input, user) {
|
|
114
|
+
const body = {
|
|
115
|
+
...input
|
|
116
|
+
};
|
|
117
|
+
if (user) {
|
|
118
|
+
body.endUser = user;
|
|
119
|
+
}
|
|
120
|
+
const response = await this.request(
|
|
121
|
+
"POST",
|
|
122
|
+
"/api/v1/feedback",
|
|
123
|
+
{ body }
|
|
124
|
+
);
|
|
125
|
+
return response.feedback;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* List feedback items (paginated)
|
|
129
|
+
*/
|
|
130
|
+
async list(options) {
|
|
131
|
+
return this.request(
|
|
132
|
+
"GET",
|
|
133
|
+
"/api/v1/feedback",
|
|
134
|
+
{
|
|
135
|
+
params: {
|
|
136
|
+
status: options?.status ? Array.isArray(options.status) ? options.status : [options.status] : void 0,
|
|
137
|
+
type: options?.type ? Array.isArray(options.type) ? options.type : [options.type] : void 0,
|
|
138
|
+
search: options?.search,
|
|
139
|
+
sortBy: options?.sortBy,
|
|
140
|
+
page: options?.page,
|
|
141
|
+
limit: options?.limit
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get a single feedback item with details
|
|
148
|
+
*/
|
|
149
|
+
async get(feedbackId, endUserId) {
|
|
150
|
+
const response = await this.request(
|
|
151
|
+
"GET",
|
|
152
|
+
`/api/v1/feedback/${feedbackId}`,
|
|
153
|
+
{
|
|
154
|
+
params: endUserId ? { endUserId } : void 0
|
|
155
|
+
}
|
|
156
|
+
);
|
|
157
|
+
return response.feedback;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Toggle vote on feedback
|
|
161
|
+
*/
|
|
162
|
+
async vote(feedbackId, user) {
|
|
163
|
+
return this.request("POST", `/api/v1/feedback/${feedbackId}/vote`, {
|
|
164
|
+
body: user ? { endUser: user } : {}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Check if user has voted on feedback
|
|
169
|
+
*/
|
|
170
|
+
async hasVoted(feedbackId, endUserId) {
|
|
171
|
+
return this.request("GET", `/api/v1/feedback/${feedbackId}/vote`, {
|
|
172
|
+
params: endUserId ? { endUserId } : void 0
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
var FeedhogApiError = class extends Error {
|
|
177
|
+
constructor(message, status, details) {
|
|
178
|
+
super(message);
|
|
179
|
+
this.status = status;
|
|
180
|
+
this.details = details;
|
|
181
|
+
this.name = "FeedhogApiError";
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// src/index.ts
|
|
186
|
+
var Feedhog = class extends EventEmitter {
|
|
187
|
+
constructor(config) {
|
|
188
|
+
super();
|
|
189
|
+
this.currentUser = null;
|
|
190
|
+
this.client = new FeedhogClient(config);
|
|
191
|
+
if (isBrowser()) {
|
|
192
|
+
const stored = getStoredUser();
|
|
193
|
+
if (stored) {
|
|
194
|
+
this.currentUser = { ...stored, identified: false };
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Get the currently identified user
|
|
200
|
+
*/
|
|
201
|
+
get user() {
|
|
202
|
+
return this.currentUser;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Identify the current user
|
|
206
|
+
*
|
|
207
|
+
* This associates feedback and votes with a specific user in your system.
|
|
208
|
+
* User data is persisted in localStorage for subsequent sessions.
|
|
209
|
+
*
|
|
210
|
+
* @param user - User identity data
|
|
211
|
+
* @returns Promise resolving to the identified user
|
|
212
|
+
*
|
|
213
|
+
* @example
|
|
214
|
+
* ```typescript
|
|
215
|
+
* await feedhog.identify({
|
|
216
|
+
* externalId: 'user-123',
|
|
217
|
+
* email: 'user@example.com',
|
|
218
|
+
* name: 'John Doe',
|
|
219
|
+
* metadata: { plan: 'pro' }
|
|
220
|
+
* });
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
async identify(user) {
|
|
224
|
+
try {
|
|
225
|
+
const identified = await this.client.identify(user);
|
|
226
|
+
this.currentUser = {
|
|
227
|
+
...user,
|
|
228
|
+
identified: true
|
|
229
|
+
};
|
|
230
|
+
if (isBrowser()) {
|
|
231
|
+
storeUser(user);
|
|
232
|
+
}
|
|
233
|
+
this.emit("identify", identified);
|
|
234
|
+
return identified;
|
|
235
|
+
} catch (error) {
|
|
236
|
+
this.emit("error", error);
|
|
237
|
+
throw error;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Submit new feedback
|
|
242
|
+
*
|
|
243
|
+
* If a user has been identified, the feedback will be associated with them.
|
|
244
|
+
*
|
|
245
|
+
* @param input - Feedback data
|
|
246
|
+
* @returns Promise resolving to the created feedback item
|
|
247
|
+
*
|
|
248
|
+
* @example
|
|
249
|
+
* ```typescript
|
|
250
|
+
* const feedback = await feedhog.submit({
|
|
251
|
+
* title: 'Add dark mode',
|
|
252
|
+
* description: 'Would love a dark theme option',
|
|
253
|
+
* type: 'idea'
|
|
254
|
+
* });
|
|
255
|
+
* console.log('Feedback submitted:', feedback.id);
|
|
256
|
+
* ```
|
|
257
|
+
*/
|
|
258
|
+
async submit(input) {
|
|
259
|
+
try {
|
|
260
|
+
const feedback = await this.client.submit(
|
|
261
|
+
input,
|
|
262
|
+
this.currentUser || void 0
|
|
263
|
+
);
|
|
264
|
+
this.emit("submit", feedback);
|
|
265
|
+
return feedback;
|
|
266
|
+
} catch (error) {
|
|
267
|
+
this.emit("error", error);
|
|
268
|
+
throw error;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* List feedback items
|
|
273
|
+
*
|
|
274
|
+
* Returns a paginated list of feedback for the project.
|
|
275
|
+
*
|
|
276
|
+
* @param options - Filter and pagination options
|
|
277
|
+
* @returns Promise resolving to paginated feedback list
|
|
278
|
+
*
|
|
279
|
+
* @example
|
|
280
|
+
* ```typescript
|
|
281
|
+
* // Get all ideas in "planned" status
|
|
282
|
+
* const { items, total } = await feedhog.list({
|
|
283
|
+
* status: ['planned', 'in-progress'],
|
|
284
|
+
* type: 'idea',
|
|
285
|
+
* sortBy: 'votes',
|
|
286
|
+
* limit: 10
|
|
287
|
+
* });
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
290
|
+
async list(options) {
|
|
291
|
+
try {
|
|
292
|
+
return await this.client.list(options);
|
|
293
|
+
} catch (error) {
|
|
294
|
+
this.emit("error", error);
|
|
295
|
+
throw error;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Get a single feedback item with full details
|
|
300
|
+
*
|
|
301
|
+
* @param feedbackId - ID of the feedback item
|
|
302
|
+
* @returns Promise resolving to feedback details including comments
|
|
303
|
+
*
|
|
304
|
+
* @example
|
|
305
|
+
* ```typescript
|
|
306
|
+
* const feedback = await feedhog.get('abc123');
|
|
307
|
+
* console.log('Comments:', feedback.comments.length);
|
|
308
|
+
* console.log('Has voted:', feedback.userHasVoted);
|
|
309
|
+
* ```
|
|
310
|
+
*/
|
|
311
|
+
async get(feedbackId) {
|
|
312
|
+
try {
|
|
313
|
+
return await this.client.get(
|
|
314
|
+
feedbackId,
|
|
315
|
+
this.currentUser?.externalId
|
|
316
|
+
);
|
|
317
|
+
} catch (error) {
|
|
318
|
+
this.emit("error", error);
|
|
319
|
+
throw error;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Toggle vote on a feedback item
|
|
324
|
+
*
|
|
325
|
+
* If the user has already voted, this will remove their vote.
|
|
326
|
+
* If they haven't voted, it will add their vote.
|
|
327
|
+
*
|
|
328
|
+
* @param feedbackId - ID of the feedback item to vote on
|
|
329
|
+
* @returns Promise resolving to vote result
|
|
330
|
+
*
|
|
331
|
+
* @example
|
|
332
|
+
* ```typescript
|
|
333
|
+
* const { voted, voteCount } = await feedhog.vote('abc123');
|
|
334
|
+
* console.log(voted ? 'Vote added' : 'Vote removed');
|
|
335
|
+
* console.log('Total votes:', voteCount);
|
|
336
|
+
* ```
|
|
337
|
+
*/
|
|
338
|
+
async vote(feedbackId) {
|
|
339
|
+
try {
|
|
340
|
+
const result = await this.client.vote(
|
|
341
|
+
feedbackId,
|
|
342
|
+
this.currentUser || void 0
|
|
343
|
+
);
|
|
344
|
+
this.emit("vote", { feedbackId, result });
|
|
345
|
+
return result;
|
|
346
|
+
} catch (error) {
|
|
347
|
+
this.emit("error", error);
|
|
348
|
+
throw error;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Check if the current user has voted on a feedback item
|
|
353
|
+
*
|
|
354
|
+
* @param feedbackId - ID of the feedback item
|
|
355
|
+
* @returns Promise resolving to vote status
|
|
356
|
+
*
|
|
357
|
+
* @example
|
|
358
|
+
* ```typescript
|
|
359
|
+
* const { voted, voteCount } = await feedhog.hasVoted('abc123');
|
|
360
|
+
* ```
|
|
361
|
+
*/
|
|
362
|
+
async hasVoted(feedbackId) {
|
|
363
|
+
try {
|
|
364
|
+
return await this.client.hasVoted(
|
|
365
|
+
feedbackId,
|
|
366
|
+
this.currentUser?.externalId
|
|
367
|
+
);
|
|
368
|
+
} catch (error) {
|
|
369
|
+
this.emit("error", error);
|
|
370
|
+
throw error;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Reset the SDK state
|
|
375
|
+
*
|
|
376
|
+
* Clears the current user and removes stored data.
|
|
377
|
+
* Use this when a user logs out.
|
|
378
|
+
*
|
|
379
|
+
* @example
|
|
380
|
+
* ```typescript
|
|
381
|
+
* feedhog.reset();
|
|
382
|
+
* ```
|
|
383
|
+
*/
|
|
384
|
+
reset() {
|
|
385
|
+
this.currentUser = null;
|
|
386
|
+
if (isBrowser()) {
|
|
387
|
+
clearStoredUser();
|
|
388
|
+
}
|
|
389
|
+
this.emit("reset", void 0);
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
var index_default = Feedhog;
|
|
393
|
+
export {
|
|
394
|
+
Feedhog,
|
|
395
|
+
FeedhogApiError,
|
|
396
|
+
index_default as default
|
|
397
|
+
};
|
|
398
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils.ts","../src/client.ts","../src/index.ts"],"sourcesContent":["/**\n * Feedhog SDK Utilities\n */\n\nconst STORAGE_KEY = \"feedhog_user\";\n\n/**\n * Store user identity in localStorage (if available)\n */\nexport function storeUser(user: {\n externalId: string;\n email?: string;\n name?: string;\n avatarUrl?: string;\n}): void {\n if (typeof window === \"undefined\" || !window.localStorage) return;\n\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(user));\n } catch {\n // Ignore storage errors (quota exceeded, private mode, etc.)\n }\n}\n\n/**\n * Retrieve stored user identity from localStorage\n */\nexport function getStoredUser(): {\n externalId: string;\n email?: string;\n name?: string;\n avatarUrl?: string;\n} | null {\n if (typeof window === \"undefined\" || !window.localStorage) return null;\n\n try {\n const stored = localStorage.getItem(STORAGE_KEY);\n if (!stored) return null;\n return JSON.parse(stored);\n } catch {\n return null;\n }\n}\n\n/**\n * Clear stored user identity\n */\nexport function clearStoredUser(): void {\n if (typeof window === \"undefined\" || !window.localStorage) return;\n\n try {\n localStorage.removeItem(STORAGE_KEY);\n } catch {\n // Ignore storage errors\n }\n}\n\n/**\n * Build URL with query parameters\n */\nexport function buildUrl(\n baseUrl: string,\n path: string,\n params?: Record<string, string | string[] | number | undefined>\n): string {\n const url = new URL(path, baseUrl);\n\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value === undefined) continue;\n\n if (Array.isArray(value)) {\n url.searchParams.set(key, value.join(\",\"));\n } else {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n return url.toString();\n}\n\n/**\n * Check if we're running in a browser environment\n */\nexport function isBrowser(): boolean {\n return typeof window !== \"undefined\" && typeof document !== \"undefined\";\n}\n\n/**\n * Simple event emitter for SDK events\n */\nexport class EventEmitter<Events extends { [key: string]: unknown }> {\n private listeners: Map<keyof Events, Set<(data: unknown) => void>> =\n new Map();\n\n on<K extends keyof Events>(\n event: K,\n callback: (data: Events[K]) => void\n ): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(callback as (data: unknown) => void);\n\n // Return unsubscribe function\n return () => {\n this.listeners.get(event)?.delete(callback as (data: unknown) => void);\n };\n }\n\n emit<K extends keyof Events>(event: K, data: Events[K]): void {\n this.listeners.get(event)?.forEach((callback) => callback(data));\n }\n\n off<K extends keyof Events>(\n event: K,\n callback: (data: Events[K]) => void\n ): void {\n this.listeners.get(event)?.delete(callback as (data: unknown) => void);\n }\n}\n","/**\n * Feedhog API Client\n * Handles all HTTP communication with the Feedhog API.\n */\n\nimport type {\n FeedhogConfig,\n UserIdentity,\n SubmitFeedbackInput,\n ListFeedbackOptions,\n FeedbackListItem,\n FeedbackDetail,\n PaginatedResponse,\n VoteResult,\n IdentifiedUser,\n ApiError,\n} from \"./types\";\nimport { buildUrl } from \"./utils\";\n\nconst DEFAULT_BASE_URL = \"https://feedhog.com\";\n\nexport class FeedhogClient {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n\n constructor(config: FeedhogConfig) {\n if (!config.apiKey) {\n throw new Error(\"Feedhog: apiKey is required\");\n }\n\n this.apiKey = config.apiKey;\n this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\\/$/, \"\");\n }\n\n /**\n * Make an authenticated API request\n */\n private async request<T>(\n method: string,\n path: string,\n options?: {\n body?: unknown;\n params?: Record<string, string | string[] | number | undefined>;\n }\n ): Promise<T> {\n const url = options?.params\n ? buildUrl(this.baseUrl, path, options.params)\n : `${this.baseUrl}${path}`;\n\n const response = await fetch(url, {\n method,\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": this.apiKey,\n },\n body: options?.body ? JSON.stringify(options.body) : undefined,\n });\n\n const data = await response.json();\n\n if (!response.ok) {\n const error = data as ApiError;\n throw new FeedhogApiError(\n error.error || \"Unknown error\",\n response.status,\n error.details\n );\n }\n\n return data as T;\n }\n\n /**\n * Identify or create an end user\n */\n async identify(user: UserIdentity): Promise<IdentifiedUser> {\n const response = await this.request<{ user: IdentifiedUser }>(\n \"POST\",\n \"/api/v1/identify\",\n { body: user }\n );\n return response.user;\n }\n\n /**\n * Submit new feedback\n */\n async submit(\n input: SubmitFeedbackInput,\n user?: UserIdentity\n ): Promise<FeedbackListItem> {\n const body: SubmitFeedbackInput & { endUser?: UserIdentity } = {\n ...input,\n };\n if (user) {\n body.endUser = user;\n }\n\n const response = await this.request<{ feedback: FeedbackListItem }>(\n \"POST\",\n \"/api/v1/feedback\",\n { body }\n );\n return response.feedback;\n }\n\n /**\n * List feedback items (paginated)\n */\n async list(\n options?: ListFeedbackOptions\n ): Promise<PaginatedResponse<FeedbackListItem>> {\n return this.request<PaginatedResponse<FeedbackListItem>>(\n \"GET\",\n \"/api/v1/feedback\",\n {\n params: {\n status: options?.status\n ? Array.isArray(options.status)\n ? options.status\n : [options.status]\n : undefined,\n type: options?.type\n ? Array.isArray(options.type)\n ? options.type\n : [options.type]\n : undefined,\n search: options?.search,\n sortBy: options?.sortBy,\n page: options?.page,\n limit: options?.limit,\n },\n }\n );\n }\n\n /**\n * Get a single feedback item with details\n */\n async get(feedbackId: string, endUserId?: string): Promise<FeedbackDetail> {\n const response = await this.request<{ feedback: FeedbackDetail }>(\n \"GET\",\n `/api/v1/feedback/${feedbackId}`,\n {\n params: endUserId ? { endUserId } : undefined,\n }\n );\n return response.feedback;\n }\n\n /**\n * Toggle vote on feedback\n */\n async vote(feedbackId: string, user?: UserIdentity): Promise<VoteResult> {\n return this.request<VoteResult>(\"POST\", `/api/v1/feedback/${feedbackId}/vote`, {\n body: user ? { endUser: user } : {},\n });\n }\n\n /**\n * Check if user has voted on feedback\n */\n async hasVoted(feedbackId: string, endUserId?: string): Promise<VoteResult> {\n return this.request<VoteResult>(\"GET\", `/api/v1/feedback/${feedbackId}/vote`, {\n params: endUserId ? { endUserId } : undefined,\n });\n }\n}\n\n/**\n * API Error with status code and optional validation details\n */\nexport class FeedhogApiError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly details?: {\n formErrors: string[];\n fieldErrors: Record<string, string[]>;\n }\n ) {\n super(message);\n this.name = \"FeedhogApiError\";\n }\n}\n","/**\n * Feedhog JavaScript SDK\n *\n * Collect user feedback from any website or application.\n *\n * @example\n * ```typescript\n * import Feedhog from '@feedhog/js';\n *\n * const feedhog = new Feedhog({ apiKey: 'fhpk_xxx' });\n *\n * // Identify the current user (optional but recommended)\n * feedhog.identify({\n * externalId: 'user-123',\n * email: 'user@example.com',\n * name: 'John Doe'\n * });\n *\n * // Submit feedback\n * await feedhog.submit({\n * title: 'Add dark mode',\n * description: 'Would love a dark theme option',\n * type: 'idea'\n * });\n * ```\n */\n\nimport { FeedhogClient, FeedhogApiError } from \"./client\";\nimport {\n storeUser,\n getStoredUser,\n clearStoredUser,\n EventEmitter,\n isBrowser,\n} from \"./utils\";\nimport type {\n FeedhogConfig,\n UserIdentity,\n SubmitFeedbackInput,\n ListFeedbackOptions,\n FeedbackListItem,\n FeedbackDetail,\n PaginatedResponse,\n VoteResult,\n IdentifiedUser,\n CurrentUser,\n FeedbackType,\n FeedbackStatus,\n SortBy,\n} from \"./types\";\n\n// SDK Events\ninterface FeedhogEvents {\n [key: string]: unknown;\n identify: IdentifiedUser;\n submit: FeedbackListItem;\n vote: { feedbackId: string; result: VoteResult };\n error: Error;\n reset: void;\n}\n\n/**\n * Feedhog SDK main class\n */\nexport class Feedhog extends EventEmitter<FeedhogEvents> {\n private readonly client: FeedhogClient;\n private currentUser: CurrentUser | null = null;\n\n constructor(config: FeedhogConfig) {\n super();\n this.client = new FeedhogClient(config);\n\n // Try to restore user from storage\n if (isBrowser()) {\n const stored = getStoredUser();\n if (stored) {\n this.currentUser = { ...stored, identified: false };\n }\n }\n }\n\n /**\n * Get the currently identified user\n */\n get user(): CurrentUser | null {\n return this.currentUser;\n }\n\n /**\n * Identify the current user\n *\n * This associates feedback and votes with a specific user in your system.\n * User data is persisted in localStorage for subsequent sessions.\n *\n * @param user - User identity data\n * @returns Promise resolving to the identified user\n *\n * @example\n * ```typescript\n * await feedhog.identify({\n * externalId: 'user-123',\n * email: 'user@example.com',\n * name: 'John Doe',\n * metadata: { plan: 'pro' }\n * });\n * ```\n */\n async identify(user: UserIdentity): Promise<IdentifiedUser> {\n try {\n const identified = await this.client.identify(user);\n\n this.currentUser = {\n ...user,\n identified: true,\n };\n\n // Persist to storage\n if (isBrowser()) {\n storeUser(user);\n }\n\n this.emit(\"identify\", identified);\n return identified;\n } catch (error) {\n this.emit(\"error\", error as Error);\n throw error;\n }\n }\n\n /**\n * Submit new feedback\n *\n * If a user has been identified, the feedback will be associated with them.\n *\n * @param input - Feedback data\n * @returns Promise resolving to the created feedback item\n *\n * @example\n * ```typescript\n * const feedback = await feedhog.submit({\n * title: 'Add dark mode',\n * description: 'Would love a dark theme option',\n * type: 'idea'\n * });\n * console.log('Feedback submitted:', feedback.id);\n * ```\n */\n async submit(input: SubmitFeedbackInput): Promise<FeedbackListItem> {\n try {\n const feedback = await this.client.submit(\n input,\n this.currentUser || undefined\n );\n this.emit(\"submit\", feedback);\n return feedback;\n } catch (error) {\n this.emit(\"error\", error as Error);\n throw error;\n }\n }\n\n /**\n * List feedback items\n *\n * Returns a paginated list of feedback for the project.\n *\n * @param options - Filter and pagination options\n * @returns Promise resolving to paginated feedback list\n *\n * @example\n * ```typescript\n * // Get all ideas in \"planned\" status\n * const { items, total } = await feedhog.list({\n * status: ['planned', 'in-progress'],\n * type: 'idea',\n * sortBy: 'votes',\n * limit: 10\n * });\n * ```\n */\n async list(\n options?: ListFeedbackOptions\n ): Promise<PaginatedResponse<FeedbackListItem>> {\n try {\n return await this.client.list(options);\n } catch (error) {\n this.emit(\"error\", error as Error);\n throw error;\n }\n }\n\n /**\n * Get a single feedback item with full details\n *\n * @param feedbackId - ID of the feedback item\n * @returns Promise resolving to feedback details including comments\n *\n * @example\n * ```typescript\n * const feedback = await feedhog.get('abc123');\n * console.log('Comments:', feedback.comments.length);\n * console.log('Has voted:', feedback.userHasVoted);\n * ```\n */\n async get(feedbackId: string): Promise<FeedbackDetail> {\n try {\n return await this.client.get(\n feedbackId,\n this.currentUser?.externalId\n );\n } catch (error) {\n this.emit(\"error\", error as Error);\n throw error;\n }\n }\n\n /**\n * Toggle vote on a feedback item\n *\n * If the user has already voted, this will remove their vote.\n * If they haven't voted, it will add their vote.\n *\n * @param feedbackId - ID of the feedback item to vote on\n * @returns Promise resolving to vote result\n *\n * @example\n * ```typescript\n * const { voted, voteCount } = await feedhog.vote('abc123');\n * console.log(voted ? 'Vote added' : 'Vote removed');\n * console.log('Total votes:', voteCount);\n * ```\n */\n async vote(feedbackId: string): Promise<VoteResult> {\n try {\n const result = await this.client.vote(\n feedbackId,\n this.currentUser || undefined\n );\n this.emit(\"vote\", { feedbackId, result });\n return result;\n } catch (error) {\n this.emit(\"error\", error as Error);\n throw error;\n }\n }\n\n /**\n * Check if the current user has voted on a feedback item\n *\n * @param feedbackId - ID of the feedback item\n * @returns Promise resolving to vote status\n *\n * @example\n * ```typescript\n * const { voted, voteCount } = await feedhog.hasVoted('abc123');\n * ```\n */\n async hasVoted(feedbackId: string): Promise<VoteResult> {\n try {\n return await this.client.hasVoted(\n feedbackId,\n this.currentUser?.externalId\n );\n } catch (error) {\n this.emit(\"error\", error as Error);\n throw error;\n }\n }\n\n /**\n * Reset the SDK state\n *\n * Clears the current user and removes stored data.\n * Use this when a user logs out.\n *\n * @example\n * ```typescript\n * feedhog.reset();\n * ```\n */\n reset(): void {\n this.currentUser = null;\n if (isBrowser()) {\n clearStoredUser();\n }\n this.emit(\"reset\", undefined);\n }\n}\n\n// Export as default for UMD builds\nexport default Feedhog;\n\n// Export types\nexport type {\n FeedhogConfig,\n UserIdentity,\n SubmitFeedbackInput,\n ListFeedbackOptions,\n FeedbackListItem,\n FeedbackDetail,\n PaginatedResponse,\n VoteResult,\n IdentifiedUser,\n CurrentUser,\n FeedbackType,\n FeedbackStatus,\n SortBy,\n};\n\n// Export error class\nexport { FeedhogApiError };\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var Feedhog=(()=>{var l=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var w=Object.getOwnPropertyNames;var U=Object.prototype.hasOwnProperty;var v=(s,e)=>{for(var t in e)l(s,t,{get:e[t],enumerable:!0})},F=(s,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of w(e))!U.call(s,i)&&i!==t&&l(s,i,{get:()=>e[i],enumerable:!(r=k(e,i))||r.enumerable});return s};var I=s=>F(l({},"__esModule",{value:!0}),s);var P={};v(P,{Feedhog:()=>u,FeedhogApiError:()=>a,default:()=>S});var f="feedhog_user";function h(s){if(!(typeof window>"u"||!window.localStorage))try{localStorage.setItem(f,JSON.stringify(s))}catch{}}function g(){if(typeof window>"u"||!window.localStorage)return null;try{let s=localStorage.getItem(f);return s?JSON.parse(s):null}catch{return null}}function m(){if(!(typeof window>"u"||!window.localStorage))try{localStorage.removeItem(f)}catch{}}function b(s,e,t){let r=new URL(e,s);if(t)for(let[i,n]of Object.entries(t))n!==void 0&&(Array.isArray(n)?r.searchParams.set(i,n.join(",")):r.searchParams.set(i,String(n)));return r.toString()}function d(){return typeof window<"u"&&typeof document<"u"}var o=class{constructor(){this.listeners=new Map}on(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>{this.listeners.get(e)?.delete(t)}}emit(e,t){this.listeners.get(e)?.forEach(r=>r(t))}off(e,t){this.listeners.get(e)?.delete(t)}};var E="https://feedhog.com",c=class{constructor(e){if(!e.apiKey)throw new Error("Feedhog: apiKey is required");this.apiKey=e.apiKey,this.baseUrl=(e.baseUrl||E).replace(/\/$/,"")}async request(e,t,r){let i=r?.params?b(this.baseUrl,t,r.params):`${this.baseUrl}${t}`,n=await fetch(i,{method:e,headers:{"Content-Type":"application/json","x-api-key":this.apiKey},body:r?.body?JSON.stringify(r.body):void 0}),y=await n.json();if(!n.ok){let p=y;throw new a(p.error||"Unknown error",n.status,p.details)}return y}async identify(e){return(await this.request("POST","/api/v1/identify",{body:e})).user}async submit(e,t){let r={...e};return t&&(r.endUser=t),(await this.request("POST","/api/v1/feedback",{body:r})).feedback}async list(e){return this.request("GET","/api/v1/feedback",{params:{status:e?.status?Array.isArray(e.status)?e.status:[e.status]:void 0,type:e?.type?Array.isArray(e.type)?e.type:[e.type]:void 0,search:e?.search,sortBy:e?.sortBy,page:e?.page,limit:e?.limit}})}async get(e,t){return(await this.request("GET",`/api/v1/feedback/${e}`,{params:t?{endUserId:t}:void 0})).feedback}async vote(e,t){return this.request("POST",`/api/v1/feedback/${e}/vote`,{body:t?{endUser:t}:{}})}async hasVoted(e,t){return this.request("GET",`/api/v1/feedback/${e}/vote`,{params:t?{endUserId:t}:void 0})}},a=class extends Error{constructor(t,r,i){super(t);this.status=r;this.details=i;this.name="FeedhogApiError"}};var u=class extends o{constructor(t){super();this.currentUser=null;if(this.client=new c(t),d()){let r=g();r&&(this.currentUser={...r,identified:!1})}}get user(){return this.currentUser}async identify(t){try{let r=await this.client.identify(t);return this.currentUser={...t,identified:!0},d()&&h(t),this.emit("identify",r),r}catch(r){throw this.emit("error",r),r}}async submit(t){try{let r=await this.client.submit(t,this.currentUser||void 0);return this.emit("submit",r),r}catch(r){throw this.emit("error",r),r}}async list(t){try{return await this.client.list(t)}catch(r){throw this.emit("error",r),r}}async get(t){try{return await this.client.get(t,this.currentUser?.externalId)}catch(r){throw this.emit("error",r),r}}async vote(t){try{let r=await this.client.vote(t,this.currentUser||void 0);return this.emit("vote",{feedbackId:t,result:r}),r}catch(r){throw this.emit("error",r),r}}async hasVoted(t){try{return await this.client.hasVoted(t,this.currentUser?.externalId)}catch(r){throw this.emit("error",r),r}}reset(){this.currentUser=null,d()&&m(),this.emit("reset",void 0)}},S=u;return I(P);})();
|
|
2
|
+
if(typeof Feedhog!=='undefined'&&Feedhog.default)window.Feedhog=Feedhog.default;
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@feedhog/js",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "JavaScript SDK for Feedhog - collect user feedback from any website or app",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsup",
|
|
26
|
+
"dev": "tsup --watch",
|
|
27
|
+
"typecheck": "tsc --noEmit",
|
|
28
|
+
"clean": "rm -rf dist"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"feedhog",
|
|
32
|
+
"feedback",
|
|
33
|
+
"user-feedback",
|
|
34
|
+
"widget",
|
|
35
|
+
"sdk"
|
|
36
|
+
],
|
|
37
|
+
"author": "Feedhog",
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://github.com/feedhog/feedhog"
|
|
42
|
+
},
|
|
43
|
+
"homepage": "https://feedhog.com/docs",
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"tsup": "^8.0.0",
|
|
46
|
+
"typescript": "^5.3.0"
|
|
47
|
+
},
|
|
48
|
+
"peerDependencies": {},
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=18"
|
|
51
|
+
}
|
|
52
|
+
}
|