@molecule/api-wearable-fitbit 1.0.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.
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Fitbit wearable bond secret definitions — self-registered at import time so the
3
+ * runtime secrets registry (`@molecule/api-secrets`) can drive boot-time
4
+ * configuration reports and actionable "not configured" errors.
5
+ *
6
+ * Content is derived MECHANICALLY from this package's mlcl registry secrets
7
+ * entry (label/instructions/setupUrl/example) via the fleet formula, so
8
+ * packages sharing a key register byte-identical definitions and
9
+ * registration order never matters.
10
+ *
11
+ * @module
12
+ */
13
+ import { registerSecrets } from '@molecule/api-secrets';
14
+ /** Secret definitions required by the Fitbit wearable bond. */
15
+ export const wearableFitbitSecretDefinitions = [
16
+ {
17
+ key: 'OAUTH_FITBIT_CLIENT_ID',
18
+ description: 'Fitbit OAuth client ID — Register an application at dev.fitbit.com and copy the OAuth 2.0 Client ID.',
19
+ helpUrl: 'https://dev.fitbit.com/apps',
20
+ required: true,
21
+ },
22
+ {
23
+ key: 'OAUTH_FITBIT_CLIENT_SECRET',
24
+ description: 'Fitbit client secret — Shown on your registered Fitbit application page.',
25
+ helpUrl: 'https://dev.fitbit.com/apps',
26
+ required: false,
27
+ },
28
+ ];
29
+ registerSecrets(wearableFitbitSecretDefinitions);
30
+ //# sourceMappingURL=secrets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secrets.js","sourceRoot":"","sources":["../src/secrets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAEvD,+DAA+D;AAC/D,MAAM,CAAC,MAAM,+BAA+B,GAAuB;IACjE;QACE,GAAG,EAAE,wBAAwB;QAC7B,WAAW,EACT,sGAAsG;QACxG,OAAO,EAAE,6BAA6B;QACtC,QAAQ,EAAE,IAAI;KACf;IACD;QACE,GAAG,EAAE,4BAA4B;QACjC,WAAW,EAAE,0EAA0E;QACvF,OAAO,EAAE,6BAA6B;QACtC,QAAQ,EAAE,KAAK;KAChB;CACF,CAAA;AAED,eAAe,CAAC,+BAA+B,CAAC,CAAA"}
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Fitbit wearable bond types for molecule.dev.
3
+ *
4
+ * @module
5
+ */
6
+ import type { UserConnection as WearableUserConnection, WearableCredentialsStore, WearableProvider as WearableProviderType } from '@molecule/api-wearable';
7
+ export type { DailyActivity, HeartRateSummary, HeartRateZone, SleepSession, SleepStage, SleepStageSegment, SleepStageSummary, UserConnection, WearableCredentialsStore, WearableDate, WearableDateRange, WearableProvider, WeightEntry, } from '@molecule/api-wearable';
8
+ declare global {
9
+ namespace NodeJS {
10
+ /**
11
+ * Process Env interface.
12
+ */
13
+ interface ProcessEnv {
14
+ /**
15
+ * The Fitbit OAuth client ID. Required to mint and refresh access
16
+ * tokens. Treated as a public identifier — sent in `client_id`
17
+ * during PKCE — but still configured as a secret for symmetry.
18
+ *
19
+ * @see https://dev.fitbit.com/build/reference/web-api/authorization/
20
+ */
21
+ OAUTH_FITBIT_CLIENT_ID?: string;
22
+ /**
23
+ * The Fitbit OAuth client secret. Required for confidential-client
24
+ * apps to refresh tokens via Basic auth. PKCE-only public clients
25
+ * may omit it (the bond falls back to the PKCE-only token call when
26
+ * absent).
27
+ *
28
+ * @see https://dev.fitbit.com/build/reference/web-api/authorization/
29
+ */
30
+ OAUTH_FITBIT_CLIENT_SECRET?: string;
31
+ }
32
+ }
33
+ }
34
+ /**
35
+ * Cache of `code_verifier` strings keyed by the in-flight authorization
36
+ * `code` string they were paired with.
37
+ *
38
+ * The Fitbit OAuth callback hands the bond an authorization `code` but
39
+ * not the `code_verifier` it was created with — the bond needs to store
40
+ * the verifier between {@link FitbitProvider.startAuthorize} and
41
+ * {@link FitbitProvider.connect}. The store contract leaves the choice
42
+ * of backing storage (Redis, Postgres, in-memory for tests) to the host.
43
+ */
44
+ export interface FitbitCodeVerifierStore {
45
+ /**
46
+ * Persists the verifier indexed by the `state` value the bond will
47
+ * round-trip through Fitbit's authorize redirect.
48
+ *
49
+ * @param state - Opaque CSRF-protection token returned in the redirect.
50
+ * @param verifier - The PKCE `code_verifier` to retrieve later.
51
+ */
52
+ put(state: string, verifier: string): Promise<void>;
53
+ /**
54
+ * Retrieves and deletes the verifier associated with `state`.
55
+ * Implementations MUST delete on read so a verifier is never reused.
56
+ *
57
+ * @param state - The `state` value extracted from the OAuth callback.
58
+ * @returns The verifier, or `null` if no entry exists.
59
+ */
60
+ take(state: string): Promise<string | null>;
61
+ }
62
+ /**
63
+ * Configuration options for {@link createProvider}.
64
+ */
65
+ export interface FitbitProviderOptions {
66
+ /**
67
+ * OAuth client id. Defaults to `process.env.OAUTH_FITBIT_CLIENT_ID`.
68
+ */
69
+ clientId?: string;
70
+ /**
71
+ * OAuth client secret. Defaults to
72
+ * `process.env.OAUTH_FITBIT_CLIENT_SECRET`. Optional — PKCE-only public
73
+ * clients omit it.
74
+ */
75
+ clientSecret?: string;
76
+ /**
77
+ * OAuth redirect URI registered with the Fitbit application. Required
78
+ * to complete the authorization-code exchange.
79
+ */
80
+ redirectUri: string;
81
+ /**
82
+ * Persists user connections (access + refresh tokens). Required.
83
+ */
84
+ credentialsStore: WearableCredentialsStore;
85
+ /**
86
+ * Optional store for PKCE `code_verifier` strings keyed by `state`.
87
+ * Required if the bond's `startAuthorize` / `connect` helpers are used
88
+ * to drive the OAuth flow; the host may omit it when wiring the OAuth
89
+ * exchange themselves.
90
+ */
91
+ codeVerifierStore?: FitbitCodeVerifierStore;
92
+ /**
93
+ * OAuth scopes to request when starting authorization. Defaults to the
94
+ * union needed for activity, sleep, heart-rate, and weight reads.
95
+ */
96
+ scopes?: readonly string[];
97
+ /**
98
+ * Override the Fitbit Web API base URL. Defaults to
99
+ * `https://api.fitbit.com/1`.
100
+ */
101
+ apiBaseUrl?: string;
102
+ /**
103
+ * Override the Fitbit OAuth authorize endpoint. Defaults to
104
+ * `https://www.fitbit.com/oauth2/authorize`.
105
+ */
106
+ authorizeUrl?: string;
107
+ /**
108
+ * Override the Fitbit OAuth token endpoint. Defaults to
109
+ * `https://api.fitbit.com/oauth2/token`.
110
+ */
111
+ tokenUrl?: string;
112
+ /**
113
+ * Override the Fitbit OAuth token-revoke endpoint. Defaults to
114
+ * `https://api.fitbit.com/oauth2/revoke`.
115
+ */
116
+ revokeUrl?: string;
117
+ /**
118
+ * Request timeout in milliseconds. Defaults to `15_000`.
119
+ */
120
+ timeoutMs?: number;
121
+ /**
122
+ * Optional override for the random-bytes generator used by PKCE / CSRF.
123
+ * Tests inject a deterministic generator.
124
+ */
125
+ randomBytes?: (size: number) => Uint8Array;
126
+ /**
127
+ * Optional clock override, primarily for tests. Defaults to `Date.now`.
128
+ */
129
+ now?: () => number;
130
+ }
131
+ /**
132
+ * Result of {@link FitbitProvider.startAuthorize} — the URL the host
133
+ * should redirect the user to plus the `state` value to round-trip.
134
+ */
135
+ export interface FitbitAuthorizeStart {
136
+ /** Fitbit OAuth authorize URL. */
137
+ url: string;
138
+ /** Opaque `state` value the host MUST verify on the callback. */
139
+ state: string;
140
+ }
141
+ /**
142
+ * Public surface returned by {@link createProvider}. Extends the
143
+ * stack-neutral {@link import('@molecule/api-wearable').WearableProvider}
144
+ * with Fitbit-specific OAuth-flow helpers.
145
+ */
146
+ export interface FitbitProvider extends WearableProviderType {
147
+ /**
148
+ * Builds the Fitbit authorize URL and persists a fresh PKCE verifier.
149
+ *
150
+ * @returns The URL to redirect to and the round-trip `state` value.
151
+ */
152
+ startAuthorize(): Promise<FitbitAuthorizeStart>;
153
+ /**
154
+ * Performs the authorization-code → token exchange with an explicit
155
+ * PKCE `code_verifier`. Use this when the host wires the OAuth flow
156
+ * itself (no `codeVerifierStore` configured).
157
+ *
158
+ * @param userId - Host-app user identifier.
159
+ * @param code - OAuth authorization `code` from the redirect callback.
160
+ * @param verifier - The PKCE `code_verifier` used to derive the challenge.
161
+ * @returns The freshly-minted user connection (already persisted).
162
+ */
163
+ connectWithVerifier(userId: string, code: string, verifier: string): Promise<WearableUserConnection>;
164
+ }
165
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,cAAc,IAAI,sBAAsB,EACxC,wBAAwB,EACxB,gBAAgB,IAAI,oBAAoB,EACzC,MAAM,wBAAwB,CAAA;AAE/B,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,UAAU,EACV,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,wBAAwB,EACxB,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,WAAW,GACZ,MAAM,wBAAwB,CAAA;AAE/B,OAAO,CAAC,MAAM,CAAC;IAEb,UAAU,MAAM,CAAC;QACf;;WAEG;QACH,UAAiB,UAAU;YACzB;;;;;;eAMG;YACH,sBAAsB,CAAC,EAAE,MAAM,CAAA;YAE/B;;;;;;;eAOG;YACH,0BAA0B,CAAC,EAAE,MAAM,CAAA;SACpC;KACF;CACF;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,uBAAuB;IACtC;;;;;;OAMG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACnD;;;;;;OAMG;IACH,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;CAC5C;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB;;OAEG;IACH,gBAAgB,EAAE,wBAAwB,CAAA;IAC1C;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,uBAAuB,CAAA;IAC3C;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,UAAU,CAAA;IAC1C;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAA;IACX,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAA;CACd;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAe,SAAQ,oBAAoB;IAC1D;;;;OAIG;IACH,cAAc,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAAA;IAC/C;;;;;;;;;OASG;IACH,mBAAmB,CACjB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,sBAAsB,CAAC,CAAA;CACnC"}
package/dist/types.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Fitbit wearable bond types for molecule.dev.
3
+ *
4
+ * @module
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@molecule/api-wearable-fitbit",
3
+ "version": "1.0.0",
4
+ "description": "Fitbit Web API bond for molecule.dev — daily activity, sleep, heart-rate, and weight ingestion via OAuth 2.0 PKCE",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "scripts": {
9
+ "build": "tsc",
10
+ "test": "vitest run",
11
+ "test:watch": "vitest"
12
+ },
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.js"
17
+ }
18
+ },
19
+ "files": [
20
+ "dist"
21
+ ],
22
+ "keywords": [
23
+ "molecule",
24
+ "wearable",
25
+ "fitbit",
26
+ "fitness",
27
+ "sleep",
28
+ "heart-rate",
29
+ "oauth"
30
+ ],
31
+ "license": "Apache-2.0",
32
+ "peerDependencies": {
33
+ "@molecule/api-bond": "^1.0.0",
34
+ "@molecule/api-http": "^1.0.0",
35
+ "@molecule/api-secrets": "^1.0.0",
36
+ "@molecule/api-wearable": "^1.0.0"
37
+ },
38
+ "devDependencies": {
39
+ "@molecule/api-bond": "1.0.0",
40
+ "@molecule/api-http": "1.0.0",
41
+ "@molecule/api-wearable": "1.0.0",
42
+ "@types/node": "26.1.2",
43
+ "typescript": "6.0.3",
44
+ "vitest": "4.1.10"
45
+ },
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "https://github.com/molecule-dev/molecule.git",
49
+ "directory": "packages/api/bonds/wearable/fitbit"
50
+ },
51
+ "homepage": "https://github.com/molecule-dev/molecule/tree/main/packages/api/bonds/wearable/fitbit",
52
+ "bugs": "https://github.com/molecule-dev/molecule/issues",
53
+ "publishConfig": {
54
+ "access": "public"
55
+ }
56
+ }