react-visual-feedback 1.4.9 → 2.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 +89 -3
- package/dist/index.esm.js +2 -2
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/integrations/config.js +664 -0
- package/dist/integrations/config.js.map +1 -0
- package/dist/integrations/index.js +4 -0
- package/dist/integrations/index.js.map +1 -0
- package/dist/server/index.js +2907 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/jira.js +1565 -0
- package/dist/server/jira.js.map +1 -0
- package/dist/server/sheets.js +1448 -0
- package/dist/server/sheets.js.map +1 -0
- package/package.json +30 -3
|
@@ -0,0 +1,1565 @@
|
|
|
1
|
+
function _arrayLikeToArray(r, a) {
|
|
2
|
+
(null == a || a > r.length) && (a = r.length);
|
|
3
|
+
for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
|
|
4
|
+
return n;
|
|
5
|
+
}
|
|
6
|
+
function _arrayWithHoles(r) {
|
|
7
|
+
if (Array.isArray(r)) return r;
|
|
8
|
+
}
|
|
9
|
+
function _arrayWithoutHoles(r) {
|
|
10
|
+
if (Array.isArray(r)) return _arrayLikeToArray(r);
|
|
11
|
+
}
|
|
12
|
+
function asyncGeneratorStep(n, t, e, r, o, a, c) {
|
|
13
|
+
try {
|
|
14
|
+
var i = n[a](c),
|
|
15
|
+
u = i.value;
|
|
16
|
+
} catch (n) {
|
|
17
|
+
return void e(n);
|
|
18
|
+
}
|
|
19
|
+
i.done ? t(u) : Promise.resolve(u).then(r, o);
|
|
20
|
+
}
|
|
21
|
+
function _asyncToGenerator(n) {
|
|
22
|
+
return function () {
|
|
23
|
+
var t = this,
|
|
24
|
+
e = arguments;
|
|
25
|
+
return new Promise(function (r, o) {
|
|
26
|
+
var a = n.apply(t, e);
|
|
27
|
+
function _next(n) {
|
|
28
|
+
asyncGeneratorStep(a, r, o, _next, _throw, "next", n);
|
|
29
|
+
}
|
|
30
|
+
function _throw(n) {
|
|
31
|
+
asyncGeneratorStep(a, r, o, _next, _throw, "throw", n);
|
|
32
|
+
}
|
|
33
|
+
_next(void 0);
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function _classCallCheck(a, n) {
|
|
38
|
+
if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");
|
|
39
|
+
}
|
|
40
|
+
function _defineProperties(e, r) {
|
|
41
|
+
for (var t = 0; t < r.length; t++) {
|
|
42
|
+
var o = r[t];
|
|
43
|
+
o.enumerable = o.enumerable || false, o.configurable = true, "value" in o && (o.writable = true), Object.defineProperty(e, _toPropertyKey(o.key), o);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function _createClass(e, r, t) {
|
|
47
|
+
return r && _defineProperties(e.prototype, r), Object.defineProperty(e, "prototype", {
|
|
48
|
+
writable: false
|
|
49
|
+
}), e;
|
|
50
|
+
}
|
|
51
|
+
function _defineProperty(e, r, t) {
|
|
52
|
+
return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
53
|
+
value: t,
|
|
54
|
+
enumerable: true,
|
|
55
|
+
configurable: true,
|
|
56
|
+
writable: true
|
|
57
|
+
}) : e[r] = t, e;
|
|
58
|
+
}
|
|
59
|
+
function _iterableToArray(r) {
|
|
60
|
+
if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r);
|
|
61
|
+
}
|
|
62
|
+
function _iterableToArrayLimit(r, l) {
|
|
63
|
+
var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
|
|
64
|
+
if (null != t) {
|
|
65
|
+
var e,
|
|
66
|
+
n,
|
|
67
|
+
i,
|
|
68
|
+
u,
|
|
69
|
+
a = [],
|
|
70
|
+
f = true,
|
|
71
|
+
o = false;
|
|
72
|
+
try {
|
|
73
|
+
if (i = (t = t.call(r)).next, 0 === l) ; else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
|
|
74
|
+
} catch (r) {
|
|
75
|
+
o = true, n = r;
|
|
76
|
+
} finally {
|
|
77
|
+
try {
|
|
78
|
+
if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
|
|
79
|
+
} finally {
|
|
80
|
+
if (o) throw n;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return a;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function _nonIterableRest() {
|
|
87
|
+
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
88
|
+
}
|
|
89
|
+
function _nonIterableSpread() {
|
|
90
|
+
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
91
|
+
}
|
|
92
|
+
function ownKeys(e, r) {
|
|
93
|
+
var t = Object.keys(e);
|
|
94
|
+
if (Object.getOwnPropertySymbols) {
|
|
95
|
+
var o = Object.getOwnPropertySymbols(e);
|
|
96
|
+
r && (o = o.filter(function (r) {
|
|
97
|
+
return Object.getOwnPropertyDescriptor(e, r).enumerable;
|
|
98
|
+
})), t.push.apply(t, o);
|
|
99
|
+
}
|
|
100
|
+
return t;
|
|
101
|
+
}
|
|
102
|
+
function _objectSpread2(e) {
|
|
103
|
+
for (var r = 1; r < arguments.length; r++) {
|
|
104
|
+
var t = null != arguments[r] ? arguments[r] : {};
|
|
105
|
+
r % 2 ? ownKeys(Object(t), true).forEach(function (r) {
|
|
106
|
+
_defineProperty(e, r, t[r]);
|
|
107
|
+
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
|
|
108
|
+
Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return e;
|
|
112
|
+
}
|
|
113
|
+
function _regenerator() {
|
|
114
|
+
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */
|
|
115
|
+
var e,
|
|
116
|
+
t,
|
|
117
|
+
r = "function" == typeof Symbol ? Symbol : {},
|
|
118
|
+
n = r.iterator || "@@iterator",
|
|
119
|
+
o = r.toStringTag || "@@toStringTag";
|
|
120
|
+
function i(r, n, o, i) {
|
|
121
|
+
var c = n && n.prototype instanceof Generator ? n : Generator,
|
|
122
|
+
u = Object.create(c.prototype);
|
|
123
|
+
return _regeneratorDefine(u, "_invoke", function (r, n, o) {
|
|
124
|
+
var i,
|
|
125
|
+
c,
|
|
126
|
+
u,
|
|
127
|
+
f = 0,
|
|
128
|
+
p = o || [],
|
|
129
|
+
y = false,
|
|
130
|
+
G = {
|
|
131
|
+
p: 0,
|
|
132
|
+
n: 0,
|
|
133
|
+
v: e,
|
|
134
|
+
a: d,
|
|
135
|
+
f: d.bind(e, 4),
|
|
136
|
+
d: function (t, r) {
|
|
137
|
+
return i = t, c = 0, u = e, G.n = r, a;
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
function d(r, n) {
|
|
141
|
+
for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) {
|
|
142
|
+
var o,
|
|
143
|
+
i = p[t],
|
|
144
|
+
d = G.p,
|
|
145
|
+
l = i[2];
|
|
146
|
+
r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0));
|
|
147
|
+
}
|
|
148
|
+
if (o || r > 1) return a;
|
|
149
|
+
throw y = true, n;
|
|
150
|
+
}
|
|
151
|
+
return function (o, p, l) {
|
|
152
|
+
if (f > 1) throw TypeError("Generator is already running");
|
|
153
|
+
for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) {
|
|
154
|
+
i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u);
|
|
155
|
+
try {
|
|
156
|
+
if (f = 2, i) {
|
|
157
|
+
if (c || (o = "next"), t = i[o]) {
|
|
158
|
+
if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object");
|
|
159
|
+
if (!t.done) return t;
|
|
160
|
+
u = t.value, c < 2 && (c = 0);
|
|
161
|
+
} else 1 === c && (t = i.return) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1);
|
|
162
|
+
i = e;
|
|
163
|
+
} else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break;
|
|
164
|
+
} catch (t) {
|
|
165
|
+
i = e, c = 1, u = t;
|
|
166
|
+
} finally {
|
|
167
|
+
f = 1;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
value: t,
|
|
172
|
+
done: y
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
}(r, o, i), true), u;
|
|
176
|
+
}
|
|
177
|
+
var a = {};
|
|
178
|
+
function Generator() {}
|
|
179
|
+
function GeneratorFunction() {}
|
|
180
|
+
function GeneratorFunctionPrototype() {}
|
|
181
|
+
t = Object.getPrototypeOf;
|
|
182
|
+
var c = [][n] ? t(t([][n]())) : (_regeneratorDefine(t = {}, n, function () {
|
|
183
|
+
return this;
|
|
184
|
+
}), t),
|
|
185
|
+
u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c);
|
|
186
|
+
function f(e) {
|
|
187
|
+
return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e;
|
|
188
|
+
}
|
|
189
|
+
return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine(u), _regeneratorDefine(u, o, "Generator"), _regeneratorDefine(u, n, function () {
|
|
190
|
+
return this;
|
|
191
|
+
}), _regeneratorDefine(u, "toString", function () {
|
|
192
|
+
return "[object Generator]";
|
|
193
|
+
}), (_regenerator = function () {
|
|
194
|
+
return {
|
|
195
|
+
w: i,
|
|
196
|
+
m: f
|
|
197
|
+
};
|
|
198
|
+
})();
|
|
199
|
+
}
|
|
200
|
+
function _regeneratorDefine(e, r, n, t) {
|
|
201
|
+
var i = Object.defineProperty;
|
|
202
|
+
try {
|
|
203
|
+
i({}, "", {});
|
|
204
|
+
} catch (e) {
|
|
205
|
+
i = 0;
|
|
206
|
+
}
|
|
207
|
+
_regeneratorDefine = function (e, r, n, t) {
|
|
208
|
+
function o(r, n) {
|
|
209
|
+
_regeneratorDefine(e, r, function (e) {
|
|
210
|
+
return this._invoke(r, n, e);
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
r ? i ? i(e, r, {
|
|
214
|
+
value: n,
|
|
215
|
+
enumerable: !t,
|
|
216
|
+
configurable: !t,
|
|
217
|
+
writable: !t
|
|
218
|
+
}) : e[r] = n : (o("next", 0), o("throw", 1), o("return", 2));
|
|
219
|
+
}, _regeneratorDefine(e, r, n, t);
|
|
220
|
+
}
|
|
221
|
+
function _slicedToArray(r, e) {
|
|
222
|
+
return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
|
|
223
|
+
}
|
|
224
|
+
function _toConsumableArray(r) {
|
|
225
|
+
return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread();
|
|
226
|
+
}
|
|
227
|
+
function _toPrimitive(t, r) {
|
|
228
|
+
if ("object" != typeof t || !t) return t;
|
|
229
|
+
var e = t[Symbol.toPrimitive];
|
|
230
|
+
if (void 0 !== e) {
|
|
231
|
+
var i = e.call(t, r);
|
|
232
|
+
if ("object" != typeof i) return i;
|
|
233
|
+
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
234
|
+
}
|
|
235
|
+
return ("string" === r ? String : Number)(t);
|
|
236
|
+
}
|
|
237
|
+
function _toPropertyKey(t) {
|
|
238
|
+
var i = _toPrimitive(t, "string");
|
|
239
|
+
return "symbol" == typeof i ? i : i + "";
|
|
240
|
+
}
|
|
241
|
+
function _typeof(o) {
|
|
242
|
+
"@babel/helpers - typeof";
|
|
243
|
+
|
|
244
|
+
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
|
|
245
|
+
return typeof o;
|
|
246
|
+
} : function (o) {
|
|
247
|
+
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
|
|
248
|
+
}, _typeof(o);
|
|
249
|
+
}
|
|
250
|
+
function _unsupportedIterableToArray(r, a) {
|
|
251
|
+
if (r) {
|
|
252
|
+
if ("string" == typeof r) return _arrayLikeToArray(r, a);
|
|
253
|
+
var t = {}.toString.call(r).slice(8, -1);
|
|
254
|
+
return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Integration Configuration & Default Mappings
|
|
260
|
+
* Users can customize these by passing their own config
|
|
261
|
+
*/
|
|
262
|
+
|
|
263
|
+
// ============================================
|
|
264
|
+
// ATLASSIAN DOCUMENT FORMAT (ADF) HELPER
|
|
265
|
+
// ============================================
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Convert plain text to Atlassian Document Format
|
|
269
|
+
* Jira Cloud requires descriptions in ADF format
|
|
270
|
+
*/
|
|
271
|
+
function textToADF(text) {
|
|
272
|
+
var lines = text.split('\n');
|
|
273
|
+
var content = [];
|
|
274
|
+
var currentParagraph = [];
|
|
275
|
+
var flushParagraph = function flushParagraph() {
|
|
276
|
+
if (currentParagraph.length > 0) {
|
|
277
|
+
content.push({
|
|
278
|
+
type: 'paragraph',
|
|
279
|
+
content: currentParagraph
|
|
280
|
+
});
|
|
281
|
+
currentParagraph = [];
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
lines.forEach(function (line, index) {
|
|
285
|
+
// Check if it's a section header (ALL CAPS)
|
|
286
|
+
if (line.match(/^[A-Z][A-Z\s]+$/) && line.trim().length > 0) {
|
|
287
|
+
flushParagraph();
|
|
288
|
+
content.push({
|
|
289
|
+
type: 'heading',
|
|
290
|
+
attrs: {
|
|
291
|
+
level: 3
|
|
292
|
+
},
|
|
293
|
+
content: [{
|
|
294
|
+
type: 'text',
|
|
295
|
+
text: line
|
|
296
|
+
}]
|
|
297
|
+
});
|
|
298
|
+
} else if (line === '---') {
|
|
299
|
+
// Horizontal rule
|
|
300
|
+
flushParagraph();
|
|
301
|
+
content.push({
|
|
302
|
+
type: 'rule'
|
|
303
|
+
});
|
|
304
|
+
} else if (line.trim() === '') {
|
|
305
|
+
// Empty line - flush paragraph
|
|
306
|
+
flushParagraph();
|
|
307
|
+
} else {
|
|
308
|
+
// Regular line
|
|
309
|
+
if (currentParagraph.length > 0) {
|
|
310
|
+
currentParagraph.push({
|
|
311
|
+
type: 'hardBreak'
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
currentParagraph.push({
|
|
315
|
+
type: 'text',
|
|
316
|
+
text: line
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
flushParagraph();
|
|
321
|
+
return {
|
|
322
|
+
type: 'doc',
|
|
323
|
+
version: 1,
|
|
324
|
+
content: content.length > 0 ? content : [{
|
|
325
|
+
type: 'paragraph',
|
|
326
|
+
content: [{
|
|
327
|
+
type: 'text',
|
|
328
|
+
text: ' '
|
|
329
|
+
}]
|
|
330
|
+
}]
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// ============================================
|
|
335
|
+
// JIRA FIELD MAPPING
|
|
336
|
+
// ============================================
|
|
337
|
+
|
|
338
|
+
var DEFAULT_JIRA_FIELDS = {
|
|
339
|
+
summary: {
|
|
340
|
+
key: 'summary',
|
|
341
|
+
source: 'feedback',
|
|
342
|
+
maxLength: 255,
|
|
343
|
+
prefix: '[Feedback] ',
|
|
344
|
+
transform: function transform(data) {
|
|
345
|
+
var prefix = '[Feedback] ';
|
|
346
|
+
var text = data.feedback || 'User Feedback';
|
|
347
|
+
var maxLen = 255 - prefix.length;
|
|
348
|
+
return prefix + (text.length > maxLen ? text.substring(0, maxLen - 3) + '...' : text);
|
|
349
|
+
}
|
|
350
|
+
},
|
|
351
|
+
description: {
|
|
352
|
+
key: 'description',
|
|
353
|
+
// Build description directly - no wiki markup, clean plain text for ADF
|
|
354
|
+
transform: function transform(data) {
|
|
355
|
+
var lines = [];
|
|
356
|
+
|
|
357
|
+
// Feedback Details
|
|
358
|
+
lines.push('FEEDBACK DETAILS');
|
|
359
|
+
lines.push("Feedback: ".concat(data.feedback || 'No feedback provided'));
|
|
360
|
+
lines.push("Type: ".concat(data.type || 'bug'));
|
|
361
|
+
lines.push("Status: ".concat(data.status || 'new'));
|
|
362
|
+
lines.push('');
|
|
363
|
+
|
|
364
|
+
// User Information
|
|
365
|
+
lines.push('USER INFORMATION');
|
|
366
|
+
lines.push("Name: ".concat(data.userName || 'Anonymous'));
|
|
367
|
+
lines.push("Email: ".concat(data.userEmail || 'Not provided'));
|
|
368
|
+
lines.push('');
|
|
369
|
+
|
|
370
|
+
// Technical Details
|
|
371
|
+
lines.push('TECHNICAL DETAILS');
|
|
372
|
+
lines.push("Page URL: ".concat(data.url || 'N/A'));
|
|
373
|
+
if (data.viewport) {
|
|
374
|
+
lines.push("Viewport: ".concat(data.viewport.width, "x").concat(data.viewport.height));
|
|
375
|
+
}
|
|
376
|
+
if (data.userAgent) {
|
|
377
|
+
// Simplify user agent
|
|
378
|
+
var browser = data.userAgent;
|
|
379
|
+
if (browser.includes('Chrome')) browser = 'Chrome';else if (browser.includes('Firefox')) browser = 'Firefox';else if (browser.includes('Safari')) browser = 'Safari';else if (browser.includes('Edge')) browser = 'Edge';
|
|
380
|
+
lines.push("Browser: ".concat(browser));
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Element info
|
|
384
|
+
if (data.elementInfo) {
|
|
385
|
+
var _data$elementInfo$com;
|
|
386
|
+
if (data.elementInfo.selector) {
|
|
387
|
+
lines.push("Element: ".concat(data.elementInfo.selector));
|
|
388
|
+
}
|
|
389
|
+
if ((_data$elementInfo$com = data.elementInfo.componentStack) !== null && _data$elementInfo$com !== void 0 && _data$elementInfo$com.length) {
|
|
390
|
+
lines.push("Component: ".concat(data.elementInfo.componentStack.join(' > ')));
|
|
391
|
+
}
|
|
392
|
+
if (data.elementInfo.sourceFile) {
|
|
393
|
+
lines.push("Source: ".concat(data.elementInfo.sourceFile, ":").concat(data.elementInfo.lineNumber || ''));
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
lines.push('');
|
|
397
|
+
|
|
398
|
+
// Attachments
|
|
399
|
+
var attachments = [];
|
|
400
|
+
if (data.screenshot) attachments.push('Screenshot');
|
|
401
|
+
if (data.video) attachments.push('Screen Recording');
|
|
402
|
+
if (attachments.length > 0) {
|
|
403
|
+
lines.push('ATTACHMENTS');
|
|
404
|
+
lines.push(attachments.join(', ') + ' attached');
|
|
405
|
+
lines.push('');
|
|
406
|
+
}
|
|
407
|
+
lines.push('---');
|
|
408
|
+
lines.push('Submitted via React Visual Feedback');
|
|
409
|
+
return lines.join('\n');
|
|
410
|
+
}
|
|
411
|
+
},
|
|
412
|
+
issuetype: {
|
|
413
|
+
key: 'issuetype',
|
|
414
|
+
// Default to 'Task' which exists in most Jira projects
|
|
415
|
+
// Can be overridden via JIRA_ISSUE_TYPE env var or config
|
|
416
|
+
value: 'Task',
|
|
417
|
+
// Map feedback types to Jira issue types (all default to Task for compatibility)
|
|
418
|
+
typeMapping: {
|
|
419
|
+
bug: 'Task',
|
|
420
|
+
feature: 'Task',
|
|
421
|
+
improvement: 'Task',
|
|
422
|
+
question: 'Task',
|
|
423
|
+
other: 'Task'
|
|
424
|
+
},
|
|
425
|
+
transform: function transform(data, config) {
|
|
426
|
+
var _process$env;
|
|
427
|
+
// Priority: env var > config value > type mapping > default
|
|
428
|
+
var envIssueType = typeof process !== 'undefined' ? (_process$env = process.env) === null || _process$env === void 0 ? void 0 : _process$env.JIRA_ISSUE_TYPE : null;
|
|
429
|
+
if (envIssueType) return envIssueType;
|
|
430
|
+
if (config !== null && config !== void 0 && config.value && config.value !== 'Task') return config.value;
|
|
431
|
+
var mapping = (config === null || config === void 0 ? void 0 : config.typeMapping) || DEFAULT_JIRA_FIELDS.issuetype.typeMapping;
|
|
432
|
+
return mapping[data.type] || (config === null || config === void 0 ? void 0 : config.value) || 'Task';
|
|
433
|
+
}
|
|
434
|
+
},
|
|
435
|
+
labels: {
|
|
436
|
+
key: 'labels',
|
|
437
|
+
value: ['user-feedback'],
|
|
438
|
+
transform: function transform(data, config) {
|
|
439
|
+
var labels = _toConsumableArray((config === null || config === void 0 ? void 0 : config.value) || ['user-feedback']);
|
|
440
|
+
if (data.type) labels.push("type-".concat(data.type));
|
|
441
|
+
return labels;
|
|
442
|
+
}
|
|
443
|
+
},
|
|
444
|
+
priority: {
|
|
445
|
+
key: 'priority',
|
|
446
|
+
// Map to Jira priority IDs (user can customize)
|
|
447
|
+
priorityMapping: {
|
|
448
|
+
bug: 'High',
|
|
449
|
+
feature: 'Medium',
|
|
450
|
+
improvement: 'Medium',
|
|
451
|
+
question: 'Low',
|
|
452
|
+
other: 'Low'
|
|
453
|
+
},
|
|
454
|
+
transform: function transform(data, config) {
|
|
455
|
+
var mapping = (config === null || config === void 0 ? void 0 : config.priorityMapping) || DEFAULT_JIRA_FIELDS.priority.priorityMapping;
|
|
456
|
+
return mapping[data.type] || 'Medium';
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
// ============================================
|
|
462
|
+
// JIRA STATUS MAPPING (Bidirectional sync)
|
|
463
|
+
// ============================================
|
|
464
|
+
|
|
465
|
+
var DEFAULT_JIRA_STATUS_MAPPING = {
|
|
466
|
+
// Our status -> Jira status
|
|
467
|
+
toJira: {
|
|
468
|
+
"new": 'To Do',
|
|
469
|
+
open: 'To Do',
|
|
470
|
+
inProgress: 'In Progress',
|
|
471
|
+
underReview: 'In Review',
|
|
472
|
+
onHold: 'On Hold',
|
|
473
|
+
resolved: 'Done',
|
|
474
|
+
closed: 'Done',
|
|
475
|
+
wontFix: 'Won\'t Do'
|
|
476
|
+
},
|
|
477
|
+
// Jira status -> Our status
|
|
478
|
+
fromJira: {
|
|
479
|
+
'To Do': 'open',
|
|
480
|
+
'Open': 'open',
|
|
481
|
+
'In Progress': 'inProgress',
|
|
482
|
+
'In Review': 'underReview',
|
|
483
|
+
'On Hold': 'onHold',
|
|
484
|
+
'Done': 'resolved',
|
|
485
|
+
'Closed': 'closed',
|
|
486
|
+
'Won\'t Do': 'wontFix',
|
|
487
|
+
'Resolved': 'resolved'
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Merge user Jira config with defaults
|
|
493
|
+
*/
|
|
494
|
+
function mergeJiraFields() {
|
|
495
|
+
var userFields = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
496
|
+
var merged = _objectSpread2({}, DEFAULT_JIRA_FIELDS);
|
|
497
|
+
Object.entries(userFields).forEach(function (_ref3) {
|
|
498
|
+
var _ref4 = _slicedToArray(_ref3, 2),
|
|
499
|
+
key = _ref4[0],
|
|
500
|
+
value = _ref4[1];
|
|
501
|
+
if (value === null || value === false) {
|
|
502
|
+
delete merged[key];
|
|
503
|
+
} else if (_typeof(value) === 'object') {
|
|
504
|
+
merged[key] = _objectSpread2(_objectSpread2({}, merged[key]), value);
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
return merged;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Transform feedback data to Jira issue
|
|
512
|
+
*/
|
|
513
|
+
function feedbackToJiraIssue(feedbackData) {
|
|
514
|
+
var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
515
|
+
var fields = mergeJiraFields(config.fields);
|
|
516
|
+
|
|
517
|
+
// Get plain text description and convert to ADF
|
|
518
|
+
var plainDescription = fields.description.transform(feedbackData, fields.description);
|
|
519
|
+
var adfDescription = textToADF(plainDescription);
|
|
520
|
+
var issue = {
|
|
521
|
+
fields: {
|
|
522
|
+
project: {
|
|
523
|
+
key: config.projectKey
|
|
524
|
+
},
|
|
525
|
+
summary: fields.summary.transform(feedbackData, fields.summary),
|
|
526
|
+
description: adfDescription,
|
|
527
|
+
issuetype: {
|
|
528
|
+
name: fields.issuetype.transform(feedbackData, fields.issuetype)
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
// Add labels if configured
|
|
534
|
+
if (fields.labels) {
|
|
535
|
+
issue.fields.labels = fields.labels.transform(feedbackData, fields.labels);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// Add priority if configured and user wants it
|
|
539
|
+
if (config.includePriority && fields.priority) {
|
|
540
|
+
issue.fields.priority = {
|
|
541
|
+
name: fields.priority.transform(feedbackData, fields.priority)
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// Add custom fields
|
|
546
|
+
if (config.customFields) {
|
|
547
|
+
Object.entries(config.customFields).forEach(function (_ref5) {
|
|
548
|
+
var _ref6 = _slicedToArray(_ref5, 2),
|
|
549
|
+
fieldId = _ref6[0],
|
|
550
|
+
fieldConfig = _ref6[1];
|
|
551
|
+
if (typeof fieldConfig === 'string') {
|
|
552
|
+
issue.fields[fieldId] = feedbackData[fieldConfig];
|
|
553
|
+
} else if (fieldConfig.transform) {
|
|
554
|
+
issue.fields[fieldId] = fieldConfig.transform(feedbackData);
|
|
555
|
+
} else if (fieldConfig.value) {
|
|
556
|
+
issue.fields[fieldId] = fieldConfig.value;
|
|
557
|
+
}
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
return issue;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Map Jira status to our status
|
|
565
|
+
*/
|
|
566
|
+
function mapJiraStatusToLocal(jiraStatus) {
|
|
567
|
+
var customMapping = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
568
|
+
var mapping = _objectSpread2(_objectSpread2({}, DEFAULT_JIRA_STATUS_MAPPING.fromJira), customMapping);
|
|
569
|
+
return mapping[jiraStatus] || 'open';
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* Map our status to Jira status
|
|
574
|
+
*/
|
|
575
|
+
function mapLocalStatusToJira(localStatus) {
|
|
576
|
+
var customMapping = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
577
|
+
var mapping = _objectSpread2(_objectSpread2({}, DEFAULT_JIRA_STATUS_MAPPING.toJira), customMapping);
|
|
578
|
+
return mapping[localStatus] || 'To Do';
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// ============================================
|
|
582
|
+
// HELPER FUNCTIONS
|
|
583
|
+
// ============================================
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Format event logs as a readable text file
|
|
587
|
+
*/
|
|
588
|
+
function formatEventLogs(eventLogs) {
|
|
589
|
+
if (!eventLogs || eventLogs.length === 0) {
|
|
590
|
+
return 'No event logs recorded.';
|
|
591
|
+
}
|
|
592
|
+
var lines = ['═══════════════════════════════════════════════════════════════', ' SESSION EVENT LOGS', '═══════════════════════════════════════════════════════════════', "Generated: ".concat(new Date().toISOString()), "Total Events: ".concat(eventLogs.length), '═══════════════════════════════════════════════════════════════', ''];
|
|
593
|
+
eventLogs.forEach(function (event, index) {
|
|
594
|
+
var _event$request, _event$response;
|
|
595
|
+
var timestamp = event.timestamp ? "[".concat((event.timestamp / 1000).toFixed(2), "s]") : '[--]';
|
|
596
|
+
switch (event.type) {
|
|
597
|
+
case 'console':
|
|
598
|
+
lines.push("".concat(timestamp, " [CONSOLE.").concat((event.level || 'log').toUpperCase(), "]"));
|
|
599
|
+
lines.push(" ".concat(event.message || 'No message'));
|
|
600
|
+
break;
|
|
601
|
+
case 'network':
|
|
602
|
+
var status = event.status || 'pending';
|
|
603
|
+
var duration = event.duration ? "(".concat(event.duration, "ms)") : '';
|
|
604
|
+
lines.push("".concat(timestamp, " [NETWORK] ").concat(event.method || 'GET', " ").concat(event.url));
|
|
605
|
+
lines.push(" Status: ".concat(status, " ").concat(duration));
|
|
606
|
+
if ((_event$request = event.request) !== null && _event$request !== void 0 && _event$request.body && event.request.body !== 'null' && event.request.body !== 'undefined') {
|
|
607
|
+
lines.push(" Request: ".concat(event.request.body.substring(0, 200)).concat(event.request.body.length > 200 ? '...' : ''));
|
|
608
|
+
}
|
|
609
|
+
if ((_event$response = event.response) !== null && _event$response !== void 0 && _event$response.body && event.response.body !== 'null' && event.response.body !== 'undefined') {
|
|
610
|
+
lines.push(" Response: ".concat(event.response.body.substring(0, 200)).concat(event.response.body.length > 200 ? '...' : ''));
|
|
611
|
+
}
|
|
612
|
+
break;
|
|
613
|
+
case 'storage':
|
|
614
|
+
lines.push("".concat(timestamp, " [").concat((event.storageType || 'storage').toUpperCase(), "] ").concat(event.action));
|
|
615
|
+
if (event.key) lines.push(" Key: ".concat(event.key));
|
|
616
|
+
if (event.value) lines.push(" Value: ".concat(event.value.substring(0, 100)).concat(event.value.length > 100 ? '...' : ''));
|
|
617
|
+
break;
|
|
618
|
+
case 'indexedDB':
|
|
619
|
+
lines.push("".concat(timestamp, " [INDEXEDDB] ").concat(event.action, " on ").concat(event.dbName || 'unknown').concat(event.storeName ? '.' + event.storeName : ''));
|
|
620
|
+
if (event.data) lines.push(" Data: ".concat(event.data.substring(0, 100)).concat(event.data.length > 100 ? '...' : ''));
|
|
621
|
+
break;
|
|
622
|
+
default:
|
|
623
|
+
lines.push("".concat(timestamp, " [").concat((event.type || 'EVENT').toUpperCase(), "]"));
|
|
624
|
+
lines.push(" ".concat(JSON.stringify(event).substring(0, 200)));
|
|
625
|
+
}
|
|
626
|
+
lines.push(''); // Empty line between events
|
|
627
|
+
});
|
|
628
|
+
lines.push('═══════════════════════════════════════════════════════════════');
|
|
629
|
+
lines.push(' END OF LOGS');
|
|
630
|
+
lines.push('═══════════════════════════════════════════════════════════════');
|
|
631
|
+
return lines.join('\n');
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// ============================================
|
|
635
|
+
// JIRA API CLIENT
|
|
636
|
+
// ============================================
|
|
637
|
+
var JiraClient = /*#__PURE__*/function () {
|
|
638
|
+
function JiraClient(config) {
|
|
639
|
+
_classCallCheck(this, JiraClient);
|
|
640
|
+
var domain = config.domain || process.env.JIRA_DOMAIN;
|
|
641
|
+
this.email = config.email || process.env.JIRA_EMAIL;
|
|
642
|
+
this.apiToken = config.apiToken || process.env.JIRA_API_TOKEN;
|
|
643
|
+
this.projectKey = config.projectKey || process.env.JIRA_PROJECT_KEY;
|
|
644
|
+
if (!domain || !this.email || !this.apiToken) {
|
|
645
|
+
throw new Error('Jira configuration missing. Required: JIRA_DOMAIN, JIRA_EMAIL, JIRA_API_TOKEN');
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// Strip protocol and trailing slashes from domain
|
|
649
|
+
this.domain = domain.replace(/^https?:\/\//, '').replace(/\/+$/, '');
|
|
650
|
+
this.baseUrl = "https://".concat(this.domain, "/rest/api/3");
|
|
651
|
+
this.authHeader = 'Basic ' + Buffer.from("".concat(this.email, ":").concat(this.apiToken)).toString('base64');
|
|
652
|
+
}
|
|
653
|
+
return _createClass(JiraClient, [{
|
|
654
|
+
key: "request",
|
|
655
|
+
value: function () {
|
|
656
|
+
var _request = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(endpoint) {
|
|
657
|
+
var options,
|
|
658
|
+
url,
|
|
659
|
+
response,
|
|
660
|
+
error,
|
|
661
|
+
text,
|
|
662
|
+
_args = arguments;
|
|
663
|
+
return _regenerator().w(function (_context) {
|
|
664
|
+
while (1) switch (_context.n) {
|
|
665
|
+
case 0:
|
|
666
|
+
options = _args.length > 1 && _args[1] !== undefined ? _args[1] : {};
|
|
667
|
+
url = "".concat(this.baseUrl).concat(endpoint);
|
|
668
|
+
_context.n = 1;
|
|
669
|
+
return fetch(url, _objectSpread2(_objectSpread2({}, options), {}, {
|
|
670
|
+
headers: _objectSpread2({
|
|
671
|
+
'Authorization': this.authHeader,
|
|
672
|
+
'Content-Type': 'application/json',
|
|
673
|
+
'Accept': 'application/json'
|
|
674
|
+
}, options.headers)
|
|
675
|
+
}));
|
|
676
|
+
case 1:
|
|
677
|
+
response = _context.v;
|
|
678
|
+
if (response.ok) {
|
|
679
|
+
_context.n = 3;
|
|
680
|
+
break;
|
|
681
|
+
}
|
|
682
|
+
_context.n = 2;
|
|
683
|
+
return response.text();
|
|
684
|
+
case 2:
|
|
685
|
+
error = _context.v;
|
|
686
|
+
throw new Error("Jira API error (".concat(response.status, "): ").concat(error));
|
|
687
|
+
case 3:
|
|
688
|
+
_context.n = 4;
|
|
689
|
+
return response.text();
|
|
690
|
+
case 4:
|
|
691
|
+
text = _context.v;
|
|
692
|
+
return _context.a(2, text ? JSON.parse(text) : null);
|
|
693
|
+
}
|
|
694
|
+
}, _callee, this);
|
|
695
|
+
}));
|
|
696
|
+
function request(_x) {
|
|
697
|
+
return _request.apply(this, arguments);
|
|
698
|
+
}
|
|
699
|
+
return request;
|
|
700
|
+
}()
|
|
701
|
+
/**
|
|
702
|
+
* Create a new issue
|
|
703
|
+
*/
|
|
704
|
+
}, {
|
|
705
|
+
key: "createIssue",
|
|
706
|
+
value: (function () {
|
|
707
|
+
var _createIssue = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(issueData) {
|
|
708
|
+
return _regenerator().w(function (_context2) {
|
|
709
|
+
while (1) switch (_context2.n) {
|
|
710
|
+
case 0:
|
|
711
|
+
return _context2.a(2, this.request('/issue', {
|
|
712
|
+
method: 'POST',
|
|
713
|
+
body: JSON.stringify(issueData)
|
|
714
|
+
}));
|
|
715
|
+
}
|
|
716
|
+
}, _callee2, this);
|
|
717
|
+
}));
|
|
718
|
+
function createIssue(_x2) {
|
|
719
|
+
return _createIssue.apply(this, arguments);
|
|
720
|
+
}
|
|
721
|
+
return createIssue;
|
|
722
|
+
}()
|
|
723
|
+
/**
|
|
724
|
+
* Get issue details
|
|
725
|
+
*/
|
|
726
|
+
)
|
|
727
|
+
}, {
|
|
728
|
+
key: "getIssue",
|
|
729
|
+
value: (function () {
|
|
730
|
+
var _getIssue = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(issueKey) {
|
|
731
|
+
return _regenerator().w(function (_context3) {
|
|
732
|
+
while (1) switch (_context3.n) {
|
|
733
|
+
case 0:
|
|
734
|
+
return _context3.a(2, this.request("/issue/".concat(issueKey)));
|
|
735
|
+
}
|
|
736
|
+
}, _callee3, this);
|
|
737
|
+
}));
|
|
738
|
+
function getIssue(_x3) {
|
|
739
|
+
return _getIssue.apply(this, arguments);
|
|
740
|
+
}
|
|
741
|
+
return getIssue;
|
|
742
|
+
}()
|
|
743
|
+
/**
|
|
744
|
+
* Update issue status via transition
|
|
745
|
+
*/
|
|
746
|
+
)
|
|
747
|
+
}, {
|
|
748
|
+
key: "transitionIssue",
|
|
749
|
+
value: (function () {
|
|
750
|
+
var _transitionIssue = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4(issueKey, transitionName) {
|
|
751
|
+
var transitions, transition;
|
|
752
|
+
return _regenerator().w(function (_context4) {
|
|
753
|
+
while (1) switch (_context4.n) {
|
|
754
|
+
case 0:
|
|
755
|
+
_context4.n = 1;
|
|
756
|
+
return this.request("/issue/".concat(issueKey, "/transitions"));
|
|
757
|
+
case 1:
|
|
758
|
+
transitions = _context4.v;
|
|
759
|
+
transition = transitions.transitions.find(function (t) {
|
|
760
|
+
return t.name.toLowerCase() === transitionName.toLowerCase() || t.to.name.toLowerCase() === transitionName.toLowerCase();
|
|
761
|
+
});
|
|
762
|
+
if (transition) {
|
|
763
|
+
_context4.n = 2;
|
|
764
|
+
break;
|
|
765
|
+
}
|
|
766
|
+
throw new Error("Transition \"".concat(transitionName, "\" not found for issue ").concat(issueKey));
|
|
767
|
+
case 2:
|
|
768
|
+
_context4.n = 3;
|
|
769
|
+
return this.request("/issue/".concat(issueKey, "/transitions"), {
|
|
770
|
+
method: 'POST',
|
|
771
|
+
body: JSON.stringify({
|
|
772
|
+
transition: {
|
|
773
|
+
id: transition.id
|
|
774
|
+
}
|
|
775
|
+
})
|
|
776
|
+
});
|
|
777
|
+
case 3:
|
|
778
|
+
return _context4.a(2, {
|
|
779
|
+
success: true,
|
|
780
|
+
transitionId: transition.id
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
}, _callee4, this);
|
|
784
|
+
}));
|
|
785
|
+
function transitionIssue(_x4, _x5) {
|
|
786
|
+
return _transitionIssue.apply(this, arguments);
|
|
787
|
+
}
|
|
788
|
+
return transitionIssue;
|
|
789
|
+
}()
|
|
790
|
+
/**
|
|
791
|
+
* Add attachment to issue
|
|
792
|
+
*/
|
|
793
|
+
)
|
|
794
|
+
}, {
|
|
795
|
+
key: "addAttachment",
|
|
796
|
+
value: (function () {
|
|
797
|
+
var _addAttachment = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5(issueKey, filename, content, contentType) {
|
|
798
|
+
var url, buffer, commaIndex, base64Data, boundary, formData, response, error;
|
|
799
|
+
return _regenerator().w(function (_context5) {
|
|
800
|
+
while (1) switch (_context5.n) {
|
|
801
|
+
case 0:
|
|
802
|
+
url = "".concat(this.baseUrl, "/issue/").concat(issueKey, "/attachments"); // Convert content to buffer
|
|
803
|
+
if (!Buffer.isBuffer(content)) {
|
|
804
|
+
_context5.n = 1;
|
|
805
|
+
break;
|
|
806
|
+
}
|
|
807
|
+
// Already a buffer
|
|
808
|
+
buffer = content;
|
|
809
|
+
_context5.n = 8;
|
|
810
|
+
break;
|
|
811
|
+
case 1:
|
|
812
|
+
if (!(typeof content === 'string')) {
|
|
813
|
+
_context5.n = 6;
|
|
814
|
+
break;
|
|
815
|
+
}
|
|
816
|
+
if (!content.startsWith('data:')) {
|
|
817
|
+
_context5.n = 4;
|
|
818
|
+
break;
|
|
819
|
+
}
|
|
820
|
+
// Data URL format: data:video/webm;base64,AAAA...
|
|
821
|
+
commaIndex = content.indexOf(',');
|
|
822
|
+
if (!(commaIndex !== -1)) {
|
|
823
|
+
_context5.n = 2;
|
|
824
|
+
break;
|
|
825
|
+
}
|
|
826
|
+
base64Data = content.substring(commaIndex + 1);
|
|
827
|
+
buffer = Buffer.from(base64Data, 'base64');
|
|
828
|
+
_context5.n = 3;
|
|
829
|
+
break;
|
|
830
|
+
case 2:
|
|
831
|
+
throw new Error('Invalid data URL format - missing comma separator');
|
|
832
|
+
case 3:
|
|
833
|
+
_context5.n = 5;
|
|
834
|
+
break;
|
|
835
|
+
case 4:
|
|
836
|
+
// Assume raw base64 string
|
|
837
|
+
buffer = Buffer.from(content, 'base64');
|
|
838
|
+
case 5:
|
|
839
|
+
_context5.n = 8;
|
|
840
|
+
break;
|
|
841
|
+
case 6:
|
|
842
|
+
if (!(content instanceof Uint8Array)) {
|
|
843
|
+
_context5.n = 7;
|
|
844
|
+
break;
|
|
845
|
+
}
|
|
846
|
+
buffer = Buffer.from(content);
|
|
847
|
+
_context5.n = 8;
|
|
848
|
+
break;
|
|
849
|
+
case 7:
|
|
850
|
+
throw new Error("Unsupported content type: ".concat(_typeof(content)));
|
|
851
|
+
case 8:
|
|
852
|
+
if (!(!buffer || buffer.length === 0)) {
|
|
853
|
+
_context5.n = 9;
|
|
854
|
+
break;
|
|
855
|
+
}
|
|
856
|
+
throw new Error('Attachment content is empty');
|
|
857
|
+
case 9:
|
|
858
|
+
// Create form data manually for Node.js
|
|
859
|
+
boundary = '----FormBoundary' + Math.random().toString(36).substring(2);
|
|
860
|
+
formData = Buffer.concat([Buffer.from("--".concat(boundary, "\r\n") + "Content-Disposition: form-data; name=\"file\"; filename=\"".concat(filename, "\"\r\n") + "Content-Type: ".concat(contentType, "\r\n\r\n")), buffer, Buffer.from("\r\n--".concat(boundary, "--\r\n"))]);
|
|
861
|
+
_context5.n = 10;
|
|
862
|
+
return fetch(url, {
|
|
863
|
+
method: 'POST',
|
|
864
|
+
headers: {
|
|
865
|
+
'Authorization': this.authHeader,
|
|
866
|
+
'X-Atlassian-Token': 'no-check',
|
|
867
|
+
'Content-Type': "multipart/form-data; boundary=".concat(boundary)
|
|
868
|
+
},
|
|
869
|
+
body: formData
|
|
870
|
+
});
|
|
871
|
+
case 10:
|
|
872
|
+
response = _context5.v;
|
|
873
|
+
if (response.ok) {
|
|
874
|
+
_context5.n = 12;
|
|
875
|
+
break;
|
|
876
|
+
}
|
|
877
|
+
_context5.n = 11;
|
|
878
|
+
return response.text();
|
|
879
|
+
case 11:
|
|
880
|
+
error = _context5.v;
|
|
881
|
+
throw new Error("Failed to upload attachment (".concat(response.status, "): ").concat(error));
|
|
882
|
+
case 12:
|
|
883
|
+
return _context5.a(2, response.json());
|
|
884
|
+
}
|
|
885
|
+
}, _callee5, this);
|
|
886
|
+
}));
|
|
887
|
+
function addAttachment(_x6, _x7, _x8, _x9) {
|
|
888
|
+
return _addAttachment.apply(this, arguments);
|
|
889
|
+
}
|
|
890
|
+
return addAttachment;
|
|
891
|
+
}()
|
|
892
|
+
/**
|
|
893
|
+
* Add comment to issue
|
|
894
|
+
*/
|
|
895
|
+
)
|
|
896
|
+
}, {
|
|
897
|
+
key: "addComment",
|
|
898
|
+
value: (function () {
|
|
899
|
+
var _addComment = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6(issueKey, comment) {
|
|
900
|
+
return _regenerator().w(function (_context6) {
|
|
901
|
+
while (1) switch (_context6.n) {
|
|
902
|
+
case 0:
|
|
903
|
+
return _context6.a(2, this.request("/issue/".concat(issueKey, "/comment"), {
|
|
904
|
+
method: 'POST',
|
|
905
|
+
body: JSON.stringify({
|
|
906
|
+
body: {
|
|
907
|
+
type: 'doc',
|
|
908
|
+
version: 1,
|
|
909
|
+
content: [{
|
|
910
|
+
type: 'paragraph',
|
|
911
|
+
content: [{
|
|
912
|
+
type: 'text',
|
|
913
|
+
text: comment
|
|
914
|
+
}]
|
|
915
|
+
}]
|
|
916
|
+
}
|
|
917
|
+
})
|
|
918
|
+
}));
|
|
919
|
+
}
|
|
920
|
+
}, _callee6, this);
|
|
921
|
+
}));
|
|
922
|
+
function addComment(_x0, _x1) {
|
|
923
|
+
return _addComment.apply(this, arguments);
|
|
924
|
+
}
|
|
925
|
+
return addComment;
|
|
926
|
+
}()
|
|
927
|
+
/**
|
|
928
|
+
* Get issue status
|
|
929
|
+
*/
|
|
930
|
+
)
|
|
931
|
+
}, {
|
|
932
|
+
key: "getIssueStatus",
|
|
933
|
+
value: (function () {
|
|
934
|
+
var _getIssueStatus = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee7(issueKey) {
|
|
935
|
+
var issue;
|
|
936
|
+
return _regenerator().w(function (_context7) {
|
|
937
|
+
while (1) switch (_context7.n) {
|
|
938
|
+
case 0:
|
|
939
|
+
_context7.n = 1;
|
|
940
|
+
return this.getIssue(issueKey);
|
|
941
|
+
case 1:
|
|
942
|
+
issue = _context7.v;
|
|
943
|
+
return _context7.a(2, issue.fields.status.name);
|
|
944
|
+
}
|
|
945
|
+
}, _callee7, this);
|
|
946
|
+
}));
|
|
947
|
+
function getIssueStatus(_x10) {
|
|
948
|
+
return _getIssueStatus.apply(this, arguments);
|
|
949
|
+
}
|
|
950
|
+
return getIssueStatus;
|
|
951
|
+
}())
|
|
952
|
+
}]);
|
|
953
|
+
}(); // ============================================
|
|
954
|
+
// REQUEST HANDLERS
|
|
955
|
+
// ============================================
|
|
956
|
+
/**
|
|
957
|
+
* Parse multipart form data from request
|
|
958
|
+
* Works with Next.js App Router, Pages Router, and Express
|
|
959
|
+
*/
|
|
960
|
+
function parseFormData(_x11) {
|
|
961
|
+
return _parseFormData.apply(this, arguments);
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
964
|
+
* Create Jira handler with configuration
|
|
965
|
+
*/
|
|
966
|
+
function _parseFormData() {
|
|
967
|
+
_parseFormData = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee1(req) {
|
|
968
|
+
var _req$headers, _req$headers$get, _req$headers2, contentType, body, formData, action, metadataStr, metadata, screenshot, video, eventLogs, feedbackData, arrayBuffer, _arrayBuffer, text, _body;
|
|
969
|
+
return _regenerator().w(function (_context1) {
|
|
970
|
+
while (1) switch (_context1.n) {
|
|
971
|
+
case 0:
|
|
972
|
+
if (!(typeof req.json === 'function' || typeof req.formData === 'function')) {
|
|
973
|
+
_context1.n = 10;
|
|
974
|
+
break;
|
|
975
|
+
}
|
|
976
|
+
// Check Content-Type to determine how to parse
|
|
977
|
+
contentType = ((_req$headers = req.headers) === null || _req$headers === void 0 || (_req$headers$get = _req$headers.get) === null || _req$headers$get === void 0 ? void 0 : _req$headers$get.call(_req$headers, 'content-type')) || ((_req$headers2 = req.headers) === null || _req$headers2 === void 0 ? void 0 : _req$headers2['content-type']) || ''; // Handle JSON requests (e.g., getStatus, updateStatus)
|
|
978
|
+
if (!contentType.includes('application/json')) {
|
|
979
|
+
_context1.n = 2;
|
|
980
|
+
break;
|
|
981
|
+
}
|
|
982
|
+
_context1.n = 1;
|
|
983
|
+
return req.json();
|
|
984
|
+
case 1:
|
|
985
|
+
body = _context1.v;
|
|
986
|
+
return _context1.a(2, {
|
|
987
|
+
action: body.action || 'create',
|
|
988
|
+
feedbackData: body.feedbackData || body,
|
|
989
|
+
issueKey: body.issueKey,
|
|
990
|
+
status: body.status,
|
|
991
|
+
comment: body.comment
|
|
992
|
+
});
|
|
993
|
+
case 2:
|
|
994
|
+
if (!(typeof req.formData === 'function')) {
|
|
995
|
+
_context1.n = 10;
|
|
996
|
+
break;
|
|
997
|
+
}
|
|
998
|
+
_context1.n = 3;
|
|
999
|
+
return req.formData();
|
|
1000
|
+
case 3:
|
|
1001
|
+
formData = _context1.v;
|
|
1002
|
+
action = formData.get('action') || 'create';
|
|
1003
|
+
metadataStr = formData.get('metadata');
|
|
1004
|
+
metadata = metadataStr ? JSON.parse(metadataStr) : {}; // Get files
|
|
1005
|
+
screenshot = formData.get('screenshot');
|
|
1006
|
+
video = formData.get('video');
|
|
1007
|
+
eventLogs = formData.get('eventLogs'); // Convert files to buffers
|
|
1008
|
+
feedbackData = _objectSpread2({}, metadata);
|
|
1009
|
+
if (!(screenshot && screenshot instanceof Blob)) {
|
|
1010
|
+
_context1.n = 5;
|
|
1011
|
+
break;
|
|
1012
|
+
}
|
|
1013
|
+
_context1.n = 4;
|
|
1014
|
+
return screenshot.arrayBuffer();
|
|
1015
|
+
case 4:
|
|
1016
|
+
arrayBuffer = _context1.v;
|
|
1017
|
+
feedbackData.screenshotBuffer = Buffer.from(arrayBuffer);
|
|
1018
|
+
feedbackData.screenshotType = screenshot.type || 'image/png';
|
|
1019
|
+
case 5:
|
|
1020
|
+
if (!(video && video instanceof Blob)) {
|
|
1021
|
+
_context1.n = 7;
|
|
1022
|
+
break;
|
|
1023
|
+
}
|
|
1024
|
+
_context1.n = 6;
|
|
1025
|
+
return video.arrayBuffer();
|
|
1026
|
+
case 6:
|
|
1027
|
+
_arrayBuffer = _context1.v;
|
|
1028
|
+
feedbackData.videoBuffer = Buffer.from(_arrayBuffer);
|
|
1029
|
+
feedbackData.videoType = video.type || 'video/webm';
|
|
1030
|
+
feedbackData.videoSize = video.size;
|
|
1031
|
+
case 7:
|
|
1032
|
+
if (!(eventLogs && eventLogs instanceof Blob)) {
|
|
1033
|
+
_context1.n = 9;
|
|
1034
|
+
break;
|
|
1035
|
+
}
|
|
1036
|
+
_context1.n = 8;
|
|
1037
|
+
return eventLogs.text();
|
|
1038
|
+
case 8:
|
|
1039
|
+
text = _context1.v;
|
|
1040
|
+
try {
|
|
1041
|
+
feedbackData.eventLogs = JSON.parse(text);
|
|
1042
|
+
} catch (e) {
|
|
1043
|
+
feedbackData.eventLogs = [];
|
|
1044
|
+
}
|
|
1045
|
+
case 9:
|
|
1046
|
+
return _context1.a(2, {
|
|
1047
|
+
action: action,
|
|
1048
|
+
feedbackData: feedbackData
|
|
1049
|
+
});
|
|
1050
|
+
case 10:
|
|
1051
|
+
if (!req.body) {
|
|
1052
|
+
_context1.n = 11;
|
|
1053
|
+
break;
|
|
1054
|
+
}
|
|
1055
|
+
_body = typeof req.body === 'string' ? JSON.parse(req.body) : req.body;
|
|
1056
|
+
return _context1.a(2, {
|
|
1057
|
+
action: _body.action || 'create',
|
|
1058
|
+
feedbackData: _body.feedbackData || _body,
|
|
1059
|
+
issueKey: _body.issueKey,
|
|
1060
|
+
status: _body.status,
|
|
1061
|
+
comment: _body.comment
|
|
1062
|
+
});
|
|
1063
|
+
case 11:
|
|
1064
|
+
throw new Error('Unable to parse request body');
|
|
1065
|
+
case 12:
|
|
1066
|
+
return _context1.a(2);
|
|
1067
|
+
}
|
|
1068
|
+
}, _callee1);
|
|
1069
|
+
}));
|
|
1070
|
+
return _parseFormData.apply(this, arguments);
|
|
1071
|
+
}
|
|
1072
|
+
function createJiraHandler() {
|
|
1073
|
+
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
1074
|
+
var handler = /*#__PURE__*/function () {
|
|
1075
|
+
var _ref = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee8(req, res) {
|
|
1076
|
+
var _yield$parseFormData, _yield$parseFormData$, action, feedbackData, issueKey, status, comment, client, result, errorResponse, _t, _t2;
|
|
1077
|
+
return _regenerator().w(function (_context8) {
|
|
1078
|
+
while (1) switch (_context8.p = _context8.n) {
|
|
1079
|
+
case 0:
|
|
1080
|
+
_context8.p = 0;
|
|
1081
|
+
_context8.n = 1;
|
|
1082
|
+
return parseFormData(req);
|
|
1083
|
+
case 1:
|
|
1084
|
+
_yield$parseFormData = _context8.v;
|
|
1085
|
+
_yield$parseFormData$ = _yield$parseFormData.action;
|
|
1086
|
+
action = _yield$parseFormData$ === void 0 ? 'create' : _yield$parseFormData$;
|
|
1087
|
+
feedbackData = _yield$parseFormData.feedbackData;
|
|
1088
|
+
issueKey = _yield$parseFormData.issueKey;
|
|
1089
|
+
status = _yield$parseFormData.status;
|
|
1090
|
+
comment = _yield$parseFormData.comment;
|
|
1091
|
+
client = new JiraClient(config);
|
|
1092
|
+
_t = action;
|
|
1093
|
+
_context8.n = _t === 'create' ? 2 : _t === 'updateStatus' ? 4 : _t === 'getStatus' ? 6 : _t === 'addComment' ? 8 : 10;
|
|
1094
|
+
break;
|
|
1095
|
+
case 2:
|
|
1096
|
+
_context8.n = 3;
|
|
1097
|
+
return handleCreate(client, feedbackData, config);
|
|
1098
|
+
case 3:
|
|
1099
|
+
result = _context8.v;
|
|
1100
|
+
return _context8.a(3, 11);
|
|
1101
|
+
case 4:
|
|
1102
|
+
_context8.n = 5;
|
|
1103
|
+
return handleStatusUpdate(client, issueKey, status, config);
|
|
1104
|
+
case 5:
|
|
1105
|
+
result = _context8.v;
|
|
1106
|
+
return _context8.a(3, 11);
|
|
1107
|
+
case 6:
|
|
1108
|
+
_context8.n = 7;
|
|
1109
|
+
return handleGetStatus(client, issueKey, config);
|
|
1110
|
+
case 7:
|
|
1111
|
+
result = _context8.v;
|
|
1112
|
+
return _context8.a(3, 11);
|
|
1113
|
+
case 8:
|
|
1114
|
+
_context8.n = 9;
|
|
1115
|
+
return handleAddComment(client, issueKey, comment);
|
|
1116
|
+
case 9:
|
|
1117
|
+
result = _context8.v;
|
|
1118
|
+
return _context8.a(3, 11);
|
|
1119
|
+
case 10:
|
|
1120
|
+
throw new Error("Unknown action: ".concat(action));
|
|
1121
|
+
case 11:
|
|
1122
|
+
if (!(res !== null && res !== void 0 && res.json)) {
|
|
1123
|
+
_context8.n = 12;
|
|
1124
|
+
break;
|
|
1125
|
+
}
|
|
1126
|
+
res.status(200).json(result);
|
|
1127
|
+
_context8.n = 13;
|
|
1128
|
+
break;
|
|
1129
|
+
case 12:
|
|
1130
|
+
return _context8.a(2, new Response(JSON.stringify(result), {
|
|
1131
|
+
status: 200,
|
|
1132
|
+
headers: {
|
|
1133
|
+
'Content-Type': 'application/json'
|
|
1134
|
+
}
|
|
1135
|
+
}));
|
|
1136
|
+
case 13:
|
|
1137
|
+
_context8.n = 16;
|
|
1138
|
+
break;
|
|
1139
|
+
case 14:
|
|
1140
|
+
_context8.p = 14;
|
|
1141
|
+
_t2 = _context8.v;
|
|
1142
|
+
errorResponse = {
|
|
1143
|
+
success: false,
|
|
1144
|
+
error: _t2.message
|
|
1145
|
+
};
|
|
1146
|
+
if (!(res !== null && res !== void 0 && res.json)) {
|
|
1147
|
+
_context8.n = 15;
|
|
1148
|
+
break;
|
|
1149
|
+
}
|
|
1150
|
+
res.status(500).json(errorResponse);
|
|
1151
|
+
_context8.n = 16;
|
|
1152
|
+
break;
|
|
1153
|
+
case 15:
|
|
1154
|
+
return _context8.a(2, new Response(JSON.stringify(errorResponse), {
|
|
1155
|
+
status: 500,
|
|
1156
|
+
headers: {
|
|
1157
|
+
'Content-Type': 'application/json'
|
|
1158
|
+
}
|
|
1159
|
+
}));
|
|
1160
|
+
case 16:
|
|
1161
|
+
return _context8.a(2);
|
|
1162
|
+
}
|
|
1163
|
+
}, _callee8, null, [[0, 14]]);
|
|
1164
|
+
}));
|
|
1165
|
+
return function handler(_x12, _x13) {
|
|
1166
|
+
return _ref.apply(this, arguments);
|
|
1167
|
+
};
|
|
1168
|
+
}();
|
|
1169
|
+
return handler;
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
/**
|
|
1173
|
+
* Handle issue creation
|
|
1174
|
+
*/
|
|
1175
|
+
function handleCreate(_x14, _x15, _x16) {
|
|
1176
|
+
return _handleCreate.apply(this, arguments);
|
|
1177
|
+
}
|
|
1178
|
+
/**
|
|
1179
|
+
* Handle status update (local -> Jira)
|
|
1180
|
+
*/
|
|
1181
|
+
function _handleCreate() {
|
|
1182
|
+
_handleCreate = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee10(client, feedbackData, config) {
|
|
1183
|
+
var issueData, issue, issueKey, attachments, result, _result, videoType, extension, _result2, videoData, _videoType, _extension, _result3, logsText, logsBuffer, _result4, debugInfo, _t4, _t5, _t6, _t7, _t8;
|
|
1184
|
+
return _regenerator().w(function (_context10) {
|
|
1185
|
+
while (1) switch (_context10.p = _context10.n) {
|
|
1186
|
+
case 0:
|
|
1187
|
+
// Transform feedback to Jira issue format
|
|
1188
|
+
issueData = feedbackToJiraIssue(feedbackData, {
|
|
1189
|
+
projectKey: config.projectKey || client.projectKey,
|
|
1190
|
+
fields: config.fields,
|
|
1191
|
+
customFields: config.customFields,
|
|
1192
|
+
includePriority: config.includePriority
|
|
1193
|
+
}); // Create the issue
|
|
1194
|
+
_context10.n = 1;
|
|
1195
|
+
return client.createIssue(issueData);
|
|
1196
|
+
case 1:
|
|
1197
|
+
issue = _context10.v;
|
|
1198
|
+
issueKey = issue.key; // Upload attachments
|
|
1199
|
+
attachments = []; // Handle screenshot - support both Buffer (from FormData) and base64 string
|
|
1200
|
+
if (!(config.uploadAttachments !== false)) {
|
|
1201
|
+
_context10.n = 10;
|
|
1202
|
+
break;
|
|
1203
|
+
}
|
|
1204
|
+
if (!feedbackData.screenshotBuffer) {
|
|
1205
|
+
_context10.n = 6;
|
|
1206
|
+
break;
|
|
1207
|
+
}
|
|
1208
|
+
_context10.p = 2;
|
|
1209
|
+
_context10.n = 3;
|
|
1210
|
+
return client.addAttachment(issueKey, "screenshot-".concat(feedbackData.id || Date.now(), ".png"), feedbackData.screenshotBuffer, feedbackData.screenshotType || 'image/png');
|
|
1211
|
+
case 3:
|
|
1212
|
+
result = _context10.v;
|
|
1213
|
+
attachments.push(_objectSpread2({
|
|
1214
|
+
type: 'screenshot'
|
|
1215
|
+
}, result[0]));
|
|
1216
|
+
_context10.n = 5;
|
|
1217
|
+
break;
|
|
1218
|
+
case 4:
|
|
1219
|
+
_context10.p = 4;
|
|
1220
|
+
_t4 = _context10.v;
|
|
1221
|
+
attachments.push({
|
|
1222
|
+
type: 'screenshot',
|
|
1223
|
+
error: _t4.message
|
|
1224
|
+
});
|
|
1225
|
+
case 5:
|
|
1226
|
+
_context10.n = 10;
|
|
1227
|
+
break;
|
|
1228
|
+
case 6:
|
|
1229
|
+
if (!(feedbackData.screenshot && typeof feedbackData.screenshot === 'string')) {
|
|
1230
|
+
_context10.n = 10;
|
|
1231
|
+
break;
|
|
1232
|
+
}
|
|
1233
|
+
_context10.p = 7;
|
|
1234
|
+
_context10.n = 8;
|
|
1235
|
+
return client.addAttachment(issueKey, "screenshot-".concat(feedbackData.id || Date.now(), ".png"), feedbackData.screenshot, 'image/png');
|
|
1236
|
+
case 8:
|
|
1237
|
+
_result = _context10.v;
|
|
1238
|
+
attachments.push(_objectSpread2({
|
|
1239
|
+
type: 'screenshot'
|
|
1240
|
+
}, _result[0]));
|
|
1241
|
+
_context10.n = 10;
|
|
1242
|
+
break;
|
|
1243
|
+
case 9:
|
|
1244
|
+
_context10.p = 9;
|
|
1245
|
+
_t5 = _context10.v;
|
|
1246
|
+
attachments.push({
|
|
1247
|
+
type: 'screenshot',
|
|
1248
|
+
error: _t5.message
|
|
1249
|
+
});
|
|
1250
|
+
case 10:
|
|
1251
|
+
if (!(config.uploadAttachments !== false)) {
|
|
1252
|
+
_context10.n = 21;
|
|
1253
|
+
break;
|
|
1254
|
+
}
|
|
1255
|
+
if (!feedbackData.videoBuffer) {
|
|
1256
|
+
_context10.n = 15;
|
|
1257
|
+
break;
|
|
1258
|
+
}
|
|
1259
|
+
_context10.p = 11;
|
|
1260
|
+
videoType = feedbackData.videoType || 'video/webm';
|
|
1261
|
+
extension = videoType.includes('mp4') ? 'mp4' : 'webm';
|
|
1262
|
+
_context10.n = 12;
|
|
1263
|
+
return client.addAttachment(issueKey, "recording-".concat(feedbackData.id || Date.now(), ".").concat(extension), feedbackData.videoBuffer, videoType);
|
|
1264
|
+
case 12:
|
|
1265
|
+
_result2 = _context10.v;
|
|
1266
|
+
attachments.push(_objectSpread2({
|
|
1267
|
+
type: 'video',
|
|
1268
|
+
size: feedbackData.videoSize || feedbackData.videoBuffer.length
|
|
1269
|
+
}, _result2[0]));
|
|
1270
|
+
_context10.n = 14;
|
|
1271
|
+
break;
|
|
1272
|
+
case 13:
|
|
1273
|
+
_context10.p = 13;
|
|
1274
|
+
_t6 = _context10.v;
|
|
1275
|
+
attachments.push({
|
|
1276
|
+
type: 'video',
|
|
1277
|
+
error: _t6.message
|
|
1278
|
+
});
|
|
1279
|
+
case 14:
|
|
1280
|
+
_context10.n = 21;
|
|
1281
|
+
break;
|
|
1282
|
+
case 15:
|
|
1283
|
+
if (!(feedbackData.video && typeof feedbackData.video === 'string')) {
|
|
1284
|
+
_context10.n = 21;
|
|
1285
|
+
break;
|
|
1286
|
+
}
|
|
1287
|
+
_context10.p = 16;
|
|
1288
|
+
videoData = feedbackData.video;
|
|
1289
|
+
if (videoData.startsWith('data:')) {
|
|
1290
|
+
_context10.n = 17;
|
|
1291
|
+
break;
|
|
1292
|
+
}
|
|
1293
|
+
throw new Error('Video data is not a valid data URL');
|
|
1294
|
+
case 17:
|
|
1295
|
+
if (!(videoData.length < 1000)) {
|
|
1296
|
+
_context10.n = 18;
|
|
1297
|
+
break;
|
|
1298
|
+
}
|
|
1299
|
+
throw new Error("Video data appears truncated (only ".concat(videoData.length, " chars)"));
|
|
1300
|
+
case 18:
|
|
1301
|
+
_videoType = 'video/webm';
|
|
1302
|
+
_extension = 'webm';
|
|
1303
|
+
if (videoData.includes('video/mp4')) {
|
|
1304
|
+
_videoType = 'video/mp4';
|
|
1305
|
+
_extension = 'mp4';
|
|
1306
|
+
}
|
|
1307
|
+
_context10.n = 19;
|
|
1308
|
+
return client.addAttachment(issueKey, "recording-".concat(feedbackData.id || Date.now(), ".").concat(_extension), videoData, _videoType);
|
|
1309
|
+
case 19:
|
|
1310
|
+
_result3 = _context10.v;
|
|
1311
|
+
attachments.push(_objectSpread2({
|
|
1312
|
+
type: 'video'
|
|
1313
|
+
}, _result3[0]));
|
|
1314
|
+
_context10.n = 21;
|
|
1315
|
+
break;
|
|
1316
|
+
case 20:
|
|
1317
|
+
_context10.p = 20;
|
|
1318
|
+
_t7 = _context10.v;
|
|
1319
|
+
attachments.push({
|
|
1320
|
+
type: 'video',
|
|
1321
|
+
error: _t7.message
|
|
1322
|
+
});
|
|
1323
|
+
case 21:
|
|
1324
|
+
if (!(feedbackData.eventLogs && feedbackData.eventLogs.length > 0 && config.uploadAttachments !== false)) {
|
|
1325
|
+
_context10.n = 25;
|
|
1326
|
+
break;
|
|
1327
|
+
}
|
|
1328
|
+
_context10.p = 22;
|
|
1329
|
+
logsText = formatEventLogs(feedbackData.eventLogs);
|
|
1330
|
+
logsBuffer = Buffer.from(logsText, 'utf-8');
|
|
1331
|
+
_context10.n = 23;
|
|
1332
|
+
return client.addAttachment(issueKey, "session-logs-".concat(feedbackData.id || Date.now(), ".txt"), logsBuffer, 'text/plain');
|
|
1333
|
+
case 23:
|
|
1334
|
+
_result4 = _context10.v;
|
|
1335
|
+
attachments.push(_objectSpread2({
|
|
1336
|
+
type: 'logs'
|
|
1337
|
+
}, _result4[0]));
|
|
1338
|
+
_context10.n = 25;
|
|
1339
|
+
break;
|
|
1340
|
+
case 24:
|
|
1341
|
+
_context10.p = 24;
|
|
1342
|
+
_t8 = _context10.v;
|
|
1343
|
+
attachments.push({
|
|
1344
|
+
type: 'logs',
|
|
1345
|
+
error: _t8.message
|
|
1346
|
+
});
|
|
1347
|
+
case 25:
|
|
1348
|
+
// Include debug info
|
|
1349
|
+
debugInfo = {
|
|
1350
|
+
videoBufferReceived: !!feedbackData.videoBuffer,
|
|
1351
|
+
videoBufferSize: feedbackData.videoBuffer ? feedbackData.videoBuffer.length : 0,
|
|
1352
|
+
videoBase64Received: !!feedbackData.video,
|
|
1353
|
+
videoBase64Length: feedbackData.video ? feedbackData.video.length : 0,
|
|
1354
|
+
screenshotBufferReceived: !!feedbackData.screenshotBuffer,
|
|
1355
|
+
eventLogsCount: feedbackData.eventLogs ? feedbackData.eventLogs.length : 0
|
|
1356
|
+
};
|
|
1357
|
+
return _context10.a(2, {
|
|
1358
|
+
success: true,
|
|
1359
|
+
issueKey: issueKey,
|
|
1360
|
+
issueId: issue.id,
|
|
1361
|
+
issueUrl: "https://".concat(client.domain, "/browse/").concat(issueKey),
|
|
1362
|
+
attachments: attachments,
|
|
1363
|
+
debug: debugInfo
|
|
1364
|
+
});
|
|
1365
|
+
}
|
|
1366
|
+
}, _callee10, null, [[22, 24], [16, 20], [11, 13], [7, 9], [2, 4]]);
|
|
1367
|
+
}));
|
|
1368
|
+
return _handleCreate.apply(this, arguments);
|
|
1369
|
+
}
|
|
1370
|
+
function handleStatusUpdate(_x17, _x18, _x19, _x20) {
|
|
1371
|
+
return _handleStatusUpdate.apply(this, arguments);
|
|
1372
|
+
}
|
|
1373
|
+
/**
|
|
1374
|
+
* Handle get status (Jira -> local)
|
|
1375
|
+
*/
|
|
1376
|
+
function _handleStatusUpdate() {
|
|
1377
|
+
_handleStatusUpdate = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee11(client, issueKey, localStatus, config) {
|
|
1378
|
+
var _config$statusMapping;
|
|
1379
|
+
var jiraStatus;
|
|
1380
|
+
return _regenerator().w(function (_context11) {
|
|
1381
|
+
while (1) switch (_context11.n) {
|
|
1382
|
+
case 0:
|
|
1383
|
+
jiraStatus = mapLocalStatusToJira(localStatus, (_config$statusMapping = config.statusMapping) === null || _config$statusMapping === void 0 ? void 0 : _config$statusMapping.toJira);
|
|
1384
|
+
_context11.n = 1;
|
|
1385
|
+
return client.transitionIssue(issueKey, jiraStatus);
|
|
1386
|
+
case 1:
|
|
1387
|
+
return _context11.a(2, {
|
|
1388
|
+
success: true,
|
|
1389
|
+
issueKey: issueKey,
|
|
1390
|
+
newStatus: jiraStatus
|
|
1391
|
+
});
|
|
1392
|
+
}
|
|
1393
|
+
}, _callee11);
|
|
1394
|
+
}));
|
|
1395
|
+
return _handleStatusUpdate.apply(this, arguments);
|
|
1396
|
+
}
|
|
1397
|
+
function handleGetStatus(_x21, _x22, _x23) {
|
|
1398
|
+
return _handleGetStatus.apply(this, arguments);
|
|
1399
|
+
}
|
|
1400
|
+
/**
|
|
1401
|
+
* Handle add comment
|
|
1402
|
+
*/
|
|
1403
|
+
function _handleGetStatus() {
|
|
1404
|
+
_handleGetStatus = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee12(client, issueKey, config) {
|
|
1405
|
+
var _config$statusMapping2;
|
|
1406
|
+
var jiraStatus, localStatus;
|
|
1407
|
+
return _regenerator().w(function (_context12) {
|
|
1408
|
+
while (1) switch (_context12.n) {
|
|
1409
|
+
case 0:
|
|
1410
|
+
_context12.n = 1;
|
|
1411
|
+
return client.getIssueStatus(issueKey);
|
|
1412
|
+
case 1:
|
|
1413
|
+
jiraStatus = _context12.v;
|
|
1414
|
+
localStatus = mapJiraStatusToLocal(jiraStatus, (_config$statusMapping2 = config.statusMapping) === null || _config$statusMapping2 === void 0 ? void 0 : _config$statusMapping2.fromJira);
|
|
1415
|
+
return _context12.a(2, {
|
|
1416
|
+
success: true,
|
|
1417
|
+
issueKey: issueKey,
|
|
1418
|
+
jiraStatus: jiraStatus,
|
|
1419
|
+
localStatus: localStatus
|
|
1420
|
+
});
|
|
1421
|
+
}
|
|
1422
|
+
}, _callee12);
|
|
1423
|
+
}));
|
|
1424
|
+
return _handleGetStatus.apply(this, arguments);
|
|
1425
|
+
}
|
|
1426
|
+
function handleAddComment(_x24, _x25, _x26) {
|
|
1427
|
+
return _handleAddComment.apply(this, arguments);
|
|
1428
|
+
} // ============================================
|
|
1429
|
+
// FRAMEWORK-SPECIFIC EXPORTS
|
|
1430
|
+
// ============================================
|
|
1431
|
+
/**
|
|
1432
|
+
* Next.js App Router handler
|
|
1433
|
+
* Returns a function that can be directly exported as POST
|
|
1434
|
+
*/
|
|
1435
|
+
function _handleAddComment() {
|
|
1436
|
+
_handleAddComment = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee13(client, issueKey, comment) {
|
|
1437
|
+
return _regenerator().w(function (_context13) {
|
|
1438
|
+
while (1) switch (_context13.n) {
|
|
1439
|
+
case 0:
|
|
1440
|
+
_context13.n = 1;
|
|
1441
|
+
return client.addComment(issueKey, comment);
|
|
1442
|
+
case 1:
|
|
1443
|
+
return _context13.a(2, {
|
|
1444
|
+
success: true,
|
|
1445
|
+
issueKey: issueKey
|
|
1446
|
+
});
|
|
1447
|
+
}
|
|
1448
|
+
}, _callee13);
|
|
1449
|
+
}));
|
|
1450
|
+
return _handleAddComment.apply(this, arguments);
|
|
1451
|
+
}
|
|
1452
|
+
function createNextAppHandler() {
|
|
1453
|
+
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
1454
|
+
var handler = createJiraHandler(config);
|
|
1455
|
+
return /*#__PURE__*/function () {
|
|
1456
|
+
var _ref2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee9(request) {
|
|
1457
|
+
return _regenerator().w(function (_context9) {
|
|
1458
|
+
while (1) switch (_context9.n) {
|
|
1459
|
+
case 0:
|
|
1460
|
+
return _context9.a(2, handler(request, null));
|
|
1461
|
+
}
|
|
1462
|
+
}, _callee9);
|
|
1463
|
+
}));
|
|
1464
|
+
return function (_x27) {
|
|
1465
|
+
return _ref2.apply(this, arguments);
|
|
1466
|
+
};
|
|
1467
|
+
}();
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
/**
|
|
1471
|
+
* Next.js Pages Router handler
|
|
1472
|
+
*/
|
|
1473
|
+
function createNextPagesHandler() {
|
|
1474
|
+
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
1475
|
+
return createJiraHandler(config);
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
/**
|
|
1479
|
+
* Express middleware
|
|
1480
|
+
*/
|
|
1481
|
+
function createExpressMiddleware() {
|
|
1482
|
+
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
1483
|
+
var handler = createJiraHandler(config);
|
|
1484
|
+
return /*#__PURE__*/function () {
|
|
1485
|
+
var _ref3 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee0(req, res, next) {
|
|
1486
|
+
var _t3;
|
|
1487
|
+
return _regenerator().w(function (_context0) {
|
|
1488
|
+
while (1) switch (_context0.p = _context0.n) {
|
|
1489
|
+
case 0:
|
|
1490
|
+
_context0.p = 0;
|
|
1491
|
+
_context0.n = 1;
|
|
1492
|
+
return handler(req, res);
|
|
1493
|
+
case 1:
|
|
1494
|
+
_context0.n = 3;
|
|
1495
|
+
break;
|
|
1496
|
+
case 2:
|
|
1497
|
+
_context0.p = 2;
|
|
1498
|
+
_t3 = _context0.v;
|
|
1499
|
+
next(_t3);
|
|
1500
|
+
case 3:
|
|
1501
|
+
return _context0.a(2);
|
|
1502
|
+
}
|
|
1503
|
+
}, _callee0, null, [[0, 2]]);
|
|
1504
|
+
}));
|
|
1505
|
+
return function (_x28, _x29, _x30) {
|
|
1506
|
+
return _ref3.apply(this, arguments);
|
|
1507
|
+
};
|
|
1508
|
+
}();
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
/**
|
|
1512
|
+
* Generic handler for any framework
|
|
1513
|
+
*/
|
|
1514
|
+
function createGenericHandler() {
|
|
1515
|
+
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
1516
|
+
return createJiraHandler(config);
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
// ============================================
|
|
1520
|
+
// WEBHOOK HANDLERS (For Jira Automation / Zapier)
|
|
1521
|
+
// ============================================
|
|
1522
|
+
|
|
1523
|
+
/**
|
|
1524
|
+
* Format feedback for Jira Automation webhook
|
|
1525
|
+
*/
|
|
1526
|
+
function formatForJiraAutomation(feedbackData) {
|
|
1527
|
+
var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
1528
|
+
return {
|
|
1529
|
+
summary: "[Feedback] ".concat((feedbackData.feedback || '').substring(0, 200)),
|
|
1530
|
+
description: feedbackToJiraIssue(feedbackData, config).fields.description,
|
|
1531
|
+
type: feedbackData.type || 'bug',
|
|
1532
|
+
userName: feedbackData.userName || 'Anonymous',
|
|
1533
|
+
userEmail: feedbackData.userEmail || '',
|
|
1534
|
+
url: feedbackData.url || '',
|
|
1535
|
+
hasScreenshot: !!feedbackData.screenshot,
|
|
1536
|
+
hasVideo: !!feedbackData.video,
|
|
1537
|
+
timestamp: feedbackData.timestamp || new Date().toISOString()
|
|
1538
|
+
};
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
/**
|
|
1542
|
+
* Format feedback for Zapier webhook
|
|
1543
|
+
*/
|
|
1544
|
+
function formatForZapier(feedbackData) {
|
|
1545
|
+
var _feedbackData$element, _feedbackData$element2, _feedbackData$element3;
|
|
1546
|
+
return {
|
|
1547
|
+
id: feedbackData.id,
|
|
1548
|
+
feedback: feedbackData.feedback,
|
|
1549
|
+
type: feedbackData.type,
|
|
1550
|
+
status: feedbackData.status,
|
|
1551
|
+
user_name: feedbackData.userName,
|
|
1552
|
+
user_email: feedbackData.userEmail,
|
|
1553
|
+
page_url: feedbackData.url,
|
|
1554
|
+
viewport: feedbackData.viewport ? "".concat(feedbackData.viewport.width, "x").concat(feedbackData.viewport.height) : '',
|
|
1555
|
+
has_screenshot: !!feedbackData.screenshot,
|
|
1556
|
+
has_video: !!feedbackData.video,
|
|
1557
|
+
element_selector: ((_feedbackData$element = feedbackData.elementInfo) === null || _feedbackData$element === void 0 ? void 0 : _feedbackData$element.selector) || '',
|
|
1558
|
+
component_name: (((_feedbackData$element2 = feedbackData.elementInfo) === null || _feedbackData$element2 === void 0 ? void 0 : _feedbackData$element2.componentStack) || [])[0] || '',
|
|
1559
|
+
source_file: ((_feedbackData$element3 = feedbackData.elementInfo) === null || _feedbackData$element3 === void 0 ? void 0 : _feedbackData$element3.sourceFile) || '',
|
|
1560
|
+
timestamp: feedbackData.timestamp || new Date().toISOString()
|
|
1561
|
+
};
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
export { createExpressMiddleware, createGenericHandler, createJiraHandler, createNextAppHandler, createNextPagesHandler, createJiraHandler as default, formatForJiraAutomation, formatForZapier };
|
|
1565
|
+
//# sourceMappingURL=jira.js.map
|