Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
2c13c30
docs: spec for one hostname per tenant with optional cloud storage
tieubao Oct 1, 2026
64d206a
docs: fold round 1 spec review into the tenant spec
tieubao Oct 1, 2026
f90fcb5
docs: fold round 2 spec review into the tenant spec
tieubao Oct 1, 2026
1205017
docs: fold round 3 spec review and mark the tenant spec validated
tieubao Oct 1, 2026
c74d127
docs: record the edge spike for the tenant route Worker
tieubao Oct 1, 2026
bcb5b5c
docs: record the account spike and amend the tenant spec
tieubao Oct 1, 2026
3ea7dfe
feat: per-link storage on an origin with R2 on
tieubao Oct 1, 2026
36ad8ab
docs: proof of done for the first tenant batch
tieubao Oct 1, 2026
6df0318
feat: storage dispatch, reconcile, and pointer sweep on an origin
tieubao Oct 1, 2026
b26797d
docs: record the dispatch and reconcile proof for the tenant spec
tieubao Oct 1, 2026
2fcbdb1
feat: tenant Worker v3 in front of the tunnel
tieubao Oct 1, 2026
268e9a9
docs: record the Worker v3 proof for the tenant spec
tieubao Oct 1, 2026
19926b1
feat: setup --r2 and --no-r2 on a tunnel tenant's origin
tieubao Oct 1, 2026
10627f7
docs: record the setup --r2 proof for the tenant spec
tieubao Oct 1, 2026
625c586
docs: correct the route-order control trace
tieubao Oct 1, 2026
fcd24bd
fix: member hits names the origin for a count it cannot see
tieubao Oct 1, 2026
d246452
feat: setup --r2 --alias folds an r2 hostname into a tenant
tieubao Oct 1, 2026
1f9fb4b
feat: one shared list of machine and cloud links per tenant
tieubao Oct 1, 2026
fe7aa4f
feat: decode tenant listing fields in Share Bar snapshots
tieubao Oct 1, 2026
d40ff58
feat: map share rows to type, storage, and link symbols
tieubao Oct 1, 2026
70be38d
feat: menu rows carry glyphs, cloud error, and cloud more
tieubao Oct 1, 2026
477b9bf
feat: render row badges and the cloud links error line
tieubao Oct 1, 2026
fca0d1e
feat: the publish dialog gains a storage popup
tieubao Oct 1, 2026
e6476ae
docs: record the Share Bar tenant rows notes
tieubao Oct 1, 2026
97c2d06
fix(mac): say about N more when cloud counts include orphans
tieubao Oct 1, 2026
72aec7a
test(share): add e2e-tenant.sh for SPEC-008 live legs L1-L10 and R1
tieubao Oct 1, 2026
32a502e
feat: share import and setup --token-stdin for migrate
tieubao Oct 1, 2026
61e0a72
docs: record the batch 3 runs and negative controls
tieubao Oct 1, 2026
f981c30
Merge remote-tracking branch 'origin/feat/tenant-share-bar' into docs…
tieubao Oct 1, 2026
4b0e74e
Merge remote-tracking branch 'origin/test/e2e-tenant' into docs/one-h…
tieubao Oct 1, 2026
51499d4
fix(share): file-back e2e-tenant member tokens and the Keychain stub …
tieubao Oct 1, 2026
f0dc1ac
feat(share): add migrate to move a tenant origin between machines
tieubao Oct 1, 2026
dfdb8e9
docs(share): record TASK-7b migrate in the spec and verification log
tieubao Oct 1, 2026
a045013
fix(share): never hand a migrate target the source's own tunnel
tieubao Oct 1, 2026
6966692
fix(share): detect an aborted test run instead of a clean summary
tieubao Oct 1, 2026
c8a4bd1
fix(share): refuse setup on a not_setup profile holding gated rows
tieubao Oct 1, 2026
018f31d
fix(worker): pass a dead live port's 502 through unchanged
tieubao Oct 1, 2026
b4ff0d7
fix(share): read a missing tunnel_name back by id before migrate
tieubao Oct 1, 2026
1a4e99f
fix(share): drop a stale self_hosted_domains before a shrinking PUT
tieubao Oct 1, 2026
2a0fb65
test(share): fix e2e-tenant.sh script bugs from the live rehearsals
tieubao Oct 1, 2026
1440259
docs(share): record the kit:battery fix pass verification
tieubao Oct 1, 2026
e6b2a13
fix(share): print the alias rollback list when no rows or pointers exist
tieubao Oct 5, 2026
f6a6f41
docs(share): document one host per tenant and check the docs against …
tieubao Oct 5, 2026
743b229
test(share): fix three e2e-tenant.sh legs found by the live R1 rerun
tieubao Oct 5, 2026
dac8541
test(share): fix two more R1 rollback checks in e2e-tenant.sh
tieubao Oct 5, 2026
476f4f8
docs(share): record the live R1 rerun, the new negative controls, and…
tieubao Oct 5, 2026
af40a01
fix(share): clear the three shellcheck findings CI's older shellcheck…
tieubao Oct 5, 2026
1a76f2e
fix(share): refuse unproven tunnel deletes, retry domain adds, verify…
tieubao Oct 5, 2026
c0ebcca
test(share): stub caddy and cloudflared for the migrate rows so CI ca…
tieubao Oct 5, 2026
58e1726
test(share): stub caddy and cloudflared in the migrate remote bin
tieubao Oct 5, 2026
27e481d
test(share): wait for echo-off before the pty test types the token
tieubao Oct 5, 2026
3d8a787
test(share): give the row 29 member join a wait that survives a slow …
tieubao Oct 5, 2026
9ae6350
fix(share): migrate sends the whole pub/<id> tree, not only the share…
tieubao Oct 5, 2026
f37e816
fix(share): do not refuse a migrate target for holding its own ports
tieubao Oct 5, 2026
bab23a4
test(share): add the live rehearsal of the personal move
tieubao Oct 5, 2026
c72ded4
docs(share): name the commit of the second rehearsal fix
tieubao Oct 5, 2026
9079c33
test(share): add a read-only prod snapshot for the go-live
tieubao Oct 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ share profiles # default a
| **Menu bar app** | Share Bar shows what's shared and lets you drag a file onto the icon to publish it |
| **Profiles** | `share --profile work ...` runs a second setup (another account or hostname) beside the first, on its own port and service |
| **Private links** | `--access email:a@x,b@y`, `domain:example.com`, or `group:<rule group>` puts a Cloudflare Access login (one-time PIN) on one link; the other links stay public. See [Private links](#private-links) |
| **One hostname per tenant** | local by default; the admin can turn R2 on at the origin (`setup <host> --r2 --bucket <name>`) and each link picks local or cloud (`add --cloud`). See [One hostname per tenant](#one-hostname-per-tenant) |
| **Links with the machine off** | `setup <host> --backend r2 --bucket <name>`: snapshots live in a private R2 bucket, a Worker serves them, and a whole team publishes to one hostname. See [R2 backend](#r2-backend-links-that-stay-up-while-the-machine-is-off) |

On the default tunnel backend, links are live only while the machine is awake; visitors get Cloudflare 530 when it sleeps. `https://<hostname>/healthz` answers `ok` while share is serving; the site root 404s by design.
Expand Down Expand Up @@ -91,6 +92,9 @@ share stop | start # take all links down / bring them back
share teardown [--yes] # remove tunnel, service, and config; the shares on disk stay
share --profile <name> ... # any command against another setup (or SHARE_PROFILE=<name>); share profiles lists them
share setup <host> --backend r2 --bucket <name> # serve from a private R2 bucket through a Worker (see below)
share setup <host> --r2 --bucket <name> # on a tunnel profile's origin: R2 on, per-link storage (--alias <old-host> folds an old r2 hostname in; --no-r2 rolls back)
share add --cloud|--local <file|dir> # R2 on: this link in the bucket, or on this machine
share migrate --to <ssh-target> # move a tenant's origin (R2 off) to another machine, links kept
```

A share from a private GitHub repo prints a warning; the content is public to anyone with the link.
Expand Down Expand Up @@ -150,6 +154,27 @@ One add holds at most 500 files (`SHARE_R2_MAX_FILES`), each at most 300 MiB. A

`share --profile df teardown` on an r2 profile is local: it forgets this install's token and config, and the bucket, the Worker, and every share stay for the other publishers. `CLOUDFLARE_API_TOKEN=<admin token> share --profile df teardown --yes --purge` deletes every share (gated ones with their Access apps), the Worker, its domain, and the bucket once it is empty, for everyone. Detail: [docs/how-it-works.md](docs/how-it-works.md#r2-backend).

## One hostname per tenant

A tenant is one hostname with one shared list. By default every link is served from the origin machine's disk through its tunnel, exactly as above. The tenant admin can turn R2 on at the origin; after that each link picks local or cloud, and a teammate can publish from another machine.

```sh
CLOUDFLARE_API_TOKEN=<admin token> share setup s.example.com --r2 --bucket share-s # on the origin, once
share add ./report.pdf # the tenant default (local unless --storage-default cloud)
share add --cloud ./report.pdf # in the bucket: answers while the origin is off
share add --local ./notes # on the origin's disk
```

| | R2 off (default) | R2 on |
|---|---|---|
| Hostname | one | the same one; storage is a badge on the row |
| Link while the origin is off | Cloudflare 530 | cloud links serve; machine links answer a 503 offline page |
| Who publishes | the origin | the origin (local or cloud), members (cloud only) |
| Live dev servers, `--host` | yes | yes, on the origin |
| Rollback | none needed | `setup <host> --no-r2` deletes the route; the tunnel serves alone again |

`setup <host> --r2 --bucket <name> --alias <old-host>` folds a former r2 hostname into the tenant: the old name answers 301 to the same path and each gated link keeps its Access app. `share migrate --to <ssh-target>` moves an R2-off tenant to another always-on machine with every link kept, and prints the rollback line if a step fails. Share Bar shows one section per tenant, and each row carries a storage badge, a file-type icon, the link type, and a lock for gated links. Admin steps, tokens, and rollbacks: [docs/setup.md](docs/setup.md#4h-one-hostname-per-tenant-r2-on-the-origin-the-alias-fold-moving-the-origin); the model: [docs/how-it-works.md](docs/how-it-works.md#tenants-one-hostname-local-or-cloud) and [ADR-0008](docs/decisions/ADR-0008-one-host-per-tenant.md).

## Menu bar app

```sh
Expand Down Expand Up @@ -180,7 +205,7 @@ CLI call and action.

## Docs

- [docs/setup.md](docs/setup.md): API token setup (no browser), the R2 backend and teammate onboarding, moving machines, troubleshooting
- [docs/setup.md](docs/setup.md): API token setup (no browser), the R2 backend and teammate onboarding, a tenant's R2 and alias fold, moving machines, troubleshooting
- [docs/how-it-works.md](docs/how-it-works.md): architecture, config keys, security model, the R2 data model and Worker, testing

## License
Expand Down
Loading
Loading