@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.
- package/README.md +130 -8
- package/dist/index.cjs +93 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +64 -1
- package/dist/index.mjs +93 -16
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -5
- package/.turbo/turbo-build.log +0 -40
- package/.turbo/turbo-test.log +0 -119
- package/CHANGELOG.md +0 -62
- package/eslint.config.mjs +0 -22
- package/rollup.config.js +0 -75
- package/src/auth/OAuthClient.ts +0 -497
- package/src/core/SDK.ts +0 -410
- package/src/core/config.ts +0 -243
- package/src/core/errors.ts +0 -257
- package/src/core/interfaces.ts +0 -324
- package/src/core/types.ts +0 -282
- package/src/errors.ts +0 -57
- package/src/index.ts +0 -107
- package/src/lexicons.ts +0 -64
- package/src/repository/BlobOperationsImpl.ts +0 -199
- package/src/repository/CollaboratorOperationsImpl.ts +0 -442
- package/src/repository/HypercertOperationsImpl.ts +0 -1146
- package/src/repository/LexiconRegistry.ts +0 -332
- package/src/repository/OrganizationOperationsImpl.ts +0 -282
- package/src/repository/ProfileOperationsImpl.ts +0 -281
- package/src/repository/RecordOperationsImpl.ts +0 -340
- package/src/repository/Repository.ts +0 -482
- package/src/repository/interfaces.ts +0 -909
- package/src/repository/types.ts +0 -111
- package/src/services/hypercerts/types.ts +0 -87
- package/src/storage/InMemorySessionStore.ts +0 -127
- package/src/storage/InMemoryStateStore.ts +0 -146
- package/src/storage.ts +0 -63
- package/src/testing/index.ts +0 -67
- package/src/testing/mocks.ts +0 -142
- package/src/testing/stores.ts +0 -285
- package/src/testing.ts +0 -64
- package/src/types.ts +0 -86
- package/tests/auth/OAuthClient.test.ts +0 -164
- package/tests/core/SDK.test.ts +0 -176
- package/tests/core/errors.test.ts +0 -81
- package/tests/repository/BlobOperationsImpl.test.ts +0 -155
- package/tests/repository/CollaboratorOperationsImpl.test.ts +0 -438
- package/tests/repository/HypercertOperationsImpl.test.ts +0 -652
- package/tests/repository/LexiconRegistry.test.ts +0 -192
- package/tests/repository/OrganizationOperationsImpl.test.ts +0 -240
- package/tests/repository/ProfileOperationsImpl.test.ts +0 -254
- package/tests/repository/RecordOperationsImpl.test.ts +0 -375
- package/tests/repository/Repository.test.ts +0 -149
- package/tests/utils/fixtures.ts +0 -117
- package/tests/utils/mocks.ts +0 -109
- package/tests/utils/repository-fixtures.ts +0 -78
- package/tsconfig.json +0 -11
- package/tsconfig.tsbuildinfo +0 -1
- 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
|
-
}
|
package/src/core/config.ts
DELETED
|
@@ -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
|
-
}
|