@feedclip/sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/COMMERCIAL-LICENSE.md +32 -0
- package/COMPLIANCE.md +110 -0
- package/LICENSE +21 -0
- package/README.md +676 -0
- package/dist/FeedClip-BmVeLeSY.cjs +6 -0
- package/dist/FeedClip-Czdkvwzl.js +1176 -0
- package/dist/angular.cjs +1 -0
- package/dist/angular.js +42 -0
- package/dist/feedclip.cjs +2 -0
- package/dist/feedclip.css +3 -0
- package/dist/feedclip.js +133 -0
- package/dist/types/ai.d.ts +2 -0
- package/dist/types/angular.d.ts +15 -0
- package/dist/types/atom.d.ts +9 -0
- package/dist/types/components/Alert.d.ts +8 -0
- package/dist/types/components/Controls.d.ts +10 -0
- package/dist/types/components/FeedClip.d.ts +11 -0
- package/dist/types/components/FeedbackDetails.d.ts +14 -0
- package/dist/types/components/FeedbackResult.d.ts +7 -0
- package/dist/types/components/HandleUpload.d.ts +21 -0
- package/dist/types/components/PauseRecording.d.ts +8 -0
- package/dist/types/components/Reset.d.ts +11 -0
- package/dist/types/components/StartRecording.d.ts +15 -0
- package/dist/types/components/StopRecording.d.ts +7 -0
- package/dist/types/components/TrimControls.d.ts +10 -0
- package/dist/types/components/Video.d.ts +8 -0
- package/dist/types/configuration-context.d.ts +2 -0
- package/dist/types/configuration.d.ts +22 -0
- package/dist/types/entitlements.d.ts +6 -0
- package/dist/types/feedback.d.ts +55 -0
- package/dist/types/i18n.d.ts +33 -0
- package/dist/types/index.d.ts +17 -0
- package/dist/types/indexed-db-store.d.ts +11 -0
- package/dist/types/license.d.ts +30 -0
- package/dist/types/transport.d.ts +7 -0
- package/dist/types/uploaders.d.ts +14 -0
- package/dist/types/utils.d.ts +6 -0
- package/dist/types/vue.d.ts +18 -0
- package/dist/vue.cjs +1 -0
- package/dist/vue.js +23 -0
- package/package.json +118 -0
- package/scripts/generate-license-keypair.mjs +25 -0
- package/scripts/issue-license.mjs +69 -0
|
@@ -0,0 +1,1176 @@
|
|
|
1
|
+
import { createContext as e, useContext as t, useEffect as n, useRef as r, useState as i } from "react";
|
|
2
|
+
import { atom as a, useSetAtom as o } from "jotai";
|
|
3
|
+
import { useAtom as s, useAtomValue as c } from "jotai/react";
|
|
4
|
+
//#region \0rolldown/runtime.js
|
|
5
|
+
var l = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t.exports), u = /* @__PURE__ */ ((e) => typeof require < "u" ? require : typeof Proxy < "u" ? new Proxy(e, { get: (e, t) => (typeof require < "u" ? require : e)[t] }) : e)(function(e) {
|
|
6
|
+
if (typeof require < "u") return require.apply(this, arguments);
|
|
7
|
+
throw Error("Calling `require` for \"" + e + "\" in an environment that doesn't expose the `require` function. See https://rolldown.rs/in-depth/bundling-cjs#require-external-modules for more details.");
|
|
8
|
+
}), d = a(!1);
|
|
9
|
+
a(!1);
|
|
10
|
+
var f = a(null), p = /* @__PURE__ */ l(((e) => {
|
|
11
|
+
var t = Symbol.for("react.transitional.element"), n = Symbol.for("react.fragment");
|
|
12
|
+
function r(e, n, r) {
|
|
13
|
+
var i = null;
|
|
14
|
+
if (r !== void 0 && (i = "" + r), n.key !== void 0 && (i = "" + n.key), "key" in n) for (var a in r = {}, n) a !== "key" && (r[a] = n[a]);
|
|
15
|
+
else r = n;
|
|
16
|
+
return n = r.ref, {
|
|
17
|
+
$$typeof: t,
|
|
18
|
+
type: e,
|
|
19
|
+
key: i,
|
|
20
|
+
ref: n === void 0 ? null : n,
|
|
21
|
+
props: r
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
e.Fragment = n, e.jsx = r, e.jsxs = r;
|
|
25
|
+
})), m = /* @__PURE__ */ l(((e) => {
|
|
26
|
+
process.env.NODE_ENV !== "production" && (function() {
|
|
27
|
+
function t(e) {
|
|
28
|
+
if (e == null) return null;
|
|
29
|
+
if (typeof e == "function") return e.$$typeof === k ? null : e.displayName || e.name || null;
|
|
30
|
+
if (typeof e == "string") return e;
|
|
31
|
+
switch (e) {
|
|
32
|
+
case v: return "Fragment";
|
|
33
|
+
case b: return "Profiler";
|
|
34
|
+
case y: return "StrictMode";
|
|
35
|
+
case w: return "Suspense";
|
|
36
|
+
case T: return "SuspenseList";
|
|
37
|
+
case O: return "Activity";
|
|
38
|
+
}
|
|
39
|
+
if (typeof e == "object") switch (typeof e.tag == "number" && console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."), e.$$typeof) {
|
|
40
|
+
case _: return "Portal";
|
|
41
|
+
case S: return e.displayName || "Context";
|
|
42
|
+
case x: return (e._context.displayName || "Context") + ".Consumer";
|
|
43
|
+
case C:
|
|
44
|
+
var n = e.render;
|
|
45
|
+
return e = e.displayName, e ||= (e = n.displayName || n.name || "", e === "" ? "ForwardRef" : "ForwardRef(" + e + ")"), e;
|
|
46
|
+
case E: return n = e.displayName || null, n === null ? t(e.type) || "Memo" : n;
|
|
47
|
+
case D:
|
|
48
|
+
n = e._payload, e = e._init;
|
|
49
|
+
try {
|
|
50
|
+
return t(e(n));
|
|
51
|
+
} catch {}
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
function n(e) {
|
|
56
|
+
return "" + e;
|
|
57
|
+
}
|
|
58
|
+
function r(e) {
|
|
59
|
+
try {
|
|
60
|
+
n(e);
|
|
61
|
+
var t = !1;
|
|
62
|
+
} catch {
|
|
63
|
+
t = !0;
|
|
64
|
+
}
|
|
65
|
+
if (t) {
|
|
66
|
+
t = console;
|
|
67
|
+
var r = t.error, i = typeof Symbol == "function" && Symbol.toStringTag && e[Symbol.toStringTag] || e.constructor.name || "Object";
|
|
68
|
+
return r.call(t, "The provided key is an unsupported type %s. This value must be coerced to a string before using it here.", i), n(e);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function i(e) {
|
|
72
|
+
if (e === v) return "<>";
|
|
73
|
+
if (typeof e == "object" && e && e.$$typeof === D) return "<...>";
|
|
74
|
+
try {
|
|
75
|
+
var n = t(e);
|
|
76
|
+
return n ? "<" + n + ">" : "<...>";
|
|
77
|
+
} catch {
|
|
78
|
+
return "<...>";
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function a() {
|
|
82
|
+
var e = A.A;
|
|
83
|
+
return e === null ? null : e.getOwner();
|
|
84
|
+
}
|
|
85
|
+
function o() {
|
|
86
|
+
return Error("react-stack-top-frame");
|
|
87
|
+
}
|
|
88
|
+
function s(e) {
|
|
89
|
+
if (j.call(e, "key")) {
|
|
90
|
+
var t = Object.getOwnPropertyDescriptor(e, "key").get;
|
|
91
|
+
if (t && t.isReactWarning) return !1;
|
|
92
|
+
}
|
|
93
|
+
return e.key !== void 0;
|
|
94
|
+
}
|
|
95
|
+
function c(e, t) {
|
|
96
|
+
function n() {
|
|
97
|
+
P || (P = !0, console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)", t));
|
|
98
|
+
}
|
|
99
|
+
n.isReactWarning = !0, Object.defineProperty(e, "key", {
|
|
100
|
+
get: n,
|
|
101
|
+
configurable: !0
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
function l() {
|
|
105
|
+
var e = t(this.type);
|
|
106
|
+
return F[e] || (F[e] = !0, console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")), e = this.props.ref, e === void 0 ? null : e;
|
|
107
|
+
}
|
|
108
|
+
function d(e, t, n, r, i, a) {
|
|
109
|
+
var o = n.ref;
|
|
110
|
+
return e = {
|
|
111
|
+
$$typeof: g,
|
|
112
|
+
type: e,
|
|
113
|
+
key: t,
|
|
114
|
+
props: n,
|
|
115
|
+
_owner: r
|
|
116
|
+
}, (o === void 0 ? null : o) === null ? Object.defineProperty(e, "ref", {
|
|
117
|
+
enumerable: !1,
|
|
118
|
+
value: null
|
|
119
|
+
}) : Object.defineProperty(e, "ref", {
|
|
120
|
+
enumerable: !1,
|
|
121
|
+
get: l
|
|
122
|
+
}), e._store = {}, Object.defineProperty(e._store, "validated", {
|
|
123
|
+
configurable: !1,
|
|
124
|
+
enumerable: !1,
|
|
125
|
+
writable: !0,
|
|
126
|
+
value: 0
|
|
127
|
+
}), Object.defineProperty(e, "_debugInfo", {
|
|
128
|
+
configurable: !1,
|
|
129
|
+
enumerable: !1,
|
|
130
|
+
writable: !0,
|
|
131
|
+
value: null
|
|
132
|
+
}), Object.defineProperty(e, "_debugStack", {
|
|
133
|
+
configurable: !1,
|
|
134
|
+
enumerable: !1,
|
|
135
|
+
writable: !0,
|
|
136
|
+
value: i
|
|
137
|
+
}), Object.defineProperty(e, "_debugTask", {
|
|
138
|
+
configurable: !1,
|
|
139
|
+
enumerable: !1,
|
|
140
|
+
writable: !0,
|
|
141
|
+
value: a
|
|
142
|
+
}), Object.freeze && (Object.freeze(e.props), Object.freeze(e)), e;
|
|
143
|
+
}
|
|
144
|
+
function f(e, n, i, o, l, u) {
|
|
145
|
+
var f = n.children;
|
|
146
|
+
if (f !== void 0) if (o) if (M(f)) {
|
|
147
|
+
for (o = 0; o < f.length; o++) p(f[o]);
|
|
148
|
+
Object.freeze && Object.freeze(f);
|
|
149
|
+
} else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");
|
|
150
|
+
else p(f);
|
|
151
|
+
if (j.call(n, "key")) {
|
|
152
|
+
f = t(e);
|
|
153
|
+
var m = Object.keys(n).filter(function(e) {
|
|
154
|
+
return e !== "key";
|
|
155
|
+
});
|
|
156
|
+
o = 0 < m.length ? "{key: someKey, " + m.join(": ..., ") + ": ...}" : "{key: someKey}", R[f + o] || (m = 0 < m.length ? "{" + m.join(": ..., ") + ": ...}" : "{}", console.error("A props object containing a \"key\" prop is being spread into JSX:\n let props = %s;\n <%s {...props} />\nReact keys must be passed directly to JSX without using spread:\n let props = %s;\n <%s key={someKey} {...props} />", o, f, m, f), R[f + o] = !0);
|
|
157
|
+
}
|
|
158
|
+
if (f = null, i !== void 0 && (r(i), f = "" + i), s(n) && (r(n.key), f = "" + n.key), "key" in n) for (var h in i = {}, n) h !== "key" && (i[h] = n[h]);
|
|
159
|
+
else i = n;
|
|
160
|
+
return f && c(i, typeof e == "function" ? e.displayName || e.name || "Unknown" : e), d(e, f, i, a(), l, u);
|
|
161
|
+
}
|
|
162
|
+
function p(e) {
|
|
163
|
+
m(e) ? e._store && (e._store.validated = 1) : typeof e == "object" && e && e.$$typeof === D && (e._payload.status === "fulfilled" ? m(e._payload.value) && e._payload.value._store && (e._payload.value._store.validated = 1) : e._store && (e._store.validated = 1));
|
|
164
|
+
}
|
|
165
|
+
function m(e) {
|
|
166
|
+
return typeof e == "object" && !!e && e.$$typeof === g;
|
|
167
|
+
}
|
|
168
|
+
var h = u("react"), g = Symbol.for("react.transitional.element"), _ = Symbol.for("react.portal"), v = Symbol.for("react.fragment"), y = Symbol.for("react.strict_mode"), b = Symbol.for("react.profiler"), x = Symbol.for("react.consumer"), S = Symbol.for("react.context"), C = Symbol.for("react.forward_ref"), w = Symbol.for("react.suspense"), T = Symbol.for("react.suspense_list"), E = Symbol.for("react.memo"), D = Symbol.for("react.lazy"), O = Symbol.for("react.activity"), k = Symbol.for("react.client.reference"), A = h.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, j = Object.prototype.hasOwnProperty, M = Array.isArray, N = console.createTask ? console.createTask : function() {
|
|
169
|
+
return null;
|
|
170
|
+
};
|
|
171
|
+
h = { react_stack_bottom_frame: function(e) {
|
|
172
|
+
return e();
|
|
173
|
+
} };
|
|
174
|
+
var P, F = {}, I = h.react_stack_bottom_frame.bind(h, o)(), L = N(i(o)), R = {};
|
|
175
|
+
e.Fragment = v, e.jsx = function(e, t, n) {
|
|
176
|
+
var r = 1e4 > A.recentlyCreatedOwnerStacks++;
|
|
177
|
+
return f(e, t, n, !1, r ? Error("react-stack-top-frame") : I, r ? N(i(e)) : L);
|
|
178
|
+
}, e.jsxs = function(e, t, n) {
|
|
179
|
+
var r = 1e4 > A.recentlyCreatedOwnerStacks++;
|
|
180
|
+
return f(e, t, n, !0, r ? Error("react-stack-top-frame") : I, r ? N(i(e)) : L);
|
|
181
|
+
};
|
|
182
|
+
})();
|
|
183
|
+
})), h = (/* @__PURE__ */ l(((e, t) => {
|
|
184
|
+
process.env.NODE_ENV === "production" ? t.exports = p() : t.exports = m();
|
|
185
|
+
})))(), g = (e) => {
|
|
186
|
+
let { videoRef: t, removeBranding: n = !1, thumbnailsEnabled: r = !1 } = e, a = c(d), o = c(f), [s, l] = i(!1);
|
|
187
|
+
return /* @__PURE__ */ (0, h.jsxs)("div", {
|
|
188
|
+
className: "feedclip-video-frame",
|
|
189
|
+
children: [
|
|
190
|
+
/* @__PURE__ */ (0, h.jsx)("video", {
|
|
191
|
+
ref: t,
|
|
192
|
+
className: "feedclip-video",
|
|
193
|
+
controls: a,
|
|
194
|
+
poster: a && r && o ? o : void 0,
|
|
195
|
+
onPlaying: () => l(!0),
|
|
196
|
+
onEmptied: () => l(!1)
|
|
197
|
+
}),
|
|
198
|
+
!a && !s && /* @__PURE__ */ (0, h.jsx)("div", {
|
|
199
|
+
className: "feedclip-video-idle",
|
|
200
|
+
"aria-hidden": "true",
|
|
201
|
+
children: /* @__PURE__ */ (0, h.jsx)("span", {
|
|
202
|
+
className: "feedclip-video-idle-icon",
|
|
203
|
+
children: /* @__PURE__ */ (0, h.jsxs)("svg", {
|
|
204
|
+
viewBox: "0 0 24 24",
|
|
205
|
+
fill: "none",
|
|
206
|
+
children: [/* @__PURE__ */ (0, h.jsx)("path", { d: "M8 8.5h5A2.5 2.5 0 0 1 15.5 11v2A2.5 2.5 0 0 1 13 15.5H8A2.5 2.5 0 0 1 5.5 13v-2A2.5 2.5 0 0 1 8 8.5Z" }), /* @__PURE__ */ (0, h.jsx)("path", { d: "m15.5 11 2.7-1.5a.55.55 0 0 1 .8.48v4.04a.55.55 0 0 1-.8.48L15.5 13" })]
|
|
207
|
+
})
|
|
208
|
+
})
|
|
209
|
+
}),
|
|
210
|
+
!n && /* @__PURE__ */ (0, h.jsx)("div", {
|
|
211
|
+
className: "feedclip-watermark",
|
|
212
|
+
children: "Powered by FeedClip"
|
|
213
|
+
})
|
|
214
|
+
]
|
|
215
|
+
});
|
|
216
|
+
}, _ = e(void 0), v = (e) => {
|
|
217
|
+
try {
|
|
218
|
+
let t = document.createElement("canvas");
|
|
219
|
+
return t.width = e.videoWidth || 640, t.height = e.videoHeight || 480, t.getContext("2d")?.drawImage(e, 0, 0), t.toDataURL("image/jpeg", .8);
|
|
220
|
+
} catch {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
}, y = (e, t, n, r) => new Promise((i, a) => {
|
|
224
|
+
let o = document.createElement("video"), s = URL.createObjectURL(e);
|
|
225
|
+
o.src = s, o.muted = !0, o.addEventListener("loadedmetadata", () => {
|
|
226
|
+
let e = o.duration, c = n > 0 && n <= e ? n : e, l = t >= 0 && t < c ? t : 0, u = document.createElement("canvas");
|
|
227
|
+
u.width = o.videoWidth || 640, u.height = o.videoHeight || 480;
|
|
228
|
+
let d = u.getContext("2d");
|
|
229
|
+
if (!d) {
|
|
230
|
+
URL.revokeObjectURL(s), a(/* @__PURE__ */ Error("Canvas 2D context unavailable"));
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
let f = u.captureStream(), p = new MediaRecorder(f), m = [];
|
|
234
|
+
p.ondataavailable = (e) => {
|
|
235
|
+
e.data.size > 0 && m.push(e.data);
|
|
236
|
+
}, p.onstop = () => {
|
|
237
|
+
URL.revokeObjectURL(s), i(new Blob(m, { type: `video/${r}` }));
|
|
238
|
+
}, o.currentTime = l, o.addEventListener("seeked", function e() {
|
|
239
|
+
o.removeEventListener("seeked", e), p.start(), o.play();
|
|
240
|
+
let t, n = () => {
|
|
241
|
+
d.drawImage(o, 0, 0), o.currentTime >= c ? (cancelAnimationFrame(t), p.stop(), o.pause()) : t = requestAnimationFrame(n);
|
|
242
|
+
};
|
|
243
|
+
t = requestAnimationFrame(n);
|
|
244
|
+
});
|
|
245
|
+
}), o.addEventListener("error", () => {
|
|
246
|
+
URL.revokeObjectURL(s), a(/* @__PURE__ */ Error("Failed to load video for trimming"));
|
|
247
|
+
});
|
|
248
|
+
}), b = (e, t) => {
|
|
249
|
+
switch (e) {
|
|
250
|
+
case "UnixTimestamp": return `${Date.now()}.${t}`;
|
|
251
|
+
case "ISO 8601": return `${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.${t}`;
|
|
252
|
+
case "Custom": return `recording.${t}`;
|
|
253
|
+
default: return `${Date.now()}.${t}`;
|
|
254
|
+
}
|
|
255
|
+
}, x = {
|
|
256
|
+
webm: [
|
|
257
|
+
"video/webm;codecs=vp9,opus",
|
|
258
|
+
"video/webm;codecs=vp8,opus",
|
|
259
|
+
"video/webm"
|
|
260
|
+
],
|
|
261
|
+
mp4: [
|
|
262
|
+
"video/mp4;codecs=h264,aac",
|
|
263
|
+
"video/mp4",
|
|
264
|
+
"video/webm;codecs=h264",
|
|
265
|
+
"video/webm"
|
|
266
|
+
],
|
|
267
|
+
mov: ["video/mp4", "video/webm"],
|
|
268
|
+
avi: [
|
|
269
|
+
"video/webm;codecs=vp9,opus",
|
|
270
|
+
"video/webm;codecs=vp8,opus",
|
|
271
|
+
"video/webm"
|
|
272
|
+
],
|
|
273
|
+
mkv: ["video/x-matroska;codecs=avc1", "video/webm"]
|
|
274
|
+
}, S = (e) => {
|
|
275
|
+
let t = x[e] ?? ["video/webm"];
|
|
276
|
+
for (let e of t) if (typeof MediaRecorder < "u" && MediaRecorder.isTypeSupported(e)) return e;
|
|
277
|
+
return "video/webm";
|
|
278
|
+
}, C = {
|
|
279
|
+
"en-US": {
|
|
280
|
+
startRecordingError: "Unable to access camera and microphone. Please check your permissions.",
|
|
281
|
+
browserNotSupported: "Your browser does not support video recording. Please use a modern browser.",
|
|
282
|
+
uploading: "Uploading...",
|
|
283
|
+
uploadSuccess: "Video uploaded successfully!",
|
|
284
|
+
uploadError: "Error uploading video.",
|
|
285
|
+
fileSizeError: "File size exceeds the maximum allowed size.",
|
|
286
|
+
startRecording: "Start recording",
|
|
287
|
+
stopRecording: "Stop recording",
|
|
288
|
+
pauseRecording: "Pause recording",
|
|
289
|
+
resumeRecording: "Resume recording",
|
|
290
|
+
uploadVideo: "Upload video",
|
|
291
|
+
resetRecording: "Discard and reset"
|
|
292
|
+
},
|
|
293
|
+
"ru-RU": {
|
|
294
|
+
startRecordingError: "Не удалось получить доступ к камере и микрофону. Пожалуйста, проверьте разрешения.",
|
|
295
|
+
browserNotSupported: "Ваш браузер не поддерживает запись видео. Пожалуйста, используйте современный браузер.",
|
|
296
|
+
uploading: "Загрузка...",
|
|
297
|
+
uploadSuccess: "Видео успешно загружено!",
|
|
298
|
+
uploadError: "Ошибка при загрузке видео.",
|
|
299
|
+
fileSizeError: "Размер файла превышает максимально допустимый.",
|
|
300
|
+
startRecording: "Начать запись",
|
|
301
|
+
stopRecording: "Остановить запись",
|
|
302
|
+
pauseRecording: "Пауза записи",
|
|
303
|
+
resumeRecording: "Возобновить запись",
|
|
304
|
+
uploadVideo: "Загрузить видео",
|
|
305
|
+
resetRecording: "Отменить и сбросить"
|
|
306
|
+
},
|
|
307
|
+
"es-ES": {
|
|
308
|
+
startRecordingError: "No se puede acceder a la cámara y al micrófono. Por favor, comprueba tus permisos.",
|
|
309
|
+
browserNotSupported: "Tu navegador no admite la grabación de vídeo. Por favor, usa un navegador moderno.",
|
|
310
|
+
uploading: "Subiendo...",
|
|
311
|
+
uploadSuccess: "¡Vídeo subido correctamente!",
|
|
312
|
+
uploadError: "Error al subir el vídeo.",
|
|
313
|
+
fileSizeError: "El tamaño del archivo supera el máximo permitido.",
|
|
314
|
+
startRecording: "Iniciar grabación",
|
|
315
|
+
stopRecording: "Detener grabación",
|
|
316
|
+
pauseRecording: "Pausar grabación",
|
|
317
|
+
resumeRecording: "Reanudar grabación",
|
|
318
|
+
uploadVideo: "Subir vídeo",
|
|
319
|
+
resetRecording: "Descartar y restablecer"
|
|
320
|
+
},
|
|
321
|
+
"fr-FR": {
|
|
322
|
+
startRecordingError: "Impossible d'accéder à la caméra et au microphone. Veuillez vérifier vos autorisations.",
|
|
323
|
+
browserNotSupported: "Votre navigateur ne prend pas en charge l'enregistrement vidéo. Veuillez utiliser un navigateur moderne.",
|
|
324
|
+
uploading: "Téléversement...",
|
|
325
|
+
uploadSuccess: "Vidéo téléversée avec succès !",
|
|
326
|
+
uploadError: "Erreur lors du téléversement de la vidéo.",
|
|
327
|
+
fileSizeError: "La taille du fichier dépasse la taille maximale autorisée.",
|
|
328
|
+
startRecording: "Démarrer l'enregistrement",
|
|
329
|
+
stopRecording: "Arrêter l'enregistrement",
|
|
330
|
+
pauseRecording: "Mettre en pause",
|
|
331
|
+
resumeRecording: "Reprendre l'enregistrement",
|
|
332
|
+
uploadVideo: "Téléverser la vidéo",
|
|
333
|
+
resetRecording: "Annuler et réinitialiser"
|
|
334
|
+
},
|
|
335
|
+
"de-DE": {
|
|
336
|
+
startRecordingError: "Kamera und Mikrofon sind nicht zugänglich. Bitte überprüfen Sie Ihre Berechtigungen.",
|
|
337
|
+
browserNotSupported: "Ihr Browser unterstützt keine Videoaufnahme. Bitte verwenden Sie einen modernen Browser.",
|
|
338
|
+
uploading: "Wird hochgeladen...",
|
|
339
|
+
uploadSuccess: "Video erfolgreich hochgeladen!",
|
|
340
|
+
uploadError: "Fehler beim Hochladen des Videos.",
|
|
341
|
+
fileSizeError: "Die Dateigröße überschreitet die maximal zulässige Größe.",
|
|
342
|
+
startRecording: "Aufnahme starten",
|
|
343
|
+
stopRecording: "Aufnahme stoppen",
|
|
344
|
+
pauseRecording: "Aufnahme pausieren",
|
|
345
|
+
resumeRecording: "Aufnahme fortsetzen",
|
|
346
|
+
uploadVideo: "Video hochladen",
|
|
347
|
+
resetRecording: "Verwerfen und zurücksetzen"
|
|
348
|
+
},
|
|
349
|
+
"it-IT": {
|
|
350
|
+
startRecordingError: "Impossibile accedere alla fotocamera e al microfono. Controlla le tue autorizzazioni.",
|
|
351
|
+
browserNotSupported: "Il tuo browser non supporta la registrazione video. Utilizza un browser moderno.",
|
|
352
|
+
uploading: "Caricamento...",
|
|
353
|
+
uploadSuccess: "Video caricato con successo!",
|
|
354
|
+
uploadError: "Errore durante il caricamento del video.",
|
|
355
|
+
fileSizeError: "La dimensione del file supera la dimensione massima consentita.",
|
|
356
|
+
startRecording: "Avvia registrazione",
|
|
357
|
+
stopRecording: "Interrompi registrazione",
|
|
358
|
+
pauseRecording: "Metti in pausa la registrazione",
|
|
359
|
+
resumeRecording: "Riprendi registrazione",
|
|
360
|
+
uploadVideo: "Carica video",
|
|
361
|
+
resetRecording: "Annulla e ripristina"
|
|
362
|
+
},
|
|
363
|
+
"pt-PT": {
|
|
364
|
+
startRecordingError: "Não foi possível aceder à câmara e ao microfone. Por favor, verifique as suas permissões.",
|
|
365
|
+
browserNotSupported: "O seu navegador não suporta gravação de vídeo. Por favor, utilize um navegador moderno.",
|
|
366
|
+
uploading: "A carregar...",
|
|
367
|
+
uploadSuccess: "Vídeo carregado com sucesso!",
|
|
368
|
+
uploadError: "Erro ao carregar o vídeo.",
|
|
369
|
+
fileSizeError: "O tamanho do ficheiro excede o tamanho máximo permitido.",
|
|
370
|
+
startRecording: "Iniciar gravação",
|
|
371
|
+
stopRecording: "Parar gravação",
|
|
372
|
+
pauseRecording: "Pausar gravação",
|
|
373
|
+
resumeRecording: "Retomar gravação",
|
|
374
|
+
uploadVideo: "Carregar vídeo",
|
|
375
|
+
resetRecording: "Descartar e repor"
|
|
376
|
+
},
|
|
377
|
+
"zh-CN": {
|
|
378
|
+
startRecordingError: "无法访问摄像头和麦克风。请检查您的权限。",
|
|
379
|
+
browserNotSupported: "您的浏览器不支持视频录制。请使用现代浏览器。",
|
|
380
|
+
uploading: "上传中...",
|
|
381
|
+
uploadSuccess: "视频上传成功!",
|
|
382
|
+
uploadError: "视频上传失败。",
|
|
383
|
+
fileSizeError: "文件大小超过允许的最大值。",
|
|
384
|
+
startRecording: "开始录制",
|
|
385
|
+
stopRecording: "停止录制",
|
|
386
|
+
pauseRecording: "暂停录制",
|
|
387
|
+
resumeRecording: "恢复录制",
|
|
388
|
+
uploadVideo: "上传视频",
|
|
389
|
+
resetRecording: "放弃并重置"
|
|
390
|
+
},
|
|
391
|
+
"ja-JP": {
|
|
392
|
+
startRecordingError: "カメラとマイクにアクセスできません。権限を確認してください。",
|
|
393
|
+
browserNotSupported: "お使いのブラウザは動画録画に対応していません。最新のブラウザをご利用ください。",
|
|
394
|
+
uploading: "アップロード中...",
|
|
395
|
+
uploadSuccess: "動画のアップロードに成功しました!",
|
|
396
|
+
uploadError: "動画のアップロードに失敗しました。",
|
|
397
|
+
fileSizeError: "ファイルサイズが許可される最大サイズを超えています。",
|
|
398
|
+
startRecording: "録画を開始",
|
|
399
|
+
stopRecording: "録画を停止",
|
|
400
|
+
pauseRecording: "録画を一時停止",
|
|
401
|
+
resumeRecording: "録画を再開",
|
|
402
|
+
uploadVideo: "動画をアップロード",
|
|
403
|
+
resetRecording: "破棄してリセット"
|
|
404
|
+
},
|
|
405
|
+
"ko-KR": {
|
|
406
|
+
startRecordingError: "카메라와 마이크에 접근할 수 없습니다. 권한을 확인해 주세요.",
|
|
407
|
+
browserNotSupported: "브라우저가 동영상 녹화를 지원하지 않습니다. 최신 브라우저를 사용해 주세요.",
|
|
408
|
+
uploading: "업로드 중...",
|
|
409
|
+
uploadSuccess: "동영상이 성공적으로 업로드되었습니다!",
|
|
410
|
+
uploadError: "동영상 업로드 중 오류가 발생했습니다.",
|
|
411
|
+
fileSizeError: "파일 크기가 허용된 최대 크기를 초과합니다.",
|
|
412
|
+
startRecording: "녹화 시작",
|
|
413
|
+
stopRecording: "녹화 중지",
|
|
414
|
+
pauseRecording: "녹화 일시정지",
|
|
415
|
+
resumeRecording: "녹화 재개",
|
|
416
|
+
uploadVideo: "동영상 업로드",
|
|
417
|
+
resetRecording: "취소 및 초기화"
|
|
418
|
+
}
|
|
419
|
+
}, w = {
|
|
420
|
+
"en-US": {
|
|
421
|
+
feedbackType: "Feedback type",
|
|
422
|
+
feedbackBug: "Bug",
|
|
423
|
+
feedbackIdea: "Idea",
|
|
424
|
+
feedbackQuestion: "Question",
|
|
425
|
+
feedbackOther: "Other",
|
|
426
|
+
feedbackDescription: "What happened?",
|
|
427
|
+
feedbackPlaceholder: "Describe the problem or idea. The recording adds the context.",
|
|
428
|
+
attachScreenshot: "Attach screenshot",
|
|
429
|
+
recorderTitle: "Record your feedback",
|
|
430
|
+
recorderSubtitle: "Show what happened and tell us what you expected.",
|
|
431
|
+
recorderPrivacy: "Camera and microphone are used only while recording",
|
|
432
|
+
recordingActive: "Recording in progress",
|
|
433
|
+
recordingPaused: "Recording paused",
|
|
434
|
+
reviewTitle: "Review and send",
|
|
435
|
+
reviewReady: "Your recording is ready"
|
|
436
|
+
},
|
|
437
|
+
"ru-RU": {
|
|
438
|
+
feedbackType: "Тип обращения",
|
|
439
|
+
feedbackBug: "Ошибка",
|
|
440
|
+
feedbackIdea: "Идея",
|
|
441
|
+
feedbackQuestion: "Вопрос",
|
|
442
|
+
feedbackOther: "Другое",
|
|
443
|
+
feedbackDescription: "Что произошло?",
|
|
444
|
+
feedbackPlaceholder: "Опишите проблему или идею. Запись добавит контекст.",
|
|
445
|
+
attachScreenshot: "Прикрепить скриншот",
|
|
446
|
+
recorderTitle: "Запишите отзыв",
|
|
447
|
+
recorderSubtitle: "Покажите, что произошло, и расскажите, чего вы ожидали.",
|
|
448
|
+
recorderPrivacy: "Камера и микрофон используются только во время записи",
|
|
449
|
+
recordingActive: "Идёт запись",
|
|
450
|
+
recordingPaused: "Запись приостановлена",
|
|
451
|
+
reviewTitle: "Проверьте и отправьте",
|
|
452
|
+
reviewReady: "Запись готова"
|
|
453
|
+
}
|
|
454
|
+
}, T = (e) => ({
|
|
455
|
+
...C[e] ?? C["en-US"],
|
|
456
|
+
...w[e] ?? w["en-US"]
|
|
457
|
+
}), E = (e) => {
|
|
458
|
+
let t = new URL(window.location.href);
|
|
459
|
+
return t.username = "", t.password = "", t.hash = "", e || (t.search = ""), t.toString();
|
|
460
|
+
}, D = () => {
|
|
461
|
+
if (document.referrer) try {
|
|
462
|
+
let e = new URL(document.referrer);
|
|
463
|
+
return e.username = "", e.password = "", e.search = "", e.hash = "", e.toString();
|
|
464
|
+
} catch {
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
}, O = (e = {}) => ({
|
|
468
|
+
url: E(e.includeQueryString === !0),
|
|
469
|
+
title: document.title,
|
|
470
|
+
userAgent: navigator.userAgent,
|
|
471
|
+
language: navigator.language,
|
|
472
|
+
viewport: {
|
|
473
|
+
width: window.innerWidth,
|
|
474
|
+
height: window.innerHeight,
|
|
475
|
+
devicePixelRatio: window.devicePixelRatio
|
|
476
|
+
},
|
|
477
|
+
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
478
|
+
referrer: e.includeReferrer ? D() : void 0
|
|
479
|
+
}), k = () => typeof crypto < "u" && "randomUUID" in crypto ? crypto.randomUUID() : `feedback_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`, A = (e) => {
|
|
480
|
+
let { recordedBlob: n, uploading: r, uploadProgress: i, setUploading: a, setUploadProgress: o, setAlert: s, onComplete: c, trimStart: l = 0, trimEnd: u = 0, trimmingEnabled: d = !1, uploadProgressEnabled: f = !1, kind: p, description: m, screenshot: g } = e, v = t(_), x = T(v?.locale ?? "en-US");
|
|
481
|
+
return /* @__PURE__ */ (0, h.jsxs)("div", {
|
|
482
|
+
className: "feedclip-upload",
|
|
483
|
+
children: [r && f && /* @__PURE__ */ (0, h.jsx)("div", {
|
|
484
|
+
className: "feedclip-progress",
|
|
485
|
+
role: "progressbar",
|
|
486
|
+
"aria-valuemin": 0,
|
|
487
|
+
"aria-valuemax": 100,
|
|
488
|
+
"aria-valuenow": i,
|
|
489
|
+
children: /* @__PURE__ */ (0, h.jsx)("div", {
|
|
490
|
+
className: "feedclip-progress-value",
|
|
491
|
+
style: { width: `${i}%` }
|
|
492
|
+
})
|
|
493
|
+
}), /* @__PURE__ */ (0, h.jsxs)("button", {
|
|
494
|
+
onClick: async () => {
|
|
495
|
+
if (!n) return;
|
|
496
|
+
let e = v?.defaultVideoFileExtension ?? "webm", t = n;
|
|
497
|
+
if (d && (l > 0 || u > 0)) try {
|
|
498
|
+
t = await y(n, l, u, e);
|
|
499
|
+
} catch {
|
|
500
|
+
s({
|
|
501
|
+
type: "error",
|
|
502
|
+
message: x.uploadError
|
|
503
|
+
});
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
if (v?.maxFileSize && t.size > v.maxFileSize) {
|
|
507
|
+
s({
|
|
508
|
+
type: "error",
|
|
509
|
+
message: x.fileSizeError
|
|
510
|
+
});
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
a(!0), o(0);
|
|
514
|
+
let r = b(v?.defaultVideoFileNameStyle ?? "UnixTimestamp", e), i = new File([t], r, { type: t.type || `video/${e}` });
|
|
515
|
+
try {
|
|
516
|
+
let e = await v?.getContext?.(), t = {
|
|
517
|
+
id: k(),
|
|
518
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
519
|
+
kind: p,
|
|
520
|
+
description: m.trim(),
|
|
521
|
+
video: i,
|
|
522
|
+
screenshot: g ?? void 0,
|
|
523
|
+
context: O(v?.browserContext),
|
|
524
|
+
customContext: e
|
|
525
|
+
}, n;
|
|
526
|
+
if (v?.onSubmit) n = await v.onSubmit(t, (e) => o(e));
|
|
527
|
+
else if (v?.onUpload) await v.onUpload(i, (e) => o(e));
|
|
528
|
+
else throw Error("FeedClip requires onSubmit or onUpload");
|
|
529
|
+
s({
|
|
530
|
+
type: "success",
|
|
531
|
+
message: x.uploadSuccess
|
|
532
|
+
}), c(n ?? void 0);
|
|
533
|
+
} catch {
|
|
534
|
+
s({
|
|
535
|
+
type: "error",
|
|
536
|
+
message: x.uploadError
|
|
537
|
+
});
|
|
538
|
+
} finally {
|
|
539
|
+
a(!1), o(0);
|
|
540
|
+
}
|
|
541
|
+
},
|
|
542
|
+
disabled: r,
|
|
543
|
+
"aria-label": r ? x.uploading : x.uploadVideo,
|
|
544
|
+
className: "feedclip-button feedclip-button-primary",
|
|
545
|
+
children: [r ? x.uploading : /* @__PURE__ */ (0, h.jsx)("svg", {
|
|
546
|
+
className: "feedclip-button-icon",
|
|
547
|
+
"aria-hidden": "true",
|
|
548
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
549
|
+
width: "24",
|
|
550
|
+
height: "24",
|
|
551
|
+
fill: "currentColor",
|
|
552
|
+
viewBox: "0 0 24 24",
|
|
553
|
+
children: /* @__PURE__ */ (0, h.jsx)("path", {
|
|
554
|
+
fillRule: "evenodd",
|
|
555
|
+
d: "M12 3a1 1 0 0 1 .78.375l4 5a1 1 0 1 1-1.56 1.25L13 6.85V14a1 1 0 1 1-2 0V6.85L8.78 9.626a1 1 0 1 1-1.56-1.25l4-5A1 1 0 0 1 12 3ZM9 14v-1H5a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2h-4v1a3 3 0 1 1-6 0Zm8 2a1 1 0 1 0 0 2h.01a1 1 0 1 0 0-2H17Z",
|
|
556
|
+
clipRule: "evenodd"
|
|
557
|
+
})
|
|
558
|
+
}), !r && /* @__PURE__ */ (0, h.jsx)("span", { children: x.uploadVideo })]
|
|
559
|
+
})]
|
|
560
|
+
});
|
|
561
|
+
}, j = (e) => {
|
|
562
|
+
let { setIsRecording: n, setRecordedBlob: r, mediaRecorderRef: i, streamRef: a, chunksRef: s, videoRef: c } = e, l = o(d), u = T(t(_)?.locale ?? "en-US"), f = () => {
|
|
563
|
+
if (c.current) {
|
|
564
|
+
let e = c.current.src;
|
|
565
|
+
e && e.startsWith("blob:") && URL.revokeObjectURL(e), c.current.src = "", c.current.load();
|
|
566
|
+
}
|
|
567
|
+
n(!1), l(!1), r(null), i.current = null, a.current = null, s.current = [];
|
|
568
|
+
};
|
|
569
|
+
return /* @__PURE__ */ (0, h.jsxs)("button", {
|
|
570
|
+
type: "button",
|
|
571
|
+
"data-tooltip-target": "tooltip-default",
|
|
572
|
+
"aria-label": u.resetRecording,
|
|
573
|
+
onClick: () => f(),
|
|
574
|
+
className: "feedclip-button feedclip-button-ghost",
|
|
575
|
+
children: [/* @__PURE__ */ (0, h.jsx)("svg", {
|
|
576
|
+
className: "feedclip-button-icon",
|
|
577
|
+
"aria-hidden": "true",
|
|
578
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
579
|
+
width: "24",
|
|
580
|
+
height: "24",
|
|
581
|
+
fill: "none",
|
|
582
|
+
viewBox: "0 0 24 24",
|
|
583
|
+
children: /* @__PURE__ */ (0, h.jsx)("path", {
|
|
584
|
+
stroke: "currentColor",
|
|
585
|
+
strokeLinecap: "round",
|
|
586
|
+
strokeLinejoin: "round",
|
|
587
|
+
strokeWidth: "2",
|
|
588
|
+
d: "M21 9H8a5 5 0 0 0 0 10h9m4-10-4-4m4 4-4 4"
|
|
589
|
+
})
|
|
590
|
+
}), /* @__PURE__ */ (0, h.jsx)("span", { children: u.resetRecording })]
|
|
591
|
+
});
|
|
592
|
+
}, M = (e) => {
|
|
593
|
+
let { streamRef: n, chunksRef: r, videoRef: i, mediaRecorderRef: a, setIsRecording: o, setIsPaused: c, setRecordedBlob: l, setAlert: u, thumbnailsEnabled: p = !1 } = e, m = t(_), [, g] = s(d), [, y] = s(f), b = T(m?.locale ?? "en-US");
|
|
594
|
+
return /* @__PURE__ */ (0, h.jsxs)("button", {
|
|
595
|
+
onClick: async () => {
|
|
596
|
+
if (!navigator.mediaDevices?.getUserMedia || typeof MediaRecorder > "u") {
|
|
597
|
+
u({
|
|
598
|
+
type: "error",
|
|
599
|
+
message: b.browserNotSupported
|
|
600
|
+
});
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
c(!1);
|
|
604
|
+
try {
|
|
605
|
+
let e = await navigator.mediaDevices.getUserMedia({
|
|
606
|
+
video: !0,
|
|
607
|
+
audio: !0
|
|
608
|
+
});
|
|
609
|
+
n.current = e, i.current && (i.current.srcObject = e, i.current.muted = !0, i.current.play()), r.current = [];
|
|
610
|
+
let t = S(m?.defaultVideoFileExtension ?? "webm"), o = new MediaRecorder(e, { mimeType: t });
|
|
611
|
+
o.ondataavailable = (e) => r.current.push(e.data), o.onstop = () => {
|
|
612
|
+
let n = o.mimeType || t, a = new Blob(r.current, { type: n });
|
|
613
|
+
p && i.current && y(v(i.current)), e.getTracks().forEach((e) => e.stop()), i.current && (i.current.srcObject = null, i.current.src = URL.createObjectURL(a), i.current.muted = !1), l(a), g(!0);
|
|
614
|
+
}, a.current = o, o.start();
|
|
615
|
+
} catch {
|
|
616
|
+
u({
|
|
617
|
+
type: "error",
|
|
618
|
+
message: b.startRecordingError
|
|
619
|
+
});
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
o(!0), setTimeout(() => {
|
|
623
|
+
a.current && (a.current.state === "recording" || a.current.state === "paused") && (a.current.stop(), o(!1), c(!1));
|
|
624
|
+
}, m?.maxDurationMilliSeconds ?? 6e4);
|
|
625
|
+
},
|
|
626
|
+
"aria-label": b.startRecording,
|
|
627
|
+
className: "feedclip-button feedclip-button-primary feedclip-button-start",
|
|
628
|
+
children: [/* @__PURE__ */ (0, h.jsx)("svg", {
|
|
629
|
+
className: "feedclip-button-icon",
|
|
630
|
+
"aria-hidden": "true",
|
|
631
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
632
|
+
width: "24",
|
|
633
|
+
height: "24",
|
|
634
|
+
fill: "currentColor",
|
|
635
|
+
viewBox: "0 0 24 24",
|
|
636
|
+
children: /* @__PURE__ */ (0, h.jsx)("path", {
|
|
637
|
+
fillRule: "evenodd",
|
|
638
|
+
d: "M14 7a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V7Zm2 9.387 4.684 1.562A1 1 0 0 0 22 17V7a1 1 0 0 0-1.316-.949L16 7.613v8.774Z",
|
|
639
|
+
clipRule: "evenodd"
|
|
640
|
+
})
|
|
641
|
+
}), /* @__PURE__ */ (0, h.jsx)("span", { children: b.startRecording })]
|
|
642
|
+
});
|
|
643
|
+
}, N = (e) => {
|
|
644
|
+
let { setIsRecording: n, mediaRecorderRef: r } = e, i = T(t(_)?.locale ?? "en-US");
|
|
645
|
+
return /* @__PURE__ */ (0, h.jsxs)("button", {
|
|
646
|
+
className: "feedclip-button feedclip-button-danger",
|
|
647
|
+
"aria-label": i.stopRecording,
|
|
648
|
+
onClick: () => {
|
|
649
|
+
r.current && r.current.state === "recording" && (r.current.stop(), n(!1));
|
|
650
|
+
},
|
|
651
|
+
children: [/* @__PURE__ */ (0, h.jsx)("svg", {
|
|
652
|
+
className: "feedclip-button-icon",
|
|
653
|
+
"aria-hidden": "true",
|
|
654
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
655
|
+
width: "24",
|
|
656
|
+
height: "24",
|
|
657
|
+
fill: "currentColor",
|
|
658
|
+
viewBox: "0 0 24 24",
|
|
659
|
+
children: /* @__PURE__ */ (0, h.jsx)("path", { d: "M7 5a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2H7Z" })
|
|
660
|
+
}), /* @__PURE__ */ (0, h.jsx)("span", { children: i.stopRecording })]
|
|
661
|
+
});
|
|
662
|
+
}, P = (e) => {
|
|
663
|
+
let { mediaRecorderRef: n, isPaused: r, setIsPaused: i } = e, a = T(t(_)?.locale ?? "en-US");
|
|
664
|
+
return /* @__PURE__ */ (0, h.jsxs)("button", {
|
|
665
|
+
onClick: () => {
|
|
666
|
+
let e = n.current;
|
|
667
|
+
e && (r ? (e.resume(), i(!1)) : (e.pause(), i(!0)));
|
|
668
|
+
},
|
|
669
|
+
"aria-label": r ? a.resumeRecording : a.pauseRecording,
|
|
670
|
+
className: "feedclip-button feedclip-button-secondary",
|
|
671
|
+
children: [r ? /* @__PURE__ */ (0, h.jsx)("svg", {
|
|
672
|
+
className: "feedclip-button-icon",
|
|
673
|
+
"aria-hidden": "true",
|
|
674
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
675
|
+
width: "24",
|
|
676
|
+
height: "24",
|
|
677
|
+
fill: "currentColor",
|
|
678
|
+
viewBox: "0 0 24 24",
|
|
679
|
+
children: /* @__PURE__ */ (0, h.jsx)("path", {
|
|
680
|
+
fillRule: "evenodd",
|
|
681
|
+
d: "M8.6 5.2A1 1 0 0 0 7 6v12a1 1 0 0 0 1.6.8l8-6a1 1 0 0 0 0-1.6l-8-6Z",
|
|
682
|
+
clipRule: "evenodd"
|
|
683
|
+
})
|
|
684
|
+
}) : /* @__PURE__ */ (0, h.jsx)("svg", {
|
|
685
|
+
className: "feedclip-button-icon",
|
|
686
|
+
"aria-hidden": "true",
|
|
687
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
688
|
+
width: "24",
|
|
689
|
+
height: "24",
|
|
690
|
+
fill: "currentColor",
|
|
691
|
+
viewBox: "0 0 24 24",
|
|
692
|
+
children: /* @__PURE__ */ (0, h.jsx)("path", {
|
|
693
|
+
fillRule: "evenodd",
|
|
694
|
+
d: "M8 5a2 2 0 0 0-2 2v10a2 2 0 0 0 4 0V7a2 2 0 0 0-2-2Zm8 0a2 2 0 0 0-2 2v10a2 2 0 0 0 4 0V7a2 2 0 0 0-2-2Z",
|
|
695
|
+
clipRule: "evenodd"
|
|
696
|
+
})
|
|
697
|
+
}), /* @__PURE__ */ (0, h.jsx)("span", { children: r ? a.resumeRecording : a.pauseRecording })]
|
|
698
|
+
});
|
|
699
|
+
}, F = (e) => {
|
|
700
|
+
let { videoRef: t, trimStart: r, trimEnd: a, setTrimStart: o, setTrimEnd: s } = e, [c, l] = i(0);
|
|
701
|
+
if (n(() => {
|
|
702
|
+
let e = t.current;
|
|
703
|
+
if (!e) return;
|
|
704
|
+
let n = () => {
|
|
705
|
+
let t = e.duration || 0;
|
|
706
|
+
l(t), a === 0 && s(t);
|
|
707
|
+
};
|
|
708
|
+
if (e.readyState >= 1) n();
|
|
709
|
+
else return e.addEventListener("loadedmetadata", n), () => e.removeEventListener("loadedmetadata", n);
|
|
710
|
+
}, [
|
|
711
|
+
t,
|
|
712
|
+
a,
|
|
713
|
+
s
|
|
714
|
+
]), c === 0) return null;
|
|
715
|
+
let u = (e) => `${Math.floor(e / 60)}:${String(Math.floor(e % 60)).padStart(2, "0")}`;
|
|
716
|
+
return /* @__PURE__ */ (0, h.jsxs)("div", {
|
|
717
|
+
className: "w-full px-2 mt-2 mb-1",
|
|
718
|
+
children: [/* @__PURE__ */ (0, h.jsxs)("div", {
|
|
719
|
+
className: "flex justify-between text-xs text-gray-500 mb-1",
|
|
720
|
+
children: [/* @__PURE__ */ (0, h.jsx)("span", { children: "✂️ Trim" }), /* @__PURE__ */ (0, h.jsxs)("span", { children: [
|
|
721
|
+
u(r),
|
|
722
|
+
" – ",
|
|
723
|
+
u(a)
|
|
724
|
+
] })]
|
|
725
|
+
}), /* @__PURE__ */ (0, h.jsxs)("div", {
|
|
726
|
+
className: "flex flex-col gap-1",
|
|
727
|
+
children: [/* @__PURE__ */ (0, h.jsxs)("label", {
|
|
728
|
+
className: "text-xs text-gray-500",
|
|
729
|
+
children: ["Start", /* @__PURE__ */ (0, h.jsx)("input", {
|
|
730
|
+
type: "range",
|
|
731
|
+
min: 0,
|
|
732
|
+
max: c,
|
|
733
|
+
step: .1,
|
|
734
|
+
value: r,
|
|
735
|
+
onChange: (e) => {
|
|
736
|
+
let t = parseFloat(e.target.value);
|
|
737
|
+
t < a && o(t);
|
|
738
|
+
},
|
|
739
|
+
className: "w-full accent-blue-600"
|
|
740
|
+
})]
|
|
741
|
+
}), /* @__PURE__ */ (0, h.jsxs)("label", {
|
|
742
|
+
className: "text-xs text-gray-500",
|
|
743
|
+
children: ["End", /* @__PURE__ */ (0, h.jsx)("input", {
|
|
744
|
+
type: "range",
|
|
745
|
+
min: 0,
|
|
746
|
+
max: c,
|
|
747
|
+
step: .1,
|
|
748
|
+
value: a,
|
|
749
|
+
onChange: (e) => {
|
|
750
|
+
let t = parseFloat(e.target.value);
|
|
751
|
+
t > r && s(t);
|
|
752
|
+
},
|
|
753
|
+
className: "w-full accent-blue-600"
|
|
754
|
+
})]
|
|
755
|
+
})]
|
|
756
|
+
})]
|
|
757
|
+
});
|
|
758
|
+
}, I = ({ locale: e, kind: t, description: n, screenshot: r, setKind: i, setDescription: a, setScreenshot: o }) => {
|
|
759
|
+
let s = T(e);
|
|
760
|
+
return /* @__PURE__ */ (0, h.jsxs)("div", {
|
|
761
|
+
className: "feedclip-form",
|
|
762
|
+
children: [
|
|
763
|
+
/* @__PURE__ */ (0, h.jsxs)("label", {
|
|
764
|
+
className: "feedclip-field",
|
|
765
|
+
children: [/* @__PURE__ */ (0, h.jsx)("span", { children: s.feedbackType }), /* @__PURE__ */ (0, h.jsxs)("select", {
|
|
766
|
+
value: t,
|
|
767
|
+
onChange: (e) => i(e.target.value),
|
|
768
|
+
className: "feedclip-input",
|
|
769
|
+
children: [
|
|
770
|
+
/* @__PURE__ */ (0, h.jsx)("option", {
|
|
771
|
+
value: "bug",
|
|
772
|
+
children: s.feedbackBug
|
|
773
|
+
}),
|
|
774
|
+
/* @__PURE__ */ (0, h.jsx)("option", {
|
|
775
|
+
value: "idea",
|
|
776
|
+
children: s.feedbackIdea
|
|
777
|
+
}),
|
|
778
|
+
/* @__PURE__ */ (0, h.jsx)("option", {
|
|
779
|
+
value: "question",
|
|
780
|
+
children: s.feedbackQuestion
|
|
781
|
+
}),
|
|
782
|
+
/* @__PURE__ */ (0, h.jsx)("option", {
|
|
783
|
+
value: "other",
|
|
784
|
+
children: s.feedbackOther
|
|
785
|
+
})
|
|
786
|
+
]
|
|
787
|
+
})]
|
|
788
|
+
}),
|
|
789
|
+
/* @__PURE__ */ (0, h.jsxs)("label", {
|
|
790
|
+
className: "feedclip-field",
|
|
791
|
+
children: [/* @__PURE__ */ (0, h.jsx)("span", { children: s.feedbackDescription }), /* @__PURE__ */ (0, h.jsx)("textarea", {
|
|
792
|
+
value: n,
|
|
793
|
+
onChange: (e) => a(e.target.value),
|
|
794
|
+
placeholder: s.feedbackPlaceholder,
|
|
795
|
+
rows: 3,
|
|
796
|
+
className: "feedclip-input feedclip-textarea"
|
|
797
|
+
})]
|
|
798
|
+
}),
|
|
799
|
+
/* @__PURE__ */ (0, h.jsxs)("label", {
|
|
800
|
+
className: "feedclip-field",
|
|
801
|
+
children: [
|
|
802
|
+
/* @__PURE__ */ (0, h.jsx)("span", { children: s.attachScreenshot }),
|
|
803
|
+
/* @__PURE__ */ (0, h.jsx)("input", {
|
|
804
|
+
type: "file",
|
|
805
|
+
accept: "image/*",
|
|
806
|
+
onChange: (e) => {
|
|
807
|
+
o(e.target.files?.[0] ?? null);
|
|
808
|
+
},
|
|
809
|
+
className: "feedclip-file-input"
|
|
810
|
+
}),
|
|
811
|
+
r && /* @__PURE__ */ (0, h.jsx)("span", {
|
|
812
|
+
className: "feedclip-file-name",
|
|
813
|
+
children: r.name
|
|
814
|
+
})
|
|
815
|
+
]
|
|
816
|
+
})
|
|
817
|
+
]
|
|
818
|
+
});
|
|
819
|
+
}, L = ({ receipt: e }) => {
|
|
820
|
+
if (!e.analysis && !e.issue) return null;
|
|
821
|
+
let t = e.issue, n = (() => {
|
|
822
|
+
if (t?.url) try {
|
|
823
|
+
let e = new URL(t.url);
|
|
824
|
+
return ["http:", "https:"].includes(e.protocol) ? e.toString() : void 0;
|
|
825
|
+
} catch {
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
})();
|
|
829
|
+
return /* @__PURE__ */ (0, h.jsxs)("section", {
|
|
830
|
+
className: "feedclip-result",
|
|
831
|
+
children: [
|
|
832
|
+
/* @__PURE__ */ (0, h.jsxs)("div", {
|
|
833
|
+
className: "feedclip-result-heading",
|
|
834
|
+
children: [/* @__PURE__ */ (0, h.jsx)("strong", { children: e.analysis?.title ?? "Feedback received" }), e.analysis?.priority && /* @__PURE__ */ (0, h.jsx)("span", {
|
|
835
|
+
className: "feedclip-result-priority",
|
|
836
|
+
children: e.analysis.priority
|
|
837
|
+
})]
|
|
838
|
+
}),
|
|
839
|
+
e.analysis?.summary && /* @__PURE__ */ (0, h.jsx)("p", { children: e.analysis.summary }),
|
|
840
|
+
n ? /* @__PURE__ */ (0, h.jsxs)("a", {
|
|
841
|
+
href: n,
|
|
842
|
+
target: "_blank",
|
|
843
|
+
rel: "noreferrer",
|
|
844
|
+
className: "feedclip-result-link",
|
|
845
|
+
children: [
|
|
846
|
+
t?.provider,
|
|
847
|
+
": ",
|
|
848
|
+
t?.id
|
|
849
|
+
]
|
|
850
|
+
}) : t ? /* @__PURE__ */ (0, h.jsxs)("span", {
|
|
851
|
+
className: "feedclip-result-link",
|
|
852
|
+
children: [
|
|
853
|
+
t.provider,
|
|
854
|
+
": ",
|
|
855
|
+
t.id
|
|
856
|
+
]
|
|
857
|
+
}) : null
|
|
858
|
+
]
|
|
859
|
+
});
|
|
860
|
+
}, R = (e) => {
|
|
861
|
+
let { videoRef: n, setAlert: a, entitlements: o } = e, s = c(d), l = t(_), u = T(l?.locale ?? "en-US"), f = (() => {
|
|
862
|
+
if (l?.privacyNotice?.url) try {
|
|
863
|
+
let e = new URL(l.privacyNotice.url, window.location.href);
|
|
864
|
+
return ["http:", "https:"].includes(e.protocol) ? e.toString() : void 0;
|
|
865
|
+
} catch {
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
})(), [p, m] = i(!1), [g, v] = i(!1), [y, b] = i(null), [x, S] = i(!1), [C, w] = i(0), [E, D] = i(0), [O, k] = i(0), [R, z] = i("bug"), [B, V] = i(""), [H, U] = i(null), [W, G] = i(null), K = r(null), q = r(null), J = r([]);
|
|
869
|
+
return /* @__PURE__ */ (0, h.jsxs)(h.Fragment, { children: [
|
|
870
|
+
!p && !s && /* @__PURE__ */ (0, h.jsxs)("div", {
|
|
871
|
+
className: "feedclip-start-panel",
|
|
872
|
+
children: [
|
|
873
|
+
/* @__PURE__ */ (0, h.jsxs)("div", { children: [/* @__PURE__ */ (0, h.jsx)("h2", { children: u.recorderTitle }), /* @__PURE__ */ (0, h.jsx)("p", { children: u.recorderSubtitle })] }),
|
|
874
|
+
/* @__PURE__ */ (0, h.jsx)(M, {
|
|
875
|
+
streamRef: q,
|
|
876
|
+
chunksRef: J,
|
|
877
|
+
videoRef: n,
|
|
878
|
+
mediaRecorderRef: K,
|
|
879
|
+
setIsRecording: m,
|
|
880
|
+
setIsPaused: v,
|
|
881
|
+
setRecordedBlob: b,
|
|
882
|
+
setAlert: a,
|
|
883
|
+
thumbnailsEnabled: o?.thumbnails
|
|
884
|
+
}),
|
|
885
|
+
/* @__PURE__ */ (0, h.jsxs)("p", {
|
|
886
|
+
className: "feedclip-privacy",
|
|
887
|
+
children: [
|
|
888
|
+
/* @__PURE__ */ (0, h.jsx)("svg", {
|
|
889
|
+
viewBox: "0 0 20 20",
|
|
890
|
+
fill: "none",
|
|
891
|
+
"aria-hidden": "true",
|
|
892
|
+
children: /* @__PURE__ */ (0, h.jsx)("path", { d: "M6.5 8V6.5a3.5 3.5 0 1 1 7 0V8m-8 0h9a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-9a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1Z" })
|
|
893
|
+
}),
|
|
894
|
+
u.recorderPrivacy,
|
|
895
|
+
f && /* @__PURE__ */ (0, h.jsxs)(h.Fragment, { children: [" ", /* @__PURE__ */ (0, h.jsx)("a", {
|
|
896
|
+
href: f,
|
|
897
|
+
target: "_blank",
|
|
898
|
+
rel: "noreferrer",
|
|
899
|
+
children: l?.privacyNotice?.label
|
|
900
|
+
})] })
|
|
901
|
+
]
|
|
902
|
+
})
|
|
903
|
+
]
|
|
904
|
+
}),
|
|
905
|
+
p && /* @__PURE__ */ (0, h.jsxs)("div", {
|
|
906
|
+
className: "feedclip-recording-panel",
|
|
907
|
+
children: [/* @__PURE__ */ (0, h.jsxs)("div", {
|
|
908
|
+
className: "feedclip-recording-status",
|
|
909
|
+
role: "status",
|
|
910
|
+
"aria-live": "polite",
|
|
911
|
+
children: [/* @__PURE__ */ (0, h.jsx)("span", {}), g ? u.recordingPaused : u.recordingActive]
|
|
912
|
+
}), /* @__PURE__ */ (0, h.jsxs)("div", {
|
|
913
|
+
className: "feedclip-recording-actions",
|
|
914
|
+
children: [/* @__PURE__ */ (0, h.jsx)(P, {
|
|
915
|
+
mediaRecorderRef: K,
|
|
916
|
+
isPaused: g,
|
|
917
|
+
setIsPaused: v
|
|
918
|
+
}), /* @__PURE__ */ (0, h.jsx)(N, {
|
|
919
|
+
setIsRecording: m,
|
|
920
|
+
mediaRecorderRef: K
|
|
921
|
+
})]
|
|
922
|
+
})]
|
|
923
|
+
}),
|
|
924
|
+
s && /* @__PURE__ */ (0, h.jsxs)("div", {
|
|
925
|
+
className: "feedclip-review",
|
|
926
|
+
children: [
|
|
927
|
+
/* @__PURE__ */ (0, h.jsxs)("div", {
|
|
928
|
+
className: "feedclip-section-heading",
|
|
929
|
+
children: [/* @__PURE__ */ (0, h.jsx)("span", { children: u.reviewTitle }), /* @__PURE__ */ (0, h.jsx)("small", { children: u.reviewReady })]
|
|
930
|
+
}),
|
|
931
|
+
/* @__PURE__ */ (0, h.jsx)(I, {
|
|
932
|
+
locale: l?.locale ?? "en-US",
|
|
933
|
+
kind: R,
|
|
934
|
+
description: B,
|
|
935
|
+
screenshot: H,
|
|
936
|
+
setKind: z,
|
|
937
|
+
setDescription: V,
|
|
938
|
+
setScreenshot: U
|
|
939
|
+
}),
|
|
940
|
+
o?.trimming && /* @__PURE__ */ (0, h.jsx)(F, {
|
|
941
|
+
videoRef: n,
|
|
942
|
+
trimStart: E,
|
|
943
|
+
trimEnd: O,
|
|
944
|
+
setTrimStart: D,
|
|
945
|
+
setTrimEnd: k
|
|
946
|
+
}),
|
|
947
|
+
/* @__PURE__ */ (0, h.jsxs)("div", {
|
|
948
|
+
className: "feedclip-submit-actions",
|
|
949
|
+
children: [/* @__PURE__ */ (0, h.jsx)(A, {
|
|
950
|
+
recordedBlob: y,
|
|
951
|
+
uploading: x,
|
|
952
|
+
uploadProgress: C,
|
|
953
|
+
setUploading: S,
|
|
954
|
+
setUploadProgress: w,
|
|
955
|
+
onComplete: (e) => {
|
|
956
|
+
G(e ?? null);
|
|
957
|
+
},
|
|
958
|
+
setAlert: a,
|
|
959
|
+
trimStart: E,
|
|
960
|
+
trimEnd: O,
|
|
961
|
+
trimmingEnabled: o?.trimming,
|
|
962
|
+
uploadProgressEnabled: o?.uploadProgress,
|
|
963
|
+
kind: R,
|
|
964
|
+
description: B,
|
|
965
|
+
screenshot: H
|
|
966
|
+
}), /* @__PURE__ */ (0, h.jsx)(j, {
|
|
967
|
+
setIsRecording: m,
|
|
968
|
+
streamRef: q,
|
|
969
|
+
chunksRef: J,
|
|
970
|
+
mediaRecorderRef: K,
|
|
971
|
+
setRecordedBlob: b,
|
|
972
|
+
videoRef: n
|
|
973
|
+
})]
|
|
974
|
+
})
|
|
975
|
+
]
|
|
976
|
+
}),
|
|
977
|
+
W && /* @__PURE__ */ (0, h.jsx)(L, { receipt: W })
|
|
978
|
+
] });
|
|
979
|
+
}, z = (e) => {
|
|
980
|
+
let { alert: t, setAlert: n } = e;
|
|
981
|
+
return /* @__PURE__ */ (0, h.jsxs)("div", {
|
|
982
|
+
id: "alert",
|
|
983
|
+
className: `feedclip-alert feedclip-alert-${t?.type ?? "info"}`,
|
|
984
|
+
role: "alert",
|
|
985
|
+
children: [
|
|
986
|
+
/* @__PURE__ */ (0, h.jsx)("svg", {
|
|
987
|
+
"aria-hidden": "true",
|
|
988
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
989
|
+
fill: "currentColor",
|
|
990
|
+
viewBox: "0 0 20 20",
|
|
991
|
+
children: /* @__PURE__ */ (0, h.jsx)("path", { d: "M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z" })
|
|
992
|
+
}),
|
|
993
|
+
/* @__PURE__ */ (0, h.jsx)("span", {
|
|
994
|
+
className: "sr-only",
|
|
995
|
+
children: "Info"
|
|
996
|
+
}),
|
|
997
|
+
/* @__PURE__ */ (0, h.jsx)("div", { children: t?.message }),
|
|
998
|
+
/* @__PURE__ */ (0, h.jsxs)("button", {
|
|
999
|
+
type: "button",
|
|
1000
|
+
className: "feedclip-alert-close",
|
|
1001
|
+
"data-dismiss-target": "#alert",
|
|
1002
|
+
"aria-label": "Close",
|
|
1003
|
+
onClick: () => n(null),
|
|
1004
|
+
children: [/* @__PURE__ */ (0, h.jsx)("span", {
|
|
1005
|
+
className: "sr-only",
|
|
1006
|
+
children: "Close"
|
|
1007
|
+
}), /* @__PURE__ */ (0, h.jsx)("svg", {
|
|
1008
|
+
"aria-hidden": "true",
|
|
1009
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1010
|
+
fill: "none",
|
|
1011
|
+
viewBox: "0 0 14 14",
|
|
1012
|
+
children: /* @__PURE__ */ (0, h.jsx)("path", {
|
|
1013
|
+
stroke: "currentColor",
|
|
1014
|
+
strokeLinecap: "round",
|
|
1015
|
+
strokeLinejoin: "round",
|
|
1016
|
+
strokeWidth: "2",
|
|
1017
|
+
d: "m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"
|
|
1018
|
+
})
|
|
1019
|
+
})]
|
|
1020
|
+
})
|
|
1021
|
+
]
|
|
1022
|
+
});
|
|
1023
|
+
}, B = [
|
|
1024
|
+
"videoCapture",
|
|
1025
|
+
"voiceCapture",
|
|
1026
|
+
"feedbackDetails",
|
|
1027
|
+
"screenshotAttachment",
|
|
1028
|
+
"browserContext",
|
|
1029
|
+
"customContext",
|
|
1030
|
+
"selfHostedTransport",
|
|
1031
|
+
"indexedDbStorage",
|
|
1032
|
+
"pauseRecording",
|
|
1033
|
+
"preview"
|
|
1034
|
+
], V = [
|
|
1035
|
+
...B,
|
|
1036
|
+
"removeBranding",
|
|
1037
|
+
"thumbnails",
|
|
1038
|
+
"trimming",
|
|
1039
|
+
"uploadProgress",
|
|
1040
|
+
"cloudUploaders"
|
|
1041
|
+
], H = [
|
|
1042
|
+
...V,
|
|
1043
|
+
"screenRecording",
|
|
1044
|
+
"diagnostics",
|
|
1045
|
+
"privacyRedaction",
|
|
1046
|
+
"customBranding",
|
|
1047
|
+
"resumableUploads",
|
|
1048
|
+
"managedStorage",
|
|
1049
|
+
"transcription",
|
|
1050
|
+
"aiAnalysis",
|
|
1051
|
+
"issueIntegrations",
|
|
1052
|
+
"dashboard",
|
|
1053
|
+
"deduplication",
|
|
1054
|
+
"webhooks",
|
|
1055
|
+
"sso",
|
|
1056
|
+
"rbac",
|
|
1057
|
+
"auditLogs",
|
|
1058
|
+
"dataResidency",
|
|
1059
|
+
"sla"
|
|
1060
|
+
], U = (e) => {
|
|
1061
|
+
let t = new Set(e);
|
|
1062
|
+
return Object.freeze(Object.fromEntries(H.map((e) => [e, t.has(e)])));
|
|
1063
|
+
}, W = Object.freeze({
|
|
1064
|
+
free: U(B),
|
|
1065
|
+
paid: U(V)
|
|
1066
|
+
}), G = W.free, K = (e, t = {}) => Object.freeze({
|
|
1067
|
+
...W[e],
|
|
1068
|
+
...t
|
|
1069
|
+
}), q = 16384, J = /* @__PURE__ */ new WeakSet(), Y = (e) => {
|
|
1070
|
+
let t = e.replace(/-/g, "+").replace(/_/g, "/"), n = t.padEnd(Math.ceil(t.length / 4) * 4, "="), r = atob(n);
|
|
1071
|
+
return Uint8Array.from(r, (e) => e.charCodeAt(0));
|
|
1072
|
+
}, X = (e) => {
|
|
1073
|
+
let t = new TextDecoder().decode(Y(e));
|
|
1074
|
+
return JSON.parse(t);
|
|
1075
|
+
}, Z = (e) => ({
|
|
1076
|
+
valid: !1,
|
|
1077
|
+
plan: "free",
|
|
1078
|
+
entitlements: G,
|
|
1079
|
+
reason: e
|
|
1080
|
+
}), ee = (e, t) => Array.isArray(e) ? e.includes(t) : e === t, Q = async ({ token: e, publicKey: t, issuer: n, audience: r, projectId: i, clockToleranceSeconds: a = 30 }) => {
|
|
1081
|
+
try {
|
|
1082
|
+
if (!globalThis.crypto?.subtle) return Z("Web Crypto is unavailable");
|
|
1083
|
+
if (e.length > q) return Z("License token is too large");
|
|
1084
|
+
let o = e.split(".");
|
|
1085
|
+
if (o.length !== 3) return Z("License token has an invalid format");
|
|
1086
|
+
let [s, c, l] = o, u = X(s), d = X(c);
|
|
1087
|
+
if (u.alg !== "ES256" || u.typ !== "FCL") return Z("License token uses an unsupported algorithm");
|
|
1088
|
+
if (!["free", "paid"].includes(d.plan)) return Z("License token contains an unknown plan");
|
|
1089
|
+
if (d.iss !== n) return Z("License token issuer does not match");
|
|
1090
|
+
if (!ee(d.aud, r)) return Z("License token audience does not match");
|
|
1091
|
+
if (d.projectId !== i) return Z("License token project does not match");
|
|
1092
|
+
let f = Math.floor(Date.now() / 1e3);
|
|
1093
|
+
if (d.exp + a < f) return Z("License token has expired");
|
|
1094
|
+
if (d.iat - a > f) return Z("License token is not active yet");
|
|
1095
|
+
let p = await crypto.subtle.importKey("jwk", t, {
|
|
1096
|
+
name: "ECDSA",
|
|
1097
|
+
namedCurve: "P-256"
|
|
1098
|
+
}, !1, ["verify"]), m = new TextEncoder().encode(`${s}.${c}`), h = Y(l);
|
|
1099
|
+
if (!await crypto.subtle.verify({
|
|
1100
|
+
name: "ECDSA",
|
|
1101
|
+
hash: "SHA-256"
|
|
1102
|
+
}, p, h, m)) return Z("License token signature is invalid");
|
|
1103
|
+
let g = {
|
|
1104
|
+
valid: !0,
|
|
1105
|
+
plan: d.plan,
|
|
1106
|
+
claims: d,
|
|
1107
|
+
entitlements: K(d.plan, d.features ?? {})
|
|
1108
|
+
};
|
|
1109
|
+
return J.add(g), g;
|
|
1110
|
+
} catch {
|
|
1111
|
+
return Z("License token could not be verified");
|
|
1112
|
+
}
|
|
1113
|
+
}, te = (e, t) => e.entitlements[t] === !0, ne = (e, t) => {
|
|
1114
|
+
if (!e || !J.has(e) || !te(e, t)) throw Error(`A verified FeedClip license is required for ${t}`);
|
|
1115
|
+
}, $ = () => ({
|
|
1116
|
+
valid: !0,
|
|
1117
|
+
plan: "free",
|
|
1118
|
+
entitlements: G
|
|
1119
|
+
}), re = (e) => {
|
|
1120
|
+
let { config: t } = e, [a, o] = i(null), [s, c] = i($), l = r(null), u = t?.license, d = t?.onLicenseError;
|
|
1121
|
+
n(() => {
|
|
1122
|
+
let e = !0;
|
|
1123
|
+
return u ? (Q(u).then((t) => {
|
|
1124
|
+
e && (c(t), t.valid || d?.(t.reason ?? "License validation failed"));
|
|
1125
|
+
}), () => {
|
|
1126
|
+
e = !1;
|
|
1127
|
+
}) : (c($()), () => {
|
|
1128
|
+
e = !1;
|
|
1129
|
+
});
|
|
1130
|
+
}, [u, d]);
|
|
1131
|
+
let f = s.entitlements, p = s.plan === "paid" ? "Paid" : "Free";
|
|
1132
|
+
return /* @__PURE__ */ (0, h.jsx)("section", {
|
|
1133
|
+
className: "feedclip-shell",
|
|
1134
|
+
children: /* @__PURE__ */ (0, h.jsxs)(_.Provider, {
|
|
1135
|
+
value: t,
|
|
1136
|
+
children: [/* @__PURE__ */ (0, h.jsxs)("header", {
|
|
1137
|
+
className: "feedclip-header",
|
|
1138
|
+
children: [/* @__PURE__ */ (0, h.jsxs)("div", {
|
|
1139
|
+
className: "feedclip-brand",
|
|
1140
|
+
children: [/* @__PURE__ */ (0, h.jsx)("span", {
|
|
1141
|
+
className: "feedclip-brand-mark",
|
|
1142
|
+
"aria-hidden": "true",
|
|
1143
|
+
children: /* @__PURE__ */ (0, h.jsxs)("svg", {
|
|
1144
|
+
viewBox: "0 0 24 24",
|
|
1145
|
+
fill: "none",
|
|
1146
|
+
children: [/* @__PURE__ */ (0, h.jsx)("path", { d: "M8.5 7.5h5A2.5 2.5 0 0 1 16 10v4a2.5 2.5 0 0 1-2.5 2.5h-5A2.5 2.5 0 0 1 6 14v-4a2.5 2.5 0 0 1 2.5-2.5Z" }), /* @__PURE__ */ (0, h.jsx)("path", { d: "m16 10.4 2.6-1.55a.6.6 0 0 1 .9.52v5.26a.6.6 0 0 1-.9.52L16 13.6" })]
|
|
1147
|
+
})
|
|
1148
|
+
}), /* @__PURE__ */ (0, h.jsxs)("span", { children: [/* @__PURE__ */ (0, h.jsx)("strong", { children: "FeedClip" }), /* @__PURE__ */ (0, h.jsx)("small", { children: "Customer feedback" })] })]
|
|
1149
|
+
}), /* @__PURE__ */ (0, h.jsx)("span", {
|
|
1150
|
+
className: "feedclip-plan",
|
|
1151
|
+
children: p
|
|
1152
|
+
})]
|
|
1153
|
+
}), /* @__PURE__ */ (0, h.jsxs)("div", {
|
|
1154
|
+
className: "feedclip-content",
|
|
1155
|
+
children: [
|
|
1156
|
+
a && /* @__PURE__ */ (0, h.jsx)(z, {
|
|
1157
|
+
alert: a,
|
|
1158
|
+
setAlert: o
|
|
1159
|
+
}),
|
|
1160
|
+
/* @__PURE__ */ (0, h.jsx)(g, {
|
|
1161
|
+
videoRef: l,
|
|
1162
|
+
removeBranding: f?.removeBranding,
|
|
1163
|
+
thumbnailsEnabled: f?.thumbnails
|
|
1164
|
+
}),
|
|
1165
|
+
/* @__PURE__ */ (0, h.jsx)(R, {
|
|
1166
|
+
videoRef: l,
|
|
1167
|
+
setAlert: o,
|
|
1168
|
+
entitlements: f
|
|
1169
|
+
})
|
|
1170
|
+
]
|
|
1171
|
+
})]
|
|
1172
|
+
})
|
|
1173
|
+
});
|
|
1174
|
+
};
|
|
1175
|
+
//#endregion
|
|
1176
|
+
export { Q as a, K as c, te as i, O as l, ne as n, G as o, $ as r, W as s, re as t, k as u };
|