@hypercerts-org/sdk-core 0.5.0-beta.0 → 0.7.0-beta.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.
Files changed (57) hide show
  1. package/README.md +130 -8
  2. package/dist/index.cjs +93 -15
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.ts +64 -1
  5. package/dist/index.mjs +93 -16
  6. package/dist/index.mjs.map +1 -1
  7. package/package.json +9 -5
  8. package/.turbo/turbo-build.log +0 -40
  9. package/.turbo/turbo-test.log +0 -119
  10. package/CHANGELOG.md +0 -62
  11. package/eslint.config.mjs +0 -22
  12. package/rollup.config.js +0 -75
  13. package/src/auth/OAuthClient.ts +0 -497
  14. package/src/core/SDK.ts +0 -410
  15. package/src/core/config.ts +0 -243
  16. package/src/core/errors.ts +0 -257
  17. package/src/core/interfaces.ts +0 -324
  18. package/src/core/types.ts +0 -282
  19. package/src/errors.ts +0 -57
  20. package/src/index.ts +0 -107
  21. package/src/lexicons.ts +0 -64
  22. package/src/repository/BlobOperationsImpl.ts +0 -199
  23. package/src/repository/CollaboratorOperationsImpl.ts +0 -442
  24. package/src/repository/HypercertOperationsImpl.ts +0 -1146
  25. package/src/repository/LexiconRegistry.ts +0 -332
  26. package/src/repository/OrganizationOperationsImpl.ts +0 -282
  27. package/src/repository/ProfileOperationsImpl.ts +0 -281
  28. package/src/repository/RecordOperationsImpl.ts +0 -340
  29. package/src/repository/Repository.ts +0 -482
  30. package/src/repository/interfaces.ts +0 -909
  31. package/src/repository/types.ts +0 -111
  32. package/src/services/hypercerts/types.ts +0 -87
  33. package/src/storage/InMemorySessionStore.ts +0 -127
  34. package/src/storage/InMemoryStateStore.ts +0 -146
  35. package/src/storage.ts +0 -63
  36. package/src/testing/index.ts +0 -67
  37. package/src/testing/mocks.ts +0 -142
  38. package/src/testing/stores.ts +0 -285
  39. package/src/testing.ts +0 -64
  40. package/src/types.ts +0 -86
  41. package/tests/auth/OAuthClient.test.ts +0 -164
  42. package/tests/core/SDK.test.ts +0 -176
  43. package/tests/core/errors.test.ts +0 -81
  44. package/tests/repository/BlobOperationsImpl.test.ts +0 -155
  45. package/tests/repository/CollaboratorOperationsImpl.test.ts +0 -438
  46. package/tests/repository/HypercertOperationsImpl.test.ts +0 -652
  47. package/tests/repository/LexiconRegistry.test.ts +0 -192
  48. package/tests/repository/OrganizationOperationsImpl.test.ts +0 -240
  49. package/tests/repository/ProfileOperationsImpl.test.ts +0 -254
  50. package/tests/repository/RecordOperationsImpl.test.ts +0 -375
  51. package/tests/repository/Repository.test.ts +0 -149
  52. package/tests/utils/fixtures.ts +0 -117
  53. package/tests/utils/mocks.ts +0 -109
  54. package/tests/utils/repository-fixtures.ts +0 -78
  55. package/tsconfig.json +0 -11
  56. package/tsconfig.tsbuildinfo +0 -1
  57. package/vitest.config.ts +0 -30
package/src/core/SDK.ts DELETED
@@ -1,410 +0,0 @@
1
- import { OAuthClient } from "../auth/OAuthClient.js";
2
- import { LexiconRegistry } from "../repository/LexiconRegistry.js";
3
- import { Repository } from "../repository/Repository.js";
4
- import type { RepositoryOptions } from "../repository/types.js";
5
- import { InMemorySessionStore } from "../storage/InMemorySessionStore.js";
6
- import { InMemoryStateStore } from "../storage/InMemoryStateStore.js";
7
- import type { ATProtoSDKConfig } from "./config.js";
8
- import { ATProtoSDKConfigSchema } from "./config.js";
9
- import { ValidationError } from "./errors.js";
10
- import type { Session } from "./types.js";
11
-
12
- /**
13
- * Options for the OAuth authorization flow.
14
- */
15
- export interface AuthorizeOptions {
16
- /**
17
- * OAuth scope string to request specific permissions.
18
- * Overrides the default scope configured in {@link ATProtoSDKConfig.oauth.scope}.
19
- *
20
- * @example
21
- * ```typescript
22
- * // Request read-only access
23
- * await sdk.authorize("user.bsky.social", { scope: "atproto" });
24
- *
25
- * // Request full access (default typically includes transition:generic)
26
- * await sdk.authorize("user.bsky.social", { scope: "atproto transition:generic" });
27
- * ```
28
- */
29
- scope?: string;
30
- }
31
-
32
- /**
33
- * Main ATProto SDK class providing OAuth authentication and repository access.
34
- *
35
- * This is the primary entry point for interacting with AT Protocol servers.
36
- * It handles the OAuth 2.0 flow with DPoP (Demonstrating Proof of Possession)
37
- * and provides access to repository operations for managing records, blobs,
38
- * and profiles.
39
- *
40
- * @example Basic usage with OAuth flow
41
- * ```typescript
42
- * import { ATProtoSDK, InMemorySessionStore, InMemoryStateStore } from "@hypercerts-org/sdk";
43
- *
44
- * const sdk = new ATProtoSDK({
45
- * oauth: {
46
- * clientId: "https://my-app.com/client-metadata.json",
47
- * redirectUri: "https://my-app.com/callback",
48
- * scope: "atproto transition:generic",
49
- * jwksUri: "https://my-app.com/.well-known/jwks.json",
50
- * jwkPrivate: process.env.JWK_PRIVATE_KEY!,
51
- * },
52
- * servers: {
53
- * pds: "https://bsky.social",
54
- * sds: "https://sds.hypercerts.org",
55
- * },
56
- * });
57
- *
58
- * // Start OAuth flow - redirect user to this URL
59
- * const authUrl = await sdk.authorize("user.bsky.social");
60
- *
61
- * // After user returns, handle the callback
62
- * const session = await sdk.callback(new URLSearchParams(window.location.search));
63
- *
64
- * // Get a repository to work with data
65
- * const repo = sdk.repository(session);
66
- * ```
67
- *
68
- * @example Restoring an existing session
69
- * ```typescript
70
- * // Restore a previous session by DID
71
- * const session = await sdk.restoreSession("did:plc:abc123...");
72
- * if (session) {
73
- * const repo = sdk.repository(session);
74
- * // Continue working with the restored session
75
- * }
76
- * ```
77
- *
78
- * @see {@link ATProtoSDKConfig} for configuration options
79
- * @see {@link Repository} for data operations
80
- * @see {@link OAuthClient} for OAuth implementation details
81
- */
82
- export class ATProtoSDK {
83
- private oauthClient: OAuthClient;
84
- private config: ATProtoSDKConfig;
85
- private logger?: ATProtoSDKConfig["logger"];
86
- private lexiconRegistry: LexiconRegistry;
87
-
88
- /**
89
- * Creates a new ATProto SDK instance.
90
- *
91
- * @param config - SDK configuration including OAuth credentials, server URLs, and optional storage adapters
92
- * @throws {@link ValidationError} if the configuration is invalid (e.g., malformed URLs, missing required fields)
93
- *
94
- * @remarks
95
- * If no storage adapters are provided, in-memory implementations are used.
96
- * These are suitable for development and testing but **not recommended for production**
97
- * as sessions will be lost on restart.
98
- *
99
- * @example
100
- * ```typescript
101
- * // Minimal configuration (uses in-memory storage)
102
- * const sdk = new ATProtoSDK({
103
- * oauth: {
104
- * clientId: "https://my-app.com/client-metadata.json",
105
- * redirectUri: "https://my-app.com/callback",
106
- * scope: "atproto",
107
- * jwksUri: "https://my-app.com/.well-known/jwks.json",
108
- * jwkPrivate: privateKeyJwk,
109
- * },
110
- * servers: { pds: "https://bsky.social" },
111
- * });
112
- * ```
113
- */
114
- constructor(config: ATProtoSDKConfig) {
115
- // Validate configuration
116
- const validationResult = ATProtoSDKConfigSchema.safeParse(config);
117
- if (!validationResult.success) {
118
- throw new ValidationError(`Invalid SDK configuration: ${validationResult.error.message}`, validationResult.error);
119
- }
120
-
121
- // Apply defaults for optional storage
122
- const configWithDefaults: ATProtoSDKConfig = {
123
- ...config,
124
- storage: {
125
- sessionStore: config.storage?.sessionStore ?? new InMemorySessionStore(),
126
- stateStore: config.storage?.stateStore ?? new InMemoryStateStore(),
127
- },
128
- };
129
-
130
- this.config = configWithDefaults;
131
- this.logger = config.logger;
132
-
133
- // Initialize OAuth client
134
- this.oauthClient = new OAuthClient(configWithDefaults);
135
-
136
- // Initialize lexicon registry
137
- this.lexiconRegistry = new LexiconRegistry();
138
-
139
- this.logger?.info("ATProto SDK initialized");
140
- }
141
-
142
- /**
143
- * Initiates the OAuth authorization flow.
144
- *
145
- * This method starts the OAuth 2.0 authorization flow by resolving the user's
146
- * identity and generating an authorization URL. The user should be redirected
147
- * to this URL to authenticate.
148
- *
149
- * @param identifier - The user's ATProto identifier. Can be:
150
- * - A handle (e.g., `"user.bsky.social"`)
151
- * - A DID (e.g., `"did:plc:abc123..."`)
152
- * - A PDS URL (e.g., `"https://bsky.social"`)
153
- * @param options - Optional authorization settings
154
- * @returns A Promise resolving to the authorization URL to redirect the user to
155
- * @throws {@link ValidationError} if the identifier is empty or invalid
156
- * @throws {@link NetworkError} if the identity cannot be resolved
157
- *
158
- * @example
159
- * ```typescript
160
- * // Using a handle
161
- * const authUrl = await sdk.authorize("alice.bsky.social");
162
- *
163
- * // Using a DID directly
164
- * const authUrl = await sdk.authorize("did:plc:abc123xyz");
165
- *
166
- * // With custom scope
167
- * const authUrl = await sdk.authorize("alice.bsky.social", {
168
- * scope: "atproto transition:generic"
169
- * });
170
- *
171
- * // Redirect user to authUrl
172
- * window.location.href = authUrl;
173
- * ```
174
- */
175
- async authorize(identifier: string, options?: AuthorizeOptions): Promise<string> {
176
- if (!identifier || !identifier.trim()) {
177
- throw new ValidationError("ATProto identifier is required");
178
- }
179
-
180
- return this.oauthClient.authorize(identifier.trim(), options);
181
- }
182
-
183
- /**
184
- * Handles the OAuth callback and exchanges the authorization code for tokens.
185
- *
186
- * Call this method when the user is redirected back to your application
187
- * after authenticating. It validates the OAuth state, exchanges the
188
- * authorization code for access/refresh tokens, and creates a session.
189
- *
190
- * @param params - URL search parameters from the callback URL
191
- * @returns A Promise resolving to the authenticated OAuth session
192
- * @throws {@link AuthenticationError} if the callback parameters are invalid or the code exchange fails
193
- * @throws {@link ValidationError} if required parameters are missing
194
- *
195
- * @example
196
- * ```typescript
197
- * // In your callback route handler
198
- * const params = new URLSearchParams(window.location.search);
199
- * // params contains: code, state, iss (issuer)
200
- *
201
- * const session = await sdk.callback(params);
202
- * console.log(`Authenticated as ${session.did}`);
203
- *
204
- * // Store the DID to restore the session later
205
- * localStorage.setItem("userDid", session.did);
206
- * ```
207
- */
208
- async callback(params: URLSearchParams): Promise<Session> {
209
- return this.oauthClient.callback(params);
210
- }
211
-
212
- /**
213
- * Restores an existing OAuth session by DID.
214
- *
215
- * Use this method to restore a previously authenticated session, typically
216
- * on application startup. The method retrieves the stored session and
217
- * automatically refreshes expired tokens if needed.
218
- *
219
- * @param did - The user's Decentralized Identifier (DID), e.g., `"did:plc:abc123..."`
220
- * @returns A Promise resolving to the restored session, or `null` if no session exists
221
- * @throws {@link ValidationError} if the DID is empty
222
- * @throws {@link SessionExpiredError} if the session cannot be refreshed
223
- *
224
- * @example
225
- * ```typescript
226
- * // On application startup
227
- * const savedDid = localStorage.getItem("userDid");
228
- * if (savedDid) {
229
- * const session = await sdk.restoreSession(savedDid);
230
- * if (session) {
231
- * // User is still authenticated
232
- * const repo = sdk.repository(session);
233
- * } else {
234
- * // Session not found, user needs to re-authenticate
235
- * const authUrl = await sdk.authorize(savedDid);
236
- * }
237
- * }
238
- * ```
239
- */
240
- async restoreSession(did: string): Promise<Session | null> {
241
- if (!did || !did.trim()) {
242
- throw new ValidationError("DID is required");
243
- }
244
-
245
- return this.oauthClient.restore(did.trim());
246
- }
247
-
248
- /**
249
- * Revokes an OAuth session, logging the user out.
250
- *
251
- * This method invalidates the session's tokens and removes it from storage.
252
- * After revocation, the session can no longer be used or restored.
253
- *
254
- * @param did - The user's DID to revoke the session for
255
- * @throws {@link ValidationError} if the DID is empty
256
- *
257
- * @example
258
- * ```typescript
259
- * // Log out the user
260
- * await sdk.revokeSession(session.did);
261
- * localStorage.removeItem("userDid");
262
- * ```
263
- */
264
- async revokeSession(did: string): Promise<void> {
265
- if (!did || !did.trim()) {
266
- throw new ValidationError("DID is required");
267
- }
268
-
269
- return this.oauthClient.revoke(did.trim());
270
- }
271
-
272
- /**
273
- * Creates a repository instance for data operations.
274
- *
275
- * The repository provides a fluent API for working with AT Protocol data
276
- * including records, blobs, profiles, and domain-specific operations like
277
- * hypercerts and collaborators.
278
- *
279
- * @param session - An authenticated OAuth session
280
- * @param options - Repository configuration options
281
- * @returns A {@link Repository} instance configured for the specified server
282
- * @throws {@link ValidationError} if the session is invalid or server URL is not configured
283
- *
284
- * @remarks
285
- * - **PDS (Personal Data Server)**: User's own data storage, default for most operations
286
- * - **SDS (Shared Data Server)**: Shared data storage with collaborator support
287
- *
288
- * @example Using default PDS
289
- * ```typescript
290
- * const repo = sdk.repository(session);
291
- * const profile = await repo.profile.get();
292
- * ```
293
- *
294
- * @example Using configured SDS
295
- * ```typescript
296
- * const sdsRepo = sdk.repository(session, { server: "sds" });
297
- * const collaborators = await sdsRepo.collaborators.list();
298
- * ```
299
- *
300
- * @example Using custom server URL
301
- * ```typescript
302
- * const customRepo = sdk.repository(session, {
303
- * serverUrl: "https://custom.atproto.server"
304
- * });
305
- * ```
306
- */
307
- repository(session: Session, options?: RepositoryOptions): Repository {
308
- if (!session) {
309
- throw new ValidationError("Session is required");
310
- }
311
-
312
- // Determine server URL
313
- let serverUrl: string;
314
- let isSDS = false;
315
-
316
- if (options?.serverUrl) {
317
- // Custom URL provided
318
- serverUrl = options.serverUrl;
319
- // Check if it matches configured SDS
320
- isSDS = this.config.servers?.sds === serverUrl;
321
- } else if (options?.server === "sds") {
322
- // Use configured SDS
323
- if (!this.config.servers?.sds) {
324
- throw new ValidationError("SDS server URL not configured");
325
- }
326
- serverUrl = this.config.servers.sds;
327
- isSDS = true;
328
- } else if (options?.server === "pds" || !options?.server) {
329
- // Use configured PDS (default)
330
- if (!this.config.servers?.pds) {
331
- throw new ValidationError("PDS server URL not configured");
332
- }
333
- serverUrl = this.config.servers.pds;
334
- isSDS = false;
335
- } else {
336
- // Custom server string (treat as URL)
337
- serverUrl = options.server;
338
- isSDS = this.config.servers?.sds === serverUrl;
339
- }
340
-
341
- // Get repository DID (default to session DID)
342
- const repoDid = session.did || session.sub;
343
-
344
- return new Repository(session, serverUrl, repoDid, this.lexiconRegistry, isSDS, this.logger);
345
- }
346
-
347
- /**
348
- * Gets the lexicon registry for schema validation.
349
- *
350
- * The lexicon registry manages AT Protocol lexicon schemas used for
351
- * validating record data. You can register custom lexicons to extend
352
- * the SDK's capabilities.
353
- *
354
- * @returns The {@link LexiconRegistry} instance
355
- *
356
- * @example
357
- * ```typescript
358
- * const registry = sdk.getLexiconRegistry();
359
- *
360
- * // Register custom lexicons
361
- * registry.register(myCustomLexicons);
362
- *
363
- * // Check if a lexicon is registered
364
- * const hasLexicon = registry.has("org.example.myRecord");
365
- * ```
366
- */
367
- getLexiconRegistry(): LexiconRegistry {
368
- return this.lexiconRegistry;
369
- }
370
-
371
- /**
372
- * The configured PDS (Personal Data Server) URL.
373
- *
374
- * @returns The PDS URL if configured, otherwise `undefined`
375
- */
376
- get pdsUrl(): string | undefined {
377
- return this.config.servers?.pds;
378
- }
379
-
380
- /**
381
- * The configured SDS (Shared Data Server) URL.
382
- *
383
- * @returns The SDS URL if configured, otherwise `undefined`
384
- */
385
- get sdsUrl(): string | undefined {
386
- return this.config.servers?.sds;
387
- }
388
- }
389
-
390
- /**
391
- * Factory function to create an ATProto SDK instance.
392
- *
393
- * This is a convenience function equivalent to `new ATProtoSDK(config)`.
394
- *
395
- * @param config - SDK configuration
396
- * @returns A new {@link ATProtoSDK} instance
397
- *
398
- * @example
399
- * ```typescript
400
- * import { createATProtoSDK } from "@hypercerts-org/sdk";
401
- *
402
- * const sdk = createATProtoSDK({
403
- * oauth: { ... },
404
- * servers: { pds: "https://bsky.social" },
405
- * });
406
- * ```
407
- */
408
- export function createATProtoSDK(config: ATProtoSDKConfig): ATProtoSDK {
409
- return new ATProtoSDK(config);
410
- }
@@ -1,243 +0,0 @@
1
- import { z } from "zod";
2
- import type { SessionStore, StateStore, CacheInterface, LoggerInterface } from "./interfaces.js";
3
-
4
- /**
5
- * Zod schema for OAuth configuration validation.
6
- *
7
- * @remarks
8
- * All URLs must be valid and use HTTPS in production. The `jwkPrivate` field
9
- * should contain the private key in JWK (JSON Web Key) format as a string.
10
- */
11
- export const OAuthConfigSchema = z.object({
12
- /**
13
- * URL to the OAuth client metadata JSON document.
14
- * This document describes your application to the authorization server.
15
- *
16
- * @see https://atproto.com/specs/oauth#client-metadata
17
- */
18
- clientId: z.string().url(),
19
-
20
- /**
21
- * URL where users are redirected after authentication.
22
- * Must match one of the redirect URIs in your client metadata.
23
- */
24
- redirectUri: z.string().url(),
25
-
26
- /**
27
- * OAuth scopes to request, space-separated.
28
- * Common scopes: "atproto", "transition:generic"
29
- */
30
- scope: z.string(),
31
-
32
- /**
33
- * URL to your public JWKS (JSON Web Key Set) endpoint.
34
- * Used by the authorization server to verify your client's signatures.
35
- */
36
- jwksUri: z.string().url(),
37
-
38
- /**
39
- * Private JWK (JSON Web Key) as a JSON string.
40
- * Used for signing DPoP proofs and client assertions.
41
- *
42
- * @remarks
43
- * This should be kept secret and never exposed to clients.
44
- * Typically loaded from environment variables or a secrets manager.
45
- */
46
- jwkPrivate: z.string(),
47
- });
48
-
49
- /**
50
- * Zod schema for server URL configuration.
51
- *
52
- * @remarks
53
- * At least one server (PDS or SDS) should be configured for the SDK to be useful.
54
- */
55
- export const ServerConfigSchema = z.object({
56
- /**
57
- * Personal Data Server URL - the user's own AT Protocol server.
58
- * This is the primary server for user data operations.
59
- *
60
- * @example "https://bsky.social"
61
- */
62
- pds: z.string().url().optional(),
63
-
64
- /**
65
- * Shared Data Server URL - for collaborative data storage.
66
- * Required for collaborator and organization operations.
67
- *
68
- * @example "https://sds.hypercerts.org"
69
- */
70
- sds: z.string().url().optional(),
71
- });
72
-
73
- /**
74
- * Zod schema for timeout configuration.
75
- *
76
- * @remarks
77
- * All timeout values are in milliseconds.
78
- */
79
- export const TimeoutConfigSchema = z.object({
80
- /**
81
- * Timeout for fetching PDS metadata during identity resolution.
82
- * @default 5000 (5 seconds, set by OAuthClient)
83
- */
84
- pdsMetadata: z.number().positive().optional(),
85
-
86
- /**
87
- * Timeout for general API requests to PDS/SDS.
88
- * @default 30000 (30 seconds)
89
- */
90
- apiRequests: z.number().positive().optional(),
91
- });
92
-
93
- /**
94
- * Zod schema for SDK configuration validation.
95
- *
96
- * @remarks
97
- * This schema validates only the primitive/serializable parts of the configuration.
98
- * Storage interfaces ({@link SessionStore}, {@link StateStore}) cannot be validated
99
- * with Zod as they are runtime objects.
100
- */
101
- export const ATProtoSDKConfigSchema = z.object({
102
- oauth: OAuthConfigSchema,
103
- servers: ServerConfigSchema.optional(),
104
- timeouts: TimeoutConfigSchema.optional(),
105
- });
106
-
107
- /**
108
- * Configuration options for the ATProto SDK.
109
- *
110
- * This interface defines all configuration needed to initialize the SDK,
111
- * including OAuth credentials, server endpoints, and optional customizations.
112
- *
113
- * @example Minimal configuration
114
- * ```typescript
115
- * const config: ATProtoSDKConfig = {
116
- * oauth: {
117
- * clientId: "https://my-app.com/client-metadata.json",
118
- * redirectUri: "https://my-app.com/callback",
119
- * scope: "atproto transition:generic",
120
- * jwksUri: "https://my-app.com/.well-known/jwks.json",
121
- * jwkPrivate: process.env.JWK_PRIVATE_KEY!,
122
- * },
123
- * servers: {
124
- * pds: "https://bsky.social",
125
- * },
126
- * };
127
- * ```
128
- *
129
- * @example Full configuration with custom storage
130
- * ```typescript
131
- * const config: ATProtoSDKConfig = {
132
- * oauth: { ... },
133
- * servers: {
134
- * pds: "https://bsky.social",
135
- * sds: "https://sds.hypercerts.org",
136
- * },
137
- * storage: {
138
- * sessionStore: new RedisSessionStore(redisClient),
139
- * stateStore: new RedisStateStore(redisClient),
140
- * },
141
- * timeouts: {
142
- * pdsMetadata: 5000,
143
- * apiRequests: 30000,
144
- * },
145
- * logger: console,
146
- * };
147
- * ```
148
- */
149
- export interface ATProtoSDKConfig {
150
- /**
151
- * OAuth 2.0 configuration for authentication.
152
- *
153
- * Required fields for the OAuth flow with DPoP (Demonstrating Proof of Possession).
154
- * Your application must host the client metadata and JWKS endpoints.
155
- *
156
- * @see https://atproto.com/specs/oauth for AT Protocol OAuth specification
157
- */
158
- oauth: z.infer<typeof OAuthConfigSchema>;
159
-
160
- /**
161
- * Server URLs for PDS and SDS connections.
162
- *
163
- * - **PDS**: Personal Data Server - user's own data storage
164
- * - **SDS**: Shared Data Server - collaborative storage with access control
165
- */
166
- servers?: z.infer<typeof ServerConfigSchema>;
167
-
168
- /**
169
- * Storage adapters for persisting OAuth sessions and state.
170
- *
171
- * If not provided, in-memory implementations are used automatically.
172
- * **Warning**: In-memory storage is lost on process restart - use persistent
173
- * storage (Redis, database, etc.) in production.
174
- *
175
- * @example
176
- * ```typescript
177
- * storage: {
178
- * sessionStore: new RedisSessionStore(redis),
179
- * stateStore: new RedisStateStore(redis),
180
- * }
181
- * ```
182
- */
183
- storage?: {
184
- /**
185
- * Persistent storage for OAuth sessions.
186
- * Sessions contain access tokens, refresh tokens, and DPoP keys.
187
- */
188
- sessionStore?: SessionStore;
189
-
190
- /**
191
- * Temporary storage for OAuth state during the authorization flow.
192
- * State is short-lived and used for PKCE and CSRF protection.
193
- */
194
- stateStore?: StateStore;
195
- };
196
-
197
- /**
198
- * Custom fetch implementation for HTTP requests.
199
- *
200
- * Use this to add custom headers, logging, or to use a different HTTP client.
201
- * Must be compatible with the standard Fetch API.
202
- *
203
- * @example
204
- * ```typescript
205
- * fetch: async (url, init) => {
206
- * console.log(`Fetching: ${url}`);
207
- * return globalThis.fetch(url, init);
208
- * }
209
- * ```
210
- */
211
- fetch?: typeof fetch;
212
-
213
- /**
214
- * Timeout configuration for network requests.
215
- * Values are in milliseconds.
216
- */
217
- timeouts?: z.infer<typeof TimeoutConfigSchema>;
218
-
219
- /**
220
- * Cache for profiles, metadata, and other frequently accessed data.
221
- *
222
- * Implementing caching can significantly reduce API calls and improve performance.
223
- * The SDK does not provide a default cache - you must implement {@link CacheInterface}.
224
- */
225
- cache?: CacheInterface;
226
-
227
- /**
228
- * Logger for debugging and observability.
229
- *
230
- * The logger receives debug, info, warn, and error messages from the SDK.
231
- * Compatible with `console` or any logger implementing {@link LoggerInterface}.
232
- *
233
- * @example
234
- * ```typescript
235
- * logger: console
236
- * // or
237
- * logger: pino()
238
- * // or
239
- * logger: winston.createLogger({ ... })
240
- * ```
241
- */
242
- logger?: LoggerInterface;
243
- }