@zykeco/sync-server 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +131 -0
- package/dist/db/schema.d.ts +1009 -0
- package/dist/db/schema.js +80 -1
- package/dist/db/schema.js.map +1 -1
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -1
- package/dist/routes/daily-stress-burden.d.ts +3 -0
- package/dist/routes/daily-stress-burden.js +24 -0
- package/dist/routes/daily-stress-burden.js.map +1 -0
- package/dist/routes/heart-rate-minute.d.ts +3 -0
- package/dist/routes/heart-rate-minute.js +24 -0
- package/dist/routes/heart-rate-minute.js.map +1 -0
- package/dist/routes/hr-zone-history.d.ts +3 -0
- package/dist/routes/hr-zone-history.js +24 -0
- package/dist/routes/hr-zone-history.js.map +1 -0
- package/dist/routes/user-profile.d.ts +3 -0
- package/dist/routes/user-profile.js +24 -0
- package/dist/routes/user-profile.js.map +1 -0
- package/dist/routes/user-timezones.d.ts +3 -0
- package/dist/routes/user-timezones.js +24 -0
- package/dist/routes/user-timezones.js.map +1 -0
- package/dist/routes/wipe.d.ts +6 -1
- package/dist/routes/wipe.js +16 -2
- package/dist/routes/wipe.js.map +1 -1
- package/dist/stores/daily-stress-burden.d.ts +3 -0
- package/dist/stores/daily-stress-burden.js +58 -0
- package/dist/stores/daily-stress-burden.js.map +1 -0
- package/dist/stores/heart-rate-minute.d.ts +3 -0
- package/dist/stores/heart-rate-minute.js +48 -0
- package/dist/stores/heart-rate-minute.js.map +1 -0
- package/dist/stores/hr-zone-history.d.ts +3 -0
- package/dist/stores/hr-zone-history.js +49 -0
- package/dist/stores/hr-zone-history.js.map +1 -0
- package/dist/stores/user-profile.d.ts +3 -0
- package/dist/stores/user-profile.js +76 -0
- package/dist/stores/user-profile.js.map +1 -0
- package/dist/stores/user-timezones.d.ts +3 -0
- package/dist/stores/user-timezones.js +43 -0
- package/dist/stores/user-timezones.js.map +1 -0
- package/drizzle/0001_sweet_firebird.sql +78 -0
- package/drizzle/meta/0001_snapshot.json +733 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +3 -3
package/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# @zykeco/sync-server
|
|
2
|
+
|
|
3
|
+
Self-hosted sync server for the Zyke mobile app. A small [Hono](https://hono.dev) HTTP service backed by [libsql](https://github.com/tursodatabase/libsql) and [Drizzle ORM](https://orm.drizzle.team), validated end-to-end with [TypeBox](https://github.com/sinclairzx81/typebox) schemas from [`@zykeco/sync-protocol`](https://www.npmjs.com/package/@zykeco/sync-protocol).
|
|
4
|
+
|
|
5
|
+
- **Single-tenant, secret-gated.** One server per deployment; two bearer secrets (`READ_SECRET`, `WRITE_SECRET`).
|
|
6
|
+
- **Writes + hard-deletes only.** No read API surface — the mobile client is the source of truth, the server is a durable buffer for backup/restore.
|
|
7
|
+
- **Schemaless `sleep_sessions`.** Domain fields live inside a JSON `payload`, so the mobile app evolves the shape without a server release.
|
|
8
|
+
- **Three CLI bins.** `zyke-sync-startup`, `zyke-sync-upgrade`, and `zyke-sync-migrate` cover first-run setup, version bumps, and ad-hoc migrations.
|
|
9
|
+
|
|
10
|
+
Requires **Node ≥ 24** and **npm ≥ 11**.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @zykeco/sync-server
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
For a deployment-ready starter that already wires up `startup` / `start` / `upgrade`, see the [`@zykeco/sync-self-host`](https://github.com/zykeco/sync/tree/main/apps/self-host) template — copy it onto your server and you're done.
|
|
19
|
+
|
|
20
|
+
## Quick start (manual)
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# 1. Create a project directory with @zykeco/sync-server installed.
|
|
24
|
+
mkdir my-sync && cd my-sync
|
|
25
|
+
npm init -y && npm pkg set type=module
|
|
26
|
+
npm install @zykeco/sync-server
|
|
27
|
+
|
|
28
|
+
# 2. Generate .env (READ_SECRET / WRITE_SECRET) and run migrations.
|
|
29
|
+
npx zyke-sync-startup
|
|
30
|
+
|
|
31
|
+
# 3. Create index.js with one line, then start.
|
|
32
|
+
echo "import '@zykeco/sync-server';" > index.js
|
|
33
|
+
node index.js
|
|
34
|
+
# → zyke-sync listening on http://localhost:3000
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Bins
|
|
38
|
+
|
|
39
|
+
| Command | Purpose |
|
|
40
|
+
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
41
|
+
| `zyke-sync-startup` | First-run setup. Runs `npm install`, generates/updates `.env` with crypto-random `READ_SECRET` and `WRITE_SECRET` (mode `0600`), creates the libsql data dir, then runs migrations. Idempotent. |
|
|
42
|
+
| `zyke-sync-upgrade` | Upgrades the package and migrates. `zyke-sync-upgrade --to 0.5.0` for a specific version; no arg defaults to `latest`. |
|
|
43
|
+
| `zyke-sync-migrate` | Applies all pending Drizzle migrations against `DATABASE_URL`. Run by `startup` / `upgrade`; useful on its own for ad-hoc migrations. |
|
|
44
|
+
|
|
45
|
+
## Environment
|
|
46
|
+
|
|
47
|
+
The server reads these via `process.env` (and `.env` if present):
|
|
48
|
+
|
|
49
|
+
| Var | Default | Purpose |
|
|
50
|
+
| -------------- | --------------------- | -------------------------------------------------------------------------------- |
|
|
51
|
+
| `PORT` | `3000` | HTTP listen port. |
|
|
52
|
+
| `DATABASE_URL` | `file:./data/sync.db` | libsql connection string. Accepts local SQLite (`file:`) or remote libsql/Turso. |
|
|
53
|
+
| `READ_SECRET` | _required_ | Bearer token for read endpoints (currently unused — reads are not exposed). |
|
|
54
|
+
| `WRITE_SECRET` | _required_ | Bearer token for write + delete + wipe endpoints. |
|
|
55
|
+
|
|
56
|
+
`zyke-sync-startup` generates 32-byte hex values for both secrets if they're missing, writes the file with mode `0600`, and leaves existing values alone on subsequent runs.
|
|
57
|
+
|
|
58
|
+
## HTTP API
|
|
59
|
+
|
|
60
|
+
All write endpoints take `Authorization: Bearer ${WRITE_SECRET}` and respond with JSON.
|
|
61
|
+
|
|
62
|
+
### Health
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
GET /v1/health → { ok: true }
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Per-namespace batch upsert
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
POST /v1/sync/daily-metrics/batch
|
|
72
|
+
POST /v1/sync/weekly-metrics/batch
|
|
73
|
+
POST /v1/sync/sleep-sessions/batch
|
|
74
|
+
|
|
75
|
+
body: { rows: [...] } // max 500 daily/weekly, 200 sleep
|
|
76
|
+
reply: { stored: number[], serverNowMs: number }
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Upserts by `id` (client-generated integer PK) with a **last-write-wins** guard on `updatedAt` — older writes are silently ignored.
|
|
80
|
+
|
|
81
|
+
### Per-namespace hard-delete
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
POST /v1/sync/daily-metrics/delete
|
|
85
|
+
POST /v1/sync/weekly-metrics/delete
|
|
86
|
+
POST /v1/sync/sleep-sessions/delete
|
|
87
|
+
|
|
88
|
+
body: { ids: number[] } // max 200
|
|
89
|
+
reply: { deleted: number[], serverNowMs: number }
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Missing ids are silent successes — safe to retry.
|
|
93
|
+
|
|
94
|
+
### Wipe everything (destructive)
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
POST /v1/sync/wipe
|
|
98
|
+
|
|
99
|
+
body: { confirm: "wipe-all-data" }
|
|
100
|
+
reply: { wiped: { dailyMetrics, weeklyMetrics, sleepSessions: number }, serverNowMs }
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Deletes every row across the three sync namespaces (blobs untouched). The literal `confirm` string is enforced at the protocol layer.
|
|
104
|
+
|
|
105
|
+
## Data model
|
|
106
|
+
|
|
107
|
+
- **`daily_metrics`**, **`weekly_metrics`** — `{ id (PK), isoDate / weekStartIsoDate, metricKey, value, createdAt, updatedAt }`. Composite unique on `(date, metricKey)`.
|
|
108
|
+
- **`sleep_sessions`** — schemaless envelope: `{ id (PK), isoDate, updatedAt, payloadVersion, payload (JSON) }`.
|
|
109
|
+
|
|
110
|
+
All timestamps are epoch milliseconds. `id`s are client-generated integers (no autoincrement on the server).
|
|
111
|
+
|
|
112
|
+
## Programmatic use
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
import '@zykeco/sync-server'; // auto-starts on import using process.env
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
There is no module API to embed the server in another process — the package is import-to-run by design.
|
|
119
|
+
|
|
120
|
+
## Compatibility
|
|
121
|
+
|
|
122
|
+
| Runtime | Status |
|
|
123
|
+
| ---------- | -------------------------- |
|
|
124
|
+
| Node ≥ 24 | ✅ |
|
|
125
|
+
| Bun / Deno | ❌ (libsql native binding) |
|
|
126
|
+
|
|
127
|
+
For embedded/edge runtimes, point a stock Node deployment at a remote libsql (Turso) URL.
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
AGPL-3.0-or-later — see [LICENSE](./LICENSE).
|