···22#+AUTHOR: Jonathan Raphaelson
33#+EMAIL: jon@accidental.cc
4455-An offline first RSS & Podcast PWA Application
55+an offline-first RSS & podcast PWA application
6677-* What is Skypod?
77+* what is skypod?
8899- rss/podcast subscription management
1010- offline first; cache audio locally, and p2p sync between devices
1111-- podcast playback with nice features; skip silence, volume correction, etc.
1111+- podcast playback with nice features; skip silence, volume
1212+ correction, etc.
1213- fun to hack on
13141414-* How does it work?
1515+* how does it work?
15161616-- PWA stores and displays cached feeds, subscription, and listening history data locally
1717-- Feed proxy server provides a nice API for fetching feeds and extracting metadata
1818-- WebSocket signaling server for WebRTC peering, devices sync cached data and play state
1717+- PWA stores and displays cached feeds, subscription, and listening
1818+ history data locally in IndexedDB
1919+- WebSocket signaling server for WebRTC peering, devices sync cached
2020+ data and play state using a hybrid logical clock for causal ordering
2121+- feed proxy server provides a nice API for fetching feeds and
2222+ extracting metadata
19232020-* Development
2424+* getting started with devenv
21252222-Run the pwa+server with:
2626+this project uses [[https://devenv.sh][devenv.sh]] for reproducible development environments.
2727+2828+if you have devenv installed:
2929+3030+#+BEGIN_SRC bash
3131+ $ devenv shell
3232+ $ npm install
3333+ $ npm run dev
3434+#+END_SRC
3535+3636+if you don't have devenv, you can install it from [[https://devenv.sh][devenv.sh]] or just
3737+use node v24+ directly.
3838+3939+* development
4040+4141+run the pwa+server with:
23422443#+BEGIN_SRC bash
2544 $ npm install
2645 $ npm run dev # lots of stuff concurrently with wireit
2746#+END_SRC
28472929-- Common
3030- - ES2024 Javascript, running on in modern browsers or [[https://nodejs.org][Node v24]]
3131- - [[https://github.com/panva/jose][~jose~]] for cross-platform webcrypto and JWT management
3232- - [[https://zod.dev/][Zod v4]] describes schema and builds transformation pipelines
3333-- Backend
3434- - [[https://expressjs.com/][Express]] and Node's ~stdlib~ for HTTP and WebSocket servers
3535-- Frontend
3636- - [[https://vite.dev/][Vite]] does FE builds
3737- - [[https://preactjs.com/][Preact]] + [[https://zustand.docs.pmnd.rs][Zustand]] for UI
3838-- Build & DX
3939- - [[https://github.com/google/wireit][Wireit]] does script dependencies and services
4040- - [[https://jsdoc.app/][JSDoc]], along with [[https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html][Typescript's JSDoc support]] does typechecking
4141- - [[https://eslint.org][ESLint]] and a plethora of plugins keeps the code nice
4848+this starts:
4949+- vite dev server at ~http://127.0.0.1:4000~ (frontend)
5050+- backend server at ~http://127.0.0.1:4001~ (WebSocket + API)
5151+- live type-checking and linting in watch mode
5252+5353+** technology stack
42544343-Still thinking about:
5555+*** common
5656+- typescript with strict mode
5757+- [[https://github.com/panva/jose][~jose~]] for cross-platform webcrypto and JWT management
5858+- [[https://zod.dev/][Zod]] describes schema and builds transformation pipelines
44594545-- [[https://dexie.org/][Dexie]] for browser storage and enabling syncing
4646-- per-realm SQLite databases with node's native sqlite support
4747-- docker compose for deployment with self-hosted realm storage
6060+*** backend
6161+- [[https://expressjs.com/][Express]] for HTTP and WebSocket servers
6262+- [[https://github.com/Level/level][Level]] for persistent realm kv storage
48634949-See [[./readme-devlog.org]] for design and architecture thoughts.
6464+*** frontend
6565+- [[https://vite.dev/][Vite]] for builds
6666+- [[https://preactjs.com/][Preact]] for UI
6767+- [[https://dexie.org/][Dexie]] for IndexedDB storage
6868+- [[https://github.com/feross/simple-peer][simple-peer]] for WebRTC
50695151-** Scripts
7070+*** build & dx
7171+- typescript for type-checking
7272+- [[https://github.com/google/wireit][Wireit]] does script dependencies and services
7373+- [[https://eslint.org][ESLint]] and prettier keep the code nice
52745353-All scripts can have ~--watch~ passed as an argument to have ~wireit~ rerun when inputs change.
5454-This is not useful for everything.
7575+** scripts
55765677- ~npm run dev~ :: alias for ~npm run start:dev~
5778- ~npm run lint~ :: runs ~eslint~
5879- ~npm run types~ :: runs ~tsc~ (no emitting, just typechecking)
5959-- ~npm run docs~ :: runs ~jsdoc~ to generate docs in ~./docs~
8080+- ~npm run build~ :: build production frontend
6081- ~npm run test~ :: runs ~jest~ as a one-off
6161-- ~npm run start:dev~ :: runs BE/FE, tests in watch mode, and typecheck/linting
8282+- ~npm run start:tests~ :: runs ~jest~ in watch mode
8383+- ~npm run start:dev~ :: runs BE/FE with live type-checking and linting
6284- ~npm run start:prod~ :: builds and runs everything in production mode
63856464-* Contributing
8686+** running tests
8787+8888+There's not much here yet, I want to figure it out first.
8989+9090+#+BEGIN_SRC bash
9191+ $ npm run test # run all tests once
9292+ $ npm run start:tests # run tests in watch mode
9393+#+END_SRC
9494+9595+to run a single test file:
9696+9797+#+BEGIN_SRC bash
9898+ $ npx jest src/path/to/file.spec.ts
9999+#+END_SRC
100100+101101+** git hooks
102102+103103+pre-commit hook runs type-checking and linting automatically. enable with:
104104+105105+#+BEGIN_SRC bash
106106+ $ git config core.hooksPath .githooks
107107+#+END_SRC
108108+109109+* architecture
110110+111111+the codebase is organized into modules with path aliases:
112112+113113+- ~#client/*~ (~src/client/~) - preact frontend application
114114+- ~#server/*~ (~src/server/~) - node.js express backend
115115+- ~#common/*~ (~src/common/~) - shared code (protocol, crypto, utilities)
116116+- ~#realm/*~ (~src/realm/~) - p2p connection and sync protocol
117117+- ~#skypod/*~ (~src/skypod/~) - domain-specific schemas and actions
118118+119119+** key architectural components
120120+121121+*** p2p synchronization
122122+123123+uses a hybrid logical clock (HLC) for causal ordering of events across
124124+distributed peers. clients PULL complete action history when catching
125125+up, and PUSH tailored updates to each peer based on knowledge vectors.
126126+127127+*** offline-first
128128+129129+all user data lives in IndexedDB via dexie. the server is stateless
130130+regarding user data (only maintains ephemeral realm/peer state).
131131+132132+*** webrtc for p2p
133133+134134+peers communicate directly via WebRTC data channels. the WebSocket
135135+connection to the server is only used for signaling and as a fallback
136136+broadcast mechanism.
137137+138138+*** realm system
139139+140140+a realm is a collection of verified identities that can communicate
141141+securely. realms are not publicly routable; access requires the realm
142142+id and an invitation from an existing member.
143143+144144+see [[./docs/readme-brainstorm.org]] for detailed architecture thoughts
145145+and connection flow diagrams.
651466666-- run ~git config core.hooksPath .githooks~ to install pre-commit hooks for lint/fmt
6767-- not really open to contributions right now, come back later.
147147+* contributing
681486969-* License & Copyright
149149+- run ~git config core.hooksPath .githooks~ to install pre-commit
150150+ hooks for lint/fmt
151151+- honestly, not really open to contributions right now, come back
152152+ later.
701537171-Copyright (C) 2025 Jonathan Raphaelson
154154+* license & copyright
721557373-This program is free software: you can redistribute it and/or modify it under the terms of
7474-the **Affero General Public License verson 3 or later** (AGPLv3+).
156156+copyright (C) 2025 jonathan raphaelson
751577676-Please see [[./readme-license.txt]] for a copy of the full license.
158158+this program is free software: you can redistribute it and/or modify
159159+it under the terms of the **affero general public license version 3 or
160160+later** (AGPLv3+).
161161+162162+see [[./readme-license.txt]] for a copy of the full license.