@zykeco/sync-server 0.8.0 → 0.9.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 +35 -17
- package/dist/app.js +10 -0
- package/dist/app.js.map +1 -1
- package/dist/db/schema.d.ts +693 -0
- package/dist/db/schema.js +49 -0
- package/dist/db/schema.js.map +1 -1
- package/dist/env.d.ts +10 -0
- package/dist/env.js +45 -6
- package/dist/env.js.map +1 -1
- package/dist/mcp/oauth.d.ts +48 -0
- package/dist/mcp/oauth.js +118 -1
- package/dist/mcp/oauth.js.map +1 -1
- package/dist/routes/activities.d.ts +3 -0
- package/dist/routes/activities.js +24 -0
- package/dist/routes/activities.js.map +1 -0
- package/dist/routes/activity-heart-rate.d.ts +3 -0
- package/dist/routes/activity-heart-rate.js +24 -0
- package/dist/routes/activity-heart-rate.js.map +1 -0
- package/dist/routes/mcp.js +44 -18
- package/dist/routes/mcp.js.map +1 -1
- package/dist/routes/wipe.d.ts +3 -1
- package/dist/routes/wipe.js +5 -1
- package/dist/routes/wipe.js.map +1 -1
- package/dist/stores/activities.d.ts +3 -0
- package/dist/stores/activities.js +102 -0
- package/dist/stores/activities.js.map +1 -0
- package/dist/stores/activity-heart-rate.d.ts +3 -0
- package/dist/stores/activity-heart-rate.js +29 -0
- package/dist/stores/activity-heart-rate.js.map +1 -0
- package/drizzle/0003_real_kate_bishop.sql +49 -0
- package/drizzle/meta/0003_snapshot.json +1065 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +3 -3
package/dist/db/schema.js
CHANGED
|
@@ -115,4 +115,53 @@ export const hrZoneHistory = sqliteTable('hr_zone_history', {
|
|
|
115
115
|
}, (t) => ({
|
|
116
116
|
uniqueEffective: uniqueIndex('hrzh_unique_effective_idx').on(t.effectiveFromIsoDate),
|
|
117
117
|
}));
|
|
118
|
+
export const activities = sqliteTable('activities', {
|
|
119
|
+
id: integer('id').primaryKey({ autoIncrement: false }),
|
|
120
|
+
type: text('type'),
|
|
121
|
+
source: text('source').notNull(),
|
|
122
|
+
startedAtUtc: integer('started_at_utc').notNull(),
|
|
123
|
+
endedAtUtc: integer('ended_at_utc').notNull(),
|
|
124
|
+
title: text('title'),
|
|
125
|
+
notes: text('notes'),
|
|
126
|
+
sRpe: integer('s_rpe'),
|
|
127
|
+
feelingBefore: integer('feeling_before'),
|
|
128
|
+
feelingAfter: integer('feeling_after'),
|
|
129
|
+
deviceId: text('device_id'),
|
|
130
|
+
indoorOutdoor: text('indoor_outdoor'),
|
|
131
|
+
avgBpm: real('avg_bpm'),
|
|
132
|
+
maxBpm: real('max_bpm'),
|
|
133
|
+
minBpm: real('min_bpm'),
|
|
134
|
+
hrSampleCount: integer('hr_sample_count'),
|
|
135
|
+
trimp: real('trimp'),
|
|
136
|
+
cardioLoad: real('cardio_load'),
|
|
137
|
+
movementLoad: real('movement_load'),
|
|
138
|
+
loadScore: real('load_score'),
|
|
139
|
+
hrSpikes: integer('hr_spikes'),
|
|
140
|
+
calories: real('calories'),
|
|
141
|
+
hrZoneDistribution: text('hr_zone_distribution'),
|
|
142
|
+
accelEnergyTotal: real('accel_energy_total'),
|
|
143
|
+
recoveryHrBpm: real('recovery_hr_bpm'),
|
|
144
|
+
distanceMeters: real('distance_meters'),
|
|
145
|
+
avgPaceSecPerKm: real('avg_pace_sec_per_km'),
|
|
146
|
+
elevationGainMeters: real('elevation_gain_meters'),
|
|
147
|
+
weatherTempCelsius: real('weather_temp_celsius'),
|
|
148
|
+
weatherHumidityPct: real('weather_humidity_pct'),
|
|
149
|
+
weatherCondition: text('weather_condition'),
|
|
150
|
+
weatherWindSpeedMs: real('weather_wind_speed_ms'),
|
|
151
|
+
isDeleted: integer('is_deleted').notNull().default(0),
|
|
152
|
+
createdAt: integer('created_at').notNull(),
|
|
153
|
+
updatedAt: integer('updated_at').notNull(),
|
|
154
|
+
}, (t) => ({
|
|
155
|
+
updatedIdx: index('act_updated_idx').on(t.updatedAt),
|
|
156
|
+
isDeletedIdx: index('act_is_deleted_idx').on(t.isDeleted),
|
|
157
|
+
}));
|
|
158
|
+
export const activityHeartRate = sqliteTable('activity_heart_rate', {
|
|
159
|
+
id: integer('id').primaryKey({ autoIncrement: false }),
|
|
160
|
+
activityId: integer('activity_id').notNull(),
|
|
161
|
+
offsetMs: integer('offset_ms').notNull(),
|
|
162
|
+
bpm: real('bpm').notNull(),
|
|
163
|
+
}, (t) => ({
|
|
164
|
+
activityIdx: index('ahr_activity_idx').on(t.activityId),
|
|
165
|
+
uniqueActivityOffset: uniqueIndex('ahr_unique_activity_offset_idx').on(t.activityId, t.offsetMs),
|
|
166
|
+
}));
|
|
118
167
|
//# sourceMappingURL=schema.js.map
|
package/dist/db/schema.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"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"}
|
package/dist/env.d.ts
CHANGED
|
@@ -18,5 +18,15 @@ export interface McpEnv {
|
|
|
18
18
|
clientId: string;
|
|
19
19
|
tokenSecret: string;
|
|
20
20
|
tokenTtlSeconds: number;
|
|
21
|
+
/** Whether to issue refresh tokens on the authorization_code grant. */
|
|
22
|
+
refreshEnabled: boolean;
|
|
23
|
+
/** Lifetime of a freshly issued (or re-issued) refresh token, in seconds. */
|
|
24
|
+
refreshTtlSeconds: number;
|
|
25
|
+
/**
|
|
26
|
+
* Absolute cap on a refresh-token chain, in seconds from first issue. Once a
|
|
27
|
+
* refresh token's chain is older than this, re-issue stops extending it and
|
|
28
|
+
* the user must re-authenticate. Prevents an indefinitely sliding session.
|
|
29
|
+
*/
|
|
30
|
+
refreshMaxTtlSeconds: number;
|
|
21
31
|
}
|
|
22
32
|
export declare function loadEnv(): Env;
|
package/dist/env.js
CHANGED
|
@@ -6,15 +6,54 @@ export function loadEnv() {
|
|
|
6
6
|
const writeSecret = required('WRITE_SECRET');
|
|
7
7
|
const publicUrl = process.env.PUBLIC_URL ? normalizePublicUrl(process.env.PUBLIC_URL) : null;
|
|
8
8
|
const mcpEnabled = (process.env.MCP_ENABLED ?? 'true').toLowerCase() !== 'false';
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
let mcp = null;
|
|
10
|
+
if (mcpEnabled) {
|
|
11
|
+
const refreshTtlSeconds = positiveIntEnv('MCP_REFRESH_TTL_SECONDS', 2592000); // 30d
|
|
12
|
+
const refreshMaxTtlSeconds = positiveIntEnv('MCP_REFRESH_MAX_TTL_SECONDS', 7776000); // 90d
|
|
13
|
+
if (refreshMaxTtlSeconds < refreshTtlSeconds) {
|
|
14
|
+
throw new Error(`MCP_REFRESH_MAX_TTL_SECONDS (${refreshMaxTtlSeconds}) must be >= MCP_REFRESH_TTL_SECONDS (${refreshTtlSeconds})`);
|
|
14
15
|
}
|
|
15
|
-
|
|
16
|
+
mcp = {
|
|
17
|
+
clientId: required('MCP_CLIENT_ID'),
|
|
18
|
+
tokenSecret: requiredSecret('MCP_TOKEN_SECRET', 32),
|
|
19
|
+
tokenTtlSeconds: positiveIntEnv('MCP_TOKEN_TTL_SECONDS', 3600),
|
|
20
|
+
refreshEnabled: (process.env.MCP_REFRESH_ENABLED ?? 'true').toLowerCase() !== 'false',
|
|
21
|
+
refreshTtlSeconds,
|
|
22
|
+
refreshMaxTtlSeconds,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
16
25
|
return { port, databaseUrl, readSecret, writeSecret, publicUrl, mcp };
|
|
17
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Parse an env var as a positive (>= 1) integer number of seconds, falling back
|
|
29
|
+
* to `def` when unset. Throws on non-numeric, non-finite, non-integer, zero, or
|
|
30
|
+
* negative values so a typo'd TTL fails loudly at startup rather than silently
|
|
31
|
+
* minting unusable tokens.
|
|
32
|
+
*/
|
|
33
|
+
function positiveIntEnv(name, def) {
|
|
34
|
+
const raw = process.env[name];
|
|
35
|
+
if (raw === undefined || raw === '')
|
|
36
|
+
return def;
|
|
37
|
+
const n = Number(raw);
|
|
38
|
+
if (!Number.isInteger(n) || n < 1) {
|
|
39
|
+
throw new Error(`${name} must be a positive integer (got: ${raw})`);
|
|
40
|
+
}
|
|
41
|
+
return n;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Like `required`, but additionally enforces a minimum length. Used for the
|
|
45
|
+
* HMAC signing secret: it now protects refresh tokens that live for weeks, so a
|
|
46
|
+
* short/guessable value would let an attacker forge long-lived bearer tokens.
|
|
47
|
+
* The `>= 32 chars` floor admits a raw 32-byte secret (and any longer hex/base64
|
|
48
|
+
* encoding of one) while rejecting placeholder values like `change-me-...`.
|
|
49
|
+
*/
|
|
50
|
+
function requiredSecret(name, minLen) {
|
|
51
|
+
const value = required(name);
|
|
52
|
+
if (value.length < minLen) {
|
|
53
|
+
throw new Error(`${name} must be at least ${minLen} characters (got ${value.length})`);
|
|
54
|
+
}
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
18
57
|
function normalizePublicUrl(raw) {
|
|
19
58
|
let u;
|
|
20
59
|
try {
|
package/dist/env.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp/oauth.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ import type { AuthStore } from './auth-store.js';
|
|
|
3
3
|
export interface TokenIssueResult {
|
|
4
4
|
accessToken: string;
|
|
5
5
|
expiresIn: number;
|
|
6
|
+
/** Present only when refresh tokens are enabled (authorization_code grant). */
|
|
7
|
+
refreshToken?: string;
|
|
6
8
|
}
|
|
7
9
|
export type TokenVerifyResult = {
|
|
8
10
|
ok: true;
|
|
@@ -11,6 +13,14 @@ export type TokenVerifyResult = {
|
|
|
11
13
|
ok: false;
|
|
12
14
|
reason: 'malformed' | 'bad_signature' | 'expired';
|
|
13
15
|
};
|
|
16
|
+
export type RefreshVerifyResult = {
|
|
17
|
+
ok: true;
|
|
18
|
+
clientId: string;
|
|
19
|
+
absoluteMaxAt: number;
|
|
20
|
+
} | {
|
|
21
|
+
ok: false;
|
|
22
|
+
reason: 'malformed' | 'bad_signature' | 'expired' | 'wrong_type';
|
|
23
|
+
};
|
|
14
24
|
/**
|
|
15
25
|
* Issue an opaque, HMAC-signed bearer token.
|
|
16
26
|
*
|
|
@@ -21,6 +31,24 @@ export type TokenVerifyResult = {
|
|
|
21
31
|
*/
|
|
22
32
|
export declare function issueToken(env: McpEnv, nowMs?: number): TokenIssueResult;
|
|
23
33
|
export declare function verifyToken(token: string, env: McpEnv, nowMs?: number): TokenVerifyResult;
|
|
34
|
+
/**
|
|
35
|
+
* Issue a stateless, HMAC-signed refresh token.
|
|
36
|
+
*
|
|
37
|
+
* Token layout: `${b64url(JSON(payload))}.${hex(hmac_sha256(b64url, secret))}`
|
|
38
|
+
* where the payload binds the issuing `client_id` (`cid`), a sliding expiry
|
|
39
|
+
* (`exp`) and the absolute chain cap (`max`). Because the binding is carried in
|
|
40
|
+
* the signature — not in server state — the token keeps working across server
|
|
41
|
+
* restarts (the in-memory client registry being lost does not matter).
|
|
42
|
+
*
|
|
43
|
+
* `absoluteMaxAt` (unix seconds) caps the chain on re-issue; omit it on first
|
|
44
|
+
* issue to start a fresh `refreshMaxTtlSeconds` window.
|
|
45
|
+
*
|
|
46
|
+
* NOTE: these tokens are stateless, so re-issue is NOT reuse-detected
|
|
47
|
+
* rotation — a previously issued refresh token remains valid until its own
|
|
48
|
+
* `exp`. See `grantRefreshToken`.
|
|
49
|
+
*/
|
|
50
|
+
export declare function issueRefreshToken(env: McpEnv, clientId: string, nowMs?: number, absoluteMaxAt?: number): string;
|
|
51
|
+
export declare function verifyRefreshToken(token: string, env: McpEnv, nowMs?: number): RefreshVerifyResult;
|
|
24
52
|
export interface ClientCredentialsRequest {
|
|
25
53
|
clientId: string;
|
|
26
54
|
clientSecret: string;
|
|
@@ -59,3 +87,23 @@ export interface AuthCodeRequest {
|
|
|
59
87
|
* of validation outcome past the lookup.
|
|
60
88
|
*/
|
|
61
89
|
export declare function grantAuthorizationCode(req: AuthCodeRequest, env: McpEnv, store: AuthStore, nowMs?: number): GrantResult;
|
|
90
|
+
export interface RefreshTokenRequest {
|
|
91
|
+
grantType: string;
|
|
92
|
+
refreshToken: string;
|
|
93
|
+
clientId: string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Validate a refresh_token grant and exchange it for a fresh access token plus
|
|
97
|
+
* a re-issued refresh token. Stateless: the refresh token's own signature is
|
|
98
|
+
* the sole credential, and the re-issued token inherits the original chain cap
|
|
99
|
+
* (`absoluteMaxAt`) so a session cannot slide forever.
|
|
100
|
+
*
|
|
101
|
+
* SECURITY NOTE: because there is no server-side state, this is sliding
|
|
102
|
+
* re-issuance, NOT reuse-detected rotation. The presented refresh token is
|
|
103
|
+
* still valid until its own `exp` after this call, so a leaked refresh token
|
|
104
|
+
* cannot be individually revoked before then (it can be replayed to mint
|
|
105
|
+
* parallel chains, all bounded by the same `absoluteMaxAt`). Rotate
|
|
106
|
+
* `tokenSecret` to invalidate every outstanding token at once. Reuse detection
|
|
107
|
+
* would require persisting `jti` — out of scope for the stateless design.
|
|
108
|
+
*/
|
|
109
|
+
export declare function grantRefreshToken(req: RefreshTokenRequest, env: McpEnv, nowMs?: number): GrantResult;
|
package/dist/mcp/oauth.js
CHANGED
|
@@ -60,6 +60,79 @@ export function verifyToken(token, env, nowMs = Date.now()) {
|
|
|
60
60
|
}
|
|
61
61
|
return { ok: true, expiresAt };
|
|
62
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Issue a stateless, HMAC-signed refresh token.
|
|
65
|
+
*
|
|
66
|
+
* Token layout: `${b64url(JSON(payload))}.${hex(hmac_sha256(b64url, secret))}`
|
|
67
|
+
* where the payload binds the issuing `client_id` (`cid`), a sliding expiry
|
|
68
|
+
* (`exp`) and the absolute chain cap (`max`). Because the binding is carried in
|
|
69
|
+
* the signature — not in server state — the token keeps working across server
|
|
70
|
+
* restarts (the in-memory client registry being lost does not matter).
|
|
71
|
+
*
|
|
72
|
+
* `absoluteMaxAt` (unix seconds) caps the chain on re-issue; omit it on first
|
|
73
|
+
* issue to start a fresh `refreshMaxTtlSeconds` window.
|
|
74
|
+
*
|
|
75
|
+
* NOTE: these tokens are stateless, so re-issue is NOT reuse-detected
|
|
76
|
+
* rotation — a previously issued refresh token remains valid until its own
|
|
77
|
+
* `exp`. See `grantRefreshToken`.
|
|
78
|
+
*/
|
|
79
|
+
export function issueRefreshToken(env, clientId, nowMs = Date.now(), absoluteMaxAt) {
|
|
80
|
+
const nowSec = Math.floor(nowMs / 1000);
|
|
81
|
+
const max = absoluteMaxAt ?? nowSec + env.refreshMaxTtlSeconds;
|
|
82
|
+
const exp = Math.min(nowSec + env.refreshTtlSeconds, max);
|
|
83
|
+
const payload = {
|
|
84
|
+
v: 1,
|
|
85
|
+
typ: 'refresh',
|
|
86
|
+
cid: clientId,
|
|
87
|
+
jti: randomBytes(12).toString('base64url'),
|
|
88
|
+
exp,
|
|
89
|
+
max,
|
|
90
|
+
};
|
|
91
|
+
const b64 = b64urlEncode(Buffer.from(JSON.stringify(payload)));
|
|
92
|
+
const sig = sign(Buffer.from(b64), env.tokenSecret);
|
|
93
|
+
return `${b64}.${sig}`;
|
|
94
|
+
}
|
|
95
|
+
export function verifyRefreshToken(token, env, nowMs = Date.now()) {
|
|
96
|
+
const dot = token.indexOf('.');
|
|
97
|
+
if (dot <= 0)
|
|
98
|
+
return { ok: false, reason: 'malformed' };
|
|
99
|
+
const b64 = token.slice(0, dot);
|
|
100
|
+
const sigHex = token.slice(dot + 1);
|
|
101
|
+
if (sigHex.length !== SIG_HEX_LEN)
|
|
102
|
+
return { ok: false, reason: 'malformed' };
|
|
103
|
+
const expectedSigHex = sign(Buffer.from(b64), env.tokenSecret);
|
|
104
|
+
const a = Buffer.from(sigHex, 'hex');
|
|
105
|
+
const b = Buffer.from(expectedSigHex, 'hex');
|
|
106
|
+
if (a.length !== b.length || !timingSafeEqual(a, b)) {
|
|
107
|
+
return { ok: false, reason: 'bad_signature' };
|
|
108
|
+
}
|
|
109
|
+
const raw = b64urlDecode(b64);
|
|
110
|
+
if (!raw)
|
|
111
|
+
return { ok: false, reason: 'malformed' };
|
|
112
|
+
let payload;
|
|
113
|
+
try {
|
|
114
|
+
payload = JSON.parse(raw.toString('utf8'));
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
return { ok: false, reason: 'malformed' };
|
|
118
|
+
}
|
|
119
|
+
if (payload.typ !== 'refresh')
|
|
120
|
+
return { ok: false, reason: 'wrong_type' };
|
|
121
|
+
if (payload.v !== 1)
|
|
122
|
+
return { ok: false, reason: 'malformed' };
|
|
123
|
+
if (typeof payload.cid !== 'string' ||
|
|
124
|
+
payload.cid.length === 0 ||
|
|
125
|
+
typeof payload.jti !== 'string' ||
|
|
126
|
+
payload.jti.length === 0 ||
|
|
127
|
+
typeof payload.exp !== 'number' ||
|
|
128
|
+
typeof payload.max !== 'number') {
|
|
129
|
+
return { ok: false, reason: 'malformed' };
|
|
130
|
+
}
|
|
131
|
+
if (Math.floor(nowMs / 1000) >= payload.exp) {
|
|
132
|
+
return { ok: false, reason: 'expired' };
|
|
133
|
+
}
|
|
134
|
+
return { ok: true, clientId: payload.cid, absoluteMaxAt: payload.max };
|
|
135
|
+
}
|
|
63
136
|
/**
|
|
64
137
|
* Validate a client_credentials grant request against the configured MCP env
|
|
65
138
|
* + the read secret. Returns the access token on success.
|
|
@@ -144,6 +217,50 @@ export function grantAuthorizationCode(req, env, store, nowMs = Date.now()) {
|
|
|
144
217
|
if (!timingSafeEqualStr(expected, rec.codeChallenge)) {
|
|
145
218
|
return { ok: false, status: 400, error: 'invalid_grant', description: 'pkce mismatch' };
|
|
146
219
|
}
|
|
147
|
-
|
|
220
|
+
const token = issueToken(env, nowMs);
|
|
221
|
+
if (env.refreshEnabled) {
|
|
222
|
+
token.refreshToken = issueRefreshToken(env, rec.clientId, nowMs);
|
|
223
|
+
}
|
|
224
|
+
return { ok: true, token };
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Validate a refresh_token grant and exchange it for a fresh access token plus
|
|
228
|
+
* a re-issued refresh token. Stateless: the refresh token's own signature is
|
|
229
|
+
* the sole credential, and the re-issued token inherits the original chain cap
|
|
230
|
+
* (`absoluteMaxAt`) so a session cannot slide forever.
|
|
231
|
+
*
|
|
232
|
+
* SECURITY NOTE: because there is no server-side state, this is sliding
|
|
233
|
+
* re-issuance, NOT reuse-detected rotation. The presented refresh token is
|
|
234
|
+
* still valid until its own `exp` after this call, so a leaked refresh token
|
|
235
|
+
* cannot be individually revoked before then (it can be replayed to mint
|
|
236
|
+
* parallel chains, all bounded by the same `absoluteMaxAt`). Rotate
|
|
237
|
+
* `tokenSecret` to invalidate every outstanding token at once. Reuse detection
|
|
238
|
+
* would require persisting `jti` — out of scope for the stateless design.
|
|
239
|
+
*/
|
|
240
|
+
export function grantRefreshToken(req, env, nowMs = Date.now()) {
|
|
241
|
+
if (req.grantType !== 'refresh_token') {
|
|
242
|
+
return { ok: false, status: 400, error: 'unsupported_grant_type' };
|
|
243
|
+
}
|
|
244
|
+
if (!env.refreshEnabled) {
|
|
245
|
+
return {
|
|
246
|
+
ok: false,
|
|
247
|
+
status: 400,
|
|
248
|
+
error: 'unsupported_grant_type',
|
|
249
|
+
description: 'refresh tokens are disabled',
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
if (!req.refreshToken || !req.clientId) {
|
|
253
|
+
return { ok: false, status: 400, error: 'invalid_request', description: 'missing parameter' };
|
|
254
|
+
}
|
|
255
|
+
const v = verifyRefreshToken(req.refreshToken, env, nowMs);
|
|
256
|
+
if (!v.ok) {
|
|
257
|
+
return { ok: false, status: 400, error: 'invalid_grant', description: `refresh ${v.reason}` };
|
|
258
|
+
}
|
|
259
|
+
if (!timingSafeEqualStr(v.clientId, req.clientId)) {
|
|
260
|
+
return { ok: false, status: 400, error: 'invalid_grant', description: 'client_id mismatch' };
|
|
261
|
+
}
|
|
262
|
+
const token = issueToken(env, nowMs);
|
|
263
|
+
token.refreshToken = issueRefreshToken(env, v.clientId, nowMs, v.absoluteMaxAt);
|
|
264
|
+
return { ok: true, token };
|
|
148
265
|
}
|
|
149
266
|
//# sourceMappingURL=oauth.js.map
|
package/dist/mcp/oauth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/mcp/oauth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/mcp/oauth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ActivitiesBatchWrite, DeletionsBatchWrite } from '@zykeco/sync-protocol';
|
|
2
|
+
import { Hono } from 'hono';
|
|
3
|
+
import { requireAuth } from './auth.js';
|
|
4
|
+
import { parseJsonBody } from './validate.js';
|
|
5
|
+
export function activitiesRoutes(store, auth) {
|
|
6
|
+
const app = new Hono();
|
|
7
|
+
app.post('/batch', requireAuth('write', auth), async (c) => {
|
|
8
|
+
const body = await parseJsonBody(c, ActivitiesBatchWrite);
|
|
9
|
+
if (body instanceof Response)
|
|
10
|
+
return body;
|
|
11
|
+
const serverNowMs = Date.now();
|
|
12
|
+
const stored = await store.upsertBatch(body.rows, serverNowMs);
|
|
13
|
+
return c.json({ stored, serverNowMs });
|
|
14
|
+
});
|
|
15
|
+
app.post('/delete', requireAuth('write', auth), async (c) => {
|
|
16
|
+
const body = await parseJsonBody(c, DeletionsBatchWrite);
|
|
17
|
+
if (body instanceof Response)
|
|
18
|
+
return body;
|
|
19
|
+
const deleted = await store.deleteBatch(body.ids);
|
|
20
|
+
return c.json({ deleted, serverNowMs: Date.now() });
|
|
21
|
+
});
|
|
22
|
+
return app;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=activities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activities.js","sourceRoot":"","sources":["../../src/routes/activities.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,UAAU,gBAAgB,CAAC,KAAsB,EAAE,IAAgB;IACvE,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACzD,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,CAAC,EAAE,oBAAoB,CAAC,CAAC;QAC1D,IAAI,IAAI,YAAY,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC1C,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QAC/D,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC1D,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC;QACzD,IAAI,IAAI,YAAY,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC1C,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClD,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ActivityHeartRatesBatchWrite, DeletionsBatchWrite } from '@zykeco/sync-protocol';
|
|
2
|
+
import { Hono } from 'hono';
|
|
3
|
+
import { requireAuth } from './auth.js';
|
|
4
|
+
import { parseJsonBody } from './validate.js';
|
|
5
|
+
export function activityHeartRateRoutes(store, auth) {
|
|
6
|
+
const app = new Hono();
|
|
7
|
+
app.post('/batch', requireAuth('write', auth), async (c) => {
|
|
8
|
+
const body = await parseJsonBody(c, ActivityHeartRatesBatchWrite);
|
|
9
|
+
if (body instanceof Response)
|
|
10
|
+
return body;
|
|
11
|
+
const serverNowMs = Date.now();
|
|
12
|
+
const stored = await store.upsertBatch(body.rows, serverNowMs);
|
|
13
|
+
return c.json({ stored, serverNowMs });
|
|
14
|
+
});
|
|
15
|
+
app.post('/delete', requireAuth('write', auth), async (c) => {
|
|
16
|
+
const body = await parseJsonBody(c, DeletionsBatchWrite);
|
|
17
|
+
if (body instanceof Response)
|
|
18
|
+
return body;
|
|
19
|
+
const deleted = await store.deleteBatch(body.ids);
|
|
20
|
+
return c.json({ deleted, serverNowMs: Date.now() });
|
|
21
|
+
});
|
|
22
|
+
return app;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=activity-heart-rate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activity-heart-rate.js","sourceRoot":"","sources":["../../src/routes/activity-heart-rate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,4BAA4B,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC1F,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,UAAU,uBAAuB,CAAC,KAA6B,EAAE,IAAgB;IACrF,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACzD,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,CAAC,EAAE,4BAA4B,CAAC,CAAC;QAClE,IAAI,IAAI,YAAY,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC1C,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QAC/D,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC1D,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC;QACzD,IAAI,IAAI,YAAY,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC1C,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClD,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/routes/mcp.js
CHANGED
|
@@ -2,7 +2,7 @@ import { timingSafeEqual } from 'node:crypto';
|
|
|
2
2
|
import { Hono } from 'hono';
|
|
3
3
|
import { createAuthStore } from '../mcp/auth-store.js';
|
|
4
4
|
import { renderConsent } from '../mcp/consent.js';
|
|
5
|
-
import { grantAuthorizationCode, grantClientCredentials, verifyToken } from '../mcp/oauth.js';
|
|
5
|
+
import { grantAuthorizationCode, grantClientCredentials, grantRefreshToken, verifyToken, } from '../mcp/oauth.js';
|
|
6
6
|
import { createMcpServer } from '../mcp/server.js';
|
|
7
7
|
import { buildTools } from '../mcp/tools.js';
|
|
8
8
|
import { createTimezoneResolver } from '../mcp/timezones.js';
|
|
@@ -27,13 +27,16 @@ function issuerFrom(req, publicUrl) {
|
|
|
27
27
|
const host = fwdHost || u.host;
|
|
28
28
|
return `${proto}://${host}`;
|
|
29
29
|
}
|
|
30
|
-
function authMetadata(issuer) {
|
|
30
|
+
function authMetadata(issuer, refreshEnabled) {
|
|
31
|
+
const grantTypes = ['authorization_code', 'client_credentials'];
|
|
32
|
+
if (refreshEnabled)
|
|
33
|
+
grantTypes.push('refresh_token');
|
|
31
34
|
return {
|
|
32
35
|
issuer,
|
|
33
36
|
authorization_endpoint: `${issuer}/mcp/authorize`,
|
|
34
37
|
token_endpoint: `${issuer}/mcp/oauth/token`,
|
|
35
38
|
registration_endpoint: `${issuer}/mcp/register`,
|
|
36
|
-
grant_types_supported:
|
|
39
|
+
grant_types_supported: grantTypes,
|
|
37
40
|
response_types_supported: ['code'],
|
|
38
41
|
code_challenge_methods_supported: ['S256'],
|
|
39
42
|
token_endpoint_auth_methods_supported: ['none', 'client_secret_post', 'client_secret_basic'],
|
|
@@ -67,7 +70,7 @@ export function mcpRoutes(deps) {
|
|
|
67
70
|
// Kept under `/mcp/oauth/...` for backward compat with older clients.
|
|
68
71
|
app.get('/oauth/.well-known/oauth-authorization-server', (c) => {
|
|
69
72
|
addCorsHeaders(c);
|
|
70
|
-
return c.json(authMetadata(issuerFrom(c.req, env.publicUrl)));
|
|
73
|
+
return c.json(authMetadata(issuerFrom(c.req, env.publicUrl), mcp.refreshEnabled));
|
|
71
74
|
});
|
|
72
75
|
// --- Dynamic Client Registration (RFC 7591) ------------------------------
|
|
73
76
|
app.post('/register', async (c) => {
|
|
@@ -98,7 +101,9 @@ export function mcpRoutes(deps) {
|
|
|
98
101
|
client_id_issued_at: Math.floor(client.createdAt / 1000),
|
|
99
102
|
redirect_uris: client.redirectUris,
|
|
100
103
|
...(client.clientName ? { client_name: client.clientName } : {}),
|
|
101
|
-
grant_types:
|
|
104
|
+
grant_types: mcp.refreshEnabled
|
|
105
|
+
? ['authorization_code', 'refresh_token']
|
|
106
|
+
: ['authorization_code'],
|
|
102
107
|
response_types: ['code'],
|
|
103
108
|
token_endpoint_auth_method: 'none',
|
|
104
109
|
}, 201);
|
|
@@ -202,6 +207,19 @@ export function mcpRoutes(deps) {
|
|
|
202
207
|
return c.json({ error: 'invalid_request', error_description: 'malformed body' }, 400);
|
|
203
208
|
}
|
|
204
209
|
const grantType = params.get('grant_type') ?? '';
|
|
210
|
+
// RFC 6749 §2.3.1: client credentials may also be supplied via HTTP Basic.
|
|
211
|
+
// Parse once up front so every grant branch can see the client_id.
|
|
212
|
+
let basicClientId = '';
|
|
213
|
+
let basicClientSecret = '';
|
|
214
|
+
const basic = c.req.header('authorization');
|
|
215
|
+
if (basic?.toLowerCase().startsWith('basic ')) {
|
|
216
|
+
const decoded = Buffer.from(basic.slice(6), 'base64').toString('utf8');
|
|
217
|
+
const sep = decoded.indexOf(':');
|
|
218
|
+
if (sep > 0) {
|
|
219
|
+
basicClientId = decoded.slice(0, sep);
|
|
220
|
+
basicClientSecret = decoded.slice(sep + 1);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
205
223
|
if (grantType === 'authorization_code') {
|
|
206
224
|
const result = grantAuthorizationCode({
|
|
207
225
|
grantType,
|
|
@@ -220,22 +238,30 @@ export function mcpRoutes(deps) {
|
|
|
220
238
|
access_token: result.token.accessToken,
|
|
221
239
|
token_type: 'Bearer',
|
|
222
240
|
expires_in: result.token.expiresIn,
|
|
241
|
+
...(result.token.refreshToken ? { refresh_token: result.token.refreshToken } : {}),
|
|
223
242
|
});
|
|
224
243
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
clientSecret = decoded.slice(sep + 1);
|
|
244
|
+
if (grantType === 'refresh_token') {
|
|
245
|
+
const result = grantRefreshToken({
|
|
246
|
+
grantType,
|
|
247
|
+
refreshToken: params.get('refresh_token') ?? '',
|
|
248
|
+
clientId: params.get('client_id') || basicClientId,
|
|
249
|
+
}, mcp);
|
|
250
|
+
if (!result.ok) {
|
|
251
|
+
return c.json({
|
|
252
|
+
error: result.error,
|
|
253
|
+
...(result.description ? { error_description: result.description } : {}),
|
|
254
|
+
}, result.status);
|
|
237
255
|
}
|
|
256
|
+
return c.json({
|
|
257
|
+
access_token: result.token.accessToken,
|
|
258
|
+
token_type: 'Bearer',
|
|
259
|
+
expires_in: result.token.expiresIn,
|
|
260
|
+
...(result.token.refreshToken ? { refresh_token: result.token.refreshToken } : {}),
|
|
261
|
+
});
|
|
238
262
|
}
|
|
263
|
+
const clientId = params.get('client_id') || basicClientId;
|
|
264
|
+
const clientSecret = params.get('client_secret') || basicClientSecret;
|
|
239
265
|
const result = grantClientCredentials({ clientId, clientSecret, grantType }, mcp, env.readSecret);
|
|
240
266
|
if (!result.ok) {
|
|
241
267
|
return c.json({
|
|
@@ -318,7 +344,7 @@ export function mcpRoutes(deps) {
|
|
|
318
344
|
});
|
|
319
345
|
discovery.get('/.well-known/oauth-authorization-server', (c) => {
|
|
320
346
|
addCorsHeaders(c);
|
|
321
|
-
return c.json(authMetadata(issuerFrom(c.req, env.publicUrl)));
|
|
347
|
+
return c.json(authMetadata(issuerFrom(c.req, env.publicUrl), mcp.refreshEnabled));
|
|
322
348
|
});
|
|
323
349
|
discovery.get('/.well-known/oauth-protected-resource', (c) => {
|
|
324
350
|
addCorsHeaders(c);
|