@hypercerts-org/sdk-core 0.2.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 (83) hide show
  1. package/.turbo/turbo-build.log +328 -0
  2. package/.turbo/turbo-test.log +118 -0
  3. package/CHANGELOG.md +16 -0
  4. package/LICENSE +21 -0
  5. package/README.md +100 -0
  6. package/dist/errors.cjs +260 -0
  7. package/dist/errors.cjs.map +1 -0
  8. package/dist/errors.d.ts +233 -0
  9. package/dist/errors.mjs +253 -0
  10. package/dist/errors.mjs.map +1 -0
  11. package/dist/index.cjs +4531 -0
  12. package/dist/index.cjs.map +1 -0
  13. package/dist/index.d.ts +3430 -0
  14. package/dist/index.mjs +4448 -0
  15. package/dist/index.mjs.map +1 -0
  16. package/dist/lexicons.cjs +420 -0
  17. package/dist/lexicons.cjs.map +1 -0
  18. package/dist/lexicons.d.ts +227 -0
  19. package/dist/lexicons.mjs +410 -0
  20. package/dist/lexicons.mjs.map +1 -0
  21. package/dist/storage.cjs +270 -0
  22. package/dist/storage.cjs.map +1 -0
  23. package/dist/storage.d.ts +474 -0
  24. package/dist/storage.mjs +267 -0
  25. package/dist/storage.mjs.map +1 -0
  26. package/dist/testing.cjs +415 -0
  27. package/dist/testing.cjs.map +1 -0
  28. package/dist/testing.d.ts +928 -0
  29. package/dist/testing.mjs +410 -0
  30. package/dist/testing.mjs.map +1 -0
  31. package/dist/types.cjs +220 -0
  32. package/dist/types.cjs.map +1 -0
  33. package/dist/types.d.ts +2118 -0
  34. package/dist/types.mjs +212 -0
  35. package/dist/types.mjs.map +1 -0
  36. package/eslint.config.mjs +22 -0
  37. package/package.json +90 -0
  38. package/rollup.config.js +75 -0
  39. package/src/auth/OAuthClient.ts +497 -0
  40. package/src/core/SDK.ts +410 -0
  41. package/src/core/config.ts +243 -0
  42. package/src/core/errors.ts +257 -0
  43. package/src/core/interfaces.ts +324 -0
  44. package/src/core/types.ts +281 -0
  45. package/src/errors.ts +57 -0
  46. package/src/index.ts +107 -0
  47. package/src/lexicons.ts +64 -0
  48. package/src/repository/BlobOperationsImpl.ts +199 -0
  49. package/src/repository/CollaboratorOperationsImpl.ts +288 -0
  50. package/src/repository/HypercertOperationsImpl.ts +1146 -0
  51. package/src/repository/LexiconRegistry.ts +332 -0
  52. package/src/repository/OrganizationOperationsImpl.ts +234 -0
  53. package/src/repository/ProfileOperationsImpl.ts +281 -0
  54. package/src/repository/RecordOperationsImpl.ts +340 -0
  55. package/src/repository/Repository.ts +482 -0
  56. package/src/repository/interfaces.ts +868 -0
  57. package/src/repository/types.ts +111 -0
  58. package/src/services/hypercerts/types.ts +87 -0
  59. package/src/storage/InMemorySessionStore.ts +127 -0
  60. package/src/storage/InMemoryStateStore.ts +146 -0
  61. package/src/storage.ts +63 -0
  62. package/src/testing/index.ts +67 -0
  63. package/src/testing/mocks.ts +142 -0
  64. package/src/testing/stores.ts +285 -0
  65. package/src/testing.ts +64 -0
  66. package/src/types.ts +86 -0
  67. package/tests/auth/OAuthClient.test.ts +164 -0
  68. package/tests/core/SDK.test.ts +176 -0
  69. package/tests/core/errors.test.ts +81 -0
  70. package/tests/repository/BlobOperationsImpl.test.ts +154 -0
  71. package/tests/repository/CollaboratorOperationsImpl.test.ts +323 -0
  72. package/tests/repository/HypercertOperationsImpl.test.ts +652 -0
  73. package/tests/repository/LexiconRegistry.test.ts +192 -0
  74. package/tests/repository/OrganizationOperationsImpl.test.ts +242 -0
  75. package/tests/repository/ProfileOperationsImpl.test.ts +254 -0
  76. package/tests/repository/RecordOperationsImpl.test.ts +375 -0
  77. package/tests/repository/Repository.test.ts +149 -0
  78. package/tests/utils/fixtures.ts +117 -0
  79. package/tests/utils/mocks.ts +109 -0
  80. package/tests/utils/repository-fixtures.ts +78 -0
  81. package/tsconfig.json +11 -0
  82. package/tsconfig.tsbuildinfo +1 -0
  83. package/vitest.config.ts +30 -0
@@ -0,0 +1,3430 @@
1
+ import { Agent } from '@atproto/api';
2
+ import { LexiconDoc } from '@atproto/lexicon';
3
+ import { NodeSavedSession, NodeSavedState, OAuthSession } from '@atproto/oauth-client-node';
4
+ import { z } from 'zod';
5
+ import { EventEmitter } from 'eventemitter3';
6
+ import { OrgHypercertsClaim, OrgHypercertsCollection, ComAtprotoRepoStrongRef, OrgHypercertsClaimRights, OrgHypercertsClaimContribution, OrgHypercertsClaimMeasurement, OrgHypercertsClaimEvaluation, AppCertifiedLocation } from '@hypercerts-org/lexicon';
7
+ export { AppCertifiedDefs, AppCertifiedLocation, ComAtprotoRepoStrongRef, HYPERCERT_COLLECTIONS, HYPERCERT_LEXICONS, OrgHypercertsClaim, OrgHypercertsClaimContribution, OrgHypercertsClaimEvaluation, OrgHypercertsClaimEvidence, OrgHypercertsClaimMeasurement, OrgHypercertsClaimRights, OrgHypercertsCollection, ids, lexicons, schemaDict, schemas, validate } from '@hypercerts-org/lexicon';
8
+
9
+ /**
10
+ * Result of validating a record against a lexicon schema.
11
+ */
12
+ interface ValidationResult {
13
+ /**
14
+ * Whether the record is valid according to the lexicon schema.
15
+ */
16
+ valid: boolean;
17
+ /**
18
+ * Error message if validation failed.
19
+ *
20
+ * Only present when `valid` is `false`.
21
+ */
22
+ error?: string;
23
+ }
24
+ /**
25
+ * Registry for managing and validating AT Protocol lexicon schemas.
26
+ *
27
+ * Lexicons are schema definitions that describe the structure of records
28
+ * in the AT Protocol. This registry allows you to:
29
+ *
30
+ * - Register custom lexicons for your application's record types
31
+ * - Validate records against their lexicon schemas
32
+ * - Extend the AT Protocol Agent with custom lexicon support
33
+ *
34
+ * @remarks
35
+ * The SDK automatically registers hypercert lexicons when creating a Repository.
36
+ * You only need to use this class directly if you're working with custom
37
+ * record types.
38
+ *
39
+ * **Lexicon IDs** follow the NSID (Namespaced Identifier) format:
40
+ * `{authority}.{name}` (e.g., `org.hypercerts.hypercert`)
41
+ *
42
+ * @example Registering custom lexicons
43
+ * ```typescript
44
+ * const registry = sdk.getLexiconRegistry();
45
+ *
46
+ * // Register a single lexicon
47
+ * registry.register({
48
+ * lexicon: 1,
49
+ * id: "org.example.myRecord",
50
+ * defs: {
51
+ * main: {
52
+ * type: "record",
53
+ * key: "tid",
54
+ * record: {
55
+ * type: "object",
56
+ * required: ["title", "createdAt"],
57
+ * properties: {
58
+ * title: { type: "string" },
59
+ * description: { type: "string" },
60
+ * createdAt: { type: "string", format: "datetime" },
61
+ * },
62
+ * },
63
+ * },
64
+ * },
65
+ * });
66
+ *
67
+ * // Register multiple lexicons at once
68
+ * registry.registerMany([lexicon1, lexicon2, lexicon3]);
69
+ * ```
70
+ *
71
+ * @example Validating records
72
+ * ```typescript
73
+ * const result = registry.validate("org.example.myRecord", {
74
+ * title: "Test",
75
+ * createdAt: new Date().toISOString(),
76
+ * });
77
+ *
78
+ * if (!result.valid) {
79
+ * console.error(`Validation failed: ${result.error}`);
80
+ * }
81
+ * ```
82
+ *
83
+ * @see https://atproto.com/specs/lexicon for the Lexicon specification
84
+ */
85
+ declare class LexiconRegistry {
86
+ /** Map of lexicon ID to lexicon document */
87
+ private lexicons;
88
+ /** Lexicons collection for validation */
89
+ private lexiconsCollection;
90
+ /**
91
+ * Creates a new LexiconRegistry.
92
+ *
93
+ * The registry starts empty. Use {@link register} or {@link registerMany}
94
+ * to add lexicons.
95
+ */
96
+ constructor();
97
+ /**
98
+ * Registers a single lexicon schema.
99
+ *
100
+ * @param lexicon - The lexicon document to register
101
+ * @throws {@link ValidationError} if the lexicon doesn't have an `id` field
102
+ *
103
+ * @remarks
104
+ * If a lexicon with the same ID is already registered, it will be
105
+ * replaced with the new definition. This is useful for testing but
106
+ * should generally be avoided in production.
107
+ *
108
+ * @example
109
+ * ```typescript
110
+ * registry.register({
111
+ * lexicon: 1,
112
+ * id: "org.example.post",
113
+ * defs: {
114
+ * main: {
115
+ * type: "record",
116
+ * key: "tid",
117
+ * record: {
118
+ * type: "object",
119
+ * required: ["text", "createdAt"],
120
+ * properties: {
121
+ * text: { type: "string", maxLength: 300 },
122
+ * createdAt: { type: "string", format: "datetime" },
123
+ * },
124
+ * },
125
+ * },
126
+ * },
127
+ * });
128
+ * ```
129
+ */
130
+ register(lexicon: LexiconDoc): void;
131
+ /**
132
+ * Registers multiple lexicons at once.
133
+ *
134
+ * @param lexicons - Array of lexicon documents to register
135
+ *
136
+ * @example
137
+ * ```typescript
138
+ * import { HYPERCERT_LEXICONS } from "@hypercerts-org/sdk/lexicons";
139
+ *
140
+ * registry.registerMany(HYPERCERT_LEXICONS);
141
+ * ```
142
+ */
143
+ registerMany(lexicons: LexiconDoc[]): void;
144
+ /**
145
+ * Gets a lexicon document by ID.
146
+ *
147
+ * @param id - The lexicon NSID (e.g., "org.hypercerts.hypercert")
148
+ * @returns The lexicon document, or `undefined` if not registered
149
+ *
150
+ * @example
151
+ * ```typescript
152
+ * const lexicon = registry.get("org.hypercerts.hypercert");
153
+ * if (lexicon) {
154
+ * console.log(`Found lexicon: ${lexicon.id}`);
155
+ * }
156
+ * ```
157
+ */
158
+ get(id: string): LexiconDoc | undefined;
159
+ /**
160
+ * Validates a record against a collection's lexicon schema.
161
+ *
162
+ * @param collection - The collection NSID (same as lexicon ID)
163
+ * @param record - The record data to validate
164
+ * @returns Validation result with `valid` boolean and optional `error` message
165
+ *
166
+ * @remarks
167
+ * - If no lexicon is registered for the collection, validation passes
168
+ * (we can't validate against unknown schemas)
169
+ * - Validation checks required fields and type constraints defined
170
+ * in the lexicon schema
171
+ *
172
+ * @example
173
+ * ```typescript
174
+ * const result = registry.validate("org.hypercerts.hypercert", {
175
+ * title: "My Hypercert",
176
+ * description: "Description...",
177
+ * // ... other fields
178
+ * });
179
+ *
180
+ * if (!result.valid) {
181
+ * throw new Error(`Invalid record: ${result.error}`);
182
+ * }
183
+ * ```
184
+ */
185
+ validate(collection: string, record: unknown): ValidationResult;
186
+ /**
187
+ * Adds all registered lexicons to an AT Protocol Agent instance.
188
+ *
189
+ * This allows the Agent to understand custom lexicon types when making
190
+ * API requests.
191
+ *
192
+ * @param agent - The Agent instance to extend
193
+ *
194
+ * @remarks
195
+ * This is called automatically when creating a Repository. You typically
196
+ * don't need to call this directly unless you're using the Agent
197
+ * independently.
198
+ *
199
+ * @internal
200
+ */
201
+ addToAgent(agent: Agent): void;
202
+ /**
203
+ * Gets all registered lexicon IDs.
204
+ *
205
+ * @returns Array of lexicon NSIDs
206
+ *
207
+ * @example
208
+ * ```typescript
209
+ * const ids = registry.getRegisteredIds();
210
+ * console.log(`Registered lexicons: ${ids.join(", ")}`);
211
+ * ```
212
+ */
213
+ getRegisteredIds(): string[];
214
+ /**
215
+ * Checks if a lexicon is registered.
216
+ *
217
+ * @param id - The lexicon NSID to check
218
+ * @returns `true` if the lexicon is registered
219
+ *
220
+ * @example
221
+ * ```typescript
222
+ * if (registry.has("org.hypercerts.hypercert")) {
223
+ * // Hypercert lexicon is available
224
+ * }
225
+ * ```
226
+ */
227
+ has(id: string): boolean;
228
+ }
229
+
230
+ /**
231
+ * Storage interface for persisting OAuth sessions.
232
+ *
233
+ * Implement this interface to provide persistent storage for user sessions.
234
+ * Sessions contain sensitive data including access tokens, refresh tokens,
235
+ * and DPoP key pairs.
236
+ *
237
+ * The SDK provides {@link InMemorySessionStore} for development/testing,
238
+ * but **production applications should implement persistent storage**
239
+ * (e.g., Redis, PostgreSQL, MongoDB).
240
+ *
241
+ * @remarks
242
+ * - Sessions are keyed by the user's DID (Decentralized Identifier)
243
+ * - The `NodeSavedSession` type comes from `@atproto/oauth-client-node`
244
+ * - Sessions may be large (~2-4KB) due to embedded cryptographic keys
245
+ * - Consider encrypting sessions at rest for additional security
246
+ *
247
+ * @example Redis implementation
248
+ * ```typescript
249
+ * import { Redis } from "ioredis";
250
+ * import type { SessionStore } from "@hypercerts-org/sdk";
251
+ * import type { NodeSavedSession } from "@atproto/oauth-client-node";
252
+ *
253
+ * class RedisSessionStore implements SessionStore {
254
+ * constructor(private redis: Redis, private prefix = "session:") {}
255
+ *
256
+ * async get(did: string): Promise<NodeSavedSession | undefined> {
257
+ * const data = await this.redis.get(this.prefix + did);
258
+ * return data ? JSON.parse(data) : undefined;
259
+ * }
260
+ *
261
+ * async set(did: string, session: NodeSavedSession): Promise<void> {
262
+ * // Set with 30-day expiry (sessions can be refreshed)
263
+ * await this.redis.setex(
264
+ * this.prefix + did,
265
+ * 30 * 24 * 60 * 60,
266
+ * JSON.stringify(session)
267
+ * );
268
+ * }
269
+ *
270
+ * async del(did: string): Promise<void> {
271
+ * await this.redis.del(this.prefix + did);
272
+ * }
273
+ * }
274
+ * ```
275
+ *
276
+ * @see {@link InMemorySessionStore} for the default in-memory implementation
277
+ */
278
+ interface SessionStore {
279
+ /**
280
+ * Retrieves a session by DID.
281
+ *
282
+ * @param did - The user's Decentralized Identifier (e.g., "did:plc:abc123...")
283
+ * @returns The stored session, or `undefined` if not found
284
+ */
285
+ get(did: string): Promise<NodeSavedSession | undefined>;
286
+ /**
287
+ * Stores or updates a session.
288
+ *
289
+ * This is called after successful authentication and whenever tokens are refreshed.
290
+ *
291
+ * @param did - The user's DID to use as the storage key
292
+ * @param session - The session data to store (contains tokens, DPoP keys, etc.)
293
+ */
294
+ set(did: string, session: NodeSavedSession): Promise<void>;
295
+ /**
296
+ * Deletes a session.
297
+ *
298
+ * Called when a user logs out or when a session is revoked.
299
+ *
300
+ * @param did - The user's DID
301
+ */
302
+ del(did: string): Promise<void>;
303
+ }
304
+ /**
305
+ * Storage interface for OAuth state during the authorization flow.
306
+ *
307
+ * Implement this interface to provide temporary storage for OAuth state
308
+ * parameters. State is used for CSRF protection and PKCE (Proof Key for
309
+ * Code Exchange) during the authorization flow.
310
+ *
311
+ * @remarks
312
+ * - State is short-lived (typically 10-15 minutes)
313
+ * - Keys are random state strings generated by the OAuth client
314
+ * - The `NodeSavedState` type comes from `@atproto/oauth-client-node`
315
+ * - State should be automatically cleaned up after expiry
316
+ *
317
+ * @example Redis implementation with automatic expiry
318
+ * ```typescript
319
+ * import { Redis } from "ioredis";
320
+ * import type { StateStore } from "@hypercerts-org/sdk";
321
+ * import type { NodeSavedState } from "@atproto/oauth-client-node";
322
+ *
323
+ * class RedisStateStore implements StateStore {
324
+ * constructor(
325
+ * private redis: Redis,
326
+ * private prefix = "oauth-state:",
327
+ * private ttlSeconds = 900 // 15 minutes
328
+ * ) {}
329
+ *
330
+ * async get(key: string): Promise<NodeSavedState | undefined> {
331
+ * const data = await this.redis.get(this.prefix + key);
332
+ * return data ? JSON.parse(data) : undefined;
333
+ * }
334
+ *
335
+ * async set(key: string, state: NodeSavedState): Promise<void> {
336
+ * await this.redis.setex(
337
+ * this.prefix + key,
338
+ * this.ttlSeconds,
339
+ * JSON.stringify(state)
340
+ * );
341
+ * }
342
+ *
343
+ * async del(key: string): Promise<void> {
344
+ * await this.redis.del(this.prefix + key);
345
+ * }
346
+ * }
347
+ * ```
348
+ *
349
+ * @see {@link InMemoryStateStore} for the default in-memory implementation
350
+ */
351
+ interface StateStore {
352
+ /**
353
+ * Retrieves OAuth state by key.
354
+ *
355
+ * @param key - The state key (random string from authorization URL)
356
+ * @returns The stored state, or `undefined` if not found or expired
357
+ */
358
+ get(key: string): Promise<NodeSavedState | undefined>;
359
+ /**
360
+ * Stores OAuth state temporarily.
361
+ *
362
+ * Called when starting the authorization flow. The state should be
363
+ * stored with a short TTL (10-15 minutes recommended).
364
+ *
365
+ * @param key - The state key to use for storage
366
+ * @param state - The OAuth state data (includes PKCE verifier, etc.)
367
+ */
368
+ set(key: string, state: NodeSavedState): Promise<void>;
369
+ /**
370
+ * Deletes OAuth state.
371
+ *
372
+ * Called after the state has been used (successful or failed callback).
373
+ *
374
+ * @param key - The state key to delete
375
+ */
376
+ del(key: string): Promise<void>;
377
+ }
378
+ /**
379
+ * Generic cache interface for profiles, metadata, and other data.
380
+ *
381
+ * Implement this interface to provide caching for frequently accessed data.
382
+ * Caching can significantly reduce API calls and improve performance.
383
+ *
384
+ * @remarks
385
+ * The SDK does not provide a default cache implementation - you must
386
+ * implement this interface if you want caching. Consider using:
387
+ * - In-memory cache (e.g., `lru-cache`) for single-instance applications
388
+ * - Redis for distributed applications
389
+ * - Database-backed cache for persistence
390
+ *
391
+ * @example LRU cache implementation
392
+ * ```typescript
393
+ * import { LRUCache } from "lru-cache";
394
+ * import type { CacheInterface } from "@hypercerts-org/sdk";
395
+ *
396
+ * class LRUCacheAdapter implements CacheInterface {
397
+ * private cache = new LRUCache<string, unknown>({
398
+ * max: 1000,
399
+ * ttl: 5 * 60 * 1000, // 5 minutes default
400
+ * });
401
+ *
402
+ * async get<T>(key: string): Promise<T | undefined> {
403
+ * return this.cache.get(key) as T | undefined;
404
+ * }
405
+ *
406
+ * async set<T>(key: string, value: T, ttlSeconds?: number): Promise<void> {
407
+ * this.cache.set(key, value, {
408
+ * ttl: ttlSeconds ? ttlSeconds * 1000 : undefined,
409
+ * });
410
+ * }
411
+ *
412
+ * async del(key: string): Promise<void> {
413
+ * this.cache.delete(key);
414
+ * }
415
+ *
416
+ * async clear(): Promise<void> {
417
+ * this.cache.clear();
418
+ * }
419
+ * }
420
+ * ```
421
+ */
422
+ interface CacheInterface {
423
+ /**
424
+ * Gets a cached value by key.
425
+ *
426
+ * @typeParam T - The expected type of the cached value
427
+ * @param key - The cache key
428
+ * @returns The cached value, or `undefined` if not found or expired
429
+ */
430
+ get<T>(key: string): Promise<T | undefined>;
431
+ /**
432
+ * Sets a cached value with optional TTL (time-to-live).
433
+ *
434
+ * @typeParam T - The type of the value being cached
435
+ * @param key - The cache key
436
+ * @param value - The value to cache
437
+ * @param ttlSeconds - Optional time-to-live in seconds. If not provided,
438
+ * the cache implementation should use its default TTL.
439
+ */
440
+ set<T>(key: string, value: T, ttlSeconds?: number): Promise<void>;
441
+ /**
442
+ * Deletes a cached value.
443
+ *
444
+ * @param key - The cache key to delete
445
+ */
446
+ del(key: string): Promise<void>;
447
+ /**
448
+ * Clears all cached values.
449
+ *
450
+ * Use with caution in production as this affects all cached data.
451
+ */
452
+ clear(): Promise<void>;
453
+ }
454
+ /**
455
+ * Logger interface for debugging and observability.
456
+ *
457
+ * Implement this interface to receive log messages from the SDK.
458
+ * The interface is compatible with `console` and most popular
459
+ * logging libraries (Pino, Winston, Bunyan, etc.).
460
+ *
461
+ * @remarks
462
+ * Log levels follow standard conventions:
463
+ * - `debug`: Detailed information for debugging (tokens, request details)
464
+ * - `info`: General operational messages (initialization, successful auth)
465
+ * - `warn`: Potentially problematic situations (deprecated features, retries)
466
+ * - `error`: Errors that don't crash the application (failed requests, validation)
467
+ *
468
+ * @example Using console
469
+ * ```typescript
470
+ * const sdk = new ATProtoSDK({
471
+ * // ...
472
+ * logger: console,
473
+ * });
474
+ * ```
475
+ *
476
+ * @example Using Pino
477
+ * ```typescript
478
+ * import pino from "pino";
479
+ *
480
+ * const logger = pino({ level: "debug" });
481
+ * const sdk = new ATProtoSDK({
482
+ * // ...
483
+ * logger: logger,
484
+ * });
485
+ * ```
486
+ *
487
+ * @example Custom logger with context
488
+ * ```typescript
489
+ * const logger: LoggerInterface = {
490
+ * debug: (msg, ...args) => console.debug(`[SDK] ${msg}`, ...args),
491
+ * info: (msg, ...args) => console.info(`[SDK] ${msg}`, ...args),
492
+ * warn: (msg, ...args) => console.warn(`[SDK] ${msg}`, ...args),
493
+ * error: (msg, ...args) => console.error(`[SDK] ${msg}`, ...args),
494
+ * };
495
+ * ```
496
+ */
497
+ interface LoggerInterface {
498
+ /**
499
+ * Logs debug-level messages.
500
+ *
501
+ * Used for detailed diagnostic information. May include sensitive
502
+ * data like request URLs and headers (but not tokens).
503
+ *
504
+ * @param message - The log message
505
+ * @param args - Additional arguments (objects, error details, etc.)
506
+ */
507
+ debug(message: string, ...args: unknown[]): void;
508
+ /**
509
+ * Logs info-level messages.
510
+ *
511
+ * Used for general operational information like successful
512
+ * initialization, authentication events, etc.
513
+ *
514
+ * @param message - The log message
515
+ * @param args - Additional arguments
516
+ */
517
+ info(message: string, ...args: unknown[]): void;
518
+ /**
519
+ * Logs warning-level messages.
520
+ *
521
+ * Used for potentially problematic situations that don't prevent
522
+ * operation but may indicate issues.
523
+ *
524
+ * @param message - The log message
525
+ * @param args - Additional arguments
526
+ */
527
+ warn(message: string, ...args: unknown[]): void;
528
+ /**
529
+ * Logs error-level messages.
530
+ *
531
+ * Used for error conditions that should be investigated.
532
+ * The SDK continues to operate after logging errors.
533
+ *
534
+ * @param message - The log message
535
+ * @param args - Additional arguments (typically includes the error object)
536
+ */
537
+ error(message: string, ...args: unknown[]): void;
538
+ }
539
+
540
+ /**
541
+ * Decentralized Identifier (DID) - a unique, persistent identifier for AT Protocol users.
542
+ *
543
+ * DIDs are the canonical identifier for users in the AT Protocol ecosystem.
544
+ * Unlike handles which can change, DIDs remain constant for the lifetime of an account.
545
+ *
546
+ * @remarks
547
+ * AT Protocol supports multiple DID methods:
548
+ * - `did:plc:` - PLC (Public Ledger of Credentials) DIDs, most common for Bluesky users
549
+ * - `did:web:` - Web DIDs, resolved via HTTPS
550
+ *
551
+ * @example
552
+ * ```typescript
553
+ * const did: DID = "did:plc:ewvi7nxzyoun6zhxrhs64oiz";
554
+ * const webDid: DID = "did:web:example.com";
555
+ * ```
556
+ *
557
+ * @see https://atproto.com/specs/did for DID specification
558
+ */
559
+ type DID = string;
560
+ /**
561
+ * OAuth session with DPoP (Demonstrating Proof of Possession) support.
562
+ *
563
+ * This type represents an authenticated user session. It wraps the
564
+ * `@atproto/oauth-client-node` OAuthSession and contains:
565
+ * - Access token for API requests
566
+ * - Refresh token for obtaining new access tokens
567
+ * - DPoP key pair for proof-of-possession
568
+ * - User's DID and other identity information
569
+ *
570
+ * @remarks
571
+ * Sessions are managed by the SDK and automatically refresh when tokens expire.
572
+ * Store the user's DID to restore sessions later with {@link ATProtoSDK.restoreSession}.
573
+ *
574
+ * Key properties from OAuthSession:
575
+ * - `did` or `sub`: The user's DID
576
+ * - `handle`: The user's handle (e.g., "user.bsky.social")
577
+ *
578
+ * @example
579
+ * ```typescript
580
+ * const session = await sdk.callback(params);
581
+ *
582
+ * // Access user identity
583
+ * console.log(`Logged in as: ${session.did}`);
584
+ *
585
+ * // Use session for repository operations
586
+ * const repo = sdk.repository(session);
587
+ * ```
588
+ *
589
+ * @see https://atproto.com/specs/oauth for OAuth specification
590
+ */
591
+ type Session = OAuthSession;
592
+ /**
593
+ * Zod schema for collaborator permissions in SDS repositories.
594
+ *
595
+ * Defines the granular permissions a collaborator can have on a shared repository.
596
+ * Permissions follow a hierarchical model where higher-level permissions
597
+ * typically imply lower-level ones.
598
+ */
599
+ declare const CollaboratorPermissionsSchema: z.ZodObject<{
600
+ /**
601
+ * Can read/view records in the repository.
602
+ * This is the most basic permission level.
603
+ */
604
+ read: z.ZodBoolean;
605
+ /**
606
+ * Can create new records in the repository.
607
+ * Typically implies `read` permission.
608
+ */
609
+ create: z.ZodBoolean;
610
+ /**
611
+ * Can modify existing records in the repository.
612
+ * Typically implies `read` and `create` permissions.
613
+ */
614
+ update: z.ZodBoolean;
615
+ /**
616
+ * Can delete records from the repository.
617
+ * Typically implies `read`, `create`, and `update` permissions.
618
+ */
619
+ delete: z.ZodBoolean;
620
+ /**
621
+ * Can manage collaborators and their permissions.
622
+ * Administrative permission that allows inviting/removing collaborators.
623
+ */
624
+ admin: z.ZodBoolean;
625
+ /**
626
+ * Full ownership of the repository.
627
+ * Owners have all permissions and cannot be removed by other admins.
628
+ * There must always be at least one owner.
629
+ */
630
+ owner: z.ZodBoolean;
631
+ }, "strip", z.ZodTypeAny, {
632
+ read: boolean;
633
+ create: boolean;
634
+ update: boolean;
635
+ delete: boolean;
636
+ admin: boolean;
637
+ owner: boolean;
638
+ }, {
639
+ read: boolean;
640
+ create: boolean;
641
+ update: boolean;
642
+ delete: boolean;
643
+ admin: boolean;
644
+ owner: boolean;
645
+ }>;
646
+ /**
647
+ * Collaborator permissions for SDS (Shared Data Server) repositories.
648
+ *
649
+ * These permissions control what actions a collaborator can perform
650
+ * on records within a shared repository.
651
+ *
652
+ * @example
653
+ * ```typescript
654
+ * // Read-only collaborator
655
+ * const readOnlyPerms: CollaboratorPermissions = {
656
+ * read: true,
657
+ * create: false,
658
+ * update: false,
659
+ * delete: false,
660
+ * admin: false,
661
+ * owner: false,
662
+ * };
663
+ *
664
+ * // Editor collaborator
665
+ * const editorPerms: CollaboratorPermissions = {
666
+ * read: true,
667
+ * create: true,
668
+ * update: true,
669
+ * delete: false,
670
+ * admin: false,
671
+ * owner: false,
672
+ * };
673
+ *
674
+ * // Admin collaborator
675
+ * const adminPerms: CollaboratorPermissions = {
676
+ * read: true,
677
+ * create: true,
678
+ * update: true,
679
+ * delete: true,
680
+ * admin: true,
681
+ * owner: false,
682
+ * };
683
+ * ```
684
+ */
685
+ type CollaboratorPermissions = z.infer<typeof CollaboratorPermissionsSchema>;
686
+ /**
687
+ * Zod schema for SDS organization data.
688
+ *
689
+ * Organizations are top-level entities in SDS that can own repositories
690
+ * and have multiple collaborators with different permission levels.
691
+ */
692
+ declare const OrganizationSchema: z.ZodObject<{
693
+ /**
694
+ * The organization's DID - unique identifier.
695
+ * Format: "did:plc:..." or "did:web:..."
696
+ */
697
+ did: z.ZodString;
698
+ /**
699
+ * The organization's handle - human-readable identifier.
700
+ * Format: "orgname.sds.hypercerts.org" or similar
701
+ */
702
+ handle: z.ZodString;
703
+ /**
704
+ * Display name for the organization.
705
+ */
706
+ name: z.ZodString;
707
+ /**
708
+ * Optional description of the organization's purpose.
709
+ */
710
+ description: z.ZodOptional<z.ZodString>;
711
+ /**
712
+ * ISO 8601 timestamp when the organization was created.
713
+ * Format: "2024-01-15T10:30:00.000Z"
714
+ */
715
+ createdAt: z.ZodString;
716
+ /**
717
+ * The current user's permissions within this organization.
718
+ */
719
+ permissions: z.ZodObject<{
720
+ /**
721
+ * Can read/view records in the repository.
722
+ * This is the most basic permission level.
723
+ */
724
+ read: z.ZodBoolean;
725
+ /**
726
+ * Can create new records in the repository.
727
+ * Typically implies `read` permission.
728
+ */
729
+ create: z.ZodBoolean;
730
+ /**
731
+ * Can modify existing records in the repository.
732
+ * Typically implies `read` and `create` permissions.
733
+ */
734
+ update: z.ZodBoolean;
735
+ /**
736
+ * Can delete records from the repository.
737
+ * Typically implies `read`, `create`, and `update` permissions.
738
+ */
739
+ delete: z.ZodBoolean;
740
+ /**
741
+ * Can manage collaborators and their permissions.
742
+ * Administrative permission that allows inviting/removing collaborators.
743
+ */
744
+ admin: z.ZodBoolean;
745
+ /**
746
+ * Full ownership of the repository.
747
+ * Owners have all permissions and cannot be removed by other admins.
748
+ * There must always be at least one owner.
749
+ */
750
+ owner: z.ZodBoolean;
751
+ }, "strip", z.ZodTypeAny, {
752
+ read: boolean;
753
+ create: boolean;
754
+ update: boolean;
755
+ delete: boolean;
756
+ admin: boolean;
757
+ owner: boolean;
758
+ }, {
759
+ read: boolean;
760
+ create: boolean;
761
+ update: boolean;
762
+ delete: boolean;
763
+ admin: boolean;
764
+ owner: boolean;
765
+ }>;
766
+ /**
767
+ * How the current user relates to this organization.
768
+ * - `"owner"`: User created or owns the organization
769
+ * - `"collaborator"`: User was invited to collaborate
770
+ */
771
+ accessType: z.ZodEnum<["owner", "collaborator"]>;
772
+ }, "strip", z.ZodTypeAny, {
773
+ did: string;
774
+ handle: string;
775
+ name: string;
776
+ createdAt: string;
777
+ permissions: {
778
+ read: boolean;
779
+ create: boolean;
780
+ update: boolean;
781
+ delete: boolean;
782
+ admin: boolean;
783
+ owner: boolean;
784
+ };
785
+ accessType: "owner" | "collaborator";
786
+ description?: string | undefined;
787
+ }, {
788
+ did: string;
789
+ handle: string;
790
+ name: string;
791
+ createdAt: string;
792
+ permissions: {
793
+ read: boolean;
794
+ create: boolean;
795
+ update: boolean;
796
+ delete: boolean;
797
+ admin: boolean;
798
+ owner: boolean;
799
+ };
800
+ accessType: "owner" | "collaborator";
801
+ description?: string | undefined;
802
+ }>;
803
+ /**
804
+ * SDS Organization entity.
805
+ *
806
+ * Represents an organization on a Shared Data Server. Organizations
807
+ * provide a way to group repositories and manage access for teams.
808
+ *
809
+ * @example
810
+ * ```typescript
811
+ * const org: Organization = {
812
+ * did: "did:plc:org123abc",
813
+ * handle: "my-team.sds.hypercerts.org",
814
+ * name: "My Team",
815
+ * description: "A team working on impact certificates",
816
+ * createdAt: "2024-01-15T10:30:00.000Z",
817
+ * permissions: {
818
+ * read: true,
819
+ * create: true,
820
+ * update: true,
821
+ * delete: true,
822
+ * admin: true,
823
+ * owner: true,
824
+ * },
825
+ * accessType: "owner",
826
+ * };
827
+ * ```
828
+ */
829
+ type Organization = z.infer<typeof OrganizationSchema>;
830
+ /**
831
+ * Zod schema for collaborator data.
832
+ *
833
+ * Represents a user who has been granted access to a shared repository
834
+ * or organization with specific permissions.
835
+ */
836
+ declare const CollaboratorSchema: z.ZodObject<{
837
+ /**
838
+ * The collaborator's DID - their unique identifier.
839
+ * Format: "did:plc:..." or "did:web:..."
840
+ */
841
+ userDid: z.ZodString;
842
+ /**
843
+ * The permissions granted to this collaborator.
844
+ */
845
+ permissions: z.ZodObject<{
846
+ /**
847
+ * Can read/view records in the repository.
848
+ * This is the most basic permission level.
849
+ */
850
+ read: z.ZodBoolean;
851
+ /**
852
+ * Can create new records in the repository.
853
+ * Typically implies `read` permission.
854
+ */
855
+ create: z.ZodBoolean;
856
+ /**
857
+ * Can modify existing records in the repository.
858
+ * Typically implies `read` and `create` permissions.
859
+ */
860
+ update: z.ZodBoolean;
861
+ /**
862
+ * Can delete records from the repository.
863
+ * Typically implies `read`, `create`, and `update` permissions.
864
+ */
865
+ delete: z.ZodBoolean;
866
+ /**
867
+ * Can manage collaborators and their permissions.
868
+ * Administrative permission that allows inviting/removing collaborators.
869
+ */
870
+ admin: z.ZodBoolean;
871
+ /**
872
+ * Full ownership of the repository.
873
+ * Owners have all permissions and cannot be removed by other admins.
874
+ * There must always be at least one owner.
875
+ */
876
+ owner: z.ZodBoolean;
877
+ }, "strip", z.ZodTypeAny, {
878
+ read: boolean;
879
+ create: boolean;
880
+ update: boolean;
881
+ delete: boolean;
882
+ admin: boolean;
883
+ owner: boolean;
884
+ }, {
885
+ read: boolean;
886
+ create: boolean;
887
+ update: boolean;
888
+ delete: boolean;
889
+ admin: boolean;
890
+ owner: boolean;
891
+ }>;
892
+ /**
893
+ * DID of the user who granted these permissions.
894
+ * Useful for audit trails.
895
+ */
896
+ grantedBy: z.ZodString;
897
+ /**
898
+ * ISO 8601 timestamp when permissions were granted.
899
+ * Format: "2024-01-15T10:30:00.000Z"
900
+ */
901
+ grantedAt: z.ZodString;
902
+ /**
903
+ * ISO 8601 timestamp when permissions were revoked, if applicable.
904
+ * Undefined if the collaborator is still active.
905
+ */
906
+ revokedAt: z.ZodOptional<z.ZodString>;
907
+ }, "strip", z.ZodTypeAny, {
908
+ permissions: {
909
+ read: boolean;
910
+ create: boolean;
911
+ update: boolean;
912
+ delete: boolean;
913
+ admin: boolean;
914
+ owner: boolean;
915
+ };
916
+ userDid: string;
917
+ grantedBy: string;
918
+ grantedAt: string;
919
+ revokedAt?: string | undefined;
920
+ }, {
921
+ permissions: {
922
+ read: boolean;
923
+ create: boolean;
924
+ update: boolean;
925
+ delete: boolean;
926
+ admin: boolean;
927
+ owner: boolean;
928
+ };
929
+ userDid: string;
930
+ grantedBy: string;
931
+ grantedAt: string;
932
+ revokedAt?: string | undefined;
933
+ }>;
934
+ /**
935
+ * Collaborator information for SDS repositories.
936
+ *
937
+ * Represents a user who has been granted access to collaborate on
938
+ * a shared repository or organization.
939
+ *
940
+ * @example
941
+ * ```typescript
942
+ * const collaborator: Collaborator = {
943
+ * userDid: "did:plc:user456def",
944
+ * permissions: {
945
+ * read: true,
946
+ * create: true,
947
+ * update: true,
948
+ * delete: false,
949
+ * admin: false,
950
+ * owner: false,
951
+ * },
952
+ * grantedBy: "did:plc:owner123abc",
953
+ * grantedAt: "2024-02-01T14:00:00.000Z",
954
+ * };
955
+ * ```
956
+ */
957
+ type Collaborator = z.infer<typeof CollaboratorSchema>;
958
+
959
+ /**
960
+ * Repository types - Shared types for repository operations
961
+ * @packageDocumentation
962
+ */
963
+
964
+ /**
965
+ * Options for creating a repository instance
966
+ */
967
+ interface RepositoryOptions {
968
+ /** Use "sds" for configured SDS server, or provide a custom URL */
969
+ server?: "pds" | "sds" | string;
970
+ /** Custom server URL (overrides server option) */
971
+ serverUrl?: string;
972
+ }
973
+ /**
974
+ * Result of a create operation
975
+ */
976
+ interface CreateResult {
977
+ uri: string;
978
+ cid: string;
979
+ }
980
+ /**
981
+ * Result of an update operation
982
+ */
983
+ interface UpdateResult {
984
+ uri: string;
985
+ cid: string;
986
+ }
987
+ /**
988
+ * Paginated list result
989
+ */
990
+ interface PaginatedList<T> {
991
+ records: T[];
992
+ cursor?: string;
993
+ }
994
+ /**
995
+ * List parameters
996
+ */
997
+ interface ListParams {
998
+ limit?: number;
999
+ cursor?: string;
1000
+ }
1001
+ /**
1002
+ * Role for repository access
1003
+ */
1004
+ type RepositoryRole = "viewer" | "editor" | "admin" | "owner";
1005
+ /**
1006
+ * Repository access grant
1007
+ */
1008
+ interface RepositoryAccessGrant {
1009
+ userDid: string;
1010
+ role: RepositoryRole;
1011
+ permissions: CollaboratorPermissions;
1012
+ grantedBy: string;
1013
+ grantedAt: string;
1014
+ revokedAt?: string;
1015
+ }
1016
+ /**
1017
+ * Organization info
1018
+ */
1019
+ interface OrganizationInfo {
1020
+ did: string;
1021
+ handle: string;
1022
+ name: string;
1023
+ description?: string;
1024
+ createdAt: string;
1025
+ accessType: "owner" | "collaborator";
1026
+ permissions: CollaboratorPermissions;
1027
+ collaboratorCount?: number;
1028
+ profile?: {
1029
+ displayName?: string;
1030
+ avatar?: string;
1031
+ banner?: string;
1032
+ website?: string;
1033
+ };
1034
+ }
1035
+ /**
1036
+ * Progress step for long-running operations
1037
+ */
1038
+ interface ProgressStep {
1039
+ name: string;
1040
+ status: "start" | "success" | "error";
1041
+ data?: unknown;
1042
+ error?: Error;
1043
+ }
1044
+
1045
+ /**
1046
+ * TypeScript types for hypercert lexicon schemas.
1047
+ *
1048
+ * Re-exports generated types and validation from `@hypercerts-org/lexicon`.
1049
+ *
1050
+ * @packageDocumentation
1051
+ */
1052
+
1053
+ type StrongRef = ComAtprotoRepoStrongRef.Main;
1054
+ type HypercertClaim = OrgHypercertsClaim.Main;
1055
+ type HypercertRights = OrgHypercertsClaimRights.Main;
1056
+ type HypercertContribution = OrgHypercertsClaimContribution.Main;
1057
+ type HypercertMeasurement = OrgHypercertsClaimMeasurement.Main;
1058
+ type HypercertEvaluation = OrgHypercertsClaimEvaluation.Main;
1059
+ type HypercertCollection = OrgHypercertsCollection.Main;
1060
+ type HypercertCollectionClaimItem = OrgHypercertsCollection.ClaimItem;
1061
+ type HypercertLocation = AppCertifiedLocation.Main;
1062
+ /** Blob reference for uploaded files (images, GeoJSON, etc.) */
1063
+ interface BlobRef {
1064
+ $type: "blob";
1065
+ ref: {
1066
+ $link: string;
1067
+ };
1068
+ mimeType: string;
1069
+ size: number;
1070
+ }
1071
+ /** Evidence item for operations */
1072
+ interface HypercertEvidence {
1073
+ uri: string;
1074
+ title?: string;
1075
+ description?: string;
1076
+ }
1077
+ /** Image input for operations */
1078
+ type HypercertImage = {
1079
+ type: "uri";
1080
+ uri: string;
1081
+ } | {
1082
+ type: "blob";
1083
+ blob: Blob;
1084
+ };
1085
+ /** Hypercert with AT Protocol metadata */
1086
+ interface HypercertWithMetadata {
1087
+ uri: string;
1088
+ cid: string;
1089
+ record: HypercertClaim;
1090
+ }
1091
+
1092
+ /**
1093
+ * Repository interfaces - Operation contracts for repository functionality.
1094
+ *
1095
+ * This module defines the interfaces for all repository operations,
1096
+ * providing clear contracts for record management, blob handling,
1097
+ * profile management, and domain-specific operations.
1098
+ *
1099
+ * @packageDocumentation
1100
+ */
1101
+
1102
+ /**
1103
+ * Parameters for creating a new hypercert.
1104
+ *
1105
+ * This interface defines all the data needed to create a hypercert
1106
+ * along with optional related records (location, contributions, evidence).
1107
+ *
1108
+ * @example Minimal hypercert
1109
+ * ```typescript
1110
+ * const params: CreateHypercertParams = {
1111
+ * title: "Community Garden Project",
1112
+ * description: "Established a 1-acre community garden serving 50 families",
1113
+ * workScope: "Food Security",
1114
+ * workTimeframeFrom: "2024-01-01",
1115
+ * workTimeframeTo: "2024-06-30",
1116
+ * rights: {
1117
+ * name: "Attribution",
1118
+ * type: "license",
1119
+ * description: "CC-BY-4.0",
1120
+ * },
1121
+ * };
1122
+ * ```
1123
+ *
1124
+ * @example Full hypercert with all options
1125
+ * ```typescript
1126
+ * const params: CreateHypercertParams = {
1127
+ * title: "Reforestation Initiative",
1128
+ * description: "Planted 10,000 trees in deforested areas",
1129
+ * shortDescription: "10K trees planted",
1130
+ * workScope: "Environmental Restoration",
1131
+ * workTimeframeFrom: "2024-01-01",
1132
+ * workTimeframeTo: "2024-12-31",
1133
+ * rights: {
1134
+ * name: "Open Impact",
1135
+ * type: "impact-rights",
1136
+ * description: "Transferable impact rights",
1137
+ * },
1138
+ * image: coverImageBlob,
1139
+ * location: {
1140
+ * value: "Amazon Rainforest, Brazil",
1141
+ * name: "Amazon Basin",
1142
+ * description: "Southern Amazon region",
1143
+ * },
1144
+ * contributions: [
1145
+ * {
1146
+ * contributors: ["did:plc:lead-org"],
1147
+ * role: "coordinator",
1148
+ * description: "Project coordination and funding",
1149
+ * },
1150
+ * {
1151
+ * contributors: ["did:plc:local-partner"],
1152
+ * role: "implementer",
1153
+ * description: "On-ground planting and monitoring",
1154
+ * },
1155
+ * ],
1156
+ * evidence: [
1157
+ * {
1158
+ * uri: "https://example.com/satellite-data",
1159
+ * description: "Satellite imagery showing reforestation progress",
1160
+ * },
1161
+ * ],
1162
+ * onProgress: (step) => console.log(`${step.name}: ${step.status}`),
1163
+ * };
1164
+ * ```
1165
+ */
1166
+ interface CreateHypercertParams {
1167
+ /**
1168
+ * Title of the hypercert.
1169
+ *
1170
+ * Should be concise but descriptive of the impact claim.
1171
+ */
1172
+ title: string;
1173
+ /**
1174
+ * Detailed description of the impact.
1175
+ *
1176
+ * Can include methodology, outcomes, and other relevant details.
1177
+ * Supports markdown formatting.
1178
+ */
1179
+ description: string;
1180
+ /**
1181
+ * Scope of work or impact area.
1182
+ *
1183
+ * @example "Climate Action", "Education", "Healthcare"
1184
+ */
1185
+ workScope: string;
1186
+ /**
1187
+ * Start date of the work period.
1188
+ *
1189
+ * ISO 8601 date format (YYYY-MM-DD).
1190
+ */
1191
+ workTimeframeFrom: string;
1192
+ /**
1193
+ * End date of the work period.
1194
+ *
1195
+ * ISO 8601 date format (YYYY-MM-DD).
1196
+ */
1197
+ workTimeframeTo: string;
1198
+ /**
1199
+ * Rights associated with the hypercert.
1200
+ */
1201
+ rights: {
1202
+ /**
1203
+ * Name of the rights.
1204
+ *
1205
+ * @example "Attribution", "Impact Rights", "Public Domain"
1206
+ */
1207
+ name: string;
1208
+ /**
1209
+ * Type of rights.
1210
+ *
1211
+ * @example "license", "impact-rights", "ownership"
1212
+ */
1213
+ type: string;
1214
+ /**
1215
+ * Description of the rights terms.
1216
+ *
1217
+ * @example "CC-BY-4.0", "Transferable impact rights"
1218
+ */
1219
+ description: string;
1220
+ };
1221
+ /**
1222
+ * Optional short description for display in lists/cards.
1223
+ *
1224
+ * Should be under 200 characters.
1225
+ */
1226
+ shortDescription?: string;
1227
+ /**
1228
+ * Optional cover image for the hypercert.
1229
+ *
1230
+ * Recommended size: 1200x630 pixels (social media preview ratio).
1231
+ */
1232
+ image?: Blob;
1233
+ /**
1234
+ * Optional geographic location of the impact.
1235
+ */
1236
+ location?: {
1237
+ /**
1238
+ * Location value/address.
1239
+ *
1240
+ * @example "San Francisco, CA, USA"
1241
+ */
1242
+ value: string;
1243
+ /**
1244
+ * Human-readable location name.
1245
+ *
1246
+ * @example "SF Bay Area"
1247
+ */
1248
+ name?: string;
1249
+ /**
1250
+ * Description of the location scope.
1251
+ */
1252
+ description?: string;
1253
+ /**
1254
+ * Spatial Reference System identifier.
1255
+ *
1256
+ * @example "EPSG:4326" for WGS84
1257
+ */
1258
+ srs?: string;
1259
+ /**
1260
+ * GeoJSON file as a Blob for precise boundaries.
1261
+ */
1262
+ geojson?: Blob;
1263
+ };
1264
+ /**
1265
+ * Optional list of contributions to the impact.
1266
+ *
1267
+ * Use this to credit multiple contributors with different roles.
1268
+ */
1269
+ contributions?: Array<{
1270
+ /**
1271
+ * DIDs of the contributors.
1272
+ */
1273
+ contributors: string[];
1274
+ /**
1275
+ * Role in the contribution.
1276
+ *
1277
+ * @example "coordinator", "implementer", "funder", "volunteer"
1278
+ */
1279
+ role: string;
1280
+ /**
1281
+ * Description of the contribution.
1282
+ */
1283
+ description?: string;
1284
+ }>;
1285
+ /**
1286
+ * Optional evidence supporting the impact claim.
1287
+ */
1288
+ evidence?: HypercertEvidence[];
1289
+ /**
1290
+ * Optional callback for progress updates during creation.
1291
+ *
1292
+ * Called for each step of the creation process (image upload,
1293
+ * record creation, attachment linking, etc.).
1294
+ */
1295
+ onProgress?: (step: ProgressStep) => void;
1296
+ }
1297
+ /**
1298
+ * Result of creating a hypercert.
1299
+ *
1300
+ * Contains URIs and CIDs for all created records.
1301
+ */
1302
+ interface CreateHypercertResult {
1303
+ /**
1304
+ * AT-URI of the main hypercert record.
1305
+ */
1306
+ hypercertUri: string;
1307
+ /**
1308
+ * AT-URI of the associated rights record.
1309
+ */
1310
+ rightsUri: string;
1311
+ /**
1312
+ * CID of the hypercert record.
1313
+ */
1314
+ hypercertCid: string;
1315
+ /**
1316
+ * CID of the rights record.
1317
+ */
1318
+ rightsCid: string;
1319
+ /**
1320
+ * AT-URI of the location record, if location was provided.
1321
+ */
1322
+ locationUri?: string;
1323
+ /**
1324
+ * AT-URIs of contribution records, if contributions were provided.
1325
+ */
1326
+ contributionUris?: string[];
1327
+ }
1328
+ /**
1329
+ * Low-level record operations for AT Protocol CRUD.
1330
+ *
1331
+ * Use this interface for direct access to AT Protocol records when
1332
+ * the high-level APIs don't meet your needs.
1333
+ *
1334
+ * @example
1335
+ * ```typescript
1336
+ * // Create a record
1337
+ * const { uri, cid } = await repo.records.create({
1338
+ * collection: "org.example.mytype",
1339
+ * record: { foo: "bar", createdAt: new Date().toISOString() },
1340
+ * });
1341
+ *
1342
+ * // Get a record
1343
+ * const { value } = await repo.records.get({
1344
+ * collection: "org.example.mytype",
1345
+ * rkey: "abc123",
1346
+ * });
1347
+ *
1348
+ * // Update a record
1349
+ * await repo.records.update({
1350
+ * collection: "org.example.mytype",
1351
+ * rkey: "abc123",
1352
+ * record: { ...value, foo: "updated" },
1353
+ * });
1354
+ *
1355
+ * // List records
1356
+ * const { records, cursor } = await repo.records.list({
1357
+ * collection: "org.example.mytype",
1358
+ * limit: 50,
1359
+ * });
1360
+ *
1361
+ * // Delete a record
1362
+ * await repo.records.delete({
1363
+ * collection: "org.example.mytype",
1364
+ * rkey: "abc123",
1365
+ * });
1366
+ * ```
1367
+ */
1368
+ interface RecordOperations {
1369
+ /**
1370
+ * Creates a new record in a collection.
1371
+ *
1372
+ * @param params - Creation parameters
1373
+ * @param params.collection - NSID of the collection (e.g., "org.hypercerts.hypercert")
1374
+ * @param params.record - Record data (must conform to collection's lexicon)
1375
+ * @param params.rkey - Optional record key. Auto-generated if not provided.
1376
+ * @returns Promise resolving to the created record's URI and CID
1377
+ */
1378
+ create(params: {
1379
+ collection: string;
1380
+ record: unknown;
1381
+ rkey?: string;
1382
+ }): Promise<CreateResult>;
1383
+ /**
1384
+ * Updates an existing record.
1385
+ *
1386
+ * @param params - Update parameters
1387
+ * @param params.collection - NSID of the collection
1388
+ * @param params.rkey - Record key to update
1389
+ * @param params.record - New record data (replaces entire record)
1390
+ * @returns Promise resolving to the updated record's URI and CID
1391
+ */
1392
+ update(params: {
1393
+ collection: string;
1394
+ rkey: string;
1395
+ record: unknown;
1396
+ }): Promise<UpdateResult>;
1397
+ /**
1398
+ * Gets a single record by collection and key.
1399
+ *
1400
+ * @param params - Get parameters
1401
+ * @param params.collection - NSID of the collection
1402
+ * @param params.rkey - Record key
1403
+ * @returns Promise resolving to the record's URI, CID, and value
1404
+ */
1405
+ get(params: {
1406
+ collection: string;
1407
+ rkey: string;
1408
+ }): Promise<{
1409
+ uri: string;
1410
+ cid: string;
1411
+ value: unknown;
1412
+ }>;
1413
+ /**
1414
+ * Lists records in a collection with pagination.
1415
+ *
1416
+ * @param params - List parameters
1417
+ * @param params.collection - NSID of the collection
1418
+ * @param params.limit - Maximum records to return (default varies by server)
1419
+ * @param params.cursor - Pagination cursor from previous response
1420
+ * @returns Promise resolving to paginated list of records
1421
+ */
1422
+ list(params: {
1423
+ collection: string;
1424
+ limit?: number;
1425
+ cursor?: string;
1426
+ }): Promise<PaginatedList<{
1427
+ uri: string;
1428
+ cid: string;
1429
+ value: unknown;
1430
+ }>>;
1431
+ /**
1432
+ * Deletes a record.
1433
+ *
1434
+ * @param params - Delete parameters
1435
+ * @param params.collection - NSID of the collection
1436
+ * @param params.rkey - Record key to delete
1437
+ */
1438
+ delete(params: {
1439
+ collection: string;
1440
+ rkey: string;
1441
+ }): Promise<void>;
1442
+ }
1443
+ /**
1444
+ * Blob operations for binary data handling.
1445
+ *
1446
+ * Blobs are used for images, files, and other binary content.
1447
+ * They are referenced from records using blob references.
1448
+ *
1449
+ * @example
1450
+ * ```typescript
1451
+ * // Upload an image
1452
+ * const imageBlob = new Blob([imageData], { type: "image/jpeg" });
1453
+ * const { ref, mimeType, size } = await repo.blobs.upload(imageBlob);
1454
+ *
1455
+ * // Use the ref in a record
1456
+ * await repo.records.create({
1457
+ * collection: "org.example.post",
1458
+ * record: {
1459
+ * text: "Hello!",
1460
+ * image: ref, // { $link: "bafyrei..." }
1461
+ * },
1462
+ * });
1463
+ *
1464
+ * // Retrieve a blob
1465
+ * const { data, mimeType } = await repo.blobs.get(ref.$link);
1466
+ * ```
1467
+ */
1468
+ interface BlobOperations {
1469
+ /**
1470
+ * Uploads a blob to the server.
1471
+ *
1472
+ * @param blob - The blob to upload
1473
+ * @returns Promise resolving to blob reference and metadata
1474
+ */
1475
+ upload(blob: Blob): Promise<{
1476
+ /**
1477
+ * Blob reference to use in records.
1478
+ *
1479
+ * Contains `$link` property with the CID.
1480
+ */
1481
+ ref: {
1482
+ $link: string;
1483
+ };
1484
+ /**
1485
+ * MIME type of the uploaded blob.
1486
+ */
1487
+ mimeType: string;
1488
+ /**
1489
+ * Size of the blob in bytes.
1490
+ */
1491
+ size: number;
1492
+ }>;
1493
+ /**
1494
+ * Retrieves a blob by its CID.
1495
+ *
1496
+ * @param cid - Content Identifier of the blob
1497
+ * @returns Promise resolving to blob data and MIME type
1498
+ */
1499
+ get(cid: string): Promise<{
1500
+ /**
1501
+ * Raw blob data as Uint8Array.
1502
+ */
1503
+ data: Uint8Array;
1504
+ /**
1505
+ * MIME type of the blob.
1506
+ */
1507
+ mimeType: string;
1508
+ }>;
1509
+ }
1510
+ /**
1511
+ * Profile operations for user profile management.
1512
+ *
1513
+ * @example
1514
+ * ```typescript
1515
+ * // Get profile
1516
+ * const profile = await repo.profile.get();
1517
+ * console.log(profile.displayName);
1518
+ *
1519
+ * // Update profile
1520
+ * await repo.profile.update({
1521
+ * displayName: "New Name",
1522
+ * description: "Updated bio",
1523
+ * });
1524
+ *
1525
+ * // Update avatar
1526
+ * await repo.profile.update({
1527
+ * avatar: new Blob([avatarData], { type: "image/png" }),
1528
+ * });
1529
+ *
1530
+ * // Clear a field by passing null
1531
+ * await repo.profile.update({
1532
+ * website: null, // Removes website
1533
+ * });
1534
+ * ```
1535
+ */
1536
+ interface ProfileOperations {
1537
+ /**
1538
+ * Gets the repository's profile.
1539
+ *
1540
+ * @returns Promise resolving to profile data
1541
+ */
1542
+ get(): Promise<{
1543
+ /**
1544
+ * User's handle (e.g., "alice.bsky.social").
1545
+ */
1546
+ handle: string;
1547
+ /**
1548
+ * Display name.
1549
+ */
1550
+ displayName?: string;
1551
+ /**
1552
+ * Profile description/bio.
1553
+ */
1554
+ description?: string;
1555
+ /**
1556
+ * Avatar image URL or blob reference.
1557
+ */
1558
+ avatar?: string;
1559
+ /**
1560
+ * Banner image URL or blob reference.
1561
+ */
1562
+ banner?: string;
1563
+ /**
1564
+ * Website URL.
1565
+ */
1566
+ website?: string;
1567
+ }>;
1568
+ /**
1569
+ * Updates the repository's profile.
1570
+ *
1571
+ * Pass `null` to clear a field. Omitted fields are unchanged.
1572
+ *
1573
+ * @param params - Fields to update
1574
+ * @returns Promise resolving to update result
1575
+ */
1576
+ update(params: {
1577
+ displayName?: string | null;
1578
+ description?: string | null;
1579
+ avatar?: Blob | null;
1580
+ banner?: Blob | null;
1581
+ website?: string | null;
1582
+ }): Promise<UpdateResult>;
1583
+ }
1584
+ /**
1585
+ * Events emitted by hypercert operations.
1586
+ *
1587
+ * Use these to track progress of complex operations or react
1588
+ * to record changes.
1589
+ */
1590
+ interface HypercertEvents {
1591
+ /**
1592
+ * Emitted when a hypercert record is created.
1593
+ */
1594
+ recordCreated: {
1595
+ uri: string;
1596
+ cid: string;
1597
+ };
1598
+ /**
1599
+ * Emitted when a hypercert record is updated.
1600
+ */
1601
+ recordUpdated: {
1602
+ uri: string;
1603
+ cid: string;
1604
+ };
1605
+ /**
1606
+ * Emitted when a rights record is created.
1607
+ */
1608
+ rightsCreated: {
1609
+ uri: string;
1610
+ cid: string;
1611
+ };
1612
+ /**
1613
+ * Emitted when a location is attached to a hypercert.
1614
+ */
1615
+ locationAttached: {
1616
+ uri: string;
1617
+ cid: string;
1618
+ hypercertUri: string;
1619
+ };
1620
+ /**
1621
+ * Emitted when a contribution record is created.
1622
+ */
1623
+ contributionCreated: {
1624
+ uri: string;
1625
+ cid: string;
1626
+ };
1627
+ /**
1628
+ * Emitted when evidence is added to a hypercert.
1629
+ */
1630
+ evidenceAdded: {
1631
+ uri: string;
1632
+ cid: string;
1633
+ };
1634
+ /**
1635
+ * Emitted when a collection is created.
1636
+ */
1637
+ collectionCreated: {
1638
+ uri: string;
1639
+ cid: string;
1640
+ };
1641
+ }
1642
+ /**
1643
+ * High-level hypercert operations.
1644
+ *
1645
+ * Provides a convenient API for creating and managing hypercerts
1646
+ * with automatic handling of related records (rights, locations,
1647
+ * contributions, etc.).
1648
+ *
1649
+ * Extends EventEmitter to provide progress events.
1650
+ *
1651
+ * @example Basic usage
1652
+ * ```typescript
1653
+ * // Create a hypercert
1654
+ * const result = await repo.hypercerts.create({
1655
+ * title: "Impact Project",
1656
+ * description: "Description...",
1657
+ * workScope: "Climate",
1658
+ * workTimeframeFrom: "2024-01-01",
1659
+ * workTimeframeTo: "2024-12-31",
1660
+ * rights: { name: "CC-BY", type: "license", description: "..." },
1661
+ * });
1662
+ *
1663
+ * // List hypercerts
1664
+ * const { records } = await repo.hypercerts.list({ limit: 20 });
1665
+ *
1666
+ * // Get a specific hypercert
1667
+ * const hypercert = await repo.hypercerts.get(result.hypercertUri);
1668
+ * ```
1669
+ *
1670
+ * @example With events
1671
+ * ```typescript
1672
+ * repo.hypercerts.on("recordCreated", ({ uri }) => {
1673
+ * console.log(`Created: ${uri}`);
1674
+ * });
1675
+ * ```
1676
+ */
1677
+ interface HypercertOperations extends EventEmitter<HypercertEvents> {
1678
+ /**
1679
+ * Creates a new hypercert with all related records.
1680
+ *
1681
+ * @param params - Creation parameters
1682
+ * @returns Promise resolving to URIs and CIDs of created records
1683
+ */
1684
+ create(params: CreateHypercertParams): Promise<CreateHypercertResult>;
1685
+ /**
1686
+ * Updates an existing hypercert.
1687
+ *
1688
+ * @param params - Update parameters
1689
+ * @param params.uri - AT-URI of the hypercert to update
1690
+ * @param params.updates - Fields to update
1691
+ * @param params.image - New image, or `null` to remove
1692
+ * @returns Promise resolving to update result
1693
+ */
1694
+ update(params: {
1695
+ uri: string;
1696
+ updates: Partial<Omit<HypercertClaim, "$type" | "createdAt" | "rights">>;
1697
+ image?: Blob | null;
1698
+ }): Promise<UpdateResult>;
1699
+ /**
1700
+ * Gets a hypercert by URI.
1701
+ *
1702
+ * @param uri - AT-URI of the hypercert
1703
+ * @returns Promise resolving to hypercert data
1704
+ */
1705
+ get(uri: string): Promise<{
1706
+ uri: string;
1707
+ cid: string;
1708
+ record: HypercertClaim;
1709
+ }>;
1710
+ /**
1711
+ * Lists hypercerts with pagination.
1712
+ *
1713
+ * @param params - Optional pagination parameters
1714
+ * @returns Promise resolving to paginated list
1715
+ */
1716
+ list(params?: ListParams): Promise<PaginatedList<{
1717
+ uri: string;
1718
+ cid: string;
1719
+ record: HypercertClaim;
1720
+ }>>;
1721
+ /**
1722
+ * Deletes a hypercert.
1723
+ *
1724
+ * Note: This does not automatically delete related records
1725
+ * (rights, locations, contributions).
1726
+ *
1727
+ * @param uri - AT-URI of the hypercert to delete
1728
+ */
1729
+ delete(uri: string): Promise<void>;
1730
+ /**
1731
+ * Attaches a location to an existing hypercert.
1732
+ *
1733
+ * @param uri - AT-URI of the hypercert
1734
+ * @param location - Location data
1735
+ * @returns Promise resolving to location record result
1736
+ */
1737
+ attachLocation(uri: string, location: {
1738
+ value: string;
1739
+ name?: string;
1740
+ description?: string;
1741
+ srs?: string;
1742
+ geojson?: Blob;
1743
+ }): Promise<CreateResult>;
1744
+ /**
1745
+ * Adds evidence to an existing hypercert.
1746
+ *
1747
+ * @param uri - AT-URI of the hypercert
1748
+ * @param evidence - Array of evidence items to add
1749
+ * @returns Promise resolving to update result
1750
+ */
1751
+ addEvidence(uri: string, evidence: HypercertEvidence[]): Promise<UpdateResult>;
1752
+ /**
1753
+ * Creates a contribution record.
1754
+ *
1755
+ * @param params - Contribution parameters
1756
+ * @returns Promise resolving to contribution record result
1757
+ */
1758
+ addContribution(params: {
1759
+ hypercertUri?: string;
1760
+ contributors: string[];
1761
+ role: string;
1762
+ description?: string;
1763
+ }): Promise<CreateResult>;
1764
+ /**
1765
+ * Creates a measurement record for a hypercert.
1766
+ *
1767
+ * @param params - Measurement parameters
1768
+ * @returns Promise resolving to measurement record result
1769
+ */
1770
+ addMeasurement(params: {
1771
+ hypercertUri: string;
1772
+ measurers: string[];
1773
+ metric: string;
1774
+ value: string;
1775
+ methodUri?: string;
1776
+ evidenceUris?: string[];
1777
+ }): Promise<CreateResult>;
1778
+ /**
1779
+ * Creates an evaluation record.
1780
+ *
1781
+ * @param params - Evaluation parameters
1782
+ * @returns Promise resolving to evaluation record result
1783
+ */
1784
+ addEvaluation(params: {
1785
+ subjectUri: string;
1786
+ evaluators: string[];
1787
+ summary: string;
1788
+ }): Promise<CreateResult>;
1789
+ /**
1790
+ * Creates a collection of hypercerts.
1791
+ *
1792
+ * @param params - Collection parameters
1793
+ * @returns Promise resolving to collection record result
1794
+ */
1795
+ createCollection(params: {
1796
+ title: string;
1797
+ claims: Array<{
1798
+ uri: string;
1799
+ cid: string;
1800
+ weight: string;
1801
+ }>;
1802
+ shortDescription?: string;
1803
+ coverPhoto?: Blob;
1804
+ }): Promise<CreateResult>;
1805
+ /**
1806
+ * Gets a collection by URI.
1807
+ *
1808
+ * @param uri - AT-URI of the collection
1809
+ * @returns Promise resolving to collection data
1810
+ */
1811
+ getCollection(uri: string): Promise<{
1812
+ uri: string;
1813
+ cid: string;
1814
+ record: HypercertCollection;
1815
+ }>;
1816
+ /**
1817
+ * Lists collections with pagination.
1818
+ *
1819
+ * @param params - Optional pagination parameters
1820
+ * @returns Promise resolving to paginated list
1821
+ */
1822
+ listCollections(params?: ListParams): Promise<PaginatedList<{
1823
+ uri: string;
1824
+ cid: string;
1825
+ record: HypercertCollection;
1826
+ }>>;
1827
+ }
1828
+ /**
1829
+ * Collaborator operations for SDS access control.
1830
+ *
1831
+ * **SDS Only**: These operations are only available on Shared Data Servers.
1832
+ *
1833
+ * @example
1834
+ * ```typescript
1835
+ * // Grant access
1836
+ * await repo.collaborators.grant({
1837
+ * userDid: "did:plc:new-user",
1838
+ * role: "editor",
1839
+ * });
1840
+ *
1841
+ * // List collaborators
1842
+ * const collaborators = await repo.collaborators.list();
1843
+ *
1844
+ * // Check access
1845
+ * const hasAccess = await repo.collaborators.hasAccess("did:plc:someone");
1846
+ * const role = await repo.collaborators.getRole("did:plc:someone");
1847
+ *
1848
+ * // Revoke access
1849
+ * await repo.collaborators.revoke({ userDid: "did:plc:former-user" });
1850
+ * ```
1851
+ */
1852
+ interface CollaboratorOperations {
1853
+ /**
1854
+ * Grants repository access to a user.
1855
+ *
1856
+ * @param params - Grant parameters
1857
+ * @param params.userDid - DID of the user to grant access to
1858
+ * @param params.role - Role to assign
1859
+ */
1860
+ grant(params: {
1861
+ userDid: string;
1862
+ role: RepositoryRole;
1863
+ }): Promise<void>;
1864
+ /**
1865
+ * Revokes repository access from a user.
1866
+ *
1867
+ * @param params - Revoke parameters
1868
+ * @param params.userDid - DID of the user to revoke access from
1869
+ */
1870
+ revoke(params: {
1871
+ userDid: string;
1872
+ }): Promise<void>;
1873
+ /**
1874
+ * Lists all collaborators on the repository.
1875
+ *
1876
+ * @returns Promise resolving to array of access grants
1877
+ */
1878
+ list(): Promise<RepositoryAccessGrant[]>;
1879
+ /**
1880
+ * Checks if a user has any access to the repository.
1881
+ *
1882
+ * @param userDid - DID to check
1883
+ * @returns Promise resolving to boolean
1884
+ */
1885
+ hasAccess(userDid: string): Promise<boolean>;
1886
+ /**
1887
+ * Gets the role assigned to a user.
1888
+ *
1889
+ * @param userDid - DID to check
1890
+ * @returns Promise resolving to role, or `null` if no access
1891
+ */
1892
+ getRole(userDid: string): Promise<RepositoryRole | null>;
1893
+ }
1894
+ /**
1895
+ * Organization operations for SDS organization management.
1896
+ *
1897
+ * **SDS Only**: These operations are only available on Shared Data Servers.
1898
+ *
1899
+ * @example
1900
+ * ```typescript
1901
+ * // Create an organization
1902
+ * const org = await repo.organizations.create({
1903
+ * name: "My Team",
1904
+ * description: "A team for impact projects",
1905
+ * });
1906
+ *
1907
+ * // List organizations
1908
+ * const orgs = await repo.organizations.list();
1909
+ *
1910
+ * // Get organization details
1911
+ * const orgInfo = await repo.organizations.get(org.did);
1912
+ * ```
1913
+ */
1914
+ interface OrganizationOperations {
1915
+ /**
1916
+ * Creates a new organization.
1917
+ *
1918
+ * @param params - Organization parameters
1919
+ * @param params.name - Organization name
1920
+ * @param params.description - Optional description
1921
+ * @param params.handle - Optional custom handle
1922
+ * @returns Promise resolving to organization info
1923
+ */
1924
+ create(params: {
1925
+ name: string;
1926
+ description?: string;
1927
+ handle?: string;
1928
+ }): Promise<OrganizationInfo>;
1929
+ /**
1930
+ * Gets an organization by DID.
1931
+ *
1932
+ * @param did - Organization DID
1933
+ * @returns Promise resolving to organization info, or `null` if not found
1934
+ */
1935
+ get(did: string): Promise<OrganizationInfo | null>;
1936
+ /**
1937
+ * Lists organizations the current user has access to.
1938
+ *
1939
+ * @returns Promise resolving to array of organization info
1940
+ */
1941
+ list(): Promise<OrganizationInfo[]>;
1942
+ }
1943
+
1944
+ /**
1945
+ * Repository - Unified fluent API for ATProto repository operations.
1946
+ *
1947
+ * This module provides the main interface for interacting with AT Protocol
1948
+ * data servers (PDS and SDS) through a consistent, fluent API.
1949
+ *
1950
+ * @packageDocumentation
1951
+ */
1952
+
1953
+ /**
1954
+ * Repository provides a fluent API for AT Protocol data operations.
1955
+ *
1956
+ * This class is the primary interface for working with data in the AT Protocol
1957
+ * ecosystem. It provides organized access to:
1958
+ *
1959
+ * - **Records**: Low-level CRUD operations for any AT Protocol record type
1960
+ * - **Blobs**: Binary data upload and retrieval (images, files)
1961
+ * - **Profile**: User profile management
1962
+ * - **Hypercerts**: High-level hypercert creation and management
1963
+ * - **Collaborators**: Access control for shared repositories (SDS only)
1964
+ * - **Organizations**: Organization management (SDS only)
1965
+ *
1966
+ * @remarks
1967
+ * The Repository uses lazy initialization for operation handlers - they are
1968
+ * created only when first accessed. This improves performance when you only
1969
+ * need a subset of operations.
1970
+ *
1971
+ * **PDS vs SDS:**
1972
+ * - **PDS (Personal Data Server)**: User's own data storage. All operations
1973
+ * except collaborators and organizations are available.
1974
+ * - **SDS (Shared Data Server)**: Collaborative data storage with access
1975
+ * control. All operations including collaborators and organizations.
1976
+ *
1977
+ * @example Basic usage
1978
+ * ```typescript
1979
+ * // Get a repository from the SDK
1980
+ * const repo = sdk.repository(session);
1981
+ *
1982
+ * // Access user profile
1983
+ * const profile = await repo.profile.get();
1984
+ *
1985
+ * // Create a hypercert
1986
+ * const result = await repo.hypercerts.create({
1987
+ * title: "My Impact",
1988
+ * description: "Description of the impact",
1989
+ * workScope: "Climate Action",
1990
+ * workTimeframeFrom: "2024-01-01",
1991
+ * workTimeframeTo: "2024-12-31",
1992
+ * rights: {
1993
+ * name: "Attribution",
1994
+ * type: "license",
1995
+ * description: "CC-BY-4.0",
1996
+ * },
1997
+ * });
1998
+ * ```
1999
+ *
2000
+ * @example Working with a different user's repository
2001
+ * ```typescript
2002
+ * // Get the current user's repo
2003
+ * const myRepo = sdk.repository(session);
2004
+ *
2005
+ * // Get another user's repo (read-only for most operations)
2006
+ * const otherRepo = myRepo.repo("did:plc:other-user-did");
2007
+ * const theirProfile = await otherRepo.profile.get();
2008
+ * ```
2009
+ *
2010
+ * @example SDS operations
2011
+ * ```typescript
2012
+ * // Get SDS repository for collaborator features
2013
+ * const sdsRepo = sdk.repository(session, { server: "sds" });
2014
+ *
2015
+ * // Manage collaborators
2016
+ * await sdsRepo.collaborators.grant({
2017
+ * userDid: "did:plc:collaborator",
2018
+ * role: "editor",
2019
+ * });
2020
+ *
2021
+ * // List organizations
2022
+ * const orgs = await sdsRepo.organizations.list();
2023
+ * ```
2024
+ *
2025
+ * @see {@link ATProtoSDK.repository} for creating Repository instances
2026
+ */
2027
+ declare class Repository {
2028
+ private session;
2029
+ private serverUrl;
2030
+ private repoDid;
2031
+ private lexiconRegistry;
2032
+ private logger?;
2033
+ private agent;
2034
+ private _isSDS;
2035
+ private _records?;
2036
+ private _blobs?;
2037
+ private _profile?;
2038
+ private _hypercerts?;
2039
+ private _collaborators?;
2040
+ private _organizations?;
2041
+ /**
2042
+ * Creates a new Repository instance.
2043
+ *
2044
+ * @param session - Authenticated OAuth session
2045
+ * @param serverUrl - Base URL of the AT Protocol server
2046
+ * @param repoDid - DID of the repository to operate on
2047
+ * @param lexiconRegistry - Registry for lexicon validation
2048
+ * @param isSDS - Whether this is a Shared Data Server
2049
+ * @param logger - Optional logger for debugging
2050
+ *
2051
+ * @remarks
2052
+ * This constructor is typically not called directly. Use
2053
+ * {@link ATProtoSDK.repository} to create Repository instances.
2054
+ *
2055
+ * @internal
2056
+ */
2057
+ constructor(session: Session, serverUrl: string, repoDid: string, lexiconRegistry: LexiconRegistry, isSDS: boolean, logger?: LoggerInterface);
2058
+ /**
2059
+ * The DID (Decentralized Identifier) of this repository.
2060
+ *
2061
+ * This is the user or organization that owns the repository data.
2062
+ *
2063
+ * @example
2064
+ * ```typescript
2065
+ * console.log(`Working with repo: ${repo.did}`);
2066
+ * // Output: Working with repo: did:plc:abc123xyz...
2067
+ * ```
2068
+ */
2069
+ get did(): string;
2070
+ /**
2071
+ * Whether this repository is on a Shared Data Server (SDS).
2072
+ *
2073
+ * SDS servers support additional features like collaborators and
2074
+ * organizations. Attempting to use these features on a PDS will
2075
+ * throw {@link SDSRequiredError}.
2076
+ *
2077
+ * @example
2078
+ * ```typescript
2079
+ * if (repo.isSDS) {
2080
+ * const collaborators = await repo.collaborators.list();
2081
+ * }
2082
+ * ```
2083
+ */
2084
+ get isSDS(): boolean;
2085
+ /**
2086
+ * Gets the server URL this repository connects to.
2087
+ *
2088
+ * @returns The base URL of the AT Protocol server
2089
+ *
2090
+ * @example
2091
+ * ```typescript
2092
+ * console.log(repo.getServerUrl());
2093
+ * // Output: https://bsky.social or https://sds.hypercerts.org
2094
+ * ```
2095
+ */
2096
+ getServerUrl(): string;
2097
+ /**
2098
+ * Creates a Repository instance for a different DID on the same server.
2099
+ *
2100
+ * This allows you to read data from other users' repositories while
2101
+ * maintaining your authenticated session.
2102
+ *
2103
+ * @param did - The DID of the repository to access
2104
+ * @returns A new Repository instance for the specified DID
2105
+ *
2106
+ * @remarks
2107
+ * Write operations on another user's repository will typically fail
2108
+ * unless you have been granted collaborator access (SDS only).
2109
+ *
2110
+ * @example
2111
+ * ```typescript
2112
+ * // Read another user's profile
2113
+ * const otherRepo = repo.repo("did:plc:other-user");
2114
+ * const profile = await otherRepo.profile.get();
2115
+ *
2116
+ * // List their public hypercerts
2117
+ * const hypercerts = await otherRepo.hypercerts.list();
2118
+ * ```
2119
+ */
2120
+ repo(did: string): Repository;
2121
+ /**
2122
+ * Low-level record operations for CRUD on any AT Protocol record type.
2123
+ *
2124
+ * Use this for direct access to AT Protocol records when the high-level
2125
+ * APIs don't meet your needs.
2126
+ *
2127
+ * @returns {@link RecordOperations} interface for record CRUD
2128
+ *
2129
+ * @example
2130
+ * ```typescript
2131
+ * // Create a custom record
2132
+ * const result = await repo.records.create({
2133
+ * collection: "org.example.myRecord",
2134
+ * record: { foo: "bar" },
2135
+ * });
2136
+ *
2137
+ * // List records in a collection
2138
+ * const list = await repo.records.list({
2139
+ * collection: "org.example.myRecord",
2140
+ * limit: 50,
2141
+ * });
2142
+ *
2143
+ * // Get a specific record
2144
+ * const record = await repo.records.get({
2145
+ * collection: "org.example.myRecord",
2146
+ * rkey: "abc123",
2147
+ * });
2148
+ * ```
2149
+ */
2150
+ get records(): RecordOperations;
2151
+ /**
2152
+ * Blob operations for uploading and retrieving binary data.
2153
+ *
2154
+ * Blobs are used for images, files, and other binary content associated
2155
+ * with records.
2156
+ *
2157
+ * @returns {@link BlobOperations} interface for blob management
2158
+ *
2159
+ * @example
2160
+ * ```typescript
2161
+ * // Upload an image
2162
+ * const imageBlob = new Blob([imageData], { type: "image/png" });
2163
+ * const uploadResult = await repo.blobs.upload(imageBlob);
2164
+ *
2165
+ * // The ref can be used in records
2166
+ * console.log(uploadResult.ref.$link); // CID of the blob
2167
+ *
2168
+ * // Retrieve a blob by CID
2169
+ * const { data, mimeType } = await repo.blobs.get(cid);
2170
+ * ```
2171
+ */
2172
+ get blobs(): BlobOperations;
2173
+ /**
2174
+ * Profile operations for managing user profiles.
2175
+ *
2176
+ * @returns {@link ProfileOperations} interface for profile management
2177
+ *
2178
+ * @example
2179
+ * ```typescript
2180
+ * // Get current profile
2181
+ * const profile = await repo.profile.get();
2182
+ * console.log(profile.displayName);
2183
+ *
2184
+ * // Update profile
2185
+ * await repo.profile.update({
2186
+ * displayName: "New Name",
2187
+ * description: "Updated bio",
2188
+ * avatar: avatarBlob, // Optional: update avatar image
2189
+ * });
2190
+ * ```
2191
+ */
2192
+ get profile(): ProfileOperations;
2193
+ /**
2194
+ * High-level hypercert operations.
2195
+ *
2196
+ * Provides a convenient API for creating and managing hypercerts,
2197
+ * including related records like locations, contributions, and evidence.
2198
+ *
2199
+ * @returns {@link HypercertOperations} interface with EventEmitter capabilities
2200
+ *
2201
+ * @example Creating a hypercert
2202
+ * ```typescript
2203
+ * const result = await repo.hypercerts.create({
2204
+ * title: "Climate Action Project",
2205
+ * description: "Reduced carbon emissions by 1000 tons",
2206
+ * workScope: "Climate Action",
2207
+ * workTimeframeFrom: "2024-01-01",
2208
+ * workTimeframeTo: "2024-06-30",
2209
+ * rights: {
2210
+ * name: "Public Domain",
2211
+ * type: "license",
2212
+ * description: "CC0 - No Rights Reserved",
2213
+ * },
2214
+ * image: imageBlob, // Optional cover image
2215
+ * location: {
2216
+ * value: "San Francisco, CA",
2217
+ * name: "SF Bay Area",
2218
+ * },
2219
+ * });
2220
+ * console.log(`Created: ${result.hypercertUri}`);
2221
+ * ```
2222
+ *
2223
+ * @example Listening to events
2224
+ * ```typescript
2225
+ * repo.hypercerts.on("recordCreated", ({ uri, cid }) => {
2226
+ * console.log(`Record created: ${uri}`);
2227
+ * });
2228
+ * ```
2229
+ */
2230
+ get hypercerts(): HypercertOperations;
2231
+ /**
2232
+ * Collaborator operations for managing repository access.
2233
+ *
2234
+ * **SDS Only**: This property throws {@link SDSRequiredError} if accessed
2235
+ * on a PDS repository.
2236
+ *
2237
+ * @returns {@link CollaboratorOperations} interface for access control
2238
+ * @throws {@link SDSRequiredError} if not connected to an SDS server
2239
+ *
2240
+ * @example
2241
+ * ```typescript
2242
+ * // Ensure we're on SDS
2243
+ * const sdsRepo = sdk.repository(session, { server: "sds" });
2244
+ *
2245
+ * // Grant editor access
2246
+ * await sdsRepo.collaborators.grant({
2247
+ * userDid: "did:plc:new-collaborator",
2248
+ * role: "editor",
2249
+ * });
2250
+ *
2251
+ * // List all collaborators
2252
+ * const collaborators = await sdsRepo.collaborators.list();
2253
+ *
2254
+ * // Check access
2255
+ * const hasAccess = await sdsRepo.collaborators.hasAccess("did:plc:someone");
2256
+ *
2257
+ * // Revoke access
2258
+ * await sdsRepo.collaborators.revoke({ userDid: "did:plc:former-collaborator" });
2259
+ * ```
2260
+ */
2261
+ get collaborators(): CollaboratorOperations;
2262
+ /**
2263
+ * Organization operations for creating and managing organizations.
2264
+ *
2265
+ * **SDS Only**: This property throws {@link SDSRequiredError} if accessed
2266
+ * on a PDS repository.
2267
+ *
2268
+ * @returns {@link OrganizationOperations} interface for organization management
2269
+ * @throws {@link SDSRequiredError} if not connected to an SDS server
2270
+ *
2271
+ * @example
2272
+ * ```typescript
2273
+ * // Ensure we're on SDS
2274
+ * const sdsRepo = sdk.repository(session, { server: "sds" });
2275
+ *
2276
+ * // Create an organization
2277
+ * const org = await sdsRepo.organizations.create({
2278
+ * name: "My Organization",
2279
+ * description: "A team working on impact certificates",
2280
+ * handle: "my-org", // Optional custom handle
2281
+ * });
2282
+ *
2283
+ * // List organizations you have access to
2284
+ * const orgs = await sdsRepo.organizations.list();
2285
+ *
2286
+ * // Get specific organization
2287
+ * const orgInfo = await sdsRepo.organizations.get(org.did);
2288
+ * ```
2289
+ */
2290
+ get organizations(): OrganizationOperations;
2291
+ }
2292
+
2293
+ /**
2294
+ * Zod schema for OAuth configuration validation.
2295
+ *
2296
+ * @remarks
2297
+ * All URLs must be valid and use HTTPS in production. The `jwkPrivate` field
2298
+ * should contain the private key in JWK (JSON Web Key) format as a string.
2299
+ */
2300
+ declare const OAuthConfigSchema: z.ZodObject<{
2301
+ /**
2302
+ * URL to the OAuth client metadata JSON document.
2303
+ * This document describes your application to the authorization server.
2304
+ *
2305
+ * @see https://atproto.com/specs/oauth#client-metadata
2306
+ */
2307
+ clientId: z.ZodString;
2308
+ /**
2309
+ * URL where users are redirected after authentication.
2310
+ * Must match one of the redirect URIs in your client metadata.
2311
+ */
2312
+ redirectUri: z.ZodString;
2313
+ /**
2314
+ * OAuth scopes to request, space-separated.
2315
+ * Common scopes: "atproto", "transition:generic"
2316
+ */
2317
+ scope: z.ZodString;
2318
+ /**
2319
+ * URL to your public JWKS (JSON Web Key Set) endpoint.
2320
+ * Used by the authorization server to verify your client's signatures.
2321
+ */
2322
+ jwksUri: z.ZodString;
2323
+ /**
2324
+ * Private JWK (JSON Web Key) as a JSON string.
2325
+ * Used for signing DPoP proofs and client assertions.
2326
+ *
2327
+ * @remarks
2328
+ * This should be kept secret and never exposed to clients.
2329
+ * Typically loaded from environment variables or a secrets manager.
2330
+ */
2331
+ jwkPrivate: z.ZodString;
2332
+ }, "strip", z.ZodTypeAny, {
2333
+ clientId: string;
2334
+ redirectUri: string;
2335
+ scope: string;
2336
+ jwksUri: string;
2337
+ jwkPrivate: string;
2338
+ }, {
2339
+ clientId: string;
2340
+ redirectUri: string;
2341
+ scope: string;
2342
+ jwksUri: string;
2343
+ jwkPrivate: string;
2344
+ }>;
2345
+ /**
2346
+ * Zod schema for server URL configuration.
2347
+ *
2348
+ * @remarks
2349
+ * At least one server (PDS or SDS) should be configured for the SDK to be useful.
2350
+ */
2351
+ declare const ServerConfigSchema: z.ZodObject<{
2352
+ /**
2353
+ * Personal Data Server URL - the user's own AT Protocol server.
2354
+ * This is the primary server for user data operations.
2355
+ *
2356
+ * @example "https://bsky.social"
2357
+ */
2358
+ pds: z.ZodOptional<z.ZodString>;
2359
+ /**
2360
+ * Shared Data Server URL - for collaborative data storage.
2361
+ * Required for collaborator and organization operations.
2362
+ *
2363
+ * @example "https://sds.hypercerts.org"
2364
+ */
2365
+ sds: z.ZodOptional<z.ZodString>;
2366
+ }, "strip", z.ZodTypeAny, {
2367
+ pds?: string | undefined;
2368
+ sds?: string | undefined;
2369
+ }, {
2370
+ pds?: string | undefined;
2371
+ sds?: string | undefined;
2372
+ }>;
2373
+ /**
2374
+ * Zod schema for timeout configuration.
2375
+ *
2376
+ * @remarks
2377
+ * All timeout values are in milliseconds.
2378
+ */
2379
+ declare const TimeoutConfigSchema: z.ZodObject<{
2380
+ /**
2381
+ * Timeout for fetching PDS metadata during identity resolution.
2382
+ * @default 5000 (5 seconds, set by OAuthClient)
2383
+ */
2384
+ pdsMetadata: z.ZodOptional<z.ZodNumber>;
2385
+ /**
2386
+ * Timeout for general API requests to PDS/SDS.
2387
+ * @default 30000 (30 seconds)
2388
+ */
2389
+ apiRequests: z.ZodOptional<z.ZodNumber>;
2390
+ }, "strip", z.ZodTypeAny, {
2391
+ pdsMetadata?: number | undefined;
2392
+ apiRequests?: number | undefined;
2393
+ }, {
2394
+ pdsMetadata?: number | undefined;
2395
+ apiRequests?: number | undefined;
2396
+ }>;
2397
+ /**
2398
+ * Zod schema for SDK configuration validation.
2399
+ *
2400
+ * @remarks
2401
+ * This schema validates only the primitive/serializable parts of the configuration.
2402
+ * Storage interfaces ({@link SessionStore}, {@link StateStore}) cannot be validated
2403
+ * with Zod as they are runtime objects.
2404
+ */
2405
+ declare const ATProtoSDKConfigSchema: z.ZodObject<{
2406
+ oauth: z.ZodObject<{
2407
+ /**
2408
+ * URL to the OAuth client metadata JSON document.
2409
+ * This document describes your application to the authorization server.
2410
+ *
2411
+ * @see https://atproto.com/specs/oauth#client-metadata
2412
+ */
2413
+ clientId: z.ZodString;
2414
+ /**
2415
+ * URL where users are redirected after authentication.
2416
+ * Must match one of the redirect URIs in your client metadata.
2417
+ */
2418
+ redirectUri: z.ZodString;
2419
+ /**
2420
+ * OAuth scopes to request, space-separated.
2421
+ * Common scopes: "atproto", "transition:generic"
2422
+ */
2423
+ scope: z.ZodString;
2424
+ /**
2425
+ * URL to your public JWKS (JSON Web Key Set) endpoint.
2426
+ * Used by the authorization server to verify your client's signatures.
2427
+ */
2428
+ jwksUri: z.ZodString;
2429
+ /**
2430
+ * Private JWK (JSON Web Key) as a JSON string.
2431
+ * Used for signing DPoP proofs and client assertions.
2432
+ *
2433
+ * @remarks
2434
+ * This should be kept secret and never exposed to clients.
2435
+ * Typically loaded from environment variables or a secrets manager.
2436
+ */
2437
+ jwkPrivate: z.ZodString;
2438
+ }, "strip", z.ZodTypeAny, {
2439
+ clientId: string;
2440
+ redirectUri: string;
2441
+ scope: string;
2442
+ jwksUri: string;
2443
+ jwkPrivate: string;
2444
+ }, {
2445
+ clientId: string;
2446
+ redirectUri: string;
2447
+ scope: string;
2448
+ jwksUri: string;
2449
+ jwkPrivate: string;
2450
+ }>;
2451
+ servers: z.ZodOptional<z.ZodObject<{
2452
+ /**
2453
+ * Personal Data Server URL - the user's own AT Protocol server.
2454
+ * This is the primary server for user data operations.
2455
+ *
2456
+ * @example "https://bsky.social"
2457
+ */
2458
+ pds: z.ZodOptional<z.ZodString>;
2459
+ /**
2460
+ * Shared Data Server URL - for collaborative data storage.
2461
+ * Required for collaborator and organization operations.
2462
+ *
2463
+ * @example "https://sds.hypercerts.org"
2464
+ */
2465
+ sds: z.ZodOptional<z.ZodString>;
2466
+ }, "strip", z.ZodTypeAny, {
2467
+ pds?: string | undefined;
2468
+ sds?: string | undefined;
2469
+ }, {
2470
+ pds?: string | undefined;
2471
+ sds?: string | undefined;
2472
+ }>>;
2473
+ timeouts: z.ZodOptional<z.ZodObject<{
2474
+ /**
2475
+ * Timeout for fetching PDS metadata during identity resolution.
2476
+ * @default 5000 (5 seconds, set by OAuthClient)
2477
+ */
2478
+ pdsMetadata: z.ZodOptional<z.ZodNumber>;
2479
+ /**
2480
+ * Timeout for general API requests to PDS/SDS.
2481
+ * @default 30000 (30 seconds)
2482
+ */
2483
+ apiRequests: z.ZodOptional<z.ZodNumber>;
2484
+ }, "strip", z.ZodTypeAny, {
2485
+ pdsMetadata?: number | undefined;
2486
+ apiRequests?: number | undefined;
2487
+ }, {
2488
+ pdsMetadata?: number | undefined;
2489
+ apiRequests?: number | undefined;
2490
+ }>>;
2491
+ }, "strip", z.ZodTypeAny, {
2492
+ oauth: {
2493
+ clientId: string;
2494
+ redirectUri: string;
2495
+ scope: string;
2496
+ jwksUri: string;
2497
+ jwkPrivate: string;
2498
+ };
2499
+ servers?: {
2500
+ pds?: string | undefined;
2501
+ sds?: string | undefined;
2502
+ } | undefined;
2503
+ timeouts?: {
2504
+ pdsMetadata?: number | undefined;
2505
+ apiRequests?: number | undefined;
2506
+ } | undefined;
2507
+ }, {
2508
+ oauth: {
2509
+ clientId: string;
2510
+ redirectUri: string;
2511
+ scope: string;
2512
+ jwksUri: string;
2513
+ jwkPrivate: string;
2514
+ };
2515
+ servers?: {
2516
+ pds?: string | undefined;
2517
+ sds?: string | undefined;
2518
+ } | undefined;
2519
+ timeouts?: {
2520
+ pdsMetadata?: number | undefined;
2521
+ apiRequests?: number | undefined;
2522
+ } | undefined;
2523
+ }>;
2524
+ /**
2525
+ * Configuration options for the ATProto SDK.
2526
+ *
2527
+ * This interface defines all configuration needed to initialize the SDK,
2528
+ * including OAuth credentials, server endpoints, and optional customizations.
2529
+ *
2530
+ * @example Minimal configuration
2531
+ * ```typescript
2532
+ * const config: ATProtoSDKConfig = {
2533
+ * oauth: {
2534
+ * clientId: "https://my-app.com/client-metadata.json",
2535
+ * redirectUri: "https://my-app.com/callback",
2536
+ * scope: "atproto transition:generic",
2537
+ * jwksUri: "https://my-app.com/.well-known/jwks.json",
2538
+ * jwkPrivate: process.env.JWK_PRIVATE_KEY!,
2539
+ * },
2540
+ * servers: {
2541
+ * pds: "https://bsky.social",
2542
+ * },
2543
+ * };
2544
+ * ```
2545
+ *
2546
+ * @example Full configuration with custom storage
2547
+ * ```typescript
2548
+ * const config: ATProtoSDKConfig = {
2549
+ * oauth: { ... },
2550
+ * servers: {
2551
+ * pds: "https://bsky.social",
2552
+ * sds: "https://sds.hypercerts.org",
2553
+ * },
2554
+ * storage: {
2555
+ * sessionStore: new RedisSessionStore(redisClient),
2556
+ * stateStore: new RedisStateStore(redisClient),
2557
+ * },
2558
+ * timeouts: {
2559
+ * pdsMetadata: 5000,
2560
+ * apiRequests: 30000,
2561
+ * },
2562
+ * logger: console,
2563
+ * };
2564
+ * ```
2565
+ */
2566
+ interface ATProtoSDKConfig {
2567
+ /**
2568
+ * OAuth 2.0 configuration for authentication.
2569
+ *
2570
+ * Required fields for the OAuth flow with DPoP (Demonstrating Proof of Possession).
2571
+ * Your application must host the client metadata and JWKS endpoints.
2572
+ *
2573
+ * @see https://atproto.com/specs/oauth for AT Protocol OAuth specification
2574
+ */
2575
+ oauth: z.infer<typeof OAuthConfigSchema>;
2576
+ /**
2577
+ * Server URLs for PDS and SDS connections.
2578
+ *
2579
+ * - **PDS**: Personal Data Server - user's own data storage
2580
+ * - **SDS**: Shared Data Server - collaborative storage with access control
2581
+ */
2582
+ servers?: z.infer<typeof ServerConfigSchema>;
2583
+ /**
2584
+ * Storage adapters for persisting OAuth sessions and state.
2585
+ *
2586
+ * If not provided, in-memory implementations are used automatically.
2587
+ * **Warning**: In-memory storage is lost on process restart - use persistent
2588
+ * storage (Redis, database, etc.) in production.
2589
+ *
2590
+ * @example
2591
+ * ```typescript
2592
+ * storage: {
2593
+ * sessionStore: new RedisSessionStore(redis),
2594
+ * stateStore: new RedisStateStore(redis),
2595
+ * }
2596
+ * ```
2597
+ */
2598
+ storage?: {
2599
+ /**
2600
+ * Persistent storage for OAuth sessions.
2601
+ * Sessions contain access tokens, refresh tokens, and DPoP keys.
2602
+ */
2603
+ sessionStore?: SessionStore;
2604
+ /**
2605
+ * Temporary storage for OAuth state during the authorization flow.
2606
+ * State is short-lived and used for PKCE and CSRF protection.
2607
+ */
2608
+ stateStore?: StateStore;
2609
+ };
2610
+ /**
2611
+ * Custom fetch implementation for HTTP requests.
2612
+ *
2613
+ * Use this to add custom headers, logging, or to use a different HTTP client.
2614
+ * Must be compatible with the standard Fetch API.
2615
+ *
2616
+ * @example
2617
+ * ```typescript
2618
+ * fetch: async (url, init) => {
2619
+ * console.log(`Fetching: ${url}`);
2620
+ * return globalThis.fetch(url, init);
2621
+ * }
2622
+ * ```
2623
+ */
2624
+ fetch?: typeof fetch;
2625
+ /**
2626
+ * Timeout configuration for network requests.
2627
+ * Values are in milliseconds.
2628
+ */
2629
+ timeouts?: z.infer<typeof TimeoutConfigSchema>;
2630
+ /**
2631
+ * Cache for profiles, metadata, and other frequently accessed data.
2632
+ *
2633
+ * Implementing caching can significantly reduce API calls and improve performance.
2634
+ * The SDK does not provide a default cache - you must implement {@link CacheInterface}.
2635
+ */
2636
+ cache?: CacheInterface;
2637
+ /**
2638
+ * Logger for debugging and observability.
2639
+ *
2640
+ * The logger receives debug, info, warn, and error messages from the SDK.
2641
+ * Compatible with `console` or any logger implementing {@link LoggerInterface}.
2642
+ *
2643
+ * @example
2644
+ * ```typescript
2645
+ * logger: console
2646
+ * // or
2647
+ * logger: pino()
2648
+ * // or
2649
+ * logger: winston.createLogger({ ... })
2650
+ * ```
2651
+ */
2652
+ logger?: LoggerInterface;
2653
+ }
2654
+
2655
+ /**
2656
+ * Options for the OAuth authorization flow.
2657
+ */
2658
+ interface AuthorizeOptions {
2659
+ /**
2660
+ * OAuth scope string to request specific permissions.
2661
+ * Overrides the default scope configured in {@link ATProtoSDKConfig.oauth.scope}.
2662
+ *
2663
+ * @example
2664
+ * ```typescript
2665
+ * // Request read-only access
2666
+ * await sdk.authorize("user.bsky.social", { scope: "atproto" });
2667
+ *
2668
+ * // Request full access (default typically includes transition:generic)
2669
+ * await sdk.authorize("user.bsky.social", { scope: "atproto transition:generic" });
2670
+ * ```
2671
+ */
2672
+ scope?: string;
2673
+ }
2674
+ /**
2675
+ * Main ATProto SDK class providing OAuth authentication and repository access.
2676
+ *
2677
+ * This is the primary entry point for interacting with AT Protocol servers.
2678
+ * It handles the OAuth 2.0 flow with DPoP (Demonstrating Proof of Possession)
2679
+ * and provides access to repository operations for managing records, blobs,
2680
+ * and profiles.
2681
+ *
2682
+ * @example Basic usage with OAuth flow
2683
+ * ```typescript
2684
+ * import { ATProtoSDK, InMemorySessionStore, InMemoryStateStore } from "@hypercerts-org/sdk";
2685
+ *
2686
+ * const sdk = new ATProtoSDK({
2687
+ * oauth: {
2688
+ * clientId: "https://my-app.com/client-metadata.json",
2689
+ * redirectUri: "https://my-app.com/callback",
2690
+ * scope: "atproto transition:generic",
2691
+ * jwksUri: "https://my-app.com/.well-known/jwks.json",
2692
+ * jwkPrivate: process.env.JWK_PRIVATE_KEY!,
2693
+ * },
2694
+ * servers: {
2695
+ * pds: "https://bsky.social",
2696
+ * sds: "https://sds.hypercerts.org",
2697
+ * },
2698
+ * });
2699
+ *
2700
+ * // Start OAuth flow - redirect user to this URL
2701
+ * const authUrl = await sdk.authorize("user.bsky.social");
2702
+ *
2703
+ * // After user returns, handle the callback
2704
+ * const session = await sdk.callback(new URLSearchParams(window.location.search));
2705
+ *
2706
+ * // Get a repository to work with data
2707
+ * const repo = sdk.repository(session);
2708
+ * ```
2709
+ *
2710
+ * @example Restoring an existing session
2711
+ * ```typescript
2712
+ * // Restore a previous session by DID
2713
+ * const session = await sdk.restoreSession("did:plc:abc123...");
2714
+ * if (session) {
2715
+ * const repo = sdk.repository(session);
2716
+ * // Continue working with the restored session
2717
+ * }
2718
+ * ```
2719
+ *
2720
+ * @see {@link ATProtoSDKConfig} for configuration options
2721
+ * @see {@link Repository} for data operations
2722
+ * @see {@link OAuthClient} for OAuth implementation details
2723
+ */
2724
+ declare class ATProtoSDK {
2725
+ private oauthClient;
2726
+ private config;
2727
+ private logger?;
2728
+ private lexiconRegistry;
2729
+ /**
2730
+ * Creates a new ATProto SDK instance.
2731
+ *
2732
+ * @param config - SDK configuration including OAuth credentials, server URLs, and optional storage adapters
2733
+ * @throws {@link ValidationError} if the configuration is invalid (e.g., malformed URLs, missing required fields)
2734
+ *
2735
+ * @remarks
2736
+ * If no storage adapters are provided, in-memory implementations are used.
2737
+ * These are suitable for development and testing but **not recommended for production**
2738
+ * as sessions will be lost on restart.
2739
+ *
2740
+ * @example
2741
+ * ```typescript
2742
+ * // Minimal configuration (uses in-memory storage)
2743
+ * const sdk = new ATProtoSDK({
2744
+ * oauth: {
2745
+ * clientId: "https://my-app.com/client-metadata.json",
2746
+ * redirectUri: "https://my-app.com/callback",
2747
+ * scope: "atproto",
2748
+ * jwksUri: "https://my-app.com/.well-known/jwks.json",
2749
+ * jwkPrivate: privateKeyJwk,
2750
+ * },
2751
+ * servers: { pds: "https://bsky.social" },
2752
+ * });
2753
+ * ```
2754
+ */
2755
+ constructor(config: ATProtoSDKConfig);
2756
+ /**
2757
+ * Initiates the OAuth authorization flow.
2758
+ *
2759
+ * This method starts the OAuth 2.0 authorization flow by resolving the user's
2760
+ * identity and generating an authorization URL. The user should be redirected
2761
+ * to this URL to authenticate.
2762
+ *
2763
+ * @param identifier - The user's ATProto identifier. Can be:
2764
+ * - A handle (e.g., `"user.bsky.social"`)
2765
+ * - A DID (e.g., `"did:plc:abc123..."`)
2766
+ * - A PDS URL (e.g., `"https://bsky.social"`)
2767
+ * @param options - Optional authorization settings
2768
+ * @returns A Promise resolving to the authorization URL to redirect the user to
2769
+ * @throws {@link ValidationError} if the identifier is empty or invalid
2770
+ * @throws {@link NetworkError} if the identity cannot be resolved
2771
+ *
2772
+ * @example
2773
+ * ```typescript
2774
+ * // Using a handle
2775
+ * const authUrl = await sdk.authorize("alice.bsky.social");
2776
+ *
2777
+ * // Using a DID directly
2778
+ * const authUrl = await sdk.authorize("did:plc:abc123xyz");
2779
+ *
2780
+ * // With custom scope
2781
+ * const authUrl = await sdk.authorize("alice.bsky.social", {
2782
+ * scope: "atproto transition:generic"
2783
+ * });
2784
+ *
2785
+ * // Redirect user to authUrl
2786
+ * window.location.href = authUrl;
2787
+ * ```
2788
+ */
2789
+ authorize(identifier: string, options?: AuthorizeOptions): Promise<string>;
2790
+ /**
2791
+ * Handles the OAuth callback and exchanges the authorization code for tokens.
2792
+ *
2793
+ * Call this method when the user is redirected back to your application
2794
+ * after authenticating. It validates the OAuth state, exchanges the
2795
+ * authorization code for access/refresh tokens, and creates a session.
2796
+ *
2797
+ * @param params - URL search parameters from the callback URL
2798
+ * @returns A Promise resolving to the authenticated OAuth session
2799
+ * @throws {@link AuthenticationError} if the callback parameters are invalid or the code exchange fails
2800
+ * @throws {@link ValidationError} if required parameters are missing
2801
+ *
2802
+ * @example
2803
+ * ```typescript
2804
+ * // In your callback route handler
2805
+ * const params = new URLSearchParams(window.location.search);
2806
+ * // params contains: code, state, iss (issuer)
2807
+ *
2808
+ * const session = await sdk.callback(params);
2809
+ * console.log(`Authenticated as ${session.did}`);
2810
+ *
2811
+ * // Store the DID to restore the session later
2812
+ * localStorage.setItem("userDid", session.did);
2813
+ * ```
2814
+ */
2815
+ callback(params: URLSearchParams): Promise<Session>;
2816
+ /**
2817
+ * Restores an existing OAuth session by DID.
2818
+ *
2819
+ * Use this method to restore a previously authenticated session, typically
2820
+ * on application startup. The method retrieves the stored session and
2821
+ * automatically refreshes expired tokens if needed.
2822
+ *
2823
+ * @param did - The user's Decentralized Identifier (DID), e.g., `"did:plc:abc123..."`
2824
+ * @returns A Promise resolving to the restored session, or `null` if no session exists
2825
+ * @throws {@link ValidationError} if the DID is empty
2826
+ * @throws {@link SessionExpiredError} if the session cannot be refreshed
2827
+ *
2828
+ * @example
2829
+ * ```typescript
2830
+ * // On application startup
2831
+ * const savedDid = localStorage.getItem("userDid");
2832
+ * if (savedDid) {
2833
+ * const session = await sdk.restoreSession(savedDid);
2834
+ * if (session) {
2835
+ * // User is still authenticated
2836
+ * const repo = sdk.repository(session);
2837
+ * } else {
2838
+ * // Session not found, user needs to re-authenticate
2839
+ * const authUrl = await sdk.authorize(savedDid);
2840
+ * }
2841
+ * }
2842
+ * ```
2843
+ */
2844
+ restoreSession(did: string): Promise<Session | null>;
2845
+ /**
2846
+ * Revokes an OAuth session, logging the user out.
2847
+ *
2848
+ * This method invalidates the session's tokens and removes it from storage.
2849
+ * After revocation, the session can no longer be used or restored.
2850
+ *
2851
+ * @param did - The user's DID to revoke the session for
2852
+ * @throws {@link ValidationError} if the DID is empty
2853
+ *
2854
+ * @example
2855
+ * ```typescript
2856
+ * // Log out the user
2857
+ * await sdk.revokeSession(session.did);
2858
+ * localStorage.removeItem("userDid");
2859
+ * ```
2860
+ */
2861
+ revokeSession(did: string): Promise<void>;
2862
+ /**
2863
+ * Creates a repository instance for data operations.
2864
+ *
2865
+ * The repository provides a fluent API for working with AT Protocol data
2866
+ * including records, blobs, profiles, and domain-specific operations like
2867
+ * hypercerts and collaborators.
2868
+ *
2869
+ * @param session - An authenticated OAuth session
2870
+ * @param options - Repository configuration options
2871
+ * @returns A {@link Repository} instance configured for the specified server
2872
+ * @throws {@link ValidationError} if the session is invalid or server URL is not configured
2873
+ *
2874
+ * @remarks
2875
+ * - **PDS (Personal Data Server)**: User's own data storage, default for most operations
2876
+ * - **SDS (Shared Data Server)**: Shared data storage with collaborator support
2877
+ *
2878
+ * @example Using default PDS
2879
+ * ```typescript
2880
+ * const repo = sdk.repository(session);
2881
+ * const profile = await repo.profile.get();
2882
+ * ```
2883
+ *
2884
+ * @example Using configured SDS
2885
+ * ```typescript
2886
+ * const sdsRepo = sdk.repository(session, { server: "sds" });
2887
+ * const collaborators = await sdsRepo.collaborators.list();
2888
+ * ```
2889
+ *
2890
+ * @example Using custom server URL
2891
+ * ```typescript
2892
+ * const customRepo = sdk.repository(session, {
2893
+ * serverUrl: "https://custom.atproto.server"
2894
+ * });
2895
+ * ```
2896
+ */
2897
+ repository(session: Session, options?: RepositoryOptions): Repository;
2898
+ /**
2899
+ * Gets the lexicon registry for schema validation.
2900
+ *
2901
+ * The lexicon registry manages AT Protocol lexicon schemas used for
2902
+ * validating record data. You can register custom lexicons to extend
2903
+ * the SDK's capabilities.
2904
+ *
2905
+ * @returns The {@link LexiconRegistry} instance
2906
+ *
2907
+ * @example
2908
+ * ```typescript
2909
+ * const registry = sdk.getLexiconRegistry();
2910
+ *
2911
+ * // Register custom lexicons
2912
+ * registry.register(myCustomLexicons);
2913
+ *
2914
+ * // Check if a lexicon is registered
2915
+ * const hasLexicon = registry.has("org.example.myRecord");
2916
+ * ```
2917
+ */
2918
+ getLexiconRegistry(): LexiconRegistry;
2919
+ /**
2920
+ * The configured PDS (Personal Data Server) URL.
2921
+ *
2922
+ * @returns The PDS URL if configured, otherwise `undefined`
2923
+ */
2924
+ get pdsUrl(): string | undefined;
2925
+ /**
2926
+ * The configured SDS (Shared Data Server) URL.
2927
+ *
2928
+ * @returns The SDS URL if configured, otherwise `undefined`
2929
+ */
2930
+ get sdsUrl(): string | undefined;
2931
+ }
2932
+ /**
2933
+ * Factory function to create an ATProto SDK instance.
2934
+ *
2935
+ * This is a convenience function equivalent to `new ATProtoSDK(config)`.
2936
+ *
2937
+ * @param config - SDK configuration
2938
+ * @returns A new {@link ATProtoSDK} instance
2939
+ *
2940
+ * @example
2941
+ * ```typescript
2942
+ * import { createATProtoSDK } from "@hypercerts-org/sdk";
2943
+ *
2944
+ * const sdk = createATProtoSDK({
2945
+ * oauth: { ... },
2946
+ * servers: { pds: "https://bsky.social" },
2947
+ * });
2948
+ * ```
2949
+ */
2950
+ declare function createATProtoSDK(config: ATProtoSDKConfig): ATProtoSDK;
2951
+
2952
+ /**
2953
+ * Base error class for all SDK errors.
2954
+ *
2955
+ * All errors thrown by the Hypercerts SDK extend this class, making it easy
2956
+ * to catch and handle SDK-specific errors.
2957
+ *
2958
+ * @example Catching all SDK errors
2959
+ * ```typescript
2960
+ * try {
2961
+ * await sdk.authorize("user.bsky.social");
2962
+ * } catch (error) {
2963
+ * if (error instanceof ATProtoSDKError) {
2964
+ * console.error(`SDK Error [${error.code}]: ${error.message}`);
2965
+ * console.error(`HTTP Status: ${error.status}`);
2966
+ * }
2967
+ * }
2968
+ * ```
2969
+ *
2970
+ * @example Checking error codes
2971
+ * ```typescript
2972
+ * try {
2973
+ * await repo.records.get(collection, rkey);
2974
+ * } catch (error) {
2975
+ * if (error instanceof ATProtoSDKError) {
2976
+ * switch (error.code) {
2977
+ * case "AUTHENTICATION_ERROR":
2978
+ * // Redirect to login
2979
+ * break;
2980
+ * case "VALIDATION_ERROR":
2981
+ * // Show form errors
2982
+ * break;
2983
+ * case "NETWORK_ERROR":
2984
+ * // Retry or show offline message
2985
+ * break;
2986
+ * }
2987
+ * }
2988
+ * }
2989
+ * ```
2990
+ */
2991
+ declare class ATProtoSDKError extends Error {
2992
+ code: string;
2993
+ status?: number | undefined;
2994
+ cause?: unknown | undefined;
2995
+ /**
2996
+ * Creates a new SDK error.
2997
+ *
2998
+ * @param message - Human-readable error description
2999
+ * @param code - Machine-readable error code for programmatic handling
3000
+ * @param status - HTTP status code associated with this error type
3001
+ * @param cause - The underlying error that caused this error, if any
3002
+ */
3003
+ constructor(message: string, code: string, status?: number | undefined, cause?: unknown | undefined);
3004
+ }
3005
+ /**
3006
+ * Error thrown when authentication fails.
3007
+ *
3008
+ * This error indicates problems with the OAuth flow, invalid credentials,
3009
+ * or failed token exchanges. Common causes:
3010
+ * - Invalid authorization code
3011
+ * - Expired or invalid state parameter
3012
+ * - Revoked or invalid tokens
3013
+ * - User denied authorization
3014
+ *
3015
+ * @example
3016
+ * ```typescript
3017
+ * try {
3018
+ * const session = await sdk.callback(params);
3019
+ * } catch (error) {
3020
+ * if (error instanceof AuthenticationError) {
3021
+ * // Clear any stored state and redirect to login
3022
+ * console.error("Authentication failed:", error.message);
3023
+ * }
3024
+ * }
3025
+ * ```
3026
+ */
3027
+ declare class AuthenticationError extends ATProtoSDKError {
3028
+ /**
3029
+ * Creates an authentication error.
3030
+ *
3031
+ * @param message - Description of what went wrong during authentication
3032
+ * @param cause - The underlying error (e.g., from the OAuth client)
3033
+ */
3034
+ constructor(message: string, cause?: unknown);
3035
+ }
3036
+ /**
3037
+ * Error thrown when a session has expired and cannot be refreshed.
3038
+ *
3039
+ * This typically occurs when:
3040
+ * - The refresh token has expired (usually after extended inactivity)
3041
+ * - The user has revoked access to your application
3042
+ * - The PDS has invalidated all sessions for the user
3043
+ *
3044
+ * When this error occurs, the user must re-authenticate.
3045
+ *
3046
+ * @example
3047
+ * ```typescript
3048
+ * try {
3049
+ * const session = await sdk.restoreSession(did);
3050
+ * } catch (error) {
3051
+ * if (error instanceof SessionExpiredError) {
3052
+ * // Clear stored session and prompt user to log in again
3053
+ * localStorage.removeItem("userDid");
3054
+ * window.location.href = "/login";
3055
+ * }
3056
+ * }
3057
+ * ```
3058
+ */
3059
+ declare class SessionExpiredError extends ATProtoSDKError {
3060
+ /**
3061
+ * Creates a session expired error.
3062
+ *
3063
+ * @param message - Description of why the session expired
3064
+ * @param cause - The underlying error from the token refresh attempt
3065
+ */
3066
+ constructor(message?: string, cause?: unknown);
3067
+ }
3068
+ /**
3069
+ * Error thrown when input validation fails.
3070
+ *
3071
+ * This error indicates that provided data doesn't meet the required format
3072
+ * or constraints. Common causes:
3073
+ * - Missing required fields
3074
+ * - Invalid URL formats
3075
+ * - Invalid DID format
3076
+ * - Schema validation failures for records
3077
+ * - Invalid configuration values
3078
+ *
3079
+ * @example
3080
+ * ```typescript
3081
+ * try {
3082
+ * await sdk.authorize(""); // Empty identifier
3083
+ * } catch (error) {
3084
+ * if (error instanceof ValidationError) {
3085
+ * console.error("Invalid input:", error.message);
3086
+ * // Show validation error to user
3087
+ * }
3088
+ * }
3089
+ * ```
3090
+ *
3091
+ * @example With Zod validation cause
3092
+ * ```typescript
3093
+ * try {
3094
+ * await repo.records.create(collection, record);
3095
+ * } catch (error) {
3096
+ * if (error instanceof ValidationError && error.cause) {
3097
+ * // error.cause may be a ZodError with detailed field errors
3098
+ * const zodError = error.cause as ZodError;
3099
+ * zodError.errors.forEach(e => {
3100
+ * console.error(`Field ${e.path.join(".")}: ${e.message}`);
3101
+ * });
3102
+ * }
3103
+ * }
3104
+ * ```
3105
+ */
3106
+ declare class ValidationError extends ATProtoSDKError {
3107
+ /**
3108
+ * Creates a validation error.
3109
+ *
3110
+ * @param message - Description of what validation failed
3111
+ * @param cause - The underlying validation error (e.g., ZodError)
3112
+ */
3113
+ constructor(message: string, cause?: unknown);
3114
+ }
3115
+ /**
3116
+ * Error thrown when a network request fails.
3117
+ *
3118
+ * This error indicates connectivity issues or server unavailability.
3119
+ * Common causes:
3120
+ * - No internet connection
3121
+ * - DNS resolution failure
3122
+ * - Server timeout
3123
+ * - Server returned 5xx error
3124
+ * - TLS/SSL errors
3125
+ *
3126
+ * These errors are typically transient and may succeed on retry.
3127
+ *
3128
+ * @example
3129
+ * ```typescript
3130
+ * try {
3131
+ * await repo.records.list(collection);
3132
+ * } catch (error) {
3133
+ * if (error instanceof NetworkError) {
3134
+ * // Implement retry logic or show offline indicator
3135
+ * console.error("Network error:", error.message);
3136
+ * await retryWithBackoff(() => repo.records.list(collection));
3137
+ * }
3138
+ * }
3139
+ * ```
3140
+ */
3141
+ declare class NetworkError extends ATProtoSDKError {
3142
+ /**
3143
+ * Creates a network error.
3144
+ *
3145
+ * @param message - Description of the network failure
3146
+ * @param cause - The underlying error (e.g., fetch error, timeout)
3147
+ */
3148
+ constructor(message: string, cause?: unknown);
3149
+ }
3150
+ /**
3151
+ * Error thrown when an SDS-only operation is attempted on a PDS.
3152
+ *
3153
+ * Certain operations are only available on Shared Data Servers (SDS),
3154
+ * such as collaborator management and organization operations.
3155
+ * This error is thrown when these operations are attempted on a
3156
+ * Personal Data Server (PDS).
3157
+ *
3158
+ * @example
3159
+ * ```typescript
3160
+ * const pdsRepo = sdk.repository(session); // Default is PDS
3161
+ *
3162
+ * try {
3163
+ * // This will throw SDSRequiredError
3164
+ * await pdsRepo.collaborators.list();
3165
+ * } catch (error) {
3166
+ * if (error instanceof SDSRequiredError) {
3167
+ * // Switch to SDS for this operation
3168
+ * const sdsRepo = sdk.repository(session, { server: "sds" });
3169
+ * const collaborators = await sdsRepo.collaborators.list();
3170
+ * }
3171
+ * }
3172
+ * ```
3173
+ */
3174
+ declare class SDSRequiredError extends ATProtoSDKError {
3175
+ /**
3176
+ * Creates an SDS required error.
3177
+ *
3178
+ * @param message - Description of which operation requires SDS
3179
+ * @param cause - Any underlying error
3180
+ */
3181
+ constructor(message?: string, cause?: unknown);
3182
+ }
3183
+
3184
+ /**
3185
+ * In-memory implementation of the SessionStore interface.
3186
+ *
3187
+ * This store keeps OAuth sessions in memory using a Map. It's intended
3188
+ * for development, testing, and simple use cases where session persistence
3189
+ * across restarts is not required.
3190
+ *
3191
+ * @remarks
3192
+ * **Warning**: This implementation is **not suitable for production** because:
3193
+ * - Sessions are lost when the process restarts
3194
+ * - Sessions cannot be shared across multiple server instances
3195
+ * - No automatic cleanup of expired sessions
3196
+ *
3197
+ * For production, implement {@link SessionStore} with a persistent backend:
3198
+ * - **Redis**: Good for distributed systems, supports TTL
3199
+ * - **PostgreSQL/MySQL**: Good for existing database infrastructure
3200
+ * - **MongoDB**: Good for document-based storage
3201
+ *
3202
+ * @example Basic usage
3203
+ * ```typescript
3204
+ * import { InMemorySessionStore } from "@hypercerts-org/sdk/storage";
3205
+ *
3206
+ * const sessionStore = new InMemorySessionStore();
3207
+ *
3208
+ * const sdk = new ATProtoSDK({
3209
+ * oauth: { ... },
3210
+ * storage: {
3211
+ * sessionStore, // Will warn in logs for production
3212
+ * },
3213
+ * });
3214
+ * ```
3215
+ *
3216
+ * @example Testing usage
3217
+ * ```typescript
3218
+ * const sessionStore = new InMemorySessionStore();
3219
+ *
3220
+ * // After tests, clean up
3221
+ * sessionStore.clear();
3222
+ * ```
3223
+ *
3224
+ * @see {@link SessionStore} for the interface definition
3225
+ * @see {@link InMemoryStateStore} for the corresponding state store
3226
+ */
3227
+ declare class InMemorySessionStore implements SessionStore {
3228
+ /**
3229
+ * Internal storage for sessions, keyed by DID.
3230
+ * @internal
3231
+ */
3232
+ private sessions;
3233
+ /**
3234
+ * Retrieves a session by DID.
3235
+ *
3236
+ * @param did - The user's Decentralized Identifier
3237
+ * @returns Promise resolving to the session, or `undefined` if not found
3238
+ *
3239
+ * @example
3240
+ * ```typescript
3241
+ * const session = await sessionStore.get("did:plc:abc123");
3242
+ * if (session) {
3243
+ * console.log("Session found");
3244
+ * }
3245
+ * ```
3246
+ */
3247
+ get(did: string): Promise<NodeSavedSession | undefined>;
3248
+ /**
3249
+ * Stores or updates a session.
3250
+ *
3251
+ * @param did - The user's DID to use as the key
3252
+ * @param session - The session data to store
3253
+ *
3254
+ * @remarks
3255
+ * If a session already exists for the DID, it is overwritten.
3256
+ *
3257
+ * @example
3258
+ * ```typescript
3259
+ * await sessionStore.set("did:plc:abc123", sessionData);
3260
+ * ```
3261
+ */
3262
+ set(did: string, session: NodeSavedSession): Promise<void>;
3263
+ /**
3264
+ * Deletes a session by DID.
3265
+ *
3266
+ * @param did - The DID of the session to delete
3267
+ *
3268
+ * @remarks
3269
+ * If no session exists for the DID, this is a no-op.
3270
+ *
3271
+ * @example
3272
+ * ```typescript
3273
+ * await sessionStore.del("did:plc:abc123");
3274
+ * ```
3275
+ */
3276
+ del(did: string): Promise<void>;
3277
+ /**
3278
+ * Clears all stored sessions.
3279
+ *
3280
+ * This is primarily useful for testing to ensure a clean state
3281
+ * between test runs.
3282
+ *
3283
+ * @remarks
3284
+ * This method is synchronous (not async) for convenience in test cleanup.
3285
+ *
3286
+ * @example
3287
+ * ```typescript
3288
+ * // In test teardown
3289
+ * afterEach(() => {
3290
+ * sessionStore.clear();
3291
+ * });
3292
+ * ```
3293
+ */
3294
+ clear(): void;
3295
+ }
3296
+
3297
+ /**
3298
+ * In-memory implementation of the StateStore interface.
3299
+ *
3300
+ * This store keeps OAuth state parameters in memory using a Map. State is
3301
+ * used during the OAuth authorization flow for CSRF protection and PKCE.
3302
+ *
3303
+ * @remarks
3304
+ * **Warning**: This implementation is **not suitable for production** because:
3305
+ * - State is lost when the process restarts (breaking in-progress OAuth flows)
3306
+ * - State cannot be shared across multiple server instances
3307
+ * - No automatic cleanup of expired state (memory leak potential)
3308
+ *
3309
+ * For production, implement {@link StateStore} with a persistent backend
3310
+ * that supports TTL (time-to-live):
3311
+ * - **Redis**: Ideal choice with built-in TTL support
3312
+ * - **Database with cleanup job**: PostgreSQL/MySQL with periodic cleanup
3313
+ *
3314
+ * **State Lifecycle**:
3315
+ * 1. Created when user starts OAuth flow (`authorize()`)
3316
+ * 2. Retrieved and validated during callback
3317
+ * 3. Deleted after successful or failed callback
3318
+ * 4. Should expire after ~15 minutes if callback never happens
3319
+ *
3320
+ * @example Basic usage
3321
+ * ```typescript
3322
+ * import { InMemoryStateStore } from "@hypercerts-org/sdk/storage";
3323
+ *
3324
+ * const stateStore = new InMemoryStateStore();
3325
+ *
3326
+ * const sdk = new ATProtoSDK({
3327
+ * oauth: { ... },
3328
+ * storage: {
3329
+ * stateStore, // Will warn in logs for production
3330
+ * },
3331
+ * });
3332
+ * ```
3333
+ *
3334
+ * @example Testing usage
3335
+ * ```typescript
3336
+ * const stateStore = new InMemoryStateStore();
3337
+ *
3338
+ * // After tests, clean up
3339
+ * stateStore.clear();
3340
+ * ```
3341
+ *
3342
+ * @see {@link StateStore} for the interface definition
3343
+ * @see {@link InMemorySessionStore} for the corresponding session store
3344
+ */
3345
+ declare class InMemoryStateStore implements StateStore {
3346
+ /**
3347
+ * Internal storage for OAuth state, keyed by state string.
3348
+ * @internal
3349
+ */
3350
+ private states;
3351
+ /**
3352
+ * Retrieves OAuth state by key.
3353
+ *
3354
+ * @param key - The state key (random string from authorization URL)
3355
+ * @returns Promise resolving to the state, or `undefined` if not found
3356
+ *
3357
+ * @remarks
3358
+ * The key is a cryptographically random string generated during
3359
+ * the authorization request. It's included in the callback URL
3360
+ * and used to retrieve the associated PKCE verifier and other data.
3361
+ *
3362
+ * @example
3363
+ * ```typescript
3364
+ * // During OAuth callback
3365
+ * const state = await stateStore.get(params.get("state")!);
3366
+ * if (!state) {
3367
+ * throw new Error("Invalid or expired state");
3368
+ * }
3369
+ * ```
3370
+ */
3371
+ get(key: string): Promise<NodeSavedState | undefined>;
3372
+ /**
3373
+ * Stores OAuth state temporarily.
3374
+ *
3375
+ * @param key - The state key to use for storage
3376
+ * @param state - The OAuth state data (includes PKCE verifier, etc.)
3377
+ *
3378
+ * @remarks
3379
+ * In production implementations, state should be stored with a TTL
3380
+ * of approximately 10-15 minutes to prevent stale state accumulation.
3381
+ *
3382
+ * @example
3383
+ * ```typescript
3384
+ * // Called internally by OAuthClient during authorize()
3385
+ * await stateStore.set(stateKey, {
3386
+ * // PKCE code verifier, redirect URI, etc.
3387
+ * });
3388
+ * ```
3389
+ */
3390
+ set(key: string, state: NodeSavedState): Promise<void>;
3391
+ /**
3392
+ * Deletes OAuth state by key.
3393
+ *
3394
+ * @param key - The state key to delete
3395
+ *
3396
+ * @remarks
3397
+ * Called after the OAuth callback is processed (whether successful or not)
3398
+ * to clean up the temporary state.
3399
+ *
3400
+ * @example
3401
+ * ```typescript
3402
+ * // After processing callback
3403
+ * await stateStore.del(stateKey);
3404
+ * ```
3405
+ */
3406
+ del(key: string): Promise<void>;
3407
+ /**
3408
+ * Clears all stored state.
3409
+ *
3410
+ * This is primarily useful for testing to ensure a clean state
3411
+ * between test runs.
3412
+ *
3413
+ * @remarks
3414
+ * This method is synchronous (not async) for convenience in test cleanup.
3415
+ * In production, be careful using this as it will invalidate all
3416
+ * in-progress OAuth flows.
3417
+ *
3418
+ * @example
3419
+ * ```typescript
3420
+ * // In test teardown
3421
+ * afterEach(() => {
3422
+ * stateStore.clear();
3423
+ * });
3424
+ * ```
3425
+ */
3426
+ clear(): void;
3427
+ }
3428
+
3429
+ export { ATProtoSDK, ATProtoSDKConfigSchema, ATProtoSDKError, AuthenticationError, CollaboratorPermissionsSchema, CollaboratorSchema, InMemorySessionStore, InMemoryStateStore, LexiconRegistry, NetworkError, OAuthConfigSchema, OrganizationSchema, Repository, SDSRequiredError, ServerConfigSchema, SessionExpiredError, TimeoutConfigSchema, ValidationError, createATProtoSDK };
3430
+ export type { ATProtoSDKConfig, AuthorizeOptions, BlobOperations, BlobRef, CacheInterface, Collaborator, CollaboratorOperations, CollaboratorPermissions, CreateHypercertParams, CreateHypercertResult, CreateResult, DID, HypercertClaim, HypercertCollection, HypercertCollectionClaimItem, HypercertContribution, HypercertEvaluation, HypercertEvents, HypercertEvidence, HypercertImage, HypercertLocation, HypercertMeasurement, HypercertOperations, HypercertRights, HypercertWithMetadata, ListParams, LoggerInterface, Organization, OrganizationInfo, OrganizationOperations, PaginatedList, ProfileOperations, ProgressStep, RecordOperations, RepositoryAccessGrant, RepositoryOptions, RepositoryRole, Session, SessionStore, StateStore, StrongRef, UpdateResult, ValidationResult };