BrewBridge is a proof-of-concept data-transfer bridge for TizenBrew. It lets a smart TV app (or any sender) push small JSON payloads to a phone or second screen in real time — with no accounts, no pairing, just a QR code.
A Sender creates an ephemeral session and sends JSON messages over a Cloudflare Worker API. A Viewer scans the QR code and polls for new messages every 2 seconds.
cd worker
npm install
npm run dev # starts wrangler dev on http://localhost:8787cd web
npm install
VITE_API_BASE_URL=http://localhost:8787 npm run devOpen http://localhost:5173/brewbridge/ in your browser.
- Go to
/#/sendto create a session and send messages. - Scan the QR code (or copy the URL) and open
/#/view?s=…&r=…on another device.
-
Install Wrangler and log in:
npm install -g wrangler wrangler login
-
Edit
worker/wrangler.tomland set youraccount_id. -
Deploy:
cd worker npm run deploy -
Note the Worker URL (e.g.
https://brewbridge-worker.<your-subdomain>.workers.dev). -
Set the
ALLOWED_ORIGINSsecret on your Worker to the origin(s) that are allowed to call it. For a GitHub Pages deployment this is your Pages origin:https://<org>.github.ioMultiple origins can be comma-separated. Loopback origins (
http://127.0.0.1,http://localhost) are always allowed automatically so TizenBrew works without any configuration.Note:
ALLOWED_ORIGINSis origin-based (scheme + host + optional port), not path-based. You never need to update this value when bumping the app version or changing which HTML file is served.Set it with Wrangler:
wrangler secret put ALLOWED_ORIGINS # paste: https://<org>.github.io
Set the VITE_API_BASE_URL environment variable before building:
# .env file in /web (do not commit)
VITE_API_BASE_URL=https://brewbridge-worker.<your-subdomain>.workers.devOr pass it inline:
VITE_API_BASE_URL=https://... npm run buildFor GitHub Actions, set it as a repository variable (vars.VITE_API_BASE_URL) in Settings → Secrets and variables → Actions → Variables.
Push to main and the deploy.yml workflow will build the web app and deploy it to GitHub Pages automatically.
Enable GitHub Pages in Settings → Pages → Source: GitHub Actions.
The site will be available at https://<org>.github.io/brewbridge/.
BrewBridge can be installed directly on a Samsung Smart TV running TizenBrew.
The root-level package.json declares BrewBridge as a TizenBrew mods module. In mods mode TizenBrew navigates the TV WebView to websiteURL (the GitHub Pages deployment — index.html?v=<version> for cache busting) and injects the main script. The keys field lists the TVInputDevice key names that the app registers with the TV: ColorF0Red, ColorF1Green, ColorF2Yellow, ColorF3Blue, ChannelUp, and ChannelDown. Yellow toggles the JSON/Human-Readable view (Viewer) or Text/JSON input mode (Sender); Blue scrolls the content back to the top; Channel Up / Channel Down scroll the content pane up or down by one page; Red and Green navigate between app pages.
- On your TV, open TizenBrew and navigate to the Module Manager (3rd icon from the left).
- Select Add Module.
- Enter
axelnanol/brewbridge. - TizenBrew fetches the latest release tag, reads
package.json, and registers the module. - BrewBridge now appears in your TizenBrew dashboard.
The old versioned-HTML scheme (index-0005.html) was meant to bypass jsdelivr's CDN cache by changing the URL on each release. It had a fatal flaw: the TV must first fetch a fresh package.json to discover the new appPath — but package.json itself was also cached by jsdelivr, so the TV never saw the new path and stayed stuck on the old file.
The current approach is simpler and more reliable:
- Every push to
maintriggers CI, which buildsweb/dist/and commits the result. - CI then calls the jsdelivr purge API for both
package.jsonandweb/dist/index.html, forcing the CDN to fetch fresh content from GitHub immediately. - The JS bundle inside
web/dist/is always content-hashed by Vite (e.g.index-BZd8MSNk.js), so the browser never serves a stale script. appPathstays fixed atweb/dist/index.html— no need to update it on every version bump.
TizenBrew fetches files directly from the repository at the release tag, so the built assets in web/dist/ must be committed before the tag is created.
To cut a new release:
- Bump
versioninpackage.json(root), e.g.:"version": "0007"
- Push the change to
main— CI will rebuildweb/dist/and purge the jsdelivr cache automatically. Wait for the workflow to complete (check the Actions tab) before creating the tag. - Create and push a git tag matching the new version:
git pull # fetch the CI commit git tag 0007 git push origin 0007 - Create a GitHub release from that tag. TizenBrew will read
package.jsonand serveweb/dist/index.htmldirectly from the repository at that tag.
- Click Create New Session — a session ID, write key, and read key are generated by the Worker.
- A viewer URL and QR code are displayed. Share them with the receiver.
- Paste any JSON into the text area and click Send JSON, or click Send Test Message to send a pre-built payload.
- Open the URL (or scan the QR code).
- Messages appear automatically as they are sent (polled every 2 seconds).
- Click ⬇ Download Latest JSON to save the most recent message as a
.jsonfile.
brewbridge/
├── package.json TizenBrew module metadata (mods type)
├── web/ Vite + vanilla JS web app
│ ├── src/
│ │ ├── main.js Hash router
│ │ ├── api.js API client
│ │ ├── qr.js QR code helper
│ │ └── pages/
│ │ ├── sender.js
│ │ └── viewer.js
│ ├── index.html
│ └── vite.config.js
├── worker/ Cloudflare Worker + Durable Object
│ ├── src/
│ │ ├── index.js Worker entry + routing
│ │ └── session.js Durable Object (session storage)
│ └── wrangler.toml
└── .github/workflows/
└── deploy.yml GitHub Pages CI/CD