@hypercerts-org/sdk-core 0.10.0-beta.8 → 0.10.0-beta.9
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/CHANGELOG.md +332 -0
- package/README.md +168 -78
- package/dist/index.cjs +1692 -1282
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +546 -179
- package/dist/index.mjs +1691 -1286
- package/dist/index.mjs.map +1 -1
- package/dist/lexicons.cjs +9 -0
- package/dist/lexicons.cjs.map +1 -1
- package/dist/lexicons.d.ts +8 -0
- package/dist/lexicons.mjs +10 -1
- package/dist/lexicons.mjs.map +1 -1
- package/dist/testing.cjs +11 -5
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.ts +25 -28
- package/dist/testing.mjs +11 -5
- package/dist/testing.mjs.map +1 -1
- package/dist/types.cjs +15 -16
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.ts +332 -143
- package/dist/types.mjs +15 -16
- package/dist/types.mjs.map +1 -1
- package/package.json +8 -4
package/dist/lexicons.cjs
CHANGED
|
@@ -480,6 +480,7 @@ const HYPERCERT_LEXICONS = [
|
|
|
480
480
|
lexicon$1.ATTACHMENT_LEXICON_JSON,
|
|
481
481
|
lexicon$1.MEASUREMENT_LEXICON_JSON,
|
|
482
482
|
lexicon$1.RIGHTS_LEXICON_JSON,
|
|
483
|
+
lexicon$1.ACTOR_PROFILE_LEXICON_JSON,
|
|
483
484
|
lexicon$1.BADGE_AWARD_LEXICON_JSON,
|
|
484
485
|
lexicon$1.BADGE_DEFINITION_LEXICON_JSON,
|
|
485
486
|
lexicon$1.BADGE_RESPONSE_LEXICON_JSON,
|
|
@@ -553,6 +554,14 @@ const HYPERCERT_COLLECTIONS = {
|
|
|
553
554
|
* For defining reusable work scope atoms.
|
|
554
555
|
*/
|
|
555
556
|
WORK_SCOPE_TAG: lexicon$1.WORK_SCOPE_TAG_NSID,
|
|
557
|
+
/**
|
|
558
|
+
* Bluesky profile collection (app.bsky.actor.profile).
|
|
559
|
+
*/
|
|
560
|
+
BSKY_PROFILE: "app.bsky.actor.profile",
|
|
561
|
+
/**
|
|
562
|
+
* Certified profile collection (app.certified.actor.profile).
|
|
563
|
+
*/
|
|
564
|
+
CERTIFIED_PROFILE: lexicon$1.ACTOR_PROFILE_NSID,
|
|
556
565
|
};
|
|
557
566
|
|
|
558
567
|
exports.HYPERCERT_COLLECTIONS = HYPERCERT_COLLECTIONS;
|
package/dist/lexicons.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lexicons.cjs","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 ATTACHMENT_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 ATTACHMENT_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 ATTACHMENT_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 * Attachment record collection.\n */\n ATTACHMENT: ATTACHMENT_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":["Lexicons","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","ATTACHMENT_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","ACTIVITY_NSID","RIGHTS_NSID","LOCATION_NSID","CONTRIBUTION_DETAILS_NSID","CONTRIBUTOR_INFORMATION_NSID","MEASUREMENT_NSID","EVALUATION_NSID","ATTACHMENT_NSID","COLLECTION_NSID","BADGE_AWARD_NSID","BADGE_DEFINITION_NSID","BADGE_RESPONSE_NSID","FUNDING_RECEIPT_NSID","WORK_SCOPE_TAG_NSID"],"mappings":";;;;;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCG;AACG,MAAO,eAAgB,SAAQ,KAAK,CAAA;AACxC;;;;;;;AAOG;AACH,IAAA,WAAA,CACE,OAAe,EACR,IAAY,EACZ,MAAe,EACf,KAAe,EAAA;QAEtB,KAAK,CAAC,OAAO,CAAC;QAJP,IAAA,CAAA,IAAI,GAAJ,IAAI;QACJ,IAAA,CAAA,MAAM,GAAN,MAAM;QACN,IAAA,CAAA,KAAK,GAAL,KAAK;AAGZ,QAAA,IAAI,CAAC,IAAI,GAAG,iBAAiB;QAC7B,KAAK,CAAC,iBAAiB,GAAG,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC;IACnD;AACD;AAyED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCG;AACG,MAAO,eAAgB,SAAQ,eAAe,CAAA;AAClD;;;;;AAKG;IACH,WAAA,CAAY,OAAe,EAAE,KAAe,EAAA;QAC1C,KAAK,CAAC,OAAO,EAAE,kBAAkB,EAAE,GAAG,EAAE,KAAK,CAAC;AAC9C,QAAA,IAAI,CAAC,IAAI,GAAG,iBAAiB;IAC/B;AACD;;ACpLD;;;;;;;;AAQG;AAsBH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CG;MACU,eAAe,CAAA;AAI1B;;;;AAIG;AACH,IAAA,WAAA,CAAY,eAA8B,EAAA;AACxC,QAAA,IAAI,CAAC,QAAQ,GAAG,IAAIA,gBAAQ,EAAE;AAC9B,QAAA,IAAI,CAAC,aAAa,GAAG,IAAI,GAAG,EAAE;QAE9B,IAAI,eAAe,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE;AACjD,YAAA,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC;QACpC;IACF;AAEA;;;;;;;;;;;;;;AAcG;AACH,IAAA,QAAQ,CAAC,OAAmB,EAAA;AAC1B,QAAA,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE;AACf,YAAA,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC;QAC5C;QAEA,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE;YACtC,MAAM,IAAI,KAAK,CAAC,CAAA,QAAA,EAAW,OAAO,CAAC,EAAE,CAAA,sBAAA,CAAwB,CAAC;QAChE;AAEA,QAAA,IAAI;;;AAGF,YAAA,MAAM,eAAe,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YAErD,IAAI,CAAC,eAAe,EAAE;;AAEpB,gBAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC;YAC5B;;YAGA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC;QAAE,OAAO,KAAK,EAAE;YACd,MAAM,IAAI,KAAK,CACb,CAAA,2BAAA,EAA8B,OAAO,CAAC,EAAE,CAAA,EAAA,EAAK,KAAK,YAAY,KAAK,GAAG,KAAK,CAAC,OAAO,GAAG,eAAe,CAAA,CAAE,CACxG;QACH;IACF;AAEA;;;;;;;;;;AAUG;AACH,IAAA,YAAY,CAAC,QAAsB,EAAA;AACjC,QAAA,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;AAC9B,YAAA,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;QACxB;IACF;AAEA;;;;;;;;;;;;;;AAcG;AACH,IAAA,gBAAgB,CAAC,WAAoB,EAAA;;QAEnC,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,KAAK,IAAI,EAAE;AAC3D,YAAA,MAAM,IAAI,eAAe,CAAC,qCAAqC,CAAC;QAClE;;AAGA,QAAA,IAAI,CAAC,QAAQ,CAAC,WAAyB,CAAC;IAC1C;AAEA;;;;;;;;;;AAUG;AACH,IAAA,UAAU,CAAC,IAAY,EAAA;QACrB,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;AACjC,YAAA,OAAO,KAAK;QACd;AAEA,QAAA,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC;;;;AAI/B,QAAA,OAAO,IAAI;IACb;AAEA;;;;;;;;;;;;AAYG;AACH,IAAA,YAAY,CAAC,IAAY,EAAA;QACvB,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;IACrC;AAEA;;;;;;;;;;;;;AAaG;AACH,IAAA,GAAG,CAAC,IAAY,EAAA;QACd,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE;AAC5B,YAAA,OAAO,SAAS;QAClB;QAEA,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;IAChC;AAEA;;;;;;;;;;AAUG;IACH,MAAM,GAAA;QACJ,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC;IACvC;AAEA;;;;;;;;;;;;;;;;;;AAkBG;IACH,QAAQ,CAAC,IAAY,EAAE,MAAe,EAAA;QACpC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE;YAC5B,OAAO;AACL,gBAAA,KAAK,EAAE,KAAK;gBACZ,KAAK,EAAE,CAAA,QAAA,EAAW,IAAI,CAAA,kBAAA,CAAoB;aAC3C;QACH;AAEA,QAAA,IAAI;YACF,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC;AAC7C,YAAA,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE;QACxB;QAAE,OAAO,KAAK,EAAE;YACd,OAAO;AACL,gBAAA,KAAK,EAAE,KAAK;AACZ,gBAAA,KAAK,EAAE,KAAK,YAAY,KAAK,GAAG,KAAK,CAAC,OAAO,GAAG,mBAAmB;aACpE;QACH;IACF;AAEA;;;;;;;;;;;;;;;;;;AAkBG;AACH,IAAA,UAAU,CAAC,MAAa,EAAA;;;;IAIxB;AAEA;;;;;;;;;;;;;AAaG;IACH,WAAW,GAAA;QACT,OAAO,IAAI,CAAC,QAAQ;IACtB;AACD;;AC9UD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0DG;AA2CH;;;AAGG;AACI,MAAM,kBAAkB,GAAiB;IAC9CC,qCAAyC;IACzCC,+BAAmC;IACnCC,iCAAqC;IACrCC,sCAA0C;IAC1CC,+BAAmC;IACnCC,iCAAqC;IACrCC,2CAA+C;IAC/CC,8CAAkD;IAClDC,iCAAqC;IACrCC,iCAAqC;IACrCC,kCAAsC;IACtCC,6BAAiC;IACjCC,kCAAsC;IACtCC,uCAA2C;IAC3CC,qCAAyC;IACzCC,sCAA0C;IAC1CC,qCAAyC;;AAG3C;;;;;AAKG;AACI,MAAM,qBAAqB,GAAG;AACnC;;AAEG;AACH,IAAA,KAAK,EAAEC,uBAAa;AAEpB;;AAEG;AACH,IAAA,MAAM,EAAEC,qBAAW;AAEnB;;AAEG;AACH,IAAA,QAAQ,EAAEC,uBAAa;AAEvB;;;AAGG;AACH,IAAA,oBAAoB,EAAEC,mCAAyB;AAE/C;;;AAGG;AACH,IAAA,uBAAuB,EAAEC,sCAA4B;AAErD;;AAEG;AACH,IAAA,WAAW,EAAEC,0BAAgB;AAE7B;;AAEG;AACH,IAAA,UAAU,EAAEC,yBAAe;AAE3B;;AAEG;AACH,IAAA,UAAU,EAAEC,yBAAe;AAE3B;;;AAGG;AACH,IAAA,UAAU,EAAEC,yBAAe;AAE3B;;AAEG;AACH,IAAA,WAAW,EAAEC,0BAAgB;AAE7B;;AAEG;AACH,IAAA,gBAAgB,EAAEC,+BAAqB;AAEvC;;AAEG;AACH,IAAA,cAAc,EAAEC,6BAAmB;AAEnC;;AAEG;AACH,IAAA,eAAe,EAAEC,8BAAoB;AAErC;;;AAGG;AACH,IAAA,cAAc,EAAEC,6BAAmB;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"lexicons.cjs","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 ATTACHMENT_LEXICON_JSON,\n MEASUREMENT_LEXICON_JSON,\n RIGHTS_LEXICON_JSON,\n ACTOR_PROFILE_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 ATTACHMENT_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 ACTOR_PROFILE_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 ATTACHMENT_LEXICON_JSON as LexiconDoc,\n MEASUREMENT_LEXICON_JSON as LexiconDoc,\n RIGHTS_LEXICON_JSON as LexiconDoc,\n ACTOR_PROFILE_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 * Attachment record collection.\n */\n ATTACHMENT: ATTACHMENT_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\n /**\n * Bluesky profile collection (app.bsky.actor.profile).\n */\n BSKY_PROFILE: \"app.bsky.actor.profile\",\n\n /**\n * Certified profile collection (app.certified.actor.profile).\n */\n CERTIFIED_PROFILE: ACTOR_PROFILE_NSID,\n} as const;\n"],"names":["Lexicons","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","ATTACHMENT_LEXICON_JSON","MEASUREMENT_LEXICON_JSON","RIGHTS_LEXICON_JSON","ACTOR_PROFILE_LEXICON_JSON","BADGE_AWARD_LEXICON_JSON","BADGE_DEFINITION_LEXICON_JSON","BADGE_RESPONSE_LEXICON_JSON","FUNDING_RECEIPT_LEXICON_JSON","WORK_SCOPE_TAG_LEXICON_JSON","ACTIVITY_NSID","RIGHTS_NSID","LOCATION_NSID","CONTRIBUTION_DETAILS_NSID","CONTRIBUTOR_INFORMATION_NSID","MEASUREMENT_NSID","EVALUATION_NSID","ATTACHMENT_NSID","COLLECTION_NSID","BADGE_AWARD_NSID","BADGE_DEFINITION_NSID","BADGE_RESPONSE_NSID","FUNDING_RECEIPT_NSID","WORK_SCOPE_TAG_NSID","ACTOR_PROFILE_NSID"],"mappings":"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"}
|
package/dist/lexicons.d.ts
CHANGED
|
@@ -363,6 +363,14 @@ declare const HYPERCERT_COLLECTIONS: {
|
|
|
363
363
|
* For defining reusable work scope atoms.
|
|
364
364
|
*/
|
|
365
365
|
readonly WORK_SCOPE_TAG: "org.hypercerts.helper.workScopeTag";
|
|
366
|
+
/**
|
|
367
|
+
* Bluesky profile collection (app.bsky.actor.profile).
|
|
368
|
+
*/
|
|
369
|
+
readonly BSKY_PROFILE: "app.bsky.actor.profile";
|
|
370
|
+
/**
|
|
371
|
+
* Certified profile collection (app.certified.actor.profile).
|
|
372
|
+
*/
|
|
373
|
+
readonly CERTIFIED_PROFILE: "app.certified.actor.profile";
|
|
366
374
|
};
|
|
367
375
|
|
|
368
376
|
export { HYPERCERT_COLLECTIONS, HYPERCERT_LEXICONS, LexiconRegistry };
|
package/dist/lexicons.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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, ATTACHMENT_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, ATTACHMENT_NSID, EVALUATION_NSID, MEASUREMENT_NSID, CONTRIBUTOR_INFORMATION_NSID, CONTRIBUTION_DETAILS_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, ATTACHMENT_LEXICON_JSON, MEASUREMENT_LEXICON_JSON, RIGHTS_LEXICON_JSON, ACTOR_PROFILE_LEXICON_JSON, BADGE_AWARD_LEXICON_JSON, BADGE_DEFINITION_LEXICON_JSON, BADGE_RESPONSE_LEXICON_JSON, FUNDING_RECEIPT_LEXICON_JSON, WORK_SCOPE_TAG_LEXICON_JSON, ACTOR_PROFILE_NSID, WORK_SCOPE_TAG_NSID, FUNDING_RECEIPT_NSID, BADGE_RESPONSE_NSID, BADGE_DEFINITION_NSID, BADGE_AWARD_NSID, COLLECTION_NSID, ATTACHMENT_NSID, EVALUATION_NSID, MEASUREMENT_NSID, CONTRIBUTOR_INFORMATION_NSID, CONTRIBUTION_DETAILS_NSID, LOCATION_NSID, RIGHTS_NSID, ACTIVITY_NSID } from '@hypercerts-org/lexicon';
|
|
2
2
|
import { Lexicons } from '@atproto/lexicon';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -478,6 +478,7 @@ const HYPERCERT_LEXICONS = [
|
|
|
478
478
|
ATTACHMENT_LEXICON_JSON,
|
|
479
479
|
MEASUREMENT_LEXICON_JSON,
|
|
480
480
|
RIGHTS_LEXICON_JSON,
|
|
481
|
+
ACTOR_PROFILE_LEXICON_JSON,
|
|
481
482
|
BADGE_AWARD_LEXICON_JSON,
|
|
482
483
|
BADGE_DEFINITION_LEXICON_JSON,
|
|
483
484
|
BADGE_RESPONSE_LEXICON_JSON,
|
|
@@ -551,6 +552,14 @@ const HYPERCERT_COLLECTIONS = {
|
|
|
551
552
|
* For defining reusable work scope atoms.
|
|
552
553
|
*/
|
|
553
554
|
WORK_SCOPE_TAG: WORK_SCOPE_TAG_NSID,
|
|
555
|
+
/**
|
|
556
|
+
* Bluesky profile collection (app.bsky.actor.profile).
|
|
557
|
+
*/
|
|
558
|
+
BSKY_PROFILE: "app.bsky.actor.profile",
|
|
559
|
+
/**
|
|
560
|
+
* Certified profile collection (app.certified.actor.profile).
|
|
561
|
+
*/
|
|
562
|
+
CERTIFIED_PROFILE: ACTOR_PROFILE_NSID,
|
|
554
563
|
};
|
|
555
564
|
|
|
556
565
|
export { HYPERCERT_COLLECTIONS, HYPERCERT_LEXICONS, LexiconRegistry };
|
package/dist/lexicons.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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 ATTACHMENT_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 ATTACHMENT_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 ATTACHMENT_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 * Attachment record collection.\n */\n ATTACHMENT: ATTACHMENT_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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"}
|
|
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 ATTACHMENT_LEXICON_JSON,\n MEASUREMENT_LEXICON_JSON,\n RIGHTS_LEXICON_JSON,\n ACTOR_PROFILE_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 ATTACHMENT_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 ACTOR_PROFILE_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 ATTACHMENT_LEXICON_JSON as LexiconDoc,\n MEASUREMENT_LEXICON_JSON as LexiconDoc,\n RIGHTS_LEXICON_JSON as LexiconDoc,\n ACTOR_PROFILE_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 * Attachment record collection.\n */\n ATTACHMENT: ATTACHMENT_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\n /**\n * Bluesky profile collection (app.bsky.actor.profile).\n */\n BSKY_PROFILE: \"app.bsky.actor.profile\",\n\n /**\n * Certified profile collection (app.certified.actor.profile).\n */\n CERTIFIED_PROFILE: ACTOR_PROFILE_NSID,\n} as const;\n"],"names":[],"mappings":"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"}
|
package/dist/testing.cjs
CHANGED
|
@@ -67,6 +67,14 @@ function createMockSession(overrides = {}) {
|
|
|
67
67
|
headers: { "Content-Type": "application/json" },
|
|
68
68
|
});
|
|
69
69
|
},
|
|
70
|
+
getTokenInfo: async () => ({
|
|
71
|
+
expiresAt: new Date(Date.now() + 3600 * 1000),
|
|
72
|
+
expired: false,
|
|
73
|
+
scope: "atproto",
|
|
74
|
+
iss: "https://bsky.social",
|
|
75
|
+
aud: "https://bsky.social",
|
|
76
|
+
sub: "did:plc:test123",
|
|
77
|
+
}),
|
|
70
78
|
...overrides,
|
|
71
79
|
};
|
|
72
80
|
return mockSession;
|
|
@@ -98,12 +106,10 @@ function createMockSession(overrides = {}) {
|
|
|
98
106
|
* const sdk = new ATProtoSDK(config);
|
|
99
107
|
* ```
|
|
100
108
|
*
|
|
101
|
-
* @example With custom
|
|
109
|
+
* @example With custom handle resolver
|
|
102
110
|
* ```typescript
|
|
103
111
|
* const config = createTestConfig({
|
|
104
|
-
*
|
|
105
|
-
* pds: "https://custom-pds.example.com",
|
|
106
|
-
* },
|
|
112
|
+
* handleResolver: "https://custom-resolver.example.com",
|
|
107
113
|
* });
|
|
108
114
|
* ```
|
|
109
115
|
*
|
|
@@ -129,8 +135,8 @@ function createTestConfig(overrides = {}) {
|
|
|
129
135
|
d: "test",
|
|
130
136
|
}),
|
|
131
137
|
},
|
|
138
|
+
handleResolver: "https://pds-eu-west4.test.certified.app",
|
|
132
139
|
servers: {
|
|
133
|
-
pds: "https://bsky.social",
|
|
134
140
|
sds: "https://sds.example.com",
|
|
135
141
|
},
|
|
136
142
|
...overrides,
|
package/dist/testing.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.cjs","sources":["../src/testing/mocks.ts","../src/testing/stores.ts"],"sourcesContent":["/**\n * Mock factories for testing.\n *\n * This module provides factory functions to create mock objects\n * for testing SDK functionality without real AT Protocol connections.\n *\n * @packageDocumentation\n */\n\nimport type { Session } from \"../core/types.js\";\nimport type { ATProtoSDKConfig } from \"../core/config.js\";\n\n/**\n * Creates a mock OAuth session for testing.\n *\n * The mock session includes all required properties and a mock\n * `fetchHandler` that returns empty successful responses by default.\n *\n * @param overrides - Partial session object to override default values\n * @returns A mock Session object suitable for testing\n *\n * @remarks\n * The mock session is cast to `Session` type for compatibility.\n * In real usage, sessions come from the OAuth flow and contain\n * actual tokens and a real fetch handler.\n *\n * **Default Values**:\n * - `did`: `\"did:plc:test123\"`\n * - `handle`: `\"test.bsky.social\"`\n * - `fetchHandler`: Returns `Response` with `{}` body\n *\n * @example Basic mock session\n * ```typescript\n * import { createMockSession } from \"@hypercerts-org/sdk/testing\";\n *\n * const session = createMockSession();\n * const repo = sdk.repository(session);\n * ```\n *\n * @example With custom DID\n * ```typescript\n * const session = createMockSession({\n * did: \"did:plc:custom-test-user\",\n * handle: \"custom.bsky.social\",\n * });\n * ```\n *\n * @example With custom fetch handler\n * ```typescript\n * const session = createMockSession({\n * fetchHandler: async (url, init) => {\n * // Custom response logic\n * return new Response(JSON.stringify({ success: true }));\n * },\n * });\n * ```\n */\nexport function createMockSession(overrides: Partial<Session> = {}): Session {\n const mockSession = {\n did: \"did:plc:test123\",\n sub: \"did:plc:test123\",\n handle: \"test.bsky.social\",\n accessJwt: \"mock-access-jwt\",\n refreshJwt: \"mock-refresh-jwt\",\n active: true,\n fetchHandler: async (_input: RequestInfo | URL, _init?: RequestInit) => {\n return new Response(JSON.stringify({}), {\n status: 200,\n headers: { \"Content-Type\": \"application/json\" },\n });\n },\n ...overrides,\n } as unknown as Session;\n\n return mockSession;\n}\n\n/**\n * Creates a mock SDK configuration for testing.\n *\n * The configuration includes all required OAuth settings with\n * placeholder values suitable for testing (not real credentials).\n *\n * @param overrides - Partial configuration to override default values\n * @returns A complete ATProtoSDKConfig suitable for testing\n *\n * @remarks\n * The default configuration uses example.com domains and a minimal\n * JWK structure. This is sufficient for unit tests but won't work\n * for integration tests that require real OAuth flows.\n *\n * **Default Values**:\n * - `clientId`: `\"https://test.example.com/client-metadata.json\"`\n * - `pds`: `\"https://bsky.social\"`\n * - `sds`: `\"https://sds.example.com\"`\n *\n * @example Basic test config\n * ```typescript\n * import { createTestConfig } from \"@hypercerts-org/sdk/testing\";\n *\n * const config = createTestConfig();\n * const sdk = new ATProtoSDK(config);\n * ```\n *\n * @example With custom PDS\n * ```typescript\n * const config = createTestConfig({\n * servers: {\n * pds: \"https://custom-pds.example.com\",\n * },\n * });\n * ```\n *\n * @example With logger for debugging tests\n * ```typescript\n * const config = createTestConfig({\n * logger: console,\n * });\n * ```\n */\nexport function createTestConfig(overrides: Partial<ATProtoSDKConfig> = {}): ATProtoSDKConfig {\n return {\n oauth: {\n clientId: \"https://test.example.com/client-metadata.json\",\n redirectUri: \"https://test.example.com/callback\",\n scope: \"atproto transition:generic\",\n jwksUri: \"https://test.example.com/jwks.json\",\n jwkPrivate: JSON.stringify({\n kty: \"EC\",\n crv: \"P-256\",\n x: \"test\",\n y: \"test\",\n d: \"test\",\n }),\n },\n servers: {\n pds: \"https://bsky.social\",\n sds: \"https://sds.example.com\",\n },\n ...overrides,\n };\n}\n","/**\n * Mock storage implementations for testing.\n *\n * This module provides mock implementations of SessionStore and StateStore\n * that track all operations for verification in tests.\n *\n * @packageDocumentation\n */\n\nimport type { SessionStore, StateStore } from \"../core/interfaces.js\";\nimport type { NodeSavedSession, NodeSavedState } from \"@atproto/oauth-client-node\";\n\n/**\n * Mock session store that tracks all operations.\n *\n * This implementation stores sessions in memory and records all\n * method calls for verification in tests.\n *\n * @remarks\n * Use this in tests to:\n * - Verify that sessions are being stored correctly\n * - Check what DIDs have been accessed\n * - Assert on the number and order of operations\n * - Pre-populate sessions for testing restore flows\n *\n * @example Basic usage\n * ```typescript\n * import { MockSessionStore } from \"@hypercerts-org/sdk/testing\";\n *\n * const sessionStore = new MockSessionStore();\n * const sdk = new ATProtoSDK({\n * ...config,\n * storage: { sessionStore },\n * });\n *\n * // After some operations...\n * expect(sessionStore.setCalls).toHaveLength(1);\n * expect(sessionStore.getCalls).toContain(\"did:plc:test123\");\n * ```\n *\n * @example Pre-populating for tests\n * ```typescript\n * const sessionStore = new MockSessionStore();\n *\n * // Pre-populate a session\n * await sessionStore.set(\"did:plc:existing\", mockSessionData);\n *\n * // Reset tracking (keeps the data)\n * sessionStore.getCalls = [];\n * sessionStore.setCalls = [];\n *\n * // Now test restore behavior\n * const session = await sdk.restoreSession(\"did:plc:existing\");\n * expect(sessionStore.getCalls).toContain(\"did:plc:existing\");\n * ```\n *\n * @example Asserting on operations\n * ```typescript\n * const sessionStore = new MockSessionStore();\n *\n * // ... perform operations ...\n *\n * // Verify session was stored for correct DID\n * expect(sessionStore.setCalls[0].did).toBe(\"did:plc:expected\");\n *\n * // Verify session was deleted on logout\n * expect(sessionStore.delCalls).toContain(\"did:plc:logged-out\");\n * ```\n */\nexport class MockSessionStore implements SessionStore {\n /**\n * Internal storage for sessions.\n * @internal\n */\n private store = new Map<string, NodeSavedSession>();\n\n /**\n * Record of all `get()` calls made to this store.\n *\n * Each entry is the DID that was requested.\n */\n public getCalls: string[] = [];\n\n /**\n * Record of all `set()` calls made to this store.\n *\n * Each entry contains the DID and session that was stored.\n */\n public setCalls: Array<{ did: string; session: NodeSavedSession }> = [];\n\n /**\n * Record of all `del()` calls made to this store.\n *\n * Each entry is the DID that was deleted.\n */\n public delCalls: string[] = [];\n\n /**\n * Retrieves a session by DID.\n *\n * Records the call in `getCalls`.\n *\n * @param did - The DID to look up\n * @returns The stored session or undefined\n */\n async get(did: string): Promise<NodeSavedSession | undefined> {\n this.getCalls.push(did);\n return this.store.get(did);\n }\n\n /**\n * Stores a session.\n *\n * Records the call in `setCalls`.\n *\n * @param did - The DID to store under\n * @param session - The session data to store\n */\n async set(did: string, session: NodeSavedSession): Promise<void> {\n this.setCalls.push({ did, session });\n this.store.set(did, session);\n }\n\n /**\n * Deletes a session.\n *\n * Records the call in `delCalls`.\n *\n * @param did - The DID to delete\n */\n async del(did: string): Promise<void> {\n this.delCalls.push(did);\n this.store.delete(did);\n }\n\n /**\n * Resets the store to initial state.\n *\n * Clears all stored sessions and all recorded calls.\n * Call this in `beforeEach` or `afterEach` to ensure test isolation.\n *\n * @example\n * ```typescript\n * beforeEach(() => {\n * sessionStore.reset();\n * });\n * ```\n */\n reset(): void {\n this.store.clear();\n this.getCalls = [];\n this.setCalls = [];\n this.delCalls = [];\n }\n}\n\n/**\n * Mock state store that tracks all operations.\n *\n * This implementation stores OAuth state in memory and records all\n * method calls for verification in tests.\n *\n * @remarks\n * Use this in tests to:\n * - Verify OAuth state is being created during authorization\n * - Check that state is retrieved during callback\n * - Assert that state is cleaned up after use\n * - Test error handling for missing/invalid state\n *\n * @example Basic usage\n * ```typescript\n * import { MockStateStore } from \"@hypercerts-org/sdk/testing\";\n *\n * const stateStore = new MockStateStore();\n * const sdk = new ATProtoSDK({\n * ...config,\n * storage: { stateStore },\n * });\n *\n * // After authorize()\n * expect(stateStore.setCalls).toHaveLength(1);\n *\n * // After callback()\n * expect(stateStore.getCalls).toHaveLength(1);\n * expect(stateStore.delCalls).toHaveLength(1);\n * ```\n *\n * @example Testing invalid state\n * ```typescript\n * const stateStore = new MockStateStore();\n * // Don't pre-populate - state will be missing\n *\n * // This should fail because state doesn't exist\n * await expect(sdk.callback(params)).rejects.toThrow();\n *\n * // Verify the lookup was attempted\n * expect(stateStore.getCalls).toContain(stateKey);\n * ```\n */\nexport class MockStateStore implements StateStore {\n /**\n * Internal storage for OAuth state.\n * @internal\n */\n private store = new Map<string, NodeSavedState>();\n\n /**\n * Record of all `get()` calls made to this store.\n *\n * Each entry is the state key that was requested.\n */\n public getCalls: string[] = [];\n\n /**\n * Record of all `set()` calls made to this store.\n *\n * Each entry contains the key and state that was stored.\n */\n public setCalls: Array<{ key: string; state: NodeSavedState }> = [];\n\n /**\n * Record of all `del()` calls made to this store.\n *\n * Each entry is the state key that was deleted.\n */\n public delCalls: string[] = [];\n\n /**\n * Retrieves OAuth state by key.\n *\n * Records the call in `getCalls`.\n *\n * @param key - The state key to look up\n * @returns The stored state or undefined\n */\n async get(key: string): Promise<NodeSavedState | undefined> {\n this.getCalls.push(key);\n return this.store.get(key);\n }\n\n /**\n * Stores OAuth state.\n *\n * Records the call in `setCalls`.\n *\n * @param key - The state key to store under\n * @param state - The OAuth state data to store\n */\n async set(key: string, state: NodeSavedState): Promise<void> {\n this.setCalls.push({ key, state });\n this.store.set(key, state);\n }\n\n /**\n * Deletes OAuth state.\n *\n * Records the call in `delCalls`.\n *\n * @param key - The state key to delete\n */\n async del(key: string): Promise<void> {\n this.delCalls.push(key);\n this.store.delete(key);\n }\n\n /**\n * Resets the store to initial state.\n *\n * Clears all stored state and all recorded calls.\n * Call this in `beforeEach` or `afterEach` to ensure test isolation.\n *\n * @example\n * ```typescript\n * beforeEach(() => {\n * stateStore.reset();\n * });\n * ```\n */\n reset(): void {\n this.store.clear();\n this.getCalls = [];\n this.setCalls = [];\n this.delCalls = [];\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"testing.cjs","sources":["../src/testing/mocks.ts","../src/testing/stores.ts"],"sourcesContent":["/**\n * Mock factories for testing.\n *\n * This module provides factory functions to create mock objects\n * for testing SDK functionality without real AT Protocol connections.\n *\n * @packageDocumentation\n */\n\nimport type { Session } from \"../core/types.js\";\nimport type { ATProtoSDKConfig } from \"../core/config.js\";\n\n/**\n * Creates a mock OAuth session for testing.\n *\n * The mock session includes all required properties and a mock\n * `fetchHandler` that returns empty successful responses by default.\n *\n * @param overrides - Partial session object to override default values\n * @returns A mock Session object suitable for testing\n *\n * @remarks\n * The mock session is cast to `Session` type for compatibility.\n * In real usage, sessions come from the OAuth flow and contain\n * actual tokens and a real fetch handler.\n *\n * **Default Values**:\n * - `did`: `\"did:plc:test123\"`\n * - `handle`: `\"test.bsky.social\"`\n * - `fetchHandler`: Returns `Response` with `{}` body\n *\n * @example Basic mock session\n * ```typescript\n * import { createMockSession } from \"@hypercerts-org/sdk/testing\";\n *\n * const session = createMockSession();\n * const repo = sdk.repository(session);\n * ```\n *\n * @example With custom DID\n * ```typescript\n * const session = createMockSession({\n * did: \"did:plc:custom-test-user\",\n * handle: \"custom.bsky.social\",\n * });\n * ```\n *\n * @example With custom fetch handler\n * ```typescript\n * const session = createMockSession({\n * fetchHandler: async (url, init) => {\n * // Custom response logic\n * return new Response(JSON.stringify({ success: true }));\n * },\n * });\n * ```\n */\nexport function createMockSession(overrides: Partial<Session> = {}): Session {\n const mockSession = {\n did: \"did:plc:test123\",\n sub: \"did:plc:test123\",\n handle: \"test.bsky.social\",\n accessJwt: \"mock-access-jwt\",\n refreshJwt: \"mock-refresh-jwt\",\n active: true,\n fetchHandler: async (_input: RequestInfo | URL, _init?: RequestInit) => {\n return new Response(JSON.stringify({}), {\n status: 200,\n headers: { \"Content-Type\": \"application/json\" },\n });\n },\n getTokenInfo: async () => ({\n expiresAt: new Date(Date.now() + 3600 * 1000),\n expired: false,\n scope: \"atproto\" as const,\n iss: \"https://bsky.social\",\n aud: \"https://bsky.social\",\n sub: \"did:plc:test123\",\n }),\n ...overrides,\n } as unknown as Session;\n\n return mockSession;\n}\n\n/**\n * Creates a mock SDK configuration for testing.\n *\n * The configuration includes all required OAuth settings with\n * placeholder values suitable for testing (not real credentials).\n *\n * @param overrides - Partial configuration to override default values\n * @returns A complete ATProtoSDKConfig suitable for testing\n *\n * @remarks\n * The default configuration uses example.com domains and a minimal\n * JWK structure. This is sufficient for unit tests but won't work\n * for integration tests that require real OAuth flows.\n *\n * **Default Values**:\n * - `clientId`: `\"https://test.example.com/client-metadata.json\"`\n * - `pds`: `\"https://bsky.social\"`\n * - `sds`: `\"https://sds.example.com\"`\n *\n * @example Basic test config\n * ```typescript\n * import { createTestConfig } from \"@hypercerts-org/sdk/testing\";\n *\n * const config = createTestConfig();\n * const sdk = new ATProtoSDK(config);\n * ```\n *\n * @example With custom handle resolver\n * ```typescript\n * const config = createTestConfig({\n * handleResolver: \"https://custom-resolver.example.com\",\n * });\n * ```\n *\n * @example With logger for debugging tests\n * ```typescript\n * const config = createTestConfig({\n * logger: console,\n * });\n * ```\n */\nexport function createTestConfig(overrides: Partial<ATProtoSDKConfig> = {}): ATProtoSDKConfig {\n return {\n oauth: {\n clientId: \"https://test.example.com/client-metadata.json\",\n redirectUri: \"https://test.example.com/callback\",\n scope: \"atproto transition:generic\",\n jwksUri: \"https://test.example.com/jwks.json\",\n jwkPrivate: JSON.stringify({\n kty: \"EC\",\n crv: \"P-256\",\n x: \"test\",\n y: \"test\",\n d: \"test\",\n }),\n },\n handleResolver: \"https://pds-eu-west4.test.certified.app\",\n servers: {\n sds: \"https://sds.example.com\",\n },\n ...overrides,\n };\n}\n","/**\n * Mock storage implementations for testing.\n *\n * This module provides mock implementations of SessionStore and StateStore\n * that track all operations for verification in tests.\n *\n * @packageDocumentation\n */\n\nimport type { SessionStore, StateStore } from \"../core/interfaces.js\";\nimport type { NodeSavedSession, NodeSavedState } from \"@atproto/oauth-client-node\";\n\n/**\n * Mock session store that tracks all operations.\n *\n * This implementation stores sessions in memory and records all\n * method calls for verification in tests.\n *\n * @remarks\n * Use this in tests to:\n * - Verify that sessions are being stored correctly\n * - Check what DIDs have been accessed\n * - Assert on the number and order of operations\n * - Pre-populate sessions for testing restore flows\n *\n * @example Basic usage\n * ```typescript\n * import { MockSessionStore } from \"@hypercerts-org/sdk/testing\";\n *\n * const sessionStore = new MockSessionStore();\n * const sdk = new ATProtoSDK({\n * ...config,\n * storage: { sessionStore },\n * });\n *\n * // After some operations...\n * expect(sessionStore.setCalls).toHaveLength(1);\n * expect(sessionStore.getCalls).toContain(\"did:plc:test123\");\n * ```\n *\n * @example Pre-populating for tests\n * ```typescript\n * const sessionStore = new MockSessionStore();\n *\n * // Pre-populate a session\n * await sessionStore.set(\"did:plc:existing\", mockSessionData);\n *\n * // Reset tracking (keeps the data)\n * sessionStore.getCalls = [];\n * sessionStore.setCalls = [];\n *\n * // Now test restore behavior\n * const session = await sdk.restoreSession(\"did:plc:existing\");\n * expect(sessionStore.getCalls).toContain(\"did:plc:existing\");\n * ```\n *\n * @example Asserting on operations\n * ```typescript\n * const sessionStore = new MockSessionStore();\n *\n * // ... perform operations ...\n *\n * // Verify session was stored for correct DID\n * expect(sessionStore.setCalls[0].did).toBe(\"did:plc:expected\");\n *\n * // Verify session was deleted on logout\n * expect(sessionStore.delCalls).toContain(\"did:plc:logged-out\");\n * ```\n */\nexport class MockSessionStore implements SessionStore {\n /**\n * Internal storage for sessions.\n * @internal\n */\n private store = new Map<string, NodeSavedSession>();\n\n /**\n * Record of all `get()` calls made to this store.\n *\n * Each entry is the DID that was requested.\n */\n public getCalls: string[] = [];\n\n /**\n * Record of all `set()` calls made to this store.\n *\n * Each entry contains the DID and session that was stored.\n */\n public setCalls: Array<{ did: string; session: NodeSavedSession }> = [];\n\n /**\n * Record of all `del()` calls made to this store.\n *\n * Each entry is the DID that was deleted.\n */\n public delCalls: string[] = [];\n\n /**\n * Retrieves a session by DID.\n *\n * Records the call in `getCalls`.\n *\n * @param did - The DID to look up\n * @returns The stored session or undefined\n */\n async get(did: string): Promise<NodeSavedSession | undefined> {\n this.getCalls.push(did);\n return this.store.get(did);\n }\n\n /**\n * Stores a session.\n *\n * Records the call in `setCalls`.\n *\n * @param did - The DID to store under\n * @param session - The session data to store\n */\n async set(did: string, session: NodeSavedSession): Promise<void> {\n this.setCalls.push({ did, session });\n this.store.set(did, session);\n }\n\n /**\n * Deletes a session.\n *\n * Records the call in `delCalls`.\n *\n * @param did - The DID to delete\n */\n async del(did: string): Promise<void> {\n this.delCalls.push(did);\n this.store.delete(did);\n }\n\n /**\n * Resets the store to initial state.\n *\n * Clears all stored sessions and all recorded calls.\n * Call this in `beforeEach` or `afterEach` to ensure test isolation.\n *\n * @example\n * ```typescript\n * beforeEach(() => {\n * sessionStore.reset();\n * });\n * ```\n */\n reset(): void {\n this.store.clear();\n this.getCalls = [];\n this.setCalls = [];\n this.delCalls = [];\n }\n}\n\n/**\n * Mock state store that tracks all operations.\n *\n * This implementation stores OAuth state in memory and records all\n * method calls for verification in tests.\n *\n * @remarks\n * Use this in tests to:\n * - Verify OAuth state is being created during authorization\n * - Check that state is retrieved during callback\n * - Assert that state is cleaned up after use\n * - Test error handling for missing/invalid state\n *\n * @example Basic usage\n * ```typescript\n * import { MockStateStore } from \"@hypercerts-org/sdk/testing\";\n *\n * const stateStore = new MockStateStore();\n * const sdk = new ATProtoSDK({\n * ...config,\n * storage: { stateStore },\n * });\n *\n * // After authorize()\n * expect(stateStore.setCalls).toHaveLength(1);\n *\n * // After callback()\n * expect(stateStore.getCalls).toHaveLength(1);\n * expect(stateStore.delCalls).toHaveLength(1);\n * ```\n *\n * @example Testing invalid state\n * ```typescript\n * const stateStore = new MockStateStore();\n * // Don't pre-populate - state will be missing\n *\n * // This should fail because state doesn't exist\n * await expect(sdk.callback(params)).rejects.toThrow();\n *\n * // Verify the lookup was attempted\n * expect(stateStore.getCalls).toContain(stateKey);\n * ```\n */\nexport class MockStateStore implements StateStore {\n /**\n * Internal storage for OAuth state.\n * @internal\n */\n private store = new Map<string, NodeSavedState>();\n\n /**\n * Record of all `get()` calls made to this store.\n *\n * Each entry is the state key that was requested.\n */\n public getCalls: string[] = [];\n\n /**\n * Record of all `set()` calls made to this store.\n *\n * Each entry contains the key and state that was stored.\n */\n public setCalls: Array<{ key: string; state: NodeSavedState }> = [];\n\n /**\n * Record of all `del()` calls made to this store.\n *\n * Each entry is the state key that was deleted.\n */\n public delCalls: string[] = [];\n\n /**\n * Retrieves OAuth state by key.\n *\n * Records the call in `getCalls`.\n *\n * @param key - The state key to look up\n * @returns The stored state or undefined\n */\n async get(key: string): Promise<NodeSavedState | undefined> {\n this.getCalls.push(key);\n return this.store.get(key);\n }\n\n /**\n * Stores OAuth state.\n *\n * Records the call in `setCalls`.\n *\n * @param key - The state key to store under\n * @param state - The OAuth state data to store\n */\n async set(key: string, state: NodeSavedState): Promise<void> {\n this.setCalls.push({ key, state });\n this.store.set(key, state);\n }\n\n /**\n * Deletes OAuth state.\n *\n * Records the call in `delCalls`.\n *\n * @param key - The state key to delete\n */\n async del(key: string): Promise<void> {\n this.delCalls.push(key);\n this.store.delete(key);\n }\n\n /**\n * Resets the store to initial state.\n *\n * Clears all stored state and all recorded calls.\n * Call this in `beforeEach` or `afterEach` to ensure test isolation.\n *\n * @example\n * ```typescript\n * beforeEach(() => {\n * stateStore.reset();\n * });\n * ```\n */\n reset(): void {\n this.store.clear();\n this.getCalls = [];\n this.setCalls = [];\n this.delCalls = [];\n }\n}\n"],"names":[],"mappings":"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"}
|
package/dist/testing.d.ts
CHANGED
|
@@ -455,25 +455,11 @@ declare const OAuthConfigSchema: z.ZodObject<{
|
|
|
455
455
|
* Zod schema for server URL configuration.
|
|
456
456
|
*
|
|
457
457
|
* @remarks
|
|
458
|
-
*
|
|
458
|
+
* Configure SDS here for collaborative operations.
|
|
459
|
+
* PDS URLs are auto-detected from the user's OAuth session and do not need configuration.
|
|
459
460
|
* For local development, HTTP loopback URLs are allowed.
|
|
460
461
|
*/
|
|
461
462
|
declare const ServerConfigSchema: z.ZodObject<{
|
|
462
|
-
/**
|
|
463
|
-
* Personal Data Server URL - the user's own AT Protocol server.
|
|
464
|
-
* This is the primary server for user data operations.
|
|
465
|
-
*
|
|
466
|
-
* @example Production
|
|
467
|
-
* ```typescript
|
|
468
|
-
* pds: "https://bsky.social"
|
|
469
|
-
* ```
|
|
470
|
-
*
|
|
471
|
-
* @example Local development
|
|
472
|
-
* ```typescript
|
|
473
|
-
* pds: "http://localhost:2583"
|
|
474
|
-
* ```
|
|
475
|
-
*/
|
|
476
|
-
pds: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
477
463
|
/**
|
|
478
464
|
* Shared Data Server URL - for collaborative data storage.
|
|
479
465
|
* Required for collaborator and organization operations.
|
|
@@ -490,10 +476,8 @@ declare const ServerConfigSchema: z.ZodObject<{
|
|
|
490
476
|
*/
|
|
491
477
|
sds: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
492
478
|
}, "strip", z.ZodTypeAny, {
|
|
493
|
-
pds?: string | undefined;
|
|
494
479
|
sds?: string | undefined;
|
|
495
480
|
}, {
|
|
496
|
-
pds?: string | undefined;
|
|
497
481
|
sds?: string | undefined;
|
|
498
482
|
}>;
|
|
499
483
|
/**
|
|
@@ -536,9 +520,6 @@ declare const TimeoutConfigSchema: z.ZodObject<{
|
|
|
536
520
|
* jwksUri: "https://my-app.com/.well-known/jwks.json",
|
|
537
521
|
* jwkPrivate: process.env.JWK_PRIVATE_KEY!,
|
|
538
522
|
* },
|
|
539
|
-
* servers: {
|
|
540
|
-
* pds: "https://bsky.social",
|
|
541
|
-
* },
|
|
542
523
|
* };
|
|
543
524
|
* ```
|
|
544
525
|
*
|
|
@@ -546,8 +527,8 @@ declare const TimeoutConfigSchema: z.ZodObject<{
|
|
|
546
527
|
* ```typescript
|
|
547
528
|
* const config: ATProtoSDKConfig = {
|
|
548
529
|
* oauth: { ... },
|
|
530
|
+
* handleResolver: "https://bsky.social",
|
|
549
531
|
* servers: {
|
|
550
|
-
* pds: "https://bsky.social",
|
|
551
532
|
* sds: "https://sds.hypercerts.org",
|
|
552
533
|
* },
|
|
553
534
|
* storage: {
|
|
@@ -573,10 +554,28 @@ interface ATProtoSDKConfig {
|
|
|
573
554
|
*/
|
|
574
555
|
oauth: z.infer<typeof OAuthConfigSchema>;
|
|
575
556
|
/**
|
|
576
|
-
*
|
|
557
|
+
* URL string used for resolving AT Protocol handles to DIDs during the OAuth
|
|
558
|
+
* authorization flow. This can be any server that speaks the
|
|
559
|
+
* `com.atproto.identity.resolveHandle` XRPC method.
|
|
560
|
+
*
|
|
561
|
+
* If not provided, the `@atproto` library falls back to DNS-based handle resolution.
|
|
562
|
+
*
|
|
563
|
+
* Note: This is NOT the user's PDS URL. The user's PDS is auto-detected from
|
|
564
|
+
* the OAuth session during `callback()` and `restoreSession()`.
|
|
565
|
+
*
|
|
566
|
+
* @example
|
|
567
|
+
* ```typescript
|
|
568
|
+
* handleResolver: "https://pds-eu-west4.test.certified.app"
|
|
569
|
+
* ```
|
|
570
|
+
*/
|
|
571
|
+
handleResolver?: string;
|
|
572
|
+
/**
|
|
573
|
+
* Server URLs for SDS connections.
|
|
577
574
|
*
|
|
578
|
-
* - **PDS**: Personal Data Server - user's own data storage
|
|
579
575
|
* - **SDS**: Shared Data Server - collaborative storage with access control
|
|
576
|
+
*
|
|
577
|
+
* Note: PDS (Personal Data Server) URLs are auto-detected from the user's
|
|
578
|
+
* OAuth session and do not need to be configured.
|
|
580
579
|
*/
|
|
581
580
|
servers?: z.infer<typeof ServerConfigSchema>;
|
|
582
581
|
/**
|
|
@@ -733,12 +732,10 @@ declare function createMockSession(overrides?: Partial<Session>): Session;
|
|
|
733
732
|
* const sdk = new ATProtoSDK(config);
|
|
734
733
|
* ```
|
|
735
734
|
*
|
|
736
|
-
* @example With custom
|
|
735
|
+
* @example With custom handle resolver
|
|
737
736
|
* ```typescript
|
|
738
737
|
* const config = createTestConfig({
|
|
739
|
-
*
|
|
740
|
-
* pds: "https://custom-pds.example.com",
|
|
741
|
-
* },
|
|
738
|
+
* handleResolver: "https://custom-resolver.example.com",
|
|
742
739
|
* });
|
|
743
740
|
* ```
|
|
744
741
|
*
|
package/dist/testing.mjs
CHANGED
|
@@ -65,6 +65,14 @@ function createMockSession(overrides = {}) {
|
|
|
65
65
|
headers: { "Content-Type": "application/json" },
|
|
66
66
|
});
|
|
67
67
|
},
|
|
68
|
+
getTokenInfo: async () => ({
|
|
69
|
+
expiresAt: new Date(Date.now() + 3600 * 1000),
|
|
70
|
+
expired: false,
|
|
71
|
+
scope: "atproto",
|
|
72
|
+
iss: "https://bsky.social",
|
|
73
|
+
aud: "https://bsky.social",
|
|
74
|
+
sub: "did:plc:test123",
|
|
75
|
+
}),
|
|
68
76
|
...overrides,
|
|
69
77
|
};
|
|
70
78
|
return mockSession;
|
|
@@ -96,12 +104,10 @@ function createMockSession(overrides = {}) {
|
|
|
96
104
|
* const sdk = new ATProtoSDK(config);
|
|
97
105
|
* ```
|
|
98
106
|
*
|
|
99
|
-
* @example With custom
|
|
107
|
+
* @example With custom handle resolver
|
|
100
108
|
* ```typescript
|
|
101
109
|
* const config = createTestConfig({
|
|
102
|
-
*
|
|
103
|
-
* pds: "https://custom-pds.example.com",
|
|
104
|
-
* },
|
|
110
|
+
* handleResolver: "https://custom-resolver.example.com",
|
|
105
111
|
* });
|
|
106
112
|
* ```
|
|
107
113
|
*
|
|
@@ -127,8 +133,8 @@ function createTestConfig(overrides = {}) {
|
|
|
127
133
|
d: "test",
|
|
128
134
|
}),
|
|
129
135
|
},
|
|
136
|
+
handleResolver: "https://pds-eu-west4.test.certified.app",
|
|
130
137
|
servers: {
|
|
131
|
-
pds: "https://bsky.social",
|
|
132
138
|
sds: "https://sds.example.com",
|
|
133
139
|
},
|
|
134
140
|
...overrides,
|