@bernierllc/dropbox-oauth 0.2.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/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (c) 2025 Bernier LLC
2
+
3
+ This file is licensed to the client under a limited-use license.
4
+ The client may use and modify this code *only within the scope of the project it was delivered for*.
5
+ Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
6
+
7
+
package/README.md ADDED
@@ -0,0 +1,168 @@
1
+ # @bernierllc/dropbox-oauth
2
+
3
+ OAuth 2.0 authentication and token management for Dropbox.
4
+
5
+ ## Features
6
+
7
+ - OAuth 2.0 authorization URL generation with PKCE
8
+ - Authorization code exchange for access tokens
9
+ - Automatic token refresh with refresh tokens
10
+ - Token validation and expiration checking
11
+ - Secure credential storage interfaces
12
+ - Multi-user token management
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @bernierllc/dropbox-oauth
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ### Basic Authentication Flow
23
+
24
+ ```typescript
25
+ import { DropboxOAuth } from '@bernierllc/dropbox-oauth';
26
+
27
+ // Create auth instance
28
+ const dropboxAuth = new DropboxOAuth({
29
+ clientId: 'your-client-id',
30
+ clientSecret: 'your-client-secret',
31
+ redirectUri: 'https://your-app.com/oauth/dropbox/callback'
32
+ });
33
+
34
+ // Step 1: Generate authorization URL
35
+ const { url, state } = dropboxAuth.getAuthorizationUrl();
36
+ // Store state in session for CSRF protection
37
+ // Redirect user to url
38
+
39
+ // Step 2: Exchange authorization code for tokens
40
+ const tokens = await dropboxAuth.exchangeCodeForTokens(code, state);
41
+ console.log('Access token:', tokens.accessToken);
42
+ console.log('Refresh token:', tokens.refreshToken);
43
+ ```
44
+
45
+ ### Token Refresh
46
+
47
+ ```typescript
48
+ // Manually refresh token
49
+ const newTokens = await dropboxAuth.refreshAccessToken(refreshToken);
50
+
51
+ // Or use automatic refresh with storage
52
+ const storage: TokenStorage = {
53
+ async store(key, tokens) {
54
+ // Store tokens in your database
55
+ await db.saveTokens(key, tokens);
56
+ },
57
+ async retrieve(key) {
58
+ // Retrieve tokens from your database
59
+ return await db.getTokens(key);
60
+ },
61
+ async delete(key) {
62
+ // Delete tokens from your database
63
+ await db.deleteTokens(key);
64
+ }
65
+ };
66
+
67
+ const authWithStorage = new DropboxOAuth(config, storage);
68
+
69
+ // Automatically refreshes if token is expired
70
+ const validToken = await authWithStorage.getValidToken('user-123');
71
+ ```
72
+
73
+ ### Token Validation
74
+
75
+ ```typescript
76
+ const isValid = await dropboxAuth.validateToken(accessToken);
77
+ if (!isValid) {
78
+ console.log('Token is invalid or expired');
79
+ }
80
+ ```
81
+
82
+ ## API
83
+
84
+ ### `DropboxOAuth`
85
+
86
+ #### Constructor
87
+
88
+ ```typescript
89
+ constructor(config: DropboxOAuthConfig, storage?: TokenStorage)
90
+ ```
91
+
92
+ - `config.clientId` - Dropbox app client ID
93
+ - `config.clientSecret` - Dropbox app client secret
94
+ - `config.redirectUri` - OAuth redirect URI
95
+ - `config.logger` - (Optional) Custom logger instance
96
+ - `storage` - (Optional) Token storage implementation
97
+
98
+ #### Methods
99
+
100
+ ##### `getAuthorizationUrl(state?: string, scopes?: string[]): { url: string; state: string }`
101
+
102
+ Generate OAuth authorization URL with PKCE.
103
+
104
+ ##### `exchangeCodeForTokens(code: string, state: string): Promise<DropboxOAuthTokens>`
105
+
106
+ Exchange authorization code for access and refresh tokens.
107
+
108
+ ##### `refreshAccessToken(refreshToken: string): Promise<DropboxOAuthTokens>`
109
+
110
+ Refresh access token using refresh token.
111
+
112
+ ##### `validateToken(accessToken: string): Promise<boolean>`
113
+
114
+ Validate access token against Dropbox API.
115
+
116
+ ##### `getValidToken(storageKey: string): Promise<string>`
117
+
118
+ Get a valid access token, automatically refreshing if expired (requires storage).
119
+
120
+ ##### `storeTokens(key: string, tokens: DropboxOAuthTokens): Promise<void>`
121
+
122
+ Store tokens (requires storage).
123
+
124
+ ##### `revokeTokens(storageKey: string): Promise<void>`
125
+
126
+ Revoke and delete tokens (requires storage).
127
+
128
+ ### `TokenStorage` Interface
129
+
130
+ ```typescript
131
+ interface TokenStorage {
132
+ store(key: string, tokens: DropboxOAuthTokens): Promise<void>;
133
+ retrieve(key: string): Promise<DropboxOAuthTokens | null>;
134
+ delete(key: string): Promise<void>;
135
+ }
136
+ ```
137
+
138
+ Implement this interface to provide persistent token storage.
139
+
140
+ ## Token Expiration
141
+
142
+ Tokens are automatically refreshed when:
143
+ - Less than 5 minutes remaining before expiration
144
+ - `getValidToken()` is called with valid refresh token
145
+
146
+ ## Error Handling
147
+
148
+ ```typescript
149
+ try {
150
+ const tokens = await dropboxAuth.exchangeCodeForTokens(code, state);
151
+ } catch (error) {
152
+ console.error('OAuth failed:', error.message);
153
+ }
154
+ ```
155
+
156
+ All methods throw descriptive errors on failure.
157
+
158
+ ## Integration
159
+
160
+ ### Logger Integration
161
+
162
+ This package uses `@bernierllc/logger` for structured logging. The logger is optional and will use a no-op logger if not provided.
163
+
164
+ ## License
165
+
166
+ Copyright (c) 2025 Bernier LLC. See LICENSE file for details.
167
+
168
+
@@ -0,0 +1,83 @@
1
+ import { Logger } from "@bernierllc/logger";
2
+ import { DropboxOAuthConfig, DropboxOAuthTokens, TokenStorage } from "./types";
3
+ /**
4
+ * Extended configuration including logger
5
+ */
6
+ export interface DropboxOAuthConfigWithLogger extends DropboxOAuthConfig {
7
+ logger?: Logger;
8
+ }
9
+ /**
10
+ * DropboxOAuth - OAuth 2.0 authentication and token management for Dropbox
11
+ *
12
+ * Handles:
13
+ * - Authorization URL generation with PKCE
14
+ * - Authorization code exchange
15
+ * - Token refresh
16
+ * - Token validation
17
+ * - Automatic token refresh with storage
18
+ */
19
+ export declare class DropboxOAuth {
20
+ private config;
21
+ private logger;
22
+ private storage;
23
+ private auth;
24
+ /**
25
+ * Create a new DropboxOAuth instance
26
+ * @param config - OAuth configuration
27
+ * @param storage - Optional token storage for automatic refresh
28
+ */
29
+ constructor(config: DropboxOAuthConfigWithLogger, storage?: TokenStorage);
30
+ /**
31
+ * Generate OAuth authorization URL with PKCE
32
+ * @param state - Optional state parameter for CSRF protection (auto-generated if not provided)
33
+ * @param scopes - Requested Dropbox scopes (default: ['files.content.write', 'files.content.read'])
34
+ * @returns Object with authorization URL and state
35
+ */
36
+ getAuthorizationUrl(state?: string, scopes?: string[]): {
37
+ url: string;
38
+ state: string;
39
+ };
40
+ /**
41
+ * Exchange authorization code for access and refresh tokens
42
+ * @param code - Authorization code from OAuth callback
43
+ * @param state - State token for CSRF validation
44
+ * @returns OAuth tokens
45
+ * @throws Error if exchange fails
46
+ */
47
+ exchangeCodeForTokens(code: string, _state: string): Promise<DropboxOAuthTokens>;
48
+ /**
49
+ * Refresh access token using refresh token
50
+ * @param refreshToken - Refresh token
51
+ * @returns New OAuth tokens
52
+ * @throws Error if refresh fails
53
+ */
54
+ refreshAccessToken(refreshToken: string): DropboxOAuthTokens;
55
+ /**
56
+ * Validate access token by making a test request to Dropbox API
57
+ * @param accessToken - Access token to validate
58
+ * @returns True if token is valid, false otherwise
59
+ */
60
+ validateToken(accessToken: string): Promise<boolean>;
61
+ /**
62
+ * Get a valid access token, automatically refreshing if expired
63
+ * Requires storage to be configured
64
+ * @param storageKey - Key to retrieve tokens from storage
65
+ * @returns Valid access token
66
+ * @throws Error if storage not configured or tokens not found
67
+ */
68
+ getValidToken(storageKey: string): Promise<string>;
69
+ /**
70
+ * Store tokens using configured storage
71
+ * @param key - Storage key
72
+ * @param tokens - Tokens to store
73
+ * @throws Error if storage not configured
74
+ */
75
+ storeTokens(key: string, tokens: DropboxOAuthTokens): Promise<void>;
76
+ /**
77
+ * Revoke and delete tokens from storage
78
+ * @param storageKey - Storage key
79
+ * @throws Error if storage not configured
80
+ */
81
+ revokeTokens(storageKey: string): Promise<void>;
82
+ }
83
+ //# sourceMappingURL=DropboxOAuth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DropboxOAuth.d.ts","sourceRoot":"","sources":["../src/DropboxOAuth.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,MAAM,EAAgB,MAAM,oBAAoB,CAAC;AAG1D,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,YAAY,EAEb,MAAM,SAAS,CAAC;AAEjB;;GAEG;AACH,MAAM,WAAW,4BAA6B,SAAQ,kBAAkB;IACtE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,IAAI,CAAc;IAE1B;;;;OAIG;gBACS,MAAM,EAAE,4BAA4B,EAAE,OAAO,CAAC,EAAE,YAAY;IAwBxE;;;;;OAKG;IACH,mBAAmB,CACjB,KAAK,CAAC,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,EAAE,GAChB;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;IA+BjC;;;;;;OAMG;IACG,qBAAqB,CACzB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,kBAAkB,CAAC;IAyC9B;;;;;OAKG;IACH,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,kBAAkB;IAwC5D;;;;OAIG;IACG,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAc1D;;;;;;OAMG;IACG,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA0BxD;;;;;OAKG;IACG,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IASzE;;;;OAIG;IACG,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAQtD"}
@@ -0,0 +1,228 @@
1
+ "use strict";
2
+ /*
3
+ Copyright (c) 2025 Bernier LLC
4
+
5
+ This file is licensed to the client under a limited-use license.
6
+ The client may use and modify this code *only within the scope of the project it was delivered for*.
7
+ Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.DropboxOAuth = void 0;
11
+ const logger_1 = require("@bernierllc/logger");
12
+ const dropbox_1 = require("dropbox");
13
+ const uuid_1 = require("uuid");
14
+ /**
15
+ * DropboxOAuth - OAuth 2.0 authentication and token management for Dropbox
16
+ *
17
+ * Handles:
18
+ * - Authorization URL generation with PKCE
19
+ * - Authorization code exchange
20
+ * - Token refresh
21
+ * - Token validation
22
+ * - Automatic token refresh with storage
23
+ */
24
+ class DropboxOAuth {
25
+ /**
26
+ * Create a new DropboxOAuth instance
27
+ * @param config - OAuth configuration
28
+ * @param storage - Optional token storage for automatic refresh
29
+ */
30
+ constructor(config, storage) {
31
+ this.config = {
32
+ clientId: config.clientId,
33
+ clientSecret: config.clientSecret,
34
+ redirectUri: config.redirectUri,
35
+ };
36
+ this.logger =
37
+ config.logger ||
38
+ (0, logger_1.createLogger)({
39
+ context: {
40
+ service: "DropboxOAuth",
41
+ version: "0.1.0",
42
+ environment: process.env.NODE_ENV || "development",
43
+ },
44
+ });
45
+ this.storage = storage;
46
+ // Initialize DropboxAuth
47
+ this.auth = new dropbox_1.DropboxAuth({
48
+ clientId: this.config.clientId,
49
+ clientSecret: this.config.clientSecret,
50
+ });
51
+ }
52
+ /**
53
+ * Generate OAuth authorization URL with PKCE
54
+ * @param state - Optional state parameter for CSRF protection (auto-generated if not provided)
55
+ * @param scopes - Requested Dropbox scopes (default: ['files.content.write', 'files.content.read'])
56
+ * @returns Object with authorization URL and state
57
+ */
58
+ getAuthorizationUrl(state, scopes) {
59
+ const authState = state || (0, uuid_1.v4)();
60
+ const requestedScopes = scopes || [
61
+ "files.content.write",
62
+ "files.content.read",
63
+ "account_info.read",
64
+ ];
65
+ // Dropbox uses PKCE, so we need to get the auth URL from the SDK
66
+ // getAuthenticationUrl returns a string synchronously
67
+ const authUrl = this.auth.getAuthenticationUrl(this.config.redirectUri, authState, "code", "offline", requestedScopes, "none", false);
68
+ this.logger.info("Authorization URL generated", {
69
+ state: authState,
70
+ scopes: requestedScopes,
71
+ });
72
+ return {
73
+ url: authUrl,
74
+ state: authState,
75
+ };
76
+ }
77
+ /**
78
+ * Exchange authorization code for access and refresh tokens
79
+ * @param code - Authorization code from OAuth callback
80
+ * @param state - State token for CSRF validation
81
+ * @returns OAuth tokens
82
+ * @throws Error if exchange fails
83
+ */
84
+ async exchangeCodeForTokens(code, _state) {
85
+ try {
86
+ // Dropbox SDK handles the token exchange
87
+ const tokenResult = await this.auth.getAccessTokenFromCode(this.config.redirectUri, code);
88
+ if (!tokenResult.result) {
89
+ throw new Error("No token result from Dropbox");
90
+ }
91
+ const result = tokenResult.result;
92
+ const tokens = {
93
+ accessToken: result.access_token,
94
+ refreshToken: result.refresh_token ?? undefined,
95
+ expiresAt: result.expires_in
96
+ ? new Date(Date.now() + result.expires_in * 1000)
97
+ : undefined,
98
+ tokenType: result.token_type ?? "bearer",
99
+ scope: result.scope ?? undefined,
100
+ accountId: result.account_id ?? undefined,
101
+ };
102
+ this.logger.info("OAuth tokens obtained", {
103
+ hasRefreshToken: !!tokens.refreshToken,
104
+ expiresAt: tokens.expiresAt,
105
+ accountId: tokens.accountId,
106
+ });
107
+ return tokens;
108
+ }
109
+ catch (error) {
110
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
111
+ this.logger.error("Failed to exchange code for tokens", undefined, {
112
+ errorMessage,
113
+ });
114
+ throw new Error(`OAuth token exchange failed: ${errorMessage}`);
115
+ }
116
+ }
117
+ /**
118
+ * Refresh access token using refresh token
119
+ * @param refreshToken - Refresh token
120
+ * @returns New OAuth tokens
121
+ * @throws Error if refresh fails
122
+ */
123
+ refreshAccessToken(refreshToken) {
124
+ try {
125
+ // Set the refresh token in the auth instance
126
+ this.auth.setRefreshToken(refreshToken);
127
+ // Refresh access token - this updates the internal state
128
+ // Note: refreshAccessToken() returns void but is synchronous
129
+ this.auth.refreshAccessToken();
130
+ // Get the access token from the auth instance
131
+ const accessToken = this.auth.getAccessToken();
132
+ if (!accessToken) {
133
+ throw new Error("No access token after refresh");
134
+ }
135
+ // Dropbox refresh doesn't return expiry, so we'll set a default
136
+ // Access tokens typically last 4 hours
137
+ const tokens = {
138
+ accessToken: accessToken,
139
+ refreshToken: refreshToken || undefined, // Keep existing refresh token
140
+ expiresAt: new Date(Date.now() + 4 * 60 * 60 * 1000), // 4 hours default
141
+ tokenType: "bearer",
142
+ scope: undefined,
143
+ };
144
+ this.logger.info("Access token refreshed", {
145
+ expiresAt: tokens.expiresAt,
146
+ });
147
+ return tokens;
148
+ }
149
+ catch (error) {
150
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
151
+ this.logger.error("Failed to refresh access token", undefined, {
152
+ errorMessage,
153
+ });
154
+ throw new Error(`Token refresh failed: ${errorMessage}`);
155
+ }
156
+ }
157
+ /**
158
+ * Validate access token by making a test request to Dropbox API
159
+ * @param accessToken - Access token to validate
160
+ * @returns True if token is valid, false otherwise
161
+ */
162
+ async validateToken(accessToken) {
163
+ try {
164
+ const dbx = new dropbox_1.Dropbox({ accessToken });
165
+ const response = await dbx.usersGetCurrentAccount();
166
+ return !!response.result;
167
+ }
168
+ catch (error) {
169
+ this.logger.warn("Token validation failed", {
170
+ error: error instanceof Error ? error.message : "Unknown error",
171
+ });
172
+ return false;
173
+ }
174
+ }
175
+ /**
176
+ * Get a valid access token, automatically refreshing if expired
177
+ * Requires storage to be configured
178
+ * @param storageKey - Key to retrieve tokens from storage
179
+ * @returns Valid access token
180
+ * @throws Error if storage not configured or tokens not found
181
+ */
182
+ async getValidToken(storageKey) {
183
+ if (!this.storage) {
184
+ throw new Error("Token storage not configured");
185
+ }
186
+ const tokens = await this.storage.retrieve(storageKey);
187
+ if (!tokens) {
188
+ throw new Error("No tokens found in storage");
189
+ }
190
+ // Check if token is expired (with 5 minute buffer)
191
+ const isExpiring = tokens.expiresAt &&
192
+ tokens.expiresAt.getTime() - Date.now() < 5 * 60 * 1000;
193
+ if (isExpiring && tokens.refreshToken) {
194
+ this.logger.info("Token expiring, refreshing...", { storageKey });
195
+ const newTokens = this.refreshAccessToken(tokens.refreshToken);
196
+ await this.storage.store(storageKey, newTokens);
197
+ return newTokens.accessToken;
198
+ }
199
+ return tokens.accessToken;
200
+ }
201
+ /**
202
+ * Store tokens using configured storage
203
+ * @param key - Storage key
204
+ * @param tokens - Tokens to store
205
+ * @throws Error if storage not configured
206
+ */
207
+ async storeTokens(key, tokens) {
208
+ if (!this.storage) {
209
+ throw new Error("Token storage not configured");
210
+ }
211
+ await this.storage.store(key, tokens);
212
+ this.logger.info("Tokens stored", { key });
213
+ }
214
+ /**
215
+ * Revoke and delete tokens from storage
216
+ * @param storageKey - Storage key
217
+ * @throws Error if storage not configured
218
+ */
219
+ async revokeTokens(storageKey) {
220
+ if (!this.storage) {
221
+ throw new Error("Token storage not configured");
222
+ }
223
+ await this.storage.delete(storageKey);
224
+ this.logger.info("Tokens revoked", { storageKey });
225
+ }
226
+ }
227
+ exports.DropboxOAuth = DropboxOAuth;
228
+ //# sourceMappingURL=DropboxOAuth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DropboxOAuth.js","sourceRoot":"","sources":["../src/DropboxOAuth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { DropboxOAuth, type DropboxOAuthConfigWithLogger, } from "./DropboxOAuth";
2
+ export type { DropboxOAuthTokens, DropboxOAuthConfig, TokenStorage, } from "./types";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,YAAY,EACZ,KAAK,4BAA4B,GAClC,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,kBAAkB,EAClB,kBAAkB,EAClB,YAAY,GACb,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ /*
3
+ Copyright (c) 2025 Bernier LLC
4
+
5
+ This file is licensed to the client under a limited-use license.
6
+ The client may use and modify this code *only within the scope of the project it was delivered for*.
7
+ Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.DropboxOAuth = void 0;
11
+ var DropboxOAuth_1 = require("./DropboxOAuth");
12
+ Object.defineProperty(exports, "DropboxOAuth", { enumerable: true, get: function () { return DropboxOAuth_1.DropboxOAuth; } });
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;EAME;;;AAEF,+CAGwB;AAFtB,4GAAA,YAAY,OAAA"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * OAuth 2.0 tokens returned by Dropbox
3
+ */
4
+ export interface DropboxOAuthTokens {
5
+ accessToken: string;
6
+ refreshToken?: string | undefined;
7
+ expiresAt?: Date | undefined;
8
+ tokenType: string;
9
+ scope?: string | undefined;
10
+ accountId?: string | undefined;
11
+ }
12
+ /**
13
+ * OAuth 2.0 configuration for Dropbox
14
+ */
15
+ export interface DropboxOAuthConfig {
16
+ clientId: string;
17
+ clientSecret: string;
18
+ redirectUri: string;
19
+ logger?: import("@bernierllc/logger").Logger;
20
+ }
21
+ /**
22
+ * Token storage interface for persistent credential management
23
+ */
24
+ export interface TokenStorage {
25
+ /**
26
+ * Store OAuth tokens
27
+ * @param key - Storage key (e.g., user ID)
28
+ * @param tokens - OAuth tokens to store
29
+ */
30
+ store(_key: string, _tokens: DropboxOAuthTokens): Promise<void>;
31
+ /**
32
+ * Retrieve OAuth tokens
33
+ * @param key - Storage key
34
+ * @returns Tokens if found, null otherwise
35
+ */
36
+ retrieve(_key: string): Promise<DropboxOAuthTokens | null>;
37
+ /**
38
+ * Delete OAuth tokens
39
+ * @param key - Storage key
40
+ */
41
+ delete(_key: string): Promise<void>;
42
+ }
43
+ /**
44
+ * Dropbox API token result structure
45
+ * This matches the structure returned by Dropbox SDK's getAccessTokenFromCode
46
+ */
47
+ export interface DropboxTokenResult {
48
+ access_token: string;
49
+ refresh_token?: string;
50
+ expires_in?: number;
51
+ token_type?: string;
52
+ scope?: string;
53
+ account_id?: string;
54
+ }
55
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,SAAS,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,oBAAoB,EAAE,MAAM,CAAC;CAC9C;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhE;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC;IAE3D;;;OAGG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrC;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB"}
package/dist/types.js ADDED
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ /*
3
+ Copyright (c) 2025 Bernier LLC
4
+
5
+ This file is licensed to the client under a limited-use license.
6
+ The client may use and modify this code *only within the scope of the project it was delivered for*.
7
+ Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA;;;;;;EAME"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@bernierllc/dropbox-oauth",
3
+ "version": "0.2.0",
4
+ "description": "OAuth 2.0 authentication and token management for Dropbox",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "author": "Bernier LLC",
8
+ "license": "SEE LICENSE IN LICENSE",
9
+ "files": [
10
+ "dist",
11
+ "LICENSE"
12
+ ],
13
+ "publishConfig": {
14
+ "access": "public",
15
+ "registry": "https://registry.npmjs.org/"
16
+ },
17
+ "dependencies": {
18
+ "dropbox": "^10.34.0",
19
+ "uuid": "^11.1.0",
20
+ "@bernierllc/logger": "1.0.3"
21
+ },
22
+ "devDependencies": {
23
+ "@types/jest": "^29.5.12",
24
+ "@types/node": "^20.12.12",
25
+ "@types/uuid": "^9.0.4",
26
+ "@typescript-eslint/eslint-plugin": "^7.9.0",
27
+ "@typescript-eslint/parser": "^7.9.0",
28
+ "eslint": "^8.57.0",
29
+ "eslint-config-prettier": "^9.1.0",
30
+ "eslint-plugin-prettier": "^5.1.3",
31
+ "jest": "^29.7.0",
32
+ "prettier": "^3.2.5",
33
+ "ts-jest": "^29.1.2",
34
+ "typescript": "^5.4.5"
35
+ },
36
+ "peerDependencies": {
37
+ "dropbox": "^10.34.0"
38
+ },
39
+ "scripts": {
40
+ "build": "tsc",
41
+ "test": "jest",
42
+ "test:run": "jest --runInBand --collectCoverage",
43
+ "test:coverage": "jest --runInBand --collectCoverage",
44
+ "lint": "eslint \"src/**/*.ts\" \"__tests__/**/*.ts\" --max-warnings 0"
45
+ }
46
+ }