commit 1e339c08dbd3bcaee80b7a2c30421db675fd0ce5 Author: Admin Date: Tue Aug 12 11:02:05 2025 +0700 first commit diff --git a/auto-listing-facebook-marketplace/.gitignore b/auto-listing-facebook-marketplace/.gitignore new file mode 100644 index 0000000..43ea321 --- /dev/null +++ b/auto-listing-facebook-marketplace/.gitignore @@ -0,0 +1,31 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/auto-listing-facebook-marketplace/README.md b/auto-listing-facebook-marketplace/README.md new file mode 100644 index 0000000..4d49b44 --- /dev/null +++ b/auto-listing-facebook-marketplace/README.md @@ -0,0 +1,19 @@ +function rightClickElementById(id) { +const element = document.getElementById(id); +if (!element) { +console.error("Element not found:", id); +return; +} + +const event = new MouseEvent("contextmenu", { +bubbles: true, +cancelable: true, +view: window, +button: 2, // Chuột phải +buttons: 2, +clientX: element.getBoundingClientRect().left, +clientY: element.getBoundingClientRect().top +}); + +element.dispatchEvent(event); +} diff --git a/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/assets/app-2S0BUUWF.js b/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/assets/app-2S0BUUWF.js new file mode 100644 index 0000000..be96adf --- /dev/null +++ b/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/assets/app-2S0BUUWF.js @@ -0,0 +1 @@ +function n(e){return new Promise(t=>setTimeout(t,e))}export{n as d}; diff --git a/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/background.js b/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/background.js new file mode 100644 index 0000000..f9be6f7 --- /dev/null +++ b/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/background.js @@ -0,0 +1 @@ +function O(s){return s&&s.__esModule&&Object.prototype.hasOwnProperty.call(s,"default")?s.default:s}var E={exports:{}},_;function L(){return _||(_=1,function(s){var e=Object.prototype.hasOwnProperty,t="~";function a(){}Object.create&&(a.prototype=Object.create(null),new a().__proto__||(t=!1));function l(h,i,n){this.fn=h,this.context=i,this.once=n||!1}function u(h,i,n,r,y){if(typeof n!="function")throw new TypeError("The listener must be a function");var c=new l(n,r||h,y),m=t?t+i:i;return h._events[m]?h._events[m].fn?h._events[m]=[h._events[m],c]:h._events[m].push(c):(h._events[m]=c,h._eventsCount++),h}function f(h,i){--h._eventsCount===0?h._events=new a:delete h._events[i]}function d(){this._events=new a,this._eventsCount=0}d.prototype.eventNames=function(){var i=[],n,r;if(this._eventsCount===0)return i;for(r in n=this._events)e.call(n,r)&&i.push(t?r.slice(1):r);return Object.getOwnPropertySymbols?i.concat(Object.getOwnPropertySymbols(n)):i},d.prototype.listeners=function(i){var n=t?t+i:i,r=this._events[n];if(!r)return[];if(r.fn)return[r.fn];for(var y=0,c=r.length,m=new Array(c);yglobalThis.DOMException===void 0?new S(s):new DOMException(s),T=s=>{const e=s.reason===void 0?x("This operation was aborted."):s.reason;return e instanceof Error?e:x(e)};function q(s,e){const{milliseconds:t,fallback:a,message:l,customTimers:u={setTimeout,clearTimeout}}=e;let f,d;const i=new Promise((n,r)=>{if(typeof t!="number"||Math.sign(t)!==1)throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${t}\``);if(e.signal){const{signal:c}=e;c.aborted&&r(T(c)),d=()=>{r(T(c))},c.addEventListener("abort",d,{once:!0})}if(t===Number.POSITIVE_INFINITY){s.then(n,r);return}const y=new C;f=u.setTimeout.call(void 0,()=>{if(a){try{n(a())}catch(c){r(c)}return}typeof s.cancel=="function"&&s.cancel(),l===!1?n():l instanceof Error?r(l):(y.message=l??`Promise timed out after ${t} milliseconds`,r(y))},t),(async()=>{try{n(await s)}catch(c){r(c)}})()}).finally(()=>{i.clear(),d&&e.signal&&e.signal.removeEventListener("abort",d)});return i.clear=()=>{u.clearTimeout.call(void 0,f),f=void 0},i}function z(s,e,t){let a=0,l=s.length;for(;l>0;){const u=Math.trunc(l/2);let f=a+u;t(s[f],e)<=0?(a=++f,l-=u+1):l=u}return a}class ${#e=[];enqueue(e,t){t={priority:0,...t};const a={priority:t.priority,id:t.id,run:e};if(this.size===0||this.#e[this.size-1].priority>=t.priority){this.#e.push(a);return}const l=z(this.#e,a,(u,f)=>f.priority-u.priority);this.#e.splice(l,0,a)}setPriority(e,t){const a=this.#e.findIndex(u=>u.id===e);if(a===-1)throw new ReferenceError(`No promise function with the id "${e}" exists in the queue.`);const[l]=this.#e.splice(a,1);this.enqueue(l.run,{priority:t,id:e})}dequeue(){return this.#e.shift()?.run}filter(e){return this.#e.filter(t=>t.priority===e.priority).map(t=>t.run)}get size(){return this.#e.length}}class k extends A{#e;#o;#s=0;#d;#a;#m=0;#r;#u;#t;#v;#n=0;#c;#i;#y;#b=1n;timeout;constructor(e){if(super(),e={carryoverConcurrencyCount:!1,intervalCap:Number.POSITIVE_INFINITY,interval:0,concurrency:Number.POSITIVE_INFINITY,autoStart:!0,queueClass:$,...e},!(typeof e.intervalCap=="number"&&e.intervalCap>=1))throw new TypeError(`Expected \`intervalCap\` to be a number from 1 and up, got \`${e.intervalCap?.toString()??""}\` (${typeof e.intervalCap})`);if(e.interval===void 0||!(Number.isFinite(e.interval)&&e.interval>=0))throw new TypeError(`Expected \`interval\` to be a finite number >= 0, got \`${e.interval?.toString()??""}\` (${typeof e.interval})`);this.#e=e.carryoverConcurrencyCount,this.#o=e.intervalCap===Number.POSITIVE_INFINITY||e.interval===0,this.#d=e.intervalCap,this.#a=e.interval,this.#t=new e.queueClass,this.#v=e.queueClass,this.concurrency=e.concurrency,this.timeout=e.timeout,this.#y=e.throwOnTimeout===!0,this.#i=e.autoStart===!1}get#g(){return this.#o||this.#s{this.#_()},t)),!0}return!1}#h(){if(this.#t.size===0)return this.#r&&clearInterval(this.#r),this.#r=void 0,this.emit("empty"),this.#n===0&&this.emit("idle"),!1;if(!this.#i){const e=!this.#x;if(this.#g&&this.#E){const t=this.#t.dequeue();return t?(this.emit("active"),t(),e&&this.#p(),!0):!1}}return!1}#p(){this.#o||this.#r!==void 0||(this.#r=setInterval(()=>{this.#w()},this.#a),this.#m=Date.now()+this.#a)}#w(){this.#s===0&&this.#n===0&&this.#r&&(clearInterval(this.#r),this.#r=void 0),this.#s=this.#e?this.#n:0,this.#l()}#l(){for(;this.#h(););}get concurrency(){return this.#c}set concurrency(e){if(!(typeof e=="number"&&e>=1))throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${e}\` (${typeof e})`);this.#c=e,this.#l()}async#T(e){return new Promise((t,a)=>{e.addEventListener("abort",()=>{a(e.reason)},{once:!0})})}setPriority(e,t){this.#t.setPriority(e,t)}async add(e,t={}){return t.id??=(this.#b++).toString(),t={timeout:this.timeout,throwOnTimeout:this.#y,...t},new Promise((a,l)=>{this.#t.enqueue(async()=>{this.#n++,this.#s++;try{t.signal?.throwIfAborted();let u=e({signal:t.signal});t.timeout&&(u=q(Promise.resolve(u),{milliseconds:t.timeout})),t.signal&&(u=Promise.race([u,this.#T(t.signal)]));const f=await u;a(f),this.emit("completed",f)}catch(u){if(u instanceof C&&!t.throwOnTimeout){a();return}l(u),this.emit("error",u)}finally{this.#I()}},t),this.emit("add"),this.#h()})}async addAll(e,t){return Promise.all(e.map(async a=>this.add(a,t)))}start(){return this.#i?(this.#i=!1,this.#l(),this):this}pause(){this.#i=!0}clear(){this.#t=new this.#v}async onEmpty(){this.#t.size!==0&&await this.#f("empty")}async onSizeLessThan(e){this.#t.sizethis.#t.size{const l=()=>{t&&!t()||(this.off(e,l),a())};this.on(e,l)})}get size(){return this.#t.size}sizeBy(e){return this.#t.filter(e).length}get pending(){return this.#n}get isPaused(){return this.#i}}let I=[];const D=new k({concurrency:1});chrome.runtime.onConnect.addListener(s=>{I.push(s),s.onDisconnect.addListener(()=>{I=I.filter(e=>e!==s)})});(()=>{const s=new EventSource("http://localhost:4000/api/v1/products/publist-stream");s.onmessage=e=>{const t=JSON.parse(e.data);console.log("New event:",t),D.add(()=>M(t))},s.onerror=e=>{console.error("EventSource failed:",e)}})();async function M(s){return new Promise(e=>{chrome.tabs.create({url:"https://www.facebook.com/marketplace/create/item",active:!0},t=>{if(!t?.id)return e();const a=t.id,l=f=>{f.sender?.tab?.id===a&&(f.postMessage({type:"publist-event",payload:s}),chrome.runtime.onConnect.removeListener(l))};chrome.runtime.onConnect.addListener(l);const u=f=>{f===a&&(chrome.tabs.onRemoved.removeListener(u),e())};chrome.tabs.onRemoved.addListener(u)})})}chrome.runtime.onMessage.addListener((s,e)=>{if(s.type==="close-tab"){const t=e.tab?.id;t&&chrome.tabs.remove(t)}}); diff --git a/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/content.js b/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/content.js new file mode 100644 index 0000000..ea71c74 --- /dev/null +++ b/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/content.js @@ -0,0 +1,6 @@ +function S(e){return new Promise(t=>setTimeout(t,e))}function Ne(e,t){return function(){return e.apply(t,arguments)}}const{toString:nt}=Object.prototype,{getPrototypeOf:fe}=Object,{iterator:G,toStringTag:Le}=Symbol,Z=(e=>t=>{const n=nt.call(t);return e[n]||(e[n]=n.slice(8,-1).toLowerCase())})(Object.create(null)),_=e=>(e=e.toLowerCase(),t=>Z(t)===e),Q=e=>t=>typeof t===e,{isArray:j}=Array,M=Q("undefined");function rt(e){return e!==null&&!M(e)&&e.constructor!==null&&!M(e.constructor)&&x(e.constructor.isBuffer)&&e.constructor.isBuffer(e)}const Be=_("ArrayBuffer");function it(e){let t;return typeof ArrayBuffer<"u"&&ArrayBuffer.isView?t=ArrayBuffer.isView(e):t=e&&e.buffer&&Be(e.buffer),t}const st=Q("string"),x=Q("function"),Fe=Q("number"),Y=e=>e!==null&&typeof e=="object",ot=e=>e===!0||e===!1,J=e=>{if(Z(e)!=="object")return!1;const t=fe(e);return(t===null||t===Object.prototype||Object.getPrototypeOf(t)===null)&&!(Le in e)&&!(G in e)},at=_("Date"),ct=_("File"),lt=_("Blob"),dt=_("FileList"),ut=e=>Y(e)&&x(e.pipe),ft=e=>{let t;return e&&(typeof FormData=="function"&&e instanceof FormData||x(e.append)&&((t=Z(e))==="formdata"||t==="object"&&x(e.toString)&&e.toString()==="[object FormData]"))},pt=_("URLSearchParams"),[ht,mt,vt,wt]=["ReadableStream","Request","Response","Headers"].map(_),yt=e=>e.trim?e.trim():e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"");function H(e,t,{allOwnKeys:n=!1}={}){if(e===null||typeof e>"u")return;let r,i;if(typeof e!="object"&&(e=[e]),j(e))for(r=0,i=e.length;r0;)if(i=n[r],t===i.toLowerCase())return i;return null}const k=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:global,Ue=e=>!M(e)&&e!==k;function oe(){const{caseless:e}=Ue(this)&&this||{},t={},n=(r,i)=>{const s=e&&ke(t,i)||i;J(t[s])&&J(r)?t[s]=oe(t[s],r):J(r)?t[s]=oe({},r):j(r)?t[s]=r.slice():t[s]=r};for(let r=0,i=arguments.length;r(H(t,(i,s)=>{n&&x(i)?e[s]=Ne(i,n):e[s]=i},{allOwnKeys:r}),e),Et=e=>(e.charCodeAt(0)===65279&&(e=e.slice(1)),e),gt=(e,t,n,r)=>{e.prototype=Object.create(t.prototype,r),e.prototype.constructor=e,Object.defineProperty(e,"super",{value:t.prototype}),n&&Object.assign(e.prototype,n)},Rt=(e,t,n,r)=>{let i,s,o;const c={};if(t=t||{},e==null)return t;do{for(i=Object.getOwnPropertyNames(e),s=i.length;s-- >0;)o=i[s],(!r||r(o,e,t))&&!c[o]&&(t[o]=e[o],c[o]=!0);e=n!==!1&&fe(e)}while(e&&(!n||n(e,t))&&e!==Object.prototype);return t},St=(e,t,n)=>{e=String(e),(n===void 0||n>e.length)&&(n=e.length),n-=t.length;const r=e.indexOf(t,n);return r!==-1&&r===n},Tt=e=>{if(!e)return null;if(j(e))return e;let t=e.length;if(!Fe(t))return null;const n=new Array(t);for(;t-- >0;)n[t]=e[t];return n},Ot=(e=>t=>e&&t instanceof e)(typeof Uint8Array<"u"&&fe(Uint8Array)),At=(e,t)=>{const r=(e&&e[G]).call(e);let i;for(;(i=r.next())&&!i.done;){const s=i.value;t.call(e,s[0],s[1])}},xt=(e,t)=>{let n;const r=[];for(;(n=e.exec(t))!==null;)r.push(n);return r},Ct=_("HTMLFormElement"),Pt=e=>e.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g,function(n,r,i){return r.toUpperCase()+i}),ve=(({hasOwnProperty:e})=>(t,n)=>e.call(t,n))(Object.prototype),_t=_("RegExp"),De=(e,t)=>{const n=Object.getOwnPropertyDescriptors(e),r={};H(n,(i,s)=>{let o;(o=t(i,s,e))!==!1&&(r[s]=o||i)}),Object.defineProperties(e,r)},Nt=e=>{De(e,(t,n)=>{if(x(e)&&["arguments","caller","callee"].indexOf(n)!==-1)return!1;const r=e[n];if(x(r)){if(t.enumerable=!1,"writable"in t){t.writable=!1;return}t.set||(t.set=()=>{throw Error("Can not rewrite read-only method '"+n+"'")})}})},Lt=(e,t)=>{const n={},r=i=>{i.forEach(s=>{n[s]=!0})};return j(e)?r(e):r(String(e).split(t)),n},Bt=()=>{},Ft=(e,t)=>e!=null&&Number.isFinite(e=+e)?e:t;function kt(e){return!!(e&&x(e.append)&&e[Le]==="FormData"&&e[G])}const Ut=e=>{const t=new Array(10),n=(r,i)=>{if(Y(r)){if(t.indexOf(r)>=0)return;if(!("toJSON"in r)){t[i]=r;const s=j(r)?[]:{};return H(r,(o,c)=>{const u=n(o,i+1);!M(u)&&(s[c]=u)}),t[i]=void 0,s}}return r};return n(e,0)},Dt=_("AsyncFunction"),jt=e=>e&&(Y(e)||x(e))&&x(e.then)&&x(e.catch),je=((e,t)=>e?setImmediate:t?((n,r)=>(k.addEventListener("message",({source:i,data:s})=>{i===k&&s===n&&r.length&&r.shift()()},!1),i=>{r.push(i),k.postMessage(n,"*")}))(`axios@${Math.random()}`,[]):n=>setTimeout(n))(typeof setImmediate=="function",x(k.postMessage)),It=typeof queueMicrotask<"u"?queueMicrotask.bind(k):typeof process<"u"&&process.nextTick||je,qt=e=>e!=null&&x(e[G]),a={isArray:j,isArrayBuffer:Be,isBuffer:rt,isFormData:ft,isArrayBufferView:it,isString:st,isNumber:Fe,isBoolean:ot,isObject:Y,isPlainObject:J,isReadableStream:ht,isRequest:mt,isResponse:vt,isHeaders:wt,isUndefined:M,isDate:at,isFile:ct,isBlob:lt,isRegExp:_t,isFunction:x,isStream:ut,isURLSearchParams:pt,isTypedArray:Ot,isFileList:dt,forEach:H,merge:oe,extend:bt,trim:yt,stripBOM:Et,inherits:gt,toFlatObject:Rt,kindOf:Z,kindOfTest:_,endsWith:St,toArray:Tt,forEachEntry:At,matchAll:xt,isHTMLForm:Ct,hasOwnProperty:ve,hasOwnProp:ve,reduceDescriptors:De,freezeMethods:Nt,toObjectSet:Lt,toCamelCase:Pt,noop:Bt,toFiniteNumber:Ft,findKey:ke,global:k,isContextDefined:Ue,isSpecCompliantForm:kt,toJSONObject:Ut,isAsyncFn:Dt,isThenable:jt,setImmediate:je,asap:It,isIterable:qt};function m(e,t,n,r,i){Error.call(this),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=new Error().stack,this.message=e,this.name="AxiosError",t&&(this.code=t),n&&(this.config=n),r&&(this.request=r),i&&(this.response=i,this.status=i.status?i.status:null)}a.inherits(m,Error,{toJSON:function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:a.toJSONObject(this.config),code:this.code,status:this.status}}});const Ie=m.prototype,qe={};["ERR_BAD_OPTION_VALUE","ERR_BAD_OPTION","ECONNABORTED","ETIMEDOUT","ERR_NETWORK","ERR_FR_TOO_MANY_REDIRECTS","ERR_DEPRECATED","ERR_BAD_RESPONSE","ERR_BAD_REQUEST","ERR_CANCELED","ERR_NOT_SUPPORT","ERR_INVALID_URL"].forEach(e=>{qe[e]={value:e}});Object.defineProperties(m,qe);Object.defineProperty(Ie,"isAxiosError",{value:!0});m.from=(e,t,n,r,i,s)=>{const o=Object.create(Ie);return a.toFlatObject(e,o,function(u){return u!==Error.prototype},c=>c!=="isAxiosError"),m.call(o,e.message,t,n,r,i),o.cause=e,o.name=e.name,s&&Object.assign(o,s),o};const Mt=null;function ae(e){return a.isPlainObject(e)||a.isArray(e)}function Me(e){return a.endsWith(e,"[]")?e.slice(0,-2):e}function we(e,t,n){return e?e.concat(t).map(function(i,s){return i=Me(i),!n&&s?"["+i+"]":i}).join(n?".":""):t}function Ht(e){return a.isArray(e)&&!e.some(ae)}const $t=a.toFlatObject(a,{},null,function(t){return/^is[A-Z]/.test(t)});function ee(e,t,n){if(!a.isObject(e))throw new TypeError("target must be an object");t=t||new FormData,n=a.toFlatObject(n,{metaTokens:!0,dots:!1,indexes:!1},!1,function(v,h){return!a.isUndefined(h[v])});const r=n.metaTokens,i=n.visitor||d,s=n.dots,o=n.indexes,u=(n.Blob||typeof Blob<"u"&&Blob)&&a.isSpecCompliantForm(t);if(!a.isFunction(i))throw new TypeError("visitor must be a function");function l(f){if(f===null)return"";if(a.isDate(f))return f.toISOString();if(a.isBoolean(f))return f.toString();if(!u&&a.isBlob(f))throw new m("Blob is not supported. Use a Buffer instead.");return a.isArrayBuffer(f)||a.isTypedArray(f)?u&&typeof Blob=="function"?new Blob([f]):Buffer.from(f):f}function d(f,v,h){let b=f;if(f&&!h&&typeof f=="object"){if(a.endsWith(v,"{}"))v=r?v:v.slice(0,-2),f=JSON.stringify(f);else if(a.isArray(f)&&Ht(f)||(a.isFileList(f)||a.endsWith(v,"[]"))&&(b=a.toArray(f)))return v=Me(v),b.forEach(function(T,L){!(a.isUndefined(T)||T===null)&&t.append(o===!0?we([v],L,s):o===null?v:v+"[]",l(T))}),!1}return ae(f)?!0:(t.append(we(h,v,s),l(f)),!1)}const p=[],w=Object.assign($t,{defaultVisitor:d,convertValue:l,isVisitable:ae});function g(f,v){if(!a.isUndefined(f)){if(p.indexOf(f)!==-1)throw Error("Circular reference detected in "+v.join("."));p.push(f),a.forEach(f,function(b,R){(!(a.isUndefined(b)||b===null)&&i.call(t,b,a.isString(R)?R.trim():R,v,w))===!0&&g(b,v?v.concat(R):[R])}),p.pop()}}if(!a.isObject(e))throw new TypeError("data must be an object");return g(e),t}function ye(e){const t={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+","%00":"\0"};return encodeURIComponent(e).replace(/[!'()~]|%20|%00/g,function(r){return t[r]})}function pe(e,t){this._pairs=[],e&&ee(e,this,t)}const He=pe.prototype;He.append=function(t,n){this._pairs.push([t,n])};He.toString=function(t){const n=t?function(r){return t.call(this,r,ye)}:ye;return this._pairs.map(function(i){return n(i[0])+"="+n(i[1])},"").join("&")};function zt(e){return encodeURIComponent(e).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}function $e(e,t,n){if(!t)return e;const r=n&&n.encode||zt;a.isFunction(n)&&(n={serialize:n});const i=n&&n.serialize;let s;if(i?s=i(t,n):s=a.isURLSearchParams(t)?t.toString():new pe(t,n).toString(r),s){const o=e.indexOf("#");o!==-1&&(e=e.slice(0,o)),e+=(e.indexOf("?")===-1?"?":"&")+s}return e}class be{constructor(){this.handlers=[]}use(t,n,r){return this.handlers.push({fulfilled:t,rejected:n,synchronous:r?r.synchronous:!1,runWhen:r?r.runWhen:null}),this.handlers.length-1}eject(t){this.handlers[t]&&(this.handlers[t]=null)}clear(){this.handlers&&(this.handlers=[])}forEach(t){a.forEach(this.handlers,function(r){r!==null&&t(r)})}}const ze={silentJSONParsing:!0,forcedJSONParsing:!0,clarifyTimeoutError:!1},Jt=typeof URLSearchParams<"u"?URLSearchParams:pe,Vt=typeof FormData<"u"?FormData:null,Kt=typeof Blob<"u"?Blob:null,Wt={isBrowser:!0,classes:{URLSearchParams:Jt,FormData:Vt,Blob:Kt},protocols:["http","https","file","blob","url","data"]},he=typeof window<"u"&&typeof document<"u",ce=typeof navigator=="object"&&navigator||void 0,Xt=he&&(!ce||["ReactNative","NativeScript","NS"].indexOf(ce.product)<0),Gt=typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope&&typeof self.importScripts=="function",Zt=he&&window.location.href||"http://localhost",Qt=Object.freeze(Object.defineProperty({__proto__:null,hasBrowserEnv:he,hasStandardBrowserEnv:Xt,hasStandardBrowserWebWorkerEnv:Gt,navigator:ce,origin:Zt},Symbol.toStringTag,{value:"Module"})),O={...Qt,...Wt};function Yt(e,t){return ee(e,new O.classes.URLSearchParams,Object.assign({visitor:function(n,r,i,s){return O.isNode&&a.isBuffer(n)?(this.append(r,n.toString("base64")),!1):s.defaultVisitor.apply(this,arguments)}},t))}function en(e){return a.matchAll(/\w+|\[(\w*)]/g,e).map(t=>t[0]==="[]"?"":t[1]||t[0])}function tn(e){const t={},n=Object.keys(e);let r;const i=n.length;let s;for(r=0;r=n.length;return o=!o&&a.isArray(i)?i.length:o,u?(a.hasOwnProp(i,o)?i[o]=[i[o],r]:i[o]=r,!c):((!i[o]||!a.isObject(i[o]))&&(i[o]=[]),t(n,r,i[o],s)&&a.isArray(i[o])&&(i[o]=tn(i[o])),!c)}if(a.isFormData(e)&&a.isFunction(e.entries)){const n={};return a.forEachEntry(e,(r,i)=>{t(en(r),i,n,0)}),n}return null}function nn(e,t,n){if(a.isString(e))try{return(t||JSON.parse)(e),a.trim(e)}catch(r){if(r.name!=="SyntaxError")throw r}return(n||JSON.stringify)(e)}const $={transitional:ze,adapter:["xhr","http","fetch"],transformRequest:[function(t,n){const r=n.getContentType()||"",i=r.indexOf("application/json")>-1,s=a.isObject(t);if(s&&a.isHTMLForm(t)&&(t=new FormData(t)),a.isFormData(t))return i?JSON.stringify(Je(t)):t;if(a.isArrayBuffer(t)||a.isBuffer(t)||a.isStream(t)||a.isFile(t)||a.isBlob(t)||a.isReadableStream(t))return t;if(a.isArrayBufferView(t))return t.buffer;if(a.isURLSearchParams(t))return n.setContentType("application/x-www-form-urlencoded;charset=utf-8",!1),t.toString();let c;if(s){if(r.indexOf("application/x-www-form-urlencoded")>-1)return Yt(t,this.formSerializer).toString();if((c=a.isFileList(t))||r.indexOf("multipart/form-data")>-1){const u=this.env&&this.env.FormData;return ee(c?{"files[]":t}:t,u&&new u,this.formSerializer)}}return s||i?(n.setContentType("application/json",!1),nn(t)):t}],transformResponse:[function(t){const n=this.transitional||$.transitional,r=n&&n.forcedJSONParsing,i=this.responseType==="json";if(a.isResponse(t)||a.isReadableStream(t))return t;if(t&&a.isString(t)&&(r&&!this.responseType||i)){const o=!(n&&n.silentJSONParsing)&&i;try{return JSON.parse(t)}catch(c){if(o)throw c.name==="SyntaxError"?m.from(c,m.ERR_BAD_RESPONSE,this,null,this.response):c}}return t}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,maxBodyLength:-1,env:{FormData:O.classes.FormData,Blob:O.classes.Blob},validateStatus:function(t){return t>=200&&t<300},headers:{common:{Accept:"application/json, text/plain, */*","Content-Type":void 0}}};a.forEach(["delete","get","head","post","put","patch"],e=>{$.headers[e]={}});const rn=a.toObjectSet(["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"]),sn=e=>{const t={};let n,r,i;return e&&e.split(` +`).forEach(function(o){i=o.indexOf(":"),n=o.substring(0,i).trim().toLowerCase(),r=o.substring(i+1).trim(),!(!n||t[n]&&rn[n])&&(n==="set-cookie"?t[n]?t[n].push(r):t[n]=[r]:t[n]=t[n]?t[n]+", "+r:r)}),t},Ee=Symbol("internals");function q(e){return e&&String(e).trim().toLowerCase()}function V(e){return e===!1||e==null?e:a.isArray(e)?e.map(V):String(e)}function on(e){const t=Object.create(null),n=/([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g;let r;for(;r=n.exec(e);)t[r[1]]=r[2];return t}const an=e=>/^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(e.trim());function re(e,t,n,r,i){if(a.isFunction(r))return r.call(this,t,n);if(i&&(t=n),!!a.isString(t)){if(a.isString(r))return t.indexOf(r)!==-1;if(a.isRegExp(r))return r.test(t)}}function cn(e){return e.trim().toLowerCase().replace(/([a-z\d])(\w*)/g,(t,n,r)=>n.toUpperCase()+r)}function ln(e,t){const n=a.toCamelCase(" "+t);["get","set","has"].forEach(r=>{Object.defineProperty(e,r+n,{value:function(i,s,o){return this[r].call(this,t,i,s,o)},configurable:!0})})}let C=class{constructor(t){t&&this.set(t)}set(t,n,r){const i=this;function s(c,u,l){const d=q(u);if(!d)throw new Error("header name must be a non-empty string");const p=a.findKey(i,d);(!p||i[p]===void 0||l===!0||l===void 0&&i[p]!==!1)&&(i[p||u]=V(c))}const o=(c,u)=>a.forEach(c,(l,d)=>s(l,d,u));if(a.isPlainObject(t)||t instanceof this.constructor)o(t,n);else if(a.isString(t)&&(t=t.trim())&&!an(t))o(sn(t),n);else if(a.isObject(t)&&a.isIterable(t)){let c={},u,l;for(const d of t){if(!a.isArray(d))throw TypeError("Object iterator must return a key-value pair");c[l=d[0]]=(u=c[l])?a.isArray(u)?[...u,d[1]]:[u,d[1]]:d[1]}o(c,n)}else t!=null&&s(n,t,r);return this}get(t,n){if(t=q(t),t){const r=a.findKey(this,t);if(r){const i=this[r];if(!n)return i;if(n===!0)return on(i);if(a.isFunction(n))return n.call(this,i,r);if(a.isRegExp(n))return n.exec(i);throw new TypeError("parser must be boolean|regexp|function")}}}has(t,n){if(t=q(t),t){const r=a.findKey(this,t);return!!(r&&this[r]!==void 0&&(!n||re(this,this[r],r,n)))}return!1}delete(t,n){const r=this;let i=!1;function s(o){if(o=q(o),o){const c=a.findKey(r,o);c&&(!n||re(r,r[c],c,n))&&(delete r[c],i=!0)}}return a.isArray(t)?t.forEach(s):s(t),i}clear(t){const n=Object.keys(this);let r=n.length,i=!1;for(;r--;){const s=n[r];(!t||re(this,this[s],s,t,!0))&&(delete this[s],i=!0)}return i}normalize(t){const n=this,r={};return a.forEach(this,(i,s)=>{const o=a.findKey(r,s);if(o){n[o]=V(i),delete n[s];return}const c=t?cn(s):String(s).trim();c!==s&&delete n[s],n[c]=V(i),r[c]=!0}),this}concat(...t){return this.constructor.concat(this,...t)}toJSON(t){const n=Object.create(null);return a.forEach(this,(r,i)=>{r!=null&&r!==!1&&(n[i]=t&&a.isArray(r)?r.join(", "):r)}),n}[Symbol.iterator](){return Object.entries(this.toJSON())[Symbol.iterator]()}toString(){return Object.entries(this.toJSON()).map(([t,n])=>t+": "+n).join(` +`)}getSetCookie(){return this.get("set-cookie")||[]}get[Symbol.toStringTag](){return"AxiosHeaders"}static from(t){return t instanceof this?t:new this(t)}static concat(t,...n){const r=new this(t);return n.forEach(i=>r.set(i)),r}static accessor(t){const r=(this[Ee]=this[Ee]={accessors:{}}).accessors,i=this.prototype;function s(o){const c=q(o);r[c]||(ln(i,o),r[c]=!0)}return a.isArray(t)?t.forEach(s):s(t),this}};C.accessor(["Content-Type","Content-Length","Accept","Accept-Encoding","User-Agent","Authorization"]);a.reduceDescriptors(C.prototype,({value:e},t)=>{let n=t[0].toUpperCase()+t.slice(1);return{get:()=>e,set(r){this[n]=r}}});a.freezeMethods(C);function ie(e,t){const n=this||$,r=t||n,i=C.from(r.headers);let s=r.data;return a.forEach(e,function(c){s=c.call(n,s,i.normalize(),t?t.status:void 0)}),i.normalize(),s}function Ve(e){return!!(e&&e.__CANCEL__)}function I(e,t,n){m.call(this,e??"canceled",m.ERR_CANCELED,t,n),this.name="CanceledError"}a.inherits(I,m,{__CANCEL__:!0});function Ke(e,t,n){const r=n.config.validateStatus;!n.status||!r||r(n.status)?e(n):t(new m("Request failed with status code "+n.status,[m.ERR_BAD_REQUEST,m.ERR_BAD_RESPONSE][Math.floor(n.status/100)-4],n.config,n.request,n))}function dn(e){const t=/^([-+\w]{1,25})(:?\/\/|:)/.exec(e);return t&&t[1]||""}function un(e,t){e=e||10;const n=new Array(e),r=new Array(e);let i=0,s=0,o;return t=t!==void 0?t:1e3,function(u){const l=Date.now(),d=r[s];o||(o=l),n[i]=u,r[i]=l;let p=s,w=0;for(;p!==i;)w+=n[p++],p=p%e;if(i=(i+1)%e,i===s&&(s=(s+1)%e),l-o{n=d,i=null,s&&(clearTimeout(s),s=null),e.apply(null,l)};return[(...l)=>{const d=Date.now(),p=d-n;p>=r?o(l,d):(i=l,s||(s=setTimeout(()=>{s=null,o(i)},r-p)))},()=>i&&o(i)]}const W=(e,t,n=3)=>{let r=0;const i=un(50,250);return fn(s=>{const o=s.loaded,c=s.lengthComputable?s.total:void 0,u=o-r,l=i(u),d=o<=c;r=o;const p={loaded:o,total:c,progress:c?o/c:void 0,bytes:u,rate:l||void 0,estimated:l&&c&&d?(c-o)/l:void 0,event:s,lengthComputable:c!=null,[t?"download":"upload"]:!0};e(p)},n)},ge=(e,t)=>{const n=e!=null;return[r=>t[0]({lengthComputable:n,total:e,loaded:r}),t[1]]},Re=e=>(...t)=>a.asap(()=>e(...t)),pn=O.hasStandardBrowserEnv?((e,t)=>n=>(n=new URL(n,O.origin),e.protocol===n.protocol&&e.host===n.host&&(t||e.port===n.port)))(new URL(O.origin),O.navigator&&/(msie|trident)/i.test(O.navigator.userAgent)):()=>!0,hn=O.hasStandardBrowserEnv?{write(e,t,n,r,i,s){const o=[e+"="+encodeURIComponent(t)];a.isNumber(n)&&o.push("expires="+new Date(n).toGMTString()),a.isString(r)&&o.push("path="+r),a.isString(i)&&o.push("domain="+i),s===!0&&o.push("secure"),document.cookie=o.join("; ")},read(e){const t=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return t?decodeURIComponent(t[3]):null},remove(e){this.write(e,"",Date.now()-864e5)}}:{write(){},read(){return null},remove(){}};function mn(e){return/^([a-z][a-z\d+\-.]*:)?\/\//i.test(e)}function vn(e,t){return t?e.replace(/\/?\/$/,"")+"/"+t.replace(/^\/+/,""):e}function We(e,t,n){let r=!mn(t);return e&&(r||n==!1)?vn(e,t):t}const Se=e=>e instanceof C?{...e}:e;function D(e,t){t=t||{};const n={};function r(l,d,p,w){return a.isPlainObject(l)&&a.isPlainObject(d)?a.merge.call({caseless:w},l,d):a.isPlainObject(d)?a.merge({},d):a.isArray(d)?d.slice():d}function i(l,d,p,w){if(a.isUndefined(d)){if(!a.isUndefined(l))return r(void 0,l,p,w)}else return r(l,d,p,w)}function s(l,d){if(!a.isUndefined(d))return r(void 0,d)}function o(l,d){if(a.isUndefined(d)){if(!a.isUndefined(l))return r(void 0,l)}else return r(void 0,d)}function c(l,d,p){if(p in t)return r(l,d);if(p in e)return r(void 0,l)}const u={url:s,method:s,data:s,baseURL:o,transformRequest:o,transformResponse:o,paramsSerializer:o,timeout:o,timeoutMessage:o,withCredentials:o,withXSRFToken:o,adapter:o,responseType:o,xsrfCookieName:o,xsrfHeaderName:o,onUploadProgress:o,onDownloadProgress:o,decompress:o,maxContentLength:o,maxBodyLength:o,beforeRedirect:o,transport:o,httpAgent:o,httpsAgent:o,cancelToken:o,socketPath:o,responseEncoding:o,validateStatus:c,headers:(l,d,p)=>i(Se(l),Se(d),p,!0)};return a.forEach(Object.keys(Object.assign({},e,t)),function(d){const p=u[d]||i,w=p(e[d],t[d],d);a.isUndefined(w)&&p!==c||(n[d]=w)}),n}const Xe=e=>{const t=D({},e);let{data:n,withXSRFToken:r,xsrfHeaderName:i,xsrfCookieName:s,headers:o,auth:c}=t;t.headers=o=C.from(o),t.url=$e(We(t.baseURL,t.url,t.allowAbsoluteUrls),e.params,e.paramsSerializer),c&&o.set("Authorization","Basic "+btoa((c.username||"")+":"+(c.password?unescape(encodeURIComponent(c.password)):"")));let u;if(a.isFormData(n)){if(O.hasStandardBrowserEnv||O.hasStandardBrowserWebWorkerEnv)o.setContentType(void 0);else if((u=o.getContentType())!==!1){const[l,...d]=u?u.split(";").map(p=>p.trim()).filter(Boolean):[];o.setContentType([l||"multipart/form-data",...d].join("; "))}}if(O.hasStandardBrowserEnv&&(r&&a.isFunction(r)&&(r=r(t)),r||r!==!1&&pn(t.url))){const l=i&&s&&hn.read(s);l&&o.set(i,l)}return t},wn=typeof XMLHttpRequest<"u",yn=wn&&function(e){return new Promise(function(n,r){const i=Xe(e);let s=i.data;const o=C.from(i.headers).normalize();let{responseType:c,onUploadProgress:u,onDownloadProgress:l}=i,d,p,w,g,f;function v(){g&&g(),f&&f(),i.cancelToken&&i.cancelToken.unsubscribe(d),i.signal&&i.signal.removeEventListener("abort",d)}let h=new XMLHttpRequest;h.open(i.method.toUpperCase(),i.url,!0),h.timeout=i.timeout;function b(){if(!h)return;const T=C.from("getAllResponseHeaders"in h&&h.getAllResponseHeaders()),A={data:!c||c==="text"||c==="json"?h.responseText:h.response,status:h.status,statusText:h.statusText,headers:T,config:e,request:h};Ke(function(F){n(F),v()},function(F){r(F),v()},A),h=null}"onloadend"in h?h.onloadend=b:h.onreadystatechange=function(){!h||h.readyState!==4||h.status===0&&!(h.responseURL&&h.responseURL.indexOf("file:")===0)||setTimeout(b)},h.onabort=function(){h&&(r(new m("Request aborted",m.ECONNABORTED,e,h)),h=null)},h.onerror=function(){r(new m("Network Error",m.ERR_NETWORK,e,h)),h=null},h.ontimeout=function(){let L=i.timeout?"timeout of "+i.timeout+"ms exceeded":"timeout exceeded";const A=i.transitional||ze;i.timeoutErrorMessage&&(L=i.timeoutErrorMessage),r(new m(L,A.clarifyTimeoutError?m.ETIMEDOUT:m.ECONNABORTED,e,h)),h=null},s===void 0&&o.setContentType(null),"setRequestHeader"in h&&a.forEach(o.toJSON(),function(L,A){h.setRequestHeader(A,L)}),a.isUndefined(i.withCredentials)||(h.withCredentials=!!i.withCredentials),c&&c!=="json"&&(h.responseType=i.responseType),l&&([w,f]=W(l,!0),h.addEventListener("progress",w)),u&&h.upload&&([p,g]=W(u),h.upload.addEventListener("progress",p),h.upload.addEventListener("loadend",g)),(i.cancelToken||i.signal)&&(d=T=>{h&&(r(!T||T.type?new I(null,e,h):T),h.abort(),h=null)},i.cancelToken&&i.cancelToken.subscribe(d),i.signal&&(i.signal.aborted?d():i.signal.addEventListener("abort",d)));const R=dn(i.url);if(R&&O.protocols.indexOf(R)===-1){r(new m("Unsupported protocol "+R+":",m.ERR_BAD_REQUEST,e));return}h.send(s||null)})},bn=(e,t)=>{const{length:n}=e=e?e.filter(Boolean):[];if(t||n){let r=new AbortController,i;const s=function(l){if(!i){i=!0,c();const d=l instanceof Error?l:this.reason;r.abort(d instanceof m?d:new I(d instanceof Error?d.message:d))}};let o=t&&setTimeout(()=>{o=null,s(new m(`timeout ${t} of ms exceeded`,m.ETIMEDOUT))},t);const c=()=>{e&&(o&&clearTimeout(o),o=null,e.forEach(l=>{l.unsubscribe?l.unsubscribe(s):l.removeEventListener("abort",s)}),e=null)};e.forEach(l=>l.addEventListener("abort",s));const{signal:u}=r;return u.unsubscribe=()=>a.asap(c),u}},En=function*(e,t){let n=e.byteLength;if(n{const i=gn(e,t);let s=0,o,c=u=>{o||(o=!0,r&&r(u))};return new ReadableStream({async pull(u){try{const{done:l,value:d}=await i.next();if(l){c(),u.close();return}let p=d.byteLength;if(n){let w=s+=p;n(w)}u.enqueue(new Uint8Array(d))}catch(l){throw c(l),l}},cancel(u){return c(u),i.return()}},{highWaterMark:2})},te=typeof fetch=="function"&&typeof Request=="function"&&typeof Response=="function",Ge=te&&typeof ReadableStream=="function",Sn=te&&(typeof TextEncoder=="function"?(e=>t=>e.encode(t))(new TextEncoder):async e=>new Uint8Array(await new Response(e).arrayBuffer())),Ze=(e,...t)=>{try{return!!e(...t)}catch{return!1}},Tn=Ge&&Ze(()=>{let e=!1;const t=new Request(O.origin,{body:new ReadableStream,method:"POST",get duplex(){return e=!0,"half"}}).headers.has("Content-Type");return e&&!t}),Oe=64*1024,le=Ge&&Ze(()=>a.isReadableStream(new Response("").body)),X={stream:le&&(e=>e.body)};te&&(e=>{["text","arrayBuffer","blob","formData","stream"].forEach(t=>{!X[t]&&(X[t]=a.isFunction(e[t])?n=>n[t]():(n,r)=>{throw new m(`Response type '${t}' is not supported`,m.ERR_NOT_SUPPORT,r)})})})(new Response);const On=async e=>{if(e==null)return 0;if(a.isBlob(e))return e.size;if(a.isSpecCompliantForm(e))return(await new Request(O.origin,{method:"POST",body:e}).arrayBuffer()).byteLength;if(a.isArrayBufferView(e)||a.isArrayBuffer(e))return e.byteLength;if(a.isURLSearchParams(e)&&(e=e+""),a.isString(e))return(await Sn(e)).byteLength},An=async(e,t)=>{const n=a.toFiniteNumber(e.getContentLength());return n??On(t)},xn=te&&(async e=>{let{url:t,method:n,data:r,signal:i,cancelToken:s,timeout:o,onDownloadProgress:c,onUploadProgress:u,responseType:l,headers:d,withCredentials:p="same-origin",fetchOptions:w}=Xe(e);l=l?(l+"").toLowerCase():"text";let g=bn([i,s&&s.toAbortSignal()],o),f;const v=g&&g.unsubscribe&&(()=>{g.unsubscribe()});let h;try{if(u&&Tn&&n!=="get"&&n!=="head"&&(h=await An(d,r))!==0){let A=new Request(t,{method:"POST",body:r,duplex:"half"}),B;if(a.isFormData(r)&&(B=A.headers.get("content-type"))&&d.setContentType(B),A.body){const[F,z]=ge(h,W(Re(u)));r=Te(A.body,Oe,F,z)}}a.isString(p)||(p=p?"include":"omit");const b="credentials"in Request.prototype;f=new Request(t,{...w,signal:g,method:n.toUpperCase(),headers:d.normalize().toJSON(),body:r,duplex:"half",credentials:b?p:void 0});let R=await fetch(f,w);const T=le&&(l==="stream"||l==="response");if(le&&(c||T&&v)){const A={};["status","statusText","headers"].forEach(me=>{A[me]=R[me]});const B=a.toFiniteNumber(R.headers.get("content-length")),[F,z]=c&&ge(B,W(Re(c),!0))||[];R=new Response(Te(R.body,Oe,F,()=>{z&&z(),v&&v()}),A)}l=l||"text";let L=await X[a.findKey(X,l)||"text"](R,e);return!T&&v&&v(),await new Promise((A,B)=>{Ke(A,B,{data:L,headers:C.from(R.headers),status:R.status,statusText:R.statusText,config:e,request:f})})}catch(b){throw v&&v(),b&&b.name==="TypeError"&&/Load failed|fetch/i.test(b.message)?Object.assign(new m("Network Error",m.ERR_NETWORK,e,f),{cause:b.cause||b}):m.from(b,b&&b.code,e,f)}}),de={http:Mt,xhr:yn,fetch:xn};a.forEach(de,(e,t)=>{if(e){try{Object.defineProperty(e,"name",{value:t})}catch{}Object.defineProperty(e,"adapterName",{value:t})}});const Ae=e=>`- ${e}`,Cn=e=>a.isFunction(e)||e===null||e===!1,Qe={getAdapter:e=>{e=a.isArray(e)?e:[e];const{length:t}=e;let n,r;const i={};for(let s=0;s`adapter ${c} `+(u===!1?"is not supported by the environment":"is not available in the build"));let o=t?s.length>1?`since : +`+s.map(Ae).join(` +`):" "+Ae(s[0]):"as no adapter specified";throw new m("There is no suitable adapter to dispatch the request "+o,"ERR_NOT_SUPPORT")}return r},adapters:de};function se(e){if(e.cancelToken&&e.cancelToken.throwIfRequested(),e.signal&&e.signal.aborted)throw new I(null,e)}function xe(e){return se(e),e.headers=C.from(e.headers),e.data=ie.call(e,e.transformRequest),["post","put","patch"].indexOf(e.method)!==-1&&e.headers.setContentType("application/x-www-form-urlencoded",!1),Qe.getAdapter(e.adapter||$.adapter)(e).then(function(r){return se(e),r.data=ie.call(e,e.transformResponse,r),r.headers=C.from(r.headers),r},function(r){return Ve(r)||(se(e),r&&r.response&&(r.response.data=ie.call(e,e.transformResponse,r.response),r.response.headers=C.from(r.response.headers))),Promise.reject(r)})}const Ye="1.10.0",ne={};["object","boolean","number","function","string","symbol"].forEach((e,t)=>{ne[e]=function(r){return typeof r===e||"a"+(t<1?"n ":" ")+e}});const Ce={};ne.transitional=function(t,n,r){function i(s,o){return"[Axios v"+Ye+"] Transitional option '"+s+"'"+o+(r?". "+r:"")}return(s,o,c)=>{if(t===!1)throw new m(i(o," has been removed"+(n?" in "+n:"")),m.ERR_DEPRECATED);return n&&!Ce[o]&&(Ce[o]=!0,console.warn(i(o," has been deprecated since v"+n+" and will be removed in the near future"))),t?t(s,o,c):!0}};ne.spelling=function(t){return(n,r)=>(console.warn(`${r} is likely a misspelling of ${t}`),!0)};function Pn(e,t,n){if(typeof e!="object")throw new m("options must be an object",m.ERR_BAD_OPTION_VALUE);const r=Object.keys(e);let i=r.length;for(;i-- >0;){const s=r[i],o=t[s];if(o){const c=e[s],u=c===void 0||o(c,s,e);if(u!==!0)throw new m("option "+s+" must be "+u,m.ERR_BAD_OPTION_VALUE);continue}if(n!==!0)throw new m("Unknown option "+s,m.ERR_BAD_OPTION)}}const K={assertOptions:Pn,validators:ne},N=K.validators;let U=class{constructor(t){this.defaults=t||{},this.interceptors={request:new be,response:new be}}async request(t,n){try{return await this._request(t,n)}catch(r){if(r instanceof Error){let i={};Error.captureStackTrace?Error.captureStackTrace(i):i=new Error;const s=i.stack?i.stack.replace(/^.+\n/,""):"";try{r.stack?s&&!String(r.stack).endsWith(s.replace(/^.+\n.+\n/,""))&&(r.stack+=` +`+s):r.stack=s}catch{}}throw r}}_request(t,n){typeof t=="string"?(n=n||{},n.url=t):n=t||{},n=D(this.defaults,n);const{transitional:r,paramsSerializer:i,headers:s}=n;r!==void 0&&K.assertOptions(r,{silentJSONParsing:N.transitional(N.boolean),forcedJSONParsing:N.transitional(N.boolean),clarifyTimeoutError:N.transitional(N.boolean)},!1),i!=null&&(a.isFunction(i)?n.paramsSerializer={serialize:i}:K.assertOptions(i,{encode:N.function,serialize:N.function},!0)),n.allowAbsoluteUrls!==void 0||(this.defaults.allowAbsoluteUrls!==void 0?n.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls:n.allowAbsoluteUrls=!0),K.assertOptions(n,{baseUrl:N.spelling("baseURL"),withXsrfToken:N.spelling("withXSRFToken")},!0),n.method=(n.method||this.defaults.method||"get").toLowerCase();let o=s&&a.merge(s.common,s[n.method]);s&&a.forEach(["delete","get","head","post","put","patch","common"],f=>{delete s[f]}),n.headers=C.concat(o,s);const c=[];let u=!0;this.interceptors.request.forEach(function(v){typeof v.runWhen=="function"&&v.runWhen(n)===!1||(u=u&&v.synchronous,c.unshift(v.fulfilled,v.rejected))});const l=[];this.interceptors.response.forEach(function(v){l.push(v.fulfilled,v.rejected)});let d,p=0,w;if(!u){const f=[xe.bind(this),void 0];for(f.unshift.apply(f,c),f.push.apply(f,l),w=f.length,d=Promise.resolve(n);p{if(!r._listeners)return;let s=r._listeners.length;for(;s-- >0;)r._listeners[s](i);r._listeners=null}),this.promise.then=i=>{let s;const o=new Promise(c=>{r.subscribe(c),s=c}).then(i);return o.cancel=function(){r.unsubscribe(s)},o},t(function(s,o,c){r.reason||(r.reason=new I(s,o,c),n(r.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(t){if(this.reason){t(this.reason);return}this._listeners?this._listeners.push(t):this._listeners=[t]}unsubscribe(t){if(!this._listeners)return;const n=this._listeners.indexOf(t);n!==-1&&this._listeners.splice(n,1)}toAbortSignal(){const t=new AbortController,n=r=>{t.abort(r)};return this.subscribe(n),t.signal.unsubscribe=()=>this.unsubscribe(n),t.signal}static source(){let t;return{token:new et(function(i){t=i}),cancel:t}}};function Nn(e){return function(n){return e.apply(null,n)}}function Ln(e){return a.isObject(e)&&e.isAxiosError===!0}const ue={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511};Object.entries(ue).forEach(([e,t])=>{ue[t]=e});function tt(e){const t=new U(e),n=Ne(U.prototype.request,t);return a.extend(n,U.prototype,t,{allOwnKeys:!0}),a.extend(n,t,null,{allOwnKeys:!0}),n.create=function(i){return tt(D(e,i))},n}const E=tt($);E.Axios=U;E.CanceledError=I;E.CancelToken=_n;E.isCancel=Ve;E.VERSION=Ye;E.toFormData=ee;E.AxiosError=m;E.Cancel=E.CanceledError;E.all=function(t){return Promise.all(t)};E.spread=Nn;E.isAxiosError=Ln;E.mergeConfig=D;E.AxiosHeaders=C;E.formToJSON=e=>Je(a.isHTMLForm(e)?new FormData(e):e);E.getAdapter=Qe.getAdapter;E.HttpStatusCode=ue;E.default=E;const{Axios:zn,AxiosError:Jn,CanceledError:Vn,isCancel:Kn,CancelToken:Wn,VERSION:Xn,all:Gn,Cancel:Zn,isAxiosError:Qn,spread:Yn,toFormData:er,AxiosHeaders:tr,HttpStatusCode:nr,formToJSON:rr,getAdapter:ir,mergeConfig:sr}=E,Bn=E.create({baseURL:"http://localhost:4000/api/v1",headers:{"Content-Type":"application/json"}});class Fn{base64ToFile(t,n,r){const i=t.includes(",")?t.split(",")[1]:t,s=atob(i),o=new ArrayBuffer(s.length),c=new Uint8Array(o);for(let l=0;l{let s=0;const o=()=>{const c=document.evaluate(t,document,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue;if(c instanceof HTMLElement){i(c);return}s++,s{const o=new FileReader;o.onloadend=()=>{typeof o.result=="string"?i(o.result.split(",")[1]):s("Không thể đọc dữ liệu ảnh")},o.onerror=s,o.readAsDataURL(r)})}getImageExtension(t){try{const r=new URL(t).pathname.match(/\.([a-zA-Z0-9]+)$/);return r?r[1].toLowerCase():null}catch{const i=t.split("?")[0].match(/\.([a-zA-Z0-9]+)$/);return i?i[1].toLowerCase():null}}imageLocalToBase64(t){return new Promise((n,r)=>{try{const i=chrome.runtime.getURL(`${t}`);fetch(i).then(s=>s.blob()).then(s=>{const o=new FileReader;o.onloadend=()=>n(o.result),o.onerror=r,o.readAsDataURL(s)}).catch(r)}catch(i){r(i)}})}scrollToElement(t,n="smooth"){t&&t.scrollIntoView({behavior:n,block:"center",inline:"nearest"})}getElementPointCoores(t){if(!t)return null;const n=t.getBoundingClientRect(),r=n.left+n.width/2,i=n.top+n.height/2;return{x:r,y:i}}setInputValue(t,n){t&&(t.value=n,t.dispatchEvent(new Event("input",{bubbles:!0})),t.dispatchEvent(new Event("change",{bubbles:!0})))}writeToInput=async(t,n)=>{const r=await this.getElementByXPath(n);if(!r)throw new Error("Xpath is not found");this.scrollToElement(r),this.clickByPoint(r),this.setInputValue(r,t)};pressEnter(t){if(!t)throw new Error("Textarea not found:",t);t.focus(),["keydown","keypress","keyup"].forEach(n=>{t.dispatchEvent(new KeyboardEvent(n,{key:"Enter",code:"Enter",keyCode:13,which:13,bubbles:!0,cancelable:!0}))})}}const y=new Fn,P={file__image_input:'input[type="file"]',title_input:"/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[2]/div[1]/div[2]/div/div/div[5]/div/div/div/label/div/input",price_input:"/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[3]/div[1]/div[2]/div/div/div[6]/div/div/div/label/div/input",brand_input:"/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[3]/div[1]/div[2]/div/div/div[9]/div/div/div[2]/div/div/div/label/div/input",description_input:"/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[3]/div[1]/div[2]/div/div/div[9]/div/div/div[3]/div/div/div/label/div/div/textarea",sku_input:"/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[3]/div[1]/div[2]/div/div/div[9]/div/div/div[6]/div/div/div[1]/label/div/input",category_select:{wraper:"/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[3]/div[1]/div[2]/div/div/div[7]/div/div/div/div",container:"/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[2]/div/div/div[1]/div[1]/div/div/div/div/div/span/div"},condition_select:{wraper:"/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[3]/div[1]/div[2]/div/div/div[8]/div/div/div/div",container:"/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[2]/div/div/div[1]/div[1]/div/div/div/div/div[1]/div"},tags_input:{input:"/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[3]/div[1]/div[2]/div/div/div[9]/div/div/div[5]/div/div/div/div[1]/label/div/div/div[2]/div/textarea"},location_select:{input:"/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[3]/div[1]/div[2]/div/div/div[9]/div/div/div[7]/div/div/div/div/div/div/div/div/label/div[2]/input",wraper:"/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[3]/div[1]/div[2]/div/div/div[9]/div/div/div[7]/div/div/div/div/div/div/div/div",container:"/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[2]/div/div/div[1]/div[1]/div/ul"},next_btn:"/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[5]/div/div/div"},kn=async e=>{const t=new DataTransfer;for(const r of e.images){console.log("Base64:",r.slice(0,50)+"...");const i=y.base64ToFile(r,e.sku,y.getImageExtension(r)||"jpg");t.items.add(i)}const n=document.querySelector(P.file__image_input);n?(n.files=t.files,n.dispatchEvent(new Event("change",{bubbles:!0}))):console.error("Không tìm thấy input[type='file']")},Pe=async(e,t)=>{const n=await y.getElementByXPath(t.wraper);if(!n)throw new Error("Wrapper xpath not found");y.scrollToElement(n),y.clickByPoint(n),await S(400);const r=await y.getElementByXPath(t.container);if(!r)throw new Error("Container xpath not found");const i=Array.from(r.children).find(s=>s.textContent?.trim().toLocaleLowerCase()===e.toLocaleLowerCase());if(!i)throw new Error(`No child found with text "${e}"`);y.scrollToElement(i),await S(200),y.clickByPoint(i)},Un=async(e,{input:t,...n})=>{await y.writeToInput(e,t),await S(400);const r=await y.getElementByXPath(n.container);if(!r)throw new Error("Container xpath not found");const i=Array.from(r.children).find(s=>s.textContent?.trim().toLocaleLowerCase().includes(e.toLocaleLowerCase()));if(!i)throw new Error(`No child found with text "${e}"`);y.scrollToElement(i),await S(200),y.clickByPoint(i)},Dn=async(e,t)=>{const n=await y.getElementByXPath(t.input);if(!n)throw new Error("Input is not found");y.scrollToElement(n),await S(200);for(const r of e)y.writeToInput(r,t.input),await S(200),y.pressEnter(n)},_e=async(e,t)=>{const{data:n}=await Bn({url:"products/publist-finish/"+e.id,method:"POST",data:t});return n},jn=async()=>{const e=await y.getElementByXPath(P.next_btn);if(!e)throw new Error("Next button is not found");y.clickByPoint(e)},In=async e=>(console.log({item:e}),await S(1e3),await kn(e),await S(200),y.writeToInput(e.title,P.title_input),await S(200),y.writeToInput(String(e.price),P.price_input),await S(200),await Pe(e.category,P.category_select),await S(200),await Pe(e.condition,P.condition_select),e.brand&&(await S(200),y.writeToInput(e.brand,P.brand_input)),await S(200),await y.writeToInput(e.description,P.description_input),await S(200),await Dn(e.tags,P.tags_input),await S(200),y.writeToInput(e.sku,P.sku_input),e?.location&&(await S(200),await Un(e.location,P.location_select)),await S(200),await jn(),!0),qn=async e=>{await S(2e3),chrome.runtime.sendMessage({type:"close-tab",payload:e})},Mn=chrome.runtime.connect();Mn.onMessage.addListener(async e=>{if(e.type==="publist-event"){const t=e.payload;if(!t)return;console.log("Received new product event:",t);try{await S(2e3),await In(t)}catch(n){await _e(t,{error:n.message,published:!1})}finally{await _e(t,{published:!0}),await qn(t)}}}); diff --git a/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/data.json b/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/data.json new file mode 100644 index 0000000..3dd7396 --- /dev/null +++ b/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/data.json @@ -0,0 +1,38 @@ +[ + { + "images": ["images/1.png", "images/2.png"], + "title": "Bộ Dụng Cụ Đa Năng 18 Món", + "price": 299000, + "category": "Tools", + "condition": "new", + "brand": "Bosch", + "description": "Bộ dụng cụ đa năng 18 món chất liệu thép không gỉ, bền bỉ, tiện lợi cho gia đình và công việc sửa chữa. Bao gồm tua vít, kìm, búa, thước dây và nhiều phụ kiện khác.", + "tags": ["dụng cụ", "đa năng", "sửa chữa", "gia đình", "Bosch"], + "sku": "BOSCH-TOOLS-18", + "location": "Hanoi, Vietnam" + }, + { + "images": ["images/1.png", "images/2.png"], + "title": "Máy Khoan Pin 21V", + "price": 1250000, + "category": "Tools", + "condition": "new", + "brand": "Makita", + "description": "Máy khoan pin 21V công suất mạnh mẽ, tốc độ điều chỉnh linh hoạt, kèm 2 pin dự phòng. Phù hợp cho công việc sửa chữa và lắp ráp tại nhà hoặc công trình.", + "tags": ["máy khoan", "dụng cụ điện", "Makita", "pin sạc"], + "sku": "MAKITA-DRILL-21V", + "location": "Ho Chi Minh City, Vietnam" + }, + { + "images": ["images/1.png", "images/2.png"], + "title": "Hộp Đựng Dụng Cụ Chuyên Nghiệp", + "price": 450000, + "category": "Tools", + "condition": "new", + "brand": "Stanley", + "description": "Hộp đựng dụng cụ chuyên nghiệp chất liệu nhựa ABS cao cấp, chịu lực và chống va đập. Thiết kế nhiều ngăn giúp sắp xếp gọn gàng các loại dụng cụ cầm tay.", + "tags": ["hộp dụng cụ", "Stanley", "chuyên nghiệp", "bảo quản"], + "sku": "STANLEY-BOX-PRO", + "location": "Da Nang, Vietnam" + } +] diff --git a/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/icons/128.png b/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/icons/128.png new file mode 100644 index 0000000..c7de32f Binary files /dev/null and b/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/icons/128.png differ diff --git a/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/icons/16.png b/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/icons/16.png new file mode 100644 index 0000000..46986c5 Binary files /dev/null and b/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/icons/16.png differ diff --git a/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/icons/32.png b/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/icons/32.png new file mode 100644 index 0000000..b82bd11 Binary files /dev/null and b/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/icons/32.png differ diff --git a/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/images/1.png b/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/images/1.png new file mode 100644 index 0000000..8772d49 Binary files /dev/null and b/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/images/1.png differ diff --git a/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/images/2.png b/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/images/2.png new file mode 100644 index 0000000..cd0fd11 Binary files /dev/null and b/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/images/2.png differ diff --git a/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/manifest.json b/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/manifest.json new file mode 100644 index 0000000..796ccae --- /dev/null +++ b/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/manifest.json @@ -0,0 +1,30 @@ +{ + "manifest_version": 3, + "name": "Auto listing facebook marketplace", + "version": "1.0", + "description": "Auto listing facebook marketplace", + + "permissions": ["storage", "tabs", "alarms"], + + "host_permissions": ["https://www.facebook.com/marketplace/*"], + + "content_scripts": [ + { + "matches": ["https://www.facebook.com/marketplace/*"], + "js": ["content.js"], + "run_at": "document_idle", + "type": "module" + } + ], + "web_accessible_resources": [ + { + "resources": ["data.json", "images/*"], + "matches": [""] + } + ], + + "background": { + "service_worker": "background.js", + "type": "module" + } +} diff --git a/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/vite.svg b/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/auto-listing-facebook-marketplace/auto-listing-facebook-marketplace/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/auto-listing-facebook-marketplace/components.json b/auto-listing-facebook-marketplace/components.json new file mode 100644 index 0000000..73afbdb --- /dev/null +++ b/auto-listing-facebook-marketplace/components.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/index.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" +} \ No newline at end of file diff --git a/auto-listing-facebook-marketplace/composer-bot-extensions/background.js b/auto-listing-facebook-marketplace/composer-bot-extensions/background.js new file mode 100644 index 0000000..e5c87f3 --- /dev/null +++ b/auto-listing-facebook-marketplace/composer-bot-extensions/background.js @@ -0,0 +1 @@ +const y=Object.create(null);y.open="0";y.close="1";y.ping="2";y.pong="3";y.message="4";y.upgrade="5";y.noop="6";const S=Object.create(null);Object.keys(y).forEach(n=>{S[y[n]]=n});const I={type:"error",data:"parser error"},ee=typeof Blob=="function"||typeof Blob<"u"&&Object.prototype.toString.call(Blob)==="[object BlobConstructor]",te=typeof ArrayBuffer=="function",se=n=>typeof ArrayBuffer.isView=="function"?ArrayBuffer.isView(n):n&&n.buffer instanceof ArrayBuffer,$=({type:n,data:e},t,s)=>ee&&e instanceof Blob?t?s(e):J(e,s):te&&(e instanceof ArrayBuffer||se(e))?t?s(e):J(new Blob([e]),s):s(y[n]+(e||"")),J=(n,e)=>{const t=new FileReader;return t.onload=function(){const s=t.result.split(",")[1];e("b"+(s||""))},t.readAsDataURL(n)};function X(n){return n instanceof Uint8Array?n:n instanceof ArrayBuffer?new Uint8Array(n):new Uint8Array(n.buffer,n.byteOffset,n.byteLength)}let P;function pe(n,e){if(ee&&n.data instanceof Blob)return n.data.arrayBuffer().then(X).then(e);if(te&&(n.data instanceof ArrayBuffer||se(n.data)))return e(X(n.data));$(n,!1,t=>{P||(P=new TextEncoder),e(P.encode(t))})}const G="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",k=typeof Uint8Array>"u"?[]:new Uint8Array(256);for(let n=0;n{let e=n.length*.75,t=n.length,s,i=0,r,o,c,h;n[n.length-1]==="="&&(e--,n[n.length-2]==="="&&e--);const g=new ArrayBuffer(e),f=new Uint8Array(g);for(s=0;s>4,f[i++]=(o&15)<<4|c>>2,f[i++]=(c&3)<<6|h&63;return g},ye=typeof ArrayBuffer=="function",K=(n,e)=>{if(typeof n!="string")return{type:"message",data:ne(n,e)};const t=n.charAt(0);return t==="b"?{type:"message",data:ge(n.substring(1),e)}:S[t]?n.length>1?{type:S[t],data:n.substring(1)}:{type:S[t]}:I},ge=(n,e)=>{if(ye){const t=de(n);return ne(t,e)}else return{base64:!0,data:n}},ne=(n,e)=>{switch(e){case"blob":return n instanceof Blob?n:new Blob([n]);case"arraybuffer":default:return n instanceof ArrayBuffer?n:n.buffer}},ie="",me=(n,e)=>{const t=n.length,s=new Array(t);let i=0;n.forEach((r,o)=>{$(r,!1,c=>{s[o]=c,++i===t&&e(s.join(ie))})})},_e=(n,e)=>{const t=n.split(ie),s=[];for(let i=0;i{const s=t.length;let i;if(s<126)i=new Uint8Array(1),new DataView(i.buffer).setUint8(0,s);else if(s<65536){i=new Uint8Array(3);const r=new DataView(i.buffer);r.setUint8(0,126),r.setUint16(1,s)}else{i=new Uint8Array(9);const r=new DataView(i.buffer);r.setUint8(0,127),r.setBigUint64(1,BigInt(s))}n.data&&typeof n.data!="string"&&(i[0]|=128),e.enqueue(i),e.enqueue(t)})}})}let q;function T(n){return n.reduce((e,t)=>e+t.length,0)}function A(n,e){if(n[0].length===e)return n.shift();const t=new Uint8Array(e);let s=0;for(let i=0;iMath.pow(2,21)-1){c.enqueue(I);break}i=f*Math.pow(2,32)+g.getUint32(4),s=3}else{if(T(t)n){c.enqueue(I);break}}}})}const re=4;function u(n){if(n)return Ee(n)}function Ee(n){for(var e in u.prototype)n[e]=u.prototype[e];return n}u.prototype.on=u.prototype.addEventListener=function(n,e){return this._callbacks=this._callbacks||{},(this._callbacks["$"+n]=this._callbacks["$"+n]||[]).push(e),this};u.prototype.once=function(n,e){function t(){this.off(n,t),e.apply(this,arguments)}return t.fn=e,this.on(n,t),this};u.prototype.off=u.prototype.removeListener=u.prototype.removeAllListeners=u.prototype.removeEventListener=function(n,e){if(this._callbacks=this._callbacks||{},arguments.length==0)return this._callbacks={},this;var t=this._callbacks["$"+n];if(!t)return this;if(arguments.length==1)return delete this._callbacks["$"+n],this;for(var s,i=0;iPromise.resolve().then(e):(e,t)=>t(e,0),l=typeof self<"u"?self:typeof window<"u"?window:Function("return this")(),ve="arraybuffer";function oe(n,...e){return e.reduce((t,s)=>(n.hasOwnProperty(s)&&(t[s]=n[s]),t),{})}const ke=l.setTimeout,Te=l.clearTimeout;function L(n,e){e.useNativeTimers?(n.setTimeoutFn=ke.bind(l),n.clearTimeoutFn=Te.bind(l)):(n.setTimeoutFn=l.setTimeout.bind(l),n.clearTimeoutFn=l.clearTimeout.bind(l))}const Ae=1.33;function Re(n){return typeof n=="string"?Se(n):Math.ceil((n.byteLength||n.size)*Ae)}function Se(n){let e=0,t=0;for(let s=0,i=n.length;s=57344?t+=3:(s++,t+=4);return t}function ae(){return Date.now().toString(36).substring(3)+Math.random().toString(36).substring(2,5)}function Oe(n){let e="";for(let t in n)n.hasOwnProperty(t)&&(e.length&&(e+="&"),e+=encodeURIComponent(t)+"="+encodeURIComponent(n[t]));return e}function Ce(n){let e={},t=n.split("&");for(let s=0,i=t.length;s{this.readyState="paused",e()};if(this._polling||!this.writable){let s=0;this._polling&&(s++,this.once("pollComplete",function(){--s||t()})),this.writable||(s++,this.once("drain",function(){--s||t()}))}else t()}_poll(){this._polling=!0,this.doPoll(),this.emitReserved("poll")}onData(e){const t=s=>{if(this.readyState==="opening"&&s.type==="open"&&this.onOpen(),s.type==="close")return this.onClose({description:"transport closed by the server"}),!1;this.onPacket(s)};_e(e,this.socket.binaryType).forEach(t),this.readyState!=="closed"&&(this._polling=!1,this.emitReserved("pollComplete"),this.readyState==="open"&&this._poll())}doClose(){const e=()=>{this.write([{type:"close"}])};this.readyState==="open"?e():this.once("open",e)}write(e){this.writable=!1,me(e,t=>{this.doWrite(t,()=>{this.writable=!0,this.emitReserved("drain")})})}uri(){const e=this.opts.secure?"https":"http",t=this.query||{};return this.opts.timestampRequests!==!1&&(t[this.opts.timestampParam]=ae()),!this.supportsBinary&&!t.sid&&(t.b64=1),this.createUri(e,t)}}let ce=!1;try{ce=typeof XMLHttpRequest<"u"&&"withCredentials"in new XMLHttpRequest}catch{}const xe=ce;function Le(){}class Pe extends Ne{constructor(e){if(super(e),typeof location<"u"){const t=location.protocol==="https:";let s=location.port;s||(s=t?"443":"80"),this.xd=typeof location<"u"&&e.hostname!==location.hostname||s!==e.port}}doWrite(e,t){const s=this.request({method:"POST",data:e});s.on("success",t),s.on("error",(i,r)=>{this.onError("xhr post error",i,r)})}doPoll(){const e=this.request();e.on("data",this.onData.bind(this)),e.on("error",(t,s)=>{this.onError("xhr poll error",t,s)}),this.pollXhr=e}}class d extends u{constructor(e,t,s){super(),this.createRequest=e,L(this,s),this._opts=s,this._method=s.method||"GET",this._uri=t,this._data=s.data!==void 0?s.data:null,this._create()}_create(){var e;const t=oe(this._opts,"agent","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","autoUnref");t.xdomain=!!this._opts.xd;const s=this._xhr=this.createRequest(t);try{s.open(this._method,this._uri,!0);try{if(this._opts.extraHeaders){s.setDisableHeaderCheck&&s.setDisableHeaderCheck(!0);for(let i in this._opts.extraHeaders)this._opts.extraHeaders.hasOwnProperty(i)&&s.setRequestHeader(i,this._opts.extraHeaders[i])}}catch{}if(this._method==="POST")try{s.setRequestHeader("Content-type","text/plain;charset=UTF-8")}catch{}try{s.setRequestHeader("Accept","*/*")}catch{}(e=this._opts.cookieJar)===null||e===void 0||e.addCookies(s),"withCredentials"in s&&(s.withCredentials=this._opts.withCredentials),this._opts.requestTimeout&&(s.timeout=this._opts.requestTimeout),s.onreadystatechange=()=>{var i;s.readyState===3&&((i=this._opts.cookieJar)===null||i===void 0||i.parseCookies(s.getResponseHeader("set-cookie"))),s.readyState===4&&(s.status===200||s.status===1223?this._onLoad():this.setTimeoutFn(()=>{this._onError(typeof s.status=="number"?s.status:0)},0))},s.send(this._data)}catch(i){this.setTimeoutFn(()=>{this._onError(i)},0);return}typeof document<"u"&&(this._index=d.requestsCount++,d.requests[this._index]=this)}_onError(e){this.emitReserved("error",e,this._xhr),this._cleanup(!0)}_cleanup(e){if(!(typeof this._xhr>"u"||this._xhr===null)){if(this._xhr.onreadystatechange=Le,e)try{this._xhr.abort()}catch{}typeof document<"u"&&delete d.requests[this._index],this._xhr=null}}_onLoad(){const e=this._xhr.responseText;e!==null&&(this.emitReserved("data",e),this.emitReserved("success"),this._cleanup())}abort(){this._cleanup()}}d.requestsCount=0;d.requests={};if(typeof document<"u"){if(typeof attachEvent=="function")attachEvent("onunload",Q);else if(typeof addEventListener=="function"){const n="onpagehide"in l?"pagehide":"unload";addEventListener(n,Q,!1)}}function Q(){for(let n in d.requests)d.requests.hasOwnProperty(n)&&d.requests[n].abort()}const qe=function(){const n=he({xdomain:!1});return n&&n.responseType!==null}();class De extends Pe{constructor(e){super(e);const t=e&&e.forceBase64;this.supportsBinary=qe&&!t}request(e={}){return Object.assign(e,{xd:this.xd},this.opts),new d(he,this.uri(),e)}}function he(n){const e=n.xdomain;try{if(typeof XMLHttpRequest<"u"&&(!e||xe))return new XMLHttpRequest}catch{}if(!e)try{return new l[["Active"].concat("Object").join("X")]("Microsoft.XMLHTTP")}catch{}}const ue=typeof navigator<"u"&&typeof navigator.product=="string"&&navigator.product.toLowerCase()==="reactnative";class Ie extends W{get name(){return"websocket"}doOpen(){const e=this.uri(),t=this.opts.protocols,s=ue?{}:oe(this.opts,"agent","perMessageDeflate","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","localAddress","protocolVersion","origin","maxPayload","family","checkServerIdentity");this.opts.extraHeaders&&(s.headers=this.opts.extraHeaders);try{this.ws=this.createSocket(e,t,s)}catch(i){return this.emitReserved("error",i)}this.ws.binaryType=this.socket.binaryType,this.addEventListeners()}addEventListeners(){this.ws.onopen=()=>{this.opts.autoUnref&&this.ws._socket.unref(),this.onOpen()},this.ws.onclose=e=>this.onClose({description:"websocket connection closed",context:e}),this.ws.onmessage=e=>this.onData(e.data),this.ws.onerror=e=>this.onError("websocket error",e)}write(e){this.writable=!1;for(let t=0;t{try{this.doWrite(s,r)}catch{}i&&x(()=>{this.writable=!0,this.emitReserved("drain")},this.setTimeoutFn)})}}doClose(){typeof this.ws<"u"&&(this.ws.onerror=()=>{},this.ws.close(),this.ws=null)}uri(){const e=this.opts.secure?"wss":"ws",t=this.query||{};return this.opts.timestampRequests&&(t[this.opts.timestampParam]=ae()),this.supportsBinary||(t.b64=1),this.createUri(e,t)}}const D=l.WebSocket||l.MozWebSocket;class Ue extends Ie{createSocket(e,t,s){return ue?new D(e,t,s):t?new D(e,t):new D(e)}doWrite(e,t){this.ws.send(t)}}class Ve extends W{get name(){return"webtransport"}doOpen(){try{this._transport=new WebTransport(this.createUri("https"),this.opts.transportOptions[this.name])}catch(e){return this.emitReserved("error",e)}this._transport.closed.then(()=>{this.onClose()}).catch(e=>{this.onError("webtransport error",e)}),this._transport.ready.then(()=>{this._transport.createBidirectionalStream().then(e=>{const t=we(Number.MAX_SAFE_INTEGER,this.socket.binaryType),s=e.readable.pipeThrough(t).getReader(),i=be();i.readable.pipeTo(e.writable),this._writer=i.writable.getWriter();const r=()=>{s.read().then(({done:c,value:h})=>{c||(this.onPacket(h),r())}).catch(c=>{})};r();const o={type:"open"};this.query.sid&&(o.data=`{"sid":"${this.query.sid}"}`),this._writer.write(o).then(()=>this.onOpen())})})}write(e){this.writable=!1;for(let t=0;t{i&&x(()=>{this.writable=!0,this.emitReserved("drain")},this.setTimeoutFn)})}}doClose(){var e;(e=this._transport)===null||e===void 0||e.close()}}const Fe={websocket:Ue,webtransport:Ve,polling:De},Me=/^(?:(?![^:@\/?#]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@\/?#]*)(?::([^:@\/?#]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/,He=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"];function U(n){if(n.length>8e3)throw"URI too long";const e=n,t=n.indexOf("["),s=n.indexOf("]");t!=-1&&s!=-1&&(n=n.substring(0,t)+n.substring(t,s).replace(/:/g,";")+n.substring(s,n.length));let i=Me.exec(n||""),r={},o=14;for(;o--;)r[He[o]]=i[o]||"";return t!=-1&&s!=-1&&(r.source=e,r.host=r.host.substring(1,r.host.length-1).replace(/;/g,":"),r.authority=r.authority.replace("[","").replace("]","").replace(/;/g,":"),r.ipv6uri=!0),r.pathNames=$e(r,r.path),r.queryKey=Ke(r,r.query),r}function $e(n,e){const t=/\/{2,9}/g,s=e.replace(t,"/").split("/");return(e.slice(0,1)=="/"||e.length===0)&&s.splice(0,1),e.slice(-1)=="/"&&s.splice(s.length-1,1),s}function Ke(n,e){const t={};return e.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,function(s,i,r){i&&(t[i]=r)}),t}const V=typeof addEventListener=="function"&&typeof removeEventListener=="function",O=[];V&&addEventListener("offline",()=>{O.forEach(n=>n())},!1);class _ extends u{constructor(e,t){if(super(),this.binaryType=ve,this.writeBuffer=[],this._prevBufferLen=0,this._pingInterval=-1,this._pingTimeout=-1,this._maxPayload=-1,this._pingTimeoutTime=1/0,e&&typeof e=="object"&&(t=e,e=null),e){const s=U(e);t.hostname=s.host,t.secure=s.protocol==="https"||s.protocol==="wss",t.port=s.port,s.query&&(t.query=s.query)}else t.host&&(t.hostname=U(t.host).host);L(this,t),this.secure=t.secure!=null?t.secure:typeof location<"u"&&location.protocol==="https:",t.hostname&&!t.port&&(t.port=this.secure?"443":"80"),this.hostname=t.hostname||(typeof location<"u"?location.hostname:"localhost"),this.port=t.port||(typeof location<"u"&&location.port?location.port:this.secure?"443":"80"),this.transports=[],this._transportsByName={},t.transports.forEach(s=>{const i=s.prototype.name;this.transports.push(i),this._transportsByName[i]=s}),this.opts=Object.assign({path:"/engine.io",agent:!1,withCredentials:!1,upgrade:!0,timestampParam:"t",rememberUpgrade:!1,addTrailingSlash:!0,rejectUnauthorized:!0,perMessageDeflate:{threshold:1024},transportOptions:{},closeOnBeforeunload:!1},t),this.opts.path=this.opts.path.replace(/\/$/,"")+(this.opts.addTrailingSlash?"/":""),typeof this.opts.query=="string"&&(this.opts.query=Ce(this.opts.query)),V&&(this.opts.closeOnBeforeunload&&(this._beforeunloadEventListener=()=>{this.transport&&(this.transport.removeAllListeners(),this.transport.close())},addEventListener("beforeunload",this._beforeunloadEventListener,!1)),this.hostname!=="localhost"&&(this._offlineEventListener=()=>{this._onClose("transport close",{description:"network connection lost"})},O.push(this._offlineEventListener))),this.opts.withCredentials&&(this._cookieJar=void 0),this._open()}createTransport(e){const t=Object.assign({},this.opts.query);t.EIO=re,t.transport=e,this.id&&(t.sid=this.id);const s=Object.assign({},this.opts,{query:t,socket:this,hostname:this.hostname,secure:this.secure,port:this.port},this.opts.transportOptions[e]);return new this._transportsByName[e](s)}_open(){if(this.transports.length===0){this.setTimeoutFn(()=>{this.emitReserved("error","No transports available")},0);return}const e=this.opts.rememberUpgrade&&_.priorWebsocketSuccess&&this.transports.indexOf("websocket")!==-1?"websocket":this.transports[0];this.readyState="opening";const t=this.createTransport(e);t.open(),this.setTransport(t)}setTransport(e){this.transport&&this.transport.removeAllListeners(),this.transport=e,e.on("drain",this._onDrain.bind(this)).on("packet",this._onPacket.bind(this)).on("error",this._onError.bind(this)).on("close",t=>this._onClose("transport close",t))}onOpen(){this.readyState="open",_.priorWebsocketSuccess=this.transport.name==="websocket",this.emitReserved("open"),this.flush()}_onPacket(e){if(this.readyState==="opening"||this.readyState==="open"||this.readyState==="closing")switch(this.emitReserved("packet",e),this.emitReserved("heartbeat"),e.type){case"open":this.onHandshake(JSON.parse(e.data));break;case"ping":this._sendPacket("pong"),this.emitReserved("ping"),this.emitReserved("pong"),this._resetPingTimeout();break;case"error":const t=new Error("server error");t.code=e.data,this._onError(t);break;case"message":this.emitReserved("data",e.data),this.emitReserved("message",e.data);break}}onHandshake(e){this.emitReserved("handshake",e),this.id=e.sid,this.transport.query.sid=e.sid,this._pingInterval=e.pingInterval,this._pingTimeout=e.pingTimeout,this._maxPayload=e.maxPayload,this.onOpen(),this.readyState!=="closed"&&this._resetPingTimeout()}_resetPingTimeout(){this.clearTimeoutFn(this._pingTimeoutTimer);const e=this._pingInterval+this._pingTimeout;this._pingTimeoutTime=Date.now()+e,this._pingTimeoutTimer=this.setTimeoutFn(()=>{this._onClose("ping timeout")},e),this.opts.autoUnref&&this._pingTimeoutTimer.unref()}_onDrain(){this.writeBuffer.splice(0,this._prevBufferLen),this._prevBufferLen=0,this.writeBuffer.length===0?this.emitReserved("drain"):this.flush()}flush(){if(this.readyState!=="closed"&&this.transport.writable&&!this.upgrading&&this.writeBuffer.length){const e=this._getWritablePackets();this.transport.send(e),this._prevBufferLen=e.length,this.emitReserved("flush")}}_getWritablePackets(){if(!(this._maxPayload&&this.transport.name==="polling"&&this.writeBuffer.length>1))return this.writeBuffer;let t=1;for(let s=0;s0&&t>this._maxPayload)return this.writeBuffer.slice(0,s);t+=2}return this.writeBuffer}_hasPingExpired(){if(!this._pingTimeoutTime)return!0;const e=Date.now()>this._pingTimeoutTime;return e&&(this._pingTimeoutTime=0,x(()=>{this._onClose("ping timeout")},this.setTimeoutFn)),e}write(e,t,s){return this._sendPacket("message",e,t,s),this}send(e,t,s){return this._sendPacket("message",e,t,s),this}_sendPacket(e,t,s,i){if(typeof t=="function"&&(i=t,t=void 0),typeof s=="function"&&(i=s,s=null),this.readyState==="closing"||this.readyState==="closed")return;s=s||{},s.compress=s.compress!==!1;const r={type:e,data:t,options:s};this.emitReserved("packetCreate",r),this.writeBuffer.push(r),i&&this.once("flush",i),this.flush()}close(){const e=()=>{this._onClose("forced close"),this.transport.close()},t=()=>{this.off("upgrade",t),this.off("upgradeError",t),e()},s=()=>{this.once("upgrade",t),this.once("upgradeError",t)};return(this.readyState==="opening"||this.readyState==="open")&&(this.readyState="closing",this.writeBuffer.length?this.once("drain",()=>{this.upgrading?s():e()}):this.upgrading?s():e()),this}_onError(e){if(_.priorWebsocketSuccess=!1,this.opts.tryAllTransports&&this.transports.length>1&&this.readyState==="opening")return this.transports.shift(),this._open();this.emitReserved("error",e),this._onClose("transport error",e)}_onClose(e,t){if(this.readyState==="opening"||this.readyState==="open"||this.readyState==="closing"){if(this.clearTimeoutFn(this._pingTimeoutTimer),this.transport.removeAllListeners("close"),this.transport.close(),this.transport.removeAllListeners(),V&&(this._beforeunloadEventListener&&removeEventListener("beforeunload",this._beforeunloadEventListener,!1),this._offlineEventListener)){const s=O.indexOf(this._offlineEventListener);s!==-1&&O.splice(s,1)}this.readyState="closed",this.id=null,this.emitReserved("close",e,t),this.writeBuffer=[],this._prevBufferLen=0}}}_.protocol=re;class We extends _{constructor(){super(...arguments),this._upgrades=[]}onOpen(){if(super.onOpen(),this.readyState==="open"&&this.opts.upgrade)for(let e=0;e{s||(t.send([{type:"ping",data:"probe"}]),t.once("packet",m=>{if(!s)if(m.type==="pong"&&m.data==="probe"){if(this.upgrading=!0,this.emitReserved("upgrading",t),!t)return;_.priorWebsocketSuccess=t.name==="websocket",this.transport.pause(()=>{s||this.readyState!=="closed"&&(f(),this.setTransport(t),t.send([{type:"upgrade"}]),this.emitReserved("upgrade",t),t=null,this.upgrading=!1,this.flush())})}else{const w=new Error("probe error");w.transport=t.name,this.emitReserved("upgradeError",w)}}))};function r(){s||(s=!0,f(),t.close(),t=null)}const o=m=>{const w=new Error("probe error: "+m);w.transport=t.name,r(),this.emitReserved("upgradeError",w)};function c(){o("transport closed")}function h(){o("socket closed")}function g(m){t&&m.name!==t.name&&r()}const f=()=>{t.removeListener("open",i),t.removeListener("error",o),t.removeListener("close",c),this.off("close",h),this.off("upgrading",g)};t.once("open",i),t.once("error",o),t.once("close",c),this.once("close",h),this.once("upgrading",g),this._upgrades.indexOf("webtransport")!==-1&&e!=="webtransport"?this.setTimeoutFn(()=>{s||t.open()},200):t.open()}onHandshake(e){this._upgrades=this._filterUpgrades(e.upgrades),super.onHandshake(e)}_filterUpgrades(e){const t=[];for(let s=0;sFe[i]).filter(i=>!!i)),super(e,s)}};function ze(n,e="",t){let s=n;t=t||typeof location<"u"&&location,n==null&&(n=t.protocol+"//"+t.host),typeof n=="string"&&(n.charAt(0)==="/"&&(n.charAt(1)==="/"?n=t.protocol+n:n=t.host+n),/^(https?|wss?):\/\//.test(n)||(typeof t<"u"?n=t.protocol+"//"+n:n="https://"+n),s=U(n)),s.port||(/^(http|ws)$/.test(s.protocol)?s.port="80":/^(http|ws)s$/.test(s.protocol)&&(s.port="443")),s.path=s.path||"/";const r=s.host.indexOf(":")!==-1?"["+s.host+"]":s.host;return s.id=s.protocol+"://"+r+":"+s.port+e,s.href=s.protocol+"://"+r+(t&&t.port===s.port?"":":"+s.port),s}const Je=typeof ArrayBuffer=="function",Xe=n=>typeof ArrayBuffer.isView=="function"?ArrayBuffer.isView(n):n.buffer instanceof ArrayBuffer,fe=Object.prototype.toString,Ge=typeof Blob=="function"||typeof Blob<"u"&&fe.call(Blob)==="[object BlobConstructor]",Qe=typeof File=="function"||typeof File<"u"&&fe.call(File)==="[object FileConstructor]";function Y(n){return Je&&(n instanceof ArrayBuffer||Xe(n))||Ge&&n instanceof Blob||Qe&&n instanceof File}function C(n,e){if(!n||typeof n!="object")return!1;if(Array.isArray(n)){for(let t=0,s=n.length;t=0&&n.num{delete this.acks[e];for(let c=0;c{this.io.clearTimeoutFn(r),t.apply(this,c)};o.withError=!0,this.acks[e]=o}emitWithAck(e,...t){return new Promise((s,i)=>{const r=(o,c)=>o?i(o):s(c);r.withError=!0,t.push(r),this.emit(e,...t)})}_addToQueue(e){let t;typeof e[e.length-1]=="function"&&(t=e.pop());const s={id:this._queueSeq++,tryCount:0,pending:!1,args:e,flags:Object.assign({fromQueue:!0},this.flags)};e.push((i,...r)=>s!==this._queue[0]?void 0:(i!==null?s.tryCount>this._opts.retries&&(this._queue.shift(),t&&t(i)):(this._queue.shift(),t&&t(null,...r)),s.pending=!1,this._drainQueue())),this._queue.push(s),this._drainQueue()}_drainQueue(e=!1){if(!this.connected||this._queue.length===0)return;const t=this._queue[0];t.pending&&!e||(t.pending=!0,t.tryCount++,this.flags=t.flags,this.emit.apply(this,t.args))}packet(e){e.nsp=this.nsp,this.io._packet(e)}onopen(){typeof this.auth=="function"?this.auth(e=>{this._sendConnectPacket(e)}):this._sendConnectPacket(this.auth)}_sendConnectPacket(e){this.packet({type:a.CONNECT,data:this._pid?Object.assign({pid:this._pid,offset:this._lastOffset},e):e})}onerror(e){this.connected||this.emitReserved("connect_error",e)}onclose(e,t){this.connected=!1,delete this.id,this.emitReserved("disconnect",e,t),this._clearAcks()}_clearAcks(){Object.keys(this.acks).forEach(e=>{if(!this.sendBuffer.some(s=>String(s.id)===e)){const s=this.acks[e];delete this.acks[e],s.withError&&s.call(this,new Error("socket has been disconnected"))}})}onpacket(e){if(e.nsp===this.nsp)switch(e.type){case a.CONNECT:e.data&&e.data.sid?this.onconnect(e.data.sid,e.data.pid):this.emitReserved("connect_error",new Error("It seems you are trying to reach a Socket.IO server in v2.x with a v3.x client, but they are not compatible (more information here: https://socket.io/docs/v3/migrating-from-2-x-to-3-0/)"));break;case a.EVENT:case a.BINARY_EVENT:this.onevent(e);break;case a.ACK:case a.BINARY_ACK:this.onack(e);break;case a.DISCONNECT:this.ondisconnect();break;case a.CONNECT_ERROR:this.destroy();const s=new Error(e.data.message);s.data=e.data.data,this.emitReserved("connect_error",s);break}}onevent(e){const t=e.data||[];e.id!=null&&t.push(this.ack(e.id)),this.connected?this.emitEvent(t):this.receiveBuffer.push(Object.freeze(t))}emitEvent(e){if(this._anyListeners&&this._anyListeners.length){const t=this._anyListeners.slice();for(const s of t)s.apply(this,e)}super.emit.apply(this,e),this._pid&&e.length&&typeof e[e.length-1]=="string"&&(this._lastOffset=e[e.length-1])}ack(e){const t=this;let s=!1;return function(...i){s||(s=!0,t.packet({type:a.ACK,id:e,data:i}))}}onack(e){const t=this.acks[e.id];typeof t=="function"&&(delete this.acks[e.id],t.withError&&e.data.unshift(null),t.apply(this,e.data))}onconnect(e,t){this.id=e,this.recovered=t&&this._pid===t,this._pid=t,this.connected=!0,this.emitBuffered(),this.emitReserved("connect"),this._drainQueue(!0)}emitBuffered(){this.receiveBuffer.forEach(e=>this.emitEvent(e)),this.receiveBuffer=[],this.sendBuffer.forEach(e=>{this.notifyOutgoingListeners(e),this.packet(e)}),this.sendBuffer=[]}ondisconnect(){this.destroy(),this.onclose("io server disconnect")}destroy(){this.subs&&(this.subs.forEach(e=>e()),this.subs=void 0),this.io._destroy(this)}disconnect(){return this.connected&&this.packet({type:a.DISCONNECT}),this.destroy(),this.connected&&this.onclose("io client disconnect"),this}close(){return this.disconnect()}compress(e){return this.flags.compress=e,this}get volatile(){return this.flags.volatile=!0,this}timeout(e){return this.flags.timeout=e,this}onAny(e){return this._anyListeners=this._anyListeners||[],this._anyListeners.push(e),this}prependAny(e){return this._anyListeners=this._anyListeners||[],this._anyListeners.unshift(e),this}offAny(e){if(!this._anyListeners)return this;if(e){const t=this._anyListeners;for(let s=0;s0&&n.jitter<=1?n.jitter:0,this.attempts=0}b.prototype.duration=function(){var n=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var e=Math.random(),t=Math.floor(e*this.jitter*n);n=(Math.floor(e*10)&1)==0?n-t:n+t}return Math.min(n,this.max)|0};b.prototype.reset=function(){this.attempts=0};b.prototype.setMin=function(n){this.ms=n};b.prototype.setMax=function(n){this.max=n};b.prototype.setJitter=function(n){this.jitter=n};class H extends u{constructor(e,t){var s;super(),this.nsps={},this.subs=[],e&&typeof e=="object"&&(t=e,e=void 0),t=t||{},t.path=t.path||"/socket.io",this.opts=t,L(this,t),this.reconnection(t.reconnection!==!1),this.reconnectionAttempts(t.reconnectionAttempts||1/0),this.reconnectionDelay(t.reconnectionDelay||1e3),this.reconnectionDelayMax(t.reconnectionDelayMax||5e3),this.randomizationFactor((s=t.randomizationFactor)!==null&&s!==void 0?s:.5),this.backoff=new b({min:this.reconnectionDelay(),max:this.reconnectionDelayMax(),jitter:this.randomizationFactor()}),this.timeout(t.timeout==null?2e4:t.timeout),this._readyState="closed",this.uri=e;const i=t.parser||it;this.encoder=new i.Encoder,this.decoder=new i.Decoder,this._autoConnect=t.autoConnect!==!1,this._autoConnect&&this.open()}reconnection(e){return arguments.length?(this._reconnection=!!e,e||(this.skipReconnect=!0),this):this._reconnection}reconnectionAttempts(e){return e===void 0?this._reconnectionAttempts:(this._reconnectionAttempts=e,this)}reconnectionDelay(e){var t;return e===void 0?this._reconnectionDelay:(this._reconnectionDelay=e,(t=this.backoff)===null||t===void 0||t.setMin(e),this)}randomizationFactor(e){var t;return e===void 0?this._randomizationFactor:(this._randomizationFactor=e,(t=this.backoff)===null||t===void 0||t.setJitter(e),this)}reconnectionDelayMax(e){var t;return e===void 0?this._reconnectionDelayMax:(this._reconnectionDelayMax=e,(t=this.backoff)===null||t===void 0||t.setMax(e),this)}timeout(e){return arguments.length?(this._timeout=e,this):this._timeout}maybeReconnectOnOpen(){!this._reconnecting&&this._reconnection&&this.backoff.attempts===0&&this.reconnect()}open(e){if(~this._readyState.indexOf("open"))return this;this.engine=new Ye(this.uri,this.opts);const t=this.engine,s=this;this._readyState="opening",this.skipReconnect=!1;const i=p(t,"open",function(){s.onopen(),e&&e()}),r=c=>{this.cleanup(),this._readyState="closed",this.emitReserved("error",c),e?e(c):this.maybeReconnectOnOpen()},o=p(t,"error",r);if(this._timeout!==!1){const c=this._timeout,h=this.setTimeoutFn(()=>{i(),r(new Error("timeout")),t.close()},c);this.opts.autoUnref&&h.unref(),this.subs.push(()=>{this.clearTimeoutFn(h)})}return this.subs.push(i),this.subs.push(o),this}connect(e){return this.open(e)}onopen(){this.cleanup(),this._readyState="open",this.emitReserved("open");const e=this.engine;this.subs.push(p(e,"ping",this.onping.bind(this)),p(e,"data",this.ondata.bind(this)),p(e,"error",this.onerror.bind(this)),p(e,"close",this.onclose.bind(this)),p(this.decoder,"decoded",this.ondecoded.bind(this)))}onping(){this.emitReserved("ping")}ondata(e){try{this.decoder.add(e)}catch(t){this.onclose("parse error",t)}}ondecoded(e){x(()=>{this.emitReserved("packet",e)},this.setTimeoutFn)}onerror(e){this.emitReserved("error",e)}socket(e,t){let s=this.nsps[e];return s?this._autoConnect&&!s.active&&s.connect():(s=new le(this,e,t),this.nsps[e]=s),s}_destroy(e){const t=Object.keys(this.nsps);for(const s of t)if(this.nsps[s].active)return;this._close()}_packet(e){const t=this.encoder.encode(e);for(let s=0;se()),this.subs.length=0,this.decoder.destroy()}_close(){this.skipReconnect=!0,this._reconnecting=!1,this.onclose("forced close")}disconnect(){return this._close()}onclose(e,t){var s;this.cleanup(),(s=this.engine)===null||s===void 0||s.close(),this.backoff.reset(),this._readyState="closed",this.emitReserved("close",e,t),this._reconnection&&!this.skipReconnect&&this.reconnect()}reconnect(){if(this._reconnecting||this.skipReconnect)return this;const e=this;if(this.backoff.attempts>=this._reconnectionAttempts)this.backoff.reset(),this.emitReserved("reconnect_failed"),this._reconnecting=!1;else{const t=this.backoff.duration();this._reconnecting=!0;const s=this.setTimeoutFn(()=>{e.skipReconnect||(this.emitReserved("reconnect_attempt",e.backoff.attempts),!e.skipReconnect&&e.open(i=>{i?(e._reconnecting=!1,e.reconnect(),this.emitReserved("reconnect_error",i)):e.onreconnect()}))},t);this.opts.autoUnref&&s.unref(),this.subs.push(()=>{this.clearTimeoutFn(s)})}}onreconnect(){const e=this.backoff.attempts;this._reconnecting=!1,this.backoff.reset(),this.emitReserved("reconnect",e)}}const E={};function B(n,e){typeof n=="object"&&(e=n,n=void 0),e=e||{};const t=ze(n,e.path||"/socket.io"),s=t.source,i=t.id,r=t.path,o=E[i]&&r in E[i].nsps,c=e.forceNew||e["force new connection"]||e.multiplex===!1||o;let h;return c?h=new H(s,e):(E[i]||(E[i]=new H(s,e)),h=E[i]),t.query&&!e.query&&(e.query=t.queryKey),h.socket(t.path,e)}Object.assign(B,{Manager:H,Socket:le,io:B,connect:B});const R={GET_CONVERSATIONS:"messages.get-conversations",GET_CONVERSATION:"messages.get-conversation",SEND_MESSAGE:"messages.send-messsage",REPLY_MESSAGE:"messages.reply-messsage"};let v=null,N=[];function ot(){v||(v=B("wss://notable-recently-seagull.ngrok-free.app",{transports:["websocket"]}),chrome.runtime.onConnect.addListener(e=>{e.name==="message"&&(N.push(e),e.postMessage({type:"status",msg:"Connected to background"}),e.onDisconnect.addListener(()=>{N=N.filter(t=>t!==e)})),e.onMessage.addListener(t=>{console.log(`[${t.event}] Received from content:`,t),t.type==="socket-response"&&v?.emit(t.event,t?.data)})}),v.on("connect",()=>{console.log("✅ Socket.IO connected"),Z({type:"socket",event:"connect",msg:"Socket.IO connected"})}),[R.GET_CONVERSATIONS,R.GET_CONVERSATION,R.SEND_MESSAGE,R.REPLY_MESSAGE].forEach(e=>{v?.on(e,t=>{Z({type:"socket",event:e,data:t})})}))}function Z(n){N.forEach(e=>{try{e.postMessage(n)}catch(t){console.warn("❌ Failed to send message:",t)}})}ot(); diff --git a/auto-listing-facebook-marketplace/composer-bot-extensions/content.js b/auto-listing-facebook-marketplace/composer-bot-extensions/content.js new file mode 100644 index 0000000..7768631 --- /dev/null +++ b/auto-listing-facebook-marketplace/composer-bot-extensions/content.js @@ -0,0 +1,6 @@ +const L={GET_CONVERSATIONS:"messages.get-conversations",GET_CONVERSATION:"messages.get-conversation",RECEIVE_CONVERSATIONS:"messages.receive-conversations",RECEIVE_CONVERSATION:"messages.receive-conversation",SEND_MESSAGE:"messages.send-messsage",REPLY_MESSAGE:"messages.reply-messsage"};function ut(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var se={exports:{}},Ee;function ft(){return Ee||(Ee=1,function(t){var e=Object.prototype.hasOwnProperty,n="~";function r(){}Object.create&&(r.prototype=Object.create(null),new r().__proto__||(n=!1));function s(f,a,u){this.fn=f,this.context=a,this.once=u||!1}function i(f,a,u,d,m){if(typeof u!="function")throw new TypeError("The listener must be a function");var g=new s(u,d||f,m),p=n?n+a:a;return f._events[p]?f._events[p].fn?f._events[p]=[f._events[p],g]:f._events[p].push(g):(f._events[p]=g,f._eventsCount++),f}function o(f,a){--f._eventsCount===0?f._events=new r:delete f._events[a]}function l(){this._events=new r,this._eventsCount=0}l.prototype.eventNames=function(){var a=[],u,d;if(this._eventsCount===0)return a;for(d in u=this._events)e.call(u,d)&&a.push(n?d.slice(1):d);return Object.getOwnPropertySymbols?a.concat(Object.getOwnPropertySymbols(u)):a},l.prototype.listeners=function(a){var u=n?n+a:a,d=this._events[u];if(!d)return[];if(d.fn)return[d.fn];for(var m=0,g=d.length,p=new Array(g);mglobalThis.DOMException===void 0?new pt(t):new DOMException(t),Se=t=>{const e=t.reason===void 0?be("This operation was aborted."):t.reason;return e instanceof Error?e:be(e)};function mt(t,e){const{milliseconds:n,fallback:r,message:s,customTimers:i={setTimeout,clearTimeout}}=e;let o,l;const a=new Promise((u,d)=>{if(typeof n!="number"||Math.sign(n)!==1)throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${n}\``);if(e.signal){const{signal:g}=e;g.aborted&&d(Se(g)),l=()=>{d(Se(g))},g.addEventListener("abort",l,{once:!0})}if(n===Number.POSITIVE_INFINITY){t.then(u,d);return}const m=new De;o=i.setTimeout.call(void 0,()=>{if(r){try{u(r())}catch(g){d(g)}return}typeof t.cancel=="function"&&t.cancel(),s===!1?u():s instanceof Error?d(s):(m.message=s??`Promise timed out after ${n} milliseconds`,d(m))},n),(async()=>{try{u(await t)}catch(g){d(g)}})()}).finally(()=>{a.clear(),l&&e.signal&&e.signal.removeEventListener("abort",l)});return a.clear=()=>{i.clearTimeout.call(void 0,o),o=void 0},a}function yt(t,e,n){let r=0,s=t.length;for(;s>0;){const i=Math.trunc(s/2);let o=r+i;n(t[o],e)<=0?(r=++o,s-=i+1):s=i}return r}class gt{#e=[];enqueue(e,n){n={priority:0,...n};const r={priority:n.priority,id:n.id,run:e};if(this.size===0||this.#e[this.size-1].priority>=n.priority){this.#e.push(r);return}const s=yt(this.#e,r,(i,o)=>o.priority-i.priority);this.#e.splice(s,0,r)}setPriority(e,n){const r=this.#e.findIndex(i=>i.id===e);if(r===-1)throw new ReferenceError(`No promise function with the id "${e}" exists in the queue.`);const[s]=this.#e.splice(r,1);this.enqueue(s.run,{priority:n,id:e})}dequeue(){return this.#e.shift()?.run}filter(e){return this.#e.filter(n=>n.priority===e.priority).map(n=>n.run)}get size(){return this.#e.length}}class wt extends ht{#e;#o;#i=0;#h;#a;#p=0;#n;#c;#t;#m;#r=0;#l;#s;#y;#E=1n;timeout;constructor(e){if(super(),e={carryoverConcurrencyCount:!1,intervalCap:Number.POSITIVE_INFINITY,interval:0,concurrency:Number.POSITIVE_INFINITY,autoStart:!0,queueClass:gt,...e},!(typeof e.intervalCap=="number"&&e.intervalCap>=1))throw new TypeError(`Expected \`intervalCap\` to be a number from 1 and up, got \`${e.intervalCap?.toString()??""}\` (${typeof e.intervalCap})`);if(e.interval===void 0||!(Number.isFinite(e.interval)&&e.interval>=0))throw new TypeError(`Expected \`interval\` to be a finite number >= 0, got \`${e.interval?.toString()??""}\` (${typeof e.interval})`);this.#e=e.carryoverConcurrencyCount,this.#o=e.intervalCap===Number.POSITIVE_INFINITY||e.interval===0,this.#h=e.intervalCap,this.#a=e.interval,this.#t=new e.queueClass,this.#m=e.queueClass,this.concurrency=e.concurrency,this.timeout=e.timeout,this.#y=e.throwOnTimeout===!0,this.#s=e.autoStart===!1}get#b(){return this.#o||this.#i{this.#v()},n)),!0}return!1}#u(){if(this.#t.size===0)return this.#n&&clearInterval(this.#n),this.#n=void 0,this.emit("empty"),this.#r===0&&this.emit("idle"),!1;if(!this.#s){const e=!this.#R;if(this.#b&&this.#S){const n=this.#t.dequeue();return n?(this.emit("active"),n(),e&&this.#g(),!0):!1}}return!1}#g(){this.#o||this.#n!==void 0||(this.#n=setInterval(()=>{this.#w()},this.#a),this.#p=Date.now()+this.#a)}#w(){this.#i===0&&this.#r===0&&this.#n&&(clearInterval(this.#n),this.#n=void 0),this.#i=this.#e?this.#r:0,this.#f()}#f(){for(;this.#u(););}get concurrency(){return this.#l}set concurrency(e){if(!(typeof e=="number"&&e>=1))throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${e}\` (${typeof e})`);this.#l=e,this.#f()}async#_(e){return new Promise((n,r)=>{e.addEventListener("abort",()=>{r(e.reason)},{once:!0})})}setPriority(e,n){this.#t.setPriority(e,n)}async add(e,n={}){return n.id??=(this.#E++).toString(),n={timeout:this.timeout,throwOnTimeout:this.#y,...n},new Promise((r,s)=>{this.#t.enqueue(async()=>{this.#r++,this.#i++;try{n.signal?.throwIfAborted();let i=e({signal:n.signal});n.timeout&&(i=mt(Promise.resolve(i),{milliseconds:n.timeout})),n.signal&&(i=Promise.race([i,this.#_(n.signal)]));const o=await i;r(o),this.emit("completed",o)}catch(i){if(i instanceof De&&!n.throwOnTimeout){r();return}s(i),this.emit("error",i)}finally{this.#T()}},n),this.emit("add"),this.#u()})}async addAll(e,n){return Promise.all(e.map(async r=>this.add(r,n)))}start(){return this.#s?(this.#s=!1,this.#f(),this):this}pause(){this.#s=!0}clear(){this.#t=new this.#m}async onEmpty(){this.#t.size!==0&&await this.#d("empty")}async onSizeLessThan(e){this.#t.sizethis.#t.size{const s=()=>{n&&!n()||(this.off(e,s),r())};this.on(e,s)})}get size(){return this.#t.size}sizeBy(e){return this.#t.filter(e).length}get pending(){return this.#r}get isPaused(){return this.#s}}const $=new wt({concurrency:1});function Be(t,e){return function(){return t.apply(e,arguments)}}const{toString:Et}=Object.prototype,{getPrototypeOf:me}=Object,{iterator:Y,toStringTag:Ue}=Symbol,Q=(t=>e=>{const n=Et.call(e);return t[n]||(t[n]=n.slice(8,-1).toLowerCase())})(Object.create(null)),C=t=>(t=t.toLowerCase(),e=>Q(e)===t),Z=t=>e=>typeof e===t,{isArray:F}=Array,q=Z("undefined");function bt(t){return t!==null&&!q(t)&&t.constructor!==null&&!q(t.constructor)&&_(t.constructor.isBuffer)&&t.constructor.isBuffer(t)}const qe=C("ArrayBuffer");function St(t){let e;return typeof ArrayBuffer<"u"&&ArrayBuffer.isView?e=ArrayBuffer.isView(t):e=t&&t.buffer&&qe(t.buffer),e}const Tt=Z("string"),_=Z("function"),je=Z("number"),ee=t=>t!==null&&typeof t=="object",vt=t=>t===!0||t===!1,J=t=>{if(Q(t)!=="object")return!1;const e=me(t);return(e===null||e===Object.prototype||Object.getPrototypeOf(e)===null)&&!(Ue in t)&&!(Y in t)},Rt=C("Date"),_t=C("File"),Ot=C("Blob"),At=C("FileList"),Ct=t=>ee(t)&&_(t.pipe),xt=t=>{let e;return t&&(typeof FormData=="function"&&t instanceof FormData||_(t.append)&&((e=Q(t))==="formdata"||e==="object"&&_(t.toString)&&t.toString()==="[object FormData]"))},Nt=C("URLSearchParams"),[Pt,It,Mt,kt]=["ReadableStream","Request","Response","Headers"].map(C),Lt=t=>t.trim?t.trim():t.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"");function j(t,e,{allOwnKeys:n=!1}={}){if(t===null||typeof t>"u")return;let r,s;if(typeof t!="object"&&(t=[t]),F(t))for(r=0,s=t.length;r0;)if(s=n[r],e===s.toLowerCase())return s;return null}const I=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:global,Ve=t=>!q(t)&&t!==I;function le(){const{caseless:t}=Ve(this)&&this||{},e={},n=(r,s)=>{const i=t&&He(e,s)||s;J(e[i])&&J(r)?e[i]=le(e[i],r):J(r)?e[i]=le({},r):F(r)?e[i]=r.slice():e[i]=r};for(let r=0,s=arguments.length;r(j(e,(s,i)=>{n&&_(s)?t[i]=Be(s,n):t[i]=s},{allOwnKeys:r}),t),Dt=t=>(t.charCodeAt(0)===65279&&(t=t.slice(1)),t),Bt=(t,e,n,r)=>{t.prototype=Object.create(e.prototype,r),t.prototype.constructor=t,Object.defineProperty(t,"super",{value:e.prototype}),n&&Object.assign(t.prototype,n)},Ut=(t,e,n,r)=>{let s,i,o;const l={};if(e=e||{},t==null)return e;do{for(s=Object.getOwnPropertyNames(t),i=s.length;i-- >0;)o=s[i],(!r||r(o,t,e))&&!l[o]&&(e[o]=t[o],l[o]=!0);t=n!==!1&&me(t)}while(t&&(!n||n(t,e))&&t!==Object.prototype);return e},qt=(t,e,n)=>{t=String(t),(n===void 0||n>t.length)&&(n=t.length),n-=e.length;const r=t.indexOf(e,n);return r!==-1&&r===n},jt=t=>{if(!t)return null;if(F(t))return t;let e=t.length;if(!je(e))return null;const n=new Array(e);for(;e-- >0;)n[e]=t[e];return n},Ht=(t=>e=>t&&e instanceof t)(typeof Uint8Array<"u"&&me(Uint8Array)),Vt=(t,e)=>{const r=(t&&t[Y]).call(t);let s;for(;(s=r.next())&&!s.done;){const i=s.value;e.call(t,i[0],i[1])}},$t=(t,e)=>{let n;const r=[];for(;(n=t.exec(e))!==null;)r.push(n);return r},zt=C("HTMLFormElement"),Jt=t=>t.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g,function(n,r,s){return r.toUpperCase()+s}),Te=(({hasOwnProperty:t})=>(e,n)=>t.call(e,n))(Object.prototype),Xt=C("RegExp"),$e=(t,e)=>{const n=Object.getOwnPropertyDescriptors(t),r={};j(n,(s,i)=>{let o;(o=e(s,i,t))!==!1&&(r[i]=o||s)}),Object.defineProperties(t,r)},Kt=t=>{$e(t,(e,n)=>{if(_(t)&&["arguments","caller","callee"].indexOf(n)!==-1)return!1;const r=t[n];if(_(r)){if(e.enumerable=!1,"writable"in e){e.writable=!1;return}e.set||(e.set=()=>{throw Error("Can not rewrite read-only method '"+n+"'")})}})},Wt=(t,e)=>{const n={},r=s=>{s.forEach(i=>{n[i]=!0})};return F(t)?r(t):r(String(t).split(e)),n},Gt=()=>{},Yt=(t,e)=>t!=null&&Number.isFinite(t=+t)?t:e;function Qt(t){return!!(t&&_(t.append)&&t[Ue]==="FormData"&&t[Y])}const Zt=t=>{const e=new Array(10),n=(r,s)=>{if(ee(r)){if(e.indexOf(r)>=0)return;if(!("toJSON"in r)){e[s]=r;const i=F(r)?[]:{};return j(r,(o,l)=>{const f=n(o,s+1);!q(f)&&(i[l]=f)}),e[s]=void 0,i}}return r};return n(t,0)},en=C("AsyncFunction"),tn=t=>t&&(ee(t)||_(t))&&_(t.then)&&_(t.catch),ze=((t,e)=>t?setImmediate:e?((n,r)=>(I.addEventListener("message",({source:s,data:i})=>{s===I&&i===n&&r.length&&r.shift()()},!1),s=>{r.push(s),I.postMessage(n,"*")}))(`axios@${Math.random()}`,[]):n=>setTimeout(n))(typeof setImmediate=="function",_(I.postMessage)),nn=typeof queueMicrotask<"u"?queueMicrotask.bind(I):typeof process<"u"&&process.nextTick||ze,rn=t=>t!=null&&_(t[Y]),c={isArray:F,isArrayBuffer:qe,isBuffer:bt,isFormData:xt,isArrayBufferView:St,isString:Tt,isNumber:je,isBoolean:vt,isObject:ee,isPlainObject:J,isReadableStream:Pt,isRequest:It,isResponse:Mt,isHeaders:kt,isUndefined:q,isDate:Rt,isFile:_t,isBlob:Ot,isRegExp:Xt,isFunction:_,isStream:Ct,isURLSearchParams:Nt,isTypedArray:Ht,isFileList:At,forEach:j,merge:le,extend:Ft,trim:Lt,stripBOM:Dt,inherits:Bt,toFlatObject:Ut,kindOf:Q,kindOfTest:C,endsWith:qt,toArray:jt,forEachEntry:Vt,matchAll:$t,isHTMLForm:zt,hasOwnProperty:Te,hasOwnProp:Te,reduceDescriptors:$e,freezeMethods:Kt,toObjectSet:Wt,toCamelCase:Jt,noop:Gt,toFiniteNumber:Yt,findKey:He,global:I,isContextDefined:Ve,isSpecCompliantForm:Qt,toJSONObject:Zt,isAsyncFn:en,isThenable:tn,setImmediate:ze,asap:nn,isIterable:rn};function w(t,e,n,r,s){Error.call(this),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=new Error().stack,this.message=t,this.name="AxiosError",e&&(this.code=e),n&&(this.config=n),r&&(this.request=r),s&&(this.response=s,this.status=s.status?s.status:null)}c.inherits(w,Error,{toJSON:function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:c.toJSONObject(this.config),code:this.code,status:this.status}}});const Je=w.prototype,Xe={};["ERR_BAD_OPTION_VALUE","ERR_BAD_OPTION","ECONNABORTED","ETIMEDOUT","ERR_NETWORK","ERR_FR_TOO_MANY_REDIRECTS","ERR_DEPRECATED","ERR_BAD_RESPONSE","ERR_BAD_REQUEST","ERR_CANCELED","ERR_NOT_SUPPORT","ERR_INVALID_URL"].forEach(t=>{Xe[t]={value:t}});Object.defineProperties(w,Xe);Object.defineProperty(Je,"isAxiosError",{value:!0});w.from=(t,e,n,r,s,i)=>{const o=Object.create(Je);return c.toFlatObject(t,o,function(f){return f!==Error.prototype},l=>l!=="isAxiosError"),w.call(o,t.message,e,n,r,s),o.cause=t,o.name=t.name,i&&Object.assign(o,i),o};const sn=null;function ue(t){return c.isPlainObject(t)||c.isArray(t)}function Ke(t){return c.endsWith(t,"[]")?t.slice(0,-2):t}function ve(t,e,n){return t?t.concat(e).map(function(s,i){return s=Ke(s),!n&&i?"["+s+"]":s}).join(n?".":""):e}function on(t){return c.isArray(t)&&!t.some(ue)}const an=c.toFlatObject(c,{},null,function(e){return/^is[A-Z]/.test(e)});function te(t,e,n){if(!c.isObject(t))throw new TypeError("target must be an object");e=e||new FormData,n=c.toFlatObject(n,{metaTokens:!0,dots:!1,indexes:!1},!1,function(y,h){return!c.isUndefined(h[y])});const r=n.metaTokens,s=n.visitor||u,i=n.dots,o=n.indexes,f=(n.Blob||typeof Blob<"u"&&Blob)&&c.isSpecCompliantForm(e);if(!c.isFunction(s))throw new TypeError("visitor must be a function");function a(p){if(p===null)return"";if(c.isDate(p))return p.toISOString();if(c.isBoolean(p))return p.toString();if(!f&&c.isBlob(p))throw new w("Blob is not supported. Use a Buffer instead.");return c.isArrayBuffer(p)||c.isTypedArray(p)?f&&typeof Blob=="function"?new Blob([p]):Buffer.from(p):p}function u(p,y,h){let b=p;if(p&&!h&&typeof p=="object"){if(c.endsWith(y,"{}"))y=r?y:y.slice(0,-2),p=JSON.stringify(p);else if(c.isArray(p)&&on(p)||(c.isFileList(p)||c.endsWith(y,"[]"))&&(b=c.toArray(p)))return y=Ke(y),b.forEach(function(E,A){!(c.isUndefined(E)||E===null)&&e.append(o===!0?ve([y],A,i):o===null?y:y+"[]",a(E))}),!1}return ue(p)?!0:(e.append(ve(h,y,i),a(p)),!1)}const d=[],m=Object.assign(an,{defaultVisitor:u,convertValue:a,isVisitable:ue});function g(p,y){if(!c.isUndefined(p)){if(d.indexOf(p)!==-1)throw Error("Circular reference detected in "+y.join("."));d.push(p),c.forEach(p,function(b,S){(!(c.isUndefined(b)||b===null)&&s.call(e,b,c.isString(S)?S.trim():S,y,m))===!0&&g(b,y?y.concat(S):[S])}),d.pop()}}if(!c.isObject(t))throw new TypeError("data must be an object");return g(t),e}function Re(t){const e={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+","%00":"\0"};return encodeURIComponent(t).replace(/[!'()~]|%20|%00/g,function(r){return e[r]})}function ye(t,e){this._pairs=[],t&&te(t,this,e)}const We=ye.prototype;We.append=function(e,n){this._pairs.push([e,n])};We.toString=function(e){const n=e?function(r){return e.call(this,r,Re)}:Re;return this._pairs.map(function(s){return n(s[0])+"="+n(s[1])},"").join("&")};function cn(t){return encodeURIComponent(t).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}function Ge(t,e,n){if(!e)return t;const r=n&&n.encode||cn;c.isFunction(n)&&(n={serialize:n});const s=n&&n.serialize;let i;if(s?i=s(e,n):i=c.isURLSearchParams(e)?e.toString():new ye(e,n).toString(r),i){const o=t.indexOf("#");o!==-1&&(t=t.slice(0,o)),t+=(t.indexOf("?")===-1?"?":"&")+i}return t}class _e{constructor(){this.handlers=[]}use(e,n,r){return this.handlers.push({fulfilled:e,rejected:n,synchronous:r?r.synchronous:!1,runWhen:r?r.runWhen:null}),this.handlers.length-1}eject(e){this.handlers[e]&&(this.handlers[e]=null)}clear(){this.handlers&&(this.handlers=[])}forEach(e){c.forEach(this.handlers,function(r){r!==null&&e(r)})}}const Ye={silentJSONParsing:!0,forcedJSONParsing:!0,clarifyTimeoutError:!1},ln=typeof URLSearchParams<"u"?URLSearchParams:ye,un=typeof FormData<"u"?FormData:null,fn=typeof Blob<"u"?Blob:null,dn={isBrowser:!0,classes:{URLSearchParams:ln,FormData:un,Blob:fn},protocols:["http","https","file","blob","url","data"]},ge=typeof window<"u"&&typeof document<"u",fe=typeof navigator=="object"&&navigator||void 0,hn=ge&&(!fe||["ReactNative","NativeScript","NS"].indexOf(fe.product)<0),pn=typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope&&typeof self.importScripts=="function",mn=ge&&window.location.href||"http://localhost",yn=Object.freeze(Object.defineProperty({__proto__:null,hasBrowserEnv:ge,hasStandardBrowserEnv:hn,hasStandardBrowserWebWorkerEnv:pn,navigator:fe,origin:mn},Symbol.toStringTag,{value:"Module"})),R={...yn,...dn};function gn(t,e){return te(t,new R.classes.URLSearchParams,Object.assign({visitor:function(n,r,s,i){return R.isNode&&c.isBuffer(n)?(this.append(r,n.toString("base64")),!1):i.defaultVisitor.apply(this,arguments)}},e))}function wn(t){return c.matchAll(/\w+|\[(\w*)]/g,t).map(e=>e[0]==="[]"?"":e[1]||e[0])}function En(t){const e={},n=Object.keys(t);let r;const s=n.length;let i;for(r=0;r=n.length;return o=!o&&c.isArray(s)?s.length:o,f?(c.hasOwnProp(s,o)?s[o]=[s[o],r]:s[o]=r,!l):((!s[o]||!c.isObject(s[o]))&&(s[o]=[]),e(n,r,s[o],i)&&c.isArray(s[o])&&(s[o]=En(s[o])),!l)}if(c.isFormData(t)&&c.isFunction(t.entries)){const n={};return c.forEachEntry(t,(r,s)=>{e(wn(r),s,n,0)}),n}return null}function bn(t,e,n){if(c.isString(t))try{return(e||JSON.parse)(t),c.trim(t)}catch(r){if(r.name!=="SyntaxError")throw r}return(n||JSON.stringify)(t)}const H={transitional:Ye,adapter:["xhr","http","fetch"],transformRequest:[function(e,n){const r=n.getContentType()||"",s=r.indexOf("application/json")>-1,i=c.isObject(e);if(i&&c.isHTMLForm(e)&&(e=new FormData(e)),c.isFormData(e))return s?JSON.stringify(Qe(e)):e;if(c.isArrayBuffer(e)||c.isBuffer(e)||c.isStream(e)||c.isFile(e)||c.isBlob(e)||c.isReadableStream(e))return e;if(c.isArrayBufferView(e))return e.buffer;if(c.isURLSearchParams(e))return n.setContentType("application/x-www-form-urlencoded;charset=utf-8",!1),e.toString();let l;if(i){if(r.indexOf("application/x-www-form-urlencoded")>-1)return gn(e,this.formSerializer).toString();if((l=c.isFileList(e))||r.indexOf("multipart/form-data")>-1){const f=this.env&&this.env.FormData;return te(l?{"files[]":e}:e,f&&new f,this.formSerializer)}}return i||s?(n.setContentType("application/json",!1),bn(e)):e}],transformResponse:[function(e){const n=this.transitional||H.transitional,r=n&&n.forcedJSONParsing,s=this.responseType==="json";if(c.isResponse(e)||c.isReadableStream(e))return e;if(e&&c.isString(e)&&(r&&!this.responseType||s)){const o=!(n&&n.silentJSONParsing)&&s;try{return JSON.parse(e)}catch(l){if(o)throw l.name==="SyntaxError"?w.from(l,w.ERR_BAD_RESPONSE,this,null,this.response):l}}return e}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,maxBodyLength:-1,env:{FormData:R.classes.FormData,Blob:R.classes.Blob},validateStatus:function(e){return e>=200&&e<300},headers:{common:{Accept:"application/json, text/plain, */*","Content-Type":void 0}}};c.forEach(["delete","get","head","post","put","patch"],t=>{H.headers[t]={}});const Sn=c.toObjectSet(["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"]),Tn=t=>{const e={};let n,r,s;return t&&t.split(` +`).forEach(function(o){s=o.indexOf(":"),n=o.substring(0,s).trim().toLowerCase(),r=o.substring(s+1).trim(),!(!n||e[n]&&Sn[n])&&(n==="set-cookie"?e[n]?e[n].push(r):e[n]=[r]:e[n]=e[n]?e[n]+", "+r:r)}),e},Oe=Symbol("internals");function B(t){return t&&String(t).trim().toLowerCase()}function X(t){return t===!1||t==null?t:c.isArray(t)?t.map(X):String(t)}function vn(t){const e=Object.create(null),n=/([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g;let r;for(;r=n.exec(t);)e[r[1]]=r[2];return e}const Rn=t=>/^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(t.trim());function ie(t,e,n,r,s){if(c.isFunction(r))return r.call(this,e,n);if(s&&(e=n),!!c.isString(e)){if(c.isString(r))return e.indexOf(r)!==-1;if(c.isRegExp(r))return r.test(e)}}function _n(t){return t.trim().toLowerCase().replace(/([a-z\d])(\w*)/g,(e,n,r)=>n.toUpperCase()+r)}function On(t,e){const n=c.toCamelCase(" "+e);["get","set","has"].forEach(r=>{Object.defineProperty(t,r+n,{value:function(s,i,o){return this[r].call(this,e,s,i,o)},configurable:!0})})}let O=class{constructor(e){e&&this.set(e)}set(e,n,r){const s=this;function i(l,f,a){const u=B(f);if(!u)throw new Error("header name must be a non-empty string");const d=c.findKey(s,u);(!d||s[d]===void 0||a===!0||a===void 0&&s[d]!==!1)&&(s[d||f]=X(l))}const o=(l,f)=>c.forEach(l,(a,u)=>i(a,u,f));if(c.isPlainObject(e)||e instanceof this.constructor)o(e,n);else if(c.isString(e)&&(e=e.trim())&&!Rn(e))o(Tn(e),n);else if(c.isObject(e)&&c.isIterable(e)){let l={},f,a;for(const u of e){if(!c.isArray(u))throw TypeError("Object iterator must return a key-value pair");l[a=u[0]]=(f=l[a])?c.isArray(f)?[...f,u[1]]:[f,u[1]]:u[1]}o(l,n)}else e!=null&&i(n,e,r);return this}get(e,n){if(e=B(e),e){const r=c.findKey(this,e);if(r){const s=this[r];if(!n)return s;if(n===!0)return vn(s);if(c.isFunction(n))return n.call(this,s,r);if(c.isRegExp(n))return n.exec(s);throw new TypeError("parser must be boolean|regexp|function")}}}has(e,n){if(e=B(e),e){const r=c.findKey(this,e);return!!(r&&this[r]!==void 0&&(!n||ie(this,this[r],r,n)))}return!1}delete(e,n){const r=this;let s=!1;function i(o){if(o=B(o),o){const l=c.findKey(r,o);l&&(!n||ie(r,r[l],l,n))&&(delete r[l],s=!0)}}return c.isArray(e)?e.forEach(i):i(e),s}clear(e){const n=Object.keys(this);let r=n.length,s=!1;for(;r--;){const i=n[r];(!e||ie(this,this[i],i,e,!0))&&(delete this[i],s=!0)}return s}normalize(e){const n=this,r={};return c.forEach(this,(s,i)=>{const o=c.findKey(r,i);if(o){n[o]=X(s),delete n[i];return}const l=e?_n(i):String(i).trim();l!==i&&delete n[i],n[l]=X(s),r[l]=!0}),this}concat(...e){return this.constructor.concat(this,...e)}toJSON(e){const n=Object.create(null);return c.forEach(this,(r,s)=>{r!=null&&r!==!1&&(n[s]=e&&c.isArray(r)?r.join(", "):r)}),n}[Symbol.iterator](){return Object.entries(this.toJSON())[Symbol.iterator]()}toString(){return Object.entries(this.toJSON()).map(([e,n])=>e+": "+n).join(` +`)}getSetCookie(){return this.get("set-cookie")||[]}get[Symbol.toStringTag](){return"AxiosHeaders"}static from(e){return e instanceof this?e:new this(e)}static concat(e,...n){const r=new this(e);return n.forEach(s=>r.set(s)),r}static accessor(e){const r=(this[Oe]=this[Oe]={accessors:{}}).accessors,s=this.prototype;function i(o){const l=B(o);r[l]||(On(s,o),r[l]=!0)}return c.isArray(e)?e.forEach(i):i(e),this}};O.accessor(["Content-Type","Content-Length","Accept","Accept-Encoding","User-Agent","Authorization"]);c.reduceDescriptors(O.prototype,({value:t},e)=>{let n=e[0].toUpperCase()+e.slice(1);return{get:()=>t,set(r){this[n]=r}}});c.freezeMethods(O);function oe(t,e){const n=this||H,r=e||n,s=O.from(r.headers);let i=r.data;return c.forEach(t,function(l){i=l.call(n,i,s.normalize(),e?e.status:void 0)}),s.normalize(),i}function Ze(t){return!!(t&&t.__CANCEL__)}function D(t,e,n){w.call(this,t??"canceled",w.ERR_CANCELED,e,n),this.name="CanceledError"}c.inherits(D,w,{__CANCEL__:!0});function et(t,e,n){const r=n.config.validateStatus;!n.status||!r||r(n.status)?t(n):e(new w("Request failed with status code "+n.status,[w.ERR_BAD_REQUEST,w.ERR_BAD_RESPONSE][Math.floor(n.status/100)-4],n.config,n.request,n))}function An(t){const e=/^([-+\w]{1,25})(:?\/\/|:)/.exec(t);return e&&e[1]||""}function Cn(t,e){t=t||10;const n=new Array(t),r=new Array(t);let s=0,i=0,o;return e=e!==void 0?e:1e3,function(f){const a=Date.now(),u=r[i];o||(o=a),n[s]=f,r[s]=a;let d=i,m=0;for(;d!==s;)m+=n[d++],d=d%t;if(s=(s+1)%t,s===i&&(i=(i+1)%t),a-o{n=u,s=null,i&&(clearTimeout(i),i=null),t.apply(null,a)};return[(...a)=>{const u=Date.now(),d=u-n;d>=r?o(a,u):(s=a,i||(i=setTimeout(()=>{i=null,o(s)},r-d)))},()=>s&&o(s)]}const W=(t,e,n=3)=>{let r=0;const s=Cn(50,250);return xn(i=>{const o=i.loaded,l=i.lengthComputable?i.total:void 0,f=o-r,a=s(f),u=o<=l;r=o;const d={loaded:o,total:l,progress:l?o/l:void 0,bytes:f,rate:a||void 0,estimated:a&&l&&u?(l-o)/a:void 0,event:i,lengthComputable:l!=null,[e?"download":"upload"]:!0};t(d)},n)},Ae=(t,e)=>{const n=t!=null;return[r=>e[0]({lengthComputable:n,total:t,loaded:r}),e[1]]},Ce=t=>(...e)=>c.asap(()=>t(...e)),Nn=R.hasStandardBrowserEnv?((t,e)=>n=>(n=new URL(n,R.origin),t.protocol===n.protocol&&t.host===n.host&&(e||t.port===n.port)))(new URL(R.origin),R.navigator&&/(msie|trident)/i.test(R.navigator.userAgent)):()=>!0,Pn=R.hasStandardBrowserEnv?{write(t,e,n,r,s,i){const o=[t+"="+encodeURIComponent(e)];c.isNumber(n)&&o.push("expires="+new Date(n).toGMTString()),c.isString(r)&&o.push("path="+r),c.isString(s)&&o.push("domain="+s),i===!0&&o.push("secure"),document.cookie=o.join("; ")},read(t){const e=document.cookie.match(new RegExp("(^|;\\s*)("+t+")=([^;]*)"));return e?decodeURIComponent(e[3]):null},remove(t){this.write(t,"",Date.now()-864e5)}}:{write(){},read(){return null},remove(){}};function In(t){return/^([a-z][a-z\d+\-.]*:)?\/\//i.test(t)}function Mn(t,e){return e?t.replace(/\/?\/$/,"")+"/"+e.replace(/^\/+/,""):t}function tt(t,e,n){let r=!In(e);return t&&(r||n==!1)?Mn(t,e):e}const xe=t=>t instanceof O?{...t}:t;function k(t,e){e=e||{};const n={};function r(a,u,d,m){return c.isPlainObject(a)&&c.isPlainObject(u)?c.merge.call({caseless:m},a,u):c.isPlainObject(u)?c.merge({},u):c.isArray(u)?u.slice():u}function s(a,u,d,m){if(c.isUndefined(u)){if(!c.isUndefined(a))return r(void 0,a,d,m)}else return r(a,u,d,m)}function i(a,u){if(!c.isUndefined(u))return r(void 0,u)}function o(a,u){if(c.isUndefined(u)){if(!c.isUndefined(a))return r(void 0,a)}else return r(void 0,u)}function l(a,u,d){if(d in e)return r(a,u);if(d in t)return r(void 0,a)}const f={url:i,method:i,data:i,baseURL:o,transformRequest:o,transformResponse:o,paramsSerializer:o,timeout:o,timeoutMessage:o,withCredentials:o,withXSRFToken:o,adapter:o,responseType:o,xsrfCookieName:o,xsrfHeaderName:o,onUploadProgress:o,onDownloadProgress:o,decompress:o,maxContentLength:o,maxBodyLength:o,beforeRedirect:o,transport:o,httpAgent:o,httpsAgent:o,cancelToken:o,socketPath:o,responseEncoding:o,validateStatus:l,headers:(a,u,d)=>s(xe(a),xe(u),d,!0)};return c.forEach(Object.keys(Object.assign({},t,e)),function(u){const d=f[u]||s,m=d(t[u],e[u],u);c.isUndefined(m)&&d!==l||(n[u]=m)}),n}const nt=t=>{const e=k({},t);let{data:n,withXSRFToken:r,xsrfHeaderName:s,xsrfCookieName:i,headers:o,auth:l}=e;e.headers=o=O.from(o),e.url=Ge(tt(e.baseURL,e.url,e.allowAbsoluteUrls),t.params,t.paramsSerializer),l&&o.set("Authorization","Basic "+btoa((l.username||"")+":"+(l.password?unescape(encodeURIComponent(l.password)):"")));let f;if(c.isFormData(n)){if(R.hasStandardBrowserEnv||R.hasStandardBrowserWebWorkerEnv)o.setContentType(void 0);else if((f=o.getContentType())!==!1){const[a,...u]=f?f.split(";").map(d=>d.trim()).filter(Boolean):[];o.setContentType([a||"multipart/form-data",...u].join("; "))}}if(R.hasStandardBrowserEnv&&(r&&c.isFunction(r)&&(r=r(e)),r||r!==!1&&Nn(e.url))){const a=s&&i&&Pn.read(i);a&&o.set(s,a)}return e},kn=typeof XMLHttpRequest<"u",Ln=kn&&function(t){return new Promise(function(n,r){const s=nt(t);let i=s.data;const o=O.from(s.headers).normalize();let{responseType:l,onUploadProgress:f,onDownloadProgress:a}=s,u,d,m,g,p;function y(){g&&g(),p&&p(),s.cancelToken&&s.cancelToken.unsubscribe(u),s.signal&&s.signal.removeEventListener("abort",u)}let h=new XMLHttpRequest;h.open(s.method.toUpperCase(),s.url,!0),h.timeout=s.timeout;function b(){if(!h)return;const E=O.from("getAllResponseHeaders"in h&&h.getAllResponseHeaders()),v={data:!l||l==="text"||l==="json"?h.responseText:h.response,status:h.status,statusText:h.statusText,headers:E,config:t,request:h};et(function(P){n(P),y()},function(P){r(P),y()},v),h=null}"onloadend"in h?h.onloadend=b:h.onreadystatechange=function(){!h||h.readyState!==4||h.status===0&&!(h.responseURL&&h.responseURL.indexOf("file:")===0)||setTimeout(b)},h.onabort=function(){h&&(r(new w("Request aborted",w.ECONNABORTED,t,h)),h=null)},h.onerror=function(){r(new w("Network Error",w.ERR_NETWORK,t,h)),h=null},h.ontimeout=function(){let A=s.timeout?"timeout of "+s.timeout+"ms exceeded":"timeout exceeded";const v=s.transitional||Ye;s.timeoutErrorMessage&&(A=s.timeoutErrorMessage),r(new w(A,v.clarifyTimeoutError?w.ETIMEDOUT:w.ECONNABORTED,t,h)),h=null},i===void 0&&o.setContentType(null),"setRequestHeader"in h&&c.forEach(o.toJSON(),function(A,v){h.setRequestHeader(v,A)}),c.isUndefined(s.withCredentials)||(h.withCredentials=!!s.withCredentials),l&&l!=="json"&&(h.responseType=s.responseType),a&&([m,p]=W(a,!0),h.addEventListener("progress",m)),f&&h.upload&&([d,g]=W(f),h.upload.addEventListener("progress",d),h.upload.addEventListener("loadend",g)),(s.cancelToken||s.signal)&&(u=E=>{h&&(r(!E||E.type?new D(null,t,h):E),h.abort(),h=null)},s.cancelToken&&s.cancelToken.subscribe(u),s.signal&&(s.signal.aborted?u():s.signal.addEventListener("abort",u)));const S=An(s.url);if(S&&R.protocols.indexOf(S)===-1){r(new w("Unsupported protocol "+S+":",w.ERR_BAD_REQUEST,t));return}h.send(i||null)})},Fn=(t,e)=>{const{length:n}=t=t?t.filter(Boolean):[];if(e||n){let r=new AbortController,s;const i=function(a){if(!s){s=!0,l();const u=a instanceof Error?a:this.reason;r.abort(u instanceof w?u:new D(u instanceof Error?u.message:u))}};let o=e&&setTimeout(()=>{o=null,i(new w(`timeout ${e} of ms exceeded`,w.ETIMEDOUT))},e);const l=()=>{t&&(o&&clearTimeout(o),o=null,t.forEach(a=>{a.unsubscribe?a.unsubscribe(i):a.removeEventListener("abort",i)}),t=null)};t.forEach(a=>a.addEventListener("abort",i));const{signal:f}=r;return f.unsubscribe=()=>c.asap(l),f}},Dn=function*(t,e){let n=t.byteLength;if(n{const s=Bn(t,e);let i=0,o,l=f=>{o||(o=!0,r&&r(f))};return new ReadableStream({async pull(f){try{const{done:a,value:u}=await s.next();if(a){l(),f.close();return}let d=u.byteLength;if(n){let m=i+=d;n(m)}f.enqueue(new Uint8Array(u))}catch(a){throw l(a),a}},cancel(f){return l(f),s.return()}},{highWaterMark:2})},ne=typeof fetch=="function"&&typeof Request=="function"&&typeof Response=="function",rt=ne&&typeof ReadableStream=="function",qn=ne&&(typeof TextEncoder=="function"?(t=>e=>t.encode(e))(new TextEncoder):async t=>new Uint8Array(await new Response(t).arrayBuffer())),st=(t,...e)=>{try{return!!t(...e)}catch{return!1}},jn=rt&&st(()=>{let t=!1;const e=new Request(R.origin,{body:new ReadableStream,method:"POST",get duplex(){return t=!0,"half"}}).headers.has("Content-Type");return t&&!e}),Pe=64*1024,de=rt&&st(()=>c.isReadableStream(new Response("").body)),G={stream:de&&(t=>t.body)};ne&&(t=>{["text","arrayBuffer","blob","formData","stream"].forEach(e=>{!G[e]&&(G[e]=c.isFunction(t[e])?n=>n[e]():(n,r)=>{throw new w(`Response type '${e}' is not supported`,w.ERR_NOT_SUPPORT,r)})})})(new Response);const Hn=async t=>{if(t==null)return 0;if(c.isBlob(t))return t.size;if(c.isSpecCompliantForm(t))return(await new Request(R.origin,{method:"POST",body:t}).arrayBuffer()).byteLength;if(c.isArrayBufferView(t)||c.isArrayBuffer(t))return t.byteLength;if(c.isURLSearchParams(t)&&(t=t+""),c.isString(t))return(await qn(t)).byteLength},Vn=async(t,e)=>{const n=c.toFiniteNumber(t.getContentLength());return n??Hn(e)},$n=ne&&(async t=>{let{url:e,method:n,data:r,signal:s,cancelToken:i,timeout:o,onDownloadProgress:l,onUploadProgress:f,responseType:a,headers:u,withCredentials:d="same-origin",fetchOptions:m}=nt(t);a=a?(a+"").toLowerCase():"text";let g=Fn([s,i&&i.toAbortSignal()],o),p;const y=g&&g.unsubscribe&&(()=>{g.unsubscribe()});let h;try{if(f&&jn&&n!=="get"&&n!=="head"&&(h=await Vn(u,r))!==0){let v=new Request(e,{method:"POST",body:r,duplex:"half"}),N;if(c.isFormData(r)&&(N=v.headers.get("content-type"))&&u.setContentType(N),v.body){const[P,V]=Ae(h,W(Ce(f)));r=Ne(v.body,Pe,P,V)}}c.isString(d)||(d=d?"include":"omit");const b="credentials"in Request.prototype;p=new Request(e,{...m,signal:g,method:n.toUpperCase(),headers:u.normalize().toJSON(),body:r,duplex:"half",credentials:b?d:void 0});let S=await fetch(p,m);const E=de&&(a==="stream"||a==="response");if(de&&(l||E&&y)){const v={};["status","statusText","headers"].forEach(we=>{v[we]=S[we]});const N=c.toFiniteNumber(S.headers.get("content-length")),[P,V]=l&&Ae(N,W(Ce(l),!0))||[];S=new Response(Ne(S.body,Pe,P,()=>{V&&V(),y&&y()}),v)}a=a||"text";let A=await G[c.findKey(G,a)||"text"](S,t);return!E&&y&&y(),await new Promise((v,N)=>{et(v,N,{data:A,headers:O.from(S.headers),status:S.status,statusText:S.statusText,config:t,request:p})})}catch(b){throw y&&y(),b&&b.name==="TypeError"&&/Load failed|fetch/i.test(b.message)?Object.assign(new w("Network Error",w.ERR_NETWORK,t,p),{cause:b.cause||b}):w.from(b,b&&b.code,t,p)}}),he={http:sn,xhr:Ln,fetch:$n};c.forEach(he,(t,e)=>{if(t){try{Object.defineProperty(t,"name",{value:e})}catch{}Object.defineProperty(t,"adapterName",{value:e})}});const Ie=t=>`- ${t}`,zn=t=>c.isFunction(t)||t===null||t===!1,it={getAdapter:t=>{t=c.isArray(t)?t:[t];const{length:e}=t;let n,r;const s={};for(let i=0;i`adapter ${l} `+(f===!1?"is not supported by the environment":"is not available in the build"));let o=e?i.length>1?`since : +`+i.map(Ie).join(` +`):" "+Ie(i[0]):"as no adapter specified";throw new w("There is no suitable adapter to dispatch the request "+o,"ERR_NOT_SUPPORT")}return r},adapters:he};function ae(t){if(t.cancelToken&&t.cancelToken.throwIfRequested(),t.signal&&t.signal.aborted)throw new D(null,t)}function Me(t){return ae(t),t.headers=O.from(t.headers),t.data=oe.call(t,t.transformRequest),["post","put","patch"].indexOf(t.method)!==-1&&t.headers.setContentType("application/x-www-form-urlencoded",!1),it.getAdapter(t.adapter||H.adapter)(t).then(function(r){return ae(t),r.data=oe.call(t,t.transformResponse,r),r.headers=O.from(r.headers),r},function(r){return Ze(r)||(ae(t),r&&r.response&&(r.response.data=oe.call(t,t.transformResponse,r.response),r.response.headers=O.from(r.response.headers))),Promise.reject(r)})}const ot="1.10.0",re={};["object","boolean","number","function","string","symbol"].forEach((t,e)=>{re[t]=function(r){return typeof r===t||"a"+(e<1?"n ":" ")+t}});const ke={};re.transitional=function(e,n,r){function s(i,o){return"[Axios v"+ot+"] Transitional option '"+i+"'"+o+(r?". "+r:"")}return(i,o,l)=>{if(e===!1)throw new w(s(o," has been removed"+(n?" in "+n:"")),w.ERR_DEPRECATED);return n&&!ke[o]&&(ke[o]=!0,console.warn(s(o," has been deprecated since v"+n+" and will be removed in the near future"))),e?e(i,o,l):!0}};re.spelling=function(e){return(n,r)=>(console.warn(`${r} is likely a misspelling of ${e}`),!0)};function Jn(t,e,n){if(typeof t!="object")throw new w("options must be an object",w.ERR_BAD_OPTION_VALUE);const r=Object.keys(t);let s=r.length;for(;s-- >0;){const i=r[s],o=e[i];if(o){const l=t[i],f=l===void 0||o(l,i,t);if(f!==!0)throw new w("option "+i+" must be "+f,w.ERR_BAD_OPTION_VALUE);continue}if(n!==!0)throw new w("Unknown option "+i,w.ERR_BAD_OPTION)}}const K={assertOptions:Jn,validators:re},x=K.validators;let M=class{constructor(e){this.defaults=e||{},this.interceptors={request:new _e,response:new _e}}async request(e,n){try{return await this._request(e,n)}catch(r){if(r instanceof Error){let s={};Error.captureStackTrace?Error.captureStackTrace(s):s=new Error;const i=s.stack?s.stack.replace(/^.+\n/,""):"";try{r.stack?i&&!String(r.stack).endsWith(i.replace(/^.+\n.+\n/,""))&&(r.stack+=` +`+i):r.stack=i}catch{}}throw r}}_request(e,n){typeof e=="string"?(n=n||{},n.url=e):n=e||{},n=k(this.defaults,n);const{transitional:r,paramsSerializer:s,headers:i}=n;r!==void 0&&K.assertOptions(r,{silentJSONParsing:x.transitional(x.boolean),forcedJSONParsing:x.transitional(x.boolean),clarifyTimeoutError:x.transitional(x.boolean)},!1),s!=null&&(c.isFunction(s)?n.paramsSerializer={serialize:s}:K.assertOptions(s,{encode:x.function,serialize:x.function},!0)),n.allowAbsoluteUrls!==void 0||(this.defaults.allowAbsoluteUrls!==void 0?n.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls:n.allowAbsoluteUrls=!0),K.assertOptions(n,{baseUrl:x.spelling("baseURL"),withXsrfToken:x.spelling("withXSRFToken")},!0),n.method=(n.method||this.defaults.method||"get").toLowerCase();let o=i&&c.merge(i.common,i[n.method]);i&&c.forEach(["delete","get","head","post","put","patch","common"],p=>{delete i[p]}),n.headers=O.concat(o,i);const l=[];let f=!0;this.interceptors.request.forEach(function(y){typeof y.runWhen=="function"&&y.runWhen(n)===!1||(f=f&&y.synchronous,l.unshift(y.fulfilled,y.rejected))});const a=[];this.interceptors.response.forEach(function(y){a.push(y.fulfilled,y.rejected)});let u,d=0,m;if(!f){const p=[Me.bind(this),void 0];for(p.unshift.apply(p,l),p.push.apply(p,a),m=p.length,u=Promise.resolve(n);d{if(!r._listeners)return;let i=r._listeners.length;for(;i-- >0;)r._listeners[i](s);r._listeners=null}),this.promise.then=s=>{let i;const o=new Promise(l=>{r.subscribe(l),i=l}).then(s);return o.cancel=function(){r.unsubscribe(i)},o},e(function(i,o,l){r.reason||(r.reason=new D(i,o,l),n(r.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(e){if(this.reason){e(this.reason);return}this._listeners?this._listeners.push(e):this._listeners=[e]}unsubscribe(e){if(!this._listeners)return;const n=this._listeners.indexOf(e);n!==-1&&this._listeners.splice(n,1)}toAbortSignal(){const e=new AbortController,n=r=>{e.abort(r)};return this.subscribe(n),e.signal.unsubscribe=()=>this.unsubscribe(n),e.signal}static source(){let e;return{token:new at(function(s){e=s}),cancel:e}}};function Kn(t){return function(n){return t.apply(null,n)}}function Wn(t){return c.isObject(t)&&t.isAxiosError===!0}const pe={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511};Object.entries(pe).forEach(([t,e])=>{pe[e]=t});function ct(t){const e=new M(t),n=Be(M.prototype.request,e);return c.extend(n,M.prototype,e,{allOwnKeys:!0}),c.extend(n,e,null,{allOwnKeys:!0}),n.create=function(s){return ct(k(t,s))},n}const T=ct(H);T.Axios=M;T.CanceledError=D;T.CancelToken=Xn;T.isCancel=Ze;T.VERSION=ot;T.toFormData=te;T.AxiosError=w;T.Cancel=T.CanceledError;T.all=function(e){return Promise.all(e)};T.spread=Kn;T.isAxiosError=Wn;T.mergeConfig=k;T.AxiosHeaders=O;T.formToJSON=t=>Qe(c.isHTMLForm(t)?new FormData(t):t);T.getAdapter=it.getAdapter;T.HttpStatusCode=pe;T.default=T;const{Axios:nr,AxiosError:rr,CanceledError:sr,isCancel:ir,CancelToken:or,VERSION:ar,all:cr,Cancel:lr,isAxiosError:ur,spread:fr,toFormData:dr,AxiosHeaders:hr,HttpStatusCode:pr,formToJSON:mr,getAdapter:yr,mergeConfig:gr}=T,Le=T.create({baseURL:"https://notable-recently-seagull.ngrok-free.app/api/v1/",headers:{"Content-Type":"application/json"}});class Gn{async sendSingleMessage(e){try{const{data:n}=await Le.post("/messages",e);return console.log("[NestJS] Response (single):",n),n}catch(n){throw console.error("[NestJS] Error (single):",n),n}}async sendBulkMessages(e){try{const{data:n}=await Le.post("/messages/bulk",{data:e});return console.log("[NestJS] Response (bulk):",n),n}catch(n){throw console.error("[NestJS] Error (bulk):",n),n}}}const ce=new Gn;class Yn{MY_NAME="Apactech com";lastMessage;initialHistories=[];elTags={container_scroll:"/html/body/div[1]/div/div/div/div[5]/div[1]/div[1]/div[2]/div[1]/div[1]/div",conatainer_conversations:"/html/body/div[1]/div/div/div/div[5]/div[1]/div[1]/div[2]/div[1]/div[1]/div/div[1]",container_chat:"/html/body/div[1]/div/div/div/div[6]/div[4]/div/div[1]/div/div[1]/div/div/div/div[1]/div/div/div[4]",root_id:'[aria-selected="true"] [id^="chat-list-item"]',room_name:'[data-tid="chat-title"]',close_reply_btn:"/html/body/div[1]/div/div/div/div[6]/div[4]/div/div[1]/div/div[3]/div/div[3]/div/div[2]/div/div[2]/div/div/card/div/div/div[2]/div/div[1]/button",reply_btn:'[aria-label="Reply"]',chat_input:"/html/body/div[1]/div/div/div/div[6]/div[4]/div/div[1]/div/div[3]/div/div[3]/div/div[2]/div/div[2]/div[1]/div"};getCurrentRoomInfo(){const e=document.querySelector(this.elTags.root_id)?.id?.replace("chat-list-item_",""),n=document.querySelector(this.elTags.room_name)?.innerText;return{room_id:e,room_name:n}}_getMessageByEl(e){if(!e)return"";let n=e.innerText||"";const r=e.querySelector("img[data-gallery-src]");if(r)return r.getAttribute("data-gallery-src")||"";const i=Array.from(e.querySelectorAll("img[itemtype]")).map(o=>o.getAttribute("alt")||"").filter(Boolean);return i.length&&(n+=i.join("")),n.trim()}parseMessageElement(e,n=!1){const r=e.querySelector(n?".fui-ChatMyMessage__timestamp":".fui-ChatMessage__timestamp"),s=e.querySelector(n?".fui-ChatMyMessage__author":".fui-ChatMessage__author");if(!r)return null;const i=r.getAttribute("datetime");if(!i)return null;const o=Number.isNaN(r.id.replace("timestamp-",""))?new Date(i).getTime():Number(r.id.replace("timestamp-","")),l=document.querySelector(`#content-${o}`),{room_id:f,room_name:a}=this.getCurrentRoomInfo();return{name:s?.innerText,message:this._getMessageByEl(l),time:o,room_id:f,room_name:a,date_time:new Date(i).getTime()}}extractAllMessages(){const e=Array.from(document.querySelectorAll(".fui-ChatMyMessage")).map(r=>this.parseMessageElement(r,!0)).filter(r=>r!==null),n=Array.from(document.querySelectorAll(".fui-ChatMessage")).map(r=>this.parseMessageElement(r,!1)).filter(r=>r!==null);return console.log({myMessages:e,otherMessages:n}),[...e,...n].sort((r,s)=>r.time-s.time)}handleNewMessage(e){console.log("%c[New incoming message]","color: #007acc;",e)}async detectNewMessages(){const e=this.extractAllMessages(),n=e.findIndex(i=>i.time===this.lastMessage?.time),r=e.slice(n+1);if(r.length===0){console.log("[Monitor] No new messages...");return}const s=r[0];s.name===this.MY_NAME?(console.log("[Monitor] My new message:",s),await ce.sendSingleMessage(s)):(console.log("[Monitor] New incoming message:",s),this.handleNewMessage(s),ce.sendSingleMessage(s)),this.lastMessage=e.pop()}async start(e=1e4){console.log("[Monitor] Starting..."),this.initialHistories=this.extractAllMessages(),this.lastMessage=this.initialHistories.pop(),await ce.sendBulkMessages(this.initialHistories),setInterval(async()=>await this.detectNewMessages(),e)}async _getConversationsInfo(e=this.elTags.conatainer_conversations){const n=document.evaluate(e,document,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue;return n?Array.from(n.children).filter(i=>i.getAttribute("role")==="none").map(i=>{const o=i.id||null,l=`title-chat-list-item_${o}`,a=document.getElementById(l)?.innerText||null;let u=null;return o?.includes("@thread.skype")?u="group":o?.includes("@oneToOne.skype")?u="personal":u="group",{id:o,name:a,type:u}}):(console.log("Không tìm thấy phần tử theo XPath."),[])}async _scrollToBottomByXPath(e=this.elTags.container_scroll,n){const{maxStableRounds:r=5,delay:s=300,maxScrolls:i=100}=n||{},o=document.evaluate(e,document,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue;if(!o){console.warn("❌ Không tìm thấy phần tử với XPath:",e);return}return new Promise(l=>{let f=-1,a=0,u=0;const d=setInterval(()=>{const m=o.scrollHeight;o.scrollTop=m,m===f?a++:(a=0,f=m),u++,(a>=r||u>=i)&&(clearInterval(d),l())},s)})}async handleGetConversations(){return await this._scrollToBottomByXPath(),this._getConversationsInfo()}}class Qn{axios=null;constructor(){this.axios=T.create({baseURL:"MyCoolApp",headers:{"Content-Type":"application/json"}})}async send(e){if(!this.axios)return null;const{data:n}=await this.axios({method:"POST",url:"type",data:{message:e}});return n}}const Fe=new Qn;function z(t){return new Promise(e=>setTimeout(e,t))}class Zn{service;port;constructor(e){this.service=new Yn,this.port=e}_forceHeightObserver;getElementByXPath(e){return document.evaluate(e,document,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue}forceHeight(e,n="100px"){if(!e)return;e.style.setProperty("height",n,"important"),e.style.setProperty("resize","none","important");const r=()=>{e.style.setProperty("height",n,"important")};e.addEventListener("focus",r),e.addEventListener("input",r),e.addEventListener("blur",r);const s=new MutationObserver(()=>{e.style.setProperty("height",n,"important")});s.observe(e,{attributes:!0,attributeFilter:["style"]}),this._forceHeightObserver=s}_clickToConversation(e){const n=document.getElementById(`chat-list-item_${e}`);return n&&(n.scrollIntoView({behavior:"smooth",block:"center"}),setTimeout(()=>n.click(),200)),n?.click()}async _waitForMessagesToAppear(e=1e4){return new Promise((n,r)=>{const s=document.getElementById("chat-pane-list");let i=null;if(!s)return r(new Error("#chat-pane-list not found"));const o=()=>Array.from(s.children),l=()=>{const a=o();a.length>0&&(f.disconnect(),i&&clearTimeout(i),n(a))},f=new MutationObserver(()=>{l()});f.observe(s,{childList:!0,subtree:!0}),l(),i=setTimeout(()=>{f.disconnect(),r(new Error("Timeout waiting for chat messages to appear"))},e)})}async _waitForNewMessages(e,n=1e4){return new Promise((r,s)=>{const i=document.getElementById("chat-pane-list");if(!i)return s(new Error("#chat-pane-list not found"));const o=()=>Array.from(i.children),l=new Set(e);let f=null;const a=new MutationObserver(()=>{const d=o().filter(m=>!l.has(m));d.length>0&&(a.disconnect(),f&&clearTimeout(f),r(d))});a.observe(i,{childList:!0,subtree:!0}),f=setTimeout(()=>{a.disconnect(),s(new Error("Timeout waiting for new messages"))},n)})}async _waitToloadMessages(e=300){return new Promise(n=>{const r=document.getElementById("chat-pane-list");if(!r)throw new Error("#chat-pane-list not found");let s=null,i=[];const o=new MutationObserver(()=>{s&&clearTimeout(s),i=Array.from(r.children),s=setTimeout(()=>{o.disconnect(),n(i)},e)});o.observe(r,{childList:!0,subtree:!0,attributes:!0,characterData:!0})})}_getTypeGeo(){const e=document.querySelector(".ck-placeholder");if(e){const n=e.getBoundingClientRect();return{top:n.top,left:n.left,right:n.right,bottom:n.bottom,width:n.width,height:n.height}}return null}async _rightClickMessage(e){const n=this.service.elTags.container_chat,r=`content-${e}`,s=m=>document.evaluate(m,document,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue,i=30,o=200;let l=0,f=s(n);if(!f){console.error("Wrapper not found:",n);return}let a=f.querySelector(`#${r}`);for(;!a&&l{const s=document.evaluate(e,document,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue;s?(s.scrollIntoView({behavior:"auto",block:"center"}),setTimeout(()=>{s.click(),n(!0)},100)):(console.warn("Không tìm thấy phần tử:",e),n(!1))})}async getConversations(e){$.add(async()=>{console.log("[Queue] Handling GET_CONVERSATIONS");const n=await this.service.handleGetConversations();this.port.postMessage({type:"socket-response",event:L.RECEIVE_CONVERSATIONS,data:n})})}async getConversation(e){$.add(async()=>{if(console.log("[Queue] Handling GET_CONVERSATION"),!e.data?.id)return;const{room_id:n}=this.service.getCurrentRoomInfo();n!=e.data.id&&(this._clickToConversation(e.data.id),await this._waitForMessagesToAppear(),await this._waitToloadMessages());const r=this.service.extractAllMessages();this.port.postMessage({type:"socket-response",event:L.RECEIVE_CONVERSATION,data:r})})}async sendMessage({data:{conversation_id:e,message:n}}){$.add(async()=>{console.log("[Queue] Handling SEND_MESSAGE");const{room_id:r}=this.service.getCurrentRoomInfo();r!=e&&this._clickToConversation(e),await z(200),await Fe.send(n)})}async replyMessage({data:{conversation_id:e,message:n,time:r}}){$.add(async()=>{console.log("[Queue] Handling REPLY_MESSAGE");const{room_id:s}=this.service.getCurrentRoomInfo();s!=e&&(this._clickToConversation(e),await this._waitForMessagesToAppear(),await this._waitToloadMessages()),this._clickIfExists(this.service.elTags.close_reply_btn),await this._rightClickMessage(r);const i=document.querySelector(this.service.elTags.reply_btn);i&&i.click(),await z(200),console.log({message:n}),await Fe.send(n)})}fixedHeightChatInput(e=20,n=1e3){(()=>{const s=this.getElementByXPath(this.service.elTags.chat_input);s?(this.forceHeight(s,"100px"),console.log("✔ Fixed height applied to chat input")):e>0?setTimeout(()=>this.fixedHeightChatInput(e-1,n),n):console.warn("✘ Element not found with provided XPath after retries")})()}}const lt=chrome.runtime.connect({name:"message"}),U=new Zn(lt);lt.onMessage.addListener(t=>{if(console.log({msg:t}),U.fixedHeightChatInput(),t.type==="socket")switch(t.event){case L.GET_CONVERSATIONS:{U.getConversations(t);break}case L.GET_CONVERSATION:{U.getConversation(t);break}case L.SEND_MESSAGE:{U.sendMessage(t);break}case L.REPLY_MESSAGE:{U.replyMessage(t);break}}}); diff --git a/auto-listing-facebook-marketplace/composer-bot-extensions/icons/128.png b/auto-listing-facebook-marketplace/composer-bot-extensions/icons/128.png new file mode 100644 index 0000000..c7de32f Binary files /dev/null and b/auto-listing-facebook-marketplace/composer-bot-extensions/icons/128.png differ diff --git a/auto-listing-facebook-marketplace/composer-bot-extensions/icons/16.png b/auto-listing-facebook-marketplace/composer-bot-extensions/icons/16.png new file mode 100644 index 0000000..46986c5 Binary files /dev/null and b/auto-listing-facebook-marketplace/composer-bot-extensions/icons/16.png differ diff --git a/auto-listing-facebook-marketplace/composer-bot-extensions/icons/32.png b/auto-listing-facebook-marketplace/composer-bot-extensions/icons/32.png new file mode 100644 index 0000000..b82bd11 Binary files /dev/null and b/auto-listing-facebook-marketplace/composer-bot-extensions/icons/32.png differ diff --git a/auto-listing-facebook-marketplace/composer-bot-extensions/manifest.json b/auto-listing-facebook-marketplace/composer-bot-extensions/manifest.json new file mode 100644 index 0000000..f9aa4dc --- /dev/null +++ b/auto-listing-facebook-marketplace/composer-bot-extensions/manifest.json @@ -0,0 +1,38 @@ +{ + "manifest_version": 3, + "name": "Composer Bot", + "version": "1.0", + "description": "Composer Bot", + + "action": { + "default_icon": { + "16": "icons/16.png", + "32": "icons/32.png", + "128": "icons/128.png" + } + }, + + "permissions": ["storage", "tabs", "alarms"], + + "host_permissions": ["https://teams.live.com/*"], + + "content_scripts": [ + { + "matches": ["https://teams.live.com/*"], + "js": ["content.js"], + "run_at": "document_idle", + "type": "module" + } + ], + + "background": { + "service_worker": "background.js", + "type": "module" + }, + + "icons": { + "16": "icons/16.png", + "32": "icons/32.png", + "128": "icons/128.png" + } +} diff --git a/auto-listing-facebook-marketplace/composer-bot-extensions/vite.svg b/auto-listing-facebook-marketplace/composer-bot-extensions/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/auto-listing-facebook-marketplace/composer-bot-extensions/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/auto-listing-facebook-marketplace/eslint.config.js b/auto-listing-facebook-marketplace/eslint.config.js new file mode 100644 index 0000000..d94e7de --- /dev/null +++ b/auto-listing-facebook-marketplace/eslint.config.js @@ -0,0 +1,23 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' +import { globalIgnores } from 'eslint/config' + +export default tseslint.config([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + js.configs.recommended, + tseslint.configs.recommended, + reactHooks.configs['recommended-latest'], + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + }, +]) diff --git a/auto-listing-facebook-marketplace/index.html b/auto-listing-facebook-marketplace/index.html new file mode 100644 index 0000000..e0d1c84 --- /dev/null +++ b/auto-listing-facebook-marketplace/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + React + TS + + +
+ + + diff --git a/auto-listing-facebook-marketplace/package-lock.json b/auto-listing-facebook-marketplace/package-lock.json new file mode 100644 index 0000000..fbcdd39 --- /dev/null +++ b/auto-listing-facebook-marketplace/package-lock.json @@ -0,0 +1,4379 @@ +{ + "name": "re-make-bid-extension", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "re-make-bid-extension", + "version": "0.0.0", + "dependencies": { + "axios": "^1.10.0", + "class-variance-authority": "^0.7.1", + "date-fns": "^4.1.0", + "next-themes": "^0.4.6", + "p-queue": "^8.1.0", + "react": "^19.1.0", + "react-dom": "^19.1.0", + "socket.io-client": "^4.8.1" + }, + "devDependencies": { + "@eslint/js": "^9.30.1", + "@types/chrome": "^0.1.0", + "@types/node": "^24.0.13", + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "eslint": "^9.30.1", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.3.0", + "typescript": "~5.8.3", + "typescript-eslint": "^8.35.1", + "vite": "^7.0.4", + "vite-plugin-static-copy": "^3.1.1" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", + "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", + "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.27.3", + "@babel/helpers": "^7.27.6", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz", + "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.0", + "@babel/types": "^7.28.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", + "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz", + "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", + "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.1", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.1.tgz", + "integrity": "sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.6.tgz", + "integrity": "sha512-ShbM/3XxwuxjFiuVBHA+d3j5dyac0aEVVq1oluIDf71hUw0aRF59dV/efUsIwFnR6m8JNM2FjZOzmaZ8yG61kw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.6.tgz", + "integrity": "sha512-S8ToEOVfg++AU/bHwdksHNnyLyVM+eMVAOf6yRKFitnwnbwwPNqKr3srzFRe7nzV69RQKb5DgchIX5pt3L53xg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.6.tgz", + "integrity": "sha512-hd5zdUarsK6strW+3Wxi5qWws+rJhCCbMiC9QZyzoxfk5uHRIE8T287giQxzVpEvCwuJ9Qjg6bEjcRJcgfLqoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.6.tgz", + "integrity": "sha512-0Z7KpHSr3VBIO9A/1wcT3NTy7EB4oNC4upJ5ye3R7taCc2GUdeynSLArnon5G8scPwaU866d3H4BCrE5xLW25A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.6.tgz", + "integrity": "sha512-FFCssz3XBavjxcFxKsGy2DYK5VSvJqa6y5HXljKzhRZ87LvEi13brPrf/wdyl/BbpbMKJNOr1Sd0jtW4Ge1pAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.6.tgz", + "integrity": "sha512-GfXs5kry/TkGM2vKqK2oyiLFygJRqKVhawu3+DOCk7OxLy/6jYkWXhlHwOoTb0WqGnWGAS7sooxbZowy+pK9Yg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.6.tgz", + "integrity": "sha512-aoLF2c3OvDn2XDTRvn8hN6DRzVVpDlj2B/F66clWd/FHLiHaG3aVZjxQX2DYphA5y/evbdGvC6Us13tvyt4pWg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.6.tgz", + "integrity": "sha512-2SkqTjTSo2dYi/jzFbU9Plt1vk0+nNg8YC8rOXXea+iA3hfNJWebKYPs3xnOUf9+ZWhKAaxnQNUf2X9LOpeiMQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.6.tgz", + "integrity": "sha512-SZHQlzvqv4Du5PrKE2faN0qlbsaW/3QQfUUc6yO2EjFcA83xnwm91UbEEVx4ApZ9Z5oG8Bxz4qPE+HFwtVcfyw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.6.tgz", + "integrity": "sha512-b967hU0gqKd9Drsh/UuAm21Khpoh6mPBSgz8mKRq4P5mVK8bpA+hQzmm/ZwGVULSNBzKdZPQBRT3+WuVavcWsQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.6.tgz", + "integrity": "sha512-aHWdQ2AAltRkLPOsKdi3xv0mZ8fUGPdlKEjIEhxCPm5yKEThcUjHpWB1idN74lfXGnZ5SULQSgtr5Qos5B0bPw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.6.tgz", + "integrity": "sha512-VgKCsHdXRSQ7E1+QXGdRPlQ/e08bN6WMQb27/TMfV+vPjjTImuT9PmLXupRlC90S1JeNNW5lzkAEO/McKeJ2yg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.6.tgz", + "integrity": "sha512-WViNlpivRKT9/py3kCmkHnn44GkGXVdXfdc4drNmRl15zVQ2+D2uFwdlGh6IuK5AAnGTo2qPB1Djppj+t78rzw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.6.tgz", + "integrity": "sha512-wyYKZ9NTdmAMb5730I38lBqVu6cKl4ZfYXIs31Baf8aoOtB4xSGi3THmDYt4BTFHk7/EcVixkOV2uZfwU3Q2Jw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.6.tgz", + "integrity": "sha512-KZh7bAGGcrinEj4qzilJ4hqTY3Dg2U82c8bv+e1xqNqZCrCyc+TL9AUEn5WGKDzm3CfC5RODE/qc96OcbIe33w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.6.tgz", + "integrity": "sha512-9N1LsTwAuE9oj6lHMyyAM+ucxGiVnEqUdp4v7IaMmrwb06ZTEVCIs3oPPplVsnjPfyjmxwHxHMF8b6vzUVAUGw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.6.tgz", + "integrity": "sha512-A6bJB41b4lKFWRKNrWoP2LHsjVzNiaurf7wyj/XtFNTsnPuxwEBWHLty+ZE0dWBKuSK1fvKgrKaNjBS7qbFKig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.6.tgz", + "integrity": "sha512-IjA+DcwoVpjEvyxZddDqBY+uJ2Snc6duLpjmkXm/v4xuS3H+3FkLZlDm9ZsAbF9rsfP3zeA0/ArNDORZgrxR/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.6.tgz", + "integrity": "sha512-dUXuZr5WenIDlMHdMkvDc1FAu4xdWixTCRgP7RQLBOkkGgwuuzaGSYcOpW4jFxzpzL1ejb8yF620UxAqnBrR9g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.6.tgz", + "integrity": "sha512-l8ZCvXP0tbTJ3iaqdNf3pjaOSd5ex/e6/omLIQCVBLmHTlfXW3zAxQ4fnDmPLOB1x9xrcSi/xtCWFwCZRIaEwg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.6.tgz", + "integrity": "sha512-hKrmDa0aOFOr71KQ/19JC7az1P0GWtCN1t2ahYAf4O007DHZt/dW8ym5+CUdJhQ/qkZmI1HAF8KkJbEFtCL7gw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.6.tgz", + "integrity": "sha512-+SqBcAWoB1fYKmpWoQP4pGtx+pUUC//RNYhFdbcSA16617cchuryuhOCRpPsjCblKukAckWsV+aQ3UKT/RMPcA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.6.tgz", + "integrity": "sha512-dyCGxv1/Br7MiSC42qinGL8KkG4kX0pEsdb0+TKhmJZgCUDBGmyo1/ArCjNGiOLiIAgdbWgmWgib4HoCi5t7kA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.6.tgz", + "integrity": "sha512-42QOgcZeZOvXfsCBJF5Afw73t4veOId//XD3i+/9gSkhSV6Gk3VPlWncctI+JcOyERv85FUo7RxuxGy+z8A43Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.6.tgz", + "integrity": "sha512-4AWhgXmDuYN7rJI6ORB+uU9DHLq/erBbuMoAuB4VWJTu5KtCgcKYPynF0YI1VkBNuEfjNlLrFr9KZPJzrtLkrQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.6.tgz", + "integrity": "sha512-NgJPHHbEpLQgDH2MjQu90pzW/5vvXIZ7KOnPyNBm92A6WgZ/7b6fJyUBjoumLqeOQQGqY2QjQxRo97ah4Sj0cA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz", + "integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", + "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.31.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.31.0.tgz", + "integrity": "sha512-LOm5OVt7D4qiKCqoiPbA7LWmI+tbw1VbTUowBcUMgQSuM6poJufkFkYDcQpo5KfgD39TnNySV26QjOh7VFpSyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.3.tgz", + "integrity": "sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.15.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.19", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.19.tgz", + "integrity": "sha512-3FL3mnMbPu0muGOCaKAhhFEYmqv9eTfPSJRJmANrCwtgK8VuxpsZDGK+m0LYAGoyO8+0j5uRe4PeyPDK1yA/hA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.45.0.tgz", + "integrity": "sha512-2o/FgACbji4tW1dzXOqAV15Eu7DdgbKsF2QKcxfG4xbh5iwU7yr5RRP5/U+0asQliSYv5M4o7BevlGIoSL0LXg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.45.0.tgz", + "integrity": "sha512-PSZ0SvMOjEAxwZeTx32eI/j5xSYtDCRxGu5k9zvzoY77xUNssZM+WV6HYBLROpY5CkXsbQjvz40fBb7WPwDqtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.45.0.tgz", + "integrity": "sha512-BA4yPIPssPB2aRAWzmqzQ3y2/KotkLyZukVB7j3psK/U3nVJdceo6qr9pLM2xN6iRP/wKfxEbOb1yrlZH6sYZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.45.0.tgz", + "integrity": "sha512-Pr2o0lvTwsiG4HCr43Zy9xXrHspyMvsvEw4FwKYqhli4FuLE5FjcZzuQ4cfPe0iUFCvSQG6lACI0xj74FDZKRA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.45.0.tgz", + "integrity": "sha512-lYE8LkE5h4a/+6VnnLiL14zWMPnx6wNbDG23GcYFpRW1V9hYWHAw9lBZ6ZUIrOaoK7NliF1sdwYGiVmziUF4vA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.45.0.tgz", + "integrity": "sha512-PVQWZK9sbzpvqC9Q0GlehNNSVHR+4m7+wET+7FgSnKG3ci5nAMgGmr9mGBXzAuE5SvguCKJ6mHL6vq1JaJ/gvw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.45.0.tgz", + "integrity": "sha512-hLrmRl53prCcD+YXTfNvXd776HTxNh8wPAMllusQ+amcQmtgo3V5i/nkhPN6FakW+QVLoUUr2AsbtIRPFU3xIA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.45.0.tgz", + "integrity": "sha512-XBKGSYcrkdiRRjl+8XvrUR3AosXU0NvF7VuqMsm7s5nRy+nt58ZMB19Jdp1RdqewLcaYnpk8zeVs/4MlLZEJxw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.45.0.tgz", + "integrity": "sha512-fRvZZPUiBz7NztBE/2QnCS5AtqLVhXmUOPj9IHlfGEXkapgImf4W9+FSkL8cWqoAjozyUzqFmSc4zh2ooaeF6g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.45.0.tgz", + "integrity": "sha512-Btv2WRZOcUGi8XU80XwIvzTg4U6+l6D0V6sZTrZx214nrwxw5nAi8hysaXj/mctyClWgesyuxbeLylCBNauimg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.45.0.tgz", + "integrity": "sha512-Li0emNnwtUZdLwHjQPBxn4VWztcrw/h7mgLyHiEI5Z0MhpeFGlzaiBHpSNVOMB/xucjXTTcO+dhv469Djr16KA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.45.0.tgz", + "integrity": "sha512-sB8+pfkYx2kvpDCfd63d5ScYT0Fz1LO6jIb2zLZvmK9ob2D8DeVqrmBDE0iDK8KlBVmsTNzrjr3G1xV4eUZhSw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.45.0.tgz", + "integrity": "sha512-5GQ6PFhh7E6jQm70p1aW05G2cap5zMOvO0se5JMecHeAdj5ZhWEHbJ4hiKpfi1nnnEdTauDXxPgXae/mqjow9w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.45.0.tgz", + "integrity": "sha512-N/euLsBd1rekWcuduakTo/dJw6U6sBP3eUq+RXM9RNfPuWTvG2w/WObDkIvJ2KChy6oxZmOSC08Ak2OJA0UiAA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.45.0.tgz", + "integrity": "sha512-2l9sA7d7QdikL0xQwNMO3xURBUNEWyHVHfAsHsUdq+E/pgLTUcCE+gih5PCdmyHmfTDeXUWVhqL0WZzg0nua3g==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.45.0.tgz", + "integrity": "sha512-XZdD3fEEQcwG2KrJDdEQu7NrHonPxxaV0/w2HpvINBdcqebz1aL+0vM2WFJq4DeiAVT6F5SUQas65HY5JDqoPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.45.0.tgz", + "integrity": "sha512-7ayfgvtmmWgKWBkCGg5+xTQ0r5V1owVm67zTrsEY1008L5ro7mCyGYORomARt/OquB9KY7LpxVBZes+oSniAAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.45.0.tgz", + "integrity": "sha512-B+IJgcBnE2bm93jEW5kHisqvPITs4ddLOROAcOc/diBgrEiQJJ6Qcjby75rFSmH5eMGrqJryUgJDhrfj942apQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.45.0.tgz", + "integrity": "sha512-+CXwwG66g0/FpWOnP/v1HnrGVSOygK/osUbu3wPRy8ECXjoYKjRAyfxYpDQOfghC5qPJYLPH0oN4MCOjwgdMug==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.45.0.tgz", + "integrity": "sha512-SRf1cytG7wqcHVLrBc9VtPK4pU5wxiB/lNIkNmW2ApKXIg+RpqwHfsaEK+e7eH4A1BpI6BX/aBWXxZCIrJg3uA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz", + "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/chrome": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.1.0.tgz", + "integrity": "sha512-Mq712O2Ykw+EVAC5D1wt4Ot4v2rfp7nDosmxhIMKULJAa8o7ELeO88rWzRasaB+AYnqayzfX/XSWaDKBfk1rYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/filesystem": "*", + "@types/har-format": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/filesystem": { + "version": "0.0.36", + "resolved": "https://registry.npmjs.org/@types/filesystem/-/filesystem-0.0.36.tgz", + "integrity": "sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/filewriter": "*" + } + }, + "node_modules/@types/filewriter": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/filewriter/-/filewriter-0.0.33.tgz", + "integrity": "sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/har-format": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@types/har-format/-/har-format-1.2.16.tgz", + "integrity": "sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.0.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.13.tgz", + "integrity": "sha512-Qm9OYVOFHFYg3wJoTSrz80hoec5Lia/dPp84do3X7dZvLikQvM1YpmvTBEdIr/e+U8HTkFjLHLnl78K/qjf+jQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.8.0" + } + }, + "node_modules/@types/react": { + "version": "19.1.8", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.8.tgz", + "integrity": "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.1.6", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.6.tgz", + "integrity": "sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.37.0.tgz", + "integrity": "sha512-jsuVWeIkb6ggzB+wPCsR4e6loj+rM72ohW6IBn2C+5NCvfUVY8s33iFPySSVXqtm5Hu29Ne/9bnA0JmyLmgenA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.37.0", + "@typescript-eslint/type-utils": "8.37.0", + "@typescript-eslint/utils": "8.37.0", + "@typescript-eslint/visitor-keys": "8.37.0", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.37.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.37.0.tgz", + "integrity": "sha512-kVIaQE9vrN9RLCQMQ3iyRlVJpTiDUY6woHGb30JDkfJErqrQEmtdWH3gV0PBAfGZgQXoqzXOO0T3K6ioApbbAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.37.0", + "@typescript-eslint/types": "8.37.0", + "@typescript-eslint/typescript-estree": "8.37.0", + "@typescript-eslint/visitor-keys": "8.37.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.37.0.tgz", + "integrity": "sha512-BIUXYsbkl5A1aJDdYJCBAo8rCEbAvdquQ8AnLb6z5Lp1u3x5PNgSSx9A/zqYc++Xnr/0DVpls8iQ2cJs/izTXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.37.0", + "@typescript-eslint/types": "^8.37.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.37.0.tgz", + "integrity": "sha512-0vGq0yiU1gbjKob2q691ybTg9JX6ShiVXAAfm2jGf3q0hdP6/BruaFjL/ManAR/lj05AvYCH+5bbVo0VtzmjOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.37.0", + "@typescript-eslint/visitor-keys": "8.37.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.37.0.tgz", + "integrity": "sha512-1/YHvAVTimMM9mmlPvTec9NP4bobA1RkDbMydxG8omqwJJLEW/Iy2C4adsAESIXU3WGLXFHSZUU+C9EoFWl4Zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.37.0.tgz", + "integrity": "sha512-SPkXWIkVZxhgwSwVq9rqj/4VFo7MnWwVaRNznfQDc/xPYHjXnPfLWn+4L6FF1cAz6e7dsqBeMawgl7QjUMj4Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.37.0", + "@typescript-eslint/typescript-estree": "8.37.0", + "@typescript-eslint/utils": "8.37.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.37.0.tgz", + "integrity": "sha512-ax0nv7PUF9NOVPs+lmQ7yIE7IQmAf8LGcXbMvHX5Gm+YJUYNAl340XkGnrimxZ0elXyoQJuN5sbg6C4evKA4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.37.0.tgz", + "integrity": "sha512-zuWDMDuzMRbQOM+bHyU4/slw27bAUEcKSKKs3hcv2aNnc/tvE/h7w60dwVw8vnal2Pub6RT1T7BI8tFZ1fE+yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.37.0", + "@typescript-eslint/tsconfig-utils": "8.37.0", + "@typescript-eslint/types": "8.37.0", + "@typescript-eslint/visitor-keys": "8.37.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.37.0.tgz", + "integrity": "sha512-TSFvkIW6gGjN2p6zbXo20FzCABbyUAuq6tBvNRGsKdsSQ6a7rnV6ADfZ7f4iI3lIiXc4F4WWvtUfDw9CJ9pO5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.37.0", + "@typescript-eslint/types": "8.37.0", + "@typescript-eslint/typescript-estree": "8.37.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.37.0.tgz", + "integrity": "sha512-YzfhzcTnZVPiLfP/oeKtDp2evwvHLMe0LOy7oe+hb9KKIumLNohYS9Hgp1ifwpu42YWxhZE8yieggz6JpqO/1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.37.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.6.0.tgz", + "integrity": "sha512-5Kgff+m8e2PB+9j51eGHEpn5kUzRKH2Ry0qGoe8ItJg7pqnkPrYPkDQZGgGmTa0EGarHrkjLvOdU3b1fzI8otQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.19", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz", + "integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.25.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001727", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz", + "integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.183", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.183.tgz", + "integrity": "sha512-vCrDBYjQCAEefWGjlK3EpoSKfKbT10pR4XXPdn65q7snuNOZnthoVpBfZPykmDapOKfoD+MMIPG8ZjKyyc9oHA==", + "dev": true, + "license": "ISC" + }, + "node_modules/engine.io-client": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.3.tgz", + "integrity": "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1", + "xmlhttprequest-ssl": "~2.1.1" + } + }, + "node_modules/engine.io-client/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.6.tgz", + "integrity": "sha512-GVuzuUwtdsghE3ocJ9Bs8PNoF13HNQ5TXbEi2AhvVb8xU1Iwt9Fos9FEamfoee+u/TOsn7GUWc04lz46n2bbTg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.6", + "@esbuild/android-arm": "0.25.6", + "@esbuild/android-arm64": "0.25.6", + "@esbuild/android-x64": "0.25.6", + "@esbuild/darwin-arm64": "0.25.6", + "@esbuild/darwin-x64": "0.25.6", + "@esbuild/freebsd-arm64": "0.25.6", + "@esbuild/freebsd-x64": "0.25.6", + "@esbuild/linux-arm": "0.25.6", + "@esbuild/linux-arm64": "0.25.6", + "@esbuild/linux-ia32": "0.25.6", + "@esbuild/linux-loong64": "0.25.6", + "@esbuild/linux-mips64el": "0.25.6", + "@esbuild/linux-ppc64": "0.25.6", + "@esbuild/linux-riscv64": "0.25.6", + "@esbuild/linux-s390x": "0.25.6", + "@esbuild/linux-x64": "0.25.6", + "@esbuild/netbsd-arm64": "0.25.6", + "@esbuild/netbsd-x64": "0.25.6", + "@esbuild/openbsd-arm64": "0.25.6", + "@esbuild/openbsd-x64": "0.25.6", + "@esbuild/openharmony-arm64": "0.25.6", + "@esbuild/sunos-x64": "0.25.6", + "@esbuild/win32-arm64": "0.25.6", + "@esbuild/win32-ia32": "0.25.6", + "@esbuild/win32-x64": "0.25.6" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.31.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.31.0.tgz", + "integrity": "sha512-QldCVh/ztyKJJZLr4jXNUByx3gR+TDYZCRXEktiZoUR3PGy4qCmSbkxcIle8GEwGpb5JBZazlaJ/CxLidXdEbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.0", + "@eslint/core": "^0.15.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.31.0", + "@eslint/plugin-kit": "^0.3.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.20", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.20.tgz", + "integrity": "sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz", + "integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs-extra": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", + "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.3.0.tgz", + "integrity": "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", + "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", + "dev": true, + "license": "MPL-2.0", + "optional": true, + "peer": true, + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/next-themes": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz", + "integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.3.tgz", + "integrity": "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-queue": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-8.1.0.tgz", + "integrity": "sha512-mxLDbbGIBEXTJL0zEx8JIylaj3xQ7Z/7eEVjcF9fJX4DBiH9oqe+oahYnlKKxm0Ci9TlWTyhSHgygxMxjIB2jw==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^5.0.1", + "p-timeout": "^6.1.2" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.4.tgz", + "integrity": "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", + "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", + "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.26.0" + }, + "peerDependencies": { + "react": "^19.1.0" + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.45.0.tgz", + "integrity": "sha512-WLjEcJRIo7i3WDDgOIJqVI2d+lAC3EwvOGy+Xfq6hs+GQuAA4Di/H72xmXkOhrIWFg2PFYSKZYfH0f4vfKXN4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.45.0", + "@rollup/rollup-android-arm64": "4.45.0", + "@rollup/rollup-darwin-arm64": "4.45.0", + "@rollup/rollup-darwin-x64": "4.45.0", + "@rollup/rollup-freebsd-arm64": "4.45.0", + "@rollup/rollup-freebsd-x64": "4.45.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.45.0", + "@rollup/rollup-linux-arm-musleabihf": "4.45.0", + "@rollup/rollup-linux-arm64-gnu": "4.45.0", + "@rollup/rollup-linux-arm64-musl": "4.45.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.45.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.45.0", + "@rollup/rollup-linux-riscv64-gnu": "4.45.0", + "@rollup/rollup-linux-riscv64-musl": "4.45.0", + "@rollup/rollup-linux-s390x-gnu": "4.45.0", + "@rollup/rollup-linux-x64-gnu": "4.45.0", + "@rollup/rollup-linux-x64-musl": "4.45.0", + "@rollup/rollup-win32-arm64-msvc": "4.45.0", + "@rollup/rollup-win32-ia32-msvc": "4.45.0", + "@rollup/rollup-win32-x64-msvc": "4.45.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/socket.io-client": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz", + "integrity": "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.6.1", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-client/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.37.0.tgz", + "integrity": "sha512-TnbEjzkE9EmcO0Q2zM+GE8NQLItNAJpMmED1BdgoBMYNdqMhzlbqfdSwiRlAzEK2pA9UzVW0gzaaIzXWg2BjfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.37.0", + "@typescript-eslint/parser": "8.37.0", + "@typescript-eslint/typescript-estree": "8.37.0", + "@typescript-eslint/utils": "8.37.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/undici-types": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", + "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", + "dev": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.4.tgz", + "integrity": "sha512-SkaSguuS7nnmV7mfJ8l81JGBFV7Gvzp8IzgE8A8t23+AxuNX61Q5H1Tpz5efduSN7NHC8nQXD3sKQKZAu5mNEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.6", + "picomatch": "^4.0.2", + "postcss": "^8.5.6", + "rollup": "^4.40.0", + "tinyglobby": "^0.2.14" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-plugin-static-copy": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-3.1.1.tgz", + "integrity": "sha512-oR53SkL5cX4KT1t18E/xU50vJDo0N8oaHza4EMk0Fm+2/u6nQivxavOfrDk3udWj+dizRizB/QnBvJOOQrTTAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.6.0", + "fs-extra": "^11.3.0", + "p-map": "^7.0.3", + "picocolors": "^1.1.1", + "tinyglobby": "^0.2.14" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", + "integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/auto-listing-facebook-marketplace/package.json b/auto-listing-facebook-marketplace/package.json new file mode 100644 index 0000000..81d6843 --- /dev/null +++ b/auto-listing-facebook-marketplace/package.json @@ -0,0 +1,39 @@ +{ + "name": "re-make-bid-extension", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview", + "dev:build": "vite build --watch" + }, + "dependencies": { + "axios": "^1.10.0", + "class-variance-authority": "^0.7.1", + "date-fns": "^4.1.0", + "next-themes": "^0.4.6", + "p-queue": "^8.1.0", + "react": "^19.1.0", + "react-dom": "^19.1.0", + "socket.io-client": "^4.8.1" + }, + "devDependencies": { + "@eslint/js": "^9.30.1", + "@types/chrome": "^0.1.0", + "@types/node": "^24.0.13", + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "eslint": "^9.30.1", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.3.0", + "typescript": "~5.8.3", + "typescript-eslint": "^8.35.1", + "vite": "^7.0.4", + "vite-plugin-static-copy": "^3.1.1" + } +} diff --git a/auto-listing-facebook-marketplace/public/data.json b/auto-listing-facebook-marketplace/public/data.json new file mode 100644 index 0000000..3dd7396 --- /dev/null +++ b/auto-listing-facebook-marketplace/public/data.json @@ -0,0 +1,38 @@ +[ + { + "images": ["images/1.png", "images/2.png"], + "title": "Bộ Dụng Cụ Đa Năng 18 Món", + "price": 299000, + "category": "Tools", + "condition": "new", + "brand": "Bosch", + "description": "Bộ dụng cụ đa năng 18 món chất liệu thép không gỉ, bền bỉ, tiện lợi cho gia đình và công việc sửa chữa. Bao gồm tua vít, kìm, búa, thước dây và nhiều phụ kiện khác.", + "tags": ["dụng cụ", "đa năng", "sửa chữa", "gia đình", "Bosch"], + "sku": "BOSCH-TOOLS-18", + "location": "Hanoi, Vietnam" + }, + { + "images": ["images/1.png", "images/2.png"], + "title": "Máy Khoan Pin 21V", + "price": 1250000, + "category": "Tools", + "condition": "new", + "brand": "Makita", + "description": "Máy khoan pin 21V công suất mạnh mẽ, tốc độ điều chỉnh linh hoạt, kèm 2 pin dự phòng. Phù hợp cho công việc sửa chữa và lắp ráp tại nhà hoặc công trình.", + "tags": ["máy khoan", "dụng cụ điện", "Makita", "pin sạc"], + "sku": "MAKITA-DRILL-21V", + "location": "Ho Chi Minh City, Vietnam" + }, + { + "images": ["images/1.png", "images/2.png"], + "title": "Hộp Đựng Dụng Cụ Chuyên Nghiệp", + "price": 450000, + "category": "Tools", + "condition": "new", + "brand": "Stanley", + "description": "Hộp đựng dụng cụ chuyên nghiệp chất liệu nhựa ABS cao cấp, chịu lực và chống va đập. Thiết kế nhiều ngăn giúp sắp xếp gọn gàng các loại dụng cụ cầm tay.", + "tags": ["hộp dụng cụ", "Stanley", "chuyên nghiệp", "bảo quản"], + "sku": "STANLEY-BOX-PRO", + "location": "Da Nang, Vietnam" + } +] diff --git a/auto-listing-facebook-marketplace/public/images/1.png b/auto-listing-facebook-marketplace/public/images/1.png new file mode 100644 index 0000000..8772d49 Binary files /dev/null and b/auto-listing-facebook-marketplace/public/images/1.png differ diff --git a/auto-listing-facebook-marketplace/public/images/2.png b/auto-listing-facebook-marketplace/public/images/2.png new file mode 100644 index 0000000..cd0fd11 Binary files /dev/null and b/auto-listing-facebook-marketplace/public/images/2.png differ diff --git a/auto-listing-facebook-marketplace/public/manifest.json b/auto-listing-facebook-marketplace/public/manifest.json new file mode 100644 index 0000000..796ccae --- /dev/null +++ b/auto-listing-facebook-marketplace/public/manifest.json @@ -0,0 +1,30 @@ +{ + "manifest_version": 3, + "name": "Auto listing facebook marketplace", + "version": "1.0", + "description": "Auto listing facebook marketplace", + + "permissions": ["storage", "tabs", "alarms"], + + "host_permissions": ["https://www.facebook.com/marketplace/*"], + + "content_scripts": [ + { + "matches": ["https://www.facebook.com/marketplace/*"], + "js": ["content.js"], + "run_at": "document_idle", + "type": "module" + } + ], + "web_accessible_resources": [ + { + "resources": ["data.json", "images/*"], + "matches": [""] + } + ], + + "background": { + "service_worker": "background.js", + "type": "module" + } +} diff --git a/auto-listing-facebook-marketplace/public/vite.svg b/auto-listing-facebook-marketplace/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/auto-listing-facebook-marketplace/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/auto-listing-facebook-marketplace/src/api/message-api.service.ts b/auto-listing-facebook-marketplace/src/api/message-api.service.ts new file mode 100644 index 0000000..90e7f4e --- /dev/null +++ b/auto-listing-facebook-marketplace/src/api/message-api.service.ts @@ -0,0 +1,27 @@ +import axios from "@/lib/axios"; + +class MessageApiService { + async sendSingleMessage(message: IMessage) { + try { + const { data } = await axios.post("/messages", message); + console.log("[NestJS] Response (single):", data); + return data; + } catch (err) { + console.error("[NestJS] Error (single):", err); + throw err; + } + } + + async sendBulkMessages(messages: IMessage[]) { + try { + const { data } = await axios.post("/messages/bulk", { data: messages }); + console.log("[NestJS] Response (bulk):", data); + return data; + } catch (err) { + console.error("[NestJS] Error (bulk):", err); + throw err; + } + } +} + +export const messageApi = new MessageApiService(); diff --git a/auto-listing-facebook-marketplace/src/background.ts b/auto-listing-facebook-marketplace/src/background.ts new file mode 100644 index 0000000..634b5ed --- /dev/null +++ b/auto-listing-facebook-marketplace/src/background.ts @@ -0,0 +1,63 @@ +import PQueue from "p-queue"; + +let ports: chrome.runtime.Port[] = []; +const queue = new PQueue({ concurrency: 1 }); + +chrome.runtime.onConnect.addListener((port) => { + ports.push(port); + port.onDisconnect.addListener(() => { + ports = ports.filter((p) => p !== port); + }); +}); + +(() => { + const evtSource = new EventSource( + `${import.meta.env.VITE_API_URL}/products/publist-stream` + ); + + evtSource.onmessage = (event) => { + const data = JSON.parse(event.data); + console.log("New event:", data); + queue.add(() => handlePublish(data)); + }; + + evtSource.onerror = (err) => { + console.error("EventSource failed:", err); + }; +})(); + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +async function handlePublish(data: any) { + return new Promise((resolve) => { + chrome.tabs.create( + { url: "https://www.facebook.com/marketplace/create/item", active: true }, + (tab) => { + if (!tab?.id) return resolve(); + const tabId = tab.id; + + const onConnectListener = (port: chrome.runtime.Port) => { + if (port.sender?.tab?.id === tabId) { + port.postMessage({ type: "publist-event", payload: data }); + chrome.runtime.onConnect.removeListener(onConnectListener); + } + }; + chrome.runtime.onConnect.addListener(onConnectListener); + + const onTabClosed = (closedTabId: number) => { + if (closedTabId === tabId) { + chrome.tabs.onRemoved.removeListener(onTabClosed); + resolve(); // Chỉ resolve khi tab này đã đóng + } + }; + chrome.tabs.onRemoved.addListener(onTabClosed); + } + ); + }); +} + +chrome.runtime.onMessage.addListener((message, sender) => { + if (message.type === "close-tab") { + const tabId = sender.tab?.id; + if (tabId) chrome.tabs.remove(tabId); + } +}); diff --git a/auto-listing-facebook-marketplace/src/content.ts b/auto-listing-facebook-marketplace/src/content.ts new file mode 100644 index 0000000..290529b --- /dev/null +++ b/auto-listing-facebook-marketplace/src/content.ts @@ -0,0 +1,306 @@ +// content.ts +import { delay } from "./features/app"; +import axios from "./lib/axios"; +import { thiefService } from "./services/thief.service"; + +const selectors = { + file__image_input: 'input[type="file"]', + title_input: + "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[2]/div[1]/div[2]/div/div/div[5]/div/div/div/label/div/input", + price_input: + "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[3]/div[1]/div[2]/div/div/div[6]/div/div/div/label/div/input", + brand_input: + "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[3]/div[1]/div[2]/div/div/div[9]/div/div/div[2]/div/div/div/label/div/input", + description_input: + "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[3]/div[1]/div[2]/div/div/div[9]/div/div/div[3]/div/div/div/label/div/div/textarea", + sku_input: + "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[3]/div[1]/div[2]/div/div/div[9]/div/div/div[6]/div/div/div[1]/label/div/input", + category_select: { + wraper: + "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[3]/div[1]/div[2]/div/div/div[7]/div/div/div/div", + container: + "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[2]/div/div/div[1]/div[1]/div/div/div/div/div/span/div", + }, + condition_select: { + wraper: + "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[3]/div[1]/div[2]/div/div/div[8]/div/div/div/div", + container: + "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[2]/div/div/div[1]/div[1]/div/div/div/div/div[1]/div", + }, + tags_input: { + input: + "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[3]/div[1]/div[2]/div/div/div[9]/div/div/div[5]/div/div/div/div[1]/label/div/div/div[2]/div/textarea", + plus_btn: + "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[3]/div[1]/div[2]/div/div/div[9]/div/div/div[5]/div/div/div/div[1]/label/div/div/div[2]/div[2]", + }, + + location_select: { + input: + "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[3]/div[1]/div[2]/div/div/div[9]/div/div/div[7]/div/div/div/div/div/div/div/div/label/div[2]/input", + wraper: + "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[3]/div[1]/div[2]/div/div/div[9]/div/div/div[7]/div/div/div/div/div/div/div/div", + container: + "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[2]/div/div/div[1]/div[1]/div/ul", + }, + next_btn: + "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[5]/div/div/div", + publish_btn: + "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[4]/div[2]/div/div", +}; + +const getData = async () => { + return new Promise((rev, rej) => { + const url = chrome.runtime.getURL("data.json"); + + fetch(url) + .then((res) => res.json()) + .then((data) => { + rev(data as IItem[]); + }) + .catch((err) => { + rej(err); + }); + }); +}; + +const uploadImages = async (item: IItem) => { + // Tạo DataTransfer để giả lập FileList + const dt: DataTransfer = new DataTransfer(); + + for (const image of item.images) { + // const base64 = await thiefService.imageLocalToBase64(image); + + console.log("Base64:", image.slice(0, 50) + "..."); + const file = thiefService.base64ToFile( + image, + item.sku, + thiefService.getImageExtension(image) || "jpg" + ); + + dt.items.add(file); + } + + // Tìm input file của Facebook + const input: HTMLInputElement | null = document.querySelector( + selectors.file__image_input + ); + + if (input) { + // Gán file vào input + input.files = dt.files; + + // Gửi event change + input.dispatchEvent(new Event("change", { bubbles: true })); + } else { + console.error("Không tìm thấy input[type='file']"); + } +}; + +const chooseSelect = async ( + value: string, + xpaths: { wraper: string; container: string } +) => { + const el = await thiefService.getElementByXPath(xpaths.wraper); + if (!el) throw new Error("Wrapper xpath not found"); + + thiefService.scrollToElement(el); + thiefService.clickByPoint(el); + + await delay(400); + const container = await thiefService.getElementByXPath(xpaths.container); + if (!container) throw new Error("Container xpath not found"); + + // Tìm phần tử con có nội dung giống value + const matchingChild = Array.from(container.children).find( + (child) => + child.textContent?.trim().toLocaleLowerCase() === + value.toLocaleLowerCase() + ) as HTMLElement | undefined; + + if (!matchingChild) throw new Error(`No child found with text "${value}"`); + + thiefService.scrollToElement(matchingChild); + + await delay(200); + thiefService.clickByPoint(matchingChild); +}; + +const chooseLocation = async ( + value: string, + { input, ...xpaths }: { wraper: string; container: string; input: string } +) => { + await thiefService.writeToInput(value, input); + + await delay(400); + + const container = await thiefService.getElementByXPath(xpaths.container); + if (!container) throw new Error("Container xpath not found"); + + // Tìm phần tử con có nội dung giống value + const matchingChild = Array.from(container.children).find((child) => + child.textContent + ?.trim() + .toLocaleLowerCase() + .includes(value.toLocaleLowerCase()) + ) as HTMLElement | undefined; + + if (!matchingChild) throw new Error(`No child found with text "${value}"`); + + thiefService.scrollToElement(matchingChild); + + await delay(200); + thiefService.clickByPoint(matchingChild); +}; + +const writeTags = async ( + tags: string[], + xpaths: { input: string; plus_btn: string } +) => { + const input = await thiefService.getElementByXPath(xpaths.input); + + if (!input) throw new Error("Input is not found"); + + thiefService.scrollToElement(input); + + await delay(200); + for (const tag of tags) { + thiefService.writeToInput(tag, xpaths.input); + + await delay(200); + + thiefService.pressEnter(input); + } +}; + +const finistPublist = async ( + item: IItem, + values: { error?: string; published: boolean } +) => { + const { data } = await axios({ + url: "products/publist-finish/" + item.id, + method: "POST", + data: values, + }); + + return data; +}; + +const clickNext = async () => { + const btn = await thiefService.getElementByXPath(selectors.next_btn); + + if (!btn) throw new Error("Next button is not found"); + + thiefService.clickByPoint(btn); +}; + +const clickPublist = async () => { + const btn = await thiefService.getElementByXPath(selectors.publish_btn); + + if (!btn) throw new Error("Publist button is not found"); + + thiefService.clickByPoint(btn); +}; + +/** + * B1. Upload images + * B2. Write title + * B3. Write price + * B4. Select category + * B5. Select condition + * + */ +const handle = async (item: IItem) => { + console.log({ item }); + + await delay(1000); + // B1. Upload images + await uploadImages(item); + + await delay(200); + // B2. Write title + thiefService.writeToInput(item.title, selectors.title_input); + + await delay(200); + // B3. Write price + thiefService.writeToInput(String(item.price), selectors.price_input); + + await delay(200); + // B4. Select category + await chooseSelect(item.category, selectors.category_select); + + await delay(200); + // B5. Select condition + await chooseSelect(item.condition, selectors.condition_select); + + if (item.brand) { + await delay(200); + // B3. Write price + thiefService.writeToInput(item.brand, selectors.brand_input); + } + + await delay(200); + // B3. Write price + await thiefService.writeToInput( + item.description, + selectors.description_input + ); + + await delay(200); + + await writeTags(item.tags, selectors.tags_input); + + await delay(200); + // B3. Write price + thiefService.writeToInput(item.sku, selectors.sku_input); + + if (item?.location) { + await delay(200); + + await chooseLocation(item.location, selectors.location_select); + } + + await delay(200); + + await clickNext(); + + // await delay(200); + + return true; +}; + +const closeTab = async (data: IItem) => { + await delay(2000); + + chrome.runtime.sendMessage({ + type: "close-tab", + payload: data, + }); +}; + +const port = chrome.runtime.connect(); + +port.onMessage.addListener(async (message) => { + if (message.type === "publist-event") { + const data = message.payload as IItem; + + if (!data) return; + + console.log("Received new product event:", data); + + // data.images = ["images/1.png", "images/2.png"]; + + try { + await delay(2000); + await handle(data); + } catch (error) { + await finistPublist(data, { + error: (error as { message: string }).message, + published: false, + }); + } finally { + await finistPublist(data, { published: true }); + + await closeTab(data); + } + } +}); diff --git a/auto-listing-facebook-marketplace/src/features/app.ts b/auto-listing-facebook-marketplace/src/features/app.ts new file mode 100644 index 0000000..99965d7 --- /dev/null +++ b/auto-listing-facebook-marketplace/src/features/app.ts @@ -0,0 +1,17 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +export function removeFalsyValues>( + obj: T, + excludeKeys: (keyof T)[] = [] +): Partial { + return Object.entries(obj).reduce((acc, [key, value]) => { + if (value || excludeKeys.includes(key as keyof T)) { + acc[key as keyof T] = value; + } + return acc; + }, {} as Partial); +} + +export function delay(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); +} diff --git a/auto-listing-facebook-marketplace/src/features/key-manager.ts b/auto-listing-facebook-marketplace/src/features/key-manager.ts new file mode 100644 index 0000000..06169b8 --- /dev/null +++ b/auto-listing-facebook-marketplace/src/features/key-manager.ts @@ -0,0 +1,21 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +export const saveKey = (payload: any) => { + window.postMessage( + { + direction: "to-content", + type: "SAVE_KEY", + payload: payload, + }, + "*" + ); +}; + +export const getKey = () => { + window.postMessage( + { + direction: "to-content", + type: "GET_KEY", + }, + "*" + ); +}; diff --git a/auto-listing-facebook-marketplace/src/features/login-state-manager.ts b/auto-listing-facebook-marketplace/src/features/login-state-manager.ts new file mode 100644 index 0000000..add182e --- /dev/null +++ b/auto-listing-facebook-marketplace/src/features/login-state-manager.ts @@ -0,0 +1,21 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +export const saveStateLogin = (payload: any) => { + window.postMessage( + { + direction: "to-content", + type: "SAVE_STATE_LOGIN", + payload: payload, + }, + "*" + ); +}; + +export const getStateLogin = () => { + window.postMessage( + { + direction: "to-content", + type: "GET_STATE_LOGIN", + }, + "*" + ); +}; diff --git a/auto-listing-facebook-marketplace/src/inject-ui.tsx b/auto-listing-facebook-marketplace/src/inject-ui.tsx new file mode 100644 index 0000000..fbb8217 --- /dev/null +++ b/auto-listing-facebook-marketplace/src/inject-ui.tsx @@ -0,0 +1,9 @@ +// import { TeamsChatService } from "./services/teams-chat.service"; + +// const service = new TeamsChatService(); +// service.start(); // Mỗi 10 giây sẽ quét tin nhắn mới + +// setTimeout(async () => { +// await service.scrollToBottomByXPath.bind(service)(); +// await service.getConversationsInfo.bind(service)(); +// }, 5000); diff --git a/auto-listing-facebook-marketplace/src/interfate.d.ts b/auto-listing-facebook-marketplace/src/interfate.d.ts new file mode 100644 index 0000000..1fdf9a3 --- /dev/null +++ b/auto-listing-facebook-marketplace/src/interfate.d.ts @@ -0,0 +1,13 @@ +interface IItem { + images: string[]; + title: string; + price: number; + category: string; + condition: string; + brand?: string; + description: string; + tags: string[]; + sku: string; + location?: string; + id: number; +} diff --git a/auto-listing-facebook-marketplace/src/lib/axios.ts b/auto-listing-facebook-marketplace/src/lib/axios.ts new file mode 100644 index 0000000..e628c0f --- /dev/null +++ b/auto-listing-facebook-marketplace/src/lib/axios.ts @@ -0,0 +1,11 @@ +import ax from "axios"; + +const axios = ax.create({ + // Dev + baseURL: import.meta.env.VITE_API_URL, + headers: { + "Content-Type": "application/json", + }, +}); + +export default axios; diff --git a/auto-listing-facebook-marketplace/src/lib/event.ts b/auto-listing-facebook-marketplace/src/lib/event.ts new file mode 100644 index 0000000..41f7176 --- /dev/null +++ b/auto-listing-facebook-marketplace/src/lib/event.ts @@ -0,0 +1,8 @@ +export const EVENTS = { + GET_CONVERSATIONS: "messages.get-conversations", + GET_CONVERSATION: "messages.get-conversation", + RECEIVE_CONVERSATIONS: "messages.receive-conversations", + RECEIVE_CONVERSATION: "messages.receive-conversation", + SEND_MESSAGE: "messages.send-messsage", + REPLY_MESSAGE: "messages.reply-messsage", +}; diff --git a/auto-listing-facebook-marketplace/src/lib/queue.ts b/auto-listing-facebook-marketplace/src/lib/queue.ts new file mode 100644 index 0000000..b4778ee --- /dev/null +++ b/auto-listing-facebook-marketplace/src/lib/queue.ts @@ -0,0 +1,3 @@ +import PQueue from "p-queue"; +// Khởi tạo queue xử lý tuần tự +export const queue = new PQueue({ concurrency: 1 }); diff --git a/auto-listing-facebook-marketplace/src/lib/utils.ts b/auto-listing-facebook-marketplace/src/lib/utils.ts new file mode 100644 index 0000000..bd0c391 --- /dev/null +++ b/auto-listing-facebook-marketplace/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/auto-listing-facebook-marketplace/src/services/thief.service.ts b/auto-listing-facebook-marketplace/src/services/thief.service.ts new file mode 100644 index 0000000..6d3ecb7 --- /dev/null +++ b/auto-listing-facebook-marketplace/src/services/thief.service.ts @@ -0,0 +1,190 @@ +class ThiefService { + base64ToFile(base64: string, filename: string, mimeType: string): File { + // Nếu có tiền tố "data:image/xxx;base64," thì cắt bỏ + const pureBase64 = base64.includes(",") ? base64.split(",")[1] : base64; + + const byteString = atob(pureBase64); + const ab = new ArrayBuffer(byteString.length); + const ia = new Uint8Array(ab); + + for (let i = 0; i < byteString.length; i++) { + ia[i] = byteString.charCodeAt(i); + } + + const blob = new Blob([ab], { type: mimeType }); + return new File([blob], filename, { type: mimeType }); + } + + clickByPoint(el: Element) { + const rect: DOMRect = el.getBoundingClientRect(); + const x: number = rect.left + rect.width / 2; + const y: number = rect.top + rect.height / 2; + + const target: Element | null = document.elementFromPoint(x, y); + if (target) { + target.dispatchEvent( + new MouseEvent("click", { + bubbles: true, + cancelable: true, + view: window, + }) + ); + } + } + + async getElementByXPath( + xpath: string, + retryCount: number = 3, + delay: number = 400 + ): Promise { + return new Promise((resolve) => { + let attempts = 0; + + const tryFind = () => { + const el: Node | null = document.evaluate( + xpath, + document, + null, + XPathResult.FIRST_ORDERED_NODE_TYPE, + null + ).singleNodeValue; + + if (el instanceof HTMLElement) { + resolve(el); + return; + } + + attempts++; + if (attempts < retryCount) { + setTimeout(tryFind, delay); + } else { + resolve(null); + } + }; + + tryFind(); + }); + } + + async imageUrlToBase64(url: string): Promise { + const response = await fetch(url); + const blob = await response.blob(); + + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onloadend = () => { + if (typeof reader.result === "string") { + // Kết quả là data URL (base64) + resolve(reader.result.split(",")[1]); + } else { + reject("Không thể đọc dữ liệu ảnh"); + } + }; + reader.onerror = reject; + reader.readAsDataURL(blob); + }); + } + + getImageExtension(url: string): string | null { + try { + const pathname = new URL(url).pathname; // Lấy phần path từ URL + const match = pathname.match(/\.([a-zA-Z0-9]+)$/); // Tìm đuôi file + return match ? match[1].toLowerCase() : null; + } catch { + // Nếu url không hợp lệ thì fallback sang split + const parts = url.split("?"); + const path = parts[0]; + const match = path.match(/\.([a-zA-Z0-9]+)$/); + return match ? match[1].toLowerCase() : null; + } + } + + imageLocalToBase64(relativePath: string): Promise { + return new Promise((resolve, reject) => { + try { + // Lấy URL đầy đủ trong extension + const url = chrome.runtime.getURL(`${relativePath}`); + + // Fetch file + fetch(url) + .then((res) => res.blob()) + .then((blob) => { + const reader = new FileReader(); + reader.onloadend = () => resolve(reader.result as string); // base64 + reader.onerror = reject; + reader.readAsDataURL(blob); + }) + .catch(reject); + } catch (err) { + reject(err); + } + }); + } + + scrollToElement(el: HTMLElement, behavior: ScrollBehavior = "smooth") { + if (!el) return; + el.scrollIntoView({ + behavior, // "smooth" hoặc "auto" + block: "center", // Đưa phần tử ra giữa màn hình + inline: "nearest", + }); + } + + getElementPointCoores(el: HTMLElement): { x: number; y: number } | null { + if (!el) return null; + const rect = el.getBoundingClientRect(); + const x = rect.left + rect.width / 2; + const y = rect.top + rect.height / 2; + return { x, y }; + } + + setInputValue(el: HTMLInputElement | HTMLTextAreaElement, value: string) { + if (!el) return; + + // Gán giá trị trực tiếp + el.value = value; + + // Tạo và dispatch sự kiện input + el.dispatchEvent(new Event("input", { bubbles: true })); + + // Tạo và dispatch sự kiện change (nếu cần) + el.dispatchEvent(new Event("change", { bubbles: true })); + } + + writeToInput = async (value: string, xpath: string) => { + const el = (await this.getElementByXPath(xpath)) as HTMLInputElement; + + if (!el) throw new Error("Xpath is not found"); + + // Scroll to EL + this.scrollToElement(el); + + this.clickByPoint(el); + + this.setInputValue(el, value); + }; + + pressEnter(el: HTMLElement) { + if (!el) { + throw new Error("Textarea not found:", el); + } + + el.focus(); + + // Chuỗi sự kiện bàn phím + ["keydown", "keypress", "keyup"].forEach((type) => { + el.dispatchEvent( + new KeyboardEvent(type, { + key: "Enter", + code: "Enter", + keyCode: 13, + which: 13, + bubbles: true, + cancelable: true, + }) + ); + }); + } +} + +export const thiefService = new ThiefService(); diff --git a/auto-listing-facebook-marketplace/src/vite-env.d.ts b/auto-listing-facebook-marketplace/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/auto-listing-facebook-marketplace/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/auto-listing-facebook-marketplace/tsconfig.app.json b/auto-listing-facebook-marketplace/tsconfig.app.json new file mode 100644 index 0000000..08dd040 --- /dev/null +++ b/auto-listing-facebook-marketplace/tsconfig.app.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src"] +} diff --git a/auto-listing-facebook-marketplace/tsconfig.json b/auto-listing-facebook-marketplace/tsconfig.json new file mode 100644 index 0000000..22da7dc --- /dev/null +++ b/auto-listing-facebook-marketplace/tsconfig.json @@ -0,0 +1,16 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ], + "compilerOptions": { + "baseUrl": ".", + "target": "es2020", + "module": "es2020", + "moduleResolution": "bundler", // hoặc "node" nếu bạn dùng tsc không bundler + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/auto-listing-facebook-marketplace/tsconfig.node.json b/auto-listing-facebook-marketplace/tsconfig.node.json new file mode 100644 index 0000000..f85a399 --- /dev/null +++ b/auto-listing-facebook-marketplace/tsconfig.node.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/auto-listing-facebook-marketplace/vite.config.ts b/auto-listing-facebook-marketplace/vite.config.ts new file mode 100644 index 0000000..5770675 --- /dev/null +++ b/auto-listing-facebook-marketplace/vite.config.ts @@ -0,0 +1,25 @@ +import react from "@vitejs/plugin-react"; +import path from "path"; +import { defineConfig } from "vite"; +export default defineConfig({ + plugins: [react()], + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, + build: { + outDir: "auto-listing-facebook-marketplace", + cssCodeSplit: true, + rollupOptions: { + input: { + content: "src/content.ts", + background: "src/background.ts", + }, + output: { + entryFileNames: "[name].js", + }, + }, + emptyOutDir: false, + }, +}); diff --git a/client/.dockerignore b/client/.dockerignore new file mode 100644 index 0000000..9b8d514 --- /dev/null +++ b/client/.dockerignore @@ -0,0 +1,4 @@ +.react-router +build +node_modules +README.md \ No newline at end of file diff --git a/client/.env b/client/.env new file mode 100644 index 0000000..aafaa20 --- /dev/null +++ b/client/.env @@ -0,0 +1,3 @@ +VITE_APP_NAME = 'Admin' + +VITE_BASE_URL = 'http://localhost:4000/api/v1/' \ No newline at end of file diff --git a/client/.gitignore b/client/.gitignore new file mode 100644 index 0000000..9b7c041 --- /dev/null +++ b/client/.gitignore @@ -0,0 +1,6 @@ +.DS_Store +/node_modules/ + +# React Router +/.react-router/ +/build/ diff --git a/client/Dockerfile b/client/Dockerfile new file mode 100644 index 0000000..207bf93 --- /dev/null +++ b/client/Dockerfile @@ -0,0 +1,22 @@ +FROM node:20-alpine AS development-dependencies-env +COPY . /app +WORKDIR /app +RUN npm ci + +FROM node:20-alpine AS production-dependencies-env +COPY ./package.json package-lock.json /app/ +WORKDIR /app +RUN npm ci --omit=dev + +FROM node:20-alpine AS build-env +COPY . /app/ +COPY --from=development-dependencies-env /app/node_modules /app/node_modules +WORKDIR /app +RUN npm run build + +FROM node:20-alpine +COPY ./package.json package-lock.json /app/ +COPY --from=production-dependencies-env /app/node_modules /app/node_modules +COPY --from=build-env /app/build /app/build +WORKDIR /app +CMD ["npm", "run", "start"] \ No newline at end of file diff --git a/client/README.md b/client/README.md new file mode 100644 index 0000000..5c4780a --- /dev/null +++ b/client/README.md @@ -0,0 +1,87 @@ +# Welcome to React Router! + +A modern, production-ready template for building full-stack React applications using React Router. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/remix-run/react-router-templates/tree/main/default) + +## Features + +- 🚀 Server-side rendering +- ⚡️ Hot Module Replacement (HMR) +- 📦 Asset bundling and optimization +- 🔄 Data loading and mutations +- 🔒 TypeScript by default +- 🎉 TailwindCSS for styling +- 📖 [React Router docs](https://reactrouter.com/) + +## Getting Started + +### Installation + +Install the dependencies: + +```bash +npm install +``` + +### Development + +Start the development server with HMR: + +```bash +npm run dev +``` + +Your application will be available at `http://localhost:5173`. + +## Building for Production + +Create a production build: + +```bash +npm run build +``` + +## Deployment + +### Docker Deployment + +To build and run using Docker: + +```bash +docker build -t my-app . + +# Run the container +docker run -p 3000:3000 my-app +``` + +The containerized application can be deployed to any platform that supports Docker, including: + +- AWS ECS +- Google Cloud Run +- Azure Container Apps +- Digital Ocean App Platform +- Fly.io +- Railway + +### DIY Deployment + +If you're familiar with deploying Node applications, the built-in app server is production-ready. + +Make sure to deploy the output of `npm run build` + +``` +├── package.json +├── package-lock.json (or pnpm-lock.yaml, or bun.lockb) +├── build/ +│ ├── client/ # Static assets +│ └── server/ # Server-side code +``` + +## Styling + +This template comes with [Tailwind CSS](https://tailwindcss.com/) already configured for a simple default starting experience. You can use whatever CSS framework you prefer. + +--- + +Built with ❤️ using React Router. diff --git a/client/app/api/auth-api.service.ts b/client/app/api/auth-api.service.ts new file mode 100644 index 0000000..d244eca --- /dev/null +++ b/client/app/api/auth-api.service.ts @@ -0,0 +1,65 @@ +import axios from "~/lib/axios"; +import { handleError, handleSuccess } from "."; + +class AuthApiService { + async login(credentials: { input: string; password: string }) { + try { + const { data } = await axios({ + url: "auth/login", + data: credentials, + method: "POST", + withCredentials: true, + }); + + return data as IResponse; + } catch (error) { + handleError(error); + } + } + + async logout() { + try { + const { data } = await axios({ + url: "auth/logout", + method: "POST", + withCredentials: true, + }); + + return data as IResponse; + } catch (error) { + handleError(error); + } + } + + async changePassword(credentials: { newPassword: string; password: string }) { + try { + const { data } = await axios({ + url: "auth/change-password", + data: credentials, + method: "POST", + withCredentials: true, + }); + + handleSuccess(data); + return data as IResponse; + } catch (error) { + handleError(error); + } + } + + async me() { + try { + const { data } = await axios({ + url: "auth/me", + method: "GET", + withCredentials: true, + }); + + return data as IResponse; + } catch (error) { + handleError(error); + } + } +} + +export const authApi = new AuthApiService(); diff --git a/client/app/api/core-api-service.ts b/client/app/api/core-api-service.ts new file mode 100644 index 0000000..0342503 --- /dev/null +++ b/client/app/api/core-api-service.ts @@ -0,0 +1,143 @@ +// base-api.service.ts +import type { TableState } from "~/components/core/data-table"; +import { removeUndefinedValues } from "~/features/remove-falsy-values"; +import { mapTableStateToPaginationQueryDSL } from "~/features/table"; +import { handleError, handleSuccess } from "."; +import axios from "../lib/axios"; +import type { DeepPartial } from "react-hook-form"; + +export class BaseApiService { + constructor(protected readonly resourceUrl: string) {} + + async index(values?: DeepPartial> | undefined) { + const params = values + ? mapTableStateToPaginationQueryDSL(values as TableState) + : {}; + + const response = await axios({ + url: this.resourceUrl, + params: params, + // withCredentials: true, + method: "GET", + }); + + return response.data; + } + + async get(id: T["id"]) { + const response = await axios({ + url: this.resourceUrl + "/" + id, + // withCredentials: true, + method: "GET", + }); + + return response.data; + } + + async create(data: Partial>) { + try { + const newData = removeUndefinedValues(data); + const { data: result } = await axios({ + url: this.resourceUrl, + // withCredentials: true, + method: "POST", + data: newData, + }); + + handleSuccess(result, this.resourceUrl); + return result; + } catch (error) { + handleError(error); + } + } + + async update(id: T["id"], data: Partial) { + try { + const cleaned = removeUndefinedValues(data); + const { data: result } = await axios({ + url: `${this.resourceUrl}/${id}`, + // withCredentials: true, + method: "PUT", + data: cleaned, + }); + + handleSuccess(result, this.resourceUrl); + + return result; + } catch (error) { + handleError(error); + } + } + + async delete(entity: T) { + try { + const { data } = await axios({ + url: `${this.resourceUrl}/${entity.id}`, + // withCredentials: true, + method: "DELETE", + }); + + handleSuccess(data, this.resourceUrl); + return data; + } catch (error) { + handleError(error); + } + } + + async bulkDelete(entities: T[]) { + const ids = entities.map((e) => e.id); + try { + const { data } = await axios({ + url: `${this.resourceUrl}/bulk-delete`, + // withCredentials: true, + method: "DELETE", + data: { ids }, + }); + + handleSuccess(data, this.resourceUrl); + + return data; + } catch (error) { + handleError(error); + } + } + + async bulkUpdate(entities: T[]) { + try { + const { data } = await axios({ + url: `${this.resourceUrl}/bulk-update`, + // withCredentials: true, + method: "PUT", + data: entities, + }); + + handleSuccess(data, this.resourceUrl); + + return data; + } catch (error) { + handleError(error); + } + } + + // Optional: override this in subclass if needed + async customAction( + id: number, + endpoint: string, + payload?: Record, + method?: string + ) { + try { + const { data } = await axios({ + url: `${this.resourceUrl}/${endpoint}/${id}`, + method: method || "POST", + data: removeUndefinedValues(payload || {}), + // withCredentials: true, + }); + + handleSuccess(data, this.resourceUrl); + return data; + } catch (error) { + handleError(error); + } + } +} diff --git a/client/app/api/index.ts b/client/app/api/index.ts new file mode 100644 index 0000000..ea9632f --- /dev/null +++ b/client/app/api/index.ts @@ -0,0 +1,56 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { AxiosError, HttpStatusCode } from "axios"; +import { toast } from "sonner"; + +export const handleError = (error: unknown) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const response = (error as AxiosError).response as Record; + + const data = response.data; + + if (response.status === HttpStatusCode.Forbidden) return; + + if (data?.errors && (data.errors as []).length) { + let newMessage = data.errors[0].errors[0]; + + if ((data.errors as []).length > 1) { + newMessage = newMessage + ` and ${data.errors.length} errors`; + } + + toast.error(newMessage || "Internal Server Error"); + + return; + } + toast.error((response?.data.message as string) || "Internal Server Error"); +}; + +export const handleSuccess = (data: IResponse, key?: string) => { + toast.success(data.message.replaceAll("@key", key || "")); +}; + +export function generateNestParams(params: Record) { + const excludeKeys = ["page"]; + + const prefixSortKey = ""; + + if (!params) return params; + + const newParams = Object.keys(params).reduce((prev, cur) => { + if (excludeKeys.includes(cur)) { + prev[cur] = params[cur]; + } else if (cur.includes(prefixSortKey)) { + prev["sortBy"] = `${cur.replace("", "")}:${String( + params[cur] + ).toLocaleUpperCase()}`; + } else if (cur === "per_page") { + prev["limit"] = params[cur]; + } else if (cur === "") { + prev["search"] = params[cur]; + } else { + prev[`filter.${cur}`] = params[cur]; + } + + return prev; + }, {} as Record); + return newParams; +} diff --git a/client/app/api/products-api.service.ts b/client/app/api/products-api.service.ts new file mode 100644 index 0000000..fde0dbd --- /dev/null +++ b/client/app/api/products-api.service.ts @@ -0,0 +1,11 @@ +// admin-api.service.ts + +import { BaseApiService } from "./core-api-service"; + +class ProductApiService extends BaseApiService { + constructor() { + super("products"); + } +} + +export const productApi = new ProductApiService(); diff --git a/client/app/api/resource-api.service.ts b/client/app/api/resource-api.service.ts new file mode 100644 index 0000000..36ef995 --- /dev/null +++ b/client/app/api/resource-api.service.ts @@ -0,0 +1,46 @@ +// admin-api.service.ts + +import type { DeepPartial } from "react-hook-form"; +import { BaseApiService } from "./core-api-service"; +import { mapTableStateToPaginationQueryDSL } from "~/features/table"; +import axios from "~/lib/axios"; + +class ResourceApiService extends BaseApiService { + constructor() { + super("resources"); + } + + async resourceByRole( + role_id: IRole["id"], + values?: DeepPartial> | undefined + ) { + const params = values + ? mapTableStateToPaginationQueryDSL(values as TableState) + : {}; + + const response = await axios({ + url: `${this.resourceUrl}/role/${role_id}`, + params: { ...params }, + withCredentials: true, + method: "GET", + }); + + return response.data; + } + + async updateResourceRoles(role_id: IRole["id"], values: number[]) { + const response = await axios({ + url: `${this.resourceUrl}/role/${role_id}`, + withCredentials: true, + data: { + resource_ids: values, + role_id, + }, + method: "PUT", + }); + + return response.data; + } +} + +export const resourceApi = new ResourceApiService(); diff --git a/client/app/api/roles-api.service.ts b/client/app/api/roles-api.service.ts new file mode 100644 index 0000000..bf12f9c --- /dev/null +++ b/client/app/api/roles-api.service.ts @@ -0,0 +1,11 @@ +// admin-api.service.ts + +import { BaseApiService } from "./core-api-service"; + +class RolesApiService extends BaseApiService { + constructor() { + super("roles"); + } +} + +export const rolesApi = new RolesApiService(); diff --git a/client/app/api/user-api.service.ts b/client/app/api/user-api.service.ts new file mode 100644 index 0000000..201577f --- /dev/null +++ b/client/app/api/user-api.service.ts @@ -0,0 +1,17 @@ +// admin-api.service.ts + +import { BaseApiService } from "./core-api-service"; + +class UserApiService extends BaseApiService { + constructor() { + super("users"); + } + + // grantNewPassword(admin: Partial) { + // return this.customAction(admin.id!, 'grant-new-password', { + // password: admin.password, + // }); + // } +} + +export const userApi = new UserApiService(); diff --git a/client/app/app.css b/client/app/app.css new file mode 100644 index 0000000..062470e --- /dev/null +++ b/client/app/app.css @@ -0,0 +1,125 @@ +@import "tailwindcss"; +@import "tw-animate-css"; + +@custom-variant dark (&:is(.dark *)); + +@theme { + --font-sans: "Inter", ui-sans-serif, system-ui, sans-serif, + "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; +} + +@theme inline { + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); +} + +:root { + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/client/app/components/app-sidebar.tsx b/client/app/components/app-sidebar.tsx new file mode 100644 index 0000000..516e20d --- /dev/null +++ b/client/app/components/app-sidebar.tsx @@ -0,0 +1,75 @@ +import { + AudioWaveform, + Box, + Command, + FolderKey, + GalleryVerticalEnd, +} from "lucide-react"; +import * as React from "react"; +import { useSelector } from "react-redux"; + +import { NavMain } from "~/components/nav-main"; +import { NavUser } from "~/components/nav-user"; +import { TeamSwitcher } from "~/components/team-switcher"; +import { + Sidebar, + SidebarContent, + SidebarFooter, + SidebarHeader, + SidebarRail, +} from "~/components/ui/sidebar"; +import { Links } from "~/lib/links"; +import type { RootState } from "~/store"; +import Loader from "./loader"; + +export function AppSidebar({ ...props }: React.ComponentProps) { + // This is sample data. + const data = { + teams: [ + { + name: "Acme Inc", + logo: GalleryVerticalEnd, + plan: "Enterprise", + }, + { + name: "Acme Corp.", + logo: AudioWaveform, + plan: "Startup", + }, + { + name: "Evil Corp.", + logo: Command, + plan: "Free", + }, + ], + navMain: [ + { + title: "Products", + url: "#", + icon: Box, + isActive: true, + items: [ + { + title: "List", + url: Links.PRODUCTS, + }, + ], + }, + ], + }; + + return ( + + {/* + + */} + + + + {/* + + */} + + + ); +} diff --git a/client/app/components/btn/confirm-alert.tsx b/client/app/components/btn/confirm-alert.tsx new file mode 100644 index 0000000..98a59d4 --- /dev/null +++ b/client/app/components/btn/confirm-alert.tsx @@ -0,0 +1,65 @@ +import { useState, type ReactNode } from "react"; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from "~/components/ui/alert-dialog"; +import Loader from "../loader"; +import { delay } from "~/features/delay"; +import { Button } from "../ui/button"; + +export function ConfirmAlert({ + children, + title = "Bạn có chắc không?", + description = "Hành động này không thể hoàn tác.", + onConfirm, +}: { + children: ReactNode; + title?: string; + description?: string; + onConfirm: () => void | Promise; +}) { + const [loading, setLoading] = useState(false); + const [open, setOpen] = useState(false); + return ( + + {children} + + + {title} + {description} + + + Hủy + + + + + ); +} diff --git a/client/app/components/core/data-container.tsx b/client/app/components/core/data-container.tsx new file mode 100644 index 0000000..1642809 --- /dev/null +++ b/client/app/components/core/data-container.tsx @@ -0,0 +1,1416 @@ +"use client"; + +import type React from "react"; +import { format } from "date-fns"; +import { vi } from "date-fns/locale"; +import { + ArrowDown, + ArrowUp, + ArrowUpDown, + CalendarIcon, + ChevronLeft, + ChevronRight, + ChevronsLeft, + ChevronsRight, + Filter, + MoreHorizontal, + Search, + X, +} from "lucide-react"; +import { + useCallback, + useEffect, + useMemo, + useRef, + useState, + type ReactNode, +} from "react"; +import type { DateRange } from "react-day-picker"; +import { Badge } from "~/components/ui/badge"; +import { Button } from "~/components/ui/button"; +import { Calendar } from "~/components/ui/calendar"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "~/components/ui/dialog"; +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "~/components/ui/dropdown-menu"; +import { Input } from "~/components/ui/input"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "~/components/ui/popover"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "~/components/ui/select"; +import Loader from "../loader"; +import { Checkbox } from "../ui/checkbox"; + +export interface DataContainerProps { + data: T[]; + searchKeys?: (keyof T)[]; + filterOptions?: FilterOption[]; + sortOptions?: SortOption[]; // New sorting options + pageSize?: number; + onPageSizeChange?: (newPageSize: number) => void; + selectable?: boolean; + onSelectionChange?: (selectedRows: T[]) => void; + onSortChange?: (sortConfig: { + key: keyof T | null; + direction: "asc" | "desc"; + }) => void; + onFilterChange?: (filters: { + search: string; + select: Record; + text: Record; + date: Record; + dateRange: Record; + number: Record; + numberRange: Record; + }) => void; + onPaginationChange?: (pagination: PaginationData) => void; + pagination?: PaginationData; + loading?: boolean; + initialState?: InitialState; + children: ReactNode; + customActions?: BulkAction[]; +} + +export function DataContainer>({ + data, + searchKeys = [], + filterOptions = [], + sortOptions = [], // New prop + pageSize = 10, + onPageSizeChange, + selectable = false, + onSelectionChange, + onSortChange, + onFilterChange, + onPaginationChange, + pagination, + loading = false, + initialState, + children, + customActions = [], +}: DataContainerProps) { + const [searchTerm, setSearchTerm] = useState(initialState?.search || ""); + const [sortConfig, setSortConfig] = useState<{ + key: keyof T | null; + direction: "asc" | "desc"; + }>(initialState?.sort || { key: null, direction: "asc" }); + + // Different filter states for different types + const [filters, setFilters] = useState>( + initialState?.filters?.select || {} + ); + const [textFilters, setTextFilters] = useState>( + initialState?.filters?.text || {} + ); + const [dateFilters, setDateFilters] = useState< + Record + >(initialState?.filters?.date || {}); + const [dateRangeFilters, setDateRangeFilters] = useState< + Record + >(initialState?.filters?.dateRange || {}); + const [numberFilters, setNumberFilters] = useState< + Record + >(initialState?.filters?.number || {}); + const [numberRangeFilters, setNumberRangeFilters] = useState< + Record + >(initialState?.filters?.numberRange || {}); + + // Pending states for modal + const [pendingFilters, setPendingFilters] = useState< + Record + >(initialState?.filters?.select || {}); + const [pendingTextFilters, setPendingTextFilters] = useState< + Record + >(initialState?.filters?.text || {}); + const [pendingDateFilters, setPendingDateFilters] = useState< + Record + >(initialState?.filters?.date || {}); + const [pendingDateRangeFilters, setPendingDateRangeFilters] = useState< + Record + >(initialState?.filters?.dateRange || {}); + const [pendingNumberFilters, setPendingNumberFilters] = useState< + Record + >(initialState?.filters?.number || {}); + const [pendingNumberRangeFilters, setPendingNumberRangeFilters] = useState< + Record + >(initialState?.filters?.numberRange || {}); + const [pendingSearchTerm, setPendingSearchTerm] = useState( + initialState?.search || "" + ); + + // Local search state + const [localSearchTerm, setLocalSearchTerm] = useState( + initialState?.search || "" + ); + const searchTimeoutRef = useRef(null); + + // Other states + const [showBulkConfirm, setShowBulkConfirm] = useState(false); + const [pendingBulkAction, setPendingBulkAction] = + useState | null>(null); + const [internalCurrentPage, setInternalCurrentPage] = useState( + initialState?.pagination?.currentPage || 1 + ); + const [selectedRows, setSelectedRows] = useState([]); + const [showFilterModal, setShowFilterModal] = useState(false); + + // Refs for preventing unnecessary callbacks + const prevSortConfigRef = useRef<{ + key: keyof T | null; + direction: "asc" | "desc"; + }>({ key: null, direction: "asc" }); + const prevFiltersRef = useRef<{ + search: string; + select: Record; + text: Record; + date: Record; + dateRange: Record; + number: Record; + numberRange: Record; + }>({ + search: "", + select: {}, + text: {}, + date: {}, + dateRange: {}, + number: {}, + numberRange: {}, + }); + + // Debounced search function + const debouncedSearch = useCallback( + (term: string) => { + if (searchTimeoutRef.current) { + clearTimeout(searchTimeoutRef.current); + } + searchTimeoutRef.current = setTimeout(() => { + setSearchTerm(term); + // Reset to page 1 when searching + if (pagination) { + onPaginationChange?.({ + ...pagination, + currentPage: 1, + }); + } else { + setInternalCurrentPage(1); + } + }, 300); + }, + [pagination, onPaginationChange] + ); + + // Handle immediate search (Enter key) + const handleImmediateSearch = useCallback(() => { + if (searchTimeoutRef.current) { + clearTimeout(searchTimeoutRef.current); + } + setSearchTerm(localSearchTerm); + if (pagination) { + onPaginationChange?.({ + ...pagination, + currentPage: 1, + }); + } else { + setInternalCurrentPage(1); + } + }, [localSearchTerm, pagination, onPaginationChange]); + + // Handle search input change + const handleSearchChange = useCallback( + (value: string) => { + setLocalSearchTerm(value); + setPendingSearchTerm(value); + debouncedSearch(value); + }, + [debouncedSearch] + ); + + // Handle Enter key press + const handleSearchKeyPress = useCallback( + (e: React.KeyboardEvent) => { + if (e.key === "Enter") { + e.preventDefault(); + handleImmediateSearch(); + } + }, + [handleImmediateSearch] + ); + + // Cleanup timeout on unmount + useEffect(() => { + return () => { + if (searchTimeoutRef.current) { + clearTimeout(searchTimeoutRef.current); + } + }; + }, []); + + // Determine current pagination values + const currentPage = pagination?.currentPage ?? internalCurrentPage; + const currentPageSize = + pagination?.pageSize ?? initialState?.pagination?.pageSize ?? pageSize; + const totalPages = + pagination?.totalPages ?? Math.ceil(data.length / currentPageSize); + const totalItems = pagination?.totalItems ?? data.length; + + const filteredData = useMemo(() => { + if (pagination) { + return data; + } + + let filtered = data; + + // Apply search + if (searchTerm && searchKeys.length > 0) { + filtered = filtered.filter((item) => + searchKeys.some((key) => + String(item[key]).toLowerCase().includes(searchTerm.toLowerCase()) + ) + ); + } + + // Apply select filters + Object.entries(filters).forEach(([filterKey, filterValues]) => { + if (filterValues.length > 0) { + filtered = filtered.filter((item) => + filterValues.includes(String(item[filterKey])) + ); + } + }); + + // Apply text filters + Object.entries(textFilters).forEach(([filterKey, filterValue]) => { + if (filterValue.trim()) { + filtered = filtered.filter((item) => + String(item[filterKey]) + .toLowerCase() + .includes(filterValue.toLowerCase()) + ); + } + }); + + // Apply date filters + Object.entries(dateFilters).forEach(([filterKey, filterValue]) => { + if (filterValue) { + filtered = filtered.filter((item) => { + const itemDate = new Date(item[filterKey]); + return itemDate.toDateString() === filterValue.toDateString(); + }); + } + }); + + // Apply date range filters + Object.entries(dateRangeFilters).forEach(([filterKey, filterValue]) => { + if (filterValue.from || filterValue.to) { + filtered = filtered.filter((item) => { + const itemDate = new Date(item[filterKey]); + if (filterValue.from && itemDate < filterValue.from) return false; + if (filterValue.to && itemDate > filterValue.to) return false; + return true; + }); + } + }); + + // Apply number filters + Object.entries(numberFilters).forEach(([filterKey, filterValue]) => { + if (filterValue !== undefined) { + filtered = filtered.filter( + (item) => Number(item[filterKey]) === filterValue + ); + } + }); + + // Apply number range filters + Object.entries(numberRangeFilters).forEach(([filterKey, filterValue]) => { + if (filterValue.min !== undefined || filterValue.max !== undefined) { + filtered = filtered.filter((item) => { + const itemValue = Number(item[filterKey]); + if (filterValue.min !== undefined && itemValue < filterValue.min) + return false; + if (filterValue.max !== undefined && itemValue > filterValue.max) + return false; + return true; + }); + } + }); + + return filtered; + }, [ + data, + searchTerm, + searchKeys, + filters, + textFilters, + dateFilters, + dateRangeFilters, + numberFilters, + numberRangeFilters, + pagination, + ]); + + const sortedData = useMemo(() => { + if (pagination) { + return filteredData; + } + + if (!sortConfig.key) return filteredData; + + return [...filteredData].sort((a, b) => { + const aValue = a[sortConfig.key!]; + const bValue = b[sortConfig.key!]; + + if (aValue < bValue) { + return sortConfig.direction === "asc" ? -1 : 1; + } + if (aValue > bValue) { + return sortConfig.direction === "asc" ? 1 : -1; + } + return 0; + }); + }, [filteredData, sortConfig, pagination]); + + const paginatedData = useMemo(() => { + if (pagination) { + return sortedData; + } + + const startIndex = (currentPage - 1) * currentPageSize; + return sortedData.slice(startIndex, startIndex + currentPageSize); + }, [sortedData, currentPage, currentPageSize, pagination]); + + const handleSort = (key: keyof T) => { + const newSortConfig = { + key, + direction: + sortConfig.key === key && sortConfig.direction === "asc" + ? ("desc" as const) + : ("asc" as const), + }; + setSortConfig(newSortConfig); + }; + + const handleClearSort = () => { + setSortConfig({ key: null, direction: "asc" }); + }; + + const handleFilterChange = ( + filterKey: string, + value: string, + checked: boolean + ) => { + setPendingFilters((prev) => { + const currentValues = prev[filterKey] || []; + if (checked) { + return { ...prev, [filterKey]: [...currentValues, value] }; + } else { + return { + ...prev, + [filterKey]: currentValues.filter((v) => v !== value), + }; + } + }); + }; + + const handleTextFilterChange = (filterKey: string, value: string) => { + setPendingTextFilters((prev) => ({ ...prev, [filterKey]: value })); + }; + + const handleDateFilterChange = ( + filterKey: string, + date: Date | undefined + ) => { + setPendingDateFilters((prev) => ({ ...prev, [filterKey]: date })); + }; + + const handleDateRangeFilterChange = ( + filterKey: string, + range: { from?: Date; to?: Date } + ) => { + setPendingDateRangeFilters((prev) => ({ ...prev, [filterKey]: range })); + }; + + const handleNumberFilterChange = ( + filterKey: string, + value: number | undefined + ) => { + setPendingNumberFilters((prev) => ({ ...prev, [filterKey]: value })); + }; + + const handleNumberRangeFilterChange = ( + filterKey: string, + range: { min?: number; max?: number } + ) => { + setPendingNumberRangeFilters((prev) => ({ ...prev, [filterKey]: range })); + }; + + const applyFilters = () => { + setFilters(pendingFilters); + setTextFilters(pendingTextFilters); + setDateFilters(pendingDateFilters); + setDateRangeFilters(pendingDateRangeFilters); + setNumberFilters(pendingNumberFilters); + setNumberRangeFilters(pendingNumberRangeFilters); + setSearchTerm(pendingSearchTerm); + + // Reset to page 1 when applying filters + if (pagination) { + onPaginationChange?.({ + ...pagination, + currentPage: 1, + }); + } else { + setInternalCurrentPage(1); + } + }; + + const resetPendingFilters = () => { + setPendingFilters(filters); + setPendingTextFilters(textFilters); + setPendingDateFilters(dateFilters); + setPendingDateRangeFilters(dateRangeFilters); + setPendingNumberFilters(numberFilters); + setPendingNumberRangeFilters(numberRangeFilters); + setPendingSearchTerm(searchTerm); + }; + + const clearAllFilters = () => { + setFilters({}); + setTextFilters({}); + setDateFilters({}); + setDateRangeFilters({}); + setNumberFilters({}); + setNumberRangeFilters({}); + setSearchTerm(""); + setLocalSearchTerm(""); + + // Also clear pending + setPendingFilters({}); + setPendingTextFilters({}); + setPendingDateFilters({}); + setPendingDateRangeFilters({}); + setPendingNumberFilters({}); + setPendingNumberRangeFilters({}); + setPendingSearchTerm(""); + + // Clear search timeout + if (searchTimeoutRef.current) { + clearTimeout(searchTimeoutRef.current); + } + }; + + const getActiveFiltersCount = () => { + return ( + Object.keys(filters).reduce((acc, key) => acc + filters[key].length, 0) + + Object.keys(textFilters).filter((key) => textFilters[key].trim()).length + + Object.keys(dateFilters).filter((key) => dateFilters[key]).length + + Object.keys(dateRangeFilters).filter( + (key) => dateRangeFilters[key].from || dateRangeFilters[key].to + ).length + + Object.keys(numberFilters).filter( + (key) => numberFilters[key] !== undefined + ).length + + Object.keys(numberRangeFilters).filter( + (key) => + numberRangeFilters[key].min !== undefined || + numberRangeFilters[key].max !== undefined + ).length + ); + }; + + const hasActiveFilters = () => { + return ( + Object.keys(filters).some((key) => filters[key].length > 0) || + Object.keys(textFilters).some((key) => textFilters[key].trim()) || + Object.keys(dateFilters).some((key) => dateFilters[key]) || + Object.keys(dateRangeFilters).some( + (key) => dateRangeFilters[key].from || dateRangeFilters[key].to + ) || + Object.keys(numberFilters).some( + (key) => numberFilters[key] !== undefined + ) || + Object.keys(numberRangeFilters).some( + (key) => + numberRangeFilters[key].min !== undefined || + numberRangeFilters[key].max !== undefined + ) || + searchTerm.trim() || + localSearchTerm.trim() + ); + }; + + const hasPendingChanges = () => { + return ( + JSON.stringify(pendingFilters) !== JSON.stringify(filters) || + JSON.stringify(pendingTextFilters) !== JSON.stringify(textFilters) || + JSON.stringify(pendingDateFilters) !== JSON.stringify(dateFilters) || + JSON.stringify(pendingDateRangeFilters) !== + JSON.stringify(dateRangeFilters) || + JSON.stringify(pendingNumberFilters) !== JSON.stringify(numberFilters) || + JSON.stringify(pendingNumberRangeFilters) !== + JSON.stringify(numberRangeFilters) || + pendingSearchTerm !== searchTerm + ); + }; + + const handleRowSelection = (row: T, checked: boolean) => { + const newSelection = checked + ? [...selectedRows, row] + : selectedRows.filter((r) => r !== row); + setSelectedRows(newSelection); + onSelectionChange?.(newSelection); + }; + + const handleSelectAll = (checked: boolean) => { + const newSelection = checked ? paginatedData : []; + setSelectedRows(newSelection); + onSelectionChange?.(newSelection); + }; + + const handleBulkAction = (action: BulkAction) => { + if (action.confirmMessage) { + setPendingBulkAction(action); + setShowBulkConfirm(true); + } else { + action.action(selectedRows); + } + }; + + const confirmBulkAction = () => { + if (pendingBulkAction) { + pendingBulkAction.action(selectedRows); + setPendingBulkAction(null); + } + setShowBulkConfirm(false); + }; + + const cancelBulkAction = () => { + setPendingBulkAction(null); + setShowBulkConfirm(false); + }; + + // Pagination handlers + const handlePageChange = (newPage: number) => { + if (pagination && onPaginationChange) { + onPaginationChange({ + ...pagination, + currentPage: newPage, + }); + } else { + setInternalCurrentPage(newPage); + } + }; + + const handlePageSizeChange = (newPageSize: number) => { + if (pagination && onPaginationChange) { + onPaginationChange({ + ...pagination, + pageSize: newPageSize, + currentPage: 1, + }); + } else { + setInternalCurrentPage(1); + onPageSizeChange?.(newPageSize); + } + }; + + const renderFilter = (filterOption: FilterOption) => { + switch (filterOption.type) { + case "select": + return ( + + + + + + {filterOption.label} + + {filterOption.options?.map((option) => ( + + handleFilterChange(filterOption.key, option.value, checked) + } + > + {option.label} + + ))} + + + ); + + case "text": + return ( +
+ + handleTextFilterChange(filterOption.key, e.target.value) + } + className="w-full" + /> + {pendingTextFilters[filterOption.key] && ( + + )} +
+ ); + + case "date": + return ( + + + + + + + handleDateFilterChange(filterOption.key, date) + } + initialFocus + /> + {pendingDateFilters[filterOption.key] && ( +
+ +
+ )} +
+
+ ); + + case "dateRange": + const dateRange = pendingDateRangeFilters[filterOption.key] || {}; + return ( + + + + + + + handleDateRangeFilterChange(filterOption.key, range || {}) + } + numberOfMonths={2} + initialFocus + /> + {(dateRange.from || dateRange.to) && ( +
+ +
+ )} +
+
+ ); + + case "number": + return ( +
+ + handleNumberFilterChange( + filterOption.key, + e.target.value ? Number(e.target.value) : undefined + ) + } + min={filterOption.min} + max={filterOption.max} + className="w-full" + /> + {pendingNumberFilters[filterOption.key] !== undefined && ( + + )} +
+ ); + + case "numberRange": + const numberRange = pendingNumberRangeFilters[filterOption.key] || {}; + return ( + + + + + +
+
+ + + handleNumberRangeFilterChange(filterOption.key, { + ...numberRange, + min: e.target.value + ? Number(e.target.value) + : undefined, + }) + } + min={filterOption.min} + max={filterOption.max} + /> +
+
+ + + handleNumberRangeFilterChange(filterOption.key, { + ...numberRange, + max: e.target.value + ? Number(e.target.value) + : undefined, + }) + } + min={filterOption.min} + max={filterOption.max} + /> +
+ {(numberRange.min !== undefined || + numberRange.max !== undefined) && ( + + )} +
+
+
+ ); + + default: + return null; + } + }; + + // Effect hooks for callbacks + useEffect(() => { + const currentSortConfig = sortConfig; + if ( + JSON.stringify(currentSortConfig) !== + JSON.stringify(prevSortConfigRef.current) && + onSortChange + ) { + prevSortConfigRef.current = currentSortConfig; + onSortChange(currentSortConfig); + } + }, [sortConfig, onSortChange]); + + useEffect(() => { + const currentFilters = { + search: searchTerm, + select: filters, + text: textFilters, + date: dateFilters, + dateRange: dateRangeFilters, + number: numberFilters, + numberRange: numberRangeFilters, + }; + + if ( + JSON.stringify(currentFilters) !== + JSON.stringify(prevFiltersRef.current) && + onFilterChange + ) { + prevFiltersRef.current = currentFilters; + onFilterChange(currentFilters); + } + }, [ + searchTerm, + filters, + textFilters, + dateFilters, + dateRangeFilters, + numberFilters, + numberRangeFilters, + onFilterChange, + ]); + + return ( +
+ {/* Search and Filter Toggle */} +
+
+ {searchKeys.length > 0 && ( +
+ + handleSearchChange(e.target.value)} + onKeyPress={handleSearchKeyPress} + className="pl-8 pr-8" + disabled={loading} + /> + {localSearchTerm && localSearchTerm !== searchTerm && ( +
+
+
+ )} + {localSearchTerm && ( + + )} +
+ )} + +
+ {/* Sort Dropdown - New Addition */} + {sortOptions.length > 0 && ( + + + + + + Sắp xếp theo + + {sortOptions.map((option) => ( + handleSort(option.key)} + className="cursor-pointer" + > +
+ {option.label} + {sortConfig.key === option.key && ( +
+ {sortConfig.direction === "asc" ? ( + + ) : ( + + )} +
+ )} +
+
+ ))} + {sortConfig.key && ( + <> + + + + Xóa sắp xếp + + + )} +
+
+ )} + + {filterOptions.length > 0 && ( + + + + + + + Bộ lọc nâng cao + + Tùy chỉnh các tiêu chí lọc để tìm kiếm dữ liệu chính xác + hơn + + + +
+
+ {/* Quick Filters (Select types) */} + {filterOptions.filter((f) => f.type === "select").length > + 0 && ( +
+ +
+ {filterOptions + .filter((f) => f.type === "select") + .map(renderFilter)} +
+
+ )} + + {/* Text Filters */} + {filterOptions.filter((f) => f.type === "text").length > + 0 && ( +
+ +
+ {filterOptions + .filter((f) => f.type === "text") + .map(renderFilter)} +
+
+ )} + + {/* Date Filters */} + {filterOptions.filter( + (f) => f.type === "date" || f.type === "dateRange" + ).length > 0 && ( +
+ +
+ {filterOptions + .filter( + (f) => + f.type === "date" || f.type === "dateRange" + ) + .map(renderFilter)} +
+
+ )} + + {/* Number Filters */} + {filterOptions.filter( + (f) => f.type === "number" || f.type === "numberRange" + ).length > 0 && ( +
+ +
+ {filterOptions + .filter( + (f) => + f.type === "number" || + f.type === "numberRange" + ) + .map(renderFilter)} +
+
+ )} +
+ + {/* Filter Summary */} +
+
+
+
+ {getActiveFiltersCount()} bộ lọc đang áp dụng +
+ {hasPendingChanges() && ( + + Có thay đổi chưa áp dụng + + )} +
+ +
+
+
+ + + +
+ + +
+
+
+
+ )} + + {/* Custom Actions Menu */} + {customActions && customActions.length > 0 && ( + + + + + + {customActions.map((action) => ( + handleBulkAction(action)} + className={`cursor-pointer ${ + action.variant === "destructive" + ? "text-destructive focus:text-destructive" + : "" + }`} + > + {action.icon && ( + {action.icon} + )} + {action.label} + + ))} + + + )} + + {sortConfig.key && ( + + )} + + {hasActiveFilters() && ( + + )} +
+
+
+ + {/* Container */} + {loading ? ( +
+ +
+ ) : data.length > 0 ? ( + children + ) : ( +
+ Không có dữ liệu. +
+ )} + + {/* Pagination */} +
+
+

Hiển thị

+ +

trên {totalItems} kết quả

+
+ + {totalPages > 1 && ( +
+

+ Trang {currentPage} / {totalPages} +

+
+ + + + +
+
+ )} +
+ + {/* Bulk Action Confirmation Dialog */} + {showBulkConfirm && pendingBulkAction && ( +
+
+

Xác nhận hành động

+

+ {pendingBulkAction.confirmMessage} +

+

+ Thao tác này sẽ áp dụng cho {selectedRows.length} mục đã chọn. +

+
+ + +
+
+
+ )} +
+ ); +} diff --git a/client/app/components/core/data-table.md b/client/app/components/core/data-table.md new file mode 100644 index 0000000..b200303 --- /dev/null +++ b/client/app/components/core/data-table.md @@ -0,0 +1,254 @@ +# 📊 `DataTable` Component + +Component bảng dữ liệu mạnh mẽ, tùy biến cao, hỗ trợ các chức năng như tìm kiếm, lọc, phân trang, sắp xếp, hành động hàng loạt và hành động tùy chỉnh — được xây dựng bằng Tailwind, Shadcn UI, và Lucide Icons. + +--- + +## 🚀 Cài đặt + +```tsx +import { DataTable } from "~/components/data-table"; // Đường dẫn có thể khác tùy theo cấu trúc dự án +``` + +--- + +## 🧩 Props + +### 1. `data: T[]` + +Danh sách dữ liệu hiển thị. + +### 2. `columns: Column[]` + +Cấu hình cột (xem bên dưới). + +### 3. `searchKeys?: (keyof T)[]` + +Các field dùng để tìm kiếm toàn cục. + +### 4. `filterOptions?: FilterOption[]` + +Cấu hình bộ lọc nâng cao (theo field, số, ngày, v.v.). + +### 5. `pageSize?: number` + +Số dòng mặc định mỗi trang (mặc định: 10). + +### 6. `onPageSizeChange?: (size: number) => void` + +Callback khi thay đổi `pageSize`. + +### 7. `onRowClick?: (row: T) => void` + +Sự kiện click vào 1 hàng. + +### 8. `onView`, `onEdit`, `onDelete` + +Callback khi người dùng chọn thao tác tương ứng từ menu hành động. + +### 9. `selectable?: boolean` + +Cho phép chọn nhiều dòng. + +### 10. `bulkActions?: BulkAction[]` + +Hành động hàng loạt với các dòng được chọn. + +### 11. `customActions?: CustomAction[]` + +Hành động tùy chỉnh cho từng dòng (menu 3 chấm). + +### 12. `pagination?: PaginationData` + +Phân trang điều khiển từ ngoài (server-side). + +### 13. `onPaginationChange?: (pagination: PaginationData) => void` + +Callback khi thay đổi phân trang. + +### 14. `onSortChange`, `onFilterChange`, `onDataChange` + +Callback khi sort / lọc / dữ liệu thay đổi. + +### 15. `loading?: boolean` + +Trạng thái đang tải dữ liệu. + +--- + +## 🧱 Column Definition + +```ts +interface Column { + key: keyof T; + label: string; + sortable?: boolean; + filterable?: boolean; + displayType?: "text" | "avatar" | "badge" | "currency" | ...; + displayOptions?: object; + render?: (value: any, row: T) => React.ReactNode; +} +``` + +> Hỗ trợ nhiều kiểu hiển thị: `text`, `password`, `image`, `badge`, `currency`, `boolean`, `link`, `email`, `tags`, `progress`, `status`, `rating`, `filesize`, `percentage`, `custom`, v.v. + +--- + +## 🔍 Filter Options + +```ts +interface FilterOption { + key: string; + label: string; + type: "select" | "text" | "date" | "dateRange" | "number" | "numberRange"; + options?: { value: string; label: string }[]; +} +``` + +> Hiển thị bộ lọc nâng cao thông qua dialog. + +--- + +## 🔧 Bulk & Custom Actions + +```ts +interface BulkAction { + key: string; + label: string; + action: (selected: T[]) => void; + confirmMessage?: string; +} + +interface CustomAction { + key: string; + label: string; + action: (row: T) => void; + show?: (row: T) => boolean; +} +``` + +--- + +## 🟢 Hiển thị Trạng Thái (`displayType: "status"`) + +Dùng để hiển thị trạng thái dưới dạng badge màu. Ví dụ các trạng thái như `"active"`, `"inactive"`, `"pending"`. + +### ✅ Cú pháp: + +```ts +{ + key: "status", + label: "Trạng thái", + displayType: "status", + displayOptions: { + statusMap: { + active: { + label: "Hoạt động", + variant: "default", + }, + inactive: { + label: "Ngừng hoạt động", + variant: "secondary", + }, + pending: { + label: "Đang chờ", + variant: "outline", + }, + }, + }, +} +``` + +### 🎨 Tuỳ chọn nâng cao với màu cụ thể (dùng Tailwind): + +```ts +{ + key: "status", + label: "Trạng thái", + displayType: "status", + displayOptions: { + statusMap: { + active: { + label: "Hoạt động", + variant: "default", + color: "bg-green-100 text-green-800 border-green-200", + }, + inactive: { + label: "Ngừng hoạt động", + variant: "secondary", + color: "bg-gray-100 text-gray-800 border-gray-200", + }, + pending: { + label: "Đang chờ", + variant: "outline", + color: "bg-yellow-100 text-yellow-800 border-yellow-200", + }, + }, + }, +} +``` + +> 🔁 Nếu `statusMap` không được định nghĩa: +> +> - `label` sẽ là giá trị gốc (`value`) của field +> - `variant` sẽ mặc định là `"default"` + +--- + +## 📦 Ví dụ sử dụng + +```tsx + console.log("Edit:", row)} + onDelete={(row) => console.log("Delete:", row)} + bulkActions={[ + { + key: "delete", + label: "Xoá đã chọn", + variant: "destructive", + confirmMessage: "Bạn có chắc chắn muốn xoá những dòng này?", + action: (rows) => console.log("Bulk delete:", rows), + }, + ]} +/> +``` + +--- + +## ✅ TODO + +- Export CSV / Excel +- Resizable columns +- Grouping columns +- Column reorder / drag-drop diff --git a/client/app/components/core/data-table.tsx b/client/app/components/core/data-table.tsx new file mode 100644 index 0000000..1cb1335 --- /dev/null +++ b/client/app/components/core/data-table.tsx @@ -0,0 +1,2168 @@ +"use client"; + +import type React from "react"; + +import { format } from "date-fns"; +import { vi } from "date-fns/locale"; +import { + ArrowDown, + ArrowUp, + ArrowUpDown, + CalendarIcon, + ChevronLeft, + ChevronRight, + ChevronsLeft, + ChevronsRight, + Edit, + ExternalLink, + Eye, + EyeOff, + Filter, + Mail, + MoreHorizontal, + Phone, + Search, + Star, + StarHalf, + Trash2, + X, +} from "lucide-react"; +import { + useCallback, + useEffect, + useMemo, + useRef, + useState, + type ReactNode, +} from "react"; +import type { DateRange } from "react-day-picker"; +import { Avatar, AvatarFallback, AvatarImage } from "~/components/ui/avatar"; +import { Badge } from "~/components/ui/badge"; +import { Button } from "~/components/ui/button"; +import { Calendar } from "~/components/ui/calendar"; +import { Checkbox } from "~/components/ui/checkbox"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "~/components/ui/dialog"; +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "~/components/ui/dropdown-menu"; +import { Input } from "~/components/ui/input"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "~/components/ui/popover"; +import { Progress } from "~/components/ui/progress"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "~/components/ui/select"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "~/components/ui/table"; +import { ConfirmAlert } from "../btn/confirm-alert"; + +export interface Column { + key: keyof T; + label: string; + sortable?: boolean; + filterable?: boolean; + displayType?: + | "text" + | "password" + | "image" + | "avatar" + | "badge" + | "currency" + | "date" + | "datetime" + | "boolean" + | "progress" + | "link" + | "email" + | "phone" + | "tags" + | "status" + | "rating" + | "filesize" + | "percentage" + | "custom"; + displayOptions?: { + // For badge + badgeVariant?: "default" | "secondary" | "destructive" | "outline"; + badgeColorMap?: Record; + + // For currency + currency?: string; + locale?: string; + + // For date + dateFormat?: string; + + // For boolean + trueLabel?: string; + falseLabel?: string; + + // For progress + showPercentage?: boolean; + colorThreshold?: { value: number; color: string }[]; + + // For link + openInNewTab?: boolean; + + // For avatar + fallbackText?: (row: T) => string; + + // For status + statusMap?: Record< + string, + { + label: string; + variant: "default" | "secondary" | "destructive" | "outline"; + color?: string; + } + >; + + // For rating + maxRating?: number; + showHalfStars?: boolean; + + // For tags + maxTags?: number; + tagVariant?: "default" | "secondary" | "destructive" | "outline"; + }; + render?: (value: any, row: T) => React.ReactNode; +} + +// Thêm interface cho custom actions +interface CustomAction { + key: string; + label: string; + icon?: React.ReactNode; + variant?: "default" | "secondary" | "destructive" | "outline"; + action: (row: T) => void; + show?: (row: T) => boolean; // Điều kiện hiển thị action +} + +export interface InitialState { + pagination?: { + currentPage?: number; + pageSize?: number; + }; + search?: string; + sort?: { + key: keyof T; + direction: "asc" | "desc"; + }; + filters?: { + select?: Record; + text?: Record; + date?: Record; + dateRange?: Record; + number?: Record; + numberRange?: Record; + }; +} + +export interface TableState { + pagination: { + currentPage: number; + pageSize: number; + totalPages: number; + totalItems: number; + startIndex: number; + endIndex: number; + }; + search: string; + sort: { + key: keyof T | null; + direction: "asc" | "desc"; + }; + filters: { + select: Record; + text: Record; + date: Record; + dateRange: Record; + number: Record; + numberRange: Record; + not?: Record; + }; + data: { + filtered: T[]; + sorted: T[]; + paginated: T[]; + }; + selection: T[]; +} + +export interface DataTableProps { + data: T[]; + columns: Column[]; + searchKeys?: (keyof T)[]; + filterOptions?: FilterOption[]; + pageSize?: number; + onPageSizeChange?: (newPageSize: number) => void; + onRowClick?: (row: T) => void; + onEdit?: (row: T) => void; + onDelete?: (row: T) => void; + onView?: (row: T) => void; + selectable?: boolean; + onSelectionChange?: (selectedRows: T[]) => void; + // Thêm các callback mới + onSortChange?: (sortConfig: { + key: keyof T | null; + direction: "asc" | "desc"; + }) => void; + onFilterChange?: (filters: { + search: string; + select: Record; + text: Record; + date: Record; + dateRange: Record; + number: Record; + numberRange: Record; + }) => void; + onDataChange?: (data: { + filtered: T[]; + sorted: T[]; + paginated: T[]; + totalPages: number; + currentPage: number; + }) => void; + bulkActions?: BulkAction[]; + customActions?: CustomAction[]; // Thêm prop cho custom actions + onPaginationChange?: (pagination: PaginationData) => void; + // Thêm pagination props để control từ bên ngoài + pagination?: PaginationData; + loading?: boolean; + initialState?: InitialState; + onStateChange?: (state: TableState) => void; + options?: { + disableDel?: boolean | ((data: T) => boolean); + }; +} + +export function DataTable>({ + data, + columns, + searchKeys = [], + filterOptions = [], + pageSize = 10, + onPageSizeChange, + onRowClick, + onEdit, + onDelete, + onView, + selectable = false, + onSelectionChange, + onSortChange, + onFilterChange, + onDataChange, + bulkActions = [], + customActions = [], // Thêm prop mới + onPaginationChange, + pagination, + loading = false, + initialState, // Add this line + onStateChange, + options, +}: DataTableProps) { + const [searchTerm, setSearchTerm] = useState(initialState?.search || ""); + const [sortConfig, setSortConfig] = useState<{ + key: keyof T | null; + direction: "asc" | "desc"; + }>(initialState?.sort || { key: null, direction: "asc" }); + + // Different filter states for different types + const [filters, setFilters] = useState>( + initialState?.filters?.select || {} + ); + const [textFilters, setTextFilters] = useState>( + initialState?.filters?.text || {} + ); + const [dateFilters, setDateFilters] = useState< + Record + >(initialState?.filters?.date || {}); + const [dateRangeFilters, setDateRangeFilters] = useState< + Record + >(initialState?.filters?.dateRange || {}); + const [numberFilters, setNumberFilters] = useState< + Record + >(initialState?.filters?.number || {}); + const [numberRangeFilters, setNumberRangeFilters] = useState< + Record + >(initialState?.filters?.numberRange || {}); + + // Thêm sau các state hiện tại + const [pendingFilters, setPendingFilters] = useState< + Record + >(initialState?.filters?.select || {}); + const [pendingTextFilters, setPendingTextFilters] = useState< + Record + >(initialState?.filters?.text || {}); + const [pendingDateFilters, setPendingDateFilters] = useState< + Record + >(initialState?.filters?.date || {}); + const [pendingDateRangeFilters, setPendingDateRangeFilters] = useState< + Record + >(initialState?.filters?.dateRange || {}); + const [pendingNumberFilters, setPendingNumberFilters] = useState< + Record + >(initialState?.filters?.number || {}); + const [pendingNumberRangeFilters, setPendingNumberRangeFilters] = useState< + Record + >(initialState?.filters?.numberRange || {}); + const [pendingSearchTerm, setPendingSearchTerm] = useState( + initialState?.search || "" + ); + + // Thêm state cho search độc lập + const [localSearchTerm, setLocalSearchTerm] = useState( + initialState?.search || "" + ); + const searchTimeoutRef = useRef(null); + + // Debounced search function + const debouncedSearch = useCallback( + (term: string) => { + if (searchTimeoutRef.current) { + clearTimeout(searchTimeoutRef.current); + } + + searchTimeoutRef.current = setTimeout(() => { + setSearchTerm(term); + // Reset to page 1 when searching + if (pagination) { + onPaginationChange?.({ + ...pagination, + currentPage: 1, + }); + } else { + setInternalCurrentPage(1); + } + }, 300); // 300ms delay + }, + [pagination, onPaginationChange] + ); + + // Handle immediate search (Enter key) + const handleImmediateSearch = useCallback(() => { + if (searchTimeoutRef.current) { + clearTimeout(searchTimeoutRef.current); + } + setSearchTerm(localSearchTerm); + // Reset to page 1 when searching + if (pagination) { + onPaginationChange?.({ + ...pagination, + currentPage: 1, + }); + } else { + setInternalCurrentPage(1); + } + }, [localSearchTerm, pagination, onPaginationChange]); + + // Handle search input change + const handleSearchChange = useCallback( + (value: string) => { + setLocalSearchTerm(value); + setPendingSearchTerm(value); // Sync with pending for modal + + // Auto search with debounce + debouncedSearch(value); + }, + [debouncedSearch] + ); + + // Handle Enter key press + const handleSearchKeyPress = useCallback( + (e: React.KeyboardEvent) => { + if (e.key === "Enter") { + e.preventDefault(); + handleImmediateSearch(); + } + }, + [handleImmediateSearch] + ); + + // Cleanup timeout on unmount + useEffect(() => { + return () => { + if (searchTimeoutRef.current) { + clearTimeout(searchTimeoutRef.current); + } + }; + }, []); + + const [showBulkConfirm, setShowBulkConfirm] = useState(false); + const [pendingBulkAction, setPendingBulkAction] = + useState | null>(null); + + // Sử dụng internal pagination state nếu không có pagination props + const [internalCurrentPage, setInternalCurrentPage] = useState( + initialState?.pagination?.currentPage || 1 + ); + const [selectedRows, setSelectedRows] = useState([]); + const [showFilterModal, setShowFilterModal] = useState(false); + const [visiblePasswords, setVisiblePasswords] = useState>( + new Set() + ); + + // Use refs to track previous values and prevent unnecessary callback calls + const prevSortConfigRef = useRef<{ + key: keyof T | null; + direction: "asc" | "desc"; + }>({ key: null, direction: "asc" }); + const prevFiltersRef = useRef<{ + search: string; + select: Record; + text: Record; + date: Record; + dateRange: Record; + number: Record; + numberRange: Record; + }>({ + search: "", + select: {}, + text: {}, + date: {}, + dateRange: {}, + number: {}, + numberRange: {}, + }); + const prevDataRef = useRef<{ + filtered: T[]; + sorted: T[]; + paginated: T[]; + totalPages: number; + currentPage: number; + }>({ + filtered: [], + sorted: [], + paginated: [], + totalPages: 0, + currentPage: 1, + }); + const prevPaginationRef = useRef({ + currentPage: 1, + pageSize: 10, + totalPages: 0, + totalItems: 0, + startIndex: 0, + endIndex: 0, + }); + + const prevTableStateRef = useRef | null>(null); + + // Determine current pagination values + const currentPage = pagination?.currentPage ?? internalCurrentPage; + const currentPageSize = + pagination?.pageSize ?? initialState?.pagination?.pageSize ?? pageSize; + const totalPages = + pagination?.totalPages ?? Math.ceil(data.length / currentPageSize); + const totalItems = pagination?.totalItems ?? data.length; + + const filteredData = useMemo(() => { + // Nếu có pagination props, nghĩa là data đã được filter/sort từ server + if (pagination) { + return data; + } + + // Nếu không có pagination props, thực hiện client-side filtering + let filtered = data; + + // Apply search + if (searchTerm && searchKeys.length > 0) { + filtered = filtered.filter((item) => + searchKeys.some((key) => + String(item[key]).toLowerCase().includes(searchTerm.toLowerCase()) + ) + ); + } + + // Apply select filters + Object.entries(filters).forEach(([filterKey, filterValues]) => { + if (filterValues.length > 0) { + filtered = filtered.filter((item) => + filterValues.includes(String(item[filterKey])) + ); + } + }); + + // Apply text filters + Object.entries(textFilters).forEach(([filterKey, filterValue]) => { + if (filterValue.trim()) { + filtered = filtered.filter((item) => + String(item[filterKey]) + .toLowerCase() + .includes(filterValue.toLowerCase()) + ); + } + }); + + // Apply date filters + Object.entries(dateFilters).forEach(([filterKey, filterValue]) => { + if (filterValue) { + filtered = filtered.filter((item) => { + const itemDate = new Date(item[filterKey]); + return itemDate.toDateString() === filterValue.toDateString(); + }); + } + }); + + // Apply date range filters + Object.entries(dateRangeFilters).forEach(([filterKey, filterValue]) => { + if (filterValue.from || filterValue.to) { + filtered = filtered.filter((item) => { + const itemDate = new Date(item[filterKey]); + if (filterValue.from && itemDate < filterValue.from) return false; + if (filterValue.to && itemDate > filterValue.to) return false; + return true; + }); + } + }); + + // Apply number filters + Object.entries(numberFilters).forEach(([filterKey, filterValue]) => { + if (filterValue !== undefined) { + filtered = filtered.filter( + (item) => Number(item[filterKey]) === filterValue + ); + } + }); + + // Apply number range filters + Object.entries(numberRangeFilters).forEach(([filterKey, filterValue]) => { + if (filterValue.min !== undefined || filterValue.max !== undefined) { + filtered = filtered.filter((item) => { + const itemValue = Number(item[filterKey]); + if (filterValue.min !== undefined && itemValue < filterValue.min) + return false; + if (filterValue.max !== undefined && itemValue < filterValue.max) + return false; + return true; + }); + } + }); + + return filtered; + }, [ + data, + searchTerm, + searchKeys, + filters, + textFilters, + dateFilters, + dateRangeFilters, + numberFilters, + numberRangeFilters, + pagination, + ]); + + const sortedData = useMemo(() => { + // Nếu có pagination props, data đã được sort từ server + if (pagination) { + return filteredData; + } + + if (!sortConfig.key) return filteredData; + + return [...filteredData].sort((a, b) => { + const aValue = a[sortConfig.key!]; + const bValue = b[sortConfig.key!]; + + if (aValue < bValue) { + return sortConfig.direction === "asc" ? -1 : 1; + } + if (aValue > bValue) { + return sortConfig.direction === "asc" ? 1 : -1; + } + return 0; + }); + }, [filteredData, sortConfig, pagination]); + + const paginatedData = useMemo(() => { + // Nếu có pagination props, data đã được paginate từ server + if (pagination) { + return sortedData; + } + + // Client-side pagination + const startIndex = (currentPage - 1) * currentPageSize; + return sortedData.slice(startIndex, startIndex + currentPageSize); + }, [sortedData, currentPage, currentPageSize, pagination]); + + const handleSort = (key: keyof T) => { + const newSortConfig = { + key, + direction: (sortConfig.key === key && sortConfig.direction === "asc" + ? "desc" + : "asc") as "asc" | "desc", + }; + setSortConfig(newSortConfig); + }; + + const handleClearSort = () => { + setSortConfig({ key: null, direction: "asc" }); + }; + + const handleFilterChange = ( + filterKey: string, + value: string, + checked: boolean + ) => { + setPendingFilters((prev) => { + const currentValues = prev[filterKey] || []; + if (checked) { + return { ...prev, [filterKey]: [...currentValues, value] }; + } else { + return { + ...prev, + [filterKey]: currentValues.filter((v) => v !== value), + }; + } + }); + }; + + const handleTextFilterChange = (filterKey: string, value: string) => { + setPendingTextFilters((prev) => ({ ...prev, [filterKey]: value })); + }; + + const handleDateFilterChange = ( + filterKey: string, + date: Date | undefined + ) => { + setPendingDateFilters((prev) => ({ ...prev, [filterKey]: date })); + }; + + const handleDateRangeFilterChange = ( + filterKey: string, + range: { from?: Date; to?: Date } + ) => { + setPendingDateRangeFilters((prev) => ({ ...prev, [filterKey]: range })); + }; + + const handleNumberFilterChange = ( + filterKey: string, + value: number | undefined + ) => { + setPendingNumberFilters((prev) => ({ ...prev, [filterKey]: value })); + }; + + const handleNumberRangeFilterChange = ( + filterKey: string, + range: { min?: number; max?: number } + ) => { + setPendingNumberRangeFilters((prev) => ({ ...prev, [filterKey]: range })); + }; + + const applyFilters = () => { + setFilters(pendingFilters); + setTextFilters(pendingTextFilters); + setDateFilters(pendingDateFilters); + setDateRangeFilters(pendingDateRangeFilters); + setNumberFilters(pendingNumberFilters); + setNumberRangeFilters(pendingNumberRangeFilters); + setSearchTerm(pendingSearchTerm); + + // Reset to page 1 when applying filters + if (pagination) { + onPaginationChange?.({ + ...pagination, + currentPage: 1, + }); + } else { + setInternalCurrentPage(1); + } + }; + + const resetPendingFilters = () => { + setPendingFilters(filters); + setTextFilters(textFilters); + setDateFilters(dateFilters); + setDateRangeFilters(dateRangeFilters); + setNumberFilters(numberFilters); + setNumberRangeFilters(numberRangeFilters); + setPendingSearchTerm(searchTerm); + }; + + const clearAllFilters = () => { + setFilters({}); + setTextFilters({}); + setDateFilters({}); + setDateRangeFilters({}); + setNumberFilters({}); + setNumberRangeFilters({}); + setSearchTerm(""); + setLocalSearchTerm(""); // Thêm dòng này + // Also clear pending + setPendingFilters({}); + setPendingTextFilters({}); + setPendingDateFilters({}); + setPendingDateRangeFilters({}); + setPendingNumberFilters({}); + setPendingNumberRangeFilters({}); + setPendingSearchTerm(""); + + // Clear search timeout + if (searchTimeoutRef.current) { + clearTimeout(searchTimeoutRef.current); + } + }; + + const getActiveFiltersCount = () => { + return ( + Object.keys(filters).reduce((acc, key) => acc + filters[key].length, 0) + + Object.keys(textFilters).filter((key) => textFilters[key].trim()).length + + Object.keys(dateFilters).filter((key) => dateFilters[key]).length + + Object.keys(dateRangeFilters).filter( + (key) => dateRangeFilters[key].from || dateRangeFilters[key].to + ).length + + Object.keys(numberFilters).filter( + (key) => numberFilters[key] !== undefined + ).length + + Object.keys(numberRangeFilters).filter( + (key) => + numberRangeFilters[key].min !== undefined || + numberRangeFilters[key].max !== undefined + ).length + ); + }; + + const hasActiveFilters = () => { + return ( + Object.keys(filters).some((key) => filters[key].length > 0) || + Object.keys(textFilters).some((key) => textFilters[key].trim()) || + Object.keys(dateFilters).some((key) => dateFilters[key]) || + Object.keys(dateRangeFilters).some( + (key) => dateRangeFilters[key].from || dateRangeFilters[key].to + ) || + Object.keys(numberFilters).some( + (key) => numberFilters[key] !== undefined + ) || + Object.keys(numberRangeFilters).some( + (key) => + numberRangeFilters[key].min !== undefined || + numberRangeFilters[key].max !== undefined + ) || + searchTerm.trim() || + localSearchTerm.trim() // Thêm localSearchTerm + ); + }; + + const hasPendingChanges = () => { + return ( + JSON.stringify(pendingFilters) !== JSON.stringify(filters) || + JSON.stringify(pendingTextFilters) !== JSON.stringify(textFilters) || + JSON.stringify(pendingDateFilters) !== JSON.stringify(dateFilters) || + JSON.stringify(pendingDateRangeFilters) !== + JSON.stringify(dateRangeFilters) || + JSON.stringify(pendingNumberFilters) !== JSON.stringify(numberFilters) || + JSON.stringify(pendingNumberRangeFilters) !== + JSON.stringify(numberRangeFilters) || + pendingSearchTerm !== searchTerm + ); + }; + + const handleRowSelection = (row: T, checked: boolean) => { + const newSelection = checked + ? [...selectedRows, row] + : selectedRows.filter((r) => r !== row); + + setSelectedRows(newSelection); + onSelectionChange?.(newSelection); + }; + + const handleSelectAll = (checked: boolean) => { + const newSelection = checked ? paginatedData : []; + setSelectedRows(newSelection); + onSelectionChange?.(newSelection); + }; + + const handleBulkAction = (action: BulkAction) => { + if (action.confirmMessage) { + setPendingBulkAction(action); + setShowBulkConfirm(true); + } else { + action.action(selectedRows); + } + }; + + const confirmBulkAction = () => { + if (pendingBulkAction) { + pendingBulkAction.action(selectedRows); + setPendingBulkAction(null); + } + setShowBulkConfirm(false); + }; + + const cancelBulkAction = () => { + setPendingBulkAction(null); + setShowBulkConfirm(false); + }; + + // Pagination handlers + const handlePageChange = (newPage: number) => { + if (pagination && onPaginationChange) { + onPaginationChange({ + ...pagination, + currentPage: newPage, + }); + } else { + setInternalCurrentPage(newPage); + } + }; + + const handlePageSizeChange = (newPageSize: number) => { + if (pagination && onPaginationChange) { + onPaginationChange({ + ...pagination, + pageSize: newPageSize, + currentPage: 1, // Reset to first page when changing page size + }); + } else { + setInternalCurrentPage(1); + onPageSizeChange?.(newPageSize); + } + }; + + const getSortIcon = (key: keyof T) => { + if (sortConfig.key !== key) { + return ; + } + return sortConfig.direction === "asc" ? ( + + ) : ( + + ); + }; + + const renderFilter = (filterOption: FilterOption) => { + switch (filterOption.type) { + case "select": + return ( + + + + + + {filterOption.label} + + {filterOption.options?.map((option) => ( + + handleFilterChange(filterOption.key, option.value, checked) + } + > + {option.label} + + ))} + + + ); + + case "text": + return ( +
+ + handleTextFilterChange(filterOption.key, e.target.value) + } + className="w-full" + /> + {pendingTextFilters[filterOption.key] && ( + + )} +
+ ); + + case "date": + return ( + + + + + + + handleDateFilterChange(filterOption.key, date) + } + initialFocus + /> + {pendingDateFilters[filterOption.key] && ( +
+ +
+ )} +
+
+ ); + + case "dateRange": + const dateRange = pendingDateRangeFilters[filterOption.key] || {}; + return ( + + + + + + + handleDateRangeFilterChange(filterOption.key, range || {}) + } + numberOfMonths={2} + initialFocus + /> + {(dateRange.from || dateRange.to) && ( +
+ +
+ )} +
+
+ ); + + case "number": + return ( +
+ + handleNumberFilterChange( + filterOption.key, + e.target.value ? Number(e.target.value) : undefined + ) + } + min={filterOption.min} + max={filterOption.max} + className="w-full" + /> + {pendingNumberFilters[filterOption.key] !== undefined && ( + + )} +
+ ); + + case "numberRange": + const numberRange = pendingNumberRangeFilters[filterOption.key] || {}; + return ( + + + + + +
+
+ + + handleNumberRangeFilterChange(filterOption.key, { + ...numberRange, + min: e.target.value + ? Number(e.target.value) + : undefined, + }) + } + min={filterOption.min} + max={filterOption.max} + /> +
+
+ + + handleNumberRangeFilterChange(filterOption.key, { + ...numberRange, + max: e.target.value + ? Number(e.target.value) + : undefined, + }) + } + min={filterOption.min} + max={filterOption.max} + /> +
+ {(numberRange.min !== undefined || + numberRange.max !== undefined) && ( + + )} +
+
+
+ ); + + default: + return null; + } + }; + + const renderDisplayType = (column: Column, value: any, row: T) => { + const { displayType, displayOptions = {} } = column; + + switch (displayType) { + case "password": + const passwordKey = `${String(column.key)}-${row.id || Math.random()}`; + const isVisible = visiblePasswords.has(passwordKey); + return ( +
+ + {isVisible ? value : "••••••••"} + + +
+ ); + + case "image": + return ( + Image + ); + + case "avatar": + const fallback = displayOptions.fallbackText + ? displayOptions.fallbackText(row) + : String(value).charAt(0).toUpperCase(); + return ( + + + {fallback} + + ); + + case "badge": + const badgeVariant = displayOptions.badgeVariant || "default"; + const colorMap = displayOptions.badgeColorMap || {}; + const badgeColor = colorMap[String(value)]; + return ( + + {value} + + ); + + case "currency": + const currency = displayOptions.currency || "VND"; + const locale = displayOptions.locale || "vi-VN"; + return new Intl.NumberFormat(locale, { + style: "currency", + currency: currency, + }).format(Number(value)); + + case "date": + const dateFormat = displayOptions.dateFormat || "dd/MM/yyyy"; + return format(new Date(value), dateFormat, { locale: vi }); + + case "datetime": + return format(new Date(value), "dd/MM/yyyy HH:mm", { locale: vi }); + + case "boolean": + const trueLabel = displayOptions.trueLabel || "Có"; + const falseLabel = displayOptions.falseLabel || "Không"; + const boolValue = Boolean(value); + return ( + + {boolValue ? trueLabel : falseLabel} + + ); + + case "progress": + const percentage = Math.min(100, Math.max(0, Number(value))); + const showPercentage = displayOptions.showPercentage !== false; + const thresholds = displayOptions.colorThreshold || []; + + let progressColor = "bg-primary"; + for (const threshold of thresholds) { + if (percentage >= threshold.value) { + progressColor = threshold.color; + } + } + + return ( +
+ + {showPercentage && ( + + {percentage}% + + )} +
+ ); + + case "link": + const openInNewTab = displayOptions.openInNewTab !== false; + return ( + e.stopPropagation()} + > + {value} + {openInNewTab && } + + ); + + case "email": + return ( + e.stopPropagation()} + > + + {value} + + ); + + case "phone": + return ( + e.stopPropagation()} + > + + {value} + + ); + + case "tags": + const tags = Array.isArray(value) + ? value + : String(value) + .split(",") + .map((s) => s.trim()); + const maxTags = displayOptions.maxTags || 3; + const tagVariant = displayOptions.tagVariant || "secondary"; + const visibleTags = tags.slice(0, maxTags); + const remainingCount = tags.length - maxTags; + + return ( +
+ {visibleTags.map((tag, index) => ( + + {tag} + + ))} + {remainingCount > 0 && ( + + +{remainingCount} + + )} +
+ ); + + case "status": + const statusMap = displayOptions.statusMap || {}; + const statusConfig = statusMap[String(value)] || { + label: String(value), + variant: "default" as const, + }; + return ( + + {statusConfig.label} + + ); + + case "rating": + const rating = Number(value); + const maxRating = displayOptions.maxRating || 5; + const showHalfStars = displayOptions.showHalfStars !== false; + + return ( +
+
+ {Array.from({ length: maxRating }, (_, i) => { + const starValue = i + 1; + if (rating >= starValue) { + return ( + + ); + } else if (showHalfStars && rating >= starValue - 0.5) { + return ( + + ); + } else { + return ; + } + })} +
+ ({rating}) +
+ ); + + case "filesize": + const bytes = Number(value); + const sizes = ["Bytes", "KB", "MB", "GB", "TB"]; + if (bytes === 0) return "0 Bytes"; + const i = Math.floor(Math.log(bytes) / Math.log(1024)); + return ( + Math.round((bytes / Math.pow(1024, i)) * 100) / 100 + " " + sizes[i] + ); + + case "percentage": + return `${Number(value).toFixed(1)}%`; + + case "custom": + return column.render ? column.render(value, row) : String(value); + + default: + return String(value); + } + }; + + // Function để render action menu + const renderActionMenu = (row: T) => { + // Kiểm tra xem có action nào để hiển thị không + const hasDefaultActions = onView || onEdit || onDelete; + const visibleCustomActions = customActions.filter( + (action) => !action.show || action.show(row) + ); + const hasActions = hasDefaultActions || visibleCustomActions.length > 0; + + if (!hasActions) return null; + + return ( + + +
+ +
+
+ + {/* Default actions */} + {onView && ( + onView(row)} + className="cursor-pointer" + > + + Xem + + )} + {onEdit && ( + onEdit(row)} + className="cursor-pointer" + > + + Sửa + + )} + + {/* Custom actions */} + {visibleCustomActions.map((action) => ( + action.action(row)} + className={`cursor-pointer ${ + action.variant === "destructive" + ? "text-destructive focus:text-destructive" + : "" + }`} + > + {action.icon && {action.icon}} + {action.label} + + ))} + + {/* Separator before delete if there are other actions */} + {onDelete && + (hasDefaultActions || visibleCustomActions.length > 0) && ( + + )} + + {/* Delete action (always last) */} + {onDelete && ( + { + e.preventDefault(); // Ngăn dropdown đóng lại + e.stopPropagation(); + }} + > + onDelete(row)}> +
+ + Xóa +
+
+
+ )} +
+
+ ); + }; + + // Only call callbacks when values actually change + useEffect(() => { + const currentSortConfig = sortConfig; + if ( + JSON.stringify(currentSortConfig) !== + JSON.stringify(prevSortConfigRef.current) && + onSortChange + ) { + prevSortConfigRef.current = currentSortConfig; + onSortChange(currentSortConfig); + } + }, [sortConfig, onSortChange]); + + useEffect(() => { + const currentFilters = { + search: searchTerm, + select: filters, + text: textFilters, + date: dateFilters, + dateRange: dateRangeFilters, + number: numberFilters, + numberRange: numberRangeFilters, + }; + + if ( + JSON.stringify(currentFilters) !== + JSON.stringify(prevFiltersRef.current) && + onFilterChange + ) { + prevFiltersRef.current = currentFilters; + onFilterChange(currentFilters); + } + }, [ + searchTerm, + filters, + textFilters, + dateFilters, + dateRangeFilters, + numberFilters, + numberRangeFilters, + onFilterChange, + ]); + + useEffect(() => { + const currentData = { + filtered: filteredData, + sorted: sortedData, + paginated: paginatedData, + totalPages, + currentPage, + }; + + if ( + JSON.stringify(currentData) !== JSON.stringify(prevDataRef.current) && + onDataChange + ) { + prevDataRef.current = currentData; + onDataChange(currentData); + } + }, [ + filteredData, + sortedData, + paginatedData, + totalPages, + currentPage, + onDataChange, + ]); + + useEffect(() => { + const startIndex = (currentPage - 1) * currentPageSize + 1; + const endIndex = Math.min(currentPage * currentPageSize, totalItems); + + const currentPagination = { + currentPage, + pageSize: currentPageSize, + totalPages, + totalItems, + startIndex, + endIndex, + }; + + if ( + JSON.stringify(currentPagination) !== + JSON.stringify(prevPaginationRef.current) && + onPaginationChange && + !pagination + ) { + prevPaginationRef.current = currentPagination; + onPaginationChange(currentPagination); + } + }, [ + currentPage, + currentPageSize, + totalPages, + totalItems, + onPaginationChange, + pagination, + ]); + + useEffect(() => { + const startIndex = (currentPage - 1) * currentPageSize + 1; + const endIndex = Math.min(currentPage * currentPageSize, totalItems); + + const currentTableState: TableState = { + pagination: { + currentPage, + pageSize: currentPageSize, + totalPages, + totalItems, + startIndex, + endIndex, + }, + search: searchTerm, + sort: sortConfig, + filters: { + select: filters, + text: textFilters, + date: dateFilters, + dateRange: dateRangeFilters, + number: numberFilters, + numberRange: numberRangeFilters, + }, + data: { + filtered: filteredData, + sorted: sortedData, + paginated: paginatedData, + }, + selection: selectedRows, + }; + + if ( + JSON.stringify(currentTableState) !== + JSON.stringify(prevTableStateRef.current) && + onStateChange + ) { + prevTableStateRef.current = currentTableState; + onStateChange(currentTableState); + } + }, [ + currentPage, + currentPageSize, + totalPages, + totalItems, + searchTerm, + sortConfig, + filters, + textFilters, + dateFilters, + dateRangeFilters, + numberFilters, + numberRangeFilters, + filteredData, + sortedData, + paginatedData, + selectedRows, + onStateChange, + ]); + + return ( +
+ {/* Search and Filter Toggle */} +
+
+ {searchKeys.length > 0 && ( +
+ + handleSearchChange(e.target.value)} + onKeyPress={handleSearchKeyPress} + className="pl-8 pr-8" + disabled={loading} + /> + {localSearchTerm && localSearchTerm !== searchTerm && ( +
+
+
+ )} + {localSearchTerm && ( + + )} +
+ )} + +
+ {filterOptions.length > 0 && ( + + + + + + + Advanced Filters + + Customize filter criteria to find more precise data + + + + {/* Filter content */} +
+ {/* Organized Filter Groups - Responsive Grid */} +
+ {/* Quick Filters (Select types) */} + {filterOptions.filter((f) => f.type === "select").length > + 0 && ( +
+ +
+ {filterOptions + .filter((f) => f.type === "select") + .map(renderFilter)} +
+
+ )} + + {/* Text Filters */} + {filterOptions.filter((f) => f.type === "text").length > + 0 && ( +
+ +
+ {filterOptions + .filter((f) => f.type === "text") + .map(renderFilter)} +
+
+ )} + + {/* Date Filters */} + {filterOptions.filter( + (f) => f.type === "date" || f.type === "dateRange" + ).length > 0 && ( +
+ +
+ {filterOptions + .filter( + (f) => + f.type === "date" || f.type === "dateRange" + ) + .map(renderFilter)} +
+
+ )} + + {/* Number Filters */} + {filterOptions.filter( + (f) => f.type === "number" || f.type === "numberRange" + ).length > 0 && ( +
+ +
+ {filterOptions + .filter( + (f) => + f.type === "number" || + f.type === "numberRange" + ) + .map(renderFilter)} +
+
+ )} +
+ + {/* Filter Summary */} +
+
+
+
+ {getActiveFiltersCount()} Filter is applied +
+ {hasPendingChanges() && ( + + There are changes not yet applied + + )} +
+ +
+
+
+ + + +
+ + +
+
+
+
+ )} + + {/* Bulk Actions Menu - Moved here */} + {selectedRows.length > 0 && bulkActions.length > 0 && ( + + + + + + Multiple actions + + {bulkActions.map((action) => ( + handleBulkAction(action)} + className={`cursor-pointer ${ + action.variant === "destructive" + ? "text-destructive focus:text-destructive" + : "" + }`} + > + {action.icon && ( + {action.icon} + )} + {action.label} + + ))} + + { + setSelectedRows([]); + onSelectionChange?.([]); + }} + className="cursor-pointer text-muted-foreground" + > + + Clear selected + + + + )} + + {sortConfig.key && ( + + )} + + {hasActiveFilters() && ( + + )} +
+
+
+ + {/* Table */} +
+ + + + {selectable && ( + + 0 && + paginatedData.every((row) => selectedRows.includes(row)) + } + onCheckedChange={handleSelectAll} + disabled={loading} + /> + + )} + {columns.map((column) => ( + + {column.sortable ? ( + + ) : ( + column.label + )} + + ))} + {(onEdit || onDelete || onView || customActions.length > 0) && ( + + Action + + )} + + + + {loading ? ( + + 0 + ? 1 + : 0) + } + className="h-24 text-center" + > +
+
+ Loading... +
+
+
+ ) : paginatedData.length === 0 ? ( + + 0 + ? 1 + : 0) + } + className="h-24 text-center" + > + No Data. + + + ) : ( + paginatedData.map((row, index) => ( + !loading && onRowClick?.(row)} + > + {selectable && ( + + + handleRowSelection(row, checked) + } + onClick={(e) => e.stopPropagation()} + disabled={loading} + /> + + )} + {columns.map((column) => ( + + {renderDisplayType(column, row[column.key], row)} + + ))} + {(onEdit || + onDelete || + onView || + customActions.length > 0) && ( + + {renderActionMenu(row)} + + )} + + )) + )} +
+
+
+ + {/* Pagination */} +
+
+

Show

+ +

{totalItems} result

+
+ + {totalPages > 1 && ( +
+

+ Trang {currentPage} / {totalPages} +

+
+ + + + +
+
+ )} +
+ + {/* Bulk Action Confirmation Dialog */} + {showBulkConfirm && pendingBulkAction && ( +
+
+

Confirm action

+

+ {pendingBulkAction.confirmMessage} +

+

+ This action will be applied to the selected item{" "} + {selectedRows.length}. +

+
+ + +
+
+
+ )} +
+ ); +} diff --git a/client/app/components/core/type.d.ts b/client/app/components/core/type.d.ts new file mode 100644 index 0000000..c911972 --- /dev/null +++ b/client/app/components/core/type.d.ts @@ -0,0 +1,82 @@ +interface FilterOption { + key: string; + label: string; + type: "select" | "text" | "date" | "dateRange" | "number" | "numberRange"; + options?: { value: string; label: string }[]; + placeholder?: string; + min?: number; + max?: number; +} + +interface BulkAction { + key: string; + label: string; + icon?: React.ReactNode; + variant?: "default" | "secondary" | "destructive" | "outline"; + action: (selectedRows: T[]) => void; + confirmMessage?: string; +} + +interface PaginationData { + currentPage: number; + pageSize: number; + totalPages: number; + totalItems: number; + startIndex: number; + endIndex: number; +} + +interface InitialState { + pagination?: { + currentPage?: number; + pageSize?: number; + }; + search?: string; + sort?: { + key: keyof T; + direction: "asc" | "desc"; + }; + filters?: { + select?: Record; + text?: Record; + date?: Record; + dateRange?: Record; + number?: Record; + numberRange?: Record; + }; +} + +interface TableState { + pagination: { + currentPage: number; + pageSize: number; + totalPages: number; + totalItems: number; + startIndex: number; + endIndex: number; + }; + search: string; + sort: { + key: keyof T | null; + direction: "asc" | "desc"; + }; + filters: { + select: Record; + text: Record; + date: Record; + dateRange: Record; + number: Record; + numberRange: Record; + }; + data: { + filtered: T[]; + sorted: T[]; + paginated: T[]; + }; + selection: T[]; +} + +interface SortOption { + key: keyof T; + label: string; +} diff --git a/client/app/components/input-password.tsx b/client/app/components/input-password.tsx new file mode 100644 index 0000000..1ee32da --- /dev/null +++ b/client/app/components/input-password.tsx @@ -0,0 +1,25 @@ +import { Eye, EyeOff } from "lucide-react"; +import { useState, type ComponentProps } from "react"; +import { Button } from "./ui/button"; +import { Input } from "./ui/input"; + +export interface IInputPasswordProps {} + +export default function InputPassword(props: ComponentProps<"input">) { + const [open, setOpen] = useState(false); + + return ( +
+ + +
+ ); +} diff --git a/client/app/components/input-search.tsx b/client/app/components/input-search.tsx new file mode 100644 index 0000000..feb8b45 --- /dev/null +++ b/client/app/components/input-search.tsx @@ -0,0 +1,45 @@ +import { Search, X } from "lucide-react"; +import { useState, useEffect, type ComponentProps } from "react"; +import { Button } from "./ui/button"; +import { Input } from "./ui/input"; +import { cn } from "~/lib/utils"; + +export default function InputSearch(props: ComponentProps<"input">) { + const [value, setValue] = useState(String(props.value ?? "")); + + // Đồng bộ khi value từ props thay đổi + useEffect(() => { + setValue(String(props.value ?? "")); + }, [props.value]); + + const handleChange = (newValue: string) => { + setValue(newValue); + props.onChange?.({ + ...({} as any), // Type trick + target: { value: newValue }, + } as React.ChangeEvent); + }; + + return ( +
+ + handleChange(e.target.value)} + value={value} + /> + {value.length > 0 && ( + + )} +
+ ); +} diff --git a/client/app/components/loader.tsx b/client/app/components/loader.tsx new file mode 100644 index 0000000..2b0785a --- /dev/null +++ b/client/app/components/loader.tsx @@ -0,0 +1,37 @@ +import type { DetailedHTMLProps } from "react"; +import { cn } from "~/lib/utils"; + +export interface ILoaderProps + extends DetailedHTMLProps< + React.HTMLAttributes, + HTMLDivElement + > { + size?: string; + showLabel?: boolean; + color?: "black" | "white"; +} + +export default function Loader({ color = "black", ...props }: ILoaderProps) { + return ( +
+
+ + {props.showLabel && Đang tải...} +
+ ); +} diff --git a/client/app/components/login-form.tsx b/client/app/components/login-form.tsx new file mode 100644 index 0000000..3cda4c8 --- /dev/null +++ b/client/app/components/login-form.tsx @@ -0,0 +1,122 @@ +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; +import { cn } from "~/lib/utils"; + +import { Button } from "~/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "~/components/ui/card"; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "~/components/ui/form"; +import { Input } from "~/components/ui/input"; +import { useNavigate } from "react-router"; +import { Links } from "~/lib/links"; +import { authApi } from "~/api/auth-api.service"; + +const loginSchema = z.object({ + input: z.string().email("Email không hợp lệ"), + password: z.string().min(6, "Mật khẩu phải ít nhất 6 ký tự"), +}); + +type LoginFormValues = z.infer; + +export function LoginForm({ + className, + ...props +}: React.ComponentProps<"div">) { + const navigate = useNavigate(); + + const form = useForm({ + resolver: zodResolver(loginSchema), + defaultValues: { + input: "", + password: "", + }, + }); + + const onSubmit = async (values: LoginFormValues) => { + // Gọi API login + const response = await authApi.login(values); + + // Nếu login thành công => reload lại trang + if (response?.data) { + navigate(Links.HOME, { replace: true, state: { from: Links.LOGIN } }); + } + }; + + return ( +
+ + + Login to your account + + Enter your email below to login to your account + + + +
+ +
+ ( + + Email + + + + + + )} + /> + + ( + +
+ Mật khẩu + + Quên mật khẩu? + +
+ + + + +
+ )} + /> + + +
+
+ +
+
+
+ ); +} diff --git a/client/app/components/multi-select.tsx b/client/app/components/multi-select.tsx new file mode 100644 index 0000000..104e49f --- /dev/null +++ b/client/app/components/multi-select.tsx @@ -0,0 +1,381 @@ +// src/components/multi-select.tsx + +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; +import { + CheckIcon, + XCircle, + ChevronDown, + XIcon, + WandSparkles, +} from "lucide-react"; + +import { cn } from "~/lib/utils"; +import { Separator } from "~/components/ui/separator"; +import { Button } from "~/components/ui/button"; +import { Badge } from "~/components/ui/badge"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "~/components/ui/popover"; +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, + CommandSeparator, +} from "~/components/ui/command"; + +/** + * Variants for the multi-select component to handle different styles. + * Uses class-variance-authority (cva) to define different styles based on "variant" prop. + */ +const multiSelectVariants = cva( + "m-1 transition ease-in-out delay-150 hover:-translate-y-1 hover:scale-110 duration-300", + { + variants: { + variant: { + default: + "border-foreground/10 text-foreground bg-card hover:bg-card/80", + secondary: + "border-foreground/10 bg-secondary text-secondary-foreground hover:bg-secondary/80", + destructive: + "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", + inverted: "inverted", + }, + }, + defaultVariants: { + variant: "default", + }, + } +); + +/** + * Props for MultiSelect component + */ +export interface MultiSelectProps + extends React.ButtonHTMLAttributes, + VariantProps { + /** + * An array of option objects to be displayed in the multi-select component. + * Each option object has a label, value, and an optional icon. + */ + options: { + /** The text to display for the option. */ + label: string; + /** The unique value associated with the option. */ + value: string; + /** Optional icon component to display alongside the option. */ + icon?: React.ComponentType<{ className?: string }>; + }[]; + + /** + * Callback function triggered when the selected values change. + * Receives an array of the new selected values. + */ + onValueChange: (value: string[]) => void; + + /** The default selected values when the component mounts. */ + defaultValue?: string[]; + + /** + * Placeholder text to be displayed when no values are selected. + * Optional, defaults to "Select options". + */ + placeholder?: string; + + /** + * Animation duration in seconds for the visual effects (e.g., bouncing badges). + * Optional, defaults to 0 (no animation). + */ + animation?: number; + + /** + * Maximum number of items to display. Extra selected items will be summarized. + * Optional, defaults to 3. + */ + maxCount?: number; + + /** + * The modality of the popover. When set to true, interaction with outside elements + * will be disabled and only popover content will be visible to screen readers. + * Optional, defaults to false. + */ + modalPopover?: boolean; + + /** + * If true, renders the multi-select component as a child of another component. + * Optional, defaults to false. + */ + asChild?: boolean; + + /** + * Additional class names to apply custom styles to the multi-select component. + * Optional, can be used to add custom styles. + */ + className?: string; +} + +export const MultiSelect = React.forwardRef< + HTMLButtonElement, + MultiSelectProps +>( + ( + { + options, + onValueChange, + variant, + defaultValue = [], + placeholder = "Select options", + animation = 0, + maxCount = 3, + modalPopover = false, + asChild = false, + className, + ...props + }, + ref + ) => { + const [selectedValues, setSelectedValues] = + React.useState(defaultValue); + const [isPopoverOpen, setIsPopoverOpen] = React.useState(false); + const [isAnimating, setIsAnimating] = React.useState(false); + + const handleInputKeyDown = ( + event: React.KeyboardEvent + ) => { + if (event.key === "Enter") { + setIsPopoverOpen(true); + } else if (event.key === "Backspace" && !event.currentTarget.value) { + const newSelectedValues = [...selectedValues]; + newSelectedValues.pop(); + setSelectedValues(newSelectedValues); + onValueChange(newSelectedValues); + } + }; + + const toggleOption = (option: string) => { + const newSelectedValues = selectedValues.includes(option) + ? selectedValues.filter((value) => value !== option) + : [...selectedValues, option]; + setSelectedValues(newSelectedValues); + onValueChange(newSelectedValues); + }; + + const handleClear = () => { + setSelectedValues([]); + onValueChange([]); + }; + + const handleTogglePopover = () => { + setIsPopoverOpen((prev) => !prev); + }; + + const clearExtraOptions = () => { + const newSelectedValues = selectedValues.slice(0, maxCount); + setSelectedValues(newSelectedValues); + onValueChange(newSelectedValues); + }; + + const toggleAll = () => { + if (selectedValues.length === options.length) { + handleClear(); + } else { + const allValues = options.map((option) => option.value); + setSelectedValues(allValues); + onValueChange(allValues); + } + }; + + return ( + + + + + setIsPopoverOpen(false)} + > + + + + No results found. + + +
+ +
+ (Select All) +
+ {options.map((option) => { + const isSelected = selectedValues.includes(option.value); + return ( + toggleOption(option.value)} + className="cursor-pointer" + > +
+ +
+ {option.icon && ( + + )} + {option.label} +
+ ); + })} +
+ + +
+ {selectedValues.length > 0 && ( + <> + + Clear + + + + )} + setIsPopoverOpen(false)} + className="flex-1 justify-center cursor-pointer max-w-full" + > + Close + +
+
+
+
+
+ {animation > 0 && selectedValues.length > 0 && ( + setIsAnimating(!isAnimating)} + /> + )} +
+ ); + } +); + +MultiSelect.displayName = "MultiSelect"; diff --git a/client/app/components/nav-main.tsx b/client/app/components/nav-main.tsx new file mode 100644 index 0000000..e5ef5ce --- /dev/null +++ b/client/app/components/nav-main.tsx @@ -0,0 +1,73 @@ +"use client"; + +import { ChevronRight, type LucideIcon } from "lucide-react"; +import { Link } from "react-router"; + +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from "~/components/ui/collapsible"; +import { + SidebarGroup, + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + SidebarMenuSub, + SidebarMenuSubButton, + SidebarMenuSubItem, +} from "~/components/ui/sidebar"; + +export function NavMain({ + items, +}: { + items: { + title: string; + url: string; + icon?: LucideIcon; + isActive?: boolean; + items?: { + title: string; + url: string; + }[]; + }[]; +}) { + return ( + + {/* Platform */} + + {items.map((item) => ( + + + + + {item.icon && } + {item.title} + + + + + + {item.items?.map((subItem) => ( + + + + {subItem.title} + + + + ))} + + + + + ))} + + + ); +} diff --git a/client/app/components/nav-projects.tsx b/client/app/components/nav-projects.tsx new file mode 100644 index 0000000..f18482e --- /dev/null +++ b/client/app/components/nav-projects.tsx @@ -0,0 +1,87 @@ +import { + Folder, + Forward, + MoreHorizontal, + Trash2, + type LucideIcon, +} from "lucide-react" + +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "~/components/ui/dropdown-menu" +import { + SidebarGroup, + SidebarGroupLabel, + SidebarMenu, + SidebarMenuAction, + SidebarMenuButton, + SidebarMenuItem, + useSidebar, +} from "~/components/ui/sidebar" + +export function NavProjects({ + projects, +}: { + projects: { + name: string + url: string + icon: LucideIcon + }[] +}) { + const { isMobile } = useSidebar() + + return ( + + Projects + + {projects.map((item) => ( + + + + + {item.name} + + + + + + + More + + + + + + View Project + + + + Share Project + + + + + Delete Project + + + + + ))} + + + + More + + + + + ) +} diff --git a/client/app/components/nav-user.tsx b/client/app/components/nav-user.tsx new file mode 100644 index 0000000..03e97c3 --- /dev/null +++ b/client/app/components/nav-user.tsx @@ -0,0 +1,126 @@ +"use client"; + +import { BadgeCheck, Bell, ChevronsUpDown, LogOut } from "lucide-react"; + +import { useSelector } from "react-redux"; +import { authApi } from "~/api/auth-api.service"; +import { Avatar, AvatarFallback, AvatarImage } from "~/components/ui/avatar"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "~/components/ui/dropdown-menu"; +import { + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + useSidebar, +} from "~/components/ui/sidebar"; +import { useAppDispatch } from "~/hooks/use-app-dispatch"; +import type { RootState } from "~/store"; +import { clearUser } from "~/store/slices/app.slice"; +import { ConfirmAlert } from "./btn/confirm-alert"; +import Loader from "./loader"; +import { Button } from "./ui/button"; + +export function NavUser() { + const { user } = useSelector((state: RootState) => state.app); + + const { isMobile } = useSidebar(); + + const dispatch = useAppDispatch(); + + const handleLogout = async () => { + const response = await authApi.logout(); + + if (response?.data) { + dispatch(clearUser()); + location.reload(); + } + }; + + const fullname = (user: IUser) => { + return `${user.first_name} ${user.last_name}`; + }; + + if (!user) return ; + + return ( + + + + + + + + + {user.first_name[0]} + + +
+ {fullname(user)} + {user.email} +
+ +
+
+ + +
+ + + CN + +
+ {fullname(user)} + {user.email} +
+
+
+ + + + + + Account + + + + Notifications + + + + + + + + +
+
+
+
+ ); +} diff --git a/client/app/components/team-switcher.tsx b/client/app/components/team-switcher.tsx new file mode 100644 index 0000000..4e3c527 --- /dev/null +++ b/client/app/components/team-switcher.tsx @@ -0,0 +1,89 @@ +import * as React from "react" +import { ChevronsUpDown, Plus } from "lucide-react" + +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuTrigger, +} from "~/components/ui/dropdown-menu" +import { + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + useSidebar, +} from "~/components/ui/sidebar" + +export function TeamSwitcher({ + teams, +}: { + teams: { + name: string + logo: React.ElementType + plan: string + }[] +}) { + const { isMobile } = useSidebar() + const [activeTeam, setActiveTeam] = React.useState(teams[0]) + + if (!activeTeam) { + return null + } + + return ( + + + + + +
+ +
+
+ {activeTeam.name} + {activeTeam.plan} +
+ +
+
+ + + Teams + + {teams.map((team, index) => ( + setActiveTeam(team)} + className="gap-2 p-2" + > +
+ +
+ {team.name} + ⌘{index + 1} +
+ ))} + + +
+ +
+
Add team
+
+
+
+
+
+ ) +} diff --git a/client/app/components/ui/alert-dialog.tsx b/client/app/components/ui/alert-dialog.tsx new file mode 100644 index 0000000..59eaa6c --- /dev/null +++ b/client/app/components/ui/alert-dialog.tsx @@ -0,0 +1,155 @@ +import * as React from "react" +import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog" + +import { cn } from "~/lib/utils" +import { buttonVariants } from "~/components/ui/button" + +function AlertDialog({ + ...props +}: React.ComponentProps) { + return +} + +function AlertDialogTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogPortal({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + + ) +} + +function AlertDialogHeader({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertDialogFooter({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertDialogTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogAction({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogCancel({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + AlertDialog, + AlertDialogPortal, + AlertDialogOverlay, + AlertDialogTrigger, + AlertDialogContent, + AlertDialogHeader, + AlertDialogFooter, + AlertDialogTitle, + AlertDialogDescription, + AlertDialogAction, + AlertDialogCancel, +} diff --git a/client/app/components/ui/avatar.tsx b/client/app/components/ui/avatar.tsx new file mode 100644 index 0000000..70cee5f --- /dev/null +++ b/client/app/components/ui/avatar.tsx @@ -0,0 +1,53 @@ +"use client" + +import * as React from "react" +import * as AvatarPrimitive from "@radix-ui/react-avatar" + +import { cn } from "~/lib/utils" + +function Avatar({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AvatarImage({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AvatarFallback({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Avatar, AvatarImage, AvatarFallback } diff --git a/client/app/components/ui/badge.tsx b/client/app/components/ui/badge.tsx new file mode 100644 index 0000000..fc40406 --- /dev/null +++ b/client/app/components/ui/badge.tsx @@ -0,0 +1,46 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "~/lib/utils" + +const badgeVariants = cva( + "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90", + secondary: + "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90", + destructive: + "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +function Badge({ + className, + variant, + asChild = false, + ...props +}: React.ComponentProps<"span"> & + VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot : "span" + + return ( + + ) +} + +export { Badge, badgeVariants } diff --git a/client/app/components/ui/breadcrumb.tsx b/client/app/components/ui/breadcrumb.tsx new file mode 100644 index 0000000..6da6cbc --- /dev/null +++ b/client/app/components/ui/breadcrumb.tsx @@ -0,0 +1,109 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { ChevronRight, MoreHorizontal } from "lucide-react" + +import { cn } from "~/lib/utils" + +function Breadcrumb({ ...props }: React.ComponentProps<"nav">) { + return