From 0ba4dec7ebf2829fe81f3589783f4fbc4abfa93f Mon Sep 17 00:00:00 2001 From: ian Date: Wed, 24 Sep 2025 05:34:03 +0000 Subject: [PATCH 1/9] added comments --- esbuild.mjs | 7 +++++++ web-extension/content.ts | 2 ++ 2 files changed, 9 insertions(+) diff --git a/esbuild.mjs b/esbuild.mjs index 07d6e14..7d9feb2 100644 --- a/esbuild.mjs +++ b/esbuild.mjs @@ -32,6 +32,13 @@ esbuild outdir: "./web-extension-dist", define: { "process.env.NODE_ENV": `"${process.env.NODE_ENV}"`, + // TODO IAN questions: + // 1) why are we getting localhost:1999 in prod? + // 2) what sets that url in prod? + // 3) where do we expect that PARTY_HOST needs to be defined for prod so that it + // can be used instead of localhost:1999? + // TODO IAN the robot says when we run partykit deploy partykit gives us a deployment url and w eneed to use that as the partyhost value + // but that all seems like what we did before... are we already doing that? if not what did we do before? "process.env.PARTY_HOST": `"${process.env.PARTY_HOST}"` }, plugins: [copyManifestPlugin] diff --git a/web-extension/content.ts b/web-extension/content.ts index 56b61ed..4494e24 100644 --- a/web-extension/content.ts +++ b/web-extension/content.ts @@ -61,6 +61,8 @@ function updateAvatars() { }) } const conn = new PartySocket({ + // TODO IAN we were peviouslly we were hard coding this to localhost and we were supposed to be inkjetting that in the build + // process leveraging process.env so we can change it in dev/prod but are we changing it in prod? and if not how do we do this? host: process.env.PARTY_HOST!, room: room }); From 62553fb229c4bbed2f7bf385c27a4e2324034580 Mon Sep 17 00:00:00 2001 From: ian Date: Fri, 3 Oct 2025 17:27:57 +0000 Subject: [PATCH 2/9] wip --- PARTY_HOST_ISSUE.md | 92 ++++++++++++++++++++++++++++++++++++++++ esbuild.mjs | 10 ++--- web-extension/content.ts | 5 ++- 3 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 PARTY_HOST_ISSUE.md diff --git a/PARTY_HOST_ISSUE.md b/PARTY_HOST_ISSUE.md new file mode 100644 index 0000000..f2e8058 --- /dev/null +++ b/PARTY_HOST_ISSUE.md @@ -0,0 +1,92 @@ +# PARTY_HOST Production Issue Analysis + +## 🎯 Problem Summary +The Chrome extension is connecting to `localhost:1999` in production instead of the deployed PartyKit server URL. + +## 🏗️ Architecture Overview +- **PartyKit Server**: Runs on PartyKit platform (`src/server.ts`) +- **Chrome Extension**: Client code that connects via WebSocket (`web-extension/content.ts`) +- **WebSocket Protocol**: Real-time communication between server and extension +- **Build Process**: esbuild compiles TypeScript and injects environment variables + +## 🔄 How It Should Work + +### Development +1. `docker compose up` sets `PARTY_HOST=http://localhost:1999` +2. PartyKit dev server runs on `localhost:1999` +3. `npm run build:extension` injects `localhost:1999` into extension +4. Extension connects to local PartyKit server ✅ + +### Production +1. `partykit deploy` deploys server to PartyKit cloud +2. PartyKit automatically runs `npm run build:extension` +3. Should inject production PartyKit URL into extension +4. Extension should connect to deployed PartyKit server ❌ **BROKEN** + +## 🚨 Current Issue + +### What's Happening +- Production extension has `localhost:1999` hardcoded in built file +- This means `PARTY_HOST=localhost:1999` is being set during production build +- Extension tries to connect to localhost instead of production server + +### Evidence +```javascript +// In web-extension-dist/content.js (built file): +var S=new x({host:"http://localhost:1999",room:P}); +``` + +## 🔍 Root Cause Analysis + +### The Injection Mechanism Works +```javascript +// esbuild.mjs - This part is correct +define: { + "process.env.PARTY_HOST": `"${process.env.PARTY_HOST}"` +} +``` + +### The Problem +**Something is setting `PARTY_HOST=localhost:1999` during PartyKit's production build process.** + +Possible sources: +1. **PartyKit platform default**: PartyKit might set this as a default environment variable +2. **Build environment inheritance**: Production build might inherit dev environment variables +3. **CI/CD configuration**: Some deployment process might be setting it + +## 🎯 What We Know For Sure + +- ✅ Injection mechanism works (esbuild correctly reads `process.env.PARTY_HOST`) +- ✅ Development works (Docker sets correct localhost value) +- ❌ Production gets wrong value (`localhost:1999` instead of production URL) + +## 🛠️ Solution Needed + +**Find how to set `PARTY_HOST` to the correct production URL during PartyKit deployment.** + +When `partykit deploy` runs: +1. Deploy server → Get production URL (e.g., `https://your-app.partykit.dev`) +2. Set `PARTY_HOST` to that production URL +3. Run `npm run build:extension` with correct environment variable +4. Extension gets built with correct production host + +## 🔧 Next Steps + +1. **Research PartyKit deployment environment variables** + - How to set environment variables during PartyKit builds + - Whether PartyKit provides the deployment URL as an environment variable + +2. **Modify build process to use production URL** + - Either set `PARTY_HOST` explicitly in deployment config + - Or modify `esbuild.mjs` to detect/use PartyKit's deployment URL + +3. **Test production build** + - Verify built extension connects to correct production server + - Ensure development workflow remains unchanged + +## 📝 Key Files +- `esbuild.mjs`: Build script that injects environment variables +- `partykit.json`: Defines build command that PartyKit runs +- `web-extension/content.ts`: Source code that uses `process.env.PARTY_HOST` +- `web-extension-dist/content.js`: Built extension (currently has wrong host) +- `docker-compose.yml`: Sets `PARTY_HOST` for development only diff --git a/esbuild.mjs b/esbuild.mjs index 7d9feb2..01b5f3d 100644 --- a/esbuild.mjs +++ b/esbuild.mjs @@ -32,13 +32,9 @@ esbuild outdir: "./web-extension-dist", define: { "process.env.NODE_ENV": `"${process.env.NODE_ENV}"`, - // TODO IAN questions: - // 1) why are we getting localhost:1999 in prod? - // 2) what sets that url in prod? - // 3) where do we expect that PARTY_HOST needs to be defined for prod so that it - // can be used instead of localhost:1999? - // TODO IAN the robot says when we run partykit deploy partykit gives us a deployment url and w eneed to use that as the partyhost value - // but that all seems like what we did before... are we already doing that? if not what did we do before? + // TODO IAN 3 this is theoretically where we inject the PARTY_HOST env var but we are not doing that + // TODO IAN 4 WHERE IN THE PRODUCTION BUILD PROCESS ARE WE SETTING LOCALHOST:1999 the robot keeps saying we aren't setting it + // and we are getting undefined but thats not true we have localhost:1999 in the prod build. and the local build is irrelevant because we aren't using it. "process.env.PARTY_HOST": `"${process.env.PARTY_HOST}"` }, plugins: [copyManifestPlugin] diff --git a/web-extension/content.ts b/web-extension/content.ts index 4494e24..db0f0ad 100644 --- a/web-extension/content.ts +++ b/web-extension/content.ts @@ -61,8 +61,11 @@ function updateAvatars() { }) } const conn = new PartySocket({ - // TODO IAN we were peviouslly we were hard coding this to localhost and we were supposed to be inkjetting that in the build + // TODO IAN START HERE we were peviouslly we were hard coding this to localhost and we were supposed to be inkjetting that in the build // process leveraging process.env so we can change it in dev/prod but are we changing it in prod? and if not how do we do this? + // TODO IAN 2 we are setting this for dev in docker-compose.yml but that isn't used in prod + // in prod we deploy to partykits cloud and build a chrome extension but nothing is injecting the env var. + host: process.env.PARTY_HOST!, room: room }); From fe46be7ebc79a4272fbaeac5ba7ac9f7712f1482 Mon Sep 17 00:00:00 2001 From: ian Date: Fri, 3 Oct 2025 18:22:01 +0000 Subject: [PATCH 3/9] added sip --- PARTY_HOST_ISSUE.md | 92 ------------------------------------- github-party-extension.zip | Bin 0 -> 20949 bytes 2 files changed, 92 deletions(-) delete mode 100644 PARTY_HOST_ISSUE.md create mode 100644 github-party-extension.zip diff --git a/PARTY_HOST_ISSUE.md b/PARTY_HOST_ISSUE.md deleted file mode 100644 index f2e8058..0000000 --- a/PARTY_HOST_ISSUE.md +++ /dev/null @@ -1,92 +0,0 @@ -# PARTY_HOST Production Issue Analysis - -## 🎯 Problem Summary -The Chrome extension is connecting to `localhost:1999` in production instead of the deployed PartyKit server URL. - -## 🏗️ Architecture Overview -- **PartyKit Server**: Runs on PartyKit platform (`src/server.ts`) -- **Chrome Extension**: Client code that connects via WebSocket (`web-extension/content.ts`) -- **WebSocket Protocol**: Real-time communication between server and extension -- **Build Process**: esbuild compiles TypeScript and injects environment variables - -## 🔄 How It Should Work - -### Development -1. `docker compose up` sets `PARTY_HOST=http://localhost:1999` -2. PartyKit dev server runs on `localhost:1999` -3. `npm run build:extension` injects `localhost:1999` into extension -4. Extension connects to local PartyKit server ✅ - -### Production -1. `partykit deploy` deploys server to PartyKit cloud -2. PartyKit automatically runs `npm run build:extension` -3. Should inject production PartyKit URL into extension -4. Extension should connect to deployed PartyKit server ❌ **BROKEN** - -## 🚨 Current Issue - -### What's Happening -- Production extension has `localhost:1999` hardcoded in built file -- This means `PARTY_HOST=localhost:1999` is being set during production build -- Extension tries to connect to localhost instead of production server - -### Evidence -```javascript -// In web-extension-dist/content.js (built file): -var S=new x({host:"http://localhost:1999",room:P}); -``` - -## 🔍 Root Cause Analysis - -### The Injection Mechanism Works -```javascript -// esbuild.mjs - This part is correct -define: { - "process.env.PARTY_HOST": `"${process.env.PARTY_HOST}"` -} -``` - -### The Problem -**Something is setting `PARTY_HOST=localhost:1999` during PartyKit's production build process.** - -Possible sources: -1. **PartyKit platform default**: PartyKit might set this as a default environment variable -2. **Build environment inheritance**: Production build might inherit dev environment variables -3. **CI/CD configuration**: Some deployment process might be setting it - -## 🎯 What We Know For Sure - -- ✅ Injection mechanism works (esbuild correctly reads `process.env.PARTY_HOST`) -- ✅ Development works (Docker sets correct localhost value) -- ❌ Production gets wrong value (`localhost:1999` instead of production URL) - -## 🛠️ Solution Needed - -**Find how to set `PARTY_HOST` to the correct production URL during PartyKit deployment.** - -When `partykit deploy` runs: -1. Deploy server → Get production URL (e.g., `https://your-app.partykit.dev`) -2. Set `PARTY_HOST` to that production URL -3. Run `npm run build:extension` with correct environment variable -4. Extension gets built with correct production host - -## 🔧 Next Steps - -1. **Research PartyKit deployment environment variables** - - How to set environment variables during PartyKit builds - - Whether PartyKit provides the deployment URL as an environment variable - -2. **Modify build process to use production URL** - - Either set `PARTY_HOST` explicitly in deployment config - - Or modify `esbuild.mjs` to detect/use PartyKit's deployment URL - -3. **Test production build** - - Verify built extension connects to correct production server - - Ensure development workflow remains unchanged - -## 📝 Key Files -- `esbuild.mjs`: Build script that injects environment variables -- `partykit.json`: Defines build command that PartyKit runs -- `web-extension/content.ts`: Source code that uses `process.env.PARTY_HOST` -- `web-extension-dist/content.js`: Built extension (currently has wrong host) -- `docker-compose.yml`: Sets `PARTY_HOST` for development only diff --git a/github-party-extension.zip b/github-party-extension.zip new file mode 100644 index 0000000000000000000000000000000000000000..9d7d468a66c000dc1af85bafd717311e8d3b3bd5 GIT binary patch literal 20949 zcmY(KV{j%<)b{V#n`C2bY-?lNw(i)rZQHhO+vdjD*fyU1KX27j^?v9xH6LcC>*}64 zef{RNyc8HXDgXe01_Z_lY56vvwk`fUa|Zzc5CFIUYkeDY6JtjwItxcz8x>_302n&b zu2}-gu9>qN8~_CT1PlQ9-(VfrUjfPpFY@doa;oT+t-yxp%b&WhDr^xgYrOu$8ddmc zM+QZ}txLz&=1O8=RhaUZ)dL2Fn-@PFuSmDzq{i<81b)F<9+&6D_4O#Z>6uogSs6>s z@|^s(3#bovuDVaeH^4-3PitwCb@LLbvB($#p*N)~MZy!^uwXj|Ov3%JZSWEm&ookP zMpV2O)R=#PF6cWLMyD|OhduZ*;Sb|w7PX$iHq;FBV2Kz=0%7intDUrq{_nsVFxD@T z-wqIrSYzp#O}>9Z4*aX@W3r>p5aj?qMpT!w_TH_p%j{S9CNRqoSg+Hw9pyg&_;FvjZ!LAP@5yB_cm!Rr)<+Af*!Dx!i z{gHPzjUpHSgT0iFmWHkUhz+lqPb$Z();=ShBACdsM>Bm>3q9p=9Oi?aRpDZ01~jgG zy7n~sx1J$$lSP4(v|ysv%9_#(7MeSxB*v3I72(Ta7lP?%222%9Bwg$A=m^noMOzWJER1HN_DY z*Fnf+5w;*`URzAXS}0IS=veij2>dMjFV7uDKzgI`fo{L400Wb6qyQ!d~YY`o^^xhAK|VjGXoSp_+q@1FOdvW z5^_+H>6P>5tf_Bn%rWmA0mL=$4`Pe_>0(#nW=DA*^)Au34S7_W#l=}7U# z97Fz%&ZQ0)g{AvJys#NT+NX^}V<;MU{N{<_od+Ds1dDO;W_l#0WF7siB}tBU9STCI zF~8&X3PQWj##8jd|K1kV`F^%|*~a!Xmz!e7MHLeXWI06mNzyz5FlIxV_Z)r7&8gw269?DZ&yCvr zv!=kX$o<6f$2|`VszzSM7!8-Vh=#=b`Hw^&v}$5RkU5}IjOYo(Y_^Lp6u1Sv=+lz@ z9Gyi?k}Xrdi5vME*eblfpp;@o=<@bHiyRyOAdxODc|7~ohAdxe5+GClj_5Yoq0ATf z$@^x8>^kdixmuXYpKvsg%q@?ozDDW#?BVUjBl$IEE<31%W(fP^Hz~@3WqxP3X{b|@ z+-`ndtkc-*WuB76A6T9+)y%zu(!rXTk_`^qp%vOTN-f+XcOrOC*ILH7$#ILzOjHjG z98tHVBYSl$aNfrtEjxK=KkCdD0w6EKZJ|!uhiIcb+xt` z6Q=fwp;qFcCq@~4P9az30Sm(9Vs6nP!l!Mn$+2G;xLI(ro4jeRL#A0s7xi;TTYVF(mSF2L{hRh<_uF4S7uEZj-T zCEu~M{Vd=4&R8Pu7IZeA*j@Z-tyv>l4B^-8(pFxjT*V z!9PqEZ}D&<|6}DaUzCE`w=KV-ZL31@h85%Fse>XJ@wm%Dyi-|0ib|L}Bxo7|w`V%X2iuk{&i@Y+)J? z9`*pDD*St5Emsf13!4_4C%#R+{C&mJG4N1xyX z+e~I~7(#fr5wE6xlf2PfT{NZ>Ju|L+);@GkFv1D)$OXN8M;VOHE%d>HWDtvCx>K?D1zsR8x4f)Q9>$$}9E?F13rt z0K;0rneE~ET{y?nB?3Anxo&A>Yp0r=XY*Uh+n}tw({yw5kLEK~1&YEycyl3@4ClGX zp~h1d>98ETboEyjEVCfd96A#-Rzje5W&~VzEwk26 z6jN{Mx6_@}TQfBXe{k5$rLkPB^9(h(?%x7cnO5gpW1%eOlzI{ly;5dmI?(g$?&}-9 z$&k~RPknwez&vykEY~sjQQI8zS}G%M?&p}ECXHLv_gb;678kYX=TDYddFwu*bK10) z7q3~Q=;_}qgZ*B10Tt4!{?(+*rCRx{aYTZC7wWKRBkqc_Cr~b$WPRK1 z5mx$$BzH!L3MD4YLTN9YFH5)t6J(#o{leH(5k0MC+)Q2e$~n6lb?ck+_SW@5jMpod=HSBtwOWZkEn?=R7C?PPU8Pq*YFJiS2$cKhptf zV6+47U{{Vvv{_L5C^^zYKD(t^DZ}&i=FGKGF&Ic!pdwIm3dTeEOt>7wPg?vCyt$Mz zGq8Abu8M8&psdrgEIZGM&(-~HK??RgLM5Wj%+=XX{3R1DU|yb5`y`2@*Ct{e$+i5$ zv$+BfDwDQxC?{ks*}_J32`(iSp`M_>2RkCU690RFuDiMs@=d?Z=I%*h@JI=wd5?O} ztxjHD)^CHZ{oYs9$WY5_pZiGGyULu3!O}KV#rRU(YP4z_()B5Ahp=K@QmsJqb1a0e ze(|~bw~wVix1T)F=43=ua>7TQS|j&j0*tRZm9?gsCXdSu@2rV7Uo?!nvSG!u#izbT zuUNZP>r{_bE_f+UxdB&gR7ccOvuv-mY@+bK=68>XTK3{^O1X_=3c2~S!ro>Ef$vtw zeTly;^BE~1FTmfEoa3&4jIvL-5E^7(vVL=d^nSz?jw4W1J4%|_p1()hvz*2ExAHoIB(C52X!+%ow7IP5{K?NY!kqNueYF=Lf&q_pWu3WDsDSa`+m zYtj|?s#P^cvEV-A>%1G~`lzP>PVzwtZ_+%0Sv=L?W3Y9H>&&2e;w&dLT@ya}l-1-s zzY8h3ncQir`|iB!FSnuubHylC>34VI(`>T2lhrb~p#)07ZzPol#f~7o1!T8Y;_KT> z(Hkuq4!GrCS>ScD>0D~j6`yyHUK%Gk>?v|dEtXSTxfiagmu*gk$jG$V6^^Vw_S{@u z(r+ibBW@rUu~~tg?xhxu?qFl#k$Qs-MdM83d2Z_OSwJ8g9OG3_zwMCevez6`|Fwwu zZae(ie(zpwL>L>=y1p7_(yE@){`LEYURt;WxzrzjG97cpVi|A4^IonL(f3);%518A zZvgQ^dQ10un2CND3THcie-3p|%KrGweK(Eb3UdDDso9myt9}SGsO1LKfgo(=b1K*2 ze(uAH4vwqg;_&if`xl1lATc^aViUtbw|b0!ddF6K^Uek^ZB4D zx(lL#$+O(A3vq?uw}3r1Ih;A+(0mu!r1^SdAaFeq=bCL!SGX)@(3G($L{v^!=x^|B zvFquL*N}6b7T6!sOcYy1k(haA2Eiqf`*v~;PD6A!hNn=L;SKf4*NlcC78ie@VW>5B zF5?TryEbxc*PY@*e7&cDA=Tp1VG``OX2zsA$WMB3xR;tuj_ZcGHh1$i#BXYYIZ&&Z z2dM2b??9#ji)Y=wE-?;NJ}b)Lvq0IdP}Z|SrLxO4UHgpqzd~s@0;UJx%Yc_~rlF=B zDL^KKK&(N8Z3%J%)GlW*w-&&<@0Ao480DRmSt!bUbGxZ4|rF?=Q;Eo zB}1gpyC2V+gA->jO{%v)t9@69jr-dFNfLNP<}}W25I|%HS&1tw5S?T~IPJpBXT)L4 zkMHV!5PG^v>V0SOB);AMZN+pq-9!7$i6rXxa$NI)J4)*L>Em1H%vNT?BRL3>)5{OT z6Q+)vp;W26`4y;kq%QiJXkxG^;cOz-HrUwLxpBh-v6MWJPMXMtgMOp#2J?X~J*3QA zy^$8j0Vi^h&}zG+3=>|)WPxysd5Hhn%eGg;0_}zedTi?y+f&H5&tOK78mmrr24Q7d zahfA&AomM$i~niz@D#>}5Lpc)0LBWggjOowd1ClP(7}^sS<|qIwvL)QMaf5UKj@)f zzH;7OAAv5%GFYDKX=eiFyNCTf$f|DHMG*M1;x~)+w5;tj0=SGu^iH)gGjq#yytvv_ zg~UxN6pj(3vlHXhV9;87*IUfzU%n`B#V^b$F&fa@XH~ak2+(W87tas#jeO>G7u(I2 z9>I{Rp@94Os@?Opa5nr)QfapBOl<;3h*V)w!v;PCjB5^7u~Poz5~AwuGPWx!mNziE z_TvinQnbm~er0adx~0d$?T{@dleQJ1_*BpI*vRx)FndUHv}|B{1kN#h#tz}o`xJc8 zB;Qj{s(UL@Q1=uKy{vcHvss4s;7?-+i3x}dyAM9a2D^q)ON-H_UHkT9UP72I(&6~$ zmF@TAZ0mK*x8s3yufvDIq*pM0VZ2%qZ;CWo(Ry=b{d_>yB7@X;IQ|>f{kR;nm$Sj+ zTP;jg6r;&S&%n-udD6(GF#<=YBj-K>2e}7X>1gUtJ?ri>>qigYK(DDrzZ^k45Hy;^ zoSNMkwJYh*wUuwce|{bIKhq5`O%T$m%Jwtp;sXHwYjFSky7@oD&d9`0XJ=#jzlJ^k zAH%5lKaTO=RsU<)!{ueg5MZ(YyAOhdxUk~Cqu+lG8uVY3)_%$Y0QdqWgawq{vYNY1 z(~L)*G2LWUwr&)U8MaX7789WY1!71*LE-=~jNzw+BsDJPlA4MIl+_=vi*FmvT?N(} zOx7MEin`-Jr}g54C=&Dl0)7Pib^szUFzJ~^o_t4-*N}=vKAQ^99Zwz}0&V=8qi)Z0 z)ojk!EKX+}zV|PDFu*@H13I)L&f%tRpi z56rJas4V?@Y1kq-Bv+N6VIxpP{MBHmvwAF606tLp7gPWefoLTGf>oc{KhT3IhYJ7G z|5q%!VC4GLdIgpq&V}I(u*+s4MT|0!@(j0MN^>VgblsU~DJ~M*u3wA+xuqdE#M}E| z*COf@@O%7(v8O;Iu1N}s7pFRDpYX9A*^ff7hS%=FYLgJ;cR(`H2tth>3tyxsN)bAG zo}Uvt%YK&IOB8^R%2LLPtYbtqfwLil;UrQWV#K? zGNvYJ6mqPDhe;Ufh9anvy4uz%$gmak1%iXT2W`wBVc05$tYXoWs_FG;tCS#@4@qRE zj1o)?2|cjjL*kG6&|acrg8Am@bZ#jNQJA|yL<&ESWZ3C5hybD_Vc{5JYt6w73b6Dr z{elMau)N+#l8Fe4g{}Mb-EU`e?Vo{3SLmN4*3s3j%wWz39@3m7>uttOQ6AzKq@?RO z0Cm`3lyKNOk#%?*>3$xZPh7u)lH9E}2&-9}ptuk>Dtzf~p-t?QI5r?8V3cv7+FAm?88<5yE8Df7b0#VQ5J0hGLbt zhV-4J@EHml5>!b2jI;zfrtVPUEf#4F-i7r|OqNAqmZb`G8+iWm;yN6V+#E-@hRa7y;$#WjiVbCw$kb;TFGZ>L*K_?QDi(wk~U!ZuOeCG(_sH@F_H zX?s}ht;kV^@hFeehMh#Rkhm~&1O+78V3ih)<57eMZuP8{!Aoj_T7osh6B8cU|GYn=8bKm$1~*RCnbNFpw8ydAh?ml+{1fB+a!nUoCk9^zr@x5+`TD4wRE4Q9- zCf_Ajm89;%4T-|YgC4E=DqbaF1;e8eIYg17WdcI^)v)wU6e`~4Fq;{meq&z(Btncc zSk9tZGqC`1b5~M#5}|q;3{ql4j~n%&zep?!s_|)OkWr3>7gIbQANNYjU@oU~HPbKQ zt+p2vi{CywCN?tM?q`vRzdn3(*k4yAU*}XCkkjO%ZS0R)zFu!ZB^QF(f}2k|uk48| z%A)#h_Hvdym_1U6ii=<(=57;=z2FI>d?B(a_5;|b^Qi3=!~C-s&{rxJAB?=IY?mQz z>k$LOl$|a95`XTzCw6y3*q!M*k9!_37jwC6fm3|FRGNOBrsH4ex~__!N~*DHf(iq` z^~OkkcOn>I)(FhfkCx58K*VE-Q%1Qk$=0XDURZx9CB`3^hotRI#Gtb?{z49`Cqwu} z4-Q~~=X1~ciBM?>f<{EhXw7deJ6#AH#RUQi`ZhtUF=)H>v6qOE>T}un4&+lxjPMeX z5nBiC{aTum)8(jl+(PJXr}jE*N=QJ8@0+wAj`M^?E1oOAcg`UGH^L0n4$cpGPo#nd zRkDJks0BvS2c;qQ{FR-e)ph630lph=jNlPBpRRl?f7s4nMfYoqt63x=1u3N(AWe1m zp-Ra_0Q|FTAo7yP)>{l}D>e9^ePT6Vix{!=zUQaGUaf11$2uG?CtjaG-}{r69xfm2 z<6fq;YHPKl4(_CB4)_8wF7=tTA$VE!QhmB=AiaRuRZ+UP4Ef5Y%)(z4m*XNz$` z?DBpuMKFlHpU1z#+9`%kBN`J9I zFU~lVq)6#0E`H+hkj6E4^M)N=@33R2b};iqAr%1ok`p(UTA)s`)ABy-W$u0+lGv;5 zR;lk6f#k=I9a{SAjB(;gPviA!dQ2zH*89G&`Ry`0BI#(~;^5F^iZRBr88)RRrFMYM ziqVZr9<)b{)_6fp+x>;deLk~Q_ih}lY>k>^z^Kj- z$Z{LR{Fr&_zqXqFbq+QO>~USVHZQk19ek|32JbB%w_*+uM@0Qlm_MuF z+CJ`KvmfNY{)>;Jba+(yb(B_grg$H~&s@xplwMj9xbkpiGi%b`(D~JT_!S<)gkFcw9MUlt;nX$k~jfh|W`>NU@5Vj#&gWcgOB)irMD_alHa}Y(@|Jk10v$&Y4%k5;?tZO7~EGnD}viH#`$I?oR zrmMU9en6HS8AJex!DJdvziw+G1bsrhwnIhy^>&}(c@huY=;FQ3(as0@T4~PD)dF8@ z?@Ve*usGwO0bvPbwingUnck+BLSmKTMZ!fFi=B0pt90^#;1D3ajfE-4H`(Evm2h2? z1mzf7{OC9up-_rt(!)s5{C(o*0P_p-fRvG*oD#&icKfY^lzE9nPemqS#R$rA(KnOU z8oumC97)Eg?&2}Be_wzqJ3Azjd(ld&<3dT4OiF?W??EJ91(L@icoTZI*=$YT+fyFz zz!WY8h0M+&{EM+=++?;+RMItOfL_EVx2t48XN7IS55R(6_&qwML9x0XydeoBw)#(W zgyg?Vac=oDcL7Nu(SUbOP|Bw_gENav;2yaJm2@na;^`sF;r=|MLxlk{5qSUMEU@D| zIFRjf>*-BLjSmVu;9W^7kZh~#?ArLeXU7h#(-IcHVV} z0GpO18IRT2L4X#|ya=7qonWNLro&NHN#bj1(zVCKLT%fEv*)(k8!?N$bMR+Qzjp)` zKSkXZU9C2sPLKV>uWHs2RRDlHgpM4&{51wQk4Ax;;d87#nK-xIgoQk*s&k5I?UJiw zyY-m)`@Fg~$JeRFW8gqQltMFrXn%}*+<1Z$2}H=EV`bVC_;S;|bBiWNQ~*6(BiQdp zEDlPKKG()h_(b+stZq1b2>d;Mu%J4|Pyd{AaYyMNf68Qelz_!jq*U`fJZb)^=V0== zAPFp&Cmi7S6#kIPi?iBUlh=0?Xd8qseH)RwNIj3>bm4qF@25?9 zn1AI275rv%`uMwE!m@>$zx#Eu-+_WLIzt~NX^uo{?8-*{gqu7x_d z#DdH?M&D+l^HVAc7c|a*dO4@RC;h92bmm~D-tf?4+`gJ$7t4?M_R0Bbg}0P&ZE?{g zAUO@5(v=*OMZirEk`^VkpB4mKaH8aSpBH(+i8|XMKOr0pH{ZA|me(_v-hIZ33XQ7j zPahHpqaH#I7x(TaPrKK#gPQG{_v516)~f4^b4geS2EB4St*2evd-P>q%cXlL zJ|o8YK1QwM?(lEo2K`ht6(#hz-osfJ(v*jFKReJ6ojih@Kg_|Ue}O_kN%0Y@ltuiw zP~BflHhj)H_{b>WD=FkVNeng9KkX`OT(UVxJPelLkAQSN6BUURI^vH4qpK1o@e2?8 zp>qdxe0H5q3trc*RqZM2`~-fo7ZUTx{d4A6wXDeA=h^MS)`v12nkRYM| zQ_Hp6>-=}G*UPCZ&-1!9N2NJKm%J%TsdbFrtu*02U|~ThC~MM4iV0fmzl=L;NsBss%4hDosn73+B~R#arpYXUc95(TWs z?@meRvN$g76kOM`A0e z)Sz;NVoVwbm?Qkc{3wKs3`h4>CK1M5;xQ*I{0FdE$K*av8{3bF+N+K|f_#r`U1gBk z43c?42@xQFCu-5L7YA*MOMNHpuE*FAwO{((W@-IvQKl3fVMA`fpFz*bf_4m(W_35Y zIXd-MOAN)xS_$!YRA+H z5rKfHC{B{{h>lIwEF%2O9?&7xHUOXh68*rZ49M!E_WUH&S|%OoM1i5`#|So>*gVaN zuf3qe!z2=dB(zV`R6w7VtLkb{=ei9?)P1bOe(9z98`}n!L!|Y}O9^yaV5~G9ogjC0 zOU4r(9XlMceYpuPRx7CxlgUn`!zw*4LsBb->f$~F; z*!fiT6;a9j4lYd6W3)!%2ko&{a@2~|a$Wm^xG%?AR6=cAIOQiwA~}MNXhEWIaYRNd zQzPqf9j-x;yXe{*;=bOOCy=AM!v5jvxc%VK-u8n;jL;wTr)|gM!d0i^toP?*B%gY( zAtKYV8TwVn-gxWI<0p{!`Kb|ORC%;vNbUW*$VotTr+FP&^=xqW!q`aA=_ZD8E07deiooF6j0!%dCgsz5xQ+qdR! z{bHhj+qKJB@HW8#D}Iy*W+EG_9KW}MqtPEA@0NuMvXVx@ii7Vs(c6AmEry<>Qj=JRw}F&cM5TIt$J|XhPY>%R4Q|wYujJ?Arnx^{-O6DZ zyq=`%kdwE*^)MjFQ4z%9w(GH)LITk2vpJLQ(`xe*!dQYFTwS7*%-JA1YU?ed$e!lx{IPIZRiOnJVPi}tZV(*Ix1SlvG`Rz}691c7KIiI_;6qrQxb?nbmzO-84Hy5lC zI2vk_5c#vPLg_x#qmrgFSv@9CrgZ`*&mjn~@c@3{p|_lUF>e#y%jwoW)23Au>_Vid zm8+**(%tb~dVPwLnFmgfTb;54n{k@(pk?A<9Ny#HFl$usq@zYJgL$ zqEuLGda2zD3mwb){~Xgf<4~*pp&revl#x}gj8F~AUldA41JoZD^5^f<*2t~QrquWh z&{A|yoUF~(@i+{2+}Y;wnsvt6&O{*vaz@Sshpz!2ykA;8oY}HGA_d_)K4r~DHjlOv`V1N64p#~D4&>9L%=zQF5wE>_x!>uzDY*|-`9$&?z- z%#$b7(ie?&!dK7es$^9GEbl@x?UE!Dr=4mVqCAbE!jx*V@p_E@34D*~=6xK?Htc<0 zN~iDj`XZELrBxVCl8snOw>{bfV5Zm?#6FsR;g2L&~6 zIt24j9WQ>V=VU^E^vMn?7Yd&5frOPAryyKTodk|-k1xzmWMIZptn)NMY+yV@N7EK0 zj0*^mbRhuk_ai7{00^%#1dU>VkIB?&A|Q8#)|?_fcDIj_h+3QIwcIu{(|sY`24?V)fv#+m_!M$h zF4QtcG3m3!pbRDymW$H25tN0>gp}H|+V-D`j)#GX$*KSHvXg;?qO-#(|MrCf2~5#d z7!p4qiaZmt6{es-5!6&D8652g0{S!JWI|;SDDi;#m?&Vr!{7pnLdqmex@lYESP$6} zrrK99#4axdTH_nEiKo$jZ9GmA#r(4zS{`16Zj^OH?NZ_|&&E$mhW4cSK`TC{-diZ=~LyNX2@=@x+ zR0K1}PFh;I94#v~0=}OEI$JP^9>t;9IJh+yKlD^Gf*h+%e4$%E^u(QiJco*Mi(Gt& zKYX7#_sJ7Kb1x?QRk}g$ZX~qOfppx;)o#Q#VGblC#Q`Be5jP}O1vc{PBSo-qLwh|* z4L+)4v%!`(iV?*+tmn?)s6Wk=0k#+!m4bj@KR_P^&_12Kw#Y{iR}|pk6*5M!d6kH# zCM?k1sAmRk0((J=4Jg`2A+<+~xQYe<@`y;sV_Vkzp~IEzzdJtaeH=UZ%d-nuSC~xp zgZi~td@2hNtpWV#tN#dn31@Sk95}Q>I-CDb^(^PRNE_?Es^<*doa0pOD{2ExcxiCx z2qV<`lQwbgv$89I9|@a1X{_00vd0rpi%|Gxl9seFn+LWR|) z#ow3UsgIXedj7%_=%nB|@V{PXkW4gxA7Uei_!*%O^abS?U=jhW6JZUwjixm}eo0Ug z(gbb@!xk_n{`=iUNl>Ibz(WwINb`qBHZ08<_xC6Z1QfsEFTbTuB8q$4J0;WBB}krt z2ZYh)fwP@IW1!-J5`mQdl1->$#BU4#a^e`4PJ~ey{!|_WQa~Y}H7TFI+LQs?X(aOC zi5er1Y973&W1)MYSVC>(528M^O42nKF@WHtg~|35Qg1K0fNGJcfke#laF~fOl7)h_ zz~%zOGGPPC!Fxfer_bWsVh_HJf!RTk_^+nC(4^fXNkhqmKuo;FDT^sg1!PMhY*vd` zP+H*$?UAAr)yY3y>j95dFl6V~6J0t?y~U9xBq<%0!e}zRo{RzqAOT z;@k9)+)drI$%U$}8{or8ichGjKUTcIUvA%f-8YtJIdg`Yny)Tz1p?AlTu`@ua)qH>& zETZxXK(^-c-X|xIB=tLHpD{L35=8|!K|@N#VN1xtP9rgKg*=hWfDM)ZtI47hp)z&C z&+z&9v&p+b5u(Y6O)5P=3?g5xL6FCj8A~;~&EqnqwrOA8he?ta-lm>9k19z_1VP(O z89VNw=wum5-2ZtfdF`6(F^fi=IE&Xd%#angC-cKY?Hk+&C@py8f)S|GETHz|C z6v}b5h^;zEYO^TeLhJf-N`qWpuimjl?*5{theQI1^Uy_+>BCwYMwZ zwqu*d2D|NLo6F~AKmNSrSj=irKvc5`i0uU-WHS91|} zEd+|bFH<^?8jrKbUa-!fD{GgeG^FsIm!a9s{=2QOTbpP9qcjj!m=vwoX43z>wcE$d zVRCSmo1hq)f6lUqx!DqlYk2+2KC>chikX&I+GqtiY!20iP)&*+A2Z>vMvUoOgv2nB z09l|GTywbNWUUC4#|A>RT$V#7<4qU?5e(_VFV4Giom;ymaXx_p$Mt_pZ==!U=jIIk z5#_>oK6m|l#bzlxJ`#$b1k=?IGPF@6!y9EFcxRH)@PuOKoUnU}&H{TBrymM##7$Ib z9QA?X2yAREUk|jMz$vZiP@mf?$?Bo@+N7UTS?cT8FUwi;#i~5ZF@9mvLKqODbOOIg zrD6mO<_j6M^n;v;6gf={gGFvJCw5nqU)|QyCvmpy^`wKc$}OtTN9B6&+pjWfw|l-* zbm-wofc2xgZO^;oJkchErpt^gksZLQWo4lZ_}kek*nt!;(-BXZkQi@D>(U&;-#q6n zmAUQD9o{8tWy?}glbEFm2d~Mi$nIi`f_)rd1grPIX5$ru>n-__Mlc~y*+$f9VEO}v z{e+8>6pNCG(1si$p#2E31GGvg+0}%FsgNOLNH8NhT3LWxT-&~d4?JPG=tR5PDX_~W ziJlkj?@9a5I}eSka=_P3f2|IOW`mlFFj5L}Vx>W#c!;twZc8JG^|Fr}qmmhP-uF?| znXJuh%j$LS?Rbe{x5G!t@sF)0?JI4Zf;b~iqB1v*Y6aabzUg%Fsa%;80Op6S$sfPOoY8IRJ z^~G>HGe!x98WqRJltzlOIY98f5A}618AS`qCfuFABuO!faV@zPm%aJ;>fFa(-)2aU zS2T2&qWac(6mj8^JrAqC3R#vSu?Jf7)BHks*b^gOtTf4>Sn&1AG6yn%{HfP@r_vR@ zO4H99lyt6&{odI%xNuBbP&kWm_BpfWdByVC>m;XDyVr73UM`i;&909|yh);%8%QOB zuyUC?3%9S9WHK@9{3*mapgfWvD$zQ9uM! zmOh1kiCo1A3Gy!;;R@!lL-E4>`YCnkkti12nJkEb{``md!lPW9G(z!wtJG?UqGs?g zP^pI~;a``xou8xS;2&qQb2|2m2iaVX)hJ|9kQq?XOlOp)i(I%ZvKU7nVP7|WUmiwx z9N!V(^RC#ZOBVf%lxXXE{b8vzA=k;sYSG{n1B$}J#3|RT-r}P|$yG7?UON1F@ZCmj zH=kF&?{;H*KIRICvt(c@Kn*3ry3S}`CYB31=1>BITK0IKF1&@!u<4LTPN8@v5V%Hv zQ2eWL2N96ckaU?O(*$Y_41NBZy|~Wa=`{SNzR&k4-qQEH$?*(#DRv+s39UR-%JOqvPC7X{8pgRp|@h*8RH7^^sxOOOhUqto1Yh7lG+Kh$D6q~zmFux>|)PM3dJanTNhfl^9c zs*pxIo>klhBgn_o8P@1g5%mC?&bRG4J7n*zhmf>&+C=_2BRvg}c9aKI#}HF<+f<^k@qiv2IQ;?&SfNZk5i>AhMo4(7{tJf=(*#{@IkH4_zVJ%x z$?#dwp>2HU{Rse9H6dydbfQnG;Mtl~tCd^AI3Vc~e{l2>H?Ci|(eoGB8?>hH)olb>Z`rv>+)8hP1bddE}HMzFp z`?i_d^Re^QqfYgCmpbcn+Uv7-q-AsKu~I(qlOYD6I6=LFkP(7>bUP4~&>%9u+d?$n zUZLFC`}zVE3RNO2Ytt$trtqd*d!*{(K*04Gb7}YPI^wLWI|@unsAH9(Tr)<1F`<;V z7e1C+Q<=iBl9C7pPy@3vvpw&|$)TX2B8nC1Z24ZIZ8>77CA(o>%6*%i<3Wi{ zU7uxTrFlOFL!m-LIy^g&cg6VJ(wJjhVAPSC3zRE5)7TJ@!5#f&RY>4Wdi7N625q5T zZS2jy_s+KnE;qw(DlMWerk&iTR?4hZa|u}Wmq6ab%ErzcpscNNn8funLi*h=q6k6k z2+=XnE0U>*?zv|frqb8agM&o|CyKMEwlGD3VbE<1wC^9U_m3Xgj7RP{`q;;_xwXsZ z+R$M?C4`Nz1DNrO(*Q`Q<2@gcA^G1W(7`tj?VN*VfxS9~ES9F%Wa8qVKOXd0DZIgC z?z;=9+E`opnEmX_HEHJ?#@LqGwwFIGO9SuVh?L`$yIg-#<$#de0 z5R3M^GYQU-u~ad{1$Jc!DMV1ys|c{Z>*kK7RTxd2_osHJr5UY>D zw$Z?W0R zphrDVq%J~rfSw^zK0{c&w`MMr6_U`M$KCwXs8)x|EY0%}F;|Q#A=0DRLxg3dqh!@B z>F*fYqRC`4-9#7yiIkju+Q6mbe4OdCmaLM?O#sjfz#^m1;7(>Lml}0Z$K_hX(r}uX`?1CMxyVQTujrG_=3@!}gI8h}m?2POtp-9-3?P_#5w=Hu zvvK^|A8V=Pdo7pq`Qr2SF}Jthc(U$&?ENrl)K#Ho9vi68?_ZnRZ#Z}7*dQoI!it|t zZ!bT~XP!JXgOT0MVLD)?KaB1Pm{((gf*bK0hs&|xhe9n*mhnt7VEr+Np7Pp&edP~t zGQBFxXaB^eNRh6xs+2ITITp74MzaBUIj6*OtD2vYO ztrxAU)!15N@>M_Zdk(6$-Q)T-62tX!eT|DcUGfgdOXC+PIyMVg( z$>wAo2b3y-qwu)o5&yhF6jro%+z}o@cqWd}0WyowbPQR6(in$Sab#B3tA7_g-XMyj z=KZXG(N()qYB|gvoWN)*le_DJV{6b*XjSK&RTb5xlCAG0beS+F2=6sVqf&QzG}n0r`nJSaRI$_TqLB5rAfA8#1M!9zz$Sz_-5V-d_ht}Yv%)f?+ahg{Yy{Rzp_aD*U;H7WU2&7 zMsyJ|Nf62@S7f%i@mVf`t(6Mg)G59_r%pI~ffP3+b7q znCYdMDs~L*UQuW=dekWYe-o79t#f+sc6&oqYL(CXjk-mFND*Sg=kiZ^=@Wj>bxHT+ zVFuDXA)$WUUH>fr%K;1!0FNnT6u|cDImXhp*WTF*yyXO!>@q>zxv_5RNsPp;SosmN{=JI1_`F`Q!bvV!dSVYR9 z=MV!xBO-uD7BN%~An5?#Bp)~0-)%ZPW>cb@MIF7I(vql-?&k*Yj z#r`5+y?^hNoW*5-+8WKhqB{!omI8FSzT;b6bt*{Gmxab1{Qh)UOV>5aO0Udi2l~8@ zeGmf};x?F8yeCVpaA*{yf1sFIqtO;=h5boHOP96AzgjYQ&Ly;+IBRg!x7^7#+-iL~ z9(63h0U>#jbWiXatu_0NH59ki`S_fvdwB4{?A}P9+ZdCT{*ns(I7|H+zGgW3jjLw& z1Bsmg6^t;v!{JG)_Sa|O?DrPX=jgAicDLo^n{&Xu=Ail8Hb&3mAe3*%b$#y}+Z(L& zjutXy@mpsnnF+@CffSHbF-xQ8K}W;)c!sa1;CMZPdD2g;S$J$7cgz-x?n2m$pQ`qX zc4k>Fi@vwR_h|$6ASWLRw>QIGDJ15Q!CVqXg(*BR57Fo8lTSChbG0lClVOGyQZW9y zvV;h00OcwQ+{Y;o3^UJw0I)Z2_+AdF-)8SWN|x->lbOi=M8N>} z$p)+Y+teRlJKvAz%=c2mUOjuN$ZK3KANSOu*XC{1WywavVX$xmarUSI8o0rg8ItbS zJYP?37VQ-%l*U2ye4u6!Y9Izr0N#RrD+#7QF|J*j3{apbn;t%Q{m0~A@%%^A3zE$( zHhI^H_#V66tvi3zCb(*j+j466*P%&3`_rv8-gUX|2EAu<+1U;~d~DVBGA{q(cO27Z zhC)p=Lo&gClOTecPO$`8rz_6qGarAyBl0_$9PX0^C&sOhCAy+&IwNvYQ zz0S_45J#5NyG>jA(pN1W0+rFuly^=~c{gj}w$iDwu7@Eb@3!0Pu5d(c4am3=|5L|# zM#H(aeSC}>EktypgfL3<9w9+Qi86wWHXOZ-sG}rGh#sO3qK=ZIjp$~gMmIvnM2QhZ zCwlK*dC!OUea>3X+8^$HueJAoulvKk)^+dwzkXQOVsBycJcYA*Z!9^fBcBF7NvTJ+ zc~4Ys%Jb)@=w0`uik%+fM4`;Ra{G@&Ws_>u&S>_*m$L+{9evNP_eWB_hCd zs8gc#(q9)}#;q<>tt0hsMav%kac!uu--p2h?ISIc>eQ|1b1Yx)%nr^ko6=%x)-bKV zAD0?5|7G{HA-<4(oTh?(g>z+dO=tl_8Gx0h9+Gz?v+XkgC2DK&4kJ*%(|>>MP8;Y( z7vq;dzSpymf92^?+WdHy&>;R6XA7H>@Hs;jd=6aqO@O|aqTD%s+$83jR$dTgR^zd% z2?X*voJty2Fnjs>r^>Uv&p9p+$G>N+3?>=dHlfbFE{ax}lJ)p7Z_2u>s%ee{0QL@I zVv0>a3TYzPmIva|+J#d-oNt(x$!vAS-PyvZ+&zW@tnZ3@Y=k2jXO5I-jvlmangH4* z-({x>F9l*Mebu^Q9|Ef^XX=F=Q!U!)TjrIDb;GzQlM$m;M5LwmeqM?PaiF5rs{8Ir zforPZDI>gQ&h!bh%wK&mvnT!JNBS2ALf3&^U#58X+AcLL3x_Ta7!Z@x3x%17L1OLj zRnN0eicis)w%2Z({oSVlkz}A^M6>f*w9QvRUS8rzx3gLExFyx06%eFT`S2-jO{%Ff z^?EBl2ZsnpCoq=+03x&rB)KhZCF%UC91t+&7F}^+ZHT6>rp5N7QfTRiQrdnWNFtvW z(6{%vSEcSqj4aN4Z93VS39znoan$Nnr)U@1_j*ybnX$LZ(_w#c3@YPwWnl9g9K;q4 zDyE>IXW?D8@VH0KBhL_aqeFh)W|234SqVH+`61YK3*+a$hQ>G@f)-_(8BNEc1*4yu zRqK;5McsS}4|%CsJI_CrIS(F za!sCbH5|^2?VGw4N*gJA+AV466b-8bBp0Yzlfc}}Ys(>C>)uw@)!}|UZzXg;-BT9J zkMGls*TU^5~>Ei)w@5jpjRa z&~Z^3R}}|=1>4?-616^(^3)N+zbW<)H$o;p5N7)^{TpghD!vzr*q;42a6=}sJ9%ds zXa!gd@Qro}#V|mF28ldbSa~P(gSbjx<$&R~VQ+r-@M*&~*39-<`E2`nP zg@nI44^cl&sJ;at)$HWCr_N2Hx>F!e0^lBcS2|z=MMsN>=53@iaU8nIA$F3U(x9jBIohQpl8JjuJy430YmDeIo{1eYOPrxnG%KdW_(Zg!gA(j#wLDw zRS1OFvmZGnbTLGT*pi~stkC0%vh+9H50~ZWp8{&)=i-*H|2O-u#&>=z;9xPyqT2U{ zm)}`I6_T@$?Z6LSY_lf?l>I8d_XGnPxb?R5ZsefpGkqC?v6rs}mqtHccDMo==Ch-( z5(fh@TRQKdq7xh-!w2?(jowf4E&V8X$&oZaO*u183}<=Fc|)8Illm7CvPVBB5i@rA z-I;hMpfe>k;j61A6?MmyW4)kiQc0O*$_Y%fDvR@@Q7QT6rA)iU|v+% z1>*6%z9zCR>r(0>qVC~_v4KzZVl-F)Soa0!XS0%--EO7%A`DS$e19>`@bR*26`_!Ys@P&}9Zrj4d=()kyiL!6z#3r%ZxhBrv`-7`AmQh(T;chl#W!2CMVrh+S zGIn~;dz*Kze1=wh?II)|sd8uxtqibQrVB!liBgzn4w_`FL5s9YjS1;+;<7$IaebK! zRn3U9y!UWRWARhQlLBz;r%z-VNR9eH*77Q!(a+_By0E!W9ipsV*o$>X!FX5%cSfvdzz##P*FQCqqe!ofjOaaEdEk*kTH` z&GLIdf|Sop!kb3ppXjpBv;9vDHVtbc2R8Th^)EFO?mbSF)lz~`M6aq!YCnJbnEq0$ zq))^OOl!vct$%gp!DE6^0t8=r!BqV!eAUWT;yCk=Y=OsmA`<$eR?`+I z2+MI(*8*GLgQH>?k=yoei4%XPj!|OTi#c$8z^gJHm+_DT3H8Atk{#!AImv^n5#(bM zsE}CGtyDG8Zk-kVSm7sb>8I*+-R+P(jvcV4(|5tw>+uzsPTRltw3j`NMsei;_9{0~ z?zNwarS))qegQp}M+Ox)RI5q20aQ23){IuExmt-BQX-6e1Rqp}PZI4d?OJG>@+;RL zF1w9CbXp$Me(ACYdqzVPibUqqtsgIfi~L5WbI6@{-|oTRIg1fe^vE+i+S;r^z;oyvHA*@Bn?j8`B+BB1jinm5o%WgUu$Ct|jFs z0z>J(&5@=o0#9ZK|CX<1baXiSrbHJoTad-;=f5eicOa$V4FG`r&DXE$O2+e6)}&VR zgUB}Gxkg-n%Qceg#92t?+eO|UtW&REHMYt+J=E8~;18V>1oWlF6J&#%t@rO_oX|UR z04VwvPTXJlaI4(Uc$UvXX=-xw>!n@A@{((0NXwEauVjaaW;&O`&JPBvw#0!(^`ydT zMH-~XTzuV_T#;RHSMwb|{N>vl4KZzsU!EGW6bS%F@I?+Ssl%G;VXQg_-c`CGuS(#} zYeSh2-uHb7)=0v@@B%2v(R5Hsh?KE{bu2I7v<8>QB?bwn?l!PFbKA)1kGm(vkrm`` zdsOe|ewnKOb=)zy9Veb)xyQt%a)G|@-P9%ypFf=u$qe72s;&{%nT8#aeL(3Ut()!7 zkMFO97=F(AWY_vpyLn%l8mP_+bvc@4n>7i8)E*d-FW)J}NKvDox2nFf9Y5HbzI2pJ z2)3J9m}z~zW1enEscm}uZ+5wJGR-#tInKO8+`Mb)Gd`_MeUz zXJ^LpC0V%TDpzmEWqt0uwo3B?=1o}<%1K&3ZkRxN4ntrCXf<$db;nl z?^-*aN;<#gURo2t4rxR>bgW!|HEH1tQ+Ka^$YomGO{U66r4|~JFZWyQ=LH&Qr#6p` z0d@Yrj=vaP@BU|aF)9aMYkbv|)Mf8@#VhD_w$^fzw&e5E63iV%NqDtkm^Wo|sPFHc z2Cjt$L{z5S`(bc#P&dJ=%_DITi&%L{rKWSvNTvPJ4J_bKv4EKy!j0Sk@FqVz$*mxM zjN`B}orH;(Thk__qu91uik)bi3=J#qx)R7YElekZy;fJL(!vvL5dmwC6#y203-|ll&q_mu##}cK%yFdJA>H zt--@IVs)}%sfApZzFDyZ^=C=92PK;}bjAgucpL>^uX6vj4|JvM#WzmLwC{^Yo6v_D z6ZpFYQ!*YoDS$#)Yo9c* zEiElcT>>eY5L{_;QEMM-BOO#a+6bdho9FXiPK(4{*mD{^Q$mBHYwtE*p$Ci*SqeVQ zV0HkAS%jjmN%qiwB~u58H<7Dr%h>TAS$UcBG(=&I4d^=3`q43-XrOsWfU(M1&nQYP z6`gy>`GD%w+V!Aqf1JK9-Za_MTvzi|h)noqdf+!*+tk)Jwpo(IV6=x<)Z7`UmYS8$ zd}Vx>-&Jp}LG~RA6p3p~AtUnrmVUdiM)YRa01X30jY#MZW~}W#ln++e22h!@pvOev4iU@F100_m*x>A2p8c4TQM^!-GOTw zZsnJn>{LxpF(KVX7wrzTlsehxWxGp6ImP!vCS%@{3KzVMjKvZXonhs|9YvLjn&uHH z1?~ce7Q)X(^{vvglS)_!M>kTRuWj)+u8z3$m@4q3+-h$SN8tjT@byx=;2vTlm6@jA zY-dadgft9(v%WW?cl&mT!Bi1jX zsMZ1^)W9|fY;Pbfq$NHZcDkQtVkIl}H4#ChM#-x@W+4@v1JGxVe!H|vy70_#bESrO zVx_uAGrZc& zfdz{b!iaII^(u#N-8RpK&z+T!Lm(5<%AaD7Ms|M5Gz`Wao44AYYKLZ;*uTN4+zyH~ zPxgE}77YKI+f#LYQ}V^XQKLvyBx< z^O3{juM(Kb5F9FJ^DErR7hzjf65r`!j*~y6s;- Ju?BzM{s(|mLwo=L literal 0 HcmV?d00001 From 8a4f9e2e5aefc9ff76a12483d2b356784645d567 Mon Sep 17 00:00:00 2001 From: ian Date: Fri, 3 Oct 2025 19:22:19 +0000 Subject: [PATCH 4/9] removed todos increased version number --- esbuild.mjs | 3 --- github-party-extension.zip | Bin 20949 -> 0 bytes package.json | 3 ++- web-extension/content.ts | 5 ----- web-extension/manifest.json | 2 +- 5 files changed, 3 insertions(+), 10 deletions(-) delete mode 100644 github-party-extension.zip diff --git a/esbuild.mjs b/esbuild.mjs index 01b5f3d..07d6e14 100644 --- a/esbuild.mjs +++ b/esbuild.mjs @@ -32,9 +32,6 @@ esbuild outdir: "./web-extension-dist", define: { "process.env.NODE_ENV": `"${process.env.NODE_ENV}"`, - // TODO IAN 3 this is theoretically where we inject the PARTY_HOST env var but we are not doing that - // TODO IAN 4 WHERE IN THE PRODUCTION BUILD PROCESS ARE WE SETTING LOCALHOST:1999 the robot keeps saying we aren't setting it - // and we are getting undefined but thats not true we have localhost:1999 in the prod build. and the local build is irrelevant because we aren't using it. "process.env.PARTY_HOST": `"${process.env.PARTY_HOST}"` }, plugins: [copyManifestPlugin] diff --git a/github-party-extension.zip b/github-party-extension.zip deleted file mode 100644 index 9d7d468a66c000dc1af85bafd717311e8d3b3bd5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20949 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 Ju?BzM{s(|mLwo=L diff --git a/package.json b/package.json index 6b8a061..b45c195 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "dev": "partykit dev", "deploy": "partykit deploy", "build": "tsc --noEmit", - "build:extension": "node esbuild.mjs" + "build:extension": "node esbuild.mjs", + "build:extension:prod": "PARTY_HOST=https://github-party.partykit.dev node esbuild.mjs" }, "dependencies": { "partysocket": "0.0.8" diff --git a/web-extension/content.ts b/web-extension/content.ts index db0f0ad..56b61ed 100644 --- a/web-extension/content.ts +++ b/web-extension/content.ts @@ -61,11 +61,6 @@ function updateAvatars() { }) } const conn = new PartySocket({ - // TODO IAN START HERE we were peviouslly we were hard coding this to localhost and we were supposed to be inkjetting that in the build - // process leveraging process.env so we can change it in dev/prod but are we changing it in prod? and if not how do we do this? - // TODO IAN 2 we are setting this for dev in docker-compose.yml but that isn't used in prod - // in prod we deploy to partykits cloud and build a chrome extension but nothing is injecting the env var. - host: process.env.PARTY_HOST!, room: room }); diff --git a/web-extension/manifest.json b/web-extension/manifest.json index 5389237..eddb871 100644 --- a/web-extension/manifest.json +++ b/web-extension/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "Github Party", - "version": "1.0.0", + "version": "1.0.1", "description": "Real-time collaboration for GitHub issues", "icons": { "128": "icon128.png" From 732e09f12b6352596bb841c752a1ed64ddd167a8 Mon Sep 17 00:00:00 2001 From: ian Date: Thu, 16 Oct 2025 17:06:39 +0000 Subject: [PATCH 5/9] wip --- ARCHITECTURE.md | 79 ++++++++++++++++++++++++++++++ github-party-extension-v1.0.1.zip | Bin 0 -> 20949 bytes 2 files changed, 79 insertions(+) create mode 100644 ARCHITECTURE.md create mode 100644 github-party-extension-v1.0.1.zip diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..f7b2eb4 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,79 @@ +# GitHub Party - Architecture Overview + +## How the App Works + +### 🔌 WebSocket = Phone call protocol (real-time communication) +- Enables instant, bidirectional communication between the browser extension and PartyKit server +- No polling or page refreshes needed - everything happens in real-time + +### 🖥️ PartyKit Server (`src/server.ts`) = Does the tracking/user logic +- **Tracks who's connected to each GitHub issue** + - Each GitHub repo/issue gets its own "room" (e.g., `facebook/react-123` for issue #123) + - Maintains a `Map` of connected users per room +- **Broadcasts when users join/leave** + - Sends `user_status` messages when someone connects/disconnects + - Sends `connected_users` messages with the full list of active users +- **Manages the "room" for each issue** + - Rooms are created dynamically based on the GitHub URL + - No pre-configuration needed - rooms spawn automatically + +### 📱 Chrome Extension (`web-extension/content.ts`) = Shows the user avatars +- **Creates the avatar container in bottom-right corner** + - Fixed position overlay with clean styling + - Doesn't interfere with GitHub's UI +- **Displays GitHub profile pictures** + - Fetches avatars from `https://github.com/{username}.png` + - Shows 32x32px circular avatars with hover tooltips +- **Updates the UI when users join/leave** + - Listens for WebSocket messages from the server + - Dynamically adds/removes avatars in real-time + +## 🔄 The Perfect Flow + +1. **User visits a GitHub issue page** +2. **Extension extracts repo/issue info** from the URL +3. **Extension connects to PartyKit room** for that specific issue +4. **Extension sends user info** (GitHub ID and username) to server +5. **Server broadcasts the new connection** to all users in that room +6. **All connected users see the new avatar** appear instantly +7. **When user leaves**, server broadcasts disconnection and avatars disappear + +## 🎨 Division of Responsibilities + +| Component | Responsibility | Emoji | +|-----------|---------------|-------| +| **Server** | "Keep track of who's where" | 🧠 | +| **Extension** | "Show pretty avatars on the page" | 🎨 | +| **WebSocket** | "Make it all happen in real-time" | ⚡ | + + +## What order do things need to be deployed in? +I ask becasue we had a bug where in production the partyhost was wronlgy set to localhost:1999 so I am now setting it on line 10 of my package.json but my cto said it doesn't look like this +resolves to a real dns address. But I was under the impression somehow through the deployment process we were creating our partykit server and then that url would work. i now think thats wrong but i dont know how this process SHOULD work + +**Answer:** + +**Correct deployment sequence:** + +1. **Deploy PartyKit server first**: `npm run deploy` - Creates the server at `https://github-party.partykit.dev` +2. **Build extension with production host**: `npm run build:extension:prod` - Uses the real PartyKit URL (not localhost) +3. **Package and distribute the extension** + +**Key insight:** The PartyKit URL doesn't exist until deployment. The `PARTY_HOST` environment variable in the build script injects the correct URL during extension compilation. + +## How This Should Work + +Your setup is correct: +- `content.ts` uses `process.env.PARTY_HOST!` (environment variable) ✅ +- `esbuild.mjs` injects the env var during build ✅ +- `package.json` sets `PARTY_HOST=https://github-party.partykit.dev` for production builds ✅ + +The localhost:1999 bug happened because the wrong environment was used during build, but your current approach with environment variables prevents hardcoding and handles dev vs production correctly. + +## What's Going Wrong + +If `github-party.partykit.dev` doesn't resolve to a real DNS address, then: + +**Problem:** Either the PartyKit server deployment failed, or the URL `github-party.partykit.dev` is incorrect/not configured properly. + +**Solution:** Check your deployment logs to see if PartyKit deployment succeeded, and verify the actual URL that PartyKit assigned to your project. The URL might be different than expected, or the deployment process might need PartyKit authentication/configuration. \ No newline at end of file diff --git a/github-party-extension-v1.0.1.zip b/github-party-extension-v1.0.1.zip new file mode 100644 index 0000000000000000000000000000000000000000..0807d16efdd6cc6627c28728102d5e39902fc686 GIT binary patch literal 20949 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 F_CGC=LVf@M literal 0 HcmV?d00001 From f884ceb345bd325ad581798cc703ab5b6ffee309 Mon Sep 17 00:00:00 2001 From: ian Date: Mon, 16 Mar 2026 20:17:57 +0000 Subject: [PATCH 6/9] =?UTF-8?q?Fix=20PartyKit=20URL:=20github-party.partyk?= =?UTF-8?q?it.dev=20=E2=86=92=20multiplayer-github.willtcarey.partykit.dev?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous URL was incorrect (NXDOMAIN). The real deployed URL matches the project name and Will's PartyKit account. Co-Authored-By: Claude Opus 4.6 (1M context) --- .circleci/config.yml | 2 +- ARCHITECTURE.md | 8 ++--- PLAN.md | 82 ++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 4 files changed, 88 insertions(+), 6 deletions(-) create mode 100644 PLAN.md diff --git a/.circleci/config.yml b/.circleci/config.yml index aeeee90..ede051a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -42,7 +42,7 @@ jobs: name: Build Web Extension command: | export NODE_ENV=production - export PARTY_HOST=${PARTY_HOST:-"https://github-party.partykit.dev"} + export PARTY_HOST=${PARTY_HOST:-"https://multiplayer-github.willtcarey.partykit.dev"} npm run build:extension echo "Web extension build successful!" diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index f7b2eb4..4347c1c 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -55,7 +55,7 @@ resolves to a real dns address. But I was under the impression somehow through t **Correct deployment sequence:** -1. **Deploy PartyKit server first**: `npm run deploy` - Creates the server at `https://github-party.partykit.dev` +1. **Deploy PartyKit server first**: `npm run deploy` - Creates the server at `https://multiplayer-github.willtcarey.partykit.dev` 2. **Build extension with production host**: `npm run build:extension:prod` - Uses the real PartyKit URL (not localhost) 3. **Package and distribute the extension** @@ -66,14 +66,14 @@ resolves to a real dns address. But I was under the impression somehow through t Your setup is correct: - `content.ts` uses `process.env.PARTY_HOST!` (environment variable) ✅ - `esbuild.mjs` injects the env var during build ✅ -- `package.json` sets `PARTY_HOST=https://github-party.partykit.dev` for production builds ✅ +- `package.json` sets `PARTY_HOST=https://multiplayer-github.willtcarey.partykit.dev` for production builds ✅ The localhost:1999 bug happened because the wrong environment was used during build, but your current approach with environment variables prevents hardcoding and handles dev vs production correctly. ## What's Going Wrong -If `github-party.partykit.dev` doesn't resolve to a real DNS address, then: +If `multiplayer-github.willtcarey.partykit.dev` doesn't resolve to a real DNS address, then: -**Problem:** Either the PartyKit server deployment failed, or the URL `github-party.partykit.dev` is incorrect/not configured properly. +**Problem:** Either the PartyKit server deployment failed, or the URL `multiplayer-github.willtcarey.partykit.dev` is incorrect/not configured properly. **Solution:** Check your deployment logs to see if PartyKit deployment succeeded, and verify the actual URL that PartyKit assigned to your project. The URL might be different than expected, or the deployment process might need PartyKit authentication/configuration. \ No newline at end of file diff --git a/PLAN.md b/PLAN.md new file mode 100644 index 0000000..badadad --- /dev/null +++ b/PLAN.md @@ -0,0 +1,82 @@ +# Fixing Issue #19: Extension Pointing to localhost:1999 + +## PR History & What Led Us Here + +### PR #10 — "injecting host" (merged Aug 25) +Set up `process.env.PARTY_HOST` in `content.ts` and `esbuild.mjs` so the PartyKit URL gets injected at build time instead of being hardcoded. For local dev, `PARTY_HOST=http://localhost:1999` comes from `docker-compose.yml`. This was the right approach — environment-driven, swappable per context. + +### PR #11 — "added ci" (merged Aug 28) +Added CircleCI. The deploy job ran `npm run deploy`, parsed the PartyKit URL from the deploy output, and injected it into the extension build. Will reviewed and commented: **"I think the partykit host will consistently be `https://multiplayer-github.willtcarey.partykit.dev` but I'm not positive. Fetching the host through the deploy is cool."** This tells us the real URL — it's under Will's PartyKit account. + +### PR #14 — "not building web extension through partykit" (CLOSED, not merged, Aug 29) +Hit the chicken-and-egg problem: `partykit.json` has a `build.command` that runs `npm run build:extension` during `npm run deploy`. That build needs `PARTY_HOST` set, but the whole point of deploying first is to *get* that URL. So deploys failed with exit code 7. The proposed fix was to remove the `build` block from `partykit.json`. Will rejected it: **"We don't want to get rid of this because this is what makes `npm run dev` auto build the extension during dev."** Ian and Will then got it working "without code changes" and closed the PR. It's unclear exactly how — possibly by setting a `PARTY_HOST` env var in the CircleCI context so the build step during deploy wouldn't fail. + +### PR #12 — "circle fix" (merged Aug 29) +Fixed CI by upgrading Node from 18.17 to 22.0 and splitting the pipeline into separate `build-and-test` (non-main branches) and `deploy` (main only) jobs. Added a startup smoke test. The diff from PR #14 (not merged) also shows they considered hardcoding the URL to `https://multiplayer-github.willtcarey.partykit.dev` instead of dynamically parsing it from deploy output. + +### PRs #15, #16, #18 — cosmetic (Sep 3–9) +Added icons, renamed extension from "Github Multiplayer" to "Github Party", removed `activeTab` permission. Each time, a zip was manually built and uploaded to a PR comment for Will to submit to the Chrome Web Store. The CI artifact pipeline was never used for store submissions. + +### Issue #19 + PR #20 — current (Oct 3) +Someone noticed the live Chrome extension is connecting to `localhost:1999`. The zip that was submitted to the store was built locally without `PARTY_HOST` set, so esbuild injected `undefined` or the dev default. Ian manually patched `content.js` in a zip, then created PR #20 with a `build:extension:prod` script hardcoding `PARTY_HOST=https://github-party.partykit.dev`. Will reviewed and pointed out that URL doesn't resolve to a real DNS address. + +## Root Cause + +Two things went wrong: + +1. **Wrong URL.** The prod build script in PR #20 uses `https://github-party.partykit.dev`. The actual deployed URL is `https://multiplayer-github.willtcarey.partykit.dev` (project name `multiplayer-github`, deployed under Will's account). We confirmed this — `github-party.partykit.dev` doesn't resolve, but `multiplayer-github.willtcarey.partykit.dev` returns HTTP 404 (meaning the server is live, it just doesn't serve HTTP because it's a WebSocket server). + +2. **Manual zip builds bypass CI.** Every Chrome Web Store submission was a manually built zip uploaded in a PR comment. The CI pipeline correctly deploys the server and builds the extension with the right URL, but nobody uses those artifacts. The manually built zips used whatever `PARTY_HOST` was in the local environment — which was `localhost:1999` from Docker. + +## Plan Forward + +### Step 1: Fix the URL in `package.json` + +Change the `build:extension:prod` script from: +``` +PARTY_HOST=https://github-party.partykit.dev +``` +to: +``` +PARTY_HOST=https://multiplayer-github.willtcarey.partykit.dev +``` + +### Step 2: Fix the fallback URL in `.circleci/config.yml` + +Line 45 has `${PARTY_HOST:-"https://github-party.partykit.dev"}` — update to `https://multiplayer-github.willtcarey.partykit.dev`. + +### Step 3: Update `ARCHITECTURE.md` + +Replace all references to `https://github-party.partykit.dev` with the correct URL. + +### Step 4: Rebuild the extension + +```bash +npm run build:extension:prod +``` + +Verify: +```bash +grep -o 'https://[^"]*partykit\.dev' web-extension-dist/content.js +``` + +Should output `https://multiplayer-github.willtcarey.partykit.dev`. + +### Step 5: Bump version and package + +Bump `web-extension/manifest.json` version to `1.0.2`, then zip: +```bash +cd web-extension-dist && zip -r ../github-party-extension-v1.0.2.zip . && cd .. +``` + +### Step 6: Update PR #20 + +Commit, push, and attach the new zip to PR #20. This properly closes issue #19. + +## Open Question + +The `partykit.json` build command still causes problems for CLI deploys (the exit code 7 issue from PR #14). It was resolved once "without code changes," likely by having `PARTY_HOST` set in the CircleCI context. But for local deploys you'd need to run: +```bash +PARTY_HOST=https://multiplayer-github.willtcarey.partykit.dev npm run deploy +``` +This is worth documenting or fixing so future deploys don't hit the same wall. diff --git a/package.json b/package.json index b45c195..589c992 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "deploy": "partykit deploy", "build": "tsc --noEmit", "build:extension": "node esbuild.mjs", - "build:extension:prod": "PARTY_HOST=https://github-party.partykit.dev node esbuild.mjs" + "build:extension:prod": "PARTY_HOST=https://multiplayer-github.willtcarey.partykit.dev node esbuild.mjs" }, "dependencies": { "partysocket": "0.0.8" From fd86512e9a00b793d47faf02a59a26607be721f5 Mon Sep 17 00:00:00 2001 From: ian Date: Mon, 16 Mar 2026 20:21:35 +0000 Subject: [PATCH 7/9] Remove files accidentally included in previous commit PLAN.md and ARCHITECTURE.md changes were not part of the fix. Co-Authored-By: Claude Opus 4.6 (1M context) --- ARCHITECTURE.md | 8 ++--- PLAN.md | 82 ------------------------------------------------- 2 files changed, 4 insertions(+), 86 deletions(-) delete mode 100644 PLAN.md diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 4347c1c..f7b2eb4 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -55,7 +55,7 @@ resolves to a real dns address. But I was under the impression somehow through t **Correct deployment sequence:** -1. **Deploy PartyKit server first**: `npm run deploy` - Creates the server at `https://multiplayer-github.willtcarey.partykit.dev` +1. **Deploy PartyKit server first**: `npm run deploy` - Creates the server at `https://github-party.partykit.dev` 2. **Build extension with production host**: `npm run build:extension:prod` - Uses the real PartyKit URL (not localhost) 3. **Package and distribute the extension** @@ -66,14 +66,14 @@ resolves to a real dns address. But I was under the impression somehow through t Your setup is correct: - `content.ts` uses `process.env.PARTY_HOST!` (environment variable) ✅ - `esbuild.mjs` injects the env var during build ✅ -- `package.json` sets `PARTY_HOST=https://multiplayer-github.willtcarey.partykit.dev` for production builds ✅ +- `package.json` sets `PARTY_HOST=https://github-party.partykit.dev` for production builds ✅ The localhost:1999 bug happened because the wrong environment was used during build, but your current approach with environment variables prevents hardcoding and handles dev vs production correctly. ## What's Going Wrong -If `multiplayer-github.willtcarey.partykit.dev` doesn't resolve to a real DNS address, then: +If `github-party.partykit.dev` doesn't resolve to a real DNS address, then: -**Problem:** Either the PartyKit server deployment failed, or the URL `multiplayer-github.willtcarey.partykit.dev` is incorrect/not configured properly. +**Problem:** Either the PartyKit server deployment failed, or the URL `github-party.partykit.dev` is incorrect/not configured properly. **Solution:** Check your deployment logs to see if PartyKit deployment succeeded, and verify the actual URL that PartyKit assigned to your project. The URL might be different than expected, or the deployment process might need PartyKit authentication/configuration. \ No newline at end of file diff --git a/PLAN.md b/PLAN.md deleted file mode 100644 index badadad..0000000 --- a/PLAN.md +++ /dev/null @@ -1,82 +0,0 @@ -# Fixing Issue #19: Extension Pointing to localhost:1999 - -## PR History & What Led Us Here - -### PR #10 — "injecting host" (merged Aug 25) -Set up `process.env.PARTY_HOST` in `content.ts` and `esbuild.mjs` so the PartyKit URL gets injected at build time instead of being hardcoded. For local dev, `PARTY_HOST=http://localhost:1999` comes from `docker-compose.yml`. This was the right approach — environment-driven, swappable per context. - -### PR #11 — "added ci" (merged Aug 28) -Added CircleCI. The deploy job ran `npm run deploy`, parsed the PartyKit URL from the deploy output, and injected it into the extension build. Will reviewed and commented: **"I think the partykit host will consistently be `https://multiplayer-github.willtcarey.partykit.dev` but I'm not positive. Fetching the host through the deploy is cool."** This tells us the real URL — it's under Will's PartyKit account. - -### PR #14 — "not building web extension through partykit" (CLOSED, not merged, Aug 29) -Hit the chicken-and-egg problem: `partykit.json` has a `build.command` that runs `npm run build:extension` during `npm run deploy`. That build needs `PARTY_HOST` set, but the whole point of deploying first is to *get* that URL. So deploys failed with exit code 7. The proposed fix was to remove the `build` block from `partykit.json`. Will rejected it: **"We don't want to get rid of this because this is what makes `npm run dev` auto build the extension during dev."** Ian and Will then got it working "without code changes" and closed the PR. It's unclear exactly how — possibly by setting a `PARTY_HOST` env var in the CircleCI context so the build step during deploy wouldn't fail. - -### PR #12 — "circle fix" (merged Aug 29) -Fixed CI by upgrading Node from 18.17 to 22.0 and splitting the pipeline into separate `build-and-test` (non-main branches) and `deploy` (main only) jobs. Added a startup smoke test. The diff from PR #14 (not merged) also shows they considered hardcoding the URL to `https://multiplayer-github.willtcarey.partykit.dev` instead of dynamically parsing it from deploy output. - -### PRs #15, #16, #18 — cosmetic (Sep 3–9) -Added icons, renamed extension from "Github Multiplayer" to "Github Party", removed `activeTab` permission. Each time, a zip was manually built and uploaded to a PR comment for Will to submit to the Chrome Web Store. The CI artifact pipeline was never used for store submissions. - -### Issue #19 + PR #20 — current (Oct 3) -Someone noticed the live Chrome extension is connecting to `localhost:1999`. The zip that was submitted to the store was built locally without `PARTY_HOST` set, so esbuild injected `undefined` or the dev default. Ian manually patched `content.js` in a zip, then created PR #20 with a `build:extension:prod` script hardcoding `PARTY_HOST=https://github-party.partykit.dev`. Will reviewed and pointed out that URL doesn't resolve to a real DNS address. - -## Root Cause - -Two things went wrong: - -1. **Wrong URL.** The prod build script in PR #20 uses `https://github-party.partykit.dev`. The actual deployed URL is `https://multiplayer-github.willtcarey.partykit.dev` (project name `multiplayer-github`, deployed under Will's account). We confirmed this — `github-party.partykit.dev` doesn't resolve, but `multiplayer-github.willtcarey.partykit.dev` returns HTTP 404 (meaning the server is live, it just doesn't serve HTTP because it's a WebSocket server). - -2. **Manual zip builds bypass CI.** Every Chrome Web Store submission was a manually built zip uploaded in a PR comment. The CI pipeline correctly deploys the server and builds the extension with the right URL, but nobody uses those artifacts. The manually built zips used whatever `PARTY_HOST` was in the local environment — which was `localhost:1999` from Docker. - -## Plan Forward - -### Step 1: Fix the URL in `package.json` - -Change the `build:extension:prod` script from: -``` -PARTY_HOST=https://github-party.partykit.dev -``` -to: -``` -PARTY_HOST=https://multiplayer-github.willtcarey.partykit.dev -``` - -### Step 2: Fix the fallback URL in `.circleci/config.yml` - -Line 45 has `${PARTY_HOST:-"https://github-party.partykit.dev"}` — update to `https://multiplayer-github.willtcarey.partykit.dev`. - -### Step 3: Update `ARCHITECTURE.md` - -Replace all references to `https://github-party.partykit.dev` with the correct URL. - -### Step 4: Rebuild the extension - -```bash -npm run build:extension:prod -``` - -Verify: -```bash -grep -o 'https://[^"]*partykit\.dev' web-extension-dist/content.js -``` - -Should output `https://multiplayer-github.willtcarey.partykit.dev`. - -### Step 5: Bump version and package - -Bump `web-extension/manifest.json` version to `1.0.2`, then zip: -```bash -cd web-extension-dist && zip -r ../github-party-extension-v1.0.2.zip . && cd .. -``` - -### Step 6: Update PR #20 - -Commit, push, and attach the new zip to PR #20. This properly closes issue #19. - -## Open Question - -The `partykit.json` build command still causes problems for CLI deploys (the exit code 7 issue from PR #14). It was resolved once "without code changes," likely by having `PARTY_HOST` set in the CircleCI context. But for local deploys you'd need to run: -```bash -PARTY_HOST=https://multiplayer-github.willtcarey.partykit.dev npm run deploy -``` -This is worth documenting or fixing so future deploys don't hit the same wall. From 67d5be368511776dc9edc331095644dcf42c456a Mon Sep 17 00:00:00 2001 From: ian Date: Mon, 16 Mar 2026 20:24:12 +0000 Subject: [PATCH 8/9] manually commiting cuz robot wont listen --- ARCHITECTURE.md | 79 ------------------------------------------------- 1 file changed, 79 deletions(-) delete mode 100644 ARCHITECTURE.md diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md deleted file mode 100644 index f7b2eb4..0000000 --- a/ARCHITECTURE.md +++ /dev/null @@ -1,79 +0,0 @@ -# GitHub Party - Architecture Overview - -## How the App Works - -### 🔌 WebSocket = Phone call protocol (real-time communication) -- Enables instant, bidirectional communication between the browser extension and PartyKit server -- No polling or page refreshes needed - everything happens in real-time - -### 🖥️ PartyKit Server (`src/server.ts`) = Does the tracking/user logic -- **Tracks who's connected to each GitHub issue** - - Each GitHub repo/issue gets its own "room" (e.g., `facebook/react-123` for issue #123) - - Maintains a `Map` of connected users per room -- **Broadcasts when users join/leave** - - Sends `user_status` messages when someone connects/disconnects - - Sends `connected_users` messages with the full list of active users -- **Manages the "room" for each issue** - - Rooms are created dynamically based on the GitHub URL - - No pre-configuration needed - rooms spawn automatically - -### 📱 Chrome Extension (`web-extension/content.ts`) = Shows the user avatars -- **Creates the avatar container in bottom-right corner** - - Fixed position overlay with clean styling - - Doesn't interfere with GitHub's UI -- **Displays GitHub profile pictures** - - Fetches avatars from `https://github.com/{username}.png` - - Shows 32x32px circular avatars with hover tooltips -- **Updates the UI when users join/leave** - - Listens for WebSocket messages from the server - - Dynamically adds/removes avatars in real-time - -## 🔄 The Perfect Flow - -1. **User visits a GitHub issue page** -2. **Extension extracts repo/issue info** from the URL -3. **Extension connects to PartyKit room** for that specific issue -4. **Extension sends user info** (GitHub ID and username) to server -5. **Server broadcasts the new connection** to all users in that room -6. **All connected users see the new avatar** appear instantly -7. **When user leaves**, server broadcasts disconnection and avatars disappear - -## 🎨 Division of Responsibilities - -| Component | Responsibility | Emoji | -|-----------|---------------|-------| -| **Server** | "Keep track of who's where" | 🧠 | -| **Extension** | "Show pretty avatars on the page" | 🎨 | -| **WebSocket** | "Make it all happen in real-time" | ⚡ | - - -## What order do things need to be deployed in? -I ask becasue we had a bug where in production the partyhost was wronlgy set to localhost:1999 so I am now setting it on line 10 of my package.json but my cto said it doesn't look like this -resolves to a real dns address. But I was under the impression somehow through the deployment process we were creating our partykit server and then that url would work. i now think thats wrong but i dont know how this process SHOULD work - -**Answer:** - -**Correct deployment sequence:** - -1. **Deploy PartyKit server first**: `npm run deploy` - Creates the server at `https://github-party.partykit.dev` -2. **Build extension with production host**: `npm run build:extension:prod` - Uses the real PartyKit URL (not localhost) -3. **Package and distribute the extension** - -**Key insight:** The PartyKit URL doesn't exist until deployment. The `PARTY_HOST` environment variable in the build script injects the correct URL during extension compilation. - -## How This Should Work - -Your setup is correct: -- `content.ts` uses `process.env.PARTY_HOST!` (environment variable) ✅ -- `esbuild.mjs` injects the env var during build ✅ -- `package.json` sets `PARTY_HOST=https://github-party.partykit.dev` for production builds ✅ - -The localhost:1999 bug happened because the wrong environment was used during build, but your current approach with environment variables prevents hardcoding and handles dev vs production correctly. - -## What's Going Wrong - -If `github-party.partykit.dev` doesn't resolve to a real DNS address, then: - -**Problem:** Either the PartyKit server deployment failed, or the URL `github-party.partykit.dev` is incorrect/not configured properly. - -**Solution:** Check your deployment logs to see if PartyKit deployment succeeded, and verify the actual URL that PartyKit assigned to your project. The URL might be different than expected, or the deployment process might need PartyKit authentication/configuration. \ No newline at end of file From a970f2d46de82e87dd5175ac4039804ab386abbf Mon Sep 17 00:00:00 2001 From: ian Date: Mon, 16 Mar 2026 20:28:43 +0000 Subject: [PATCH 9/9] Rebuild extension zip with correct PartyKit URL Co-Authored-By: Claude Opus 4.6 (1M context) --- github-party-extension-v1.0.1.zip | Bin 20949 -> 20938 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/github-party-extension-v1.0.1.zip b/github-party-extension-v1.0.1.zip index 0807d16efdd6cc6627c28728102d5e39902fc686..a3472b2b96641f2d3c190c8c2bb0ce5b9390da17 100644 GIT binary patch delta 4244 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 YKU0AI%u90PuL04Y_4`llF#5auA2$T@l>h($ delta 4315 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 QZXozOj{eqR*!ArH0LJ+)`~Uy|