Social Annotations in the Atmosphere
1{
2 description = "seams.so - atproto web annotation extension";
3
4 inputs = {
5 nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
6 flake-utils.url = "github:numtide/flake-utils";
7 };
8
9 outputs =
10 {
11 self,
12 nixpkgs,
13 flake-utils,
14 }:
15 flake-utils.lib.eachDefaultSystem (
16 system:
17 let
18 pkgs = nixpkgs.legacyPackages.${system};
19
20 # Path to proxy dist (must be built before nix build)
21 # Requires --impure flag since dist/ is gitignored
22 # Run: pnpm build:proxy && nix build .#proxy --impure
23 proxyDistPath = builtins.getEnv "PROXY_DIST";
24 proxyDist =
25 if proxyDistPath != "" then
26 /. + proxyDistPath
27 else
28 builtins.throw "PROXY_DIST env var required. Run: PROXY_DIST=$PWD/proxy/dist nix build .#proxy --impure";
29
30 # Build Go backend server
31 server = pkgs.buildGoModule {
32 pname = "seams-server";
33 version = "0.1.0";
34 src = ./server;
35
36 vendorHash = null;
37
38 subPackages = [ "cmd/server" ];
39
40 nativeBuildInputs = [ pkgs.gcc ];
41 };
42
43 in
44 {
45 packages = {
46 # Docker image containing Go backend + static landing page
47 docker = pkgs.dockerTools.buildImage {
48 name = "seams-server";
49 tag = "latest";
50
51 copyToRoot = pkgs.buildEnv {
52 name = "image-root";
53 paths = [
54 pkgs.coreutils
55 pkgs.bash
56 pkgs.cacert # Required for HTTPS certificate verification
57 server
58 (pkgs.runCommand "static-files" { } ''
59 mkdir -p $out/app/public
60 cp -r ${./landing}/* $out/app/public/
61 '')
62 (pkgs.writeScriptBin "start-server.sh" ''
63 #!${pkgs.bash}/bin/bash
64 set -e
65
66 # Create db directory for SQLite (if not already mounted)
67 ${pkgs.coreutils}/bin/mkdir -p /app/db
68
69 # Start the Go server (serves both API and static files)
70 exec ${server}/bin/server
71 '')
72 ];
73 pathsToLink = [
74 "/bin"
75 "/app"
76 ];
77 };
78
79 config = {
80 Cmd = [ "start-server.sh" ];
81 ExposedPorts = {
82 "8080/tcp" = { };
83 };
84 WorkingDir = "/app";
85 Env = [
86 "PORT=8080"
87 "DB_PATH=/app/db/annotations.db"
88 "PUBLIC_DIR=/app/public"
89 "SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
90 ];
91 };
92 };
93
94 # Docker image for Proxy (wabac.js-based)
95 # Simple setup matching dev: serve for static files + Node.js CORS proxy
96 proxy = pkgs.dockerTools.buildImage {
97 name = "seams-proxy";
98 tag = "latest";
99
100 copyToRoot = pkgs.buildEnv {
101 name = "image-root";
102 paths = [
103 pkgs.coreutils
104 pkgs.bash
105 pkgs.nodejs_22
106 pkgs.cacert
107
108 # Create /usr/bin/env symlink (required for npx/tsx shebangs)
109 (pkgs.runCommand "usr-bin-env" { } ''
110 mkdir -p $out/usr/bin
111 ln -s ${pkgs.coreutils}/bin/env $out/usr/bin/env
112 '')
113
114 # Static files and CORS proxy source
115 (pkgs.runCommand "proxy-files" { } ''
116 mkdir -p $out/app/dist
117 mkdir -p $out/app/cors-proxy
118
119 # Copy built static files
120 cp -r ${proxyDist}/* $out/app/dist/
121
122 # Copy CORS proxy source
123 cp -r ${./proxy/cors-proxy}/* $out/app/cors-proxy/
124 '')
125
126 # Startup script - mirrors dev setup exactly
127 (pkgs.writeScriptBin "start-proxy.sh" ''
128 #!${pkgs.bash}/bin/bash
129 set -e
130
131 echo "Starting Seams Proxy..."
132
133 # Ensure HOME exists for npm
134 ${pkgs.coreutils}/bin/mkdir -p /root
135
136 # Install CORS proxy dependencies
137 cd /app/cors-proxy
138 echo "Installing CORS proxy dependencies..."
139 ${pkgs.nodejs_22}/bin/npm install 2>/dev/null || ${pkgs.nodejs_22}/bin/npm install
140
141 # Start static file server on port 8081, bind to 0.0.0.0 for Docker
142 # Note: Don't use -s (SPA mode) - it redirects .html to clean URLs which breaks OAuth callback
143 cd /app/dist
144 echo "Starting static server on 0.0.0.0:8081..."
145 ${pkgs.nodejs_22}/bin/npx serve -l tcp://0.0.0.0:8081 . &
146
147 # Start CORS proxy on port 8082 (same as dev)
148 cd /app/cors-proxy
149 echo "Starting CORS proxy on :8082..."
150 PORT=8082 CORS_ALLOWED_ORIGINS="$CORS_ALLOWED_ORIGINS" ${pkgs.nodejs_22}/bin/npx tsx index.ts
151 '')
152 ];
153 pathsToLink = [
154 "/bin"
155 "/app"
156 "/usr"
157 ];
158 };
159
160 config = {
161 Cmd = [ "start-proxy.sh" ];
162 ExposedPorts = {
163 "8081/tcp" = { };
164 "8082/tcp" = { };
165 };
166 WorkingDir = "/app";
167 Env = [
168 "PATH=/bin"
169 "SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
170 "HOME=/root"
171 # Default CORS origins - override with CORS_ALLOWED_ORIGINS env var
172 "CORS_ALLOWED_ORIGINS=https://sure.seams.so/"
173 ];
174 };
175 };
176 };
177
178 devShells = {
179 # Default: Full development environment (Extension + Server)
180 default = pkgs.mkShell {
181 buildInputs =
182 with pkgs;
183 [
184 bun
185 nodejs_22
186 pnpm
187 typescript
188 git
189 curl
190 jq
191 go
192 sqlite
193 gcc
194 air
195 dnscontrol
196 ]
197 ++ (if pkgs.stdenv.isLinux then [ chromium ] else [ ]);
198
199 shellHook = ''
200 export PATH="$PWD/node_modules/.bin:$PATH"
201 export API_PORT=''${API_PORT:-3000}
202
203 echo "Full development environment (Extension + Server)"
204 echo ""
205 echo "Extension: pnpm dev, pnpm build, pnpm zip"
206 echo "Server: cd server && air"
207 '';
208 };
209
210 # Extension-only development shell
211 extension = pkgs.mkShell {
212 buildInputs =
213 with pkgs;
214 [
215 bun
216 nodejs_22
217 pnpm
218 typescript
219 git
220 curl
221 jq
222 ]
223 ++ (if pkgs.stdenv.isLinux then [ chromium ] else [ ]);
224
225 shellHook = ''
226 export PATH="$PWD/node_modules/.bin:$PATH"
227 export API_PORT=''${API_PORT:-3000}
228
229 echo "Extension development environment"
230 echo "Commands:"
231 echo " pnpm dev - Extension development server"
232 echo " pnpm build - Build extension"
233 '';
234 };
235
236 # Go backend development shell
237 server = pkgs.mkShell {
238 buildInputs = with pkgs; [
239 go
240 sqlite
241 gcc
242 air
243 ];
244
245 shellHook = ''
246 echo "Go backend development environment"
247 echo "Go version: $(go version)"
248 echo ""
249 echo "Commands:"
250 echo " cd server && air - Start server with hot reload"
251 echo " cd server && go run cmd/server/main.go - Start server"
252 echo " cd server && go test ./... - Run tests"
253 echo " cd server && go mod tidy - Update dependencies"
254 '';
255 };
256 };
257 }
258 );
259}