@jezweb/oauth-token-manager 0.1.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 +184 -0
- package/SECURITY.md +162 -0
- package/dist/crypto.d.ts +43 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +107 -0
- package/dist/crypto.js.map +1 -0
- package/dist/errors.d.ts +75 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +117 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +58 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/github.d.ts +45 -0
- package/dist/providers/github.d.ts.map +1 -0
- package/dist/providers/github.js +70 -0
- package/dist/providers/github.js.map +1 -0
- package/dist/providers/google.d.ts +24 -0
- package/dist/providers/google.d.ts.map +1 -0
- package/dist/providers/google.js +63 -0
- package/dist/providers/google.js.map +1 -0
- package/dist/providers/microsoft.d.ts +29 -0
- package/dist/providers/microsoft.d.ts.map +1 -0
- package/dist/providers/microsoft.js +72 -0
- package/dist/providers/microsoft.js.map +1 -0
- package/dist/providers/types.d.ts +7 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +7 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/storage/d1.d.ts +22 -0
- package/dist/storage/d1.d.ts.map +1 -0
- package/dist/storage/d1.js +31 -0
- package/dist/storage/d1.js.map +1 -0
- package/dist/storage/kv.d.ts +38 -0
- package/dist/storage/kv.d.ts.map +1 -0
- package/dist/storage/kv.js +143 -0
- package/dist/storage/kv.js.map +1 -0
- package/dist/storage/types.d.ts +7 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/storage/types.js +7 -0
- package/dist/storage/types.js.map +1 -0
- package/dist/token-manager.d.ts +88 -0
- package/dist/token-manager.d.ts.map +1 -0
- package/dist/token-manager.js +199 -0
- package/dist/token-manager.js.map +1 -0
- package/dist/types.d.ts +158 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +88 -0
package/dist/errors.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error types for OAuth Token Manager
|
|
3
|
+
*
|
|
4
|
+
* These errors provide clear, actionable information about what went wrong
|
|
5
|
+
* and what the application should do to recover.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Base error class for all token manager errors
|
|
9
|
+
*/
|
|
10
|
+
export class TokenManagerError extends Error {
|
|
11
|
+
code;
|
|
12
|
+
constructor(message, code) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.code = code;
|
|
15
|
+
this.name = 'TokenManagerError';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Token not found for the given user and provider
|
|
20
|
+
*
|
|
21
|
+
* Recovery: Redirect user to OAuth flow to connect this provider
|
|
22
|
+
*/
|
|
23
|
+
export class TokenNotFoundError extends TokenManagerError {
|
|
24
|
+
userId;
|
|
25
|
+
provider;
|
|
26
|
+
constructor(userId, provider) {
|
|
27
|
+
super(`No token found for user "${userId}" and provider "${provider}". User needs to connect this provider.`, 'TOKEN_NOT_FOUND');
|
|
28
|
+
this.userId = userId;
|
|
29
|
+
this.provider = provider;
|
|
30
|
+
this.name = 'TokenNotFoundError';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Token has expired and refresh failed or no refresh token available
|
|
35
|
+
*
|
|
36
|
+
* Recovery: Redirect user to OAuth flow to re-authenticate
|
|
37
|
+
*/
|
|
38
|
+
export class TokenExpiredError extends TokenManagerError {
|
|
39
|
+
userId;
|
|
40
|
+
provider;
|
|
41
|
+
reason;
|
|
42
|
+
constructor(userId, provider, reason) {
|
|
43
|
+
const reasons = {
|
|
44
|
+
no_refresh_token: 'No refresh token available',
|
|
45
|
+
refresh_failed: 'Token refresh request failed',
|
|
46
|
+
refresh_token_expired: 'Refresh token has expired',
|
|
47
|
+
};
|
|
48
|
+
super(`Token expired for user "${userId}" and provider "${provider}". ${reasons[reason]}. User needs to re-authenticate.`, 'TOKEN_EXPIRED');
|
|
49
|
+
this.userId = userId;
|
|
50
|
+
this.provider = provider;
|
|
51
|
+
this.reason = reason;
|
|
52
|
+
this.name = 'TokenExpiredError';
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Token exists but doesn't have the required scopes
|
|
57
|
+
*
|
|
58
|
+
* Recovery: Redirect user to OAuth flow with incremental consent for missing scopes
|
|
59
|
+
*/
|
|
60
|
+
export class InsufficientScopesError extends TokenManagerError {
|
|
61
|
+
userId;
|
|
62
|
+
provider;
|
|
63
|
+
requiredScopes;
|
|
64
|
+
grantedScopes;
|
|
65
|
+
constructor(userId, provider, requiredScopes, grantedScopes) {
|
|
66
|
+
const missing = requiredScopes.filter((s) => !grantedScopes.includes(s));
|
|
67
|
+
super(`Token for user "${userId}" and provider "${provider}" is missing required scopes: ${missing.join(', ')}. User needs to grant additional permissions.`, 'INSUFFICIENT_SCOPES');
|
|
68
|
+
this.userId = userId;
|
|
69
|
+
this.provider = provider;
|
|
70
|
+
this.requiredScopes = requiredScopes;
|
|
71
|
+
this.grantedScopes = grantedScopes;
|
|
72
|
+
this.name = 'InsufficientScopesError';
|
|
73
|
+
}
|
|
74
|
+
get missingScopes() {
|
|
75
|
+
return this.requiredScopes.filter((s) => !this.grantedScopes.includes(s));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Provider is not configured in the token manager
|
|
80
|
+
*
|
|
81
|
+
* Recovery: Add provider configuration to TokenManager constructor
|
|
82
|
+
*/
|
|
83
|
+
export class ProviderNotConfiguredError extends TokenManagerError {
|
|
84
|
+
provider;
|
|
85
|
+
constructor(provider) {
|
|
86
|
+
super(`Provider "${provider}" is not configured. Add it to the TokenManager providers config.`, 'PROVIDER_NOT_CONFIGURED');
|
|
87
|
+
this.provider = provider;
|
|
88
|
+
this.name = 'ProviderNotConfiguredError';
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Encryption/decryption failed
|
|
93
|
+
*
|
|
94
|
+
* Recovery: Check encryption key is correct and hasn't changed
|
|
95
|
+
*/
|
|
96
|
+
export class CryptoError extends TokenManagerError {
|
|
97
|
+
cause;
|
|
98
|
+
constructor(operation, cause) {
|
|
99
|
+
super(`Failed to ${operation} token data. This may indicate a corrupted token or incorrect encryption key.`, 'CRYPTO_ERROR');
|
|
100
|
+
this.cause = cause;
|
|
101
|
+
this.name = 'CryptoError';
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Storage operation failed
|
|
106
|
+
*
|
|
107
|
+
* Recovery: Check storage backend (KV/D1) is available and configured correctly
|
|
108
|
+
*/
|
|
109
|
+
export class StorageError extends TokenManagerError {
|
|
110
|
+
cause;
|
|
111
|
+
constructor(operation, cause) {
|
|
112
|
+
super(`Storage operation "${operation}" failed. Check your storage backend configuration.`, 'STORAGE_ERROR');
|
|
113
|
+
this.cause = cause;
|
|
114
|
+
this.name = 'StorageError';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jezweb/oauth-token-manager
|
|
3
|
+
*
|
|
4
|
+
* OAuth token management for Cloudflare Workers.
|
|
5
|
+
* Store, refresh, and retrieve tokens for downstream API access.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { TokenManager } from '@jezweb/oauth-token-manager';
|
|
10
|
+
* import { KVStorage } from '@jezweb/oauth-token-manager/storage/kv';
|
|
11
|
+
*
|
|
12
|
+
* const tokens = new TokenManager({
|
|
13
|
+
* storage: new KVStorage({
|
|
14
|
+
* namespace: env.TOKEN_KV,
|
|
15
|
+
* encryptionKey: env.TOKEN_ENCRYPTION_KEY,
|
|
16
|
+
* }),
|
|
17
|
+
* encryptionKey: env.TOKEN_ENCRYPTION_KEY,
|
|
18
|
+
* providers: {
|
|
19
|
+
* google: {
|
|
20
|
+
* clientId: env.GOOGLE_CLIENT_ID,
|
|
21
|
+
* clientSecret: env.GOOGLE_CLIENT_SECRET,
|
|
22
|
+
* },
|
|
23
|
+
* },
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* // Store token after OAuth callback
|
|
27
|
+
* await tokens.store({
|
|
28
|
+
* userId: 'user-123',
|
|
29
|
+
* provider: 'google',
|
|
30
|
+
* accessToken: '...',
|
|
31
|
+
* refreshToken: '...',
|
|
32
|
+
* expiresAt: Date.now() + 3600000,
|
|
33
|
+
* scopes: ['calendar', 'drive'],
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
* // Get valid token (auto-refreshes if expired)
|
|
37
|
+
* const { accessToken } = await tokens.get({
|
|
38
|
+
* userId: 'user-123',
|
|
39
|
+
* provider: 'google',
|
|
40
|
+
* requiredScopes: ['calendar'],
|
|
41
|
+
* });
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @packageDocumentation
|
|
45
|
+
*/
|
|
46
|
+
export { TokenManager } from './token-manager';
|
|
47
|
+
export type { TokenManagerConfig, TokenStorage, TokenProvider, ProviderConfig, StoredToken, TokenData, StoreTokenOptions, GetTokenOptions, ListTokensOptions, ConnectedProvider, RevokeTokenOptions, RefreshResult, } from './types';
|
|
48
|
+
export { TokenManagerError, TokenNotFoundError, TokenExpiredError, InsufficientScopesError, ProviderNotConfiguredError, CryptoError, StorageError, } from './errors';
|
|
49
|
+
export { encrypt, decrypt, encryptObject, decryptObject } from './crypto';
|
|
50
|
+
export { KVStorage, type KVStorageOptions } from './storage/kv';
|
|
51
|
+
export { GoogleProvider, googleProvider } from './providers/google';
|
|
52
|
+
export { MicrosoftProvider, microsoftProvider } from './providers/microsoft';
|
|
53
|
+
export { GitHubProvider, githubProvider, revokeGitHubToken, } from './providers/github';
|
|
54
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG/C,YAAY,EACV,kBAAkB,EAClB,YAAY,EACZ,aAAa,EACb,cAAc,EACd,WAAW,EACX,SAAS,EACT,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,aAAa,GACd,MAAM,SAAS,CAAC;AAGjB,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,uBAAuB,EACvB,0BAA0B,EAC1B,WAAW,EACX,YAAY,GACb,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAG1E,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGhE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,EACL,cAAc,EACd,cAAc,EACd,iBAAiB,GAClB,MAAM,oBAAoB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jezweb/oauth-token-manager
|
|
3
|
+
*
|
|
4
|
+
* OAuth token management for Cloudflare Workers.
|
|
5
|
+
* Store, refresh, and retrieve tokens for downstream API access.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { TokenManager } from '@jezweb/oauth-token-manager';
|
|
10
|
+
* import { KVStorage } from '@jezweb/oauth-token-manager/storage/kv';
|
|
11
|
+
*
|
|
12
|
+
* const tokens = new TokenManager({
|
|
13
|
+
* storage: new KVStorage({
|
|
14
|
+
* namespace: env.TOKEN_KV,
|
|
15
|
+
* encryptionKey: env.TOKEN_ENCRYPTION_KEY,
|
|
16
|
+
* }),
|
|
17
|
+
* encryptionKey: env.TOKEN_ENCRYPTION_KEY,
|
|
18
|
+
* providers: {
|
|
19
|
+
* google: {
|
|
20
|
+
* clientId: env.GOOGLE_CLIENT_ID,
|
|
21
|
+
* clientSecret: env.GOOGLE_CLIENT_SECRET,
|
|
22
|
+
* },
|
|
23
|
+
* },
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* // Store token after OAuth callback
|
|
27
|
+
* await tokens.store({
|
|
28
|
+
* userId: 'user-123',
|
|
29
|
+
* provider: 'google',
|
|
30
|
+
* accessToken: '...',
|
|
31
|
+
* refreshToken: '...',
|
|
32
|
+
* expiresAt: Date.now() + 3600000,
|
|
33
|
+
* scopes: ['calendar', 'drive'],
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
* // Get valid token (auto-refreshes if expired)
|
|
37
|
+
* const { accessToken } = await tokens.get({
|
|
38
|
+
* userId: 'user-123',
|
|
39
|
+
* provider: 'google',
|
|
40
|
+
* requiredScopes: ['calendar'],
|
|
41
|
+
* });
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @packageDocumentation
|
|
45
|
+
*/
|
|
46
|
+
// Main class
|
|
47
|
+
export { TokenManager } from './token-manager';
|
|
48
|
+
// Errors
|
|
49
|
+
export { TokenManagerError, TokenNotFoundError, TokenExpiredError, InsufficientScopesError, ProviderNotConfiguredError, CryptoError, StorageError, } from './errors';
|
|
50
|
+
// Crypto utilities (for advanced usage)
|
|
51
|
+
export { encrypt, decrypt, encryptObject, decryptObject } from './crypto';
|
|
52
|
+
// Storage adapters (re-exported for convenience)
|
|
53
|
+
export { KVStorage } from './storage/kv';
|
|
54
|
+
// Provider implementations (for extension)
|
|
55
|
+
export { GoogleProvider, googleProvider } from './providers/google';
|
|
56
|
+
export { MicrosoftProvider, microsoftProvider } from './providers/microsoft';
|
|
57
|
+
export { GitHubProvider, githubProvider, revokeGitHubToken, } from './providers/github';
|
|
58
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,aAAa;AACb,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAkB/C,SAAS;AACT,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,uBAAuB,EACvB,0BAA0B,EAC1B,WAAW,EACX,YAAY,GACb,MAAM,UAAU,CAAC;AAElB,wCAAwC;AACxC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE1E,iDAAiD;AACjD,OAAO,EAAE,SAAS,EAAyB,MAAM,cAAc,CAAC;AAEhE,2CAA2C;AAC3C,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,EACL,cAAc,EACd,cAAc,EACd,iBAAiB,GAClB,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub OAuth Provider
|
|
3
|
+
*
|
|
4
|
+
* Token characteristics:
|
|
5
|
+
* - Access token lifetime: Does not expire!
|
|
6
|
+
* - Refresh token: Not applicable (tokens don't expire)
|
|
7
|
+
* - Token rotation: Not applicable
|
|
8
|
+
*
|
|
9
|
+
* GitHub tokens are valid until explicitly revoked by the user or
|
|
10
|
+
* the OAuth app is deleted. This makes GitHub simpler to handle
|
|
11
|
+
* but also means stale tokens may accumulate if users disconnect
|
|
12
|
+
* without revoking access.
|
|
13
|
+
*
|
|
14
|
+
* To revoke a token programmatically, use the GitHub API:
|
|
15
|
+
* DELETE /applications/{client_id}/token
|
|
16
|
+
*/
|
|
17
|
+
import type { TokenProvider, ProviderConfig, RefreshResult } from '../types';
|
|
18
|
+
/**
|
|
19
|
+
* GitHub OAuth token provider
|
|
20
|
+
*
|
|
21
|
+
* Note: GitHub tokens don't expire, so refresh() is a no-op that
|
|
22
|
+
* always returns null (indicating no refresh was needed/possible).
|
|
23
|
+
*/
|
|
24
|
+
export declare class GitHubProvider implements TokenProvider {
|
|
25
|
+
readonly id = "github";
|
|
26
|
+
readonly supportsRefresh = false;
|
|
27
|
+
refresh(_refreshToken: string, _config: ProviderConfig): Promise<RefreshResult | null>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Default GitHub provider instance
|
|
31
|
+
*/
|
|
32
|
+
export declare const githubProvider: GitHubProvider;
|
|
33
|
+
/**
|
|
34
|
+
* Revoke a GitHub OAuth token
|
|
35
|
+
*
|
|
36
|
+
* Call this when a user disconnects their GitHub account to properly
|
|
37
|
+
* clean up the token on GitHub's side.
|
|
38
|
+
*
|
|
39
|
+
* @param accessToken - The token to revoke
|
|
40
|
+
* @param clientId - Your GitHub OAuth app client ID
|
|
41
|
+
* @param clientSecret - Your GitHub OAuth app client secret
|
|
42
|
+
* @returns true if revoked successfully, false otherwise
|
|
43
|
+
*/
|
|
44
|
+
export declare function revokeGitHubToken(accessToken: string, clientId: string, clientSecret: string): Promise<boolean>;
|
|
45
|
+
//# sourceMappingURL=github.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/providers/github.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE7E;;;;;GAKG;AACH,qBAAa,cAAe,YAAW,aAAa;IAClD,QAAQ,CAAC,EAAE,YAAY;IACvB,QAAQ,CAAC,eAAe,SAAS;IAE3B,OAAO,CACX,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;CASjC;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,gBAAuB,CAAC;AAEnD;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,OAAO,CAAC,CAuBlB"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub OAuth Provider
|
|
3
|
+
*
|
|
4
|
+
* Token characteristics:
|
|
5
|
+
* - Access token lifetime: Does not expire!
|
|
6
|
+
* - Refresh token: Not applicable (tokens don't expire)
|
|
7
|
+
* - Token rotation: Not applicable
|
|
8
|
+
*
|
|
9
|
+
* GitHub tokens are valid until explicitly revoked by the user or
|
|
10
|
+
* the OAuth app is deleted. This makes GitHub simpler to handle
|
|
11
|
+
* but also means stale tokens may accumulate if users disconnect
|
|
12
|
+
* without revoking access.
|
|
13
|
+
*
|
|
14
|
+
* To revoke a token programmatically, use the GitHub API:
|
|
15
|
+
* DELETE /applications/{client_id}/token
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* GitHub OAuth token provider
|
|
19
|
+
*
|
|
20
|
+
* Note: GitHub tokens don't expire, so refresh() is a no-op that
|
|
21
|
+
* always returns null (indicating no refresh was needed/possible).
|
|
22
|
+
*/
|
|
23
|
+
export class GitHubProvider {
|
|
24
|
+
id = 'github';
|
|
25
|
+
supportsRefresh = false;
|
|
26
|
+
async refresh(_refreshToken, _config) {
|
|
27
|
+
// GitHub tokens don't expire - no refresh needed
|
|
28
|
+
// If a token is invalid, user needs to re-authenticate
|
|
29
|
+
console.warn('[GitHubProvider] refresh() called but GitHub tokens do not expire. ' +
|
|
30
|
+
'If the token is invalid, user needs to re-authenticate.');
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Default GitHub provider instance
|
|
36
|
+
*/
|
|
37
|
+
export const githubProvider = new GitHubProvider();
|
|
38
|
+
/**
|
|
39
|
+
* Revoke a GitHub OAuth token
|
|
40
|
+
*
|
|
41
|
+
* Call this when a user disconnects their GitHub account to properly
|
|
42
|
+
* clean up the token on GitHub's side.
|
|
43
|
+
*
|
|
44
|
+
* @param accessToken - The token to revoke
|
|
45
|
+
* @param clientId - Your GitHub OAuth app client ID
|
|
46
|
+
* @param clientSecret - Your GitHub OAuth app client secret
|
|
47
|
+
* @returns true if revoked successfully, false otherwise
|
|
48
|
+
*/
|
|
49
|
+
export async function revokeGitHubToken(accessToken, clientId, clientSecret) {
|
|
50
|
+
try {
|
|
51
|
+
const response = await fetch(`https://api.github.com/applications/${clientId}/token`, {
|
|
52
|
+
method: 'DELETE',
|
|
53
|
+
headers: {
|
|
54
|
+
Accept: 'application/vnd.github+json',
|
|
55
|
+
'X-GitHub-Api-Version': '2022-11-28',
|
|
56
|
+
Authorization: `Basic ${btoa(`${clientId}:${clientSecret}`)}`,
|
|
57
|
+
'Content-Type': 'application/json',
|
|
58
|
+
},
|
|
59
|
+
body: JSON.stringify({ access_token: accessToken }),
|
|
60
|
+
});
|
|
61
|
+
// 204 No Content = success
|
|
62
|
+
// 404 = token already invalid/revoked
|
|
63
|
+
return response.status === 204 || response.status === 404;
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
console.error('[GitHubProvider] Token revocation failed:', error);
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=github.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/providers/github.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH;;;;;GAKG;AACH,MAAM,OAAO,cAAc;IAChB,EAAE,GAAG,QAAQ,CAAC;IACd,eAAe,GAAG,KAAK,CAAC;IAEjC,KAAK,CAAC,OAAO,CACX,aAAqB,EACrB,OAAuB;QAEvB,iDAAiD;QACjD,uDAAuD;QACvD,OAAO,CAAC,IAAI,CACV,qEAAqE;YACnE,yDAAyD,CAC5D,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,cAAc,EAAE,CAAC;AAEnD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,WAAmB,EACnB,QAAgB,EAChB,YAAoB;IAEpB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAC1B,uCAAuC,QAAQ,QAAQ,EACvD;YACE,MAAM,EAAE,QAAQ;YAChB,OAAO,EAAE;gBACP,MAAM,EAAE,6BAA6B;gBACrC,sBAAsB,EAAE,YAAY;gBACpC,aAAa,EAAE,SAAS,IAAI,CAAC,GAAG,QAAQ,IAAI,YAAY,EAAE,CAAC,EAAE;gBAC7D,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC;SACpD,CACF,CAAC;QAEF,2BAA2B;QAC3B,sCAAsC;QACtC,OAAO,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,CAAC;IAC5D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,2CAA2C,EAAE,KAAK,CAAC,CAAC;QAClE,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google OAuth Provider
|
|
3
|
+
*
|
|
4
|
+
* Token characteristics:
|
|
5
|
+
* - Access token lifetime: ~1 hour
|
|
6
|
+
* - Refresh token: Does not expire (unless revoked)
|
|
7
|
+
* - Token rotation: Optional (configurable in Google Cloud Console)
|
|
8
|
+
*
|
|
9
|
+
* Requires `access_type=offline` during initial OAuth to get refresh token
|
|
10
|
+
*/
|
|
11
|
+
import type { TokenProvider, ProviderConfig, RefreshResult } from '../types';
|
|
12
|
+
/**
|
|
13
|
+
* Google OAuth token provider
|
|
14
|
+
*/
|
|
15
|
+
export declare class GoogleProvider implements TokenProvider {
|
|
16
|
+
readonly id = "google";
|
|
17
|
+
readonly supportsRefresh = true;
|
|
18
|
+
refresh(refreshToken: string, config: ProviderConfig): Promise<RefreshResult | null>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Default Google provider instance
|
|
22
|
+
*/
|
|
23
|
+
export declare const googleProvider: GoogleProvider;
|
|
24
|
+
//# sourceMappingURL=google.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../src/providers/google.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAiB7E;;GAEG;AACH,qBAAa,cAAe,YAAW,aAAa;IAClD,QAAQ,CAAC,EAAE,YAAY;IACvB,QAAQ,CAAC,eAAe,QAAQ;IAE1B,OAAO,CACX,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;CAgDjC;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,gBAAuB,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google OAuth Provider
|
|
3
|
+
*
|
|
4
|
+
* Token characteristics:
|
|
5
|
+
* - Access token lifetime: ~1 hour
|
|
6
|
+
* - Refresh token: Does not expire (unless revoked)
|
|
7
|
+
* - Token rotation: Optional (configurable in Google Cloud Console)
|
|
8
|
+
*
|
|
9
|
+
* Requires `access_type=offline` during initial OAuth to get refresh token
|
|
10
|
+
*/
|
|
11
|
+
const TOKEN_URL = 'https://oauth2.googleapis.com/token';
|
|
12
|
+
/**
|
|
13
|
+
* Google OAuth token provider
|
|
14
|
+
*/
|
|
15
|
+
export class GoogleProvider {
|
|
16
|
+
id = 'google';
|
|
17
|
+
supportsRefresh = true;
|
|
18
|
+
async refresh(refreshToken, config) {
|
|
19
|
+
try {
|
|
20
|
+
const response = await fetch(TOKEN_URL, {
|
|
21
|
+
method: 'POST',
|
|
22
|
+
headers: {
|
|
23
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
24
|
+
},
|
|
25
|
+
body: new URLSearchParams({
|
|
26
|
+
client_id: config.clientId,
|
|
27
|
+
client_secret: config.clientSecret,
|
|
28
|
+
refresh_token: refreshToken,
|
|
29
|
+
grant_type: 'refresh_token',
|
|
30
|
+
}).toString(),
|
|
31
|
+
});
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
const error = (await response.json());
|
|
34
|
+
console.error(`[GoogleProvider] Token refresh failed: ${error.error} - ${error.error_description}`);
|
|
35
|
+
// Check for specific errors that indicate re-auth is needed
|
|
36
|
+
if (error.error === 'invalid_grant' ||
|
|
37
|
+
error.error === 'unauthorized_client') {
|
|
38
|
+
// Refresh token is invalid/revoked - user needs to re-authenticate
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
// Other errors - throw to retry later
|
|
42
|
+
throw new Error(`Token refresh failed: ${error.error}`);
|
|
43
|
+
}
|
|
44
|
+
const data = (await response.json());
|
|
45
|
+
return {
|
|
46
|
+
accessToken: data.access_token,
|
|
47
|
+
// Google may return a new refresh token (rare, but handle it)
|
|
48
|
+
refreshToken: data.refresh_token,
|
|
49
|
+
expiresAt: Date.now() + data.expires_in * 1000,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
console.error('[GoogleProvider] Refresh error:', error);
|
|
54
|
+
// Network errors or unexpected issues - return null to trigger re-auth
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Default Google provider instance
|
|
61
|
+
*/
|
|
62
|
+
export const googleProvider = new GoogleProvider();
|
|
63
|
+
//# sourceMappingURL=google.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google.js","sourceRoot":"","sources":["../../src/providers/google.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,SAAS,GAAG,qCAAqC,CAAC;AAexD;;GAEG;AACH,MAAM,OAAO,cAAc;IAChB,EAAE,GAAG,QAAQ,CAAC;IACd,eAAe,GAAG,IAAI,CAAC;IAEhC,KAAK,CAAC,OAAO,CACX,YAAoB,EACpB,MAAsB;QAEtB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,SAAS,EAAE;gBACtC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,mCAAmC;iBACpD;gBACD,IAAI,EAAE,IAAI,eAAe,CAAC;oBACxB,SAAS,EAAE,MAAM,CAAC,QAAQ;oBAC1B,aAAa,EAAE,MAAM,CAAC,YAAY;oBAClC,aAAa,EAAE,YAAY;oBAC3B,UAAU,EAAE,eAAe;iBAC5B,CAAC,CAAC,QAAQ,EAAE;aACd,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,KAAK,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAwB,CAAC;gBAC7D,OAAO,CAAC,KAAK,CACX,0CAA0C,KAAK,CAAC,KAAK,MAAM,KAAK,CAAC,iBAAiB,EAAE,CACrF,CAAC;gBAEF,4DAA4D;gBAC5D,IACE,KAAK,CAAC,KAAK,KAAK,eAAe;oBAC/B,KAAK,CAAC,KAAK,KAAK,qBAAqB,EACrC,CAAC;oBACD,mEAAmE;oBACnE,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,sCAAsC;gBACtC,MAAM,IAAI,KAAK,CAAC,yBAAyB,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;YAC1D,CAAC;YAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAwB,CAAC;YAE5D,OAAO;gBACL,WAAW,EAAE,IAAI,CAAC,YAAY;gBAC9B,8DAA8D;gBAC9D,YAAY,EAAE,IAAI,CAAC,aAAa;gBAChC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI;aAC/C,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,iCAAiC,EAAE,KAAK,CAAC,CAAC;YACxD,uEAAuE;YACvE,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;CACF;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Microsoft OAuth Provider (Azure AD / Entra)
|
|
3
|
+
*
|
|
4
|
+
* Token characteristics:
|
|
5
|
+
* - Access token lifetime: ~1 hour (configurable via token lifetime policies)
|
|
6
|
+
* - Refresh token: 90 days (revoked on password change)
|
|
7
|
+
* - Token rotation: Yes (Microsoft rotates refresh tokens by default)
|
|
8
|
+
*
|
|
9
|
+
* Tenant options:
|
|
10
|
+
* - 'common': Any Microsoft account (personal + work)
|
|
11
|
+
* - 'organizations': Work/school accounts only
|
|
12
|
+
* - 'consumers': Personal Microsoft accounts only
|
|
13
|
+
* - '{tenant-id}': Specific organization only
|
|
14
|
+
*/
|
|
15
|
+
import type { TokenProvider, ProviderConfig, RefreshResult } from '../types';
|
|
16
|
+
/**
|
|
17
|
+
* Microsoft OAuth token provider
|
|
18
|
+
*/
|
|
19
|
+
export declare class MicrosoftProvider implements TokenProvider {
|
|
20
|
+
readonly id = "microsoft";
|
|
21
|
+
readonly supportsRefresh = true;
|
|
22
|
+
private getTokenUrl;
|
|
23
|
+
refresh(refreshToken: string, config: ProviderConfig): Promise<RefreshResult | null>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Default Microsoft provider instance
|
|
27
|
+
*/
|
|
28
|
+
export declare const microsoftProvider: MicrosoftProvider;
|
|
29
|
+
//# sourceMappingURL=microsoft.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"microsoft.d.ts","sourceRoot":"","sources":["../../src/providers/microsoft.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAkB7E;;GAEG;AACH,qBAAa,iBAAkB,YAAW,aAAa;IACrD,QAAQ,CAAC,EAAE,eAAe;IAC1B,QAAQ,CAAC,eAAe,QAAQ;IAEhC,OAAO,CAAC,WAAW;IAIb,OAAO,CACX,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;CAqDjC;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB,mBAA0B,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Microsoft OAuth Provider (Azure AD / Entra)
|
|
3
|
+
*
|
|
4
|
+
* Token characteristics:
|
|
5
|
+
* - Access token lifetime: ~1 hour (configurable via token lifetime policies)
|
|
6
|
+
* - Refresh token: 90 days (revoked on password change)
|
|
7
|
+
* - Token rotation: Yes (Microsoft rotates refresh tokens by default)
|
|
8
|
+
*
|
|
9
|
+
* Tenant options:
|
|
10
|
+
* - 'common': Any Microsoft account (personal + work)
|
|
11
|
+
* - 'organizations': Work/school accounts only
|
|
12
|
+
* - 'consumers': Personal Microsoft accounts only
|
|
13
|
+
* - '{tenant-id}': Specific organization only
|
|
14
|
+
*/
|
|
15
|
+
const DEFAULT_TENANT = 'common';
|
|
16
|
+
/**
|
|
17
|
+
* Microsoft OAuth token provider
|
|
18
|
+
*/
|
|
19
|
+
export class MicrosoftProvider {
|
|
20
|
+
id = 'microsoft';
|
|
21
|
+
supportsRefresh = true;
|
|
22
|
+
getTokenUrl(tenantId) {
|
|
23
|
+
return `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
|
|
24
|
+
}
|
|
25
|
+
async refresh(refreshToken, config) {
|
|
26
|
+
const tenantId = config.tenantId ?? DEFAULT_TENANT;
|
|
27
|
+
const tokenUrl = this.getTokenUrl(tenantId);
|
|
28
|
+
try {
|
|
29
|
+
const response = await fetch(tokenUrl, {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
headers: {
|
|
32
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
33
|
+
},
|
|
34
|
+
body: new URLSearchParams({
|
|
35
|
+
client_id: config.clientId,
|
|
36
|
+
client_secret: config.clientSecret,
|
|
37
|
+
refresh_token: refreshToken,
|
|
38
|
+
grant_type: 'refresh_token',
|
|
39
|
+
}).toString(),
|
|
40
|
+
});
|
|
41
|
+
if (!response.ok) {
|
|
42
|
+
const error = (await response.json());
|
|
43
|
+
console.error(`[MicrosoftProvider] Token refresh failed: ${error.error} - ${error.error_description}`);
|
|
44
|
+
// Check for specific AADSTS errors that indicate re-auth is needed
|
|
45
|
+
// AADSTS70000: Refresh token expired
|
|
46
|
+
// AADSTS50173: Refresh token expired (password change)
|
|
47
|
+
// AADSTS700082: Refresh token expired (inactivity)
|
|
48
|
+
if (error.error === 'invalid_grant' ||
|
|
49
|
+
error.error_codes?.some((code) => [70000, 50173, 700082].includes(code))) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
throw new Error(`Token refresh failed: ${error.error}`);
|
|
53
|
+
}
|
|
54
|
+
const data = (await response.json());
|
|
55
|
+
return {
|
|
56
|
+
accessToken: data.access_token,
|
|
57
|
+
// Microsoft typically returns a new refresh token - always use it!
|
|
58
|
+
refreshToken: data.refresh_token,
|
|
59
|
+
expiresAt: Date.now() + data.expires_in * 1000,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
console.error('[MicrosoftProvider] Refresh error:', error);
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Default Microsoft provider instance
|
|
70
|
+
*/
|
|
71
|
+
export const microsoftProvider = new MicrosoftProvider();
|
|
72
|
+
//# sourceMappingURL=microsoft.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"microsoft.js","sourceRoot":"","sources":["../../src/providers/microsoft.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,MAAM,cAAc,GAAG,QAAQ,CAAC;AAgBhC;;GAEG;AACH,MAAM,OAAO,iBAAiB;IACnB,EAAE,GAAG,WAAW,CAAC;IACjB,eAAe,GAAG,IAAI,CAAC;IAExB,WAAW,CAAC,QAAgB;QAClC,OAAO,qCAAqC,QAAQ,oBAAoB,CAAC;IAC3E,CAAC;IAED,KAAK,CAAC,OAAO,CACX,YAAoB,EACpB,MAAsB;QAEtB,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,cAAc,CAAC;QACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QAE5C,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;gBACrC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,mCAAmC;iBACpD;gBACD,IAAI,EAAE,IAAI,eAAe,CAAC;oBACxB,SAAS,EAAE,MAAM,CAAC,QAAQ;oBAC1B,aAAa,EAAE,MAAM,CAAC,YAAY;oBAClC,aAAa,EAAE,YAAY;oBAC3B,UAAU,EAAE,eAAe;iBAC5B,CAAC,CAAC,QAAQ,EAAE;aACd,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,KAAK,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA2B,CAAC;gBAChE,OAAO,CAAC,KAAK,CACX,6CAA6C,KAAK,CAAC,KAAK,MAAM,KAAK,CAAC,iBAAiB,EAAE,CACxF,CAAC;gBAEF,mEAAmE;gBACnE,qCAAqC;gBACrC,uDAAuD;gBACvD,mDAAmD;gBACnD,IACE,KAAK,CAAC,KAAK,KAAK,eAAe;oBAC/B,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAC/B,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CACtC,EACD,CAAC;oBACD,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,MAAM,IAAI,KAAK,CAAC,yBAAyB,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;YAC1D,CAAC;YAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA2B,CAAC;YAE/D,OAAO;gBACL,WAAW,EAAE,IAAI,CAAC,YAAY;gBAC9B,mEAAmE;gBACnE,YAAY,EAAE,IAAI,CAAC,aAAa;gBAChC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI;aAC/C,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,KAAK,CAAC,CAAC;YAC3D,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;CACF;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,iBAAiB,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloudflare D1 Storage Adapter (Placeholder)
|
|
3
|
+
*
|
|
4
|
+
* D1 provides stronger consistency guarantees than KV and allows
|
|
5
|
+
* for more complex queries (e.g., find all tokens expiring soon).
|
|
6
|
+
*
|
|
7
|
+
* TODO: Implement full D1 adapter with migrations
|
|
8
|
+
*/
|
|
9
|
+
import type { TokenStorage, StoredToken, ConnectedProvider } from '../types';
|
|
10
|
+
/**
|
|
11
|
+
* D1 Storage adapter for Cloudflare D1
|
|
12
|
+
*
|
|
13
|
+
* NOT YET IMPLEMENTED - Use KVStorage for now
|
|
14
|
+
*/
|
|
15
|
+
export declare class D1Storage implements TokenStorage {
|
|
16
|
+
constructor(_db: D1Database, _encryptionKey: string);
|
|
17
|
+
get(_userId: string, _provider: string): Promise<StoredToken | null>;
|
|
18
|
+
set(_token: StoredToken): Promise<void>;
|
|
19
|
+
delete(_userId: string, _provider: string): Promise<void>;
|
|
20
|
+
list(_userId: string): Promise<ConnectedProvider[]>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=d1.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"d1.d.ts","sourceRoot":"","sources":["../../src/storage/d1.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE7E;;;;GAIG;AACH,qBAAa,SAAU,YAAW,YAAY;gBAChC,GAAG,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM;IAMnD,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAIpE,GAAG,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvC,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzD,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;CAGpD"}
|