@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/testing.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.mjs","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.mjs","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/types.cjs
CHANGED
|
@@ -136,25 +136,11 @@ const OAuthConfigSchema = zod.z.object({
|
|
|
136
136
|
* Zod schema for server URL configuration.
|
|
137
137
|
*
|
|
138
138
|
* @remarks
|
|
139
|
-
*
|
|
139
|
+
* Configure SDS here for collaborative operations.
|
|
140
|
+
* PDS URLs are auto-detected from the user's OAuth session and do not need configuration.
|
|
140
141
|
* For local development, HTTP loopback URLs are allowed.
|
|
141
142
|
*/
|
|
142
143
|
const ServerConfigSchema = zod.z.object({
|
|
143
|
-
/**
|
|
144
|
-
* Personal Data Server URL - the user's own AT Protocol server.
|
|
145
|
-
* This is the primary server for user data operations.
|
|
146
|
-
*
|
|
147
|
-
* @example Production
|
|
148
|
-
* ```typescript
|
|
149
|
-
* pds: "https://bsky.social"
|
|
150
|
-
* ```
|
|
151
|
-
*
|
|
152
|
-
* @example Local development
|
|
153
|
-
* ```typescript
|
|
154
|
-
* pds: "http://localhost:2583"
|
|
155
|
-
* ```
|
|
156
|
-
*/
|
|
157
|
-
pds: urlOrLoopback.optional(),
|
|
158
144
|
/**
|
|
159
145
|
* Shared Data Server URL - for collaborative data storage.
|
|
160
146
|
* Required for collaborator and organization operations.
|
|
@@ -199,6 +185,19 @@ const TimeoutConfigSchema = zod.z.object({
|
|
|
199
185
|
*/
|
|
200
186
|
const ATProtoSDKConfigSchema = zod.z.object({
|
|
201
187
|
oauth: OAuthConfigSchema,
|
|
188
|
+
/**
|
|
189
|
+
* URL string used for resolving AT Protocol handles to DIDs
|
|
190
|
+
* during the OAuth authorization flow. This can be any server that speaks
|
|
191
|
+
* the `com.atproto.identity.resolveHandle` XRPC method.
|
|
192
|
+
*
|
|
193
|
+
* If not provided, the `@atproto` library falls back to DNS-based handle resolution.
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* ```typescript
|
|
197
|
+
* handleResolver: "https://pds-eu-west4.test.certified.app"
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
handleResolver: urlOrLoopback.optional(),
|
|
202
201
|
servers: ServerConfigSchema.optional(),
|
|
203
202
|
timeouts: TimeoutConfigSchema.optional(),
|
|
204
203
|
});
|
package/dist/types.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.cjs","sources":["../src/core/config.ts","../src/core/types.ts"],"sourcesContent":["import { z } from \"zod\";\nimport type { SessionStore, StateStore, CacheInterface, LoggerInterface } from \"./interfaces.js\";\n\n/**\n * Type for HTTP loopback URLs (localhost, 127.0.0.1, [::1])\n */\nexport type LoopbackUrl = `http://localhost${string}` | `http://127.0.0.1${string}` | `http://[::1]${string}`;\n\n/**\n * Type for HTTPS URLs (production)\n */\nexport type HttpsUrl = `https://${string}`;\n\n/**\n * Type for URLs that can be used in development or production\n */\nexport type DevelopmentOrProductionUrl = HttpsUrl | LoopbackUrl;\n\n/**\n * Custom URL validator that allows HTTP loopback addresses for development.\n *\n * Accepts:\n * - Any HTTPS URL (production)\n * - http://localhost (with optional port and path)\n * - http://127.0.0.1 (with optional port and path)\n * - http://[::1] (with optional port and path) - IPv6 loopback\n *\n * Rejects:\n * - Other HTTP URLs (e.g., http://example.com)\n * - Invalid URLs\n *\n * @internal\n */\nconst urlOrLoopback = z.string().refine(\n (value) => {\n try {\n const url = new URL(value);\n\n // Always allow HTTPS\n if (url.protocol === \"https:\") {\n return true;\n }\n\n // For HTTP, only allow loopback addresses\n if (url.protocol === \"http:\") {\n const hostname = url.hostname.toLowerCase();\n return hostname === \"localhost\" || hostname === \"127.0.0.1\" || hostname === \"[::1]\";\n }\n\n return false;\n } catch {\n return false;\n }\n },\n {\n message: \"Must be a valid HTTPS URL or HTTP loopback URL (localhost, 127.0.0.1, [::1])\",\n },\n);\n\n/**\n * Zod schema for OAuth configuration validation.\n *\n * @remarks\n * All URLs must be valid and use HTTPS in production. For local development,\n * HTTP loopback URLs (localhost, 127.0.0.1, [::1]) are allowed.\n * The `jwkPrivate` field should contain the private key in JWK (JSON Web Key) format as a string.\n */\nexport const OAuthConfigSchema = z.object({\n /**\n * URL to the OAuth client metadata JSON document.\n * This document describes your application to the authorization server.\n *\n * For local development, you can use `http://localhost/` as a loopback client.\n *\n * @see https://atproto.com/specs/oauth#client-metadata\n */\n clientId: urlOrLoopback,\n\n /**\n * URL where users are redirected after authentication.\n * Must match one of the redirect URIs in your client metadata.\n *\n * For local development, you can use HTTP loopback URLs like\n * `http://127.0.0.1:3000/callback` or `http://localhost:3000/callback`.\n */\n redirectUri: urlOrLoopback,\n\n /**\n * OAuth scopes to request, space-separated.\n *\n * Can be a string of space-separated permissions or use the permission system:\n *\n * @example Using presets\n * ```typescript\n * import { ScopePresets } from '@hypercerts-org/sdk-core';\n * scope: ScopePresets.EMAIL_AND_PROFILE\n * ```\n *\n * @example Building custom scopes\n * ```typescript\n * import { PermissionBuilder, buildScope } from '@hypercerts-org/sdk-core';\n * scope: buildScope(\n * new PermissionBuilder()\n * .accountEmail('read')\n * .repoWrite('app.bsky.feed.post')\n * .build()\n * )\n * ```\n *\n * @example Legacy scopes\n * ```typescript\n * scope: \"atproto transition:generic\"\n * ```\n *\n * @see https://atproto.com/specs/permission for permission details\n */\n scope: z.string().min(1, \"OAuth scope is required\"),\n\n /**\n * URL to your public JWKS (JSON Web Key Set) endpoint.\n * Used by the authorization server to verify your client's signatures.\n *\n * For local development, you can serve JWKS from a loopback URL like\n * `http://127.0.0.1:3000/.well-known/jwks.json`.\n */\n jwksUri: urlOrLoopback,\n\n /**\n * Private JWK (JSON Web Key) as a JSON string.\n * Used for signing DPoP proofs and client assertions.\n *\n * @remarks\n * This should be kept secret and never exposed to clients.\n * Typically loaded from environment variables or a secrets manager.\n */\n jwkPrivate: z.string(),\n\n /**\n * Enable development mode features (optional).\n *\n * When true, suppresses warnings about using HTTP loopback URLs.\n * Should be set to true for local development to reduce console noise.\n *\n * @default false\n *\n * @example\n * ```typescript\n * oauth: {\n * clientId: \"http://localhost/\",\n * redirectUri: \"http://127.0.0.1:3000/callback\",\n * // ... other config\n * developmentMode: true, // Suppress loopback warnings\n * }\n * ```\n */\n developmentMode: z.boolean().optional(),\n});\n\n/**\n * Zod schema for server URL configuration.\n *\n * @remarks\n * At least one server (PDS or SDS) should be configured for the SDK to be useful.\n * For local development, HTTP loopback URLs are allowed.\n */\nexport const ServerConfigSchema = z.object({\n /**\n * Personal Data Server URL - the user's own AT Protocol server.\n * This is the primary server for user data operations.\n *\n * @example Production\n * ```typescript\n * pds: \"https://bsky.social\"\n * ```\n *\n * @example Local development\n * ```typescript\n * pds: \"http://localhost:2583\"\n * ```\n */\n pds: urlOrLoopback.optional(),\n\n /**\n * Shared Data Server URL - for collaborative data storage.\n * Required for collaborator and organization operations.\n *\n * @example Production\n * ```typescript\n * sds: \"https://sds.hypercerts.org\"\n * ```\n *\n * @example Local development\n * ```typescript\n * sds: \"http://127.0.0.1:2584\"\n * ```\n */\n sds: urlOrLoopback.optional(),\n});\n\n/**\n * Zod schema for timeout configuration.\n *\n * @remarks\n * All timeout values are in milliseconds.\n */\nexport const TimeoutConfigSchema = z.object({\n /**\n * Timeout for fetching PDS metadata during identity resolution.\n * @default 5000 (5 seconds, set by OAuthClient)\n */\n pdsMetadata: z.number().positive().optional(),\n\n /**\n * Timeout for general API requests to PDS/SDS.\n * @default 30000 (30 seconds)\n */\n apiRequests: z.number().positive().optional(),\n});\n\n/**\n * Zod schema for SDK configuration validation.\n *\n * @remarks\n * This schema validates only the primitive/serializable parts of the configuration.\n * Storage interfaces ({@link SessionStore}, {@link StateStore}) cannot be validated\n * with Zod as they are runtime objects.\n */\nexport const ATProtoSDKConfigSchema = z.object({\n oauth: OAuthConfigSchema,\n servers: ServerConfigSchema.optional(),\n timeouts: TimeoutConfigSchema.optional(),\n});\n\n/**\n * Configuration options for the ATProto SDK.\n *\n * This interface defines all configuration needed to initialize the SDK,\n * including OAuth credentials, server endpoints, and optional customizations.\n *\n * @example Minimal configuration\n * ```typescript\n * const config: ATProtoSDKConfig = {\n * oauth: {\n * clientId: \"https://my-app.com/client-metadata.json\",\n * redirectUri: \"https://my-app.com/callback\",\n * scope: \"atproto transition:generic\",\n * jwksUri: \"https://my-app.com/.well-known/jwks.json\",\n * jwkPrivate: process.env.JWK_PRIVATE_KEY!,\n * },\n * servers: {\n * pds: \"https://bsky.social\",\n * },\n * };\n * ```\n *\n * @example Full configuration with custom storage\n * ```typescript\n * const config: ATProtoSDKConfig = {\n * oauth: { ... },\n * servers: {\n * pds: \"https://bsky.social\",\n * sds: \"https://sds.hypercerts.org\",\n * },\n * storage: {\n * sessionStore: new RedisSessionStore(redisClient),\n * stateStore: new RedisStateStore(redisClient),\n * },\n * timeouts: {\n * pdsMetadata: 5000,\n * apiRequests: 30000,\n * },\n * logger: console,\n * };\n * ```\n */\nexport interface ATProtoSDKConfig {\n /**\n * OAuth 2.0 configuration for authentication.\n *\n * Required fields for the OAuth flow with DPoP (Demonstrating Proof of Possession).\n * Your application must host the client metadata and JWKS endpoints.\n *\n * @see https://atproto.com/specs/oauth for AT Protocol OAuth specification\n */\n oauth: z.infer<typeof OAuthConfigSchema>;\n\n /**\n * Server URLs for PDS and SDS connections.\n *\n * - **PDS**: Personal Data Server - user's own data storage\n * - **SDS**: Shared Data Server - collaborative storage with access control\n */\n servers?: z.infer<typeof ServerConfigSchema>;\n\n /**\n * Storage adapters for persisting OAuth sessions and state.\n *\n * If not provided, in-memory implementations are used automatically.\n * **Warning**: In-memory storage is lost on process restart - use persistent\n * storage (Redis, database, etc.) in production.\n *\n * @example\n * ```typescript\n * storage: {\n * sessionStore: new RedisSessionStore(redis),\n * stateStore: new RedisStateStore(redis),\n * }\n * ```\n */\n storage?: {\n /**\n * Persistent storage for OAuth sessions.\n * Sessions contain access tokens, refresh tokens, and DPoP keys.\n */\n sessionStore?: SessionStore;\n\n /**\n * Temporary storage for OAuth state during the authorization flow.\n * State is short-lived and used for PKCE and CSRF protection.\n */\n stateStore?: StateStore;\n };\n\n /**\n * Custom fetch implementation for HTTP requests.\n *\n * Use this to add custom headers, logging, or to use a different HTTP client.\n * Must be compatible with the standard Fetch API.\n *\n * @example\n * ```typescript\n * fetch: async (url, init) => {\n * console.log(`Fetching: ${url}`);\n * return globalThis.fetch(url, init);\n * }\n * ```\n */\n fetch?: typeof fetch;\n\n /**\n * Timeout configuration for network requests.\n * Values are in milliseconds.\n */\n timeouts?: z.infer<typeof TimeoutConfigSchema>;\n\n /**\n * Cache for profiles, metadata, and other frequently accessed data.\n *\n * Implementing caching can significantly reduce API calls and improve performance.\n * The SDK does not provide a default cache - you must implement {@link CacheInterface}.\n */\n cache?: CacheInterface;\n\n /**\n * Logger for debugging and observability.\n *\n * The logger receives debug, info, warn, and error messages from the SDK.\n * Compatible with `console` or any logger implementing {@link LoggerInterface}.\n *\n * @example\n * ```typescript\n * logger: console\n * // or\n * logger: pino()\n * // or\n * logger: winston.createLogger({ ... })\n * ```\n */\n logger?: LoggerInterface;\n}\n","import type { OAuthSession } from \"@atproto/oauth-client-node\";\nimport { z } from \"zod\";\n\n/**\n * Decentralized Identifier (DID) - a unique, persistent identifier for AT Protocol users.\n *\n * DIDs are the canonical identifier for users in the AT Protocol ecosystem.\n * Unlike handles which can change, DIDs remain constant for the lifetime of an account.\n *\n * @remarks\n * AT Protocol supports multiple DID methods:\n * - `did:plc:` - PLC (Public Ledger of Credentials) DIDs, most common for Bluesky users\n * - `did:web:` - Web DIDs, resolved via HTTPS\n *\n * @example\n * ```typescript\n * const did: DID = \"did:plc:ewvi7nxzyoun6zhxrhs64oiz\";\n * const webDid: DID = \"did:web:example.com\";\n * ```\n *\n * @see https://atproto.com/specs/did for DID specification\n */\nexport type DID = string;\n\n/**\n * OAuth session with DPoP (Demonstrating Proof of Possession) support.\n *\n * This type represents an authenticated user session. It wraps the\n * `@atproto/oauth-client-node` OAuthSession and contains:\n * - Access token for API requests\n * - Refresh token for obtaining new access tokens\n * - DPoP key pair for proof-of-possession\n * - User's DID and other identity information\n *\n * @remarks\n * Sessions are managed by the SDK and automatically refresh when tokens expire.\n * Store the user's DID to restore sessions later with {@link ATProtoSDK.restoreSession}.\n *\n * Key properties from OAuthSession:\n * - `did` or `sub`: The user's DID\n * - `handle`: The user's handle (e.g., \"user.bsky.social\")\n *\n * @example\n * ```typescript\n * const session = await sdk.callback(params);\n *\n * // Access user identity\n * console.log(`Logged in as: ${session.did}`);\n *\n * // Use session for repository operations\n * const repo = sdk.repository(session);\n * ```\n *\n * @see https://atproto.com/specs/oauth for OAuth specification\n */\nexport type Session = OAuthSession;\n\n/**\n * Zod schema for collaborator permissions in SDS repositories.\n *\n * Defines the granular permissions a collaborator can have on a shared repository.\n * Permissions follow a hierarchical model where higher-level permissions\n * typically imply lower-level ones.\n */\nexport const CollaboratorPermissionsSchema = z.object({\n /**\n * Can read/view records in the repository.\n * This is the most basic permission level.\n */\n read: z.boolean(),\n\n /**\n * Can create new records in the repository.\n * Typically implies `read` permission.\n */\n create: z.boolean(),\n\n /**\n * Can modify existing records in the repository.\n * Typically implies `read` and `create` permissions.\n */\n update: z.boolean(),\n\n /**\n * Can delete records from the repository.\n * Typically implies `read`, `create`, and `update` permissions.\n */\n delete: z.boolean(),\n\n /**\n * Can manage collaborators and their permissions.\n * Administrative permission that allows inviting/removing collaborators.\n */\n admin: z.boolean(),\n\n /**\n * Full ownership of the repository.\n * Owners have all permissions and cannot be removed by other admins.\n * There must always be at least one owner.\n */\n owner: z.boolean(),\n});\n\n/**\n * Collaborator permissions for SDS (Shared Data Server) repositories.\n *\n * These permissions control what actions a collaborator can perform\n * on records within a shared repository.\n *\n * @example\n * ```typescript\n * // Read-only collaborator\n * const readOnlyPerms: CollaboratorPermissions = {\n * read: true,\n * create: false,\n * update: false,\n * delete: false,\n * admin: false,\n * owner: false,\n * };\n *\n * // Editor collaborator\n * const editorPerms: CollaboratorPermissions = {\n * read: true,\n * create: true,\n * update: true,\n * delete: false,\n * admin: false,\n * owner: false,\n * };\n *\n * // Admin collaborator\n * const adminPerms: CollaboratorPermissions = {\n * read: true,\n * create: true,\n * update: true,\n * delete: true,\n * admin: true,\n * owner: false,\n * };\n * ```\n */\nexport type CollaboratorPermissions = z.infer<typeof CollaboratorPermissionsSchema>;\n\n/**\n * Zod schema for SDS organization data.\n *\n * Organizations are top-level entities in SDS that can own repositories\n * and have multiple collaborators with different permission levels.\n */\nexport const OrganizationSchema = z.object({\n /**\n * The organization's DID - unique identifier.\n * Format: \"did:plc:...\" or \"did:web:...\"\n */\n did: z.string(),\n\n /**\n * The organization's handle - human-readable identifier.\n * Format: \"orgname.sds.hypercerts.org\" or similar\n */\n handle: z.string(),\n\n /**\n * Display name for the organization.\n */\n name: z.string(),\n\n /**\n * Optional description of the organization's purpose.\n */\n description: z.string().optional(),\n\n /**\n * ISO 8601 timestamp when the organization was created.\n * Format: \"2024-01-15T10:30:00.000Z\"\n */\n createdAt: z.string(),\n\n /**\n * The current user's permissions within this organization.\n */\n permissions: CollaboratorPermissionsSchema,\n\n /**\n * How the current user relates to this organization.\n * - `\"owner\"`: User created or owns the organization\n * - `\"shared\"`: User was invited to collaborate (has permissions)\n * - `\"none\"`: User has no access to this organization\n */\n accessType: z.enum([\"owner\", \"shared\", \"none\"]),\n});\n\n/**\n * SDS Organization entity.\n *\n * Represents an organization on a Shared Data Server. Organizations\n * provide a way to group repositories and manage access for teams.\n *\n * @example\n * ```typescript\n * const org: Organization = {\n * did: \"did:plc:org123abc\",\n * handle: \"my-team.sds.hypercerts.org\",\n * name: \"My Team\",\n * description: \"A team working on impact certificates\",\n * createdAt: \"2024-01-15T10:30:00.000Z\",\n * permissions: {\n * read: true,\n * create: true,\n * update: true,\n * delete: true,\n * admin: true,\n * owner: true,\n * },\n * accessType: \"owner\",\n * };\n * ```\n */\nexport type Organization = z.infer<typeof OrganizationSchema>;\n\n/**\n * Zod schema for collaborator data.\n *\n * Represents a user who has been granted access to a shared repository\n * or organization with specific permissions.\n */\nexport const CollaboratorSchema = z.object({\n /**\n * The collaborator's DID - their unique identifier.\n * Format: \"did:plc:...\" or \"did:web:...\"\n */\n userDid: z.string(),\n\n /**\n * The permissions granted to this collaborator.\n */\n permissions: CollaboratorPermissionsSchema,\n\n /**\n * DID of the user who granted these permissions.\n * Useful for audit trails.\n */\n grantedBy: z.string(),\n\n /**\n * ISO 8601 timestamp when permissions were granted.\n * Format: \"2024-01-15T10:30:00.000Z\"\n */\n grantedAt: z.string(),\n\n /**\n * ISO 8601 timestamp when permissions were revoked, if applicable.\n * Undefined if the collaborator is still active.\n */\n revokedAt: z.string().optional(),\n});\n\n/**\n * Collaborator information for SDS repositories.\n *\n * Represents a user who has been granted access to collaborate on\n * a shared repository or organization.\n *\n * @example\n * ```typescript\n * const collaborator: Collaborator = {\n * userDid: \"did:plc:user456def\",\n * permissions: {\n * read: true,\n * create: true,\n * update: true,\n * delete: false,\n * admin: false,\n * owner: false,\n * },\n * grantedBy: \"did:plc:owner123abc\",\n * grantedAt: \"2024-02-01T14:00:00.000Z\",\n * };\n * ```\n */\nexport type Collaborator = z.infer<typeof CollaboratorSchema>;\n"],"names":["z"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.cjs","sources":["../src/core/config.ts","../src/core/types.ts"],"sourcesContent":["import { z } from \"zod\";\nimport type { SessionStore, StateStore, CacheInterface, LoggerInterface } from \"./interfaces.js\";\n\n/**\n * Type for HTTP loopback URLs (localhost, 127.0.0.1, [::1])\n */\nexport type LoopbackUrl = `http://localhost${string}` | `http://127.0.0.1${string}` | `http://[::1]${string}`;\n\n/**\n * Type for HTTPS URLs (production)\n */\nexport type HttpsUrl = `https://${string}`;\n\n/**\n * Type for URLs that can be used in development or production\n */\nexport type DevelopmentOrProductionUrl = HttpsUrl | LoopbackUrl;\n\n/**\n * Custom URL validator that allows HTTP loopback addresses for development.\n *\n * Accepts:\n * - Any HTTPS URL (production)\n * - http://localhost (with optional port and path)\n * - http://127.0.0.1 (with optional port and path)\n * - http://[::1] (with optional port and path) - IPv6 loopback\n *\n * Rejects:\n * - Other HTTP URLs (e.g., http://example.com)\n * - Invalid URLs\n *\n * @internal\n */\nconst urlOrLoopback = z.string().refine(\n (value) => {\n try {\n const url = new URL(value);\n\n // Always allow HTTPS\n if (url.protocol === \"https:\") {\n return true;\n }\n\n // For HTTP, only allow loopback addresses\n if (url.protocol === \"http:\") {\n const hostname = url.hostname.toLowerCase();\n return hostname === \"localhost\" || hostname === \"127.0.0.1\" || hostname === \"[::1]\";\n }\n\n return false;\n } catch {\n return false;\n }\n },\n {\n message: \"Must be a valid HTTPS URL or HTTP loopback URL (localhost, 127.0.0.1, [::1])\",\n },\n);\n\n/**\n * Zod schema for OAuth configuration validation.\n *\n * @remarks\n * All URLs must be valid and use HTTPS in production. For local development,\n * HTTP loopback URLs (localhost, 127.0.0.1, [::1]) are allowed.\n * The `jwkPrivate` field should contain the private key in JWK (JSON Web Key) format as a string.\n */\nexport const OAuthConfigSchema = z.object({\n /**\n * URL to the OAuth client metadata JSON document.\n * This document describes your application to the authorization server.\n *\n * For local development, you can use `http://localhost/` as a loopback client.\n *\n * @see https://atproto.com/specs/oauth#client-metadata\n */\n clientId: urlOrLoopback,\n\n /**\n * URL where users are redirected after authentication.\n * Must match one of the redirect URIs in your client metadata.\n *\n * For local development, you can use HTTP loopback URLs like\n * `http://127.0.0.1:3000/callback` or `http://localhost:3000/callback`.\n */\n redirectUri: urlOrLoopback,\n\n /**\n * OAuth scopes to request, space-separated.\n *\n * Can be a string of space-separated permissions or use the permission system:\n *\n * @example Using presets\n * ```typescript\n * import { ScopePresets } from '@hypercerts-org/sdk-core';\n * scope: ScopePresets.EMAIL_AND_PROFILE\n * ```\n *\n * @example Building custom scopes\n * ```typescript\n * import { PermissionBuilder, buildScope } from '@hypercerts-org/sdk-core';\n * scope: buildScope(\n * new PermissionBuilder()\n * .accountEmail('read')\n * .repoWrite('app.bsky.feed.post')\n * .build()\n * )\n * ```\n *\n * @example Legacy scopes\n * ```typescript\n * scope: \"atproto transition:generic\"\n * ```\n *\n * @see https://atproto.com/specs/permission for permission details\n */\n scope: z.string().min(1, \"OAuth scope is required\"),\n\n /**\n * URL to your public JWKS (JSON Web Key Set) endpoint.\n * Used by the authorization server to verify your client's signatures.\n *\n * For local development, you can serve JWKS from a loopback URL like\n * `http://127.0.0.1:3000/.well-known/jwks.json`.\n */\n jwksUri: urlOrLoopback,\n\n /**\n * Private JWK (JSON Web Key) as a JSON string.\n * Used for signing DPoP proofs and client assertions.\n *\n * @remarks\n * This should be kept secret and never exposed to clients.\n * Typically loaded from environment variables or a secrets manager.\n */\n jwkPrivate: z.string(),\n\n /**\n * Enable development mode features (optional).\n *\n * When true, suppresses warnings about using HTTP loopback URLs.\n * Should be set to true for local development to reduce console noise.\n *\n * @default false\n *\n * @example\n * ```typescript\n * oauth: {\n * clientId: \"http://localhost/\",\n * redirectUri: \"http://127.0.0.1:3000/callback\",\n * // ... other config\n * developmentMode: true, // Suppress loopback warnings\n * }\n * ```\n */\n developmentMode: z.boolean().optional(),\n});\n\n/**\n * Zod schema for server URL configuration.\n *\n * @remarks\n * Configure SDS here for collaborative operations.\n * PDS URLs are auto-detected from the user's OAuth session and do not need configuration.\n * For local development, HTTP loopback URLs are allowed.\n */\nexport const ServerConfigSchema = z.object({\n /**\n * Shared Data Server URL - for collaborative data storage.\n * Required for collaborator and organization operations.\n *\n * @example Production\n * ```typescript\n * sds: \"https://sds.hypercerts.org\"\n * ```\n *\n * @example Local development\n * ```typescript\n * sds: \"http://127.0.0.1:2584\"\n * ```\n */\n sds: urlOrLoopback.optional(),\n});\n\n/**\n * Zod schema for timeout configuration.\n *\n * @remarks\n * All timeout values are in milliseconds.\n */\nexport const TimeoutConfigSchema = z.object({\n /**\n * Timeout for fetching PDS metadata during identity resolution.\n * @default 5000 (5 seconds, set by OAuthClient)\n */\n pdsMetadata: z.number().positive().optional(),\n\n /**\n * Timeout for general API requests to PDS/SDS.\n * @default 30000 (30 seconds)\n */\n apiRequests: z.number().positive().optional(),\n});\n\n/**\n * Zod schema for SDK configuration validation.\n *\n * @remarks\n * This schema validates only the primitive/serializable parts of the configuration.\n * Storage interfaces ({@link SessionStore}, {@link StateStore}) cannot be validated\n * with Zod as they are runtime objects.\n */\nexport const ATProtoSDKConfigSchema = z.object({\n oauth: OAuthConfigSchema,\n /**\n * URL string used for resolving AT Protocol handles to DIDs\n * during the OAuth authorization flow. This can be any server that speaks\n * the `com.atproto.identity.resolveHandle` XRPC method.\n *\n * If not provided, the `@atproto` library falls back to DNS-based handle resolution.\n *\n * @example\n * ```typescript\n * handleResolver: \"https://pds-eu-west4.test.certified.app\"\n * ```\n */\n handleResolver: urlOrLoopback.optional(),\n servers: ServerConfigSchema.optional(),\n timeouts: TimeoutConfigSchema.optional(),\n});\n\n/**\n * Configuration options for the ATProto SDK.\n *\n * This interface defines all configuration needed to initialize the SDK,\n * including OAuth credentials, server endpoints, and optional customizations.\n *\n * @example Minimal configuration\n * ```typescript\n * const config: ATProtoSDKConfig = {\n * oauth: {\n * clientId: \"https://my-app.com/client-metadata.json\",\n * redirectUri: \"https://my-app.com/callback\",\n * scope: \"atproto transition:generic\",\n * jwksUri: \"https://my-app.com/.well-known/jwks.json\",\n * jwkPrivate: process.env.JWK_PRIVATE_KEY!,\n * },\n * };\n * ```\n *\n * @example Full configuration with custom storage\n * ```typescript\n * const config: ATProtoSDKConfig = {\n * oauth: { ... },\n * handleResolver: \"https://bsky.social\",\n * servers: {\n * sds: \"https://sds.hypercerts.org\",\n * },\n * storage: {\n * sessionStore: new RedisSessionStore(redisClient),\n * stateStore: new RedisStateStore(redisClient),\n * },\n * timeouts: {\n * pdsMetadata: 5000,\n * apiRequests: 30000,\n * },\n * logger: console,\n * };\n * ```\n */\nexport interface ATProtoSDKConfig {\n /**\n * OAuth 2.0 configuration for authentication.\n *\n * Required fields for the OAuth flow with DPoP (Demonstrating Proof of Possession).\n * Your application must host the client metadata and JWKS endpoints.\n *\n * @see https://atproto.com/specs/oauth for AT Protocol OAuth specification\n */\n oauth: z.infer<typeof OAuthConfigSchema>;\n\n /**\n * URL string used for resolving AT Protocol handles to DIDs during the OAuth\n * authorization flow. This can be any server that speaks the\n * `com.atproto.identity.resolveHandle` XRPC method.\n *\n * If not provided, the `@atproto` library falls back to DNS-based handle resolution.\n *\n * Note: This is NOT the user's PDS URL. The user's PDS is auto-detected from\n * the OAuth session during `callback()` and `restoreSession()`.\n *\n * @example\n * ```typescript\n * handleResolver: \"https://pds-eu-west4.test.certified.app\"\n * ```\n */\n handleResolver?: string;\n\n /**\n * Server URLs for SDS connections.\n *\n * - **SDS**: Shared Data Server - collaborative storage with access control\n *\n * Note: PDS (Personal Data Server) URLs are auto-detected from the user's\n * OAuth session and do not need to be configured.\n */\n servers?: z.infer<typeof ServerConfigSchema>;\n\n /**\n * Storage adapters for persisting OAuth sessions and state.\n *\n * If not provided, in-memory implementations are used automatically.\n * **Warning**: In-memory storage is lost on process restart - use persistent\n * storage (Redis, database, etc.) in production.\n *\n * @example\n * ```typescript\n * storage: {\n * sessionStore: new RedisSessionStore(redis),\n * stateStore: new RedisStateStore(redis),\n * }\n * ```\n */\n storage?: {\n /**\n * Persistent storage for OAuth sessions.\n * Sessions contain access tokens, refresh tokens, and DPoP keys.\n */\n sessionStore?: SessionStore;\n\n /**\n * Temporary storage for OAuth state during the authorization flow.\n * State is short-lived and used for PKCE and CSRF protection.\n */\n stateStore?: StateStore;\n };\n\n /**\n * Custom fetch implementation for HTTP requests.\n *\n * Use this to add custom headers, logging, or to use a different HTTP client.\n * Must be compatible with the standard Fetch API.\n *\n * @example\n * ```typescript\n * fetch: async (url, init) => {\n * console.log(`Fetching: ${url}`);\n * return globalThis.fetch(url, init);\n * }\n * ```\n */\n fetch?: typeof fetch;\n\n /**\n * Timeout configuration for network requests.\n * Values are in milliseconds.\n */\n timeouts?: z.infer<typeof TimeoutConfigSchema>;\n\n /**\n * Cache for profiles, metadata, and other frequently accessed data.\n *\n * Implementing caching can significantly reduce API calls and improve performance.\n * The SDK does not provide a default cache - you must implement {@link CacheInterface}.\n */\n cache?: CacheInterface;\n\n /**\n * Logger for debugging and observability.\n *\n * The logger receives debug, info, warn, and error messages from the SDK.\n * Compatible with `console` or any logger implementing {@link LoggerInterface}.\n *\n * @example\n * ```typescript\n * logger: console\n * // or\n * logger: pino()\n * // or\n * logger: winston.createLogger({ ... })\n * ```\n */\n logger?: LoggerInterface;\n}\n","import type { OAuthSession } from \"@atproto/oauth-client-node\";\nimport { z } from \"zod\";\n\n/**\n * Decentralized Identifier (DID) - a unique, persistent identifier for AT Protocol users.\n *\n * DIDs are the canonical identifier for users in the AT Protocol ecosystem.\n * Unlike handles which can change, DIDs remain constant for the lifetime of an account.\n *\n * @remarks\n * AT Protocol supports multiple DID methods:\n * - `did:plc:` - PLC (Public Ledger of Credentials) DIDs, most common for Bluesky users\n * - `did:web:` - Web DIDs, resolved via HTTPS\n *\n * @example\n * ```typescript\n * const did: DID = \"did:plc:ewvi7nxzyoun6zhxrhs64oiz\";\n * const webDid: DID = \"did:web:example.com\";\n * ```\n *\n * @see https://atproto.com/specs/did for DID specification\n */\nexport type DID = string;\n\n/**\n * Validates that a string is a valid DID format.\n *\n * DIDs must follow the format: `did:<method>:<method-specific-id>`\n * where method is lowercase letters and digits, and the identifier contains\n * alphanumeric characters plus `.`, `_`, `:`, `%`, and `-`.\n *\n * @param did - The string to validate\n * @returns true if the string is a valid DID format\n *\n * @example\n * ```typescript\n * isValidDid(\"did:plc:ewvi7nxzyoun6zhxrhs64oiz\"); // true\n * isValidDid(\"did:web:example.com\"); // true\n * isValidDid(\"not-a-did\"); // false\n * isValidDid(\"did:\"); // false\n * ```\n *\n * @see https://www.w3.org/TR/did-core/#did-syntax for DID syntax specification\n */\nexport function isValidDid(did: string): boolean {\n // DID format: did:<method>:<method-specific-id>\n // Method: lowercase letters and digits (per W3C DID Core spec)\n // Identifier: alphanumeric plus . _ : % -\n // method-specific-id must end with at least one non-colon idchar (W3C DID Core 1.0)\n return /^did:[a-z0-9]+:(?:[a-zA-Z0-9._%-]+:)*[a-zA-Z0-9._%-]+$/.test(did);\n}\n\n/**\n * OAuth session with DPoP (Demonstrating Proof of Possession) support.\n *\n * This type represents an authenticated user session. It wraps the\n * `@atproto/oauth-client-node` OAuthSession and contains:\n * - Access token for API requests\n * - Refresh token for obtaining new access tokens\n * - DPoP key pair for proof-of-possession\n * - User's DID and other identity information\n *\n * @remarks\n * Sessions are managed by the SDK and automatically refresh when tokens expire.\n * Store the user's DID to restore sessions later with {@link ATProtoSDK.restoreSession}.\n *\n * Key properties from OAuthSession:\n * - `did` or `sub`: The user's DID\n * - `handle`: The user's handle (e.g., \"user.bsky.social\")\n *\n * @example\n * ```typescript\n * const session = await sdk.callback(params);\n *\n * // Access user identity\n * console.log(`Logged in as: ${session.did}`);\n *\n * // Use session for repository operations\n * const repo = sdk.repository(session);\n * ```\n *\n * @see https://atproto.com/specs/oauth for OAuth specification\n */\nexport type Session = OAuthSession;\n\n/**\n * Zod schema for collaborator permissions in SDS repositories.\n *\n * Defines the granular permissions a collaborator can have on a shared repository.\n * Permissions follow a hierarchical model where higher-level permissions\n * typically imply lower-level ones.\n */\nexport const CollaboratorPermissionsSchema = z.object({\n /**\n * Can read/view records in the repository.\n * This is the most basic permission level.\n */\n read: z.boolean(),\n\n /**\n * Can create new records in the repository.\n * Typically implies `read` permission.\n */\n create: z.boolean(),\n\n /**\n * Can modify existing records in the repository.\n * Typically implies `read` and `create` permissions.\n */\n update: z.boolean(),\n\n /**\n * Can delete records from the repository.\n * Typically implies `read`, `create`, and `update` permissions.\n */\n delete: z.boolean(),\n\n /**\n * Can manage collaborators and their permissions.\n * Administrative permission that allows inviting/removing collaborators.\n */\n admin: z.boolean(),\n\n /**\n * Full ownership of the repository.\n * Owners have all permissions and cannot be removed by other admins.\n * There must always be at least one owner.\n */\n owner: z.boolean(),\n});\n\n/**\n * Collaborator permissions for SDS (Shared Data Server) repositories.\n *\n * These permissions control what actions a collaborator can perform\n * on records within a shared repository.\n *\n * @example\n * ```typescript\n * // Read-only collaborator\n * const readOnlyPerms: CollaboratorPermissions = {\n * read: true,\n * create: false,\n * update: false,\n * delete: false,\n * admin: false,\n * owner: false,\n * };\n *\n * // Editor collaborator\n * const editorPerms: CollaboratorPermissions = {\n * read: true,\n * create: true,\n * update: true,\n * delete: false,\n * admin: false,\n * owner: false,\n * };\n *\n * // Admin collaborator\n * const adminPerms: CollaboratorPermissions = {\n * read: true,\n * create: true,\n * update: true,\n * delete: true,\n * admin: true,\n * owner: false,\n * };\n * ```\n */\nexport type CollaboratorPermissions = z.infer<typeof CollaboratorPermissionsSchema>;\n\n/**\n * Zod schema for SDS organization data.\n *\n * Organizations are top-level entities in SDS that can own repositories\n * and have multiple collaborators with different permission levels.\n */\nexport const OrganizationSchema = z.object({\n /**\n * The organization's DID - unique identifier.\n * Format: \"did:plc:...\" or \"did:web:...\"\n */\n did: z.string(),\n\n /**\n * The organization's handle - human-readable identifier.\n * Format: \"orgname.sds.hypercerts.org\" or similar\n */\n handle: z.string(),\n\n /**\n * Display name for the organization.\n */\n name: z.string(),\n\n /**\n * Optional description of the organization's purpose.\n */\n description: z.string().optional(),\n\n /**\n * ISO 8601 timestamp when the organization was created.\n * Format: \"2024-01-15T10:30:00.000Z\"\n */\n createdAt: z.string(),\n\n /**\n * The current user's permissions within this organization.\n */\n permissions: CollaboratorPermissionsSchema,\n\n /**\n * How the current user relates to this organization.\n * - `\"owner\"`: User created or owns the organization\n * - `\"shared\"`: User was invited to collaborate (has permissions)\n * - `\"none\"`: User has no access to this organization\n */\n accessType: z.enum([\"owner\", \"shared\", \"none\"]),\n});\n\n/**\n * SDS Organization entity.\n *\n * Represents an organization on a Shared Data Server. Organizations\n * provide a way to group repositories and manage access for teams.\n *\n * @example\n * ```typescript\n * const org: Organization = {\n * did: \"did:plc:org123abc\",\n * handle: \"my-team.sds.hypercerts.org\",\n * name: \"My Team\",\n * description: \"A team working on impact certificates\",\n * createdAt: \"2024-01-15T10:30:00.000Z\",\n * permissions: {\n * read: true,\n * create: true,\n * update: true,\n * delete: true,\n * admin: true,\n * owner: true,\n * },\n * accessType: \"owner\",\n * };\n * ```\n */\nexport type Organization = z.infer<typeof OrganizationSchema>;\n\n/**\n * Zod schema for collaborator data.\n *\n * Represents a user who has been granted access to a shared repository\n * or organization with specific permissions.\n */\nexport const CollaboratorSchema = z.object({\n /**\n * The collaborator's DID - their unique identifier.\n * Format: \"did:plc:...\" or \"did:web:...\"\n */\n userDid: z.string(),\n\n /**\n * The permissions granted to this collaborator.\n */\n permissions: CollaboratorPermissionsSchema,\n\n /**\n * DID of the user who granted these permissions.\n * Useful for audit trails.\n */\n grantedBy: z.string(),\n\n /**\n * ISO 8601 timestamp when permissions were granted.\n * Format: \"2024-01-15T10:30:00.000Z\"\n */\n grantedAt: z.string(),\n\n /**\n * ISO 8601 timestamp when permissions were revoked, if applicable.\n * Undefined if the collaborator is still active.\n */\n revokedAt: z.string().optional(),\n});\n\n/**\n * Collaborator information for SDS repositories.\n *\n * Represents a user who has been granted access to collaborate on\n * a shared repository or organization.\n *\n * @example\n * ```typescript\n * const collaborator: Collaborator = {\n * userDid: \"did:plc:user456def\",\n * permissions: {\n * read: true,\n * create: true,\n * update: true,\n * delete: false,\n * admin: false,\n * owner: false,\n * },\n * grantedBy: \"did:plc:owner123abc\",\n * grantedAt: \"2024-02-01T14:00:00.000Z\",\n * };\n * ```\n */\nexport type Collaborator = z.infer<typeof CollaboratorSchema>;\n"],"names":["z"],"mappings":"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"}
|