@feedclip/sdk 0.1.1 → 0.1.3
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 +9 -6
- package/README.md +17 -13
- package/dist/FeedClip-CRJV41Le.cjs +6 -0
- package/dist/FeedClip-Dsecr8ST.js +1174 -0
- package/dist/angular.cjs +1 -1
- package/dist/angular.js +43 -44
- package/dist/feedclip.cjs +2 -2
- package/dist/feedclip.css +3 -1
- package/dist/feedclip.js +132 -166
- package/dist/types/angular.d.ts +8 -0
- package/dist/types/license.d.ts +1 -1
- package/dist/vue.cjs +1 -1
- package/dist/vue.js +22 -27
- package/package.json +3 -3
- package/scripts/issue-license.mjs +5 -2
- package/dist/FeedClip-BaEsiBcA.cjs +0 -6
- package/dist/FeedClip-DnvGmNwe.js +0 -1390
package/COMMERCIAL-LICENSE.md
CHANGED
|
@@ -12,11 +12,13 @@ The currently sold Paid version enables:
|
|
|
12
12
|
- removal of FeedClip branding;
|
|
13
13
|
- thumbnails, trimming, and upload progress;
|
|
14
14
|
- Supabase and S3 uploader helpers;
|
|
15
|
+
- access to FeedClip server-side transcription and structured AI analysis for
|
|
16
|
+
the licensed project.
|
|
15
17
|
|
|
16
18
|
Screen recording, diagnostics, privacy redaction, resumable uploads, managed
|
|
17
|
-
storage,
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
storage, issue integrations, dashboards, SSO, RBAC, audit logs, data residency,
|
|
20
|
+
and SLA products are roadmap items and are not included in the current
|
|
21
|
+
purchase.
|
|
20
22
|
|
|
21
23
|
Official Paid capabilities require a valid project-bound FeedClip license
|
|
22
24
|
token. Tokens are signed by the FeedClip licensing service and may not be
|
|
@@ -24,9 +26,10 @@ shared between projects or customers.
|
|
|
24
26
|
|
|
25
27
|
## Pricing
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
Feedclip Pro is a one-time USD 49 lifetime license for one project. It does not
|
|
30
|
+
expire or renew automatically. Third-party storage is not included. Server-side
|
|
31
|
+
AI processing provided by FeedClip is included for the licensed project and is
|
|
32
|
+
subject to the service's published acceptable-use and technical limits.
|
|
30
33
|
|
|
31
34
|
Unauthorized activation of the implemented FeedClip Paid feature gates is
|
|
32
35
|
prohibited.
|
package/README.md
CHANGED
|
@@ -28,13 +28,14 @@ The repository currently includes:
|
|
|
28
28
|
- legacy file-only upload support;
|
|
29
29
|
- Supabase and S3 uploader helpers;
|
|
30
30
|
- localization for 10 languages;
|
|
31
|
-
- React implementation with Vue 3 and Angular 19 lifecycle adapters;
|
|
31
|
+
- React implementation with Vue 3 and Angular 19–21 lifecycle adapters;
|
|
32
32
|
- ESM, CommonJS, CSS, and TypeScript declaration builds;
|
|
33
|
-
-
|
|
33
|
+
- automated SDK, licensing, and adapter tests.
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
Feedclip Pro includes the server-side ingestion, transcription, and structured
|
|
36
|
+
analysis path. Durable production workers, a persistent dashboard,
|
|
37
|
+
deduplication, and native issue-tracker connectors remain separate platform
|
|
38
|
+
work.
|
|
38
39
|
|
|
39
40
|
## Installation
|
|
40
41
|
|
|
@@ -50,7 +51,7 @@ Vue 3:
|
|
|
50
51
|
npm install @feedclip/sdk vue react react-dom
|
|
51
52
|
```
|
|
52
53
|
|
|
53
|
-
Angular 19:
|
|
54
|
+
Angular 19–21:
|
|
54
55
|
|
|
55
56
|
```bash
|
|
56
57
|
npm install @feedclip/sdk @angular/core react react-dom
|
|
@@ -444,16 +445,18 @@ including commercial use, is free under the terms of [LICENSE](./LICENSE).
|
|
|
444
445
|
| Pause and preview | Yes | Yes |
|
|
445
446
|
| Trimming, thumbnails, upload progress | No | Yes |
|
|
446
447
|
| Supabase/S3 uploader helpers | No | Yes |
|
|
448
|
+
| FeedClip-hosted transcription and AI analysis | No | Yes |
|
|
447
449
|
| Screen recording, console and network capture | Roadmap | Roadmap |
|
|
448
450
|
| Privacy redaction and resumable uploads | Roadmap | Roadmap |
|
|
449
451
|
| Custom branding and UI themes | Roadmap | Roadmap |
|
|
450
|
-
| Managed storage
|
|
452
|
+
| Managed storage | Roadmap | Roadmap |
|
|
451
453
|
| Native issue generation | Roadmap | Roadmap |
|
|
452
454
|
| Dashboard, search, deduplication, webhooks | Roadmap | Roadmap |
|
|
453
455
|
| SSO, RBAC, audit logs, data residency, SLA | Roadmap | Roadmap |
|
|
454
456
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
+
Feedclip Pro includes access to the FeedClip server-side feedback pipeline for
|
|
458
|
+
transcription and structured analysis. The repository also contains the API
|
|
459
|
+
implementation for local development and private deployments.
|
|
457
460
|
|
|
458
461
|
The Paid version uses a compact ECDSA P-256 signed license token. The private key stays
|
|
459
462
|
on the FeedClip licensing server; the SDK receives only the token and public
|
|
@@ -512,10 +515,12 @@ npm run license:issue -- \
|
|
|
512
515
|
--project project_123 \
|
|
513
516
|
--plan paid \
|
|
514
517
|
--issuer https://feedclip.dev \
|
|
515
|
-
--audience @feedclip/sdk
|
|
516
|
-
--days 365
|
|
518
|
+
--audience @feedclip/sdk
|
|
517
519
|
```
|
|
518
520
|
|
|
521
|
+
Licenses are lifetime by default. Pass `--days <number>` only when a temporary
|
|
522
|
+
token is intentionally required.
|
|
523
|
+
|
|
519
524
|
Optional feature overrides are signed into the token for development and
|
|
520
525
|
future product rollout:
|
|
521
526
|
|
|
@@ -657,9 +662,8 @@ dist/types/
|
|
|
657
662
|
|
|
658
663
|
## Roadmap
|
|
659
664
|
|
|
660
|
-
- hosted multi-tenant ingestion API;
|
|
661
665
|
- secure direct uploads and resumable large-file support;
|
|
662
|
-
- production
|
|
666
|
+
- durable production processing workers;
|
|
663
667
|
- native GitHub, Linear, and Jira connectors;
|
|
664
668
|
- semantic deduplication and feedback clustering;
|
|
665
669
|
- dashboard, search, status tracking, and release linkage;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
var e=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports);let t=require("react"),n=require("jotai"),r=require("jotai/react");var i=(0,n.atom)(!1);(0,n.atom)(!1);var a=(0,n.atom)(null),o=e((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.fragment`);function r(e,n,r){var i=null;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]);else r=n;return n=r.ref,{$$typeof:t,type:e,key:i,ref:n===void 0?null:n,props:r}}e.Fragment=n,e.jsx=r,e.jsxs=r})),s=e((e=>{process.env.NODE_ENV!==`production`&&(function(){function t(e){if(e==null)return null;if(typeof e==`function`)return e.$$typeof===O?null:e.displayName||e.name||null;if(typeof e==`string`)return e;switch(e){case _:return`Fragment`;case y:return`Profiler`;case v:return`StrictMode`;case C:return`Suspense`;case w:return`SuspenseList`;case D:return`Activity`}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){case g:return`Portal`;case x:return e.displayName||`Context`;case b:return(e._context.displayName||`Context`)+`.Consumer`;case S:var n=e.render;return e=e.displayName,e||=(e=n.displayName||n.name||``,e===``?`ForwardRef`:`ForwardRef(`+e+`)`),e;case T:return n=e.displayName||null,n===null?t(e.type)||`Memo`:n;case E:n=e._payload,e=e._init;try{return t(e(n))}catch{}}return null}function n(e){return``+e}function r(e){try{n(e);var t=!1}catch{t=!0}if(t){t=console;var r=t.error,i=typeof Symbol==`function`&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||`Object`;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)}}function i(e){if(e===_)return`<>`;if(typeof e==`object`&&e&&e.$$typeof===E)return`<...>`;try{var n=t(e);return n?`<`+n+`>`:`<...>`}catch{return`<...>`}}function a(){var e=k.A;return e===null?null:e.getOwner()}function o(){return Error(`react-stack-top-frame`)}function s(e){if(A.call(e,`key`)){var t=Object.getOwnPropertyDescriptor(e,`key`).get;if(t&&t.isReactWarning)return!1}return e.key!==void 0}function c(e,t){function n(){N||(N=!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))}n.isReactWarning=!0,Object.defineProperty(e,"key",{get:n,configurable:!0})}function l(){var e=t(this.type);return P[e]||(P[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}function u(e,t,n,r,i,a){var o=n.ref;return e={$$typeof:h,type:e,key:t,props:n,_owner:r},(o===void 0?null:o)===null?Object.defineProperty(e,"ref",{enumerable:!1,value:null}):Object.defineProperty(e,"ref",{enumerable:!1,get:l}),e._store={},Object.defineProperty(e._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(e,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(e,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:i}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:a}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}function d(e,n,i,o,l,d){var p=n.children;if(p!==void 0)if(o)if(j(p)){for(o=0;o<p.length;o++)f(p[o]);Object.freeze&&Object.freeze(p)}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.`);else f(p);if(A.call(n,`key`)){p=t(e);var m=Object.keys(n).filter(function(e){return e!==`key`});o=0<m.length?`{key: someKey, `+m.join(`: ..., `)+`: ...}`:`{key: someKey}`,L[p+o]||(m=0<m.length?`{`+m.join(`: ..., `)+`: ...}`:`{}`,console.error(`A props object containing a "key" prop is being spread into JSX:
|
|
2
|
+
let props = %s;
|
|
3
|
+
<%s {...props} />
|
|
4
|
+
React keys must be passed directly to JSX without using spread:
|
|
5
|
+
let props = %s;
|
|
6
|
+
<%s key={someKey} {...props} />`,o,p,m,p),L[p+o]=!0)}if(p=null,i!==void 0&&(r(i),p=``+i),s(n)&&(r(n.key),p=``+n.key),`key`in n)for(var h in i={},n)h!==`key`&&(i[h]=n[h]);else i=n;return p&&c(i,typeof e==`function`?e.displayName||e.name||`Unknown`:e),u(e,p,i,a(),l,d)}function f(e){p(e)?e._store&&(e._store.validated=1):typeof e==`object`&&e&&e.$$typeof===E&&(e._payload.status===`fulfilled`?p(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function p(e){return typeof e==`object`&&!!e&&e.$$typeof===h}var m=require("react"),h=Symbol.for(`react.transitional.element`),g=Symbol.for(`react.portal`),_=Symbol.for(`react.fragment`),v=Symbol.for(`react.strict_mode`),y=Symbol.for(`react.profiler`),b=Symbol.for(`react.consumer`),x=Symbol.for(`react.context`),S=Symbol.for(`react.forward_ref`),C=Symbol.for(`react.suspense`),w=Symbol.for(`react.suspense_list`),T=Symbol.for(`react.memo`),E=Symbol.for(`react.lazy`),D=Symbol.for(`react.activity`),O=Symbol.for(`react.client.reference`),k=m.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,A=Object.prototype.hasOwnProperty,j=Array.isArray,M=console.createTask?console.createTask:function(){return null};m={react_stack_bottom_frame:function(e){return e()}};var N,P={},F=m.react_stack_bottom_frame.bind(m,o)(),I=M(i(o)),L={};e.Fragment=_,e.jsx=function(e,t,n){var r=1e4>k.recentlyCreatedOwnerStacks++;return d(e,t,n,!1,r?Error(`react-stack-top-frame`):F,r?M(i(e)):I)},e.jsxs=function(e,t,n){var r=1e4>k.recentlyCreatedOwnerStacks++;return d(e,t,n,!0,r?Error(`react-stack-top-frame`):F,r?M(i(e)):I)}})()})),c=e(((e,t)=>{process.env.NODE_ENV===`production`?t.exports=o():t.exports=s()}))(),l=e=>{let{videoRef:n,removeBranding:o=!1,thumbnailsEnabled:s=!1}=e,l=(0,r.useAtomValue)(i),u=(0,r.useAtomValue)(a),[d,f]=(0,t.useState)(!1);return(0,c.jsxs)(`div`,{className:`feedclip-video-frame`,children:[(0,c.jsx)(`video`,{ref:n,className:`feedclip-video`,controls:l,poster:l&&s&&u?u:void 0,onPlaying:()=>f(!0),onEmptied:()=>f(!1)}),!l&&!d&&(0,c.jsx)(`div`,{className:`feedclip-video-idle`,"aria-hidden":`true`,children:(0,c.jsx)(`span`,{className:`feedclip-video-idle-icon`,children:(0,c.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,children:[(0,c.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`}),(0,c.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`})]})})}),!o&&(0,c.jsx)(`div`,{className:`feedclip-watermark`,children:`Powered by FeedClip`})]})},u=(0,t.createContext)(void 0),d=e=>{try{let t=document.createElement(`canvas`);return t.width=e.videoWidth||640,t.height=e.videoHeight||480,t.getContext(`2d`)?.drawImage(e,0,0),t.toDataURL(`image/jpeg`,.8)}catch{return null}},f=(e,t,n,r)=>new Promise((i,a)=>{let o=document.createElement(`video`),s=URL.createObjectURL(e);o.src=s,o.muted=!0,o.addEventListener(`loadedmetadata`,()=>{let e=o.duration,c=n>0&&n<=e?n:e,l=t>=0&&t<c?t:0,u=document.createElement(`canvas`);u.width=o.videoWidth||640,u.height=o.videoHeight||480;let d=u.getContext(`2d`);if(!d){URL.revokeObjectURL(s),a(Error(`Canvas 2D context unavailable`));return}let f=u.captureStream(),p=new MediaRecorder(f),m=[];p.ondataavailable=e=>{e.data.size>0&&m.push(e.data)},p.onstop=()=>{URL.revokeObjectURL(s),i(new Blob(m,{type:`video/${r}`}))},o.currentTime=l,o.addEventListener(`seeked`,function e(){o.removeEventListener(`seeked`,e),p.start(),o.play();let t,n=()=>{d.drawImage(o,0,0),o.currentTime>=c?(cancelAnimationFrame(t),p.stop(),o.pause()):t=requestAnimationFrame(n)};t=requestAnimationFrame(n)})}),o.addEventListener(`error`,()=>{URL.revokeObjectURL(s),a(Error(`Failed to load video for trimming`))})}),p=(e,t)=>{switch(e){case`UnixTimestamp`:return`${Date.now()}.${t}`;case`ISO 8601`:return`${new Date().toISOString().replace(/[:.]/g,`-`)}.${t}`;case`Custom`:return`recording.${t}`;default:return`${Date.now()}.${t}`}},m={webm:[`video/webm;codecs=vp9,opus`,`video/webm;codecs=vp8,opus`,`video/webm`],mp4:[`video/mp4;codecs=h264,aac`,`video/mp4`,`video/webm;codecs=h264`,`video/webm`],mov:[`video/mp4`,`video/webm`],avi:[`video/webm;codecs=vp9,opus`,`video/webm;codecs=vp8,opus`,`video/webm`],mkv:[`video/x-matroska;codecs=avc1`,`video/webm`]},h=e=>{let t=m[e]??[`video/webm`];for(let e of t)if(typeof MediaRecorder<`u`&&MediaRecorder.isTypeSupported(e))return e;return`video/webm`},g={"en-US":{startRecordingError:`Unable to access camera and microphone. Please check your permissions.`,browserNotSupported:`Your browser does not support video recording. Please use a modern browser.`,uploading:`Uploading...`,uploadSuccess:`Video uploaded successfully!`,uploadError:`Error uploading video.`,fileSizeError:`File size exceeds the maximum allowed size.`,startRecording:`Start recording`,stopRecording:`Stop recording`,pauseRecording:`Pause recording`,resumeRecording:`Resume recording`,uploadVideo:`Upload video`,resetRecording:`Discard and reset`},"ru-RU":{startRecordingError:`Не удалось получить доступ к камере и микрофону. Пожалуйста, проверьте разрешения.`,browserNotSupported:`Ваш браузер не поддерживает запись видео. Пожалуйста, используйте современный браузер.`,uploading:`Загрузка...`,uploadSuccess:`Видео успешно загружено!`,uploadError:`Ошибка при загрузке видео.`,fileSizeError:`Размер файла превышает максимально допустимый.`,startRecording:`Начать запись`,stopRecording:`Остановить запись`,pauseRecording:`Пауза записи`,resumeRecording:`Возобновить запись`,uploadVideo:`Загрузить видео`,resetRecording:`Отменить и сбросить`},"es-ES":{startRecordingError:`No se puede acceder a la cámara y al micrófono. Por favor, comprueba tus permisos.`,browserNotSupported:`Tu navegador no admite la grabación de vídeo. Por favor, usa un navegador moderno.`,uploading:`Subiendo...`,uploadSuccess:`¡Vídeo subido correctamente!`,uploadError:`Error al subir el vídeo.`,fileSizeError:`El tamaño del archivo supera el máximo permitido.`,startRecording:`Iniciar grabación`,stopRecording:`Detener grabación`,pauseRecording:`Pausar grabación`,resumeRecording:`Reanudar grabación`,uploadVideo:`Subir vídeo`,resetRecording:`Descartar y restablecer`},"fr-FR":{startRecordingError:`Impossible d'accéder à la caméra et au microphone. Veuillez vérifier vos autorisations.`,browserNotSupported:`Votre navigateur ne prend pas en charge l'enregistrement vidéo. Veuillez utiliser un navigateur moderne.`,uploading:`Téléversement...`,uploadSuccess:`Vidéo téléversée avec succès !`,uploadError:`Erreur lors du téléversement de la vidéo.`,fileSizeError:`La taille du fichier dépasse la taille maximale autorisée.`,startRecording:`Démarrer l'enregistrement`,stopRecording:`Arrêter l'enregistrement`,pauseRecording:`Mettre en pause`,resumeRecording:`Reprendre l'enregistrement`,uploadVideo:`Téléverser la vidéo`,resetRecording:`Annuler et réinitialiser`},"de-DE":{startRecordingError:`Kamera und Mikrofon sind nicht zugänglich. Bitte überprüfen Sie Ihre Berechtigungen.`,browserNotSupported:`Ihr Browser unterstützt keine Videoaufnahme. Bitte verwenden Sie einen modernen Browser.`,uploading:`Wird hochgeladen...`,uploadSuccess:`Video erfolgreich hochgeladen!`,uploadError:`Fehler beim Hochladen des Videos.`,fileSizeError:`Die Dateigröße überschreitet die maximal zulässige Größe.`,startRecording:`Aufnahme starten`,stopRecording:`Aufnahme stoppen`,pauseRecording:`Aufnahme pausieren`,resumeRecording:`Aufnahme fortsetzen`,uploadVideo:`Video hochladen`,resetRecording:`Verwerfen und zurücksetzen`},"it-IT":{startRecordingError:`Impossibile accedere alla fotocamera e al microfono. Controlla le tue autorizzazioni.`,browserNotSupported:`Il tuo browser non supporta la registrazione video. Utilizza un browser moderno.`,uploading:`Caricamento...`,uploadSuccess:`Video caricato con successo!`,uploadError:`Errore durante il caricamento del video.`,fileSizeError:`La dimensione del file supera la dimensione massima consentita.`,startRecording:`Avvia registrazione`,stopRecording:`Interrompi registrazione`,pauseRecording:`Metti in pausa la registrazione`,resumeRecording:`Riprendi registrazione`,uploadVideo:`Carica video`,resetRecording:`Annulla e ripristina`},"pt-PT":{startRecordingError:`Não foi possível aceder à câmara e ao microfone. Por favor, verifique as suas permissões.`,browserNotSupported:`O seu navegador não suporta gravação de vídeo. Por favor, utilize um navegador moderno.`,uploading:`A carregar...`,uploadSuccess:`Vídeo carregado com sucesso!`,uploadError:`Erro ao carregar o vídeo.`,fileSizeError:`O tamanho do ficheiro excede o tamanho máximo permitido.`,startRecording:`Iniciar gravação`,stopRecording:`Parar gravação`,pauseRecording:`Pausar gravação`,resumeRecording:`Retomar gravação`,uploadVideo:`Carregar vídeo`,resetRecording:`Descartar e repor`},"zh-CN":{startRecordingError:`无法访问摄像头和麦克风。请检查您的权限。`,browserNotSupported:`您的浏览器不支持视频录制。请使用现代浏览器。`,uploading:`上传中...`,uploadSuccess:`视频上传成功!`,uploadError:`视频上传失败。`,fileSizeError:`文件大小超过允许的最大值。`,startRecording:`开始录制`,stopRecording:`停止录制`,pauseRecording:`暂停录制`,resumeRecording:`恢复录制`,uploadVideo:`上传视频`,resetRecording:`放弃并重置`},"ja-JP":{startRecordingError:`カメラとマイクにアクセスできません。権限を確認してください。`,browserNotSupported:`お使いのブラウザは動画録画に対応していません。最新のブラウザをご利用ください。`,uploading:`アップロード中...`,uploadSuccess:`動画のアップロードに成功しました!`,uploadError:`動画のアップロードに失敗しました。`,fileSizeError:`ファイルサイズが許可される最大サイズを超えています。`,startRecording:`録画を開始`,stopRecording:`録画を停止`,pauseRecording:`録画を一時停止`,resumeRecording:`録画を再開`,uploadVideo:`動画をアップロード`,resetRecording:`破棄してリセット`},"ko-KR":{startRecordingError:`카메라와 마이크에 접근할 수 없습니다. 권한을 확인해 주세요.`,browserNotSupported:`브라우저가 동영상 녹화를 지원하지 않습니다. 최신 브라우저를 사용해 주세요.`,uploading:`업로드 중...`,uploadSuccess:`동영상이 성공적으로 업로드되었습니다!`,uploadError:`동영상 업로드 중 오류가 발생했습니다.`,fileSizeError:`파일 크기가 허용된 최대 크기를 초과합니다.`,startRecording:`녹화 시작`,stopRecording:`녹화 중지`,pauseRecording:`녹화 일시정지`,resumeRecording:`녹화 재개`,uploadVideo:`동영상 업로드`,resetRecording:`취소 및 초기화`}},_={"en-US":{feedbackType:`Feedback type`,feedbackBug:`Bug`,feedbackIdea:`Idea`,feedbackQuestion:`Question`,feedbackOther:`Other`,feedbackDescription:`What happened?`,feedbackPlaceholder:`Describe the problem or idea. The recording adds the context.`,attachScreenshot:`Attach screenshot`,recorderTitle:`Record your feedback`,recorderSubtitle:`Show what happened and tell us what you expected.`,recorderPrivacy:`Camera and microphone are used only while recording`,recordingActive:`Recording in progress`,recordingPaused:`Recording paused`,reviewTitle:`Review and send`,reviewReady:`Your recording is ready`},"ru-RU":{feedbackType:`Тип обращения`,feedbackBug:`Ошибка`,feedbackIdea:`Идея`,feedbackQuestion:`Вопрос`,feedbackOther:`Другое`,feedbackDescription:`Что произошло?`,feedbackPlaceholder:`Опишите проблему или идею. Запись добавит контекст.`,attachScreenshot:`Прикрепить скриншот`,recorderTitle:`Запишите отзыв`,recorderSubtitle:`Покажите, что произошло, и расскажите, чего вы ожидали.`,recorderPrivacy:`Камера и микрофон используются только во время записи`,recordingActive:`Идёт запись`,recordingPaused:`Запись приостановлена`,reviewTitle:`Проверьте и отправьте`,reviewReady:`Запись готова`}},v=e=>({...g[e]??g[`en-US`],..._[e]??_[`en-US`]}),y=e=>{let t=new URL(window.location.href);return t.username=``,t.password=``,t.hash=``,e||(t.search=``),t.toString()},b=()=>{if(document.referrer)try{let e=new URL(document.referrer);return e.username=``,e.password=``,e.search=``,e.hash=``,e.toString()}catch{return}},x=(e={})=>({url:y(e.includeQueryString===!0),title:document.title,userAgent:navigator.userAgent,language:navigator.language,viewport:{width:window.innerWidth,height:window.innerHeight,devicePixelRatio:window.devicePixelRatio},timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,referrer:e.includeReferrer?b():void 0}),S=()=>typeof crypto<`u`&&`randomUUID`in crypto?crypto.randomUUID():`feedback_${Date.now()}_${Math.random().toString(36).slice(2,10)}`,C=e=>{let{recordedBlob:n,uploading:r,uploadProgress:i,setUploading:a,setUploadProgress:o,setAlert:s,onComplete:l,trimStart:d=0,trimEnd:m=0,trimmingEnabled:h=!1,uploadProgressEnabled:g=!1,kind:_,description:y,screenshot:b}=e,C=(0,t.useContext)(u),w=v(C?.locale??`en-US`);return(0,c.jsxs)(`div`,{className:`feedclip-upload`,children:[r&&g&&(0,c.jsx)(`div`,{className:`feedclip-progress`,role:`progressbar`,"aria-valuemin":0,"aria-valuemax":100,"aria-valuenow":i,children:(0,c.jsx)(`div`,{className:`feedclip-progress-value`,style:{width:`${i}%`}})}),(0,c.jsxs)(`button`,{onClick:async()=>{if(!n)return;let e=C?.defaultVideoFileExtension??`webm`,t=n;if(h&&(d>0||m>0))try{t=await f(n,d,m,e)}catch{s({type:`error`,message:w.uploadError});return}if(C?.maxFileSize&&t.size>C.maxFileSize){s({type:`error`,message:w.fileSizeError});return}a(!0),o(0);let r=p(C?.defaultVideoFileNameStyle??`UnixTimestamp`,e),i=new File([t],r,{type:t.type||`video/${e}`});try{let e=await C?.getContext?.(),t={id:S(),createdAt:new Date().toISOString(),kind:_,description:y.trim(),video:i,screenshot:b??void 0,context:x(C?.browserContext),customContext:e},n;if(C?.onSubmit)n=await C.onSubmit(t,e=>o(e));else if(C?.onUpload)await C.onUpload(i,e=>o(e));else throw Error(`FeedClip requires onSubmit or onUpload`);s({type:`success`,message:w.uploadSuccess}),l(n??void 0)}catch{s({type:`error`,message:w.uploadError})}finally{a(!1),o(0)}},disabled:r,"aria-label":r?w.uploading:w.uploadVideo,className:`feedclip-button feedclip-button-primary`,children:[r?w.uploading:(0,c.jsx)(`svg`,{className:`feedclip-button-icon`,"aria-hidden":`true`,xmlns:`http://www.w3.org/2000/svg`,width:`24`,height:`24`,fill:`currentColor`,viewBox:`0 0 24 24`,children:(0,c.jsx)(`path`,{fillRule:`evenodd`,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`,clipRule:`evenodd`})}),!r&&(0,c.jsx)(`span`,{children:w.uploadVideo})]})]})},w=e=>{let{setIsRecording:r,setRecordedBlob:a,mediaRecorderRef:o,streamRef:s,chunksRef:l,videoRef:d}=e,f=(0,n.useSetAtom)(i),p=v((0,t.useContext)(u)?.locale??`en-US`),m=()=>{if(d.current){let e=d.current.src;e&&e.startsWith(`blob:`)&&URL.revokeObjectURL(e),d.current.src=``,d.current.load()}r(!1),f(!1),a(null),o.current=null,s.current=null,l.current=[]};return(0,c.jsxs)(`button`,{type:`button`,"data-tooltip-target":`tooltip-default`,"aria-label":p.resetRecording,onClick:()=>m(),className:`feedclip-button feedclip-button-ghost`,children:[(0,c.jsx)(`svg`,{className:`feedclip-button-icon`,"aria-hidden":`true`,xmlns:`http://www.w3.org/2000/svg`,width:`24`,height:`24`,fill:`none`,viewBox:`0 0 24 24`,children:(0,c.jsx)(`path`,{stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:`2`,d:`M21 9H8a5 5 0 0 0 0 10h9m4-10-4-4m4 4-4 4`})}),(0,c.jsx)(`span`,{children:p.resetRecording})]})},T=e=>{let{streamRef:n,chunksRef:o,videoRef:s,mediaRecorderRef:l,setIsRecording:f,setIsPaused:p,setRecordedBlob:m,setAlert:g,thumbnailsEnabled:_=!1}=e,y=(0,t.useContext)(u),[,b]=(0,r.useAtom)(i),[,x]=(0,r.useAtom)(a),S=v(y?.locale??`en-US`);return(0,c.jsxs)(`button`,{onClick:async()=>{if(!navigator.mediaDevices?.getUserMedia||typeof MediaRecorder>`u`){g({type:`error`,message:S.browserNotSupported});return}p(!1);try{let e=await navigator.mediaDevices.getUserMedia({video:!0,audio:!0});n.current=e,s.current&&(s.current.srcObject=e,s.current.muted=!0,s.current.play()),o.current=[];let t=h(y?.defaultVideoFileExtension??`webm`),r=new MediaRecorder(e,{mimeType:t});r.ondataavailable=e=>o.current.push(e.data),r.onstop=()=>{let n=r.mimeType||t,i=new Blob(o.current,{type:n});_&&s.current&&x(d(s.current)),e.getTracks().forEach(e=>e.stop()),s.current&&(s.current.srcObject=null,s.current.src=URL.createObjectURL(i),s.current.muted=!1),m(i),b(!0)},l.current=r,r.start()}catch{g({type:`error`,message:S.startRecordingError});return}f(!0),setTimeout(()=>{l.current&&(l.current.state===`recording`||l.current.state===`paused`)&&(l.current.stop(),f(!1),p(!1))},y?.maxDurationMilliSeconds??6e4)},"aria-label":S.startRecording,className:`feedclip-button feedclip-button-primary feedclip-button-start`,children:[(0,c.jsx)(`svg`,{className:`feedclip-button-icon`,"aria-hidden":`true`,xmlns:`http://www.w3.org/2000/svg`,width:`24`,height:`24`,fill:`currentColor`,viewBox:`0 0 24 24`,children:(0,c.jsx)(`path`,{fillRule:`evenodd`,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`,clipRule:`evenodd`})}),(0,c.jsx)(`span`,{children:S.startRecording})]})},E=e=>{let{setIsRecording:n,mediaRecorderRef:r}=e,i=v((0,t.useContext)(u)?.locale??`en-US`);return(0,c.jsxs)(`button`,{className:`feedclip-button feedclip-button-danger`,"aria-label":i.stopRecording,onClick:()=>{r.current&&r.current.state===`recording`&&(r.current.stop(),n(!1))},children:[(0,c.jsx)(`svg`,{className:`feedclip-button-icon`,"aria-hidden":`true`,xmlns:`http://www.w3.org/2000/svg`,width:`24`,height:`24`,fill:`currentColor`,viewBox:`0 0 24 24`,children:(0,c.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`})}),(0,c.jsx)(`span`,{children:i.stopRecording})]})},D=e=>{let{mediaRecorderRef:n,isPaused:r,setIsPaused:i}=e,a=v((0,t.useContext)(u)?.locale??`en-US`);return(0,c.jsxs)(`button`,{onClick:()=>{let e=n.current;e&&(r?(e.resume(),i(!1)):(e.pause(),i(!0)))},"aria-label":r?a.resumeRecording:a.pauseRecording,className:`feedclip-button feedclip-button-secondary`,children:[r?(0,c.jsx)(`svg`,{className:`feedclip-button-icon`,"aria-hidden":`true`,xmlns:`http://www.w3.org/2000/svg`,width:`24`,height:`24`,fill:`currentColor`,viewBox:`0 0 24 24`,children:(0,c.jsx)(`path`,{fillRule:`evenodd`,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`,clipRule:`evenodd`})}):(0,c.jsx)(`svg`,{className:`feedclip-button-icon`,"aria-hidden":`true`,xmlns:`http://www.w3.org/2000/svg`,width:`24`,height:`24`,fill:`currentColor`,viewBox:`0 0 24 24`,children:(0,c.jsx)(`path`,{fillRule:`evenodd`,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`,clipRule:`evenodd`})}),(0,c.jsx)(`span`,{children:r?a.resumeRecording:a.pauseRecording})]})},O=e=>{let{videoRef:n,trimStart:r,trimEnd:i,setTrimStart:a,setTrimEnd:o}=e,[s,l]=(0,t.useState)(0);if((0,t.useEffect)(()=>{let e=n.current;if(!e)return;let t=()=>{let t=e.duration||0;l(t),i===0&&o(t)};if(e.readyState>=1)t();else return e.addEventListener(`loadedmetadata`,t),()=>e.removeEventListener(`loadedmetadata`,t)},[n,i,o]),s===0)return null;let u=e=>`${Math.floor(e/60)}:${String(Math.floor(e%60)).padStart(2,`0`)}`;return(0,c.jsxs)(`div`,{className:`w-full px-2 mt-2 mb-1`,children:[(0,c.jsxs)(`div`,{className:`flex justify-between text-xs text-gray-500 mb-1`,children:[(0,c.jsx)(`span`,{children:`✂️ Trim`}),(0,c.jsxs)(`span`,{children:[u(r),` – `,u(i)]})]}),(0,c.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,c.jsxs)(`label`,{className:`text-xs text-gray-500`,children:[`Start`,(0,c.jsx)(`input`,{type:`range`,min:0,max:s,step:.1,value:r,onChange:e=>{let t=parseFloat(e.target.value);t<i&&a(t)},className:`w-full accent-blue-600`})]}),(0,c.jsxs)(`label`,{className:`text-xs text-gray-500`,children:[`End`,(0,c.jsx)(`input`,{type:`range`,min:0,max:s,step:.1,value:i,onChange:e=>{let t=parseFloat(e.target.value);t>r&&o(t)},className:`w-full accent-blue-600`})]})]})]})},k=({locale:e,kind:t,description:n,screenshot:r,setKind:i,setDescription:a,setScreenshot:o})=>{let s=v(e);return(0,c.jsxs)(`div`,{className:`feedclip-form`,children:[(0,c.jsxs)(`label`,{className:`feedclip-field`,children:[(0,c.jsx)(`span`,{children:s.feedbackType}),(0,c.jsxs)(`select`,{value:t,onChange:e=>i(e.target.value),className:`feedclip-input`,children:[(0,c.jsx)(`option`,{value:`bug`,children:s.feedbackBug}),(0,c.jsx)(`option`,{value:`idea`,children:s.feedbackIdea}),(0,c.jsx)(`option`,{value:`question`,children:s.feedbackQuestion}),(0,c.jsx)(`option`,{value:`other`,children:s.feedbackOther})]})]}),(0,c.jsxs)(`label`,{className:`feedclip-field`,children:[(0,c.jsx)(`span`,{children:s.feedbackDescription}),(0,c.jsx)(`textarea`,{value:n,onChange:e=>a(e.target.value),placeholder:s.feedbackPlaceholder,rows:3,className:`feedclip-input feedclip-textarea`})]}),(0,c.jsxs)(`label`,{className:`feedclip-field`,children:[(0,c.jsx)(`span`,{children:s.attachScreenshot}),(0,c.jsx)(`input`,{type:`file`,accept:`image/*`,onChange:e=>{o(e.target.files?.[0]??null)},className:`feedclip-file-input`}),r&&(0,c.jsx)(`span`,{className:`feedclip-file-name`,children:r.name})]})]})},A=({receipt:e})=>{if(!e.analysis&&!e.issue)return null;let t=e.issue,n=(()=>{if(t?.url)try{let e=new URL(t.url);return[`http:`,`https:`].includes(e.protocol)?e.toString():void 0}catch{return}})();return(0,c.jsxs)(`section`,{className:`feedclip-result`,children:[(0,c.jsxs)(`div`,{className:`feedclip-result-heading`,children:[(0,c.jsx)(`strong`,{children:e.analysis?.title??`Feedback received`}),e.analysis?.priority&&(0,c.jsx)(`span`,{className:`feedclip-result-priority`,children:e.analysis.priority})]}),e.analysis?.summary&&(0,c.jsx)(`p`,{children:e.analysis.summary}),n?(0,c.jsxs)(`a`,{href:n,target:`_blank`,rel:`noreferrer`,className:`feedclip-result-link`,children:[t?.provider,`: `,t?.id]}):t?(0,c.jsxs)(`span`,{className:`feedclip-result-link`,children:[t.provider,`: `,t.id]}):null]})},j=e=>{let{videoRef:n,setAlert:a,entitlements:o}=e,s=(0,r.useAtomValue)(i),l=(0,t.useContext)(u),d=v(l?.locale??`en-US`),f=(()=>{if(l?.privacyNotice?.url)try{let e=new URL(l.privacyNotice.url,window.location.href);return[`http:`,`https:`].includes(e.protocol)?e.toString():void 0}catch{return}})(),[p,m]=(0,t.useState)(!1),[h,g]=(0,t.useState)(!1),[_,y]=(0,t.useState)(null),[b,x]=(0,t.useState)(!1),[S,j]=(0,t.useState)(0),[M,N]=(0,t.useState)(0),[P,F]=(0,t.useState)(0),[I,L]=(0,t.useState)(`bug`),[R,z]=(0,t.useState)(``),[B,V]=(0,t.useState)(null),[H,U]=(0,t.useState)(null),W=(0,t.useRef)(null),G=(0,t.useRef)(null),K=(0,t.useRef)([]);return(0,c.jsxs)(c.Fragment,{children:[!p&&!s&&(0,c.jsxs)(`div`,{className:`feedclip-start-panel`,children:[(0,c.jsxs)(`div`,{children:[(0,c.jsx)(`h2`,{children:d.recorderTitle}),(0,c.jsx)(`p`,{children:d.recorderSubtitle})]}),(0,c.jsx)(T,{streamRef:G,chunksRef:K,videoRef:n,mediaRecorderRef:W,setIsRecording:m,setIsPaused:g,setRecordedBlob:y,setAlert:a,thumbnailsEnabled:o?.thumbnails}),(0,c.jsxs)(`p`,{className:`feedclip-privacy`,children:[(0,c.jsx)(`svg`,{viewBox:`0 0 20 20`,fill:`none`,"aria-hidden":`true`,children:(0,c.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`})}),d.recorderPrivacy,f&&(0,c.jsxs)(c.Fragment,{children:[` `,(0,c.jsx)(`a`,{href:f,target:`_blank`,rel:`noreferrer`,children:l?.privacyNotice?.label})]})]})]}),p&&(0,c.jsxs)(`div`,{className:`feedclip-recording-panel`,children:[(0,c.jsxs)(`div`,{className:`feedclip-recording-status`,role:`status`,"aria-live":`polite`,children:[(0,c.jsx)(`span`,{}),h?d.recordingPaused:d.recordingActive]}),(0,c.jsxs)(`div`,{className:`feedclip-recording-actions`,children:[(0,c.jsx)(D,{mediaRecorderRef:W,isPaused:h,setIsPaused:g}),(0,c.jsx)(E,{setIsRecording:m,mediaRecorderRef:W})]})]}),s&&(0,c.jsxs)(`div`,{className:`feedclip-review`,children:[(0,c.jsxs)(`div`,{className:`feedclip-section-heading`,children:[(0,c.jsx)(`span`,{children:d.reviewTitle}),(0,c.jsx)(`small`,{children:d.reviewReady})]}),(0,c.jsx)(k,{locale:l?.locale??`en-US`,kind:I,description:R,screenshot:B,setKind:L,setDescription:z,setScreenshot:V}),o?.trimming&&(0,c.jsx)(O,{videoRef:n,trimStart:M,trimEnd:P,setTrimStart:N,setTrimEnd:F}),(0,c.jsxs)(`div`,{className:`feedclip-submit-actions`,children:[(0,c.jsx)(C,{recordedBlob:_,uploading:b,uploadProgress:S,setUploading:x,setUploadProgress:j,onComplete:e=>{U(e??null)},setAlert:a,trimStart:M,trimEnd:P,trimmingEnabled:o?.trimming,uploadProgressEnabled:o?.uploadProgress,kind:I,description:R,screenshot:B}),(0,c.jsx)(w,{setIsRecording:m,streamRef:G,chunksRef:K,mediaRecorderRef:W,setRecordedBlob:y,videoRef:n})]})]}),H&&(0,c.jsx)(A,{receipt:H})]})},M=e=>{let{alert:t,setAlert:n}=e;return(0,c.jsxs)(`div`,{id:`alert`,className:`feedclip-alert feedclip-alert-${t?.type??`info`}`,role:`alert`,children:[(0,c.jsx)(`svg`,{"aria-hidden":`true`,xmlns:`http://www.w3.org/2000/svg`,fill:`currentColor`,viewBox:`0 0 20 20`,children:(0,c.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`})}),(0,c.jsx)(`span`,{className:`sr-only`,children:`Info`}),(0,c.jsx)(`div`,{children:t?.message}),(0,c.jsxs)(`button`,{type:`button`,className:`feedclip-alert-close`,"data-dismiss-target":`#alert`,"aria-label":`Close`,onClick:()=>n(null),children:[(0,c.jsx)(`span`,{className:`sr-only`,children:`Close`}),(0,c.jsx)(`svg`,{"aria-hidden":`true`,xmlns:`http://www.w3.org/2000/svg`,fill:`none`,viewBox:`0 0 14 14`,children:(0,c.jsx)(`path`,{stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:`2`,d:`m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6`})})]})]})},N=[`videoCapture`,`voiceCapture`,`feedbackDetails`,`screenshotAttachment`,`browserContext`,`customContext`,`selfHostedTransport`,`indexedDbStorage`,`pauseRecording`,`preview`],P=[...N,`removeBranding`,`thumbnails`,`trimming`,`uploadProgress`,`cloudUploaders`,`transcription`,`aiAnalysis`],F=[...P,`screenRecording`,`diagnostics`,`privacyRedaction`,`customBranding`,`resumableUploads`,`managedStorage`,`issueIntegrations`,`dashboard`,`deduplication`,`webhooks`,`sso`,`rbac`,`auditLogs`,`dataResidency`,`sla`],I=e=>{let t=new Set(e);return Object.freeze(Object.fromEntries(F.map(e=>[e,t.has(e)])))},L=Object.freeze({free:I(N),paid:I(P)}),R=L.free,z=(e,t={})=>Object.freeze({...L[e],...t}),B=16384,V=new WeakSet,H=e=>{let t=e.replace(/-/g,`+`).replace(/_/g,`/`),n=t.padEnd(Math.ceil(t.length/4)*4,`=`),r=atob(n);return Uint8Array.from(r,e=>e.charCodeAt(0))},U=e=>{let t=new TextDecoder().decode(H(e));return JSON.parse(t)},W=e=>({valid:!1,plan:`free`,entitlements:R,reason:e}),G=(e,t)=>Array.isArray(e)?e.includes(t):e===t,K=async({token:e,publicKey:t,issuer:n,audience:r,projectId:i,clockToleranceSeconds:a=30})=>{try{if(!globalThis.crypto?.subtle)return W(`Web Crypto is unavailable`);if(e.length>B)return W(`License token is too large`);let o=e.split(`.`);if(o.length!==3)return W(`License token has an invalid format`);let[s,c,l]=o,u=U(s),d=U(c);if(u.alg!==`ES256`||u.typ!==`FCL`)return W(`License token uses an unsupported algorithm`);if(![`free`,`paid`].includes(d.plan))return W(`License token contains an unknown plan`);if(d.iss!==n)return W(`License token issuer does not match`);if(!G(d.aud,r))return W(`License token audience does not match`);if(d.projectId!==i)return W(`License token project does not match`);let f=Math.floor(Date.now()/1e3);if(typeof d.exp==`number`&&d.exp+a<f)return W(`License token has expired`);if(d.iat-a>f)return W(`License token is not active yet`);let p=await crypto.subtle.importKey(`jwk`,t,{name:`ECDSA`,namedCurve:`P-256`},!1,[`verify`]),m=new TextEncoder().encode(`${s}.${c}`),h=new Uint8Array(H(l));if(!await crypto.subtle.verify({name:`ECDSA`,hash:`SHA-256`},p,h,m))return W(`License token signature is invalid`);let g={valid:!0,plan:d.plan,claims:d,entitlements:z(d.plan,d.features??{})};return V.add(g),g}catch{return W(`License token could not be verified`)}},q=(e,t)=>e.entitlements[t]===!0,J=(e,t)=>{if(!e||!V.has(e)||!q(e,t))throw Error(`A verified FeedClip license is required for ${t}`)},Y=()=>({valid:!0,plan:`free`,entitlements:R}),X=e=>{let{config:n}=e,[r,i]=(0,t.useState)(null),[a,o]=(0,t.useState)(Y),s=(0,t.useRef)(null),d=n?.license,f=n?.onLicenseError;(0,t.useEffect)(()=>{let e=!0;return d&&K(d).then(t=>{e&&(o(t),t.valid||f?.(t.reason??`License validation failed`))}),()=>{e=!1}},[d,f]);let p=d?a:Y(),m=p.entitlements,h=p.plan===`paid`?`Paid`:`Free`;return(0,c.jsx)(`section`,{className:`feedclip-shell`,children:(0,c.jsxs)(u.Provider,{value:n,children:[(0,c.jsxs)(`header`,{className:`feedclip-header`,children:[(0,c.jsxs)(`div`,{className:`feedclip-brand`,children:[(0,c.jsx)(`span`,{className:`feedclip-brand-mark`,"aria-hidden":`true`,children:(0,c.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,children:[(0,c.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`}),(0,c.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`})]})}),(0,c.jsxs)(`span`,{children:[(0,c.jsx)(`strong`,{children:`FeedClip`}),(0,c.jsx)(`small`,{children:`Customer feedback`})]})]}),(0,c.jsx)(`span`,{className:`feedclip-plan`,children:h})]}),(0,c.jsxs)(`div`,{className:`feedclip-content`,children:[r&&(0,c.jsx)(M,{alert:r,setAlert:i}),(0,c.jsx)(l,{videoRef:s,removeBranding:m?.removeBranding,thumbnailsEnabled:m?.thumbnails}),(0,c.jsx)(j,{videoRef:s,setAlert:i,entitlements:m})]})]})})};Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return K}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return z}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return q}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return x}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return J}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return R}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return Y}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return L}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return X}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return S}});
|