reflet-sdk 0.1.4 → 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/README.md +415 -127
- package/dist/client-BYuSKJw5.js +270 -0
- package/dist/client-BYuSKJw5.js.map +1 -0
- package/dist/client-Bi-GlSii.d.ts +129 -0
- package/dist/client-Bi-GlSii.d.ts.map +1 -0
- package/dist/feedback.d.ts +130 -0
- package/dist/feedback.d.ts.map +1 -0
- package/dist/feedback.js +2276 -0
- package/dist/feedback.js.map +1 -0
- package/dist/index.d.ts +3 -302
- package/dist/index.js +2 -3
- package/dist/react-context-DZw_HHjj.js +85 -0
- package/dist/react-context-DZw_HHjj.js.map +1 -0
- package/dist/react.d.ts +208 -89
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +1248 -340
- package/dist/react.js.map +1 -1
- package/dist/server.d.ts +18 -16
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +118 -117
- package/dist/server.js.map +1 -1
- package/dist/types-xyOadyfX.d.ts +269 -0
- package/dist/types-xyOadyfX.d.ts.map +1 -0
- package/package.json +29 -9
- package/dist/chunk-U7TQSXOE.js +0 -282
- package/dist/chunk-U7TQSXOE.js.map +0 -1
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
//#region src/types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Reflet SDK Types
|
|
4
|
+
*/
|
|
5
|
+
interface RefletConfig {
|
|
6
|
+
/** API base URL (optional, defaults to Reflet production API) */
|
|
7
|
+
baseUrl?: string;
|
|
8
|
+
/** Your organization's public API key (fb_pub_xxx) */
|
|
9
|
+
publicKey: string;
|
|
10
|
+
/** User identification for SSO */
|
|
11
|
+
user?: RefletUser;
|
|
12
|
+
/** Pre-signed user token (alternative to user object) */
|
|
13
|
+
userToken?: string;
|
|
14
|
+
}
|
|
15
|
+
interface RefletUser {
|
|
16
|
+
/** URL to user's avatar image */
|
|
17
|
+
avatar?: string;
|
|
18
|
+
/** User's email address */
|
|
19
|
+
email?: string;
|
|
20
|
+
/** Unique identifier for the user in your system */
|
|
21
|
+
id: string;
|
|
22
|
+
/** Additional metadata */
|
|
23
|
+
metadata?: Record<string, unknown>;
|
|
24
|
+
/** User's display name */
|
|
25
|
+
name?: string;
|
|
26
|
+
}
|
|
27
|
+
interface OrganizationConfig {
|
|
28
|
+
description?: string;
|
|
29
|
+
id: string;
|
|
30
|
+
isPublic: boolean;
|
|
31
|
+
logo?: string;
|
|
32
|
+
name: string;
|
|
33
|
+
primaryColor?: string;
|
|
34
|
+
settings?: OrganizationSettings;
|
|
35
|
+
slug: string;
|
|
36
|
+
statuses: OrganizationStatus[];
|
|
37
|
+
}
|
|
38
|
+
interface OrganizationSettings {
|
|
39
|
+
allowAnonymousVoting?: boolean;
|
|
40
|
+
defaultStatus?: FeedbackStatus;
|
|
41
|
+
requireApproval?: boolean;
|
|
42
|
+
}
|
|
43
|
+
interface OrganizationStatus {
|
|
44
|
+
color: string;
|
|
45
|
+
icon?: string;
|
|
46
|
+
id: string;
|
|
47
|
+
name: string;
|
|
48
|
+
order: number;
|
|
49
|
+
}
|
|
50
|
+
type FeedbackStatus = "open" | "under_review" | "planned" | "in_progress" | "completed" | "closed";
|
|
51
|
+
interface FeedbackItem {
|
|
52
|
+
author: FeedbackAuthor | null;
|
|
53
|
+
commentCount: number;
|
|
54
|
+
completedAt?: number;
|
|
55
|
+
createdAt: number;
|
|
56
|
+
description: string;
|
|
57
|
+
hasVoted: boolean;
|
|
58
|
+
id: string;
|
|
59
|
+
isPinned: boolean;
|
|
60
|
+
organizationStatus: {
|
|
61
|
+
id: string;
|
|
62
|
+
name: string;
|
|
63
|
+
color: string;
|
|
64
|
+
} | null;
|
|
65
|
+
status: FeedbackStatus;
|
|
66
|
+
tags: FeedbackTag[];
|
|
67
|
+
title: string;
|
|
68
|
+
updatedAt: number;
|
|
69
|
+
voteCount: number;
|
|
70
|
+
}
|
|
71
|
+
interface FeedbackDetail extends FeedbackItem {
|
|
72
|
+
isSubscribed: boolean;
|
|
73
|
+
}
|
|
74
|
+
interface FeedbackTag {
|
|
75
|
+
color: string;
|
|
76
|
+
id: string;
|
|
77
|
+
name: string;
|
|
78
|
+
}
|
|
79
|
+
interface FeedbackAuthor {
|
|
80
|
+
avatar?: string;
|
|
81
|
+
email?: string;
|
|
82
|
+
isExternal: boolean;
|
|
83
|
+
name?: string;
|
|
84
|
+
}
|
|
85
|
+
interface FeedbackListResponse {
|
|
86
|
+
hasMore: boolean;
|
|
87
|
+
items: FeedbackItem[];
|
|
88
|
+
total: number;
|
|
89
|
+
}
|
|
90
|
+
interface FeedbackListParams {
|
|
91
|
+
/** Number of items to return (max 100) */
|
|
92
|
+
limit?: number;
|
|
93
|
+
/** Offset for pagination */
|
|
94
|
+
offset?: number;
|
|
95
|
+
/** Search in title and description */
|
|
96
|
+
search?: string;
|
|
97
|
+
/** Sort order */
|
|
98
|
+
sortBy?: "votes" | "newest" | "oldest" | "comments";
|
|
99
|
+
/** Filter by status name */
|
|
100
|
+
status?: FeedbackStatus;
|
|
101
|
+
/** Filter by custom status ID */
|
|
102
|
+
statusId?: string;
|
|
103
|
+
}
|
|
104
|
+
interface ElementRect {
|
|
105
|
+
height: number;
|
|
106
|
+
width: number;
|
|
107
|
+
x: number;
|
|
108
|
+
y: number;
|
|
109
|
+
}
|
|
110
|
+
interface ElementSelection {
|
|
111
|
+
/** React component names owning the element, innermost first. */
|
|
112
|
+
componentStack: string[];
|
|
113
|
+
/** Truncated outerHTML of the selected element. */
|
|
114
|
+
html: string;
|
|
115
|
+
/** Short human-readable description, e.g. `button "Sign in"`. */
|
|
116
|
+
label: string;
|
|
117
|
+
rect: ElementRect;
|
|
118
|
+
selector: string;
|
|
119
|
+
/** `src/components/login-form.tsx:46:19` when the React build exposes it. */
|
|
120
|
+
sourceLocation?: string;
|
|
121
|
+
}
|
|
122
|
+
interface ConsoleEvent {
|
|
123
|
+
level: "error" | "warn";
|
|
124
|
+
message: string;
|
|
125
|
+
timestamp: number;
|
|
126
|
+
}
|
|
127
|
+
interface PageContext {
|
|
128
|
+
browser?: string;
|
|
129
|
+
device?: string;
|
|
130
|
+
language?: string;
|
|
131
|
+
os?: string;
|
|
132
|
+
pageTitle?: string;
|
|
133
|
+
referrer?: string;
|
|
134
|
+
screen?: {
|
|
135
|
+
height: number;
|
|
136
|
+
width: number;
|
|
137
|
+
};
|
|
138
|
+
timezone?: string;
|
|
139
|
+
url?: string;
|
|
140
|
+
userAgent?: string;
|
|
141
|
+
viewport?: {
|
|
142
|
+
devicePixelRatio: number;
|
|
143
|
+
height: number;
|
|
144
|
+
width: number;
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
/** Everything the widget knows about where and how the feedback was written. */
|
|
148
|
+
interface FeedbackContext extends PageContext {
|
|
149
|
+
consoleEvents?: ConsoleEvent[];
|
|
150
|
+
metadata?: Record<string, string>;
|
|
151
|
+
sdkVersion?: string;
|
|
152
|
+
selection?: ElementSelection;
|
|
153
|
+
}
|
|
154
|
+
interface CreateFeedbackParams {
|
|
155
|
+
context?: FeedbackContext;
|
|
156
|
+
description: string;
|
|
157
|
+
title: string;
|
|
158
|
+
}
|
|
159
|
+
interface ScreenshotAnnotation {
|
|
160
|
+
color?: string;
|
|
161
|
+
endX?: number;
|
|
162
|
+
endY?: number;
|
|
163
|
+
height?: number;
|
|
164
|
+
points?: Array<{
|
|
165
|
+
x: number;
|
|
166
|
+
y: number;
|
|
167
|
+
}>;
|
|
168
|
+
text?: string;
|
|
169
|
+
type: "arrow" | "blur" | "highlight" | "pen" | "rectangle" | "text";
|
|
170
|
+
width?: number;
|
|
171
|
+
x: number;
|
|
172
|
+
y: number;
|
|
173
|
+
}
|
|
174
|
+
interface SaveScreenshotParams {
|
|
175
|
+
annotatedStorageId?: string;
|
|
176
|
+
annotations?: ScreenshotAnnotation[];
|
|
177
|
+
feedbackId: string;
|
|
178
|
+
filename?: string;
|
|
179
|
+
height?: number;
|
|
180
|
+
mimeType?: string;
|
|
181
|
+
pageUrl?: string;
|
|
182
|
+
size?: number;
|
|
183
|
+
storageId: string;
|
|
184
|
+
width?: number;
|
|
185
|
+
}
|
|
186
|
+
interface CreateFeedbackResponse {
|
|
187
|
+
feedbackId: string;
|
|
188
|
+
isApproved: boolean;
|
|
189
|
+
}
|
|
190
|
+
interface VoteResponse {
|
|
191
|
+
voteCount: number;
|
|
192
|
+
voted: boolean;
|
|
193
|
+
}
|
|
194
|
+
interface Comment {
|
|
195
|
+
author: FeedbackAuthor | null;
|
|
196
|
+
body: string;
|
|
197
|
+
createdAt: number;
|
|
198
|
+
id: string;
|
|
199
|
+
isOfficial: boolean;
|
|
200
|
+
replies: CommentReply[];
|
|
201
|
+
updatedAt: number;
|
|
202
|
+
}
|
|
203
|
+
interface CommentReply {
|
|
204
|
+
author: FeedbackAuthor | null;
|
|
205
|
+
body: string;
|
|
206
|
+
createdAt: number;
|
|
207
|
+
id: string;
|
|
208
|
+
isOfficial: boolean;
|
|
209
|
+
updatedAt: number;
|
|
210
|
+
}
|
|
211
|
+
interface AddCommentParams {
|
|
212
|
+
body: string;
|
|
213
|
+
feedbackId: string;
|
|
214
|
+
parentId?: string;
|
|
215
|
+
}
|
|
216
|
+
interface AddCommentResponse {
|
|
217
|
+
commentId: string;
|
|
218
|
+
}
|
|
219
|
+
interface SubscribeResponse {
|
|
220
|
+
alreadySubscribed?: boolean;
|
|
221
|
+
subscribed: boolean;
|
|
222
|
+
}
|
|
223
|
+
interface UnsubscribeResponse {
|
|
224
|
+
unsubscribed: boolean;
|
|
225
|
+
wasNotSubscribed?: boolean;
|
|
226
|
+
}
|
|
227
|
+
interface Roadmap {
|
|
228
|
+
lanes: RoadmapLane[];
|
|
229
|
+
}
|
|
230
|
+
interface RoadmapLane {
|
|
231
|
+
color: string;
|
|
232
|
+
id: string;
|
|
233
|
+
items: RoadmapItem[];
|
|
234
|
+
name: string;
|
|
235
|
+
}
|
|
236
|
+
interface RoadmapItem {
|
|
237
|
+
id: string;
|
|
238
|
+
status: FeedbackStatus;
|
|
239
|
+
title: string;
|
|
240
|
+
voteCount: number;
|
|
241
|
+
}
|
|
242
|
+
interface ChangelogEntry {
|
|
243
|
+
description?: string;
|
|
244
|
+
feedback: {
|
|
245
|
+
id: string;
|
|
246
|
+
title: string;
|
|
247
|
+
}[];
|
|
248
|
+
id: string;
|
|
249
|
+
publishedAt?: number;
|
|
250
|
+
title: string;
|
|
251
|
+
version?: string;
|
|
252
|
+
}
|
|
253
|
+
declare class RefletError extends Error {
|
|
254
|
+
readonly status: number;
|
|
255
|
+
readonly code?: string;
|
|
256
|
+
constructor(message: string, status: number, code?: string);
|
|
257
|
+
}
|
|
258
|
+
declare class RefletAuthError extends RefletError {
|
|
259
|
+
constructor(message: string);
|
|
260
|
+
}
|
|
261
|
+
declare class RefletValidationError extends RefletError {
|
|
262
|
+
constructor(message: string);
|
|
263
|
+
}
|
|
264
|
+
declare class RefletNotFoundError extends RefletError {
|
|
265
|
+
constructor(message: string);
|
|
266
|
+
}
|
|
267
|
+
//#endregion
|
|
268
|
+
export { SubscribeResponse as A, RefletNotFoundError as C, RoadmapItem as D, Roadmap as E, VoteResponse as M, RoadmapLane as O, RefletError as S, RefletValidationError as T, OrganizationConfig as _, CommentReply as a, RefletAuthError as b, ElementSelection as c, FeedbackDetail as d, FeedbackItem as f, FeedbackTag as g, FeedbackStatus as h, Comment as i, UnsubscribeResponse as j, SaveScreenshotParams as k, FeedbackAuthor as l, FeedbackListResponse as m, AddCommentResponse as n, CreateFeedbackParams as o, FeedbackListParams as p, ChangelogEntry as r, CreateFeedbackResponse as s, AddCommentParams as t, FeedbackContext as u, OrganizationSettings as v, RefletUser as w, RefletConfig as x, OrganizationStatus as y };
|
|
269
|
+
//# sourceMappingURL=types-xyOadyfX.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-xyOadyfX.d.ts","names":[],"sources":["../src/types.ts"],"mappings":";;;;UAQiB;;EAEf;;EAEA;;EAEA,OAAO;;EAEP;;UAGe;;EAEf;;EAEA;;EAEA;;EAEA,WAAW;;EAEX;;UAOe;EACf;EACA;EACA;EACA;EACA;EACA;EACA,WAAW;EACX;EACA,UAAU;;UAGK;EACf;EACA,gBAAgB;EAChB;;UAGe;EACf;EACA;EACA;EACA;EACA;;KAGU;UAYK;EACf,QAAQ;EACR;EACA;EACA;EACA;EACA;EACA;EACA;EACA;IACE;IACA;IACA;;EAEF,QAAQ;EACR,MAAM;EACN;EACA;EACA;;UAGe,uBAAuB;EACtC;;UAGe;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA,OAAO;EACP;;UAGe;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA,SAAS;;EAET;;UAGe;EACf;EACA;EACA;EACA;;UAGe;;EAEf;;EAEA;;EAEA;EACA,MAAM;EACN;;EAEA;;UAGe;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;IAAW;IAAgB;;EAC3B;EACA;EACA;EACA;IAAa;IAA0B;IAAgB;;;;UAIxC,wBAAwB;EACvC,gBAAgB;EAChB,WAAW;EACX;EACA,YAAY;;UAGG;EACf,UAAU;EACV;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA,SAAS;IAAQ;IAAW;;EAC5B;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA,cAAc;EACd;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;;UAOe;EACf,QAAQ;EACR;EACA;EACA;EACA;EACA,SAAS;EACT;;UAGe;EACf,QAAQ;EACR;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;;UAGe;EACf;;UAOe;EACf;EACA;;UAGe;EACf;EACA;;UAOe;EACf,OAAO;;UAGQ;EACf;EACA;EACA,OAAO;EACP;;UAGe;EACf;EACA,QAAQ;EACR;EACA;;UAOe;EACf;EACA;IAAY;IAAY;;EACxB;EACA;EACA;EACA;;cAOW,oBAAoB;WACtB;WACA;EAET,YAAY,iBAAiB,gBAAgB;;cAQlC,wBAAwB;EACnC,YAAY;;cAMD,8BAA8B;EACzC,YAAY;;cAMD,4BAA4B;EACvC,YAAY"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reflet-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Official Reflet SDK - Collect user feedback, feature requests, and bug reports from your app",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Reflet <hello@reflet.app>",
|
|
@@ -39,6 +39,10 @@
|
|
|
39
39
|
"import": "./dist/react.js",
|
|
40
40
|
"types": "./dist/react.d.ts"
|
|
41
41
|
},
|
|
42
|
+
"./feedback": {
|
|
43
|
+
"import": "./dist/feedback.js",
|
|
44
|
+
"types": "./dist/feedback.d.ts"
|
|
45
|
+
},
|
|
42
46
|
"./server": {
|
|
43
47
|
"import": "./dist/server.js",
|
|
44
48
|
"types": "./dist/server.d.ts"
|
|
@@ -53,9 +57,10 @@
|
|
|
53
57
|
"CHANGELOG.md"
|
|
54
58
|
],
|
|
55
59
|
"scripts": {
|
|
56
|
-
"build": "
|
|
57
|
-
"dev": "
|
|
58
|
-
"
|
|
60
|
+
"build": "tsdown",
|
|
61
|
+
"dev": "tsdown --watch",
|
|
62
|
+
"check-types": "tsc --noEmit",
|
|
63
|
+
"test:unit": "vitest run",
|
|
59
64
|
"lint": "cd ../.. && bun x ultracite check packages/sdk",
|
|
60
65
|
"prepublishOnly": "npm run build",
|
|
61
66
|
"version:patch": "npm version patch && npm run release",
|
|
@@ -64,18 +69,33 @@
|
|
|
64
69
|
"release": "npm run build && npm publish"
|
|
65
70
|
},
|
|
66
71
|
"peerDependencies": {
|
|
67
|
-
"react": "^18.0.0 || ^19.0.0"
|
|
72
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
73
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
68
74
|
},
|
|
69
75
|
"peerDependenciesMeta": {
|
|
70
76
|
"react": {
|
|
71
77
|
"optional": true
|
|
78
|
+
},
|
|
79
|
+
"react-dom": {
|
|
80
|
+
"optional": true
|
|
72
81
|
}
|
|
73
82
|
},
|
|
83
|
+
"dependencies": {
|
|
84
|
+
"@zumer/snapdom": "^2.23.1"
|
|
85
|
+
},
|
|
74
86
|
"devDependencies": {
|
|
75
|
-
"@
|
|
76
|
-
"react": "^
|
|
77
|
-
"
|
|
78
|
-
"
|
|
87
|
+
"@testing-library/dom": "^10.4.1",
|
|
88
|
+
"@testing-library/react": "^16.3.2",
|
|
89
|
+
"@testing-library/user-event": "^14.6.1",
|
|
90
|
+
"@types/react": "^19.2.17",
|
|
91
|
+
"jsdom": "^30.0.1",
|
|
92
|
+
"react": "^19.2.8",
|
|
93
|
+
"react-dom": "^19.2.8",
|
|
94
|
+
"tsdown": "catalog:",
|
|
95
|
+
"typescript": "catalog:",
|
|
96
|
+
"vite": "catalog:",
|
|
97
|
+
"vitest": "catalog:",
|
|
98
|
+
"@types/react-dom": "19.2.3"
|
|
79
99
|
},
|
|
80
100
|
"engines": {
|
|
81
101
|
"node": ">=18.0.0"
|
package/dist/chunk-U7TQSXOE.js
DELETED
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
// src/types.ts
|
|
2
|
-
var RefletError = class extends Error {
|
|
3
|
-
status;
|
|
4
|
-
code;
|
|
5
|
-
constructor(message, status, code) {
|
|
6
|
-
super(message);
|
|
7
|
-
this.name = "RefletError";
|
|
8
|
-
this.status = status;
|
|
9
|
-
this.code = code;
|
|
10
|
-
}
|
|
11
|
-
};
|
|
12
|
-
var RefletAuthError = class extends RefletError {
|
|
13
|
-
constructor(message) {
|
|
14
|
-
super(message, 401, "AUTH_ERROR");
|
|
15
|
-
this.name = "RefletAuthError";
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
var RefletValidationError = class extends RefletError {
|
|
19
|
-
constructor(message) {
|
|
20
|
-
super(message, 400, "VALIDATION_ERROR");
|
|
21
|
-
this.name = "RefletValidationError";
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
var RefletNotFoundError = class extends RefletError {
|
|
25
|
-
constructor(message) {
|
|
26
|
-
super(message, 404, "NOT_FOUND");
|
|
27
|
-
this.name = "RefletNotFoundError";
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
// src/client.ts
|
|
32
|
-
var DEFAULT_API_URL = "https://harmless-clam-802.convex.site";
|
|
33
|
-
var Reflet = class {
|
|
34
|
-
publicKey;
|
|
35
|
-
baseUrl;
|
|
36
|
-
userToken;
|
|
37
|
-
user;
|
|
38
|
-
constructor(config) {
|
|
39
|
-
this.publicKey = config.publicKey;
|
|
40
|
-
this.baseUrl = config.baseUrl ?? DEFAULT_API_URL;
|
|
41
|
-
this.userToken = config.userToken;
|
|
42
|
-
this.user = config.user;
|
|
43
|
-
if (!this.publicKey) {
|
|
44
|
-
throw new Error("Reflet: publicKey is required");
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Update the user identification
|
|
49
|
-
*/
|
|
50
|
-
setUser(user) {
|
|
51
|
-
this.user = user;
|
|
52
|
-
this.userToken = void 0;
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Set the user token directly (for server-signed tokens)
|
|
56
|
-
*/
|
|
57
|
-
setUserToken(token) {
|
|
58
|
-
this.userToken = token;
|
|
59
|
-
this.user = void 0;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Get the board configuration
|
|
63
|
-
*/
|
|
64
|
-
async getConfig() {
|
|
65
|
-
return await this.request("GET", "/api/v1/feedback");
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* List feedback items with optional filtering
|
|
69
|
-
*/
|
|
70
|
-
async list(params) {
|
|
71
|
-
const searchParams = new URLSearchParams();
|
|
72
|
-
if (params?.statusId) {
|
|
73
|
-
searchParams.set("statusId", params.statusId);
|
|
74
|
-
}
|
|
75
|
-
if (params?.status) {
|
|
76
|
-
searchParams.set("status", params.status);
|
|
77
|
-
}
|
|
78
|
-
if (params?.search) {
|
|
79
|
-
searchParams.set("search", params.search);
|
|
80
|
-
}
|
|
81
|
-
if (params?.sortBy) {
|
|
82
|
-
searchParams.set("sortBy", params.sortBy);
|
|
83
|
-
}
|
|
84
|
-
if (params?.limit) {
|
|
85
|
-
searchParams.set("limit", String(params.limit));
|
|
86
|
-
}
|
|
87
|
-
if (params?.offset) {
|
|
88
|
-
searchParams.set("offset", String(params.offset));
|
|
89
|
-
}
|
|
90
|
-
const query = searchParams.toString();
|
|
91
|
-
const url = `/api/v1/feedback/list${query ? `?${query}` : ""}`;
|
|
92
|
-
return await this.request("GET", url);
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Get a single feedback item by ID
|
|
96
|
-
*/
|
|
97
|
-
async get(feedbackId) {
|
|
98
|
-
const result = await this.request(
|
|
99
|
-
"GET",
|
|
100
|
-
`/api/v1/feedback/item?id=${encodeURIComponent(feedbackId)}`
|
|
101
|
-
);
|
|
102
|
-
if (!result) {
|
|
103
|
-
throw new RefletNotFoundError("Feedback not found");
|
|
104
|
-
}
|
|
105
|
-
return result;
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Create new feedback
|
|
109
|
-
* Requires user identification
|
|
110
|
-
*/
|
|
111
|
-
async create(params) {
|
|
112
|
-
return await this.request(
|
|
113
|
-
"POST",
|
|
114
|
-
"/api/v1/feedback/create",
|
|
115
|
-
params
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Toggle vote on feedback
|
|
120
|
-
* Requires user identification
|
|
121
|
-
*/
|
|
122
|
-
async vote(feedbackId, type = "upvote") {
|
|
123
|
-
return await this.request("POST", "/api/v1/feedback/vote", {
|
|
124
|
-
feedbackId,
|
|
125
|
-
voteType: type
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Get comments for a feedback item
|
|
130
|
-
*/
|
|
131
|
-
async getComments(feedbackId, sortBy = "oldest") {
|
|
132
|
-
return await this.request(
|
|
133
|
-
"GET",
|
|
134
|
-
`/api/v1/feedback/comments?feedbackId=${encodeURIComponent(feedbackId)}&sortBy=${sortBy}`
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Add a comment to feedback
|
|
139
|
-
* Requires user identification
|
|
140
|
-
*/
|
|
141
|
-
async comment(params) {
|
|
142
|
-
return await this.request(
|
|
143
|
-
"POST",
|
|
144
|
-
"/api/v1/feedback/comment",
|
|
145
|
-
params
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* Subscribe to feedback updates
|
|
150
|
-
* Requires user identification
|
|
151
|
-
*/
|
|
152
|
-
async subscribe(feedbackId) {
|
|
153
|
-
return await this.request(
|
|
154
|
-
"POST",
|
|
155
|
-
"/api/v1/feedback/subscribe",
|
|
156
|
-
{
|
|
157
|
-
feedbackId
|
|
158
|
-
}
|
|
159
|
-
);
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* Unsubscribe from feedback updates
|
|
163
|
-
* Requires user identification
|
|
164
|
-
*/
|
|
165
|
-
async unsubscribe(feedbackId) {
|
|
166
|
-
return await this.request(
|
|
167
|
-
"POST",
|
|
168
|
-
"/api/v1/feedback/unsubscribe",
|
|
169
|
-
{
|
|
170
|
-
feedbackId
|
|
171
|
-
}
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
/**
|
|
175
|
-
* Get roadmap data
|
|
176
|
-
*/
|
|
177
|
-
async getRoadmap() {
|
|
178
|
-
return await this.request("GET", "/api/v1/feedback/roadmap");
|
|
179
|
-
}
|
|
180
|
-
/**
|
|
181
|
-
* Get changelog entries
|
|
182
|
-
*/
|
|
183
|
-
async getChangelog(limit) {
|
|
184
|
-
const url = limit ? `/api/v1/feedback/changelog?limit=${limit}` : "/api/v1/feedback/changelog";
|
|
185
|
-
return await this.request("GET", url);
|
|
186
|
-
}
|
|
187
|
-
/**
|
|
188
|
-
* Build request headers with authentication
|
|
189
|
-
*/
|
|
190
|
-
buildHeaders() {
|
|
191
|
-
const headers = {
|
|
192
|
-
"Content-Type": "application/json",
|
|
193
|
-
Authorization: `Bearer ${this.publicKey}`
|
|
194
|
-
};
|
|
195
|
-
const token = this.userToken ?? this.generateUserToken();
|
|
196
|
-
if (token) {
|
|
197
|
-
headers["X-User-Token"] = token;
|
|
198
|
-
}
|
|
199
|
-
return headers;
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* Parse JSON response text safely
|
|
203
|
-
*/
|
|
204
|
-
parseJsonSafely(text, status) {
|
|
205
|
-
try {
|
|
206
|
-
return JSON.parse(text);
|
|
207
|
-
} catch (parseError) {
|
|
208
|
-
throw new RefletError(
|
|
209
|
-
`Invalid response: ${parseError instanceof Error ? parseError.message : "Failed to parse JSON"}`,
|
|
210
|
-
status
|
|
211
|
-
);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
/**
|
|
215
|
-
* Throw appropriate error based on status code
|
|
216
|
-
*/
|
|
217
|
-
throwHttpError(message, status) {
|
|
218
|
-
if (status === 401) {
|
|
219
|
-
throw new RefletAuthError(message);
|
|
220
|
-
}
|
|
221
|
-
if (status === 404) {
|
|
222
|
-
throw new RefletNotFoundError(message);
|
|
223
|
-
}
|
|
224
|
-
throw new RefletError(message, status);
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Make an authenticated API request
|
|
228
|
-
*/
|
|
229
|
-
async request(method, path, body) {
|
|
230
|
-
let response;
|
|
231
|
-
try {
|
|
232
|
-
response = await fetch(`${this.baseUrl}${path}`, {
|
|
233
|
-
method,
|
|
234
|
-
headers: this.buildHeaders(),
|
|
235
|
-
body: body ? JSON.stringify(body) : void 0
|
|
236
|
-
});
|
|
237
|
-
} catch (networkError) {
|
|
238
|
-
const message = networkError instanceof Error ? networkError.message : "Failed to connect";
|
|
239
|
-
throw new RefletError(`Network error: ${message}`, 0);
|
|
240
|
-
}
|
|
241
|
-
const text = await response.text();
|
|
242
|
-
if (!text) {
|
|
243
|
-
if (!response.ok) {
|
|
244
|
-
this.throwHttpError(
|
|
245
|
-
`Request failed with status ${response.status}`,
|
|
246
|
-
response.status
|
|
247
|
-
);
|
|
248
|
-
}
|
|
249
|
-
return {};
|
|
250
|
-
}
|
|
251
|
-
const data = this.parseJsonSafely(text, response.status);
|
|
252
|
-
if (!response.ok) {
|
|
253
|
-
const errorMessage = data.error ?? `Request failed with status ${response.status}`;
|
|
254
|
-
this.throwHttpError(errorMessage, response.status);
|
|
255
|
-
}
|
|
256
|
-
return data;
|
|
257
|
-
}
|
|
258
|
-
/**
|
|
259
|
-
* Generate a simple user token for client-side use
|
|
260
|
-
* Note: For production, use server-side token signing
|
|
261
|
-
*/
|
|
262
|
-
generateUserToken() {
|
|
263
|
-
if (!this.user) {
|
|
264
|
-
return void 0;
|
|
265
|
-
}
|
|
266
|
-
const payload = {
|
|
267
|
-
id: this.user.id,
|
|
268
|
-
email: this.user.email,
|
|
269
|
-
name: this.user.name,
|
|
270
|
-
iat: Math.floor(Date.now() / 1e3),
|
|
271
|
-
exp: Math.floor(Date.now() / 1e3) + 86400
|
|
272
|
-
// 24 hours
|
|
273
|
-
};
|
|
274
|
-
const header = btoa(JSON.stringify({ alg: "none", typ: "JWT" }));
|
|
275
|
-
const payloadB64 = btoa(JSON.stringify(payload));
|
|
276
|
-
return `${header}.${payloadB64}.`;
|
|
277
|
-
}
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
export { Reflet, RefletAuthError, RefletError, RefletNotFoundError, RefletValidationError };
|
|
281
|
-
//# sourceMappingURL=chunk-U7TQSXOE.js.map
|
|
282
|
-
//# sourceMappingURL=chunk-U7TQSXOE.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/client.ts"],"names":[],"mappings":"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","file":"chunk-U7TQSXOE.js","sourcesContent":["/**\n * Reflet SDK Types\n */\n\n// ============================================\n// Configuration\n// ============================================\n\nexport interface RefletConfig {\n /** Your board's public API key (fb_pub_xxx) */\n publicKey: string;\n /** API base URL (optional, defaults to Reflet production API) */\n baseUrl?: string;\n /** User identification for SSO */\n user?: RefletUser;\n /** Pre-signed user token (alternative to user object) */\n userToken?: string;\n}\n\nexport interface RefletUser {\n /** Unique identifier for the user in your system */\n id: string;\n /** User's email address */\n email?: string;\n /** User's display name */\n name?: string;\n /** URL to user's avatar image */\n avatar?: string;\n /** Additional metadata */\n metadata?: Record<string, unknown>;\n}\n\n// ============================================\n// API Responses\n// ============================================\n\nexport interface BoardConfig {\n id: string;\n name: string;\n slug: string;\n description?: string;\n isPublic: boolean;\n settings?: BoardSettings;\n organization: {\n id: string;\n name: string;\n slug: string;\n logo?: string;\n primaryColor?: string;\n };\n statuses: BoardStatus[];\n}\n\nexport interface BoardSettings {\n allowAnonymousVoting?: boolean;\n requireApproval?: boolean;\n defaultStatus?: FeedbackStatus;\n}\n\nexport interface BoardStatus {\n id: string;\n name: string;\n color: string;\n icon?: string;\n order: number;\n}\n\nexport type FeedbackStatus =\n | \"open\"\n | \"under_review\"\n | \"planned\"\n | \"in_progress\"\n | \"completed\"\n | \"closed\";\n\n// ============================================\n// Feedback\n// ============================================\n\nexport interface FeedbackItem {\n id: string;\n title: string;\n description: string;\n status: FeedbackStatus;\n voteCount: number;\n commentCount: number;\n isPinned: boolean;\n hasVoted: boolean;\n createdAt: number;\n updatedAt: number;\n completedAt?: number;\n tags: FeedbackTag[];\n boardStatus: {\n id: string;\n name: string;\n color: string;\n } | null;\n author: FeedbackAuthor | null;\n}\n\nexport interface FeedbackDetail extends FeedbackItem {\n isSubscribed: boolean;\n}\n\nexport interface FeedbackTag {\n id: string;\n name: string;\n color: string;\n}\n\nexport interface FeedbackAuthor {\n name?: string;\n email?: string;\n avatar?: string;\n isExternal: boolean;\n}\n\nexport interface FeedbackListResponse {\n items: FeedbackItem[];\n total: number;\n hasMore: boolean;\n}\n\nexport interface FeedbackListParams {\n /** Filter by custom status ID */\n statusId?: string;\n /** Filter by status name */\n status?: FeedbackStatus;\n /** Search in title and description */\n search?: string;\n /** Sort order */\n sortBy?: \"votes\" | \"newest\" | \"oldest\" | \"comments\";\n /** Number of items to return (max 100) */\n limit?: number;\n /** Offset for pagination */\n offset?: number;\n}\n\nexport interface CreateFeedbackParams {\n title: string;\n description: string;\n}\n\nexport interface CreateFeedbackResponse {\n feedbackId: string;\n isApproved: boolean;\n}\n\nexport interface VoteResponse {\n voted: boolean;\n voteCount: number;\n}\n\n// ============================================\n// Comments\n// ============================================\n\nexport interface Comment {\n id: string;\n body: string;\n isOfficial: boolean;\n author: FeedbackAuthor | null;\n replies: CommentReply[];\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface CommentReply {\n id: string;\n body: string;\n isOfficial: boolean;\n author: FeedbackAuthor | null;\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface AddCommentParams {\n feedbackId: string;\n body: string;\n parentId?: string;\n}\n\nexport interface AddCommentResponse {\n commentId: string;\n}\n\n// ============================================\n// Subscriptions\n// ============================================\n\nexport interface SubscribeResponse {\n subscribed: boolean;\n alreadySubscribed?: boolean;\n}\n\nexport interface UnsubscribeResponse {\n unsubscribed: boolean;\n wasNotSubscribed?: boolean;\n}\n\n// ============================================\n// Roadmap\n// ============================================\n\nexport interface Roadmap {\n lanes: RoadmapLane[];\n}\n\nexport interface RoadmapLane {\n id: string;\n name: string;\n color: string;\n items: RoadmapItem[];\n}\n\nexport interface RoadmapItem {\n id: string;\n title: string;\n status: FeedbackStatus;\n voteCount: number;\n}\n\n// ============================================\n// Changelog\n// ============================================\n\nexport interface ChangelogEntry {\n id: string;\n title: string;\n description?: string;\n version?: string;\n publishedAt?: number;\n feedback: { id: string; title: string }[];\n}\n\n// ============================================\n// Errors\n// ============================================\n\nexport class RefletError extends Error {\n readonly status: number;\n readonly code?: string;\n\n constructor(message: string, status: number, code?: string) {\n super(message);\n this.name = \"RefletError\";\n this.status = status;\n this.code = code;\n }\n}\n\nexport class RefletAuthError extends RefletError {\n constructor(message: string) {\n super(message, 401, \"AUTH_ERROR\");\n this.name = \"RefletAuthError\";\n }\n}\n\nexport class RefletValidationError extends RefletError {\n constructor(message: string) {\n super(message, 400, \"VALIDATION_ERROR\");\n this.name = \"RefletValidationError\";\n }\n}\n\nexport class RefletNotFoundError extends RefletError {\n constructor(message: string) {\n super(message, 404, \"NOT_FOUND\");\n this.name = \"RefletNotFoundError\";\n }\n}\n","import {\n type AddCommentParams,\n type AddCommentResponse,\n type BoardConfig,\n type ChangelogEntry,\n type Comment,\n type CreateFeedbackParams,\n type CreateFeedbackResponse,\n type FeedbackDetail,\n type FeedbackListParams,\n type FeedbackListResponse,\n RefletAuthError,\n type RefletConfig,\n RefletError,\n RefletNotFoundError,\n type RefletUser,\n type Roadmap,\n type SubscribeResponse,\n type UnsubscribeResponse,\n type VoteResponse,\n} from \"./types\";\n\n// Default to Reflet production API (HTTP routes use .convex.site)\nconst DEFAULT_API_URL = \"https://harmless-clam-802.convex.site\";\n\n/**\n * Reflet SDK Client\n *\n * @example\n * ```ts\n * import { Reflet } from 'reflet-sdk';\n *\n * const reflet = new Reflet({\n * publicKey: 'fb_pub_xxx',\n * user: { id: 'user_123', email: 'user@example.com', name: 'John' }\n * });\n *\n * // List feedback\n * const { items } = await reflet.list({ status: 'open' });\n *\n * // Vote on feedback\n * await reflet.vote('feedback_id');\n *\n * // Submit new feedback\n * await reflet.create({ title: 'Great idea', description: 'Details...' });\n * ```\n */\nexport class Reflet {\n private readonly publicKey: string;\n private readonly baseUrl: string;\n private userToken: string | undefined;\n private user: RefletUser | undefined;\n\n constructor(config: RefletConfig) {\n this.publicKey = config.publicKey;\n this.baseUrl = config.baseUrl ?? DEFAULT_API_URL;\n this.userToken = config.userToken;\n this.user = config.user;\n\n if (!this.publicKey) {\n throw new Error(\"Reflet: publicKey is required\");\n }\n }\n\n /**\n * Update the user identification\n */\n setUser(user: RefletUser | undefined): void {\n this.user = user;\n this.userToken = undefined;\n }\n\n /**\n * Set the user token directly (for server-signed tokens)\n */\n setUserToken(token: string | undefined): void {\n this.userToken = token;\n this.user = undefined;\n }\n\n /**\n * Get the board configuration\n */\n async getConfig(): Promise<BoardConfig> {\n return await this.request<BoardConfig>(\"GET\", \"/api/v1/feedback\");\n }\n\n /**\n * List feedback items with optional filtering\n */\n async list(params?: FeedbackListParams): Promise<FeedbackListResponse> {\n const searchParams = new URLSearchParams();\n\n if (params?.statusId) {\n searchParams.set(\"statusId\", params.statusId);\n }\n if (params?.status) {\n searchParams.set(\"status\", params.status);\n }\n if (params?.search) {\n searchParams.set(\"search\", params.search);\n }\n if (params?.sortBy) {\n searchParams.set(\"sortBy\", params.sortBy);\n }\n if (params?.limit) {\n searchParams.set(\"limit\", String(params.limit));\n }\n if (params?.offset) {\n searchParams.set(\"offset\", String(params.offset));\n }\n\n const query = searchParams.toString();\n const url = `/api/v1/feedback/list${query ? `?${query}` : \"\"}`;\n\n return await this.request<FeedbackListResponse>(\"GET\", url);\n }\n\n /**\n * Get a single feedback item by ID\n */\n async get(feedbackId: string): Promise<FeedbackDetail> {\n const result = await this.request<FeedbackDetail | null>(\n \"GET\",\n `/api/v1/feedback/item?id=${encodeURIComponent(feedbackId)}`\n );\n\n if (!result) {\n throw new RefletNotFoundError(\"Feedback not found\");\n }\n\n return result;\n }\n\n /**\n * Create new feedback\n * Requires user identification\n */\n async create(params: CreateFeedbackParams): Promise<CreateFeedbackResponse> {\n return await this.request<CreateFeedbackResponse>(\n \"POST\",\n \"/api/v1/feedback/create\",\n params\n );\n }\n\n /**\n * Toggle vote on feedback\n * Requires user identification\n */\n async vote(\n feedbackId: string,\n type: \"upvote\" | \"downvote\" = \"upvote\"\n ): Promise<VoteResponse> {\n return await this.request<VoteResponse>(\"POST\", \"/api/v1/feedback/vote\", {\n feedbackId,\n voteType: type,\n });\n }\n\n /**\n * Get comments for a feedback item\n */\n async getComments(\n feedbackId: string,\n sortBy: \"newest\" | \"oldest\" = \"oldest\"\n ): Promise<Comment[]> {\n return await this.request<Comment[]>(\n \"GET\",\n `/api/v1/feedback/comments?feedbackId=${encodeURIComponent(feedbackId)}&sortBy=${sortBy}`\n );\n }\n\n /**\n * Add a comment to feedback\n * Requires user identification\n */\n async comment(params: AddCommentParams): Promise<AddCommentResponse> {\n return await this.request<AddCommentResponse>(\n \"POST\",\n \"/api/v1/feedback/comment\",\n params\n );\n }\n\n /**\n * Subscribe to feedback updates\n * Requires user identification\n */\n async subscribe(feedbackId: string): Promise<SubscribeResponse> {\n return await this.request<SubscribeResponse>(\n \"POST\",\n \"/api/v1/feedback/subscribe\",\n {\n feedbackId,\n }\n );\n }\n\n /**\n * Unsubscribe from feedback updates\n * Requires user identification\n */\n async unsubscribe(feedbackId: string): Promise<UnsubscribeResponse> {\n return await this.request<UnsubscribeResponse>(\n \"POST\",\n \"/api/v1/feedback/unsubscribe\",\n {\n feedbackId,\n }\n );\n }\n\n /**\n * Get roadmap data\n */\n async getRoadmap(): Promise<Roadmap> {\n return await this.request<Roadmap>(\"GET\", \"/api/v1/feedback/roadmap\");\n }\n\n /**\n * Get changelog entries\n */\n async getChangelog(limit?: number): Promise<ChangelogEntry[]> {\n const url = limit\n ? `/api/v1/feedback/changelog?limit=${limit}`\n : \"/api/v1/feedback/changelog\";\n\n return await this.request<ChangelogEntry[]>(\"GET\", url);\n }\n\n /**\n * Build request headers with authentication\n */\n private buildHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.publicKey}`,\n };\n\n const token = this.userToken ?? this.generateUserToken();\n if (token) {\n headers[\"X-User-Token\"] = token;\n }\n\n return headers;\n }\n\n /**\n * Parse JSON response text safely\n */\n private parseJsonSafely<T>(\n text: string,\n status: number\n ): T | { error: string } {\n try {\n return JSON.parse(text) as T | { error: string };\n } catch (parseError) {\n throw new RefletError(\n `Invalid response: ${parseError instanceof Error ? parseError.message : \"Failed to parse JSON\"}`,\n status\n );\n }\n }\n\n /**\n * Throw appropriate error based on status code\n */\n private throwHttpError(message: string, status: number): never {\n if (status === 401) {\n throw new RefletAuthError(message);\n }\n if (status === 404) {\n throw new RefletNotFoundError(message);\n }\n throw new RefletError(message, status);\n }\n\n /**\n * Make an authenticated API request\n */\n private async request<T>(\n method: string,\n path: string,\n body?: unknown\n ): Promise<T> {\n let response: Response;\n try {\n response = await fetch(`${this.baseUrl}${path}`, {\n method,\n headers: this.buildHeaders(),\n body: body ? JSON.stringify(body) : undefined,\n });\n } catch (networkError) {\n const message =\n networkError instanceof Error\n ? networkError.message\n : \"Failed to connect\";\n throw new RefletError(`Network error: ${message}`, 0);\n }\n\n const text = await response.text();\n\n // Handle empty response\n if (!text) {\n if (!response.ok) {\n this.throwHttpError(\n `Request failed with status ${response.status}`,\n response.status\n );\n }\n return {} as T;\n }\n\n const data = this.parseJsonSafely<T>(text, response.status);\n\n if (!response.ok) {\n const errorMessage =\n (data as { error?: string }).error ??\n `Request failed with status ${response.status}`;\n this.throwHttpError(errorMessage, response.status);\n }\n\n return data as T;\n }\n\n /**\n * Generate a simple user token for client-side use\n * Note: For production, use server-side token signing\n */\n private generateUserToken(): string | undefined {\n if (!this.user) {\n return undefined;\n }\n\n // Simple base64 encoding for client-side use\n // In production, tokens should be signed server-side\n const payload = {\n id: this.user.id,\n email: this.user.email,\n name: this.user.name,\n iat: Math.floor(Date.now() / 1000),\n exp: Math.floor(Date.now() / 1000) + 86_400, // 24 hours\n };\n\n const header = btoa(JSON.stringify({ alg: \"none\", typ: \"JWT\" }));\n const payloadB64 = btoa(JSON.stringify(payload));\n\n return `${header}.${payloadB64}.`;\n }\n}\n"]}
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|