From 7ca45ddda333f5c801304c61ccb321fc5699d458 Mon Sep 17 00:00:00 2001 From: D-K-P <8297864+D-K-P@users.noreply.github.com> Date: Thu, 4 Sep 2025 20:35:49 +0100 Subject: [PATCH 01/39] wip --- product-image-generator/.gitignore | 43 + product-image-generator/README.md | 36 + product-image-generator/app/actions.ts | 24 + product-image-generator/app/favicon.ico | Bin 0 -> 25931 bytes product-image-generator/app/globals.css | 122 + product-image-generator/app/layout.tsx | 38 + product-image-generator/app/page.tsx | 190 + product-image-generator/components.json | 22 + .../components/ui/button.tsx | 59 + .../components/ui/card.tsx | 92 + product-image-generator/eslint.config.mjs | 25 + product-image-generator/lib/utils.ts | 6 + product-image-generator/package.json | 76 + product-image-generator/pnpm-lock.yaml | 4004 +++++++++++++++++ product-image-generator/postcss.config.mjs | 5 + product-image-generator/public/file.svg | 1 + product-image-generator/public/globe.svg | 1 + product-image-generator/public/next.svg | 1 + product-image-generator/public/vercel.svg | 1 + product-image-generator/public/window.svg | 1 + .../src/trigger/example.ts | 16 + product-image-generator/src/trigger/index.ts | 1 + product-image-generator/trigger.config.ts | 22 + product-image-generator/tsconfig.json | 27 + 24 files changed, 4813 insertions(+) create mode 100644 product-image-generator/.gitignore create mode 100644 product-image-generator/README.md create mode 100644 product-image-generator/app/actions.ts create mode 100644 product-image-generator/app/favicon.ico create mode 100644 product-image-generator/app/globals.css create mode 100644 product-image-generator/app/layout.tsx create mode 100644 product-image-generator/app/page.tsx create mode 100644 product-image-generator/components.json create mode 100644 product-image-generator/components/ui/button.tsx create mode 100644 product-image-generator/components/ui/card.tsx create mode 100644 product-image-generator/eslint.config.mjs create mode 100644 product-image-generator/lib/utils.ts create mode 100644 product-image-generator/package.json create mode 100644 product-image-generator/pnpm-lock.yaml create mode 100644 product-image-generator/postcss.config.mjs create mode 100644 product-image-generator/public/file.svg create mode 100644 product-image-generator/public/globe.svg create mode 100644 product-image-generator/public/next.svg create mode 100644 product-image-generator/public/vercel.svg create mode 100644 product-image-generator/public/window.svg create mode 100644 product-image-generator/src/trigger/example.ts create mode 100644 product-image-generator/src/trigger/index.ts create mode 100644 product-image-generator/trigger.config.ts create mode 100644 product-image-generator/tsconfig.json diff --git a/product-image-generator/.gitignore b/product-image-generator/.gitignore new file mode 100644 index 0000000..ac7bf9b --- /dev/null +++ b/product-image-generator/.gitignore @@ -0,0 +1,43 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +.trigger \ No newline at end of file diff --git a/product-image-generator/README.md b/product-image-generator/README.md new file mode 100644 index 0000000..e215bc4 --- /dev/null +++ b/product-image-generator/README.md @@ -0,0 +1,36 @@ +This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. + +This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. diff --git a/product-image-generator/app/actions.ts b/product-image-generator/app/actions.ts new file mode 100644 index 0000000..b566236 --- /dev/null +++ b/product-image-generator/app/actions.ts @@ -0,0 +1,24 @@ +"use server"; + +import { tasks } from "@trigger.dev/sdk"; +import type { helloWorldTask } from "@/src/trigger/example"; + +export async function triggerHelloWorld(message: string) { + try { + const handle = await tasks.trigger( + "hello-world", + message, + ); + + return { + success: true as const, + runId: handle.id, + }; + } catch (error) { + console.error("Error triggering hello-world task:", error); + return { + success: false as const, + error: "Failed to trigger task", + }; + } +} diff --git a/product-image-generator/app/favicon.ico b/product-image-generator/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..718d6fea4835ec2d246af9800eddb7ffb276240c GIT binary patch literal 25931 zcmeHv30#a{`}aL_*G&7qml|y<+KVaDM2m#dVr!KsA!#An?kSQM(q<_dDNCpjEux83 zLb9Z^XxbDl(w>%i@8hT6>)&Gu{h#Oeyszu?xtw#Zb1mO{pgX9699l+Qppw7jXaYf~-84xW z)w4x8?=youko|}Vr~(D$UXIbiXABHh`p1?nn8Po~fxRJv}|0e(BPs|G`(TT%kKVJAdg5*Z|x0leQq0 zkdUBvb#>9F()jo|T~kx@OM8$9wzs~t2l;K=woNssA3l6|sx2r3+kdfVW@e^8e*E}v zA1y5{bRi+3Z`uD3{F7LgFJDdvm;nJilkzDku>BwXH(8ItVCXk*-lSJnR?-2UN%hJ){&rlvg`CDTj z)Bzo!3v7Ou#83zEDEFcKt(f1E0~=rqeEbTnMvWR#{+9pg%7G8y>u1OVRUSoox-ovF z2Ydma(;=YuBY(eI|04{hXzZD6_f(v~H;C~y5=DhAC{MMS>2fm~1H_t2$56pc$NH8( z5bH|<)71dV-_oCHIrzrT`2s-5w_+2CM0$95I6X8p^r!gHp+j_gd;9O<1~CEQQGS8) zS9Qh3#p&JM-G8rHekNmKVewU;pJRcTAog68KYo^dRo}(M>36U4Us zfgYWSiHZL3;lpWT=zNAW>Dh#mB!_@Lg%$ms8N-;aPqMn+C2HqZgz&9~Eu z4|Kp<`$q)Uw1R?y(~S>ePdonHxpV1#eSP1B;Ogo+-Pk}6#0GsZZ5!||ev2MGdh}_m z{DeR7?0-1^zVs&`AV6Vt;r3`I`OI_wgs*w=eO%_#7Kepl{B@xiyCANc(l zzIyd4y|c6PXWq9-|KM8(zIk8LPk(>a)zyFWjhT!$HJ$qX1vo@d25W<fvZQ2zUz5WRc(UnFMKHwe1| zWmlB1qdbiA(C0jmnV<}GfbKtmcu^2*P^O?MBLZKt|As~ge8&AAO~2K@zbXelK|4T<{|y4`raF{=72kC2Kn(L4YyenWgrPiv z@^mr$t{#X5VuIMeL!7Ab6_kG$&#&5p*Z{+?5U|TZ`B!7llpVmp@skYz&n^8QfPJzL z0G6K_OJM9x+Wu2gfN45phANGt{7=C>i34CV{Xqlx(fWpeAoj^N0Biu`w+MVcCUyU* zDZuzO0>4Z6fbu^T_arWW5n!E45vX8N=bxTVeFoep_G#VmNlQzAI_KTIc{6>c+04vr zx@W}zE5JNSU>!THJ{J=cqjz+4{L4A{Ob9$ZJ*S1?Ggg3klFp!+Y1@K+pK1DqI|_gq z5ZDXVpge8-cs!o|;K73#YXZ3AShj50wBvuq3NTOZ`M&qtjj#GOFfgExjg8Gn8>Vq5 z`85n+9|!iLCZF5$HJ$Iu($dm?8~-ofu}tEc+-pyke=3!im#6pk_Wo8IA|fJwD&~~F zc16osQ)EBo58U7XDuMexaPRjU@h8tXe%S{fA0NH3vGJFhuyyO!Uyl2^&EOpX{9As0 zWj+P>{@}jxH)8|r;2HdupP!vie{sJ28b&bo!8`D^x}TE$%zXNb^X1p@0PJ86`dZyj z%ce7*{^oo+6%&~I!8hQy-vQ7E)0t0ybH4l%KltWOo~8cO`T=157JqL(oq_rC%ea&4 z2NcTJe-HgFjNg-gZ$6!Y`SMHrlj}Etf7?r!zQTPPSv}{so2e>Fjs1{gzk~LGeesX%r(Lh6rbhSo_n)@@G-FTQy93;l#E)hgP@d_SGvyCp0~o(Y;Ee8{ zdVUDbHm5`2taPUOY^MAGOw*>=s7=Gst=D+p+2yON!0%Hk` zz5mAhyT4lS*T3LS^WSxUy86q&GnoHxzQ6vm8)VS}_zuqG?+3td68_x;etQAdu@sc6 zQJ&5|4(I?~3d-QOAODHpZ=hlSg(lBZ!JZWCtHHSj`0Wh93-Uk)_S%zsJ~aD>{`A0~ z9{AG(e|q3g5B%wYKRxiL2Y$8(4w6bzchKuloQW#e&S3n+P- z8!ds-%f;TJ1>)v)##>gd{PdS2Oc3VaR`fr=`O8QIO(6(N!A?pr5C#6fc~Ge@N%Vvu zaoAX2&(a6eWy_q&UwOhU)|P3J0Qc%OdhzW=F4D|pt0E4osw;%<%Dn58hAWD^XnZD= z>9~H(3bmLtxpF?a7su6J7M*x1By7YSUbxGi)Ot0P77`}P3{)&5Un{KD?`-e?r21!4vTTnN(4Y6Lin?UkSM z`MXCTC1@4A4~mvz%Rh2&EwY))LeoT=*`tMoqcEXI>TZU9WTP#l?uFv+@Dn~b(>xh2 z;>B?;Tz2SR&KVb>vGiBSB`@U7VIWFSo=LDSb9F{GF^DbmWAfpms8Sx9OX4CnBJca3 zlj9(x!dIjN?OG1X4l*imJNvRCk}F%!?SOfiOq5y^mZW)jFL@a|r-@d#f7 z2gmU8L3IZq0ynIws=}~m^#@&C%J6QFo~Mo4V`>v7MI-_!EBMMtb%_M&kvAaN)@ZVw z+`toz&WG#HkWDjnZE!6nk{e-oFdL^$YnbOCN}JC&{$#$O27@|Tn-skXr)2ml2~O!5 zX+gYoxhoc7qoU?C^3~&!U?kRFtnSEecWuH0B0OvLodgUAi}8p1 zrO6RSXHH}DMc$&|?D004DiOVMHV8kXCP@7NKB zgaZq^^O<7PoKEp72kby@W0Z!Y*Ay{&vfg#C&gG@YVR9g?FEocMUi1gSN$+V+ayF45{a zuDZDTN}mS|;BO%gEf}pjBfN2-gIrU#G5~cucA;dokXW89%>AyXJJI z9X4UlIWA|ZYHgbI z5?oFk@A=Ik7lrEQPDH!H+b`7_Y~aDb_qa=B2^Y&Ow41cU=4WDd40dp5(QS-WMN-=Y z9g;6_-JdNU;|6cPwf$ak*aJIcwL@1n$#l~zi{c{EW?T;DaW*E8DYq?Umtz{nJ&w-M zEMyTDrC&9K$d|kZe2#ws6)L=7K+{ zQw{XnV6UC$6-rW0emqm8wJoeZK)wJIcV?dST}Z;G0Arq{dVDu0&4kd%N!3F1*;*pW zR&qUiFzK=@44#QGw7k1`3t_d8&*kBV->O##t|tonFc2YWrL7_eqg+=+k;!F-`^b8> z#KWCE8%u4k@EprxqiV$VmmtiWxDLgnGu$Vs<8rppV5EajBXL4nyyZM$SWVm!wnCj-B!Wjqj5-5dNXukI2$$|Bu3Lrw}z65Lc=1G z^-#WuQOj$hwNGG?*CM_TO8Bg-1+qc>J7k5c51U8g?ZU5n?HYor;~JIjoWH-G>AoUP ztrWWLbRNqIjW#RT*WqZgPJXU7C)VaW5}MiijYbABmzoru6EmQ*N8cVK7a3|aOB#O& zBl8JY2WKfmj;h#Q!pN%9o@VNLv{OUL?rixHwOZuvX7{IJ{(EdPpuVFoQqIOa7giLVkBOKL@^smUA!tZ1CKRK}#SSM)iQHk)*R~?M!qkCruaS!#oIL1c z?J;U~&FfH#*98^G?i}pA{ z9Jg36t4=%6mhY(quYq*vSxptes9qy|7xSlH?G=S@>u>Ebe;|LVhs~@+06N<4CViBk zUiY$thvX;>Tby6z9Y1edAMQaiH zm^r3v#$Q#2T=X>bsY#D%s!bhs^M9PMAcHbCc0FMHV{u-dwlL;a1eJ63v5U*?Q_8JO zT#50!RD619#j_Uf))0ooADz~*9&lN!bBDRUgE>Vud-i5ck%vT=r^yD*^?Mp@Q^v+V zG#-?gKlr}Eeqifb{|So?HM&g91P8|av8hQoCmQXkd?7wIJwb z_^v8bbg`SAn{I*4bH$u(RZ6*xUhuA~hc=8czK8SHEKTzSxgbwi~9(OqJB&gwb^l4+m`k*Q;_?>Y-APi1{k zAHQ)P)G)f|AyjSgcCFps)Fh6Bca*Xznq36!pV6Az&m{O8$wGFD? zY&O*3*J0;_EqM#jh6^gMQKpXV?#1?>$ml1xvh8nSN>-?H=V;nJIwB07YX$e6vLxH( zqYwQ>qxwR(i4f)DLd)-$P>T-no_c!LsN@)8`e;W@)-Hj0>nJ-}Kla4-ZdPJzI&Mce zv)V_j;(3ERN3_@I$N<^|4Lf`B;8n+bX@bHbcZTopEmDI*Jfl)-pFDvo6svPRoo@(x z);_{lY<;);XzT`dBFpRmGrr}z5u1=pC^S-{ce6iXQlLGcItwJ^mZx{m$&DA_oEZ)B{_bYPq-HA zcH8WGoBG(aBU_j)vEy+_71T34@4dmSg!|M8Vf92Zj6WH7Q7t#OHQqWgFE3ARt+%!T z?oLovLVlnf?2c7pTc)~cc^($_8nyKwsN`RA-23ed3sdj(ys%pjjM+9JrctL;dy8a( z@en&CQmnV(()bu|Y%G1-4a(6x{aLytn$T-;(&{QIJB9vMox11U-1HpD@d(QkaJdEb zG{)+6Dos_L+O3NpWo^=gR?evp|CqEG?L&Ut#D*KLaRFOgOEK(Kq1@!EGcTfo+%A&I z=dLbB+d$u{sh?u)xP{PF8L%;YPPW53+@{>5W=Jt#wQpN;0_HYdw1{ksf_XhO4#2F= zyPx6Lx2<92L-;L5PD`zn6zwIH`Jk($?Qw({erA$^bC;q33hv!d!>%wRhj# zal^hk+WGNg;rJtb-EB(?czvOM=H7dl=vblBwAv>}%1@{}mnpUznfq1cE^sgsL0*4I zJ##!*B?=vI_OEVis5o+_IwMIRrpQyT_Sq~ZU%oY7c5JMIADzpD!Upz9h@iWg_>>~j zOLS;wp^i$-E?4<_cp?RiS%Rd?i;f*mOz=~(&3lo<=@(nR!_Rqiprh@weZlL!t#NCc zO!QTcInq|%#>OVgobj{~ixEUec`E25zJ~*DofsQdzIa@5^nOXj2T;8O`l--(QyU^$t?TGY^7#&FQ+2SS3B#qK*k3`ye?8jUYSajE5iBbJls75CCc(m3dk{t?- zopcER9{Z?TC)mk~gpi^kbbu>b-+a{m#8-y2^p$ka4n60w;Sc2}HMf<8JUvhCL0B&Btk)T`ctE$*qNW8L$`7!r^9T+>=<=2qaq-;ll2{`{Rg zc5a0ZUI$oG&j-qVOuKa=*v4aY#IsoM+1|c4Z)<}lEDvy;5huB@1RJPquU2U*U-;gu z=En2m+qjBzR#DEJDO`WU)hdd{Vj%^0V*KoyZ|5lzV87&g_j~NCjwv0uQVqXOb*QrQ zy|Qn`hxx(58c70$E;L(X0uZZ72M1!6oeg)(cdKO ze0gDaTz+ohR-#d)NbAH4x{I(21yjwvBQfmpLu$)|m{XolbgF!pmsqJ#D}(ylp6uC> z{bqtcI#hT#HW=wl7>p!38sKsJ`r8}lt-q%Keqy%u(xk=yiIJiUw6|5IvkS+#?JTBl z8H5(Q?l#wzazujH!8o>1xtn8#_w+397*_cy8!pQGP%K(Ga3pAjsaTbbXJlQF_+m+-UpUUent@xM zg%jqLUExj~o^vQ3Gl*>wh=_gOr2*|U64_iXb+-111aH}$TjeajM+I20xw(((>fej-@CIz4S1pi$(#}P7`4({6QS2CaQS4NPENDp>sAqD z$bH4KGzXGffkJ7R>V>)>tC)uax{UsN*dbeNC*v}#8Y#OWYwL4t$ePR?VTyIs!wea+ z5Urmc)X|^`MG~*dS6pGSbU+gPJoq*^a=_>$n4|P^w$sMBBy@f*Z^Jg6?n5?oId6f{ z$LW4M|4m502z0t7g<#Bx%X;9<=)smFolV&(V^(7Cv2-sxbxopQ!)*#ZRhTBpx1)Fc zNm1T%bONzv6@#|dz(w02AH8OXe>kQ#1FMCzO}2J_mST)+ExmBr9cva-@?;wnmWMOk z{3_~EX_xadgJGv&H@zK_8{(x84`}+c?oSBX*Ge3VdfTt&F}yCpFP?CpW+BE^cWY0^ zb&uBN!Ja3UzYHK-CTyA5=L zEMW{l3Usky#ly=7px648W31UNV@K)&Ub&zP1c7%)`{);I4b0Q<)B}3;NMG2JH=X$U zfIW4)4n9ZM`-yRj67I)YSLDK)qfUJ_ij}a#aZN~9EXrh8eZY2&=uY%2N0UFF7<~%M zsB8=erOWZ>Ct_#^tHZ|*q`H;A)5;ycw*IcmVxi8_0Xk}aJA^ath+E;xg!x+As(M#0=)3!NJR6H&9+zd#iP(m0PIW8$ z1Y^VX`>jm`W!=WpF*{ioM?C9`yOR>@0q=u7o>BP-eSHqCgMDj!2anwH?s%i2p+Q7D zzszIf5XJpE)IG4;d_(La-xenmF(tgAxK`Y4sQ}BSJEPs6N_U2vI{8=0C_F?@7<(G; zo$~G=8p+076G;`}>{MQ>t>7cm=zGtfbdDXm6||jUU|?X?CaE?(<6bKDYKeHlz}DA8 zXT={X=yp_R;HfJ9h%?eWvQ!dRgz&Su*JfNt!Wu>|XfU&68iRikRrHRW|ZxzRR^`eIGt zIeiDgVS>IeExKVRWW8-=A=yA`}`)ZkWBrZD`hpWIxBGkh&f#ijr449~m`j6{4jiJ*C!oVA8ZC?$1RM#K(_b zL9TW)kN*Y4%^-qPpMP7d4)o?Nk#>aoYHT(*g)qmRUb?**F@pnNiy6Fv9rEiUqD(^O zzyS?nBrX63BTRYduaG(0VVG2yJRe%o&rVrLjbxTaAFTd8s;<<@Qs>u(<193R8>}2_ zuwp{7;H2a*X7_jryzriZXMg?bTuegABb^87@SsKkr2)0Gyiax8KQWstw^v#ix45EVrcEhr>!NMhprl$InQMzjSFH54x5k9qHc`@9uKQzvL4ihcq{^B zPrVR=o_ic%Y>6&rMN)hTZsI7I<3&`#(nl+3y3ys9A~&^=4?PL&nd8)`OfG#n zwAMN$1&>K++c{^|7<4P=2y(B{jJsQ0a#U;HTo4ZmWZYvI{+s;Td{Yzem%0*k#)vjpB zia;J&>}ICate44SFYY3vEelqStQWFihx%^vQ@Do(sOy7yR2@WNv7Y9I^yL=nZr3mb zXKV5t@=?-Sk|b{XMhA7ZGB@2hqsx}4xwCW!in#C zI@}scZlr3-NFJ@NFaJlhyfcw{k^vvtGl`N9xSo**rDW4S}i zM9{fMPWo%4wYDG~BZ18BD+}h|GQKc-g^{++3MY>}W_uq7jGHx{mwE9fZiPCoxN$+7 zrODGGJrOkcPQUB(FD5aoS4g~7#6NR^ma7-!>mHuJfY5kTe6PpNNKC9GGRiu^L31uG z$7v`*JknQHsYB!Tm_W{a32TM099djW%5e+j0Ve_ct}IM>XLF1Ap+YvcrLV=|CKo6S zb+9Nl3_YdKP6%Cxy@6TxZ>;4&nTneadr z_ES90ydCev)LV!dN=#(*f}|ZORFdvkYBni^aLbUk>BajeWIOcmHP#8S)*2U~QKI%S zyrLmtPqb&TphJ;>yAxri#;{uyk`JJqODDw%(Z=2`1uc}br^V%>j!gS)D*q*f_-qf8&D;W1dJgQMlaH5er zN2U<%Smb7==vE}dDI8K7cKz!vs^73o9f>2sgiTzWcwY|BMYHH5%Vn7#kiw&eItCqa zIkR2~Q}>X=Ar8W|^Ms41Fm8o6IB2_j60eOeBB1Br!boW7JnoeX6Gs)?7rW0^5psc- zjS16yb>dFn>KPOF;imD}e!enuIniFzv}n$m2#gCCv4jM#ArwlzZ$7@9&XkFxZ4n!V zj3dyiwW4Ki2QG{@i>yuZXQizw_OkZI^-3otXC{!(lUpJF33gI60ak;Uqitp74|B6I zgg{b=Iz}WkhCGj1M=hu4#Aw173YxIVbISaoc z-nLZC*6Tgivd5V`K%GxhBsp@SUU60-rfc$=wb>zdJzXS&-5(NRRodFk;Kxk!S(O(a0e7oY=E( zAyS;Ow?6Q&XA+cnkCb{28_1N8H#?J!*$MmIwLq^*T_9-z^&UE@A(z9oGYtFy6EZef LrJugUA?W`A8`#=m literal 0 HcmV?d00001 diff --git a/product-image-generator/app/globals.css b/product-image-generator/app/globals.css new file mode 100644 index 0000000..97afb5e --- /dev/null +++ b/product-image-generator/app/globals.css @@ -0,0 +1,122 @@ +@import "tailwindcss"; +@import "tw-animate-css"; + +@custom-variant dark (&:is(.dark *)); + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); + --color-sidebar-ring: var(--sidebar-ring); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar: var(--sidebar); + --color-chart-5: var(--chart-5); + --color-chart-4: var(--chart-4); + --color-chart-3: var(--chart-3); + --color-chart-2: var(--chart-2); + --color-chart-1: var(--chart-1); + --color-ring: var(--ring); + --color-input: var(--input); + --color-border: var(--border); + --color-destructive: var(--destructive); + --color-accent-foreground: var(--accent-foreground); + --color-accent: var(--accent); + --color-muted-foreground: var(--muted-foreground); + --color-muted: var(--muted); + --color-secondary-foreground: var(--secondary-foreground); + --color-secondary: var(--secondary); + --color-primary-foreground: var(--primary-foreground); + --color-primary: var(--primary); + --color-popover-foreground: var(--popover-foreground); + --color-popover: var(--popover); + --color-card-foreground: var(--card-foreground); + --color-card: var(--card); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); +} + +:root { + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.141 0.005 285.823); + --card: oklch(1 0 0); + --card-foreground: oklch(0.141 0.005 285.823); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.141 0.005 285.823); + --primary: oklch(0.21 0.006 285.885); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.967 0.001 286.375); + --secondary-foreground: oklch(0.21 0.006 285.885); + --muted: oklch(0.967 0.001 286.375); + --muted-foreground: oklch(0.552 0.016 285.938); + --accent: oklch(0.967 0.001 286.375); + --accent-foreground: oklch(0.21 0.006 285.885); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.92 0.004 286.32); + --input: oklch(0.92 0.004 286.32); + --ring: oklch(0.705 0.015 286.067); + --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.141 0.005 285.823); + --sidebar-primary: oklch(0.21 0.006 285.885); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.967 0.001 286.375); + --sidebar-accent-foreground: oklch(0.21 0.006 285.885); + --sidebar-border: oklch(0.92 0.004 286.32); + --sidebar-ring: oklch(0.705 0.015 286.067); +} + +.dark { + --background: oklch(0.141 0.005 285.823); + --foreground: oklch(0.985 0 0); + --card: oklch(0.21 0.006 285.885); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.21 0.006 285.885); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.92 0.004 286.32); + --primary-foreground: oklch(0.21 0.006 285.885); + --secondary: oklch(0.274 0.006 286.033); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.274 0.006 286.033); + --muted-foreground: oklch(0.705 0.015 286.067); + --accent: oklch(0.274 0.006 286.033); + --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.552 0.016 285.938); + --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.21 0.006 285.885); + --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.274 0.006 286.033); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.552 0.016 285.938); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/product-image-generator/app/layout.tsx b/product-image-generator/app/layout.tsx new file mode 100644 index 0000000..bb54325 --- /dev/null +++ b/product-image-generator/app/layout.tsx @@ -0,0 +1,38 @@ +import type React from "react"; +import type { Metadata } from "next"; +import { GeistSans } from "geist/font/sans"; +import { GeistMono } from "geist/font/mono"; +import { Playfair_Display } from "next/font/google"; +import { Analytics } from "@vercel/analytics/next"; +import { Suspense } from "react"; +import "./globals.css"; + +const playfairDisplay = Playfair_Display({ + subsets: ["latin"], + display: "swap", + variable: "--font-playfair", + weight: ["400", "700"], +}); + +export const metadata: Metadata = { + title: "ImageFlow - Modern Image Management", + description: "Professional image management and organization tool", + generator: "v0.app", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + {children} + + + + ); +} diff --git a/product-image-generator/app/page.tsx b/product-image-generator/app/page.tsx new file mode 100644 index 0000000..c234fb2 --- /dev/null +++ b/product-image-generator/app/page.tsx @@ -0,0 +1,190 @@ +"use client"; + +import { Button } from "@/components/ui/button"; +import { Card } from "@/components/ui/card"; +import { Upload, User, Settings, Home, ImageIcon } from "lucide-react"; +import { useState, useRef } from "react"; +import { triggerHelloWorld } from "./actions"; +import type { helloWorldTask } from "@/src/trigger/example"; + +export default function ImageManagementApp() { + const [isDragOver, setIsDragOver] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const [runId, setRunId] = useState(null); + const [error, setError] = useState(null); + const fileInputRef = useRef(null); + + // Trigger task via Server Action + const triggerTask = async (payload: string) => { + setIsLoading(true); + setError(null); + + try { + const result = await triggerHelloWorld(payload); + + if (result.success) { + setRunId(result.runId || null); + } else { + setError(result.error || "Failed to trigger task"); + } + } catch (err) { + setError(err instanceof Error ? err.message : "Failed to trigger task"); + } finally { + setIsLoading(false); + } + }; + + const handleDragOver = (e: React.DragEvent) => { + e.preventDefault(); + setIsDragOver(true); + }; + + const handleDragLeave = (e: React.DragEvent) => { + e.preventDefault(); + setIsDragOver(false); + }; + + const handleDrop = async (e: React.DragEvent) => { + e.preventDefault(); + setIsDragOver(false); + + const files = Array.from(e.dataTransfer.files); + const imageFile = files.find((file) => file.type.startsWith("image/")); + + if (imageFile) { + await triggerTask(`Hello from ${imageFile.name}!`); + } + }; + + const handleFileSelect = async (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (file && file.type.startsWith("image/")) { + await triggerTask(`Hello from ${file.name}!`); + } + }; + + return ( +
+ {/* Navigation Header */} +
+
+
+

+ ImageFlow +

+ +
+ +
+
+ + {/* Main Content */} +
+
+

+ Image Gallery +

+

+ Upload and organize your images with our intuitive drag-and-drop + interface +

+
+ + {/* Image Grid */} +
+ {/* First Slot - Drag and Drop Area */} + fileInputRef.current?.click()} + > +
+
+ {isLoading ? ( +
+ ) : ( + + )} +
+

+ {isLoading ? "Processing..." : "Drag and drop an image here"} +

+

+ {isLoading ? "Please wait" : "or click to browse"} +

+ {runId && ( +

+ Task triggered! Run ID: {runId} +

+ )} + {error && ( +

Error: {error}

+ )} +
+ +
+ + {/* Remaining 7 Slots - Blank States */} + {Array.from({ length: 7 }).map((_, index) => ( + +
+
+ +
+
+
+ ))} +
+ + {/* Action Buttons */} +
+ + +
+
+
+ ); +} diff --git a/product-image-generator/components.json b/product-image-generator/components.json new file mode 100644 index 0000000..761072a --- /dev/null +++ b/product-image-generator/components.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/app/globals.css", + "baseColor": "zinc", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "registries": {} +} diff --git a/product-image-generator/components/ui/button.tsx b/product-image-generator/components/ui/button.tsx new file mode 100644 index 0000000..a2df8dc --- /dev/null +++ b/product-image-generator/components/ui/button.tsx @@ -0,0 +1,59 @@ +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 buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-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", + { + variants: { + variant: { + default: + "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90", + destructive: + "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50", + secondary: + "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80", + ghost: + "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-9 px-4 py-2 has-[>svg]:px-3", + sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5", + lg: "h-10 rounded-md px-6 has-[>svg]:px-4", + icon: "size-9", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +) + +function Button({ + className, + variant, + size, + asChild = false, + ...props +}: React.ComponentProps<"button"> & + VariantProps & { + asChild?: boolean + }) { + const Comp = asChild ? Slot : "button" + + return ( + + ) +} + +export { Button, buttonVariants } diff --git a/product-image-generator/components/ui/card.tsx b/product-image-generator/components/ui/card.tsx new file mode 100644 index 0000000..d05bbc6 --- /dev/null +++ b/product-image-generator/components/ui/card.tsx @@ -0,0 +1,92 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +function Card({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardTitle({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardDescription({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardAction({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardContent({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +export { + Card, + CardHeader, + CardFooter, + CardTitle, + CardAction, + CardDescription, + CardContent, +} diff --git a/product-image-generator/eslint.config.mjs b/product-image-generator/eslint.config.mjs new file mode 100644 index 0000000..719cea2 --- /dev/null +++ b/product-image-generator/eslint.config.mjs @@ -0,0 +1,25 @@ +import { dirname } from "path"; +import { fileURLToPath } from "url"; +import { FlatCompat } from "@eslint/eslintrc"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const compat = new FlatCompat({ + baseDirectory: __dirname, +}); + +const eslintConfig = [ + ...compat.extends("next/core-web-vitals", "next/typescript"), + { + ignores: [ + "node_modules/**", + ".next/**", + "out/**", + "build/**", + "next-env.d.ts", + ], + }, +]; + +export default eslintConfig; diff --git a/product-image-generator/lib/utils.ts b/product-image-generator/lib/utils.ts new file mode 100644 index 0000000..bd0c391 --- /dev/null +++ b/product-image-generator/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/product-image-generator/package.json b/product-image-generator/package.json new file mode 100644 index 0000000..035608f --- /dev/null +++ b/product-image-generator/package.json @@ -0,0 +1,76 @@ +{ + "name": "my-v0-project", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "@hookform/resolvers": "^3.10.0", + "@radix-ui/react-accordion": "1.2.2", + "@radix-ui/react-alert-dialog": "1.1.4", + "@radix-ui/react-aspect-ratio": "1.1.1", + "@radix-ui/react-avatar": "1.1.2", + "@radix-ui/react-checkbox": "1.1.3", + "@radix-ui/react-collapsible": "1.1.2", + "@radix-ui/react-context-menu": "2.2.4", + "@radix-ui/react-dialog": "1.1.4", + "@radix-ui/react-dropdown-menu": "2.1.4", + "@radix-ui/react-hover-card": "1.1.4", + "@radix-ui/react-label": "2.1.1", + "@radix-ui/react-menubar": "1.1.4", + "@radix-ui/react-navigation-menu": "1.2.3", + "@radix-ui/react-popover": "1.1.4", + "@radix-ui/react-progress": "1.1.1", + "@radix-ui/react-radio-group": "1.2.2", + "@radix-ui/react-scroll-area": "1.2.2", + "@radix-ui/react-select": "2.1.4", + "@radix-ui/react-separator": "1.1.1", + "@radix-ui/react-slider": "1.2.2", + "@radix-ui/react-slot": "1.1.1", + "@radix-ui/react-switch": "1.1.2", + "@radix-ui/react-tabs": "1.1.2", + "@radix-ui/react-toast": "1.2.4", + "@radix-ui/react-toggle": "1.1.1", + "@radix-ui/react-toggle-group": "1.1.1", + "@radix-ui/react-tooltip": "1.1.6", + "@trigger.dev/react-hooks": "^4.0.2", + "@trigger.dev/sdk": "^4.0.2", + "@vercel/analytics": "1.3.1", + "autoprefixer": "^10.4.20", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "cmdk": "1.0.4", + "date-fns": "4.1.0", + "embla-carousel-react": "8.5.1", + "geist": "^1.3.1", + "input-otp": "1.4.1", + "lucide-react": "^0.454.0", + "next": "14.2.25", + "next-themes": "^0.4.6", + "react": "^19", + "react-day-picker": "9.8.0", + "react-dom": "^19", + "react-hook-form": "^7.60.0", + "react-resizable-panels": "^2.1.7", + "recharts": "2.15.4", + "sonner": "^1.7.4", + "tailwind-merge": "^3.3.1", + "tailwindcss-animate": "^1.0.7", + "vaul": "^0.9.9", + "zod": "3.25.67" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4.1.9", + "@types/node": "^22", + "@types/react": "^18", + "@types/react-dom": "^18", + "postcss": "^8.5", + "tailwindcss": "^4.1.9", + "tw-animate-css": "1.3.3", + "typescript": "^5" + } +} diff --git a/product-image-generator/pnpm-lock.yaml b/product-image-generator/pnpm-lock.yaml new file mode 100644 index 0000000..463f900 --- /dev/null +++ b/product-image-generator/pnpm-lock.yaml @@ -0,0 +1,4004 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@hookform/resolvers': + specifier: ^3.10.0 + version: 3.10.0(react-hook-form@7.62.0(react@19.1.0)) + '@radix-ui/react-accordion': + specifier: 1.2.2 + version: 1.2.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-alert-dialog': + specifier: 1.1.4 + version: 1.1.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-aspect-ratio': + specifier: 1.1.1 + version: 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-avatar': + specifier: 1.1.2 + version: 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-checkbox': + specifier: 1.1.3 + version: 1.1.3(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-collapsible': + specifier: 1.1.2 + version: 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-context-menu': + specifier: 2.2.4 + version: 2.2.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-dialog': + specifier: 1.1.4 + version: 1.1.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-dropdown-menu': + specifier: 2.1.4 + version: 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-hover-card': + specifier: 1.1.4 + version: 1.1.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-label': + specifier: 2.1.1 + version: 2.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-menubar': + specifier: 1.1.4 + version: 1.1.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-navigation-menu': + specifier: 1.2.3 + version: 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-popover': + specifier: 1.1.4 + version: 1.1.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-progress': + specifier: 1.1.1 + version: 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-radio-group': + specifier: 1.2.2 + version: 1.2.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-scroll-area': + specifier: 1.2.2 + version: 1.2.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-select': + specifier: 2.1.4 + version: 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-separator': + specifier: 1.1.1 + version: 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-slider': + specifier: 1.2.2 + version: 1.2.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-slot': + specifier: 1.1.1 + version: 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-switch': + specifier: 1.1.2 + version: 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-tabs': + specifier: 1.1.2 + version: 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-toast': + specifier: 1.2.4 + version: 1.2.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-toggle': + specifier: 1.1.1 + version: 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-toggle-group': + specifier: 1.1.1 + version: 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-tooltip': + specifier: 1.1.6 + version: 1.1.6(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@trigger.dev/react-hooks': + specifier: ^4.0.2 + version: 4.0.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@trigger.dev/sdk': + specifier: ^4.0.2 + version: 4.0.2(zod@3.25.67) + '@vercel/analytics': + specifier: 1.3.1 + version: 1.3.1(next@14.2.25(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0) + autoprefixer: + specifier: ^10.4.20 + version: 10.4.21(postcss@8.5.6) + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + cmdk: + specifier: 1.0.4 + version: 1.0.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + date-fns: + specifier: 4.1.0 + version: 4.1.0 + embla-carousel-react: + specifier: 8.5.1 + version: 8.5.1(react@19.1.0) + geist: + specifier: ^1.3.1 + version: 1.4.2(next@14.2.25(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)) + input-otp: + specifier: 1.4.1 + version: 1.4.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + lucide-react: + specifier: ^0.454.0 + version: 0.454.0(react@19.1.0) + next: + specifier: 14.2.25 + version: 14.2.25(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + next-themes: + specifier: ^0.4.6 + version: 0.4.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: + specifier: ^19 + version: 19.1.0 + react-day-picker: + specifier: 9.8.0 + version: 9.8.0(react@19.1.0) + react-dom: + specifier: ^19 + version: 19.1.0(react@19.1.0) + react-hook-form: + specifier: ^7.60.0 + version: 7.62.0(react@19.1.0) + react-resizable-panels: + specifier: ^2.1.7 + version: 2.1.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + recharts: + specifier: 2.15.4 + version: 2.15.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + sonner: + specifier: ^1.7.4 + version: 1.7.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + tailwind-merge: + specifier: ^3.3.1 + version: 3.3.1 + tailwindcss-animate: + specifier: ^1.0.7 + version: 1.0.7(tailwindcss@4.1.12) + vaul: + specifier: ^0.9.9 + version: 0.9.9(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + zod: + specifier: 3.25.67 + version: 3.25.67 + devDependencies: + '@tailwindcss/postcss': + specifier: ^4.1.9 + version: 4.1.12 + '@types/node': + specifier: ^22 + version: 22.18.1 + '@types/react': + specifier: ^18 + version: 18.3.24 + '@types/react-dom': + specifier: ^18 + version: 18.3.7(@types/react@18.3.24) + postcss: + specifier: ^8.5 + version: 8.5.6 + tailwindcss: + specifier: ^4.1.9 + version: 4.1.12 + tw-animate-css: + specifier: 1.3.3 + version: 1.3.3 + typescript: + specifier: ^5 + version: 5.9.2 + +packages: + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@babel/runtime@7.28.3': + resolution: {integrity: sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==} + engines: {node: '>=6.9.0'} + + '@bugsnag/cuid@3.2.1': + resolution: {integrity: sha512-zpvN8xQ5rdRWakMd/BcVkdn2F8HKlDSbM3l7duueK590WmI1T0ObTLc1V/1e55r14WNjPd5AJTYX4yPEAFVi+Q==} + + '@date-fns/tz@1.2.0': + resolution: {integrity: sha512-LBrd7MiJZ9McsOgxqWX7AaxrDjcFVjWH/tIKJd7pnR7McaslGYOP1QmmiBXdJH/H/yLCT+rcQ7FaPBUxRGUtrg==} + + '@electric-sql/client@1.0.0-beta.1': + resolution: {integrity: sha512-Ei9jN3pDoGzc+a/bGqnB5ajb52IvSv7/n2btuyzUlcOHIR2kM9fqtYTJXPwZYKLkGZlHWlpHgWyRtrinkP2nHg==} + + '@floating-ui/core@1.7.3': + resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} + + '@floating-ui/dom@1.7.4': + resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} + + '@floating-ui/react-dom@2.1.6': + resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + + '@google-cloud/precise-date@4.0.0': + resolution: {integrity: sha512-1TUx3KdaU3cN7nfCdNf+UVqA/PSX29Cjcox3fZZBtINlRrXVTmUkQnCKv2MbBUbCopbK4olAT1IHl76uZyCiVA==} + engines: {node: '>=14.0.0'} + + '@hookform/resolvers@3.10.0': + resolution: {integrity: sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag==} + peerDependencies: + react-hook-form: ^7.0.0 + + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.30': + resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==} + + '@jsonhero/path@1.0.21': + resolution: {integrity: sha512-gVUDj/92acpVoJwsVJ/RuWOaHyG4oFzn898WNGQItLCTQ+hOaVlEaImhwE1WqOTf+l3dGOUkbSiVKlb3q1hd1Q==} + + '@next/env@14.2.25': + resolution: {integrity: sha512-JnzQ2cExDeG7FxJwqAksZ3aqVJrHjFwZQAEJ9gQZSoEhIow7SNoKZzju/AwQ+PLIR4NY8V0rhcVozx/2izDO0w==} + + '@next/swc-darwin-arm64@14.2.25': + resolution: {integrity: sha512-09clWInF1YRd6le00vt750s3m7SEYNehz9C4PUcSu3bAdCTpjIV4aTYQZ25Ehrr83VR1rZeqtKUPWSI7GfuKZQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@14.2.25': + resolution: {integrity: sha512-V+iYM/QR+aYeJl3/FWWU/7Ix4b07ovsQ5IbkwgUK29pTHmq+5UxeDr7/dphvtXEq5pLB/PucfcBNh9KZ8vWbug==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@14.2.25': + resolution: {integrity: sha512-LFnV2899PJZAIEHQ4IMmZIgL0FBieh5keMnriMY1cK7ompR+JUd24xeTtKkcaw8QmxmEdhoE5Mu9dPSuDBgtTg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-arm64-musl@14.2.25': + resolution: {integrity: sha512-QC5y5PPTmtqFExcKWKYgUNkHeHE/z3lUsu83di488nyP0ZzQ3Yse2G6TCxz6nNsQwgAx1BehAJTZez+UQxzLfw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-x64-gnu@14.2.25': + resolution: {integrity: sha512-y6/ML4b9eQ2D/56wqatTJN5/JR8/xdObU2Fb1RBidnrr450HLCKr6IJZbPqbv7NXmje61UyxjF5kvSajvjye5w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-linux-x64-musl@14.2.25': + resolution: {integrity: sha512-sPX0TSXHGUOZFvv96GoBXpB3w4emMqKeMgemrSxI7A6l55VBJp/RKYLwZIB9JxSqYPApqiREaIIap+wWq0RU8w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-win32-arm64-msvc@14.2.25': + resolution: {integrity: sha512-ReO9S5hkA1DU2cFCsGoOEp7WJkhFzNbU/3VUF6XxNGUCQChyug6hZdYL/istQgfT/GWE6PNIg9cm784OI4ddxQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-ia32-msvc@14.2.25': + resolution: {integrity: sha512-DZ/gc0o9neuCDyD5IumyTGHVun2dCox5TfPQI/BJTYwpSNYM3CZDI4i6TOdjeq1JMo+Ug4kPSMuZdwsycwFbAw==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@next/swc-win32-x64-msvc@14.2.25': + resolution: {integrity: sha512-KSznmS6eFjQ9RJ1nEc66kJvtGIL1iZMYmGEXsZPh2YtnLtqrgdVvKXJY2ScjjoFnG6nGLyPFR0UiEvDwVah4Tw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@opentelemetry/api-logs@0.203.0': + resolution: {integrity: sha512-9B9RU0H7Ya1Dx/Rkyc4stuBZSGVQF27WigitInx2QQoj6KUpEFYPKoWjdFTunJYxmXmh17HeBvbMa1EhGyPmqQ==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/api@1.9.0': + resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/context-async-hooks@2.0.1': + resolution: {integrity: sha512-XuY23lSI3d4PEqKA+7SLtAgwqIfc6E/E9eAQWLN1vlpC53ybO3o6jW4BsXo1xvz9lYyyWItfQDDLzezER01mCw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/core@2.0.1': + resolution: {integrity: sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/exporter-logs-otlp-http@0.203.0': + resolution: {integrity: sha512-s0hys1ljqlMTbXx2XiplmMJg9wG570Z5lH7wMvrZX6lcODI56sG4HL03jklF63tBeyNwK2RV1/ntXGo3HgG4Qw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-trace-otlp-http@0.203.0': + resolution: {integrity: sha512-ZDiaswNYo0yq/cy1bBLJFe691izEJ6IgNmkjm4C6kE9ub/OMQqDXORx2D2j8fzTBTxONyzusbaZlqtfmyqURPw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation@0.203.0': + resolution: {integrity: sha512-ke1qyM+3AK2zPuBPb6Hk/GCsc5ewbLvPNkEuELx/JmANeEp6ZjnZ+wypPAJSucTw0wvCGrUaibDSdcrGFoWxKQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/otlp-exporter-base@0.203.0': + resolution: {integrity: sha512-Wbxf7k+87KyvxFr5D7uOiSq/vHXWommvdnNE7vECO3tAhsA2GfOlpWINCMWUEPdHZ7tCXxw6Epp3vgx3jU7llQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/otlp-transformer@0.203.0': + resolution: {integrity: sha512-Y8I6GgoCna0qDQ2W6GCRtaF24SnvqvA8OfeTi7fqigD23u8Jpb4R5KFv/pRvrlGagcCLICMIyh9wiejp4TXu/A==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/resources@2.0.1': + resolution: {integrity: sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/sdk-logs@0.203.0': + resolution: {integrity: sha512-vM2+rPq0Vi3nYA5akQD2f3QwossDnTDLvKbea6u/A2NZ3XDkPxMfo/PNrDoXhDUD/0pPo2CdH5ce/thn9K0kLw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.4.0 <1.10.0' + + '@opentelemetry/sdk-metrics@2.0.1': + resolution: {integrity: sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.9.0 <1.10.0' + + '@opentelemetry/sdk-trace-base@2.0.1': + resolution: {integrity: sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/sdk-trace-node@2.0.1': + resolution: {integrity: sha512-UhdbPF19pMpBtCWYP5lHbTogLWx9N0EBxtdagvkn5YtsAnCBZzL7SjktG+ZmupRgifsHMjwUaCCaVmqGfSADmA==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/semantic-conventions@1.36.0': + resolution: {integrity: sha512-TtxJSRD8Ohxp6bKkhrm27JRHAxPczQA7idtcTOMYI+wQRRrfgqxHv1cFbCApcSnNjtXkmzFozn6jQtFrOmbjPQ==} + engines: {node: '>=14'} + + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.4': + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + + '@protobufjs/eventemitter@1.1.0': + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + + '@protobufjs/fetch@1.1.0': + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/inquire@1.1.0': + resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.0': + resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + + '@radix-ui/number@1.1.0': + resolution: {integrity: sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==} + + '@radix-ui/primitive@1.1.1': + resolution: {integrity: sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==} + + '@radix-ui/react-accordion@1.2.2': + resolution: {integrity: sha512-b1oh54x4DMCdGsB4/7ahiSrViXxaBwRPotiZNnYXjLha9vfuURSAZErki6qjDoSIV0eXx5v57XnTGVtGwnfp2g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-alert-dialog@1.1.4': + resolution: {integrity: sha512-A6Kh23qZDLy3PSU4bh2UJZznOrUdHImIXqF8YtUa6CN73f8EOO9XlXSCd9IHyPvIquTaa/kwaSWzZTtUvgXVGw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-arrow@1.1.1': + resolution: {integrity: sha512-NaVpZfmv8SKeZbn4ijN2V3jlHA9ngBG16VnIIm22nUR0Yk8KUALyBxT3KYEUnNuch9sTE8UTsS3whzBgKOL30w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-aspect-ratio@1.1.1': + resolution: {integrity: sha512-kNU4FIpcFMBLkOUcgeIteH06/8JLBcYY6Le1iKenDGCYNYFX3TQqCZjzkOsz37h7r94/99GTb7YhEr98ZBJibw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-avatar@1.1.2': + resolution: {integrity: sha512-GaC7bXQZ5VgZvVvsJ5mu/AEbjYLnhhkoidOboC50Z6FFlLA03wG2ianUoH+zgDQ31/9gCF59bE4+2bBgTyMiig==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-checkbox@1.1.3': + resolution: {integrity: sha512-HD7/ocp8f1B3e6OHygH0n7ZKjONkhciy1Nh0yuBgObqThc3oyx+vuMfFHKAknXRHHWVE9XvXStxJFyjUmB8PIw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collapsible@1.1.2': + resolution: {integrity: sha512-PliMB63vxz7vggcyq0IxNYk8vGDrLXVWw4+W4B8YnwI1s18x7YZYqlG9PLX7XxAJUi0g2DxP4XKJMFHh/iVh9A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collection@1.1.1': + resolution: {integrity: sha512-LwT3pSho9Dljg+wY2KN2mrrh6y3qELfftINERIzBUO9e0N+t0oMTyn3k9iv+ZqgrwGkRnLpNJrsMv9BZlt2yuA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-compose-refs@1.1.1': + resolution: {integrity: sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context-menu@2.2.4': + resolution: {integrity: sha512-ap4wdGwK52rJxGkwukU1NrnEodsUFQIooANKu+ey7d6raQ2biTcEf8za1zr0mgFHieevRTB2nK4dJeN8pTAZGQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-context@1.1.1': + resolution: {integrity: sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dialog@1.1.4': + resolution: {integrity: sha512-Ur7EV1IwQGCyaAuyDRiOLA5JIUZxELJljF+MbM/2NC0BYwfuRrbpS30BiQBJrVruscgUkieKkqXYDOoByaxIoA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-direction@1.1.0': + resolution: {integrity: sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dismissable-layer@1.1.3': + resolution: {integrity: sha512-onrWn/72lQoEucDmJnr8uczSNTujT0vJnA/X5+3AkChVPowr8n1yvIKIabhWyMQeMvvmdpsvcyDqx3X1LEXCPg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-dropdown-menu@2.1.4': + resolution: {integrity: sha512-iXU1Ab5ecM+yEepGAWK8ZhMyKX4ubFdCNtol4sT9D0OVErG9PNElfx3TQhjw7n7BC5nFVz68/5//clWy+8TXzA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.1.1': + resolution: {integrity: sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.1.1': + resolution: {integrity: sha512-01omzJAYRxXdG2/he/+xy+c8a8gCydoQ1yOxnWNcRhrrBW5W+RQJ22EK1SaO8tb3WoUsuEw7mJjBozPzihDFjA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-hover-card@1.1.4': + resolution: {integrity: sha512-QSUUnRA3PQ2UhvoCv3eYvMnCAgGQW+sTu86QPuNb+ZMi+ZENd6UWpiXbcWDQ4AEaKF9KKpCHBeaJz9Rw6lRlaQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-id@1.1.0': + resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-id@1.1.1': + resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-label@2.1.1': + resolution: {integrity: sha512-UUw5E4e/2+4kFMH7+YxORXGWggtY6sM8WIwh5RZchhLuUg2H1hc98Py+pr8HMz6rdaYrK2t296ZEjYLOCO5uUw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-menu@2.1.4': + resolution: {integrity: sha512-BnOgVoL6YYdHAG6DtXONaR29Eq4nvbi8rutrV/xlr3RQCMMb3yqP85Qiw/3NReozrSW+4dfLkK+rc1hb4wPU/A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-menubar@1.1.4': + resolution: {integrity: sha512-+KMpi7VAZuB46+1LD7a30zb5IxyzLgC8m8j42gk3N4TUCcViNQdX8FhoH1HDvYiA8quuqcek4R4bYpPn/SY1GA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-navigation-menu@1.2.3': + resolution: {integrity: sha512-IQWAsQ7dsLIYDrn0WqPU+cdM7MONTv9nqrLVYoie3BPiabSfUVDe6Fr+oEt0Cofsr9ONDcDe9xhmJbL1Uq1yKg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popover@1.1.4': + resolution: {integrity: sha512-aUACAkXx8LaFymDma+HQVji7WhvEhpFJ7+qPz17Nf4lLZqtreGOFRiNQWQmhzp7kEWg9cOyyQJpdIMUMPc/CPw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popper@1.2.1': + resolution: {integrity: sha512-3kn5Me69L+jv82EKRuQCXdYyf1DqHwD2U/sxoNgBGCB7K9TRc3bQamQ+5EPM9EvyPdli0W41sROd+ZU1dTCztw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.1.3': + resolution: {integrity: sha512-NciRqhXnGojhT93RPyDaMPfLH3ZSl4jjIFbZQ1b/vxvZEdHsBZ49wP9w8L3HzUQwep01LcWtkUvm0OVB5JAHTw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.2': + resolution: {integrity: sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.0.1': + resolution: {integrity: sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.3': + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-progress@1.1.1': + resolution: {integrity: sha512-6diOawA84f/eMxFHcWut0aE1C2kyE9dOyCTQOMRR2C/qPiXz/X0SaiA/RLbapQaXUCmy0/hLMf9meSccD1N0pA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-radio-group@1.2.2': + resolution: {integrity: sha512-E0MLLGfOP0l8P/NxgVzfXJ8w3Ch8cdO6UDzJfDChu4EJDy+/WdO5LqpdY8PYnCErkmZH3gZhDL1K7kQ41fAHuQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-roving-focus@1.1.1': + resolution: {integrity: sha512-QE1RoxPGJ/Nm8Qmk0PxP8ojmoaS67i0s7hVssS7KuI2FQoc/uzVlZsqKfQvxPE6D8hICCPHJ4D88zNhT3OOmkw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-scroll-area@1.2.2': + resolution: {integrity: sha512-EFI1N/S3YxZEW/lJ/H1jY3njlvTd8tBmgKEn4GHi51+aMm94i6NmAJstsm5cu3yJwYqYc93gpCPm21FeAbFk6g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-select@2.1.4': + resolution: {integrity: sha512-pOkb2u8KgO47j/h7AylCj7dJsm69BXcjkrvTqMptFqsE2i0p8lHkfgneXKjAgPzBMivnoMyt8o4KiV4wYzDdyQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-separator@1.1.1': + resolution: {integrity: sha512-RRiNRSrD8iUiXriq/Y5n4/3iE8HzqgLHsusUSg5jVpU2+3tqcUFPJXHDymwEypunc2sWxDUS3UC+rkZRlHedsw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slider@1.2.2': + resolution: {integrity: sha512-sNlU06ii1/ZcbHf8I9En54ZPW0Vil/yPVg4vQMcFNjrIx51jsHbFl1HYHQvCIWJSr1q0ZmA+iIs/ZTv8h7HHSA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.1.1': + resolution: {integrity: sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-slot@1.2.3': + resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-switch@1.1.2': + resolution: {integrity: sha512-zGukiWHjEdBCRyXvKR6iXAQG6qXm2esuAD6kDOi9Cn+1X6ev3ASo4+CsYaD6Fov9r/AQFekqnD/7+V0Cs6/98g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-tabs@1.1.2': + resolution: {integrity: sha512-9u/tQJMcC2aGq7KXpGivMm1mgq7oRJKXphDwdypPd/j21j/2znamPU8WkXgnhUaTrSFNIt8XhOyCAupg8/GbwQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-toast@1.2.4': + resolution: {integrity: sha512-Sch9idFJHJTMH9YNpxxESqABcAFweJG4tKv+0zo0m5XBvUSL8FM5xKcJLFLXononpePs8IclyX1KieL5SDUNgA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-toggle-group@1.1.1': + resolution: {integrity: sha512-OgDLZEA30Ylyz8YSXvnGqIHtERqnUt1KUYTKdw/y8u7Ci6zGiJfXc02jahmcSNK3YcErqioj/9flWC9S1ihfwg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-toggle@1.1.1': + resolution: {integrity: sha512-i77tcgObYr743IonC1hrsnnPmszDRn8p+EGUsUt+5a/JFn28fxaM88Py6V2mc8J5kELMWishI0rLnuGLFD/nnQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-tooltip@1.1.6': + resolution: {integrity: sha512-TLB5D8QLExS1uDn7+wH/bjEmRurNMTzNrtq7IjaS4kjion9NtzsTGkvR5+i7yc9q01Pi2KMM2cN3f8UG4IvvXA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-use-callback-ref@1.1.0': + resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.1.0': + resolution: {integrity: sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.1.0': + resolution: {integrity: sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.0': + resolution: {integrity: sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-previous@1.1.0': + resolution: {integrity: sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-rect@1.1.0': + resolution: {integrity: sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.1.0': + resolution: {integrity: sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-visually-hidden@1.1.1': + resolution: {integrity: sha512-vVfA2IZ9q/J+gEamvj761Oq1FpWgCDaNOOIfbPVp2MVPLEomUr5+Vf7kJGwQ24YxZSlQVar7Bes8kyTo5Dshpg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/rect@1.1.0': + resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==} + + '@rollup/rollup-darwin-arm64@4.50.0': + resolution: {integrity: sha512-vwSXQN8T4sKf1RHr1F0s98Pf8UPz7pS6P3LG9NSmuw0TVh7EmaE+5Ny7hJOZ0M2yuTctEsHHRTMi2wuHkdS6Hg==} + cpu: [arm64] + os: [darwin] + + '@socket.io/component-emitter@3.1.2': + resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} + + '@swc/counter@0.1.3': + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + + '@swc/helpers@0.5.5': + resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} + + '@tailwindcss/node@4.1.12': + resolution: {integrity: sha512-3hm9brwvQkZFe++SBt+oLjo4OLDtkvlE8q2WalaD/7QWaeM7KEJbAiY/LJZUaCs7Xa8aUu4xy3uoyX4q54UVdQ==} + + '@tailwindcss/oxide-android-arm64@4.1.12': + resolution: {integrity: sha512-oNY5pq+1gc4T6QVTsZKwZaGpBb2N1H1fsc1GD4o7yinFySqIuRZ2E4NvGasWc6PhYJwGK2+5YT1f9Tp80zUQZQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.1.12': + resolution: {integrity: sha512-cq1qmq2HEtDV9HvZlTtrj671mCdGB93bVY6J29mwCyaMYCP/JaUBXxrQQQm7Qn33AXXASPUb2HFZlWiiHWFytw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.12': + resolution: {integrity: sha512-6UCsIeFUcBfpangqlXay9Ffty9XhFH1QuUFn0WV83W8lGdX8cD5/+2ONLluALJD5+yJ7k8mVtwy3zMZmzEfbLg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.1.12': + resolution: {integrity: sha512-JOH/f7j6+nYXIrHobRYCtoArJdMJh5zy5lr0FV0Qu47MID/vqJAY3r/OElPzx1C/wdT1uS7cPq+xdYYelny1ww==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.12': + resolution: {integrity: sha512-v4Ghvi9AU1SYgGr3/j38PD8PEe6bRfTnNSUE3YCMIRrrNigCFtHZ2TCm8142X8fcSqHBZBceDx+JlFJEfNg5zQ==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.12': + resolution: {integrity: sha512-YP5s1LmetL9UsvVAKusHSyPlzSRqYyRB0f+Kl/xcYQSPLEw/BvGfxzbH+ihUciePDjiXwHh+p+qbSP3SlJw+6g==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.12': + resolution: {integrity: sha512-V8pAM3s8gsrXcCv6kCHSuwyb/gPsd863iT+v1PGXC4fSL/OJqsKhfK//v8P+w9ThKIoqNbEnsZqNy+WDnwQqCA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.12': + resolution: {integrity: sha512-xYfqYLjvm2UQ3TZggTGrwxjYaLB62b1Wiysw/YE3Yqbh86sOMoTn0feF98PonP7LtjsWOWcXEbGqDL7zv0uW8Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.1.12': + resolution: {integrity: sha512-ha0pHPamN+fWZY7GCzz5rKunlv9L5R8kdh+YNvP5awe3LtuXb5nRi/H27GeL2U+TdhDOptU7T6Is7mdwh5Ar3A==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.1.12': + resolution: {integrity: sha512-4tSyu3dW+ktzdEpuk6g49KdEangu3eCYoqPhWNsZgUhyegEda3M9rG0/j1GV/JjVVsj+lG7jWAyrTlLzd/WEBg==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.12': + resolution: {integrity: sha512-iGLyD/cVP724+FGtMWslhcFyg4xyYyM+5F4hGvKA7eifPkXHRAUDFaimu53fpNg9X8dfP75pXx/zFt/jlNF+lg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.12': + resolution: {integrity: sha512-NKIh5rzw6CpEodv/++r0hGLlfgT/gFN+5WNdZtvh6wpU2BpGNgdjvj6H2oFc8nCM839QM1YOhjpgbAONUb4IxA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.1.12': + resolution: {integrity: sha512-gM5EoKHW/ukmlEtphNwaGx45fGoEmP10v51t9unv55voWh6WrOL19hfuIdo2FjxIaZzw776/BUQg7Pck++cIVw==} + engines: {node: '>= 10'} + + '@tailwindcss/postcss@4.1.12': + resolution: {integrity: sha512-5PpLYhCAwf9SJEeIsSmCDLgyVfdBhdBpzX1OJ87anT9IVR0Z9pjM0FNixCAUAHGnMBGB8K99SwAheXrT0Kh6QQ==} + + '@trigger.dev/core@4.0.2': + resolution: {integrity: sha512-hc/alfT7iVdJNZ5YSMbGR9FirLjURqdZ7tCBX4btKas0GDg6M5onwcQsJ3oom5TDp/Nrt+dHaviNMhFxhKCu3g==} + engines: {node: '>=18.20.0'} + + '@trigger.dev/react-hooks@4.0.2': + resolution: {integrity: sha512-xIKRUFu+X+16HmrRvkdLpIR7Bl/z2VIc4mGqzvrbeo9/sc70K8t2yEn6S4e48p59mfUBZBk3kG7aUmvMI3MvIA==} + engines: {node: '>=18.20.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^18.0 || ^19.0 || ^19.0.0-rc + + '@trigger.dev/sdk@4.0.2': + resolution: {integrity: sha512-ulhWJRSHPXOHz0bMvkhAKThkW63x7lnjAb87LPi6dUps1YwwoOL8Nkr15xLXa73UrldPFT+9Y/GvQ9qpzU478w==} + engines: {node: '>=18.20.0'} + peerDependencies: + ai: ^4.2.0 || ^5.0.0 + zod: ^3.0.0 || ^4.0.0 + peerDependenciesMeta: + ai: + optional: true + + '@types/cookie@0.4.1': + resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==} + + '@types/cors@2.8.19': + resolution: {integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==} + + '@types/d3-array@3.2.1': + resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + + '@types/d3-shape@3.1.7': + resolution: {integrity: sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + + '@types/node@22.18.1': + resolution: {integrity: sha512-rzSDyhn4cYznVG+PCzGe1lwuMYJrcBS1fc3JqSa2PvtABwWo+dZ1ij5OVok3tqfpEBCBoaR4d7upFJk73HRJDw==} + + '@types/prop-types@15.7.15': + resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} + + '@types/react-dom@18.3.7': + resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} + peerDependencies: + '@types/react': ^18.0.0 + + '@types/react@18.3.24': + resolution: {integrity: sha512-0dLEBsA1kI3OezMBF8nSsb7Nk19ZnsyE1LLhB8r27KbgU5H4pvuqZLdtE+aUkJVoXgTVuA+iLIwmZ0TuK4tx6A==} + + '@vercel/analytics@1.3.1': + resolution: {integrity: sha512-xhSlYgAuJ6Q4WQGkzYTLmXwhYl39sWjoMA3nHxfkvG+WdBT25c563a7QhwwKivEOZtPJXifYHR1m2ihoisbWyA==} + peerDependencies: + next: '>= 13' + react: ^18 || ^19 + peerDependenciesMeta: + next: + optional: true + react: + optional: true + + accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + + acorn-import-attributes@1.9.5: + resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} + peerDependencies: + acorn: ^8 + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + + autoprefixer@10.4.21: + resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + base64id@2.0.0: + resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} + engines: {node: ^4.5.0 || >= 5.9} + + bintrees@1.0.2: + resolution: {integrity: sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==} + + browserslist@4.25.4: + resolution: {integrity: sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + + caniuse-lite@1.0.30001739: + resolution: {integrity: sha512-y+j60d6ulelrNSwpPyrHdl+9mJnQzHBr08xm48Qno0nSk4h3Qojh+ziv2qE6rXf4k3tadF4o1J/1tAbVm1NtnA==} + + chalk@5.6.0: + resolution: {integrity: sha512-46QrSQFyVSEyYAgQ22hQ+zDa60YHA4fBstHmtSApj1Y5vKtG27fWowW03jCk5KcbXEWPZUIR894aARCA/G1kfQ==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + + cjs-module-lexer@1.4.3: + resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} + + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + cmdk@1.0.4: + resolution: {integrity: sha512-AnsjfHyHpQ/EFeAnG216WY7A5LiYCoZzCSygiLvfXC3H3LFGCprErteUcszaVluGOhuOTbJS3jWHrSDYPBBygg==} + peerDependencies: + react: ^18 || ^19 || ^19.0.0-rc + react-dom: ^18 || ^19 || ^19.0.0-rc + + cookie@0.4.2: + resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} + engines: {node: '>= 0.6'} + + copy-anything@3.0.5: + resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} + engines: {node: '>=12.13'} + + cors@2.8.5: + resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} + engines: {node: '>= 0.10'} + + cronstrue@2.59.0: + resolution: {integrity: sha512-YKGmAy84hKH+hHIIER07VCAHf9u0Ldelx1uU6EBxsRPDXIA1m5fsKmJfyC3xBhw6cVC/1i83VdbL4PvepTrt8A==} + hasBin: true + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-format@3.1.0: + resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + date-fns-jalali@4.1.0-0: + resolution: {integrity: sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==} + + date-fns@4.1.0: + resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.1: + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decimal.js-light@2.5.1: + resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + detect-libc@2.0.4: + resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} + engines: {node: '>=8'} + + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + + dom-helpers@5.2.1: + resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + + electron-to-chromium@1.5.214: + resolution: {integrity: sha512-TpvUNdha+X3ybfU78NoQatKvQEm1oq3lf2QbnmCEdw+Bd9RuIAY+hJTvq1avzHM0f7EJfnH3vbCnbzKzisc/9Q==} + + embla-carousel-react@8.5.1: + resolution: {integrity: sha512-z9Y0K84BJvhChXgqn2CFYbfEi6AwEr+FFVVKm/MqbTQ2zIzO1VQri6w67LcfpVF0AjbhwVMywDZqY4alYkjW5w==} + peerDependencies: + react: ^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + + embla-carousel-reactive-utils@8.5.1: + resolution: {integrity: sha512-n7VSoGIiiDIc4MfXF3ZRTO59KDp820QDuyBDGlt5/65+lumPHxX2JLz0EZ23hZ4eg4vZGUXwMkYv02fw2JVo/A==} + peerDependencies: + embla-carousel: 8.5.1 + + embla-carousel@8.5.1: + resolution: {integrity: sha512-JUb5+FOHobSiWQ2EJNaueCNT/cQU9L6XWBbWmorWPQT9bkbk+fhsuLr8wWrzXKagO3oWszBO7MSx+GfaRk4E6A==} + + engine.io-client@6.5.4: + resolution: {integrity: sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==} + + engine.io-parser@5.2.3: + resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==} + engines: {node: '>=10.0.0'} + + engine.io@6.5.5: + resolution: {integrity: sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==} + engines: {node: '>=10.2.0'} + + enhanced-resolve@5.18.3: + resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + engines: {node: '>=10.13.0'} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + eventemitter3@4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + + eventsource-parser@3.0.6: + resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + + evt@2.5.9: + resolution: {integrity: sha512-GpjX476FSlttEGWHT8BdVMoI8wGXQGbEOtKcP4E+kggg+yJzXBZN2n4x7TS/zPBJ1DZqWI+rguZZApjjzQ0HpA==} + + execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + + fast-equals@5.2.2: + resolution: {integrity: sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw==} + engines: {node: '>=6.0.0'} + + fraction.js@4.3.7: + resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + geist@1.4.2: + resolution: {integrity: sha512-OQUga/KUc8ueijck6EbtT07L4tZ5+TZgjw8PyWfxo16sL5FWk7gNViPNU8hgCFjy6bJi9yuTP+CRpywzaGN8zw==} + peerDependencies: + next: '>=13.2.0' + + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + + get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + + humanize-duration@3.33.0: + resolution: {integrity: sha512-vYJX7BSzn7EQ4SaP2lPYVy+icHDppB6k7myNeI3wrSRfwMS5+BHyGgzpHR0ptqJ2AQ6UuIKrclSg5ve6Ci4IAQ==} + + import-in-the-middle@1.14.2: + resolution: {integrity: sha512-5tCuY9BV8ujfOpwtAGgsTx9CGUapcFMEEyByLv1B+v2+6DhAcw+Zr0nhQT7uwaZ7DiourxFEscghOR8e1aPLQw==} + + input-otp@1.4.1: + resolution: {integrity: sha512-+yvpmKYKHi9jIGngxagY9oWiiblPB7+nEO75F2l2o4vs+6vpPZZmUl4tBNYuTCvQjhvEIbdNeJu70bhfYP2nbw==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + is-what@4.1.16: + resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} + engines: {node: '>=12.13'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jiti@2.5.1: + resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==} + hasBin: true + + jose@5.10.0: + resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + lightningcss-darwin-arm64@1.30.1: + resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.30.1: + resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.30.1: + resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.30.1: + resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.30.1: + resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.30.1: + resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.30.1: + resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.30.1: + resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.30.1: + resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.30.1: + resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.30.1: + resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} + engines: {node: '>= 12.0.0'} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lucide-react@0.454.0: + resolution: {integrity: sha512-hw7zMDwykCLnEzgncEEjHeA6+45aeEzRYuKHuyRSOPkhko+J3ySGjGIzu+mmMfDFG1vazHepMaYFYHbTFAZAAQ==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc + + magic-string@0.30.18: + resolution: {integrity: sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + + minimal-polyfills@2.2.3: + resolution: {integrity: sha512-oxdmJ9cL+xV72h0xYxp4tP2d5/fTBpP45H8DIOn9pASuF8a3IYTf+25fMGDYGiWW+MFsuog6KD6nfmhZJQ+uUw==} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@3.0.2: + resolution: {integrity: sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==} + engines: {node: '>= 18'} + + mkdirp@3.0.1: + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} + hasBin: true + + module-details-from-path@1.0.4: + resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + nanoid@3.3.8: + resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + + next-themes@0.4.6: + resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==} + peerDependencies: + react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + + next@14.2.25: + resolution: {integrity: sha512-N5M7xMc4wSb4IkPvEV5X2BRRXUmhVHNyaXwEM86+voXthSZz8ZiRyQW4p9mwAoAPIm6OzuVZtn7idgEJeAJN3Q==} + engines: {node: '>=18.17.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.41.2 + react: ^18.2.0 + react-dom: ^18.2.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + sass: + optional: true + + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + + normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + + npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + prom-client@15.1.3: + resolution: {integrity: sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g==} + engines: {node: ^16 || ^18 || >=20} + + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + + protobufjs@7.5.4: + resolution: {integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==} + engines: {node: '>=12.0.0'} + + react-day-picker@9.8.0: + resolution: {integrity: sha512-E0yhhg7R+pdgbl/2toTb0xBhsEAtmAx1l7qjIWYfcxOy8w4rTSVfbtBoSzVVhPwKP/5E9iL38LivzoE3AQDhCQ==} + engines: {node: '>=18'} + peerDependencies: + react: '>=16.8.0' + + react-dom@19.1.0: + resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==} + peerDependencies: + react: ^19.1.0 + + react-hook-form@7.62.0: + resolution: {integrity: sha512-7KWFejc98xqG/F4bAxpL41NB3o1nnvQO1RWZT3TqRZYL8RryQETGfEdVnJN2fy1crCiBLLjkRBVK05j24FxJGA==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 || ^19 + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.7.1: + resolution: {integrity: sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-resizable-panels@2.1.9: + resolution: {integrity: sha512-z77+X08YDIrgAes4jl8xhnUu1LNIRp4+E7cv4xHmLOxxUPO/ML7PSrE813b90vj7xvQ1lcf7g2uA9GeMZonjhQ==} + peerDependencies: + react: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + + react-smooth@4.0.4: + resolution: {integrity: sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-transition-group@4.4.5: + resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} + peerDependencies: + react: '>=16.6.0' + react-dom: '>=16.6.0' + + react@19.1.0: + resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} + engines: {node: '>=0.10.0'} + + recharts-scale@0.4.5: + resolution: {integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==} + + recharts@2.15.4: + resolution: {integrity: sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==} + engines: {node: '>=14'} + peerDependencies: + react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + require-in-the-middle@7.5.2: + resolution: {integrity: sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==} + engines: {node: '>=8.6.0'} + + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} + hasBin: true + + run-exclusive@2.2.19: + resolution: {integrity: sha512-K3mdoAi7tjJ/qT7Flj90L7QyPozwUaAG+CVhkdDje4HLKXUYC3N/Jzkau3flHVDLQVhiHBtcimVodMjN9egYbA==} + + scheduler@0.26.0: + resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + + server-only@0.0.1: + resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + slug@6.1.0: + resolution: {integrity: sha512-x6vLHCMasg4DR2LPiyFGI0gJJhywY6DTiGhCrOMzb3SOk/0JVLIaL4UhyFSHu04SD3uAavrKY/K3zZ3i6iRcgA==} + + socket.io-adapter@2.5.5: + resolution: {integrity: sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==} + + socket.io-client@4.7.5: + resolution: {integrity: sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==} + engines: {node: '>=10.0.0'} + + socket.io-parser@4.2.4: + resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==} + engines: {node: '>=10.0.0'} + + socket.io@4.7.4: + resolution: {integrity: sha512-DcotgfP1Zg9iP/dH9zvAQcWrE0TtbMVwXmlV4T4mqsvY+gw+LqUGPfx2AoVyRk0FLME+GQhufDMyacFmw7ksqw==} + engines: {node: '>=10.2.0'} + + sonner@1.7.4: + resolution: {integrity: sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + std-env@3.9.0: + resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} + + streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + + styled-jsx@5.1.1: + resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + + superjson@2.2.2: + resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==} + engines: {node: '>=16'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + swr@2.3.6: + resolution: {integrity: sha512-wfHRmHWk/isGNMwlLGlZX5Gzz/uTgo0o2IRuTMcf4CPuPFJZlq0rDaKUx+ozB5nBOReNV1kiOyzMfj+MBMikLw==} + peerDependencies: + react: ^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + tailwind-merge@3.3.1: + resolution: {integrity: sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==} + + tailwindcss-animate@1.0.7: + resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + + tailwindcss@4.1.12: + resolution: {integrity: sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==} + + tapable@2.2.3: + resolution: {integrity: sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==} + engines: {node: '>=6'} + + tar@7.4.3: + resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} + engines: {node: '>=18'} + + tdigest@0.1.2: + resolution: {integrity: sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==} + + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tsafe@1.8.5: + resolution: {integrity: sha512-LFWTWQrW6rwSY+IBNFl2ridGfUzVsPwrZ26T4KUJww/py8rzaQ/SY+MIz6YROozpUCaRcuISqagmlwub9YT9kw==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tw-animate-css@1.3.3: + resolution: {integrity: sha512-tXE2TRWrskc4TU3RDd7T8n8Np/wCfoeH9gz22c7PzYqNPQ9FBGFbWWzwL0JyHcFp+jHozmF76tbHfPAx22ua2Q==} + + typescript@5.9.2: + resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} + engines: {node: '>=14.17'} + hasBin: true + + ulid@2.4.0: + resolution: {integrity: sha512-fIRiVTJNcSRmXKPZtGzFQv9WRrZ3M9eoptl/teFJvjOzmpU+/K/JH6HZ8deBfb5vMEpicJcLn7JmvdknlMq7Zg==} + hasBin: true + + uncrypto@0.1.3: + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + update-browserslist-db@1.1.3: + resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sync-external-store@1.5.0: + resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + uuid@9.0.1: + resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + hasBin: true + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + vaul@0.9.9: + resolution: {integrity: sha512-7afKg48srluhZwIkaU+lgGtFCUsYBSGOl8vcc8N/M3YQlZFlynHD15AE+pwrYdc826o7nrIND4lL9Y6b9WWZZQ==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + + victory-vendor@36.9.2: + resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + ws@8.17.1: + resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} + 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 + + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + 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 + + xmlhttprequest-ssl@2.0.0: + resolution: {integrity: sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==} + engines: {node: '>=0.4.0'} + + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + + zod-error@1.5.0: + resolution: {integrity: sha512-zzopKZ/skI9iXpqCEPj+iLCKl9b88E43ehcU+sbRoHuwGd9F1IDVGQ70TyO6kmfiRL1g4IXkjsXK+g1gLYl4WQ==} + + zod-validation-error@1.5.0: + resolution: {integrity: sha512-/7eFkAI4qV0tcxMBB/3+d2c1P6jzzZYdYSlBuAklzMuCrJu5bzJfHS0yVAS87dRHVlhftd6RFJDIvv03JgkSbw==} + engines: {node: '>=16.0.0'} + peerDependencies: + zod: ^3.18.0 + + zod@3.25.67: + resolution: {integrity: sha512-idA2YXwpCdqUSKRCACDE6ItZD9TZzy3OZMtpfLoh6oPR47lipysRrJfjzMqFxQ3uJuUPyUeWe1r9vLH33xO/Qw==} + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + +snapshots: + + '@alloc/quick-lru@5.2.0': {} + + '@babel/runtime@7.28.3': {} + + '@bugsnag/cuid@3.2.1': {} + + '@date-fns/tz@1.2.0': {} + + '@electric-sql/client@1.0.0-beta.1': + optionalDependencies: + '@rollup/rollup-darwin-arm64': 4.50.0 + + '@floating-ui/core@1.7.3': + dependencies: + '@floating-ui/utils': 0.2.10 + + '@floating-ui/dom@1.7.4': + dependencies: + '@floating-ui/core': 1.7.3 + '@floating-ui/utils': 0.2.10 + + '@floating-ui/react-dom@2.1.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@floating-ui/dom': 1.7.4 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + + '@floating-ui/utils@0.2.10': {} + + '@google-cloud/precise-date@4.0.0': {} + + '@hookform/resolvers@3.10.0(react-hook-form@7.62.0(react@19.1.0))': + dependencies: + react-hook-form: 7.62.0(react@19.1.0) + + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.2 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.30 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.30': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@jsonhero/path@1.0.21': {} + + '@next/env@14.2.25': {} + + '@next/swc-darwin-arm64@14.2.25': + optional: true + + '@next/swc-darwin-x64@14.2.25': + optional: true + + '@next/swc-linux-arm64-gnu@14.2.25': + optional: true + + '@next/swc-linux-arm64-musl@14.2.25': + optional: true + + '@next/swc-linux-x64-gnu@14.2.25': + optional: true + + '@next/swc-linux-x64-musl@14.2.25': + optional: true + + '@next/swc-win32-arm64-msvc@14.2.25': + optional: true + + '@next/swc-win32-ia32-msvc@14.2.25': + optional: true + + '@next/swc-win32-x64-msvc@14.2.25': + optional: true + + '@opentelemetry/api-logs@0.203.0': + dependencies: + '@opentelemetry/api': 1.9.0 + + '@opentelemetry/api@1.9.0': {} + + '@opentelemetry/context-async-hooks@2.0.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + + '@opentelemetry/core@2.0.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/semantic-conventions': 1.36.0 + + '@opentelemetry/exporter-logs-otlp-http@0.203.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.203.0 + '@opentelemetry/core': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.203.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.203.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.203.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/exporter-trace-otlp-http@0.203.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.203.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.203.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.0.1(@opentelemetry/api@1.9.0) + + '@opentelemetry/instrumentation@0.203.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.203.0 + import-in-the-middle: 1.14.2 + require-in-the-middle: 7.5.2 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/otlp-exporter-base@0.203.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.203.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/otlp-transformer@0.203.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.203.0 + '@opentelemetry/core': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.203.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.0.1(@opentelemetry/api@1.9.0) + protobufjs: 7.5.4 + + '@opentelemetry/resources@2.0.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.36.0 + + '@opentelemetry/sdk-logs@0.203.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.203.0 + '@opentelemetry/core': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.0.1(@opentelemetry/api@1.9.0) + + '@opentelemetry/sdk-metrics@2.0.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.0.1(@opentelemetry/api@1.9.0) + + '@opentelemetry/sdk-trace-base@2.0.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.36.0 + + '@opentelemetry/sdk-trace-node@2.0.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/context-async-hooks': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.0.1(@opentelemetry/api@1.9.0) + + '@opentelemetry/semantic-conventions@1.36.0': {} + + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.4': {} + + '@protobufjs/eventemitter@1.1.0': {} + + '@protobufjs/fetch@1.1.0': + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.0 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/inquire@1.1.0': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.0': {} + + '@radix-ui/number@1.1.0': {} + + '@radix-ui/primitive@1.1.1': {} + + '@radix-ui/react-accordion@1.2.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-collapsible': 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-collection': 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-alert-dialog@1.1.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-dialog': 1.1.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-arrow@1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-aspect-ratio@1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-avatar@1.1.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-checkbox@1.1.3(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-size': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-collapsible@1.1.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-collection@1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-compose-refs@1.1.1(@types/react@18.3.24)(react@19.1.0)': + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 18.3.24 + + '@radix-ui/react-compose-refs@1.1.2(@types/react@18.3.24)(react@19.1.0)': + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 18.3.24 + + '@radix-ui/react-context-menu@2.2.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-menu': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-context@1.1.1(@types/react@18.3.24)(react@19.1.0)': + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 18.3.24 + + '@radix-ui/react-dialog@1.1.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.3(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-focus-guards': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-portal': 1.1.3(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.24)(react@19.1.0) + aria-hidden: 1.2.6 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + react-remove-scroll: 2.7.1(@types/react@18.3.24)(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-direction@1.1.0(@types/react@18.3.24)(react@19.1.0)': + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 18.3.24 + + '@radix-ui/react-dismissable-layer@1.1.3(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-dropdown-menu@2.1.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-menu': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-focus-guards@1.1.1(@types/react@18.3.24)(react@19.1.0)': + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 18.3.24 + + '@radix-ui/react-focus-scope@1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-hover-card@1.1.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.3(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-popper': 1.2.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.3(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-id@1.1.0(@types/react@18.3.24)(react@19.1.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + optionalDependencies: + '@types/react': 18.3.24 + + '@radix-ui/react-id@1.1.1(@types/react@18.3.24)(react@19.1.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + optionalDependencies: + '@types/react': 18.3.24 + + '@radix-ui/react-label@2.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-menu@2.1.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-collection': 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.3(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-focus-guards': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-popper': 1.2.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.3(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.24)(react@19.1.0) + aria-hidden: 1.2.6 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + react-remove-scroll: 2.7.1(@types/react@18.3.24)(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-menubar@1.1.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-collection': 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-menu': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-navigation-menu@1.2.3(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-collection': 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.3(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-visually-hidden': 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-popover@1.1.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.3(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-focus-guards': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-popper': 1.2.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.3(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.24)(react@19.1.0) + aria-hidden: 1.2.6 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + react-remove-scroll: 2.7.1(@types/react@18.3.24)(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-popper@1.2.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@floating-ui/react-dom': 2.1.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-arrow': 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-rect': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-size': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/rect': 1.1.0 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-portal@1.1.3(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-presence@1.1.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-primitive@2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-primitive@2.1.3(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-progress@1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-radio-group@1.2.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-size': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-roving-focus@1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-collection': 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-scroll-area@1.2.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/number': 1.1.0 + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-select@2.1.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/number': 1.1.0 + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-collection': 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.3(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-focus-guards': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-popper': 1.2.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.3(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-visually-hidden': 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + aria-hidden: 1.2.6 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + react-remove-scroll: 2.7.1(@types/react@18.3.24)(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-separator@1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-slider@1.2.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/number': 1.1.0 + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-collection': 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-size': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-slot@1.1.1(@types/react@18.3.24)(react@19.1.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + optionalDependencies: + '@types/react': 18.3.24 + + '@radix-ui/react-slot@1.2.3(@types/react@18.3.24)(react@19.1.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + optionalDependencies: + '@types/react': 18.3.24 + + '@radix-ui/react-switch@1.1.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-size': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-tabs@1.1.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-toast@1.2.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-collection': 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.3(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.3(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-visually-hidden': 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-toggle-group@1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-toggle': 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-toggle@1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-tooltip@1.1.6(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.3(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-popper': 1.2.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.3(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-visually-hidden': 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/react-use-callback-ref@1.1.0(@types/react@18.3.24)(react@19.1.0)': + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 18.3.24 + + '@radix-ui/react-use-controllable-state@1.1.0(@types/react@18.3.24)(react@19.1.0)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + optionalDependencies: + '@types/react': 18.3.24 + + '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@18.3.24)(react@19.1.0)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + optionalDependencies: + '@types/react': 18.3.24 + + '@radix-ui/react-use-layout-effect@1.1.0(@types/react@18.3.24)(react@19.1.0)': + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 18.3.24 + + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@18.3.24)(react@19.1.0)': + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 18.3.24 + + '@radix-ui/react-use-previous@1.1.0(@types/react@18.3.24)(react@19.1.0)': + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 18.3.24 + + '@radix-ui/react-use-rect@1.1.0(@types/react@18.3.24)(react@19.1.0)': + dependencies: + '@radix-ui/rect': 1.1.0 + react: 19.1.0 + optionalDependencies: + '@types/react': 18.3.24 + + '@radix-ui/react-use-size@1.1.0(@types/react@18.3.24)(react@19.1.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.24)(react@19.1.0) + react: 19.1.0 + optionalDependencies: + '@types/react': 18.3.24 + + '@radix-ui/react-visually-hidden@1.1.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + '@types/react-dom': 18.3.7(@types/react@18.3.24) + + '@radix-ui/rect@1.1.0': {} + + '@rollup/rollup-darwin-arm64@4.50.0': + optional: true + + '@socket.io/component-emitter@3.1.2': {} + + '@swc/counter@0.1.3': {} + + '@swc/helpers@0.5.5': + dependencies: + '@swc/counter': 0.1.3 + tslib: 2.8.1 + + '@tailwindcss/node@4.1.12': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.18.3 + jiti: 2.5.1 + lightningcss: 1.30.1 + magic-string: 0.30.18 + source-map-js: 1.2.1 + tailwindcss: 4.1.12 + + '@tailwindcss/oxide-android-arm64@4.1.12': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.12': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.12': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.12': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.12': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.12': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.12': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.12': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.12': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.12': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.12': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.12': + optional: true + + '@tailwindcss/oxide@4.1.12': + dependencies: + detect-libc: 2.0.4 + tar: 7.4.3 + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.12 + '@tailwindcss/oxide-darwin-arm64': 4.1.12 + '@tailwindcss/oxide-darwin-x64': 4.1.12 + '@tailwindcss/oxide-freebsd-x64': 4.1.12 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.12 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.12 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.12 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.12 + '@tailwindcss/oxide-linux-x64-musl': 4.1.12 + '@tailwindcss/oxide-wasm32-wasi': 4.1.12 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.12 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.12 + + '@tailwindcss/postcss@4.1.12': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.1.12 + '@tailwindcss/oxide': 4.1.12 + postcss: 8.5.6 + tailwindcss: 4.1.12 + + '@trigger.dev/core@4.0.2': + dependencies: + '@bugsnag/cuid': 3.2.1 + '@electric-sql/client': 1.0.0-beta.1 + '@google-cloud/precise-date': 4.0.0 + '@jsonhero/path': 1.0.21 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.203.0 + '@opentelemetry/core': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-logs-otlp-http': 0.203.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-trace-otlp-http': 0.203.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.203.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.203.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-node': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.36.0 + dequal: 2.0.3 + eventsource: 3.0.7 + eventsource-parser: 3.0.6 + execa: 8.0.1 + humanize-duration: 3.33.0 + jose: 5.10.0 + nanoid: 3.3.8 + prom-client: 15.1.3 + socket.io: 4.7.4 + socket.io-client: 4.7.5 + std-env: 3.9.0 + superjson: 2.2.2 + tinyexec: 0.3.2 + uncrypto: 0.1.3 + zod: 3.25.76 + zod-error: 1.5.0 + zod-validation-error: 1.5.0(zod@3.25.76) + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@trigger.dev/react-hooks@4.0.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@trigger.dev/core': 4.0.2 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + swr: 2.3.6(react@19.1.0) + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@trigger.dev/sdk@4.0.2(zod@3.25.67)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/semantic-conventions': 1.36.0 + '@trigger.dev/core': 4.0.2 + chalk: 5.6.0 + cronstrue: 2.59.0 + debug: 4.4.1 + evt: 2.5.9 + slug: 6.1.0 + ulid: 2.4.0 + uncrypto: 0.1.3 + uuid: 9.0.1 + ws: 8.18.3 + zod: 3.25.67 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@types/cookie@0.4.1': {} + + '@types/cors@2.8.19': + dependencies: + '@types/node': 22.18.1 + + '@types/d3-array@3.2.1': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-shape@3.1.7': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + + '@types/node@22.18.1': + dependencies: + undici-types: 6.21.0 + + '@types/prop-types@15.7.15': {} + + '@types/react-dom@18.3.7(@types/react@18.3.24)': + dependencies: + '@types/react': 18.3.24 + + '@types/react@18.3.24': + dependencies: + '@types/prop-types': 15.7.15 + csstype: 3.1.3 + + '@vercel/analytics@1.3.1(next@14.2.25(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)': + dependencies: + server-only: 0.0.1 + optionalDependencies: + next: 14.2.25(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + + accepts@1.3.8: + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + + acorn-import-attributes@1.9.5(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + + autoprefixer@10.4.21(postcss@8.5.6): + dependencies: + browserslist: 4.25.4 + caniuse-lite: 1.0.30001739 + fraction.js: 4.3.7 + normalize-range: 0.1.2 + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + base64id@2.0.0: {} + + bintrees@1.0.2: {} + + browserslist@4.25.4: + dependencies: + caniuse-lite: 1.0.30001739 + electron-to-chromium: 1.5.214 + node-releases: 2.0.19 + update-browserslist-db: 1.1.3(browserslist@4.25.4) + + busboy@1.6.0: + dependencies: + streamsearch: 1.1.0 + + caniuse-lite@1.0.30001739: {} + + chalk@5.6.0: {} + + chownr@3.0.0: {} + + cjs-module-lexer@1.4.3: {} + + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + + client-only@0.0.1: {} + + clsx@2.1.1: {} + + cmdk@1.0.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + '@radix-ui/react-dialog': 1.1.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.24)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + use-sync-external-store: 1.5.0(react@19.1.0) + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' + + cookie@0.4.2: {} + + copy-anything@3.0.5: + dependencies: + is-what: 4.1.16 + + cors@2.8.5: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + + cronstrue@2.59.0: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.1.3: {} + + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-color@3.1.0: {} + + d3-ease@3.0.1: {} + + d3-format@3.1.0: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@3.1.0: {} + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.0 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + date-fns-jalali@4.1.0-0: {} + + date-fns@4.1.0: {} + + debug@4.3.7: + dependencies: + ms: 2.1.3 + + debug@4.4.1: + dependencies: + ms: 2.1.3 + + decimal.js-light@2.5.1: {} + + dequal@2.0.3: {} + + detect-libc@2.0.4: {} + + detect-node-es@1.1.0: {} + + dom-helpers@5.2.1: + dependencies: + '@babel/runtime': 7.28.3 + csstype: 3.1.3 + + electron-to-chromium@1.5.214: {} + + embla-carousel-react@8.5.1(react@19.1.0): + dependencies: + embla-carousel: 8.5.1 + embla-carousel-reactive-utils: 8.5.1(embla-carousel@8.5.1) + react: 19.1.0 + + embla-carousel-reactive-utils@8.5.1(embla-carousel@8.5.1): + dependencies: + embla-carousel: 8.5.1 + + embla-carousel@8.5.1: {} + + engine.io-client@6.5.4: + dependencies: + '@socket.io/component-emitter': 3.1.2 + debug: 4.3.7 + engine.io-parser: 5.2.3 + ws: 8.17.1 + xmlhttprequest-ssl: 2.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + engine.io-parser@5.2.3: {} + + engine.io@6.5.5: + dependencies: + '@types/cookie': 0.4.1 + '@types/cors': 2.8.19 + '@types/node': 22.18.1 + accepts: 1.3.8 + base64id: 2.0.0 + cookie: 0.4.2 + cors: 2.8.5 + debug: 4.3.7 + engine.io-parser: 5.2.3 + ws: 8.17.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + enhanced-resolve@5.18.3: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.3 + + escalade@3.2.0: {} + + eventemitter3@4.0.7: {} + + eventsource-parser@3.0.6: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.0.6 + + evt@2.5.9: + dependencies: + minimal-polyfills: 2.2.3 + run-exclusive: 2.2.19 + tsafe: 1.8.5 + + execa@8.0.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + + fast-equals@5.2.2: {} + + fraction.js@4.3.7: {} + + function-bind@1.1.2: {} + + geist@1.4.2(next@14.2.25(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)): + dependencies: + next: 14.2.25(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + + get-nonce@1.0.1: {} + + get-stream@8.0.1: {} + + graceful-fs@4.2.11: {} + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + human-signals@5.0.0: {} + + humanize-duration@3.33.0: {} + + import-in-the-middle@1.14.2: + dependencies: + acorn: 8.15.0 + acorn-import-attributes: 1.9.5(acorn@8.15.0) + cjs-module-lexer: 1.4.3 + module-details-from-path: 1.0.4 + + input-otp@1.4.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + + internmap@2.0.3: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-stream@3.0.0: {} + + is-what@4.1.16: {} + + isexe@2.0.0: {} + + jiti@2.5.1: {} + + jose@5.10.0: {} + + js-tokens@4.0.0: {} + + lightningcss-darwin-arm64@1.30.1: + optional: true + + lightningcss-darwin-x64@1.30.1: + optional: true + + lightningcss-freebsd-x64@1.30.1: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.1: + optional: true + + lightningcss-linux-arm64-gnu@1.30.1: + optional: true + + lightningcss-linux-arm64-musl@1.30.1: + optional: true + + lightningcss-linux-x64-gnu@1.30.1: + optional: true + + lightningcss-linux-x64-musl@1.30.1: + optional: true + + lightningcss-win32-arm64-msvc@1.30.1: + optional: true + + lightningcss-win32-x64-msvc@1.30.1: + optional: true + + lightningcss@1.30.1: + dependencies: + detect-libc: 2.0.4 + 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 + + lodash@4.17.21: {} + + long@5.3.2: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lucide-react@0.454.0(react@19.1.0): + dependencies: + react: 19.1.0 + + magic-string@0.30.18: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + merge-stream@2.0.0: {} + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mimic-fn@4.0.0: {} + + minimal-polyfills@2.2.3: {} + + minipass@7.1.2: {} + + minizlib@3.0.2: + dependencies: + minipass: 7.1.2 + + mkdirp@3.0.1: {} + + module-details-from-path@1.0.4: {} + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + nanoid@3.3.8: {} + + negotiator@0.6.3: {} + + next-themes@0.4.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + + next@14.2.25(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + '@next/env': 14.2.25 + '@swc/helpers': 0.5.5 + busboy: 1.6.0 + caniuse-lite: 1.0.30001739 + graceful-fs: 4.2.11 + postcss: 8.4.31 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + styled-jsx: 5.1.1(react@19.1.0) + optionalDependencies: + '@next/swc-darwin-arm64': 14.2.25 + '@next/swc-darwin-x64': 14.2.25 + '@next/swc-linux-arm64-gnu': 14.2.25 + '@next/swc-linux-arm64-musl': 14.2.25 + '@next/swc-linux-x64-gnu': 14.2.25 + '@next/swc-linux-x64-musl': 14.2.25 + '@next/swc-win32-arm64-msvc': 14.2.25 + '@next/swc-win32-ia32-msvc': 14.2.25 + '@next/swc-win32-x64-msvc': 14.2.25 + '@opentelemetry/api': 1.9.0 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + node-releases@2.0.19: {} + + normalize-range@0.1.2: {} + + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + + object-assign@4.1.1: {} + + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + + path-key@3.1.1: {} + + path-key@4.0.0: {} + + path-parse@1.0.7: {} + + picocolors@1.1.1: {} + + postcss-value-parser@4.2.0: {} + + postcss@8.4.31: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prom-client@15.1.3: + dependencies: + '@opentelemetry/api': 1.9.0 + tdigest: 0.1.2 + + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + protobufjs@7.5.4: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.4 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.0 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.0 + '@types/node': 22.18.1 + long: 5.3.2 + + react-day-picker@9.8.0(react@19.1.0): + dependencies: + '@date-fns/tz': 1.2.0 + date-fns: 4.1.0 + date-fns-jalali: 4.1.0-0 + react: 19.1.0 + + react-dom@19.1.0(react@19.1.0): + dependencies: + react: 19.1.0 + scheduler: 0.26.0 + + react-hook-form@7.62.0(react@19.1.0): + dependencies: + react: 19.1.0 + + react-is@16.13.1: {} + + react-is@18.3.1: {} + + react-remove-scroll-bar@2.3.8(@types/react@18.3.24)(react@19.1.0): + dependencies: + react: 19.1.0 + react-style-singleton: 2.2.3(@types/react@18.3.24)(react@19.1.0) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 18.3.24 + + react-remove-scroll@2.7.1(@types/react@18.3.24)(react@19.1.0): + dependencies: + react: 19.1.0 + react-remove-scroll-bar: 2.3.8(@types/react@18.3.24)(react@19.1.0) + react-style-singleton: 2.2.3(@types/react@18.3.24)(react@19.1.0) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@18.3.24)(react@19.1.0) + use-sidecar: 1.1.3(@types/react@18.3.24)(react@19.1.0) + optionalDependencies: + '@types/react': 18.3.24 + + react-resizable-panels@2.1.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + + react-smooth@4.0.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + fast-equals: 5.2.2 + prop-types: 15.8.1 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + react-transition-group: 4.4.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + + react-style-singleton@2.2.3(@types/react@18.3.24)(react@19.1.0): + dependencies: + get-nonce: 1.0.1 + react: 19.1.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 18.3.24 + + react-transition-group@4.4.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + '@babel/runtime': 7.28.3 + dom-helpers: 5.2.1 + loose-envify: 1.4.0 + prop-types: 15.8.1 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + + react@19.1.0: {} + + recharts-scale@0.4.5: + dependencies: + decimal.js-light: 2.5.1 + + recharts@2.15.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + clsx: 2.1.1 + eventemitter3: 4.0.7 + lodash: 4.17.21 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + react-is: 18.3.1 + react-smooth: 4.0.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + recharts-scale: 0.4.5 + tiny-invariant: 1.3.3 + victory-vendor: 36.9.2 + + require-in-the-middle@7.5.2: + dependencies: + debug: 4.4.1 + module-details-from-path: 1.0.4 + resolve: 1.22.10 + transitivePeerDependencies: + - supports-color + + resolve@1.22.10: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + run-exclusive@2.2.19: + dependencies: + minimal-polyfills: 2.2.3 + + scheduler@0.26.0: {} + + server-only@0.0.1: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + signal-exit@4.1.0: {} + + slug@6.1.0: {} + + socket.io-adapter@2.5.5: + dependencies: + debug: 4.3.7 + ws: 8.17.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + socket.io-client@4.7.5: + dependencies: + '@socket.io/component-emitter': 3.1.2 + debug: 4.3.7 + engine.io-client: 6.5.4 + socket.io-parser: 4.2.4 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + socket.io-parser@4.2.4: + dependencies: + '@socket.io/component-emitter': 3.1.2 + debug: 4.3.7 + transitivePeerDependencies: + - supports-color + + socket.io@4.7.4: + dependencies: + accepts: 1.3.8 + base64id: 2.0.0 + cors: 2.8.5 + debug: 4.3.7 + engine.io: 6.5.5 + socket.io-adapter: 2.5.5 + socket.io-parser: 4.2.4 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + sonner@1.7.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + + source-map-js@1.2.1: {} + + std-env@3.9.0: {} + + streamsearch@1.1.0: {} + + strip-final-newline@3.0.0: {} + + styled-jsx@5.1.1(react@19.1.0): + dependencies: + client-only: 0.0.1 + react: 19.1.0 + + superjson@2.2.2: + dependencies: + copy-anything: 3.0.5 + + supports-preserve-symlinks-flag@1.0.0: {} + + swr@2.3.6(react@19.1.0): + dependencies: + dequal: 2.0.3 + react: 19.1.0 + use-sync-external-store: 1.5.0(react@19.1.0) + + tailwind-merge@3.3.1: {} + + tailwindcss-animate@1.0.7(tailwindcss@4.1.12): + dependencies: + tailwindcss: 4.1.12 + + tailwindcss@4.1.12: {} + + tapable@2.2.3: {} + + tar@7.4.3: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.2 + minizlib: 3.0.2 + mkdirp: 3.0.1 + yallist: 5.0.0 + + tdigest@0.1.2: + dependencies: + bintrees: 1.0.2 + + tiny-invariant@1.3.3: {} + + tinyexec@0.3.2: {} + + tsafe@1.8.5: {} + + tslib@2.8.1: {} + + tw-animate-css@1.3.3: {} + + typescript@5.9.2: {} + + ulid@2.4.0: {} + + uncrypto@0.1.3: {} + + undici-types@6.21.0: {} + + update-browserslist-db@1.1.3(browserslist@4.25.4): + dependencies: + browserslist: 4.25.4 + escalade: 3.2.0 + picocolors: 1.1.1 + + use-callback-ref@1.3.3(@types/react@18.3.24)(react@19.1.0): + dependencies: + react: 19.1.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 18.3.24 + + use-sidecar@1.1.3(@types/react@18.3.24)(react@19.1.0): + dependencies: + detect-node-es: 1.1.0 + react: 19.1.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 18.3.24 + + use-sync-external-store@1.5.0(react@19.1.0): + dependencies: + react: 19.1.0 + + uuid@9.0.1: {} + + vary@1.1.2: {} + + vaul@0.9.9(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + '@radix-ui/react-dialog': 1.1.4(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' + + victory-vendor@36.9.2: + dependencies: + '@types/d3-array': 3.2.1 + '@types/d3-ease': 3.0.2 + '@types/d3-interpolate': 3.0.4 + '@types/d3-scale': 4.0.9 + '@types/d3-shape': 3.1.7 + '@types/d3-time': 3.0.4 + '@types/d3-timer': 3.0.2 + d3-array: 3.2.4 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-scale: 4.0.2 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-timer: 3.0.1 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + ws@8.17.1: {} + + ws@8.18.3: {} + + xmlhttprequest-ssl@2.0.0: {} + + yallist@5.0.0: {} + + zod-error@1.5.0: + dependencies: + zod: 3.25.67 + + zod-validation-error@1.5.0(zod@3.25.76): + dependencies: + zod: 3.25.76 + + zod@3.25.67: {} + + zod@3.25.76: {} diff --git a/product-image-generator/postcss.config.mjs b/product-image-generator/postcss.config.mjs new file mode 100644 index 0000000..c7bcb4b --- /dev/null +++ b/product-image-generator/postcss.config.mjs @@ -0,0 +1,5 @@ +const config = { + plugins: ["@tailwindcss/postcss"], +}; + +export default config; diff --git a/product-image-generator/public/file.svg b/product-image-generator/public/file.svg new file mode 100644 index 0000000..004145c --- /dev/null +++ b/product-image-generator/public/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/product-image-generator/public/globe.svg b/product-image-generator/public/globe.svg new file mode 100644 index 0000000..567f17b --- /dev/null +++ b/product-image-generator/public/globe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/product-image-generator/public/next.svg b/product-image-generator/public/next.svg new file mode 100644 index 0000000..5174b28 --- /dev/null +++ b/product-image-generator/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/product-image-generator/public/vercel.svg b/product-image-generator/public/vercel.svg new file mode 100644 index 0000000..7705396 --- /dev/null +++ b/product-image-generator/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/product-image-generator/public/window.svg b/product-image-generator/public/window.svg new file mode 100644 index 0000000..b2b2a44 --- /dev/null +++ b/product-image-generator/public/window.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/product-image-generator/src/trigger/example.ts b/product-image-generator/src/trigger/example.ts new file mode 100644 index 0000000..871d8c0 --- /dev/null +++ b/product-image-generator/src/trigger/example.ts @@ -0,0 +1,16 @@ +import { logger, task, wait } from "@trigger.dev/sdk/v3"; + +export const helloWorldTask = task({ + id: "hello-world", + // Set an optional maxDuration to prevent tasks from running indefinitely + maxDuration: 300, // Stop executing after 300 secs (5 mins) of compute + run: async (payload: any, { ctx }) => { + logger.log("Hello, world!", { payload, ctx }); + + await wait.for({ seconds: 5 }); + + return { + message: "Hello, world!", + }; + }, +}); diff --git a/product-image-generator/src/trigger/index.ts b/product-image-generator/src/trigger/index.ts new file mode 100644 index 0000000..a11d031 --- /dev/null +++ b/product-image-generator/src/trigger/index.ts @@ -0,0 +1 @@ +export { helloWorldTask } from "./example"; diff --git a/product-image-generator/trigger.config.ts b/product-image-generator/trigger.config.ts new file mode 100644 index 0000000..727e7e5 --- /dev/null +++ b/product-image-generator/trigger.config.ts @@ -0,0 +1,22 @@ +import { defineConfig } from "@trigger.dev/sdk/v3"; + +export default defineConfig({ + project: "proj_xjminyoyogxbrfipkrkt", + runtime: "node", + logLevel: "log", + // The max compute seconds a task is allowed to run. If the task run exceeds this duration, it will be stopped. + // You can override this on an individual task. + // See https://trigger.dev/docs/runs/max-duration + maxDuration: 3600, + retries: { + enabledInDev: true, + default: { + maxAttempts: 3, + minTimeoutInMs: 1000, + maxTimeoutInMs: 10000, + factor: 2, + randomize: true, + }, + }, + dirs: ["./src/trigger"], +}); diff --git a/product-image-generator/tsconfig.json b/product-image-generator/tsconfig.json new file mode 100644 index 0000000..c133409 --- /dev/null +++ b/product-image-generator/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +} From 81a084a59b6634dd10eeb6b6145109bcdb3a83b1 Mon Sep 17 00:00:00 2001 From: D-K-P <8297864+D-K-P@users.noreply.github.com> Date: Fri, 5 Sep 2025 09:47:37 +0100 Subject: [PATCH 02/39] Implemented drag and drop, deleted hello world and other changes --- product-image-generator/app/actions.ts | 67 +- .../app/components/UploadCard.tsx | 243 ++++ .../{ => app}/components/ui/button.tsx | 0 .../{ => app}/components/ui/card.tsx | 0 .../{ => app}/lib/utils.ts | 0 product-image-generator/app/page.tsx | 118 +- product-image-generator/package.json | 1 + product-image-generator/pnpm-lock.yaml | 1191 +++++++++++++++++ .../src/trigger/example.ts | 16 - .../src/trigger/image-upload.ts | 122 ++ product-image-generator/src/trigger/index.ts | 1 - product-image-generator/trigger.config.ts | 2 +- product-image-generator/tsconfig.json | 11 +- 13 files changed, 1631 insertions(+), 141 deletions(-) create mode 100644 product-image-generator/app/components/UploadCard.tsx rename product-image-generator/{ => app}/components/ui/button.tsx (100%) rename product-image-generator/{ => app}/components/ui/card.tsx (100%) rename product-image-generator/{ => app}/lib/utils.ts (100%) delete mode 100644 product-image-generator/src/trigger/example.ts create mode 100644 product-image-generator/src/trigger/image-upload.ts delete mode 100644 product-image-generator/src/trigger/index.ts diff --git a/product-image-generator/app/actions.ts b/product-image-generator/app/actions.ts index b566236..98611d5 100644 --- a/product-image-generator/app/actions.ts +++ b/product-image-generator/app/actions.ts @@ -1,24 +1,75 @@ "use server"; -import { tasks } from "@trigger.dev/sdk"; -import type { helloWorldTask } from "@/src/trigger/example"; +import { auth, tasks } from "@trigger.dev/sdk/v3"; +import type { uploadImageToR2 } from "../src/trigger/image-upload"; -export async function triggerHelloWorld(message: string) { +export async function createPublicAccessToken(runId: string) { try { - const handle = await tasks.trigger( - "hello-world", - message, + const publicAccessToken = await auth.createPublicToken({ + scopes: { + read: { + runs: [runId], + }, + }, + }); + + return { + success: true as const, + token: publicAccessToken, + }; + } catch (error) { + console.error("Error creating public access token:", error); + return { + success: false as const, + error: "Failed to create access token", + }; + } +} + +export async function uploadImageToR2Action(formData: FormData) { + try { + const file = formData.get("image") as File; + if (!file) { + return { + success: false as const, + error: "No file provided", + }; + } + + // Convert file to base64 + const bytes = await file.arrayBuffer(); + const buffer = Buffer.from(bytes); + const base64 = buffer.toString("base64"); + + const handle = await tasks.trigger( + "upload-image-to-r2", + { + imageBuffer: base64, + fileName: file.name, + contentType: file.type, + }, ); + // Create a public access token for this specific run + const tokenResult = await createPublicAccessToken(handle.id); + + if (!tokenResult.success) { + return { + success: false as const, + error: tokenResult.error, + }; + } + return { success: true as const, runId: handle.id, + accessToken: tokenResult.token, }; } catch (error) { - console.error("Error triggering hello-world task:", error); + console.error("Error triggering image upload task:", error); return { success: false as const, - error: "Failed to trigger task", + error: "Failed to upload image", }; } } diff --git a/product-image-generator/app/components/UploadCard.tsx b/product-image-generator/app/components/UploadCard.tsx new file mode 100644 index 0000000..1c4857e --- /dev/null +++ b/product-image-generator/app/components/UploadCard.tsx @@ -0,0 +1,243 @@ +"use client"; + +import { Button } from "./ui/button"; +import { Card } from "./ui/card"; +import { Upload } from "lucide-react"; +import { useRef, useState, useEffect } from "react"; +import { uploadImageToR2Action } from "../actions"; +import { runs, configure } from "@trigger.dev/sdk/v3"; + +export default function UploadCard() { + const [isDragOver, setIsDragOver] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const [runId, setRunId] = useState(null); + const [accessToken, setAccessToken] = useState(null); + const [error, setError] = useState(null); + const [uploadedImageUrl, setUploadedImageUrl] = useState(null); + const [uploadProgress, setUploadProgress] = useState("idle"); + const [progressMessage, setProgressMessage] = useState(""); + const [progressStep, setProgressStep] = useState<{ + step: number; + total: number; + } | null>(null); + const fileInputRef = useRef(null); + + // Subscribe to run updates when runId and accessToken are available + useEffect(() => { + if (!runId || !accessToken) return; + + const subscribeToRun = async () => { + try { + // Configure the SDK with the access token for client-side authentication + configure({ + secretKey: accessToken, + }); + + for await (const run of runs.subscribeToRun(runId)) { + // Update progress from metadata + if (run.metadata?.progress) { + const progress = run.metadata.progress as { + step: number; + total: number; + message: string; + }; + setProgressMessage(progress.message); + setProgressStep({ step: progress.step, total: progress.total }); + } + + // Handle completion + if (run.status === "COMPLETED" && run.output) { + setUploadedImageUrl(run.output.publicUrl); + setUploadProgress("completed"); + setProgressMessage("Upload completed!"); + setIsLoading(false); + break; + } else if (run.status === "FAILED") { + const errorMsg = run.metadata?.error || "Upload failed"; + setError(typeof errorMsg === "string" ? errorMsg : "Upload failed"); + setUploadProgress("idle"); + setProgressMessage(""); + setIsLoading(false); + break; + } + } + } catch (err) { + setError("Failed to get task updates"); + setUploadProgress("idle"); + setIsLoading(false); + } + }; + + subscribeToRun(); + }, [runId, accessToken]); + + // Upload image with realtime subscription + const uploadImage = async (file: File) => { + setIsLoading(true); + setError(null); + setUploadProgress("uploading"); + setUploadedImageUrl(null); + setProgressMessage(""); + setProgressStep(null); + + try { + // Create FormData and upload + const formData = new FormData(); + formData.append("image", file); + + const result = await uploadImageToR2Action(formData); + + if (result.success && result.runId && result.accessToken) { + setRunId(result.runId); + setAccessToken(result.accessToken); + setUploadProgress("processing"); + // The useEffect will handle the subscription + } else { + setError(result.error || "Failed to upload image"); + setUploadProgress("idle"); + setIsLoading(false); + } + } catch (err) { + setError(err instanceof Error ? err.message : "Failed to upload image"); + setUploadProgress("idle"); + setIsLoading(false); + } + }; + + const handleDragOver = (e: React.DragEvent) => { + e.preventDefault(); + setIsDragOver(true); + }; + + const handleDragLeave = (e: React.DragEvent) => { + e.preventDefault(); + setIsDragOver(false); + }; + + const handleDrop = async (e: React.DragEvent) => { + e.preventDefault(); + setIsDragOver(false); + + const files = Array.from(e.dataTransfer.files); + const imageFile = files.find((file) => file.type.startsWith("image/")); + + if (imageFile) { + await uploadImage(imageFile); + } + }; + + const handleFileSelect = async (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (file && file.type.startsWith("image/")) { + await uploadImage(file); + } + }; + + const handleReset = () => { + setUploadedImageUrl(null); + setUploadProgress("idle"); + setRunId(null); + setAccessToken(null); + setError(null); + setProgressMessage(""); + setProgressStep(null); + }; + + return ( + !uploadedImageUrl && fileInputRef.current?.click()} + > + {uploadedImageUrl ? ( + // Show uploaded image +
+ Uploaded image + {uploadProgress === "processing" && ( +
+
+
+ )} +
+ +
+
+ ) : ( + // Show upload area +
+
+ {isLoading ? ( +
+ ) : ( + + )} +
+

+ {uploadProgress === "uploading" + ? "Uploading..." + : uploadProgress === "processing" + ? progressMessage || "Processing..." + : "Drag and drop an image here"} +

+

+ {isLoading + ? progressStep + ? `Step ${progressStep.step} of ${progressStep.total}` + : "Please wait" + : "or click to browse"} +

+ {progressStep && uploadProgress === "processing" && ( +
+
+
+ )} + {runId && uploadProgress !== "idle" && ( +

Run ID: {runId}

+ )} + {error &&

Error: {error}

} +
+ )} + +
+ ); +} diff --git a/product-image-generator/components/ui/button.tsx b/product-image-generator/app/components/ui/button.tsx similarity index 100% rename from product-image-generator/components/ui/button.tsx rename to product-image-generator/app/components/ui/button.tsx diff --git a/product-image-generator/components/ui/card.tsx b/product-image-generator/app/components/ui/card.tsx similarity index 100% rename from product-image-generator/components/ui/card.tsx rename to product-image-generator/app/components/ui/card.tsx diff --git a/product-image-generator/lib/utils.ts b/product-image-generator/app/lib/utils.ts similarity index 100% rename from product-image-generator/lib/utils.ts rename to product-image-generator/app/lib/utils.ts diff --git a/product-image-generator/app/page.tsx b/product-image-generator/app/page.tsx index c234fb2..612735d 100644 --- a/product-image-generator/app/page.tsx +++ b/product-image-generator/app/page.tsx @@ -1,68 +1,9 @@ -"use client"; - -import { Button } from "@/components/ui/button"; -import { Card } from "@/components/ui/card"; -import { Upload, User, Settings, Home, ImageIcon } from "lucide-react"; -import { useState, useRef } from "react"; -import { triggerHelloWorld } from "./actions"; -import type { helloWorldTask } from "@/src/trigger/example"; +import { Home, ImageIcon, Settings, Upload, User } from "lucide-react"; +import { Button } from "./components/ui/button"; +import { Card } from "./components/ui/card"; +import UploadCard from "./components/UploadCard"; export default function ImageManagementApp() { - const [isDragOver, setIsDragOver] = useState(false); - const [isLoading, setIsLoading] = useState(false); - const [runId, setRunId] = useState(null); - const [error, setError] = useState(null); - const fileInputRef = useRef(null); - - // Trigger task via Server Action - const triggerTask = async (payload: string) => { - setIsLoading(true); - setError(null); - - try { - const result = await triggerHelloWorld(payload); - - if (result.success) { - setRunId(result.runId || null); - } else { - setError(result.error || "Failed to trigger task"); - } - } catch (err) { - setError(err instanceof Error ? err.message : "Failed to trigger task"); - } finally { - setIsLoading(false); - } - }; - - const handleDragOver = (e: React.DragEvent) => { - e.preventDefault(); - setIsDragOver(true); - }; - - const handleDragLeave = (e: React.DragEvent) => { - e.preventDefault(); - setIsDragOver(false); - }; - - const handleDrop = async (e: React.DragEvent) => { - e.preventDefault(); - setIsDragOver(false); - - const files = Array.from(e.dataTransfer.files); - const imageFile = files.find((file) => file.type.startsWith("image/")); - - if (imageFile) { - await triggerTask(`Hello from ${imageFile.name}!`); - } - }; - - const handleFileSelect = async (e: React.ChangeEvent) => { - const file = e.target.files?.[0]; - if (file && file.type.startsWith("image/")) { - await triggerTask(`Hello from ${file.name}!`); - } - }; - return (
{/* Navigation Header */} @@ -108,55 +49,8 @@ export default function ImageManagementApp() { {/* Image Grid */}
- {/* First Slot - Drag and Drop Area */} - fileInputRef.current?.click()} - > -
-
- {isLoading ? ( -
- ) : ( - - )} -
-

- {isLoading ? "Processing..." : "Drag and drop an image here"} -

-

- {isLoading ? "Please wait" : "or click to browse"} -

- {runId && ( -

- Task triggered! Run ID: {runId} -

- )} - {error && ( -

Error: {error}

- )} -
- -
+ {/* First Slot - Upload Card */} + {/* Remaining 7 Slots - Blank States */} {Array.from({ length: 7 }).map((_, index) => ( diff --git a/product-image-generator/package.json b/product-image-generator/package.json index 035608f..c0fb4f3 100644 --- a/product-image-generator/package.json +++ b/product-image-generator/package.json @@ -9,6 +9,7 @@ "lint": "next lint" }, "dependencies": { + "@aws-sdk/client-s3": "^3.882.0", "@hookform/resolvers": "^3.10.0", "@radix-ui/react-accordion": "1.2.2", "@radix-ui/react-alert-dialog": "1.1.4", diff --git a/product-image-generator/pnpm-lock.yaml b/product-image-generator/pnpm-lock.yaml index 463f900..90e65b5 100644 --- a/product-image-generator/pnpm-lock.yaml +++ b/product-image-generator/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + '@aws-sdk/client-s3': + specifier: ^3.882.0 + version: 3.882.0 '@hookform/resolvers': specifier: ^3.10.0 version: 3.10.0(react-hook-form@7.62.0(react@19.1.0)) @@ -199,6 +202,157 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + '@aws-crypto/crc32@5.2.0': + resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/crc32c@5.2.0': + resolution: {integrity: sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==} + + '@aws-crypto/sha1-browser@5.2.0': + resolution: {integrity: sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==} + + '@aws-crypto/sha256-browser@5.2.0': + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} + + '@aws-crypto/sha256-js@5.2.0': + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/supports-web-crypto@5.2.0': + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + + '@aws-crypto/util@5.2.0': + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + + '@aws-sdk/client-s3@3.882.0': + resolution: {integrity: sha512-0IrBUOrBepQeuH025t+b4KqgBRQT+B//JlTU3+629WUGWwsWVfFkCTkn4xK/oQP9/K6npZtfDTuO6XfXSLimmg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/client-sso@3.882.0': + resolution: {integrity: sha512-JFWJB+2PZvygDuqb4iWKCro1Tl5L4tGBXMHe94jYMYnfajYGm58bW3RsPj3cKD2+TvIMUSXmNriNv+LbDKZmNw==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/core@3.882.0': + resolution: {integrity: sha512-m43/gEDbxqxLT/Mbn/OA21TuFpyocOUzjiSA2HBnLQ3KivA4ez0nsW91vh0Sp3TOfLgiZbRbVhmI6XfsFinwBg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-env@3.882.0': + resolution: {integrity: sha512-khhE1k+4XvGm8Mk6vVUbrVvEnx3r8E6dymSKSiAKf0lwsnKWAWd1RLGwLusqVgtGR4Jfsrbg7ox9MczIjgCiTg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-http@3.882.0': + resolution: {integrity: sha512-j3mBF+Q6RU3u8t5O1KOWbQQCi0WNSl47sNIa1RvyN6qK1WIA8BxM1hB25mI9TMPrNZMFthljVec+JcNjRNG34A==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-ini@3.882.0': + resolution: {integrity: sha512-nUacsSYKyTUmv/Fqe0efihCRCabea5MZtGSZF0l2V8QBo39yJjw0wVmRK6G4bfm5lY7v2EVVIUCpiTvxRRUbHg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-node@3.882.0': + resolution: {integrity: sha512-sELdV+leCfY+Bw8NQo3H65oIT+9thqZU0RWyv85EfZVvKEwWDt4McA7+Co1VkH+nCY21s5jz4SOqIrYuT0cSQg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-process@3.882.0': + resolution: {integrity: sha512-S3BgGcaR+L7CQAQn3Ysy9KSnck7+hDicAGM/dYvvJ8GwZNIOc0542Y+ntpV1UYa7OuZPWzGy2v2NcJSCbYDXEA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-sso@3.882.0': + resolution: {integrity: sha512-1pZRTKiDl6Oh/jP75lEoSkJrer1YEm8lMconB8dX9bsaWbp9cZeMJMK6pts5VQcveeOLr/8/U9TESboPjHBcyA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.882.0': + resolution: {integrity: sha512-EvpsD0Vcz5WgXjpC53KAQ2CkeUp0KwwiV6brgQTXl+9yV/M8M0aK5Qk5ep/MPbAn5gtbqXHaCkiExaN4YYOhCg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-bucket-endpoint@3.873.0': + resolution: {integrity: sha512-b4bvr0QdADeTUs+lPc9Z48kXzbKHXQKgTvxx/jXDgSW9tv4KmYPO1gIj6Z9dcrBkRWQuUtSW3Tu2S5n6pe+zeg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-expect-continue@3.873.0': + resolution: {integrity: sha512-GIqoc8WgRcf/opBOZXFLmplJQKwOMjiOMmDz9gQkaJ8FiVJoAp8EGVmK2TOWZMQUYsavvHYsHaor5R2xwPoGVg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-flexible-checksums@3.882.0': + resolution: {integrity: sha512-VZSeGckiRNEUYNYni8JFGB+uFqPq6L+IWPXTOMh6RtpDpamDSqZLgDEfXqopc+Awxpz1sQbdxSHMm2HZlqVW2g==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-host-header@3.873.0': + resolution: {integrity: sha512-KZ/W1uruWtMOs7D5j3KquOxzCnV79KQW9MjJFZM/M0l6KI8J6V3718MXxFHsTjUE4fpdV6SeCNLV1lwGygsjJA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-location-constraint@3.873.0': + resolution: {integrity: sha512-r+hIaORsW/8rq6wieDordXnA/eAu7xAPLue2InhoEX6ML7irP52BgiibHLpt9R0psiCzIHhju8qqKa4pJOrmiw==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-logger@3.876.0': + resolution: {integrity: sha512-cpWJhOuMSyz9oV25Z/CMHCBTgafDCbv7fHR80nlRrPdPZ8ETNsahwRgltXP1QJJ8r3X/c1kwpOR7tc+RabVzNA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-recursion-detection@3.873.0': + resolution: {integrity: sha512-OtgY8EXOzRdEWR//WfPkA/fXl0+WwE8hq0y9iw2caNyKPtca85dzrrZWnPqyBK/cpImosrpR1iKMYr41XshsCg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-sdk-s3@3.882.0': + resolution: {integrity: sha512-j5Ya7RKSQSKkpcLsO+Rh272zKD63JYkLKY/N8m5MVNWQafMdUbkZi7nwwjq7s5t7r3Pmz7a4gLf4n6ZEL5eaow==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-ssec@3.873.0': + resolution: {integrity: sha512-AF55J94BoiuzN7g3hahy0dXTVZahVi8XxRBLgzNp6yQf0KTng+hb/V9UQZVYY1GZaDczvvvnqC54RGe9OZZ9zQ==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-user-agent@3.882.0': + resolution: {integrity: sha512-IdLVpV2b0qryxFb/gNPwZoayLUdgmb41fWpLiIf99pyNwR7TGs/9Ri2amS3PnaQHuES947xYSYZ9Ej0kBgjHKg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/nested-clients@3.882.0': + resolution: {integrity: sha512-IQkOtl/DhLV5+tJI7ZwjBDJO1lIoYOcmNQzcg8ly9RTdMoTcEtklevxmAwWB4DEFiIctUk2OSjHqhfWjeYredA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/region-config-resolver@3.873.0': + resolution: {integrity: sha512-q9sPoef+BBG6PJnc4x60vK/bfVwvRWsPgcoQyIra057S/QGjq5VkjvNk6H8xedf6vnKlXNBwq9BaANBXnldUJg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/signature-v4-multi-region@3.882.0': + resolution: {integrity: sha512-hAmA9BgL3nIRTGoOGjMXMqVtPhtPFKBFaqhgQkgmkzpbZ6aaGecNIqBfGxi9oezR4dnvI+PvKoRo2F8csF7fMA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/token-providers@3.882.0': + resolution: {integrity: sha512-/Z6F8Cc+QjBMEPh3ZXy7JM1vMZCS41+Nh9VgdUwvvdJTA7LRXSDBRDL3cQPa7bii9unZ8SqsIC+7Nlw1LKwwJA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/types@3.862.0': + resolution: {integrity: sha512-Bei+RL0cDxxV+lW2UezLbCYYNeJm6Nzee0TpW0FfyTRBhH9C1XQh4+x+IClriXvgBnRquTMMYsmJfvx8iyLKrg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/util-arn-parser@3.873.0': + resolution: {integrity: sha512-qag+VTqnJWDn8zTAXX4wiVioa0hZDQMtbZcGRERVnLar4/3/VIKBhxX2XibNQXFu1ufgcRn4YntT/XEPecFWcg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/util-endpoints@3.879.0': + resolution: {integrity: sha512-aVAJwGecYoEmbEFju3127TyJDF9qJsKDUUTRMDuS8tGn+QiWQFnfInmbt+el9GU1gEJupNTXV+E3e74y51fb7A==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/util-locate-window@3.873.0': + resolution: {integrity: sha512-xcVhZF6svjM5Rj89T1WzkjQmrTF6dpR2UvIHPMTnSZoNe6CixejPZ6f0JJ2kAhO8H+dUHwNBlsUgOTIKiK/Syg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/util-user-agent-browser@3.873.0': + resolution: {integrity: sha512-AcRdbK6o19yehEcywI43blIBhOCSo6UgyWcuOJX5CFF8k39xm1ILCjQlRRjchLAxWrm0lU0Q7XV90RiMMFMZtA==} + + '@aws-sdk/util-user-agent-node@3.882.0': + resolution: {integrity: sha512-7zPtGXeAs6UzKjrrSbMNiFMSLZ/2DWvJ26KBOasS3zQbL534yoNos4HUA3OOXSpKFBAIEcYWu6rzR4ptlvx50w==} + engines: {node: '>=18.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true + + '@aws-sdk/xml-builder@3.873.0': + resolution: {integrity: sha512-kLO7k7cGJ6KaHiExSJWojZurF7SnGMDHXRuQunFnEoD0n1yB6Lqy/S/zHiQ7oJnBhPr9q0TW9qFkrsZb1Uc54w==} + engines: {node: '>=18.0.0'} + '@babel/runtime@7.28.3': resolution: {integrity: sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==} engines: {node: '>=6.9.0'} @@ -1091,6 +1245,218 @@ packages: cpu: [arm64] os: [darwin] + '@smithy/abort-controller@4.1.0': + resolution: {integrity: sha512-wEhSYznxOmx7EdwK1tYEWJF5+/wmSFsff9BfTOn8oO/+KPl3gsmThrb6MJlWbOC391+Ya31s5JuHiC2RlT80Zg==} + engines: {node: '>=18.0.0'} + + '@smithy/chunked-blob-reader-native@4.1.0': + resolution: {integrity: sha512-Bnv0B3nSlfB2mPO0WgM49I/prl7+kamF042rrf3ezJ3Z4C7csPYvyYgZfXTGXwXfj1mAwDWjE/ybIf49PzFzvA==} + engines: {node: '>=18.0.0'} + + '@smithy/chunked-blob-reader@5.1.0': + resolution: {integrity: sha512-a36AtR7Q7XOhRPt6F/7HENmTWcB8kN7mDJcOFM/+FuKO6x88w8MQJfYCufMWh4fGyVkPjUh3Rrz/dnqFQdo6OQ==} + engines: {node: '>=18.0.0'} + + '@smithy/config-resolver@4.2.0': + resolution: {integrity: sha512-FA10YhPFLy23uxeWu7pOM2ctlw+gzbPMTZQwrZ8FRIfyJ/p8YIVz7AVTB5jjLD+QIerydyKcVMZur8qzzDILAQ==} + engines: {node: '>=18.0.0'} + + '@smithy/core@3.10.0': + resolution: {integrity: sha512-bXyD3Ij6b1qDymEYlEcF+QIjwb9gObwZNaRjETJsUEvSIzxFdynSQ3E4ysY7lUFSBzeWBNaFvX+5A0smbC2q6A==} + engines: {node: '>=18.0.0'} + + '@smithy/credential-provider-imds@4.1.0': + resolution: {integrity: sha512-iVwNhxTsCQTPdp++4C/d9xvaDmuEWhXi55qJobMp9QMaEHRGH3kErU4F8gohtdsawRqnUy/ANylCjKuhcR2mPw==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-codec@4.1.0': + resolution: {integrity: sha512-MSOb6pwG3Tss1UwlZMHC+rYergWCo4fwep3Y1fJxwdLLxReSaKFfXxPQhEHi/8LSNQFEcBYBxybgjXjw4jJWqQ==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-browser@4.1.0': + resolution: {integrity: sha512-VvHXoBoLos2OCdMtUvKWK7ckcvun6ZP4KBYhf38+kszk6BEuK9k8c3xbIMIpC6K4vTK72qHlHAdBoR9qU+F7xw==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-config-resolver@4.2.0': + resolution: {integrity: sha512-T7YlcU0cP2bjAC4eXo9E6puqrrmqv5VHBL8bPMOMgEE1p4m+bwkDWRQpeiXqn/idoKM1qwXq8PvRLYmpbYB6uw==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-node@4.1.0': + resolution: {integrity: sha512-WlIKVRkcPjwuN3x+e8+5KOI9nL6s93bxgWH+39VwwQMl+4FagKPtTM3VCumSoZJ9qn/CNl4W5mVdFFRkDF84lQ==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-universal@4.1.0': + resolution: {integrity: sha512-GjMezHHd0xrjJcWLAcnXlVePe7PY8KsdxzKeXcMn7V3vfIScGUpKQJrlSmEXwzFH9Mjl0G0EdOS5GzewZEwtxg==} + engines: {node: '>=18.0.0'} + + '@smithy/fetch-http-handler@5.2.0': + resolution: {integrity: sha512-VZenjDdVaUGiy3hwQtxm75nhXZrhFG+3xyL93qCQAlYDyhT/jeDWM8/3r5uCFMlTmmyrIjiDyiOynVFchb0BSg==} + engines: {node: '>=18.0.0'} + + '@smithy/hash-blob-browser@4.1.0': + resolution: {integrity: sha512-brRgh2qEYPHYImfqoQB/xfcT/CjSz9Z/dH2vURSS0lIw3bImFK5t15l4iypwRw4GtZlZTK/VsLqsR54OJWRerg==} + engines: {node: '>=18.0.0'} + + '@smithy/hash-node@4.1.0': + resolution: {integrity: sha512-mXkJQ/6lAXTuoSsEH+d/fHa4ms4qV5LqYoPLYhmhCRTNcMMdg+4Ya8cMgU1W8+OR40eX0kzsExT7fAILqtTl2w==} + engines: {node: '>=18.0.0'} + + '@smithy/hash-stream-node@4.1.0': + resolution: {integrity: sha512-9TToqq62msanK/L6pV1ZAOm2+1VgCz9gE6/TVJhZXV352DnAItaO9jx6FFGujUDXrRJV0lpwe4c0vymz/vXMUQ==} + engines: {node: '>=18.0.0'} + + '@smithy/invalid-dependency@4.1.0': + resolution: {integrity: sha512-4/FcV6aCMzgpM4YyA/GRzTtG28G0RQJcWK722MmpIgzOyfSceWcI9T9c8matpHU9qYYLaWtk8pSGNCLn5kzDRw==} + engines: {node: '>=18.0.0'} + + '@smithy/is-array-buffer@2.2.0': + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + + '@smithy/is-array-buffer@4.1.0': + resolution: {integrity: sha512-ePTYUOV54wMogio+he4pBybe8fwg4sDvEVDBU8ZlHOZXbXK3/C0XfJgUCu6qAZcawv05ZhZzODGUerFBPsPUDQ==} + engines: {node: '>=18.0.0'} + + '@smithy/md5-js@4.1.0': + resolution: {integrity: sha512-RW1+/E3rv80254ekFqiUTM8ExtN0dG9dkUwU2x17rxS4Mn2ib3SrTCdayCiNbfj6xWHupzgOJB6iNoXiOzNe6g==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-content-length@4.1.0': + resolution: {integrity: sha512-x3dgLFubk/ClKVniJu+ELeZGk4mq7Iv0HgCRUlxNUIcerHTLVmq7Q5eGJL0tOnUltY6KFw5YOKaYxwdcMwox/w==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-endpoint@4.2.0': + resolution: {integrity: sha512-J1eCF7pPDwgv7fGwRd2+Y+H9hlIolF3OZ2PjptonzzyOXXGh/1KGJAHpEcY1EX+WLlclKu2yC5k+9jWXdUG4YQ==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-retry@4.2.0': + resolution: {integrity: sha512-raL5oWYf5ALl3jCJrajE8enKJEnV/2wZkKS6mb3ZRY2tg3nj66ssdWy5Ps8E6Yu8Wqh3Tt+Sb9LozjvwZupq+A==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-serde@4.1.0': + resolution: {integrity: sha512-CtLFYlHt7c2VcztyVRc+25JLV4aGpmaSv9F1sPB0AGFL6S+RPythkqpGDa2XBQLJQooKkjLA1g7Xe4450knShg==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-stack@4.1.0': + resolution: {integrity: sha512-91Fuw4IKp0eK8PNhMXrHRcYA1jvbZ9BJGT91wwPy3bTQT8mHTcQNius/EhSQTlT9QUI3Ki1wjHeNXbWK0tO8YQ==} + engines: {node: '>=18.0.0'} + + '@smithy/node-config-provider@4.2.0': + resolution: {integrity: sha512-8/fpilqKurQ+f8nFvoFkJ0lrymoMJ+5/CQV5IcTv/MyKhk2Q/EFYCAgTSWHD4nMi9ux9NyBBynkyE9SLg2uSLA==} + engines: {node: '>=18.0.0'} + + '@smithy/node-http-handler@4.2.0': + resolution: {integrity: sha512-G4NV70B4hF9vBrUkkvNfWO6+QR4jYjeO4tc+4XrKCb4nPYj49V9Hu8Ftio7Mb0/0IlFyEOORudHrm+isY29nCA==} + engines: {node: '>=18.0.0'} + + '@smithy/property-provider@4.1.0': + resolution: {integrity: sha512-eksMjMHUlG5PwOUWO3k+rfLNOPVPJ70mUzyYNKb5lvyIuAwS4zpWGsxGiuT74DFWonW0xRNy+jgzGauUzX7SyA==} + engines: {node: '>=18.0.0'} + + '@smithy/protocol-http@5.2.0': + resolution: {integrity: sha512-bwjlh5JwdOQnA01be+5UvHK4HQz4iaRKlVG46hHSJuqi0Ribt3K06Z1oQ29i35Np4G9MCDgkOGcHVyLMreMcbg==} + engines: {node: '>=18.0.0'} + + '@smithy/querystring-builder@4.1.0': + resolution: {integrity: sha512-JqTWmVIq4AF8R8OK/2cCCiQo5ZJ0SRPsDkDgLO5/3z8xxuUp1oMIBBjfuueEe+11hGTZ6rRebzYikpKc6yQV9Q==} + engines: {node: '>=18.0.0'} + + '@smithy/querystring-parser@4.1.0': + resolution: {integrity: sha512-VgdHhr8YTRsjOl4hnKFm7xEMOCRTnKw3FJ1nU+dlWNhdt/7eEtxtkdrJdx7PlRTabdANTmvyjE4umUl9cK4awg==} + engines: {node: '>=18.0.0'} + + '@smithy/service-error-classification@4.1.0': + resolution: {integrity: sha512-UBpNFzBNmS20jJomuYn++Y+soF8rOK9AvIGjS9yGP6uRXF5rP18h4FDUsoNpWTlSsmiJ87e2DpZo9ywzSMH7PQ==} + engines: {node: '>=18.0.0'} + + '@smithy/shared-ini-file-loader@4.1.0': + resolution: {integrity: sha512-W0VMlz9yGdQ/0ZAgWICFjFHTVU0YSfGoCVpKaExRM/FDkTeP/yz8OKvjtGjs6oFokCRm0srgj/g4Cg0xuHu8Rw==} + engines: {node: '>=18.0.0'} + + '@smithy/signature-v4@5.2.0': + resolution: {integrity: sha512-ObX1ZqG2DdZQlXx9mLD7yAR8AGb7yXurGm+iWx9x4l1fBZ8CZN2BRT09aSbcXVPZXWGdn5VtMuupjxhOTI2EjA==} + engines: {node: '>=18.0.0'} + + '@smithy/smithy-client@4.6.0': + resolution: {integrity: sha512-TvlIshqx5PIi0I0AiR+PluCpJ8olVG++xbYkAIGCUkByaMUlfOXLgjQTmYbr46k4wuDe8eHiTIlUflnjK2drPQ==} + engines: {node: '>=18.0.0'} + + '@smithy/types@4.4.0': + resolution: {integrity: sha512-4jY91NgZz+ZnSFcVzWwngOW6VuK3gR/ihTwSU1R/0NENe9Jd8SfWgbhDCAGUWL3bI7DiDSW7XF6Ui6bBBjrqXw==} + engines: {node: '>=18.0.0'} + + '@smithy/url-parser@4.1.0': + resolution: {integrity: sha512-/LYEIOuO5B2u++tKr1NxNxhZTrr3A63jW8N73YTwVeUyAlbB/YM+hkftsvtKAcMt3ADYo0FsF1GY3anehffSVQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-base64@4.1.0': + resolution: {integrity: sha512-RUGd4wNb8GeW7xk+AY5ghGnIwM96V0l2uzvs/uVHf+tIuVX2WSvynk5CxNoBCsM2rQRSZElAo9rt3G5mJ/gktQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-body-length-browser@4.1.0': + resolution: {integrity: sha512-V2E2Iez+bo6bUMOTENPr6eEmepdY8Hbs+Uc1vkDKgKNA/brTJqOW/ai3JO1BGj9GbCeLqw90pbbH7HFQyFotGQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-body-length-node@4.1.0': + resolution: {integrity: sha512-BOI5dYjheZdgR9XiEM3HJcEMCXSoqbzu7CzIgYrx0UtmvtC3tC2iDGpJLsSRFffUpy8ymsg2ARMP5fR8mtuUQQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-buffer-from@2.2.0': + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-buffer-from@4.1.0': + resolution: {integrity: sha512-N6yXcjfe/E+xKEccWEKzK6M+crMrlwaCepKja0pNnlSkm6SjAeLKKA++er5Ba0I17gvKfN/ThV+ZOx/CntKTVw==} + engines: {node: '>=18.0.0'} + + '@smithy/util-config-provider@4.1.0': + resolution: {integrity: sha512-swXz2vMjrP1ZusZWVTB/ai5gK+J8U0BWvP10v9fpcFvg+Xi/87LHvHfst2IgCs1i0v4qFZfGwCmeD/KNCdJZbQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-defaults-mode-browser@4.1.0': + resolution: {integrity: sha512-D27cLtJtC4EEeERJXS+JPoogz2tE5zeE3zhWSSu6ER5/wJ5gihUxIzoarDX6K1U27IFTHit5YfHqU4Y9RSGE0w==} + engines: {node: '>=18.0.0'} + + '@smithy/util-defaults-mode-node@4.1.0': + resolution: {integrity: sha512-gnZo3u5dP1o87plKupg39alsbeIY1oFFnCyV2nI/++pL19vTtBLgOyftLEjPjuXmoKn2B2rskX8b7wtC/+3Okg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-endpoints@3.1.0': + resolution: {integrity: sha512-5LFg48KkunBVGrNs3dnQgLlMXJLVo7k9sdZV5su3rjO3c3DmQ2LwUZI0Zr49p89JWK6sB7KmzyI2fVcDsZkwuw==} + engines: {node: '>=18.0.0'} + + '@smithy/util-hex-encoding@4.1.0': + resolution: {integrity: sha512-1LcueNN5GYC4tr8mo14yVYbh/Ur8jHhWOxniZXii+1+ePiIbsLZ5fEI0QQGtbRRP5mOhmooos+rLmVASGGoq5w==} + engines: {node: '>=18.0.0'} + + '@smithy/util-middleware@4.1.0': + resolution: {integrity: sha512-612onNcKyxhP7/YOTKFTb2F6sPYtMRddlT5mZvYf1zduzaGzkYhpYIPxIeeEwBZFjnvEqe53Ijl2cYEfJ9d6/Q==} + engines: {node: '>=18.0.0'} + + '@smithy/util-retry@4.1.0': + resolution: {integrity: sha512-5AGoBHb207xAKSVwaUnaER+L55WFY8o2RhlafELZR3mB0J91fpL+Qn+zgRkPzns3kccGaF2vy0HmNVBMWmN6dA==} + engines: {node: '>=18.0.0'} + + '@smithy/util-stream@4.3.0': + resolution: {integrity: sha512-ZOYS94jksDwvsCJtppHprUhsIscRnCKGr6FXCo3SxgQ31ECbza3wqDBqSy6IsAak+h/oAXb1+UYEBmDdseAjUQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-uri-escape@4.1.0': + resolution: {integrity: sha512-b0EFQkq35K5NHUYxU72JuoheM6+pytEVUGlTwiFxWFpmddA+Bpz3LgsPRIpBk8lnPE47yT7AF2Egc3jVnKLuPg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-utf8@2.3.0': + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} + + '@smithy/util-utf8@4.1.0': + resolution: {integrity: sha512-mEu1/UIXAdNYuBcyEPbjScKi/+MQVXNIuY/7Cm5XLIWe319kDrT5SizBE95jqtmEXoDbGoZxKLCMttdZdqTZKQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-waiter@4.1.0': + resolution: {integrity: sha512-IUuj2zpGdeKaY5OdGnU83BUJsv7OA9uw3rNVSOuvzLMXMpBTU+W6V0SsQh6iI32lKUJArlnEU4BIzp83hghR/g==} + engines: {node: '>=18.0.0'} + '@socket.io/component-emitter@3.1.2': resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} @@ -1256,6 +1622,9 @@ packages: '@types/react@18.3.24': resolution: {integrity: sha512-0dLEBsA1kI3OezMBF8nSsb7Nk19ZnsyE1LLhB8r27KbgU5H4pvuqZLdtE+aUkJVoXgTVuA+iLIwmZ0TuK4tx6A==} + '@types/uuid@9.0.8': + resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} + '@vercel/analytics@1.3.1': resolution: {integrity: sha512-xhSlYgAuJ6Q4WQGkzYTLmXwhYl39sWjoMA3nHxfkvG+WdBT25c563a7QhwwKivEOZtPJXifYHR1m2ihoisbWyA==} peerDependencies: @@ -1299,6 +1668,9 @@ packages: bintrees@1.0.2: resolution: {integrity: sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==} + bowser@2.12.1: + resolution: {integrity: sha512-z4rE2Gxh7tvshQ4hluIT7XcFrgLIQaw9X3A+kTTRdovCz5PMukm/0QC/BKSYPj3omF5Qfypn9O/c5kgpmvYUCw==} + browserslist@4.25.4: resolution: {integrity: sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -1503,6 +1875,10 @@ packages: resolution: {integrity: sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw==} engines: {node: '>=6.0.0'} + fast-xml-parser@5.2.5: + resolution: {integrity: sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==} + hasBin: true + fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} @@ -1940,6 +2316,9 @@ packages: resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} engines: {node: '>=12'} + strnum@2.1.1: + resolution: {integrity: sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==} + styled-jsx@5.1.1: resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} engines: {node: '>= 12.0.0'} @@ -2122,6 +2501,472 @@ snapshots: '@alloc/quick-lru@5.2.0': {} + '@aws-crypto/crc32@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.862.0 + tslib: 2.8.1 + + '@aws-crypto/crc32c@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.862.0 + tslib: 2.8.1 + + '@aws-crypto/sha1-browser@5.2.0': + dependencies: + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.862.0 + '@aws-sdk/util-locate-window': 3.873.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-crypto/sha256-browser@5.2.0': + dependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.862.0 + '@aws-sdk/util-locate-window': 3.873.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-crypto/sha256-js@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.862.0 + tslib: 2.8.1 + + '@aws-crypto/supports-web-crypto@5.2.0': + dependencies: + tslib: 2.8.1 + + '@aws-crypto/util@5.2.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-sdk/client-s3@3.882.0': + dependencies: + '@aws-crypto/sha1-browser': 5.2.0 + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.882.0 + '@aws-sdk/credential-provider-node': 3.882.0 + '@aws-sdk/middleware-bucket-endpoint': 3.873.0 + '@aws-sdk/middleware-expect-continue': 3.873.0 + '@aws-sdk/middleware-flexible-checksums': 3.882.0 + '@aws-sdk/middleware-host-header': 3.873.0 + '@aws-sdk/middleware-location-constraint': 3.873.0 + '@aws-sdk/middleware-logger': 3.876.0 + '@aws-sdk/middleware-recursion-detection': 3.873.0 + '@aws-sdk/middleware-sdk-s3': 3.882.0 + '@aws-sdk/middleware-ssec': 3.873.0 + '@aws-sdk/middleware-user-agent': 3.882.0 + '@aws-sdk/region-config-resolver': 3.873.0 + '@aws-sdk/signature-v4-multi-region': 3.882.0 + '@aws-sdk/types': 3.862.0 + '@aws-sdk/util-endpoints': 3.879.0 + '@aws-sdk/util-user-agent-browser': 3.873.0 + '@aws-sdk/util-user-agent-node': 3.882.0 + '@aws-sdk/xml-builder': 3.873.0 + '@smithy/config-resolver': 4.2.0 + '@smithy/core': 3.10.0 + '@smithy/eventstream-serde-browser': 4.1.0 + '@smithy/eventstream-serde-config-resolver': 4.2.0 + '@smithy/eventstream-serde-node': 4.1.0 + '@smithy/fetch-http-handler': 5.2.0 + '@smithy/hash-blob-browser': 4.1.0 + '@smithy/hash-node': 4.1.0 + '@smithy/hash-stream-node': 4.1.0 + '@smithy/invalid-dependency': 4.1.0 + '@smithy/md5-js': 4.1.0 + '@smithy/middleware-content-length': 4.1.0 + '@smithy/middleware-endpoint': 4.2.0 + '@smithy/middleware-retry': 4.2.0 + '@smithy/middleware-serde': 4.1.0 + '@smithy/middleware-stack': 4.1.0 + '@smithy/node-config-provider': 4.2.0 + '@smithy/node-http-handler': 4.2.0 + '@smithy/protocol-http': 5.2.0 + '@smithy/smithy-client': 4.6.0 + '@smithy/types': 4.4.0 + '@smithy/url-parser': 4.1.0 + '@smithy/util-base64': 4.1.0 + '@smithy/util-body-length-browser': 4.1.0 + '@smithy/util-body-length-node': 4.1.0 + '@smithy/util-defaults-mode-browser': 4.1.0 + '@smithy/util-defaults-mode-node': 4.1.0 + '@smithy/util-endpoints': 3.1.0 + '@smithy/util-middleware': 4.1.0 + '@smithy/util-retry': 4.1.0 + '@smithy/util-stream': 4.3.0 + '@smithy/util-utf8': 4.1.0 + '@smithy/util-waiter': 4.1.0 + '@types/uuid': 9.0.8 + tslib: 2.8.1 + uuid: 9.0.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sso@3.882.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.882.0 + '@aws-sdk/middleware-host-header': 3.873.0 + '@aws-sdk/middleware-logger': 3.876.0 + '@aws-sdk/middleware-recursion-detection': 3.873.0 + '@aws-sdk/middleware-user-agent': 3.882.0 + '@aws-sdk/region-config-resolver': 3.873.0 + '@aws-sdk/types': 3.862.0 + '@aws-sdk/util-endpoints': 3.879.0 + '@aws-sdk/util-user-agent-browser': 3.873.0 + '@aws-sdk/util-user-agent-node': 3.882.0 + '@smithy/config-resolver': 4.2.0 + '@smithy/core': 3.10.0 + '@smithy/fetch-http-handler': 5.2.0 + '@smithy/hash-node': 4.1.0 + '@smithy/invalid-dependency': 4.1.0 + '@smithy/middleware-content-length': 4.1.0 + '@smithy/middleware-endpoint': 4.2.0 + '@smithy/middleware-retry': 4.2.0 + '@smithy/middleware-serde': 4.1.0 + '@smithy/middleware-stack': 4.1.0 + '@smithy/node-config-provider': 4.2.0 + '@smithy/node-http-handler': 4.2.0 + '@smithy/protocol-http': 5.2.0 + '@smithy/smithy-client': 4.6.0 + '@smithy/types': 4.4.0 + '@smithy/url-parser': 4.1.0 + '@smithy/util-base64': 4.1.0 + '@smithy/util-body-length-browser': 4.1.0 + '@smithy/util-body-length-node': 4.1.0 + '@smithy/util-defaults-mode-browser': 4.1.0 + '@smithy/util-defaults-mode-node': 4.1.0 + '@smithy/util-endpoints': 3.1.0 + '@smithy/util-middleware': 4.1.0 + '@smithy/util-retry': 4.1.0 + '@smithy/util-utf8': 4.1.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/core@3.882.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@aws-sdk/xml-builder': 3.873.0 + '@smithy/core': 3.10.0 + '@smithy/node-config-provider': 4.2.0 + '@smithy/property-provider': 4.1.0 + '@smithy/protocol-http': 5.2.0 + '@smithy/signature-v4': 5.2.0 + '@smithy/smithy-client': 4.6.0 + '@smithy/types': 4.4.0 + '@smithy/util-base64': 4.1.0 + '@smithy/util-body-length-browser': 4.1.0 + '@smithy/util-middleware': 4.1.0 + '@smithy/util-utf8': 4.1.0 + fast-xml-parser: 5.2.5 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-env@3.882.0': + dependencies: + '@aws-sdk/core': 3.882.0 + '@aws-sdk/types': 3.862.0 + '@smithy/property-provider': 4.1.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-http@3.882.0': + dependencies: + '@aws-sdk/core': 3.882.0 + '@aws-sdk/types': 3.862.0 + '@smithy/fetch-http-handler': 5.2.0 + '@smithy/node-http-handler': 4.2.0 + '@smithy/property-provider': 4.1.0 + '@smithy/protocol-http': 5.2.0 + '@smithy/smithy-client': 4.6.0 + '@smithy/types': 4.4.0 + '@smithy/util-stream': 4.3.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-ini@3.882.0': + dependencies: + '@aws-sdk/core': 3.882.0 + '@aws-sdk/credential-provider-env': 3.882.0 + '@aws-sdk/credential-provider-http': 3.882.0 + '@aws-sdk/credential-provider-process': 3.882.0 + '@aws-sdk/credential-provider-sso': 3.882.0 + '@aws-sdk/credential-provider-web-identity': 3.882.0 + '@aws-sdk/nested-clients': 3.882.0 + '@aws-sdk/types': 3.862.0 + '@smithy/credential-provider-imds': 4.1.0 + '@smithy/property-provider': 4.1.0 + '@smithy/shared-ini-file-loader': 4.1.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-node@3.882.0': + dependencies: + '@aws-sdk/credential-provider-env': 3.882.0 + '@aws-sdk/credential-provider-http': 3.882.0 + '@aws-sdk/credential-provider-ini': 3.882.0 + '@aws-sdk/credential-provider-process': 3.882.0 + '@aws-sdk/credential-provider-sso': 3.882.0 + '@aws-sdk/credential-provider-web-identity': 3.882.0 + '@aws-sdk/types': 3.862.0 + '@smithy/credential-provider-imds': 4.1.0 + '@smithy/property-provider': 4.1.0 + '@smithy/shared-ini-file-loader': 4.1.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-process@3.882.0': + dependencies: + '@aws-sdk/core': 3.882.0 + '@aws-sdk/types': 3.862.0 + '@smithy/property-provider': 4.1.0 + '@smithy/shared-ini-file-loader': 4.1.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-sso@3.882.0': + dependencies: + '@aws-sdk/client-sso': 3.882.0 + '@aws-sdk/core': 3.882.0 + '@aws-sdk/token-providers': 3.882.0 + '@aws-sdk/types': 3.862.0 + '@smithy/property-provider': 4.1.0 + '@smithy/shared-ini-file-loader': 4.1.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-web-identity@3.882.0': + dependencies: + '@aws-sdk/core': 3.882.0 + '@aws-sdk/nested-clients': 3.882.0 + '@aws-sdk/types': 3.862.0 + '@smithy/property-provider': 4.1.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/middleware-bucket-endpoint@3.873.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@aws-sdk/util-arn-parser': 3.873.0 + '@smithy/node-config-provider': 4.2.0 + '@smithy/protocol-http': 5.2.0 + '@smithy/types': 4.4.0 + '@smithy/util-config-provider': 4.1.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-expect-continue@3.873.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@smithy/protocol-http': 5.2.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-flexible-checksums@3.882.0': + dependencies: + '@aws-crypto/crc32': 5.2.0 + '@aws-crypto/crc32c': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/core': 3.882.0 + '@aws-sdk/types': 3.862.0 + '@smithy/is-array-buffer': 4.1.0 + '@smithy/node-config-provider': 4.2.0 + '@smithy/protocol-http': 5.2.0 + '@smithy/types': 4.4.0 + '@smithy/util-middleware': 4.1.0 + '@smithy/util-stream': 4.3.0 + '@smithy/util-utf8': 4.1.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-host-header@3.873.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@smithy/protocol-http': 5.2.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-location-constraint@3.873.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-logger@3.876.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-recursion-detection@3.873.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@smithy/protocol-http': 5.2.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-sdk-s3@3.882.0': + dependencies: + '@aws-sdk/core': 3.882.0 + '@aws-sdk/types': 3.862.0 + '@aws-sdk/util-arn-parser': 3.873.0 + '@smithy/core': 3.10.0 + '@smithy/node-config-provider': 4.2.0 + '@smithy/protocol-http': 5.2.0 + '@smithy/signature-v4': 5.2.0 + '@smithy/smithy-client': 4.6.0 + '@smithy/types': 4.4.0 + '@smithy/util-config-provider': 4.1.0 + '@smithy/util-middleware': 4.1.0 + '@smithy/util-stream': 4.3.0 + '@smithy/util-utf8': 4.1.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-ssec@3.873.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-user-agent@3.882.0': + dependencies: + '@aws-sdk/core': 3.882.0 + '@aws-sdk/types': 3.862.0 + '@aws-sdk/util-endpoints': 3.879.0 + '@smithy/core': 3.10.0 + '@smithy/protocol-http': 5.2.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@aws-sdk/nested-clients@3.882.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.882.0 + '@aws-sdk/middleware-host-header': 3.873.0 + '@aws-sdk/middleware-logger': 3.876.0 + '@aws-sdk/middleware-recursion-detection': 3.873.0 + '@aws-sdk/middleware-user-agent': 3.882.0 + '@aws-sdk/region-config-resolver': 3.873.0 + '@aws-sdk/types': 3.862.0 + '@aws-sdk/util-endpoints': 3.879.0 + '@aws-sdk/util-user-agent-browser': 3.873.0 + '@aws-sdk/util-user-agent-node': 3.882.0 + '@smithy/config-resolver': 4.2.0 + '@smithy/core': 3.10.0 + '@smithy/fetch-http-handler': 5.2.0 + '@smithy/hash-node': 4.1.0 + '@smithy/invalid-dependency': 4.1.0 + '@smithy/middleware-content-length': 4.1.0 + '@smithy/middleware-endpoint': 4.2.0 + '@smithy/middleware-retry': 4.2.0 + '@smithy/middleware-serde': 4.1.0 + '@smithy/middleware-stack': 4.1.0 + '@smithy/node-config-provider': 4.2.0 + '@smithy/node-http-handler': 4.2.0 + '@smithy/protocol-http': 5.2.0 + '@smithy/smithy-client': 4.6.0 + '@smithy/types': 4.4.0 + '@smithy/url-parser': 4.1.0 + '@smithy/util-base64': 4.1.0 + '@smithy/util-body-length-browser': 4.1.0 + '@smithy/util-body-length-node': 4.1.0 + '@smithy/util-defaults-mode-browser': 4.1.0 + '@smithy/util-defaults-mode-node': 4.1.0 + '@smithy/util-endpoints': 3.1.0 + '@smithy/util-middleware': 4.1.0 + '@smithy/util-retry': 4.1.0 + '@smithy/util-utf8': 4.1.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/region-config-resolver@3.873.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@smithy/node-config-provider': 4.2.0 + '@smithy/types': 4.4.0 + '@smithy/util-config-provider': 4.1.0 + '@smithy/util-middleware': 4.1.0 + tslib: 2.8.1 + + '@aws-sdk/signature-v4-multi-region@3.882.0': + dependencies: + '@aws-sdk/middleware-sdk-s3': 3.882.0 + '@aws-sdk/types': 3.862.0 + '@smithy/protocol-http': 5.2.0 + '@smithy/signature-v4': 5.2.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.882.0': + dependencies: + '@aws-sdk/core': 3.882.0 + '@aws-sdk/nested-clients': 3.882.0 + '@aws-sdk/types': 3.862.0 + '@smithy/property-provider': 4.1.0 + '@smithy/shared-ini-file-loader': 4.1.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/types@3.862.0': + dependencies: + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@aws-sdk/util-arn-parser@3.873.0': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/util-endpoints@3.879.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@smithy/types': 4.4.0 + '@smithy/url-parser': 4.1.0 + '@smithy/util-endpoints': 3.1.0 + tslib: 2.8.1 + + '@aws-sdk/util-locate-window@3.873.0': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-browser@3.873.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@smithy/types': 4.4.0 + bowser: 2.12.1 + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-node@3.882.0': + dependencies: + '@aws-sdk/middleware-user-agent': 3.882.0 + '@aws-sdk/types': 3.862.0 + '@smithy/node-config-provider': 4.2.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@aws-sdk/xml-builder@3.873.0': + dependencies: + '@smithy/types': 4.4.0 + tslib: 2.8.1 + '@babel/runtime@7.28.3': {} '@bugsnag/cuid@3.2.1': {} @@ -3021,6 +3866,342 @@ snapshots: '@rollup/rollup-darwin-arm64@4.50.0': optional: true + '@smithy/abort-controller@4.1.0': + dependencies: + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@smithy/chunked-blob-reader-native@4.1.0': + dependencies: + '@smithy/util-base64': 4.1.0 + tslib: 2.8.1 + + '@smithy/chunked-blob-reader@5.1.0': + dependencies: + tslib: 2.8.1 + + '@smithy/config-resolver@4.2.0': + dependencies: + '@smithy/node-config-provider': 4.2.0 + '@smithy/types': 4.4.0 + '@smithy/util-config-provider': 4.1.0 + '@smithy/util-middleware': 4.1.0 + tslib: 2.8.1 + + '@smithy/core@3.10.0': + dependencies: + '@smithy/middleware-serde': 4.1.0 + '@smithy/protocol-http': 5.2.0 + '@smithy/types': 4.4.0 + '@smithy/util-base64': 4.1.0 + '@smithy/util-body-length-browser': 4.1.0 + '@smithy/util-middleware': 4.1.0 + '@smithy/util-stream': 4.3.0 + '@smithy/util-utf8': 4.1.0 + '@types/uuid': 9.0.8 + tslib: 2.8.1 + uuid: 9.0.1 + + '@smithy/credential-provider-imds@4.1.0': + dependencies: + '@smithy/node-config-provider': 4.2.0 + '@smithy/property-provider': 4.1.0 + '@smithy/types': 4.4.0 + '@smithy/url-parser': 4.1.0 + tslib: 2.8.1 + + '@smithy/eventstream-codec@4.1.0': + dependencies: + '@aws-crypto/crc32': 5.2.0 + '@smithy/types': 4.4.0 + '@smithy/util-hex-encoding': 4.1.0 + tslib: 2.8.1 + + '@smithy/eventstream-serde-browser@4.1.0': + dependencies: + '@smithy/eventstream-serde-universal': 4.1.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@smithy/eventstream-serde-config-resolver@4.2.0': + dependencies: + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@smithy/eventstream-serde-node@4.1.0': + dependencies: + '@smithy/eventstream-serde-universal': 4.1.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@smithy/eventstream-serde-universal@4.1.0': + dependencies: + '@smithy/eventstream-codec': 4.1.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@smithy/fetch-http-handler@5.2.0': + dependencies: + '@smithy/protocol-http': 5.2.0 + '@smithy/querystring-builder': 4.1.0 + '@smithy/types': 4.4.0 + '@smithy/util-base64': 4.1.0 + tslib: 2.8.1 + + '@smithy/hash-blob-browser@4.1.0': + dependencies: + '@smithy/chunked-blob-reader': 5.1.0 + '@smithy/chunked-blob-reader-native': 4.1.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@smithy/hash-node@4.1.0': + dependencies: + '@smithy/types': 4.4.0 + '@smithy/util-buffer-from': 4.1.0 + '@smithy/util-utf8': 4.1.0 + tslib: 2.8.1 + + '@smithy/hash-stream-node@4.1.0': + dependencies: + '@smithy/types': 4.4.0 + '@smithy/util-utf8': 4.1.0 + tslib: 2.8.1 + + '@smithy/invalid-dependency@4.1.0': + dependencies: + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@smithy/is-array-buffer@2.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/is-array-buffer@4.1.0': + dependencies: + tslib: 2.8.1 + + '@smithy/md5-js@4.1.0': + dependencies: + '@smithy/types': 4.4.0 + '@smithy/util-utf8': 4.1.0 + tslib: 2.8.1 + + '@smithy/middleware-content-length@4.1.0': + dependencies: + '@smithy/protocol-http': 5.2.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@smithy/middleware-endpoint@4.2.0': + dependencies: + '@smithy/core': 3.10.0 + '@smithy/middleware-serde': 4.1.0 + '@smithy/node-config-provider': 4.2.0 + '@smithy/shared-ini-file-loader': 4.1.0 + '@smithy/types': 4.4.0 + '@smithy/url-parser': 4.1.0 + '@smithy/util-middleware': 4.1.0 + tslib: 2.8.1 + + '@smithy/middleware-retry@4.2.0': + dependencies: + '@smithy/node-config-provider': 4.2.0 + '@smithy/protocol-http': 5.2.0 + '@smithy/service-error-classification': 4.1.0 + '@smithy/smithy-client': 4.6.0 + '@smithy/types': 4.4.0 + '@smithy/util-middleware': 4.1.0 + '@smithy/util-retry': 4.1.0 + '@types/uuid': 9.0.8 + tslib: 2.8.1 + uuid: 9.0.1 + + '@smithy/middleware-serde@4.1.0': + dependencies: + '@smithy/protocol-http': 5.2.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@smithy/middleware-stack@4.1.0': + dependencies: + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@smithy/node-config-provider@4.2.0': + dependencies: + '@smithy/property-provider': 4.1.0 + '@smithy/shared-ini-file-loader': 4.1.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@smithy/node-http-handler@4.2.0': + dependencies: + '@smithy/abort-controller': 4.1.0 + '@smithy/protocol-http': 5.2.0 + '@smithy/querystring-builder': 4.1.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@smithy/property-provider@4.1.0': + dependencies: + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@smithy/protocol-http@5.2.0': + dependencies: + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@smithy/querystring-builder@4.1.0': + dependencies: + '@smithy/types': 4.4.0 + '@smithy/util-uri-escape': 4.1.0 + tslib: 2.8.1 + + '@smithy/querystring-parser@4.1.0': + dependencies: + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@smithy/service-error-classification@4.1.0': + dependencies: + '@smithy/types': 4.4.0 + + '@smithy/shared-ini-file-loader@4.1.0': + dependencies: + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@smithy/signature-v4@5.2.0': + dependencies: + '@smithy/is-array-buffer': 4.1.0 + '@smithy/protocol-http': 5.2.0 + '@smithy/types': 4.4.0 + '@smithy/util-hex-encoding': 4.1.0 + '@smithy/util-middleware': 4.1.0 + '@smithy/util-uri-escape': 4.1.0 + '@smithy/util-utf8': 4.1.0 + tslib: 2.8.1 + + '@smithy/smithy-client@4.6.0': + dependencies: + '@smithy/core': 3.10.0 + '@smithy/middleware-endpoint': 4.2.0 + '@smithy/middleware-stack': 4.1.0 + '@smithy/protocol-http': 5.2.0 + '@smithy/types': 4.4.0 + '@smithy/util-stream': 4.3.0 + tslib: 2.8.1 + + '@smithy/types@4.4.0': + dependencies: + tslib: 2.8.1 + + '@smithy/url-parser@4.1.0': + dependencies: + '@smithy/querystring-parser': 4.1.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@smithy/util-base64@4.1.0': + dependencies: + '@smithy/util-buffer-from': 4.1.0 + '@smithy/util-utf8': 4.1.0 + tslib: 2.8.1 + + '@smithy/util-body-length-browser@4.1.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-body-length-node@4.1.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-buffer-from@2.2.0': + dependencies: + '@smithy/is-array-buffer': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-buffer-from@4.1.0': + dependencies: + '@smithy/is-array-buffer': 4.1.0 + tslib: 2.8.1 + + '@smithy/util-config-provider@4.1.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-defaults-mode-browser@4.1.0': + dependencies: + '@smithy/property-provider': 4.1.0 + '@smithy/smithy-client': 4.6.0 + '@smithy/types': 4.4.0 + bowser: 2.12.1 + tslib: 2.8.1 + + '@smithy/util-defaults-mode-node@4.1.0': + dependencies: + '@smithy/config-resolver': 4.2.0 + '@smithy/credential-provider-imds': 4.1.0 + '@smithy/node-config-provider': 4.2.0 + '@smithy/property-provider': 4.1.0 + '@smithy/smithy-client': 4.6.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@smithy/util-endpoints@3.1.0': + dependencies: + '@smithy/node-config-provider': 4.2.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@smithy/util-hex-encoding@4.1.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-middleware@4.1.0': + dependencies: + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@smithy/util-retry@4.1.0': + dependencies: + '@smithy/service-error-classification': 4.1.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + + '@smithy/util-stream@4.3.0': + dependencies: + '@smithy/fetch-http-handler': 5.2.0 + '@smithy/node-http-handler': 4.2.0 + '@smithy/types': 4.4.0 + '@smithy/util-base64': 4.1.0 + '@smithy/util-buffer-from': 4.1.0 + '@smithy/util-hex-encoding': 4.1.0 + '@smithy/util-utf8': 4.1.0 + tslib: 2.8.1 + + '@smithy/util-uri-escape@4.1.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-utf8@2.3.0': + dependencies: + '@smithy/util-buffer-from': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-utf8@4.1.0': + dependencies: + '@smithy/util-buffer-from': 4.1.0 + tslib: 2.8.1 + + '@smithy/util-waiter@4.1.0': + dependencies: + '@smithy/abort-controller': 4.1.0 + '@smithy/types': 4.4.0 + tslib: 2.8.1 + '@socket.io/component-emitter@3.1.2': {} '@swc/counter@0.1.3': {} @@ -3217,6 +4398,8 @@ snapshots: '@types/prop-types': 15.7.15 csstype: 3.1.3 + '@types/uuid@9.0.8': {} + '@vercel/analytics@1.3.1(next@14.2.25(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)': dependencies: server-only: 0.0.1 @@ -3253,6 +4436,8 @@ snapshots: bintrees@1.0.2: {} + bowser@2.12.1: {} + browserslist@4.25.4: dependencies: caniuse-lite: 1.0.30001739 @@ -3456,6 +4641,10 @@ snapshots: fast-equals@5.2.2: {} + fast-xml-parser@5.2.5: + dependencies: + strnum: 2.1.1 + fraction.js@4.3.7: {} function-bind@1.1.2: {} @@ -3866,6 +5055,8 @@ snapshots: strip-final-newline@3.0.0: {} + strnum@2.1.1: {} + styled-jsx@5.1.1(react@19.1.0): dependencies: client-only: 0.0.1 diff --git a/product-image-generator/src/trigger/example.ts b/product-image-generator/src/trigger/example.ts deleted file mode 100644 index 871d8c0..0000000 --- a/product-image-generator/src/trigger/example.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { logger, task, wait } from "@trigger.dev/sdk/v3"; - -export const helloWorldTask = task({ - id: "hello-world", - // Set an optional maxDuration to prevent tasks from running indefinitely - maxDuration: 300, // Stop executing after 300 secs (5 mins) of compute - run: async (payload: any, { ctx }) => { - logger.log("Hello, world!", { payload, ctx }); - - await wait.for({ seconds: 5 }); - - return { - message: "Hello, world!", - }; - }, -}); diff --git a/product-image-generator/src/trigger/image-upload.ts b/product-image-generator/src/trigger/image-upload.ts new file mode 100644 index 0000000..6e585dc --- /dev/null +++ b/product-image-generator/src/trigger/image-upload.ts @@ -0,0 +1,122 @@ +import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3"; +import { logger, metadata, task } from "@trigger.dev/sdk"; +import { Buffer } from "buffer"; + +// Initialize S3 client for R2 +const s3Client = new S3Client({ + region: "auto", + endpoint: process.env.R2_ENDPOINT, + credentials: { + accessKeyId: process.env.R2_ACCESS_KEY_ID ?? "", + secretAccessKey: process.env.R2_SECRET_ACCESS_KEY ?? "", + }, +}); + +export const uploadImageToR2 = task({ + id: "upload-image-to-r2", + maxDuration: 300, // 5 minutes max + run: async (payload: { + imageBuffer: string; // base64 encoded image + fileName: string; + contentType: string; + }) => { + const { imageBuffer, fileName, contentType } = payload; + + // Set initial metadata + metadata.set("status", "starting"); + metadata.set("progress", { + step: 1, + total: 4, + message: "Preparing upload...", + }); + + logger.log("Starting image upload to R2", { fileName, contentType }); + + // Convert base64 to buffer + metadata.set("progress", { + step: 2, + total: 4, + message: "Processing image data...", + }); + const buffer = Buffer.from(imageBuffer, "base64"); + const fileSize = buffer.length; + + logger.log(`Image size: ${fileSize} bytes`); + + // Generate unique key for R2 + const timestamp = Date.now(); + const sanitizedFileName = fileName.replace(/[^a-zA-Z0-9.-]/g, "_"); + const r2Key = `uploaded-images/${timestamp}-${sanitizedFileName}`; + + metadata.set("progress", { + step: 3, + total: 4, + message: "Uploading to storage...", + }); + + const uploadParams = { + Bucket: process.env.R2_BUCKET, + Key: r2Key, + Body: buffer, + ContentType: contentType, + // Add cache control for better performance + CacheControl: "public, max-age=31536000", // 1 year + }; + + try { + // Upload to R2 + logger.log("About to upload to R2", { + bucket: process.env.R2_BUCKET, + endpoint: process.env.R2_ENDPOINT, + r2Key, + fileSize, + hasAccessKey: !!process.env.R2_ACCESS_KEY_ID, + hasSecretKey: !!process.env.R2_SECRET_ACCESS_KEY, + }); + + const result = await s3Client.send(new PutObjectCommand(uploadParams)); + logger.log("S3 PutObject response:", result as any); + logger.log(`Image uploaded successfully to R2`, { r2Key }); + + // Update metadata for completion + metadata.set("progress", { + step: 4, + total: 4, + message: "Upload completed!", + }); + metadata.set("status", "completed"); + + // Construct the public URL using the R2_PUBLIC_URL env var + const publicUrl = `${process.env.R2_PUBLIC_URL}/${r2Key}`; + + // Set final metadata with result + metadata.set("result", { + publicUrl, + r2Key, + fileSize, + fileName: sanitizedFileName, + }); + + return { + success: true, + bucket: process.env.R2_BUCKET, + r2Key, + publicUrl, + fileSize, + contentType, + fileName: sanitizedFileName, + }; + } catch (error) { + // Set error metadata + metadata.set("status", "failed"); + metadata.set("progress", { step: 0, total: 4, message: "Upload failed" }); + metadata.set( + "error", + error instanceof Error ? error.message : "Unknown error", + ); + + logger.error("Failed to upload image to R2", { error, r2Key }); + throw error; + } + }, +}); diff --git a/product-image-generator/src/trigger/index.ts b/product-image-generator/src/trigger/index.ts deleted file mode 100644 index a11d031..0000000 --- a/product-image-generator/src/trigger/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { helloWorldTask } from "./example"; diff --git a/product-image-generator/trigger.config.ts b/product-image-generator/trigger.config.ts index 727e7e5..6fe60ff 100644 --- a/product-image-generator/trigger.config.ts +++ b/product-image-generator/trigger.config.ts @@ -11,7 +11,7 @@ export default defineConfig({ retries: { enabledInDev: true, default: { - maxAttempts: 3, + maxAttempts: 1, minTimeoutInMs: 1000, maxTimeoutInMs: 10000, factor: 2, diff --git a/product-image-generator/tsconfig.json b/product-image-generator/tsconfig.json index c133409..ceb6ecf 100644 --- a/product-image-generator/tsconfig.json +++ b/product-image-generator/tsconfig.json @@ -19,9 +19,14 @@ } ], "paths": { - "@/*": ["./src/*"] + "@/*": ["./app/*"] } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], - "exclude": ["node_modules"] + "include": [ + "next-env.d.ts", + "app/**/*.ts", + "app/**/*.tsx", + ".next/types/**/*.ts" + ], + "exclude": ["node_modules", "src"] } From 22c1d27fbe525c4f204bedb768aa3fbcd36abd61 Mon Sep 17 00:00:00 2001 From: D-K-P <8297864+D-K-P@users.noreply.github.com> Date: Fri, 5 Sep 2025 11:10:00 +0100 Subject: [PATCH 03/39] Added more tasks and updated actions --- product-image-generator/README.md | 242 ++++++++++++++++-- product-image-generator/app/actions.ts | 97 +++++++ .../app/components/GeneratedCard.tsx | 194 ++++++++++++++ .../app/components/UploadCard.tsx | 13 +- product-image-generator/app/layout.tsx | 9 +- product-image-generator/app/page.tsx | 158 ++++++++++-- product-image-generator/package.json | 2 + product-image-generator/pnpm-lock.yaml | 81 +++++- .../src/trigger/batch-generate-and-upload.ts | 143 +++++++++++ .../src/trigger/batch-generate-images.ts | 143 +++++++++++ .../src/trigger/generate-and-upload-image.ts | 169 ++++++++++++ .../src/trigger/generate-image.ts | 147 +++++++++++ 12 files changed, 1358 insertions(+), 40 deletions(-) create mode 100644 product-image-generator/app/components/GeneratedCard.tsx create mode 100644 product-image-generator/src/trigger/batch-generate-and-upload.ts create mode 100644 product-image-generator/src/trigger/batch-generate-images.ts create mode 100644 product-image-generator/src/trigger/generate-and-upload-image.ts create mode 100644 product-image-generator/src/trigger/generate-image.ts diff --git a/product-image-generator/README.md b/product-image-generator/README.md index e215bc4..f514242 100644 --- a/product-image-generator/README.md +++ b/product-image-generator/README.md @@ -1,36 +1,240 @@ -This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). +# AI Product Image Generator + +Transform product photos into professional marketing materials using AI-powered image generation. + +Upload a product image and automatically generate three marketing variations: isolated table shots, lifestyle scenes, and hero presentations. Built with Next.js, Trigger.dev, and OpenAI's DALL-E 3. + +## Features + +- Real-time progress tracking with WebSocket subscriptions +- Product-focused AI prompts that maintain identical product appearance +- Responsive design with portrait-oriented image cards +- Automatic upload to Cloudflare R2 with public URLs +- Individual retry mechanisms for failed generations +- One-click download functionality +- Parallel processing for multiple image generations + +## Architecture + +### Task Structure + +``` +uploadImageToR2 +├── Handles user image uploads to R2 storage +├── 4-step progress tracking + +generateAndUploadImage +├── Generates AI image using DALL-E 3 +├── Uploads result to R2 storage +├── 5-step progress tracking + +batchGenerateAndUploadImages +├── Triggers 3x generateAndUploadImage tasks in parallel +├── Returns individual run IDs for UI subscription +``` + +### Component Architecture + +``` +UploadCard (aspect-square) +├── Drag & drop image upload +├── Progress tracking via run subscription +├── Triggers batch generation on completion + +GeneratedCard (aspect-[3/4]) +├── Individual task progress tracking +├── Real-time image display via subscription +├── Download and retry functionality + +Main Page +├── Grid layout: 1 upload + 3 generated cards +├── State management for run IDs and access tokens +├── Individual generation triggering and retry handling +``` ## Getting Started -First, run the development server: +### Prerequisites + +- Node.js 18+ and pnpm +- Trigger.dev account and project +- OpenAI API key with DALL-E 3 access +- Cloudflare R2 bucket for image storage + +### Environment Variables + +```env +# Trigger.dev +TRIGGER_SECRET_KEY=tr_dev_your_secret_key_here + +# OpenAI +OPENAI_API_KEY=sk-your_openai_api_key_here + +# Cloudflare R2 Storage +R2_ENDPOINT=https://your-account-id.r2.cloudflarestorage.com +R2_ACCESS_KEY_ID=your_r2_access_key +R2_SECRET_ACCESS_KEY=your_r2_secret_key +R2_BUCKET=your-bucket-name +R2_PUBLIC_URL=https://your-public-domain.com +``` + +### Installation ```bash -npm run dev -# or -yarn dev -# or +# Install dependencies +pnpm install + +# Start development server pnpm dev -# or -bun dev + +# Start Trigger.dev dev server (separate terminal) +pnpm dlx trigger.dev@latest dev ``` -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. +## Usage + +1. Upload a product image via drag & drop or file selection +2. Upload task runs with 4-step progress tracking +3. On completion, batch task triggers 3 parallel generation tasks +4. Each GeneratedCard subscribes to its individual task progress +5. Generated images display with download functionality +6. Failed generations can be retried individually + +## Technical Implementation + +### AI Prompt Engineering + +Each generation uses prompts that emphasize: + +- Product consistency: "EXACT same product from reference image" +- Material preservation: "Identical colors, textures, materials, and design details" +- Context adaptation: Only backgrounds and lighting change + +### Progress Tracking Implementation + +- Upload Task: 4 steps (prepare → process → upload → complete) +- Generation Tasks: 5 steps (prepare → generate → prepare upload → upload → complete) +- Real-time updates via `runs.subscribeToRun()` with public access tokens + +### Image Processing + +- Format: Portrait 1024x1792 for optimal display in 3:4 aspect ratio cards +- Display: `object-contain` CSS to prevent cropping +- Storage: Cloudflare R2 with automatic public URL generation +- Fallback: Base64 blob URLs if storage unavailable + +## Project Structure + +``` +src/ +├── trigger/ +│ ├── image-upload.ts # User image upload to R2 +│ ├── generate-and-upload-image.ts # AI generation + upload (single task) +│ └── batch-generate-and-upload.ts # Batch processing coordinator +├── app/ +│ ├── actions.ts # Server actions for task triggering +│ ├── components/ +│ │ ├── UploadCard.tsx # Image upload with progress +│ │ ├── GeneratedCard.tsx # Generated image display with subscription +│ │ └── ui/ # shadcn/ui components +│ └── page.tsx # Main application interface +└── trigger.config.ts # Trigger.dev configuration +``` + +## Task Flow Details + +### Upload Flow + +1. `UploadCard` triggers `uploadImageToR2` task +2. Task converts file to base64, uploads to R2, returns public URL +3. `UploadCard` subscribes to run progress, displays completion +4. On completion, triggers `batchGenerateAndUploadImages` + +### Generation Flow + +1. `batchGenerateAndUploadImages` triggers 3x `generateAndUploadImage` tasks +2. Each task: generates image → uploads to R2 → returns public URL +3. `GeneratedCard` components subscribe to individual task progress +4. Images display automatically when tasks complete + +### Error Handling + +- Individual task failures don't affect other generations +- Retry functionality re-triggers specific failed tasks +- Comprehensive error logging and user feedback + +## Customization + +### Adding Generation Styles + +Edit prompts in `src/trigger/batch-generate-and-upload.ts`: + +```typescript +const prompts = [ + { + id: "your-style-id", + prompt: "Your detailed prompt here...", + }, +]; +``` + +### Modifying Image Dimensions + +Change size parameter in actions: + +```typescript +size: "1024x1792", // Portrait +size: "1792x1024", // Landscape +size: "1024x1024", // Square +``` + +### Custom Progress Messages + +Update metadata in task files: + +```typescript +metadata.set("progress", { + step: 2, + total: 5, + message: "Custom progress message", +}); +``` + +## Deployment + +### Production Deployment + +```bash +# Deploy tasks to Trigger.dev +pnpm dlx trigger.dev@latest deploy + +# Deploy frontend (Vercel recommended) +vercel deploy +``` -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. +### Environment Configuration -This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. +- Add all environment variables to deployment platform +- Configure R2 bucket CORS for production domain +- Update `R2_PUBLIC_URL` for production storage access +- Ensure OpenAI API key has sufficient credits and rate limits -## Learn More +## Development Notes -To learn more about Next.js, take a look at the following resources: +### Key Implementation Details -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. +- Uses `triggerAndWait()` for sequential task dependencies +- Public access tokens enable client-side run subscriptions +- `aspect-[3/4]` Tailwind class for portrait card layout +- Error boundaries and timeout handling for stuck tasks -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! +### Performance Considerations -## Deploy on Vercel +- Parallel task execution for multiple image generations +- Efficient base64 to blob conversion for image display +- Proper cleanup of blob URLs and timeouts +- Rate limiting considerations for OpenAI API calls -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. +## License -Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. +MIT License - see LICENSE file for details. diff --git a/product-image-generator/app/actions.ts b/product-image-generator/app/actions.ts index 98611d5..bd52367 100644 --- a/product-image-generator/app/actions.ts +++ b/product-image-generator/app/actions.ts @@ -2,6 +2,8 @@ import { auth, tasks } from "@trigger.dev/sdk/v3"; import type { uploadImageToR2 } from "../src/trigger/image-upload"; +import type { batchGenerateAndUploadImages } from "../src/trigger/batch-generate-and-upload"; +import type { generateAndUploadImage } from "../src/trigger/generate-and-upload-image"; export async function createPublicAccessToken(runId: string) { try { @@ -73,3 +75,98 @@ export async function uploadImageToR2Action(formData: FormData) { }; } } + +export async function batchGenerateImagesAction( + baseImageUrl: string, + productDescription?: string, +) { + try { + const handle = await tasks.trigger( + "batch-generate-and-upload-images", + { + baseImageUrl, + productDescription, + }, + ); + + // Create a public access token for this specific run + const tokenResult = await createPublicAccessToken(handle.id); + + if (!tokenResult.success) { + return { + success: false as const, + error: tokenResult.error, + }; + } + + return { + success: true as const, + runId: handle.id, + accessToken: tokenResult.token, + }; + } catch (error) { + console.error("Failed to trigger batch generation:", error); + return { + success: false as const, + error: "Failed to trigger batch generation", + }; + } +} + +export async function generateSingleImageAction( + baseImageUrl: string, + promptId: string, + productDescription: string = "product", +) { + try { + // Define the prompts - emphasizing exact product replication + const prompts = { + "isolated-table": + `Create a professional product photography shot showing the EXACT same product from the reference image, maintaining identical colors, textures, materials, and design details. Place this identical product isolated on a clean white table surface with studio lighting, minimalist background, commercial photography style, high resolution, sharp focus. The product must look exactly the same as in the reference image.`, + "lifestyle-scene": + `Create a lifestyle product photography shot showing the EXACT same product from the reference image, maintaining identical colors, textures, materials, and design details. Place this identical product in a modern home setting with natural lighting, styled environment, aspirational lifestyle, professional commercial photography. The product must look exactly the same as in the reference image, only the background and setting should change.`, + "hero-shot": + `Create a hero product shot showing the EXACT same product from the reference image, maintaining identical colors, textures, materials, and design details. Present this identical product with dramatic lighting, premium presentation, luxury commercial photography style, perfect for marketing materials, high-end aesthetic. The product must look exactly the same as in the reference image, only the lighting and presentation should be enhanced.`, + }; + + const prompt = prompts[promptId as keyof typeof prompts]; + if (!prompt) { + return { + success: false as const, + error: "Invalid prompt ID", + }; + } + + const handle = await tasks.trigger( + "generate-and-upload-image", + { + prompt, + baseImageUrl, + model: "dall-e-3", + size: "1024x1792", // Portrait format for better slot fitting + }, + ); + + // Create a public access token for this specific run + const tokenResult = await createPublicAccessToken(handle.id); + + if (!tokenResult.success) { + return { + success: false as const, + error: tokenResult.error, + }; + } + + return { + success: true as const, + runId: handle.id, + accessToken: tokenResult.token, + }; + } catch (error) { + console.error("Failed to trigger single image generation:", error); + return { + success: false as const, + error: "Failed to trigger image generation", + }; + } +} diff --git a/product-image-generator/app/components/GeneratedCard.tsx b/product-image-generator/app/components/GeneratedCard.tsx new file mode 100644 index 0000000..dfa13a9 --- /dev/null +++ b/product-image-generator/app/components/GeneratedCard.tsx @@ -0,0 +1,194 @@ +"use client"; + +import { Button } from "./ui/button"; +import { Card } from "./ui/card"; +import { Download, RefreshCw } from "lucide-react"; +import { useState, useEffect } from "react"; +import { runs, configure } from "@trigger.dev/sdk/v3"; + +interface GeneratedCardProps { + runId: string | null; + accessToken: string | null; + promptId: string; + promptTitle: string; + onRetry?: () => void; +} + +export default function GeneratedCard({ + runId, + accessToken, + promptId, + promptTitle, + onRetry, +}: GeneratedCardProps) { + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(null); + const [generatedImageUrl, setGeneratedImageUrl] = useState( + null + ); + const [generationProgress, setGenerationProgress] = useState("idle"); + const [progressMessage, setProgressMessage] = useState(""); + const [progressStep, setProgressStep] = useState<{ + step: number; + total: number; + } | null>(null); + + // Subscribe to run updates when runId and accessToken are available + useEffect(() => { + if (!runId || !accessToken) return; + + const subscribeToRun = async () => { + setIsLoading(true); + setGenerationProgress("generating"); + setError(null); + + try { + configure({ + secretKey: accessToken, + }); + + for await (const run of runs.subscribeToRun(runId)) { + // Update progress from metadata + if (run.metadata?.progress) { + const progress = run.metadata.progress as { + step: number; + total: number; + message: string; + }; + setProgressMessage(progress.message); + setProgressStep({ step: progress.step, total: progress.total }); + } + + // Handle completion + if (run.status === "COMPLETED" && run.output) { + setGeneratedImageUrl(run.output.publicUrl); + setGenerationProgress("completed"); + setProgressMessage("Generation completed!"); + setIsLoading(false); + break; + } else if (run.status === "FAILED") { + const errorMsg = run.metadata?.error || "Generation failed"; + setError( + typeof errorMsg === "string" ? errorMsg : "Generation failed" + ); + setGenerationProgress("failed"); + setProgressMessage(""); + setIsLoading(false); + break; + } + } + } catch (err) { + setError("Failed to get task updates"); + setGenerationProgress("failed"); + setIsLoading(false); + } + }; + + subscribeToRun(); + }, [runId, accessToken]); + + const handleDownload = () => { + if (generatedImageUrl) { + const link = document.createElement("a"); + link.href = generatedImageUrl; + link.download = `generated-${promptId}-${Date.now()}.png`; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } + }; + + const handleRetry = () => { + if (onRetry) { + setError(null); + setGeneratedImageUrl(null); + setGenerationProgress("idle"); + setProgressMessage(""); + setProgressStep(null); + onRetry(); + } + }; + + return ( + + {generatedImageUrl ? ( + // Show generated image +
+ {`Generated + {/* Download button */} +
+ +
+ {/* Title overlay */} +
+

{promptTitle}

+
+
+ ) : generationProgress === "failed" ? ( + // Show error state +
+
+ +
+

+ {promptTitle} +

+

{error}

+ {onRetry && ( + + )} +
+ ) : ( + // Show loading/waiting state +
+
+ {isLoading && generationProgress === "generating" ? ( +
+ ) : ( +
+ )} +
+

+ {promptTitle} +

+

+ {generationProgress === "generating" + ? progressMessage || "Generating..." + : generationProgress === "idle" + ? "Waiting to start..." + : "Ready"} +

+ {progressStep && generationProgress === "generating" && ( + <> +
+
+
+

+ Step {progressStep.step} of {progressStep.total} +

+ + )} +
+ )} +
+ ); +} diff --git a/product-image-generator/app/components/UploadCard.tsx b/product-image-generator/app/components/UploadCard.tsx index 1c4857e..d49b5d8 100644 --- a/product-image-generator/app/components/UploadCard.tsx +++ b/product-image-generator/app/components/UploadCard.tsx @@ -7,7 +7,11 @@ import { useRef, useState, useEffect } from "react"; import { uploadImageToR2Action } from "../actions"; import { runs, configure } from "@trigger.dev/sdk/v3"; -export default function UploadCard() { +interface UploadCardProps { + onUploadComplete?: (imageUrl: string) => void; +} + +export default function UploadCard({ onUploadComplete }: UploadCardProps) { const [isDragOver, setIsDragOver] = useState(false); const [isLoading, setIsLoading] = useState(false); const [runId, setRunId] = useState(null); @@ -51,6 +55,11 @@ export default function UploadCard() { setUploadProgress("completed"); setProgressMessage("Upload completed!"); setIsLoading(false); + + // Notify parent component + if (onUploadComplete && run.output.publicUrl) { + onUploadComplete(run.output.publicUrl); + } break; } else if (run.status === "FAILED") { const errorMsg = run.metadata?.error || "Upload failed"; @@ -145,7 +154,7 @@ export default function UploadCard() { return ( (null); + const [generationRunIds, setGenerationRunIds] = useState<{ + [key: string]: string | null; + }>({ + "isolated-table": null, + "lifestyle-scene": null, + "hero-shot": null, + }); + const [generationAccessTokens, setGenerationAccessTokens] = useState<{ + [key: string]: string | null; + }>({ + "isolated-table": null, + "lifestyle-scene": null, + "hero-shot": null, + }); + + const promptTitles = { + "isolated-table": "Table Shot", + "lifestyle-scene": "Lifestyle Scene", + "hero-shot": "Hero Shot", + }; + + const handleUploadComplete = async (imageUrl: string) => { + try { + // Store the uploaded image URL for retries + setUploadedImageUrl(imageUrl); + + // Trigger all 3 generations individually for better progress tracking + const promptIds = ["isolated-table", "lifestyle-scene", "hero-shot"]; + + for (const promptId of promptIds) { + const result = await generateSingleImageAction( + imageUrl, + promptId, + "product" + ); + + if (result.success) { + console.log(`Successfully triggered generation for ${promptId}:`, { + runId: result.runId, + hasAccessToken: !!result.accessToken, + }); + setGenerationRunIds((prev) => ({ + ...prev, + [promptId]: result.runId, + })); + setGenerationAccessTokens((prev) => ({ + ...prev, + [promptId]: result.accessToken, + })); + } else { + console.error( + `Failed to start generation for ${promptId}:`, + result.error + ); + } + } + } catch (error) { + console.error("Failed to start image generations:", error); + } + }; + + const handleRetryGeneration = async (promptId: string) => { + if (!uploadedImageUrl) { + console.error("No base image URL available for retry"); + return; + } + + try { + // Reset the specific generation + setGenerationRunIds((prev) => ({ ...prev, [promptId]: null })); + setGenerationAccessTokens((prev) => ({ ...prev, [promptId]: null })); + + // Trigger the specific generation again + const result = await generateSingleImageAction( + uploadedImageUrl, + promptId, + "product" + ); + + if (result.success) { + setGenerationRunIds((prev) => ({ ...prev, [promptId]: result.runId })); + setGenerationAccessTokens((prev) => ({ + ...prev, + [promptId]: result.accessToken, + })); + } else { + console.error( + `Failed to retry generation for ${promptId}:`, + result.error + ); + } + } catch (error) { + console.error(`Failed to retry generation for ${promptId}:`, error); + } + }; + return (
{/* Navigation Header */} @@ -39,28 +141,54 @@ export default function ImageManagementApp() {

- Image Gallery + Product Image Generator

- Upload and organize your images with our intuitive drag-and-drop - interface + Upload a product image and automatically generate professional + marketing shots

- {/* Image Grid */} -
- {/* First Slot - Upload Card */} - + {/* Top Row - Upload + 3 Generated Images */} +
+ {/* Upload card stays square */} + + handleRetryGeneration("isolated-table")} + /> + handleRetryGeneration("lifestyle-scene")} + /> + handleRetryGeneration("hero-shot")} + /> +
- {/* Remaining 7 Slots - Blank States */} - {Array.from({ length: 7 }).map((_, index) => ( + {/* Bottom Row - 4 More Cards (Future Implementation) */} +
+ {Array.from({ length: 4 }).map((_, index) => (
-
- +
+
+ +
+

Coming Soon

@@ -71,11 +199,11 @@ export default function ImageManagementApp() {
diff --git a/product-image-generator/package.json b/product-image-generator/package.json index c0fb4f3..07decbe 100644 --- a/product-image-generator/package.json +++ b/product-image-generator/package.json @@ -9,6 +9,7 @@ "lint": "next lint" }, "dependencies": { + "@ai-sdk/openai": "^2.0.24", "@aws-sdk/client-s3": "^3.882.0", "@hookform/resolvers": "^3.10.0", "@radix-ui/react-accordion": "1.2.2", @@ -41,6 +42,7 @@ "@trigger.dev/react-hooks": "^4.0.2", "@trigger.dev/sdk": "^4.0.2", "@vercel/analytics": "1.3.1", + "ai": "^5.0.33", "autoprefixer": "^10.4.20", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", diff --git a/product-image-generator/pnpm-lock.yaml b/product-image-generator/pnpm-lock.yaml index 90e65b5..bf6f9ab 100644 --- a/product-image-generator/pnpm-lock.yaml +++ b/product-image-generator/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + '@ai-sdk/openai': + specifier: ^2.0.24 + version: 2.0.24(zod@3.25.67) '@aws-sdk/client-s3': specifier: ^3.882.0 version: 3.882.0 @@ -100,10 +103,13 @@ importers: version: 4.0.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@trigger.dev/sdk': specifier: ^4.0.2 - version: 4.0.2(zod@3.25.67) + version: 4.0.2(ai@5.0.33(zod@3.25.67))(zod@3.25.67) '@vercel/analytics': specifier: 1.3.1 version: 1.3.1(next@14.2.25(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0) + ai: + specifier: ^5.0.33 + version: 5.0.33(zod@3.25.67) autoprefixer: specifier: ^10.4.20 version: 10.4.21(postcss@8.5.6) @@ -198,6 +204,28 @@ importers: packages: + '@ai-sdk/gateway@1.0.18': + resolution: {integrity: sha512-tpUF9nwTVFJGH+u9LHccf1TTRMeUrfJPzYJVpHH1tc1vclO695SQUTIR9jnTCuvn1XFYtkiXUALYpQhBYWf3Pg==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4 + + '@ai-sdk/openai@2.0.24': + resolution: {integrity: sha512-8fPFvlb6PpDjy6JtJBP3Hqs4THKFNYOw6+j7nG7iJivNp+uvHlrHwnU6wQgMAesxEDjZRmVB6ntXWxGPCbBeJw==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4 + + '@ai-sdk/provider-utils@3.0.8': + resolution: {integrity: sha512-cDj1iigu7MW2tgAQeBzOiLhjHOUM9vENsgh4oAVitek0d//WdgfPCsKO3euP7m7LyO/j9a1vr/So+BGNdpFXYw==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4 + + '@ai-sdk/provider@2.0.0': + resolution: {integrity: sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==} + engines: {node: '>=18'} + '@alloc/quick-lru@5.2.0': resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} @@ -1460,6 +1488,9 @@ packages: '@socket.io/component-emitter@3.1.2': resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} + '@standard-schema/spec@1.0.0': + resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} @@ -1650,6 +1681,12 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + ai@5.0.33: + resolution: {integrity: sha512-qmYQTb+K0204mawkjhCMGYPutDqPgmCeh/tQ9I3FpZfxvUe8R462D/MQUgLMFnMQ0z2kpUMoOJBKX6dSKb0OwA==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4 + aria-hidden@1.2.6: resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} engines: {node: '>=10'} @@ -1950,6 +1987,9 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + lightningcss-darwin-arm64@1.30.1: resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==} engines: {node: '>= 12.0.0'} @@ -2499,6 +2539,29 @@ packages: snapshots: + '@ai-sdk/gateway@1.0.18(zod@3.25.67)': + dependencies: + '@ai-sdk/provider': 2.0.0 + '@ai-sdk/provider-utils': 3.0.8(zod@3.25.67) + zod: 3.25.67 + + '@ai-sdk/openai@2.0.24(zod@3.25.67)': + dependencies: + '@ai-sdk/provider': 2.0.0 + '@ai-sdk/provider-utils': 3.0.8(zod@3.25.67) + zod: 3.25.67 + + '@ai-sdk/provider-utils@3.0.8(zod@3.25.67)': + dependencies: + '@ai-sdk/provider': 2.0.0 + '@standard-schema/spec': 1.0.0 + eventsource-parser: 3.0.6 + zod: 3.25.67 + + '@ai-sdk/provider@2.0.0': + dependencies: + json-schema: 0.4.0 + '@alloc/quick-lru@5.2.0': {} '@aws-crypto/crc32@5.2.0': @@ -4204,6 +4267,8 @@ snapshots: '@socket.io/component-emitter@3.1.2': {} + '@standard-schema/spec@1.0.0': {} + '@swc/counter@0.1.3': {} '@swc/helpers@0.5.5': @@ -4333,7 +4398,7 @@ snapshots: - supports-color - utf-8-validate - '@trigger.dev/sdk@4.0.2(zod@3.25.67)': + '@trigger.dev/sdk@4.0.2(ai@5.0.33(zod@3.25.67))(zod@3.25.67)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/semantic-conventions': 1.36.0 @@ -4348,6 +4413,8 @@ snapshots: uuid: 9.0.1 ws: 8.18.3 zod: 3.25.67 + optionalDependencies: + ai: 5.0.33(zod@3.25.67) transitivePeerDependencies: - bufferutil - supports-color @@ -4418,6 +4485,14 @@ snapshots: acorn@8.15.0: {} + ai@5.0.33(zod@3.25.67): + dependencies: + '@ai-sdk/gateway': 1.0.18(zod@3.25.67) + '@ai-sdk/provider': 2.0.0 + '@ai-sdk/provider-utils': 3.0.8(zod@3.25.67) + '@opentelemetry/api': 1.9.0 + zod: 3.25.67 + aria-hidden@1.2.6: dependencies: tslib: 2.8.1 @@ -4697,6 +4772,8 @@ snapshots: js-tokens@4.0.0: {} + json-schema@0.4.0: {} + lightningcss-darwin-arm64@1.30.1: optional: true diff --git a/product-image-generator/src/trigger/batch-generate-and-upload.ts b/product-image-generator/src/trigger/batch-generate-and-upload.ts new file mode 100644 index 0000000..ec8e502 --- /dev/null +++ b/product-image-generator/src/trigger/batch-generate-and-upload.ts @@ -0,0 +1,143 @@ +import { logger, metadata, task } from "@trigger.dev/sdk"; +import { generateAndUploadImage } from "./generate-and-upload-image"; + +export const batchGenerateAndUploadImages = task({ + id: "batch-generate-and-upload-images", + maxDuration: 900, // 15 minutes max for all 3 images + run: async (payload: { + baseImageUrl: string; + productDescription?: string; + }) => { + const { baseImageUrl, productDescription = "product" } = payload; + + // Set initial metadata + metadata.set("status", "starting"); + metadata.set("progress", { + step: 1, + total: 4, + message: "Preparing batch generation...", + }); + + logger.log("Starting batch image generation and upload", { + baseImageUrl, + productDescription, + }); + + // Define the 3 marketing prompts - emphasizing exact product replication + const prompts = [ + { + id: "isolated-table", + prompt: + `Create a professional product photography shot showing the EXACT same product from the reference image, maintaining identical colors, textures, materials, and design details. Place this identical product isolated on a clean white table surface with studio lighting, minimalist background, commercial photography style, high resolution, sharp focus. The product must look exactly the same as in the reference image.`, + }, + { + id: "lifestyle-scene", + prompt: + `Create a lifestyle product photography shot showing the EXACT same product from the reference image, maintaining identical colors, textures, materials, and design details. Place this identical product in a modern home setting with natural lighting, styled environment, aspirational lifestyle, professional commercial photography. The product must look exactly the same as in the reference image, only the background and setting should change.`, + }, + { + id: "hero-shot", + prompt: + `Create a hero product shot showing the EXACT same product from the reference image, maintaining identical colors, textures, materials, and design details. Present this identical product with dramatic lighting, premium presentation, luxury commercial photography style, perfect for marketing materials, high-end aesthetic. The product must look exactly the same as in the reference image, only the lighting and presentation should be enhanced.`, + }, + ]; + + try { + // Update progress + metadata.set("progress", { + step: 2, + total: 4, + message: "Triggering individual generation tasks...", + }); + + // Trigger all 3 generation tasks in parallel + const generationPromises = prompts.map(async ({ id, prompt }) => { + logger.log(`Triggering generation for ${id}`, { prompt }); + + try { + const result = await generateAndUploadImage.trigger({ + prompt, + baseImageUrl, + model: "dall-e-3", + size: "1024x1792", + }); + + return { + id, + success: true, + runId: result.id, + prompt, + }; + } catch (error) { + logger.error(`Failed to trigger generation for ${id}`, { error }); + return { + id, + success: false, + error: error instanceof Error ? error.message : "Unknown error", + prompt, + }; + } + }); + + // Wait for all triggers to complete + metadata.set("progress", { + step: 3, + total: 4, + message: "All generation tasks triggered, monitoring progress...", + }); + + const results = await Promise.all(generationPromises); + + // Update progress + metadata.set("progress", { + step: 4, + total: 4, + message: "Batch generation initiated successfully!", + }); + metadata.set("status", "completed"); + + // Set final metadata with results + metadata.set("result", { + baseImageUrl, + productDescription, + generations: results, + totalTasks: results.length, + successfulTasks: results.filter((r) => r.success).length, + failedTasks: results.filter((r) => !r.success).length, + }); + + logger.log("Batch generation completed", { + successful: results.filter((r) => r.success).length, + failed: results.filter((r) => !r.success).length, + }); + + return { + success: true, + baseImageUrl, + productDescription, + generations: results, + totalTasks: results.length, + successfulTasks: results.filter((r) => r.success).length, + failedTasks: results.filter((r) => !r.success).length, + }; + } catch (error) { + // Set error metadata + metadata.set("status", "failed"); + metadata.set("progress", { + step: 0, + total: 4, + message: "Batch generation failed", + }); + metadata.set( + "error", + error instanceof Error ? error.message : "Unknown error", + ); + + logger.error("Failed to complete batch generation", { + error, + baseImageUrl, + }); + throw error; + } + }, +}); diff --git a/product-image-generator/src/trigger/batch-generate-images.ts b/product-image-generator/src/trigger/batch-generate-images.ts new file mode 100644 index 0000000..6f3f52c --- /dev/null +++ b/product-image-generator/src/trigger/batch-generate-images.ts @@ -0,0 +1,143 @@ +import { logger, metadata, task } from "@trigger.dev/sdk"; +import { generateProductImage } from "./generate-image"; + +export const batchGenerateProductImages = task({ + id: "batch-generate-product-images", + maxDuration: 900, // 15 minutes max for all 3 images + run: async (payload: { + baseImageUrl: string; + productDescription?: string; + }) => { + const { baseImageUrl, productDescription = "product" } = payload; + + // Set initial metadata + metadata.set("status", "starting"); + metadata.set("progress", { + step: 1, + total: 4, + message: "Preparing batch image generation...", + }); + + logger.log("Starting batch image generation", { + baseImageUrl, + productDescription, + }); + + // Define the 3 marketing prompts - emphasizing exact product replication + const prompts = [ + { + id: "isolated-table", + prompt: + `Create a professional product photography shot showing the EXACT same product from the reference image, maintaining identical colors, textures, materials, and design details. Place this identical product isolated on a clean white table surface with studio lighting, minimalist background, commercial photography style, high resolution, sharp focus. The product must look exactly the same as in the reference image.`, + }, + { + id: "lifestyle-scene", + prompt: + `Create a lifestyle product photography shot showing the EXACT same product from the reference image, maintaining identical colors, textures, materials, and design details. Place this identical product in a modern home setting with natural lighting, styled environment, aspirational lifestyle, professional commercial photography. The product must look exactly the same as in the reference image, only the background and setting should change.`, + }, + { + id: "hero-shot", + prompt: + `Create a hero product shot showing the EXACT same product from the reference image, maintaining identical colors, textures, materials, and design details. Present this identical product with dramatic lighting, premium presentation, luxury commercial photography style, perfect for marketing materials, high-end aesthetic. The product must look exactly the same as in the reference image, only the lighting and presentation should be enhanced.`, + }, + ]; + + try { + // Update progress + metadata.set("progress", { + step: 2, + total: 4, + message: "Triggering image generation tasks...", + }); + + // Trigger all 3 image generation tasks in parallel + const generationPromises = prompts.map(async ({ id, prompt }) => { + logger.log(`Triggering generation for ${id}`, { prompt }); + + try { + const result = await generateProductImage.trigger({ + prompt, + baseImageUrl, + model: "dall-e-3", + size: "1024x1792", // Portrait format for better slot fitting + }); + + return { + id, + success: true, + runId: result.id, + prompt, + }; + } catch (error) { + logger.error(`Failed to trigger generation for ${id}`, { error }); + return { + id, + success: false, + error: error instanceof Error ? error.message : "Unknown error", + prompt, + }; + } + }); + + // Wait for all triggers to complete + metadata.set("progress", { + step: 3, + total: 4, + message: "All generation tasks triggered, monitoring progress...", + }); + + const results = await Promise.all(generationPromises); + + // Update progress + metadata.set("progress", { + step: 4, + total: 4, + message: "Batch generation initiated successfully!", + }); + metadata.set("status", "completed"); + + // Set final metadata with results + metadata.set("result", { + baseImageUrl, + productDescription, + generations: results, + totalTasks: results.length, + successfulTasks: results.filter((r) => r.success).length, + failedTasks: results.filter((r) => !r.success).length, + }); + + logger.log("Batch generation completed", { + successful: results.filter((r) => r.success).length, + failed: results.filter((r) => !r.success).length, + }); + + return { + success: true, + baseImageUrl, + productDescription, + generations: results, + totalTasks: results.length, + successfulTasks: results.filter((r) => r.success).length, + failedTasks: results.filter((r) => !r.success).length, + }; + } catch (error) { + // Set error metadata + metadata.set("status", "failed"); + metadata.set("progress", { + step: 0, + total: 4, + message: "Batch generation failed", + }); + metadata.set( + "error", + error instanceof Error ? error.message : "Unknown error", + ); + + logger.error("Failed to complete batch generation", { + error, + baseImageUrl, + }); + throw error; + } + }, +}); diff --git a/product-image-generator/src/trigger/generate-and-upload-image.ts b/product-image-generator/src/trigger/generate-and-upload-image.ts new file mode 100644 index 0000000..355e31e --- /dev/null +++ b/product-image-generator/src/trigger/generate-and-upload-image.ts @@ -0,0 +1,169 @@ +import { experimental_generateImage } from "ai"; +import { logger, metadata, task } from "@trigger.dev/sdk"; +import { openai } from "@ai-sdk/openai"; +import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3"; +import { Buffer } from "buffer"; + +// Initialize S3 client for R2 +const s3Client = new S3Client({ + region: "auto", + endpoint: process.env.R2_ENDPOINT, + credentials: { + accessKeyId: process.env.R2_ACCESS_KEY_ID ?? "", + secretAccessKey: process.env.R2_SECRET_ACCESS_KEY ?? "", + }, +}); + +export const generateAndUploadImage = task({ + id: "generate-and-upload-image", + maxDuration: 600, // 10 minutes max + run: async (payload: { + prompt: string; + baseImageUrl: string; + model?: "dall-e-2" | "dall-e-3"; + size?: "1024x1024" | "1792x1024" | "1024x1792"; + }) => { + const { + prompt, + baseImageUrl, + model = "dall-e-3", + size = "1024x1792", + } = payload; + + // Set initial metadata with 5 steps total + metadata.set("status", "starting"); + metadata.set("progress", { + step: 1, + total: 5, + message: "Preparing image generation...", + }); + + logger.log("Starting image generation and upload", { + prompt, + baseImageUrl, + model, + size, + }); + + try { + // Step 2: Generate image + metadata.set("progress", { + step: 2, + total: 5, + message: "Generating image with AI...", + }); + + const generateParams: any = { + model: openai.image(model), + prompt: + `Create a professional marketing image: ${prompt}. Use the product from this reference image: ${baseImageUrl}. Maintain the product's key features and characteristics while adapting it to the new scenario.`, + size, + }; + + const { image } = await experimental_generateImage(generateParams); + logger.log("Image generated successfully"); + + // Step 3: Prepare for upload + metadata.set("progress", { + step: 3, + total: 5, + message: "Preparing image for upload...", + }); + + const imageBuffer = Buffer.from(image.uint8Array); + const base64Image = imageBuffer.toString("base64"); + + const timestamp = Date.now(); + const filename = `generated-${timestamp}.png`; + + // Step 4: Upload to storage + metadata.set("progress", { + step: 4, + total: 5, + message: "Uploading to storage...", + }); + + // Generate unique key for R2 + const sanitizedFileName = filename.replace(/[^a-zA-Z0-9.-]/g, "_"); + const r2Key = `uploaded-images/${timestamp}-${sanitizedFileName}`; + + const uploadParams = { + Bucket: process.env.R2_BUCKET, + Key: r2Key, + Body: imageBuffer, + ContentType: "image/png", + // Add cache control for better performance + CacheControl: "public, max-age=31536000", // 1 year + }; + + // Upload to R2 + logger.log("About to upload to R2", { + bucket: process.env.R2_BUCKET, + endpoint: process.env.R2_ENDPOINT, + r2Key, + fileSize: imageBuffer.length, + hasAccessKey: !!process.env.R2_ACCESS_KEY_ID, + hasSecretKey: !!process.env.R2_SECRET_ACCESS_KEY, + }); + + const result = await s3Client.send(new PutObjectCommand(uploadParams)); + logger.log("S3 PutObject response:", result as any); + logger.log(`Image uploaded successfully to R2`, { r2Key }); + + // Construct the public URL using the R2_PUBLIC_URL env var + const publicUrl = `${process.env.R2_PUBLIC_URL}/${r2Key}`; + + const uploadOutput = { + publicUrl, + r2Key, + fileSize: imageBuffer.length, + fileName: sanitizedFileName, + }; + + // Step 5: Complete + metadata.set("progress", { + step: 5, + total: 5, + message: "Generation and upload completed!", + }); + metadata.set("status", "completed"); + + // Set final metadata with result + metadata.set("result", { + prompt, + model, + size, + imageSize: imageBuffer.length, + publicUrl: uploadOutput.publicUrl, + r2Key: uploadOutput.r2Key, + }); + + return { + success: true, + publicUrl: uploadOutput.publicUrl, + r2Key: uploadOutput.r2Key, + imageSize: imageBuffer.length, + contentType: "image/png", + model, + size, + prompt, + baseImageUrl, + }; + } catch (error) { + // Set error metadata + metadata.set("status", "failed"); + metadata.set("progress", { + step: 0, + total: 5, + message: "Generation and upload failed", + }); + metadata.set( + "error", + error instanceof Error ? error.message : "Unknown error", + ); + + logger.error("Failed to generate and upload image", { error, prompt }); + throw error; + } + }, +}); diff --git a/product-image-generator/src/trigger/generate-image.ts b/product-image-generator/src/trigger/generate-image.ts new file mode 100644 index 0000000..207537c --- /dev/null +++ b/product-image-generator/src/trigger/generate-image.ts @@ -0,0 +1,147 @@ +import { experimental_generateImage } from "ai"; +import { logger, metadata, task } from "@trigger.dev/sdk"; +import { openai } from "@ai-sdk/openai"; +import { uploadImageToR2 } from "./image-upload"; + +export const generateProductImage = task({ + id: "generate-product-image", + maxDuration: 600, // 10 minutes max (includes upload time) + run: async (payload: { + prompt: string; + model?: "dall-e-2" | "dall-e-3"; + size?: "1024x1024" | "1792x1024" | "1024x1792"; + baseImageUrl?: string; // For creating derivatives + }) => { + const { + prompt, + model = "dall-e-3", + size = "1024x1024", + baseImageUrl, + } = payload; + + // Set initial metadata + metadata.set("status", "starting"); + metadata.set("progress", { + step: 1, + total: 4, + message: "Preparing image generation...", + }); + + logger.log("Starting image generation", { + prompt, + model, + size, + baseImageUrl, + isDerivative: !!baseImageUrl, + }); + + try { + // Update progress + metadata.set("progress", { + step: 2, + total: 4, + message: "Generating image with AI...", + }); + + // Generate the image using AI SDK + const generateParams: any = { + model: openai.image(model), + prompt: baseImageUrl + ? `${prompt}. Base this on the product shown in this reference image: ${baseImageUrl}` + : prompt, + size, + }; + + // Add image reference if provided (for derivatives) + if (baseImageUrl) { + generateParams.prompt = + `Create a professional marketing image: ${prompt}. Use the product from this reference image: ${baseImageUrl}. Maintain the product's key features and characteristics while adapting it to the new scenario.`; + } + + const { image } = await experimental_generateImage(generateParams); + + logger.log("Image generated successfully"); + + // Update progress + metadata.set("progress", { + step: 3, + total: 4, + message: "Uploading generated image...", + }); + + // Convert the image to base64 and upload to R2 + const imageBuffer = Buffer.from(image.uint8Array); + const base64Image = imageBuffer.toString("base64"); + + // Generate a filename for the generated image + const timestamp = Date.now(); + const filename = baseImageUrl + ? `generated-derivative-${timestamp}.png` + : `generated-${timestamp}.png`; + + // Upload the generated image to R2 and wait for completion + const uploadResult = await uploadImageToR2.triggerAndWait({ + imageBuffer: base64Image, + fileName: filename, + contentType: "image/png", + }); + + if (!uploadResult.ok) { + throw new Error(`Image upload failed: ${uploadResult.error}`); + } + + const uploadOutput = uploadResult.output; + + // Log the upload completion + logger.log("Upload task completed successfully"); + + // Update final progress + metadata.set("progress", { + step: 4, + total: 4, + message: "Generation and upload completed!", + }); + metadata.set("status", "completed"); + + // Set final metadata with result + metadata.set("result", { + prompt, + model, + size, + imageSize: imageBuffer.length, + publicUrl: uploadOutput.publicUrl, + r2Key: uploadOutput.r2Key, + }); + + return { + success: true, + imageBuffer: base64Image, + imageSize: imageBuffer.length, + contentType: "image/png", + publicUrl: uploadOutput.publicUrl, + r2Key: uploadOutput.r2Key, + // Note: We don't include uploadRunId since we're using triggerAndWait + model, + size, + prompt, + baseImageUrl, + isDerivative: !!baseImageUrl, + }; + } catch (error) { + // Set error metadata + metadata.set("status", "failed"); + metadata.set("progress", { + step: 0, + total: 4, + message: "Generation failed", + }); + metadata.set( + "error", + error instanceof Error ? error.message : "Unknown error", + ); + + logger.error("Failed to generate image", { error, prompt }); + throw error; + } + }, +}); From 68c220070435f4c581af3355673f5db76f9b46f1 Mon Sep 17 00:00:00 2001 From: D-K-P <8297864+D-K-P@users.noreply.github.com> Date: Fri, 5 Sep 2025 11:28:47 +0100 Subject: [PATCH 04/39] Images rendering in the first 4 slots --- .../app/components/GeneratedCard.tsx | 120 +++++++----------- .../app/components/UploadCard.tsx | 4 +- .../src/trigger/generate-and-upload-image.ts | 13 +- .../src/trigger/generate-image.ts | 76 ++++++++--- 4 files changed, 114 insertions(+), 99 deletions(-) diff --git a/product-image-generator/app/components/GeneratedCard.tsx b/product-image-generator/app/components/GeneratedCard.tsx index dfa13a9..c6c1d19 100644 --- a/product-image-generator/app/components/GeneratedCard.tsx +++ b/product-image-generator/app/components/GeneratedCard.tsx @@ -3,8 +3,8 @@ import { Button } from "./ui/button"; import { Card } from "./ui/card"; import { Download, RefreshCw } from "lucide-react"; -import { useState, useEffect } from "react"; -import { runs, configure } from "@trigger.dev/sdk/v3"; +import { useState } from "react"; +import { useRealtimeRun } from "@trigger.dev/react-hooks"; interface GeneratedCardProps { runId: string | null; @@ -21,71 +21,50 @@ export default function GeneratedCard({ promptTitle, onRetry, }: GeneratedCardProps) { - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); const [generatedImageUrl, setGeneratedImageUrl] = useState( null ); - const [generationProgress, setGenerationProgress] = useState("idle"); - const [progressMessage, setProgressMessage] = useState(""); - const [progressStep, setProgressStep] = useState<{ - step: number; - total: number; - } | null>(null); - // Subscribe to run updates when runId and accessToken are available - useEffect(() => { - if (!runId || !accessToken) return; + // Use the React hook for realtime run subscription + const { run, error } = useRealtimeRun(runId || undefined, { + accessToken: accessToken || undefined, + enabled: !!(runId && accessToken), // Only subscribe if we have both + }); - const subscribeToRun = async () => { - setIsLoading(true); - setGenerationProgress("generating"); - setError(null); + // Extract progress information from run metadata + const progressData = run?.metadata?.progress as + | { + step: number; + total: number; + message: string; + } + | undefined; - try { - configure({ - secretKey: accessToken, - }); + const isLoading = run?.status === "EXECUTING" || run?.status === "QUEUED"; + const generationProgress = + run?.status === "COMPLETED" + ? "completed" + : run?.status === "FAILED" + ? "failed" + : run?.status === "EXECUTING" + ? "generating" + : "idle"; - for await (const run of runs.subscribeToRun(runId)) { - // Update progress from metadata - if (run.metadata?.progress) { - const progress = run.metadata.progress as { - step: number; - total: number; - message: string; - }; - setProgressMessage(progress.message); - setProgressStep({ step: progress.step, total: progress.total }); - } + // Update generated image URL when run completes + if (run?.status === "COMPLETED" && !generatedImageUrl) { + // First try to get publicUrl from output + let publicUrl = run.output?.publicUrl; - // Handle completion - if (run.status === "COMPLETED" && run.output) { - setGeneratedImageUrl(run.output.publicUrl); - setGenerationProgress("completed"); - setProgressMessage("Generation completed!"); - setIsLoading(false); - break; - } else if (run.status === "FAILED") { - const errorMsg = run.metadata?.error || "Generation failed"; - setError( - typeof errorMsg === "string" ? errorMsg : "Generation failed" - ); - setGenerationProgress("failed"); - setProgressMessage(""); - setIsLoading(false); - break; - } - } - } catch (err) { - setError("Failed to get task updates"); - setGenerationProgress("failed"); - setIsLoading(false); - } - }; + // If not in output, try metadata.result (our new pattern) + if (!publicUrl && run.metadata?.result) { + const result = run.metadata.result as any; + publicUrl = result.publicUrl; + } - subscribeToRun(); - }, [runId, accessToken]); + if (publicUrl) { + setGeneratedImageUrl(publicUrl); + } + } const handleDownload = () => { if (generatedImageUrl) { @@ -100,11 +79,7 @@ export default function GeneratedCard({ const handleRetry = () => { if (onRetry) { - setError(null); setGeneratedImageUrl(null); - setGenerationProgress("idle"); - setProgressMessage(""); - setProgressStep(null); onRetry(); } }; @@ -144,7 +119,9 @@ export default function GeneratedCard({

{promptTitle}

-

{error}

+

+ {error?.message || "Generation failed"} +

{onRetry && (
{/* Title overlay */} -
-

{promptTitle}

+
+

+ {promptTitle} +

) : generationProgress === "failed" ? ( diff --git a/product-image-generator/package.json b/product-image-generator/package.json index 07decbe..d2b2edb 100644 --- a/product-image-generator/package.json +++ b/product-image-generator/package.json @@ -10,6 +10,7 @@ }, "dependencies": { "@ai-sdk/openai": "^2.0.24", + "@ai-sdk/replicate": "^1.0.8", "@aws-sdk/client-s3": "^3.882.0", "@hookform/resolvers": "^3.10.0", "@radix-ui/react-accordion": "1.2.2", diff --git a/product-image-generator/pnpm-lock.yaml b/product-image-generator/pnpm-lock.yaml index bf6f9ab..9e318ab 100644 --- a/product-image-generator/pnpm-lock.yaml +++ b/product-image-generator/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: '@ai-sdk/openai': specifier: ^2.0.24 version: 2.0.24(zod@3.25.67) + '@ai-sdk/replicate': + specifier: ^1.0.8 + version: 1.0.8(zod@3.25.67) '@aws-sdk/client-s3': specifier: ^3.882.0 version: 3.882.0 @@ -226,6 +229,12 @@ packages: resolution: {integrity: sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==} engines: {node: '>=18'} + '@ai-sdk/replicate@1.0.8': + resolution: {integrity: sha512-lCisqVAZt/x1HmVhVbKlLa73f69+yC+P9QmRIKbXaZb1kqnL27urTehEpSLsT+iungmWOsMY3Xr4PXhNf/8FwQ==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4 + '@alloc/quick-lru@5.2.0': resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} @@ -2562,6 +2571,12 @@ snapshots: dependencies: json-schema: 0.4.0 + '@ai-sdk/replicate@1.0.8(zod@3.25.67)': + dependencies: + '@ai-sdk/provider': 2.0.0 + '@ai-sdk/provider-utils': 3.0.8(zod@3.25.67) + zod: 3.25.67 + '@alloc/quick-lru@5.2.0': {} '@aws-crypto/crc32@5.2.0': diff --git a/product-image-generator/src/trigger/batch-generate-and-upload.ts b/product-image-generator/src/trigger/batch-generate-and-upload.ts deleted file mode 100644 index ec8e502..0000000 --- a/product-image-generator/src/trigger/batch-generate-and-upload.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { logger, metadata, task } from "@trigger.dev/sdk"; -import { generateAndUploadImage } from "./generate-and-upload-image"; - -export const batchGenerateAndUploadImages = task({ - id: "batch-generate-and-upload-images", - maxDuration: 900, // 15 minutes max for all 3 images - run: async (payload: { - baseImageUrl: string; - productDescription?: string; - }) => { - const { baseImageUrl, productDescription = "product" } = payload; - - // Set initial metadata - metadata.set("status", "starting"); - metadata.set("progress", { - step: 1, - total: 4, - message: "Preparing batch generation...", - }); - - logger.log("Starting batch image generation and upload", { - baseImageUrl, - productDescription, - }); - - // Define the 3 marketing prompts - emphasizing exact product replication - const prompts = [ - { - id: "isolated-table", - prompt: - `Create a professional product photography shot showing the EXACT same product from the reference image, maintaining identical colors, textures, materials, and design details. Place this identical product isolated on a clean white table surface with studio lighting, minimalist background, commercial photography style, high resolution, sharp focus. The product must look exactly the same as in the reference image.`, - }, - { - id: "lifestyle-scene", - prompt: - `Create a lifestyle product photography shot showing the EXACT same product from the reference image, maintaining identical colors, textures, materials, and design details. Place this identical product in a modern home setting with natural lighting, styled environment, aspirational lifestyle, professional commercial photography. The product must look exactly the same as in the reference image, only the background and setting should change.`, - }, - { - id: "hero-shot", - prompt: - `Create a hero product shot showing the EXACT same product from the reference image, maintaining identical colors, textures, materials, and design details. Present this identical product with dramatic lighting, premium presentation, luxury commercial photography style, perfect for marketing materials, high-end aesthetic. The product must look exactly the same as in the reference image, only the lighting and presentation should be enhanced.`, - }, - ]; - - try { - // Update progress - metadata.set("progress", { - step: 2, - total: 4, - message: "Triggering individual generation tasks...", - }); - - // Trigger all 3 generation tasks in parallel - const generationPromises = prompts.map(async ({ id, prompt }) => { - logger.log(`Triggering generation for ${id}`, { prompt }); - - try { - const result = await generateAndUploadImage.trigger({ - prompt, - baseImageUrl, - model: "dall-e-3", - size: "1024x1792", - }); - - return { - id, - success: true, - runId: result.id, - prompt, - }; - } catch (error) { - logger.error(`Failed to trigger generation for ${id}`, { error }); - return { - id, - success: false, - error: error instanceof Error ? error.message : "Unknown error", - prompt, - }; - } - }); - - // Wait for all triggers to complete - metadata.set("progress", { - step: 3, - total: 4, - message: "All generation tasks triggered, monitoring progress...", - }); - - const results = await Promise.all(generationPromises); - - // Update progress - metadata.set("progress", { - step: 4, - total: 4, - message: "Batch generation initiated successfully!", - }); - metadata.set("status", "completed"); - - // Set final metadata with results - metadata.set("result", { - baseImageUrl, - productDescription, - generations: results, - totalTasks: results.length, - successfulTasks: results.filter((r) => r.success).length, - failedTasks: results.filter((r) => !r.success).length, - }); - - logger.log("Batch generation completed", { - successful: results.filter((r) => r.success).length, - failed: results.filter((r) => !r.success).length, - }); - - return { - success: true, - baseImageUrl, - productDescription, - generations: results, - totalTasks: results.length, - successfulTasks: results.filter((r) => r.success).length, - failedTasks: results.filter((r) => !r.success).length, - }; - } catch (error) { - // Set error metadata - metadata.set("status", "failed"); - metadata.set("progress", { - step: 0, - total: 4, - message: "Batch generation failed", - }); - metadata.set( - "error", - error instanceof Error ? error.message : "Unknown error", - ); - - logger.error("Failed to complete batch generation", { - error, - baseImageUrl, - }); - throw error; - } - }, -}); diff --git a/product-image-generator/src/trigger/batch-generate-images.ts b/product-image-generator/src/trigger/batch-generate-images.ts deleted file mode 100644 index 6f3f52c..0000000 --- a/product-image-generator/src/trigger/batch-generate-images.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { logger, metadata, task } from "@trigger.dev/sdk"; -import { generateProductImage } from "./generate-image"; - -export const batchGenerateProductImages = task({ - id: "batch-generate-product-images", - maxDuration: 900, // 15 minutes max for all 3 images - run: async (payload: { - baseImageUrl: string; - productDescription?: string; - }) => { - const { baseImageUrl, productDescription = "product" } = payload; - - // Set initial metadata - metadata.set("status", "starting"); - metadata.set("progress", { - step: 1, - total: 4, - message: "Preparing batch image generation...", - }); - - logger.log("Starting batch image generation", { - baseImageUrl, - productDescription, - }); - - // Define the 3 marketing prompts - emphasizing exact product replication - const prompts = [ - { - id: "isolated-table", - prompt: - `Create a professional product photography shot showing the EXACT same product from the reference image, maintaining identical colors, textures, materials, and design details. Place this identical product isolated on a clean white table surface with studio lighting, minimalist background, commercial photography style, high resolution, sharp focus. The product must look exactly the same as in the reference image.`, - }, - { - id: "lifestyle-scene", - prompt: - `Create a lifestyle product photography shot showing the EXACT same product from the reference image, maintaining identical colors, textures, materials, and design details. Place this identical product in a modern home setting with natural lighting, styled environment, aspirational lifestyle, professional commercial photography. The product must look exactly the same as in the reference image, only the background and setting should change.`, - }, - { - id: "hero-shot", - prompt: - `Create a hero product shot showing the EXACT same product from the reference image, maintaining identical colors, textures, materials, and design details. Present this identical product with dramatic lighting, premium presentation, luxury commercial photography style, perfect for marketing materials, high-end aesthetic. The product must look exactly the same as in the reference image, only the lighting and presentation should be enhanced.`, - }, - ]; - - try { - // Update progress - metadata.set("progress", { - step: 2, - total: 4, - message: "Triggering image generation tasks...", - }); - - // Trigger all 3 image generation tasks in parallel - const generationPromises = prompts.map(async ({ id, prompt }) => { - logger.log(`Triggering generation for ${id}`, { prompt }); - - try { - const result = await generateProductImage.trigger({ - prompt, - baseImageUrl, - model: "dall-e-3", - size: "1024x1792", // Portrait format for better slot fitting - }); - - return { - id, - success: true, - runId: result.id, - prompt, - }; - } catch (error) { - logger.error(`Failed to trigger generation for ${id}`, { error }); - return { - id, - success: false, - error: error instanceof Error ? error.message : "Unknown error", - prompt, - }; - } - }); - - // Wait for all triggers to complete - metadata.set("progress", { - step: 3, - total: 4, - message: "All generation tasks triggered, monitoring progress...", - }); - - const results = await Promise.all(generationPromises); - - // Update progress - metadata.set("progress", { - step: 4, - total: 4, - message: "Batch generation initiated successfully!", - }); - metadata.set("status", "completed"); - - // Set final metadata with results - metadata.set("result", { - baseImageUrl, - productDescription, - generations: results, - totalTasks: results.length, - successfulTasks: results.filter((r) => r.success).length, - failedTasks: results.filter((r) => !r.success).length, - }); - - logger.log("Batch generation completed", { - successful: results.filter((r) => r.success).length, - failed: results.filter((r) => !r.success).length, - }); - - return { - success: true, - baseImageUrl, - productDescription, - generations: results, - totalTasks: results.length, - successfulTasks: results.filter((r) => r.success).length, - failedTasks: results.filter((r) => !r.success).length, - }; - } catch (error) { - // Set error metadata - metadata.set("status", "failed"); - metadata.set("progress", { - step: 0, - total: 4, - message: "Batch generation failed", - }); - metadata.set( - "error", - error instanceof Error ? error.message : "Unknown error", - ); - - logger.error("Failed to complete batch generation", { - error, - baseImageUrl, - }); - throw error; - } - }, -}); diff --git a/product-image-generator/src/trigger/generate-and-upload-image.ts b/product-image-generator/src/trigger/generate-and-upload-image.ts index 1c5dc67..9f6323c 100644 --- a/product-image-generator/src/trigger/generate-and-upload-image.ts +++ b/product-image-generator/src/trigger/generate-and-upload-image.ts @@ -1,6 +1,7 @@ import { experimental_generateImage } from "ai"; import { logger, metadata, task } from "@trigger.dev/sdk"; import { openai } from "@ai-sdk/openai"; +import { replicate } from "@ai-sdk/replicate"; import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3"; import { Buffer } from "buffer"; @@ -20,14 +21,22 @@ export const generateAndUploadImage = task({ run: async (payload: { prompt: string; baseImageUrl: string; - model?: "dall-e-2" | "dall-e-3"; + model?: "flux" | "dall-e-3"; size?: "1024x1024" | "1792x1024" | "1024x1792"; + strength?: number; + guidance?: number; + steps?: number; + seed?: number; }) => { const { prompt, baseImageUrl, - model = "dall-e-3", - size = "1024x1792", + model = "flux", + size = "1024x1024", // Match your settings + strength = 0.7, + guidance = 7, // From your settings + steps = 30, // From your settings + seed = 1601, // From your settings } = payload; // Set initial metadata with 5 steps total @@ -53,11 +62,18 @@ export const generateAndUploadImage = task({ message: "Generating image with AI...", }); + // Use Flux with your exact settings from the screenshot const generateParams: any = { - model: openai.image(model), - prompt: - `Create a professional marketing image: ${prompt}. Use the product from this reference image: ${baseImageUrl}. Maintain the product's key features and characteristics while adapting it to the new scenario.`, - size, + model: replicate.image("black-forest-labs/flux-dev"), + prompt: prompt, + image: baseImageUrl, // Reference image for img2img + width: 1024, // From your settings + height: 1024, // From your settings + guidance_scale: 7, // From your settings + num_inference_steps: 30, // From your settings + strength: 0.7, // Good balance for product preservation + seed: 1601, // From your settings + num_outputs: 1, }; const { image } = await experimental_generateImage(generateParams); diff --git a/product-image-generator/src/trigger/generate-image.ts b/product-image-generator/src/trigger/generate-image.ts deleted file mode 100644 index 018c241..0000000 --- a/product-image-generator/src/trigger/generate-image.ts +++ /dev/null @@ -1,181 +0,0 @@ -import { experimental_generateImage } from "ai"; -import { logger, metadata, task } from "@trigger.dev/sdk"; -import { openai } from "@ai-sdk/openai"; -import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3"; -import { Buffer } from "buffer"; - -// Initialize S3 client for R2 -const s3Client = new S3Client({ - region: "auto", - endpoint: process.env.R2_ENDPOINT, - credentials: { - accessKeyId: process.env.R2_ACCESS_KEY_ID ?? "", - secretAccessKey: process.env.R2_SECRET_ACCESS_KEY ?? "", - }, -}); - -export const generateProductImage = task({ - id: "generate-product-image", - maxDuration: 600, // 10 minutes max (includes upload time) - run: async (payload: { - prompt: string; - model?: "dall-e-2" | "dall-e-3"; - size?: "1024x1024" | "1792x1024" | "1024x1792"; - baseImageUrl?: string; // For creating derivatives - }) => { - const { - prompt, - model = "dall-e-3", - size = "1024x1024", - baseImageUrl, - } = payload; - - // Set initial metadata - metadata.set("status", "starting"); - metadata.set("progress", { - step: 1, - total: 4, - message: "Preparing image generation...", - }); - - logger.log("Starting image generation", { - prompt, - model, - size, - baseImageUrl, - isDerivative: !!baseImageUrl, - }); - - try { - // Update progress - metadata.set("progress", { - step: 2, - total: 4, - message: "Generating image with AI...", - }); - - // Generate the image using AI SDK - const generateParams: any = { - model: openai.image(model), - prompt: baseImageUrl - ? `${prompt}. Base this on the product shown in this reference image: ${baseImageUrl}` - : prompt, - size, - }; - - // Add image reference if provided (for derivatives) - if (baseImageUrl) { - generateParams.prompt = - `Create a professional marketing image: ${prompt}. Use the product from this reference image: ${baseImageUrl}. Maintain the product's key features and characteristics while adapting it to the new scenario.`; - } - - const { image } = await experimental_generateImage(generateParams); - - logger.log("Image generated successfully"); - - // Update progress - metadata.set("progress", { - step: 3, - total: 4, - message: "Uploading generated image...", - }); - - // Convert the image to base64 and upload to R2 - const imageBuffer = Buffer.from(image.uint8Array); - const base64Image = imageBuffer.toString("base64"); - - // Generate a filename for the generated image - const timestamp = Date.now(); - const filename = baseImageUrl - ? `generated-derivative-${timestamp}.png` - : `generated-${timestamp}.png`; - - // Generate unique key for R2 - const sanitizedFileName = filename.replace(/[^a-zA-Z0-9.-]/g, "_"); - const r2Key = `uploaded-images/${timestamp}-${sanitizedFileName}`; - - const uploadParams = { - Bucket: process.env.R2_BUCKET, - Key: r2Key, - Body: imageBuffer, - ContentType: "image/png", - // Add cache control for better performance - CacheControl: "public, max-age=31536000", // 1 year - }; - - // Upload to R2 - logger.log("About to upload to R2", { - bucket: process.env.R2_BUCKET, - endpoint: process.env.R2_ENDPOINT, - r2Key, - fileSize: imageBuffer.length, - hasAccessKey: !!process.env.R2_ACCESS_KEY_ID, - hasSecretKey: !!process.env.R2_SECRET_ACCESS_KEY, - }); - - const result = await s3Client.send(new PutObjectCommand(uploadParams)); - logger.log("S3 PutObject response:", result as any); - logger.log(`Image uploaded successfully to R2`, { r2Key }); - - // Construct the public URL using the R2_PUBLIC_URL env var - const publicUrl = `${process.env.R2_PUBLIC_URL}/${r2Key}`; - - const uploadOutput = { - publicUrl, - r2Key, - fileSize: imageBuffer.length, - fileName: sanitizedFileName, - }; - - // Update final progress - metadata.set("progress", { - step: 4, - total: 4, - message: "Generation and upload completed!", - }); - metadata.set("status", "completed"); - - // Set final metadata with result - this is the best practice for Trigger.dev - metadata.set("result", { - success: true, - publicUrl: uploadOutput.publicUrl, - r2Key: uploadOutput.r2Key, - imageSize: imageBuffer.length, - contentType: "image/png", - model: model as string, - size: size as string, - prompt, - baseImageUrl: baseImageUrl || null, - isDerivative: !!baseImageUrl, - }); - - return { - success: true, - publicUrl: uploadOutput.publicUrl, - r2Key: uploadOutput.r2Key, - imageSize: imageBuffer.length, - contentType: "image/png", - model, - size, - prompt, - baseImageUrl, - isDerivative: !!baseImageUrl, - }; - } catch (error) { - // Set error metadata - metadata.set("status", "failed"); - metadata.set("progress", { - step: 0, - total: 4, - message: "Generation failed", - }); - metadata.set( - "error", - error instanceof Error ? error.message : "Unknown error", - ); - - logger.error("Failed to generate image", { error, prompt }); - throw error; - } - }, -}); From 3e0906c7c308fa65aa01444b310231882f59ad34 Mon Sep 17 00:00:00 2001 From: D-K-P <8297864+D-K-P@users.noreply.github.com> Date: Fri, 5 Sep 2025 13:33:53 +0100 Subject: [PATCH 06/39] Working nicely --- product-image-generator/app/actions.ts | 28 +---- .../app/components/UploadCard.tsx | 11 +- product-image-generator/app/page.tsx | 28 +++-- product-image-generator/package.json | 1 + product-image-generator/pnpm-lock.yaml | 20 +++ .../src/trigger/generate-and-upload-image.ts | 119 ++++++++++++------ .../src/trigger/image-upload.ts | 112 ++++++++++++++--- 7 files changed, 232 insertions(+), 87 deletions(-) diff --git a/product-image-generator/app/actions.ts b/product-image-generator/app/actions.ts index f632a07..bcba8f7 100644 --- a/product-image-generator/app/actions.ts +++ b/product-image-generator/app/actions.ts @@ -75,38 +75,20 @@ export async function uploadImageToR2Action(formData: FormData) { } } - export async function generateSingleImageAction( baseImageUrl: string, + productAnalysis: any, // Structured analysis from upload task promptId: string, - productDescription: string = "product", ) { try { - // Define the prompts - emphasizing exact product replication - const prompts = { - "isolated-table": - `Create a professional product photography shot showing the EXACT same product from the reference image, maintaining identical colors, textures, materials, and design details. Place this identical product isolated on a clean white table surface with studio lighting, minimalist background, commercial photography style, high resolution, sharp focus. The product must look exactly the same as in the reference image.`, - "lifestyle-scene": - `Create a lifestyle product photography shot showing the EXACT same product from the reference image, maintaining identical colors, textures, materials, and design details. Place this identical product in a modern home setting with natural lighting, styled environment, aspirational lifestyle, professional commercial photography. The product must look exactly the same as in the reference image, only the background and setting should change.`, - "hero-shot": - `Create a hero product shot showing the EXACT same product from the reference image, maintaining identical colors, textures, materials, and design details. Present this identical product with dramatic lighting, premium presentation, luxury commercial photography style, perfect for marketing materials, high-end aesthetic. The product must look exactly the same as in the reference image, only the lighting and presentation should be enhanced.`, - }; - - const prompt = prompts[promptId as keyof typeof prompts]; - if (!prompt) { - return { - success: false as const, - error: "Invalid prompt ID", - }; - } - const handle = await tasks.trigger( "generate-and-upload-image", { - prompt, + promptStyle: promptId, // isolated-table, lifestyle-scene, hero-shot baseImageUrl, - model: "flux", // Use Flux with your settings - size: "1024x1024", // Square format from your settings + productAnalysis, + model: "flux", + size: "1024x1024", }, ); diff --git a/product-image-generator/app/components/UploadCard.tsx b/product-image-generator/app/components/UploadCard.tsx index b9be662..d0c2388 100644 --- a/product-image-generator/app/components/UploadCard.tsx +++ b/product-image-generator/app/components/UploadCard.tsx @@ -8,7 +8,7 @@ import { uploadImageToR2Action } from "../actions"; import { runs, configure } from "@trigger.dev/sdk/v3"; interface UploadCardProps { - onUploadComplete?: (imageUrl: string) => void; + onUploadComplete?: (imageUrl: string, productAnalysis?: any) => void; } export default function UploadCard({ onUploadComplete }: UploadCardProps) { @@ -56,9 +56,12 @@ export default function UploadCard({ onUploadComplete }: UploadCardProps) { setProgressMessage("Upload completed!"); setIsLoading(false); - // Notify parent component + // Notify parent component with URL and analysis if (onUploadComplete && run.output.publicUrl) { - onUploadComplete(run.output.publicUrl); + const productAnalysis = + run.output.productAnalysis || + run.metadata?.result?.productAnalysis; + onUploadComplete(run.output.publicUrl, productAnalysis); } break; } else if (run.status === "FAILED") { @@ -170,7 +173,7 @@ export default function UploadCard({ onUploadComplete }: UploadCardProps) { Uploaded image(null); + const [productAnalysis, setProductAnalysis] = useState(null); const [generationRunIds, setGenerationRunIds] = useState<{ [key: string]: string | null; }>({ @@ -31,10 +32,17 @@ export default function ImageManagementApp() { "hero-shot": "Hero Shot", }; - const handleUploadComplete = async (imageUrl: string) => { + const handleUploadComplete = async (imageUrl: string, analysis?: any) => { try { - // Store the uploaded image URL for retries + // Store the uploaded image URL and analysis for retries setUploadedImageUrl(imageUrl); + setProductAnalysis(analysis); + + // Only trigger generations if we have product analysis + if (!analysis) { + console.error("No product analysis available"); + return; + } // Trigger all 3 generations individually for better progress tracking const promptIds = ["isolated-table", "lifestyle-scene", "hero-shot"]; @@ -42,8 +50,8 @@ export default function ImageManagementApp() { for (const promptId of promptIds) { const result = await generateSingleImageAction( imageUrl, - promptId, - "product" + analysis, + promptId ); if (result.success) { @@ -72,8 +80,10 @@ export default function ImageManagementApp() { }; const handleRetryGeneration = async (promptId: string) => { - if (!uploadedImageUrl) { - console.error("No base image URL available for retry"); + if (!uploadedImageUrl || !productAnalysis) { + console.error( + "No base image URL or product analysis available for retry" + ); return; } @@ -82,11 +92,11 @@ export default function ImageManagementApp() { setGenerationRunIds((prev) => ({ ...prev, [promptId]: null })); setGenerationAccessTokens((prev) => ({ ...prev, [promptId]: null })); - // Trigger the specific generation again + // Trigger the specific generation again with product analysis const result = await generateSingleImageAction( uploadedImageUrl, - promptId, - "product" + productAnalysis, + promptId ); if (result.success) { diff --git a/product-image-generator/package.json b/product-image-generator/package.json index d2b2edb..0504a89 100644 --- a/product-image-generator/package.json +++ b/product-image-generator/package.json @@ -55,6 +55,7 @@ "lucide-react": "^0.454.0", "next": "14.2.25", "next-themes": "^0.4.6", + "openai": "^5.19.1", "react": "^19", "react-day-picker": "9.8.0", "react-dom": "^19", diff --git a/product-image-generator/pnpm-lock.yaml b/product-image-generator/pnpm-lock.yaml index 9e318ab..2f34c66 100644 --- a/product-image-generator/pnpm-lock.yaml +++ b/product-image-generator/pnpm-lock.yaml @@ -146,6 +146,9 @@ importers: next-themes: specifier: ^0.4.6 version: 0.4.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + openai: + specifier: ^5.19.1 + version: 5.19.1(ws@8.18.3)(zod@3.25.67) react: specifier: ^19 version: 19.1.0 @@ -2175,6 +2178,18 @@ packages: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} + openai@5.19.1: + resolution: {integrity: sha512-zSqnUF7oR9ksmpusKkpUgkNrj8Sl57U+OyzO8jzc7LUjTMg4DRfR3uCm+EIMA6iw06sRPNp4t7ojp3sCpEUZRQ==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.23.8 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -4925,6 +4940,11 @@ snapshots: dependencies: mimic-fn: 4.0.0 + openai@5.19.1(ws@8.18.3)(zod@3.25.67): + optionalDependencies: + ws: 8.18.3 + zod: 3.25.67 + path-key@3.1.1: {} path-key@4.0.0: {} diff --git a/product-image-generator/src/trigger/generate-and-upload-image.ts b/product-image-generator/src/trigger/generate-and-upload-image.ts index 9f6323c..870994e 100644 --- a/product-image-generator/src/trigger/generate-and-upload-image.ts +++ b/product-image-generator/src/trigger/generate-and-upload-image.ts @@ -19,9 +19,20 @@ export const generateAndUploadImage = task({ id: "generate-and-upload-image", maxDuration: 600, // 10 minutes max run: async (payload: { - prompt: string; + promptStyle: string; // Style prompt (table-shot, lifestyle, hero) baseImageUrl: string; - model?: "flux" | "dall-e-3"; + productAnalysis: { + material: string; + colors: string[]; + shape: string; + size_proportions: string; + functional_elements: string[]; + surface_finish: string; + text_branding: string; + unique_features: string[]; + product_category: string; + }; + model?: "flux"; size?: "1024x1024" | "1792x1024" | "1024x1792"; strength?: number; guidance?: number; @@ -29,61 +40,99 @@ export const generateAndUploadImage = task({ seed?: number; }) => { const { - prompt, + promptStyle, baseImageUrl, + productAnalysis, model = "flux", - size = "1024x1024", // Match your settings + size = "1024x1024", strength = 0.7, guidance = 7, // From your settings steps = 30, // From your settings - seed = 1601, // From your settings + seed = Math.floor(Math.random() * 1000000), // Random seed for variety } = payload; - // Set initial metadata with 5 steps total + // Set initial metadata with 4 steps (no analysis needed) metadata.set("status", "starting"); metadata.set("progress", { step: 1, - total: 5, + total: 4, message: "Preparing image generation...", }); logger.log("Starting image generation and upload", { - prompt, + promptStyle, baseImageUrl, + productAnalysis, model, size, }); try { - // Step 2: Generate image + // Step 2: Create structured prompt metadata.set("progress", { step: 2, - total: 5, - message: "Generating image with AI...", + total: 4, + message: "Creating enhanced prompt...", }); - // Use Flux with your exact settings from the screenshot + // Build detailed product description from analysis with fallbacks + const productDetails = [ + `Material: ${productAnalysis?.material || "unknown"}`, + `Colors: ${productAnalysis?.colors?.join(", ") || "unknown"}`, + `Shape: ${productAnalysis?.shape || "unknown"}`, + `Proportions: ${productAnalysis?.size_proportions || "standard"}`, + `Functional elements: ${ + productAnalysis?.functional_elements?.join(", ") || "standard" + }`, + `Surface finish: ${productAnalysis?.surface_finish || "standard"}`, + `Text/branding: ${productAnalysis?.text_branding || "none"}`, + `Unique features: ${ + productAnalysis?.unique_features?.join(", ") || "standard" + }`, + ].join(". "); + + // Style-specific prompts + const stylePrompts = { + "isolated-table": + `Professional product photography on clean white table with studio lighting, minimalist background, commercial style`, + "lifestyle-scene": + `Lifestyle product photography in modern home setting with natural lighting, styled environment, aspirational setting`, + "hero-shot": + `Premium hero shot with dramatic lighting, luxury commercial photography style, perfect for marketing materials`, + }; + + const baseStylePrompt = + stylePrompts[promptStyle as keyof typeof stylePrompts] || + stylePrompts["isolated-table"]; + + // Combine everything into one unambiguous prompt + const enhancedPrompt = + `${baseStylePrompt}. Product specifications that MUST be preserved exactly: ${productDetails}. The product must maintain these exact characteristics while only the background and lighting change.`; + + logger.log("Enhanced prompt created", { enhancedPrompt }); + + // Use Flux with structured prompt const generateParams: any = { model: replicate.image("black-forest-labs/flux-dev"), - prompt: prompt, + prompt: enhancedPrompt, image: baseImageUrl, // Reference image for img2img - width: 1024, // From your settings - height: 1024, // From your settings - guidance_scale: 7, // From your settings - num_inference_steps: 30, // From your settings - strength: 0.7, // Good balance for product preservation - seed: 1601, // From your settings + width: parseInt(size.split("x")[0]), + height: parseInt(size.split("x")[1]), + guidance_scale: guidance, + num_inference_steps: steps, + strength: strength, + seed: seed, num_outputs: 1, }; const { image } = await experimental_generateImage(generateParams); logger.log("Image generated successfully"); - // Step 3: Prepare for upload + // Step 4: Upload to storage metadata.set("progress", { - step: 3, - total: 5, - message: "Preparing image for upload...", + step: 4, + total: 4, + message: "Uploading to storage...", }); const imageBuffer = Buffer.from(image.uint8Array); @@ -92,13 +141,6 @@ export const generateAndUploadImage = task({ const timestamp = Date.now(); const filename = `generated-${timestamp}.png`; - // Step 4: Upload to storage - metadata.set("progress", { - step: 4, - total: 5, - message: "Uploading to storage...", - }); - // Generate unique key for R2 const sanitizedFileName = filename.replace(/[^a-zA-Z0-9.-]/g, "_"); const r2Key = `uploaded-images/${timestamp}-${sanitizedFileName}`; @@ -136,10 +178,10 @@ export const generateAndUploadImage = task({ fileName: sanitizedFileName, }; - // Step 5: Complete + // Complete metadata.set("progress", { - step: 5, - total: 5, + step: 4, + total: 4, message: "Generation and upload completed!", }); metadata.set("status", "completed"); @@ -153,7 +195,7 @@ export const generateAndUploadImage = task({ contentType: "image/png", model, size, - prompt, + promptStyle, baseImageUrl, }); @@ -165,7 +207,7 @@ export const generateAndUploadImage = task({ contentType: "image/png", model, size, - prompt, + promptStyle, baseImageUrl, }; } catch (error) { @@ -173,7 +215,7 @@ export const generateAndUploadImage = task({ metadata.set("status", "failed"); metadata.set("progress", { step: 0, - total: 5, + total: 4, message: "Generation and upload failed", }); metadata.set( @@ -181,7 +223,10 @@ export const generateAndUploadImage = task({ error instanceof Error ? error.message : "Unknown error", ); - logger.error("Failed to generate and upload image", { error, prompt }); + logger.error("Failed to generate and upload image", { + error, + promptStyle, + }); throw error; } }, diff --git a/product-image-generator/src/trigger/image-upload.ts b/product-image-generator/src/trigger/image-upload.ts index 6e585dc..a82b97e 100644 --- a/product-image-generator/src/trigger/image-upload.ts +++ b/product-image-generator/src/trigger/image-upload.ts @@ -1,6 +1,9 @@ import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3"; import { logger, metadata, task } from "@trigger.dev/sdk"; +import { openai } from "@ai-sdk/openai"; +import { generateObject } from "ai"; import { Buffer } from "buffer"; +import { z } from "zod"; // Initialize S3 client for R2 const s3Client = new S3Client({ @@ -12,6 +15,71 @@ const s3Client = new S3Client({ }, }); +// Define the product analysis schema +const productAnalysisSchema = z.object({ + material: z.string().describe( + "Primary material type (e.g., glass, plastic, metal, fabric, wood)", + ), + colors: z.array(z.string()).describe( + "Array of colors present in the product", + ), + shape: z.string().describe("Detailed shape description"), + size_proportions: z.string().describe( + "Relative size and proportions description", + ), + functional_elements: z.array(z.string()).describe("List of functional parts"), + surface_finish: z.string().describe( + "Finish type (matte, glossy, textured, etc.)", + ), + text_branding: z.string().describe("Any visible text, logos, or branding"), + unique_features: z.array(z.string()).describe( + "Distinctive identifying characteristics", + ), + product_category: z.string().describe("What type of product this is"), +}); + +// Structured product analysis using AI SDK +async function analyzeProductStructured(imageUrl: string) { + try { + const result = await generateObject({ + model: openai("gpt-4o"), + schema: productAnalysisSchema, + messages: [ + { + role: "user", + content: [ + { + type: "text", + text: + "Analyze this product image and extract detailed properties. Be extremely specific and detailed about materials, colors, shape, functional elements, and unique characteristics. This will be used to preserve exact product appearance in AI generation.", + }, + { + type: "image", + image: imageUrl, + }, + ], + }, + ], + }); + + return result.object; + } catch (error) { + logger.warn("Failed to analyze product", { error }); + // Return fallback structure + return { + material: "unknown", + colors: ["unknown"], + shape: "product shape", + size_proportions: "standard proportions", + functional_elements: ["main body"], + surface_finish: "standard finish", + text_branding: "none visible", + unique_features: ["distinctive product"], + product_category: "general product", + }; + } +} + export const uploadImageToR2 = task({ id: "upload-image-to-r2", maxDuration: 300, // 5 minutes max @@ -22,20 +90,20 @@ export const uploadImageToR2 = task({ }) => { const { imageBuffer, fileName, contentType } = payload; - // Set initial metadata + // Set initial metadata with 5 steps (added analysis) metadata.set("status", "starting"); metadata.set("progress", { step: 1, - total: 4, - message: "Preparing upload...", + total: 5, + message: "Preparing upload and analysis...", }); - logger.log("Starting image upload to R2", { fileName, contentType }); + logger.log("Starting image upload and analysis", { fileName, contentType }); // Convert base64 to buffer metadata.set("progress", { step: 2, - total: 4, + total: 5, message: "Processing image data...", }); const buffer = Buffer.from(imageBuffer, "base64"); @@ -50,7 +118,7 @@ export const uploadImageToR2 = task({ metadata.set("progress", { step: 3, - total: 4, + total: 5, message: "Uploading to storage...", }); @@ -78,23 +146,34 @@ export const uploadImageToR2 = task({ logger.log("S3 PutObject response:", result as any); logger.log(`Image uploaded successfully to R2`, { r2Key }); - // Update metadata for completion + // Construct the public URL using the R2_PUBLIC_URL env var + const publicUrl = `${process.env.R2_PUBLIC_URL}/${r2Key}`; + + // Step 4: Analyze product properties metadata.set("progress", { step: 4, - total: 4, - message: "Upload completed!", + total: 5, + message: "Analyzing product properties...", }); - metadata.set("status", "completed"); - // Construct the public URL using the R2_PUBLIC_URL env var - const publicUrl = `${process.env.R2_PUBLIC_URL}/${r2Key}`; + const productAnalysis = await analyzeProductStructured(publicUrl); + logger.log("Product analysis completed", { productAnalysis }); - // Set final metadata with result + // Step 5: Complete + metadata.set("progress", { + step: 5, + total: 5, + message: "Upload and analysis completed!", + }); + metadata.set("status", "completed"); + + // Set final metadata with result including analysis metadata.set("result", { publicUrl, r2Key, fileSize, fileName: sanitizedFileName, + productAnalysis, }); return { @@ -105,11 +184,16 @@ export const uploadImageToR2 = task({ fileSize, contentType, fileName: sanitizedFileName, + productAnalysis, }; } catch (error) { // Set error metadata metadata.set("status", "failed"); - metadata.set("progress", { step: 0, total: 4, message: "Upload failed" }); + metadata.set("progress", { + step: 0, + total: 5, + message: "Upload and analysis failed", + }); metadata.set( "error", error instanceof Error ? error.message : "Unknown error", From 208653c206b2c85a2796a88a12aa9d59ee102c1c Mon Sep 17 00:00:00 2001 From: D-K-P <8297864+D-K-P@users.noreply.github.com> Date: Fri, 5 Sep 2025 16:50:27 +0100 Subject: [PATCH 07/39] Added prompt card and improved prompts --- product-image-generator/app/actions.ts | 42 +++++ .../app/components/CustomPromptCard.tsx | 160 ++++++++++++++++++ .../app/components/GeneratedCard.tsx | 6 +- .../app/components/UploadCard.tsx | 5 +- .../app/components/ui/input.tsx | 25 +++ product-image-generator/app/page.tsx | 128 ++++++++++++-- .../src/trigger/generate-and-upload-image.ts | 31 +++- .../src/trigger/image-upload.ts | 11 +- 8 files changed, 381 insertions(+), 27 deletions(-) create mode 100644 product-image-generator/app/components/CustomPromptCard.tsx create mode 100644 product-image-generator/app/components/ui/input.tsx diff --git a/product-image-generator/app/actions.ts b/product-image-generator/app/actions.ts index bcba8f7..8d4d2b4 100644 --- a/product-image-generator/app/actions.ts +++ b/product-image-generator/app/actions.ts @@ -115,3 +115,45 @@ export async function generateSingleImageAction( }; } } + +export async function generateCustomImageAction( + baseImageUrl: string, + productAnalysis: any, // Structured analysis from upload task + customPrompt: string, +) { + try { + const handle = await tasks.trigger( + "generate-and-upload-image", + { + promptStyle: "custom", // Custom prompt style + baseImageUrl, + productAnalysis, + customPrompt, // User's custom prompt + model: "flux", + size: "1024x1024", + }, + ); + + // Create a public access token for this specific run + const tokenResult = await createPublicAccessToken(handle.id); + + if (!tokenResult.success) { + return { + success: false as const, + error: tokenResult.error, + }; + } + + return { + success: true as const, + runId: handle.id, + accessToken: tokenResult.token, + }; + } catch (error) { + console.error("Failed to trigger custom image generation:", error); + return { + success: false as const, + error: "Failed to trigger image generation", + }; + } +} diff --git a/product-image-generator/app/components/CustomPromptCard.tsx b/product-image-generator/app/components/CustomPromptCard.tsx new file mode 100644 index 0000000..d3a2de5 --- /dev/null +++ b/product-image-generator/app/components/CustomPromptCard.tsx @@ -0,0 +1,160 @@ +"use client"; + +import { Button } from "./ui/button"; +import { Card } from "./ui/card"; +import { Input } from "./ui/input"; +import { Send, RefreshCw } from "lucide-react"; +import { useState } from "react"; +import { generateCustomImageAction } from "../actions"; + +interface CustomPromptCardProps { + baseImageUrl: string | null; + productAnalysis: any | null; + onGenerationComplete?: ( + runId: string, + accessToken: string, + prompt: string + ) => void; +} + +export default function CustomPromptCard({ + baseImageUrl, + productAnalysis, + onGenerationComplete, +}: CustomPromptCardProps) { + const [customPrompt, setCustomPrompt] = useState(""); + const [isGenerating, setIsGenerating] = useState(false); + const [runId, setRunId] = useState(null); + const [accessToken, setAccessToken] = useState(null); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + + if (!customPrompt.trim() || !baseImageUrl || !productAnalysis) { + return; + } + + setIsGenerating(true); + + try { + const result = await generateCustomImageAction( + baseImageUrl, + productAnalysis, + customPrompt.trim() + ); + + if (result.success) { + setRunId(result.runId); + setAccessToken(result.accessToken); + onGenerationComplete?.( + result.runId, + result.accessToken, + customPrompt.trim() + ); + } + } catch (error) { + console.error("Failed to generate custom image:", error); + } finally { + setIsGenerating(false); + } + }; + + const handleRegenerate = async () => { + if (!customPrompt.trim() || !baseImageUrl || !productAnalysis) { + return; + } + + setIsGenerating(true); + + try { + const result = await generateCustomImageAction( + baseImageUrl, + productAnalysis, + customPrompt.trim() + ); + + if (result.success) { + setRunId(result.runId); + setAccessToken(result.accessToken); + onGenerationComplete?.( + result.runId, + result.accessToken, + customPrompt.trim() + ); + } + } catch (error) { + console.error("Failed to regenerate custom image:", error); + } finally { + setIsGenerating(false); + } + }; + + const isDisabled = !baseImageUrl || !productAnalysis || !customPrompt.trim(); + + return ( + +
+
+
+
+ +