Keep using Photos.app like you always do. Attic quietly backs up your originals and edits to an S3 bucket you control. One-way, append-only.
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add top-level error boundary with friendly messages

+78 -1
+78 -1
cli/mod.ts
··· 156 156 } 157 157 }); 158 158 159 - await main.parse(Deno.args); 159 + try { 160 + await main.parse(Deno.args); 161 + } catch (error: unknown) { 162 + handleError(error); 163 + Deno.exit(1); 164 + } 165 + 166 + function handleError(error: unknown): void { 167 + if (!(error instanceof Error)) { 168 + console.error("An unexpected error occurred."); 169 + return; 170 + } 171 + 172 + const msg = error.message; 173 + 174 + // Keychain not found 175 + if ( 176 + msg.includes("find-generic-password") || 177 + msg.includes("SecKeychainSearchCopyNext") 178 + ) { 179 + console.error("Could not read credentials from macOS Keychain."); 180 + console.error('Run "attic init" to set up your credentials.\n'); 181 + return; 182 + } 183 + 184 + // Config missing (thrown by requireConfig) 185 + if (msg.includes("No config file found")) { 186 + console.error(msg); 187 + return; 188 + } 189 + 190 + // Config validation error 191 + if (msg.startsWith("Config:")) { 192 + console.error(msg); 193 + console.error('Run "attic init" to reconfigure, or edit ~/.attic/config.json.\n'); 194 + return; 195 + } 196 + 197 + // S3 access denied 198 + if (msg.includes("AccessDenied") || msg.includes("403")) { 199 + console.error( 200 + "S3 access denied. Check your credentials and bucket permissions.", 201 + ); 202 + console.error('Run "attic init" to update credentials.\n'); 203 + return; 204 + } 205 + 206 + // S3 bucket not found 207 + if (msg.includes("NoSuchBucket")) { 208 + console.error( 209 + "S3 bucket not found. Check the bucket name in ~/.attic/config.json.", 210 + ); 211 + return; 212 + } 213 + 214 + // Network error 215 + if ( 216 + msg.includes("ECONNREFUSED") || msg.includes("ETIMEDOUT") || 217 + msg.includes("fetch failed") 218 + ) { 219 + console.error( 220 + "Could not connect to S3 endpoint. Check your network and endpoint URL in ~/.attic/config.json.", 221 + ); 222 + return; 223 + } 224 + 225 + // Photos.sqlite not found 226 + if (msg.includes("Photos.sqlite") || msg.includes("unable to open database")) { 227 + console.error("Could not open Photos database."); 228 + console.error( 229 + "Make sure Photos is set up on this Mac and the database exists.\n", 230 + ); 231 + return; 232 + } 233 + 234 + // Fallback 235 + console.error(`Error: ${msg}`); 236 + }