July 07, 2025
Light Mode! at the devlog
finished the file and login page recolorings, unfortunately you can only have one image at a time. there's an awesome pink button on the login page, but you'll have to go to the website to see it ;).
also ran into an issue that i've been having with the appview where it disconnects from jetstream w/ error 1006. I found a github issue talking about it, and the solution was literally just switch to the west coast server. so i did that and it works now lol
sir, a second catppuccin has hit the website
account page done! your pfp also shows up :). this time, the screenshot is in dark mode on a sideways ipad resolution. you might also notice that the toast is correctly themed! this required some createResource trickery + element creation because of the way the toast is made, but it looks pretty good.
new login and upload pages.
spent like 20 minutes trying to make an upload progress bar, but it didn't work out because of the way arraybuffers work with fetch in js. it would load the entire buffer, then make the request, which meant that the progress bar would get to 100% before the request even started lol.
This is a smaller change, but I added a profile button on mobile devices (i.e. small screen). I wasn't aware of the short-circuit syntax for this, which is why it took like half an hour.
You can also see a new upload icon in the top right.
Speaking of uploads, it now tries again if the upload fails the first time due to an incorrect mimetype.
About an hour of this time was spent making a sidebar. This was harder than it might seem because of the way I made the TSX components, but it got done anyways.
The last half hour was spent in a slack huddle asking people to test the site out and updating it based on their changes, along with making notes. There's a simple bug that I'm going to fix in a couple days (I can't right now because I'm at an FRC competition) but it happens because the server doesn't index profiles if it hasn't seen a user make a file before.
Another thing is that the text input box for the username can have hidden characters, which causes issues with handle resolution. Also a pretty simple fix, just some string filtering.
You can now delete files. I imagine this is a pretty important thing to be able to do, especially for those who want to delete their files.
I also fixed a couple of goofy bugs on the server. One was an issue with unpacking JSON into objects and segfaulted whenever you deleted a file. The other one was an issue with not returning all the data (which took forever to debug).
This hour sucked so badly lol. I was trying to figure out why the only thing left on agent() was the session variable. I consulted Claude after two hours of back and forth with docs and it was because makePersisted (I was persisting the agent in local storage) only saved variables, not methods.
Through the fire and the flames, there's now the basics of an account page. The login page is also basically done, but I need to add a create account button at some point (that just goes to bsky).
Right now I'm dealing with the fact that authenticated clients are bound to certain URLs. There's probably a clever way to do it that I haven't found yet, but it needs to be able to rely on https://docs.bsky.app/docs/api/com-atproto-server-get-service-auth.
Spent some time filling in more auth stuff and loading file data! It's really close to working, but the Go package repo is once again my mortal enemy (See image attached - it's always at least 8 hours behind reality).
Tomorrow I'll be able to get the server compatible again once the go package refreshes though! :)
This is a really short devlog, but it's kind of embarrassing how simple the previous issue was. I was setting the file ID in the filekey records to always be zero because the file record itself hadn't been initialized in the DB yet. anyways, it works now!
I also finished up the business logic for the getUriFromSlug lexicon and am now just waiting on the (prohibitively slow) go package repo to update. This will probably take until tomorrow, but at least it doesn't need an account :).
Speaking of package managers, I should probably get around to creating an npm package for the TS generated types (which I also regenerated to include getUriFromSlug).
I've been working on a slug system which generates 6/7 character slugs based on the base58 encoding of the sha256 of some info about the file record. This means that people will be able to actually use it as a file sharing service and not have to type out like 150 characters lol.
I'm running into a db-related issue right now where only one slug is created, even if it gets multiple files from the firehose???
Made the upload UI nicer + now supports dropping files from all around the screen.
I'm probably going to take a short hiatus from this project to work on other things (a few days, maybe up to a week or two) or at the very least work less for a bit. Can't be burning out halfway in :).
Finished the file upload page! Attached picture is firefox's visualization of it on a horizontal iPad. (still haven't finished the file view page though, lol)
Also restructured Index.tsx to use router, so different pages come up.
A new challenge I hadn't thought of is converting DIDs/URIs to shorter slugs. I'm probably going to end up using something on the server side where I hash the did + rkey to get a slug, then add nonces if necessary. This would necessitate a new lexicon, but that's probably a worthy sacrifice to not make the links like 50 characters long.
Speaking of lexicons, I'm probably going to remove the getActorFiles lexicon because it reduces liability (I think?) with various online safety acts going around (cough cough britain).
From here on out, I expect the visuals to come together much faster as I've gotten the hang of tailwindcss more. The actual frontend glue (that necessitates atcute) is going to be annoying, but should also get smoother after the first bit. This might turn out to be a 15-20 hour project to get to first ship!
Started working on the website. I'm using TSX with solidjs and tailwindcss, and have just started creating a basic outline of what it will look like.
The image is Firefox's display of a generic iPad showing the site in its current state, which is entirely placeholder at the moment. I have removed the share button that was in the original design because there isn't much use for it and it would have been more work to add anyways.
Once I finish up the skeleton (list of pages is: home, file, profile, upload), I'm going to use atcute (https://github.com/mary-ext/atcute) to implement atproto/xrpc functionality. I've already generated typescript types from the lexicons using @atcute/lex-cli.
Today I finished up the server and cleaned it up a bunch! Println's have all been replaced by slog (go builtin logger) and getActorFiles is done. The only last change that needs to be made to the server is to update the skywell package, because I accidentally wrote what should've been files
as profiles
🫤. Maybe going to add a ratelimiter to the server in the future? (foreshadowing)
The server is mostly done, just need to finish the getActorFiles endpoint now! Because it uses Go, it's pretty darn quick + small (~24mb of ram usage while consuming from Jetstream). Had to learn GORM (go db manager) to do this, but it was way better than writing SQL by hand. Currently using sqlite, which probably won't change.
Skywell is a file-sharing service built on the AT Protocol (atproto). This means two things: 1. You can log in with your existing Bluesky account. 2. Even if it shuts down, you will still keep your files, as they are tied to your account.
This was widely regarded as a great move by everyone.