@tinycloud/sdk-services 2.2.0-beta.7 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{BaseService-BiS6HRwE.d.cts → BaseService-C_iXlTeN.d.cts} +6 -1
- package/dist/{BaseService-BiS6HRwE.d.ts → BaseService-C_iXlTeN.d.ts} +6 -1
- package/dist/encryption/index.cjs +1340 -0
- package/dist/encryption/index.cjs.map +1 -0
- package/dist/encryption/index.d.cts +802 -0
- package/dist/encryption/index.d.ts +802 -0
- package/dist/encryption/index.js +1274 -0
- package/dist/encryption/index.js.map +1 -0
- package/dist/index.cjs +1555 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +55 -12
- package/dist/index.d.ts +55 -12
- package/dist/index.js +1510 -46
- package/dist/index.js.map +1 -1
- package/dist/kv/index.cjs +116 -0
- package/dist/kv/index.cjs.map +1 -1
- package/dist/kv/index.d.cts +100 -2
- package/dist/kv/index.d.ts +100 -2
- package/dist/kv/index.js +115 -0
- package/dist/kv/index.js.map +1 -1
- package/dist/sql/index.cjs.map +1 -1
- package/dist/sql/index.d.cts +1 -1
- package/dist/sql/index.d.ts +1 -1
- package/dist/sql/index.js.map +1 -1
- package/package.json +7 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/types.ts","../../src/errors.ts","../../src/base/BaseService.ts","../../src/encryption/canonical.ts","../../src/encryption/networkId.ts","../../src/encryption/types.ts","../../src/encryption/discovery.ts","../../src/encryption/envelope.ts","../../src/encryption/invocation.ts","../../src/encryption/receiverKey.ts","../../src/encryption/response.ts","../../src/encryption/EncryptionService.ts"],"sourcesContent":["/**\n * SDK Services - Core Types\n *\n * These types define the service architecture for TinyCloud SDK.\n * Services use dependency injection via IServiceContext for platform independence.\n */\n\n// =============================================================================\n// Result Type Pattern\n// =============================================================================\n\n/**\n * Result type for service operations.\n * Services return Result instead of throwing, making error handling explicit.\n *\n * @template T - The success data type\n * @template E - The error type (defaults to ServiceError)\n *\n * @example\n * ```typescript\n * const result = await kv.get('key');\n * if (result.ok) {\n * console.log(result.data);\n * } else {\n * console.error(result.error.code);\n * }\n * ```\n */\nexport type Result<T, E = ServiceError> =\n | { ok: true; data: T }\n | { ok: false; error: E };\n\n/**\n * Service error with structured information.\n */\nexport interface ServiceError {\n /** Error code for programmatic handling (e.g., 'KV_NOT_FOUND', 'AUTH_EXPIRED') */\n code: string;\n /** Human-readable error message */\n message: string;\n /** Service that produced the error (e.g., 'kv', 'sql') */\n service: string;\n /** Original error if this wraps another error */\n cause?: Error;\n /** Additional metadata about the error */\n meta?: Record<string, unknown>;\n}\n\n/**\n * Storage quota information returned with quota-related errors.\n */\nexport interface StorageQuotaInfo {\n usedBytes: number;\n limitBytes: number;\n service: string;\n}\n\n/**\n * Standard error codes used across services.\n */\nexport const ErrorCodes = {\n // Common errors\n NOT_FOUND: \"NOT_FOUND\",\n AUTH_EXPIRED: \"AUTH_EXPIRED\",\n AUTH_REQUIRED: \"AUTH_REQUIRED\",\n AUTH_UNAUTHORIZED: \"AUTH_UNAUTHORIZED\",\n NETWORK_ERROR: \"NETWORK_ERROR\",\n TIMEOUT: \"TIMEOUT\",\n ABORTED: \"ABORTED\",\n INVALID_INPUT: \"INVALID_INPUT\",\n PERMISSION_DENIED: \"PERMISSION_DENIED\",\n\n // KV-specific errors\n KV_NOT_FOUND: \"KV_NOT_FOUND\",\n KV_WRITE_FAILED: \"KV_WRITE_FAILED\",\n\n // SQL-specific errors\n SQL_ERROR: \"SQL_ERROR\",\n SQL_PERMISSION_DENIED: \"SQL_PERMISSION_DENIED\",\n SQL_DATABASE_NOT_FOUND: \"SQL_DATABASE_NOT_FOUND\",\n SQL_RESPONSE_TOO_LARGE: \"SQL_RESPONSE_TOO_LARGE\",\n SQL_QUOTA_EXCEEDED: \"SQL_QUOTA_EXCEEDED\",\n SQL_INVALID_STATEMENT: \"SQL_INVALID_STATEMENT\",\n SQL_SCHEMA_ERROR: \"SQL_SCHEMA_ERROR\",\n SQL_READONLY_VIOLATION: \"SQL_READONLY_VIOLATION\",\n\n // Storage quota errors\n STORAGE_QUOTA_EXCEEDED: \"STORAGE_QUOTA_EXCEEDED\",\n STORAGE_LIMIT_REACHED: \"STORAGE_LIMIT_REACHED\",\n\n // DuckDB-specific errors\n DUCKDB_ERROR: \"DUCKDB_ERROR\",\n DUCKDB_PERMISSION_DENIED: \"DUCKDB_PERMISSION_DENIED\",\n DUCKDB_DATABASE_NOT_FOUND: \"DUCKDB_DATABASE_NOT_FOUND\",\n DUCKDB_RESPONSE_TOO_LARGE: \"DUCKDB_RESPONSE_TOO_LARGE\",\n DUCKDB_QUOTA_EXCEEDED: \"DUCKDB_QUOTA_EXCEEDED\",\n DUCKDB_INVALID_STATEMENT: \"DUCKDB_INVALID_STATEMENT\",\n DUCKDB_SCHEMA_ERROR: \"DUCKDB_SCHEMA_ERROR\",\n DUCKDB_READONLY_VIOLATION: \"DUCKDB_READONLY_VIOLATION\",\n} as const;\n\nexport type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];\n\n// =============================================================================\n// Service Session\n// =============================================================================\n\n/**\n * Session data required for authenticated service operations.\n * Both TinyCloudSession and web-sdk Session can be cast to this interface.\n */\nexport interface ServiceSession {\n /** The delegation header containing the UCAN */\n delegationHeader: { Authorization: string };\n /** The delegation CID */\n delegationCid: string;\n /** The space ID for this session */\n spaceId: string;\n /** The verification method DID */\n verificationMethod: string;\n /** The session key JWK (required for invoke) */\n jwk: object;\n}\n\n// =============================================================================\n// Platform Dependencies (Injected)\n// =============================================================================\n\n/**\n * Headers type - compatible with both browser and Node.js.\n */\nexport type ServiceHeaders = Record<string, string> | [string, string][];\n\n/**\n * A single fact object to include in the UCAN invocation.\n * Facts are key-value objects that the server reads from the UCAN facts field.\n */\nexport interface InvocationFact {\n [key: string]: unknown;\n}\n\n/**\n * Facts to include in the UCAN invocation.\n * This is an array of fact objects per the UCAN spec.\n * Used to pass additional parameters that the server reads from the UCAN facts field.\n */\nexport type InvocationFacts = InvocationFact[];\n\n/**\n * Invoke function signature - platform-specific implementation injected via DI.\n * Both node-sdk-wasm and web-sdk-wasm export this with identical signature.\n *\n * @param session - The service session with delegation data\n * @param service - Service name (e.g., \"kv\")\n * @param path - Resource path or key\n * @param action - Action to perform (e.g., \"tinycloud.kv/get\")\n * @param facts - Optional facts to include in the UCAN (e.g., for capabilities/read params)\n * @returns Headers to include in the request\n */\nexport type InvokeFunction = (\n session: ServiceSession,\n service: string,\n path: string,\n action: string,\n facts?: InvocationFacts,\n) => ServiceHeaders;\n\n/**\n * Multi-resource invocation entry.\n */\nexport interface InvokeAnyEntry {\n /**\n * Legacy space-scoped resource. Optional when `resource` is provided.\n */\n spaceId?: string;\n service: string;\n path: string;\n action: string;\n /** Optional raw resource URI. When set, WASM signs this URI directly. */\n resource?: string;\n}\n\n/**\n * Invoke function for minting a single authorization header that covers\n * multiple capabilities across one effective invoker.\n */\nexport type InvokeAnyFunction = (\n session: ServiceSession,\n entries: InvokeAnyEntry[],\n facts?: InvocationFacts,\n) => ServiceHeaders;\n\n/**\n * Fetch request options - compatible with standard fetch API.\n */\nexport interface FetchRequestInit {\n method?: string;\n headers?: ServiceHeaders;\n body?: Blob | string;\n signal?: AbortSignal;\n}\n\n/**\n * Fetch response interface - compatible with standard Response.\n */\nexport interface FetchResponse {\n ok: boolean;\n status: number;\n statusText: string;\n body?: unknown;\n headers: {\n get(name: string): string | null;\n };\n json(): Promise<unknown>;\n text(): Promise<string>;\n arrayBuffer(): Promise<ArrayBuffer>;\n blob(): Promise<Blob>;\n}\n\n/**\n * Fetch function signature - allows for custom fetch implementations.\n * Compatible with both browser fetch and Node.js fetch.\n */\nexport type FetchFunction = (\n url: string,\n init?: FetchRequestInit,\n) => Promise<FetchResponse>;\n\n// =============================================================================\n// Retry Policy\n// =============================================================================\n\n/**\n * Configuration for automatic retry of failed requests.\n */\nexport interface RetryPolicy {\n /** Maximum number of attempts (including initial) */\n maxAttempts: number;\n /** Backoff strategy between retries */\n backoff: \"none\" | \"linear\" | \"exponential\";\n /** Base delay in milliseconds for backoff calculation */\n baseDelayMs: number;\n /** Maximum delay in milliseconds between retries */\n maxDelayMs: number;\n /** Error codes that should trigger a retry */\n retryableErrors: string[];\n}\n\n/**\n * Default retry policy.\n */\nexport const defaultRetryPolicy: RetryPolicy = {\n maxAttempts: 3,\n backoff: \"exponential\",\n baseDelayMs: 1000,\n maxDelayMs: 10000,\n retryableErrors: [ErrorCodes.NETWORK_ERROR, ErrorCodes.TIMEOUT],\n};\n\n// =============================================================================\n// Service Context\n// =============================================================================\n\n/**\n * Event handler function type.\n */\nexport type EventHandler = (data: unknown) => void;\n\n/**\n * Service interface - base contract for all services.\n */\nexport interface IService {\n /** Initialize service with context */\n initialize(context: IServiceContext): void;\n\n /** Called when session changes (sign-in, sign-out, refresh) */\n onSessionChange(session: ServiceSession | null): void;\n\n /** Called when SDK signs out - should abort pending operations */\n onSignOut(): void;\n\n /** Service-specific configuration */\n readonly config: Record<string, unknown>;\n}\n\n/**\n * Context provided to services for accessing platform dependencies.\n * The SDK creates this context and passes it to services during initialization.\n */\nexport interface IServiceContext {\n // Session management\n /** Current active session, or null if not authenticated */\n readonly session: ServiceSession | null;\n /** Whether there is an active authenticated session */\n readonly isAuthenticated: boolean;\n\n // Platform dependencies (injected by SDK)\n /** Platform-specific invoke function from WASM binding */\n readonly invoke: InvokeFunction;\n /** Optional multi-resource invoke function */\n readonly invokeAny?: InvokeAnyFunction;\n /** Fetch function (defaults to globalThis.fetch) */\n readonly fetch: FetchFunction;\n /** Available TinyCloud host URLs */\n readonly hosts: string[];\n\n // Cross-service access\n /** Get another registered service by name */\n getService<T extends IService>(name: string): T | undefined;\n\n // Telemetry/Events\n /** Emit a telemetry event */\n emit(event: string, data: unknown): void;\n /** Subscribe to events */\n on(event: string, handler: EventHandler): () => void;\n\n // Lifecycle\n /** Abort signal that fires when SDK signs out */\n readonly abortSignal: AbortSignal;\n\n // Retry policy\n /** Retry policy for failed requests */\n readonly retryPolicy: RetryPolicy;\n}\n\n// =============================================================================\n// Telemetry Events\n// =============================================================================\n\n/**\n * Event emitted before a service request.\n */\nexport interface ServiceRequestEvent {\n service: string;\n action: string;\n key?: string;\n timestamp: number;\n}\n\n/**\n * Event emitted after a service response.\n */\nexport interface ServiceResponseEvent {\n service: string;\n action: string;\n ok: boolean;\n duration: number;\n status?: number;\n}\n\n/**\n * Event emitted on service error.\n */\nexport interface ServiceErrorEvent {\n service: string;\n error: ServiceError;\n}\n\n/**\n * Event emitted on retry attempt.\n */\nexport interface ServiceRetryEvent {\n service: string;\n attempt: number;\n maxAttempts: number;\n error: ServiceError;\n}\n\n/**\n * Telemetry event names.\n */\nexport const TelemetryEvents = {\n SERVICE_REQUEST: \"service.request\",\n SERVICE_RESPONSE: \"service.response\",\n SERVICE_ERROR: \"service.error\",\n SERVICE_RETRY: \"service.retry\",\n SESSION_CHANGED: \"session.changed\",\n SESSION_EXPIRED: \"session.expired\",\n} as const;\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Create a success result.\n */\nexport function ok<T>(data: T): Result<T> {\n return { ok: true, data };\n}\n\n/**\n * Create an error result.\n */\nexport function err<E = ServiceError>(error: E): Result<never, E> {\n return { ok: false, error };\n}\n\n/**\n * Create a ServiceError.\n */\nexport function serviceError(\n code: string,\n message: string,\n service: string,\n options?: { cause?: Error; meta?: Record<string, unknown> },\n): ServiceError {\n return {\n code,\n message,\n service,\n cause: options?.cause,\n meta: options?.meta,\n };\n}\n","/**\n * SDK Services - Error Utilities\n *\n * Utilities for creating and handling service errors.\n */\n\nimport { ServiceError, ErrorCodes, err, serviceError } from \"./types\";\n\n/**\n * Create a service error for authentication required.\n */\nexport function authRequiredError(service: string): ServiceError {\n return {\n code: ErrorCodes.AUTH_REQUIRED,\n message: \"Authentication required. Please sign in first.\",\n service,\n };\n}\n\n/**\n * Create a service error for expired authentication.\n */\nexport function authExpiredError(service: string): ServiceError {\n return {\n code: ErrorCodes.AUTH_EXPIRED,\n message: \"Session has expired. Please sign in again.\",\n service,\n };\n}\n\n/**\n * Create a service error for network issues.\n */\nexport function networkError(\n service: string,\n message: string,\n cause?: Error\n): ServiceError {\n return {\n code: ErrorCodes.NETWORK_ERROR,\n message,\n service,\n cause,\n };\n}\n\n/**\n * Create a service error for timeouts.\n */\nexport function timeoutError(service: string): ServiceError {\n return {\n code: ErrorCodes.TIMEOUT,\n message: \"Request timed out.\",\n service,\n };\n}\n\n/**\n * Create a service error for aborted requests.\n */\nexport function abortedError(service: string): ServiceError {\n return {\n code: ErrorCodes.ABORTED,\n message: \"Request was aborted.\",\n service,\n };\n}\n\n/**\n * Create a service error for not found resources.\n */\nexport function notFoundError(\n service: string,\n resource: string\n): ServiceError {\n return {\n code: ErrorCodes.NOT_FOUND,\n message: `Resource not found: ${resource}`,\n service,\n };\n}\n\n/**\n * Create a service error for permission denied.\n */\nexport function permissionDeniedError(\n service: string,\n action: string\n): ServiceError {\n return {\n code: ErrorCodes.PERMISSION_DENIED,\n message: `Permission denied for action: ${action}`,\n service,\n };\n}\n\n/**\n * Parse the server's \"Unauthorized Action: {resource} / {ability}\" pattern.\n */\nexport function parseAuthError(responseText: string): { resource?: string; action?: string } {\n const match = responseText.match(/^Unauthorized Action:\\s*(.+?)\\s*\\/\\s*(tinycloud\\.\\S+)$/m);\n if (match) {\n return { resource: match[1].trim(), action: match[2].trim() };\n }\n return {};\n}\n\n/**\n * Create a service error for unauthorized action (missing capability).\n */\nexport function authUnauthorizedError(\n service: string,\n message: string,\n meta?: Record<string, unknown>\n): ServiceError {\n return serviceError(ErrorCodes.AUTH_UNAUTHORIZED, message, service, { meta });\n}\n\n/**\n * Create a service error for storage quota exceeded (402 Payment Required).\n */\nexport function storageQuotaExceededError(\n service: string,\n message: string,\n meta?: Record<string, unknown>\n): ServiceError {\n return {\n code: ErrorCodes.STORAGE_QUOTA_EXCEEDED,\n message,\n service,\n meta,\n };\n}\n\n/**\n * Create a service error for storage limit reached (413 Payload Too Large).\n */\nexport function storageLimitReachedError(\n service: string,\n message: string,\n meta?: Record<string, unknown>\n): ServiceError {\n return {\n code: ErrorCodes.STORAGE_LIMIT_REACHED,\n message,\n service,\n meta,\n };\n}\n\n/**\n * Wrap an unknown error in a ServiceError.\n */\nexport function wrapError(\n service: string,\n error: unknown,\n defaultCode: string = ErrorCodes.NETWORK_ERROR\n): ServiceError {\n if (error instanceof Error) {\n // Check for abort errors\n if (error.name === \"AbortError\") {\n return abortedError(service);\n }\n\n // Check for timeout errors (varies by platform)\n if (\n error.name === \"TimeoutError\" ||\n error.message.toLowerCase().includes(\"timeout\")\n ) {\n return timeoutError(service);\n }\n\n return {\n code: defaultCode,\n message: error.message,\n service,\n cause: error,\n };\n }\n\n return {\n code: defaultCode,\n message: String(error),\n service,\n };\n}\n\n/**\n * Create an error Result from a ServiceError.\n */\nexport function errorResult(error: ServiceError) {\n return err(error);\n}\n","/**\n * BaseService - Abstract base class for all TinyCloud services.\n *\n * Provides common functionality:\n * - Context management\n * - Session lifecycle hooks\n * - Abort signal handling\n * - Telemetry emission\n */\n\nimport {\n IService,\n IServiceContext,\n ServiceSession,\n ServiceError,\n TelemetryEvents,\n err,\n Result,\n} from \"../types\";\nimport { authRequiredError, wrapError } from \"../errors\";\n\n/**\n * Abstract base class for TinyCloud services.\n *\n * Services extend this class to get common functionality like\n * context management, session lifecycle, and abort handling.\n *\n * @example\n * ```typescript\n * class MyService extends BaseService implements IMyService {\n * static readonly serviceName = 'myservice';\n *\n * constructor(config: MyServiceConfig = {}) {\n * super();\n * this._config = config;\n * }\n *\n * async doSomething(): Promise<Result<Data>> {\n * if (!this.requireAuth()) {\n * return err(authRequiredError('myservice'));\n * }\n * // ... implementation\n * }\n * }\n * ```\n */\nexport abstract class BaseService implements IService {\n /**\n * Service identifier used for registration.\n * Must be overridden by subclasses.\n */\n static readonly serviceName: string;\n\n /**\n * Service context providing access to platform dependencies.\n * Set during initialize().\n */\n protected context!: IServiceContext;\n\n /**\n * Abort controller for this service's operations.\n * Reset on sign-out.\n */\n protected abortController: AbortController = new AbortController();\n\n /**\n * Service-specific configuration.\n */\n protected _config: Record<string, unknown> = {};\n\n /**\n * Get the service configuration.\n */\n get config(): Record<string, unknown> {\n return this._config;\n }\n\n /**\n * Initialize the service with context.\n * Called by the SDK after instantiation.\n *\n * @param context - The service context\n */\n initialize(context: IServiceContext): void {\n this.context = context;\n }\n\n /**\n * Called when session changes (sign-in, sign-out, refresh).\n * Override in subclasses to handle session changes.\n *\n * @param session - The new session, or null if signed out\n */\n onSessionChange(session: ServiceSession | null): void {\n // Override in subclass if needed\n }\n\n /**\n * Called when SDK signs out.\n * Aborts all pending operations.\n */\n onSignOut(): void {\n this.abortController.abort();\n this.abortController = new AbortController();\n }\n\n /**\n * Get the abort signal for this service.\n * Combines the service-level abort with context-level abort.\n */\n protected get abortSignal(): AbortSignal {\n return this.abortController.signal;\n }\n\n /**\n * Check if the service is authenticated.\n */\n protected get isAuthenticated(): boolean {\n return this.context?.isAuthenticated ?? false;\n }\n\n /**\n * Get the current session.\n * Throws if not authenticated.\n */\n protected get session(): ServiceSession {\n if (!this.context?.session) {\n throw new Error(\"Not authenticated\");\n }\n return this.context.session;\n }\n\n /**\n * Check authentication and return error result if not authenticated.\n * Use this at the start of methods that require authentication.\n *\n * @returns true if authenticated, false otherwise\n */\n protected requireAuth(): boolean {\n return this.isAuthenticated;\n }\n\n /**\n * Emit a telemetry event.\n *\n * @param event - Event name\n * @param data - Event data\n */\n protected emit(event: string, data: unknown): void {\n this.context?.emit(event, data);\n }\n\n /**\n * Emit a service request event.\n *\n * @param action - The action being performed\n * @param key - Optional key/path being accessed\n */\n protected emitRequest(action: string, key?: string): void {\n this.emit(TelemetryEvents.SERVICE_REQUEST, {\n service: this.getServiceName(),\n action,\n key,\n timestamp: Date.now(),\n });\n }\n\n /**\n * Emit a service response event.\n *\n * @param action - The action that was performed\n * @param ok - Whether the request was successful\n * @param startTime - Start time for duration calculation\n * @param status - Optional HTTP status code\n */\n protected emitResponse(\n action: string,\n ok: boolean,\n startTime: number,\n status?: number\n ): void {\n this.emit(TelemetryEvents.SERVICE_RESPONSE, {\n service: this.getServiceName(),\n action,\n ok,\n duration: Date.now() - startTime,\n status,\n });\n }\n\n /**\n * Emit a service error event.\n *\n * @param error - The service error\n */\n protected emitError(error: ServiceError): void {\n this.emit(TelemetryEvents.SERVICE_ERROR, {\n service: this.getServiceName(),\n error,\n });\n }\n\n /**\n * Get the service name from the static property.\n * Subclasses must define static serviceName.\n */\n protected getServiceName(): string {\n return (this.constructor as typeof BaseService).serviceName;\n }\n\n /**\n * Create a combined abort signal from multiple sources.\n *\n * @param signals - Additional abort signals to combine\n * @returns A combined abort signal\n */\n protected combineSignals(...signals: (AbortSignal | undefined)[]): AbortSignal {\n const controller = new AbortController();\n const allSignals = [this.abortSignal, ...signals.filter(Boolean)] as AbortSignal[];\n\n for (const signal of allSignals) {\n if (signal.aborted) {\n controller.abort(signal.reason);\n return controller.signal;\n }\n signal.addEventListener(\"abort\", () => controller.abort(signal.reason), {\n once: true,\n });\n }\n\n return controller.signal;\n }\n\n /**\n * Wrap an operation with error handling and telemetry.\n *\n * @param action - The action name for telemetry\n * @param key - Optional key for telemetry\n * @param operation - The operation to execute\n * @returns Result of the operation\n */\n protected async withTelemetry<T>(\n action: string,\n key: string | undefined,\n operation: () => Promise<Result<T>>\n ): Promise<Result<T>> {\n const startTime = Date.now();\n this.emitRequest(action, key);\n\n try {\n const result = await operation();\n\n if (result.ok) {\n this.emitResponse(action, true, startTime);\n } else {\n this.emitResponse(action, false, startTime);\n this.emitError(result.error);\n }\n\n return result;\n } catch (error) {\n const serviceError = wrapError(this.getServiceName(), error);\n this.emitResponse(action, false, startTime);\n this.emitError(serviceError);\n return err(serviceError);\n }\n }\n}\n","/**\n * Canonical JSON serialization and content hashing for TinyCloud\n * encryption requests/responses.\n *\n * The node and SDK must agree byte-for-byte on the canonical form so\n * that body-hash bindings (`bodyHash`, `encryptedSymmetricKeyHash`,\n * `receiverPublicKeyHash`) verify on both sides.\n *\n * Canonical rules:\n * - Object keys are sorted lexicographically by code point.\n * - Strings are encoded with the JSON.stringify default (RFC 8259).\n * - Numbers are emitted via JSON.stringify; callers should restrict to\n * integers or use string fields for high-precision values.\n * - `undefined` properties are dropped. `null` is preserved.\n * - Arrays preserve element order.\n *\n * Hashing uses SHA-256 supplied by the caller (via an `EncryptionCrypto`\n * binding) so this module stays platform-agnostic.\n */\n\nexport type Json =\n | null\n | boolean\n | number\n | string\n | Json[]\n | { [key: string]: Json | undefined };\n\n/**\n * Produce the canonical JSON string for {@link value}. Object keys are\n * sorted, `undefined` properties are dropped, and primitive types are\n * encoded by `JSON.stringify`.\n */\nexport function canonicalize(value: Json | undefined): string {\n if (value === undefined) {\n return \"\";\n }\n return stringify(value);\n}\n\nfunction stringify(value: Json): string {\n if (value === null) return \"null\";\n switch (typeof value) {\n case \"boolean\":\n case \"number\":\n return JSON.stringify(value);\n case \"string\":\n return JSON.stringify(value);\n case \"object\": {\n if (Array.isArray(value)) {\n return `[${value.map(stringify).join(\",\")}]`;\n }\n const keys = Object.keys(value).sort();\n const parts: string[] = [];\n for (const k of keys) {\n const v = value[k];\n if (v === undefined) continue;\n parts.push(`${JSON.stringify(k)}:${stringify(v)}`);\n }\n return `{${parts.join(\",\")}}`;\n }\n default:\n throw new TypeError(\n `canonicalize: unsupported value type ${typeof value}`,\n );\n }\n}\n\nconst HEX = \"0123456789abcdef\";\n\nexport function hexEncode(bytes: Uint8Array): string {\n let out = \"\";\n for (let i = 0; i < bytes.length; i++) {\n const b = bytes[i];\n out += HEX[(b >> 4) & 0xf] + HEX[b & 0xf];\n }\n return out;\n}\n\nexport function hexDecode(hex: string): Uint8Array {\n if (hex.length % 2 !== 0) {\n throw new Error(\"hex string must have even length\");\n }\n const out = new Uint8Array(hex.length / 2);\n for (let i = 0; i < out.length; i++) {\n const hi = parseInt(hex[i * 2], 16);\n const lo = parseInt(hex[i * 2 + 1], 16);\n if (Number.isNaN(hi) || Number.isNaN(lo)) {\n throw new Error(\"invalid hex character\");\n }\n out[i] = (hi << 4) | lo;\n }\n return out;\n}\n\nexport function base64Encode(bytes: Uint8Array): string {\n // base64 (standard, not url-safe) so envelopes pass through JSON cleanly.\n // We avoid `btoa` to stay node-friendly without polyfills.\n const chars =\n \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n let out = \"\";\n for (let i = 0; i < bytes.length; i += 3) {\n const b0 = bytes[i];\n const b1 = i + 1 < bytes.length ? bytes[i + 1] : 0;\n const b2 = i + 2 < bytes.length ? bytes[i + 2] : 0;\n out += chars[(b0 >> 2) & 0x3f];\n out += chars[((b0 << 4) | (b1 >> 4)) & 0x3f];\n out += i + 1 < bytes.length ? chars[((b1 << 2) | (b2 >> 6)) & 0x3f] : \"=\";\n out += i + 2 < bytes.length ? chars[b2 & 0x3f] : \"=\";\n }\n return out;\n}\n\nexport function base64Decode(s: string): Uint8Array {\n const clean = s.replace(/[^A-Za-z0-9+/=]/g, \"\");\n const len = clean.length;\n if (len % 4 !== 0) {\n throw new Error(\"invalid base64 input\");\n }\n const padding =\n clean.endsWith(\"==\") ? 2 : clean.endsWith(\"=\") ? 1 : 0;\n const outLen = (len / 4) * 3 - padding;\n const out = new Uint8Array(outLen);\n const lookup: Record<string, number> = {};\n const chars =\n \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n for (let i = 0; i < chars.length; i++) lookup[chars[i]] = i;\n\n let outIdx = 0;\n for (let i = 0; i < len; i += 4) {\n const v0 = lookup[clean[i]] ?? 0;\n const v1 = lookup[clean[i + 1]] ?? 0;\n const v2 = clean[i + 2] === \"=\" ? 0 : (lookup[clean[i + 2]] ?? 0);\n const v3 = clean[i + 3] === \"=\" ? 0 : (lookup[clean[i + 3]] ?? 0);\n const b0 = (v0 << 2) | (v1 >> 4);\n const b1 = ((v1 & 0x0f) << 4) | (v2 >> 2);\n const b2 = ((v2 & 0x03) << 6) | v3;\n if (outIdx < outLen) out[outIdx++] = b0;\n if (outIdx < outLen) out[outIdx++] = b1;\n if (outIdx < outLen) out[outIdx++] = b2;\n }\n return out;\n}\n\nexport function utf8Encode(s: string): Uint8Array {\n return new TextEncoder().encode(s);\n}\n\nexport function utf8Decode(b: Uint8Array): string {\n return new TextDecoder().decode(b);\n}\n\n/**\n * Compute `hexEncode(sha256(canonicalize(value)))`. The SHA-256 binding\n * is injected so the module remains usable in both the WASM and pure-JS\n * paths.\n */\nexport function canonicalHashHex(\n sha256: (bytes: Uint8Array) => Uint8Array,\n value: Json,\n): string {\n const canonical = canonicalize(value);\n return hexEncode(sha256(utf8Encode(canonical)));\n}\n","/**\n * TinyCloud encryption network identifiers.\n *\n * A network id is `urn:tinycloud:encryption:<principal>:<network>` where\n * `principal` is a DID (typically `did:key:...`) and `network` is a\n * non-empty label drawn from `[a-z0-9][a-z0-9-]*`.\n *\n * The embedded principal is the root authority for the network: any\n * delegation chain ending in a `tinycloud.encryption/decrypt` grant on\n * the network must root at this principal.\n */\n\nconst URN_PREFIX = \"urn:tinycloud:encryption:\";\nconst NETWORK_NAME_RE = /^[a-z0-9][a-z0-9-]*$/;\n\nexport interface ParsedNetworkId {\n /** The full URN string. */\n networkId: string;\n /** Principal DID embedded in the URN (the network's root authority). */\n principal: string;\n /** Network label (the suffix after the principal). */\n name: string;\n}\n\nexport class NetworkIdError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"NetworkIdError\";\n }\n}\n\n/**\n * Parse a network id string into its principal and name components.\n *\n * Throws {@link NetworkIdError} when the input does not match\n * `urn:tinycloud:encryption:<did>:<name>`, when the embedded DID is\n * malformed, or when the network name fails {@link NETWORK_NAME_RE}.\n */\nexport function parseNetworkId(networkId: string): ParsedNetworkId {\n if (typeof networkId !== \"string\" || networkId.length === 0) {\n throw new NetworkIdError(\"networkId must be a non-empty string\");\n }\n if (!networkId.startsWith(URN_PREFIX)) {\n throw new NetworkIdError(\n `networkId must start with ${URN_PREFIX} (got ${JSON.stringify(networkId)})`,\n );\n }\n const body = networkId.slice(URN_PREFIX.length);\n // `body` = \"<principal>:<network>\"\n // principal contains ':' (e.g. did:key:z6Mk...), so we split on the LAST colon\n // and treat the suffix as the network name.\n const lastColon = body.lastIndexOf(\":\");\n if (lastColon <= 0 || lastColon === body.length - 1) {\n throw new NetworkIdError(\n `networkId missing principal or name segment (got ${JSON.stringify(networkId)})`,\n );\n }\n const principal = body.slice(0, lastColon);\n const name = body.slice(lastColon + 1);\n\n if (!principal.startsWith(\"did:\")) {\n throw new NetworkIdError(\n `networkId principal must be a DID (got ${JSON.stringify(principal)})`,\n );\n }\n // Minimal DID shape: did:<method>:<id> — three colon-separated segments,\n // each non-empty.\n const didParts = principal.split(\":\");\n if (didParts.length < 3 || didParts.some((p) => p.length === 0)) {\n throw new NetworkIdError(\n `networkId principal is not a well-formed DID (got ${JSON.stringify(principal)})`,\n );\n }\n if (!NETWORK_NAME_RE.test(name)) {\n throw new NetworkIdError(\n `networkId name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`,\n );\n }\n return { networkId, principal, name };\n}\n\n/**\n * Construct a network id URN from a principal DID and a network name.\n * Validates inputs and throws {@link NetworkIdError} on bad shape.\n */\nexport function buildNetworkId(principal: string, name: string): string {\n if (typeof principal !== \"string\" || !principal.startsWith(\"did:\")) {\n throw new NetworkIdError(\"principal must be a DID\");\n }\n if (typeof name !== \"string\" || !NETWORK_NAME_RE.test(name)) {\n throw new NetworkIdError(\n `network name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`,\n );\n }\n const networkId = `${URN_PREFIX}${principal}:${name}`;\n // Re-validate the composed result so the same error path triggers\n // for caller inputs that compose into a malformed URN.\n parseNetworkId(networkId);\n return networkId;\n}\n\n/**\n * Returns true when {@link networkId} is a syntactically valid network URN.\n */\nexport function isNetworkId(networkId: unknown): networkId is string {\n if (typeof networkId !== \"string\") {\n return false;\n }\n try {\n parseNetworkId(networkId);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Resolve the discovery key used to look up a network's descriptor under\n * a principal's public account-space.\n *\n * Format: `.well-known/encryption/network/<name>`.\n */\nexport function networkDiscoveryKey(name: string): string {\n if (!NETWORK_NAME_RE.test(name)) {\n throw new NetworkIdError(\n `network name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`,\n );\n }\n return `.well-known/encryption/network/${name}`;\n}\n\nexport const ENCRYPTION_NETWORK_URN_PREFIX = URN_PREFIX;\nexport const NETWORK_NAME_PATTERN = NETWORK_NAME_RE;\n","/**\n * Type definitions for TinyCloud one-of-one encryption.\n *\n * Wire shapes mirror the protocol described in the encryption\n * architecture: inline envelopes carry the encrypted symmetric key\n * alongside the ciphertext; decrypt requests are short-lived UCAN\n * invocations against a target node plus networkId.\n */\n\nimport type { Json } from \"./canonical\";\n\n/** Default ciphersuite identifier for v1 envelopes. */\nexport const DEFAULT_ENCRYPTION_ALG = \"x25519-aes256gcm/v1\" as const;\n\n/** Inline-envelope schema version. */\nexport const ENVELOPE_VERSION = 1 as const;\n\n/** Default key version on freshly-created networks. */\nexport const DEFAULT_KEY_VERSION = 1 as const;\n\n/** Decrypt-invocation fact type. */\nexport const DECRYPT_FACT_TYPE = \"tinycloud.encryption.decrypt/v1\" as const;\n\n/** Decrypt response type. */\nexport const DECRYPT_RESULT_TYPE =\n \"tinycloud.encryption.decrypt-result/v1\" as const;\n\n/** Encryption service identifier (manifest long form). */\nexport const ENCRYPTION_SERVICE = \"tinycloud.encryption\" as const;\n\n/** Short form used in recap/abilities maps. */\nexport const ENCRYPTION_SERVICE_SHORT = \"encryption\" as const;\n\n/** Decrypt ability URN. */\nexport const DECRYPT_ACTION = \"tinycloud.encryption/decrypt\" as const;\n\n/**\n * Inline encrypted envelope persisted in KV/SQL records.\n *\n * - `encryptedSymmetricKey` is opaque to the SDK; only the network can\n * unwrap it.\n * - `encryptedSymmetricKeyHash` is the canonical hash of the wrapped key\n * bytes (hex-encoded sha-256 of the base64 string's canonical JSON\n * form). The node recomputes this on every decrypt request.\n * - `ciphertext` and `aad` are payload bytes only; the node never sees\n * them.\n */\nexport interface InlineEncryptedEnvelope {\n /** Schema version. */\n v: typeof ENVELOPE_VERSION;\n /** Network id URN. */\n networkId: string;\n /** Ciphersuite identifier. */\n alg: string;\n /** Network key version that was used to wrap the symmetric key. */\n keyVersion: number;\n /** Base64-encoded wrapped symmetric key / capsule. */\n encryptedSymmetricKey: string;\n /** Hex sha-256 of the canonical encryptedSymmetricKey string. */\n encryptedSymmetricKeyHash: string;\n /** Base64-encoded payload ciphertext. */\n ciphertext: string;\n /** Base64-encoded associated data, if any. */\n aad?: string;\n /** Caller-supplied metadata. Not authenticated against the node. */\n metadata?: Record<string, string>;\n}\n\n/**\n * Node-published network descriptor. The node DB is authoritative; a\n * cached copy may also live under\n * `.well-known/encryption/network/<name>` in the principal's account\n * space (a discovery record only).\n */\nexport interface NetworkDescriptor {\n networkId: string;\n principal: string;\n name: string;\n members: ReadonlyArray<{ nodeId: string; role: \"primary\" | \"share\" }>;\n threshold: { n: number; t: number };\n state: \"pending\" | \"generating\" | \"active\" | \"rotating\" | \"revoked\" | \"failed\";\n /** Base64-encoded network public key. */\n publicEncryptionKey: string;\n alg: string;\n keyVersion: number;\n keyBackend: \"local-one-of-one\" | \"dstack\" | \"threshold\";\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Decrypt-request body sent over the wire. Hashed (canonically) and\n * bound to the UCAN invocation via `facts.bodyHash`.\n */\nexport interface DecryptRequestBody {\n type: typeof DECRYPT_FACT_TYPE;\n targetNode: string;\n networkId: string;\n alg: string;\n keyVersion: number;\n /** Base64-encoded wrapped symmetric key from the envelope. */\n encryptedSymmetricKey: string;\n /** Recomputed hash of the wrapped key. */\n encryptedSymmetricKeyHash: string;\n /** Base64-encoded per-request receiver public key. */\n receiverPublicKey: string;\n /** Hash of the receiver public key. */\n receiverPublicKeyHash: string;\n}\n\n/**\n * Decrypt-response body returned by the node. The SDK verifies the\n * signature, recomputes hashes, then unwraps `wrappedKey` with the\n * per-request receiver private key before decrypting the payload.\n */\nexport interface DecryptResponseBody {\n type: typeof DECRYPT_RESULT_TYPE;\n targetNode: string;\n networkId: string;\n invocationCid: string;\n encryptedSymmetricKeyHash: string;\n receiverPublicKeyHash: string;\n /** Base64-encoded symmetric key re-encrypted to receiverPublicKey. */\n wrappedKey: string;\n alg: string;\n keyVersion: number;\n requestHash: string;\n nodeId: string;\n /** Base64-encoded ed25519 signature over canonical(response - signature field). */\n nodeSignature: string;\n}\n\n/**\n * Decrypt-invocation facts attached to the UCAN. Verifiers recompute\n * `bodyHash`, `encryptedSymmetricKeyHash`, and `receiverPublicKeyHash`\n * from the request body and reject any mismatch.\n */\nexport interface DecryptInvocationFact {\n type: typeof DECRYPT_FACT_TYPE;\n targetNode: string;\n networkId: string;\n bodyHash: string;\n encryptedSymmetricKeyHash: string;\n receiverPublicKeyHash: string;\n alg: string;\n keyVersion: number;\n}\n\n/**\n * Per-request receiver key pair (x25519). The private key never\n * leaves the SDK; the public key is sent to the node so the node can\n * rewrap the symmetric key.\n */\nexport interface ReceiverKeyPair {\n publicKey: Uint8Array;\n privateKey: Uint8Array;\n}\n\n/**\n * Crypto primitives injected into the encryption module. The SDK\n * provides these via WASM bindings; tests provide simple in-memory\n * implementations.\n */\nexport interface EncryptionCrypto {\n /** SHA-256 → 32-byte digest. */\n sha256(data: Uint8Array): Uint8Array;\n /** Cryptographically secure random bytes. */\n randomBytes(length: number): Uint8Array;\n /** Derive an x25519 key pair from a 32-byte seed. */\n x25519FromSeed(seed: Uint8Array): ReceiverKeyPair;\n /** Compute the x25519 ECDH shared secret. */\n x25519Dh(privateKey: Uint8Array, publicKey: Uint8Array): Uint8Array;\n /** Authenticated symmetric encryption (the node's symmetric scheme). */\n authEncrypt(\n key: Uint8Array,\n plaintext: Uint8Array,\n aad?: Uint8Array,\n ): Uint8Array;\n /** Authenticated symmetric decryption (matched to authEncrypt). */\n authDecrypt(\n key: Uint8Array,\n ciphertext: Uint8Array,\n aad?: Uint8Array,\n ): Uint8Array;\n /**\n * Wrap a symmetric key for the network's public encryption key using\n * a sealed-box / hpke / x25519+symmetric construction. Implementation\n * is opaque; only the node can unwrap.\n */\n sealToNetworkKey(\n networkPublicKey: Uint8Array,\n symmetricKey: Uint8Array,\n ): Uint8Array;\n /**\n * Open a wrapped symmetric key that was re-encrypted to the\n * per-request receiver public key. The matching private key must be\n * supplied here; the SDK never sends it to the node.\n */\n openWithReceiverKey(\n receiverPrivateKey: Uint8Array,\n wrappedKey: Uint8Array,\n ): Uint8Array;\n /**\n * Verify an ed25519 signature over `message` produced by the node\n * identified by `nodeId` (the public-key DID).\n */\n verifyNodeSignature(\n nodeId: string,\n message: Uint8Array,\n signature: Uint8Array,\n ): boolean;\n}\n\n/**\n * Signer interface used to derive a receiver key pair from a wallet or\n * session signer. The signature is HKDF-extracted into the receiver\n * seed so the public key is reproducible given the same context.\n */\nexport interface ReceiverKeySigner {\n signMessage(message: string): Promise<string>;\n}\n\n/** Capability proof material accompanying a decrypt invocation. */\nexport interface DecryptCapabilityProof {\n /** Delegation chain CIDs rooted at the network principal. */\n proofs: ReadonlyArray<string>;\n /** Optional Authorization header value to use instead of building one. */\n authorization?: string;\n}\n\n/**\n * Inputs to the decrypt invocation builder.\n */\nexport interface BuildDecryptInvocationInput {\n /** Target node DID — also the UCAN audience. */\n targetNode: string;\n /** Network id URN — also the recap resource. */\n networkId: string;\n /** Canonical body that will be POSTed. */\n body: DecryptRequestBody;\n /** Facts include hashes bound to the canonical body. */\n facts: DecryptInvocationFact;\n /** Capability proof chain. */\n proof: DecryptCapabilityProof;\n /** Optional `nbf` UCAN field as an ISO date string. */\n notBefore?: string;\n /** Optional `exp` UCAN field as an ISO date string. */\n expiration?: string;\n}\n\n/**\n * The output of {@link buildDecryptInvocation}.\n */\nexport interface BuiltDecryptInvocation {\n /** HTTP `Authorization` header value. */\n authorization: string;\n /** CID of the invocation (used by the node response binding). */\n invocationCid: string;\n /** Canonical body string the node will hash. */\n canonicalBody: string;\n}\n\n/**\n * Signer interface for producing the decrypt invocation. WASM bindings\n * implement this with the same session signer used for KV/SQL\n * invocations; tests can stub it.\n */\nexport interface DecryptInvocationSigner {\n signDecryptInvocation(input: BuildDecryptInvocationInput): Promise<BuiltDecryptInvocation>;\n}\n\n/**\n * Errors thrown / returned from the encryption module.\n */\nexport type EncryptionErrorInput =\n | { code: \"NETWORK_NOT_FOUND\"; networkId?: string; name?: string; message?: string }\n | { code: \"NETWORK_NOT_ACTIVE\"; state: string; message?: string }\n | { code: \"INVALID_NETWORK_ID\"; message: string }\n | { code: \"INVALID_ENVELOPE\"; message: string }\n | { code: \"DECRYPT_DENIED\"; message: string }\n | { code: \"INVALID_RESPONSE\"; message: string }\n | { code: \"RESPONSE_SIGNATURE_INVALID\"; message?: string }\n | { code: \"RESPONSE_BINDING_MISMATCH\"; field: string; message?: string }\n | { code: \"TRANSPORT_ERROR\"; cause: Error; message?: string }\n | { code: \"INVALID_INPUT\"; message: string };\n\nexport type EncryptionError = EncryptionErrorInput & {\n service: \"encryption\";\n message: string;\n};\n\nfunction defaultEncryptionMessage(input: EncryptionErrorInput): string {\n switch (input.code) {\n case \"NETWORK_NOT_FOUND\":\n return (\n input.message ??\n `Network not found: ${input.networkId ?? input.name ?? \"<unknown>\"}`\n );\n case \"NETWORK_NOT_ACTIVE\":\n return input.message ?? `Network not active (state=${input.state})`;\n case \"INVALID_NETWORK_ID\":\n return input.message;\n case \"INVALID_ENVELOPE\":\n return input.message;\n case \"DECRYPT_DENIED\":\n return input.message;\n case \"INVALID_RESPONSE\":\n return input.message;\n case \"RESPONSE_SIGNATURE_INVALID\":\n return input.message ?? \"Node response signature failed to verify\";\n case \"RESPONSE_BINDING_MISMATCH\":\n return (\n input.message ??\n `Node response binding mismatch on field ${JSON.stringify(input.field)}`\n );\n case \"TRANSPORT_ERROR\":\n return input.message ?? input.cause.message;\n case \"INVALID_INPUT\":\n return input.message;\n }\n}\n\nexport function encryptionError(input: EncryptionErrorInput): EncryptionError {\n return {\n ...input,\n service: \"encryption\",\n message: defaultEncryptionMessage(input),\n };\n}\n\n/** Helper for the test/runtime layers to coerce arbitrary throwables. */\nexport function toError(error: unknown): Error {\n if (error instanceof Error) return error;\n if (typeof error === \"object\" && error !== null) {\n return new Error(JSON.stringify(error));\n }\n return new Error(String(error));\n}\n\n/** Re-export for ergonomic typing of canonical payloads. */\nexport type CanonicalJson = Json;\n","/**\n * Network-descriptor discovery.\n *\n * Resolution order (per architecture):\n *\n * 1. The node's authoritative endpoint\n * `GET /encryption/networks/<networkId>` returns the current\n * descriptor (`state`, `publicEncryptionKey`, `keyVersion`, ...).\n * 2. If the node is unreachable, fall back to the cached discovery\n * record at `.well-known/encryption/network/<name>` inside the\n * principal's public space.\n *\n * The node DB is authoritative on conflict; cached records are\n * advisory only.\n */\n\nimport {\n NetworkIdError,\n networkDiscoveryKey,\n parseNetworkId,\n} from \"./networkId\";\nimport {\n encryptionError,\n type EncryptionError,\n type NetworkDescriptor,\n} from \"./types\";\n\nexport type DiscoverySource = \"node\" | \"well-known\";\n\nexport interface DiscoveredNetwork {\n descriptor: NetworkDescriptor;\n source: DiscoverySource;\n}\n\nexport interface NodeDescriptorFetcher {\n /** Fetch the descriptor by full networkId URN. */\n fetchByNetworkId(networkId: string): Promise<NetworkDescriptor | null>;\n}\n\nexport interface WellKnownDescriptorFetcher {\n /**\n * Read the cached well-known descriptor by principal + network name.\n * Returns null if no record exists or the record is unreadable.\n */\n fetchWellKnown(\n principal: string,\n discoveryKey: string,\n ): Promise<NetworkDescriptor | null>;\n}\n\nexport interface DiscoverNetworkInput {\n /** Either a networkId URN or a bare network name (paired with `principal`). */\n identifier: string;\n /** Required when identifier is a bare name. */\n principal?: string;\n node?: NodeDescriptorFetcher;\n wellKnown?: WellKnownDescriptorFetcher;\n}\n\n/**\n * Resolve a network descriptor. The node fetcher is preferred; the\n * well-known fallback is used only on transport failure.\n *\n * The returned descriptor is sanity-checked: `networkId`, `principal`,\n * and `name` must agree with the URN, and the public key field must\n * be non-empty.\n */\nexport async function discoverNetwork(\n input: DiscoverNetworkInput,\n):\n | Promise<{ ok: true; data: DiscoveredNetwork } | { ok: false; error: EncryptionError }> {\n let networkId: string;\n let principal: string;\n let name: string;\n try {\n if (input.identifier.startsWith(\"urn:tinycloud:encryption:\")) {\n const parsed = parseNetworkId(input.identifier);\n networkId = parsed.networkId;\n principal = parsed.principal;\n name = parsed.name;\n } else {\n if (input.principal === undefined) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_INPUT\",\n message:\n \"discoverNetwork requires `principal` when identifier is a bare network name\",\n }),\n };\n }\n networkId = `urn:tinycloud:encryption:${input.principal}:${input.identifier}`;\n const parsed = parseNetworkId(networkId);\n principal = parsed.principal;\n name = parsed.name;\n }\n } catch (err) {\n if (err instanceof NetworkIdError) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_NETWORK_ID\",\n message: err.message,\n }),\n };\n }\n throw err;\n }\n\n // 1) Try the node first.\n if (input.node !== undefined) {\n try {\n const descriptor = await input.node.fetchByNetworkId(networkId);\n if (descriptor !== null) {\n const validated = validateDescriptor(descriptor, networkId, principal, name);\n if (!validated.ok) return validated;\n return { ok: true, data: { descriptor: validated.data, source: \"node\" } };\n }\n } catch (err) {\n // Fall through to well-known\n }\n }\n\n // 2) Fallback to well-known cache.\n if (input.wellKnown !== undefined) {\n try {\n const descriptor = await input.wellKnown.fetchWellKnown(\n principal,\n networkDiscoveryKey(name),\n );\n if (descriptor !== null) {\n const validated = validateDescriptor(descriptor, networkId, principal, name);\n if (!validated.ok) return validated;\n return {\n ok: true,\n data: { descriptor: validated.data, source: \"well-known\" },\n };\n }\n } catch (err) {\n // Fall through to NOT_FOUND\n }\n }\n\n return {\n ok: false,\n error: encryptionError({\n code: \"NETWORK_NOT_FOUND\",\n networkId,\n name,\n }),\n };\n}\n\nfunction validateDescriptor(\n descriptor: NetworkDescriptor,\n networkId: string,\n principal: string,\n name: string,\n):\n | { ok: true; data: NetworkDescriptor }\n | { ok: false; error: EncryptionError } {\n if (descriptor.networkId !== networkId) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_NETWORK_ID\",\n message: `descriptor networkId ${JSON.stringify(descriptor.networkId)} does not match expected ${JSON.stringify(networkId)}`,\n }),\n };\n }\n if (descriptor.principal !== principal) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_NETWORK_ID\",\n message: \"descriptor principal does not match networkId principal\",\n }),\n };\n }\n if (descriptor.name !== name) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_NETWORK_ID\",\n message: \"descriptor name does not match networkId name\",\n }),\n };\n }\n if (\n typeof descriptor.publicEncryptionKey !== \"string\" ||\n descriptor.publicEncryptionKey.length === 0\n ) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_NETWORK_ID\",\n message: \"descriptor publicEncryptionKey must be a non-empty string\",\n }),\n };\n }\n return { ok: true, data: descriptor };\n}\n\n/**\n * Reject a descriptor that is not in a state that accepts decrypt\n * requests. Only `active` and `rotating` networks may decrypt; revoked\n * or pending networks reject.\n */\nexport function ensureNetworkUsableForDecrypt(\n descriptor: NetworkDescriptor,\n):\n | { ok: true; data: NetworkDescriptor }\n | { ok: false; error: EncryptionError } {\n if (descriptor.state === \"active\" || descriptor.state === \"rotating\") {\n return { ok: true, data: descriptor };\n }\n return {\n ok: false,\n error: encryptionError({\n code: \"NETWORK_NOT_ACTIVE\",\n state: descriptor.state,\n }),\n };\n}\n","/**\n * Inline-envelope encrypt / decrypt helpers.\n *\n * Encryption is fully local: the SDK generates a per-record symmetric\n * key, encrypts the payload, then wraps the symmetric key against the\n * network's public encryption key. The wrapped key (and key hash)\n * travels alongside the ciphertext inside an\n * {@link InlineEncryptedEnvelope}.\n *\n * Decryption is split: the node unwraps the symmetric key to the\n * per-request receiver public key (see {@link buildDecryptInvocation}\n * and the decrypt route); this module is responsible for the local\n * payload decryption once the symmetric key is available.\n */\n\nimport {\n base64Decode,\n base64Encode,\n canonicalHashHex,\n} from \"./canonical\";\nimport {\n DEFAULT_ENCRYPTION_ALG,\n DEFAULT_KEY_VERSION,\n ENVELOPE_VERSION,\n encryptionError,\n type EncryptionCrypto,\n type EncryptionError,\n type InlineEncryptedEnvelope,\n} from \"./types\";\nimport { parseNetworkId } from \"./networkId\";\n\nexport interface EncryptToNetworkInput {\n /** Target network id URN. */\n networkId: string;\n /** Network public key bytes (already discovered). */\n networkPublicKey: Uint8Array;\n /** Payload bytes to encrypt. Callers serialize objects to bytes themselves. */\n plaintext: Uint8Array;\n /** Optional associated authenticated data. */\n aad?: Uint8Array;\n /** Ciphersuite identifier. Defaults to {@link DEFAULT_ENCRYPTION_ALG}. */\n alg?: string;\n /** Key version. Defaults to {@link DEFAULT_KEY_VERSION}. */\n keyVersion?: number;\n /** Caller-supplied envelope metadata. */\n metadata?: Record<string, string>;\n}\n\nexport interface EncryptToNetworkResult {\n envelope: InlineEncryptedEnvelope;\n /** Symmetric key returned for caller bookkeeping; do NOT persist. */\n symmetricKey: Uint8Array;\n}\n\n/**\n * Local-only encrypt: generates a symmetric key, encrypts the payload,\n * wraps the key against the network public key, and returns the\n * inline envelope.\n */\nexport function encryptToNetwork(\n crypto: EncryptionCrypto,\n input: EncryptToNetworkInput,\n): EncryptToNetworkResult {\n parseNetworkId(input.networkId);\n const alg = input.alg ?? DEFAULT_ENCRYPTION_ALG;\n const keyVersion = input.keyVersion ?? DEFAULT_KEY_VERSION;\n\n const symmetricKey = crypto.randomBytes(32);\n const ciphertext = crypto.authEncrypt(symmetricKey, input.plaintext, input.aad);\n const wrapped = crypto.sealToNetworkKey(input.networkPublicKey, symmetricKey);\n const encryptedSymmetricKey = base64Encode(wrapped);\n const encryptedSymmetricKeyHash = canonicalHashHex(\n crypto.sha256,\n encryptedSymmetricKey,\n );\n\n const envelope: InlineEncryptedEnvelope = {\n v: ENVELOPE_VERSION,\n networkId: input.networkId,\n alg,\n keyVersion,\n encryptedSymmetricKey,\n encryptedSymmetricKeyHash,\n ciphertext: base64Encode(ciphertext),\n ...(input.aad !== undefined ? { aad: base64Encode(input.aad) } : {}),\n ...(input.metadata !== undefined ? { metadata: input.metadata } : {}),\n };\n\n return { envelope, symmetricKey };\n}\n\n/**\n * Validate an inline envelope shape. Returns an error if the envelope\n * is missing required fields or fails internal hash recomputation.\n */\nexport function validateEnvelope(\n crypto: EncryptionCrypto,\n envelope: unknown,\n): { ok: true; data: InlineEncryptedEnvelope } | { ok: false; error: EncryptionError } {\n if (envelope === null || typeof envelope !== \"object\") {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_ENVELOPE\",\n message: \"envelope must be an object\",\n }),\n };\n }\n const e = envelope as InlineEncryptedEnvelope;\n if (e.v !== ENVELOPE_VERSION) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_ENVELOPE\",\n message: `envelope.v must be ${ENVELOPE_VERSION} (got ${e.v as unknown as string})`,\n }),\n };\n }\n try {\n parseNetworkId(e.networkId);\n } catch (err) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_ENVELOPE\",\n message: `envelope.networkId is malformed: ${\n err instanceof Error ? err.message : String(err)\n }`,\n }),\n };\n }\n for (const field of [\n \"alg\",\n \"encryptedSymmetricKey\",\n \"encryptedSymmetricKeyHash\",\n \"ciphertext\",\n ] as const) {\n if (typeof e[field] !== \"string\" || (e[field] as string).length === 0) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_ENVELOPE\",\n message: `envelope.${field} must be a non-empty string`,\n }),\n };\n }\n }\n if (typeof e.keyVersion !== \"number\" || !Number.isInteger(e.keyVersion)) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_ENVELOPE\",\n message: \"envelope.keyVersion must be an integer\",\n }),\n };\n }\n const expectedHash = canonicalHashHex(crypto.sha256, e.encryptedSymmetricKey);\n if (expectedHash !== e.encryptedSymmetricKeyHash) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_ENVELOPE\",\n message:\n \"envelope.encryptedSymmetricKeyHash does not match canonical hash of encryptedSymmetricKey\",\n }),\n };\n }\n return { ok: true, data: e };\n}\n\n/**\n * Decrypt an inline envelope given the unwrapped symmetric key.\n *\n * Callers typically obtain the symmetric key via the node decrypt\n * endpoint plus the per-request receiver key pair (see\n * `EncryptionService.decryptEnvelope`).\n */\nexport function decryptEnvelopeWithKey(\n crypto: EncryptionCrypto,\n envelope: InlineEncryptedEnvelope,\n symmetricKey: Uint8Array,\n): Uint8Array {\n const ciphertext = base64Decode(envelope.ciphertext);\n const aad = envelope.aad !== undefined ? base64Decode(envelope.aad) : undefined;\n return crypto.authDecrypt(symmetricKey, ciphertext, aad);\n}\n","/**\n * TinyCloud encryption decrypt-invocation builder.\n *\n * The decrypt invocation is a UCAN-style TinyCloud invocation against\n * a node plus a network id. It is structurally distinct from the\n * existing space-shaped invocations:\n *\n * - `aud` (audience) is the **target node DID** (not a space owner).\n * - `att` (attenuation) uses the **networkId URN** as the resource\n * key (not a `tinycloud:pkh:...:<space>` URI).\n * - `fct` (facts) binds `bodyHash`, `encryptedSymmetricKeyHash`, and\n * `receiverPublicKeyHash` so the node can recompute them from the\n * POST body.\n *\n * Production callers inject a `DecryptInvocationSigner` backed by the\n * WASM UCAN/session signer. Tests pass a deterministic stub.\n */\n\nimport { canonicalize, canonicalHashHex, hexEncode, utf8Encode } from \"./canonical\";\nimport { parseNetworkId } from \"./networkId\";\nimport {\n DECRYPT_ACTION,\n DECRYPT_FACT_TYPE,\n ENCRYPTION_SERVICE,\n encryptionError,\n type BuildDecryptInvocationInput,\n type BuiltDecryptInvocation,\n type CanonicalJson,\n type DecryptCapabilityProof,\n type DecryptInvocationFact,\n type DecryptInvocationSigner,\n type DecryptRequestBody,\n type EncryptionCrypto,\n type EncryptionError,\n} from \"./types\";\n\nexport interface CanonicalDecryptRequest {\n /** The canonical body that the node will hash. */\n canonicalBody: string;\n /** Hex sha-256 of the canonical body bytes. */\n bodyHash: string;\n /** Hex sha-256 of the receiver public key bytes. */\n receiverPublicKeyHash: string;\n}\n\nexport interface BuildCanonicalDecryptRequestInput {\n crypto: EncryptionCrypto;\n body: DecryptRequestBody;\n receiverPublicKey: Uint8Array;\n}\n\n/**\n * Build the canonical body string and its bound hashes for a decrypt\n * request. The output is what gets POSTed to the node, and what the\n * node will hash to verify `facts.bodyHash`.\n */\nexport function buildCanonicalDecryptRequest(\n input: BuildCanonicalDecryptRequestInput,\n): CanonicalDecryptRequest {\n const canonicalBody = canonicalize(input.body as unknown as CanonicalJson);\n const bodyHash = canonicalHashHex(\n input.crypto.sha256,\n input.body as unknown as CanonicalJson,\n );\n const receiverPublicKeyHash = canonicalHashHex(\n input.crypto.sha256,\n input.body.receiverPublicKey,\n );\n return { canonicalBody, bodyHash, receiverPublicKeyHash };\n}\n\nexport interface BuildDecryptFactsInput {\n crypto: EncryptionCrypto;\n body: DecryptRequestBody;\n /** Encrypted symmetric key hash from the envelope (already canonical). */\n encryptedSymmetricKeyHash: string;\n /** Receiver public key bytes. */\n receiverPublicKey: Uint8Array;\n /** Canonical body string used to derive bodyHash. */\n canonicalBody?: string;\n}\n\n/**\n * Build the {@link DecryptInvocationFact} that will be embedded in the\n * UCAN `fct` field. Hashes are recomputed here so callers cannot drift\n * from the canonical body without the node noticing.\n */\nexport function buildDecryptFacts(\n input: BuildDecryptFactsInput,\n): DecryptInvocationFact {\n // When a precomputed canonicalBody string is supplied, hash its bytes\n // directly. Don't route it through canonicalHashHex, which would\n // re-canonicalize the string itself (escaping it as a JSON value).\n const bodyHash =\n input.canonicalBody !== undefined\n ? hexEncode(input.crypto.sha256(utf8Encode(input.canonicalBody)))\n : canonicalHashHex(\n input.crypto.sha256,\n input.body as unknown as CanonicalJson,\n );\n const receiverPublicKeyHash = canonicalHashHex(\n input.crypto.sha256,\n input.body.receiverPublicKey,\n );\n return {\n type: DECRYPT_FACT_TYPE,\n targetNode: input.body.targetNode,\n networkId: input.body.networkId,\n bodyHash,\n encryptedSymmetricKeyHash: input.encryptedSymmetricKeyHash,\n receiverPublicKeyHash,\n alg: input.body.alg,\n keyVersion: input.body.keyVersion,\n };\n}\n\n/**\n * Recap-shaped attenuation for the decrypt invocation. The resource\n * key is the networkId URN; the ability is the long-form\n * `tinycloud.encryption/decrypt`. This is intentionally distinct from\n * the existing space-shaped invocation map so callers cannot\n * accidentally fake a space prefix.\n */\nexport function buildDecryptAttenuation(\n networkId: string,\n): Record<string, Record<string, Record<string, never>>> {\n parseNetworkId(networkId);\n return {\n [networkId]: {\n [DECRYPT_ACTION]: {},\n },\n };\n}\n\n/**\n * Validate a {@link BuildDecryptInvocationInput} payload — the body\n * shape, the facts bindings, and the audience contract — without\n * actually signing. Returns either the input (typed) or a structured\n * error so callers can short-circuit before calling into WASM.\n */\nexport function checkDecryptInvocationInput(\n crypto: EncryptionCrypto,\n input: BuildDecryptInvocationInput,\n):\n | { ok: true; data: BuildDecryptInvocationInput; canonicalBody: string }\n | { ok: false; error: EncryptionError } {\n if (input.body.type !== DECRYPT_FACT_TYPE) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_INPUT\",\n message: `body.type must be ${DECRYPT_FACT_TYPE}`,\n }),\n };\n }\n if (input.facts.type !== DECRYPT_FACT_TYPE) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_INPUT\",\n message: `facts.type must be ${DECRYPT_FACT_TYPE}`,\n }),\n };\n }\n if (input.facts.targetNode !== input.targetNode) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_INPUT\",\n message:\n \"facts.targetNode must equal targetNode — the UCAN audience binds the request to a single node\",\n }),\n };\n }\n if (input.body.targetNode !== input.targetNode) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_INPUT\",\n message: \"body.targetNode must equal targetNode\",\n }),\n };\n }\n if (input.facts.networkId !== input.networkId) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_INPUT\",\n message: \"facts.networkId must equal networkId\",\n }),\n };\n }\n if (input.body.networkId !== input.networkId) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_INPUT\",\n message: \"body.networkId must equal networkId\",\n }),\n };\n }\n if (input.facts.alg !== input.body.alg) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_INPUT\",\n message: \"facts.alg must equal body.alg\",\n }),\n };\n }\n if (input.facts.keyVersion !== input.body.keyVersion) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_INPUT\",\n message: \"facts.keyVersion must equal body.keyVersion\",\n }),\n };\n }\n if (\n input.facts.encryptedSymmetricKeyHash !==\n input.body.encryptedSymmetricKeyHash\n ) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_INPUT\",\n message:\n \"facts.encryptedSymmetricKeyHash must equal body.encryptedSymmetricKeyHash\",\n }),\n };\n }\n if (\n input.facts.receiverPublicKeyHash !== input.body.receiverPublicKeyHash\n ) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_INPUT\",\n message:\n \"facts.receiverPublicKeyHash must equal body.receiverPublicKeyHash\",\n }),\n };\n }\n try {\n parseNetworkId(input.networkId);\n } catch (err) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_NETWORK_ID\",\n message: err instanceof Error ? err.message : String(err),\n }),\n };\n }\n const canonicalBody = canonicalize(\n input.body as unknown as CanonicalJson,\n );\n const expectedBodyHash = canonicalHashHex(crypto.sha256, input.body as unknown as CanonicalJson);\n if (expectedBodyHash !== input.facts.bodyHash) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_INPUT\",\n message: \"facts.bodyHash does not match the canonical body hash\",\n }),\n };\n }\n return { ok: true, data: input, canonicalBody };\n}\n\n/**\n * Compose the high-level decrypt invocation and hand it to the signer\n * for UCAN minting. The signer returns the Authorization header value\n * plus the invocation CID; this function only validates and\n * orchestrates — it does not perform crypto signing itself.\n */\nexport async function buildDecryptInvocation(\n crypto: EncryptionCrypto,\n signer: DecryptInvocationSigner,\n input: BuildDecryptInvocationInput,\n): Promise<{ ok: true; data: BuiltDecryptInvocation } | { ok: false; error: EncryptionError }> {\n const checked = checkDecryptInvocationInput(crypto, input);\n if (!checked.ok) {\n return checked;\n }\n try {\n const built = await signer.signDecryptInvocation(checked.data);\n if (!built.authorization || !built.invocationCid) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_INPUT\",\n message:\n \"decrypt-invocation signer returned an empty authorization or invocationCid\",\n }),\n };\n }\n if (built.canonicalBody !== checked.canonicalBody) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_INPUT\",\n message:\n \"decrypt-invocation signer returned a canonicalBody that does not match the SDK's canonicalization — signer must use the SDK-provided body\",\n }),\n };\n }\n return { ok: true, data: built };\n } catch (err) {\n return {\n ok: false,\n error: encryptionError({\n code: \"TRANSPORT_ERROR\",\n cause: err instanceof Error ? err : new Error(String(err)),\n message: `failed to sign decrypt invocation: ${\n err instanceof Error ? err.message : String(err)\n }`,\n }),\n };\n }\n}\n\n/** Re-export so callers can introspect the service+action constants. */\nexport { DECRYPT_ACTION, ENCRYPTION_SERVICE };\n","/**\n * Per-request receiver key generation.\n *\n * The receiver key pair is generated for a single decrypt request: the\n * SDK sends `receiverPublicKey` to the node so the node can rewrap the\n * symmetric key; the matching private key never leaves the SDK.\n *\n * Two derivation modes are supported:\n *\n * 1. **Random** — `crypto.randomBytes(32)` seeds a fresh x25519 pair.\n * This is the default for one-of-one flows.\n *\n * 2. **Signed-context** — the caller provides a signer that signs a\n * deterministic context message (network id + nonce + invocation\n * intent). The signature bytes are SHA-256'd into the seed. This is\n * useful when callers want the receiver key to be reproducible by\n * the same session signer (e.g. for delegated reads where the\n * signer is the only stable secret).\n */\n\nimport { utf8Encode } from \"./canonical\";\nimport type {\n EncryptionCrypto,\n ReceiverKeyPair,\n ReceiverKeySigner,\n} from \"./types\";\n\nexport interface RandomReceiverKeyInput {\n crypto: EncryptionCrypto;\n}\n\nexport function generateRandomReceiverKey(\n input: RandomReceiverKeyInput,\n): ReceiverKeyPair {\n const seed = input.crypto.randomBytes(32);\n return input.crypto.x25519FromSeed(seed);\n}\n\nexport interface SignedReceiverKeyInput {\n crypto: EncryptionCrypto;\n signer: ReceiverKeySigner;\n networkId: string;\n /** Optional extra context (e.g. invocation nonce) folded into the message. */\n context?: string;\n}\n\n/**\n * Deterministic receiver-key derivation: signs a context string with\n * the supplied signer, then SHA-256s the signature bytes into the\n * x25519 seed.\n *\n * The context message is:\n * `tinycloud.encryption.receiver-key/v1:<networkId>:<context>`\n *\n * Callers MUST include unique context (e.g. a fresh nonce) on every\n * request unless they explicitly want reproducibility.\n */\nexport async function deriveSignedReceiverKey(\n input: SignedReceiverKeyInput,\n): Promise<ReceiverKeyPair> {\n const message = `tinycloud.encryption.receiver-key/v1:${input.networkId}:${input.context ?? \"\"}`;\n const sig = await input.signer.signMessage(message);\n // Treat the signature as opaque bytes; sha256 collapses to a 32-byte seed.\n const sigBytes = utf8Encode(sig);\n const seed = input.crypto.sha256(sigBytes);\n return input.crypto.x25519FromSeed(seed);\n}\n","/**\n * Decrypt-response verification.\n *\n * The node returns the unwrapped symmetric key re-encrypted to the\n * per-request receiver public key. Before the SDK uses the wrapped\n * key, it must:\n *\n * 1. Verify the node signature over the canonical response (excluding\n * the signature field).\n * 2. Recompute every binding hash and reject any mismatch.\n * 3. Confirm `targetNode`, `networkId`, `alg`, and `keyVersion` echo\n * what the SDK sent.\n *\n * After verification, the SDK opens `wrappedKey` with the per-request\n * receiver private key and uses the resulting symmetric key to\n * decrypt the inline envelope payload.\n */\n\nimport { base64Decode, canonicalize, hexEncode, utf8Encode } from \"./canonical\";\nimport {\n DECRYPT_RESULT_TYPE,\n encryptionError,\n type CanonicalJson,\n type DecryptInvocationFact,\n type DecryptRequestBody,\n type DecryptResponseBody,\n type EncryptionCrypto,\n type EncryptionError,\n} from \"./types\";\n\n/**\n * Construct the canonical bytes that the node signed.\n *\n * The signature covers the response with `nodeSignature` removed. We\n * canonicalize and hash the same way the node does so the binding is\n * stable.\n */\nexport function canonicalSignedResponse(\n response: DecryptResponseBody,\n): string {\n // Strip the signature; canonicalize sorts keys for us.\n const { nodeSignature: _drop, ...rest } = response;\n return canonicalize(rest as unknown as CanonicalJson);\n}\n\nexport interface VerifyDecryptResponseInput {\n crypto: EncryptionCrypto;\n request: DecryptRequestBody;\n facts: DecryptInvocationFact;\n /** CID of the signed invocation that produced this response. */\n invocationCid: string;\n /** Hex bodyHash that was bound in `facts.bodyHash`. */\n requestBodyHash: string;\n response: DecryptResponseBody;\n}\n\n/**\n * Verify the node's decrypt response. Returns the response on success;\n * a structured error on signature, binding, or shape failure.\n */\nexport function verifyDecryptResponse(\n input: VerifyDecryptResponseInput,\n):\n | { ok: true; data: DecryptResponseBody }\n | { ok: false; error: EncryptionError } {\n const { crypto, request, facts, invocationCid, requestBodyHash, response } =\n input;\n\n if (response.type !== DECRYPT_RESULT_TYPE) {\n return {\n ok: false,\n error: encryptionError({\n code: \"INVALID_RESPONSE\",\n message: `response.type must be ${DECRYPT_RESULT_TYPE}`,\n }),\n };\n }\n if (response.targetNode !== request.targetNode) {\n return {\n ok: false,\n error: encryptionError({\n code: \"RESPONSE_BINDING_MISMATCH\",\n field: \"targetNode\",\n }),\n };\n }\n if (response.networkId !== request.networkId) {\n return {\n ok: false,\n error: encryptionError({\n code: \"RESPONSE_BINDING_MISMATCH\",\n field: \"networkId\",\n }),\n };\n }\n if (response.alg !== request.alg) {\n return {\n ok: false,\n error: encryptionError({\n code: \"RESPONSE_BINDING_MISMATCH\",\n field: \"alg\",\n }),\n };\n }\n if (response.keyVersion !== request.keyVersion) {\n return {\n ok: false,\n error: encryptionError({\n code: \"RESPONSE_BINDING_MISMATCH\",\n field: \"keyVersion\",\n }),\n };\n }\n if (\n response.encryptedSymmetricKeyHash !==\n request.encryptedSymmetricKeyHash\n ) {\n return {\n ok: false,\n error: encryptionError({\n code: \"RESPONSE_BINDING_MISMATCH\",\n field: \"encryptedSymmetricKeyHash\",\n }),\n };\n }\n if (response.receiverPublicKeyHash !== request.receiverPublicKeyHash) {\n return {\n ok: false,\n error: encryptionError({\n code: \"RESPONSE_BINDING_MISMATCH\",\n field: \"receiverPublicKeyHash\",\n }),\n };\n }\n if (response.invocationCid !== invocationCid) {\n return {\n ok: false,\n error: encryptionError({\n code: \"RESPONSE_BINDING_MISMATCH\",\n field: \"invocationCid\",\n }),\n };\n }\n // requestHash binds invocationCid || requestBodyHash per spec. The `||`\n // notation is concatenation, not a literal delimiter.\n const expectedRequestHash = hexEncode(\n crypto.sha256(utf8Encode(`${invocationCid}${requestBodyHash}`)),\n );\n if (response.requestHash !== expectedRequestHash) {\n return {\n ok: false,\n error: encryptionError({\n code: \"RESPONSE_BINDING_MISMATCH\",\n field: \"requestHash\",\n }),\n };\n }\n // The facts must agree with the response (defensive: catches a node\n // that returns a fresh body bound to a different invocation).\n if (\n facts.encryptedSymmetricKeyHash !== response.encryptedSymmetricKeyHash ||\n facts.receiverPublicKeyHash !== response.receiverPublicKeyHash ||\n facts.networkId !== response.networkId ||\n facts.targetNode !== response.targetNode ||\n facts.alg !== response.alg ||\n facts.keyVersion !== response.keyVersion\n ) {\n return {\n ok: false,\n error: encryptionError({\n code: \"RESPONSE_BINDING_MISMATCH\",\n field: \"facts\",\n }),\n };\n }\n\n const signedBytes = new TextEncoder().encode(\n canonicalSignedResponse(response),\n );\n const signatureBytes = base64Decode(response.nodeSignature);\n if (\n !crypto.verifyNodeSignature(response.nodeId, signedBytes, signatureBytes)\n ) {\n return {\n ok: false,\n error: encryptionError({\n code: \"RESPONSE_SIGNATURE_INVALID\",\n }),\n };\n }\n return { ok: true, data: response };\n}\n\n/**\n * After verification, open the response's `wrappedKey` with the\n * per-request receiver private key and return the symmetric key.\n */\nexport function openWrappedKey(\n crypto: EncryptionCrypto,\n receiverPrivateKey: Uint8Array,\n response: DecryptResponseBody,\n): Uint8Array {\n const wrapped = base64Decode(response.wrappedKey);\n return crypto.openWithReceiverKey(receiverPrivateKey, wrapped);\n}\n","/**\n * EncryptionService — TinyCloud one-of-one encryption service.\n *\n * Responsibilities:\n * - Network discovery (`discoverNetwork`).\n * - Local envelope encryption (`encryptToNetwork`).\n * - Node-mediated decrypt with full request/response binding\n * verification (`decryptEnvelope`).\n *\n * Non-responsibilities:\n * - KV/SQL access. Callers fetch encrypted envelopes from their data\n * service of choice and pass them in.\n * - Network onboarding/ceremony. Those routes are node-only.\n */\n\nimport { BaseService } from \"../base/BaseService\";\nimport { type Result } from \"../types\";\nimport {\n base64Decode,\n base64Encode,\n canonicalHashHex,\n} from \"./canonical\";\nimport {\n discoverNetwork as discoverNetworkFn,\n ensureNetworkUsableForDecrypt,\n type NodeDescriptorFetcher,\n type WellKnownDescriptorFetcher,\n} from \"./discovery\";\nimport {\n decryptEnvelopeWithKey,\n encryptToNetwork as encryptToNetworkFn,\n validateEnvelope,\n} from \"./envelope\";\nimport {\n buildCanonicalDecryptRequest,\n buildDecryptFacts,\n buildDecryptInvocation,\n} from \"./invocation\";\nimport { generateRandomReceiverKey } from \"./receiverKey\";\nimport {\n openWrappedKey,\n verifyDecryptResponse,\n} from \"./response\";\nimport {\n DECRYPT_FACT_TYPE,\n encryptionError,\n type DecryptCapabilityProof,\n type DecryptInvocationSigner,\n type DecryptRequestBody,\n type DecryptResponseBody,\n type EncryptionCrypto,\n type EncryptionError,\n type InlineEncryptedEnvelope,\n type NetworkDescriptor,\n toError,\n} from \"./types\";\nimport type {\n EncryptToNetworkOptions,\n DecryptEnvelopeOptions,\n IEncryptionService,\n} from \"./IEncryptionService\";\n\n// Local Result helpers typed to EncryptionError. The shared `ok` / `err`\n// from `../types` default the error generic to `ServiceError`, which\n// widens our return-type inference here.\nfunction encOk<T>(data: T): Result<T, EncryptionError> {\n return { ok: true, data };\n}\nfunction encErr<T = never>(error: EncryptionError): Result<T, EncryptionError> {\n return { ok: false, error };\n}\n\n/**\n * Transport for posting decrypt requests to a TinyCloud node.\n *\n * Implementations supply the `Authorization` header (built by the\n * decrypt-invocation signer) and POST the canonical body. The\n * response body is JSON-decoded into a {@link DecryptResponseBody}.\n */\nexport interface DecryptTransport {\n postDecrypt(input: {\n targetNode: string;\n networkId: string;\n authorization: string;\n canonicalBody: string;\n }): Promise<DecryptResponseBody>;\n}\n\nexport interface EncryptionServiceConfig {\n crypto: EncryptionCrypto;\n signer: DecryptInvocationSigner;\n transport: DecryptTransport;\n node?: NodeDescriptorFetcher;\n wellKnown?: WellKnownDescriptorFetcher;\n [key: string]: unknown;\n}\n\nexport class EncryptionService\n extends BaseService\n implements IEncryptionService\n{\n static readonly serviceName = \"encryption\";\n\n declare protected _config: EncryptionServiceConfig;\n\n constructor(config: EncryptionServiceConfig) {\n super();\n this._config = config;\n }\n\n get config(): EncryptionServiceConfig {\n return this._config;\n }\n\n private get crypto(): EncryptionCrypto {\n return this._config.crypto;\n }\n\n async discoverNetwork(\n identifier: string,\n principal?: string,\n ): Promise<Result<NetworkDescriptor, EncryptionError>> {\n const result = await discoverNetworkFn({\n identifier,\n ...(principal !== undefined ? { principal } : {}),\n ...(this._config.node !== undefined ? { node: this._config.node } : {}),\n ...(this._config.wellKnown !== undefined\n ? { wellKnown: this._config.wellKnown }\n : {}),\n });\n if (!result.ok) return result;\n return encOk(result.data.descriptor);\n }\n\n async encryptToNetwork(\n networkId: string,\n plaintext: Uint8Array,\n options?: EncryptToNetworkOptions,\n ): Promise<Result<InlineEncryptedEnvelope, EncryptionError>> {\n try {\n const discovered = await this.discoverNetwork(networkId);\n if (!discovered.ok) return discovered;\n const usable = ensureNetworkUsableForDecrypt(discovered.data);\n // For encryption we tolerate \"rotating\" but reject revoked/failed/pending —\n // ensureNetworkUsableForDecrypt enforces exactly that constraint.\n if (!usable.ok) return usable;\n\n const descriptor = usable.data;\n const networkPublicKey = base64Decode(descriptor.publicEncryptionKey);\n const result = encryptToNetworkFn(this.crypto, {\n networkId,\n networkPublicKey,\n plaintext,\n ...(options?.aad !== undefined ? { aad: options.aad } : {}),\n alg: options?.alg ?? descriptor.alg,\n keyVersion: options?.keyVersion ?? descriptor.keyVersion,\n ...(options?.metadata !== undefined ? { metadata: options.metadata } : {}),\n });\n return encOk(result.envelope);\n } catch (error) {\n return encErr(\n encryptionError({\n code: \"TRANSPORT_ERROR\",\n cause: toError(error),\n }),\n );\n }\n }\n\n async decryptEnvelope(\n envelope: InlineEncryptedEnvelope,\n capabilityProof: DecryptCapabilityProof,\n options?: DecryptEnvelopeOptions,\n ): Promise<Result<Uint8Array, EncryptionError>> {\n try {\n const validated = validateEnvelope(this.crypto, envelope);\n if (!validated.ok) return validated;\n\n let descriptor: NetworkDescriptor;\n if (options?.descriptor !== undefined) {\n descriptor = options.descriptor;\n } else {\n const discovered = await this.discoverNetwork(envelope.networkId);\n if (!discovered.ok) return discovered;\n descriptor = discovered.data;\n }\n const usable = ensureNetworkUsableForDecrypt(descriptor);\n if (!usable.ok) return usable;\n\n const targetNode =\n options?.targetNode ?? descriptor.members[0]?.nodeId;\n if (targetNode === undefined) {\n return encErr(\n encryptionError({\n code: \"INVALID_INPUT\",\n message: \"no target node available from descriptor\",\n }),\n );\n }\n\n // Generate per-request receiver key. We use the random mode by\n // default; callers wanting deterministic derivation must wrap\n // this service directly.\n const receiverKey = generateRandomReceiverKey({ crypto: this.crypto });\n const receiverPublicKey = base64Encode(receiverKey.publicKey);\n const receiverPublicKeyHash = canonicalHashHex(\n this.crypto.sha256,\n receiverPublicKey,\n );\n\n const body: DecryptRequestBody = {\n type: DECRYPT_FACT_TYPE,\n targetNode,\n networkId: envelope.networkId,\n alg: envelope.alg,\n keyVersion: envelope.keyVersion,\n encryptedSymmetricKey: envelope.encryptedSymmetricKey,\n encryptedSymmetricKeyHash: envelope.encryptedSymmetricKeyHash,\n receiverPublicKey,\n receiverPublicKeyHash,\n };\n const canonicalRequest = buildCanonicalDecryptRequest({\n crypto: this.crypto,\n body,\n receiverPublicKey: receiverKey.publicKey,\n });\n const facts = buildDecryptFacts({\n crypto: this.crypto,\n body,\n encryptedSymmetricKeyHash: envelope.encryptedSymmetricKeyHash,\n receiverPublicKey: receiverKey.publicKey,\n canonicalBody: canonicalRequest.canonicalBody,\n });\n\n const built = await buildDecryptInvocation(this.crypto, this._config.signer, {\n targetNode,\n networkId: envelope.networkId,\n body,\n facts,\n proof: capabilityProof,\n });\n if (!built.ok) return built;\n\n let response: DecryptResponseBody;\n try {\n response = await this._config.transport.postDecrypt({\n targetNode,\n networkId: envelope.networkId,\n authorization: built.data.authorization,\n canonicalBody: built.data.canonicalBody,\n });\n } catch (error) {\n return encErr(\n encryptionError({\n code: \"TRANSPORT_ERROR\",\n cause: toError(error),\n }),\n );\n }\n\n const verified = verifyDecryptResponse({\n crypto: this.crypto,\n request: body,\n facts,\n invocationCid: built.data.invocationCid,\n requestBodyHash: facts.bodyHash,\n response,\n });\n if (!verified.ok) return verified;\n\n const symmetricKey = openWrappedKey(\n this.crypto,\n receiverKey.privateKey,\n verified.data,\n );\n const plaintext = decryptEnvelopeWithKey(\n this.crypto,\n envelope,\n symmetricKey,\n );\n return encOk(plaintext);\n } catch (error) {\n return encErr(\n encryptionError({\n code: \"TRANSPORT_ERROR\",\n cause: toError(error),\n }),\n );\n }\n }\n}\n"],"mappings":"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","names":["serviceError","err","err","err"]}
|