4 KiB
Release
@mac-sync ships three artefacts: the Mac client, the server, and the web
SPA. They are deployed independently.
Version source
VERSION.json at the repo root is the canonical version. app.manifest.yaml:5
duplicates it for the manage-apps CLI. Bump both together.
Mac client — MacSyncApp
Build (release):
make build-release # Makefile:63-65 -> swift build -c release --product MacSyncApp
Output: .build/release/MacSyncApp. The binary is a menu-bar executable; for
distribution wrap it as a .app bundle including:
- The binary itself
- A
webapp/resource directory built fromweb/dist/(LocalWebServer.swift:138-141looks here first) - Info.plist with
LSUIElement=true(menu-bar only) - Privacy usage strings:
NSCalendarsFullAccessUsageDescription,NSRemindersFullAccessUsageDescription,NSAppleEventsUsageDescription,NSPhotoLibraryUsageDescription, plus Full Disk Access via signed entitlement
The user instals through deploy/install.sh and a LaunchAgent
(app.manifest.yaml:20-22):
ssh plum 'bash -s' < deploy/install.sh
Or via the manage-apps CLI (app.manifest.yaml:24-30):
manage-apps start mac-sync plum # runs deploy/deploy-remote.sh
manage-apps stop mac-sync plum # launchctl unload
manage-apps status mac-sync # ssh plum 'pgrep -x MacSyncApp'
manage-apps logs mac-sync # tail of ~/Library/Application Support/MacSync/stderr.log
Server — mac-sync-server
Build is implicit (Bun runs TypeScript directly). The systemd unit lives in
deploy/systemd/ and is referenced by app.manifest.yaml:42-44.
manage-apps start mac-sync black # deploy/deploy-server.sh
manage-apps status mac-sync black # curl http://localhost:3201/health
manage-apps logs mac-sync black # journalctl -u mac-sync-server
manage-apps stop mac-sync black # sudo systemctl stop mac-sync-server
Migrations apply automatically on boot
(src/server/src/app/server.ts:36-52). To verify a fresh deploy:
curl http://10.0.0.11:3201/health/deep
# {"ok":true,"checks":{"db":"ok"}}
Environment is loaded by loadConfig() (src/server/src/app/config.ts);
required vars are documented in dev-setup.
Web SPA
Two distribution paths:
-
Bundled with the Mac client. Run
cd web && bun run buildbeforemake build-release; copyweb/dist/into the.appbundle'swebapp/resource directory. Served athttp://localhost:8765/byLocalWebServer(@packages/shared/Sources/MacSyncShared/WebServer/LocalWebServer.swift:94-109). -
Hosted by the server. The nginx config in
deploy/nginx/(referenced from the deploy scripts) can serveweb/dist/from the same origin as the API.
cd web
bun install
bun run build # tsc --noEmit && vite build (web/package.json:8)
Output goes to web/dist/. Verify with bun run preview.
Rollback
- Mac client: previous
.appbundle is preserved alongside the new one onplum; relaunch vialaunchctl load. - Server:
sudo systemctl restart mac-sync-serverafter reverting the source tree. Migrations are forward-only — see Caveats below. - Web: redeploy the previous
web/dist/. The bundle is fingerprinted by Vite, so cache invalidation is automatic.
Caveats
- Migrations are forward-only.
runMigrations(db, [...])(src/server/src/app/server.ts:36-52) appends; there is nodownscript. A schema-breaking change requires manual SQL on the database. - iMessage
icloud.send_queueis on a bespoke schema. Versioning it is independent of the generic per-module tables. Don't drop and recreate it on a release — outgoing messages will be lost. - The Mac client retains
UserDefaultswatermarks across releases. If a release changes the inbound payload shape, bumpSyncManager.syncSchemaVersion(@packages/imessage/Sources/IMessageSync/SyncManager.swift:47for iMessage) so the bootstrap resets the watermark. - Don't commit from a release script. External tooling owns commits
(
CLAUDE.md:46).