@dereekb/calcom 13.32.0 → 13.34.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.
@@ -1,11 +1,12 @@
1
- import { type CalcomAccessToken, type CalcomAccessTokenCache, type CalcomRefreshToken } from '@dereekb/calcom';
1
+ import { type CalcomAccessToken, type CalcomAccessTokenCache, type CalcomAccessTokenCacheKey, type CalcomRefreshToken } from '@dereekb/calcom';
2
2
  import { type Maybe } from '@dereekb/util';
3
3
  /**
4
4
  * Service used for retrieving CalcomAccessTokenCache for Cal.com services.
5
5
  *
6
6
  * Implementations store and retrieve OAuth access tokens (and the rotated refresh tokens
7
7
  * embedded in them). The service supports both a server-level cache and per-user caches
8
- * keyed by the user's initial refresh token.
8
+ * keyed either by a caller-owned key ({@link cacheForKey}) or by the user's refresh token
9
+ * ({@link cacheForRefreshToken}).
9
10
  */
10
11
  export declare abstract class CalcomOAuthAccessTokenCacheService {
11
12
  /**
@@ -13,15 +14,27 @@ export declare abstract class CalcomOAuthAccessTokenCacheService {
13
14
  */
14
15
  abstract loadCalcomAccessTokenCache(): CalcomAccessTokenCache;
15
16
  /**
16
- * Creates or retrieves a cache for a specific user context, keyed by the refresh token.
17
+ * Creates or retrieves a cache for a specific user context, keyed by a stable caller-owned key.
17
18
  *
18
- * The refresh token is hashed to derive a stable cache key. Even though Cal.com
19
- * rotates refresh tokens, the cache instance persists the updated token in-place,
20
- * so subsequent reads return the latest token regardless of rotation.
19
+ * Prefer this over {@link cacheForRefreshToken}: a key the caller already owns (a user or
20
+ * profile id) survives refresh-token rotation, so the same entry is found on every boot.
21
+ */
22
+ abstract cacheForKey?(key: CalcomAccessTokenCacheKey): CalcomAccessTokenCache;
23
+ /**
24
+ * Creates or retrieves a cache for a specific user context, keyed by a hash of the refresh token.
25
+ *
26
+ * The cache instance persists the rotated token in-place, so reads return the latest token for
27
+ * as long as the *original* refresh token keeps being used as the lookup key. Because Cal.com
28
+ * rotates the refresh token on every use, that only holds within a single process lifetime:
29
+ * once a rotated token is persisted and then used as the key, the key changes and the previous
30
+ * entry is orphaned.
31
+ *
32
+ * Prefer {@link cacheForKey} with a stable id for anything that outlives one process.
21
33
  */
22
34
  abstract cacheForRefreshToken?(refreshToken: CalcomRefreshToken): CalcomAccessTokenCache;
23
35
  }
24
- export type CalcomOAuthAccessTokenCacheServiceWithRefreshToken = Required<CalcomOAuthAccessTokenCacheService>;
36
+ export type CalcomOAuthAccessTokenCacheServiceWithRefreshToken = Required<Pick<CalcomOAuthAccessTokenCacheService, 'cacheForRefreshToken'>> & CalcomOAuthAccessTokenCacheService;
37
+ export type CalcomOAuthAccessTokenCacheServiceWithKey = Required<Pick<CalcomOAuthAccessTokenCacheService, 'cacheForKey'>> & CalcomOAuthAccessTokenCacheService;
25
38
  /**
26
39
  * Derives a short, filesystem-safe cache key from a refresh token.
27
40
  *
@@ -31,6 +44,17 @@ export type CalcomOAuthAccessTokenCacheServiceWithRefreshToken = Required<Calcom
31
44
  * @returns A 16-character hex string suitable for use as a cache key.
32
45
  */
33
46
  export declare function calcomRefreshTokenCacheKey(refreshToken: string): string;
47
+ /**
48
+ * Converts a cache key into a filesystem-safe path segment.
49
+ *
50
+ * A key that is already safe (such as the hex output of {@link calcomRefreshTokenCacheKey}) is
51
+ * returned unchanged. Otherwise the unsafe characters are replaced and a hash of the original key
52
+ * is appended, so two different keys can never collapse onto the same file.
53
+ *
54
+ * @param key - The cache key to convert.
55
+ * @returns A filesystem-safe path segment for the key.
56
+ */
57
+ export declare function calcomAccessTokenCacheFileKey(key: CalcomAccessTokenCacheKey): string;
34
58
  export type LogMergeCalcomOAuthAccessTokenCacheServiceErrorFunction = (failedUpdates: (readonly [CalcomAccessTokenCache, unknown])[]) => void;
35
59
  /**
36
60
  * Default error logging function for {@link mergeCalcomOAuthAccessTokenCacheServices}.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dereekb/calcom",
3
- "version": "13.32.0",
3
+ "version": "13.34.0",
4
4
  "exports": {
5
5
  "./nestjs": {
6
6
  "module": "./nestjs/index.esm.js",
@@ -17,9 +17,9 @@
17
17
  }
18
18
  },
19
19
  "peerDependencies": {
20
- "@dereekb/nestjs": "13.32.0",
21
- "@dereekb/rxjs": "13.32.0",
22
- "@dereekb/util": "13.32.0",
20
+ "@dereekb/nestjs": "13.34.0",
21
+ "@dereekb/rxjs": "13.34.0",
22
+ "@dereekb/util": "13.34.0",
23
23
  "@nestjs/common": "^11.1.19",
24
24
  "@nestjs/config": "^4.0.4",
25
25
  "express": "^5.2.1",
@@ -1,7 +1,8 @@
1
- import { type FactoryWithRequiredInput, type Maybe } from '@dereekb/util';
1
+ import { type FactoryWithRequiredInput } from '@dereekb/util';
2
2
  import { type ConfiguredFetch, type FetchJsonFunction } from '@dereekb/util/fetch';
3
- import { type CalcomConfig, type CalcomRefreshToken } from '../calcom.config';
4
- import { type CalcomAccessTokenCache, type CalcomAccessTokenStringFactory } from '../oauth/oauth';
3
+ import { type CalcomConfig } from '../calcom.config';
4
+ import { type CalcomAccessTokenStringFactory } from '../oauth/oauth';
5
+ import { type CalcomRefreshTokenCredential } from '../oauth/oauth.config';
5
6
  import { type CalcomRateLimiterRef } from '../calcom.limit';
6
7
  export interface CalcomFetchFactoryInput {
7
8
  readonly calcomAccessTokenStringFactory: CalcomAccessTokenStringFactory;
@@ -30,22 +31,14 @@ export interface CalcomUserContext extends CalcomContext {
30
31
  readonly userFetch: ConfiguredFetch;
31
32
  readonly userFetchJson: FetchJsonFunction;
32
33
  }
33
- export interface CalcomUserContextFactoryInput {
34
- /**
35
- * The user's refresh token.
36
- */
37
- readonly refreshToken: CalcomRefreshToken;
38
- /**
39
- * Optional cache to use for the user's access token.
40
- *
41
- * The cache should only be configured for the user that owns the refresh token.
42
- */
43
- readonly accessTokenCache?: Maybe<CalcomAccessTokenCache>;
44
- }
45
34
  /**
46
- * Creates a CalcomUserContext from the input.
35
+ * Creates a CalcomUserContext from a user's credential.
36
+ *
37
+ * Deliberately the refresh-token arm of {@link CalcomAuthCredential} rather than the full union: a
38
+ * user context acts as a connected user, while an api key acts as whoever created it — which is the
39
+ * server context's job.
47
40
  */
48
- export type CalcomUserContextFactory = FactoryWithRequiredInput<CalcomUserContext, CalcomUserContextFactoryInput>;
41
+ export type CalcomUserContextFactory = FactoryWithRequiredInput<CalcomUserContext, CalcomRefreshTokenCredential>;
49
42
  /**
50
43
  * Context for making public (unauthenticated) requests to the Cal.com API.
51
44
  */
@@ -1,5 +1,6 @@
1
1
  export * from './oauth';
2
2
  export * from './oauth.api';
3
+ export * from './oauth.authorize';
3
4
  export * from './oauth.config';
4
5
  export * from './oauth.error.api';
5
6
  export * from './oauth.factory';
@@ -1,9 +1,16 @@
1
1
  import { type CalcomOAuthContext } from './oauth.config';
2
2
  import { type CalcomRefreshToken } from '../calcom.config';
3
3
  import { type CalcomAccessTokenScopesString, type CalcomAccessTokenString } from './oauth';
4
- import { type Maybe, type Seconds } from '@dereekb/util';
4
+ import { type Seconds } from '@dereekb/util';
5
5
  export interface CalcomOAuthRefreshTokenInput {
6
- readonly refreshToken?: Maybe<CalcomRefreshToken>;
6
+ /**
7
+ * The refresh token to exchange.
8
+ *
9
+ * Required, and deliberately not defaulted from the context's configuration: Cal.com rotates
10
+ * refresh tokens on every use, so the configured value is spent the first time the context
11
+ * refreshes. Every caller therefore has to name the token it actually holds.
12
+ */
13
+ readonly refreshToken: CalcomRefreshToken;
7
14
  }
8
15
  export interface CalcomOAuthExchangeAuthorizationCodeInput {
9
16
  readonly code: string;
@@ -26,7 +33,7 @@ export interface CalcomOAuthAccessTokenErrorResponse {
26
33
  * Cal.com uses JSON body (not Basic Auth) for token requests.
27
34
  *
28
35
  * @param context - The Cal.com OAuth context providing client credentials and fetch capabilities.
29
- * @returns Refreshes an access token using an optional refresh token override.
36
+ * @returns Refreshes an access token using the given refresh token.
30
37
  *
31
38
  * @see https://cal.com/docs/api-reference/v2/oauth/refresh-an-existing-access-token
32
39
  *
@@ -36,7 +43,7 @@ export interface CalcomOAuthAccessTokenErrorResponse {
36
43
  * console.log(response.access_token, response.refresh_token);
37
44
  * ```
38
45
  */
39
- export declare function refreshAccessToken(context: CalcomOAuthContext): (input?: CalcomOAuthRefreshTokenInput) => Promise<CalcomOAuthTokenResponse>;
46
+ export declare function refreshAccessToken(context: CalcomOAuthContext): (input: CalcomOAuthRefreshTokenInput) => Promise<CalcomOAuthTokenResponse>;
40
47
  /**
41
48
  * Exchanges an OAuth authorization code for access and refresh tokens.
42
49
  * Used during the initial OAuth flow when a user authorizes your app.
@@ -0,0 +1,91 @@
1
+ import { type Maybe, type WebsiteUrl } from '@dereekb/util';
2
+ import { type CalcomOAuthClientId } from '../calcom.config';
3
+ /**
4
+ * Every granular Cal.com OAuth scope.
5
+ *
6
+ * A runtime list rather than a bare type union, so a configured scope can be validated instead of
7
+ * being passed through to the consent screen and refused there.
8
+ *
9
+ * @see https://cal.com/docs/api-reference/v2/oauth
10
+ */
11
+ export declare const ALL_CALCOM_OAUTH_SCOPES: readonly ["PROFILE_READ", "PROFILE_WRITE", "BOOKING_READ", "BOOKING_WRITE", "SCHEDULE_READ", "SCHEDULE_WRITE", "EVENT_TYPE_READ", "EVENT_TYPE_WRITE", "APPS_READ", "APPS_WRITE", "WEBHOOK_READ", "WEBHOOK_WRITE"];
12
+ /**
13
+ * A granular Cal.com OAuth scope.
14
+ */
15
+ export type CalcomOAuthScope = (typeof ALL_CALCOM_OAUTH_SCOPES)[number];
16
+ /**
17
+ * Returns whether the input is a known {@link CalcomOAuthScope}.
18
+ *
19
+ * @param value - The value to check.
20
+ * @returns True when the value is a known Cal.com OAuth scope.
21
+ */
22
+ export declare function isCalcomOAuthScope(value: string): value is CalcomOAuthScope;
23
+ /**
24
+ * The delimiter used to join scopes in the `scope` query parameter.
25
+ *
26
+ * OAuth2 specifies a space-delimited list. Cal.com's granular scopes are documented without an
27
+ * explicit delimiter, so this is isolated here: if the consent screen rejects the `scope`
28
+ * parameter, this is the only value that needs to change.
29
+ */
30
+ export declare const CALCOM_OAUTH_SCOPE_DELIMITER = " ";
31
+ /**
32
+ * The `response_type` used by the authorization-code flow.
33
+ */
34
+ export declare const CALCOM_OAUTH_AUTHORIZE_RESPONSE_TYPE = "code";
35
+ export interface CalcomOAuthAuthorizeUrlFactoryConfig {
36
+ /**
37
+ * The OAuth client id to authorize as.
38
+ */
39
+ readonly clientId: CalcomOAuthClientId;
40
+ /**
41
+ * The redirect URI to return to after the user consents.
42
+ *
43
+ * Must match the URI registered on the Cal.com OAuth client byte-for-byte, including the port,
44
+ * and must be identical to the `redirectUri` later passed to the token exchange.
45
+ */
46
+ readonly redirectUri: WebsiteUrl;
47
+ /**
48
+ * The scopes to request.
49
+ */
50
+ readonly scopes: readonly CalcomOAuthScope[];
51
+ /**
52
+ * Optional override of the authorize URL. Defaults to {@link CALCOM_OAUTH_AUTHORIZE_URL}.
53
+ */
54
+ readonly authorizeUrl?: Maybe<WebsiteUrl>;
55
+ }
56
+ export interface CalcomOAuthAuthorizeUrlParams {
57
+ /**
58
+ * Opaque state echoed back to the redirect URI.
59
+ *
60
+ * Carries the acting user and is the CSRF defense for the handoff, so it should be signed and
61
+ * short-lived.
62
+ */
63
+ readonly state?: Maybe<string>;
64
+ }
65
+ export type CalcomOAuthAuthorizeUrlFactory = (params?: Maybe<CalcomOAuthAuthorizeUrlParams>) => WebsiteUrl;
66
+ /**
67
+ * Creates a {@link CalcomOAuthAuthorizeUrlFactory} that composes the Cal.com authorize URL that a
68
+ * user's browser is redirected to in order to begin the authorization-code flow.
69
+ *
70
+ * The client id, redirect URI, and scopes are fixed by the config, since a consumer holds those
71
+ * constant and varies only the per-request `state`.
72
+ *
73
+ * @param config - The client id, redirect URI, and scopes to request.
74
+ * @returns A factory that builds an authorize URL for the given params.
75
+ *
76
+ * @see https://cal.com/docs/api-reference/v2/oauth
77
+ *
78
+ * @example
79
+ * ```ts
80
+ * const authorizeUrlFactory = calcomOAuthAuthorizeUrlFactory({
81
+ * clientId: 'client-id',
82
+ * redirectUri: 'http://localhost:9901/oauth/calcom/callback',
83
+ * scopes: ['PROFILE_READ', 'BOOKING_READ']
84
+ * });
85
+ *
86
+ * const url = authorizeUrlFactory({ state: 'signed-state' });
87
+ * ```
88
+ *
89
+ * @__NO_SIDE_EFFECTS__
90
+ */
91
+ export declare function calcomOAuthAuthorizeUrlFactory(config: CalcomOAuthAuthorizeUrlFactoryConfig): CalcomOAuthAuthorizeUrlFactory;
@@ -3,51 +3,146 @@ import { type ConfiguredFetch, type FetchJsonFunction } from '@dereekb/util/fetc
3
3
  import { type CalcomApiKey, type CalcomAuthClientIdAndSecretPair, type CalcomRefreshToken } from '../calcom.config';
4
4
  import { type CalcomAccessTokenCache, type CalcomAccessTokenFactory } from './oauth';
5
5
  /**
6
- * The Cal.com OAuth token endpoint URL.
6
+ * The Cal.com OAuth API base URL.
7
+ *
8
+ * Endpoint paths are appended to this base, so it intentionally carries no endpoint segment of
9
+ * its own. This is the single place the OAuth host and prefix are encoded.
7
10
  */
8
- export declare const CALCOM_OAUTH_TOKEN_URL = "https://api.cal.com/v2/oauth/token";
11
+ export declare const CALCOM_OAUTH_API_URL = "https://api.cal.com/v2/auth/oauth2";
12
+ export type CalcomOAuthApiUrl = typeof CALCOM_OAUTH_API_URL;
13
+ /**
14
+ * The Cal.com OAuth token endpoint path, relative to {@link CALCOM_OAUTH_API_URL}.
15
+ */
16
+ export declare const CALCOM_OAUTH_TOKEN_PATH = "/token";
9
17
  /**
10
18
  * The Cal.com OAuth authorize URL.
11
19
  */
12
20
  export declare const CALCOM_OAUTH_AUTHORIZE_URL = "https://app.cal.com/auth/oauth2/authorize";
13
21
  /**
14
- * Configuration for CalcomOAuth.
22
+ * Authenticates as the Cal.com user who created the API key.
23
+ *
24
+ * The key IS the bearer token and does not expire, so this credential never reaches the token
25
+ * endpoint and needs no {@link CalcomOAuthConfig.client}.
15
26
  */
16
- export interface CalcomOAuthConfig extends Partial<CalcomAuthClientIdAndSecretPair> {
27
+ export interface CalcomApiKeyCredential {
28
+ readonly apiKey: CalcomApiKey;
29
+ }
30
+ /**
31
+ * Authenticates as the Cal.com user who granted the refresh token.
32
+ *
33
+ * Every exchange is authenticated with {@link CalcomOAuthConfig.client}'s id and secret, so this
34
+ * credential is unusable without one.
35
+ */
36
+ export interface CalcomRefreshTokenCredential {
17
37
  /**
18
- * Optional CalcomAccessTokenCache for caching access tokens.
38
+ * The grant's refresh token.
39
+ *
40
+ * Cal.com rotates it on every use. The factory built from this credential tracks the rotation in
41
+ * memory, so this value is read once rather than re-read per refresh.
19
42
  */
20
- readonly accessTokenCache?: Maybe<CalcomAccessTokenCache>;
43
+ readonly refreshToken: CalcomRefreshToken;
21
44
  /**
22
- * Server-level refresh token for initial authentication.
45
+ * Cache for THIS credential's access token.
46
+ *
47
+ * Must be scoped to exactly this grant. Two credentials sharing one cache overwrite each other,
48
+ * and the rotated refresh token rides along inside the cached value — so a shared cache does not
49
+ * merely lose a token, it spends one.
23
50
  */
51
+ readonly accessTokenCache?: Maybe<CalcomAccessTokenCache>;
52
+ }
53
+ /**
54
+ * A credential Cal.com calls can be made with.
55
+ *
56
+ * One union for the ambient credential and for any per-user one, because they are the same thing:
57
+ * a way to act as some Cal.com user. Discriminated by the presence of `apiKey`.
58
+ */
59
+ export type CalcomAuthCredential = CalcomApiKeyCredential | CalcomRefreshTokenCredential;
60
+ /**
61
+ * Returns whether the credential is a {@link CalcomApiKeyCredential}.
62
+ *
63
+ * @param credential - The credential to check.
64
+ * @returns True when the credential carries an api key.
65
+ *
66
+ * @__NO_SIDE_EFFECTS__
67
+ */
68
+ export declare function isCalcomApiKeyCredential(credential: CalcomAuthCredential): credential is CalcomApiKeyCredential;
69
+ export interface CalcomAuthCredentialValues {
70
+ readonly apiKey?: Maybe<CalcomApiKey>;
24
71
  readonly refreshToken?: Maybe<CalcomRefreshToken>;
72
+ readonly accessTokenCache?: Maybe<CalcomAccessTokenCache>;
73
+ }
74
+ /**
75
+ * Builds a {@link CalcomAuthCredential} from flat, optional values, as an environment-facing
76
+ * configuration provides them.
77
+ *
78
+ * An api key wins when both are present: it does not expire, so it skips the refresh loop entirely.
79
+ * The cache attaches only to the refresh-token arm, since an api key has no token to cache. Empty
80
+ * strings count as absent, so an unset environment variable read as `''` does not become a
81
+ * credential that sends `Bearer `.
82
+ *
83
+ * @param values - The flat credential values.
84
+ * @returns The equivalent credential, or undefined when neither value is present.
85
+ *
86
+ * @__NO_SIDE_EFFECTS__
87
+ */
88
+ export declare function calcomAuthCredentialFromValues(values: CalcomAuthCredentialValues): Maybe<CalcomAuthCredential>;
89
+ /**
90
+ * Configuration for CalcomOAuth.
91
+ *
92
+ * `client` is the app's OAuth *registration*. It is sent on EVERY token exchange — the ambient one
93
+ * as much as any per-user one — so it is not "the user half" of anything.
94
+ *
95
+ * `defaultAuth` is the credential used when no specific one is named, and is the only thing
96
+ * `loadAccessToken()` reads. It is not an "app identity" either: an api key acts as the user who
97
+ * created it, and a refresh token here is some user's grant being reused ambiently.
98
+ *
99
+ * An app that only acts for named users needs just `client`. An app that makes ambient calls needs
100
+ * a `defaultAuth`, plus `client` whenever that credential is a refresh token.
101
+ */
102
+ export interface CalcomOAuthConfig {
25
103
  /**
26
- * Optional API key for simple bearer token auth.
104
+ * The OAuth client registration, required for ANY refresh-token exchange.
27
105
  *
28
- * When provided, OAuth token refresh is skipped and the API key is used directly as the bearer token.
29
- * Does not expire and requires no refresh.
106
+ * Both halves of the pair are required together, so a client cannot be half-configured into a state
107
+ * that composes an authorize URL carrying `client_id=undefined`.
30
108
  */
31
- readonly apiKey?: Maybe<CalcomApiKey>;
109
+ readonly client?: Maybe<CalcomAuthClientIdAndSecretPair>;
110
+ /**
111
+ * The credential used when no specific one is named.
112
+ */
113
+ readonly defaultAuth?: Maybe<CalcomAuthCredential>;
32
114
  }
33
115
  export interface CalcomOAuthFetchFactoryInput {
34
116
  }
35
117
  export type CalcomOAuthFetchFactory = FactoryWithInput<ConfiguredFetch, CalcomOAuthFetchFactoryInput>;
36
- export type CalcomOAuthMakeUserAccessTokenFactoryInput = {
37
- readonly refreshToken: CalcomRefreshToken;
38
- readonly userAccessTokenCache?: Maybe<CalcomAccessTokenCache>;
39
- };
40
- export type CalcomOAuthMakeUserAccessTokenFactory = FactoryWithRequiredInput<CalcomAccessTokenFactory, CalcomOAuthMakeUserAccessTokenFactoryInput>;
118
+ export type CalcomOAuthMakeAccessTokenFactory = FactoryWithRequiredInput<CalcomAccessTokenFactory, CalcomAuthCredential>;
41
119
  /**
42
120
  * Context used for performing fetch() and fetchJson() calls with a configured fetch instance.
43
121
  */
44
122
  export interface CalcomOAuthContext {
45
123
  readonly fetch: ConfiguredFetch;
46
124
  readonly fetchJson: FetchJsonFunction;
125
+ /**
126
+ * Resolves the access token for {@link CalcomOAuthConfig.defaultAuth}.
127
+ *
128
+ * `makeAccessTokenFactory(config.defaultAuth)`, built once at construction so its in-memory token
129
+ * tier and its refresh-token rotation are shared across the whole context.
130
+ */
47
131
  readonly loadAccessToken: CalcomAccessTokenFactory;
48
- readonly makeUserAccessTokenFactory: CalcomOAuthMakeUserAccessTokenFactory;
132
+ /**
133
+ * Builds an access token factory for one credential.
134
+ *
135
+ * Each returned factory owns its own rotation and cache tier, so refreshing one credential never
136
+ * spends another's token.
137
+ */
138
+ readonly makeAccessTokenFactory: CalcomOAuthMakeAccessTokenFactory;
49
139
  readonly config: CalcomOAuthConfig;
50
140
  }
51
141
  export interface CalcomOAuthContextRef {
52
142
  readonly oauthContext: CalcomOAuthContext;
53
143
  }
144
+ /**
145
+ * @deprecated use {@link CALCOM_OAUTH_API_URL} instead. This was previously used as the fetch base
146
+ * URL while the endpoint path `/oauth/token` was also appended, resolving to a doubly-pathed URL.
147
+ */
148
+ export declare const CALCOM_OAUTH_TOKEN_URL = "https://api.cal.com/v2/auth/oauth2/token";
@@ -27,6 +27,13 @@ export interface CalcomAccessToken {
27
27
  */
28
28
  readonly expiresAt: Date;
29
29
  }
30
+ /**
31
+ * A stable key identifying a cached CalcomAccessToken.
32
+ *
33
+ * Should be owned by the caller (a user/profile id) rather than derived from the refresh token,
34
+ * since Cal.com rotates refresh tokens on every use and a token-derived key changes with them.
35
+ */
36
+ export type CalcomAccessTokenCacheKey = string;
30
37
  /**
31
38
  * Used for retrieving and storing CalcomAccessToken values.
32
39
  */
@@ -1,13 +1,53 @@
1
+ import { type FetchHandler } from '@dereekb/util/fetch';
1
2
  import { type CalcomOAuthConfig, type CalcomOAuthContextRef, type CalcomOAuthFetchFactory } from './oauth.config';
3
+ import { type CalcomApiKey } from '../calcom.config';
2
4
  import { type LogCalcomServerErrorFunction } from '../calcom.error.api';
3
- import { type CalcomAccessTokenCache, type CalcomAccessTokenFactory, type CalcomAccessTokenRefresher } from './oauth';
5
+ import { type CalcomAccessToken, type CalcomAccessTokenCache, type CalcomAccessTokenFactory, type CalcomAccessTokenRefresher } from './oauth';
4
6
  import { type Maybe, type Milliseconds } from '@dereekb/util';
7
+ import { type CalcomOAuthTokenResponse } from './oauth.api';
5
8
  export type CalcomOAuth = CalcomOAuthContextRef;
9
+ /**
10
+ * Maps a {@link CalcomOAuthTokenResponse} to a {@link CalcomAccessToken}.
11
+ *
12
+ * Pure: the caller owns the rotated refresh token that comes back on the result, so each token
13
+ * scope (server-level vs per-user) tracks its own rotation instead of sharing one variable.
14
+ *
15
+ * @param response - The token response returned by the Cal.com token endpoint.
16
+ * @returns The equivalent CalcomAccessToken, with `expiresAt` resolved against the current time.
17
+ *
18
+ * @__NO_SIDE_EFFECTS__
19
+ */
20
+ export declare function calcomAccessTokenFromTokenResponse(response: CalcomOAuthTokenResponse): CalcomAccessToken;
21
+ /**
22
+ * The lifetime given to the synthetic access token an api key is wrapped in.
23
+ *
24
+ * Cal.com api keys do not expire; the value only has to outlive any process holding one, so the
25
+ * token satisfies the same expiration check every other token goes through.
26
+ */
27
+ export declare const CALCOM_API_KEY_ACCESS_TOKEN_EXPIRATION: Milliseconds;
28
+ /**
29
+ * Wraps a {@link CalcomApiKey} as a static {@link CalcomAccessToken}.
30
+ *
31
+ * An api key is already a bearer token acting as the user who created it, so there is nothing to
32
+ * exchange and nothing to refresh.
33
+ *
34
+ * @param apiKey - The Cal.com api key.
35
+ * @returns The equivalent static CalcomAccessToken.
36
+ *
37
+ * @__NO_SIDE_EFFECTS__
38
+ */
39
+ export declare function calcomAccessTokenFromApiKey(apiKey: CalcomApiKey): CalcomAccessToken;
6
40
  export interface CalcomOAuthFactoryConfig {
7
41
  /**
8
42
  * Creates a new fetch instance to use when making calls.
9
43
  */
10
44
  readonly fetchFactory?: CalcomOAuthFetchFactory;
45
+ /**
46
+ * Custom FetchHandler to use with the default fetchFactory.
47
+ *
48
+ * Defaults to a {@link calcomRateLimitedFetchHandler}. Ignored when a `fetchFactory` is provided.
49
+ */
50
+ readonly fetchHandler?: Maybe<FetchHandler>;
11
51
  /**
12
52
  * Custom log error function.
13
53
  */