@hypercerts-org/sdk-core 0.10.0-beta.4 → 0.10.0-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/lexicons.mjs CHANGED
@@ -1,4 +1,406 @@
1
- import { CERTIFIED_DEFS_LEXICON_JSON, LOCATION_LEXICON_JSON, STRONGREF_LEXICON_JSON, HYPERCERTS_DEFS_LEXICON_JSON, ACTIVITY_LEXICON_JSON, COLLECTION_LEXICON_JSON, CONTRIBUTION_LEXICON_JSON, EVALUATION_LEXICON_JSON, EVIDENCE_LEXICON_JSON, MEASUREMENT_LEXICON_JSON, RIGHTS_LEXICON_JSON, PROJECT_LEXICON_JSON, BADGE_AWARD_LEXICON_JSON, BADGE_DEFINITION_LEXICON_JSON, BADGE_RESPONSE_LEXICON_JSON, FUNDING_RECEIPT_LEXICON_JSON, FUNDING_RECEIPT_NSID, BADGE_RESPONSE_NSID, BADGE_DEFINITION_NSID, BADGE_AWARD_NSID, PROJECT_NSID, COLLECTION_NSID, EVIDENCE_NSID, EVALUATION_NSID, MEASUREMENT_NSID, CONTRIBUTION_NSID, LOCATION_NSID, RIGHTS_NSID, ACTIVITY_NSID } from '@hypercerts-org/lexicon';
1
+ import { CERTIFIED_DEFS_LEXICON_JSON, LOCATION_LEXICON_JSON, STRONG_REF_LEXICON_JSON, HYPERCERTS_DEFS_LEXICON_JSON, ACTIVITY_LEXICON_JSON, COLLECTION_LEXICON_JSON, CONTRIBUTION_DETAILS_LEXICON_JSON, CONTRIBUTOR_INFORMATION_LEXICON_JSON, EVALUATION_LEXICON_JSON, EVIDENCE_LEXICON_JSON, MEASUREMENT_LEXICON_JSON, RIGHTS_LEXICON_JSON, BADGE_AWARD_LEXICON_JSON, BADGE_DEFINITION_LEXICON_JSON, BADGE_RESPONSE_LEXICON_JSON, FUNDING_RECEIPT_LEXICON_JSON, WORK_SCOPE_TAG_LEXICON_JSON, WORK_SCOPE_TAG_NSID, FUNDING_RECEIPT_NSID, BADGE_RESPONSE_NSID, BADGE_DEFINITION_NSID, BADGE_AWARD_NSID, COLLECTION_NSID, EVIDENCE_NSID, EVALUATION_NSID, MEASUREMENT_NSID, CONTRIBUTOR_INFORMATION_NSID, CONTRIBUTION_DETAILS_NSID, LOCATION_NSID, RIGHTS_NSID, ACTIVITY_NSID } from '@hypercerts-org/lexicon';
2
+ import { Lexicons } from '@atproto/lexicon';
3
+
4
+ /**
5
+ * Base error class for all SDK errors.
6
+ *
7
+ * All errors thrown by the Hypercerts SDK extend this class, making it easy
8
+ * to catch and handle SDK-specific errors.
9
+ *
10
+ * @example Catching all SDK errors
11
+ * ```typescript
12
+ * try {
13
+ * await sdk.authorize("user.bsky.social");
14
+ * } catch (error) {
15
+ * if (error instanceof ATProtoSDKError) {
16
+ * console.error(`SDK Error [${error.code}]: ${error.message}`);
17
+ * console.error(`HTTP Status: ${error.status}`);
18
+ * }
19
+ * }
20
+ * ```
21
+ *
22
+ * @example Checking error codes
23
+ * ```typescript
24
+ * try {
25
+ * await repo.records.get(collection, rkey);
26
+ * } catch (error) {
27
+ * if (error instanceof ATProtoSDKError) {
28
+ * switch (error.code) {
29
+ * case "AUTHENTICATION_ERROR":
30
+ * // Redirect to login
31
+ * break;
32
+ * case "VALIDATION_ERROR":
33
+ * // Show form errors
34
+ * break;
35
+ * case "NETWORK_ERROR":
36
+ * // Retry or show offline message
37
+ * break;
38
+ * }
39
+ * }
40
+ * }
41
+ * ```
42
+ */
43
+ class ATProtoSDKError extends Error {
44
+ /**
45
+ * Creates a new SDK error.
46
+ *
47
+ * @param message - Human-readable error description
48
+ * @param code - Machine-readable error code for programmatic handling
49
+ * @param status - HTTP status code associated with this error type
50
+ * @param cause - The underlying error that caused this error, if any
51
+ */
52
+ constructor(message, code, status, cause) {
53
+ super(message);
54
+ this.code = code;
55
+ this.status = status;
56
+ this.cause = cause;
57
+ this.name = "ATProtoSDKError";
58
+ Error.captureStackTrace?.(this, this.constructor);
59
+ }
60
+ }
61
+ /**
62
+ * Error thrown when input validation fails.
63
+ *
64
+ * This error indicates that provided data doesn't meet the required format
65
+ * or constraints. Common causes:
66
+ * - Missing required fields
67
+ * - Invalid URL formats
68
+ * - Invalid DID format
69
+ * - Schema validation failures for records
70
+ * - Invalid configuration values
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * try {
75
+ * await sdk.authorize(""); // Empty identifier
76
+ * } catch (error) {
77
+ * if (error instanceof ValidationError) {
78
+ * console.error("Invalid input:", error.message);
79
+ * // Show validation error to user
80
+ * }
81
+ * }
82
+ * ```
83
+ *
84
+ * @example With Zod validation cause
85
+ * ```typescript
86
+ * try {
87
+ * await repo.records.create(collection, record);
88
+ * } catch (error) {
89
+ * if (error instanceof ValidationError && error.cause) {
90
+ * // error.cause may be a ZodError with detailed field errors
91
+ * const zodError = error.cause as ZodError;
92
+ * zodError.errors.forEach(e => {
93
+ * console.error(`Field ${e.path.join(".")}: ${e.message}`);
94
+ * });
95
+ * }
96
+ * }
97
+ * ```
98
+ */
99
+ class ValidationError extends ATProtoSDKError {
100
+ /**
101
+ * Creates a validation error.
102
+ *
103
+ * @param message - Description of what validation failed
104
+ * @param cause - The underlying validation error (e.g., ZodError)
105
+ */
106
+ constructor(message, cause) {
107
+ super(message, "VALIDATION_ERROR", 400, cause);
108
+ this.name = "ValidationError";
109
+ }
110
+ }
111
+
112
+ /**
113
+ * LexiconRegistry - Manages custom lexicon registration and validation.
114
+ *
115
+ * This module provides a registry for AT Protocol lexicon schemas,
116
+ * allowing developers to register custom lexicons and validate records
117
+ * against registered schemas.
118
+ *
119
+ * @packageDocumentation
120
+ */
121
+ /**
122
+ * Registry for managing AT Protocol lexicon schemas.
123
+ *
124
+ * The LexiconRegistry allows developers to:
125
+ * - Register custom lexicon definitions
126
+ * - Validate records against registered schemas
127
+ * - Query registered lexicons
128
+ * - Add lexicons to AT Protocol agents
129
+ *
130
+ * @example Basic usage
131
+ * ```typescript
132
+ * const registry = new LexiconRegistry();
133
+ *
134
+ * // Register a custom lexicon
135
+ * registry.register({
136
+ * lexicon: 1,
137
+ * id: "org.myapp.customRecord",
138
+ * defs: {
139
+ * main: {
140
+ * type: "record",
141
+ * key: "tid",
142
+ * record: {
143
+ * type: "object",
144
+ * required: ["$type", "title"],
145
+ * properties: {
146
+ * "$type": { type: "string", const: "org.myapp.customRecord" },
147
+ * title: { type: "string" }
148
+ * }
149
+ * }
150
+ * }
151
+ * }
152
+ * });
153
+ *
154
+ * // Validate a record
155
+ * const result = registry.validate("org.myapp.customRecord", {
156
+ * $type: "org.myapp.customRecord",
157
+ * title: "My Record"
158
+ * });
159
+ *
160
+ * if (!result.valid) {
161
+ * console.error(result.error);
162
+ * }
163
+ * ```
164
+ */
165
+ class LexiconRegistry {
166
+ /**
167
+ * Creates a new LexiconRegistry instance.
168
+ *
169
+ * @param initialLexicons - Optional array of lexicons to register on initialization
170
+ */
171
+ constructor(initialLexicons) {
172
+ this.lexicons = new Lexicons();
173
+ this.registeredIds = new Set();
174
+ if (initialLexicons && initialLexicons.length > 0) {
175
+ this.registerMany(initialLexicons);
176
+ }
177
+ }
178
+ /**
179
+ * Registers a single lexicon definition.
180
+ *
181
+ * @param lexicon - The lexicon document to register
182
+ * @throws {Error} If the lexicon is invalid or already registered
183
+ *
184
+ * @example
185
+ * ```typescript
186
+ * registry.register({
187
+ * lexicon: 1,
188
+ * id: "org.myapp.customRecord",
189
+ * defs: { ... }
190
+ * });
191
+ * ```
192
+ */
193
+ register(lexicon) {
194
+ if (!lexicon.id) {
195
+ throw new Error("Lexicon must have an id");
196
+ }
197
+ if (this.registeredIds.has(lexicon.id)) {
198
+ throw new Error(`Lexicon ${lexicon.id} is already registered`);
199
+ }
200
+ try {
201
+ // Check if the lexicon already exists in the internal store
202
+ // (e.g., after unregister which only removes from registeredIds)
203
+ const existingLexicon = this.lexicons.get(lexicon.id);
204
+ if (!existingLexicon) {
205
+ // Lexicon is truly new, add it to the store
206
+ this.lexicons.add(lexicon);
207
+ }
208
+ // Always add to registeredIds (re-enable if previously unregistered)
209
+ this.registeredIds.add(lexicon.id);
210
+ }
211
+ catch (error) {
212
+ throw new Error(`Failed to register lexicon ${lexicon.id}: ${error instanceof Error ? error.message : "Unknown error"}`);
213
+ }
214
+ }
215
+ /**
216
+ * Registers multiple lexicon definitions at once.
217
+ *
218
+ * @param lexicons - Array of lexicon documents to register
219
+ * @throws {Error} If any lexicon is invalid or already registered
220
+ *
221
+ * @example
222
+ * ```typescript
223
+ * registry.registerMany([lexicon1, lexicon2, lexicon3]);
224
+ * ```
225
+ */
226
+ registerMany(lexicons) {
227
+ for (const lexicon of lexicons) {
228
+ this.register(lexicon);
229
+ }
230
+ }
231
+ /**
232
+ * Registers a lexicon from a JSON object.
233
+ *
234
+ * This is a convenience method for registering lexicons loaded from JSON files.
235
+ *
236
+ * @param lexiconJson - The lexicon as a plain JavaScript object
237
+ * @throws {ValidationError} If the lexicon is not a valid object
238
+ * @throws {Error} If the lexicon is invalid or already registered
239
+ *
240
+ * @example
241
+ * ```typescript
242
+ * import customLexicon from "./custom-lexicon.json";
243
+ * registry.registerFromJSON(customLexicon);
244
+ * ```
245
+ */
246
+ registerFromJSON(lexiconJson) {
247
+ // Validate that input is an object and not null
248
+ if (typeof lexiconJson !== "object" || lexiconJson === null) {
249
+ throw new ValidationError("Lexicon JSON must be a valid object");
250
+ }
251
+ // Now we can safely cast to LexiconDoc and register
252
+ this.register(lexiconJson);
253
+ }
254
+ /**
255
+ * Unregisters a lexicon by its NSID.
256
+ *
257
+ * @param nsid - The NSID of the lexicon to unregister
258
+ * @returns True if the lexicon was unregistered, false if it wasn't registered
259
+ *
260
+ * @example
261
+ * ```typescript
262
+ * registry.unregister("org.myapp.customRecord");
263
+ * ```
264
+ */
265
+ unregister(nsid) {
266
+ if (!this.registeredIds.has(nsid)) {
267
+ return false;
268
+ }
269
+ this.registeredIds.delete(nsid);
270
+ // Note: Lexicons class doesn't have a remove method,
271
+ // so we can't actually remove from the internal store.
272
+ // We track removal in our Set for isRegistered checks.
273
+ return true;
274
+ }
275
+ /**
276
+ * Checks if a lexicon is registered.
277
+ *
278
+ * @param nsid - The NSID to check
279
+ * @returns True if the lexicon is registered
280
+ *
281
+ * @example
282
+ * ```typescript
283
+ * if (registry.isRegistered("org.myapp.customRecord")) {
284
+ * // Lexicon is available
285
+ * }
286
+ * ```
287
+ */
288
+ isRegistered(nsid) {
289
+ return this.registeredIds.has(nsid);
290
+ }
291
+ /**
292
+ * Gets a lexicon definition by its NSID.
293
+ *
294
+ * @param nsid - The NSID of the lexicon to retrieve
295
+ * @returns The lexicon document, or undefined if not found
296
+ *
297
+ * @example
298
+ * ```typescript
299
+ * const lexicon = registry.get("org.myapp.customRecord");
300
+ * if (lexicon) {
301
+ * console.log(lexicon.defs);
302
+ * }
303
+ * ```
304
+ */
305
+ get(nsid) {
306
+ if (!this.isRegistered(nsid)) {
307
+ return undefined;
308
+ }
309
+ return this.lexicons.get(nsid);
310
+ }
311
+ /**
312
+ * Gets all registered lexicon NSIDs.
313
+ *
314
+ * @returns Array of registered NSIDs
315
+ *
316
+ * @example
317
+ * ```typescript
318
+ * const registered = registry.getAll();
319
+ * console.log(`Registered lexicons: ${registered.join(", ")}`);
320
+ * ```
321
+ */
322
+ getAll() {
323
+ return Array.from(this.registeredIds);
324
+ }
325
+ /**
326
+ * Validates a record against a registered lexicon.
327
+ *
328
+ * @param nsid - The collection NSID to validate against
329
+ * @param record - The record data to validate
330
+ * @returns Validation result with success status and optional error message
331
+ *
332
+ * @example
333
+ * ```typescript
334
+ * const result = registry.validate("org.myapp.customRecord", {
335
+ * $type: "org.myapp.customRecord",
336
+ * title: "My Record"
337
+ * });
338
+ *
339
+ * if (!result.valid) {
340
+ * console.error(`Validation failed: ${result.error}`);
341
+ * }
342
+ * ```
343
+ */
344
+ validate(nsid, record) {
345
+ if (!this.isRegistered(nsid)) {
346
+ return {
347
+ valid: false,
348
+ error: `Lexicon ${nsid} is not registered`,
349
+ };
350
+ }
351
+ try {
352
+ this.lexicons.assertValidRecord(nsid, record);
353
+ return { valid: true };
354
+ }
355
+ catch (error) {
356
+ return {
357
+ valid: false,
358
+ error: error instanceof Error ? error.message : "Validation failed",
359
+ };
360
+ }
361
+ }
362
+ /**
363
+ * Adds all registered lexicons to an AT Protocol Agent.
364
+ *
365
+ * This method is currently a no-op as the AT Protocol Agent
366
+ * doesn't provide a public API for adding lexicons at runtime.
367
+ * Lexicons must be registered with the server.
368
+ *
369
+ * This method is kept for future compatibility if the API
370
+ * adds support for client-side lexicon registration.
371
+ *
372
+ * @param _agent - The AT Protocol Agent (currently unused)
373
+ *
374
+ * @example
375
+ * ```typescript
376
+ * const agent = new Agent(session);
377
+ * registry.addToAgent(agent);
378
+ * // Reserved for future use
379
+ * ```
380
+ */
381
+ addToAgent(_agent) {
382
+ // No-op: AT Protocol Agent doesn't support client-side lexicon addition
383
+ // Lexicons are validated client-side via this registry,
384
+ // but server-side validation is performed by the PDS/SDS
385
+ }
386
+ /**
387
+ * Gets the underlying Lexicons instance.
388
+ *
389
+ * This provides direct access to the AT Protocol Lexicons object
390
+ * for advanced use cases.
391
+ *
392
+ * @returns The internal Lexicons instance
393
+ *
394
+ * @example
395
+ * ```typescript
396
+ * const lexicons = registry.getLexicons();
397
+ * // Use lexicons directly for advanced operations
398
+ * ```
399
+ */
400
+ getLexicons() {
401
+ return this.lexicons;
402
+ }
403
+ }
2
404
 
3
405
  /**
4
406
  * Lexicons entrypoint - Lexicon definitions and registry.
@@ -66,20 +468,21 @@ import { CERTIFIED_DEFS_LEXICON_JSON, LOCATION_LEXICON_JSON, STRONGREF_LEXICON_J
66
468
  const HYPERCERT_LEXICONS = [
67
469
  CERTIFIED_DEFS_LEXICON_JSON,
68
470
  LOCATION_LEXICON_JSON,
69
- STRONGREF_LEXICON_JSON,
471
+ STRONG_REF_LEXICON_JSON,
70
472
  HYPERCERTS_DEFS_LEXICON_JSON,
71
473
  ACTIVITY_LEXICON_JSON,
72
474
  COLLECTION_LEXICON_JSON,
73
- CONTRIBUTION_LEXICON_JSON,
475
+ CONTRIBUTION_DETAILS_LEXICON_JSON,
476
+ CONTRIBUTOR_INFORMATION_LEXICON_JSON,
74
477
  EVALUATION_LEXICON_JSON,
75
478
  EVIDENCE_LEXICON_JSON,
76
479
  MEASUREMENT_LEXICON_JSON,
77
480
  RIGHTS_LEXICON_JSON,
78
- PROJECT_LEXICON_JSON,
79
481
  BADGE_AWARD_LEXICON_JSON,
80
482
  BADGE_DEFINITION_LEXICON_JSON,
81
483
  BADGE_RESPONSE_LEXICON_JSON,
82
484
  FUNDING_RECEIPT_LEXICON_JSON,
485
+ WORK_SCOPE_TAG_LEXICON_JSON,
83
486
  ];
84
487
  /**
85
488
  * Collection NSIDs (Namespaced Identifiers) for hypercert records.
@@ -101,9 +504,15 @@ const HYPERCERT_COLLECTIONS = {
101
504
  */
102
505
  LOCATION: LOCATION_NSID,
103
506
  /**
104
- * Contribution record collection.
507
+ * Contribution details record collection.
508
+ * For storing details about a specific contribution (role, description, timeframe).
509
+ */
510
+ CONTRIBUTION_DETAILS: CONTRIBUTION_DETAILS_NSID,
511
+ /**
512
+ * Contributor information record collection.
513
+ * For storing contributor profile information (identifier, displayName, image).
105
514
  */
106
- CONTRIBUTION: CONTRIBUTION_NSID,
515
+ CONTRIBUTOR_INFORMATION: CONTRIBUTOR_INFORMATION_NSID,
107
516
  /**
108
517
  * Measurement record collection.
109
518
  */
@@ -118,12 +527,9 @@ const HYPERCERT_COLLECTIONS = {
118
527
  EVIDENCE: EVIDENCE_NSID,
119
528
  /**
120
529
  * Collection record collection (groups of hypercerts).
530
+ * Projects are now collections with type='project'.
121
531
  */
122
532
  COLLECTION: COLLECTION_NSID,
123
- /**
124
- * Project record collection.
125
- */
126
- PROJECT: PROJECT_NSID,
127
533
  /**
128
534
  * Badge award record collection.
129
535
  */
@@ -140,7 +546,12 @@ const HYPERCERT_COLLECTIONS = {
140
546
  * Funding receipt record collection.
141
547
  */
142
548
  FUNDING_RECEIPT: FUNDING_RECEIPT_NSID,
549
+ /**
550
+ * Work scope tag record collection.
551
+ * For defining reusable work scope atoms.
552
+ */
553
+ WORK_SCOPE_TAG: WORK_SCOPE_TAG_NSID,
143
554
  };
144
555
 
145
- export { HYPERCERT_COLLECTIONS, HYPERCERT_LEXICONS };
556
+ export { HYPERCERT_COLLECTIONS, HYPERCERT_LEXICONS, LexiconRegistry };
146
557
  //# sourceMappingURL=lexicons.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"lexicons.mjs","sources":["../src/lexicons.ts"],"sourcesContent":["/**\n * Lexicons entrypoint - Lexicon definitions and registry.\n *\n * This sub-entrypoint exports the lexicon registry and hypercert\n * lexicon constants for working with AT Protocol record schemas.\n *\n * @remarks\n * Import from `@hypercerts-org/sdk/lexicons`:\n *\n * ```typescript\n * import {\n * LexiconRegistry,\n * HYPERCERT_LEXICONS,\n * HYPERCERT_COLLECTIONS,\n * } from \"@hypercerts-org/sdk/lexicons\";\n * ```\n *\n * **Exports**:\n * - {@link LexiconRegistry} - Registry for managing and validating lexicons\n * - {@link HYPERCERT_LEXICONS} - Array of all hypercert lexicon documents\n * - {@link HYPERCERT_COLLECTIONS} - Constants for collection NSIDs\n *\n * @example Using collection constants\n * ```typescript\n * import { HYPERCERT_COLLECTIONS } from \"@hypercerts-org/sdk/lexicons\";\n *\n * // List hypercerts using the correct collection name\n * const records = await repo.records.list({\n * collection: HYPERCERT_COLLECTIONS.RECORD,\n * });\n *\n * // List contributions\n * const contributions = await repo.records.list({\n * collection: HYPERCERT_COLLECTIONS.CONTRIBUTION,\n * });\n * ```\n *\n * @example Custom lexicon registration\n * ```typescript\n * import { LexiconRegistry } from \"@hypercerts-org/sdk/lexicons\";\n *\n * const registry = sdk.getLexiconRegistry();\n *\n * // Register custom lexicon\n * registry.register({\n * lexicon: 1,\n * id: \"org.myapp.customRecord\",\n * defs: { ... },\n * });\n *\n * // Validate a record\n * const result = registry.validate(\"org.myapp.customRecord\", record);\n * if (!result.valid) {\n * console.error(result.error);\n * }\n * ```\n *\n * @packageDocumentation\n */\n\n// Import lexicon JSON files and constants from the published package\nimport type { LexiconDoc } from \"@atproto/lexicon\";\nimport {\n CERTIFIED_DEFS_LEXICON_JSON,\n LOCATION_LEXICON_JSON,\n STRONGREF_LEXICON_JSON,\n HYPERCERTS_DEFS_LEXICON_JSON,\n ACTIVITY_LEXICON_JSON,\n COLLECTION_LEXICON_JSON,\n CONTRIBUTION_LEXICON_JSON,\n EVALUATION_LEXICON_JSON,\n EVIDENCE_LEXICON_JSON,\n MEASUREMENT_LEXICON_JSON,\n RIGHTS_LEXICON_JSON,\n PROJECT_LEXICON_JSON,\n BADGE_AWARD_LEXICON_JSON,\n BADGE_DEFINITION_LEXICON_JSON,\n BADGE_RESPONSE_LEXICON_JSON,\n FUNDING_RECEIPT_LEXICON_JSON,\n // NSID constants\n ACTIVITY_NSID,\n RIGHTS_NSID,\n LOCATION_NSID,\n CONTRIBUTION_NSID,\n MEASUREMENT_NSID,\n EVALUATION_NSID,\n EVIDENCE_NSID,\n COLLECTION_NSID,\n PROJECT_NSID,\n BADGE_AWARD_NSID,\n BADGE_DEFINITION_NSID,\n BADGE_RESPONSE_NSID,\n FUNDING_RECEIPT_NSID,\n} from \"@hypercerts-org/lexicon\";\n\n/**\n * All hypercert-related lexicons for registration with AT Protocol Agent.\n * This array contains all lexicon documents from the published package.\n */\nexport const HYPERCERT_LEXICONS: LexiconDoc[] = [\n CERTIFIED_DEFS_LEXICON_JSON as LexiconDoc,\n LOCATION_LEXICON_JSON as LexiconDoc,\n STRONGREF_LEXICON_JSON as LexiconDoc,\n HYPERCERTS_DEFS_LEXICON_JSON as LexiconDoc,\n ACTIVITY_LEXICON_JSON as LexiconDoc,\n COLLECTION_LEXICON_JSON as LexiconDoc,\n CONTRIBUTION_LEXICON_JSON as LexiconDoc,\n EVALUATION_LEXICON_JSON as LexiconDoc,\n EVIDENCE_LEXICON_JSON as LexiconDoc,\n MEASUREMENT_LEXICON_JSON as LexiconDoc,\n RIGHTS_LEXICON_JSON as LexiconDoc,\n PROJECT_LEXICON_JSON as LexiconDoc,\n BADGE_AWARD_LEXICON_JSON as LexiconDoc,\n BADGE_DEFINITION_LEXICON_JSON as LexiconDoc,\n BADGE_RESPONSE_LEXICON_JSON as LexiconDoc,\n FUNDING_RECEIPT_LEXICON_JSON as LexiconDoc,\n];\n\n/**\n * Collection NSIDs (Namespaced Identifiers) for hypercert records.\n *\n * Use these constants when performing record operations to ensure\n * correct collection names.\n */\nexport const HYPERCERT_COLLECTIONS = {\n /**\n * Main hypercert claim record collection.\n */\n CLAIM: ACTIVITY_NSID,\n\n /**\n * Rights record collection.\n */\n RIGHTS: RIGHTS_NSID,\n\n /**\n * Location record collection (shared certified lexicon).\n */\n LOCATION: LOCATION_NSID,\n\n /**\n * Contribution record collection.\n */\n CONTRIBUTION: CONTRIBUTION_NSID,\n\n /**\n * Measurement record collection.\n */\n MEASUREMENT: MEASUREMENT_NSID,\n\n /**\n * Evaluation record collection.\n */\n EVALUATION: EVALUATION_NSID,\n\n /**\n * Evidence record collection.\n */\n EVIDENCE: EVIDENCE_NSID,\n\n /**\n * Collection record collection (groups of hypercerts).\n */\n COLLECTION: COLLECTION_NSID,\n\n /**\n * Project record collection.\n */\n PROJECT: PROJECT_NSID,\n\n /**\n * Badge award record collection.\n */\n BADGE_AWARD: BADGE_AWARD_NSID,\n\n /**\n * Badge definition record collection.\n */\n BADGE_DEFINITION: BADGE_DEFINITION_NSID,\n\n /**\n * Badge response record collection.\n */\n BADGE_RESPONSE: BADGE_RESPONSE_NSID,\n\n /**\n * Funding receipt record collection.\n */\n FUNDING_RECEIPT: FUNDING_RECEIPT_NSID,\n} as const;\n"],"names":[],"mappings":";;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0DG;AAqCH;;;AAGG;AACI,MAAM,kBAAkB,GAAiB;IAC9C,2BAAyC;IACzC,qBAAmC;IACnC,sBAAoC;IACpC,4BAA0C;IAC1C,qBAAmC;IACnC,uBAAqC;IACrC,yBAAuC;IACvC,uBAAqC;IACrC,qBAAmC;IACnC,wBAAsC;IACtC,mBAAiC;IACjC,oBAAkC;IAClC,wBAAsC;IACtC,6BAA2C;IAC3C,2BAAyC;IACzC,4BAA0C;;AAG5C;;;;;AAKG;AACI,MAAM,qBAAqB,GAAG;AACnC;;AAEG;AACH,IAAA,KAAK,EAAE,aAAa;AAEpB;;AAEG;AACH,IAAA,MAAM,EAAE,WAAW;AAEnB;;AAEG;AACH,IAAA,QAAQ,EAAE,aAAa;AAEvB;;AAEG;AACH,IAAA,YAAY,EAAE,iBAAiB;AAE/B;;AAEG;AACH,IAAA,WAAW,EAAE,gBAAgB;AAE7B;;AAEG;AACH,IAAA,UAAU,EAAE,eAAe;AAE3B;;AAEG;AACH,IAAA,QAAQ,EAAE,aAAa;AAEvB;;AAEG;AACH,IAAA,UAAU,EAAE,eAAe;AAE3B;;AAEG;AACH,IAAA,OAAO,EAAE,YAAY;AAErB;;AAEG;AACH,IAAA,WAAW,EAAE,gBAAgB;AAE7B;;AAEG;AACH,IAAA,gBAAgB,EAAE,qBAAqB;AAEvC;;AAEG;AACH,IAAA,cAAc,EAAE,mBAAmB;AAEnC;;AAEG;AACH,IAAA,eAAe,EAAE,oBAAoB;;;;;"}
1
+ {"version":3,"file":"lexicons.mjs","sources":["../src/core/errors.ts","../src/repository/LexiconRegistry.ts","../src/lexicons.ts"],"sourcesContent":["/**\n * Base error class for all SDK errors.\n *\n * All errors thrown by the Hypercerts SDK extend this class, making it easy\n * to catch and handle SDK-specific errors.\n *\n * @example Catching all SDK errors\n * ```typescript\n * try {\n * await sdk.authorize(\"user.bsky.social\");\n * } catch (error) {\n * if (error instanceof ATProtoSDKError) {\n * console.error(`SDK Error [${error.code}]: ${error.message}`);\n * console.error(`HTTP Status: ${error.status}`);\n * }\n * }\n * ```\n *\n * @example Checking error codes\n * ```typescript\n * try {\n * await repo.records.get(collection, rkey);\n * } catch (error) {\n * if (error instanceof ATProtoSDKError) {\n * switch (error.code) {\n * case \"AUTHENTICATION_ERROR\":\n * // Redirect to login\n * break;\n * case \"VALIDATION_ERROR\":\n * // Show form errors\n * break;\n * case \"NETWORK_ERROR\":\n * // Retry or show offline message\n * break;\n * }\n * }\n * }\n * ```\n */\nexport class ATProtoSDKError extends Error {\n /**\n * Creates a new SDK error.\n *\n * @param message - Human-readable error description\n * @param code - Machine-readable error code for programmatic handling\n * @param status - HTTP status code associated with this error type\n * @param cause - The underlying error that caused this error, if any\n */\n constructor(\n message: string,\n public code: string,\n public status?: number,\n public cause?: unknown,\n ) {\n super(message);\n this.name = \"ATProtoSDKError\";\n Error.captureStackTrace?.(this, this.constructor);\n }\n}\n\n/**\n * Error thrown when authentication fails.\n *\n * This error indicates problems with the OAuth flow, invalid credentials,\n * or failed token exchanges. Common causes:\n * - Invalid authorization code\n * - Expired or invalid state parameter\n * - Revoked or invalid tokens\n * - User denied authorization\n *\n * @example\n * ```typescript\n * try {\n * const session = await sdk.callback(params);\n * } catch (error) {\n * if (error instanceof AuthenticationError) {\n * // Clear any stored state and redirect to login\n * console.error(\"Authentication failed:\", error.message);\n * }\n * }\n * ```\n */\nexport class AuthenticationError extends ATProtoSDKError {\n /**\n * Creates an authentication error.\n *\n * @param message - Description of what went wrong during authentication\n * @param cause - The underlying error (e.g., from the OAuth client)\n */\n constructor(message: string, cause?: unknown) {\n super(message, \"AUTHENTICATION_ERROR\", 401, cause);\n this.name = \"AuthenticationError\";\n }\n}\n\n/**\n * Error thrown when a session has expired and cannot be refreshed.\n *\n * This typically occurs when:\n * - The refresh token has expired (usually after extended inactivity)\n * - The user has revoked access to your application\n * - The PDS has invalidated all sessions for the user\n *\n * When this error occurs, the user must re-authenticate.\n *\n * @example\n * ```typescript\n * try {\n * const session = await sdk.restoreSession(did);\n * } catch (error) {\n * if (error instanceof SessionExpiredError) {\n * // Clear stored session and prompt user to log in again\n * localStorage.removeItem(\"userDid\");\n * window.location.href = \"/login\";\n * }\n * }\n * ```\n */\nexport class SessionExpiredError extends ATProtoSDKError {\n /**\n * Creates a session expired error.\n *\n * @param message - Description of why the session expired\n * @param cause - The underlying error from the token refresh attempt\n */\n constructor(message: string = \"Session expired\", cause?: unknown) {\n super(message, \"SESSION_EXPIRED\", 401, cause);\n this.name = \"SessionExpiredError\";\n }\n}\n\n/**\n * Error thrown when input validation fails.\n *\n * This error indicates that provided data doesn't meet the required format\n * or constraints. Common causes:\n * - Missing required fields\n * - Invalid URL formats\n * - Invalid DID format\n * - Schema validation failures for records\n * - Invalid configuration values\n *\n * @example\n * ```typescript\n * try {\n * await sdk.authorize(\"\"); // Empty identifier\n * } catch (error) {\n * if (error instanceof ValidationError) {\n * console.error(\"Invalid input:\", error.message);\n * // Show validation error to user\n * }\n * }\n * ```\n *\n * @example With Zod validation cause\n * ```typescript\n * try {\n * await repo.records.create(collection, record);\n * } catch (error) {\n * if (error instanceof ValidationError && error.cause) {\n * // error.cause may be a ZodError with detailed field errors\n * const zodError = error.cause as ZodError;\n * zodError.errors.forEach(e => {\n * console.error(`Field ${e.path.join(\".\")}: ${e.message}`);\n * });\n * }\n * }\n * ```\n */\nexport class ValidationError extends ATProtoSDKError {\n /**\n * Creates a validation error.\n *\n * @param message - Description of what validation failed\n * @param cause - The underlying validation error (e.g., ZodError)\n */\n constructor(message: string, cause?: unknown) {\n super(message, \"VALIDATION_ERROR\", 400, cause);\n this.name = \"ValidationError\";\n }\n}\n\n/**\n * Error thrown when a network request fails.\n *\n * This error indicates connectivity issues or server unavailability.\n * Common causes:\n * - No internet connection\n * - DNS resolution failure\n * - Server timeout\n * - Server returned 5xx error\n * - TLS/SSL errors\n *\n * These errors are typically transient and may succeed on retry.\n *\n * @example\n * ```typescript\n * try {\n * await repo.records.list(collection);\n * } catch (error) {\n * if (error instanceof NetworkError) {\n * // Implement retry logic or show offline indicator\n * console.error(\"Network error:\", error.message);\n * await retryWithBackoff(() => repo.records.list(collection));\n * }\n * }\n * ```\n */\nexport class NetworkError extends ATProtoSDKError {\n /**\n * Creates a network error.\n *\n * @param message - Description of the network failure\n * @param cause - The underlying error (e.g., fetch error, timeout)\n */\n constructor(message: string, cause?: unknown) {\n super(message, \"NETWORK_ERROR\", 503, cause);\n this.name = \"NetworkError\";\n }\n}\n\n/**\n * Error thrown when an SDS-only operation is attempted on a PDS.\n *\n * Certain operations are only available on Shared Data Servers (SDS),\n * such as collaborator management and organization operations.\n * This error is thrown when these operations are attempted on a\n * Personal Data Server (PDS).\n *\n * @example\n * ```typescript\n * const pdsRepo = sdk.repository(session); // Default is PDS\n *\n * try {\n * // This will throw SDSRequiredError\n * await pdsRepo.collaborators.list();\n * } catch (error) {\n * if (error instanceof SDSRequiredError) {\n * // Switch to SDS for this operation\n * const sdsRepo = sdk.repository(session, { server: \"sds\" });\n * const collaborators = await sdsRepo.collaborators.list();\n * }\n * }\n * ```\n */\nexport class SDSRequiredError extends ATProtoSDKError {\n /**\n * Creates an SDS required error.\n *\n * @param message - Description of which operation requires SDS\n * @param cause - Any underlying error\n */\n constructor(message: string = \"This operation requires a Shared Data Server (SDS)\", cause?: unknown) {\n super(message, \"SDS_REQUIRED\", 400, cause);\n this.name = \"SDSRequiredError\";\n }\n}\n","/**\n * LexiconRegistry - Manages custom lexicon registration and validation.\n *\n * This module provides a registry for AT Protocol lexicon schemas,\n * allowing developers to register custom lexicons and validate records\n * against registered schemas.\n *\n * @packageDocumentation\n */\n\nimport type { LexiconDoc } from \"@atproto/lexicon\";\nimport { Lexicons } from \"@atproto/lexicon\";\nimport type { Agent } from \"@atproto/api\";\nimport { ValidationError } from \"../errors.js\";\n\n/**\n * Validation result from lexicon validation.\n */\nexport interface ValidationResult {\n /**\n * Whether the record is valid according to the lexicon.\n */\n valid: boolean;\n\n /**\n * Error message if validation failed.\n */\n error?: string;\n}\n\n/**\n * Registry for managing AT Protocol lexicon schemas.\n *\n * The LexiconRegistry allows developers to:\n * - Register custom lexicon definitions\n * - Validate records against registered schemas\n * - Query registered lexicons\n * - Add lexicons to AT Protocol agents\n *\n * @example Basic usage\n * ```typescript\n * const registry = new LexiconRegistry();\n *\n * // Register a custom lexicon\n * registry.register({\n * lexicon: 1,\n * id: \"org.myapp.customRecord\",\n * defs: {\n * main: {\n * type: \"record\",\n * key: \"tid\",\n * record: {\n * type: \"object\",\n * required: [\"$type\", \"title\"],\n * properties: {\n * \"$type\": { type: \"string\", const: \"org.myapp.customRecord\" },\n * title: { type: \"string\" }\n * }\n * }\n * }\n * }\n * });\n *\n * // Validate a record\n * const result = registry.validate(\"org.myapp.customRecord\", {\n * $type: \"org.myapp.customRecord\",\n * title: \"My Record\"\n * });\n *\n * if (!result.valid) {\n * console.error(result.error);\n * }\n * ```\n */\nexport class LexiconRegistry {\n private lexicons: Lexicons;\n private registeredIds: Set<string>;\n\n /**\n * Creates a new LexiconRegistry instance.\n *\n * @param initialLexicons - Optional array of lexicons to register on initialization\n */\n constructor(initialLexicons?: LexiconDoc[]) {\n this.lexicons = new Lexicons();\n this.registeredIds = new Set();\n\n if (initialLexicons && initialLexicons.length > 0) {\n this.registerMany(initialLexicons);\n }\n }\n\n /**\n * Registers a single lexicon definition.\n *\n * @param lexicon - The lexicon document to register\n * @throws {Error} If the lexicon is invalid or already registered\n *\n * @example\n * ```typescript\n * registry.register({\n * lexicon: 1,\n * id: \"org.myapp.customRecord\",\n * defs: { ... }\n * });\n * ```\n */\n register(lexicon: LexiconDoc): void {\n if (!lexicon.id) {\n throw new Error(\"Lexicon must have an id\");\n }\n\n if (this.registeredIds.has(lexicon.id)) {\n throw new Error(`Lexicon ${lexicon.id} is already registered`);\n }\n\n try {\n // Check if the lexicon already exists in the internal store\n // (e.g., after unregister which only removes from registeredIds)\n const existingLexicon = this.lexicons.get(lexicon.id);\n\n if (!existingLexicon) {\n // Lexicon is truly new, add it to the store\n this.lexicons.add(lexicon);\n }\n\n // Always add to registeredIds (re-enable if previously unregistered)\n this.registeredIds.add(lexicon.id);\n } catch (error) {\n throw new Error(\n `Failed to register lexicon ${lexicon.id}: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n }\n\n /**\n * Registers multiple lexicon definitions at once.\n *\n * @param lexicons - Array of lexicon documents to register\n * @throws {Error} If any lexicon is invalid or already registered\n *\n * @example\n * ```typescript\n * registry.registerMany([lexicon1, lexicon2, lexicon3]);\n * ```\n */\n registerMany(lexicons: LexiconDoc[]): void {\n for (const lexicon of lexicons) {\n this.register(lexicon);\n }\n }\n\n /**\n * Registers a lexicon from a JSON object.\n *\n * This is a convenience method for registering lexicons loaded from JSON files.\n *\n * @param lexiconJson - The lexicon as a plain JavaScript object\n * @throws {ValidationError} If the lexicon is not a valid object\n * @throws {Error} If the lexicon is invalid or already registered\n *\n * @example\n * ```typescript\n * import customLexicon from \"./custom-lexicon.json\";\n * registry.registerFromJSON(customLexicon);\n * ```\n */\n registerFromJSON(lexiconJson: unknown): void {\n // Validate that input is an object and not null\n if (typeof lexiconJson !== \"object\" || lexiconJson === null) {\n throw new ValidationError(\"Lexicon JSON must be a valid object\");\n }\n\n // Now we can safely cast to LexiconDoc and register\n this.register(lexiconJson as LexiconDoc);\n }\n\n /**\n * Unregisters a lexicon by its NSID.\n *\n * @param nsid - The NSID of the lexicon to unregister\n * @returns True if the lexicon was unregistered, false if it wasn't registered\n *\n * @example\n * ```typescript\n * registry.unregister(\"org.myapp.customRecord\");\n * ```\n */\n unregister(nsid: string): boolean {\n if (!this.registeredIds.has(nsid)) {\n return false;\n }\n\n this.registeredIds.delete(nsid);\n // Note: Lexicons class doesn't have a remove method,\n // so we can't actually remove from the internal store.\n // We track removal in our Set for isRegistered checks.\n return true;\n }\n\n /**\n * Checks if a lexicon is registered.\n *\n * @param nsid - The NSID to check\n * @returns True if the lexicon is registered\n *\n * @example\n * ```typescript\n * if (registry.isRegistered(\"org.myapp.customRecord\")) {\n * // Lexicon is available\n * }\n * ```\n */\n isRegistered(nsid: string): boolean {\n return this.registeredIds.has(nsid);\n }\n\n /**\n * Gets a lexicon definition by its NSID.\n *\n * @param nsid - The NSID of the lexicon to retrieve\n * @returns The lexicon document, or undefined if not found\n *\n * @example\n * ```typescript\n * const lexicon = registry.get(\"org.myapp.customRecord\");\n * if (lexicon) {\n * console.log(lexicon.defs);\n * }\n * ```\n */\n get(nsid: string): LexiconDoc | undefined {\n if (!this.isRegistered(nsid)) {\n return undefined;\n }\n\n return this.lexicons.get(nsid);\n }\n\n /**\n * Gets all registered lexicon NSIDs.\n *\n * @returns Array of registered NSIDs\n *\n * @example\n * ```typescript\n * const registered = registry.getAll();\n * console.log(`Registered lexicons: ${registered.join(\", \")}`);\n * ```\n */\n getAll(): string[] {\n return Array.from(this.registeredIds);\n }\n\n /**\n * Validates a record against a registered lexicon.\n *\n * @param nsid - The collection NSID to validate against\n * @param record - The record data to validate\n * @returns Validation result with success status and optional error message\n *\n * @example\n * ```typescript\n * const result = registry.validate(\"org.myapp.customRecord\", {\n * $type: \"org.myapp.customRecord\",\n * title: \"My Record\"\n * });\n *\n * if (!result.valid) {\n * console.error(`Validation failed: ${result.error}`);\n * }\n * ```\n */\n validate(nsid: string, record: unknown): ValidationResult {\n if (!this.isRegistered(nsid)) {\n return {\n valid: false,\n error: `Lexicon ${nsid} is not registered`,\n };\n }\n\n try {\n this.lexicons.assertValidRecord(nsid, record);\n return { valid: true };\n } catch (error) {\n return {\n valid: false,\n error: error instanceof Error ? error.message : \"Validation failed\",\n };\n }\n }\n\n /**\n * Adds all registered lexicons to an AT Protocol Agent.\n *\n * This method is currently a no-op as the AT Protocol Agent\n * doesn't provide a public API for adding lexicons at runtime.\n * Lexicons must be registered with the server.\n *\n * This method is kept for future compatibility if the API\n * adds support for client-side lexicon registration.\n *\n * @param _agent - The AT Protocol Agent (currently unused)\n *\n * @example\n * ```typescript\n * const agent = new Agent(session);\n * registry.addToAgent(agent);\n * // Reserved for future use\n * ```\n */\n addToAgent(_agent: Agent): void {\n // No-op: AT Protocol Agent doesn't support client-side lexicon addition\n // Lexicons are validated client-side via this registry,\n // but server-side validation is performed by the PDS/SDS\n }\n\n /**\n * Gets the underlying Lexicons instance.\n *\n * This provides direct access to the AT Protocol Lexicons object\n * for advanced use cases.\n *\n * @returns The internal Lexicons instance\n *\n * @example\n * ```typescript\n * const lexicons = registry.getLexicons();\n * // Use lexicons directly for advanced operations\n * ```\n */\n getLexicons(): Lexicons {\n return this.lexicons;\n }\n}\n","/**\n * Lexicons entrypoint - Lexicon definitions and registry.\n *\n * This sub-entrypoint exports the lexicon registry and hypercert\n * lexicon constants for working with AT Protocol record schemas.\n *\n * @remarks\n * Import from `@hypercerts-org/sdk/lexicons`:\n *\n * ```typescript\n * import {\n * LexiconRegistry,\n * HYPERCERT_LEXICONS,\n * HYPERCERT_COLLECTIONS,\n * } from \"@hypercerts-org/sdk/lexicons\";\n * ```\n *\n * **Exports**:\n * - {@link LexiconRegistry} - Registry for managing and validating lexicons\n * - {@link HYPERCERT_LEXICONS} - Array of all hypercert lexicon documents\n * - {@link HYPERCERT_COLLECTIONS} - Constants for collection NSIDs\n *\n * @example Using collection constants\n * ```typescript\n * import { HYPERCERT_COLLECTIONS } from \"@hypercerts-org/sdk/lexicons\";\n *\n * // List hypercerts using the correct collection name\n * const records = await repo.records.list({\n * collection: HYPERCERT_COLLECTIONS.RECORD,\n * });\n *\n * // List contributions\n * const contributions = await repo.records.list({\n * collection: HYPERCERT_COLLECTIONS.CONTRIBUTION,\n * });\n * ```\n *\n * @example Custom lexicon registration\n * ```typescript\n * import { LexiconRegistry } from \"@hypercerts-org/sdk/lexicons\";\n *\n * const registry = sdk.getLexiconRegistry();\n *\n * // Register custom lexicon\n * registry.register({\n * lexicon: 1,\n * id: \"org.myapp.customRecord\",\n * defs: { ... },\n * });\n *\n * // Validate a record\n * const result = registry.validate(\"org.myapp.customRecord\", record);\n * if (!result.valid) {\n * console.error(result.error);\n * }\n * ```\n *\n * @packageDocumentation\n */\n\n// Import lexicon JSON files and constants from the published package\nimport type { LexiconDoc } from \"@atproto/lexicon\";\nimport {\n CERTIFIED_DEFS_LEXICON_JSON,\n LOCATION_LEXICON_JSON,\n STRONG_REF_LEXICON_JSON,\n HYPERCERTS_DEFS_LEXICON_JSON,\n ACTIVITY_LEXICON_JSON,\n COLLECTION_LEXICON_JSON,\n CONTRIBUTION_DETAILS_LEXICON_JSON,\n CONTRIBUTOR_INFORMATION_LEXICON_JSON,\n EVALUATION_LEXICON_JSON,\n EVIDENCE_LEXICON_JSON,\n MEASUREMENT_LEXICON_JSON,\n RIGHTS_LEXICON_JSON,\n BADGE_AWARD_LEXICON_JSON,\n BADGE_DEFINITION_LEXICON_JSON,\n BADGE_RESPONSE_LEXICON_JSON,\n FUNDING_RECEIPT_LEXICON_JSON,\n WORK_SCOPE_TAG_LEXICON_JSON,\n // NSID constants\n ACTIVITY_NSID,\n RIGHTS_NSID,\n LOCATION_NSID,\n CONTRIBUTION_DETAILS_NSID,\n CONTRIBUTOR_INFORMATION_NSID,\n MEASUREMENT_NSID,\n EVALUATION_NSID,\n EVIDENCE_NSID,\n COLLECTION_NSID,\n BADGE_AWARD_NSID,\n BADGE_DEFINITION_NSID,\n BADGE_RESPONSE_NSID,\n FUNDING_RECEIPT_NSID,\n WORK_SCOPE_TAG_NSID,\n} from \"@hypercerts-org/lexicon\";\n\n// Export LexiconRegistry for custom lexicon management\nexport { LexiconRegistry } from \"./repository/LexiconRegistry.js\";\nexport type { ValidationResult } from \"./repository/LexiconRegistry.js\";\n\n/**\n * All hypercert-related lexicons for registration with AT Protocol Agent.\n * This array contains all lexicon documents from the published package.\n */\nexport const HYPERCERT_LEXICONS: LexiconDoc[] = [\n CERTIFIED_DEFS_LEXICON_JSON as LexiconDoc,\n LOCATION_LEXICON_JSON as LexiconDoc,\n STRONG_REF_LEXICON_JSON as LexiconDoc,\n HYPERCERTS_DEFS_LEXICON_JSON as LexiconDoc,\n ACTIVITY_LEXICON_JSON as LexiconDoc,\n COLLECTION_LEXICON_JSON as LexiconDoc,\n CONTRIBUTION_DETAILS_LEXICON_JSON as LexiconDoc,\n CONTRIBUTOR_INFORMATION_LEXICON_JSON as LexiconDoc,\n EVALUATION_LEXICON_JSON as LexiconDoc,\n EVIDENCE_LEXICON_JSON as LexiconDoc,\n MEASUREMENT_LEXICON_JSON as LexiconDoc,\n RIGHTS_LEXICON_JSON as LexiconDoc,\n BADGE_AWARD_LEXICON_JSON as LexiconDoc,\n BADGE_DEFINITION_LEXICON_JSON as LexiconDoc,\n BADGE_RESPONSE_LEXICON_JSON as LexiconDoc,\n FUNDING_RECEIPT_LEXICON_JSON as LexiconDoc,\n WORK_SCOPE_TAG_LEXICON_JSON as LexiconDoc,\n];\n\n/**\n * Collection NSIDs (Namespaced Identifiers) for hypercert records.\n *\n * Use these constants when performing record operations to ensure\n * correct collection names.\n */\nexport const HYPERCERT_COLLECTIONS = {\n /**\n * Main hypercert claim record collection.\n */\n CLAIM: ACTIVITY_NSID,\n\n /**\n * Rights record collection.\n */\n RIGHTS: RIGHTS_NSID,\n\n /**\n * Location record collection (shared certified lexicon).\n */\n LOCATION: LOCATION_NSID,\n\n /**\n * Contribution details record collection.\n * For storing details about a specific contribution (role, description, timeframe).\n */\n CONTRIBUTION_DETAILS: CONTRIBUTION_DETAILS_NSID,\n\n /**\n * Contributor information record collection.\n * For storing contributor profile information (identifier, displayName, image).\n */\n CONTRIBUTOR_INFORMATION: CONTRIBUTOR_INFORMATION_NSID,\n\n /**\n * Measurement record collection.\n */\n MEASUREMENT: MEASUREMENT_NSID,\n\n /**\n * Evaluation record collection.\n */\n EVALUATION: EVALUATION_NSID,\n\n /**\n * Evidence record collection.\n */\n EVIDENCE: EVIDENCE_NSID,\n\n /**\n * Collection record collection (groups of hypercerts).\n * Projects are now collections with type='project'.\n */\n COLLECTION: COLLECTION_NSID,\n\n /**\n * Badge award record collection.\n */\n BADGE_AWARD: BADGE_AWARD_NSID,\n\n /**\n * Badge definition record collection.\n */\n BADGE_DEFINITION: BADGE_DEFINITION_NSID,\n\n /**\n * Badge response record collection.\n */\n BADGE_RESPONSE: BADGE_RESPONSE_NSID,\n\n /**\n * Funding receipt record collection.\n */\n FUNDING_RECEIPT: FUNDING_RECEIPT_NSID,\n\n /**\n * Work scope tag record collection.\n * For defining reusable work scope atoms.\n */\n WORK_SCOPE_TAG: WORK_SCOPE_TAG_NSID,\n} as const;\n"],"names":[],"mappings":"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"}
package/dist/testing.d.ts CHANGED
@@ -348,22 +348,28 @@ interface LoggerInterface {
348
348
  * Zod schema for OAuth configuration validation.
349
349
  *
350
350
  * @remarks
351
- * All URLs must be valid and use HTTPS in production. The `jwkPrivate` field
352
- * should contain the private key in JWK (JSON Web Key) format as a string.
351
+ * All URLs must be valid and use HTTPS in production. For local development,
352
+ * HTTP loopback URLs (localhost, 127.0.0.1, [::1]) are allowed.
353
+ * The `jwkPrivate` field should contain the private key in JWK (JSON Web Key) format as a string.
353
354
  */
354
355
  declare const OAuthConfigSchema: z.ZodObject<{
355
356
  /**
356
357
  * URL to the OAuth client metadata JSON document.
357
358
  * This document describes your application to the authorization server.
358
359
  *
360
+ * For local development, you can use `http://localhost/` as a loopback client.
361
+ *
359
362
  * @see https://atproto.com/specs/oauth#client-metadata
360
363
  */
361
- clientId: z.ZodString;
364
+ clientId: z.ZodEffects<z.ZodString, string, string>;
362
365
  /**
363
366
  * URL where users are redirected after authentication.
364
367
  * Must match one of the redirect URIs in your client metadata.
368
+ *
369
+ * For local development, you can use HTTP loopback URLs like
370
+ * `http://127.0.0.1:3000/callback` or `http://localhost:3000/callback`.
365
371
  */
366
- redirectUri: z.ZodString;
372
+ redirectUri: z.ZodEffects<z.ZodString, string, string>;
367
373
  /**
368
374
  * OAuth scopes to request, space-separated.
369
375
  *
@@ -397,8 +403,11 @@ declare const OAuthConfigSchema: z.ZodObject<{
397
403
  /**
398
404
  * URL to your public JWKS (JSON Web Key Set) endpoint.
399
405
  * Used by the authorization server to verify your client's signatures.
406
+ *
407
+ * For local development, you can serve JWKS from a loopback URL like
408
+ * `http://127.0.0.1:3000/.well-known/jwks.json`.
400
409
  */
401
- jwksUri: z.ZodString;
410
+ jwksUri: z.ZodEffects<z.ZodString, string, string>;
402
411
  /**
403
412
  * Private JWK (JSON Web Key) as a JSON string.
404
413
  * Used for signing DPoP proofs and client assertions.
@@ -408,40 +417,78 @@ declare const OAuthConfigSchema: z.ZodObject<{
408
417
  * Typically loaded from environment variables or a secrets manager.
409
418
  */
410
419
  jwkPrivate: z.ZodString;
420
+ /**
421
+ * Enable development mode features (optional).
422
+ *
423
+ * When true, suppresses warnings about using HTTP loopback URLs.
424
+ * Should be set to true for local development to reduce console noise.
425
+ *
426
+ * @default false
427
+ *
428
+ * @example
429
+ * ```typescript
430
+ * oauth: {
431
+ * clientId: "http://localhost/",
432
+ * redirectUri: "http://127.0.0.1:3000/callback",
433
+ * // ... other config
434
+ * developmentMode: true, // Suppress loopback warnings
435
+ * }
436
+ * ```
437
+ */
438
+ developmentMode: z.ZodOptional<z.ZodBoolean>;
411
439
  }, "strip", z.ZodTypeAny, {
412
440
  clientId: string;
413
441
  redirectUri: string;
414
442
  scope: string;
415
443
  jwksUri: string;
416
444
  jwkPrivate: string;
445
+ developmentMode?: boolean | undefined;
417
446
  }, {
418
447
  clientId: string;
419
448
  redirectUri: string;
420
449
  scope: string;
421
450
  jwksUri: string;
422
451
  jwkPrivate: string;
452
+ developmentMode?: boolean | undefined;
423
453
  }>;
424
454
  /**
425
455
  * Zod schema for server URL configuration.
426
456
  *
427
457
  * @remarks
428
458
  * At least one server (PDS or SDS) should be configured for the SDK to be useful.
459
+ * For local development, HTTP loopback URLs are allowed.
429
460
  */
430
461
  declare const ServerConfigSchema: z.ZodObject<{
431
462
  /**
432
463
  * Personal Data Server URL - the user's own AT Protocol server.
433
464
  * This is the primary server for user data operations.
434
465
  *
435
- * @example "https://bsky.social"
466
+ * @example Production
467
+ * ```typescript
468
+ * pds: "https://bsky.social"
469
+ * ```
470
+ *
471
+ * @example Local development
472
+ * ```typescript
473
+ * pds: "http://localhost:2583"
474
+ * ```
436
475
  */
437
- pds: z.ZodOptional<z.ZodString>;
476
+ pds: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
438
477
  /**
439
478
  * Shared Data Server URL - for collaborative data storage.
440
479
  * Required for collaborator and organization operations.
441
480
  *
442
- * @example "https://sds.hypercerts.org"
481
+ * @example Production
482
+ * ```typescript
483
+ * sds: "https://sds.hypercerts.org"
484
+ * ```
485
+ *
486
+ * @example Local development
487
+ * ```typescript
488
+ * sds: "http://127.0.0.1:2584"
489
+ * ```
443
490
  */
444
- sds: z.ZodOptional<z.ZodString>;
491
+ sds: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
445
492
  }, "strip", z.ZodTypeAny, {
446
493
  pds?: string | undefined;
447
494
  sds?: string | undefined;