@calimero-network/mero-js 19.3.0 → 19.5.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/admin-api/admin-client.d.ts +5 -1
- package/dist/admin-api/admin-client.js +12 -0
- package/dist/admin-api/admin-types.d.ts +5 -1
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +4 -4
- package/dist/index.cjs +128 -0
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/index.mjs +128 -0
- package/dist/index.mjs.map +4 -4
- package/dist/login/index.d.ts +2 -0
- package/dist/login/index.js +1 -0
- package/dist/login/session.d.ts +108 -0
- package/dist/login/session.js +148 -0
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/index.ts", "../src/http-client/signal-utils.ts", "../src/http-client/web-client.ts", "../src/http-client/http-factory.ts", "../src/http-client/retry.ts", "../src/auth-api/auth-client.ts", "../src/auth-api/auth-factory.ts", "../src/admin-api/admin-client.ts", "../src/admin-api/admin-factory.ts", "../src/auth/index.ts", "../src/rpc/index.ts", "../src/events/group.ts", "../src/events/sse.ts", "../src/events/ws.ts", "../src/ephemeral/codec.ts", "../src/ephemeral/index.ts", "../src/cloud/cloud-client.ts", "../src/mero-js.ts", "../src/token-store/index.ts", "../src/crypto/internal.ts", "../src/warrant/warrant.ts", "../src/relay/relay-client.ts", "../src/relay/nonce-source.ts", "../src/cloud/connect.ts", "../src/device-cert/device-cert.ts", "../src/namespace-op/namespace-op.ts", "../src/login/login.ts", "../src/capabilities.ts", "../src/nodeDiscovery.ts"],
|
|
4
|
-
"sourcesContent": ["// Mero.js - Pure JavaScript SDK for Calimero\n// This will contain the pure JavaScript SDK without React dependencies\n\n// Main SDK class\nexport { MeroJs, createMeroJs } from './mero-js.js';\nexport type { MeroJsConfig, TokenData } from './mero-js.js';\n\n// HTTP client module (Web Standards based)\nexport * from './http-client/index.js';\n\n// Auth API client\nexport * from './auth-api/index.js';\n\n// Admin API client\nexport * from './admin-api/index.js';\n\n// Auth utilities\nexport { parseAuthCallback, buildAuthLoginUrl } from './auth/index.js';\nexport type { AuthCallbackResult, AuthLoginOptions } from './auth/index.js';\n\n// Token store\nexport { MemoryTokenStore, LocalStorageTokenStore } from './token-store/index.js';\nexport type { TokenStore } from './token-store/index.js';\n\n// RPC client\nexport { RpcClient, RpcError } from './rpc/index.js';\nexport type { MigrateMyEntriesSummary } from './rpc/index.js';\nexport type { ExecuteParams } from './rpc/index.js';\n\n// Events (SSE / WebSocket)\nexport { SseClient, WsClient } from './events/index.js';\nexport type {\n SseEventData,\n WsEventData,\n AppVersionChangedEvent,\n GroupMembershipEventData,\n GroupMigrationEventData,\n MigrationStartedData,\n MigrationProgressData,\n CascadeProgressData,\n MigrationCompletedData,\n} from './events/index.js';\n\n// Ephemeral presence (cursors / typing / online)\nexport { EphemeralClient, jsonCodec } from './ephemeral/index.js';\nexport type { Codec, EphemeralEntry } from './ephemeral/index.js';\n\n// Cloud client \u2014 namespaces, relays, HA, and the cloud sign-in path\nexport * from './cloud/index.js';\n\n// Relay client \u2014 write through delegated execution, holding only a signing key\nexport * from './relay/index.js';\n\n// Warrant signing \u2014 mint the author's consent for a relay to run one intent\nexport { signWarrant, intentHash } from './warrant/index.js';\nexport {\n signDeviceCert,\n mintDeviceId,\n deviceCertPayload,\n accountForRoot,\n} from './device-cert/index.js';\nexport type { DeviceCertInput } from './device-cert/index.js';\nexport {\n signMemberJoinOp,\n encodeSignedInvitation,\n SIGNED_NAMESPACE_OP_SCHEMA_VERSION,\n} from './namespace-op/index.js';\nexport type { SignMemberJoinInput } from './namespace-op/index.js';\nexport type { WarrantInput } from './warrant/index.js';\n\n// Login-statement signing \u2014 the device's half of a password-free session\nexport { signLoginStatement } from './login/index.js';\nexport type { Audience, LoginStatementInput } from './login/index.js';\n\n// Member capability bitmask constants & helpers\nexport * from './capabilities.js';\n\n// Utilities\nexport {\n DEFAULT_LOCAL_NODE_PORTS,\n localNodeUrl,\n nodeEndpoint,\n probeNodeHealth,\n discoverLocalNodes,\n} from './nodeDiscovery.js';\nexport type { DiscoverLocalNodesOptions } from './nodeDiscovery.js';\n", "// Utility for combining multiple AbortSignals\nexport function combineSignals(\n signals: Array<AbortSignal | undefined>,\n): AbortSignal | undefined {\n const list = signals.filter(Boolean) as AbortSignal[];\n if (list.length === 0) return undefined;\n\n // Prefer native any(), but fall back if unavailable or it throws\n const AbortSignalAny = AbortSignal as {\n any?: (signals: AbortSignal[]) => AbortSignal;\n };\n if (typeof AbortSignalAny.any === 'function') {\n try {\n return AbortSignalAny.any(list);\n } catch {\n // Fall through to manual implementation\n }\n }\n\n const controller = new AbortController();\n const onAbort = (evt: Event) => {\n controller.abort((evt.target as AbortSignal).reason);\n for (const s of list) s.removeEventListener('abort', onAbort);\n };\n\n for (const s of list) {\n if (s.aborted) return AbortSignal.abort(s.reason);\n s.addEventListener('abort', onAbort, { once: true });\n }\n\n return controller.signal;\n}\n\n// Helper to create a timeout signal\nexport function createTimeoutSignal(timeoutMs: number): AbortSignal {\n // Use AbortSignal.timeout if available (Node 18.17+, modern browsers)\n if (typeof AbortSignal.timeout === 'function') {\n return AbortSignal.timeout(timeoutMs);\n }\n\n // Fallback for older environments\n const controller = new AbortController();\n setTimeout(() => {\n controller.abort(new DOMException('Timeout', 'TimeoutError'));\n }, timeoutMs);\n\n return controller.signal;\n}\n", "// ErrorResponse import removed as it's not used\nimport {\n HttpClient,\n Transport,\n RequestOptions,\n ResponseParser,\n} from './http-types.js';\nimport { combineSignals, createTimeoutSignal } from './signal-utils.js';\n\n/**\n * `x-auth-error` reasons that mean the whole token family is gone.\n *\n * Refresh tokens are single-use (calimero-network/core#3083): presenting a\n * consumed refresh token is treated as token theft and the server revokes the\n * family. Refreshing or retrying afterwards is pointless \u2014 the only way out is\n * a fresh login.\n */\nconst TERMINAL_AUTH_ERRORS = new Set(['token_reuse', 'token_revoked']);\n\n/**\n * Pull the node's explanation out of an error body. Core answers every handled\n * failure with `{\"error\": \"<message>\"}` (`ApiError::into_response`); the nested\n * `{\"error\": {\"message\": ...}}` form is what proxies in front of a node emit.\n * Returns undefined for a non-JSON, empty, or envelope-less body.\n */\nfunction extractErrorMessage(bodyText?: string): string | undefined {\n if (!bodyText) return undefined;\n try {\n const error = (JSON.parse(bodyText) as { error?: unknown })?.error;\n if (typeof error === 'string' && error.trim() !== '') return error;\n const nested = (error as { message?: unknown } | null)?.message;\n if (typeof nested === 'string' && nested.trim() !== '') return nested;\n } catch {\n // Not JSON \u2014 the status line is all we can honestly report.\n }\n return undefined;\n}\n\n// Custom error class for HTTP errors\nexport class HTTPError extends Error {\n name = 'HTTPError';\n\n constructor(\n public status: number,\n public statusText: string,\n public url: string,\n public headers: Headers,\n public bodyText?: string, // cap at ~64KB\n ) {\n const explanation = extractErrorMessage(bodyText);\n super(\n explanation\n ? `HTTP ${status} ${statusText}: ${explanation}`\n : `HTTP ${status} ${statusText}`,\n );\n }\n\n toJSON(): {\n status: number;\n statusText: string;\n url: string;\n headers: Record<string, string>;\n bodyText?: string;\n } {\n return {\n status: this.status,\n statusText: this.statusText,\n url: this.url,\n headers: headersToRecord(this.headers),\n bodyText: this.bodyText,\n };\n }\n}\n\n/**\n * Terminal authentication error: the refresh-token family was revoked (single-use\n * refresh token replayed, or the token was explicitly revoked). Never retried and\n * never refreshed \u2014 apps should catch this and force a re-login.\n *\n * Extends {@link HTTPError} so existing `instanceof HTTPError` handling keeps working.\n */\nexport class AuthRevokedError extends HTTPError {\n name = 'AuthRevokedError';\n\n constructor(\n /** Value of the `x-auth-error` header, e.g. `token_reuse` or `token_revoked`. */\n public reason: string,\n status: number,\n statusText: string,\n url: string,\n headers: Headers,\n bodyText?: string,\n ) {\n super(status, statusText, url, headers, bodyText);\n this.message = `Authentication revoked (${reason}): HTTP ${status} ${statusText}`;\n }\n}\n\n// Helper function to convert Headers to Record\nfunction headersToRecord(headers: Headers): Record<string, string> {\n const record: Record<string, string> = {};\n headers.forEach((value, key) => {\n record[key] = value;\n });\n return record;\n}\n\n// Web Standards HTTP client implementation\nexport class WebHttpClient implements HttpClient {\n // Cache for concurrent refresh token calls to prevent race conditions\n private refreshTokenPromise: Promise<string> | null = null;\n // Cache for concurrent onTokenRefresh calls to prevent duplicate callbacks\n private onTokenRefreshPromise: Promise<void> | null = null;\n \n constructor(private transport: Transport) {}\n\n async get<T>(path: string, init?: RequestOptions): Promise<T> {\n return this.request<T>(path, { ...init, method: 'GET' });\n }\n\n async post<T>(\n path: string,\n body?: unknown,\n init?: RequestOptions,\n ): Promise<T> {\n return this.request<T>(path, {\n ...init,\n method: 'POST',\n body: body ? JSON.stringify(body) : undefined,\n headers: {\n 'Content-Type': 'application/json',\n ...init?.headers,\n },\n });\n }\n\n async put<T>(\n path: string,\n body?: unknown,\n init?: RequestOptions,\n ): Promise<T> {\n return this.request<T>(path, {\n ...init,\n method: 'PUT',\n body: body ? JSON.stringify(body) : undefined,\n headers: {\n 'Content-Type': 'application/json',\n ...init?.headers,\n },\n });\n }\n\n async delete<T>(path: string, init?: RequestOptions): Promise<T> {\n return this.request<T>(path, { ...init, method: 'DELETE' });\n }\n\n async patch<T>(\n path: string,\n body?: unknown,\n init?: RequestOptions,\n ): Promise<T> {\n return this.request<T>(path, {\n ...init,\n method: 'PATCH',\n body: body ? JSON.stringify(body) : undefined,\n headers: {\n 'Content-Type': 'application/json',\n ...init?.headers,\n },\n });\n }\n\n async head(\n path: string,\n init?: RequestOptions,\n ): Promise<{ headers: Record<string, string>; status: number }> {\n const response = await this.makeRequest<Response>(path, {\n ...init,\n method: 'HEAD',\n parse: 'response',\n });\n return {\n headers: headersToRecord(response.headers),\n status: response.status,\n };\n }\n\n async request<T>(path: string, init?: RequestOptions): Promise<T> {\n return this.makeRequest<T>(path, init);\n }\n\n private async makeRequest<T>(\n path: string,\n init?: RequestOptions,\n retryCount = 0,\n requestStartTime?: number,\n ): Promise<T> {\n // Maximum retry attempts to prevent infinite loops\n const MAX_RETRY_ATTEMPTS = 1;\n const url = this.buildUrl(path);\n \n // Track request start time for timeout calculation (only on first attempt)\n // Use per-request start time to avoid corruption from concurrent requests\n const startTime = requestStartTime ?? Date.now();\n // Note: Tauri proxy script now handles AbortSignal, so we can use full RequestInit\n // Removed Tauri-specific minimal path - proxy script handles AbortSignal properly\n const signal = this.createAbortSignal(init);\n const headers = await this.buildHeaders(init?.headers);\n let headersObj: Record<string, string>;\n if (headers instanceof Headers) {\n headersObj = {};\n headers.forEach((value, key) => {\n headersObj[key] = value;\n });\n } else {\n headersObj = headers;\n }\n \n const requestInit: RequestInit = {\n method: init?.method || 'GET',\n headers: headersObj,\n };\n \n // Check if body is a stream (ReadableStream) that can't be reused\n // Note: Blob is reusable, so it's not included here\n const isStreamBody = init?.body instanceof ReadableStream ||\n (typeof init?.body === 'object' && init?.body !== null && 'getReader' in init.body && !(init.body instanceof Blob));\n \n if (init?.body !== undefined && !isStreamBody) {\n requestInit.body = init.body;\n } else if (init?.body !== undefined && isStreamBody && retryCount === 0) {\n // Only include stream body on first attempt - can't retry with streams\n requestInit.body = init.body;\n }\n \n // For retries, calculate remaining timeout to prevent timeout reset\n // Track elapsed time and use remaining timeout for retry\n // Note: This is calculated before the request, so it doesn't include token refresh time\n // The actual remaining timeout check happens after token refresh completes\n let retrySignal: AbortSignal | undefined;\n if (retryCount > 0 && requestStartTime !== undefined) {\n const timeoutMs = init?.timeoutMs || this.transport.timeoutMs;\n if (timeoutMs) {\n // Calculate elapsed time (will be recalculated after token refresh if needed)\n const elapsed = Date.now() - startTime;\n const remaining = Math.max(0, timeoutMs - elapsed);\n // Create signal with remaining timeout, preserving user's signal\n retrySignal = this.createAbortSignal({ ...init, timeoutMs: remaining });\n } else {\n // No timeout, just preserve user's signal\n retrySignal = this.createAbortSignal(init);\n }\n } else {\n retrySignal = signal;\n }\n \n if (retrySignal) {\n requestInit.signal = retrySignal;\n }\n \n if (this.transport.credentials !== undefined) {\n requestInit.credentials = this.transport.credentials;\n }\n \n if (init?.mode !== undefined) {\n requestInit.mode = init.mode;\n }\n if (init?.cache !== undefined) {\n requestInit.cache = init.cache;\n }\n if (init?.redirect !== undefined) {\n requestInit.redirect = init.redirect;\n }\n if (init?.referrer !== undefined) {\n requestInit.referrer = init.referrer;\n }\n if (init?.referrerPolicy !== undefined) {\n requestInit.referrerPolicy = init.referrerPolicy;\n }\n if (init?.integrity !== undefined) {\n requestInit.integrity = init.integrity;\n }\n if (init?.keepalive !== undefined) {\n requestInit.keepalive = init.keepalive;\n }\n\n try {\n const response = await this.transport.fetch(url, requestInit);\n\n if (!response.ok) {\n const bodyText = await this.getBodyText(response);\n const httpError = new HTTPError(\n response.status,\n response.statusText,\n url,\n response.headers,\n bodyText,\n );\n\n // Handle a revoked token family (single-use refresh token replayed, or an\n // explicitly revoked token). This is terminal: refreshing would only burn\n // another token and retrying would 401 again, so clear the tokens via the\n // onAuthRevoked hook and surface a distinguishable error.\n const authError = response.headers.get('x-auth-error');\n if (\n (response.status === 401 || response.status === 403) &&\n authError &&\n TERMINAL_AUTH_ERRORS.has(authError)\n ) {\n // Any in-flight refresh is based on a now-dead family \u2014 drop the caches.\n this.refreshTokenPromise = null;\n this.onTokenRefreshPromise = null;\n\n if (this.transport.onAuthRevoked) {\n try {\n await this.transport.onAuthRevoked();\n } catch {\n // Never mask the auth error with a cleanup failure.\n }\n }\n\n throw new AuthRevokedError(\n authError,\n response.status,\n response.statusText,\n url,\n response.headers,\n bodyText,\n );\n }\n\n // Handle 401 with token_expired - attempt automatic token refresh\n const userAborted = init?.signal?.aborted === true;\n if (\n response.status === 401 &&\n this.transport.refreshToken &&\n authError === 'token_expired' &&\n retryCount < MAX_RETRY_ATTEMPTS &&\n !isStreamBody &&\n !userAborted\n ) {\n try {\n // Use cached refresh promise if one is in progress (prevents race conditions)\n let refreshPromise = this.refreshTokenPromise;\n if (!refreshPromise) {\n refreshPromise = this.transport.refreshToken();\n this.refreshTokenPromise = refreshPromise;\n }\n \n // Attempt to refresh the token\n const newToken = await refreshPromise;\n \n // Validate token - must be non-empty\n if (!newToken || newToken.trim() === '') {\n // Clear caches on error\n this.refreshTokenPromise = null;\n this.onTokenRefreshPromise = null;\n throw new Error('Refresh token returned empty token');\n }\n \n // onTokenRefresh is required when refreshToken is provided\n // Without it, the new token cannot be stored and getAuthToken() will return the old token\n if (!this.transport.onTokenRefresh) {\n // Clear caches on error\n this.refreshTokenPromise = null;\n this.onTokenRefreshPromise = null;\n throw new Error(\n 'onTokenRefresh callback is required when refreshToken is provided. ' +\n 'The callback must update the token storage so getAuthToken() returns the new token.'\n );\n }\n \n // Use cached onTokenRefresh promise if one is in progress (prevents duplicate callbacks)\n // This ensures onTokenRefresh is only called once per token refresh, even with concurrent requests\n let onTokenRefreshPromise = this.onTokenRefreshPromise;\n if (!onTokenRefreshPromise) {\n onTokenRefreshPromise = this.transport.onTokenRefresh(newToken);\n this.onTokenRefreshPromise = onTokenRefreshPromise;\n }\n \n // Update token via callback (only called once per refresh, even with concurrent requests)\n // Errors from onTokenRefresh callback should be preserved (don't mask as 401)\n // This helps developers debug token storage issues\n await onTokenRefreshPromise;\n \n // Clear caches after both refresh and callback complete\n this.refreshTokenPromise = null;\n this.onTokenRefreshPromise = null;\n \n // Check if timeout has expired during token refresh\n // If so, throw the original 401 error instead of retrying with 0ms timeout\n // This prevents timeout/abort errors that obscure the root cause (expired token)\n const timeoutMs = init?.timeoutMs || this.transport.timeoutMs;\n if (timeoutMs && requestStartTime !== undefined) {\n const elapsed = Date.now() - startTime;\n const remaining = timeoutMs - elapsed;\n if (remaining <= 0) {\n // Timeout expired during token refresh - throw original 401 error\n // This is better than retrying with 0ms timeout which would cause confusing timeout errors\n throw httpError;\n }\n }\n \n // Retry the request with the new token (increment retry count)\n // Preserve user's abort signal and start time in retry\n return this.makeRequest<T>(path, init, retryCount + 1, startTime);\n } catch (refreshError) {\n // Clear caches on error\n this.refreshTokenPromise = null;\n this.onTokenRefreshPromise = null;\n // Configuration errors (missing onTokenRefresh) should be thrown as-is\n if (refreshError instanceof Error && refreshError.message.includes('onTokenRefresh')) {\n throw refreshError;\n }\n // Errors from onTokenRefresh callback are already thrown above, so if we get here,\n // it's either a refreshToken() failure or empty token - throw original 401\n // This matches the PR description: \"If refresh fails, throws the original 401 error\"\n throw httpError;\n }\n }\n\n throw httpError;\n }\n\n return this.parseResponse<T>(response, init?.parse);\n } catch (error) {\n if (error instanceof HTTPError) {\n throw error;\n }\n // Preserve configuration errors (like missing onTokenRefresh)\n if (error instanceof Error && error.message.includes('onTokenRefresh')) {\n throw error;\n }\n throw new HTTPError(\n 0,\n 'Network Error',\n url,\n new Headers(),\n error instanceof Error ? error.message : 'Unknown error',\n );\n }\n }\n\n private buildUrl(path: string): string {\n // Handle absolute URLs\n if (path.startsWith('http://') || path.startsWith('https://')) {\n return path;\n }\n\n // Handle baseUrl with path\n const baseUrl = this.transport.baseUrl;\n if (path.startsWith('/')) {\n // If path starts with /, combine with baseUrl\n const base = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;\n return `${base}${path}`;\n } else {\n // If path doesn't start with /, append to baseUrl\n const base = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;\n return `${base}${path}`;\n }\n }\n\n private createAbortSignal(init?: RequestOptions): AbortSignal | undefined {\n const signals: AbortSignal[] = [];\n\n if (this.transport.defaultAbortSignal) {\n signals.push(this.transport.defaultAbortSignal);\n }\n\n if (init?.signal) {\n signals.push(init.signal);\n }\n\n const timeoutMs = init?.timeoutMs || this.transport.timeoutMs;\n if (timeoutMs) {\n signals.push(createTimeoutSignal(timeoutMs));\n }\n\n return signals.length > 0 ? combineSignals(signals) : undefined;\n }\n\n private async buildHeaders(\n initHeaders?: HeadersInit,\n ): Promise<Record<string, string>> {\n const headers: Record<string, string> = {\n ...this.transport.defaultHeaders,\n };\n\n // Add auth token if available and not empty\n if (this.transport.getAuthToken) {\n try {\n const token = await this.transport.getAuthToken();\n if (token && token.trim() !== '') {\n headers.Authorization = `Bearer ${token}`;\n }\n } catch (error) {\n // Ignore auth token errors\n }\n }\n\n // Add init headers\n if (initHeaders) {\n if (initHeaders instanceof Headers) {\n initHeaders.forEach((value, key) => {\n headers[key] = value;\n });\n } else if (Array.isArray(initHeaders)) {\n initHeaders.forEach(([key, value]) => {\n headers[key] = value;\n });\n } else {\n Object.assign(headers, initHeaders);\n }\n }\n\n return headers;\n }\n\n private async parseResponse<T>(\n response: Response,\n parse?: ResponseParser,\n ): Promise<T> {\n switch (parse) {\n case 'text':\n return (await response.text()) as T;\n case 'blob':\n return (await response.blob()) as T;\n case 'arrayBuffer':\n return (await response.arrayBuffer()) as T;\n case 'response':\n return response as T;\n case 'json':\n default: {\n // Tolerate empty 2xx bodies (e.g. 204 No Content from delete/resync):\n // `response.json()` throws on '', so read text and return null when empty.\n const text = await response.text();\n if (!text) return null as T;\n try {\n return JSON.parse(text) as T;\n } catch {\n // Non-JSON body on a 2xx (e.g. an HTML error page) \u2014 surface a clear\n // error with a snippet instead of a bare SyntaxError.\n throw new Error(\n `Expected a JSON response (status ${response.status}) but body was not JSON: ${text.slice(0, 200)}`,\n );\n }\n }\n }\n }\n\n private async getBodyText(response: Response): Promise<string> {\n try {\n const text = await response.text();\n return text.length > 65536 ? text.slice(0, 65536) + '...' : text;\n } catch {\n return '';\n }\n }\n}\n", "import { WebHttpClient } from './web-client.js';\nimport { Transport, HttpClient } from './http-types.js';\n\n// Factory function to create HTTP client with sensible defaults\nexport function createHttpClient(transport: Transport): HttpClient {\n return new WebHttpClient(transport);\n}\n\n// Factory function for browser environments\nexport function createBrowserHttpClient(options: {\n baseUrl: string;\n getAuthToken?: () => Promise<string | undefined>;\n onTokenRefresh?: (newToken: string) => Promise<void>;\n /**\n * Callback to refresh the access token when a 401 error with 'token_expired' is detected.\n * Should return the new access token, or throw an error if refresh fails.\n * If provided, the client will automatically retry the request after a successful refresh.\n */\n refreshToken?: () => Promise<string>;\n /**\n * Callback invoked when the server reports a revoked token family\n * (`x-auth-error: token_reuse` / `token_revoked`). Terminal \u2014 the request is\n * never retried; clear stored tokens and force a re-login.\n */\n onAuthRevoked?: () => Promise<void> | void;\n defaultHeaders?: Record<string, string>;\n timeoutMs?: number;\n credentials?: RequestCredentials;\n defaultAbortSignal?: AbortSignal;\n}): HttpClient {\n const transport: Transport = {\n // Wrap fetch in arrow function to prevent \"Illegal invocation\" error\n // This preserves the correct 'this' context when fetch is called\n fetch: (url: RequestInfo | URL, init?: RequestInit) => globalThis.fetch(url, init),\n baseUrl: options.baseUrl,\n getAuthToken: options.getAuthToken,\n onTokenRefresh: options.onTokenRefresh,\n refreshToken: options.refreshToken,\n onAuthRevoked: options.onAuthRevoked,\n defaultHeaders: options.defaultHeaders,\n timeoutMs: options.timeoutMs,\n credentials: options.credentials, // No default credentials\n defaultAbortSignal: options.defaultAbortSignal,\n };\n\n return createHttpClient(transport);\n}\n\n// Factory function for Node.js environments\nexport function createNodeHttpClient(options: {\n baseUrl: string;\n fetch?: typeof fetch; // Allow injection of undici.fetch or other fetch implementations\n getAuthToken?: () => Promise<string | undefined>;\n onTokenRefresh?: (newToken: string) => Promise<void>;\n /**\n * Callback to refresh the access token when a 401 error with 'token_expired' is detected.\n * Should return the new access token, or throw an error if refresh fails.\n * If provided, the client will automatically retry the request after a successful refresh.\n */\n refreshToken?: () => Promise<string>;\n /**\n * Callback invoked when the server reports a revoked token family\n * (`x-auth-error: token_reuse` / `token_revoked`). Terminal \u2014 the request is\n * never retried; clear stored tokens and force a re-login.\n */\n onAuthRevoked?: () => Promise<void> | void;\n defaultHeaders?: Record<string, string>;\n timeoutMs?: number;\n credentials?: RequestCredentials;\n defaultAbortSignal?: AbortSignal;\n}): HttpClient {\n // Use provided fetch or try to use global fetch (Node 18+)\n const fetchImpl = options.fetch ?? globalThis.fetch;\n\n if (!fetchImpl) {\n throw new Error(\n 'No fetch implementation available. Please provide a fetch implementation ' +\n '(e.g., undici.fetch) or use Node.js 18+ which has native fetch support.',\n );\n }\n\n // Check if we're using the default globalThis.fetch to preserve context\n // When fetchImpl is globalThis.fetch, we must call it directly, not through a variable\n // Custom fetch implementations (like undici.fetch) can be called through the variable\n const isDefaultFetch = fetchImpl === globalThis.fetch;\n\n const transport: Transport = {\n // Wrap fetch in arrow function to prevent \"Illegal invocation\" error\n // For globalThis.fetch, call it directly to preserve 'this' context\n // For custom implementations, calling through the variable is safe\n fetch: isDefaultFetch\n ? (url: RequestInfo | URL, init?: RequestInit) => globalThis.fetch(url, init)\n : (url: RequestInfo | URL, init?: RequestInit) => fetchImpl(url, init),\n baseUrl: options.baseUrl,\n getAuthToken: options.getAuthToken,\n onTokenRefresh: options.onTokenRefresh,\n refreshToken: options.refreshToken,\n onAuthRevoked: options.onAuthRevoked,\n defaultHeaders: options.defaultHeaders,\n timeoutMs: options.timeoutMs,\n credentials: options.credentials, // Node.js doesn't have default credentials\n defaultAbortSignal: options.defaultAbortSignal,\n };\n\n return createHttpClient(transport);\n}\n\n// Universal factory that works in both environments\nexport function createUniversalHttpClient(options: {\n baseUrl: string;\n fetch?: typeof fetch;\n getAuthToken?: () => Promise<string | undefined>;\n onTokenRefresh?: (newToken: string) => Promise<void>;\n /**\n * Callback to refresh the access token when a 401 error with 'token_expired' is detected.\n * Should return the new access token, or throw an error if refresh fails.\n * If provided, the client will automatically retry the request after a successful refresh.\n */\n refreshToken?: () => Promise<string>;\n /**\n * Callback invoked when the server reports a revoked token family\n * (`x-auth-error: token_reuse` / `token_revoked`). Terminal \u2014 the request is\n * never retried; clear stored tokens and force a re-login.\n */\n onAuthRevoked?: () => Promise<void> | void;\n defaultHeaders?: Record<string, string>;\n timeoutMs?: number;\n credentials?: RequestCredentials;\n defaultAbortSignal?: AbortSignal;\n}): HttpClient {\n // Try to detect environment and use appropriate factory\n if (typeof window !== 'undefined') {\n // Browser environment\n return createBrowserHttpClient(options);\n } else {\n // Node.js environment\n return createNodeHttpClient(options);\n }\n}\n", "// Retry helper for HTTP requests\nexport interface RetryOptions {\n attempts?: number;\n}\n\n// Error types for retry logic\ninterface ErrorWithName extends Error {\n name: string;\n}\n\ninterface ErrorWithStatus extends Error {\n status: number;\n}\n\ninterface ErrorWithHeaders extends Error {\n headers?: Headers;\n}\n\n// Default retry condition - retry on network errors and 5xx status codes\nfunction defaultRetryCondition(error: Error, attempt: number): boolean {\n // Don't retry on the last attempt\n if (attempt <= 0) return false;\n\n // Distinguish timeout vs. user abort:\n // - Timeout: name === 'TimeoutError' (per spec/platforms)\n // - User abort: name === 'AbortError'\n const errorWithName = error as ErrorWithName;\n const name = errorWithName?.name;\n if (name === 'TimeoutError') return true;\n if (name === 'AbortError') return false;\n\n // HTTP 5xx and 429 (including HTTPError from web-client)\n const errorWithStatus = error as ErrorWithStatus;\n if (\n 'status' in errorWithStatus &&\n typeof errorWithStatus.status === 'number'\n ) {\n const status = errorWithStatus.status;\n return status >= 500 || status === 429;\n }\n // Network TypeError (DNS/reset) is reasonably retryable\n if (name === 'TypeError') return true;\n\n return false;\n}\n\n// Calculate delay with exponential backoff and jitter\nfunction calculateDelay(attempt: number): number {\n const baseDelayMs = 250; // Base 250ms as per spec\n const delay = baseDelayMs * Math.pow(2, attempt - 1);\n\n // Add \u00B120% jitter to reduce stampedes\n const jitter = (Math.random() - 0.5) * 0.4 * delay;\n return Math.max(0, delay + jitter);\n}\n\n// Retry helper function with new signature\nexport async function withRetry<T>(\n fn: (attempt: number) => Promise<T>,\n options: RetryOptions = {},\n): Promise<T> {\n const { attempts = 3 } = options;\n\n let lastError: Error | undefined;\n\n for (let attempt = 1; attempt <= attempts; attempt++) {\n try {\n return await fn(attempt);\n } catch (error) {\n lastError = error as Error;\n\n // Check if we should retry (this handles the last attempt check)\n if (!defaultRetryCondition(lastError, attempts - attempt)) {\n throw lastError;\n }\n\n // Calculate delay\n let delayMs = calculateDelay(attempt);\n\n // Check for Retry-After header if it's an HTTP error\n const errorWithHeaders = lastError as ErrorWithHeaders;\n const hdrs = errorWithHeaders.headers;\n const retryAfter = hdrs?.get?.('Retry-After');\n if (retryAfter) {\n // If it's a number, treat as seconds\n const seconds = parseInt(retryAfter, 10);\n if (!isNaN(seconds)) {\n delayMs = Math.max(delayMs, seconds * 1000);\n } else {\n // If it's a date, calculate the difference\n const date = new Date(retryAfter);\n if (!isNaN(date.getTime())) {\n const waitTime = Math.max(0, date.getTime() - Date.now());\n // Cap wait at 60s per attempt as per spec\n delayMs = Math.max(delayMs, Math.min(waitTime, 60000));\n }\n }\n }\n\n // Wait before retrying\n await new Promise((resolve) => setTimeout(resolve, delayMs));\n }\n }\n\n throw lastError || new Error('Retry failed without error');\n}\n\n// Helper to create a retry-enabled HTTP client method\nexport function createRetryableMethod<T extends unknown[], R>(\n method: (...args: T) => Promise<R>,\n retryOptions: RetryOptions = {},\n) {\n return async (...args: T): Promise<R> => {\n return withRetry(() => method(...args), retryOptions);\n };\n}\n", "import { HttpClient } from '../http-client/index.js';\nimport {\n // Common types\n ApiResponse,\n // Health and Status\n HealthResponse,\n IdentityResponse,\n ProvidersResponse,\n // Authentication\n TokenRequest,\n TokenResponse,\n RefreshTokenRequest,\n // Mock Token (testing)\n MockTokenRequest,\n // Token Management\n RevokeTokenRequest,\n RevokeTokenResponse,\n // Key Management\n CreateKeyRequest,\n CreateKeyResponse,\n DeleteKeyResponse,\n RootKey,\n // Client Management\n ClientKey,\n GenerateClientKeyRequest,\n DeleteClientResponse,\n // Permissions\n PermissionResponse,\n UpdateKeyPermissionsRequest,\n} from './auth-types.js';\n\nexport class AuthApiClient {\n constructor(private httpClient: HttpClient) {}\n\n // Health and Status Endpoints\n async getHealth(): Promise<HealthResponse> {\n const response =\n await this.httpClient.get<ApiResponse<HealthResponse>>('/auth/health');\n if (!response.data) {\n throw new Error('Health response data is null');\n }\n return response.data;\n }\n\n async getIdentity(): Promise<IdentityResponse> {\n const response =\n await this.httpClient.get<ApiResponse<IdentityResponse>>(\n '/admin/identity',\n );\n if (!response.data) {\n throw new Error('Identity response data is null');\n }\n return response.data;\n }\n\n async getProviders(): Promise<ProvidersResponse> {\n const response =\n await this.httpClient.get<ApiResponse<ProvidersResponse>>(\n '/auth/providers',\n );\n if (!response.data) {\n throw new Error('Providers response data is null');\n }\n return response.data;\n }\n\n // Authentication Endpoints\n async getLoginPage(): Promise<string> {\n return this.httpClient.get<string>('/auth/login', { parse: 'text' });\n }\n\n async generateTokens(request: TokenRequest): Promise<TokenResponse> {\n return this.httpClient.post<TokenResponse>('/auth/token', request);\n }\n\n async refreshToken(request: RefreshTokenRequest): Promise<TokenResponse> {\n return this.httpClient.post<TokenResponse>('/auth/refresh', request);\n }\n\n async generateMockTokens(request: MockTokenRequest): Promise<TokenResponse> {\n return this.httpClient.post<TokenResponse>('/auth/mock-token', request);\n }\n\n async validateToken(token: string): Promise<{\n valid: boolean;\n headers: Record<string, string>;\n status: number;\n }> {\n try {\n const response = await this.validateTokenGet(token);\n return {\n valid: response.status === 200,\n headers: response.headers,\n status: response.status,\n };\n } catch (error) {\n return {\n valid: false,\n headers: {},\n status: 401,\n };\n }\n }\n\n async validateTokenGet(\n token: string,\n ): Promise<{ status: number; headers: Record<string, string> }> {\n const response = await this.httpClient.head('/auth/validate', {\n headers: { Authorization: `Bearer ${token}` },\n });\n return {\n status: response.status,\n headers: response.headers,\n };\n }\n\n // Token Management Endpoints\n // NOTE: node auth status lives on AdminApiClient.isAuthed() (/admin-api/is-authed);\n // there is no /auth/is-authed on the auth service.\n async revokeTokens(\n request: RevokeTokenRequest,\n ): Promise<RevokeTokenResponse> {\n const response = await this.httpClient.post<ApiResponse<RevokeTokenResponse>>(\n '/admin/revoke',\n request,\n );\n if (!response.data) {\n throw new Error('Revoke tokens response data is null');\n }\n return response.data;\n }\n\n // Key Management Endpoints\n async listRootKeys(): Promise<RootKey[]> {\n const response =\n await this.httpClient.get<ApiResponse<RootKey[]>>('/admin/keys');\n if (!response.data) {\n throw new Error('Root keys response data is null');\n }\n return response.data;\n }\n\n async createRootKey(request: CreateKeyRequest): Promise<CreateKeyResponse> {\n const response = await this.httpClient.post<ApiResponse<CreateKeyResponse>>(\n '/admin/keys',\n request,\n );\n if (!response.data) {\n throw new Error('Create root key response data is null');\n }\n return response.data;\n }\n\n async deleteRootKey(keyId: string): Promise<DeleteKeyResponse> {\n return this.httpClient.delete<DeleteKeyResponse>(`/admin/keys/${keyId}`);\n }\n\n // Client Management Endpoints\n async listClientKeys(): Promise<ClientKey[]> {\n const response = await this.httpClient.get<ApiResponse<ClientKey[]>>(\n '/admin/keys/clients',\n );\n if (!response.data) {\n throw new Error('Client keys response data is null');\n }\n return response.data;\n }\n\n async generateClientKey(\n request: GenerateClientKeyRequest,\n ): Promise<TokenResponse> {\n return this.httpClient.post<TokenResponse>('/admin/client-key', request);\n }\n\n async deleteClientKey(\n keyId: string,\n clientId: string,\n ): Promise<DeleteClientResponse> {\n return this.httpClient.delete<DeleteClientResponse>(\n `/admin/keys/${keyId}/clients/${clientId}`,\n );\n }\n\n // Permission Management Endpoints\n async getKeyPermissions(keyId: string): Promise<PermissionResponse> {\n return this.httpClient.get<PermissionResponse>(\n `/admin/keys/${keyId}/permissions`,\n );\n }\n\n async updateKeyPermissions(\n keyId: string,\n changes: UpdateKeyPermissionsRequest,\n ): Promise<PermissionResponse> {\n // Core expects an { add, remove } delta, not a { permissions } replacement.\n return this.httpClient.put<PermissionResponse>(\n `/admin/keys/${keyId}/permissions`,\n { add: changes.add, remove: changes.remove },\n );\n }\n}\n", "import { AuthApiClient } from './auth-client.js';\nimport { AuthApiClientConfig } from './auth-types.js';\nimport { HttpClient } from '../http-client/index.js';\n\n// Mock HTTP client for testing\nclass MockHttpClient implements HttpClient {\n async get<T>(): Promise<T> {\n throw new Error(\n 'HTTP client not implemented - use createAuthApiClientFromHttpClient with a real HTTP client',\n );\n }\n async post<T>(): Promise<T> {\n throw new Error(\n 'HTTP client not implemented - use createAuthApiClientFromHttpClient with a real HTTP client',\n );\n }\n async put<T>(): Promise<T> {\n throw new Error(\n 'HTTP client not implemented - use createAuthApiClientFromHttpClient with a real HTTP client',\n );\n }\n async delete<T>(): Promise<T> {\n throw new Error(\n 'HTTP client not implemented - use createAuthApiClientFromHttpClient with a real HTTP client',\n );\n }\n async patch<T>(): Promise<T> {\n throw new Error(\n 'HTTP client not implemented - use createAuthApiClientFromHttpClient with a real HTTP client',\n );\n }\n async head(): Promise<{ headers: Record<string, string>; status: number }> {\n throw new Error(\n 'HTTP client not implemented - use createAuthApiClientFromHttpClient with a real HTTP client',\n );\n }\n async request<T>(): Promise<T> {\n throw new Error(\n 'HTTP client not implemented - use createAuthApiClientFromHttpClient with a real HTTP client',\n );\n }\n}\n\n// Factory functions for creating Auth API clients\nexport function createBrowserAuthApiClient(\n _config: AuthApiClientConfig,\n): AuthApiClient {\n const httpClient = new MockHttpClient();\n return new AuthApiClient(httpClient);\n}\n\nexport function createNodeAuthApiClient(\n _config: AuthApiClientConfig,\n): AuthApiClient {\n const httpClient = new MockHttpClient();\n return new AuthApiClient(httpClient);\n}\n\nexport function createAuthApiClient(\n _config: AuthApiClientConfig,\n): AuthApiClient {\n const httpClient = new MockHttpClient();\n return new AuthApiClient(httpClient);\n}\n\nexport function createAuthApiClientFromHttpClient(\n httpClient: HttpClient,\n _config: AuthApiClientConfig,\n): AuthApiClient {\n return new AuthApiClient(httpClient);\n}\n", "import { HttpClient, withRetry } from '../http-client/index.js';\nimport type {\n HealthStatus,\n AdminAuthStatus,\n InstallApplicationRequest,\n InstallApplicationResponseData,\n InstallDevApplicationRequest,\n UninstallApplicationResponseData,\n ListApplicationsResponseData,\n GetApplicationResponseData,\n ApplicationVersionEntry,\n GetApplicationAbiResponseData,\n GetLatestVersionResponseData,\n ListPackagesResponseData,\n ListVersionsResponseData,\n RegistryBundleManifest,\n CreateContextRequest,\n CreateContextResponseData,\n DeleteContextResponseData,\n GetContextsResponseData,\n Context,\n GenerateContextIdentityResponseData,\n GetContextIdentitiesResponseData,\n JoinContextResponseData,\n JoinSubgroupInheritanceResponseData,\n ContextGroupResponseData,\n ContextStorageResponseData,\n InviteSpecializedNodeRequest,\n InviteSpecializedNodeResponseData,\n UpdateContextApplicationRequest,\n ResyncContextRequest,\n ResyncContextResponseData,\n ContextsWithExecutorsResponseData,\n UploadBlobRequest,\n UploadBlobResponseData,\n DeleteBlobResponseData,\n ListBlobsResponseData,\n GetBlobInfoResponseData,\n BlobReadOptions,\n CreateContextAliasRequest,\n CreateApplicationAliasRequest,\n CreateAliasResponseData,\n LookupAliasResponseData,\n DeleteAliasResponseData,\n ListAliasesResponseData,\n ListNamespacesResponseData,\n CreateNamespaceRequest,\n CreateNamespaceResponseData,\n DeleteNamespaceResponseData,\n CreateNamespaceInvitationRequest,\n CreateNamespaceInvitationResponseData,\n CreateRecursiveInvitationResponseData,\n JoinNamespaceRequest,\n JoinNamespaceResponseData,\n CreateGroupInNamespaceRequest,\n CreateGroupInNamespaceResponseData,\n SubgroupEntry,\n Namespace,\n NamespaceIdentity,\n NodeIdentity,\n AccountPairInitRequest,\n AccountPairInitResponseData,\n AccountPairCompleteRequest,\n AccountPairCompleteResponseData,\n RelinkDeviceRequest,\n RelinkDeviceResponseData,\n AccountDeviceEntry,\n AccountApplicationEntry,\n RevokeAccountDeviceRequest,\n RevokeAccountDeviceResponseData,\n GroupInfoResponseData,\n CreateGroupRequest,\n CreateGroupResponseData,\n DeleteGroupResponseData,\n ListGroupMembersResponseData,\n ListGroupContextsResponseData,\n AddGroupMembersRequest,\n RemoveGroupMembersRequest,\n UpdateMemberRoleRequest,\n MemberCapabilities,\n SetMemberCapabilitiesRequest,\n SetDefaultCapabilitiesRequest,\n SetMemberAutoFollowRequest,\n SetSubgroupVisibilityRequest,\n SetTeeAdmissionPolicyRequest,\n GetTeeAdmissionPolicyResponseData,\n SetGroupMetadataRequest,\n SetMemberMetadataRequest,\n SetContextMetadataRequest,\n MetadataRecord,\n GetMetadataResponseData,\n SyncGroupResponseData,\n UpgradeGroupRequest,\n UpgradeGroupResponseData,\n GroupUpgradeStatusResponseData,\n MigrationStatus,\n CascadeStatusEntry,\n RetryGroupUpgradeResponseData,\n ReparentGroupRequest,\n ReparentGroupResponseData,\n IssueOwnershipProofRequest,\n IssueNamespaceOwnershipProofRequest,\n IssueOwnershipProofResponseData,\n CreateGroupInvitationRequest,\n CreateGroupInvitationResponseData,\n CreateRecursiveGroupInvitationResponseData,\n JoinGroupRequest,\n JoinGroupResponseData,\n TeeInfoResponseData,\n TeeAttestRequest,\n TeeAttestResponseData,\n TeeVerifyQuoteRequest,\n TeeVerifyQuoteResponseData,\n PerformIntentRequest,\n PerformIntentResponseData,\n IntentRelayInfo,\n AdmitJoinRequest,\n AdmitJoinResponseData,\n} from './admin-types.js';\n\n/**\n * Helper: server wraps most responses in `{ data: T }`.\n * This extracts `.data` so callers get the inner payload directly. Null-safe so an\n * empty 2xx body (parsed as null) yields undefined instead of throwing.\n */\nfunction unwrap<T>(response: { data: T }): T {\n return response?.data as T;\n}\n\n/**\n * Compare two version strings by SemVer 2.0 precedence, ascending: negative if\n * `a < b`, positive if `a > b`, `0` if equal. Build metadata (`+...`) is stripped\n * and ignored. The numeric `major.minor.patch` core is compared field-by-field\n * (numerically when both parse, so `1.10.0 > 1.9.0`; a missing field is `0`). A\n * version WITH a pre-release ranks below the same core without one, and\n * pre-release identifiers compare per spec: dot-separated, numeric identifiers\n * numerically, alphanumeric lexically by ASCII, numeric below alphanumeric, and a\n * shorter set of identifiers loses when all preceding fields are equal.\n */\nexport function compareSemver(a: string, b: string): number {\n const [coreA, preA] = splitVersion(a);\n const [coreB, preB] = splitVersion(b);\n\n const na = coreA.split('.');\n const nb = coreB.split('.');\n const n = Math.max(na.length, nb.length);\n for (let i = 0; i < n; i++) {\n const c = compareSemverId(na[i] ?? '0', nb[i] ?? '0');\n if (c !== 0) return c;\n }\n\n // A pre-release ranks below the same core version with no pre-release.\n if (preA === undefined && preB === undefined) return 0;\n if (preA === undefined) return 1;\n if (preB === undefined) return -1;\n\n const pa = preA.split('.');\n const pb = preB.split('.');\n const m = Math.max(pa.length, pb.length);\n for (let i = 0; i < m; i++) {\n if (i >= pa.length) return -1; // shorter set loses when all preceding equal\n if (i >= pb.length) return 1;\n const c = compareSemverId(pa[i], pb[i]);\n if (c !== 0) return c;\n }\n return 0;\n}\n\n/** Drop build metadata and split the pre-release tail: `1.2.3-rc.1+b` -> `['1.2.3', 'rc.1']`. */\nfunction splitVersion(v: string): [string, string | undefined] {\n const core = v.split('+', 1)[0];\n const dash = core.indexOf('-');\n return dash === -1 ? [core, undefined] : [core.slice(0, dash), core.slice(dash + 1)];\n}\n\n/**\n * Compare one identifier: numerically when both are all-digits, else lexically by\n * ASCII with a numeric identifier ranking below an alphanumeric one. Fallback: a\n * non-numeric core component (loose/malformed input) is treated as a string, so\n * comparison never throws.\n */\nfunction compareSemverId(a: string, b: string): number {\n const na = /^\\d+$/.test(a);\n const nb = /^\\d+$/.test(b);\n if (na && nb) {\n const d = Number(a) - Number(b);\n return d < 0 ? -1 : d > 0 ? 1 : 0;\n }\n if (na) return -1;\n if (nb) return 1;\n return a < b ? -1 : a > b ? 1 : 0;\n}\n\n/**\n * Fetch a URL from the (foreign-origin) registry with a per-attempt timeout and\n * retry on transient failures. Deliberately NOT routed through the node\n * `HttpClient`: that client attaches the node's bearer token to every request,\n * which must never leak to the registry's origin. Each attempt times out after\n * ~10s; network errors and 5xx are retried (2 retries, short backoff via the\n * shared `withRetry`), while a 4xx is a definitive answer and is not retried.\n * `kind`/`context` shape the error message so failures stay debuggable in logs.\n */\nasync function fetchRegistry(url: string, kind: string, context: string): Promise<Response> {\n return withRetry(\n async () => {\n const resp = await fetch(url, { signal: AbortSignal.timeout(10000) });\n if (!resp.ok) {\n // Carry `status` so withRetry retries 5xx but leaves 4xx to throw.\n const err = new Error(\n `registry ${kind} fetch failed (${resp.status}) for ${context}`,\n ) as Error & { status: number };\n err.status = resp.status;\n throw err;\n }\n return resp;\n },\n { attempts: 3 },\n );\n}\n\nexport class AdminApiClient {\n constructor(private httpClient: HttpClient) {}\n\n // ---- Health and Status (public, no auth) ----\n\n async healthCheck(): Promise<HealthStatus> {\n return unwrap(await this.httpClient.get<{ data: HealthStatus }>('/admin-api/health'));\n }\n\n async isAuthed(): Promise<AdminAuthStatus> {\n return this.httpClient.get<AdminAuthStatus>('/admin-api/is-authed');\n }\n\n // ---- Application Management ----\n\n /**\n * Install a published application by its `package@version` coordinates. The\n * node resolves and fetches them from its own configured `[registry]`, so no\n * URL is passed and none is accepted. A 502 means the node's source has\n * nothing published at those coordinates. This is the discrete \"download\"\n * step an Updates flow pairs with a subsequent `upgradeGroup`.\n */\n async installApplication(request: InstallApplicationRequest): Promise<InstallApplicationResponseData> {\n return unwrap(await this.httpClient.post<{ data: InstallApplicationResponseData }>('/admin-api/install-application', request));\n }\n\n /**\n * List a package's published versions from the registry, newest-first by\n * semver. Reads the registry's V2 bundle listing\n * (`GET {registry}/api/v2/bundles?package={package}`), taking each bundle's\n * `appVersion`. Registry-side data \u2014 distinct from the node's\n * installed-version list \u2014 and the source an Updates view compares against\n * the running `Context.applicationVersion` to detect \"a new version exists\".\n */\n async getRegistryVersions(registryUrl: string, packageName: string): Promise<string[]> {\n const url = new URL('/api/v2/bundles', new URL(registryUrl).origin);\n url.searchParams.set('package', packageName);\n const resp = await fetchRegistry(url.toString(), 'versions', packageName);\n const bundles = (await resp.json()) as RegistryBundleManifest[];\n return (Array.isArray(bundles) ? bundles : [])\n .map((b) => b.appVersion)\n .filter((v): v is string => typeof v === 'string')\n .sort((a, b) => compareSemver(b, a));\n }\n\n async installDevApplication(request: InstallDevApplicationRequest): Promise<InstallApplicationResponseData> {\n return unwrap(await this.httpClient.post<{ data: InstallApplicationResponseData }>('/admin-api/install-dev-application', request));\n }\n\n async uninstallApplication(appId: string): Promise<UninstallApplicationResponseData> {\n return unwrap(await this.httpClient.delete<{ data: UninstallApplicationResponseData }>(`/admin-api/applications/${appId}`));\n }\n\n async listApplications(): Promise<ListApplicationsResponseData> {\n return unwrap(await this.httpClient.get<{ data: ListApplicationsResponseData }>('/admin-api/applications'));\n }\n\n async getApplication(appId: string): Promise<GetApplicationResponseData> {\n return unwrap(await this.httpClient.get<{ data: GetApplicationResponseData }>(`/admin-api/applications/${appId}`));\n }\n\n /**\n * Installed-blob inventory for an application \u2014 one entry per locally installed\n * version. This is the *installed* inventory (source for a \"pick a version to\n * pin\" UI); the registry equivalent is `listPackageVersions`.\n */\n async listApplicationVersions(applicationId: string): Promise<ApplicationVersionEntry[]> {\n return unwrap(\n await this.httpClient.get<{ data: ApplicationVersionEntry[] }>(`/admin-api/applications/${applicationId}/versions`),\n );\n }\n\n /**\n * The application's embedded `wasm-abi/1` manifest. Omit `serviceName` for\n * single-service apps; core 400s if the ABI is absent or the name is ambiguous.\n */\n async getApplicationAbi(applicationId: string, serviceName?: string): Promise<GetApplicationAbiResponseData> {\n const query = serviceName ? `?service_name=${encodeURIComponent(serviceName)}` : '';\n return unwrap(\n await this.httpClient.get<{ data: GetApplicationAbiResponseData }>(\n `/admin-api/applications/${applicationId}/abi${query}`,\n ),\n );\n }\n\n // ---- Package Management ----\n\n async listPackages(): Promise<ListPackagesResponseData> {\n // Core returns this flat ({ packages: [...] }), not under `data`; tolerate both.\n const r = await this.httpClient.get<ListPackagesResponseData & { data?: ListPackagesResponseData }>(\n '/admin-api/packages',\n );\n return (r?.data ?? r) as ListPackagesResponseData;\n }\n\n async listPackageVersions(packageName: string): Promise<ListVersionsResponseData> {\n // Core returns this flat ({ versions: [...] }), not under `data`; tolerate both.\n const r = await this.httpClient.get<ListVersionsResponseData & { data?: ListVersionsResponseData }>(\n `/admin-api/packages/${encodeURIComponent(packageName)}/versions`,\n );\n return (r?.data ?? r) as ListVersionsResponseData;\n }\n\n async getLatestPackageVersion(packageName: string): Promise<GetLatestVersionResponseData> {\n return this.httpClient.get<GetLatestVersionResponseData>(\n `/admin-api/packages/${encodeURIComponent(packageName)}/latest`,\n );\n }\n\n // ---- Context Management ----\n\n async createContext(request: CreateContextRequest): Promise<CreateContextResponseData> {\n // Core requires `initializationParams` (no default); default it to an empty\n // byte array so callers that pass none don't get a 400.\n const body = { ...request, initializationParams: request.initializationParams ?? [] };\n return unwrap(await this.httpClient.post<{ data: CreateContextResponseData }>('/admin-api/contexts', body));\n }\n\n async deleteContext(contextId: string): Promise<DeleteContextResponseData> {\n return unwrap(await this.httpClient.delete<{ data: DeleteContextResponseData }>(`/admin-api/contexts/${contextId}`));\n }\n\n async getContexts(): Promise<GetContextsResponseData> {\n return unwrap(await this.httpClient.get<{ data: GetContextsResponseData }>('/admin-api/contexts'));\n }\n\n async getContext(contextId: string): Promise<Context> {\n return unwrap(await this.httpClient.get<{ data: Context }>(`/admin-api/contexts/${contextId}`));\n }\n\n async getContextsForApplication(applicationId: string): Promise<GetContextsResponseData> {\n return unwrap(await this.httpClient.get<{ data: GetContextsResponseData }>(`/admin-api/contexts/for-application/${applicationId}`));\n }\n\n // ---- Context Identity ----\n\n async generateContextIdentity(): Promise<GenerateContextIdentityResponseData> {\n return unwrap(await this.httpClient.post<{ data: GenerateContextIdentityResponseData }>('/admin-api/identity/context', {}));\n }\n\n async getContextIdentities(contextId: string): Promise<GetContextIdentitiesResponseData> {\n return unwrap(await this.httpClient.get<{ data: GetContextIdentitiesResponseData }>(`/admin-api/contexts/${contextId}/identities`));\n }\n\n async getContextIdentitiesOwned(contextId: string): Promise<GetContextIdentitiesResponseData> {\n return unwrap(await this.httpClient.get<{ data: GetContextIdentitiesResponseData }>(`/admin-api/contexts/${contextId}/identities-owned`));\n }\n\n // ---- Context join (group membership) ----\n\n async joinContext(contextId: string): Promise<JoinContextResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: JoinContextResponseData }>(`/admin-api/contexts/${contextId}/join`, {}),\n );\n }\n\n // ---- Context group / storage / sync ----\n\n async getContextGroup(contextId: string): Promise<ContextGroupResponseData> {\n return unwrap(await this.httpClient.get<{ data: ContextGroupResponseData }>(`/admin-api/contexts/${contextId}/group`));\n }\n\n async getContextStorage(contextId: string): Promise<ContextStorageResponseData> {\n return unwrap(await this.httpClient.get<{ data: ContextStorageResponseData }>(`/admin-api/contexts/${contextId}/storage`));\n }\n\n /** Sync one context, or every context when `contextId` is omitted. */\n async syncContext(contextId?: string): Promise<void> {\n // Sync-all is `/contexts/sync` with no trailing slash - core routes the two\n // spellings separately and 404s the trailing one.\n const path = contextId ? `/admin-api/contexts/sync/${contextId}` : '/admin-api/contexts/sync';\n await this.httpClient.post(path, {});\n }\n\n /**\n * Kick off a full state re-pull for a context (operator recovery for a\n * stranded context). `force` re-pulls even when the node does not flag the\n * context as stranded.\n */\n async resyncContext(\n contextId: string,\n request: ResyncContextRequest = {},\n ): Promise<ResyncContextResponseData> {\n // Core's `ResyncContextApiResponse` is a flat payload (no inner `data`\n // field), so parse the body directly \u2014 do NOT `unwrap`, or `resyncStarted`\n // reads as undefined and the resync silently appears to never start.\n const r = await this.httpClient.post<ResyncContextResponseData | null>(\n `/admin-api/contexts/${contextId}/resync`,\n request,\n );\n // An empty 2xx body means the resync was accepted; synthesize the result so\n // callers always get a typed value instead of null.\n return r ?? { contextId, resyncStarted: true };\n }\n\n async inviteSpecializedNode(request: InviteSpecializedNodeRequest): Promise<InviteSpecializedNodeResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: InviteSpecializedNodeResponseData }>(\n '/admin-api/contexts/invite-specialized-node',\n request,\n ),\n );\n }\n\n async updateContextApplication(\n contextId: string,\n request: UpdateContextApplicationRequest,\n ): Promise<void> {\n await this.httpClient.post(`/admin-api/contexts/${contextId}/application`, request);\n }\n\n async getContextsWithExecutorsForApplication(applicationId: string): Promise<ContextsWithExecutorsResponseData> {\n // Core returns this flat as { contexts: [...] } (not a bare array under `data`).\n const r = await this.httpClient.get<\n | ContextsWithExecutorsResponseData\n | { contexts: ContextsWithExecutorsResponseData }\n | { data: ContextsWithExecutorsResponseData }\n >(`/admin-api/contexts/with-executors/for-application/${applicationId}`);\n if (Array.isArray(r)) return r;\n return (\n (r as { contexts?: ContextsWithExecutorsResponseData } | null)?.contexts ??\n (r as { data?: ContextsWithExecutorsResponseData } | null)?.data ??\n []\n );\n }\n\n // ---- Blob Management ----\n\n async uploadBlob(request: UploadBlobRequest): Promise<UploadBlobResponseData> {\n // Core streams the raw request body into blob storage (no JSON) and takes\n // its params from the query string (`hash`, `context_id` \u2014 snake_case).\n const params = new URLSearchParams();\n if (request.hash) params.set('hash', request.hash);\n if (request.contextId) params.set('context_id', request.contextId);\n const query = params.toString();\n const path = query ? `/admin-api/blobs?${query}` : '/admin-api/blobs';\n // request.data (Uint8Array view | ArrayBuffer | Blob) is a valid BodyInit and\n // is streamed verbatim \u2014 no JSON, no cast. fetch honors a Uint8Array view's\n // byteOffset/byteLength, so subarrays upload the correct region.\n // Core's BlobInfo is snake_case (`blob_id`); map to camelCase like deleteBlob.\n const res = unwrap(\n await this.httpClient.request<{ data: { blob_id: string; size: number } }>(path, {\n method: 'PUT',\n body: request.data,\n headers: { 'Content-Type': 'application/octet-stream' },\n }),\n );\n return { blobId: res.blob_id, size: res.size };\n }\n\n async deleteBlob(blobId: string): Promise<DeleteBlobResponseData> {\n // Core's `BlobDeleteResponse` is a flat, snake_case payload (`{ blob_id,\n // deleted }`) \u2014 the lone admin DTO without a camelCase rename and without an\n // inner `data` field. Parse directly (no `unwrap`) and map to camelCase.\n const body = await this.httpClient.delete<{ blob_id: string; deleted: boolean }>(\n `/admin-api/blobs/${blobId}`,\n );\n return { blobId: body.blob_id, deleted: body.deleted };\n }\n\n async listBlobs(): Promise<ListBlobsResponseData> {\n // Core's BlobInfo is snake_case (`blob_id`); map to camelCase.\n const res = unwrap(\n await this.httpClient.get<{ data: { blobs: Array<{ blob_id: string; size: number }> } }>(\n '/admin-api/blobs',\n ),\n );\n return { blobs: res.blobs.map((b) => ({ blobId: b.blob_id, size: b.size })) };\n }\n\n /**\n * Blob-read query params. `context_id` is the same snake_case param\n * {@link uploadBlob} announces with; building it in one place keeps the read\n * side from drifting from the write side.\n */\n private blobPath(blobId: string, options?: BlobReadOptions): string {\n if (!options?.contextId) return `/admin-api/blobs/${blobId}`;\n const params = new URLSearchParams({ context_id: options.contextId });\n return `/admin-api/blobs/${blobId}?${params.toString()}`;\n }\n\n /**\n * Download a blob's raw bytes. `GET /admin-api/blobs/:id` streams the blob\n * content (e.g. `application/gzip`), NOT JSON \u2014 so fetch it as an ArrayBuffer.\n * Use {@link listBlobs} for `{ blobId, size }` metadata.\n *\n * Without `contextId` the read is local-only: the node answers from its own\n * blob store and returns immediately, or 404s. Passing `contextId` opts into\n * network discovery \u2014 the node probes that context's peers (availability\n * nodes first) for a holder, then transfers the bytes. Budget for it: core\n * bounds discovery by a ~30s deadline, and the transfer is on top of that, so\n * the worst case is well past what a UI should block on unhinted.\n */\n async getBlob(blobId: string, options?: BlobReadOptions): Promise<ArrayBuffer> {\n return this.httpClient.get<ArrayBuffer>(this.blobPath(blobId, options), {\n parse: 'arrayBuffer',\n });\n }\n\n /**\n * Fetch a blob's metadata without downloading it. `HEAD /admin-api/blobs/:id`\n * returns the info in response headers (size via `content-length`, plus\n * `x-blob-id`/`x-blob-hash`/`x-blob-mime-type`).\n *\n * Without `contextId` this is a local-only presence check that returns\n * immediately. Passing `contextId` opts into the same network discovery\n * {@link getBlob} uses \u2014 presence and size answered by probing the context's\n * peers, with no transfer \u2014 so it inherits core's ~30s discovery deadline as\n * its worst case. A probe only carries `found` and `size`, so a peer-sourced\n * answer has no `hash`/`mimeType`; read `source` to tell the two apart.\n */\n async getBlobInfo(\n blobId: string,\n options?: BlobReadOptions,\n ): Promise<GetBlobInfoResponseData> {\n // HEAD throws (HttpError) on a non-2xx status, so we only reach here on success\n // \u2014 the x-blob-* headers are present. Guard size against a missing/non-numeric\n // content-length anyway (defaults to 0 rather than NaN).\n const { headers } = await this.httpClient.head(this.blobPath(blobId, options));\n const size = Number(headers['content-length']);\n return {\n blobId: headers['x-blob-id'] ?? blobId,\n size: Number.isFinite(size) ? size : 0,\n hash: headers['x-blob-hash'],\n mimeType: headers['x-blob-mime-type'],\n // Nodes that predate the context-aware HEAD omit this header entirely, so\n // it stays undefined rather than being defaulted to 'local' \u2014 absent means\n // \"the node didn't say\", which is not the same claim as \"served locally\".\n source: headers['x-blob-source'] as GetBlobInfoResponseData['source'],\n };\n }\n\n // ---- Alias Management ----\n\n async createContextAlias(\n request: CreateContextAliasRequest,\n ): Promise<CreateAliasResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: CreateAliasResponseData }>(\n '/admin-api/alias/create/context',\n { alias: request.alias, contextId: request.contextId },\n ),\n );\n }\n\n async createApplicationAlias(\n request: CreateApplicationAliasRequest,\n ): Promise<CreateAliasResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: CreateAliasResponseData }>(\n '/admin-api/alias/create/application',\n { alias: request.alias, applicationId: request.applicationId },\n ),\n );\n }\n\n async lookupContextAlias(name: string): Promise<LookupAliasResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: LookupAliasResponseData }>(\n `/admin-api/alias/lookup/context/${encodeURIComponent(name)}`,\n {},\n ),\n );\n }\n\n async lookupApplicationAlias(name: string): Promise<LookupAliasResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: LookupAliasResponseData }>(\n `/admin-api/alias/lookup/application/${encodeURIComponent(name)}`,\n {},\n ),\n );\n }\n\n async deleteContextAlias(name: string): Promise<DeleteAliasResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: DeleteAliasResponseData }>(\n `/admin-api/alias/delete/context/${encodeURIComponent(name)}`,\n {},\n ),\n );\n }\n\n async deleteApplicationAlias(name: string): Promise<DeleteAliasResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: DeleteAliasResponseData }>(\n `/admin-api/alias/delete/application/${encodeURIComponent(name)}`,\n {},\n ),\n );\n }\n\n async listContextAliases(): Promise<ListAliasesResponseData> {\n return unwrap(await this.httpClient.get<{ data: ListAliasesResponseData }>('/admin-api/alias/list/context'));\n }\n\n async listApplicationAliases(): Promise<ListAliasesResponseData> {\n return unwrap(await this.httpClient.get<{ data: ListAliasesResponseData }>('/admin-api/alias/list/application'));\n }\n\n // ---- Namespace Management ----\n\n async listNamespaces(): Promise<ListNamespacesResponseData> {\n return unwrap(await this.httpClient.get<{ data: ListNamespacesResponseData }>('/admin-api/namespaces'));\n }\n\n async getNamespace(namespaceId: string): Promise<Namespace> {\n return unwrap(await this.httpClient.get<{ data: Namespace }>(`/admin-api/namespaces/${namespaceId}`));\n }\n\n /**\n * Who this node is \u2014 the account it writes as, the device it is, the key it\n * signs with, and the account root a second device pairs against.\n *\n * Takes no namespace, and that is the point: one root key is one account\n * everywhere, and a node signs with one key, so none of it varies by\n * namespace.\n */\n async getNodeIdentity(): Promise<NodeIdentity> {\n return unwrap(await this.httpClient.get<{ data: NodeIdentity }>('/admin-api/identity'));\n }\n\n /**\n * @deprecated Use {@link getNodeIdentity} instead. Every field this returns is\n * node-level, so the namespace was only ever decoration \u2014 it now delegates to\n * the node-level route and reshapes the answer.\n *\n * Three consequences of that delegation, all visible to a caller who relied on\n * the old route's behaviour:\n *\n * - **No participation gate.** The namespace route answered 404 when this node\n * had never joined the namespace; this answers whatever the node's identity\n * is, regardless. If you were using it to ask \"am I in this namespace?\", ask\n * {@link listNamespaces} instead \u2014 that is the question you were really\n * asking.\n * - **`namespaceId` is echoed verbatim.** The old route resolved a subgroup id\n * to its root namespace and returned that; passing a subgroup id here gives\n * the subgroup id back.\n * - **404 means something else.** Previously \"not my namespace\", now \"this node\n * holds no account root yet\".\n */\n async getNamespaceIdentity(namespaceId: string): Promise<NamespaceIdentity> {\n const node = await this.getNodeIdentity();\n return { namespaceId, publicKey: node.publicKey, account: node.accountId };\n }\n\n /**\n * Ask this node to run one method on a member's behalf, under a warrant that\n * member signed.\n *\n * The node executes and signs the envelope with its own key; the change is\n * attributed to the **author**. Both halves travel together, so every peer\n * re-checks that the member consented instead of trusting the relay.\n *\n * Three things have to be true first, and none is implied by the others:\n *\n * - the author's **account** is a member of the group owning the context \u2014\n * their device joins nothing and is in no group's binding rows, which is\n * exactly the case a device certificate covers;\n * - this node holds `CAN_AUTHOR_ON_BEHALF` on that group, which is implied by\n * neither membership nor admin;\n * - the warrant has not been spent. It is single-use: presenting a valid one\n * twice is refused, because the signature stays valid forever and replay is\n * not forgery.\n *\n * A refusal comes back as a `403` carrying the reason \u2014 \"an admin must grant\n * CAN_AUTHOR_ON_BEHALF to \u2026\", or that the nonce is already spent \u2014 so a caller\n * can tell which precondition failed rather than only that one did.\n *\n * Mint the warrant with {@link signWarrant}; see\n * {@link PerformIntentRequest.warrant}.\n */\n async performIntent(\n contextId: string,\n request: PerformIntentRequest,\n ): Promise<PerformIntentResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: PerformIntentResponseData }>(\n `/admin-api/contexts/${contextId}/intents`,\n request,\n ),\n );\n }\n\n /**\n * Ask what this node can do for a member in `contextId`, before they sign\n * anything.\n *\n * The two facts {@link performIntent} needs and a client cannot derive: whose\n * account goes in the warrant's `executor`, and whether this node holds\n * `CAN_AUTHOR_ON_BEHALF` on the owning group. `canAuthorOnBehalf: false` comes\n * back as an answer rather than an error \u2014 it is the default state of every\n * context \u2014 so a caller can say \"an admin of `groupId` must grant it to\n * `executorAccount`\" instead of presenting a warrant that will be refused\n * after the author has spent a nonce on it.\n *\n * `404` means the context belongs to no group, or this node holds no account\n * yet; either way it can be named as no warrant's executor.\n *\n * For a caller with no credential on the node at all \u2014 a browser tab holding\n * one signing key \u2014 use `RelayClient`, which reads this same route on a node\n * run as a relay.\n */\n async getIntentRelay(contextId: string): Promise<IntentRelayInfo> {\n return unwrap(\n await this.httpClient.get<{ data: IntentRelayInfo }>(\n `/admin-api/contexts/${contextId}/intents`,\n ),\n );\n }\n\n async listNamespacesForApplication(applicationId: string): Promise<ListNamespacesResponseData> {\n return unwrap(await this.httpClient.get<{ data: ListNamespacesResponseData }>(`/admin-api/namespaces/for-application/${applicationId}`));\n }\n\n async createNamespace(request: CreateNamespaceRequest): Promise<CreateNamespaceResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: CreateNamespaceResponseData }>('/admin-api/namespaces', request),\n );\n }\n\n async deleteNamespace(namespaceId: string): Promise<DeleteNamespaceResponseData> {\n // Core requires `Content-Type: application/json` on this DELETE even though\n // the body is always empty, so send the header and an empty JSON object.\n return unwrap(\n await this.httpClient.request<{ data: DeleteNamespaceResponseData }>(`/admin-api/namespaces/${namespaceId}`, {\n method: 'DELETE',\n body: '{}',\n headers: { 'Content-Type': 'application/json' },\n }),\n );\n }\n\n async createNamespaceInvitation(\n namespaceId: string,\n request?: CreateNamespaceInvitationRequest,\n ): Promise<CreateNamespaceInvitationResponseData | CreateRecursiveInvitationResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: CreateNamespaceInvitationResponseData | CreateRecursiveInvitationResponseData }>(\n `/admin-api/namespaces/${namespaceId}/invite`,\n request ?? {},\n ),\n );\n }\n\n /**\n * Present a join this caller signed to a node the inviter named as an\n * admitter.\n *\n * For a member with no node. `joinNamespace` publishes the membership op from\n * the node making the call; this hands an already-signed op to somebody else's\n * node to publish. The distinction matters because a keyholder has nowhere to\n * publish from.\n *\n * The op must be signed by the **device key** in the credential it carries \u2014\n * every peer checks that when applying a join. So the admitter cannot author\n * this, only carry it: a hostile one can refuse, and nothing else. It cannot\n * admit a different account, change the group, or grant a role.\n *\n * @param namespaceId the namespace being joined, 64 hex\n * @param request the invitation and the hex-encoded signed op\n */\n async admitJoin(\n namespaceId: string,\n request: AdmitJoinRequest,\n ): Promise<AdmitJoinResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: AdmitJoinResponseData }>(\n `/admin-api/namespaces/${namespaceId}/admit`,\n request,\n { timeoutMs: 65000 },\n ),\n );\n }\n\n async joinNamespace(\n namespaceId: string,\n request: JoinNamespaceRequest,\n ): Promise<JoinNamespaceResponseData> {\n const data = unwrap(\n await this.httpClient.post<{ data: JoinNamespaceResponseData }>(\n `/admin-api/namespaces/${namespaceId}/join`,\n request,\n { timeoutMs: 65000 },\n ),\n );\n\n // core 0.11.0-rc.25 renamed this response's `groupId` to `namespaceId`\n // (core#3598). Bind whichever spelling the node actually sent rather than\n // picking one: the rename lands as `undefined` on the field the client\n // reads, and nothing errors \u2014 no 4xx, no thrown parse \u2014 so a client that\n // knows only one spelling fails much later and somewhere else. Normalising\n // here means one mero-js works against nodes either side of that release.\n if (data && data.namespaceId === undefined && data.groupId !== undefined) {\n return { ...data, namespaceId: data.groupId };\n }\n return data;\n }\n\n async createGroupInNamespace(\n namespaceId: string,\n request?: CreateGroupInNamespaceRequest,\n ): Promise<CreateGroupInNamespaceResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: CreateGroupInNamespaceResponseData }>(\n `/admin-api/namespaces/${namespaceId}/groups`,\n request ?? {},\n ),\n );\n }\n\n async listNamespaceGroups(namespaceId: string): Promise<SubgroupEntry[]> {\n return unwrap(await this.httpClient.get<{ data: SubgroupEntry[] }>(`/admin-api/namespaces/${namespaceId}/groups`));\n }\n\n // ---- Account Devices & Pairing ----\n\n /**\n * Mint this node a device for an account that already lives somewhere else -\n * the first half of pairing, run on the joining node.\n *\n * Publishes nothing and needs no key: it produces the device id, the two\n * public keys and the signature that the account holder's\n * {@link completeAccountPairing} certifies, plus a code to read out to them\n * over a channel the payload does not travel on. Until that second half runs,\n * the device this mints is inert.\n *\n * Takes a set of namespaces rather than one, and takes it from the caller\n * because this node cannot discover it: a node that is a member of nothing can\n * neither read the account's namespace set off a DAG nor derive it. One device\n * covers however many are named - the certificate is over the account, not a\n * scope - so there is one id and one code to hand over regardless.\n */\n async initAccountPairing(request: AccountPairInitRequest): Promise<AccountPairInitResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: AccountPairInitResponseData }>('/admin-api/account/pair-init', request),\n );\n }\n\n /**\n * Certify a device another node minted, link it, and deliver its scope keys -\n * the second half of pairing, run on the node that holds the account root.\n *\n * Every field but `applications` is copied verbatim out of that node's\n * {@link initAccountPairing} answer. Only this side can complete it: the\n * certificate is signed by the account root, which never leaves the node that\n * holds it.\n *\n * The scope is named in applications, not namespaces, because that is the\n * question a person can answer - a namespace is an implementation unit they\n * never chose. Leave it out to grant every application.\n */\n async completeAccountPairing(\n request: AccountPairCompleteRequest,\n ): Promise<AccountPairCompleteResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: AccountPairCompleteResponseData }>('/admin-api/account/pair-complete', request),\n );\n }\n\n /**\n * Re-run the pairing fan-out for a device this account already certified,\n * against the namespaces this node takes part in now.\n *\n * Pairing is a snapshot, and this is how it is repeated. A namespace created\n * or joined afterwards holds no binding for a device paired before it, and the\n * symptom is silence - the device simply never sees that namespace. Nothing\n * but the id is needed to repair it: the certificate is already held here,\n * root-signed and naming no namespace, so a fresh endorsement and a key wrap\n * are all a later namespace is missing. The device does not have to be online.\n *\n * Passing `applications` widens the device's stored scope as well as\n * repairing. Passing none - or an empty list - repairs against the scope\n * already stored, which is deliberately NOT the \"every application\" that an\n * empty list means on {@link completeAccountPairing}: overloading it here\n * would make the accidental request the widest one.\n */\n async relinkAccountDevice(\n deviceId: string,\n request?: RelinkDeviceRequest,\n ): Promise<RelinkDeviceResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: RelinkDeviceResponseData }>(\n `/admin-api/account/devices/${deviceId}/relink`,\n request ?? {},\n ),\n );\n }\n\n /**\n * Every device of this account, as this node sees them - its own included.\n *\n * Joined from the node-local certificate cache and the live bindings of every\n * namespace this node takes part in, so it is this node's view rather than a\n * global one: a device certified by another holder appears with an empty\n * `applications`, because the certificate that would name its scope is not\n * cached here.\n *\n * The wire wraps this in `devices` rather than the usual `data`; the array is\n * what a caller wants, so that wrapper is not passed on.\n */\n async listAccountDevices(): Promise<AccountDeviceEntry[]> {\n const response = await this.httpClient.get<{ devices: AccountDeviceEntry[] }>('/admin-api/account/devices');\n return response.devices;\n }\n\n /**\n * Every application this account speaks in, with the namespaces targeting each.\n *\n * What a device-scoping UI lists: {@link completeAccountPairing} and\n * {@link relinkAccountDevice} both take applications, and this is where the\n * ids they take come from. Derived from the namespaces this node takes part\n * in, so an application installed with no namespace yet is absent - it has\n * nothing to scope a device to until one exists.\n *\n * Wrapped in `applications` on the wire rather than `data`, unwrapped here for\n * the same reason {@link listAccountDevices} unwraps `devices`.\n */\n async listAccountApplications(): Promise<AccountApplicationEntry[]> {\n const response = await this.httpClient.get<{ applications: AccountApplicationEntry[] }>(\n '/admin-api/account/applications',\n );\n return response.applications;\n }\n\n /**\n * Withdraw a device from this account, terminally.\n *\n * Two authorities reach the same endpoint. An admin may revoke any device and\n * rotates the scope key as it goes. The account holder may revoke its own with\n * a root-signed `proof`, which does not rotate - so read\n * {@link RevokeAccountDeviceResponseData.revokedIn} rather than assuming the\n * device lost its access: a namespace reporting `keyRotated: false` has\n * stopped the device writing but leaves it able to read until an admin\n * rotates.\n *\n * `namespaceId` names where to publish from, not the extent of the revocation:\n * a device belongs to the account, so every namespace holding a binding for it\n * is withdrawn from and reported back.\n */\n async revokeAccountDevice(\n namespaceId: string,\n request: RevokeAccountDeviceRequest,\n ): Promise<RevokeAccountDeviceResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: RevokeAccountDeviceResponseData }>(\n `/admin-api/namespaces/${namespaceId}/account/revoke`,\n request,\n ),\n );\n }\n\n // ---- Group Management ----\n\n async getGroupInfo(groupId: string): Promise<GroupInfoResponseData> {\n return unwrap(await this.httpClient.get<{ data: GroupInfoResponseData }>(`/admin-api/groups/${groupId}`));\n }\n\n /** Thin wrapper over {@link getGroupInfo}: returns the group's `defaultCapabilities` bitmask. */\n async getDefaultCapabilities(groupId: string): Promise<number> {\n return (await this.getGroupInfo(groupId)).defaultCapabilities;\n }\n\n /** Thin wrapper over {@link getGroupInfo}: returns the group's `subgroupVisibility`. */\n async getSubgroupVisibility(groupId: string): Promise<string> {\n return (await this.getGroupInfo(groupId)).subgroupVisibility;\n }\n\n async deleteGroup(groupId: string): Promise<DeleteGroupResponseData> {\n // Core requires `Content-Type: application/json` on this DELETE even though\n // the body is always empty, so send the header and an empty JSON object.\n return unwrap(\n await this.httpClient.request<{ data: DeleteGroupResponseData }>(`/admin-api/groups/${groupId}`, {\n method: 'DELETE',\n body: '{}',\n headers: { 'Content-Type': 'application/json' },\n }),\n );\n }\n\n async listGroupMembers(groupId: string): Promise<ListGroupMembersResponseData> {\n const response = await this.httpClient.get<ListGroupMembersResponseData>(\n `/admin-api/groups/${groupId}/members`,\n );\n // Validate the field we declare as non-optional in the type so a\n // contract-violating response (proxy error body, future API drift,\n // etc.) surfaces as a clear error rather than silently producing an\n // empty list. Empty groups still satisfy this \u2014 merod returns\n // `members: []`, not an omitted field.\n if (!Array.isArray(response?.members)) {\n // Sanitize before interpolation: groupId reaches us from caller code,\n // not parsed input, but defending the message keeps untrusted bytes\n // out of error logs and downstream UIs.\n const safeId = String(groupId).replace(/[\\r\\n\\t\\s]/g, '').slice(0, 64);\n throw new Error(\n `Invalid listGroupMembers response for group ${safeId}: missing or non-array \\`members\\` field`,\n );\n }\n return response;\n }\n\n async listGroupContexts(groupId: string): Promise<ListGroupContextsResponseData> {\n return unwrap(await this.httpClient.get<{ data: ListGroupContextsResponseData }>(`/admin-api/groups/${groupId}/contexts`));\n }\n\n async addGroupMembers(groupId: string, request: AddGroupMembersRequest): Promise<void> {\n await this.httpClient.post(`/admin-api/groups/${groupId}/members`, request);\n }\n\n async removeGroupMembers(groupId: string, request: RemoveGroupMembersRequest): Promise<void> {\n await this.httpClient.post(`/admin-api/groups/${groupId}/members/remove`, request);\n }\n\n /**\n * `identity` is the member's ACCOUNT (64 hex), as returned by\n * {@link listGroupMembers} \u2014 not the signing key that added them. Both are\n * 64 hex, so nothing but the source tells them apart.\n */\n async updateMemberRole(\n groupId: string,\n identity: string,\n request: UpdateMemberRoleRequest,\n ): Promise<void> {\n await this.httpClient.put(`/admin-api/groups/${groupId}/members/${identity}/role`, request);\n }\n\n /**\n * `identity` is the member's ACCOUNT (64 hex), as returned by\n * {@link listGroupMembers} \u2014 not the signing key that added them. Both are\n * 64 hex, so nothing but the source tells them apart.\n */\n async getMemberCapabilities(groupId: string, identity: string): Promise<MemberCapabilities> {\n return unwrap(\n await this.httpClient.get<{ data: MemberCapabilities }>(\n `/admin-api/groups/${groupId}/members/${identity}/capabilities`,\n ),\n );\n }\n\n /**\n * `identity` is the member's ACCOUNT (64 hex), as returned by\n * {@link listGroupMembers} \u2014 not the signing key that added them. Both are\n * 64 hex, so nothing but the source tells them apart.\n */\n async setMemberCapabilities(\n groupId: string,\n identity: string,\n request: SetMemberCapabilitiesRequest,\n ): Promise<void> {\n await this.httpClient.put(`/admin-api/groups/${groupId}/members/${identity}/capabilities`, request);\n }\n\n async setDefaultCapabilities(\n groupId: string,\n request: SetDefaultCapabilitiesRequest,\n ): Promise<void> {\n await this.httpClient.put(`/admin-api/groups/${groupId}/settings/default-capabilities`, request);\n }\n\n async setSubgroupVisibility(\n groupId: string,\n request: SetSubgroupVisibilityRequest,\n ): Promise<void> {\n await this.httpClient.put(`/admin-api/groups/${groupId}/settings/subgroup-visibility`, request);\n }\n\n async setTeeAdmissionPolicy(\n groupId: string,\n request: SetTeeAdmissionPolicyRequest,\n ): Promise<void> {\n await this.httpClient.put(`/admin-api/groups/${groupId}/settings/tee-admission-policy`, request);\n }\n\n async getTeeAdmissionPolicy(groupId: string): Promise<GetTeeAdmissionPolicyResponseData> {\n // Intersection (not union) so the type is unambiguous: `data` is optional, so\n // `?? response` cleanly falls back to a flat (un-enveloped) response.\n const response = await this.httpClient.get<\n GetTeeAdmissionPolicyResponseData & { data?: GetTeeAdmissionPolicyResponseData }\n >(`/admin-api/groups/${groupId}/settings/tee-admission-policy`);\n return response.data ?? response;\n }\n\n // ---- Group / member / context metadata ----\n\n async setGroupMetadata(groupId: string, request: SetGroupMetadataRequest): Promise<void> {\n await this.httpClient.put(`/admin-api/groups/${groupId}/metadata`, request);\n }\n\n async getGroupMetadata(groupId: string): Promise<MetadataRecord | null> {\n // Core single-envelopes the record: `{ data: MetadataRecord | null }`.\n // \"No record yet\" is `{ data: null }` (or a bare null body on older nodes),\n // so optional-chain to a clean null. Returns the full record (name + data +\n // updatedAt/updatedBy), not just the data map.\n const response = await this.httpClient.get<GetMetadataResponseData | null>(\n `/admin-api/groups/${groupId}/metadata`,\n );\n return response?.data ?? null;\n }\n\n async setMemberMetadata(\n groupId: string,\n identity: string,\n request: SetMemberMetadataRequest,\n ): Promise<void> {\n await this.httpClient.put(`/admin-api/groups/${groupId}/members/${identity}/metadata`, request);\n }\n\n /**\n * `identity` is the member's ACCOUNT (64 hex), as returned by\n * {@link listGroupMembers} \u2014 not the signing key that added them. Both are\n * 64 hex, so nothing but the source tells them apart.\n */\n async getMemberMetadata(groupId: string, identity: string): Promise<MetadataRecord | null> {\n // Single-enveloped record; see getGroupMetadata.\n const response = await this.httpClient.get<GetMetadataResponseData | null>(\n `/admin-api/groups/${groupId}/members/${identity}/metadata`,\n );\n return response?.data ?? null;\n }\n\n async setContextMetadata(\n groupId: string,\n contextId: string,\n request: SetContextMetadataRequest,\n ): Promise<void> {\n await this.httpClient.put(`/admin-api/groups/${groupId}/contexts/${contextId}/metadata`, request);\n }\n\n async getContextMetadata(groupId: string, contextId: string): Promise<MetadataRecord | null> {\n // Single-enveloped record; see getGroupMetadata.\n const response = await this.httpClient.get<GetMetadataResponseData | null>(\n `/admin-api/groups/${groupId}/contexts/${contextId}/metadata`,\n );\n return response?.data ?? null;\n }\n\n async syncGroup(groupId: string): Promise<SyncGroupResponseData> {\n return unwrap(await this.httpClient.post<{ data: SyncGroupResponseData }>(`/admin-api/groups/${groupId}/sync`, {}));\n }\n\n async upgradeGroup(groupId: string, request: UpgradeGroupRequest): Promise<UpgradeGroupResponseData> {\n return unwrap(await this.httpClient.post<{ data: UpgradeGroupResponseData }>(`/admin-api/groups/${groupId}/upgrade`, request));\n }\n\n async getGroupUpgradeStatus(groupId: string): Promise<GroupUpgradeStatusResponseData> {\n return unwrap(\n await this.httpClient.get<{ data: GroupUpgradeStatusResponseData }>(`/admin-api/groups/${groupId}/upgrade/status`),\n );\n }\n\n /**\n * The operator-facing \"have all peers migrated?\" rollup for a namespace.\n * The handler serializes the payload directly, so there is no `{ data }`\n * envelope to unwrap here (unlike most admin reads).\n */\n async getMigrationStatus(namespaceId: string): Promise<MigrationStatus> {\n const id = encodeURIComponent(namespaceId);\n return this.httpClient.get<MigrationStatus>(`/admin-api/groups/${id}/migration-status`);\n }\n\n /** Per-group cascade-migration snapshots for a namespace. */\n async getCascadeStatus(namespaceId: string): Promise<CascadeStatusEntry[]> {\n const id = encodeURIComponent(namespaceId);\n return unwrap(\n await this.httpClient.get<{ data: CascadeStatusEntry[] }>(`/admin-api/groups/${id}/cascade-status`),\n );\n }\n\n async retryGroupUpgrade(groupId: string): Promise<RetryGroupUpgradeResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: RetryGroupUpgradeResponseData }>(\n `/admin-api/groups/${groupId}/upgrade/retry`,\n {},\n ),\n );\n }\n\n /** Move `childGroupId` under `request.newParentId`. */\n async reparentGroup(\n childGroupId: string,\n request: ReparentGroupRequest,\n ): Promise<ReparentGroupResponseData> {\n // Core returns this flat ({ reparented }); tolerate the { data } envelope too.\n const r = await this.httpClient.post<\n ReparentGroupResponseData & { data?: ReparentGroupResponseData }\n >(`/admin-api/groups/${childGroupId}/reparent`, request);\n return (r?.data ?? r) as ReparentGroupResponseData;\n }\n\n async listSubgroups(groupId: string): Promise<SubgroupEntry[]> {\n const response = await this.httpClient.get<{ subgroups?: SubgroupEntry[]; data?: SubgroupEntry[] }>(\n `/admin-api/groups/${groupId}/subgroups`,\n );\n return response.subgroups ?? response.data ?? [];\n }\n\n async detachContextFromGroup(groupId: string, contextId: string): Promise<void> {\n await this.httpClient.post(`/admin-api/groups/${groupId}/contexts/${contextId}/remove`, {});\n }\n\n // ---- Group Invitation & Join ----\n\n async createGroupInvitation(\n groupId: string,\n request?: CreateGroupInvitationRequest,\n ): Promise<CreateGroupInvitationResponseData | CreateRecursiveGroupInvitationResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: CreateGroupInvitationResponseData | CreateRecursiveGroupInvitationResponseData }>(\n `/admin-api/groups/${groupId}/invite`,\n request ?? {},\n ),\n );\n }\n\n async joinGroup(request: JoinGroupRequest): Promise<JoinGroupResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: JoinGroupResponseData }>('/admin-api/groups/join', request),\n );\n }\n\n async joinSubgroupInheritance(groupId: string): Promise<JoinSubgroupInheritanceResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: JoinSubgroupInheritanceResponseData }>(\n `/admin-api/groups/${groupId}/join-via-inheritance`,\n {},\n ),\n );\n }\n\n // ---- TEE ----\n\n async getTeeInfo(): Promise<TeeInfoResponseData> {\n return unwrap(await this.httpClient.get<{ data: TeeInfoResponseData }>('/admin-api/tee/info'));\n }\n\n async teeAttest(request: TeeAttestRequest): Promise<TeeAttestResponseData> {\n return unwrap(await this.httpClient.post<{ data: TeeAttestResponseData }>('/admin-api/tee/attest', request));\n }\n\n async teeVerifyQuote(request: TeeVerifyQuoteRequest): Promise<TeeVerifyQuoteResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: TeeVerifyQuoteResponseData }>('/admin-api/tee/verify-quote', request),\n );\n }\n\n // ---- Network ----\n\n async getPeersCount(): Promise<{ count: number }> {\n return this.httpClient.get<{ count: number }>('/admin-api/peers');\n }\n\n /** Node network status (GET /admin-api/network/status). */\n async getNetworkStatus(): Promise<unknown> {\n return this.httpClient.get<unknown>('/admin-api/network/status');\n }\n\n /** Node storage/usage stats (GET /admin-api/usage). */\n async getUsage(): Promise<unknown> {\n return this.httpClient.get<unknown>('/admin-api/usage');\n }\n\n /** Node TLS certificate, PEM text (GET /admin-api/certificate). */\n async getCertificate(): Promise<string> {\n return this.httpClient.get<string>('/admin-api/certificate', { parse: 'text' });\n }\n\n // ---- Group / context / namespace membership ----\n\n /** Create a standalone group (POST /admin-api/groups). */\n async createGroup(request: CreateGroupRequest): Promise<CreateGroupResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: CreateGroupResponseData }>('/admin-api/groups', request),\n );\n }\n\n /** Leave a group (POST /admin-api/groups/:group_id/leave). */\n async leaveGroup(groupId: string): Promise<void> {\n await this.httpClient.post(`/admin-api/groups/${groupId}/leave`, {});\n }\n\n /** Leave a context (POST /admin-api/contexts/:context_id/leave). */\n async leaveContext(contextId: string): Promise<void> {\n await this.httpClient.post(`/admin-api/contexts/${contextId}/leave`, {});\n }\n\n /** Leave a namespace (POST /admin-api/namespaces/:namespace_id/leave). */\n async leaveNamespace(namespaceId: string): Promise<void> {\n await this.httpClient.post(`/admin-api/namespaces/${namespaceId}/leave`, {});\n }\n\n /** Issue a group ownership proof (POST /admin-api/groups/:group_id/issue-ownership-proof). */\n async issueOwnershipProof(\n groupId: string,\n request: IssueOwnershipProofRequest,\n ): Promise<IssueOwnershipProofResponseData> {\n return this.httpClient.post<IssueOwnershipProofResponseData>(\n `/admin-api/groups/${groupId}/issue-ownership-proof`,\n request,\n );\n }\n\n /** Issue a namespace ownership proof (POST /admin-api/groups/:group_id/issue-namespace-ownership-proof). */\n async issueNamespaceOwnershipProof(\n groupId: string,\n request: IssueNamespaceOwnershipProofRequest,\n ): Promise<IssueOwnershipProofResponseData> {\n return this.httpClient.post<IssueOwnershipProofResponseData>(\n `/admin-api/groups/${groupId}/issue-namespace-ownership-proof`,\n request,\n );\n }\n\n /**\n * Set a member's auto-follow flag (PUT\n * /admin-api/groups/:group_id/members/:identity/auto-follow).\n *\n * `identity` is the member's ACCOUNT (64 hex), as returned by\n * {@link listGroupMembers} \u2014 not the signing key that added them. Both are\n * 64 hex, so nothing but the source tells them apart.\n */\n async setMemberAutoFollow(\n groupId: string,\n identity: string,\n request: SetMemberAutoFollowRequest,\n ): Promise<void> {\n await this.httpClient.put(`/admin-api/groups/${groupId}/members/${identity}/auto-follow`, request);\n }\n\n /** Abort a namespace migration (POST /admin-api/groups/:namespace_id/migration/abort). */\n async abortMigration(namespaceId: string): Promise<unknown> {\n return this.httpClient.post<unknown>(`/admin-api/groups/${namespaceId}/migration/abort`, {});\n }\n}\n", "import { AdminApiClient } from './admin-client.js';\nimport { AdminApiClientConfig } from './admin-types.js';\nimport {\n HttpClient,\n createBrowserHttpClient,\n createNodeHttpClient,\n createUniversalHttpClient,\n} from '../http-client/index.js';\n\n// Factory functions for creating Admin API clients\n\n/** Admin client over a browser HTTP transport (global `fetch`). */\nexport function createBrowserAdminApiClient(\n config: AdminApiClientConfig,\n): AdminApiClient {\n return new AdminApiClient(createBrowserHttpClient(config));\n}\n\n/** Admin client over a Node HTTP transport (Node 18+ `fetch`). */\nexport function createNodeAdminApiClient(\n config: AdminApiClientConfig,\n): AdminApiClient {\n return new AdminApiClient(createNodeHttpClient(config));\n}\n\n/** Admin client over whichever transport suits the current runtime. */\nexport function createAdminApiClient(\n config: AdminApiClientConfig,\n): AdminApiClient {\n return new AdminApiClient(createUniversalHttpClient(config));\n}\n\n/**\n * Admin client over a caller-supplied HTTP client \u2014 use this to share one\n * transport (and its token handling) with the other API clients.\n */\nexport function createAdminApiClientFromHttpClient(\n httpClient: HttpClient,\n _config: AdminApiClientConfig,\n): AdminApiClient {\n return new AdminApiClient(httpClient);\n}\n", "export interface AuthCallbackResult {\n accessToken: string;\n refreshToken: string;\n applicationId: string;\n contextId: string;\n contextIdentity: string;\n nodeUrl: string;\n}\n\nexport interface AuthLoginOptions {\n callbackUrl: string;\n packageName?: string;\n mode: string;\n permissions?: string[];\n registryUrl?: string;\n packageVersion?: string;\n}\n\n/**\n * Parse an auth callback URL hash fragment.\n * Returns null if access_token is missing.\n */\nexport function parseAuthCallback(url: string): AuthCallbackResult | null {\n try {\n const hashIndex = url.indexOf('#');\n if (hashIndex === -1) return null;\n\n const hash = url.substring(hashIndex + 1);\n const params = new URLSearchParams(hash);\n\n const accessToken = params.get('access_token');\n if (!accessToken) return null;\n\n return {\n accessToken,\n refreshToken: params.get('refresh_token') ?? '',\n applicationId: params.get('application_id') ?? '',\n contextId: params.get('context_id') ?? '',\n contextIdentity: params.get('context_identity') ?? '',\n nodeUrl: params.get('node_url') ?? '',\n };\n } catch {\n return null;\n }\n}\n\n/**\n * Build the auth login URL for redirecting users to the node's auth page.\n */\nexport function buildAuthLoginUrl(nodeUrl: string, opts: AuthLoginOptions): string {\n const params = new URLSearchParams();\n params.set('callback-url', opts.callbackUrl);\n\n if (opts.permissions && opts.permissions.length > 0) {\n params.set('permissions', opts.permissions.join(','));\n }\n\n params.set('mode', opts.mode);\n\n if (opts.packageName) {\n params.set('package-name', opts.packageName);\n if (opts.packageVersion) {\n params.set('package-version', opts.packageVersion);\n }\n if (opts.registryUrl) {\n params.set('registry-url', opts.registryUrl);\n }\n }\n\n // Trim trailing slash from nodeUrl\n const base = nodeUrl.replace(/\\/+$/, '');\n return `${base}/auth/login?${params.toString()}`;\n}\n", "import type { HttpClient } from '../http-client/index.js';\n\n/** Result of the owner-driven `migrate_my_entries` convert (counts are u32). */\nexport interface MigrateMyEntriesSummary {\n converted: number;\n remaining: number;\n}\n\nexport interface ExecuteParams {\n contextId: string;\n method: string;\n argsJson?: Record<string, unknown>;\n /** @deprecated No longer used by the server. Ignored if provided. */\n executorPublicKey?: string;\n}\n\nexport class RpcError extends Error {\n code: number;\n type?: string;\n data?: unknown;\n\n constructor(code: number, message: string, data?: unknown, type?: string) {\n super(message);\n this.name = 'RpcError';\n this.code = code;\n this.data = data;\n this.type = type;\n }\n}\n\ninterface JsonRpcResponse {\n jsonrpc: string;\n id: number;\n result?: {\n output?: unknown;\n [key: string]: unknown;\n };\n error?: {\n // Standard JSON-RPC fields\n code?: number;\n message?: string;\n // Server-specific fields\n type?: string;\n data?: unknown;\n };\n}\n\n/**\n * POST a JSON-RPC call and unwrap `result`, converting an `error` payload into\n * an `RpcError`. The node returns `{ type, data }` (not always `{ code,\n * message }`), so this is the one place that normalization lives \u2014 every\n * JSON-RPC caller in this SDK shares it rather than re-deriving a bare\n * `Error(message)` and dropping the typed detail.\n */\nexport async function jsonRpcCall<T>(\n httpClient: HttpClient,\n method: string,\n params: unknown,\n): Promise<T> {\n const response = await httpClient.post<JsonRpcResponse>('/jsonrpc', {\n jsonrpc: '2.0',\n id: 1,\n method,\n params,\n });\n\n if (response.error) {\n const err = response.error;\n throw new RpcError(err.code ?? -1, err.message ?? err.type ?? 'RPC error', err.data, err.type);\n }\n\n return response.result as T;\n}\n\nexport class RpcClient {\n private httpClient: HttpClient;\n\n constructor(opts: { httpClient: HttpClient }) {\n this.httpClient = opts.httpClient;\n }\n\n async execute<T = unknown>(params: ExecuteParams): Promise<T> {\n const result = await jsonRpcCall<JsonRpcResponse['result']>(this.httpClient, 'execute', {\n contextId: params.contextId,\n method: params.method,\n argsJson: params.argsJson ?? {},\n });\n\n if (result && 'output' in result) {\n return result.output as T;\n }\n\n return result as T;\n }\n\n /**\n * One-tap owner-driven convert: re-signs the caller's identity-gated entries\n * to the current schema. The export converts all of the caller's\n * below-target entries in a single sweep, so this issues one call and returns\n * the resulting summary \u2014 it does not loop.\n */\n async migrateMyEntries(contextId: string): Promise<MigrateMyEntriesSummary> {\n return this.execute<MigrateMyEntriesSummary>({ contextId, method: 'migrate_my_entries' });\n }\n\n /** Read-only count of the caller's entries still below the target schema. */\n async countMyPending(contextId: string): Promise<number> {\n return this.execute<number>({ contextId, method: 'count_my_pending' });\n }\n}\n", "/** Parsed group-membership event (core's untagged `NodeEvent` group variant). */\nexport interface GroupMembershipEventData {\n groupId: string;\n type: 'MemberJoined' | 'MemberAdded' | 'MemberRemoved';\n data: {\n /** The member's ACCOUNT, hex-encoded 32 bytes (64 chars) - the principal the\n * governance rows name. Not a signing key: the field this replaced\n * carried one, and both are strings, so the rename is what makes a stale\n * consumer fail loudly instead of comparing accounts against keys forever. */\n memberAccount: string;\n /** Absent on `MemberRemoved`, and on a `MemberJoined` inherited from an Open\n * subgroup. Core's set is closed. */\n role?: 'Admin' | 'Member' | 'ReadOnly' | 'ReadOnlyTee';\n };\n}\n\n/**\n * A migration was accepted and its target ABI state version resolved.\n * `toStateVersion` is the `#[app::state(version = N)]` number, not the bundle\n * semver (`toVersion`).\n */\nexport interface MigrationStartedData {\n fromVersion: string;\n toVersion: string;\n toStateVersion: number;\n /** Contexts the EMITTING NODE enumerated for the migration. Node-local, never\n * the fleet cohort size that `MigrationProgressData.total` carries. */\n localContextsTotal: number;\n}\n\n/**\n * Fleet rollup counters, recomputed as peers' heartbeat facts change. Counters\n * only: the per-member detail behind them stays in the admin-gated\n * `getMigrationStatus` read.\n */\nexport interface MigrationProgressData {\n migrated: number;\n inProgress: number;\n unknown: number;\n failed: number;\n /** The pinned FLEET COHORT size, never a node-local context count like\n * `MigrationStartedData.localContextsTotal`. */\n total: number;\n}\n\n/**\n * One subgroup's local context swaps advanced on the emitting node.\n *\n * Admin-only: it names a descendant subgroup, which a plain namespace member\n * may not enumerate, so core withholds it from non-admin subscribers. A\n * non-admin never receiving this variant is correct behaviour, not a gap.\n */\nexport interface CascadeProgressData {\n /** Hex-encoded descendant subgroup id, never the namespace root the event is\n * keyed on. */\n subgroupId: string;\n localContextsSwapped: number;\n /** Contexts the emitting node holds for THIS SUBGROUP. Node-local and\n * per-subgroup; unrelated to both sibling totals. */\n localContextsTotal: number;\n}\n\n/** Every pinned-cohort member reported the target version. */\nexport interface MigrationCompletedData {\n toVersion: string;\n /** FLEET convergence, in seconds since the epoch: the same stamp\n * `MigrationStatus.fleetCompletedAt` returns. Not `GroupUpgradeStatus.completedAt`,\n * which is this node's own local swap completion. */\n completedAt: number;\n}\n\n/**\n * Parsed group-migration event (core's `GroupMigration` `NodeEvent` variant),\n * keyed on the namespace root a client subscribes with.\n *\n * `MigrationStarted`, `MigrationProgress` and `MigrationCompleted` reach every\n * subscribed member; `CascadeProgress` reaches namespace admins only.\n */\nexport type GroupMigrationEventData =\n | { groupId: string; type: 'MigrationStarted'; data: MigrationStartedData }\n | { groupId: string; type: 'MigrationProgress'; data: MigrationProgressData }\n | { groupId: string; type: 'CascadeProgress'; data: CascadeProgressData }\n | { groupId: string; type: 'MigrationCompleted'; data: MigrationCompletedData };\n\nconst MIGRATION_EVENT_TYPES: ReadonlySet<string> = new Set([\n 'MigrationStarted',\n 'MigrationProgress',\n 'CascadeProgress',\n 'MigrationCompleted',\n]);\n\n/** Narrows a raw `'event'` payload to the group-migration family by its tag. */\nexport function isGroupMigrationEvent(\n event: { type?: string },\n): event is GroupMigrationEventData {\n return event.type !== undefined && MIGRATION_EVENT_TYPES.has(event.type);\n}\n", "import type { GroupMembershipEventData, GroupMigrationEventData } from './group.js';\nimport { isGroupMigrationEvent } from './group.js';\nimport { AuthRevokedError, HTTPError } from '../http-client/index.js';\n\n/**\n * `x-auth-error` reasons that mean the whole token family is gone, mirroring\n * the request path in `web-client.ts`. Anything else \u2014 `token_expired` above\n * all \u2014 is recoverable by refreshing and reconnecting.\n */\nconst TERMINAL_AUTH_ERRORS = new Set(['token_reuse', 'token_revoked']);\n\nexport type { GroupMembershipEventData, GroupMigrationEventData };\n\nexport interface SseEventData {\n contextId: string;\n /** The context-event discriminator (core serializes it as a sibling of\n * `data`, e.g. `\"AppVersionChanged\"`). Undefined for events without a tag. */\n type?: string;\n data: unknown;\n}\n\n/** Parsed `AppVersionChanged` context event (bundle-version flip; skew #2). */\nexport interface AppVersionChangedEvent {\n contextId: string;\n fromVersion?: string;\n toVersion?: string;\n}\n\n/** Anything the `'event'` stream can deliver: context events plus the\n * group-keyed membership and migration families. */\ntype SseEvent = SseEventData | GroupMembershipEventData | GroupMigrationEventData;\ntype SseEventHandler = (event: SseEvent) => void;\ntype SseConnectHandler = (sessionId: string) => void;\ntype SseErrorHandler = (error: Error) => void;\n\ninterface SseListeners {\n connect: SseConnectHandler[];\n event: SseEventHandler[];\n error: SseErrorHandler[];\n}\n\nexport class SseClient {\n private baseUrl: string;\n private getAuthToken: () => Promise<string>;\n private reconnectDelayMs: number;\n private sessionId: string | null = null;\n private abortController: AbortController | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private subscribedContextIds: Set<string> = new Set();\n private subscribedGroupIds: Set<string> = new Set();\n private closed = false;\n private listeners: SseListeners = { connect: [], event: [], error: [] };\n\n constructor(opts: {\n baseUrl: string;\n getAuthToken: () => Promise<string>;\n reconnectDelayMs?: number;\n }) {\n this.baseUrl = opts.baseUrl.replace(/\\/+$/, '');\n this.getAuthToken = opts.getAuthToken;\n this.reconnectDelayMs = opts.reconnectDelayMs ?? 3000;\n }\n\n on(event: 'connect', handler: SseConnectHandler): void;\n on(event: 'event', handler: SseEventHandler): void;\n on(event: 'error', handler: SseErrorHandler): void;\n on(event: string, handler: SseConnectHandler | SseEventHandler | SseErrorHandler): void {\n const key = event as keyof SseListeners;\n if (key in this.listeners) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const arr = this.listeners[key] as any[];\n if (!arr.includes(handler)) arr.push(handler);\n }\n }\n\n off(event: 'connect', handler: SseConnectHandler): void;\n off(event: 'event', handler: SseEventHandler): void;\n off(event: 'error', handler: SseErrorHandler): void;\n off(event: string, handler: SseConnectHandler | SseEventHandler | SseErrorHandler): void {\n const key = event as keyof SseListeners;\n if (key in this.listeners) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const arr = this.listeners[key] as any[];\n const idx = arr.indexOf(handler);\n if (idx !== -1) arr.splice(idx, 1);\n }\n }\n\n /**\n * Typed convenience over the generic `'event'` stream: invokes `handler` only\n * for `AppVersionChanged` context events, with the payload already parsed.\n * Returns an unsubscribe closure (so callers need not retain the listener).\n */\n onAppVersionChanged(handler: (e: AppVersionChangedEvent) => void): () => void {\n const listener: SseEventHandler = (ev) => {\n // Core flattens the tagged payload: the event carries `type` as a sibling\n // of `data`, and `data` is the `{ fromVersion?, toVersion? }` payload.\n if (ev.type !== 'AppVersionChanged') return;\n const d = ev.data as { fromVersion?: string; toVersion?: string } | undefined;\n handler({ contextId: ev.contextId, fromVersion: d?.fromVersion, toVersion: d?.toVersion });\n };\n this.on('event', listener);\n return () => this.off('event', listener);\n }\n\n /**\n * Typed convenience over the generic `'event'` stream: invokes `handler` only\n * for group-migration events, narrowed on `type` so `data` is the matching\n * payload. Returns an unsubscribe closure.\n *\n * A non-admin subscriber sees `MigrationStarted`, `MigrationProgress` and\n * `MigrationCompleted` but never `CascadeProgress`, which core delivers to\n * namespace admins only.\n */\n onMigrationEvent(handler: (e: GroupMigrationEventData) => void): () => void {\n const listener: SseEventHandler = (ev) => {\n if (isGroupMigrationEvent(ev)) handler(ev);\n };\n this.on('event', listener);\n return () => this.off('event', listener);\n }\n\n private emit(event: 'connect', sessionId: string): void;\n private emit(event: 'event', data: SseEvent): void;\n private emit(event: 'error', error: Error): void;\n private emit(event: string, arg?: string | SseEvent | Error): void {\n const key = event as keyof SseListeners;\n if (key in this.listeners) {\n for (const handler of this.listeners[key]) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (handler as any)(arg);\n } catch {\n // Swallow handler errors\n }\n }\n }\n }\n\n async connect(): Promise<void> {\n // Already connected \u2014 don't reconnect\n if (this.abortController && !this.closed) {\n return;\n }\n this.closed = false;\n this.abortController = new AbortController();\n\n try {\n const token = await this.getAuthToken();\n const url = `${this.baseUrl}/sse`;\n const response = await fetch(url, {\n headers: {\n 'Authorization': `Bearer ${token}`,\n 'Accept': 'text/event-stream',\n },\n signal: this.abortController.signal,\n });\n\n if (!response.ok) {\n // Throw the same typed errors the request path throws. A bare\n // `Error(\"SSE connection failed: 401\")` forced callers to string-match\n // the status and guess what it meant, and the honest guess \u2014 treat any\n // 401 as fatal \u2014 logs the user out on a routine reconnect after the\n // access token ages out, discarding a refresh token that was still\n // good. The distinction is in the header; surface it.\n const authError = response.headers.get('x-auth-error');\n const bodyText = await response.text().catch(() => undefined);\n\n if (\n response.status === 401 &&\n authError &&\n TERMINAL_AUTH_ERRORS.has(authError)\n ) {\n throw new AuthRevokedError(\n authError,\n response.status,\n response.statusText,\n url,\n response.headers,\n bodyText,\n );\n }\n\n throw new HTTPError(\n response.status,\n response.statusText,\n url,\n response.headers,\n bodyText,\n );\n }\n\n if (!response.body) {\n throw new Error('SSE response has no body');\n }\n\n this.readStream(response.body).catch((err) => {\n if (this.closed) return;\n const error = err instanceof Error ? err : new Error(String(err));\n this.emit('error', error);\n this.scheduleReconnect();\n });\n } catch (err) {\n if (this.closed) return;\n const error = err instanceof Error ? err : new Error(String(err));\n this.emit('error', error);\n this.scheduleReconnect();\n }\n }\n\n private async readStream(body: ReadableStream<Uint8Array>): Promise<void> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n const lines = buffer.split('\\n');\n // Keep the last partial line in the buffer\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n if (line.startsWith('data:')) {\n const jsonStr = line.slice(5).trim();\n if (jsonStr) {\n this.handleMessage(jsonStr);\n }\n }\n }\n }\n // Flush remaining bytes from the decoder\n buffer += decoder.decode();\n if (buffer.startsWith('data:')) {\n const jsonStr = buffer.slice(5).trim();\n if (jsonStr) {\n this.handleMessage(jsonStr);\n }\n }\n } catch (err) {\n if (this.closed) return;\n const error = err instanceof Error ? err : new Error(String(err));\n this.emit('error', error);\n }\n\n // Stream ended, reconnect\n if (!this.closed) {\n this.scheduleReconnect();\n }\n }\n\n private handleMessage(jsonStr: string): void {\n try {\n const msg = JSON.parse(jsonStr);\n\n // Connection message\n if (msg.type === 'connect' && msg.session_id) {\n this.sessionId = msg.session_id;\n this.emit('connect', msg.session_id);\n // Re-subscribe after reconnect\n if (this.subscribedContextIds.size > 0 || this.subscribedGroupIds.size > 0) {\n this.sendSubscription('subscribe', {\n contextIds: [...this.subscribedContextIds],\n groupIds: [...this.subscribedGroupIds],\n });\n }\n return;\n }\n\n if (!msg.result) return;\n\n let eventData = msg.result.data;\n // Decode byte-array data if needed\n if (Array.isArray(eventData)) {\n try {\n const bytes = new Uint8Array(eventData);\n const text = new TextDecoder().decode(bytes);\n eventData = JSON.parse(text);\n } catch {\n // Keep raw data\n }\n }\n\n // Context event message\n if (msg.result.contextId) {\n this.emit('event', {\n contextId: msg.result.contextId,\n // Forward the event tag (sibling of `data` in core's flattened\n // payload) so typed helpers like `onAppVersionChanged` can discriminate.\n type: msg.result.type,\n data: eventData,\n });\n return;\n }\n\n // Group-keyed event message (untagged NodeEvent's membership and\n // migration variants; the `type` tag tells them apart).\n if (msg.result.groupId) {\n this.emit('event', {\n groupId: msg.result.groupId,\n type: msg.result.type,\n data: eventData,\n });\n }\n } catch {\n // Invalid JSON, ignore\n }\n }\n\n async subscribe(idsOrOpts: string[] | { contextIds?: string[]; groupIds?: string[] }): Promise<void> {\n const opts = Array.isArray(idsOrOpts) ? { contextIds: idsOrOpts } : idsOrOpts;\n const newContextIds = (opts.contextIds ?? []).filter(id => !this.subscribedContextIds.has(id));\n const newGroupIds = (opts.groupIds ?? []).filter(id => !this.subscribedGroupIds.has(id));\n for (const id of opts.contextIds ?? []) {\n this.subscribedContextIds.add(id);\n }\n for (const id of opts.groupIds ?? []) {\n this.subscribedGroupIds.add(id);\n }\n if ((newContextIds.length > 0 || newGroupIds.length > 0) && this.sessionId) {\n await this.sendSubscription('subscribe', { contextIds: newContextIds, groupIds: newGroupIds });\n }\n }\n\n async unsubscribe(idsOrOpts: string[] | { contextIds?: string[]; groupIds?: string[] }): Promise<void> {\n const opts = Array.isArray(idsOrOpts) ? { contextIds: idsOrOpts } : idsOrOpts;\n const hadContextIds = (opts.contextIds ?? []).filter(id => this.subscribedContextIds.has(id));\n const hadGroupIds = (opts.groupIds ?? []).filter(id => this.subscribedGroupIds.has(id));\n for (const id of opts.contextIds ?? []) {\n this.subscribedContextIds.delete(id);\n }\n for (const id of opts.groupIds ?? []) {\n this.subscribedGroupIds.delete(id);\n }\n if ((hadContextIds.length > 0 || hadGroupIds.length > 0) && this.sessionId) {\n await this.sendSubscription('unsubscribe', { contextIds: hadContextIds, groupIds: hadGroupIds });\n }\n }\n\n private async sendSubscription(\n method: 'subscribe' | 'unsubscribe',\n ids: { contextIds?: string[]; groupIds?: string[] },\n ): Promise<void> {\n try {\n const token = await this.getAuthToken();\n const params: { contextIds?: string[]; groupIds?: string[] } = {};\n if (ids.contextIds && ids.contextIds.length > 0) params.contextIds = ids.contextIds;\n if (ids.groupIds && ids.groupIds.length > 0) params.groupIds = ids.groupIds;\n const response = await fetch(`${this.baseUrl}/sse/subscription`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n id: this.sessionId,\n method,\n params,\n }),\n });\n if (!response.ok) {\n this.emit('error', new Error(`SSE ${method} failed: ${response.status}`));\n }\n } catch (err) {\n this.emit('error', err instanceof Error ? err : new Error(`SSE ${method} failed`));\n }\n }\n\n private forceReconnect(): void {\n if (this.abortController) {\n this.abortController.abort();\n this.abortController = null;\n }\n this.sessionId = null;\n this.connect();\n }\n\n private scheduleReconnect(): void {\n if (this.closed) return;\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n }\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.forceReconnect();\n }, this.reconnectDelayMs);\n }\n\n close(): void {\n this.closed = true;\n if (this.abortController) {\n this.abortController.abort();\n this.abortController = null;\n }\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n this.sessionId = null;\n this.subscribedContextIds.clear();\n this.subscribedGroupIds.clear();\n }\n}\n", "import type { GroupMembershipEventData, GroupMigrationEventData } from './group.js';\n\nexport type { GroupMembershipEventData, GroupMigrationEventData };\n\nexport interface WsEventData {\n contextId: string;\n /** The context-event discriminator (core serializes it as a sibling of\n * `data`, e.g. `\"AppVersionChanged\"`). Undefined for events without a tag. */\n type?: string;\n data: unknown;\n}\n\n/** Anything the `'event'` stream can deliver: context events plus the\n * group-keyed membership and migration families. */\ntype WsEvent = WsEventData | GroupMembershipEventData | GroupMigrationEventData;\ntype WsEventHandler = (event: WsEvent) => void;\ntype WsConnectHandler = () => void;\ntype WsErrorHandler = (error: Error) => void;\n\ninterface WsListeners {\n connect: WsConnectHandler[];\n event: WsEventHandler[];\n error: WsErrorHandler[];\n}\n\n/**\n * @experimental WebSocket event client. The SSE client (`SseClient`) is the\n * recommended transport for production \u2014 use `MeroJs.events` instead of `MeroJs.ws`.\n */\nexport class WsClient {\n private baseUrl: string;\n private getAuthToken: () => Promise<string>;\n private ws: WebSocket | null = null;\n private closed = false;\n private reconnectAttempt = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private subscribedContextIds: Set<string> = new Set();\n private subscribedGroupIds: Set<string> = new Set();\n private listeners: WsListeners = { connect: [], event: [], error: [] };\n\n private static readonly MAX_BACKOFF_MS = 30000;\n\n constructor(opts: {\n baseUrl: string;\n getAuthToken: () => Promise<string>;\n }) {\n this.baseUrl = opts.baseUrl.replace(/\\/+$/, '');\n this.getAuthToken = opts.getAuthToken;\n }\n\n on(event: 'connect', handler: WsConnectHandler): void;\n on(event: 'event', handler: WsEventHandler): void;\n on(event: 'error', handler: WsErrorHandler): void;\n on(event: string, handler: WsConnectHandler | WsEventHandler | WsErrorHandler): void {\n const key = event as keyof WsListeners;\n if (key in this.listeners) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const arr = this.listeners[key] as any[];\n if (!arr.includes(handler)) arr.push(handler);\n }\n }\n\n off(event: 'connect', handler: WsConnectHandler): void;\n off(event: 'event', handler: WsEventHandler): void;\n off(event: 'error', handler: WsErrorHandler): void;\n off(event: string, handler: WsConnectHandler | WsEventHandler | WsErrorHandler): void {\n const key = event as keyof WsListeners;\n if (key in this.listeners) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const arr = this.listeners[key] as any[];\n const idx = arr.indexOf(handler);\n if (idx !== -1) arr.splice(idx, 1);\n }\n }\n\n private emit(event: 'connect'): void;\n private emit(event: 'event', data: WsEvent): void;\n private emit(event: 'error', error: Error): void;\n private emit(event: string, arg?: WsEvent | Error): void {\n const key = event as keyof WsListeners;\n if (key in this.listeners) {\n for (const handler of this.listeners[key]) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (handler as any)(arg);\n } catch {\n // Swallow handler errors\n }\n }\n }\n }\n\n async connect(): Promise<void> {\n if (this.ws && (this.ws.readyState === 0 /* CONNECTING */ || this.ws.readyState === 1 /* OPEN */)) {\n return;\n }\n this.closed = false;\n\n try {\n const token = await this.getAuthToken();\n if (!token) {\n throw new Error('No authentication token available for WebSocket connection');\n }\n // Browser WebSocket API can't set headers, use query param\n const wsUrl = this.baseUrl.replace(/^http/, 'ws');\n this.ws = new WebSocket(`${wsUrl}/ws?token=${encodeURIComponent(token)}`);\n\n this.ws.onopen = () => {\n this.reconnectAttempt = 0;\n this.emit('connect');\n this.resubscribeAfterReconnect();\n };\n\n this.ws.onmessage = (event) => {\n this.handleMessage(event.data);\n };\n\n this.ws.onerror = () => {\n this.emit('error', new Error('WebSocket error'));\n };\n\n this.ws.onclose = () => {\n if (!this.closed) {\n this.scheduleReconnect();\n }\n };\n } catch (err) {\n if (this.closed) return;\n const error = err instanceof Error ? err : new Error(String(err));\n this.emit('error', error);\n this.scheduleReconnect();\n }\n }\n\n private handleMessage(raw: string | ArrayBuffer | Blob): void {\n if (typeof raw !== 'string') return;\n\n try {\n const msg = JSON.parse(raw);\n\n if (!msg.result) return;\n\n let eventData = msg.result.data;\n if (Array.isArray(eventData)) {\n try {\n const bytes = new Uint8Array(eventData);\n const text = new TextDecoder().decode(bytes);\n eventData = JSON.parse(text);\n } catch {\n // Keep raw data\n }\n }\n\n if (msg.result.contextId) {\n this.emit('event', {\n contextId: msg.result.contextId,\n // Forward the event tag (sibling of `data` in core's flattened\n // payload) so consumers can discriminate, matching `SseClient`.\n type: msg.result.type,\n data: eventData,\n });\n return;\n }\n\n // Group-keyed event message (untagged NodeEvent's membership and\n // migration variants; the `type` tag tells them apart).\n if (msg.result.groupId) {\n this.emit('event', {\n groupId: msg.result.groupId,\n type: msg.result.type,\n data: eventData,\n });\n }\n } catch {\n // Invalid JSON, ignore\n }\n }\n\n subscribe(idsOrOpts: string[] | { contextIds?: string[]; groupIds?: string[] }): void {\n const opts = Array.isArray(idsOrOpts) ? { contextIds: idsOrOpts } : idsOrOpts;\n for (const id of opts.contextIds ?? []) {\n this.subscribedContextIds.add(id);\n }\n for (const id of opts.groupIds ?? []) {\n this.subscribedGroupIds.add(id);\n }\n\n if (this.ws && this.ws.readyState === 1 /* OPEN */) {\n this.sendMessage({\n id: null,\n method: 'subscribe',\n params: this.buildSubscriptionParams(opts.contextIds ?? [], opts.groupIds ?? []),\n });\n }\n }\n\n unsubscribe(idsOrOpts: string[] | { contextIds?: string[]; groupIds?: string[] }): void {\n const opts = Array.isArray(idsOrOpts) ? { contextIds: idsOrOpts } : idsOrOpts;\n for (const id of opts.contextIds ?? []) {\n this.subscribedContextIds.delete(id);\n }\n for (const id of opts.groupIds ?? []) {\n this.subscribedGroupIds.delete(id);\n }\n\n if (this.ws && this.ws.readyState === 1 /* OPEN */) {\n this.sendMessage({\n id: null,\n method: 'unsubscribe',\n params: this.buildSubscriptionParams(opts.contextIds ?? [], opts.groupIds ?? []),\n });\n }\n }\n\n private resubscribeAfterReconnect(): void {\n if (this.subscribedContextIds.size === 0 && this.subscribedGroupIds.size === 0) return;\n this.sendMessage({\n id: null,\n method: 'subscribe',\n params: this.buildSubscriptionParams([...this.subscribedContextIds], [...this.subscribedGroupIds]),\n });\n }\n\n private buildSubscriptionParams(\n contextIds: string[],\n groupIds: string[],\n ): { contextIds?: string[]; groupIds?: string[] } {\n const params: { contextIds?: string[]; groupIds?: string[] } = {};\n if (contextIds.length > 0) params.contextIds = contextIds;\n if (groupIds.length > 0) params.groupIds = groupIds;\n return params;\n }\n\n private sendMessage(msg: unknown): void {\n if (this.ws && this.ws.readyState === 1 /* OPEN */) {\n this.ws.send(JSON.stringify(msg));\n }\n }\n\n private scheduleReconnect(): void {\n if (this.closed) return;\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n }\n const delay = Math.min(\n 1000 * Math.pow(2, this.reconnectAttempt),\n WsClient.MAX_BACKOFF_MS,\n );\n this.reconnectAttempt++;\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect();\n }, delay);\n }\n\n close(): void {\n this.closed = true;\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.ws) {\n this.ws.onclose = null;\n this.ws.close();\n this.ws = null;\n }\n this.subscribedContextIds.clear();\n this.subscribedGroupIds.clear();\n }\n}\n", "import type { Codec } from './types.js';\n\n/** Default codec: JSON text as a byte array. The wire carries `state` as\n * `number[]`, not a string, so this encodes to bytes rather than to text. */\nexport function jsonCodec<T>(): Codec<T> {\n return {\n encode(value: T): number[] {\n return Array.from(new TextEncoder().encode(JSON.stringify(value)));\n },\n decode(bytes: number[]): T {\n return JSON.parse(new TextDecoder().decode(new Uint8Array(bytes))) as T;\n },\n };\n}\n", "import type { HttpClient } from '../http-client/index.js';\nimport type { SseClient } from '../events/index.js';\nimport { jsonRpcCall } from '../rpc/index.js';\nimport { jsonCodec } from './codec.js';\nimport type { Codec, EphemeralEntry } from './types.js';\n\nexport { jsonCodec };\nexport type { Codec, EphemeralEntry };\n\n/**\n * Ephemeral presence: transient, encrypted, never-persisted state (cursors,\n * typing, presence) that gossips between nodes without a WASM run or DAG\n * growth.\n *\n * The write/read asymmetry is the model, not an oversight. `set` takes no\n * author: you can only ever write your OWN slot, and the node resolves the\n * author server-side from its owned context identity \u2014 which is also why a\n * client cannot publish as somebody else. `subscribe` returns everyone's\n * slots, so each carries its `author`. The store is N independent\n * single-writer registers keyed by author; there is no merge across authors.\n *\n * There is a single read path: `subscribe`. On subscribing to a context, the\n * node replays that context's current presence to this connection as\n * ordinary `Ephemeral` events (carrying `ageMs`), before any live deltas\n * (which carry no `ageMs`). There is no separate snapshot RPC.\n */\nexport class EphemeralClient {\n private httpClient: HttpClient;\n private sse: SseClient;\n\n constructor(opts: { httpClient: HttpClient; sse: SseClient }) {\n this.httpClient = opts.httpClient;\n this.sse = opts.sse;\n }\n\n /**\n * Publish your own presence slice, replacing it wholesale.\n *\n * Rejects with an `RpcError` (not a bare `Error`), so a typed failure such as\n * an oversized slice keeps its `type` and `data` \u2014 e.g. `SliceTooLarge` with\n * the offending size \u2014 and is `instanceof RpcError` like every other RPC in\n * this SDK.\n */\n async set<T>(contextId: string, state: T, codec: Codec<T> = jsonCodec<T>()): Promise<void> {\n await jsonRpcCall<Record<string, never>>(this.httpClient, 'set_ephemeral', {\n contextId,\n state: codec.encode(state),\n });\n }\n\n /**\n * Observe presence changes for a context.\n *\n * This adds NO transport \u2014 it is a typed filter over the existing SSE event\n * stream, which already carries `{ contextId, type, data }`. On subscribing,\n * the node replays that context's current presence to this connection as\n * ordinary `Ephemeral` events before any live deltas; a replayed entry\n * carries `ageMs`, a live delta does not (never synthesized as `0` \u2014 absent\n * and zero mean different things). Returns an unsubscribe function.\n */\n subscribe<T>(\n contextId: string,\n handler: (entry: EphemeralEntry<T>) => void,\n codec: Codec<T> = jsonCodec<T>(),\n ): () => void {\n const listener = (event: unknown): void => {\n const e = event as { contextId?: string; type?: string; data?: unknown };\n if (e.type !== 'Ephemeral' || e.contextId !== contextId) return;\n\n const data = e.data as\n | { author?: string; state?: number[]; removed?: boolean; ageMs?: number }\n | undefined;\n if (!data?.author) return;\n\n // `removed` is omitted on an upsert, so normalize to a boolean here and\n // spare every caller the truthiness rule.\n const removed = Boolean(data.removed);\n const entry: EphemeralEntry<T> = {\n author: data.author,\n state: removed || data.state === undefined ? undefined : codec.decode(data.state),\n removed,\n };\n // `ageMs` is present only on a replayed seed entry; pass it through as-is\n // rather than defaulting a live delta to 0.\n if (data.ageMs !== undefined) entry.ageMs = data.ageMs;\n handler(entry);\n };\n\n this.sse.on('event', listener);\n // Errors surface via the SSE client's own 'error' event; nothing more to\n // do with them here.\n void this.sse.connect().catch(() => undefined);\n void this.sse.subscribe([contextId]).catch(() => undefined);\n\n return () => {\n this.sse.off('event', listener);\n };\n }\n}\n", "/**\n * Calimero Cloud (MDMA) client.\n *\n * # Why the SDK knows about the cloud at all\n *\n * Delegated execution lets an account that holds one signing key write into a\n * context without running a node \u2014 but only through a *relay*, and a relay is\n * something the client has to be told about. A warrant names an executor\n * account, so a client that cannot discover which relay serves its namespace,\n * and which account that relay writes as, cannot mint a usable warrant at all.\n *\n * For a self-hosted namespace the operator hands those two facts over out of\n * band. For the hosted tier the cloud is the directory: the user signs in, the\n * cloud knows which namespaces they own and which attested TEE nodes are\n * assigned to each, and it answers with the relay's URL and executor account.\n * That is what this client is for \u2014 it is the discovery half of\n * {@link RelayClient}, not a second way to talk to a node.\n *\n * # What it deliberately is not\n *\n * It never sees a warrant, a device secret, or an intent. Discovery goes\n * through the cloud; the write goes straight from the client to the relay. A\n * cloud that proxied intents would read every method and argument its users\n * ever sent, and would be a throughput bottleneck on a path that has no reason\n * to involve it.\n */\n\nimport { HTTPError } from '../http-client/web-client.js';\n\n/** Where the hosted cloud lives when a caller names no other. */\nconst DEFAULT_CLOUD_BASE_URL = 'https://cloud.calimero.network';\n\nexport interface CloudClientConfig {\n cloudBaseUrl?: string;\n /**\n * An MDMA session token to start out authenticated with \u2014 from a previous\n * {@link CloudClient.signInWithGoogle}, persisted by the app.\n *\n * Sessions are 7-day JWTs with a rolling refresh, so a stored one is usually\n * still live and re-running the Google flow on every launch is avoidable.\n */\n sessionToken?: string;\n /**\n * Called whenever the session token changes \u2014 a sign-in, an explicit\n * refresh, or a rolling refresh the server performed mid-request. Persist it\n * here; errors thrown are swallowed so a storage failure cannot mask the\n * response the caller is waiting for.\n */\n onSession?: (session: CloudSession | null) => void | Promise<void>;\n /** Injected for tests and non-browser runtimes. Defaults to global `fetch`. */\n fetch?: typeof fetch;\n /** Per-request timeout. Defaults to 10s, as the node clients do. */\n timeoutMs?: number;\n}\n\n/** Who is signed in, and until when. */\nexport interface CloudSession {\n sessionToken: string;\n /** Epoch **seconds**, as MDMA reports it \u2014 not milliseconds. */\n expiresAt: number;\n user: { email: string; name?: string; picture?: string };\n}\n\n/** One namespace the signed-in user owns. */\nexport interface CloudNamespace {\n namespaceId: string;\n /** Always equal to `namespaceId`; MDMA keeps it for wire compatibility. */\n groupId: string;\n /** `'enabled' | 'disabled' | 'none'` \u2014 `'none'` means HA was never enabled. */\n haStatus: string;\n haEnabledAt?: string | null;\n contexts: string[];\n fleetReplicas?: { current?: number; limit?: number } | unknown;\n}\n\n/**\n * One attested node the cloud has assigned to a namespace, described as a\n * relay.\n *\n * `authorshipReady` is the field that decides whether a write can happen, and\n * it is reported rather than assumed because it is not the cloud's to grant:\n * `CAN_AUTHOR_ON_BEHALF` is a governance capability, set by an admin of the\n * namespace, and the cloud only relays what the node observed. A relay that is\n * `active` with `authorshipReady: false` is a healthy node waiting for a grant.\n */\nexport interface CloudRelay {\n peerId: string;\n /** Base URL to present intents to, or `null` when the cloud knows none yet. */\n relayUrl: string | null;\n /** The account a warrant for this relay must name as its `executor`, hex. */\n executorAccount: string | null;\n /** `'assigned'` (admitted pending confirm) or `'active'`. */\n status: string;\n /** Whether this relay holds `CAN_AUTHOR_ON_BEHALF` on the namespace. */\n authorshipReady: boolean;\n lastSeenAt?: string | null;\n confirmedAt?: string | null;\n}\n\n/** One namespace of the caller's that a machine is serving. */\nexport interface CloudMachineNamespace {\n namespaceId: string;\n /** `'assigned'` (admitted pending confirm) or `'active'`. */\n status: string;\n /** Whether the machine holds `CAN_AUTHOR_ON_BEHALF` on this namespace. */\n authorshipReady: boolean;\n /**\n * Whether the machine's heartbeat for this namespace is recent.\n *\n * The same freshness rule the per-plan fleet cap uses, so a replica that\n * stopped polling reads as stale here rather than continuing to look\n * healthy \u2014 otherwise \"my writes stopped working\" has no visible cause.\n */\n fresh: boolean;\n confirmedAt?: string | null;\n lastSeenAt?: string | null;\n}\n\n/**\n * One attested machine serving this account.\n *\n * A narrow view on purpose: the zone, machine type, instance name, public IP\n * and KMS ids are operator data with no client use, and a cloud user is not an\n * operator.\n */\nexport interface CloudMachine {\n peerId: string;\n relayUrl: string | null;\n executorAccount: string | null;\n /**\n * Whether this machine can write for the caller *somewhere* \u2014 a URL, an\n * executor account, and the grant on at least one namespace.\n *\n * Folded here so a client does not re-derive the three-way precondition and\n * get a refusal it cannot explain.\n */\n canExecute: boolean;\n /** Only the caller's own namespaces, even on a machine shared with others. */\n namespaces: CloudMachineNamespace[];\n}\n\nexport interface EnableHAOptions {\n groupId: string;\n contextId: string;\n redirectUrl?: string;\n}\n\nexport interface DisableHAOptions {\n groupId: string;\n contextId: string;\n redirectUrl?: string;\n}\n\n/** Response headers MDMA uses to hand back a rolling-refreshed session. */\nconst REFRESH_HEADER = 'x-mdma-session-refresh';\nconst REFRESH_EXPIRES_HEADER = 'x-mdma-session-expires';\n\nexport class CloudClient {\n private baseUrl: string;\n private session: CloudSession | null = null;\n private readonly onSession?: CloudClientConfig['onSession'];\n private readonly fetchImpl: typeof fetch;\n private readonly timeoutMs: number;\n\n constructor(config: CloudClientConfig = {}) {\n this.baseUrl = (config.cloudBaseUrl || DEFAULT_CLOUD_BASE_URL).replace(/\\/+$/, '');\n this.onSession = config.onSession;\n // Bound through an arrow function: an unbound `globalThis.fetch` throws\n // \"Illegal invocation\" in a browser, the same reason the node HTTP clients\n // wrap it.\n const injected = config.fetch;\n this.fetchImpl = injected\n ? (input: RequestInfo | URL, init?: RequestInit) => injected(input, init)\n : (input: RequestInfo | URL, init?: RequestInit) => globalThis.fetch(input, init);\n this.timeoutMs = config.timeoutMs ?? 10_000;\n\n if (config.sessionToken) {\n // Expiry unknown until the server tells us; 0 means \"do not reason about\n // it locally\", never \"expired\" \u2014 the server is the only judge and it\n // answers 401 when it disagrees.\n this.session = {\n sessionToken: config.sessionToken,\n expiresAt: 0,\n user: { email: '' },\n };\n }\n }\n\n /** The current session, or `null` when nobody is signed in. */\n getSession(): CloudSession | null {\n return this.session;\n }\n\n /** Whether a session token is held. Says nothing about the server agreeing. */\n isSignedIn(): boolean {\n return this.session !== null;\n }\n\n /**\n * Exchange a Google OAuth2 ID token for an MDMA session.\n *\n * The app owns the Google flow (One Tap, an auth-code popup, a native\n * browser) and hands the resulting ID token here once. Everything after this\n * uses the returned session token, so the Google credential does not have to\n * be kept or re-minted per call.\n */\n async signInWithGoogle(idToken: string): Promise<CloudSession> {\n const body = await this.request<{\n session_token: string;\n expires_at: number;\n user: { email: string; name?: string; picture?: string };\n }>('POST', '/api/auth/google', { body: { id_token: idToken }, anonymous: true });\n return this.adoptSession(body);\n }\n\n /**\n * Refresh the session token explicitly.\n *\n * Rarely needed: MDMA rolling-refreshes on ordinary authenticated calls and\n * this client adopts the replacement automatically. Use it when an app wants\n * a fresh token before going idle rather than on the next request.\n */\n async refreshSession(): Promise<CloudSession> {\n const body = await this.request<{\n session_token: string;\n expires_at: number;\n user: { email: string; name?: string; picture?: string };\n }>('POST', '/api/auth/refresh');\n return this.adoptSession(body);\n }\n\n /**\n * Revoke this session server-side and forget it locally.\n *\n * Local state is cleared even if the server call fails: the caller asked to\n * be signed out, and keeping a token they believe is gone is the worse of the\n * two failures.\n */\n async signOut(): Promise<void> {\n try {\n if (this.session) await this.request<void>('POST', '/api/auth/logout', { parse: 'none' });\n } finally {\n this.session = null;\n void this.notifySession(null);\n }\n }\n\n /** Namespaces the signed-in user owns. */\n async getMyNamespaces(): Promise<CloudNamespace[]> {\n const rows = await this.request<Array<Record<string, unknown>>>(\n 'GET',\n '/api/cloud/me/namespaces',\n );\n return rows.map((row) => ({\n namespaceId: String(row.namespace_id ?? row.group_id ?? ''),\n groupId: String(row.group_id ?? row.namespace_id ?? ''),\n haStatus: String(row.ha_status ?? 'none'),\n haEnabledAt: (row.ha_enabled_at as string | null | undefined) ?? null,\n contexts: Array.isArray(row.contexts) ? (row.contexts as string[]) : [],\n fleetReplicas: row.fleet_replicas,\n }));\n }\n\n /**\n * The relays serving one namespace: where to present an intent, and as whom.\n *\n * Everything a client needs in order to mint a warrant it can actually\n * spend. Filter on `authorshipReady` before signing \u2014 a warrant presented to\n * a relay with no grant is refused *after* the author has burned a nonce from\n * its monotonic sequence on it.\n */\n async getNamespaceRelays(namespaceId: string): Promise<CloudRelay[]> {\n const body = await this.request<{ relays?: Array<Record<string, unknown>> }>(\n 'GET',\n `/api/cloud/me/namespaces/${encodeURIComponent(namespaceId)}/relays`,\n );\n return (body.relays ?? []).map((row) => ({\n peerId: String(row.peer_id ?? ''),\n relayUrl: (row.relay_url as string | null | undefined) ?? null,\n executorAccount: (row.executor_account as string | null | undefined) ?? null,\n status: String(row.status ?? ''),\n authorshipReady: row.authorship_ready === true,\n lastSeenAt: (row.last_seen_at as string | null | undefined) ?? null,\n confirmedAt: (row.confirmed_at as string | null | undefined) ?? null,\n }));\n }\n\n /**\n * The first relay for `namespaceId` that can actually run an intent, or\n * `null`.\n *\n * \"Can actually run one\" is three conditions, and a client that checks fewer\n * gets a refusal it cannot explain: the cloud must know a URL, the relay must\n * have reported the executor account a warrant has to name, and the grant\n * must be in place.\n */\n async findExecutingRelay(namespaceId: string): Promise<CloudRelay | null> {\n const relays = await this.getNamespaceRelays(namespaceId);\n return (\n relays.find((r) => r.authorshipReady && r.relayUrl !== null && r.executorAccount !== null) ??\n null\n );\n }\n\n /**\n * Every attested machine currently serving something this account owns.\n *\n * The account-wide view of the same rows {@link getNamespaceRelays} returns\n * per namespace, keyed by machine \u2014 so a UI can answer \"what is running for\n * me?\" in one call. `canExecute` folds the three-way precondition, so a\n * caller does not re-derive it.\n *\n * Only the caller's own namespaces appear on each machine. A plan's\n * `usersPerMachine` is greater than one, so a fleet node routinely serves\n * several accounts at once.\n */\n async getMyMachines(): Promise<CloudMachine[]> {\n const body = await this.request<{ machines?: Array<Record<string, unknown>> }>(\n 'GET',\n '/api/cloud/me/machines',\n );\n return (body.machines ?? []).map((row) => ({\n peerId: String(row.peer_id ?? ''),\n relayUrl: (row.relay_url as string | null | undefined) ?? null,\n executorAccount: (row.executor_account as string | null | undefined) ?? null,\n canExecute: row.can_execute === true,\n namespaces: (Array.isArray(row.namespaces) ? row.namespaces : []).map((n) => {\n const ns = n as Record<string, unknown>;\n return {\n namespaceId: String(ns.namespace_id ?? ''),\n status: String(ns.status ?? ''),\n authorshipReady: ns.authorship_ready === true,\n fresh: ns.fresh === true,\n confirmedAt: (ns.confirmed_at as string | null | undefined) ?? null,\n lastSeenAt: (ns.last_seen_at as string | null | undefined) ?? null,\n };\n }),\n }));\n }\n\n /**\n * Claim a namespace under this account, proving ownership.\n *\n * The cloud has no other way to learn a namespace exists \u2014 namespaces are\n * created on a node, and there is deliberately no \"create namespace\" in the\n * cloud. `ownershipProof` comes from\n * `admin.issueNamespaceOwnershipProof(namespaceId, \u2026)` on a node that is a\n * **direct admin** of that namespace; merod refuses to issue one otherwise.\n *\n * Pass merod's response object straight through. The cloud accepts core's\n * `signerPublicKey`/`signedPayload` casing as well as snake_case, so there is\n * no re-keying step \u2014 and getting that wrong used to surface as a `422`\n * naming three missing fields.\n *\n * Idempotent for the same account. A namespace already claimed by someone\n * else is a `409`; a replayed proof nonce is a `403`.\n */\n async claimNamespace(namespaceId: string, ownershipProof: unknown): Promise<void> {\n await this.request<unknown>('POST', '/api/cloud/namespaces/claim', {\n body: { namespace_id: namespaceId, ownership_proof: ownershipProof },\n });\n }\n\n /**\n * Ask the fleet to host a claimed namespace \u2014 the step that gets a relay\n * assigned.\n *\n * Takes no body: {@link claimNamespace} already established ownership, and\n * this is the separate \"now host it\" half. Idempotent.\n *\n * Not to be confused with {@link enableHA}, which opens the cloud's web flow\n * in a browser tab for a user to complete by hand. This is the API call.\n */\n async enableNamespaceHa(namespaceId: string): Promise<unknown> {\n return this.request<unknown>(\n 'POST',\n `/api/cloud/namespaces/${encodeURIComponent(namespaceId)}/enable-ha`,\n { body: {} },\n );\n }\n\n /**\n * Stop hosting a claimed namespace.\n *\n * The fleet's own reconcile loop does the rest: each assigned node notices\n * the namespace is no longer assigned to it and **self-leaves**, which makes\n * core evict it and purge its local data and keys. So this is not just a\n * billing flip.\n */\n async disableNamespaceHa(namespaceId: string): Promise<unknown> {\n return this.request<unknown>(\n 'POST',\n `/api/cloud/namespaces/${encodeURIComponent(namespaceId)}/disable-ha`,\n { body: {} },\n );\n }\n\n /**\n * The node assigned to the signed-in user, or `null`.\n *\n * @deprecated Use {@link getMyMachines}. This reads the cloud's retired\n * `NodeAssignment` ledger, which nothing has written since the v1\n * retirement, so it answers `null` for every namespace-native account \u2014\n * which reads as \"you have no machine\" when the truth is \"that is no longer\n * how a machine is assigned\".\n */\n async getMyNode(): Promise<Record<string, unknown> | null> {\n const body = await this.request<{ node: Record<string, unknown> | null }>(\n 'GET',\n '/api/cloud/me/node',\n );\n return body.node ?? null;\n }\n\n enableHA(options: EnableHAOptions): void {\n const params = new URLSearchParams({\n group_id: options.groupId,\n context_id: options.contextId,\n });\n if (options.redirectUrl) {\n params.set('redirect_url', options.redirectUrl);\n }\n window.open(`${this.baseUrl}/enable-ha?${params.toString()}`);\n }\n\n disableHA(options: DisableHAOptions): void {\n const params = new URLSearchParams({\n group_id: options.groupId,\n context_id: options.contextId,\n });\n if (options.redirectUrl) {\n params.set('redirect_url', options.redirectUrl);\n }\n window.open(`${this.baseUrl}/disable-ha?${params.toString()}`);\n }\n\n /** Record a freshly-issued session and tell the app to persist it. */\n private adoptSession(body: {\n session_token: string;\n expires_at: number;\n user: { email: string; name?: string; picture?: string };\n }): CloudSession {\n this.session = {\n sessionToken: body.session_token,\n expiresAt: body.expires_at,\n user: body.user,\n };\n void this.notifySession(this.session);\n return this.session;\n }\n\n private async notifySession(session: CloudSession | null): Promise<void> {\n try {\n await this.onSession?.(session);\n } catch {\n // A failing persistence callback must not mask the call's own result.\n }\n }\n\n private async request<T>(\n method: string,\n path: string,\n options: { body?: unknown; anonymous?: boolean; parse?: 'json' | 'none' } = {},\n ): Promise<T> {\n if (!options.anonymous && !this.session) {\n throw new Error(\n 'Not signed in to Calimero Cloud: call signInWithGoogle() or construct the client with a sessionToken',\n );\n }\n\n const headers: Record<string, string> = { Accept: 'application/json' };\n if (options.body !== undefined) headers['Content-Type'] = 'application/json';\n if (!options.anonymous && this.session) {\n headers.Authorization = `Bearer ${this.session.sessionToken}`;\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n let response: Response;\n try {\n response = await this.fetchImpl(`${this.baseUrl}${path}`, {\n method,\n headers,\n body: options.body === undefined ? undefined : JSON.stringify(options.body),\n signal: controller.signal,\n });\n } catch (err) {\n // Same shape the node clients use for a transport failure: an `HTTPError`\n // with `status: 0`, so a caller has one error type to handle rather than\n // one per layer.\n throw new HTTPError(\n 0,\n err instanceof Error ? err.name : 'NetworkError',\n `${this.baseUrl}${path}`,\n new Headers(),\n err instanceof Error ? err.message : String(err),\n );\n } finally {\n clearTimeout(timer);\n }\n\n this.adoptRollingRefresh(response);\n\n if (!response.ok) {\n const bodyText = await response.text().catch(() => undefined);\n throw new HTTPError(\n response.status,\n response.statusText,\n `${this.baseUrl}${path}`,\n response.headers,\n bodyText,\n );\n }\n\n if (options.parse === 'none' || response.status === 204) return undefined as T;\n return (await response.json()) as T;\n }\n\n /**\n * Adopt a session token the server refreshed mid-request.\n *\n * MDMA rotates the token on activity and returns the replacement in a\n * response header rather than making the client ask. Ignoring it costs\n * nothing immediately and then logs the user out a week later, which is the\n * kind of bug that is impossible to reproduce in a short session.\n *\n * The user identity is carried over: the header holds only a token, and the\n * refresh is the same logical session as the sign-in that named the user.\n */\n private adoptRollingRefresh(response: Response): void {\n const token = response.headers.get(REFRESH_HEADER);\n if (!token || !this.session) return;\n const expiresRaw = response.headers.get(REFRESH_EXPIRES_HEADER);\n const expiresAt = Number(expiresRaw);\n this.session = {\n sessionToken: token,\n expiresAt: Number.isFinite(expiresAt) && expiresAt > 0 ? expiresAt : this.session.expiresAt,\n user: this.session.user,\n };\n void this.notifySession(this.session);\n }\n}\n", "import { createBrowserHttpClient } from './http-client/index.js';\nimport { createAuthApiClientFromHttpClient } from './auth-api/index.js';\nimport { createAdminApiClientFromHttpClient } from './admin-api/index.js';\nimport type { AuthApiClient } from './auth-api/index.js';\nimport type { AdminApiClient } from './admin-api/index.js';\nimport type { HttpClient } from './http-client/index.js';\nimport type { TokenStore } from './token-store/index.js';\nimport { parseAuthCallback, buildAuthLoginUrl } from './auth/index.js';\nimport type { AuthCallbackResult, AuthLoginOptions } from './auth/index.js';\nimport { RpcClient } from './rpc/index.js';\nimport { SseClient } from './events/sse.js';\nimport { WsClient } from './events/ws.js';\nimport { EphemeralClient } from './ephemeral/index.js';\nimport { CloudClient } from './cloud/cloud-client.js';\nimport type { CloudClientConfig } from './cloud/cloud-client.js';\n\nexport interface MeroJsConfig {\n /** Base URL for the Calimero node */\n baseUrl: string;\n /** Initial credentials for authentication */\n credentials?: {\n username: string;\n password: string;\n };\n /** Custom HTTP client timeout in milliseconds */\n timeoutMs?: number;\n /** Request credentials mode for fetch (omit, same-origin, include) */\n requestCredentials?: RequestCredentials;\n /** Optional token store for persistence */\n tokenStore?: TokenStore;\n /**\n * Called when the node reports that the credential family is gone\n * (`x-auth-error: token_reuse` / `token_revoked`). Terminal: the tokens have\n * already been cleared by the time this runs and nothing is retried, so use it\n * to send the user back through login. Errors thrown here are swallowed \u2014\n * never let a UI failure mask the auth error.\n */\n onAuthRevoked?: () => Promise<void> | void;\n /**\n * Calimero Cloud, reachable as `sdk.cloud`.\n *\n * A node connection and a cloud account are separate things a client can have\n * either of, both of, or neither \u2014 a desktop app with a local node and a\n * cloud subscription has both, and needs them from one object. So this is\n * configuration on the existing SDK rather than a second SDK: pass the\n * session token (or none, and sign in through `sdk.cloud`) and the node half\n * is unaffected.\n *\n * For a caller with *no* node at all, `connectCloud` is the entry point\n * instead \u2014 it returns a connection that can write without one.\n */\n cloud?: CloudClientConfig;\n}\n\nexport interface TokenData {\n access_token: string;\n refresh_token: string;\n expires_at: number;\n}\n\n/** Name of the Web Lock that serializes token refresh across tabs / webviews. */\nconst REFRESH_LOCK_NAME = 'mero-js:token-refresh';\n\n/** Minimal structural view of the Web Locks API (not available in every runtime). */\ninterface LockManagerLike {\n request<T>(name: string, callback: () => Promise<T>): Promise<T>;\n}\n\n/** Returns `navigator.locks` when the runtime supports the Web Locks API. */\nfunction getLockManager(): LockManagerLike | null {\n const nav = (globalThis as unknown as { navigator?: { locks?: LockManagerLike } }).navigator;\n const locks = nav?.locks;\n return locks && typeof locks.request === 'function' ? locks : null;\n}\n\n/** Try to extract `exp` (seconds) from a JWT, return ms timestamp or fallback. */\nfunction expiresAtFromJwt(token: string, fallbackMs: number): number {\n try {\n const parts = token.split('.');\n if (parts.length === 3) {\n // JWT uses base64url encoding: replace -/_ with +// and add padding\n let b64 = parts[1].replace(/-/g, '+').replace(/_/g, '/');\n while (b64.length % 4) b64 += '=';\n const payload = JSON.parse(atob(b64));\n if (typeof payload.exp === 'number') {\n return payload.exp * 1000;\n }\n }\n } catch {\n // not a JWT or can't parse\n }\n return fallbackMs;\n}\n\n/**\n * Main MeroJs SDK class that manages all API clients and authentication\n */\nexport class MeroJs {\n private config: MeroJsConfig;\n private httpClient: HttpClient;\n private authClient: AuthApiClient;\n private adminClient: AdminApiClient;\n private tokenData: TokenData | null = null;\n private refreshPromise: Promise<TokenData> | null = null;\n private tokenStore: TokenStore | null;\n private rpcClient: RpcClient | null = null;\n private sseClient: SseClient | null = null;\n private wsClient: WsClient | null = null;\n private wsWarned = false;\n private ephemeralClient?: EphemeralClient;\n private cloudClient?: CloudClient;\n\n constructor(config: MeroJsConfig) {\n this.config = {\n timeoutMs: 10000,\n ...config,\n };\n\n this.tokenStore = config.tokenStore ?? null;\n\n // Restore tokens from store if available\n if (this.tokenStore) {\n this.tokenData = this.tokenStore.getTokens();\n }\n\n // Create HTTP client with token management\n // For Tauri, explicitly set credentials to 'omit' to avoid network errors\n const isTauri = typeof window !== 'undefined' && '__TAURI_INTERNALS__' in window;\n this.httpClient = createBrowserHttpClient({\n baseUrl: this.config.baseUrl,\n getAuthToken: async () => {\n const token = await this.getValidToken();\n return token?.access_token || '';\n },\n refreshToken: async () => {\n const refreshed = await this.performTokenRefresh();\n return refreshed.access_token;\n },\n onTokenRefresh: async (newToken: string) => {\n if (this.tokenData) {\n this.tokenData.access_token = newToken;\n this.tokenStore?.setTokens(this.tokenData);\n }\n },\n onAuthRevoked: async () => {\n // The refresh-token family is gone (a single-use refresh token was\n // replayed, or the token was revoked). Nothing left to refresh with \u2014\n // drop the bundle so the app can force a re-login, then let the app react.\n this.clearToken();\n try {\n await this.config.onAuthRevoked?.();\n } catch {\n // A failing app callback must not mask the auth error.\n }\n },\n timeoutMs: this.config.timeoutMs,\n credentials: this.config.requestCredentials ?? (isTauri ? 'omit' : undefined),\n });\n\n // Create API clients\n this.authClient = createAuthApiClientFromHttpClient(this.httpClient, {\n baseUrl: this.config.baseUrl,\n getAuthToken: async () => {\n const token = await this.getValidToken();\n return token?.access_token || '';\n },\n timeoutMs: this.config.timeoutMs,\n });\n\n this.adminClient = createAdminApiClientFromHttpClient(this.httpClient, {\n baseUrl: this.config.baseUrl,\n getAuthToken: async () => {\n const token = await this.getValidToken();\n return token?.access_token || '';\n },\n timeoutMs: this.config.timeoutMs,\n });\n }\n\n /**\n * Get the Auth API client\n */\n get auth(): AuthApiClient {\n return this.authClient;\n }\n\n /**\n * Get the Admin API client\n */\n get admin(): AdminApiClient {\n return this.adminClient;\n }\n\n /**\n * Get the RPC client (lazy initialized)\n */\n get rpc(): RpcClient {\n if (!this.rpcClient) {\n this.rpcClient = new RpcClient({ httpClient: this.httpClient });\n }\n return this.rpcClient;\n }\n\n /**\n * Get the SSE event client (lazy initialized)\n */\n get events(): SseClient {\n if (!this.sseClient) {\n this.sseClient = new SseClient({\n baseUrl: this.config.baseUrl,\n getAuthToken: async () => {\n const token = await this.getValidToken();\n return token?.access_token || '';\n },\n });\n }\n return this.sseClient;\n }\n\n /**\n * Get the ephemeral-presence client (lazy initialized).\n *\n * Shares this instance's SSE client, so `subscribe` reuses the one event\n * stream rather than opening a second connection.\n */\n get ephemeral(): EphemeralClient {\n if (!this.ephemeralClient) {\n this.ephemeralClient = new EphemeralClient({\n httpClient: this.httpClient,\n sse: this.events,\n });\n }\n return this.ephemeralClient;\n }\n\n /**\n * Calimero Cloud (lazy initialized).\n *\n * Available whether or not `cloud` was configured \u2014 an app that signs in\n * later gets an unauthenticated client it can call `signInWithGoogle` on,\n * which is one fewer construction path than making the getter conditional.\n * It is entirely independent of this instance's node credential: the cloud\n * knows nothing about the node's tokens and the node knows nothing about the\n * cloud session.\n */\n get cloud(): CloudClient {\n if (!this.cloudClient) {\n this.cloudClient = new CloudClient(this.config.cloud ?? {});\n }\n return this.cloudClient;\n }\n\n /**\n * Get the WebSocket event client (lazy initialized).\n * @experimental Use `events` (SSE) for production. WsClient is experimental.\n */\n get ws(): WsClient {\n if (!this.wsWarned) {\n this.wsWarned = true;\n console.warn('[mero-js] WsClient is experimental. Use mero.events (SSE) for production.');\n }\n if (!this.wsClient) {\n this.wsClient = new WsClient({\n baseUrl: this.config.baseUrl,\n getAuthToken: async () => {\n const token = await this.getValidToken();\n return token?.access_token || '';\n },\n });\n }\n return this.wsClient;\n }\n\n /**\n * Authenticate with the provided credentials\n * This will create the root key on first use\n */\n async authenticate(credentials?: {\n username: string;\n password: string;\n }): Promise<TokenData> {\n const creds = credentials || this.config.credentials;\n if (!creds) {\n throw new Error('No credentials provided for authentication');\n }\n\n try {\n const requestBody = {\n auth_method: 'user_password',\n public_key: creds.username,\n client_name: 'mero-js-sdk',\n permissions: ['admin'],\n timestamp: Math.floor(Date.now() / 1000),\n provider_data: {\n username: creds.username,\n password: creds.password,\n },\n };\n\n const response = await this.authClient.generateTokens(requestBody);\n\n const accessToken = response.data.access_token;\n this.tokenData = {\n access_token: accessToken,\n refresh_token: response.data.refresh_token,\n expires_at: expiresAtFromJwt(accessToken, Date.now() + 3600_000),\n };\n\n this.tokenStore?.setTokens(this.tokenData);\n\n return this.tokenData;\n } catch (error) {\n throw new Error(\n `Authentication failed: ${error instanceof Error ? error.message : 'Unknown error'}`,\n );\n }\n }\n\n /**\n * Get a valid token. Returns the current token as-is.\n * The server rejects refresh attempts while the access token is still valid,\n * so we never proactively refresh. Instead, the WebHttpClient handles 401\n * responses reactively via the refreshToken transport hook.\n */\n private async getValidToken(): Promise<TokenData | null> {\n return this.tokenData;\n }\n\n /**\n * Refresh the access token. Single-flight: every caller (including the HTTP\n * transport's 401 hook) goes through here.\n *\n * Refresh tokens are single-use (calimero-network/core#3083): each refresh\n * consumes the presented token and returns a new one, and replaying a consumed\n * token makes the server revoke the whole family. A refresh must therefore\n * happen exactly once per rotation, which needs three layers:\n * - an in-process promise, so concurrent 401s in this instance share one call;\n * - a Web Lock (when available), so other tabs/webviews don't refresh at the\n * same time on the same stored token;\n * - a re-read of the token store inside the lock, so a bundle that another\n * instance already rotated is adopted instead of replaying a stale token.\n */\n private async performTokenRefresh(): Promise<TokenData> {\n if (this.refreshPromise) {\n return this.refreshPromise;\n }\n\n // The access token that triggered this refresh. If the store holds a different\n // one by the time we get the lock, someone else already rotated for us.\n const triggeringAccessToken = this.tokenData?.access_token;\n\n const promise = this.withRefreshLock(() =>\n this.performTokenRefreshLocked(triggeringAccessToken),\n );\n this.refreshPromise = promise;\n\n try {\n return await promise;\n } finally {\n if (this.refreshPromise === promise) {\n this.refreshPromise = null;\n }\n }\n }\n\n /** Run `fn` under the cross-tab refresh lock, or directly if Web Locks are unavailable. */\n private withRefreshLock<T>(fn: () => Promise<T>): Promise<T> {\n const locks = getLockManager();\n return locks ? locks.request(REFRESH_LOCK_NAME, fn) : fn();\n }\n\n /**\n * Perform the actual token refresh. Runs with the refresh lock held.\n */\n private async performTokenRefreshLocked(\n triggeringAccessToken?: string,\n ): Promise<TokenData> {\n // Another instance/tab may have rotated the bundle while we were queued behind\n // the lock \u2014 the store, not our in-memory copy, is the source of truth.\n const stored = this.tokenStore?.getTokens() ?? null;\n if (stored?.refresh_token) {\n this.tokenData = stored;\n\n if (triggeringAccessToken && stored.access_token !== triggeringAccessToken) {\n // Someone else already refreshed. Reuse their bundle rather than replaying\n // our (now consumed) refresh token, which would revoke the family.\n return stored;\n }\n }\n\n if (!this.tokenData?.refresh_token) {\n throw new Error('No refresh token available');\n }\n\n try {\n const response = await this.authClient.refreshToken({\n access_token: this.tokenData.access_token,\n refresh_token: this.tokenData.refresh_token,\n });\n\n const accessToken = response.data.access_token;\n this.tokenData = {\n access_token: accessToken,\n // The refresh token is rotated on every refresh \u2014 persist the new one or\n // the next refresh replays a consumed token.\n refresh_token: response.data.refresh_token,\n expires_at: expiresAtFromJwt(accessToken, Date.now() + 3600_000),\n };\n\n this.tokenStore?.setTokens(this.tokenData);\n\n return this.tokenData;\n } catch (error) {\n // Don't clear tokens on refresh failure \u2014 the access token may still be\n // valid (server rejects refresh while access token hasn't expired yet).\n // A genuinely dead family arrives as `x-auth-error: token_reuse` and is\n // handled by the onAuthRevoked transport hook. Let the caller handle this.\n throw new Error(\n `Token refresh failed: ${error instanceof Error ? error.message : 'Unknown error'}`,\n );\n }\n }\n\n /**\n * Clear the current token\n */\n public clearToken(): void {\n this.refreshPromise = null;\n this.tokenData = null;\n this.tokenStore?.clear();\n }\n\n /**\n * Check if the SDK is authenticated\n */\n public isAuthenticated(): boolean {\n return this.tokenData !== null;\n }\n\n /**\n * Set token data directly (e.g., from auth callback).\n * If `expires_at` is missing or 0, attempts to parse the JWT exp claim,\n * falling back to 1 hour from now.\n */\n public setTokenData(data: TokenData): void {\n const expiresAt = data.expires_at || expiresAtFromJwt(data.access_token, Date.now() + 3600_000);\n this.tokenData = { ...data, expires_at: expiresAt };\n this.tokenStore?.setTokens(this.tokenData);\n }\n\n /**\n * Get the current token data (for debugging)\n */\n public getTokenData(): TokenData | null {\n return this.tokenData;\n }\n\n /**\n * Close all event connections and clean up resources\n */\n public close(): void {\n this.sseClient?.close();\n this.wsClient?.close();\n }\n\n /**\n * Parse an auth callback URL hash fragment (static utility)\n */\n static parseAuthCallback(url: string): AuthCallbackResult | null {\n return parseAuthCallback(url);\n }\n\n /**\n * Build an auth login URL (static utility)\n */\n static buildAuthLoginUrl(nodeUrl: string, opts: AuthLoginOptions): string {\n return buildAuthLoginUrl(nodeUrl, opts);\n }\n}\n\n/**\n * Create a new MeroJs SDK instance\n */\nexport function createMeroJs(config: MeroJsConfig): MeroJs {\n return new MeroJs(config);\n}\n", "import type { TokenData } from '../mero-js.js';\n\nexport interface TokenStore {\n getTokens(): TokenData | null;\n setTokens(data: TokenData): void;\n clear(): void;\n}\n\nexport class MemoryTokenStore implements TokenStore {\n private tokens: TokenData | null = null;\n\n getTokens(): TokenData | null {\n return this.tokens;\n }\n\n setTokens(data: TokenData): void {\n this.tokens = data;\n }\n\n clear(): void {\n this.tokens = null;\n }\n}\n\nconst STORAGE_KEY = 'mero-tokens';\n\nexport class LocalStorageTokenStore implements TokenStore {\n private readonly key: string;\n\n constructor(key: string = STORAGE_KEY) {\n this.key = key;\n }\n\n getTokens(): TokenData | null {\n try {\n if (typeof localStorage === 'undefined') return null;\n const raw = localStorage.getItem(this.key);\n if (!raw) return null;\n const parsed = JSON.parse(raw);\n if (parsed && parsed.access_token && parsed.refresh_token) {\n return {\n access_token: parsed.access_token,\n refresh_token: parsed.refresh_token,\n expires_at: typeof parsed.expires_at === 'number' ? parsed.expires_at : Date.now() + 3600_000,\n };\n }\n return null;\n } catch {\n return null;\n }\n }\n\n setTokens(data: TokenData): void {\n try {\n if (typeof localStorage === 'undefined') return;\n localStorage.setItem(this.key, JSON.stringify(data));\n } catch {\n // Storage unavailable\n }\n }\n\n clear(): void {\n try {\n if (typeof localStorage === 'undefined') return;\n localStorage.removeItem(this.key);\n } catch {\n // Storage unavailable\n }\n }\n}\n", "/**\n * Byte-level primitives shared by everything in this package that signs.\n *\n * Extracted from `warrant/warrant.ts` when the device-cert signer arrived and\n * needed the same `domainHash`, hex handling and ed25519 import. Keeping one\n * copy is the point: these have to stay byte-identical with core, and two\n * copies drifting apart is exactly the failure the byte-parity e2e exists to\n * catch. Internal \u2014 not exported from the package root.\n */\n\nconst PKCS8_ED25519_PREFIX = new Uint8Array([\n 0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x04,\n 0x22, 0x04, 0x20,\n]);\n\n/** Little-endian u32, for borsh fixed-width fields and epoch counters. */\nexport function u32le(value: number): Uint8Array {\n const out = new Uint8Array(4);\n new DataView(out.buffer).setUint32(0, value, true);\n return out;\n}\n\nexport function hex(bytes: Uint8Array): string {\n return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n}\n\nexport function fromHex(value: string, label: string, expectedBytes: number): Uint8Array {\n const clean = value.trim();\n if (!/^[0-9a-fA-F]*$/.test(clean) || clean.length !== expectedBytes * 2) {\n throw new Error(\n `${label} must be ${expectedBytes * 2} hex characters, got ${clean.length}`,\n );\n }\n // Indexed rather than `match(/../g)!`: the length is already validated above,\n // so the assertion would only be telling the compiler what the guard proved,\n // and this needs no assertion at all.\n const bytes = new Uint8Array(expectedBytes);\n for (let i = 0; i < expectedBytes; i += 1) {\n bytes[i] = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n}\n\nexport function u64le(value: number | bigint): Uint8Array {\n const out = new Uint8Array(8);\n new DataView(out.buffer).setBigUint64(0, BigInt(value), true);\n return out;\n}\n\nexport function concat(...parts: Uint8Array[]): Uint8Array {\n const out = new Uint8Array(parts.reduce((total, p) => total + p.length, 0));\n let offset = 0;\n for (const part of parts) {\n out.set(part, offset);\n offset += part.length;\n }\n return out;\n}\n\n/**\n * core's `domain_hash`: SHA-256 over the length-prefixed domain, then each\n * length-prefixed part. The lengths are what stop two different field splits from\n * hashing alike.\n */\nexport async function domainHash(\n domain: Uint8Array,\n parts: Uint8Array[],\n): Promise<Uint8Array> {\n const chunks: Uint8Array[] = [u64le(domain.length), domain];\n for (const part of parts) {\n chunks.push(u64le(part.length), part);\n }\n return new Uint8Array(\n await crypto.subtle.digest('SHA-256', concat(...chunks)),\n );\n}\n\nexport async function importSigningKey(secretHex: string): Promise<CryptoKey> {\n const seed = fromHex(secretHex, 'deviceSecret', 32);\n const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);\n try {\n return await crypto.subtle.importKey(\n 'pkcs8',\n pkcs8,\n { name: 'Ed25519' },\n false,\n ['sign'],\n );\n } catch (cause) {\n // The original message is folded in rather than passed as `cause`: this\n // package targets ES2020, where `Error` has no `cause` option.\n const detail = cause instanceof Error ? `: ${cause.message}` : '';\n throw new Error(\n 'this runtime has no WebCrypto Ed25519, so a warrant cannot be signed ' +\n 'here. Node 18.4+, Safari 17+, Firefox 129+ and Chrome 137+ have it; ' +\n 'otherwise mint the warrant with `merod account warrant`' +\n detail,\n );\n }\n}\n\n/**\n * The public half of an ed25519 seed.\n *\n * Derived rather than taken as an argument, for the reason core does the same: a\n * caller able to name a key it does not hold could produce a warrant it cannot\n * sign, and the field would stop meaning \"who authorised this\".\n */\nexport async function derivePublicKey(secretHex: string): Promise<Uint8Array> {\n const seed = fromHex(secretHex, 'deviceSecret', 32);\n const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);\n const key = await crypto.subtle.importKey(\n 'pkcs8',\n pkcs8,\n { name: 'Ed25519' },\n true,\n ['sign'],\n );\n const jwk = await crypto.subtle.exportKey('jwk', key);\n const raw = (jwk as JsonWebKey & { x: string }).x;\n return Uint8Array.from(atob(raw.replace(/-/g, '+').replace(/_/g, '/')), (c) =>\n c.charCodeAt(0),\n );\n}\n", "/**\n * Mint a warrant: the author's consent for one relay to run one intent, once.\n *\n * This exists because the case delegated authorship is *for* is an account that\n * holds no node \u2014 a browser tab, a Node service, a bot. Every one of those is a\n * JS runtime, and until now the only thing that could mint a warrant was `merod`,\n * so \"a member with no node\" in practice meant \"a member with a node it is not\n * allowed to use for anything else\".\n *\n * **No dependencies, and that is not incidental.** The primitives are all built\n * in: `crypto.subtle.digest('SHA-256')` for the hash, `crypto.subtle` Ed25519\n * for the signature, and `DataView` for the integers.\n *\n * Warrant v2 (core#3933) gave up the fixed-width encoding that used to make this\n * pure concatenation: `method` travels in the clear as a string and each cited\n * head list is a vector, so three borsh `u32` counts now sit inside the bytes.\n * Two widths to keep straight, and they are not the same: the counts **inside\n * the encoding** are `u32`, while the counts the **signing preimage** hashes are\n * `u64`. Same numbers, different serialization \u2014 reusing one for the other\n * produces a warrant that is well-formed and verifies nowhere.\n *\n * **The byte contract is pinned in core**, at\n * `crates/account/src/tests/warrant_wire_fixture.rs`. The domain strings below\n * are `pub(crate)` there, so nothing in that repository forces anyone to notice\n * this file depends on them \u2014 which is exactly why the fixture lives on that side\n * and this module's test asserts the same vectors. A drift would otherwise leave\n * this producing well-formed warrants whose signatures verify nowhere, surfacing\n * at a relay as a 403: an authorization refusal, nowhere near the cause.\n */\n\nimport {\n concat,\n derivePublicKey,\n domainHash,\n fromHex,\n hex,\n importSigningKey,\n u32le,\n u64le,\n} from '../crypto/internal.js';\n\nconst SIGN_DOMAIN = new TextEncoder().encode('calimero.warrant.v2');\nconst INTENT_DOMAIN = new TextEncoder().encode('calimero.warrant.intent.v1');\n\n/**\n * core's `MAX_WARRANT_CITED_HEADS`. A node refuses more than this before doing\n * any Ed25519 work, so minting past it produces a warrant nothing will spend.\n */\nconst MAX_CITED_HEADS = 64;\n\n/** 32 zero bytes \u2014 the `appVersion` default. See {@link WarrantInput.appVersion}. */\nconst UNPINNED_APP = '00'.repeat(32);\n\n/** Ed25519 PKCS#8 prefix, so a raw 32-byte seed can be imported by WebCrypto. */\n/** What a warrant authorises. */\nexport interface WarrantInput {\n /**\n * The context, hex \u2014 the same string every other method here takes.\n *\n * Hex like everything else on this interface. It was base58 while the node\n * spelled `ContextId` and `PublicKey` that way and `AccountId` and `DeviceId`\n * in hex; that split is gone, so this module no longer needs a rule per field\n * and no longer needs a base58 decoder to enforce one.\n */\n context: string;\n /** The author's account, hex \u2014 whose consent this is. */\n authorAccount: string;\n /** The relay authorised to act, hex. An account, not a key. */\n executor: string;\n /**\n * The application build this warrant is signed against, hex (32 bytes).\n *\n * Pins the code rather than a version string, so a relay cannot wait for an\n * upgrade that widens what `method` does and then spend a warrant signed\n * against the narrower one. Read it from the context\n * (`GET /admin-api/contexts/{id}` \u2192 `applicationId`); a value guessed here\n * pins the wrong build, which is worse than not pinning.\n *\n * Defaults to 32 zero bytes, matching `merod account sign-warrant`'s\n * `--app-version` default. Nothing verifies the field yet \u2014 core#3933 landed\n * the field set ahead of its enforcement so a signer is written once against\n * the final bytes \u2014 but a warrant minted with the default will be refused once\n * pinning lands, so pass the real value for anything meant to outlive it.\n */\n appVersion?: string;\n /**\n * The method the relay may run.\n *\n * Carried in the clear as of v2, so a peer can select a per-method write-set\n * without reversing a hash against the app's ABI. The *arguments* are still\n * committed to rather than carried \u2014 see {@link intentHash}.\n */\n method: string;\n /** Its arguments, as the JSON the guest will receive. */\n argsJson: unknown;\n /**\n * Monotonic per author **device**.\n *\n * Per device rather than per account because two devices of one account are\n * independent replicas: they cannot coordinate on a counter, so an\n * account-scoped sequence would have them refusing each other's warrants.\n */\n nonce: number | bigint;\n /**\n * Account-log heads this author saw when signing, each hex (32 bytes).\n *\n * Empty by default, and empty is the honest answer for a client that tracks\n * no log \u2014 a fabricated view is worse than none. At most\n * {@link MAX_CITED_HEADS}.\n */\n accountHeads?: string[];\n /**\n * Governance heads this author's view descended from, each hex (32 bytes).\n *\n * **Where these come from decides whether they mean anything.** A floor the\n * relay supplied is a floor the relay chose: a relay that withholds a\n * governance op can hand you a stale view and collect a warrant citing it.\n * Take the value from the account's own devices or a co-signing peer outside\n * the relay's operator. As it stands this detects an honest relay's staleness\n * and does not constrain a dishonest one.\n */\n governanceFloor?: string[];\n /** Unix seconds after which the relay must refuse it. */\n notAfter: number | bigint;\n /**\n * The author device's ed25519 signing secret, hex (32 bytes).\n *\n * Never sent anywhere. It signs locally and only the signature travels, which\n * is the whole reason a warrant can be minted by something holding no node.\n */\n deviceSecret: string;\n}\n\n\n\n\n\n\n\n/**\n * The commitment a warrant carries in place of the intent itself.\n *\n * Its own domain, distinct from the signing one, so a value computed for one\n * purpose cannot be presented for the other.\n */\nexport async function intentHash(\n method: string,\n argsJson: unknown,\n): Promise<Uint8Array> {\n const args = new TextEncoder().encode(JSON.stringify(argsJson));\n return domainHash(INTENT_DOMAIN, [new TextEncoder().encode(method), args]);\n}\n\n\n/**\n * Sign a warrant and return it hex-encoded, ready for `performIntent`.\n *\n * Returns the encoding rather than an object because the signature covers\n * exactly these bytes: a caller that rebuilt the fields from JSON would have a\n * second spelling able to disagree with what was signed.\n */\nexport async function signWarrant(input: WarrantInput): Promise<string> {\n const context = fromHex(input.context, 'context', 32);\n const authorAccount = fromHex(input.authorAccount, 'authorAccount', 32);\n const executor = fromHex(input.executor, 'executor', 32);\n const appVersion = fromHex(\n input.appVersion ?? UNPINNED_APP,\n 'appVersion',\n 32,\n );\n const accountHeads = citedHeads(input.accountHeads, 'accountHeads');\n const governanceFloor = citedHeads(input.governanceFloor, 'governanceFloor');\n\n const key = await importSigningKey(input.deviceSecret);\n const publicKey = await derivePublicKey(input.deviceSecret);\n\n const method = new TextEncoder().encode(input.method);\n const commitment = await intentHash(input.method, input.argsJson);\n const nonce = u64le(input.nonce);\n const notAfter = u64le(input.notAfter);\n\n // Each head list is preceded by its own count. `domainHash` length-prefixes\n // every part it is given, so the heads are individually unambiguous \u2014 but the\n // two lists are adjacent, so without the counts `accountHeads = [a, b],\n // governanceFloor = []` hashes identically to `[a], [b]`, and a relay could\n // relabel which plane a head was cited from. u64 HERE; u32 in the encoding.\n const preimage = await domainHash(SIGN_DOMAIN, [\n context,\n authorAccount,\n publicKey,\n executor,\n appVersion,\n method,\n commitment,\n u64le(accountHeads.length),\n ...accountHeads,\n u64le(governanceFloor.length),\n ...governanceFloor,\n nonce,\n notAfter,\n ]);\n\n const signature = new Uint8Array(\n await crypto.subtle.sign({ name: 'Ed25519' }, key, preimage),\n );\n\n // Borsh: a `String` is a u32 length then its UTF-8 bytes; a `Vec<[u8; 32]>` is\n // a u32 count then the elements. u32 HERE; u64 in the preimage above.\n return hex(\n concat(\n context,\n authorAccount,\n publicKey,\n executor,\n appVersion,\n u32le(method.length),\n method,\n commitment,\n u32le(accountHeads.length),\n ...accountHeads,\n u32le(governanceFloor.length),\n ...governanceFloor,\n nonce,\n notAfter,\n signature,\n ),\n );\n}\n\n/** Decode a cited-head list, refusing one longer than a node will accept. */\nfunction citedHeads(heads: string[] | undefined, label: string): Uint8Array[] {\n const list = heads ?? [];\n if (list.length > MAX_CITED_HEADS) {\n throw new Error(\n `${label} cites ${list.length} heads, over the ${MAX_CITED_HEADS} a node accepts`,\n );\n }\n return list.map((head, i) => fromHex(head, `${label}[${i}]`, 32));\n}\n\n/** A warrant's fields, as hex, decoded from the wire encoding. */\nexport interface WarrantFields {\n context: string;\n authorAccount: string;\n /** The author device key `signWarrant` derived from the secret. */\n deviceKey: string;\n executor: string;\n appVersion: string;\n method: string;\n intentHash: string;\n accountHeads: string[];\n governanceFloor: string[];\n /** u64 little-endian, as it sits on the wire. */\n nonce: string;\n /** u64 little-endian, as it sits on the wire. */\n notAfter: string;\n signature: string;\n}\n\n/**\n * Decode a hex warrant back into its fields.\n *\n * Exists because v2's offsets are no longer constants: `method` is a string and\n * the head lists are vectors, so everything after `appVersion` moves with the\n * method's length. Anything reading a warrant by fixed offset \u2014 a test, a client\n * inspecting one it was handed \u2014 silently reads the wrong field instead of\n * failing, which is how the three call sites that did so passed while comparing\n * the method's length prefix to a nonce.\n *\n * One copy of the layout, beside the encoder that produces it, so the two cannot\n * drift. Internal: not exported from the package root, because a client that\n * needs a warrant's fields has the input it signed.\n */\nexport function parseWarrant(warrant: string): WarrantFields {\n const at = (start: number, bytes: number) =>\n warrant.slice(start * 2, (start + bytes) * 2);\n // A borsh u32 is little-endian, so the hex pairs read back to front.\n const u32At = (start: number) =>\n Number.parseInt((at(start, 4).match(/../g) ?? []).reverse().join(''), 16);\n\n let o = 0;\n const take = (bytes: number) => {\n const field = at(o, bytes);\n o += bytes;\n return field;\n };\n\n const context = take(32);\n const authorAccount = take(32);\n const deviceKey = take(32);\n const executor = take(32);\n const appVersion = take(32);\n const methodLen = u32At(o);\n o += 4;\n const method = take(methodLen);\n const intentHashField = take(32);\n const accountCount = u32At(o);\n o += 4;\n const accountHeads = Array.from({ length: accountCount }, () => take(32));\n const governanceCount = u32At(o);\n o += 4;\n const governanceFloor = Array.from({ length: governanceCount }, () =>\n take(32),\n );\n const nonce = take(8);\n const notAfter = take(8);\n const signature = take(64);\n\n if (o * 2 !== warrant.length) {\n throw new Error(\n `warrant is ${warrant.length / 2} bytes but its fields account for ${o}`,\n );\n }\n\n return {\n context,\n authorAccount,\n deviceKey,\n executor,\n appVersion,\n method,\n intentHash: intentHashField,\n accountHeads,\n governanceFloor,\n nonce,\n notAfter,\n signature,\n };\n}\n", "/**\n * Write to a context through a relay, holding nothing but a signing key.\n *\n * # What this replaces\n *\n * `sdk.rpc.execute` asks a node to run a method *as itself*: it needs a node,\n * that node needs to be a member, and the caller needs a credential on it. For\n * a browser tab, a phone, or an agent, none of those three is available \u2014 the\n * runtime cannot compile WASM against materialized state, never received the\n * scope key that seals the deltas, and has no account on anybody's node.\n *\n * This client is the other path. The caller signs a warrant locally, the relay\n * runs the method as the *author's* principal, and the resulting delta is\n * attributed to the author's account and device \u2014 their replica slot, their\n * membership, their name in the app. The relay's key signs the envelope and\n * nothing else.\n *\n * # The three preconditions, and why they are checked in this order\n *\n * `describe()` answers the first two in one call, before anything is signed:\n * the relay's executor account (which the warrant must name) and whether it\n * holds `CAN_AUTHOR_ON_BEHALF` on the owning group. The third \u2014 that the\n * author's account is a member \u2014 only the group knows, and it surfaces as a\n * refusal.\n *\n * Checking before signing is not politeness. A warrant consumes a nonce from a\n * monotonic per-device sequence, and one minted against the wrong executor is\n * unspendable: the number is gone and the write never happened.\n */\n\nimport { signWarrant } from '../warrant/warrant.js';\nimport { HTTPError } from '../http-client/web-client.js';\nimport type { NonceSource } from './nonce-source.js';\n\n/** How long a freshly minted warrant stays presentable, in seconds. */\nconst DEFAULT_TTL_SECONDS = 300;\n\n/** Where and as whom to write, plus the key that consents. */\nexport interface RelayClientConfig {\n /**\n * The relay's base URL \u2014 the node's origin, not a path.\n *\n * Discover it from {@link CloudClient.getNamespaceRelays} for a hosted\n * namespace, or take it from the operator for a self-hosted one.\n */\n relayUrl: string;\n /**\n * The account the relay writes as, hex \u2014 a warrant's `executor`.\n *\n * An account rather than a key, so one of the relay's processes rotating its\n * signing key does not void warrants already issued to it. Left unset, the\n * first `execute` learns it from {@link RelayClient.describe}.\n */\n executorAccount?: string;\n /** The author's account, hex \u2014 whose consent the warrant carries. */\n authorAccount: string;\n /**\n * The author's `AccountProof<DeviceCert>`, hex-encoded borsh.\n *\n * Proves the key that signed the warrant is a device of the account it names.\n * The author sends only its own half; the relay attaches its own.\n */\n authorProof: string;\n /**\n * The author device's ed25519 signing secret, hex (32 bytes).\n *\n * Never transmitted. It signs in this process and only the signature leaves,\n * which is the whole reason a keyholder can author without a node.\n */\n deviceSecret: string;\n /** Where nonces come from. See {@link NonceSource} \u2014 a reset replays. */\n nonces: NonceSource;\n /**\n * Seconds a minted warrant stays valid. Defaults to 300.\n *\n * Checked by the relay against its own clock and deliberately never by peers,\n * so this bounds how long *this* request may sit in flight \u2014 not how long the\n * network will accept the delta.\n */\n ttlSeconds?: number;\n /** Injected for tests and non-browser runtimes. Defaults to global `fetch`. */\n fetch?: typeof fetch;\n timeoutMs?: number;\n}\n\n/** What a relay says about its ability to run intents in one context. */\nexport interface RelayDescription {\n /** The account a warrant must name as `executor`, hex. */\n executorAccount: string;\n /** Whether the relay holds `CAN_AUTHOR_ON_BEHALF` on the owning group. */\n canAuthorOnBehalf: boolean;\n /** The group whose admin grants that capability, hex. */\n groupId: string;\n}\n\n/** Where an accepted intent landed. */\nexport interface IntentResult<T = unknown> {\n /** The context's scope root after the run \u2014 did this change anything? */\n rootHash: string;\n /** The method's own return value. */\n returns: T | null;\n}\n\n/**\n * Thrown when a relay refuses an intent, carrying which precondition failed.\n *\n * The distinction is the whole reason this type exists. A `403` from this\n * endpoint means one of three unrelated things \u2014 no grant on the relay, the\n * author is not a member, or the nonce was already spent \u2014 and they send a\n * caller somewhere completely different: ask an admin, ask for an invitation,\n * or just retry. Collapsing them into \"forbidden\" makes a retryable replay look\n * like a permissions bug.\n */\nexport class IntentRefusedError extends Error {\n name = 'IntentRefusedError';\n\n constructor(\n /** The relay's own explanation, verbatim. */\n public readonly reason: string,\n /** `true` when re-presenting the same intent under a *fresh* warrant may work. */\n public readonly retryable: boolean,\n public readonly status: number,\n ) {\n super(`relay refused the intent (HTTP ${status}): ${reason}`);\n }\n}\n\nexport class RelayClient {\n private readonly baseUrl: string;\n private executorAccount: string | undefined;\n private readonly config: RelayClientConfig;\n private readonly fetchImpl: typeof fetch;\n private readonly timeoutMs: number;\n\n constructor(config: RelayClientConfig) {\n this.config = config;\n this.baseUrl = config.relayUrl.replace(/\\/+$/, '');\n this.executorAccount = config.executorAccount;\n const injected = config.fetch;\n this.fetchImpl = injected\n ? (input: RequestInfo | URL, init?: RequestInit) => injected(input, init)\n : (input: RequestInfo | URL, init?: RequestInit) => globalThis.fetch(input, init);\n this.timeoutMs = config.timeoutMs ?? 10_000;\n }\n\n /**\n * Ask the relay what it can do in `contextId`.\n *\n * Cheap and unauthenticated on a relay that serves delegated execution\n * publicly, which is what makes it usable as a precondition check rather than\n * as diagnostics after a failure.\n */\n async describe(contextId: string): Promise<RelayDescription> {\n const body = await this.json<{\n data: { executorAccount: string; canAuthorOnBehalf: boolean; groupId: string };\n }>('GET', `/admin-api/contexts/${encodeURIComponent(contextId)}/intents`);\n // Learned, not merely returned: a client that called `describe` should not\n // then have to pass the account back in to `execute`.\n this.executorAccount = body.data.executorAccount;\n return body.data;\n }\n\n /**\n * Mint a warrant for `method(args)` and present it to the relay.\n *\n * One intent, once: the warrant authorizes exactly this method and these\n * arguments in exactly this context, and its nonce is spent by the network on\n * apply. Nothing accumulates and nothing is reusable.\n */\n async execute<T = unknown>(\n contextId: string,\n method: string,\n argsJson: unknown = {},\n ): Promise<IntentResult<T>> {\n const executor = this.executorAccount ?? (await this.describe(contextId)).executorAccount;\n\n const nonce = await this.config.nonces.next();\n const ttl = this.config.ttlSeconds ?? DEFAULT_TTL_SECONDS;\n const warrant = await signWarrant({\n context: contextId,\n authorAccount: this.config.authorAccount,\n executor,\n method,\n argsJson,\n nonce,\n notAfter: BigInt(Math.floor(Date.now() / 1000)) + BigInt(ttl),\n deviceSecret: this.config.deviceSecret,\n });\n\n const body = await this.json<{ data: { rootHash: string; returns: T | null } }>(\n 'POST',\n `/admin-api/contexts/${encodeURIComponent(contextId)}/intents`,\n { method, argsJson, warrant, authorProof: this.config.authorProof },\n );\n return { rootHash: body.data.rootHash, returns: body.data.returns ?? null };\n }\n\n private async json<T>(method: string, path: string, body?: unknown): Promise<T> {\n const headers: Record<string, string> = { Accept: 'application/json' };\n if (body !== undefined) headers['Content-Type'] = 'application/json';\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n let response: Response;\n try {\n response = await this.fetchImpl(`${this.baseUrl}${path}`, {\n method,\n headers,\n body: body === undefined ? undefined : JSON.stringify(body),\n signal: controller.signal,\n });\n } catch (err) {\n throw new HTTPError(\n 0,\n err instanceof Error ? err.name : 'NetworkError',\n `${this.baseUrl}${path}`,\n new Headers(),\n err instanceof Error ? err.message : String(err),\n );\n } finally {\n clearTimeout(timer);\n }\n\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n // 400 and 403 are both caller preconditions and core separates them\n // deliberately: 400 means re-sending the same bytes cannot help, 403\n // means the bytes are genuine but authority is missing. Only the spent\n // nonce is worth retrying, and only under a fresh warrant.\n if (response.status === 400 || response.status === 403) {\n const reason = extractReason(text);\n throw new IntentRefusedError(reason, /nonce/i.test(reason), response.status);\n }\n throw new HTTPError(\n response.status,\n response.statusText,\n `${this.baseUrl}${path}`,\n response.headers,\n text,\n );\n }\n\n return (await response.json()) as T;\n }\n}\n\n/** Pull the relay's explanation out of its error body, or fall back to the raw text. */\nfunction extractReason(bodyText: string): string {\n if (!bodyText) return 'no reason given';\n try {\n const parsed = JSON.parse(bodyText) as { error?: unknown; message?: unknown };\n for (const candidate of [parsed.error, parsed.message]) {\n if (typeof candidate === 'string' && candidate) return candidate;\n }\n } catch {\n // Not JSON \u2014 the text itself is the best available explanation.\n }\n return bodyText;\n}\n", "/**\n * Where a warrant's nonce comes from.\n *\n * # Why this is a named concept and not a counter in the relay client\n *\n * A warrant's nonce is spent, once, per `(context, author device)` on every\n * node that applies the delta. So the sequence a client emits is not a local\n * detail \u2014 it is state the network remembers, and the client is the only party\n * that can keep it.\n *\n * The receiving ledger is a **sliding window** 64 wide, not a high-water mark,\n * which is what makes the two failure modes so different:\n *\n * - **Skipping** numbers is free. Gossip gives no ordering, so the window\n * exists precisely to accept whatever unseen nonce arrives.\n * - **Restarting** the sequence is fatal. A tab that reloads and resumes at `1`\n * re-presents nonces the network has already spent, and every one of those\n * writes is refused as a replay \u2014 indistinguishable, to the user, from the\n * app silently not saving.\n *\n * That asymmetry is why persistence is the default here and an in-memory source\n * is the one you have to ask for. It is also why a source may jump: reserving a\n * block and losing the tail is the correct trade.\n */\n\n/** Produces the next nonce for one author device. Must never go backwards. */\nexport interface NonceSource {\n next(): Promise<bigint>;\n}\n\n/**\n * A counter in memory, starting at `start`.\n *\n * Correct only for a process whose lifetime is the whole sequence \u2014 a script, a\n * server-side worker that owns its own device key, a test. In a browser tab it\n * resets on reload and replays; use {@link createLocalStorageNonceSource}\n * there.\n */\nexport function createMemoryNonceSource(start: number | bigint = 1): NonceSource {\n let next = BigInt(start);\n if (next < 1n) {\n throw new Error('nonce sequence starts at 1');\n }\n return {\n next(): Promise<bigint> {\n const value = next;\n next += 1n;\n return Promise.resolve(value);\n },\n };\n}\n\n/**\n * A counter persisted in `localStorage`, so a reload continues the sequence.\n *\n * Key it per author **device**, not per account: two devices of one account are\n * independent replicas with independent sequences, and sharing a counter would\n * have them refusing each other's warrants.\n *\n * **Reserve-then-hand-out.** The stored value is advanced *before* the nonce is\n * returned, so a crash between the two loses a number rather than reusing one.\n * Losing a number costs nothing (the window accepts gaps); reusing one costs a\n * write.\n *\n * Concurrent tabs are the case this cannot fully solve, because `localStorage`\n * has no atomic read-modify-write. Two tabs racing can hand out the same nonce,\n * and the loser's write is refused as a replay rather than silently\n * misattributed \u2014 a visible error, not corruption. An app that genuinely writes\n * from several tabs at once should hold a Web Lock around `next()` or give each\n * tab its own device.\n */\nexport function createLocalStorageNonceSource(\n key: string,\n storage?: { getItem(k: string): string | null; setItem(k: string, v: string): void },\n): NonceSource {\n const store =\n storage ?? (globalThis as unknown as { localStorage?: typeof storage }).localStorage;\n if (!store) {\n throw new Error(\n 'no localStorage in this runtime: pass a storage implementation, or use createMemoryNonceSource for a process that owns its whole sequence',\n );\n }\n return {\n next(): Promise<bigint> {\n const raw = store.getItem(key);\n // A missing, empty, or corrupted value means \"no sequence recorded\", and\n // the safe reading of that is not 1 \u2014 a cleared storage on a device that\n // has already written would replay. But the client cannot know, and 1 is\n // the only defensible start, so it is what a fresh key gets. This is why\n // the doc above tells apps to key per device: a device whose storage was\n // cleared should be re-paired rather than resumed.\n let current = 0n;\n if (raw !== null && raw !== '') {\n try {\n const parsed = BigInt(raw);\n if (parsed > 0n) current = parsed;\n } catch {\n current = 0n;\n }\n }\n const value = current + 1n;\n store.setItem(key, value.toString());\n return Promise.resolve(value);\n },\n };\n}\n", "/**\n * The second way to log in: sign in to Calimero Cloud instead of connecting to\n * a node.\n *\n * # Two connection shapes, one SDK\n *\n * `createMeroJs({ baseUrl })` is the node connection: point at a node, hold a\n * credential on it, and drive its admin API and JSON-RPC. It assumes the caller\n * has a node \u2014 their own, or one they have an account on.\n *\n * `connectCloud(...)` is for the caller who has neither. They sign in with the\n * identity they already use (Google, through the cloud), and the cloud answers\n * with an attested TEE relay serving their namespace. Writes then go through\n * delegated execution: signed here, run there, attributed here.\n *\n * The two are not alternatives to be picked at random \u2014 they answer different\n * questions. \"Which node do I talk to?\" has an answer for a desktop app and no\n * answer at all for a web app whose user has never installed anything. This\n * function is that missing answer, which is why the login step it replaces is\n * the *node URL prompt* rather than the authentication.\n *\n * # What it does not do\n *\n * It does not read state. A relay writes on the author's behalf; reads still\n * come from a node the client can query, or from the app's own projection of\n * the events it receives. `connectCloud` is deliberately narrow about this\n * rather than presenting a half-working `MeroJs` whose `admin` and `rpc` would\n * need a credential nobody holds.\n */\n\nimport { CloudClient } from './cloud-client.js';\nimport type { CloudClientConfig, CloudNamespace, CloudRelay } from './cloud-client.js';\nimport { RelayClient } from '../relay/relay-client.js';\nimport type { IntentResult, NonceSource } from '../relay/index.js';\nimport { createLocalStorageNonceSource, createMemoryNonceSource } from '../relay/nonce-source.js';\nimport { derivePublicKey, hex } from '../crypto/internal.js';\n\nexport interface ConnectCloudOptions {\n /** Defaults to the hosted cloud. */\n cloudBaseUrl?: string;\n /** A stored MDMA session token. Provide this or `googleIdToken`. */\n sessionToken?: string;\n /** A Google ID token to exchange for a session. Provide this or `sessionToken`. */\n googleIdToken?: string;\n /** Persist a new or rolling-refreshed session. See {@link CloudClientConfig.onSession}. */\n onSession?: CloudClientConfig['onSession'];\n\n /** The author's account, hex \u2014 whose writes these will be. */\n authorAccount: string;\n /** The author's `AccountProof<DeviceCert>`, hex-encoded borsh. */\n authorProof: string;\n /** The author device's ed25519 signing secret, hex. Never transmitted. */\n deviceSecret: string;\n\n /**\n * Which namespace to write in.\n *\n * Optional only when the user owns exactly one: guessing among several would\n * pick a tenant for them, and the failure would be a write landing in the\n * wrong place rather than an error.\n */\n namespaceId?: string;\n\n /**\n * Where nonces come from.\n *\n * Defaults to `localStorage`, keyed by the author's device public key, so a\n * reload continues the sequence instead of replaying it. Pass\n * {@link createMemoryNonceSource} explicitly for a process that owns its\n * whole sequence, or your own source to coordinate across tabs.\n */\n nonces?: NonceSource;\n /** Seconds a minted warrant stays presentable. Defaults to 300. */\n ttlSeconds?: number;\n fetch?: typeof fetch;\n timeoutMs?: number;\n}\n\n/** A signed-in cloud session with a relay ready to write through. */\nexport interface CloudConnection {\n /** The cloud API, for namespaces, billing, HA and sign-out. */\n cloud: CloudClient;\n /** The relay chosen for this namespace. */\n relay: RelayClient;\n /** The namespace writes will land in. */\n namespaceId: string;\n namespace: CloudNamespace;\n /** What the cloud reported about the chosen relay. */\n relayInfo: CloudRelay;\n /** Run one method in one context, on the author's behalf. */\n execute<T = unknown>(\n contextId: string,\n method: string,\n argsJson?: unknown,\n ): Promise<IntentResult<T>>;\n}\n\n/**\n * Sign in to the cloud and return a connection that can write.\n *\n * Throws rather than returning a half-usable connection, and the message says\n * which step is missing \u2014 no namespace, several to choose between, HA not\n * enabled, or no relay holding the authorship grant. Every one of those is\n * something the user has to go and do, and a client that reports them alike\n * cannot tell them what.\n */\nexport async function connectCloud(options: ConnectCloudOptions): Promise<CloudConnection> {\n if (!options.sessionToken && !options.googleIdToken) {\n throw new Error('connectCloud needs either a sessionToken or a googleIdToken');\n }\n\n const cloud = new CloudClient({\n cloudBaseUrl: options.cloudBaseUrl,\n sessionToken: options.sessionToken,\n onSession: options.onSession,\n fetch: options.fetch,\n timeoutMs: options.timeoutMs,\n });\n\n if (!options.sessionToken && options.googleIdToken) {\n await cloud.signInWithGoogle(options.googleIdToken);\n }\n\n const namespaces = await cloud.getMyNamespaces();\n const namespace = pickNamespace(namespaces, options.namespaceId);\n\n // One read, used for both the choice and the diagnostic. `findExecutingRelay`\n // would fetch again to explain itself, and a second call can disagree with the\n // first \u2014 reporting \"waiting for the grant\" about a relay that was already\n // usable a moment ago.\n const relays = await cloud.getNamespaceRelays(namespace.namespaceId);\n const relayInfo =\n relays.find((r) => r.authorshipReady && r.relayUrl !== null && r.executorAccount !== null) ??\n null;\n if (!relayInfo) {\n throw new Error(explainNoRelay(namespace, relays));\n }\n\n const relay = new RelayClient({\n // Checked by `findExecutingRelay`, which is the only thing that returns a\n // relay \u2014 narrowed here rather than re-validated, so the invariant lives in\n // one place.\n relayUrl: relayInfo.relayUrl as string,\n executorAccount: relayInfo.executorAccount as string,\n authorAccount: options.authorAccount,\n authorProof: options.authorProof,\n deviceSecret: options.deviceSecret,\n nonces: options.nonces ?? (await defaultNonceSource(options.deviceSecret)),\n ttlSeconds: options.ttlSeconds,\n fetch: options.fetch,\n timeoutMs: options.timeoutMs,\n });\n\n return {\n cloud,\n relay,\n namespaceId: namespace.namespaceId,\n namespace,\n relayInfo,\n execute: (contextId, method, argsJson) => relay.execute(contextId, method, argsJson),\n };\n}\n\n/** The one namespace to write in, or an error naming the actual ambiguity. */\nfunction pickNamespace(namespaces: CloudNamespace[], requested?: string): CloudNamespace {\n if (requested) {\n const found = namespaces.find((n) => n.namespaceId === requested);\n if (!found) {\n throw new Error(\n `this account owns no namespace ${requested}; it owns: ${\n namespaces.map((n) => n.namespaceId).join(', ') || '(none)'\n }`,\n );\n }\n return found;\n }\n if (namespaces.length === 0) {\n throw new Error(\n 'this account owns no namespaces in the cloud: claim one first, then enable HA on it so a relay is assigned',\n );\n }\n if (namespaces.length > 1) {\n throw new Error(\n `this account owns ${namespaces.length} namespaces \u2014 pass namespaceId to say which: ${namespaces\n .map((n) => n.namespaceId)\n .join(', ')}`,\n );\n }\n return namespaces[0];\n}\n\n/**\n * Why no relay can write here \u2014 the three states, kept apart.\n *\n * They are three different asks of the user (turn HA on, wait, or get an admin\n * to grant a capability) and one message for all of them would send them to\n * the wrong one.\n */\nfunction explainNoRelay(namespace: CloudNamespace, relays: CloudRelay[]): string {\n if (relays.length === 0) {\n return namespace.haStatus === 'enabled'\n ? `namespace ${namespace.namespaceId} has HA enabled but no relay has been assigned to it yet \u2014 retry shortly`\n : `namespace ${namespace.namespaceId} has no relays: enable HA on it in the cloud to have an attested node assigned`;\n }\n const waitingOnGrant = relays.filter((r) => !r.authorshipReady);\n if (waitingOnGrant.length === relays.length) {\n return (\n `every relay on namespace ${namespace.namespaceId} is waiting for the authorship grant: ` +\n `an admin of the namespace must grant CAN_AUTHOR_ON_BEHALF to ${\n waitingOnGrant.map((r) => r.executorAccount ?? r.peerId).join(', ') || 'the relay account'\n }`\n );\n }\n return `namespace ${namespace.namespaceId} has ${relays.length} relay(s), but none reported both a URL and an executor account yet \u2014 retry shortly`;\n}\n\n/**\n * A persisted nonce source keyed by the author's device public key.\n *\n * The key is the *public* key, derived locally: a per-device key is required\n * (two devices of one account are independent replicas) and the secret must\n * never end up in a storage key an extension or another script can enumerate.\n *\n * Falls back to memory where there is no `localStorage` \u2014 Node, a worker, an\n * edge runtime. Those are processes that own their whole sequence, which is\n * exactly the case a memory counter is correct for.\n */\nasync function defaultNonceSource(deviceSecret: string): Promise<NonceSource> {\n const key = `mero-js:warrant-nonce:${hex(await derivePublicKey(deviceSecret))}`;\n try {\n return createLocalStorageNonceSource(key);\n } catch {\n return createMemoryNonceSource(1);\n }\n}\n", "/**\n * Minting and certifying a device offline, with a key that never reaches a node.\n *\n * This is the second half of the keyholder story. `signWarrant` lets an account\n * with no node *write*; this lets one exist in the first place \u2014 an account root\n * certifies a device, and the resulting credential is what a joiner presents.\n *\n * As with the warrant signer, the risk is that this reproduces core's encoding\n * and has to keep doing so. The answer is the same: a golden vector here, and an\n * e2e that diffs this output against `merod account sign-cert` byte for byte.\n *\n * Everything below is derived from core:\n *\n * - `DeviceCert::signing_payload` \u2014 `crates/account/src/device.rs`\n * - `DeviceId::mint` \u2014 `crates/primitives/src/identity.rs`\n * - `AccountProof` / `AccountGenesis` borsh layout \u2014 `crates/account/src/{signed,account}.rs`\n */\nimport {\n concat,\n derivePublicKey,\n domainHash,\n fromHex,\n hex,\n importSigningKey,\n u32le,\n} from '../crypto/internal.js';\n\nconst CERT_DOMAIN = new TextEncoder().encode('calimero.device.cert.v1');\nconst ACCOUNT_ID_DOMAIN = new TextEncoder().encode('calimero.account.genesis.v1');\nconst DEVICE_ID_DOMAIN = new TextEncoder().encode('calimero.device.id.v1');\n\n/** `AccountGenesis::version`, which the credential's borsh encoding leads with. */\n/**\n * Core's `ACCOUNT_GENESIS_VERSION`. It is part of the `AccountId` preimage, so\n * this value decides which account a root key names \u2014 a mismatch does not fail\n * as a version error at the edge, it silently derives a different account and\n * core refuses the credential as unverifiable.\n *\n * `2` since the genesis dropped its per-namespace nonce. This was `1`, which\n * produced credentials current core rejects outright; the shape was already v2,\n * only the tag was stale.\n */\nconst ACCOUNT_GENESIS_VERSION = 2;\n\n/** What a root certifies about one device. */\nexport interface DeviceCertInput {\n /** The account root's signing secret, 64 hex. Signs the certificate. */\n rootSecret: string;\n /** The device being certified, 64 hex \u2014 see {@link mintDeviceId}. */\n device: string;\n /** The key that device signs with, 64 hex. */\n signPublicKey: string;\n /** The key the group key is delivered to, 64 hex (X25519). */\n kemPublicKey: string;\n /**\n * Must strictly exceed any epoch already folded for this device.\n *\n * The projection refuses a link that does not advance it, so a re-issued\n * certificate reusing an epoch is inert rather than a rollback.\n */\n deviceEpoch: number;\n}\n\n/**\n * Mint a device id: `H(DEVICE_ID_DOMAIN, account \u2016 nonce)`.\n *\n * Derived from the account and a fresh nonce rather than from the device's keys,\n * so rotating a keypair keeps the replica identity \u2014 and with it the counter\n * slots and HLC lineage \u2014 intact.\n */\nexport async function mintDeviceId(\n account: string,\n nonce: Uint8Array,\n): Promise<string> {\n if (nonce.length !== 16) {\n throw new Error(`nonce must be 16 bytes, got ${nonce.length}`);\n }\n const accountBytes = fromHex(account, 'account', 32);\n return hex(await domainHash(DEVICE_ID_DOMAIN, [accountBytes, nonce]));\n}\n\n/**\n * The 32 bytes a root signs to certify a device.\n *\n * Both keys are covered, so neither the signing key nor the delivery key can be\n * substituted into a certificate that otherwise verifies \u2014 which is what stops a\n * relay carrying someone's credential from making itself the reader.\n */\nexport async function deviceCertPayload(input: {\n account: string;\n device: string;\n signPublicKey: string;\n kemPublicKey: string;\n keyEpoch: number;\n deviceEpoch: number;\n}): Promise<Uint8Array> {\n return domainHash(CERT_DOMAIN, [\n fromHex(input.account, 'account', 32),\n fromHex(input.device, 'device', 32),\n fromHex(input.signPublicKey, 'signPublicKey', 32),\n fromHex(input.kemPublicKey, 'kemPublicKey', 32),\n u32le(input.keyEpoch),\n u32le(input.deviceEpoch),\n ]);\n}\n\n/**\n * Borsh-encode an `AccountProof<DeviceCert>` \u2014 what core calls a\n * `JoinAccountCredential`.\n *\n * Extracted so the device-cert path and the namespace-op signer encode this from\n * one implementation. Two copies of a borsh layout drift silently: the encoding\n * is only checked by a peer rejecting a signature, which points at the signature\n * rather than at whichever copy went stale.\n *\n * Layout is `AccountProof { genesis, chain, statement }`:\n * `AccountGenesis` (version u8 + root pk 32) + `chain` (empty Vec, u32 len) +\n * `DeviceCert` (account 32 + device 32 + sign pk 32 + kem pk 32 + key_epoch u32\n * + device_epoch u32 + signature 64) = 237 bytes with an empty chain.\n */\nexport function accountProofBytes(input: {\n rootPublicKey: Uint8Array;\n account: string;\n device: string;\n signPublicKey: string;\n kemPublicKey: string;\n keyEpoch: number;\n deviceEpoch: number;\n signature: Uint8Array;\n}): Uint8Array {\n return concat(\n new Uint8Array([ACCOUNT_GENESIS_VERSION]),\n input.rootPublicKey,\n u32le(0),\n fromHex(input.account, 'account', 32),\n fromHex(input.device, 'device', 32),\n fromHex(input.signPublicKey, 'signPublicKey', 32),\n fromHex(input.kemPublicKey, 'kemPublicKey', 32),\n u32le(input.keyEpoch),\n u32le(input.deviceEpoch),\n input.signature,\n );\n}\n\n/**\n * Certify a device, returning the hex credential `merod account sign-cert`\n * prints \u2014 a borsh-encoded `AccountProof<DeviceCert>`.\n *\n * The layout, field for field, is core's:\n *\n * ```\n * AccountProof { genesis: AccountGenesis, chain: Vec<RootKeyHandoff>, statement: DeviceCert }\n * AccountGenesis { version: u8, root_sign_pk: [u8; 32] }\n * chain \u2192 u32-LE count, then that many handoffs\n * DeviceCert { account, device, sign_pk, kem_pk: [u8; 32] x4,\n * key_epoch: u32, device_epoch: u32, signature: [u8; 64] }\n * ```\n *\n * Borsh for plain fixed-width data is concatenation; the only variable part is\n * the chain's length prefix. `chain` is empty here for the same reason it is in\n * `sign-cert`: a root that has never been handed off signs directly, and a\n * handoff chain is only needed once it has.\n *\n * `keyEpoch` is 0 for the same reason \u2014 it names the root epoch that signed, and\n * an un-rotated root is at 0. Re-signing after a handoff is a separate flow that\n * needs the chain, so this deliberately does not take it as an argument rather\n * than accepting a value it would then have to ignore.\n */\nexport async function signDeviceCert(input: DeviceCertInput): Promise<string> {\n const rootPublicKey = await derivePublicKey(input.rootSecret);\n const account = hex(\n await domainHash(ACCOUNT_ID_DOMAIN, [\n concat(new Uint8Array([ACCOUNT_GENESIS_VERSION]), rootPublicKey),\n ]),\n );\n\n const keyEpoch = 0;\n const payload = await deviceCertPayload({\n account,\n device: input.device,\n signPublicKey: input.signPublicKey,\n kemPublicKey: input.kemPublicKey,\n keyEpoch,\n deviceEpoch: input.deviceEpoch,\n });\n\n const key = await importSigningKey(input.rootSecret);\n const signature = new Uint8Array(\n await crypto.subtle.sign('Ed25519', key, payload),\n );\n\n const credential = accountProofBytes({\n rootPublicKey,\n account,\n device: input.device,\n signPublicKey: input.signPublicKey,\n kemPublicKey: input.kemPublicKey,\n keyEpoch,\n deviceEpoch: input.deviceEpoch,\n signature,\n });\n\n return hex(credential);\n}\n\n/** The account this root owns \u2014 the content address of its genesis. */\nexport async function accountForRoot(rootSecret: string): Promise<string> {\n const rootPublicKey = await derivePublicKey(rootSecret);\n return hex(\n await domainHash(ACCOUNT_ID_DOMAIN, [\n concat(new Uint8Array([ACCOUNT_GENESIS_VERSION]), rootPublicKey),\n ]),\n );\n}\n", "/**\n * Sign a namespace governance op from the SDK \u2014 specifically the membership op a\n * keyholder needs to join without running a node.\n *\n * `admitJoin` carries an already-signed op to a node the inviter named as an\n * admitter. Producing that op is the piece a keyholder could not do before: the\n * op must be signed by the device key in the credential it carries, because every\n * peer checks `signer == credential.statement.sign_pk` when applying a join. An\n * admitter can relay it and can never author it.\n *\n * The encoding is borsh, hand-written to match core's structs. Correctness is not\n * asserted against bytes recorded here \u2014 a layout transcribed by eye is exactly\n * how a golden ends up confidently wrong. It is asserted by a node accepting the\n * op, which is what the e2e does.\n */\nimport type { SignedGroupOpenInvitation } from '../admin-api/admin-types.js';\nimport {\n concat,\n derivePublicKey,\n fromHex,\n hex,\n importSigningKey,\n u32le,\n u64le,\n} from '../crypto/internal.js';\n\n/** Core's `SIGNED_NAMESPACE_OP_SCHEMA_VERSION`. A node refuses any other value. */\nexport const SIGNED_NAMESPACE_OP_SCHEMA_VERSION = 8;\n\n/** Domain prefixed to the signable bytes; core's `NAMESPACE_GOVERNANCE_SIGN_DOMAIN`. */\nconst NAMESPACE_SIGN_DOMAIN = new TextEncoder().encode('calimero.namespace.v1');\n\n/** `NamespaceOp::Root` is the first variant. */\nconst NAMESPACE_OP_ROOT = 0;\n\n/**\n * `RootOp` discriminants, in declaration order. Only the two join variants are\n * emitted here; the rest are listed so the numbering is checkable against core\n * rather than inferred from the two in use.\n */\nconst ROOT_OP = {\n GroupCreated: 0,\n GroupReparented: 1,\n GroupDeleted: 2,\n AdminChanged: 3,\n PolicyUpdated: 4,\n MemberJoined: 5,\n KeyDelivery: 6,\n MemberJoinedOpen: 7,\n MemberJoinedAt: 8,\n NamespaceCreated: 9,\n MemberJoinedViaTeeAttestation: 10,\n} as const;\n\n/** A required `[u8; 32]`, as JSON carries it: 32 byte values. */\nfunction bytes32(value: readonly number[], label: string): Uint8Array {\n if (value.length !== 32) {\n throw new Error(`${label} must be 32 bytes, got ${value.length}`);\n }\n return new Uint8Array(value);\n}\n\n/**\n * Borsh `Option<[u8; 32]>` from the byte array JSON carries it as.\n *\n * `[u8; 32]` crosses JSON as 32 numbers, not as hex \u2014 the hex spelling belongs to\n * `AccountId`, which has its own representation. Encoding one of these from a hex\n * string would silently produce the wrong 32 bytes.\n */\nfunction optionalBytes32(\n value: readonly number[] | null | undefined,\n label: string,\n): Uint8Array {\n if (value === null || value === undefined) {\n return new Uint8Array([0]);\n }\n if (value.length !== 32) {\n throw new Error(`${label} must be 32 bytes, got ${value.length}`);\n }\n return concat(new Uint8Array([1]), new Uint8Array(value));\n}\n\n/** Borsh `String`: u32 length then UTF-8 bytes. */\nfunction borshString(value: string): Uint8Array {\n const bytes = new TextEncoder().encode(value);\n return concat(u32le(bytes.length), bytes);\n}\n\n\n/**\n * Borsh-encode a `SignedGroupOpenInvitation`.\n *\n * Re-encoded rather than passed through, because it has to go inside the op that\n * gets signed. That makes this function version-locked to core: a field added to\n * the invitation and omitted here produces an op whose inner invitation no longer\n * matches the inviter's signature over it. That exact drift, in client-py, broke\n * 93 scenarios \u2014 the failure surfaces as `invalid invitation signature` and points\n * nowhere near the encoder.\n */\nexport function encodeSignedInvitation(signed: SignedGroupOpenInvitation): Uint8Array {\n const body = signed.invitation;\n const admitters = body.admitters ?? [];\n const admitterAddrs = signed.admitter_addrs ?? [];\n\n return concat(\n // GroupInvitationFromAdmin.\n //\n // `SignerId` and `ContextGroupId` cross JSON as 32 numbers; `AccountId`\n // crosses as hex. Same width, different spelling, and reading either the\n // wrong way yields 32 bytes that encode cleanly and verify as nothing.\n bytes32(body.inviter_identity, 'inviter_identity'),\n bytes32(body.group_id, 'group_id'),\n u64le(body.expiration_timestamp),\n bytes32(body.secret_salt, 'secret_salt'),\n new Uint8Array([body.invited_role]),\n u32le(admitters.length),\n ...admitters.map((a, i) => fromHex(a, `admitters[${i}]`, 32)),\n // ...then the enclosing SignedGroupOpenInvitation, in declaration order.\n // `inviter_account` sits between the signature and the addresses; putting it\n // anywhere else still encodes 32 bytes and still verifies as nothing.\n borshString(signed.inviter_signature),\n signed.inviter_account\n ? concat(new Uint8Array([1]), fromHex(signed.inviter_account, 'inviter_account', 32))\n : new Uint8Array([0]),\n // A `Vec<String>`, so each entry is a bare borsh string. This carried an\n // enum until core dropped the URL variant, and an enum writes a\n // discriminant byte ahead of each entry \u2014 encoding one here now would shift\n // every following byte and fail as `invalid invitation signature`, pointing\n // nowhere near this line.\n u32le(admitterAddrs.length),\n ...admitterAddrs.map(borshString),\n optionalBytes32(signed.application_id, 'application_id'),\n // Borsh order follows core's field order, where this is `bytecode_id`; the\n // JSON key is `app_key`, a rename covering both directions that core pins in\n // a test. Encoding by the Rust name would read `undefined` and emit a None\n // where the inviter signed a Some.\n optionalBytes32(signed.app_key, 'app_key'),\n );\n}\n\nexport interface SignMemberJoinInput {\n /** The namespace being joined, 64 hex. */\n readonly namespaceId: string;\n /** The account joining, 64 hex \u2014 the subject of the credential. */\n readonly member: string;\n /** The invitation, as the admin API returned it. */\n readonly invitation: SignedGroupOpenInvitation;\n /**\n * The joiner's `AccountProof<DeviceCert>`, hex \u2014 from `signDeviceCert`.\n *\n * Its `sign_pk` must be the public key of `deviceSecret`; a peer checks that\n * when applying the join and refuses otherwise.\n */\n readonly credential: string;\n /** The device signing secret, 64 hex. Must match the credential's `sign_pk`. */\n readonly deviceSecret: string;\n /**\n * Heads this op is written against. Empty means \"signed against an empty head\"\n * \u2014 which is NOT the same as genesis, and a node with a non-empty head will\n * reject it as stale rather than treat it as a first op.\n */\n readonly parentOpHashes?: readonly string[];\n /** Anti-replay nonce; a node keeps a window per signer. */\n readonly nonce: number | bigint;\n /**\n * When the join happened, unix seconds. Defaults to now.\n *\n * Carried only by `MemberJoinedAt`, which is the variant used whenever the\n * invitation expires \u2014 and since core clamps every invitation to\n * `MAX_INVITATION_VALIDITY_SECS`, that is every invitation. The variant is\n * inferred from the invitation rather than selected by a flag: an expiring\n * invitation joined with plain `MemberJoined` is refused at apply with\n * \"expiration is set but joined_at is absent\", which is not a mistake worth\n * leaving available.\n */\n readonly joinedAt?: number | bigint;\n}\n\n/**\n * Sign a `MemberJoined` (or `MemberJoinedAt`) namespace op and return it\n * borsh-encoded and hex \u2014 the `signedOp` that `admitJoin` takes.\n */\nexport async function signMemberJoinOp(input: SignMemberJoinInput): Promise<string> {\n const parents = input.parentOpHashes ?? [];\n const credential = fromHex(input.credential, 'credential', input.credential.length / 2);\n\n // An invitation that expires must be claimed with `MemberJoinedAt`, which\n // carries `joined_at` between the invitation and the credential. Choosing the\n // variant from the invitation keeps the two in step: the discriminant and the\n // presence of that field are one decision, and splitting them produces bytes\n // that decode into the wrong shape rather than failing to decode.\n const expires = BigInt(input.invitation.invitation.expiration_timestamp ?? 0) !== 0n;\n const joinedAt =\n input.joinedAt ?? BigInt(Math.floor(Date.now() / 1000));\n\n const rootOp = expires\n ? concat(\n new Uint8Array([ROOT_OP.MemberJoinedAt]),\n fromHex(input.member, 'member', 32),\n encodeSignedInvitation(input.invitation),\n u64le(joinedAt),\n credential,\n )\n : concat(\n new Uint8Array([ROOT_OP.MemberJoined]),\n fromHex(input.member, 'member', 32),\n encodeSignedInvitation(input.invitation),\n credential,\n );\n\n const op = concat(new Uint8Array([NAMESPACE_OP_ROOT]), rootOp);\n\n const key = await importSigningKey(input.deviceSecret);\n const signer = await derivePublicKey(input.deviceSecret);\n\n const signable = concat(\n new Uint8Array([SIGNED_NAMESPACE_OP_SCHEMA_VERSION]),\n fromHex(input.namespaceId, 'namespaceId', 32),\n u32le(parents.length),\n ...parents.map((p, i) => fromHex(p, `parentOpHashes[${i}]`, 32)),\n signer,\n u64le(input.nonce),\n op,\n );\n\n const signature = new Uint8Array(\n await crypto.subtle.sign('Ed25519', key, concat(NAMESPACE_SIGN_DOMAIN, signable)),\n );\n\n // The signed struct repeats the signable fields, then the signature, then the\n // admitter endorsement. The domain is a signing prefix only and is never part\n // of the encoded op.\n //\n // The endorsement is written as borsh `None` \u2014 a single `0x00` \u2014 and that is\n // the correct value from here, not a placeholder. It authorises the membership\n // and can only be signed by an account the invitation named as an admitter,\n // which a keyholder is not. The admitter attaches its own as it relays the op\n // through `admitJoin`.\n //\n // It sits outside `signable`, so it is outside this signature and outside the\n // op's id. That is what makes attaching it possible: the admitter changes\n // neither what was signed here nor which op this is.\n const unendorsed = new Uint8Array([0]);\n\n return hex(concat(signable, signature, unendorsed));\n}\n", "/**\n * Sign the statement a device key presents to obtain a session on a node.\n *\n * This is the half of password-free login that has to run where the device key\n * lives, and for the case delegated execution exists for that is a browser tab.\n * Until this module, the only thing that could produce a login statement was\n * `merod account login-statement` \u2014 which is to say, a client had to hold a node\n * to ask a node for a session.\n *\n * **What this gets you, and what it does not.** A statement proves a device key\n * asked for this session. It says nothing about which account that device\n * belongs to: that is the `AccountProof` travelling beside it, which the node\n * checks separately. Signing here and presenting no proof gets a 401 that looks\n * exactly like a bad signature.\n *\n * **The session key is minted by the caller, not here.** The device key signs\n * once, over a short-lived key the caller generates and keeps; that key does the\n * talking for the rest of the session, which is what keeps the device key off\n * the wire. Passing a key you do not hold the private half of produces a session\n * you cannot speak on.\n *\n * **`node` must come from something you pinned.** Not from the challenge\n * response, and not from any field the node itself chose \u2014 an attacker who can\n * answer on the node's behalf would otherwise pick what your device signs about,\n * which is the whole reason the field exists. Read it out of band from the node\n * operator.\n *\n * **The byte contract is pinned in core**, at\n * `crates/account/src/tests/login_wire_fixture.rs`, for the same reason the\n * warrant one is: `AUTH_LOGIN_SIGN_DOMAIN` is `pub(crate)` there and the field\n * order is implicit in a `derive`, so nothing on that side forces anyone to\n * notice this file depends on both. This module's test asserts the same vectors.\n */\n\nimport {\n concat,\n derivePublicKey,\n domainHash,\n fromHex,\n hex,\n importSigningKey,\n u32le,\n u64le,\n} from '../crypto/internal.js';\n\nconst SIGN_DOMAIN = new TextEncoder().encode('calimero.auth.login.v1');\n\n/**\n * The client surface a session is bound to.\n *\n * A session minted for one surface cannot be presented from another, so a single\n * compromised surface does not yield sessions usable everywhere.\n */\nexport type Audience =\n | {\n /**\n * A browser origin, spelled exactly as the browser spells it\n * (`https://host:port`, no trailing slash).\n *\n * Compared byte for byte by the node. Do not normalize it here: two\n * spellings of one origin would mean a verifier that disagrees with the\n * browser about which one a token was for. `location.origin` is already\n * the spelling you want.\n */\n kind: 'webOrigin';\n origin: string;\n }\n | {\n /** A signed native client, named by its code-signing identity. */\n kind: 'codeSigningId';\n id: string;\n }\n | {\n /**\n * A command-line client, which has no origin and no signing identity.\n *\n * Carries no payload deliberately: a string here would be an audience that\n * binds nothing while looking like it binds something.\n */\n kind: 'cli';\n };\n\n/** The borsh enum tag for each variant, in core's declaration order. */\nconst AUDIENCE_TAG: Record<Audience['kind'], number> = {\n webOrigin: 0,\n codeSigningId: 1,\n cli: 2,\n};\n\n/** The variant's payload as UTF-8 \u2014 empty for the payload-free `cli`. */\nfunction audienceBody(audience: Audience): Uint8Array {\n const encoder = new TextEncoder();\n switch (audience.kind) {\n case 'webOrigin':\n return encoder.encode(audience.origin);\n case 'codeSigningId':\n return encoder.encode(audience.id);\n case 'cli':\n return new Uint8Array(0);\n }\n}\n\n/**\n * What the audience contributes to the **signing preimage**: tag then body, with\n * no length between them.\n *\n * `domainHash` length-prefixes every part it is handed, so a length written here\n * would be counted twice and the preimage would verify nowhere. This is the one\n * field spelled differently in the two encodings \u2014 see {@link audienceWire}.\n */\nfunction audienceSigningBytes(audience: Audience): Uint8Array {\n return concat(\n Uint8Array.from([AUDIENCE_TAG[audience.kind]]),\n audienceBody(audience),\n );\n}\n\n/**\n * What the audience contributes to the **wire encoding**: the borsh enum tag,\n * then for the two payload-carrying variants a borsh `String` \u2014 its own `u32`\n * little-endian length, then the UTF-8.\n *\n * `cli` is a bare tag. Writing a `u32` zero after it instead produces four extra\n * bytes that a node reads as the start of the challenge, so the statement fails\n * as a bad signature rather than as a malformed one.\n */\nfunction audienceWire(audience: Audience): Uint8Array {\n const tag = Uint8Array.from([AUDIENCE_TAG[audience.kind]]);\n if (audience.kind === 'cli') {\n return tag;\n }\n const body = audienceBody(audience);\n return concat(tag, u32le(body.length), body);\n}\n\n/** What a device is asking for. */\nexport interface LoginStatementInput {\n /**\n * The node this session is for, hex (32 bytes) \u2014 its identity public key, as\n * you pinned it. See the module note: this must not come from the node.\n */\n node: string;\n /** The client surface the session is bound to. */\n audience: Audience;\n /** The challenge this node issued, hex (32 bytes). Proves freshness. */\n challenge: string;\n /**\n * The public half of the ephemeral key this session will speak with, hex (32\n * bytes). Minted per session by the caller and thrown away with it.\n */\n sessionKey: string;\n /** Unix seconds at signing. */\n issuedAt: number | bigint;\n /** Unix seconds after which the node must refuse it. */\n expiresAt: number | bigint;\n /**\n * The device's ed25519 signing secret, hex (32 bytes).\n *\n * Never sent anywhere. It signs locally and only the signature travels, which\n * is what lets a statement be minted by something holding no node.\n */\n deviceSecret: string;\n}\n\n/**\n * Sign a login statement and return it hex-encoded, ready to present with an\n * account proof.\n *\n * Returns the encoding rather than an object for the reason `signWarrant` does:\n * the signature covers exactly these bytes, and a caller that rebuilt the fields\n * from JSON would have a second spelling able to disagree with what was signed.\n */\nexport async function signLoginStatement(\n input: LoginStatementInput,\n): Promise<string> {\n const node = fromHex(input.node, 'node', 32);\n const challenge = fromHex(input.challenge, 'challenge', 32);\n const sessionKey = fromHex(input.sessionKey, 'sessionKey', 32);\n\n const key = await importSigningKey(input.deviceSecret);\n const deviceKey = await derivePublicKey(input.deviceSecret);\n\n const issuedAt = u64le(input.issuedAt);\n const expiresAt = u64le(input.expiresAt);\n\n const preimage = await domainHash(SIGN_DOMAIN, [\n node,\n audienceSigningBytes(input.audience),\n challenge,\n sessionKey,\n deviceKey,\n issuedAt,\n expiresAt,\n ]);\n\n const signature = new Uint8Array(\n await crypto.subtle.sign({ name: 'Ed25519' }, key, preimage),\n );\n\n return hex(\n concat(\n node,\n audienceWire(input.audience),\n challenge,\n sessionKey,\n deviceKey,\n issuedAt,\n expiresAt,\n signature,\n ),\n );\n}\n", "// Member capability bitmask constants \u2014 mirrors core's `MemberCapabilities`\n// (crates/context/config/src/lib.rs). The value stored per-member is a u32\n// bitmask. Core currently assigns bits 0..=9; bits 10 and above are unassigned\n// and may be claimed by future core versions, so an application MUST NOT\n// assume any particular bit is safe for its own use unless core documents it\n// as reserved for applications.\n\n/**\n * Capability bits as defined by core's `MemberCapabilities`.\n *\n * The per-member value is a u32 bitmask. Core currently assigns bits 0..=9\n * (the entries below); bits 10 and above are unassigned \u2014 do not repurpose\n * them for application data, as a future core release may claim them.\n */\nexport const CAPABILITIES = {\n CAN_CREATE_CONTEXT: 1 << 0,\n CAN_INVITE_MEMBERS: 1 << 1,\n CAN_JOIN_OPEN_SUBGROUPS: 1 << 2,\n MANAGE_MEMBERS: 1 << 3,\n MANAGE_APPLICATION: 1 << 4,\n CAN_CREATE_SUBGROUP: 1 << 5,\n CAN_DELETE_SUBGROUP: 1 << 6,\n CAN_MANAGE_VISIBILITY: 1 << 7,\n CAN_MANAGE_METADATA: 1 << 8,\n /**\n * Publish writes attributed to ANOTHER member, under a warrant that member\n * signed \u2014 the grant delegated execution runs on.\n *\n * Implied by nothing: not by membership, not by admin, and not propagated by\n * the subgroup-admit cascade. So every group is authorship-closed until an\n * admin sets this bit, and a relay without it is refused at\n * `performIntent` before anything executes. That is why it is worth naming\n * here rather than leaving callers to write `1 << 9`: a client granting it\n * has to be able to say what it is granting.\n */\n CAN_AUTHOR_ON_BEHALF: 1 << 9,\n} as const;\n\nexport type CapabilityName = keyof typeof CAPABILITIES;\nexport type CapabilityBit = (typeof CAPABILITIES)[CapabilityName];\n\n/**\n * Returns true if `mask` has every bit of `cap` set. Both operands are\n * coerced to unsigned 32-bit (`>>> 0`) before comparing so a high bit such\n * as `1 << 31` doesn't fall foul of `&` yielding a signed result.\n */\nexport function hasCap(mask: number, cap: number): boolean {\n const capU32 = cap >>> 0;\n return ((mask & capU32) >>> 0) === capU32;\n}\n\n/** Returns `mask` with every bit of `cap` set (u32-normalized). */\nexport function withCap(mask: number, cap: number): number {\n return (mask | cap) >>> 0;\n}\n\n/** Returns `mask` with every bit of `cap` cleared (u32-normalized). */\nexport function withoutCap(mask: number, cap: number): number {\n return (mask & ~cap) >>> 0;\n}\n", "/**\n * Local-node discovery.\n *\n * Calimero dev/desktop nodes expose a public, unauthenticated health endpoint\n * at `GET {nodeUrl}/admin-api/health` that returns `{ \"data\": { \"status\":\n * \"alive\" } }`. The most common local layouts run on a small, well-known set of\n * ports, so instead of forcing the user to type a URL we probe those ports and\n * offer whatever is actually running.\n */\n\n/**\n * Default ports probed when discovering local nodes. Covers the two-node dev\n * stacks used across the Calimero apps (RPC + alt ports for node1 / node2).\n */\nexport const DEFAULT_LOCAL_NODE_PORTS = [2428, 2429, 2528, 2529] as const;\n\n/** Host used to build local candidate URLs. */\nconst LOCAL_HOST = 'localhost';\n\n/** Per-probe timeout. A reachable local node answers almost instantly; a\n * closed port rejects fast, but a firewalled/black-holed one can hang, so we\n * cap each probe. */\nconst DEFAULT_PROBE_TIMEOUT_MS = 2000;\n\nexport interface DiscoverLocalNodesOptions {\n /** Ports to probe. Defaults to {@link DEFAULT_LOCAL_NODE_PORTS}. */\n ports?: readonly number[];\n /** Per-probe timeout in ms. Defaults to 2000. */\n timeoutMs?: number;\n /** Abort the whole discovery (e.g. when the modal closes). */\n signal?: AbortSignal;\n}\n\n/** Build the canonical base URL for a local node on the given port. */\nexport function localNodeUrl(port: number): string {\n return `http://${LOCAL_HOST}:${port}`;\n}\n\n/**\n * Resolve an API `path` against a node `baseUrl`. Ensures the base ends with a\n * slash first, so a base that carries a path prefix (e.g. a `NODE_PATH_PREFIX`\n * deployment like `http://host/node1`) keeps that segment instead of having it\n * stripped by relative URL resolution.\n */\nexport function nodeEndpoint(baseUrl: string, path: string): string {\n const base = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;\n return new URL(path, base).toString();\n}\n\n/**\n * Probe a single node's health endpoint. Resolves `true` only when the node\n * answers with a 2xx and (when the body is JSON) reports a non-dead status.\n * Any network error, timeout, or non-ok response resolves `false` \u2014 never\n * throws (except on an external abort, which is swallowed as `false`).\n */\nexport async function probeNodeHealth(\n baseUrl: string,\n options: { timeoutMs?: number; signal?: AbortSignal } = {},\n): Promise<boolean> {\n const { timeoutMs = DEFAULT_PROBE_TIMEOUT_MS, signal } = options;\n\n // Already cancelled before we start \u2014 don't fetch, and don't register a\n // timer or listener that would then need cleanup.\n if (signal?.aborted) return false;\n\n // Per-probe timeout, also linked to the caller's abort signal so closing the\n // modal cancels every in-flight probe. Bind the signal to a local so the\n // cleanup below stays symmetric with registration without re-narrowing.\n const controller = new AbortController();\n const onAbort = () => controller.abort();\n const abortSignal = signal;\n if (abortSignal) abortSignal.addEventListener('abort', onAbort, { once: true });\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n const url = nodeEndpoint(baseUrl, 'admin-api/health');\n const res = await fetch(url, {\n method: 'GET',\n signal: controller.signal,\n });\n\n if (!res.ok) return false;\n\n // Health body is `{ data: { status: \"alive\" } }`, but tolerate plain\n // `{ status }` and non-JSON 2xx responses. A *missing* status is treated as\n // alive (the 2xx is enough); a status that is present but not \"alive\"\n // (including an explicit `null`) is treated as unhealthy.\n try {\n const body = (await res.json()) as\n | { data?: { status?: string | null }; status?: string | null }\n | undefined;\n const status =\n body?.data?.status !== undefined ? body?.data?.status : body?.status;\n if (status === undefined) return true;\n return typeof status === 'string' && status.toLowerCase() === 'alive';\n } catch {\n return true;\n }\n } catch {\n return false;\n } finally {\n clearTimeout(timer);\n if (abortSignal) abortSignal.removeEventListener('abort', onAbort);\n }\n}\n\n/**\n * Probe the configured local ports in parallel and return the base URLs that\n * responded as healthy, in the same order as the `ports` argument (which\n * defaults to ascending). Returns an empty array when nothing local is running.\n */\nexport async function discoverLocalNodes(\n options: DiscoverLocalNodesOptions = {},\n): Promise<string[]> {\n const { ports = DEFAULT_LOCAL_NODE_PORTS, timeoutMs, signal } = options;\n\n const results = await Promise.all(\n ports.map(async (port) => {\n const url = localNodeUrl(port);\n const ok = await probeNodeHealth(url, { timeoutMs, signal });\n return ok ? url : null;\n }),\n );\n\n return results.filter((url): url is string => url !== null);\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["TERMINAL_AUTH_ERRORS", "SIGN_DOMAIN"]
|
|
3
|
+
"sources": ["../src/index.ts", "../src/http-client/signal-utils.ts", "../src/http-client/web-client.ts", "../src/http-client/http-factory.ts", "../src/http-client/retry.ts", "../src/auth-api/auth-client.ts", "../src/auth-api/auth-factory.ts", "../src/admin-api/admin-client.ts", "../src/admin-api/admin-factory.ts", "../src/auth/index.ts", "../src/rpc/index.ts", "../src/events/group.ts", "../src/events/sse.ts", "../src/events/ws.ts", "../src/ephemeral/codec.ts", "../src/ephemeral/index.ts", "../src/cloud/cloud-client.ts", "../src/mero-js.ts", "../src/token-store/index.ts", "../src/crypto/internal.ts", "../src/warrant/warrant.ts", "../src/relay/relay-client.ts", "../src/relay/nonce-source.ts", "../src/cloud/connect.ts", "../src/device-cert/device-cert.ts", "../src/namespace-op/namespace-op.ts", "../src/login/login.ts", "../src/login/session.ts", "../src/capabilities.ts", "../src/nodeDiscovery.ts"],
|
|
4
|
+
"sourcesContent": ["// Mero.js - Pure JavaScript SDK for Calimero\n// This will contain the pure JavaScript SDK without React dependencies\n\n// Main SDK class\nexport { MeroJs, createMeroJs } from './mero-js.js';\nexport type { MeroJsConfig, TokenData } from './mero-js.js';\n\n// HTTP client module (Web Standards based)\nexport * from './http-client/index.js';\n\n// Auth API client\nexport * from './auth-api/index.js';\n\n// Admin API client\nexport * from './admin-api/index.js';\n\n// Auth utilities\nexport { parseAuthCallback, buildAuthLoginUrl } from './auth/index.js';\nexport type { AuthCallbackResult, AuthLoginOptions } from './auth/index.js';\n\n// Token store\nexport { MemoryTokenStore, LocalStorageTokenStore } from './token-store/index.js';\nexport type { TokenStore } from './token-store/index.js';\n\n// RPC client\nexport { RpcClient, RpcError } from './rpc/index.js';\nexport type { MigrateMyEntriesSummary } from './rpc/index.js';\nexport type { ExecuteParams } from './rpc/index.js';\n\n// Events (SSE / WebSocket)\nexport { SseClient, WsClient } from './events/index.js';\nexport type {\n SseEventData,\n WsEventData,\n AppVersionChangedEvent,\n GroupMembershipEventData,\n GroupMigrationEventData,\n MigrationStartedData,\n MigrationProgressData,\n CascadeProgressData,\n MigrationCompletedData,\n} from './events/index.js';\n\n// Ephemeral presence (cursors / typing / online)\nexport { EphemeralClient, jsonCodec } from './ephemeral/index.js';\nexport type { Codec, EphemeralEntry } from './ephemeral/index.js';\n\n// Cloud client \u2014 namespaces, relays, HA, and the cloud sign-in path\nexport * from './cloud/index.js';\n\n// Relay client \u2014 write through delegated execution, holding only a signing key\nexport * from './relay/index.js';\n\n// Warrant signing \u2014 mint the author's consent for a relay to run one intent\nexport { signWarrant, intentHash } from './warrant/index.js';\nexport {\n signDeviceCert,\n mintDeviceId,\n deviceCertPayload,\n accountForRoot,\n} from './device-cert/index.js';\nexport type { DeviceCertInput } from './device-cert/index.js';\nexport {\n signMemberJoinOp,\n encodeSignedInvitation,\n SIGNED_NAMESPACE_OP_SCHEMA_VERSION,\n} from './namespace-op/index.js';\nexport type { SignMemberJoinInput } from './namespace-op/index.js';\nexport type { WarrantInput } from './warrant/index.js';\n\n// Login-statement signing \u2014 the device's half of a password-free session\nexport { signLoginStatement } from './login/index.js';\nexport type { Audience, LoginStatementInput } from './login/index.js';\nexport { login, generateSessionKey } from './login/index.js';\nexport type {\n LoginConfig,\n DelegatedSession,\n SessionKeyPair,\n} from './login/index.js';\n\n// Member capability bitmask constants & helpers\nexport * from './capabilities.js';\n\n// Utilities\nexport {\n DEFAULT_LOCAL_NODE_PORTS,\n localNodeUrl,\n nodeEndpoint,\n probeNodeHealth,\n discoverLocalNodes,\n} from './nodeDiscovery.js';\nexport type { DiscoverLocalNodesOptions } from './nodeDiscovery.js';\n", "// Utility for combining multiple AbortSignals\nexport function combineSignals(\n signals: Array<AbortSignal | undefined>,\n): AbortSignal | undefined {\n const list = signals.filter(Boolean) as AbortSignal[];\n if (list.length === 0) return undefined;\n\n // Prefer native any(), but fall back if unavailable or it throws\n const AbortSignalAny = AbortSignal as {\n any?: (signals: AbortSignal[]) => AbortSignal;\n };\n if (typeof AbortSignalAny.any === 'function') {\n try {\n return AbortSignalAny.any(list);\n } catch {\n // Fall through to manual implementation\n }\n }\n\n const controller = new AbortController();\n const onAbort = (evt: Event) => {\n controller.abort((evt.target as AbortSignal).reason);\n for (const s of list) s.removeEventListener('abort', onAbort);\n };\n\n for (const s of list) {\n if (s.aborted) return AbortSignal.abort(s.reason);\n s.addEventListener('abort', onAbort, { once: true });\n }\n\n return controller.signal;\n}\n\n// Helper to create a timeout signal\nexport function createTimeoutSignal(timeoutMs: number): AbortSignal {\n // Use AbortSignal.timeout if available (Node 18.17+, modern browsers)\n if (typeof AbortSignal.timeout === 'function') {\n return AbortSignal.timeout(timeoutMs);\n }\n\n // Fallback for older environments\n const controller = new AbortController();\n setTimeout(() => {\n controller.abort(new DOMException('Timeout', 'TimeoutError'));\n }, timeoutMs);\n\n return controller.signal;\n}\n", "// ErrorResponse import removed as it's not used\nimport {\n HttpClient,\n Transport,\n RequestOptions,\n ResponseParser,\n} from './http-types.js';\nimport { combineSignals, createTimeoutSignal } from './signal-utils.js';\n\n/**\n * `x-auth-error` reasons that mean the whole token family is gone.\n *\n * Refresh tokens are single-use (calimero-network/core#3083): presenting a\n * consumed refresh token is treated as token theft and the server revokes the\n * family. Refreshing or retrying afterwards is pointless \u2014 the only way out is\n * a fresh login.\n */\nconst TERMINAL_AUTH_ERRORS = new Set(['token_reuse', 'token_revoked']);\n\n/**\n * Pull the node's explanation out of an error body. Core answers every handled\n * failure with `{\"error\": \"<message>\"}` (`ApiError::into_response`); the nested\n * `{\"error\": {\"message\": ...}}` form is what proxies in front of a node emit.\n * Returns undefined for a non-JSON, empty, or envelope-less body.\n */\nfunction extractErrorMessage(bodyText?: string): string | undefined {\n if (!bodyText) return undefined;\n try {\n const error = (JSON.parse(bodyText) as { error?: unknown })?.error;\n if (typeof error === 'string' && error.trim() !== '') return error;\n const nested = (error as { message?: unknown } | null)?.message;\n if (typeof nested === 'string' && nested.trim() !== '') return nested;\n } catch {\n // Not JSON \u2014 the status line is all we can honestly report.\n }\n return undefined;\n}\n\n// Custom error class for HTTP errors\nexport class HTTPError extends Error {\n name = 'HTTPError';\n\n constructor(\n public status: number,\n public statusText: string,\n public url: string,\n public headers: Headers,\n public bodyText?: string, // cap at ~64KB\n ) {\n const explanation = extractErrorMessage(bodyText);\n super(\n explanation\n ? `HTTP ${status} ${statusText}: ${explanation}`\n : `HTTP ${status} ${statusText}`,\n );\n }\n\n toJSON(): {\n status: number;\n statusText: string;\n url: string;\n headers: Record<string, string>;\n bodyText?: string;\n } {\n return {\n status: this.status,\n statusText: this.statusText,\n url: this.url,\n headers: headersToRecord(this.headers),\n bodyText: this.bodyText,\n };\n }\n}\n\n/**\n * Terminal authentication error: the refresh-token family was revoked (single-use\n * refresh token replayed, or the token was explicitly revoked). Never retried and\n * never refreshed \u2014 apps should catch this and force a re-login.\n *\n * Extends {@link HTTPError} so existing `instanceof HTTPError` handling keeps working.\n */\nexport class AuthRevokedError extends HTTPError {\n name = 'AuthRevokedError';\n\n constructor(\n /** Value of the `x-auth-error` header, e.g. `token_reuse` or `token_revoked`. */\n public reason: string,\n status: number,\n statusText: string,\n url: string,\n headers: Headers,\n bodyText?: string,\n ) {\n super(status, statusText, url, headers, bodyText);\n this.message = `Authentication revoked (${reason}): HTTP ${status} ${statusText}`;\n }\n}\n\n// Helper function to convert Headers to Record\nfunction headersToRecord(headers: Headers): Record<string, string> {\n const record: Record<string, string> = {};\n headers.forEach((value, key) => {\n record[key] = value;\n });\n return record;\n}\n\n// Web Standards HTTP client implementation\nexport class WebHttpClient implements HttpClient {\n // Cache for concurrent refresh token calls to prevent race conditions\n private refreshTokenPromise: Promise<string> | null = null;\n // Cache for concurrent onTokenRefresh calls to prevent duplicate callbacks\n private onTokenRefreshPromise: Promise<void> | null = null;\n \n constructor(private transport: Transport) {}\n\n async get<T>(path: string, init?: RequestOptions): Promise<T> {\n return this.request<T>(path, { ...init, method: 'GET' });\n }\n\n async post<T>(\n path: string,\n body?: unknown,\n init?: RequestOptions,\n ): Promise<T> {\n return this.request<T>(path, {\n ...init,\n method: 'POST',\n body: body ? JSON.stringify(body) : undefined,\n headers: {\n 'Content-Type': 'application/json',\n ...init?.headers,\n },\n });\n }\n\n async put<T>(\n path: string,\n body?: unknown,\n init?: RequestOptions,\n ): Promise<T> {\n return this.request<T>(path, {\n ...init,\n method: 'PUT',\n body: body ? JSON.stringify(body) : undefined,\n headers: {\n 'Content-Type': 'application/json',\n ...init?.headers,\n },\n });\n }\n\n async delete<T>(path: string, init?: RequestOptions): Promise<T> {\n return this.request<T>(path, { ...init, method: 'DELETE' });\n }\n\n async patch<T>(\n path: string,\n body?: unknown,\n init?: RequestOptions,\n ): Promise<T> {\n return this.request<T>(path, {\n ...init,\n method: 'PATCH',\n body: body ? JSON.stringify(body) : undefined,\n headers: {\n 'Content-Type': 'application/json',\n ...init?.headers,\n },\n });\n }\n\n async head(\n path: string,\n init?: RequestOptions,\n ): Promise<{ headers: Record<string, string>; status: number }> {\n const response = await this.makeRequest<Response>(path, {\n ...init,\n method: 'HEAD',\n parse: 'response',\n });\n return {\n headers: headersToRecord(response.headers),\n status: response.status,\n };\n }\n\n async request<T>(path: string, init?: RequestOptions): Promise<T> {\n return this.makeRequest<T>(path, init);\n }\n\n private async makeRequest<T>(\n path: string,\n init?: RequestOptions,\n retryCount = 0,\n requestStartTime?: number,\n ): Promise<T> {\n // Maximum retry attempts to prevent infinite loops\n const MAX_RETRY_ATTEMPTS = 1;\n const url = this.buildUrl(path);\n \n // Track request start time for timeout calculation (only on first attempt)\n // Use per-request start time to avoid corruption from concurrent requests\n const startTime = requestStartTime ?? Date.now();\n // Note: Tauri proxy script now handles AbortSignal, so we can use full RequestInit\n // Removed Tauri-specific minimal path - proxy script handles AbortSignal properly\n const signal = this.createAbortSignal(init);\n const headers = await this.buildHeaders(init?.headers);\n let headersObj: Record<string, string>;\n if (headers instanceof Headers) {\n headersObj = {};\n headers.forEach((value, key) => {\n headersObj[key] = value;\n });\n } else {\n headersObj = headers;\n }\n \n const requestInit: RequestInit = {\n method: init?.method || 'GET',\n headers: headersObj,\n };\n \n // Check if body is a stream (ReadableStream) that can't be reused\n // Note: Blob is reusable, so it's not included here\n const isStreamBody = init?.body instanceof ReadableStream ||\n (typeof init?.body === 'object' && init?.body !== null && 'getReader' in init.body && !(init.body instanceof Blob));\n \n if (init?.body !== undefined && !isStreamBody) {\n requestInit.body = init.body;\n } else if (init?.body !== undefined && isStreamBody && retryCount === 0) {\n // Only include stream body on first attempt - can't retry with streams\n requestInit.body = init.body;\n }\n \n // For retries, calculate remaining timeout to prevent timeout reset\n // Track elapsed time and use remaining timeout for retry\n // Note: This is calculated before the request, so it doesn't include token refresh time\n // The actual remaining timeout check happens after token refresh completes\n let retrySignal: AbortSignal | undefined;\n if (retryCount > 0 && requestStartTime !== undefined) {\n const timeoutMs = init?.timeoutMs || this.transport.timeoutMs;\n if (timeoutMs) {\n // Calculate elapsed time (will be recalculated after token refresh if needed)\n const elapsed = Date.now() - startTime;\n const remaining = Math.max(0, timeoutMs - elapsed);\n // Create signal with remaining timeout, preserving user's signal\n retrySignal = this.createAbortSignal({ ...init, timeoutMs: remaining });\n } else {\n // No timeout, just preserve user's signal\n retrySignal = this.createAbortSignal(init);\n }\n } else {\n retrySignal = signal;\n }\n \n if (retrySignal) {\n requestInit.signal = retrySignal;\n }\n \n if (this.transport.credentials !== undefined) {\n requestInit.credentials = this.transport.credentials;\n }\n \n if (init?.mode !== undefined) {\n requestInit.mode = init.mode;\n }\n if (init?.cache !== undefined) {\n requestInit.cache = init.cache;\n }\n if (init?.redirect !== undefined) {\n requestInit.redirect = init.redirect;\n }\n if (init?.referrer !== undefined) {\n requestInit.referrer = init.referrer;\n }\n if (init?.referrerPolicy !== undefined) {\n requestInit.referrerPolicy = init.referrerPolicy;\n }\n if (init?.integrity !== undefined) {\n requestInit.integrity = init.integrity;\n }\n if (init?.keepalive !== undefined) {\n requestInit.keepalive = init.keepalive;\n }\n\n try {\n const response = await this.transport.fetch(url, requestInit);\n\n if (!response.ok) {\n const bodyText = await this.getBodyText(response);\n const httpError = new HTTPError(\n response.status,\n response.statusText,\n url,\n response.headers,\n bodyText,\n );\n\n // Handle a revoked token family (single-use refresh token replayed, or an\n // explicitly revoked token). This is terminal: refreshing would only burn\n // another token and retrying would 401 again, so clear the tokens via the\n // onAuthRevoked hook and surface a distinguishable error.\n const authError = response.headers.get('x-auth-error');\n if (\n (response.status === 401 || response.status === 403) &&\n authError &&\n TERMINAL_AUTH_ERRORS.has(authError)\n ) {\n // Any in-flight refresh is based on a now-dead family \u2014 drop the caches.\n this.refreshTokenPromise = null;\n this.onTokenRefreshPromise = null;\n\n if (this.transport.onAuthRevoked) {\n try {\n await this.transport.onAuthRevoked();\n } catch {\n // Never mask the auth error with a cleanup failure.\n }\n }\n\n throw new AuthRevokedError(\n authError,\n response.status,\n response.statusText,\n url,\n response.headers,\n bodyText,\n );\n }\n\n // Handle 401 with token_expired - attempt automatic token refresh\n const userAborted = init?.signal?.aborted === true;\n if (\n response.status === 401 &&\n this.transport.refreshToken &&\n authError === 'token_expired' &&\n retryCount < MAX_RETRY_ATTEMPTS &&\n !isStreamBody &&\n !userAborted\n ) {\n try {\n // Use cached refresh promise if one is in progress (prevents race conditions)\n let refreshPromise = this.refreshTokenPromise;\n if (!refreshPromise) {\n refreshPromise = this.transport.refreshToken();\n this.refreshTokenPromise = refreshPromise;\n }\n \n // Attempt to refresh the token\n const newToken = await refreshPromise;\n \n // Validate token - must be non-empty\n if (!newToken || newToken.trim() === '') {\n // Clear caches on error\n this.refreshTokenPromise = null;\n this.onTokenRefreshPromise = null;\n throw new Error('Refresh token returned empty token');\n }\n \n // onTokenRefresh is required when refreshToken is provided\n // Without it, the new token cannot be stored and getAuthToken() will return the old token\n if (!this.transport.onTokenRefresh) {\n // Clear caches on error\n this.refreshTokenPromise = null;\n this.onTokenRefreshPromise = null;\n throw new Error(\n 'onTokenRefresh callback is required when refreshToken is provided. ' +\n 'The callback must update the token storage so getAuthToken() returns the new token.'\n );\n }\n \n // Use cached onTokenRefresh promise if one is in progress (prevents duplicate callbacks)\n // This ensures onTokenRefresh is only called once per token refresh, even with concurrent requests\n let onTokenRefreshPromise = this.onTokenRefreshPromise;\n if (!onTokenRefreshPromise) {\n onTokenRefreshPromise = this.transport.onTokenRefresh(newToken);\n this.onTokenRefreshPromise = onTokenRefreshPromise;\n }\n \n // Update token via callback (only called once per refresh, even with concurrent requests)\n // Errors from onTokenRefresh callback should be preserved (don't mask as 401)\n // This helps developers debug token storage issues\n await onTokenRefreshPromise;\n \n // Clear caches after both refresh and callback complete\n this.refreshTokenPromise = null;\n this.onTokenRefreshPromise = null;\n \n // Check if timeout has expired during token refresh\n // If so, throw the original 401 error instead of retrying with 0ms timeout\n // This prevents timeout/abort errors that obscure the root cause (expired token)\n const timeoutMs = init?.timeoutMs || this.transport.timeoutMs;\n if (timeoutMs && requestStartTime !== undefined) {\n const elapsed = Date.now() - startTime;\n const remaining = timeoutMs - elapsed;\n if (remaining <= 0) {\n // Timeout expired during token refresh - throw original 401 error\n // This is better than retrying with 0ms timeout which would cause confusing timeout errors\n throw httpError;\n }\n }\n \n // Retry the request with the new token (increment retry count)\n // Preserve user's abort signal and start time in retry\n return this.makeRequest<T>(path, init, retryCount + 1, startTime);\n } catch (refreshError) {\n // Clear caches on error\n this.refreshTokenPromise = null;\n this.onTokenRefreshPromise = null;\n // Configuration errors (missing onTokenRefresh) should be thrown as-is\n if (refreshError instanceof Error && refreshError.message.includes('onTokenRefresh')) {\n throw refreshError;\n }\n // Errors from onTokenRefresh callback are already thrown above, so if we get here,\n // it's either a refreshToken() failure or empty token - throw original 401\n // This matches the PR description: \"If refresh fails, throws the original 401 error\"\n throw httpError;\n }\n }\n\n throw httpError;\n }\n\n return this.parseResponse<T>(response, init?.parse);\n } catch (error) {\n if (error instanceof HTTPError) {\n throw error;\n }\n // Preserve configuration errors (like missing onTokenRefresh)\n if (error instanceof Error && error.message.includes('onTokenRefresh')) {\n throw error;\n }\n throw new HTTPError(\n 0,\n 'Network Error',\n url,\n new Headers(),\n error instanceof Error ? error.message : 'Unknown error',\n );\n }\n }\n\n private buildUrl(path: string): string {\n // Handle absolute URLs\n if (path.startsWith('http://') || path.startsWith('https://')) {\n return path;\n }\n\n // Handle baseUrl with path\n const baseUrl = this.transport.baseUrl;\n if (path.startsWith('/')) {\n // If path starts with /, combine with baseUrl\n const base = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;\n return `${base}${path}`;\n } else {\n // If path doesn't start with /, append to baseUrl\n const base = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;\n return `${base}${path}`;\n }\n }\n\n private createAbortSignal(init?: RequestOptions): AbortSignal | undefined {\n const signals: AbortSignal[] = [];\n\n if (this.transport.defaultAbortSignal) {\n signals.push(this.transport.defaultAbortSignal);\n }\n\n if (init?.signal) {\n signals.push(init.signal);\n }\n\n const timeoutMs = init?.timeoutMs || this.transport.timeoutMs;\n if (timeoutMs) {\n signals.push(createTimeoutSignal(timeoutMs));\n }\n\n return signals.length > 0 ? combineSignals(signals) : undefined;\n }\n\n private async buildHeaders(\n initHeaders?: HeadersInit,\n ): Promise<Record<string, string>> {\n const headers: Record<string, string> = {\n ...this.transport.defaultHeaders,\n };\n\n // Add auth token if available and not empty\n if (this.transport.getAuthToken) {\n try {\n const token = await this.transport.getAuthToken();\n if (token && token.trim() !== '') {\n headers.Authorization = `Bearer ${token}`;\n }\n } catch (error) {\n // Ignore auth token errors\n }\n }\n\n // Add init headers\n if (initHeaders) {\n if (initHeaders instanceof Headers) {\n initHeaders.forEach((value, key) => {\n headers[key] = value;\n });\n } else if (Array.isArray(initHeaders)) {\n initHeaders.forEach(([key, value]) => {\n headers[key] = value;\n });\n } else {\n Object.assign(headers, initHeaders);\n }\n }\n\n return headers;\n }\n\n private async parseResponse<T>(\n response: Response,\n parse?: ResponseParser,\n ): Promise<T> {\n switch (parse) {\n case 'text':\n return (await response.text()) as T;\n case 'blob':\n return (await response.blob()) as T;\n case 'arrayBuffer':\n return (await response.arrayBuffer()) as T;\n case 'response':\n return response as T;\n case 'json':\n default: {\n // Tolerate empty 2xx bodies (e.g. 204 No Content from delete/resync):\n // `response.json()` throws on '', so read text and return null when empty.\n const text = await response.text();\n if (!text) return null as T;\n try {\n return JSON.parse(text) as T;\n } catch {\n // Non-JSON body on a 2xx (e.g. an HTML error page) \u2014 surface a clear\n // error with a snippet instead of a bare SyntaxError.\n throw new Error(\n `Expected a JSON response (status ${response.status}) but body was not JSON: ${text.slice(0, 200)}`,\n );\n }\n }\n }\n }\n\n private async getBodyText(response: Response): Promise<string> {\n try {\n const text = await response.text();\n return text.length > 65536 ? text.slice(0, 65536) + '...' : text;\n } catch {\n return '';\n }\n }\n}\n", "import { WebHttpClient } from './web-client.js';\nimport { Transport, HttpClient } from './http-types.js';\n\n// Factory function to create HTTP client with sensible defaults\nexport function createHttpClient(transport: Transport): HttpClient {\n return new WebHttpClient(transport);\n}\n\n// Factory function for browser environments\nexport function createBrowserHttpClient(options: {\n baseUrl: string;\n getAuthToken?: () => Promise<string | undefined>;\n onTokenRefresh?: (newToken: string) => Promise<void>;\n /**\n * Callback to refresh the access token when a 401 error with 'token_expired' is detected.\n * Should return the new access token, or throw an error if refresh fails.\n * If provided, the client will automatically retry the request after a successful refresh.\n */\n refreshToken?: () => Promise<string>;\n /**\n * Callback invoked when the server reports a revoked token family\n * (`x-auth-error: token_reuse` / `token_revoked`). Terminal \u2014 the request is\n * never retried; clear stored tokens and force a re-login.\n */\n onAuthRevoked?: () => Promise<void> | void;\n defaultHeaders?: Record<string, string>;\n timeoutMs?: number;\n credentials?: RequestCredentials;\n defaultAbortSignal?: AbortSignal;\n}): HttpClient {\n const transport: Transport = {\n // Wrap fetch in arrow function to prevent \"Illegal invocation\" error\n // This preserves the correct 'this' context when fetch is called\n fetch: (url: RequestInfo | URL, init?: RequestInit) => globalThis.fetch(url, init),\n baseUrl: options.baseUrl,\n getAuthToken: options.getAuthToken,\n onTokenRefresh: options.onTokenRefresh,\n refreshToken: options.refreshToken,\n onAuthRevoked: options.onAuthRevoked,\n defaultHeaders: options.defaultHeaders,\n timeoutMs: options.timeoutMs,\n credentials: options.credentials, // No default credentials\n defaultAbortSignal: options.defaultAbortSignal,\n };\n\n return createHttpClient(transport);\n}\n\n// Factory function for Node.js environments\nexport function createNodeHttpClient(options: {\n baseUrl: string;\n fetch?: typeof fetch; // Allow injection of undici.fetch or other fetch implementations\n getAuthToken?: () => Promise<string | undefined>;\n onTokenRefresh?: (newToken: string) => Promise<void>;\n /**\n * Callback to refresh the access token when a 401 error with 'token_expired' is detected.\n * Should return the new access token, or throw an error if refresh fails.\n * If provided, the client will automatically retry the request after a successful refresh.\n */\n refreshToken?: () => Promise<string>;\n /**\n * Callback invoked when the server reports a revoked token family\n * (`x-auth-error: token_reuse` / `token_revoked`). Terminal \u2014 the request is\n * never retried; clear stored tokens and force a re-login.\n */\n onAuthRevoked?: () => Promise<void> | void;\n defaultHeaders?: Record<string, string>;\n timeoutMs?: number;\n credentials?: RequestCredentials;\n defaultAbortSignal?: AbortSignal;\n}): HttpClient {\n // Use provided fetch or try to use global fetch (Node 18+)\n const fetchImpl = options.fetch ?? globalThis.fetch;\n\n if (!fetchImpl) {\n throw new Error(\n 'No fetch implementation available. Please provide a fetch implementation ' +\n '(e.g., undici.fetch) or use Node.js 18+ which has native fetch support.',\n );\n }\n\n // Check if we're using the default globalThis.fetch to preserve context\n // When fetchImpl is globalThis.fetch, we must call it directly, not through a variable\n // Custom fetch implementations (like undici.fetch) can be called through the variable\n const isDefaultFetch = fetchImpl === globalThis.fetch;\n\n const transport: Transport = {\n // Wrap fetch in arrow function to prevent \"Illegal invocation\" error\n // For globalThis.fetch, call it directly to preserve 'this' context\n // For custom implementations, calling through the variable is safe\n fetch: isDefaultFetch\n ? (url: RequestInfo | URL, init?: RequestInit) => globalThis.fetch(url, init)\n : (url: RequestInfo | URL, init?: RequestInit) => fetchImpl(url, init),\n baseUrl: options.baseUrl,\n getAuthToken: options.getAuthToken,\n onTokenRefresh: options.onTokenRefresh,\n refreshToken: options.refreshToken,\n onAuthRevoked: options.onAuthRevoked,\n defaultHeaders: options.defaultHeaders,\n timeoutMs: options.timeoutMs,\n credentials: options.credentials, // Node.js doesn't have default credentials\n defaultAbortSignal: options.defaultAbortSignal,\n };\n\n return createHttpClient(transport);\n}\n\n// Universal factory that works in both environments\nexport function createUniversalHttpClient(options: {\n baseUrl: string;\n fetch?: typeof fetch;\n getAuthToken?: () => Promise<string | undefined>;\n onTokenRefresh?: (newToken: string) => Promise<void>;\n /**\n * Callback to refresh the access token when a 401 error with 'token_expired' is detected.\n * Should return the new access token, or throw an error if refresh fails.\n * If provided, the client will automatically retry the request after a successful refresh.\n */\n refreshToken?: () => Promise<string>;\n /**\n * Callback invoked when the server reports a revoked token family\n * (`x-auth-error: token_reuse` / `token_revoked`). Terminal \u2014 the request is\n * never retried; clear stored tokens and force a re-login.\n */\n onAuthRevoked?: () => Promise<void> | void;\n defaultHeaders?: Record<string, string>;\n timeoutMs?: number;\n credentials?: RequestCredentials;\n defaultAbortSignal?: AbortSignal;\n}): HttpClient {\n // Try to detect environment and use appropriate factory\n if (typeof window !== 'undefined') {\n // Browser environment\n return createBrowserHttpClient(options);\n } else {\n // Node.js environment\n return createNodeHttpClient(options);\n }\n}\n", "// Retry helper for HTTP requests\nexport interface RetryOptions {\n attempts?: number;\n}\n\n// Error types for retry logic\ninterface ErrorWithName extends Error {\n name: string;\n}\n\ninterface ErrorWithStatus extends Error {\n status: number;\n}\n\ninterface ErrorWithHeaders extends Error {\n headers?: Headers;\n}\n\n// Default retry condition - retry on network errors and 5xx status codes\nfunction defaultRetryCondition(error: Error, attempt: number): boolean {\n // Don't retry on the last attempt\n if (attempt <= 0) return false;\n\n // Distinguish timeout vs. user abort:\n // - Timeout: name === 'TimeoutError' (per spec/platforms)\n // - User abort: name === 'AbortError'\n const errorWithName = error as ErrorWithName;\n const name = errorWithName?.name;\n if (name === 'TimeoutError') return true;\n if (name === 'AbortError') return false;\n\n // HTTP 5xx and 429 (including HTTPError from web-client)\n const errorWithStatus = error as ErrorWithStatus;\n if (\n 'status' in errorWithStatus &&\n typeof errorWithStatus.status === 'number'\n ) {\n const status = errorWithStatus.status;\n return status >= 500 || status === 429;\n }\n // Network TypeError (DNS/reset) is reasonably retryable\n if (name === 'TypeError') return true;\n\n return false;\n}\n\n// Calculate delay with exponential backoff and jitter\nfunction calculateDelay(attempt: number): number {\n const baseDelayMs = 250; // Base 250ms as per spec\n const delay = baseDelayMs * Math.pow(2, attempt - 1);\n\n // Add \u00B120% jitter to reduce stampedes\n const jitter = (Math.random() - 0.5) * 0.4 * delay;\n return Math.max(0, delay + jitter);\n}\n\n// Retry helper function with new signature\nexport async function withRetry<T>(\n fn: (attempt: number) => Promise<T>,\n options: RetryOptions = {},\n): Promise<T> {\n const { attempts = 3 } = options;\n\n let lastError: Error | undefined;\n\n for (let attempt = 1; attempt <= attempts; attempt++) {\n try {\n return await fn(attempt);\n } catch (error) {\n lastError = error as Error;\n\n // Check if we should retry (this handles the last attempt check)\n if (!defaultRetryCondition(lastError, attempts - attempt)) {\n throw lastError;\n }\n\n // Calculate delay\n let delayMs = calculateDelay(attempt);\n\n // Check for Retry-After header if it's an HTTP error\n const errorWithHeaders = lastError as ErrorWithHeaders;\n const hdrs = errorWithHeaders.headers;\n const retryAfter = hdrs?.get?.('Retry-After');\n if (retryAfter) {\n // If it's a number, treat as seconds\n const seconds = parseInt(retryAfter, 10);\n if (!isNaN(seconds)) {\n delayMs = Math.max(delayMs, seconds * 1000);\n } else {\n // If it's a date, calculate the difference\n const date = new Date(retryAfter);\n if (!isNaN(date.getTime())) {\n const waitTime = Math.max(0, date.getTime() - Date.now());\n // Cap wait at 60s per attempt as per spec\n delayMs = Math.max(delayMs, Math.min(waitTime, 60000));\n }\n }\n }\n\n // Wait before retrying\n await new Promise((resolve) => setTimeout(resolve, delayMs));\n }\n }\n\n throw lastError || new Error('Retry failed without error');\n}\n\n// Helper to create a retry-enabled HTTP client method\nexport function createRetryableMethod<T extends unknown[], R>(\n method: (...args: T) => Promise<R>,\n retryOptions: RetryOptions = {},\n) {\n return async (...args: T): Promise<R> => {\n return withRetry(() => method(...args), retryOptions);\n };\n}\n", "import { HttpClient } from '../http-client/index.js';\nimport {\n // Common types\n ApiResponse,\n // Health and Status\n HealthResponse,\n IdentityResponse,\n ProvidersResponse,\n // Authentication\n TokenRequest,\n TokenResponse,\n RefreshTokenRequest,\n // Mock Token (testing)\n MockTokenRequest,\n // Token Management\n RevokeTokenRequest,\n RevokeTokenResponse,\n // Key Management\n CreateKeyRequest,\n CreateKeyResponse,\n DeleteKeyResponse,\n RootKey,\n // Client Management\n ClientKey,\n GenerateClientKeyRequest,\n DeleteClientResponse,\n // Permissions\n PermissionResponse,\n UpdateKeyPermissionsRequest,\n} from './auth-types.js';\n\nexport class AuthApiClient {\n constructor(private httpClient: HttpClient) {}\n\n // Health and Status Endpoints\n async getHealth(): Promise<HealthResponse> {\n const response =\n await this.httpClient.get<ApiResponse<HealthResponse>>('/auth/health');\n if (!response.data) {\n throw new Error('Health response data is null');\n }\n return response.data;\n }\n\n async getIdentity(): Promise<IdentityResponse> {\n const response =\n await this.httpClient.get<ApiResponse<IdentityResponse>>(\n '/admin/identity',\n );\n if (!response.data) {\n throw new Error('Identity response data is null');\n }\n return response.data;\n }\n\n async getProviders(): Promise<ProvidersResponse> {\n const response =\n await this.httpClient.get<ApiResponse<ProvidersResponse>>(\n '/auth/providers',\n );\n if (!response.data) {\n throw new Error('Providers response data is null');\n }\n return response.data;\n }\n\n // Authentication Endpoints\n async getLoginPage(): Promise<string> {\n return this.httpClient.get<string>('/auth/login', { parse: 'text' });\n }\n\n async generateTokens(request: TokenRequest): Promise<TokenResponse> {\n return this.httpClient.post<TokenResponse>('/auth/token', request);\n }\n\n async refreshToken(request: RefreshTokenRequest): Promise<TokenResponse> {\n return this.httpClient.post<TokenResponse>('/auth/refresh', request);\n }\n\n async generateMockTokens(request: MockTokenRequest): Promise<TokenResponse> {\n return this.httpClient.post<TokenResponse>('/auth/mock-token', request);\n }\n\n async validateToken(token: string): Promise<{\n valid: boolean;\n headers: Record<string, string>;\n status: number;\n }> {\n try {\n const response = await this.validateTokenGet(token);\n return {\n valid: response.status === 200,\n headers: response.headers,\n status: response.status,\n };\n } catch (error) {\n return {\n valid: false,\n headers: {},\n status: 401,\n };\n }\n }\n\n async validateTokenGet(\n token: string,\n ): Promise<{ status: number; headers: Record<string, string> }> {\n const response = await this.httpClient.head('/auth/validate', {\n headers: { Authorization: `Bearer ${token}` },\n });\n return {\n status: response.status,\n headers: response.headers,\n };\n }\n\n // Token Management Endpoints\n // NOTE: node auth status lives on AdminApiClient.isAuthed() (/admin-api/is-authed);\n // there is no /auth/is-authed on the auth service.\n async revokeTokens(\n request: RevokeTokenRequest,\n ): Promise<RevokeTokenResponse> {\n const response = await this.httpClient.post<ApiResponse<RevokeTokenResponse>>(\n '/admin/revoke',\n request,\n );\n if (!response.data) {\n throw new Error('Revoke tokens response data is null');\n }\n return response.data;\n }\n\n // Key Management Endpoints\n async listRootKeys(): Promise<RootKey[]> {\n const response =\n await this.httpClient.get<ApiResponse<RootKey[]>>('/admin/keys');\n if (!response.data) {\n throw new Error('Root keys response data is null');\n }\n return response.data;\n }\n\n async createRootKey(request: CreateKeyRequest): Promise<CreateKeyResponse> {\n const response = await this.httpClient.post<ApiResponse<CreateKeyResponse>>(\n '/admin/keys',\n request,\n );\n if (!response.data) {\n throw new Error('Create root key response data is null');\n }\n return response.data;\n }\n\n async deleteRootKey(keyId: string): Promise<DeleteKeyResponse> {\n return this.httpClient.delete<DeleteKeyResponse>(`/admin/keys/${keyId}`);\n }\n\n // Client Management Endpoints\n async listClientKeys(): Promise<ClientKey[]> {\n const response = await this.httpClient.get<ApiResponse<ClientKey[]>>(\n '/admin/keys/clients',\n );\n if (!response.data) {\n throw new Error('Client keys response data is null');\n }\n return response.data;\n }\n\n async generateClientKey(\n request: GenerateClientKeyRequest,\n ): Promise<TokenResponse> {\n return this.httpClient.post<TokenResponse>('/admin/client-key', request);\n }\n\n async deleteClientKey(\n keyId: string,\n clientId: string,\n ): Promise<DeleteClientResponse> {\n return this.httpClient.delete<DeleteClientResponse>(\n `/admin/keys/${keyId}/clients/${clientId}`,\n );\n }\n\n // Permission Management Endpoints\n async getKeyPermissions(keyId: string): Promise<PermissionResponse> {\n return this.httpClient.get<PermissionResponse>(\n `/admin/keys/${keyId}/permissions`,\n );\n }\n\n async updateKeyPermissions(\n keyId: string,\n changes: UpdateKeyPermissionsRequest,\n ): Promise<PermissionResponse> {\n // Core expects an { add, remove } delta, not a { permissions } replacement.\n return this.httpClient.put<PermissionResponse>(\n `/admin/keys/${keyId}/permissions`,\n { add: changes.add, remove: changes.remove },\n );\n }\n}\n", "import { AuthApiClient } from './auth-client.js';\nimport { AuthApiClientConfig } from './auth-types.js';\nimport { HttpClient } from '../http-client/index.js';\n\n// Mock HTTP client for testing\nclass MockHttpClient implements HttpClient {\n async get<T>(): Promise<T> {\n throw new Error(\n 'HTTP client not implemented - use createAuthApiClientFromHttpClient with a real HTTP client',\n );\n }\n async post<T>(): Promise<T> {\n throw new Error(\n 'HTTP client not implemented - use createAuthApiClientFromHttpClient with a real HTTP client',\n );\n }\n async put<T>(): Promise<T> {\n throw new Error(\n 'HTTP client not implemented - use createAuthApiClientFromHttpClient with a real HTTP client',\n );\n }\n async delete<T>(): Promise<T> {\n throw new Error(\n 'HTTP client not implemented - use createAuthApiClientFromHttpClient with a real HTTP client',\n );\n }\n async patch<T>(): Promise<T> {\n throw new Error(\n 'HTTP client not implemented - use createAuthApiClientFromHttpClient with a real HTTP client',\n );\n }\n async head(): Promise<{ headers: Record<string, string>; status: number }> {\n throw new Error(\n 'HTTP client not implemented - use createAuthApiClientFromHttpClient with a real HTTP client',\n );\n }\n async request<T>(): Promise<T> {\n throw new Error(\n 'HTTP client not implemented - use createAuthApiClientFromHttpClient with a real HTTP client',\n );\n }\n}\n\n// Factory functions for creating Auth API clients\nexport function createBrowserAuthApiClient(\n _config: AuthApiClientConfig,\n): AuthApiClient {\n const httpClient = new MockHttpClient();\n return new AuthApiClient(httpClient);\n}\n\nexport function createNodeAuthApiClient(\n _config: AuthApiClientConfig,\n): AuthApiClient {\n const httpClient = new MockHttpClient();\n return new AuthApiClient(httpClient);\n}\n\nexport function createAuthApiClient(\n _config: AuthApiClientConfig,\n): AuthApiClient {\n const httpClient = new MockHttpClient();\n return new AuthApiClient(httpClient);\n}\n\nexport function createAuthApiClientFromHttpClient(\n httpClient: HttpClient,\n _config: AuthApiClientConfig,\n): AuthApiClient {\n return new AuthApiClient(httpClient);\n}\n", "import { HttpClient, withRetry } from '../http-client/index.js';\nimport type {\n HealthStatus,\n AdminAuthStatus,\n InstallApplicationRequest,\n InstallApplicationResponseData,\n InstallDevApplicationRequest,\n UninstallApplicationResponseData,\n ListApplicationsResponseData,\n GetApplicationResponseData,\n ApplicationVersionEntry,\n GetApplicationAbiResponseData,\n GetLatestVersionResponseData,\n ListPackagesResponseData,\n ListVersionsResponseData,\n RegistryBundleManifest,\n CreateContextRequest,\n CreateContextResponseData,\n DeleteContextResponseData,\n GetContextsResponseData,\n Context,\n GenerateContextIdentityResponseData,\n GetContextIdentitiesResponseData,\n JoinContextResponseData,\n JoinSubgroupInheritanceResponseData,\n ContextGroupResponseData,\n ContextStorageResponseData,\n InviteSpecializedNodeRequest,\n InviteSpecializedNodeResponseData,\n UpdateContextApplicationRequest,\n ResyncContextRequest,\n ResyncContextResponseData,\n ContextsWithExecutorsResponseData,\n UploadBlobRequest,\n UploadBlobResponseData,\n DeleteBlobResponseData,\n ListBlobsResponseData,\n GetBlobInfoResponseData,\n BlobReadOptions,\n CreateContextAliasRequest,\n CreateApplicationAliasRequest,\n CreateDeviceAliasRequest,\n CreateAliasResponseData,\n LookupAliasResponseData,\n DeleteAliasResponseData,\n ListAliasesResponseData,\n ListNamespacesResponseData,\n CreateNamespaceRequest,\n CreateNamespaceResponseData,\n DeleteNamespaceResponseData,\n CreateNamespaceInvitationRequest,\n CreateNamespaceInvitationResponseData,\n CreateRecursiveInvitationResponseData,\n JoinNamespaceRequest,\n JoinNamespaceResponseData,\n CreateGroupInNamespaceRequest,\n CreateGroupInNamespaceResponseData,\n SubgroupEntry,\n Namespace,\n NamespaceIdentity,\n NodeIdentity,\n AccountPairInitRequest,\n AccountPairInitResponseData,\n AccountPairCompleteRequest,\n AccountPairCompleteResponseData,\n RelinkDeviceRequest,\n RelinkDeviceResponseData,\n AccountDeviceEntry,\n AccountApplicationEntry,\n RevokeAccountDeviceRequest,\n RevokeAccountDeviceResponseData,\n GroupInfoResponseData,\n CreateGroupRequest,\n CreateGroupResponseData,\n DeleteGroupResponseData,\n ListGroupMembersResponseData,\n ListGroupContextsResponseData,\n AddGroupMembersRequest,\n RemoveGroupMembersRequest,\n UpdateMemberRoleRequest,\n MemberCapabilities,\n SetMemberCapabilitiesRequest,\n SetDefaultCapabilitiesRequest,\n SetMemberAutoFollowRequest,\n SetSubgroupVisibilityRequest,\n SetTeeAdmissionPolicyRequest,\n GetTeeAdmissionPolicyResponseData,\n SetGroupMetadataRequest,\n SetMemberMetadataRequest,\n SetContextMetadataRequest,\n MetadataRecord,\n GetMetadataResponseData,\n SyncGroupResponseData,\n UpgradeGroupRequest,\n UpgradeGroupResponseData,\n GroupUpgradeStatusResponseData,\n MigrationStatus,\n CascadeStatusEntry,\n RetryGroupUpgradeResponseData,\n ReparentGroupRequest,\n ReparentGroupResponseData,\n IssueOwnershipProofRequest,\n IssueNamespaceOwnershipProofRequest,\n IssueOwnershipProofResponseData,\n CreateGroupInvitationRequest,\n CreateGroupInvitationResponseData,\n CreateRecursiveGroupInvitationResponseData,\n JoinGroupRequest,\n JoinGroupResponseData,\n TeeInfoResponseData,\n TeeAttestRequest,\n TeeAttestResponseData,\n TeeVerifyQuoteRequest,\n TeeVerifyQuoteResponseData,\n PerformIntentRequest,\n PerformIntentResponseData,\n IntentRelayInfo,\n AdmitJoinRequest,\n AdmitJoinResponseData,\n} from './admin-types.js';\n\n/**\n * Helper: server wraps most responses in `{ data: T }`.\n * This extracts `.data` so callers get the inner payload directly. Null-safe so an\n * empty 2xx body (parsed as null) yields undefined instead of throwing.\n */\nfunction unwrap<T>(response: { data: T }): T {\n return response?.data as T;\n}\n\n/**\n * Compare two version strings by SemVer 2.0 precedence, ascending: negative if\n * `a < b`, positive if `a > b`, `0` if equal. Build metadata (`+...`) is stripped\n * and ignored. The numeric `major.minor.patch` core is compared field-by-field\n * (numerically when both parse, so `1.10.0 > 1.9.0`; a missing field is `0`). A\n * version WITH a pre-release ranks below the same core without one, and\n * pre-release identifiers compare per spec: dot-separated, numeric identifiers\n * numerically, alphanumeric lexically by ASCII, numeric below alphanumeric, and a\n * shorter set of identifiers loses when all preceding fields are equal.\n */\nexport function compareSemver(a: string, b: string): number {\n const [coreA, preA] = splitVersion(a);\n const [coreB, preB] = splitVersion(b);\n\n const na = coreA.split('.');\n const nb = coreB.split('.');\n const n = Math.max(na.length, nb.length);\n for (let i = 0; i < n; i++) {\n const c = compareSemverId(na[i] ?? '0', nb[i] ?? '0');\n if (c !== 0) return c;\n }\n\n // A pre-release ranks below the same core version with no pre-release.\n if (preA === undefined && preB === undefined) return 0;\n if (preA === undefined) return 1;\n if (preB === undefined) return -1;\n\n const pa = preA.split('.');\n const pb = preB.split('.');\n const m = Math.max(pa.length, pb.length);\n for (let i = 0; i < m; i++) {\n if (i >= pa.length) return -1; // shorter set loses when all preceding equal\n if (i >= pb.length) return 1;\n const c = compareSemverId(pa[i], pb[i]);\n if (c !== 0) return c;\n }\n return 0;\n}\n\n/** Drop build metadata and split the pre-release tail: `1.2.3-rc.1+b` -> `['1.2.3', 'rc.1']`. */\nfunction splitVersion(v: string): [string, string | undefined] {\n const core = v.split('+', 1)[0];\n const dash = core.indexOf('-');\n return dash === -1 ? [core, undefined] : [core.slice(0, dash), core.slice(dash + 1)];\n}\n\n/**\n * Compare one identifier: numerically when both are all-digits, else lexically by\n * ASCII with a numeric identifier ranking below an alphanumeric one. Fallback: a\n * non-numeric core component (loose/malformed input) is treated as a string, so\n * comparison never throws.\n */\nfunction compareSemverId(a: string, b: string): number {\n const na = /^\\d+$/.test(a);\n const nb = /^\\d+$/.test(b);\n if (na && nb) {\n const d = Number(a) - Number(b);\n return d < 0 ? -1 : d > 0 ? 1 : 0;\n }\n if (na) return -1;\n if (nb) return 1;\n return a < b ? -1 : a > b ? 1 : 0;\n}\n\n/**\n * Fetch a URL from the (foreign-origin) registry with a per-attempt timeout and\n * retry on transient failures. Deliberately NOT routed through the node\n * `HttpClient`: that client attaches the node's bearer token to every request,\n * which must never leak to the registry's origin. Each attempt times out after\n * ~10s; network errors and 5xx are retried (2 retries, short backoff via the\n * shared `withRetry`), while a 4xx is a definitive answer and is not retried.\n * `kind`/`context` shape the error message so failures stay debuggable in logs.\n */\nasync function fetchRegistry(url: string, kind: string, context: string): Promise<Response> {\n return withRetry(\n async () => {\n const resp = await fetch(url, { signal: AbortSignal.timeout(10000) });\n if (!resp.ok) {\n // Carry `status` so withRetry retries 5xx but leaves 4xx to throw.\n const err = new Error(\n `registry ${kind} fetch failed (${resp.status}) for ${context}`,\n ) as Error & { status: number };\n err.status = resp.status;\n throw err;\n }\n return resp;\n },\n { attempts: 3 },\n );\n}\n\nexport class AdminApiClient {\n constructor(private httpClient: HttpClient) {}\n\n // ---- Health and Status (public, no auth) ----\n\n async healthCheck(): Promise<HealthStatus> {\n return unwrap(await this.httpClient.get<{ data: HealthStatus }>('/admin-api/health'));\n }\n\n async isAuthed(): Promise<AdminAuthStatus> {\n return this.httpClient.get<AdminAuthStatus>('/admin-api/is-authed');\n }\n\n // ---- Application Management ----\n\n /**\n * Install a published application by its `package@version` coordinates. The\n * node resolves and fetches them from its own configured `[registry]`, so no\n * URL is passed and none is accepted. A 502 means the node's source has\n * nothing published at those coordinates. This is the discrete \"download\"\n * step an Updates flow pairs with a subsequent `upgradeGroup`.\n */\n async installApplication(request: InstallApplicationRequest): Promise<InstallApplicationResponseData> {\n return unwrap(await this.httpClient.post<{ data: InstallApplicationResponseData }>('/admin-api/install-application', request));\n }\n\n /**\n * List a package's published versions from the registry, newest-first by\n * semver. Reads the registry's V2 bundle listing\n * (`GET {registry}/api/v2/bundles?package={package}`), taking each bundle's\n * `appVersion`. Registry-side data \u2014 distinct from the node's\n * installed-version list \u2014 and the source an Updates view compares against\n * the running `Context.applicationVersion` to detect \"a new version exists\".\n */\n async getRegistryVersions(registryUrl: string, packageName: string): Promise<string[]> {\n const url = new URL('/api/v2/bundles', new URL(registryUrl).origin);\n url.searchParams.set('package', packageName);\n const resp = await fetchRegistry(url.toString(), 'versions', packageName);\n const bundles = (await resp.json()) as RegistryBundleManifest[];\n return (Array.isArray(bundles) ? bundles : [])\n .map((b) => b.appVersion)\n .filter((v): v is string => typeof v === 'string')\n .sort((a, b) => compareSemver(b, a));\n }\n\n async installDevApplication(request: InstallDevApplicationRequest): Promise<InstallApplicationResponseData> {\n return unwrap(await this.httpClient.post<{ data: InstallApplicationResponseData }>('/admin-api/install-dev-application', request));\n }\n\n async uninstallApplication(appId: string): Promise<UninstallApplicationResponseData> {\n return unwrap(await this.httpClient.delete<{ data: UninstallApplicationResponseData }>(`/admin-api/applications/${appId}`));\n }\n\n async listApplications(): Promise<ListApplicationsResponseData> {\n return unwrap(await this.httpClient.get<{ data: ListApplicationsResponseData }>('/admin-api/applications'));\n }\n\n async getApplication(appId: string): Promise<GetApplicationResponseData> {\n return unwrap(await this.httpClient.get<{ data: GetApplicationResponseData }>(`/admin-api/applications/${appId}`));\n }\n\n /**\n * Installed-blob inventory for an application \u2014 one entry per locally installed\n * version. This is the *installed* inventory (source for a \"pick a version to\n * pin\" UI); the registry equivalent is `listPackageVersions`.\n */\n async listApplicationVersions(applicationId: string): Promise<ApplicationVersionEntry[]> {\n return unwrap(\n await this.httpClient.get<{ data: ApplicationVersionEntry[] }>(`/admin-api/applications/${applicationId}/versions`),\n );\n }\n\n /**\n * The application's embedded `wasm-abi/1` manifest. Omit `serviceName` for\n * single-service apps; core 400s if the ABI is absent or the name is ambiguous.\n */\n async getApplicationAbi(applicationId: string, serviceName?: string): Promise<GetApplicationAbiResponseData> {\n const query = serviceName ? `?service_name=${encodeURIComponent(serviceName)}` : '';\n return unwrap(\n await this.httpClient.get<{ data: GetApplicationAbiResponseData }>(\n `/admin-api/applications/${applicationId}/abi${query}`,\n ),\n );\n }\n\n // ---- Package Management ----\n\n async listPackages(): Promise<ListPackagesResponseData> {\n // Core returns this flat ({ packages: [...] }), not under `data`; tolerate both.\n const r = await this.httpClient.get<ListPackagesResponseData & { data?: ListPackagesResponseData }>(\n '/admin-api/packages',\n );\n return (r?.data ?? r) as ListPackagesResponseData;\n }\n\n async listPackageVersions(packageName: string): Promise<ListVersionsResponseData> {\n // Core returns this flat ({ versions: [...] }), not under `data`; tolerate both.\n const r = await this.httpClient.get<ListVersionsResponseData & { data?: ListVersionsResponseData }>(\n `/admin-api/packages/${encodeURIComponent(packageName)}/versions`,\n );\n return (r?.data ?? r) as ListVersionsResponseData;\n }\n\n async getLatestPackageVersion(packageName: string): Promise<GetLatestVersionResponseData> {\n return this.httpClient.get<GetLatestVersionResponseData>(\n `/admin-api/packages/${encodeURIComponent(packageName)}/latest`,\n );\n }\n\n // ---- Context Management ----\n\n async createContext(request: CreateContextRequest): Promise<CreateContextResponseData> {\n // Core requires `initializationParams` (no default); default it to an empty\n // byte array so callers that pass none don't get a 400.\n const body = { ...request, initializationParams: request.initializationParams ?? [] };\n return unwrap(await this.httpClient.post<{ data: CreateContextResponseData }>('/admin-api/contexts', body));\n }\n\n async deleteContext(contextId: string): Promise<DeleteContextResponseData> {\n return unwrap(await this.httpClient.delete<{ data: DeleteContextResponseData }>(`/admin-api/contexts/${contextId}`));\n }\n\n async getContexts(): Promise<GetContextsResponseData> {\n return unwrap(await this.httpClient.get<{ data: GetContextsResponseData }>('/admin-api/contexts'));\n }\n\n async getContext(contextId: string): Promise<Context> {\n return unwrap(await this.httpClient.get<{ data: Context }>(`/admin-api/contexts/${contextId}`));\n }\n\n async getContextsForApplication(applicationId: string): Promise<GetContextsResponseData> {\n return unwrap(await this.httpClient.get<{ data: GetContextsResponseData }>(`/admin-api/contexts/for-application/${applicationId}`));\n }\n\n // ---- Context Identity ----\n\n async generateContextIdentity(): Promise<GenerateContextIdentityResponseData> {\n return unwrap(await this.httpClient.post<{ data: GenerateContextIdentityResponseData }>('/admin-api/identity/context', {}));\n }\n\n async getContextIdentities(contextId: string): Promise<GetContextIdentitiesResponseData> {\n return unwrap(await this.httpClient.get<{ data: GetContextIdentitiesResponseData }>(`/admin-api/contexts/${contextId}/identities`));\n }\n\n async getContextIdentitiesOwned(contextId: string): Promise<GetContextIdentitiesResponseData> {\n return unwrap(await this.httpClient.get<{ data: GetContextIdentitiesResponseData }>(`/admin-api/contexts/${contextId}/identities-owned`));\n }\n\n // ---- Context join (group membership) ----\n\n async joinContext(contextId: string): Promise<JoinContextResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: JoinContextResponseData }>(`/admin-api/contexts/${contextId}/join`, {}),\n );\n }\n\n // ---- Context group / storage / sync ----\n\n async getContextGroup(contextId: string): Promise<ContextGroupResponseData> {\n return unwrap(await this.httpClient.get<{ data: ContextGroupResponseData }>(`/admin-api/contexts/${contextId}/group`));\n }\n\n async getContextStorage(contextId: string): Promise<ContextStorageResponseData> {\n return unwrap(await this.httpClient.get<{ data: ContextStorageResponseData }>(`/admin-api/contexts/${contextId}/storage`));\n }\n\n /** Sync one context, or every context when `contextId` is omitted. */\n async syncContext(contextId?: string): Promise<void> {\n // Sync-all is `/contexts/sync` with no trailing slash - core routes the two\n // spellings separately and 404s the trailing one.\n const path = contextId ? `/admin-api/contexts/sync/${contextId}` : '/admin-api/contexts/sync';\n await this.httpClient.post(path, {});\n }\n\n /**\n * Kick off a full state re-pull for a context (operator recovery for a\n * stranded context). `force` re-pulls even when the node does not flag the\n * context as stranded.\n */\n async resyncContext(\n contextId: string,\n request: ResyncContextRequest = {},\n ): Promise<ResyncContextResponseData> {\n // Core's `ResyncContextApiResponse` is a flat payload (no inner `data`\n // field), so parse the body directly \u2014 do NOT `unwrap`, or `resyncStarted`\n // reads as undefined and the resync silently appears to never start.\n const r = await this.httpClient.post<ResyncContextResponseData | null>(\n `/admin-api/contexts/${contextId}/resync`,\n request,\n );\n // An empty 2xx body means the resync was accepted; synthesize the result so\n // callers always get a typed value instead of null.\n return r ?? { contextId, resyncStarted: true };\n }\n\n async inviteSpecializedNode(request: InviteSpecializedNodeRequest): Promise<InviteSpecializedNodeResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: InviteSpecializedNodeResponseData }>(\n '/admin-api/contexts/invite-specialized-node',\n request,\n ),\n );\n }\n\n async updateContextApplication(\n contextId: string,\n request: UpdateContextApplicationRequest,\n ): Promise<void> {\n await this.httpClient.post(`/admin-api/contexts/${contextId}/application`, request);\n }\n\n async getContextsWithExecutorsForApplication(applicationId: string): Promise<ContextsWithExecutorsResponseData> {\n // Core returns this flat as { contexts: [...] } (not a bare array under `data`).\n const r = await this.httpClient.get<\n | ContextsWithExecutorsResponseData\n | { contexts: ContextsWithExecutorsResponseData }\n | { data: ContextsWithExecutorsResponseData }\n >(`/admin-api/contexts/with-executors/for-application/${applicationId}`);\n if (Array.isArray(r)) return r;\n return (\n (r as { contexts?: ContextsWithExecutorsResponseData } | null)?.contexts ??\n (r as { data?: ContextsWithExecutorsResponseData } | null)?.data ??\n []\n );\n }\n\n // ---- Blob Management ----\n\n async uploadBlob(request: UploadBlobRequest): Promise<UploadBlobResponseData> {\n // Core streams the raw request body into blob storage (no JSON) and takes\n // its params from the query string (`hash`, `context_id` \u2014 snake_case).\n const params = new URLSearchParams();\n if (request.hash) params.set('hash', request.hash);\n if (request.contextId) params.set('context_id', request.contextId);\n const query = params.toString();\n const path = query ? `/admin-api/blobs?${query}` : '/admin-api/blobs';\n // request.data (Uint8Array view | ArrayBuffer | Blob) is a valid BodyInit and\n // is streamed verbatim \u2014 no JSON, no cast. fetch honors a Uint8Array view's\n // byteOffset/byteLength, so subarrays upload the correct region.\n // Core's BlobInfo is snake_case (`blob_id`); map to camelCase like deleteBlob.\n const res = unwrap(\n await this.httpClient.request<{ data: { blob_id: string; size: number } }>(path, {\n method: 'PUT',\n body: request.data,\n headers: { 'Content-Type': 'application/octet-stream' },\n }),\n );\n return { blobId: res.blob_id, size: res.size };\n }\n\n async deleteBlob(blobId: string): Promise<DeleteBlobResponseData> {\n // Core's `BlobDeleteResponse` is a flat, snake_case payload (`{ blob_id,\n // deleted }`) \u2014 the lone admin DTO without a camelCase rename and without an\n // inner `data` field. Parse directly (no `unwrap`) and map to camelCase.\n const body = await this.httpClient.delete<{ blob_id: string; deleted: boolean }>(\n `/admin-api/blobs/${blobId}`,\n );\n return { blobId: body.blob_id, deleted: body.deleted };\n }\n\n async listBlobs(): Promise<ListBlobsResponseData> {\n // Core's BlobInfo is snake_case (`blob_id`); map to camelCase.\n const res = unwrap(\n await this.httpClient.get<{ data: { blobs: Array<{ blob_id: string; size: number }> } }>(\n '/admin-api/blobs',\n ),\n );\n return { blobs: res.blobs.map((b) => ({ blobId: b.blob_id, size: b.size })) };\n }\n\n /**\n * Blob-read query params. `context_id` is the same snake_case param\n * {@link uploadBlob} announces with; building it in one place keeps the read\n * side from drifting from the write side.\n */\n private blobPath(blobId: string, options?: BlobReadOptions): string {\n if (!options?.contextId) return `/admin-api/blobs/${blobId}`;\n const params = new URLSearchParams({ context_id: options.contextId });\n return `/admin-api/blobs/${blobId}?${params.toString()}`;\n }\n\n /**\n * Download a blob's raw bytes. `GET /admin-api/blobs/:id` streams the blob\n * content (e.g. `application/gzip`), NOT JSON \u2014 so fetch it as an ArrayBuffer.\n * Use {@link listBlobs} for `{ blobId, size }` metadata.\n *\n * Without `contextId` the read is local-only: the node answers from its own\n * blob store and returns immediately, or 404s. Passing `contextId` opts into\n * network discovery \u2014 the node probes that context's peers (availability\n * nodes first) for a holder, then transfers the bytes. Budget for it: core\n * bounds discovery by a ~30s deadline, and the transfer is on top of that, so\n * the worst case is well past what a UI should block on unhinted.\n */\n async getBlob(blobId: string, options?: BlobReadOptions): Promise<ArrayBuffer> {\n return this.httpClient.get<ArrayBuffer>(this.blobPath(blobId, options), {\n parse: 'arrayBuffer',\n });\n }\n\n /**\n * Fetch a blob's metadata without downloading it. `HEAD /admin-api/blobs/:id`\n * returns the info in response headers (size via `content-length`, plus\n * `x-blob-id`/`x-blob-hash`/`x-blob-mime-type`).\n *\n * Without `contextId` this is a local-only presence check that returns\n * immediately. Passing `contextId` opts into the same network discovery\n * {@link getBlob} uses \u2014 presence and size answered by probing the context's\n * peers, with no transfer \u2014 so it inherits core's ~30s discovery deadline as\n * its worst case. A probe only carries `found` and `size`, so a peer-sourced\n * answer has no `hash`/`mimeType`; read `source` to tell the two apart.\n */\n async getBlobInfo(\n blobId: string,\n options?: BlobReadOptions,\n ): Promise<GetBlobInfoResponseData> {\n // HEAD throws (HttpError) on a non-2xx status, so we only reach here on success\n // \u2014 the x-blob-* headers are present. Guard size against a missing/non-numeric\n // content-length anyway (defaults to 0 rather than NaN).\n const { headers } = await this.httpClient.head(this.blobPath(blobId, options));\n const size = Number(headers['content-length']);\n return {\n blobId: headers['x-blob-id'] ?? blobId,\n size: Number.isFinite(size) ? size : 0,\n hash: headers['x-blob-hash'],\n mimeType: headers['x-blob-mime-type'],\n // Nodes that predate the context-aware HEAD omit this header entirely, so\n // it stays undefined rather than being defaulted to 'local' \u2014 absent means\n // \"the node didn't say\", which is not the same claim as \"served locally\".\n source: headers['x-blob-source'] as GetBlobInfoResponseData['source'],\n };\n }\n\n // ---- Alias Management ----\n\n async createContextAlias(\n request: CreateContextAliasRequest,\n ): Promise<CreateAliasResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: CreateAliasResponseData }>(\n '/admin-api/alias/create/context',\n { alias: request.alias, contextId: request.contextId },\n ),\n );\n }\n\n async createApplicationAlias(\n request: CreateApplicationAliasRequest,\n ): Promise<CreateAliasResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: CreateAliasResponseData }>(\n '/admin-api/alias/create/application',\n { alias: request.alias, applicationId: request.applicationId },\n ),\n );\n }\n\n async lookupContextAlias(name: string): Promise<LookupAliasResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: LookupAliasResponseData }>(\n `/admin-api/alias/lookup/context/${encodeURIComponent(name)}`,\n {},\n ),\n );\n }\n\n async lookupApplicationAlias(name: string): Promise<LookupAliasResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: LookupAliasResponseData }>(\n `/admin-api/alias/lookup/application/${encodeURIComponent(name)}`,\n {},\n ),\n );\n }\n\n async deleteContextAlias(name: string): Promise<DeleteAliasResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: DeleteAliasResponseData }>(\n `/admin-api/alias/delete/context/${encodeURIComponent(name)}`,\n {},\n ),\n );\n }\n\n async deleteApplicationAlias(name: string): Promise<DeleteAliasResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: DeleteAliasResponseData }>(\n `/admin-api/alias/delete/application/${encodeURIComponent(name)}`,\n {},\n ),\n );\n }\n\n async listContextAliases(): Promise<ListAliasesResponseData> {\n return unwrap(await this.httpClient.get<{ data: ListAliasesResponseData }>('/admin-api/alias/list/context'));\n }\n\n async listApplicationAliases(): Promise<ListAliasesResponseData> {\n return unwrap(await this.httpClient.get<{ data: ListAliasesResponseData }>('/admin-api/alias/list/application'));\n }\n\n async createDeviceAlias(request: CreateDeviceAliasRequest): Promise<CreateAliasResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: CreateAliasResponseData }>(\n '/admin-api/alias/create/device',\n { alias: request.alias, deviceId: request.deviceId },\n ),\n );\n }\n\n async lookupDeviceAlias(name: string): Promise<LookupAliasResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: LookupAliasResponseData }>(\n `/admin-api/alias/lookup/device/${encodeURIComponent(name)}`,\n {},\n ),\n );\n }\n\n async deleteDeviceAlias(name: string): Promise<DeleteAliasResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: DeleteAliasResponseData }>(\n `/admin-api/alias/delete/device/${encodeURIComponent(name)}`,\n {},\n ),\n );\n }\n\n async listDeviceAliases(): Promise<ListAliasesResponseData> {\n return unwrap(await this.httpClient.get<{ data: ListAliasesResponseData }>('/admin-api/alias/list/device'));\n }\n\n // ---- Namespace Management ----\n\n async listNamespaces(): Promise<ListNamespacesResponseData> {\n return unwrap(await this.httpClient.get<{ data: ListNamespacesResponseData }>('/admin-api/namespaces'));\n }\n\n async getNamespace(namespaceId: string): Promise<Namespace> {\n return unwrap(await this.httpClient.get<{ data: Namespace }>(`/admin-api/namespaces/${namespaceId}`));\n }\n\n /**\n * Who this node is \u2014 the account it writes as, the device it is, the key it\n * signs with, and the account root a second device pairs against.\n *\n * Takes no namespace, and that is the point: one root key is one account\n * everywhere, and a node signs with one key, so none of it varies by\n * namespace.\n */\n async getNodeIdentity(): Promise<NodeIdentity> {\n return unwrap(await this.httpClient.get<{ data: NodeIdentity }>('/admin-api/identity'));\n }\n\n /**\n * @deprecated Use {@link getNodeIdentity} instead. Every field this returns is\n * node-level, so the namespace was only ever decoration \u2014 it now delegates to\n * the node-level route and reshapes the answer.\n *\n * Three consequences of that delegation, all visible to a caller who relied on\n * the old route's behaviour:\n *\n * - **No participation gate.** The namespace route answered 404 when this node\n * had never joined the namespace; this answers whatever the node's identity\n * is, regardless. If you were using it to ask \"am I in this namespace?\", ask\n * {@link listNamespaces} instead \u2014 that is the question you were really\n * asking.\n * - **`namespaceId` is echoed verbatim.** The old route resolved a subgroup id\n * to its root namespace and returned that; passing a subgroup id here gives\n * the subgroup id back.\n * - **404 means something else.** Previously \"not my namespace\", now \"this node\n * holds no account root yet\".\n */\n async getNamespaceIdentity(namespaceId: string): Promise<NamespaceIdentity> {\n const node = await this.getNodeIdentity();\n return { namespaceId, publicKey: node.publicKey, account: node.accountId };\n }\n\n /**\n * Ask this node to run one method on a member's behalf, under a warrant that\n * member signed.\n *\n * The node executes and signs the envelope with its own key; the change is\n * attributed to the **author**. Both halves travel together, so every peer\n * re-checks that the member consented instead of trusting the relay.\n *\n * Three things have to be true first, and none is implied by the others:\n *\n * - the author's **account** is a member of the group owning the context \u2014\n * their device joins nothing and is in no group's binding rows, which is\n * exactly the case a device certificate covers;\n * - this node holds `CAN_AUTHOR_ON_BEHALF` on that group, which is implied by\n * neither membership nor admin;\n * - the warrant has not been spent. It is single-use: presenting a valid one\n * twice is refused, because the signature stays valid forever and replay is\n * not forgery.\n *\n * A refusal comes back as a `403` carrying the reason \u2014 \"an admin must grant\n * CAN_AUTHOR_ON_BEHALF to \u2026\", or that the nonce is already spent \u2014 so a caller\n * can tell which precondition failed rather than only that one did.\n *\n * Mint the warrant with {@link signWarrant}; see\n * {@link PerformIntentRequest.warrant}.\n */\n async performIntent(\n contextId: string,\n request: PerformIntentRequest,\n ): Promise<PerformIntentResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: PerformIntentResponseData }>(\n `/admin-api/contexts/${contextId}/intents`,\n request,\n ),\n );\n }\n\n /**\n * Ask what this node can do for a member in `contextId`, before they sign\n * anything.\n *\n * The two facts {@link performIntent} needs and a client cannot derive: whose\n * account goes in the warrant's `executor`, and whether this node holds\n * `CAN_AUTHOR_ON_BEHALF` on the owning group. `canAuthorOnBehalf: false` comes\n * back as an answer rather than an error \u2014 it is the default state of every\n * context \u2014 so a caller can say \"an admin of `groupId` must grant it to\n * `executorAccount`\" instead of presenting a warrant that will be refused\n * after the author has spent a nonce on it.\n *\n * `404` means the context belongs to no group, or this node holds no account\n * yet; either way it can be named as no warrant's executor.\n *\n * For a caller with no credential on the node at all \u2014 a browser tab holding\n * one signing key \u2014 use `RelayClient`, which reads this same route on a node\n * run as a relay.\n */\n async getIntentRelay(contextId: string): Promise<IntentRelayInfo> {\n return unwrap(\n await this.httpClient.get<{ data: IntentRelayInfo }>(\n `/admin-api/contexts/${contextId}/intents`,\n ),\n );\n }\n\n async listNamespacesForApplication(applicationId: string): Promise<ListNamespacesResponseData> {\n return unwrap(await this.httpClient.get<{ data: ListNamespacesResponseData }>(`/admin-api/namespaces/for-application/${applicationId}`));\n }\n\n async createNamespace(request: CreateNamespaceRequest): Promise<CreateNamespaceResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: CreateNamespaceResponseData }>('/admin-api/namespaces', request),\n );\n }\n\n async deleteNamespace(namespaceId: string): Promise<DeleteNamespaceResponseData> {\n // Core requires `Content-Type: application/json` on this DELETE even though\n // the body is always empty, so send the header and an empty JSON object.\n return unwrap(\n await this.httpClient.request<{ data: DeleteNamespaceResponseData }>(`/admin-api/namespaces/${namespaceId}`, {\n method: 'DELETE',\n body: '{}',\n headers: { 'Content-Type': 'application/json' },\n }),\n );\n }\n\n async createNamespaceInvitation(\n namespaceId: string,\n request?: CreateNamespaceInvitationRequest,\n ): Promise<CreateNamespaceInvitationResponseData | CreateRecursiveInvitationResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: CreateNamespaceInvitationResponseData | CreateRecursiveInvitationResponseData }>(\n `/admin-api/namespaces/${namespaceId}/invite`,\n request ?? {},\n ),\n );\n }\n\n /**\n * Present a join this caller signed to a node the inviter named as an\n * admitter.\n *\n * For a member with no node. `joinNamespace` publishes the membership op from\n * the node making the call; this hands an already-signed op to somebody else's\n * node to publish. The distinction matters because a keyholder has nowhere to\n * publish from.\n *\n * The op must be signed by the **device key** in the credential it carries \u2014\n * every peer checks that when applying a join. So the admitter cannot author\n * this, only carry it: a hostile one can refuse, and nothing else. It cannot\n * admit a different account, change the group, or grant a role.\n *\n * @param namespaceId the namespace being joined, 64 hex\n * @param request the invitation and the hex-encoded signed op\n */\n async admitJoin(\n namespaceId: string,\n request: AdmitJoinRequest,\n ): Promise<AdmitJoinResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: AdmitJoinResponseData }>(\n `/admin-api/namespaces/${namespaceId}/admit`,\n request,\n { timeoutMs: 65000 },\n ),\n );\n }\n\n async joinNamespace(\n namespaceId: string,\n request: JoinNamespaceRequest,\n ): Promise<JoinNamespaceResponseData> {\n const data = unwrap(\n await this.httpClient.post<{ data: JoinNamespaceResponseData }>(\n `/admin-api/namespaces/${namespaceId}/join`,\n request,\n { timeoutMs: 65000 },\n ),\n );\n\n // core 0.11.0-rc.25 renamed this response's `groupId` to `namespaceId`\n // (core#3598). Bind whichever spelling the node actually sent rather than\n // picking one: the rename lands as `undefined` on the field the client\n // reads, and nothing errors \u2014 no 4xx, no thrown parse \u2014 so a client that\n // knows only one spelling fails much later and somewhere else. Normalising\n // here means one mero-js works against nodes either side of that release.\n if (data && data.namespaceId === undefined && data.groupId !== undefined) {\n return { ...data, namespaceId: data.groupId };\n }\n return data;\n }\n\n async createGroupInNamespace(\n namespaceId: string,\n request?: CreateGroupInNamespaceRequest,\n ): Promise<CreateGroupInNamespaceResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: CreateGroupInNamespaceResponseData }>(\n `/admin-api/namespaces/${namespaceId}/groups`,\n request ?? {},\n ),\n );\n }\n\n async listNamespaceGroups(namespaceId: string): Promise<SubgroupEntry[]> {\n return unwrap(await this.httpClient.get<{ data: SubgroupEntry[] }>(`/admin-api/namespaces/${namespaceId}/groups`));\n }\n\n // ---- Account Devices & Pairing ----\n\n /**\n * Mint this node a device for an account that already lives somewhere else -\n * the first half of pairing, run on the joining node.\n *\n * Publishes nothing and needs no key: it produces the device id, the two\n * public keys and the signature that the account holder's\n * {@link completeAccountPairing} certifies, plus a code to read out to them\n * over a channel the payload does not travel on. Until that second half runs,\n * the device this mints is inert.\n *\n * Takes a set of namespaces rather than one, and takes it from the caller\n * because this node cannot discover it: a node that is a member of nothing can\n * neither read the account's namespace set off a DAG nor derive it. One device\n * covers however many are named - the certificate is over the account, not a\n * scope - so there is one id and one code to hand over regardless.\n */\n async initAccountPairing(request: AccountPairInitRequest): Promise<AccountPairInitResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: AccountPairInitResponseData }>('/admin-api/account/pair-init', request),\n );\n }\n\n /**\n * Certify a device another node minted, link it, and deliver its scope keys -\n * the second half of pairing, run on the node that holds the account root.\n *\n * Every field but `applications` is copied verbatim out of that node's\n * {@link initAccountPairing} answer. Only this side can complete it: the\n * certificate is signed by the account root, which never leaves the node that\n * holds it.\n *\n * The scope is named in applications, not namespaces, because that is the\n * question a person can answer - a namespace is an implementation unit they\n * never chose. Leave it out to grant every application.\n */\n async completeAccountPairing(\n request: AccountPairCompleteRequest,\n ): Promise<AccountPairCompleteResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: AccountPairCompleteResponseData }>('/admin-api/account/pair-complete', request),\n );\n }\n\n /**\n * Re-run the pairing fan-out for a device this account already certified,\n * against the namespaces this node takes part in now.\n *\n * Pairing is a snapshot, and this is how it is repeated. A namespace created\n * or joined afterwards holds no binding for a device paired before it, and the\n * symptom is silence - the device simply never sees that namespace. Nothing\n * but the id is needed to repair it: the certificate is already held here,\n * root-signed and naming no namespace, so a fresh endorsement and a key wrap\n * are all a later namespace is missing. The device does not have to be online.\n *\n * Passing `applications` widens the device's stored scope as well as\n * repairing. Passing none - or an empty list - repairs against the scope\n * already stored, which is deliberately NOT the \"every application\" that an\n * empty list means on {@link completeAccountPairing}: overloading it here\n * would make the accidental request the widest one.\n */\n async relinkAccountDevice(\n deviceId: string,\n request?: RelinkDeviceRequest,\n ): Promise<RelinkDeviceResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: RelinkDeviceResponseData }>(\n `/admin-api/account/devices/${deviceId}/relink`,\n request ?? {},\n ),\n );\n }\n\n /**\n * Every device of this account, as this node sees them - its own included.\n *\n * Joined from the node-local certificate cache and the live bindings of every\n * namespace this node takes part in, so it is this node's view rather than a\n * global one: a device certified by another holder appears with an empty\n * `applications`, because the certificate that would name its scope is not\n * cached here.\n *\n * The wire wraps this in `devices` rather than the usual `data`; the array is\n * what a caller wants, so that wrapper is not passed on.\n */\n async listAccountDevices(): Promise<AccountDeviceEntry[]> {\n const response = await this.httpClient.get<{ devices: AccountDeviceEntry[] }>('/admin-api/account/devices');\n return response.devices;\n }\n\n /**\n * Every application this account speaks in, with the namespaces targeting each.\n *\n * What a device-scoping UI lists: {@link completeAccountPairing} and\n * {@link relinkAccountDevice} both take applications, and this is where the\n * ids they take come from. Derived from the namespaces this node takes part\n * in, so an application installed with no namespace yet is absent - it has\n * nothing to scope a device to until one exists.\n *\n * Wrapped in `applications` on the wire rather than `data`, unwrapped here for\n * the same reason {@link listAccountDevices} unwraps `devices`.\n */\n async listAccountApplications(): Promise<AccountApplicationEntry[]> {\n const response = await this.httpClient.get<{ applications: AccountApplicationEntry[] }>(\n '/admin-api/account/applications',\n );\n return response.applications;\n }\n\n /**\n * Withdraw a device from this account, terminally.\n *\n * Two authorities reach the same endpoint. An admin may revoke any device and\n * rotates the scope key as it goes. The account holder may revoke its own with\n * a root-signed `proof`, which does not rotate - so read\n * {@link RevokeAccountDeviceResponseData.revokedIn} rather than assuming the\n * device lost its access: a namespace reporting `keyRotated: false` has\n * stopped the device writing but leaves it able to read until an admin\n * rotates.\n *\n * `namespaceId` names where to publish from, not the extent of the revocation:\n * a device belongs to the account, so every namespace holding a binding for it\n * is withdrawn from and reported back.\n */\n async revokeAccountDevice(\n namespaceId: string,\n request: RevokeAccountDeviceRequest,\n ): Promise<RevokeAccountDeviceResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: RevokeAccountDeviceResponseData }>(\n `/admin-api/namespaces/${namespaceId}/account/revoke`,\n request,\n ),\n );\n }\n\n // ---- Group Management ----\n\n async getGroupInfo(groupId: string): Promise<GroupInfoResponseData> {\n return unwrap(await this.httpClient.get<{ data: GroupInfoResponseData }>(`/admin-api/groups/${groupId}`));\n }\n\n /** Thin wrapper over {@link getGroupInfo}: returns the group's `defaultCapabilities` bitmask. */\n async getDefaultCapabilities(groupId: string): Promise<number> {\n return (await this.getGroupInfo(groupId)).defaultCapabilities;\n }\n\n /** Thin wrapper over {@link getGroupInfo}: returns the group's `subgroupVisibility`. */\n async getSubgroupVisibility(groupId: string): Promise<string> {\n return (await this.getGroupInfo(groupId)).subgroupVisibility;\n }\n\n async deleteGroup(groupId: string): Promise<DeleteGroupResponseData> {\n // Core requires `Content-Type: application/json` on this DELETE even though\n // the body is always empty, so send the header and an empty JSON object.\n return unwrap(\n await this.httpClient.request<{ data: DeleteGroupResponseData }>(`/admin-api/groups/${groupId}`, {\n method: 'DELETE',\n body: '{}',\n headers: { 'Content-Type': 'application/json' },\n }),\n );\n }\n\n async listGroupMembers(groupId: string): Promise<ListGroupMembersResponseData> {\n const response = await this.httpClient.get<ListGroupMembersResponseData>(\n `/admin-api/groups/${groupId}/members`,\n );\n // Validate the field we declare as non-optional in the type so a\n // contract-violating response (proxy error body, future API drift,\n // etc.) surfaces as a clear error rather than silently producing an\n // empty list. Empty groups still satisfy this \u2014 merod returns\n // `members: []`, not an omitted field.\n if (!Array.isArray(response?.members)) {\n // Sanitize before interpolation: groupId reaches us from caller code,\n // not parsed input, but defending the message keeps untrusted bytes\n // out of error logs and downstream UIs.\n const safeId = String(groupId).replace(/[\\r\\n\\t\\s]/g, '').slice(0, 64);\n throw new Error(\n `Invalid listGroupMembers response for group ${safeId}: missing or non-array \\`members\\` field`,\n );\n }\n return response;\n }\n\n async listGroupContexts(groupId: string): Promise<ListGroupContextsResponseData> {\n return unwrap(await this.httpClient.get<{ data: ListGroupContextsResponseData }>(`/admin-api/groups/${groupId}/contexts`));\n }\n\n async addGroupMembers(groupId: string, request: AddGroupMembersRequest): Promise<void> {\n await this.httpClient.post(`/admin-api/groups/${groupId}/members`, request);\n }\n\n async removeGroupMembers(groupId: string, request: RemoveGroupMembersRequest): Promise<void> {\n await this.httpClient.post(`/admin-api/groups/${groupId}/members/remove`, request);\n }\n\n /**\n * `identity` is the member's ACCOUNT (64 hex), as returned by\n * {@link listGroupMembers} \u2014 not the signing key that added them. Both are\n * 64 hex, so nothing but the source tells them apart.\n */\n async updateMemberRole(\n groupId: string,\n identity: string,\n request: UpdateMemberRoleRequest,\n ): Promise<void> {\n await this.httpClient.put(`/admin-api/groups/${groupId}/members/${identity}/role`, request);\n }\n\n /**\n * `identity` is the member's ACCOUNT (64 hex), as returned by\n * {@link listGroupMembers} \u2014 not the signing key that added them. Both are\n * 64 hex, so nothing but the source tells them apart.\n */\n async getMemberCapabilities(groupId: string, identity: string): Promise<MemberCapabilities> {\n return unwrap(\n await this.httpClient.get<{ data: MemberCapabilities }>(\n `/admin-api/groups/${groupId}/members/${identity}/capabilities`,\n ),\n );\n }\n\n /**\n * `identity` is the member's ACCOUNT (64 hex), as returned by\n * {@link listGroupMembers} \u2014 not the signing key that added them. Both are\n * 64 hex, so nothing but the source tells them apart.\n */\n async setMemberCapabilities(\n groupId: string,\n identity: string,\n request: SetMemberCapabilitiesRequest,\n ): Promise<void> {\n await this.httpClient.put(`/admin-api/groups/${groupId}/members/${identity}/capabilities`, request);\n }\n\n async setDefaultCapabilities(\n groupId: string,\n request: SetDefaultCapabilitiesRequest,\n ): Promise<void> {\n await this.httpClient.put(`/admin-api/groups/${groupId}/settings/default-capabilities`, request);\n }\n\n async setSubgroupVisibility(\n groupId: string,\n request: SetSubgroupVisibilityRequest,\n ): Promise<void> {\n await this.httpClient.put(`/admin-api/groups/${groupId}/settings/subgroup-visibility`, request);\n }\n\n async setTeeAdmissionPolicy(\n groupId: string,\n request: SetTeeAdmissionPolicyRequest,\n ): Promise<void> {\n await this.httpClient.put(`/admin-api/groups/${groupId}/settings/tee-admission-policy`, request);\n }\n\n async getTeeAdmissionPolicy(groupId: string): Promise<GetTeeAdmissionPolicyResponseData> {\n // Intersection (not union) so the type is unambiguous: `data` is optional, so\n // `?? response` cleanly falls back to a flat (un-enveloped) response.\n const response = await this.httpClient.get<\n GetTeeAdmissionPolicyResponseData & { data?: GetTeeAdmissionPolicyResponseData }\n >(`/admin-api/groups/${groupId}/settings/tee-admission-policy`);\n return response.data ?? response;\n }\n\n // ---- Group / member / context metadata ----\n\n async setGroupMetadata(groupId: string, request: SetGroupMetadataRequest): Promise<void> {\n await this.httpClient.put(`/admin-api/groups/${groupId}/metadata`, request);\n }\n\n async getGroupMetadata(groupId: string): Promise<MetadataRecord | null> {\n // Core single-envelopes the record: `{ data: MetadataRecord | null }`.\n // \"No record yet\" is `{ data: null }` (or a bare null body on older nodes),\n // so optional-chain to a clean null. Returns the full record (name + data +\n // updatedAt/updatedBy), not just the data map.\n const response = await this.httpClient.get<GetMetadataResponseData | null>(\n `/admin-api/groups/${groupId}/metadata`,\n );\n return response?.data ?? null;\n }\n\n async setMemberMetadata(\n groupId: string,\n identity: string,\n request: SetMemberMetadataRequest,\n ): Promise<void> {\n await this.httpClient.put(`/admin-api/groups/${groupId}/members/${identity}/metadata`, request);\n }\n\n /**\n * `identity` is the member's ACCOUNT (64 hex), as returned by\n * {@link listGroupMembers} \u2014 not the signing key that added them. Both are\n * 64 hex, so nothing but the source tells them apart.\n */\n async getMemberMetadata(groupId: string, identity: string): Promise<MetadataRecord | null> {\n // Single-enveloped record; see getGroupMetadata.\n const response = await this.httpClient.get<GetMetadataResponseData | null>(\n `/admin-api/groups/${groupId}/members/${identity}/metadata`,\n );\n return response?.data ?? null;\n }\n\n async setContextMetadata(\n groupId: string,\n contextId: string,\n request: SetContextMetadataRequest,\n ): Promise<void> {\n await this.httpClient.put(`/admin-api/groups/${groupId}/contexts/${contextId}/metadata`, request);\n }\n\n async getContextMetadata(groupId: string, contextId: string): Promise<MetadataRecord | null> {\n // Single-enveloped record; see getGroupMetadata.\n const response = await this.httpClient.get<GetMetadataResponseData | null>(\n `/admin-api/groups/${groupId}/contexts/${contextId}/metadata`,\n );\n return response?.data ?? null;\n }\n\n async syncGroup(groupId: string): Promise<SyncGroupResponseData> {\n return unwrap(await this.httpClient.post<{ data: SyncGroupResponseData }>(`/admin-api/groups/${groupId}/sync`, {}));\n }\n\n async upgradeGroup(groupId: string, request: UpgradeGroupRequest): Promise<UpgradeGroupResponseData> {\n return unwrap(await this.httpClient.post<{ data: UpgradeGroupResponseData }>(`/admin-api/groups/${groupId}/upgrade`, request));\n }\n\n async getGroupUpgradeStatus(groupId: string): Promise<GroupUpgradeStatusResponseData> {\n return unwrap(\n await this.httpClient.get<{ data: GroupUpgradeStatusResponseData }>(`/admin-api/groups/${groupId}/upgrade/status`),\n );\n }\n\n /**\n * The operator-facing \"have all peers migrated?\" rollup for a namespace.\n * The handler serializes the payload directly, so there is no `{ data }`\n * envelope to unwrap here (unlike most admin reads).\n */\n async getMigrationStatus(namespaceId: string): Promise<MigrationStatus> {\n const id = encodeURIComponent(namespaceId);\n return this.httpClient.get<MigrationStatus>(`/admin-api/groups/${id}/migration-status`);\n }\n\n /** Per-group cascade-migration snapshots for a namespace. */\n async getCascadeStatus(namespaceId: string): Promise<CascadeStatusEntry[]> {\n const id = encodeURIComponent(namespaceId);\n return unwrap(\n await this.httpClient.get<{ data: CascadeStatusEntry[] }>(`/admin-api/groups/${id}/cascade-status`),\n );\n }\n\n async retryGroupUpgrade(groupId: string): Promise<RetryGroupUpgradeResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: RetryGroupUpgradeResponseData }>(\n `/admin-api/groups/${groupId}/upgrade/retry`,\n {},\n ),\n );\n }\n\n /** Move `childGroupId` under `request.newParentId`. */\n async reparentGroup(\n childGroupId: string,\n request: ReparentGroupRequest,\n ): Promise<ReparentGroupResponseData> {\n // Core returns this flat ({ reparented }); tolerate the { data } envelope too.\n const r = await this.httpClient.post<\n ReparentGroupResponseData & { data?: ReparentGroupResponseData }\n >(`/admin-api/groups/${childGroupId}/reparent`, request);\n return (r?.data ?? r) as ReparentGroupResponseData;\n }\n\n async listSubgroups(groupId: string): Promise<SubgroupEntry[]> {\n const response = await this.httpClient.get<{ subgroups?: SubgroupEntry[]; data?: SubgroupEntry[] }>(\n `/admin-api/groups/${groupId}/subgroups`,\n );\n return response.subgroups ?? response.data ?? [];\n }\n\n async detachContextFromGroup(groupId: string, contextId: string): Promise<void> {\n await this.httpClient.post(`/admin-api/groups/${groupId}/contexts/${contextId}/remove`, {});\n }\n\n // ---- Group Invitation & Join ----\n\n async createGroupInvitation(\n groupId: string,\n request?: CreateGroupInvitationRequest,\n ): Promise<CreateGroupInvitationResponseData | CreateRecursiveGroupInvitationResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: CreateGroupInvitationResponseData | CreateRecursiveGroupInvitationResponseData }>(\n `/admin-api/groups/${groupId}/invite`,\n request ?? {},\n ),\n );\n }\n\n async joinGroup(request: JoinGroupRequest): Promise<JoinGroupResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: JoinGroupResponseData }>('/admin-api/groups/join', request),\n );\n }\n\n async joinSubgroupInheritance(groupId: string): Promise<JoinSubgroupInheritanceResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: JoinSubgroupInheritanceResponseData }>(\n `/admin-api/groups/${groupId}/join-via-inheritance`,\n {},\n ),\n );\n }\n\n // ---- TEE ----\n\n async getTeeInfo(): Promise<TeeInfoResponseData> {\n return unwrap(await this.httpClient.get<{ data: TeeInfoResponseData }>('/admin-api/tee/info'));\n }\n\n async teeAttest(request: TeeAttestRequest): Promise<TeeAttestResponseData> {\n return unwrap(await this.httpClient.post<{ data: TeeAttestResponseData }>('/admin-api/tee/attest', request));\n }\n\n async teeVerifyQuote(request: TeeVerifyQuoteRequest): Promise<TeeVerifyQuoteResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: TeeVerifyQuoteResponseData }>('/admin-api/tee/verify-quote', request),\n );\n }\n\n // ---- Network ----\n\n async getPeersCount(): Promise<{ count: number }> {\n return this.httpClient.get<{ count: number }>('/admin-api/peers');\n }\n\n /** Node network status (GET /admin-api/network/status). */\n async getNetworkStatus(): Promise<unknown> {\n return this.httpClient.get<unknown>('/admin-api/network/status');\n }\n\n /** Node storage/usage stats (GET /admin-api/usage). */\n async getUsage(): Promise<unknown> {\n return this.httpClient.get<unknown>('/admin-api/usage');\n }\n\n /** Node TLS certificate, PEM text (GET /admin-api/certificate). */\n async getCertificate(): Promise<string> {\n return this.httpClient.get<string>('/admin-api/certificate', { parse: 'text' });\n }\n\n // ---- Group / context / namespace membership ----\n\n /** Create a standalone group (POST /admin-api/groups). */\n async createGroup(request: CreateGroupRequest): Promise<CreateGroupResponseData> {\n return unwrap(\n await this.httpClient.post<{ data: CreateGroupResponseData }>('/admin-api/groups', request),\n );\n }\n\n /** Leave a group (POST /admin-api/groups/:group_id/leave). */\n async leaveGroup(groupId: string): Promise<void> {\n await this.httpClient.post(`/admin-api/groups/${groupId}/leave`, {});\n }\n\n /** Leave a context (POST /admin-api/contexts/:context_id/leave). */\n async leaveContext(contextId: string): Promise<void> {\n await this.httpClient.post(`/admin-api/contexts/${contextId}/leave`, {});\n }\n\n /** Leave a namespace (POST /admin-api/namespaces/:namespace_id/leave). */\n async leaveNamespace(namespaceId: string): Promise<void> {\n await this.httpClient.post(`/admin-api/namespaces/${namespaceId}/leave`, {});\n }\n\n /** Issue a group ownership proof (POST /admin-api/groups/:group_id/issue-ownership-proof). */\n async issueOwnershipProof(\n groupId: string,\n request: IssueOwnershipProofRequest,\n ): Promise<IssueOwnershipProofResponseData> {\n return this.httpClient.post<IssueOwnershipProofResponseData>(\n `/admin-api/groups/${groupId}/issue-ownership-proof`,\n request,\n );\n }\n\n /** Issue a namespace ownership proof (POST /admin-api/groups/:group_id/issue-namespace-ownership-proof). */\n async issueNamespaceOwnershipProof(\n groupId: string,\n request: IssueNamespaceOwnershipProofRequest,\n ): Promise<IssueOwnershipProofResponseData> {\n return this.httpClient.post<IssueOwnershipProofResponseData>(\n `/admin-api/groups/${groupId}/issue-namespace-ownership-proof`,\n request,\n );\n }\n\n /**\n * Set a member's auto-follow flag (PUT\n * /admin-api/groups/:group_id/members/:identity/auto-follow).\n *\n * `identity` is the member's ACCOUNT (64 hex), as returned by\n * {@link listGroupMembers} \u2014 not the signing key that added them. Both are\n * 64 hex, so nothing but the source tells them apart.\n */\n async setMemberAutoFollow(\n groupId: string,\n identity: string,\n request: SetMemberAutoFollowRequest,\n ): Promise<void> {\n await this.httpClient.put(`/admin-api/groups/${groupId}/members/${identity}/auto-follow`, request);\n }\n\n /** Abort a namespace migration (POST /admin-api/groups/:namespace_id/migration/abort). */\n async abortMigration(namespaceId: string): Promise<unknown> {\n return this.httpClient.post<unknown>(`/admin-api/groups/${namespaceId}/migration/abort`, {});\n }\n}\n", "import { AdminApiClient } from './admin-client.js';\nimport { AdminApiClientConfig } from './admin-types.js';\nimport {\n HttpClient,\n createBrowserHttpClient,\n createNodeHttpClient,\n createUniversalHttpClient,\n} from '../http-client/index.js';\n\n// Factory functions for creating Admin API clients\n\n/** Admin client over a browser HTTP transport (global `fetch`). */\nexport function createBrowserAdminApiClient(\n config: AdminApiClientConfig,\n): AdminApiClient {\n return new AdminApiClient(createBrowserHttpClient(config));\n}\n\n/** Admin client over a Node HTTP transport (Node 18+ `fetch`). */\nexport function createNodeAdminApiClient(\n config: AdminApiClientConfig,\n): AdminApiClient {\n return new AdminApiClient(createNodeHttpClient(config));\n}\n\n/** Admin client over whichever transport suits the current runtime. */\nexport function createAdminApiClient(\n config: AdminApiClientConfig,\n): AdminApiClient {\n return new AdminApiClient(createUniversalHttpClient(config));\n}\n\n/**\n * Admin client over a caller-supplied HTTP client \u2014 use this to share one\n * transport (and its token handling) with the other API clients.\n */\nexport function createAdminApiClientFromHttpClient(\n httpClient: HttpClient,\n _config: AdminApiClientConfig,\n): AdminApiClient {\n return new AdminApiClient(httpClient);\n}\n", "export interface AuthCallbackResult {\n accessToken: string;\n refreshToken: string;\n applicationId: string;\n contextId: string;\n contextIdentity: string;\n nodeUrl: string;\n}\n\nexport interface AuthLoginOptions {\n callbackUrl: string;\n packageName?: string;\n mode: string;\n permissions?: string[];\n registryUrl?: string;\n packageVersion?: string;\n}\n\n/**\n * Parse an auth callback URL hash fragment.\n * Returns null if access_token is missing.\n */\nexport function parseAuthCallback(url: string): AuthCallbackResult | null {\n try {\n const hashIndex = url.indexOf('#');\n if (hashIndex === -1) return null;\n\n const hash = url.substring(hashIndex + 1);\n const params = new URLSearchParams(hash);\n\n const accessToken = params.get('access_token');\n if (!accessToken) return null;\n\n return {\n accessToken,\n refreshToken: params.get('refresh_token') ?? '',\n applicationId: params.get('application_id') ?? '',\n contextId: params.get('context_id') ?? '',\n contextIdentity: params.get('context_identity') ?? '',\n nodeUrl: params.get('node_url') ?? '',\n };\n } catch {\n return null;\n }\n}\n\n/**\n * Build the auth login URL for redirecting users to the node's auth page.\n */\nexport function buildAuthLoginUrl(nodeUrl: string, opts: AuthLoginOptions): string {\n const params = new URLSearchParams();\n params.set('callback-url', opts.callbackUrl);\n\n if (opts.permissions && opts.permissions.length > 0) {\n params.set('permissions', opts.permissions.join(','));\n }\n\n params.set('mode', opts.mode);\n\n if (opts.packageName) {\n params.set('package-name', opts.packageName);\n if (opts.packageVersion) {\n params.set('package-version', opts.packageVersion);\n }\n if (opts.registryUrl) {\n params.set('registry-url', opts.registryUrl);\n }\n }\n\n // Trim trailing slash from nodeUrl\n const base = nodeUrl.replace(/\\/+$/, '');\n return `${base}/auth/login?${params.toString()}`;\n}\n", "import type { HttpClient } from '../http-client/index.js';\n\n/** Result of the owner-driven `migrate_my_entries` convert (counts are u32). */\nexport interface MigrateMyEntriesSummary {\n converted: number;\n remaining: number;\n}\n\nexport interface ExecuteParams {\n contextId: string;\n method: string;\n argsJson?: Record<string, unknown>;\n /** @deprecated No longer used by the server. Ignored if provided. */\n executorPublicKey?: string;\n}\n\nexport class RpcError extends Error {\n code: number;\n type?: string;\n data?: unknown;\n\n constructor(code: number, message: string, data?: unknown, type?: string) {\n super(message);\n this.name = 'RpcError';\n this.code = code;\n this.data = data;\n this.type = type;\n }\n}\n\ninterface JsonRpcResponse {\n jsonrpc: string;\n id: number;\n result?: {\n output?: unknown;\n [key: string]: unknown;\n };\n error?: {\n // Standard JSON-RPC fields\n code?: number;\n message?: string;\n // Server-specific fields\n type?: string;\n data?: unknown;\n };\n}\n\n/**\n * POST a JSON-RPC call and unwrap `result`, converting an `error` payload into\n * an `RpcError`. The node returns `{ type, data }` (not always `{ code,\n * message }`), so this is the one place that normalization lives \u2014 every\n * JSON-RPC caller in this SDK shares it rather than re-deriving a bare\n * `Error(message)` and dropping the typed detail.\n */\nexport async function jsonRpcCall<T>(\n httpClient: HttpClient,\n method: string,\n params: unknown,\n): Promise<T> {\n const response = await httpClient.post<JsonRpcResponse>('/jsonrpc', {\n jsonrpc: '2.0',\n id: 1,\n method,\n params,\n });\n\n if (response.error) {\n const err = response.error;\n throw new RpcError(err.code ?? -1, err.message ?? err.type ?? 'RPC error', err.data, err.type);\n }\n\n return response.result as T;\n}\n\nexport class RpcClient {\n private httpClient: HttpClient;\n\n constructor(opts: { httpClient: HttpClient }) {\n this.httpClient = opts.httpClient;\n }\n\n async execute<T = unknown>(params: ExecuteParams): Promise<T> {\n const result = await jsonRpcCall<JsonRpcResponse['result']>(this.httpClient, 'execute', {\n contextId: params.contextId,\n method: params.method,\n argsJson: params.argsJson ?? {},\n });\n\n if (result && 'output' in result) {\n return result.output as T;\n }\n\n return result as T;\n }\n\n /**\n * One-tap owner-driven convert: re-signs the caller's identity-gated entries\n * to the current schema. The export converts all of the caller's\n * below-target entries in a single sweep, so this issues one call and returns\n * the resulting summary \u2014 it does not loop.\n */\n async migrateMyEntries(contextId: string): Promise<MigrateMyEntriesSummary> {\n return this.execute<MigrateMyEntriesSummary>({ contextId, method: 'migrate_my_entries' });\n }\n\n /** Read-only count of the caller's entries still below the target schema. */\n async countMyPending(contextId: string): Promise<number> {\n return this.execute<number>({ contextId, method: 'count_my_pending' });\n }\n}\n", "/** Parsed group-membership event (core's untagged `NodeEvent` group variant). */\nexport interface GroupMembershipEventData {\n groupId: string;\n type: 'MemberJoined' | 'MemberAdded' | 'MemberRemoved';\n data: {\n /** The member's ACCOUNT, hex-encoded 32 bytes (64 chars) - the principal the\n * governance rows name. Not a signing key: the field this replaced\n * carried one, and both are strings, so the rename is what makes a stale\n * consumer fail loudly instead of comparing accounts against keys forever. */\n memberAccount: string;\n /** Absent on `MemberRemoved`, and on a `MemberJoined` inherited from an Open\n * subgroup. Core's set is closed. */\n role?: 'Admin' | 'Member' | 'ReadOnly' | 'ReadOnlyTee';\n };\n}\n\n/**\n * A migration was accepted and its target ABI state version resolved.\n * `toStateVersion` is the `#[app::state(version = N)]` number, not the bundle\n * semver (`toVersion`).\n */\nexport interface MigrationStartedData {\n fromVersion: string;\n toVersion: string;\n toStateVersion: number;\n /** Contexts the EMITTING NODE enumerated for the migration. Node-local, never\n * the fleet cohort size that `MigrationProgressData.total` carries. */\n localContextsTotal: number;\n}\n\n/**\n * Fleet rollup counters, recomputed as peers' heartbeat facts change. Counters\n * only: the per-member detail behind them stays in the admin-gated\n * `getMigrationStatus` read.\n */\nexport interface MigrationProgressData {\n migrated: number;\n inProgress: number;\n unknown: number;\n failed: number;\n /** The pinned FLEET COHORT size, never a node-local context count like\n * `MigrationStartedData.localContextsTotal`. */\n total: number;\n}\n\n/**\n * One subgroup's local context swaps advanced on the emitting node.\n *\n * Admin-only: it names a descendant subgroup, which a plain namespace member\n * may not enumerate, so core withholds it from non-admin subscribers. A\n * non-admin never receiving this variant is correct behaviour, not a gap.\n */\nexport interface CascadeProgressData {\n /** Hex-encoded descendant subgroup id, never the namespace root the event is\n * keyed on. */\n subgroupId: string;\n localContextsSwapped: number;\n /** Contexts the emitting node holds for THIS SUBGROUP. Node-local and\n * per-subgroup; unrelated to both sibling totals. */\n localContextsTotal: number;\n}\n\n/** Every pinned-cohort member reported the target version. */\nexport interface MigrationCompletedData {\n toVersion: string;\n /** FLEET convergence, in seconds since the epoch: the same stamp\n * `MigrationStatus.fleetCompletedAt` returns. Not `GroupUpgradeStatus.completedAt`,\n * which is this node's own local swap completion. */\n completedAt: number;\n}\n\n/**\n * Parsed group-migration event (core's `GroupMigration` `NodeEvent` variant),\n * keyed on the namespace root a client subscribes with.\n *\n * `MigrationStarted`, `MigrationProgress` and `MigrationCompleted` reach every\n * subscribed member; `CascadeProgress` reaches namespace admins only.\n */\nexport type GroupMigrationEventData =\n | { groupId: string; type: 'MigrationStarted'; data: MigrationStartedData }\n | { groupId: string; type: 'MigrationProgress'; data: MigrationProgressData }\n | { groupId: string; type: 'CascadeProgress'; data: CascadeProgressData }\n | { groupId: string; type: 'MigrationCompleted'; data: MigrationCompletedData };\n\nconst MIGRATION_EVENT_TYPES: ReadonlySet<string> = new Set([\n 'MigrationStarted',\n 'MigrationProgress',\n 'CascadeProgress',\n 'MigrationCompleted',\n]);\n\n/** Narrows a raw `'event'` payload to the group-migration family by its tag. */\nexport function isGroupMigrationEvent(\n event: { type?: string },\n): event is GroupMigrationEventData {\n return event.type !== undefined && MIGRATION_EVENT_TYPES.has(event.type);\n}\n", "import type { GroupMembershipEventData, GroupMigrationEventData } from './group.js';\nimport { isGroupMigrationEvent } from './group.js';\nimport { AuthRevokedError, HTTPError } from '../http-client/index.js';\n\n/**\n * `x-auth-error` reasons that mean the whole token family is gone, mirroring\n * the request path in `web-client.ts`. Anything else \u2014 `token_expired` above\n * all \u2014 is recoverable by refreshing and reconnecting.\n */\nconst TERMINAL_AUTH_ERRORS = new Set(['token_reuse', 'token_revoked']);\n\nexport type { GroupMembershipEventData, GroupMigrationEventData };\n\nexport interface SseEventData {\n contextId: string;\n /** The context-event discriminator (core serializes it as a sibling of\n * `data`, e.g. `\"AppVersionChanged\"`). Undefined for events without a tag. */\n type?: string;\n data: unknown;\n}\n\n/** Parsed `AppVersionChanged` context event (bundle-version flip; skew #2). */\nexport interface AppVersionChangedEvent {\n contextId: string;\n fromVersion?: string;\n toVersion?: string;\n}\n\n/** Anything the `'event'` stream can deliver: context events plus the\n * group-keyed membership and migration families. */\ntype SseEvent = SseEventData | GroupMembershipEventData | GroupMigrationEventData;\ntype SseEventHandler = (event: SseEvent) => void;\ntype SseConnectHandler = (sessionId: string) => void;\ntype SseErrorHandler = (error: Error) => void;\n\ninterface SseListeners {\n connect: SseConnectHandler[];\n event: SseEventHandler[];\n error: SseErrorHandler[];\n}\n\nexport class SseClient {\n private baseUrl: string;\n private getAuthToken: () => Promise<string>;\n private reconnectDelayMs: number;\n private sessionId: string | null = null;\n private abortController: AbortController | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private subscribedContextIds: Set<string> = new Set();\n private subscribedGroupIds: Set<string> = new Set();\n private closed = false;\n private listeners: SseListeners = { connect: [], event: [], error: [] };\n\n constructor(opts: {\n baseUrl: string;\n getAuthToken: () => Promise<string>;\n reconnectDelayMs?: number;\n }) {\n this.baseUrl = opts.baseUrl.replace(/\\/+$/, '');\n this.getAuthToken = opts.getAuthToken;\n this.reconnectDelayMs = opts.reconnectDelayMs ?? 3000;\n }\n\n on(event: 'connect', handler: SseConnectHandler): void;\n on(event: 'event', handler: SseEventHandler): void;\n on(event: 'error', handler: SseErrorHandler): void;\n on(event: string, handler: SseConnectHandler | SseEventHandler | SseErrorHandler): void {\n const key = event as keyof SseListeners;\n if (key in this.listeners) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const arr = this.listeners[key] as any[];\n if (!arr.includes(handler)) arr.push(handler);\n }\n }\n\n off(event: 'connect', handler: SseConnectHandler): void;\n off(event: 'event', handler: SseEventHandler): void;\n off(event: 'error', handler: SseErrorHandler): void;\n off(event: string, handler: SseConnectHandler | SseEventHandler | SseErrorHandler): void {\n const key = event as keyof SseListeners;\n if (key in this.listeners) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const arr = this.listeners[key] as any[];\n const idx = arr.indexOf(handler);\n if (idx !== -1) arr.splice(idx, 1);\n }\n }\n\n /**\n * Typed convenience over the generic `'event'` stream: invokes `handler` only\n * for `AppVersionChanged` context events, with the payload already parsed.\n * Returns an unsubscribe closure (so callers need not retain the listener).\n */\n onAppVersionChanged(handler: (e: AppVersionChangedEvent) => void): () => void {\n const listener: SseEventHandler = (ev) => {\n // Core flattens the tagged payload: the event carries `type` as a sibling\n // of `data`, and `data` is the `{ fromVersion?, toVersion? }` payload.\n if (ev.type !== 'AppVersionChanged') return;\n const d = ev.data as { fromVersion?: string; toVersion?: string } | undefined;\n handler({ contextId: ev.contextId, fromVersion: d?.fromVersion, toVersion: d?.toVersion });\n };\n this.on('event', listener);\n return () => this.off('event', listener);\n }\n\n /**\n * Typed convenience over the generic `'event'` stream: invokes `handler` only\n * for group-migration events, narrowed on `type` so `data` is the matching\n * payload. Returns an unsubscribe closure.\n *\n * A non-admin subscriber sees `MigrationStarted`, `MigrationProgress` and\n * `MigrationCompleted` but never `CascadeProgress`, which core delivers to\n * namespace admins only.\n */\n onMigrationEvent(handler: (e: GroupMigrationEventData) => void): () => void {\n const listener: SseEventHandler = (ev) => {\n if (isGroupMigrationEvent(ev)) handler(ev);\n };\n this.on('event', listener);\n return () => this.off('event', listener);\n }\n\n private emit(event: 'connect', sessionId: string): void;\n private emit(event: 'event', data: SseEvent): void;\n private emit(event: 'error', error: Error): void;\n private emit(event: string, arg?: string | SseEvent | Error): void {\n const key = event as keyof SseListeners;\n if (key in this.listeners) {\n for (const handler of this.listeners[key]) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (handler as any)(arg);\n } catch {\n // Swallow handler errors\n }\n }\n }\n }\n\n async connect(): Promise<void> {\n // Already connected \u2014 don't reconnect\n if (this.abortController && !this.closed) {\n return;\n }\n this.closed = false;\n this.abortController = new AbortController();\n\n try {\n const token = await this.getAuthToken();\n const url = `${this.baseUrl}/sse`;\n const response = await fetch(url, {\n headers: {\n 'Authorization': `Bearer ${token}`,\n 'Accept': 'text/event-stream',\n },\n signal: this.abortController.signal,\n });\n\n if (!response.ok) {\n // Throw the same typed errors the request path throws. A bare\n // `Error(\"SSE connection failed: 401\")` forced callers to string-match\n // the status and guess what it meant, and the honest guess \u2014 treat any\n // 401 as fatal \u2014 logs the user out on a routine reconnect after the\n // access token ages out, discarding a refresh token that was still\n // good. The distinction is in the header; surface it.\n const authError = response.headers.get('x-auth-error');\n const bodyText = await response.text().catch(() => undefined);\n\n if (\n response.status === 401 &&\n authError &&\n TERMINAL_AUTH_ERRORS.has(authError)\n ) {\n throw new AuthRevokedError(\n authError,\n response.status,\n response.statusText,\n url,\n response.headers,\n bodyText,\n );\n }\n\n throw new HTTPError(\n response.status,\n response.statusText,\n url,\n response.headers,\n bodyText,\n );\n }\n\n if (!response.body) {\n throw new Error('SSE response has no body');\n }\n\n this.readStream(response.body).catch((err) => {\n if (this.closed) return;\n const error = err instanceof Error ? err : new Error(String(err));\n this.emit('error', error);\n this.scheduleReconnect();\n });\n } catch (err) {\n if (this.closed) return;\n const error = err instanceof Error ? err : new Error(String(err));\n this.emit('error', error);\n this.scheduleReconnect();\n }\n }\n\n private async readStream(body: ReadableStream<Uint8Array>): Promise<void> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n const lines = buffer.split('\\n');\n // Keep the last partial line in the buffer\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n if (line.startsWith('data:')) {\n const jsonStr = line.slice(5).trim();\n if (jsonStr) {\n this.handleMessage(jsonStr);\n }\n }\n }\n }\n // Flush remaining bytes from the decoder\n buffer += decoder.decode();\n if (buffer.startsWith('data:')) {\n const jsonStr = buffer.slice(5).trim();\n if (jsonStr) {\n this.handleMessage(jsonStr);\n }\n }\n } catch (err) {\n if (this.closed) return;\n const error = err instanceof Error ? err : new Error(String(err));\n this.emit('error', error);\n }\n\n // Stream ended, reconnect\n if (!this.closed) {\n this.scheduleReconnect();\n }\n }\n\n private handleMessage(jsonStr: string): void {\n try {\n const msg = JSON.parse(jsonStr);\n\n // Connection message\n if (msg.type === 'connect' && msg.session_id) {\n this.sessionId = msg.session_id;\n this.emit('connect', msg.session_id);\n // Re-subscribe after reconnect\n if (this.subscribedContextIds.size > 0 || this.subscribedGroupIds.size > 0) {\n this.sendSubscription('subscribe', {\n contextIds: [...this.subscribedContextIds],\n groupIds: [...this.subscribedGroupIds],\n });\n }\n return;\n }\n\n if (!msg.result) return;\n\n let eventData = msg.result.data;\n // Decode byte-array data if needed\n if (Array.isArray(eventData)) {\n try {\n const bytes = new Uint8Array(eventData);\n const text = new TextDecoder().decode(bytes);\n eventData = JSON.parse(text);\n } catch {\n // Keep raw data\n }\n }\n\n // Context event message\n if (msg.result.contextId) {\n this.emit('event', {\n contextId: msg.result.contextId,\n // Forward the event tag (sibling of `data` in core's flattened\n // payload) so typed helpers like `onAppVersionChanged` can discriminate.\n type: msg.result.type,\n data: eventData,\n });\n return;\n }\n\n // Group-keyed event message (untagged NodeEvent's membership and\n // migration variants; the `type` tag tells them apart).\n if (msg.result.groupId) {\n this.emit('event', {\n groupId: msg.result.groupId,\n type: msg.result.type,\n data: eventData,\n });\n }\n } catch {\n // Invalid JSON, ignore\n }\n }\n\n async subscribe(idsOrOpts: string[] | { contextIds?: string[]; groupIds?: string[] }): Promise<void> {\n const opts = Array.isArray(idsOrOpts) ? { contextIds: idsOrOpts } : idsOrOpts;\n const newContextIds = (opts.contextIds ?? []).filter(id => !this.subscribedContextIds.has(id));\n const newGroupIds = (opts.groupIds ?? []).filter(id => !this.subscribedGroupIds.has(id));\n for (const id of opts.contextIds ?? []) {\n this.subscribedContextIds.add(id);\n }\n for (const id of opts.groupIds ?? []) {\n this.subscribedGroupIds.add(id);\n }\n if ((newContextIds.length > 0 || newGroupIds.length > 0) && this.sessionId) {\n await this.sendSubscription('subscribe', { contextIds: newContextIds, groupIds: newGroupIds });\n }\n }\n\n async unsubscribe(idsOrOpts: string[] | { contextIds?: string[]; groupIds?: string[] }): Promise<void> {\n const opts = Array.isArray(idsOrOpts) ? { contextIds: idsOrOpts } : idsOrOpts;\n const hadContextIds = (opts.contextIds ?? []).filter(id => this.subscribedContextIds.has(id));\n const hadGroupIds = (opts.groupIds ?? []).filter(id => this.subscribedGroupIds.has(id));\n for (const id of opts.contextIds ?? []) {\n this.subscribedContextIds.delete(id);\n }\n for (const id of opts.groupIds ?? []) {\n this.subscribedGroupIds.delete(id);\n }\n if ((hadContextIds.length > 0 || hadGroupIds.length > 0) && this.sessionId) {\n await this.sendSubscription('unsubscribe', { contextIds: hadContextIds, groupIds: hadGroupIds });\n }\n }\n\n private async sendSubscription(\n method: 'subscribe' | 'unsubscribe',\n ids: { contextIds?: string[]; groupIds?: string[] },\n ): Promise<void> {\n try {\n const token = await this.getAuthToken();\n const params: { contextIds?: string[]; groupIds?: string[] } = {};\n if (ids.contextIds && ids.contextIds.length > 0) params.contextIds = ids.contextIds;\n if (ids.groupIds && ids.groupIds.length > 0) params.groupIds = ids.groupIds;\n const response = await fetch(`${this.baseUrl}/sse/subscription`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n id: this.sessionId,\n method,\n params,\n }),\n });\n if (!response.ok) {\n this.emit('error', new Error(`SSE ${method} failed: ${response.status}`));\n }\n } catch (err) {\n this.emit('error', err instanceof Error ? err : new Error(`SSE ${method} failed`));\n }\n }\n\n private forceReconnect(): void {\n if (this.abortController) {\n this.abortController.abort();\n this.abortController = null;\n }\n this.sessionId = null;\n this.connect();\n }\n\n private scheduleReconnect(): void {\n if (this.closed) return;\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n }\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.forceReconnect();\n }, this.reconnectDelayMs);\n }\n\n close(): void {\n this.closed = true;\n if (this.abortController) {\n this.abortController.abort();\n this.abortController = null;\n }\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n this.sessionId = null;\n this.subscribedContextIds.clear();\n this.subscribedGroupIds.clear();\n }\n}\n", "import type { GroupMembershipEventData, GroupMigrationEventData } from './group.js';\n\nexport type { GroupMembershipEventData, GroupMigrationEventData };\n\nexport interface WsEventData {\n contextId: string;\n /** The context-event discriminator (core serializes it as a sibling of\n * `data`, e.g. `\"AppVersionChanged\"`). Undefined for events without a tag. */\n type?: string;\n data: unknown;\n}\n\n/** Anything the `'event'` stream can deliver: context events plus the\n * group-keyed membership and migration families. */\ntype WsEvent = WsEventData | GroupMembershipEventData | GroupMigrationEventData;\ntype WsEventHandler = (event: WsEvent) => void;\ntype WsConnectHandler = () => void;\ntype WsErrorHandler = (error: Error) => void;\n\ninterface WsListeners {\n connect: WsConnectHandler[];\n event: WsEventHandler[];\n error: WsErrorHandler[];\n}\n\n/**\n * @experimental WebSocket event client. The SSE client (`SseClient`) is the\n * recommended transport for production \u2014 use `MeroJs.events` instead of `MeroJs.ws`.\n */\nexport class WsClient {\n private baseUrl: string;\n private getAuthToken: () => Promise<string>;\n private ws: WebSocket | null = null;\n private closed = false;\n private reconnectAttempt = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private subscribedContextIds: Set<string> = new Set();\n private subscribedGroupIds: Set<string> = new Set();\n private listeners: WsListeners = { connect: [], event: [], error: [] };\n\n private static readonly MAX_BACKOFF_MS = 30000;\n\n constructor(opts: {\n baseUrl: string;\n getAuthToken: () => Promise<string>;\n }) {\n this.baseUrl = opts.baseUrl.replace(/\\/+$/, '');\n this.getAuthToken = opts.getAuthToken;\n }\n\n on(event: 'connect', handler: WsConnectHandler): void;\n on(event: 'event', handler: WsEventHandler): void;\n on(event: 'error', handler: WsErrorHandler): void;\n on(event: string, handler: WsConnectHandler | WsEventHandler | WsErrorHandler): void {\n const key = event as keyof WsListeners;\n if (key in this.listeners) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const arr = this.listeners[key] as any[];\n if (!arr.includes(handler)) arr.push(handler);\n }\n }\n\n off(event: 'connect', handler: WsConnectHandler): void;\n off(event: 'event', handler: WsEventHandler): void;\n off(event: 'error', handler: WsErrorHandler): void;\n off(event: string, handler: WsConnectHandler | WsEventHandler | WsErrorHandler): void {\n const key = event as keyof WsListeners;\n if (key in this.listeners) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const arr = this.listeners[key] as any[];\n const idx = arr.indexOf(handler);\n if (idx !== -1) arr.splice(idx, 1);\n }\n }\n\n private emit(event: 'connect'): void;\n private emit(event: 'event', data: WsEvent): void;\n private emit(event: 'error', error: Error): void;\n private emit(event: string, arg?: WsEvent | Error): void {\n const key = event as keyof WsListeners;\n if (key in this.listeners) {\n for (const handler of this.listeners[key]) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (handler as any)(arg);\n } catch {\n // Swallow handler errors\n }\n }\n }\n }\n\n async connect(): Promise<void> {\n if (this.ws && (this.ws.readyState === 0 /* CONNECTING */ || this.ws.readyState === 1 /* OPEN */)) {\n return;\n }\n this.closed = false;\n\n try {\n const token = await this.getAuthToken();\n if (!token) {\n throw new Error('No authentication token available for WebSocket connection');\n }\n // Browser WebSocket API can't set headers, use query param\n const wsUrl = this.baseUrl.replace(/^http/, 'ws');\n this.ws = new WebSocket(`${wsUrl}/ws?token=${encodeURIComponent(token)}`);\n\n this.ws.onopen = () => {\n this.reconnectAttempt = 0;\n this.emit('connect');\n this.resubscribeAfterReconnect();\n };\n\n this.ws.onmessage = (event) => {\n this.handleMessage(event.data);\n };\n\n this.ws.onerror = () => {\n this.emit('error', new Error('WebSocket error'));\n };\n\n this.ws.onclose = () => {\n if (!this.closed) {\n this.scheduleReconnect();\n }\n };\n } catch (err) {\n if (this.closed) return;\n const error = err instanceof Error ? err : new Error(String(err));\n this.emit('error', error);\n this.scheduleReconnect();\n }\n }\n\n private handleMessage(raw: string | ArrayBuffer | Blob): void {\n if (typeof raw !== 'string') return;\n\n try {\n const msg = JSON.parse(raw);\n\n if (!msg.result) return;\n\n let eventData = msg.result.data;\n if (Array.isArray(eventData)) {\n try {\n const bytes = new Uint8Array(eventData);\n const text = new TextDecoder().decode(bytes);\n eventData = JSON.parse(text);\n } catch {\n // Keep raw data\n }\n }\n\n if (msg.result.contextId) {\n this.emit('event', {\n contextId: msg.result.contextId,\n // Forward the event tag (sibling of `data` in core's flattened\n // payload) so consumers can discriminate, matching `SseClient`.\n type: msg.result.type,\n data: eventData,\n });\n return;\n }\n\n // Group-keyed event message (untagged NodeEvent's membership and\n // migration variants; the `type` tag tells them apart).\n if (msg.result.groupId) {\n this.emit('event', {\n groupId: msg.result.groupId,\n type: msg.result.type,\n data: eventData,\n });\n }\n } catch {\n // Invalid JSON, ignore\n }\n }\n\n subscribe(idsOrOpts: string[] | { contextIds?: string[]; groupIds?: string[] }): void {\n const opts = Array.isArray(idsOrOpts) ? { contextIds: idsOrOpts } : idsOrOpts;\n for (const id of opts.contextIds ?? []) {\n this.subscribedContextIds.add(id);\n }\n for (const id of opts.groupIds ?? []) {\n this.subscribedGroupIds.add(id);\n }\n\n if (this.ws && this.ws.readyState === 1 /* OPEN */) {\n this.sendMessage({\n id: null,\n method: 'subscribe',\n params: this.buildSubscriptionParams(opts.contextIds ?? [], opts.groupIds ?? []),\n });\n }\n }\n\n unsubscribe(idsOrOpts: string[] | { contextIds?: string[]; groupIds?: string[] }): void {\n const opts = Array.isArray(idsOrOpts) ? { contextIds: idsOrOpts } : idsOrOpts;\n for (const id of opts.contextIds ?? []) {\n this.subscribedContextIds.delete(id);\n }\n for (const id of opts.groupIds ?? []) {\n this.subscribedGroupIds.delete(id);\n }\n\n if (this.ws && this.ws.readyState === 1 /* OPEN */) {\n this.sendMessage({\n id: null,\n method: 'unsubscribe',\n params: this.buildSubscriptionParams(opts.contextIds ?? [], opts.groupIds ?? []),\n });\n }\n }\n\n private resubscribeAfterReconnect(): void {\n if (this.subscribedContextIds.size === 0 && this.subscribedGroupIds.size === 0) return;\n this.sendMessage({\n id: null,\n method: 'subscribe',\n params: this.buildSubscriptionParams([...this.subscribedContextIds], [...this.subscribedGroupIds]),\n });\n }\n\n private buildSubscriptionParams(\n contextIds: string[],\n groupIds: string[],\n ): { contextIds?: string[]; groupIds?: string[] } {\n const params: { contextIds?: string[]; groupIds?: string[] } = {};\n if (contextIds.length > 0) params.contextIds = contextIds;\n if (groupIds.length > 0) params.groupIds = groupIds;\n return params;\n }\n\n private sendMessage(msg: unknown): void {\n if (this.ws && this.ws.readyState === 1 /* OPEN */) {\n this.ws.send(JSON.stringify(msg));\n }\n }\n\n private scheduleReconnect(): void {\n if (this.closed) return;\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n }\n const delay = Math.min(\n 1000 * Math.pow(2, this.reconnectAttempt),\n WsClient.MAX_BACKOFF_MS,\n );\n this.reconnectAttempt++;\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect();\n }, delay);\n }\n\n close(): void {\n this.closed = true;\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.ws) {\n this.ws.onclose = null;\n this.ws.close();\n this.ws = null;\n }\n this.subscribedContextIds.clear();\n this.subscribedGroupIds.clear();\n }\n}\n", "import type { Codec } from './types.js';\n\n/** Default codec: JSON text as a byte array. The wire carries `state` as\n * `number[]`, not a string, so this encodes to bytes rather than to text. */\nexport function jsonCodec<T>(): Codec<T> {\n return {\n encode(value: T): number[] {\n return Array.from(new TextEncoder().encode(JSON.stringify(value)));\n },\n decode(bytes: number[]): T {\n return JSON.parse(new TextDecoder().decode(new Uint8Array(bytes))) as T;\n },\n };\n}\n", "import type { HttpClient } from '../http-client/index.js';\nimport type { SseClient } from '../events/index.js';\nimport { jsonRpcCall } from '../rpc/index.js';\nimport { jsonCodec } from './codec.js';\nimport type { Codec, EphemeralEntry } from './types.js';\n\nexport { jsonCodec };\nexport type { Codec, EphemeralEntry };\n\n/**\n * Ephemeral presence: transient, encrypted, never-persisted state (cursors,\n * typing, presence) that gossips between nodes without a WASM run or DAG\n * growth.\n *\n * The write/read asymmetry is the model, not an oversight. `set` takes no\n * author: you can only ever write your OWN slot, and the node resolves the\n * author server-side from its owned context identity \u2014 which is also why a\n * client cannot publish as somebody else. `subscribe` returns everyone's\n * slots, so each carries its `author`. The store is N independent\n * single-writer registers keyed by author; there is no merge across authors.\n *\n * There is a single read path: `subscribe`. On subscribing to a context, the\n * node replays that context's current presence to this connection as\n * ordinary `Ephemeral` events (carrying `ageMs`), before any live deltas\n * (which carry no `ageMs`). There is no separate snapshot RPC.\n */\nexport class EphemeralClient {\n private httpClient: HttpClient;\n private sse: SseClient;\n\n constructor(opts: { httpClient: HttpClient; sse: SseClient }) {\n this.httpClient = opts.httpClient;\n this.sse = opts.sse;\n }\n\n /**\n * Publish your own presence slice, replacing it wholesale.\n *\n * Rejects with an `RpcError` (not a bare `Error`), so a typed failure such as\n * an oversized slice keeps its `type` and `data` \u2014 e.g. `SliceTooLarge` with\n * the offending size \u2014 and is `instanceof RpcError` like every other RPC in\n * this SDK.\n */\n async set<T>(contextId: string, state: T, codec: Codec<T> = jsonCodec<T>()): Promise<void> {\n await jsonRpcCall<Record<string, never>>(this.httpClient, 'set_ephemeral', {\n contextId,\n state: codec.encode(state),\n });\n }\n\n /**\n * Observe presence changes for a context.\n *\n * This adds NO transport \u2014 it is a typed filter over the existing SSE event\n * stream, which already carries `{ contextId, type, data }`. On subscribing,\n * the node replays that context's current presence to this connection as\n * ordinary `Ephemeral` events before any live deltas; a replayed entry\n * carries `ageMs`, a live delta does not (never synthesized as `0` \u2014 absent\n * and zero mean different things). Returns an unsubscribe function.\n */\n subscribe<T>(\n contextId: string,\n handler: (entry: EphemeralEntry<T>) => void,\n codec: Codec<T> = jsonCodec<T>(),\n ): () => void {\n const listener = (event: unknown): void => {\n const e = event as { contextId?: string; type?: string; data?: unknown };\n if (e.type !== 'Ephemeral' || e.contextId !== contextId) return;\n\n const data = e.data as\n | { author?: string; state?: number[]; removed?: boolean; ageMs?: number }\n | undefined;\n if (!data?.author) return;\n\n // `removed` is omitted on an upsert, so normalize to a boolean here and\n // spare every caller the truthiness rule.\n const removed = Boolean(data.removed);\n const entry: EphemeralEntry<T> = {\n author: data.author,\n state: removed || data.state === undefined ? undefined : codec.decode(data.state),\n removed,\n };\n // `ageMs` is present only on a replayed seed entry; pass it through as-is\n // rather than defaulting a live delta to 0.\n if (data.ageMs !== undefined) entry.ageMs = data.ageMs;\n handler(entry);\n };\n\n this.sse.on('event', listener);\n // Errors surface via the SSE client's own 'error' event; nothing more to\n // do with them here.\n void this.sse.connect().catch(() => undefined);\n void this.sse.subscribe([contextId]).catch(() => undefined);\n\n return () => {\n this.sse.off('event', listener);\n };\n }\n}\n", "/**\n * Calimero Cloud (MDMA) client.\n *\n * # Why the SDK knows about the cloud at all\n *\n * Delegated execution lets an account that holds one signing key write into a\n * context without running a node \u2014 but only through a *relay*, and a relay is\n * something the client has to be told about. A warrant names an executor\n * account, so a client that cannot discover which relay serves its namespace,\n * and which account that relay writes as, cannot mint a usable warrant at all.\n *\n * For a self-hosted namespace the operator hands those two facts over out of\n * band. For the hosted tier the cloud is the directory: the user signs in, the\n * cloud knows which namespaces they own and which attested TEE nodes are\n * assigned to each, and it answers with the relay's URL and executor account.\n * That is what this client is for \u2014 it is the discovery half of\n * {@link RelayClient}, not a second way to talk to a node.\n *\n * # What it deliberately is not\n *\n * It never sees a warrant, a device secret, or an intent. Discovery goes\n * through the cloud; the write goes straight from the client to the relay. A\n * cloud that proxied intents would read every method and argument its users\n * ever sent, and would be a throughput bottleneck on a path that has no reason\n * to involve it.\n */\n\nimport { HTTPError } from '../http-client/web-client.js';\n\n/** Where the hosted cloud lives when a caller names no other. */\nconst DEFAULT_CLOUD_BASE_URL = 'https://cloud.calimero.network';\n\nexport interface CloudClientConfig {\n cloudBaseUrl?: string;\n /**\n * An MDMA session token to start out authenticated with \u2014 from a previous\n * {@link CloudClient.signInWithGoogle}, persisted by the app.\n *\n * Sessions are 7-day JWTs with a rolling refresh, so a stored one is usually\n * still live and re-running the Google flow on every launch is avoidable.\n */\n sessionToken?: string;\n /**\n * Called whenever the session token changes \u2014 a sign-in, an explicit\n * refresh, or a rolling refresh the server performed mid-request. Persist it\n * here; errors thrown are swallowed so a storage failure cannot mask the\n * response the caller is waiting for.\n */\n onSession?: (session: CloudSession | null) => void | Promise<void>;\n /** Injected for tests and non-browser runtimes. Defaults to global `fetch`. */\n fetch?: typeof fetch;\n /** Per-request timeout. Defaults to 10s, as the node clients do. */\n timeoutMs?: number;\n}\n\n/** Who is signed in, and until when. */\nexport interface CloudSession {\n sessionToken: string;\n /** Epoch **seconds**, as MDMA reports it \u2014 not milliseconds. */\n expiresAt: number;\n user: { email: string; name?: string; picture?: string };\n}\n\n/** One namespace the signed-in user owns. */\nexport interface CloudNamespace {\n namespaceId: string;\n /** Always equal to `namespaceId`; MDMA keeps it for wire compatibility. */\n groupId: string;\n /** `'enabled' | 'disabled' | 'none'` \u2014 `'none'` means HA was never enabled. */\n haStatus: string;\n haEnabledAt?: string | null;\n contexts: string[];\n fleetReplicas?: { current?: number; limit?: number } | unknown;\n}\n\n/**\n * One attested node the cloud has assigned to a namespace, described as a\n * relay.\n *\n * `authorshipReady` is the field that decides whether a write can happen, and\n * it is reported rather than assumed because it is not the cloud's to grant:\n * `CAN_AUTHOR_ON_BEHALF` is a governance capability, set by an admin of the\n * namespace, and the cloud only relays what the node observed. A relay that is\n * `active` with `authorshipReady: false` is a healthy node waiting for a grant.\n */\nexport interface CloudRelay {\n peerId: string;\n /** Base URL to present intents to, or `null` when the cloud knows none yet. */\n relayUrl: string | null;\n /** The account a warrant for this relay must name as its `executor`, hex. */\n executorAccount: string | null;\n /** `'assigned'` (admitted pending confirm) or `'active'`. */\n status: string;\n /** Whether this relay holds `CAN_AUTHOR_ON_BEHALF` on the namespace. */\n authorshipReady: boolean;\n lastSeenAt?: string | null;\n confirmedAt?: string | null;\n}\n\n/** One namespace of the caller's that a machine is serving. */\nexport interface CloudMachineNamespace {\n namespaceId: string;\n /** `'assigned'` (admitted pending confirm) or `'active'`. */\n status: string;\n /** Whether the machine holds `CAN_AUTHOR_ON_BEHALF` on this namespace. */\n authorshipReady: boolean;\n /**\n * Whether the machine's heartbeat for this namespace is recent.\n *\n * The same freshness rule the per-plan fleet cap uses, so a replica that\n * stopped polling reads as stale here rather than continuing to look\n * healthy \u2014 otherwise \"my writes stopped working\" has no visible cause.\n */\n fresh: boolean;\n confirmedAt?: string | null;\n lastSeenAt?: string | null;\n}\n\n/**\n * One attested machine serving this account.\n *\n * A narrow view on purpose: the zone, machine type, instance name, public IP\n * and KMS ids are operator data with no client use, and a cloud user is not an\n * operator.\n */\nexport interface CloudMachine {\n peerId: string;\n relayUrl: string | null;\n executorAccount: string | null;\n /**\n * Whether this machine can write for the caller *somewhere* \u2014 a URL, an\n * executor account, and the grant on at least one namespace.\n *\n * Folded here so a client does not re-derive the three-way precondition and\n * get a refusal it cannot explain.\n */\n canExecute: boolean;\n /** Only the caller's own namespaces, even on a machine shared with others. */\n namespaces: CloudMachineNamespace[];\n}\n\nexport interface EnableHAOptions {\n groupId: string;\n contextId: string;\n redirectUrl?: string;\n}\n\nexport interface DisableHAOptions {\n groupId: string;\n contextId: string;\n redirectUrl?: string;\n}\n\n/** Response headers MDMA uses to hand back a rolling-refreshed session. */\nconst REFRESH_HEADER = 'x-mdma-session-refresh';\nconst REFRESH_EXPIRES_HEADER = 'x-mdma-session-expires';\n\nexport class CloudClient {\n private baseUrl: string;\n private session: CloudSession | null = null;\n private readonly onSession?: CloudClientConfig['onSession'];\n private readonly fetchImpl: typeof fetch;\n private readonly timeoutMs: number;\n\n constructor(config: CloudClientConfig = {}) {\n this.baseUrl = (config.cloudBaseUrl || DEFAULT_CLOUD_BASE_URL).replace(/\\/+$/, '');\n this.onSession = config.onSession;\n // Bound through an arrow function: an unbound `globalThis.fetch` throws\n // \"Illegal invocation\" in a browser, the same reason the node HTTP clients\n // wrap it.\n const injected = config.fetch;\n this.fetchImpl = injected\n ? (input: RequestInfo | URL, init?: RequestInit) => injected(input, init)\n : (input: RequestInfo | URL, init?: RequestInit) => globalThis.fetch(input, init);\n this.timeoutMs = config.timeoutMs ?? 10_000;\n\n if (config.sessionToken) {\n // Expiry unknown until the server tells us; 0 means \"do not reason about\n // it locally\", never \"expired\" \u2014 the server is the only judge and it\n // answers 401 when it disagrees.\n this.session = {\n sessionToken: config.sessionToken,\n expiresAt: 0,\n user: { email: '' },\n };\n }\n }\n\n /** The current session, or `null` when nobody is signed in. */\n getSession(): CloudSession | null {\n return this.session;\n }\n\n /** Whether a session token is held. Says nothing about the server agreeing. */\n isSignedIn(): boolean {\n return this.session !== null;\n }\n\n /**\n * Exchange a Google OAuth2 ID token for an MDMA session.\n *\n * The app owns the Google flow (One Tap, an auth-code popup, a native\n * browser) and hands the resulting ID token here once. Everything after this\n * uses the returned session token, so the Google credential does not have to\n * be kept or re-minted per call.\n */\n async signInWithGoogle(idToken: string): Promise<CloudSession> {\n const body = await this.request<{\n session_token: string;\n expires_at: number;\n user: { email: string; name?: string; picture?: string };\n }>('POST', '/api/auth/google', { body: { id_token: idToken }, anonymous: true });\n return this.adoptSession(body);\n }\n\n /**\n * Refresh the session token explicitly.\n *\n * Rarely needed: MDMA rolling-refreshes on ordinary authenticated calls and\n * this client adopts the replacement automatically. Use it when an app wants\n * a fresh token before going idle rather than on the next request.\n */\n async refreshSession(): Promise<CloudSession> {\n const body = await this.request<{\n session_token: string;\n expires_at: number;\n user: { email: string; name?: string; picture?: string };\n }>('POST', '/api/auth/refresh');\n return this.adoptSession(body);\n }\n\n /**\n * Revoke this session server-side and forget it locally.\n *\n * Local state is cleared even if the server call fails: the caller asked to\n * be signed out, and keeping a token they believe is gone is the worse of the\n * two failures.\n */\n async signOut(): Promise<void> {\n try {\n if (this.session) await this.request<void>('POST', '/api/auth/logout', { parse: 'none' });\n } finally {\n this.session = null;\n void this.notifySession(null);\n }\n }\n\n /** Namespaces the signed-in user owns. */\n async getMyNamespaces(): Promise<CloudNamespace[]> {\n const rows = await this.request<Array<Record<string, unknown>>>(\n 'GET',\n '/api/cloud/me/namespaces',\n );\n return rows.map((row) => ({\n namespaceId: String(row.namespace_id ?? row.group_id ?? ''),\n groupId: String(row.group_id ?? row.namespace_id ?? ''),\n haStatus: String(row.ha_status ?? 'none'),\n haEnabledAt: (row.ha_enabled_at as string | null | undefined) ?? null,\n contexts: Array.isArray(row.contexts) ? (row.contexts as string[]) : [],\n fleetReplicas: row.fleet_replicas,\n }));\n }\n\n /**\n * The relays serving one namespace: where to present an intent, and as whom.\n *\n * Everything a client needs in order to mint a warrant it can actually\n * spend. Filter on `authorshipReady` before signing \u2014 a warrant presented to\n * a relay with no grant is refused *after* the author has burned a nonce from\n * its monotonic sequence on it.\n */\n async getNamespaceRelays(namespaceId: string): Promise<CloudRelay[]> {\n const body = await this.request<{ relays?: Array<Record<string, unknown>> }>(\n 'GET',\n `/api/cloud/me/namespaces/${encodeURIComponent(namespaceId)}/relays`,\n );\n return (body.relays ?? []).map((row) => ({\n peerId: String(row.peer_id ?? ''),\n relayUrl: (row.relay_url as string | null | undefined) ?? null,\n executorAccount: (row.executor_account as string | null | undefined) ?? null,\n status: String(row.status ?? ''),\n authorshipReady: row.authorship_ready === true,\n lastSeenAt: (row.last_seen_at as string | null | undefined) ?? null,\n confirmedAt: (row.confirmed_at as string | null | undefined) ?? null,\n }));\n }\n\n /**\n * The first relay for `namespaceId` that can actually run an intent, or\n * `null`.\n *\n * \"Can actually run one\" is three conditions, and a client that checks fewer\n * gets a refusal it cannot explain: the cloud must know a URL, the relay must\n * have reported the executor account a warrant has to name, and the grant\n * must be in place.\n */\n async findExecutingRelay(namespaceId: string): Promise<CloudRelay | null> {\n const relays = await this.getNamespaceRelays(namespaceId);\n return (\n relays.find((r) => r.authorshipReady && r.relayUrl !== null && r.executorAccount !== null) ??\n null\n );\n }\n\n /**\n * Every attested machine currently serving something this account owns.\n *\n * The account-wide view of the same rows {@link getNamespaceRelays} returns\n * per namespace, keyed by machine \u2014 so a UI can answer \"what is running for\n * me?\" in one call. `canExecute` folds the three-way precondition, so a\n * caller does not re-derive it.\n *\n * Only the caller's own namespaces appear on each machine. A plan's\n * `usersPerMachine` is greater than one, so a fleet node routinely serves\n * several accounts at once.\n */\n async getMyMachines(): Promise<CloudMachine[]> {\n const body = await this.request<{ machines?: Array<Record<string, unknown>> }>(\n 'GET',\n '/api/cloud/me/machines',\n );\n return (body.machines ?? []).map((row) => ({\n peerId: String(row.peer_id ?? ''),\n relayUrl: (row.relay_url as string | null | undefined) ?? null,\n executorAccount: (row.executor_account as string | null | undefined) ?? null,\n canExecute: row.can_execute === true,\n namespaces: (Array.isArray(row.namespaces) ? row.namespaces : []).map((n) => {\n const ns = n as Record<string, unknown>;\n return {\n namespaceId: String(ns.namespace_id ?? ''),\n status: String(ns.status ?? ''),\n authorshipReady: ns.authorship_ready === true,\n fresh: ns.fresh === true,\n confirmedAt: (ns.confirmed_at as string | null | undefined) ?? null,\n lastSeenAt: (ns.last_seen_at as string | null | undefined) ?? null,\n };\n }),\n }));\n }\n\n /**\n * Claim a namespace under this account, proving ownership.\n *\n * The cloud has no other way to learn a namespace exists \u2014 namespaces are\n * created on a node, and there is deliberately no \"create namespace\" in the\n * cloud. `ownershipProof` comes from\n * `admin.issueNamespaceOwnershipProof(namespaceId, \u2026)` on a node that is a\n * **direct admin** of that namespace; merod refuses to issue one otherwise.\n *\n * Pass merod's response object straight through. The cloud accepts core's\n * `signerPublicKey`/`signedPayload` casing as well as snake_case, so there is\n * no re-keying step \u2014 and getting that wrong used to surface as a `422`\n * naming three missing fields.\n *\n * Idempotent for the same account. A namespace already claimed by someone\n * else is a `409`; a replayed proof nonce is a `403`.\n */\n async claimNamespace(namespaceId: string, ownershipProof: unknown): Promise<void> {\n await this.request<unknown>('POST', '/api/cloud/namespaces/claim', {\n body: { namespace_id: namespaceId, ownership_proof: ownershipProof },\n });\n }\n\n /**\n * Ask the fleet to host a claimed namespace \u2014 the step that gets a relay\n * assigned.\n *\n * Takes no body: {@link claimNamespace} already established ownership, and\n * this is the separate \"now host it\" half. Idempotent.\n *\n * Not to be confused with {@link enableHA}, which opens the cloud's web flow\n * in a browser tab for a user to complete by hand. This is the API call.\n */\n async enableNamespaceHa(namespaceId: string): Promise<unknown> {\n return this.request<unknown>(\n 'POST',\n `/api/cloud/namespaces/${encodeURIComponent(namespaceId)}/enable-ha`,\n { body: {} },\n );\n }\n\n /**\n * Stop hosting a claimed namespace.\n *\n * The fleet's own reconcile loop does the rest: each assigned node notices\n * the namespace is no longer assigned to it and **self-leaves**, which makes\n * core evict it and purge its local data and keys. So this is not just a\n * billing flip.\n */\n async disableNamespaceHa(namespaceId: string): Promise<unknown> {\n return this.request<unknown>(\n 'POST',\n `/api/cloud/namespaces/${encodeURIComponent(namespaceId)}/disable-ha`,\n { body: {} },\n );\n }\n\n /**\n * The node assigned to the signed-in user, or `null`.\n *\n * @deprecated Use {@link getMyMachines}. This reads the cloud's retired\n * `NodeAssignment` ledger, which nothing has written since the v1\n * retirement, so it answers `null` for every namespace-native account \u2014\n * which reads as \"you have no machine\" when the truth is \"that is no longer\n * how a machine is assigned\".\n */\n async getMyNode(): Promise<Record<string, unknown> | null> {\n const body = await this.request<{ node: Record<string, unknown> | null }>(\n 'GET',\n '/api/cloud/me/node',\n );\n return body.node ?? null;\n }\n\n enableHA(options: EnableHAOptions): void {\n const params = new URLSearchParams({\n group_id: options.groupId,\n context_id: options.contextId,\n });\n if (options.redirectUrl) {\n params.set('redirect_url', options.redirectUrl);\n }\n window.open(`${this.baseUrl}/enable-ha?${params.toString()}`);\n }\n\n disableHA(options: DisableHAOptions): void {\n const params = new URLSearchParams({\n group_id: options.groupId,\n context_id: options.contextId,\n });\n if (options.redirectUrl) {\n params.set('redirect_url', options.redirectUrl);\n }\n window.open(`${this.baseUrl}/disable-ha?${params.toString()}`);\n }\n\n /** Record a freshly-issued session and tell the app to persist it. */\n private adoptSession(body: {\n session_token: string;\n expires_at: number;\n user: { email: string; name?: string; picture?: string };\n }): CloudSession {\n this.session = {\n sessionToken: body.session_token,\n expiresAt: body.expires_at,\n user: body.user,\n };\n void this.notifySession(this.session);\n return this.session;\n }\n\n private async notifySession(session: CloudSession | null): Promise<void> {\n try {\n await this.onSession?.(session);\n } catch {\n // A failing persistence callback must not mask the call's own result.\n }\n }\n\n private async request<T>(\n method: string,\n path: string,\n options: { body?: unknown; anonymous?: boolean; parse?: 'json' | 'none' } = {},\n ): Promise<T> {\n if (!options.anonymous && !this.session) {\n throw new Error(\n 'Not signed in to Calimero Cloud: call signInWithGoogle() or construct the client with a sessionToken',\n );\n }\n\n const headers: Record<string, string> = { Accept: 'application/json' };\n if (options.body !== undefined) headers['Content-Type'] = 'application/json';\n if (!options.anonymous && this.session) {\n headers.Authorization = `Bearer ${this.session.sessionToken}`;\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n let response: Response;\n try {\n response = await this.fetchImpl(`${this.baseUrl}${path}`, {\n method,\n headers,\n body: options.body === undefined ? undefined : JSON.stringify(options.body),\n signal: controller.signal,\n });\n } catch (err) {\n // Same shape the node clients use for a transport failure: an `HTTPError`\n // with `status: 0`, so a caller has one error type to handle rather than\n // one per layer.\n throw new HTTPError(\n 0,\n err instanceof Error ? err.name : 'NetworkError',\n `${this.baseUrl}${path}`,\n new Headers(),\n err instanceof Error ? err.message : String(err),\n );\n } finally {\n clearTimeout(timer);\n }\n\n this.adoptRollingRefresh(response);\n\n if (!response.ok) {\n const bodyText = await response.text().catch(() => undefined);\n throw new HTTPError(\n response.status,\n response.statusText,\n `${this.baseUrl}${path}`,\n response.headers,\n bodyText,\n );\n }\n\n if (options.parse === 'none' || response.status === 204) return undefined as T;\n return (await response.json()) as T;\n }\n\n /**\n * Adopt a session token the server refreshed mid-request.\n *\n * MDMA rotates the token on activity and returns the replacement in a\n * response header rather than making the client ask. Ignoring it costs\n * nothing immediately and then logs the user out a week later, which is the\n * kind of bug that is impossible to reproduce in a short session.\n *\n * The user identity is carried over: the header holds only a token, and the\n * refresh is the same logical session as the sign-in that named the user.\n */\n private adoptRollingRefresh(response: Response): void {\n const token = response.headers.get(REFRESH_HEADER);\n if (!token || !this.session) return;\n const expiresRaw = response.headers.get(REFRESH_EXPIRES_HEADER);\n const expiresAt = Number(expiresRaw);\n this.session = {\n sessionToken: token,\n expiresAt: Number.isFinite(expiresAt) && expiresAt > 0 ? expiresAt : this.session.expiresAt,\n user: this.session.user,\n };\n void this.notifySession(this.session);\n }\n}\n", "import { createBrowserHttpClient } from './http-client/index.js';\nimport { createAuthApiClientFromHttpClient } from './auth-api/index.js';\nimport { createAdminApiClientFromHttpClient } from './admin-api/index.js';\nimport type { AuthApiClient } from './auth-api/index.js';\nimport type { AdminApiClient } from './admin-api/index.js';\nimport type { HttpClient } from './http-client/index.js';\nimport type { TokenStore } from './token-store/index.js';\nimport { parseAuthCallback, buildAuthLoginUrl } from './auth/index.js';\nimport type { AuthCallbackResult, AuthLoginOptions } from './auth/index.js';\nimport { RpcClient } from './rpc/index.js';\nimport { SseClient } from './events/sse.js';\nimport { WsClient } from './events/ws.js';\nimport { EphemeralClient } from './ephemeral/index.js';\nimport { CloudClient } from './cloud/cloud-client.js';\nimport type { CloudClientConfig } from './cloud/cloud-client.js';\n\nexport interface MeroJsConfig {\n /** Base URL for the Calimero node */\n baseUrl: string;\n /** Initial credentials for authentication */\n credentials?: {\n username: string;\n password: string;\n };\n /** Custom HTTP client timeout in milliseconds */\n timeoutMs?: number;\n /** Request credentials mode for fetch (omit, same-origin, include) */\n requestCredentials?: RequestCredentials;\n /** Optional token store for persistence */\n tokenStore?: TokenStore;\n /**\n * Called when the node reports that the credential family is gone\n * (`x-auth-error: token_reuse` / `token_revoked`). Terminal: the tokens have\n * already been cleared by the time this runs and nothing is retried, so use it\n * to send the user back through login. Errors thrown here are swallowed \u2014\n * never let a UI failure mask the auth error.\n */\n onAuthRevoked?: () => Promise<void> | void;\n /**\n * Calimero Cloud, reachable as `sdk.cloud`.\n *\n * A node connection and a cloud account are separate things a client can have\n * either of, both of, or neither \u2014 a desktop app with a local node and a\n * cloud subscription has both, and needs them from one object. So this is\n * configuration on the existing SDK rather than a second SDK: pass the\n * session token (or none, and sign in through `sdk.cloud`) and the node half\n * is unaffected.\n *\n * For a caller with *no* node at all, `connectCloud` is the entry point\n * instead \u2014 it returns a connection that can write without one.\n */\n cloud?: CloudClientConfig;\n}\n\nexport interface TokenData {\n access_token: string;\n refresh_token: string;\n expires_at: number;\n}\n\n/** Name of the Web Lock that serializes token refresh across tabs / webviews. */\nconst REFRESH_LOCK_NAME = 'mero-js:token-refresh';\n\n/** Minimal structural view of the Web Locks API (not available in every runtime). */\ninterface LockManagerLike {\n request<T>(name: string, callback: () => Promise<T>): Promise<T>;\n}\n\n/** Returns `navigator.locks` when the runtime supports the Web Locks API. */\nfunction getLockManager(): LockManagerLike | null {\n const nav = (globalThis as unknown as { navigator?: { locks?: LockManagerLike } }).navigator;\n const locks = nav?.locks;\n return locks && typeof locks.request === 'function' ? locks : null;\n}\n\n/** Try to extract `exp` (seconds) from a JWT, return ms timestamp or fallback. */\nfunction expiresAtFromJwt(token: string, fallbackMs: number): number {\n try {\n const parts = token.split('.');\n if (parts.length === 3) {\n // JWT uses base64url encoding: replace -/_ with +// and add padding\n let b64 = parts[1].replace(/-/g, '+').replace(/_/g, '/');\n while (b64.length % 4) b64 += '=';\n const payload = JSON.parse(atob(b64));\n if (typeof payload.exp === 'number') {\n return payload.exp * 1000;\n }\n }\n } catch {\n // not a JWT or can't parse\n }\n return fallbackMs;\n}\n\n/**\n * Main MeroJs SDK class that manages all API clients and authentication\n */\nexport class MeroJs {\n private config: MeroJsConfig;\n private httpClient: HttpClient;\n private authClient: AuthApiClient;\n private adminClient: AdminApiClient;\n private tokenData: TokenData | null = null;\n private refreshPromise: Promise<TokenData> | null = null;\n private tokenStore: TokenStore | null;\n private rpcClient: RpcClient | null = null;\n private sseClient: SseClient | null = null;\n private wsClient: WsClient | null = null;\n private wsWarned = false;\n private ephemeralClient?: EphemeralClient;\n private cloudClient?: CloudClient;\n\n constructor(config: MeroJsConfig) {\n this.config = {\n timeoutMs: 10000,\n ...config,\n };\n\n this.tokenStore = config.tokenStore ?? null;\n\n // Restore tokens from store if available\n if (this.tokenStore) {\n this.tokenData = this.tokenStore.getTokens();\n }\n\n // Create HTTP client with token management\n // For Tauri, explicitly set credentials to 'omit' to avoid network errors\n const isTauri = typeof window !== 'undefined' && '__TAURI_INTERNALS__' in window;\n this.httpClient = createBrowserHttpClient({\n baseUrl: this.config.baseUrl,\n getAuthToken: async () => {\n const token = await this.getValidToken();\n return token?.access_token || '';\n },\n refreshToken: async () => {\n const refreshed = await this.performTokenRefresh();\n return refreshed.access_token;\n },\n onTokenRefresh: async (newToken: string) => {\n if (this.tokenData) {\n this.tokenData.access_token = newToken;\n this.tokenStore?.setTokens(this.tokenData);\n }\n },\n onAuthRevoked: async () => {\n // The refresh-token family is gone (a single-use refresh token was\n // replayed, or the token was revoked). Nothing left to refresh with \u2014\n // drop the bundle so the app can force a re-login, then let the app react.\n this.clearToken();\n try {\n await this.config.onAuthRevoked?.();\n } catch {\n // A failing app callback must not mask the auth error.\n }\n },\n timeoutMs: this.config.timeoutMs,\n credentials: this.config.requestCredentials ?? (isTauri ? 'omit' : undefined),\n });\n\n // Create API clients\n this.authClient = createAuthApiClientFromHttpClient(this.httpClient, {\n baseUrl: this.config.baseUrl,\n getAuthToken: async () => {\n const token = await this.getValidToken();\n return token?.access_token || '';\n },\n timeoutMs: this.config.timeoutMs,\n });\n\n this.adminClient = createAdminApiClientFromHttpClient(this.httpClient, {\n baseUrl: this.config.baseUrl,\n getAuthToken: async () => {\n const token = await this.getValidToken();\n return token?.access_token || '';\n },\n timeoutMs: this.config.timeoutMs,\n });\n }\n\n /**\n * Get the Auth API client\n */\n get auth(): AuthApiClient {\n return this.authClient;\n }\n\n /**\n * Get the Admin API client\n */\n get admin(): AdminApiClient {\n return this.adminClient;\n }\n\n /**\n * Get the RPC client (lazy initialized)\n */\n get rpc(): RpcClient {\n if (!this.rpcClient) {\n this.rpcClient = new RpcClient({ httpClient: this.httpClient });\n }\n return this.rpcClient;\n }\n\n /**\n * Get the SSE event client (lazy initialized)\n */\n get events(): SseClient {\n if (!this.sseClient) {\n this.sseClient = new SseClient({\n baseUrl: this.config.baseUrl,\n getAuthToken: async () => {\n const token = await this.getValidToken();\n return token?.access_token || '';\n },\n });\n }\n return this.sseClient;\n }\n\n /**\n * Get the ephemeral-presence client (lazy initialized).\n *\n * Shares this instance's SSE client, so `subscribe` reuses the one event\n * stream rather than opening a second connection.\n */\n get ephemeral(): EphemeralClient {\n if (!this.ephemeralClient) {\n this.ephemeralClient = new EphemeralClient({\n httpClient: this.httpClient,\n sse: this.events,\n });\n }\n return this.ephemeralClient;\n }\n\n /**\n * Calimero Cloud (lazy initialized).\n *\n * Available whether or not `cloud` was configured \u2014 an app that signs in\n * later gets an unauthenticated client it can call `signInWithGoogle` on,\n * which is one fewer construction path than making the getter conditional.\n * It is entirely independent of this instance's node credential: the cloud\n * knows nothing about the node's tokens and the node knows nothing about the\n * cloud session.\n */\n get cloud(): CloudClient {\n if (!this.cloudClient) {\n this.cloudClient = new CloudClient(this.config.cloud ?? {});\n }\n return this.cloudClient;\n }\n\n /**\n * Get the WebSocket event client (lazy initialized).\n * @experimental Use `events` (SSE) for production. WsClient is experimental.\n */\n get ws(): WsClient {\n if (!this.wsWarned) {\n this.wsWarned = true;\n console.warn('[mero-js] WsClient is experimental. Use mero.events (SSE) for production.');\n }\n if (!this.wsClient) {\n this.wsClient = new WsClient({\n baseUrl: this.config.baseUrl,\n getAuthToken: async () => {\n const token = await this.getValidToken();\n return token?.access_token || '';\n },\n });\n }\n return this.wsClient;\n }\n\n /**\n * Authenticate with the provided credentials\n * This will create the root key on first use\n */\n async authenticate(credentials?: {\n username: string;\n password: string;\n }): Promise<TokenData> {\n const creds = credentials || this.config.credentials;\n if (!creds) {\n throw new Error('No credentials provided for authentication');\n }\n\n try {\n const requestBody = {\n auth_method: 'user_password',\n public_key: creds.username,\n client_name: 'mero-js-sdk',\n permissions: ['admin'],\n timestamp: Math.floor(Date.now() / 1000),\n provider_data: {\n username: creds.username,\n password: creds.password,\n },\n };\n\n const response = await this.authClient.generateTokens(requestBody);\n\n const accessToken = response.data.access_token;\n this.tokenData = {\n access_token: accessToken,\n refresh_token: response.data.refresh_token,\n expires_at: expiresAtFromJwt(accessToken, Date.now() + 3600_000),\n };\n\n this.tokenStore?.setTokens(this.tokenData);\n\n return this.tokenData;\n } catch (error) {\n throw new Error(\n `Authentication failed: ${error instanceof Error ? error.message : 'Unknown error'}`,\n );\n }\n }\n\n /**\n * Get a valid token. Returns the current token as-is.\n * The server rejects refresh attempts while the access token is still valid,\n * so we never proactively refresh. Instead, the WebHttpClient handles 401\n * responses reactively via the refreshToken transport hook.\n */\n private async getValidToken(): Promise<TokenData | null> {\n return this.tokenData;\n }\n\n /**\n * Refresh the access token. Single-flight: every caller (including the HTTP\n * transport's 401 hook) goes through here.\n *\n * Refresh tokens are single-use (calimero-network/core#3083): each refresh\n * consumes the presented token and returns a new one, and replaying a consumed\n * token makes the server revoke the whole family. A refresh must therefore\n * happen exactly once per rotation, which needs three layers:\n * - an in-process promise, so concurrent 401s in this instance share one call;\n * - a Web Lock (when available), so other tabs/webviews don't refresh at the\n * same time on the same stored token;\n * - a re-read of the token store inside the lock, so a bundle that another\n * instance already rotated is adopted instead of replaying a stale token.\n */\n private async performTokenRefresh(): Promise<TokenData> {\n if (this.refreshPromise) {\n return this.refreshPromise;\n }\n\n // The access token that triggered this refresh. If the store holds a different\n // one by the time we get the lock, someone else already rotated for us.\n const triggeringAccessToken = this.tokenData?.access_token;\n\n const promise = this.withRefreshLock(() =>\n this.performTokenRefreshLocked(triggeringAccessToken),\n );\n this.refreshPromise = promise;\n\n try {\n return await promise;\n } finally {\n if (this.refreshPromise === promise) {\n this.refreshPromise = null;\n }\n }\n }\n\n /** Run `fn` under the cross-tab refresh lock, or directly if Web Locks are unavailable. */\n private withRefreshLock<T>(fn: () => Promise<T>): Promise<T> {\n const locks = getLockManager();\n return locks ? locks.request(REFRESH_LOCK_NAME, fn) : fn();\n }\n\n /**\n * Perform the actual token refresh. Runs with the refresh lock held.\n */\n private async performTokenRefreshLocked(\n triggeringAccessToken?: string,\n ): Promise<TokenData> {\n // Another instance/tab may have rotated the bundle while we were queued behind\n // the lock \u2014 the store, not our in-memory copy, is the source of truth.\n const stored = this.tokenStore?.getTokens() ?? null;\n if (stored?.refresh_token) {\n this.tokenData = stored;\n\n if (triggeringAccessToken && stored.access_token !== triggeringAccessToken) {\n // Someone else already refreshed. Reuse their bundle rather than replaying\n // our (now consumed) refresh token, which would revoke the family.\n return stored;\n }\n }\n\n if (!this.tokenData?.refresh_token) {\n throw new Error('No refresh token available');\n }\n\n try {\n const response = await this.authClient.refreshToken({\n access_token: this.tokenData.access_token,\n refresh_token: this.tokenData.refresh_token,\n });\n\n const accessToken = response.data.access_token;\n this.tokenData = {\n access_token: accessToken,\n // The refresh token is rotated on every refresh \u2014 persist the new one or\n // the next refresh replays a consumed token.\n refresh_token: response.data.refresh_token,\n expires_at: expiresAtFromJwt(accessToken, Date.now() + 3600_000),\n };\n\n this.tokenStore?.setTokens(this.tokenData);\n\n return this.tokenData;\n } catch (error) {\n // Don't clear tokens on refresh failure \u2014 the access token may still be\n // valid (server rejects refresh while access token hasn't expired yet).\n // A genuinely dead family arrives as `x-auth-error: token_reuse` and is\n // handled by the onAuthRevoked transport hook. Let the caller handle this.\n throw new Error(\n `Token refresh failed: ${error instanceof Error ? error.message : 'Unknown error'}`,\n );\n }\n }\n\n /**\n * Clear the current token\n */\n public clearToken(): void {\n this.refreshPromise = null;\n this.tokenData = null;\n this.tokenStore?.clear();\n }\n\n /**\n * Check if the SDK is authenticated\n */\n public isAuthenticated(): boolean {\n return this.tokenData !== null;\n }\n\n /**\n * Set token data directly (e.g., from auth callback).\n * If `expires_at` is missing or 0, attempts to parse the JWT exp claim,\n * falling back to 1 hour from now.\n */\n public setTokenData(data: TokenData): void {\n const expiresAt = data.expires_at || expiresAtFromJwt(data.access_token, Date.now() + 3600_000);\n this.tokenData = { ...data, expires_at: expiresAt };\n this.tokenStore?.setTokens(this.tokenData);\n }\n\n /**\n * Get the current token data (for debugging)\n */\n public getTokenData(): TokenData | null {\n return this.tokenData;\n }\n\n /**\n * Close all event connections and clean up resources\n */\n public close(): void {\n this.sseClient?.close();\n this.wsClient?.close();\n }\n\n /**\n * Parse an auth callback URL hash fragment (static utility)\n */\n static parseAuthCallback(url: string): AuthCallbackResult | null {\n return parseAuthCallback(url);\n }\n\n /**\n * Build an auth login URL (static utility)\n */\n static buildAuthLoginUrl(nodeUrl: string, opts: AuthLoginOptions): string {\n return buildAuthLoginUrl(nodeUrl, opts);\n }\n}\n\n/**\n * Create a new MeroJs SDK instance\n */\nexport function createMeroJs(config: MeroJsConfig): MeroJs {\n return new MeroJs(config);\n}\n", "import type { TokenData } from '../mero-js.js';\n\nexport interface TokenStore {\n getTokens(): TokenData | null;\n setTokens(data: TokenData): void;\n clear(): void;\n}\n\nexport class MemoryTokenStore implements TokenStore {\n private tokens: TokenData | null = null;\n\n getTokens(): TokenData | null {\n return this.tokens;\n }\n\n setTokens(data: TokenData): void {\n this.tokens = data;\n }\n\n clear(): void {\n this.tokens = null;\n }\n}\n\nconst STORAGE_KEY = 'mero-tokens';\n\nexport class LocalStorageTokenStore implements TokenStore {\n private readonly key: string;\n\n constructor(key: string = STORAGE_KEY) {\n this.key = key;\n }\n\n getTokens(): TokenData | null {\n try {\n if (typeof localStorage === 'undefined') return null;\n const raw = localStorage.getItem(this.key);\n if (!raw) return null;\n const parsed = JSON.parse(raw);\n if (parsed && parsed.access_token && parsed.refresh_token) {\n return {\n access_token: parsed.access_token,\n refresh_token: parsed.refresh_token,\n expires_at: typeof parsed.expires_at === 'number' ? parsed.expires_at : Date.now() + 3600_000,\n };\n }\n return null;\n } catch {\n return null;\n }\n }\n\n setTokens(data: TokenData): void {\n try {\n if (typeof localStorage === 'undefined') return;\n localStorage.setItem(this.key, JSON.stringify(data));\n } catch {\n // Storage unavailable\n }\n }\n\n clear(): void {\n try {\n if (typeof localStorage === 'undefined') return;\n localStorage.removeItem(this.key);\n } catch {\n // Storage unavailable\n }\n }\n}\n", "/**\n * Byte-level primitives shared by everything in this package that signs.\n *\n * Extracted from `warrant/warrant.ts` when the device-cert signer arrived and\n * needed the same `domainHash`, hex handling and ed25519 import. Keeping one\n * copy is the point: these have to stay byte-identical with core, and two\n * copies drifting apart is exactly the failure the byte-parity e2e exists to\n * catch. Internal \u2014 not exported from the package root.\n */\n\nconst PKCS8_ED25519_PREFIX = new Uint8Array([\n 0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x04,\n 0x22, 0x04, 0x20,\n]);\n\n/** Little-endian u32, for borsh fixed-width fields and epoch counters. */\nexport function u32le(value: number): Uint8Array {\n const out = new Uint8Array(4);\n new DataView(out.buffer).setUint32(0, value, true);\n return out;\n}\n\nexport function hex(bytes: Uint8Array): string {\n return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n}\n\nexport function fromHex(value: string, label: string, expectedBytes: number): Uint8Array {\n const clean = value.trim();\n if (!/^[0-9a-fA-F]*$/.test(clean) || clean.length !== expectedBytes * 2) {\n throw new Error(\n `${label} must be ${expectedBytes * 2} hex characters, got ${clean.length}`,\n );\n }\n // Indexed rather than `match(/../g)!`: the length is already validated above,\n // so the assertion would only be telling the compiler what the guard proved,\n // and this needs no assertion at all.\n const bytes = new Uint8Array(expectedBytes);\n for (let i = 0; i < expectedBytes; i += 1) {\n bytes[i] = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n}\n\nexport function u64le(value: number | bigint): Uint8Array {\n const out = new Uint8Array(8);\n new DataView(out.buffer).setBigUint64(0, BigInt(value), true);\n return out;\n}\n\nexport function concat(...parts: Uint8Array[]): Uint8Array {\n const out = new Uint8Array(parts.reduce((total, p) => total + p.length, 0));\n let offset = 0;\n for (const part of parts) {\n out.set(part, offset);\n offset += part.length;\n }\n return out;\n}\n\n/**\n * core's `domain_hash`: SHA-256 over the length-prefixed domain, then each\n * length-prefixed part. The lengths are what stop two different field splits from\n * hashing alike.\n */\nexport async function domainHash(\n domain: Uint8Array,\n parts: Uint8Array[],\n): Promise<Uint8Array> {\n const chunks: Uint8Array[] = [u64le(domain.length), domain];\n for (const part of parts) {\n chunks.push(u64le(part.length), part);\n }\n return new Uint8Array(\n await crypto.subtle.digest('SHA-256', concat(...chunks)),\n );\n}\n\nexport async function importSigningKey(secretHex: string): Promise<CryptoKey> {\n const seed = fromHex(secretHex, 'deviceSecret', 32);\n const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);\n try {\n return await crypto.subtle.importKey(\n 'pkcs8',\n pkcs8,\n { name: 'Ed25519' },\n false,\n ['sign'],\n );\n } catch (cause) {\n // The original message is folded in rather than passed as `cause`: this\n // package targets ES2020, where `Error` has no `cause` option.\n const detail = cause instanceof Error ? `: ${cause.message}` : '';\n throw new Error(\n 'this runtime has no WebCrypto Ed25519, so a warrant cannot be signed ' +\n 'here. Node 18.4+, Safari 17+, Firefox 129+ and Chrome 137+ have it; ' +\n 'otherwise mint the warrant with `merod account warrant`' +\n detail,\n );\n }\n}\n\n/**\n * The public half of an ed25519 seed.\n *\n * Derived rather than taken as an argument, for the reason core does the same: a\n * caller able to name a key it does not hold could produce a warrant it cannot\n * sign, and the field would stop meaning \"who authorised this\".\n */\nexport async function derivePublicKey(secretHex: string): Promise<Uint8Array> {\n const seed = fromHex(secretHex, 'deviceSecret', 32);\n const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);\n const key = await crypto.subtle.importKey(\n 'pkcs8',\n pkcs8,\n { name: 'Ed25519' },\n true,\n ['sign'],\n );\n const jwk = await crypto.subtle.exportKey('jwk', key);\n const raw = (jwk as JsonWebKey & { x: string }).x;\n return Uint8Array.from(atob(raw.replace(/-/g, '+').replace(/_/g, '/')), (c) =>\n c.charCodeAt(0),\n );\n}\n", "/**\n * Mint a warrant: the author's consent for one relay to run one intent, once.\n *\n * This exists because the case delegated authorship is *for* is an account that\n * holds no node \u2014 a browser tab, a Node service, a bot. Every one of those is a\n * JS runtime, and until now the only thing that could mint a warrant was `merod`,\n * so \"a member with no node\" in practice meant \"a member with a node it is not\n * allowed to use for anything else\".\n *\n * **No dependencies, and that is not incidental.** The primitives are all built\n * in: `crypto.subtle.digest('SHA-256')` for the hash, `crypto.subtle` Ed25519\n * for the signature, and `DataView` for the integers.\n *\n * Warrant v2 (core#3933) gave up the fixed-width encoding that used to make this\n * pure concatenation: `method` travels in the clear as a string and each cited\n * head list is a vector, so three borsh `u32` counts now sit inside the bytes.\n * Two widths to keep straight, and they are not the same: the counts **inside\n * the encoding** are `u32`, while the counts the **signing preimage** hashes are\n * `u64`. Same numbers, different serialization \u2014 reusing one for the other\n * produces a warrant that is well-formed and verifies nowhere.\n *\n * **The byte contract is pinned in core**, at\n * `crates/account/src/tests/warrant_wire_fixture.rs`. The domain strings below\n * are `pub(crate)` there, so nothing in that repository forces anyone to notice\n * this file depends on them \u2014 which is exactly why the fixture lives on that side\n * and this module's test asserts the same vectors. A drift would otherwise leave\n * this producing well-formed warrants whose signatures verify nowhere, surfacing\n * at a relay as a 403: an authorization refusal, nowhere near the cause.\n */\n\nimport {\n concat,\n derivePublicKey,\n domainHash,\n fromHex,\n hex,\n importSigningKey,\n u32le,\n u64le,\n} from '../crypto/internal.js';\n\nconst SIGN_DOMAIN = new TextEncoder().encode('calimero.warrant.v2');\nconst INTENT_DOMAIN = new TextEncoder().encode('calimero.warrant.intent.v1');\n\n/**\n * core's `MAX_WARRANT_CITED_HEADS`. A node refuses more than this before doing\n * any Ed25519 work, so minting past it produces a warrant nothing will spend.\n */\nconst MAX_CITED_HEADS = 64;\n\n/** 32 zero bytes \u2014 the `appVersion` default. See {@link WarrantInput.appVersion}. */\nconst UNPINNED_APP = '00'.repeat(32);\n\n/** Ed25519 PKCS#8 prefix, so a raw 32-byte seed can be imported by WebCrypto. */\n/** What a warrant authorises. */\nexport interface WarrantInput {\n /**\n * The context, hex \u2014 the same string every other method here takes.\n *\n * Hex like everything else on this interface. It was base58 while the node\n * spelled `ContextId` and `PublicKey` that way and `AccountId` and `DeviceId`\n * in hex; that split is gone, so this module no longer needs a rule per field\n * and no longer needs a base58 decoder to enforce one.\n */\n context: string;\n /** The author's account, hex \u2014 whose consent this is. */\n authorAccount: string;\n /** The relay authorised to act, hex. An account, not a key. */\n executor: string;\n /**\n * The application build this warrant is signed against, hex (32 bytes).\n *\n * Pins the code rather than a version string, so a relay cannot wait for an\n * upgrade that widens what `method` does and then spend a warrant signed\n * against the narrower one. Read it from the context\n * (`GET /admin-api/contexts/{id}` \u2192 `applicationId`); a value guessed here\n * pins the wrong build, which is worse than not pinning.\n *\n * Defaults to 32 zero bytes, matching `merod account sign-warrant`'s\n * `--app-version` default. Nothing verifies the field yet \u2014 core#3933 landed\n * the field set ahead of its enforcement so a signer is written once against\n * the final bytes \u2014 but a warrant minted with the default will be refused once\n * pinning lands, so pass the real value for anything meant to outlive it.\n */\n appVersion?: string;\n /**\n * The method the relay may run.\n *\n * Carried in the clear as of v2, so a peer can select a per-method write-set\n * without reversing a hash against the app's ABI. The *arguments* are still\n * committed to rather than carried \u2014 see {@link intentHash}.\n */\n method: string;\n /** Its arguments, as the JSON the guest will receive. */\n argsJson: unknown;\n /**\n * Monotonic per author **device**.\n *\n * Per device rather than per account because two devices of one account are\n * independent replicas: they cannot coordinate on a counter, so an\n * account-scoped sequence would have them refusing each other's warrants.\n */\n nonce: number | bigint;\n /**\n * Account-log heads this author saw when signing, each hex (32 bytes).\n *\n * Empty by default, and empty is the honest answer for a client that tracks\n * no log \u2014 a fabricated view is worse than none. At most\n * {@link MAX_CITED_HEADS}.\n */\n accountHeads?: string[];\n /**\n * Governance heads this author's view descended from, each hex (32 bytes).\n *\n * **Where these come from decides whether they mean anything.** A floor the\n * relay supplied is a floor the relay chose: a relay that withholds a\n * governance op can hand you a stale view and collect a warrant citing it.\n * Take the value from the account's own devices or a co-signing peer outside\n * the relay's operator. As it stands this detects an honest relay's staleness\n * and does not constrain a dishonest one.\n */\n governanceFloor?: string[];\n /** Unix seconds after which the relay must refuse it. */\n notAfter: number | bigint;\n /**\n * The author device's ed25519 signing secret, hex (32 bytes).\n *\n * Never sent anywhere. It signs locally and only the signature travels, which\n * is the whole reason a warrant can be minted by something holding no node.\n */\n deviceSecret: string;\n}\n\n\n\n\n\n\n\n/**\n * The commitment a warrant carries in place of the intent itself.\n *\n * Its own domain, distinct from the signing one, so a value computed for one\n * purpose cannot be presented for the other.\n */\nexport async function intentHash(\n method: string,\n argsJson: unknown,\n): Promise<Uint8Array> {\n const args = new TextEncoder().encode(JSON.stringify(argsJson));\n return domainHash(INTENT_DOMAIN, [new TextEncoder().encode(method), args]);\n}\n\n\n/**\n * Sign a warrant and return it hex-encoded, ready for `performIntent`.\n *\n * Returns the encoding rather than an object because the signature covers\n * exactly these bytes: a caller that rebuilt the fields from JSON would have a\n * second spelling able to disagree with what was signed.\n */\nexport async function signWarrant(input: WarrantInput): Promise<string> {\n const context = fromHex(input.context, 'context', 32);\n const authorAccount = fromHex(input.authorAccount, 'authorAccount', 32);\n const executor = fromHex(input.executor, 'executor', 32);\n const appVersion = fromHex(\n input.appVersion ?? UNPINNED_APP,\n 'appVersion',\n 32,\n );\n const accountHeads = citedHeads(input.accountHeads, 'accountHeads');\n const governanceFloor = citedHeads(input.governanceFloor, 'governanceFloor');\n\n const key = await importSigningKey(input.deviceSecret);\n const publicKey = await derivePublicKey(input.deviceSecret);\n\n const method = new TextEncoder().encode(input.method);\n const commitment = await intentHash(input.method, input.argsJson);\n const nonce = u64le(input.nonce);\n const notAfter = u64le(input.notAfter);\n\n // Each head list is preceded by its own count. `domainHash` length-prefixes\n // every part it is given, so the heads are individually unambiguous \u2014 but the\n // two lists are adjacent, so without the counts `accountHeads = [a, b],\n // governanceFloor = []` hashes identically to `[a], [b]`, and a relay could\n // relabel which plane a head was cited from. u64 HERE; u32 in the encoding.\n const preimage = await domainHash(SIGN_DOMAIN, [\n context,\n authorAccount,\n publicKey,\n executor,\n appVersion,\n method,\n commitment,\n u64le(accountHeads.length),\n ...accountHeads,\n u64le(governanceFloor.length),\n ...governanceFloor,\n nonce,\n notAfter,\n ]);\n\n const signature = new Uint8Array(\n await crypto.subtle.sign({ name: 'Ed25519' }, key, preimage),\n );\n\n // Borsh: a `String` is a u32 length then its UTF-8 bytes; a `Vec<[u8; 32]>` is\n // a u32 count then the elements. u32 HERE; u64 in the preimage above.\n return hex(\n concat(\n context,\n authorAccount,\n publicKey,\n executor,\n appVersion,\n u32le(method.length),\n method,\n commitment,\n u32le(accountHeads.length),\n ...accountHeads,\n u32le(governanceFloor.length),\n ...governanceFloor,\n nonce,\n notAfter,\n signature,\n ),\n );\n}\n\n/** Decode a cited-head list, refusing one longer than a node will accept. */\nfunction citedHeads(heads: string[] | undefined, label: string): Uint8Array[] {\n const list = heads ?? [];\n if (list.length > MAX_CITED_HEADS) {\n throw new Error(\n `${label} cites ${list.length} heads, over the ${MAX_CITED_HEADS} a node accepts`,\n );\n }\n return list.map((head, i) => fromHex(head, `${label}[${i}]`, 32));\n}\n\n/** A warrant's fields, as hex, decoded from the wire encoding. */\nexport interface WarrantFields {\n context: string;\n authorAccount: string;\n /** The author device key `signWarrant` derived from the secret. */\n deviceKey: string;\n executor: string;\n appVersion: string;\n method: string;\n intentHash: string;\n accountHeads: string[];\n governanceFloor: string[];\n /** u64 little-endian, as it sits on the wire. */\n nonce: string;\n /** u64 little-endian, as it sits on the wire. */\n notAfter: string;\n signature: string;\n}\n\n/**\n * Decode a hex warrant back into its fields.\n *\n * Exists because v2's offsets are no longer constants: `method` is a string and\n * the head lists are vectors, so everything after `appVersion` moves with the\n * method's length. Anything reading a warrant by fixed offset \u2014 a test, a client\n * inspecting one it was handed \u2014 silently reads the wrong field instead of\n * failing, which is how the three call sites that did so passed while comparing\n * the method's length prefix to a nonce.\n *\n * One copy of the layout, beside the encoder that produces it, so the two cannot\n * drift. Internal: not exported from the package root, because a client that\n * needs a warrant's fields has the input it signed.\n */\nexport function parseWarrant(warrant: string): WarrantFields {\n const at = (start: number, bytes: number) =>\n warrant.slice(start * 2, (start + bytes) * 2);\n // A borsh u32 is little-endian, so the hex pairs read back to front.\n const u32At = (start: number) =>\n Number.parseInt((at(start, 4).match(/../g) ?? []).reverse().join(''), 16);\n\n let o = 0;\n const take = (bytes: number) => {\n const field = at(o, bytes);\n o += bytes;\n return field;\n };\n\n const context = take(32);\n const authorAccount = take(32);\n const deviceKey = take(32);\n const executor = take(32);\n const appVersion = take(32);\n const methodLen = u32At(o);\n o += 4;\n const method = take(methodLen);\n const intentHashField = take(32);\n const accountCount = u32At(o);\n o += 4;\n const accountHeads = Array.from({ length: accountCount }, () => take(32));\n const governanceCount = u32At(o);\n o += 4;\n const governanceFloor = Array.from({ length: governanceCount }, () =>\n take(32),\n );\n const nonce = take(8);\n const notAfter = take(8);\n const signature = take(64);\n\n if (o * 2 !== warrant.length) {\n throw new Error(\n `warrant is ${warrant.length / 2} bytes but its fields account for ${o}`,\n );\n }\n\n return {\n context,\n authorAccount,\n deviceKey,\n executor,\n appVersion,\n method,\n intentHash: intentHashField,\n accountHeads,\n governanceFloor,\n nonce,\n notAfter,\n signature,\n };\n}\n", "/**\n * Write to a context through a relay, holding nothing but a signing key.\n *\n * # What this replaces\n *\n * `sdk.rpc.execute` asks a node to run a method *as itself*: it needs a node,\n * that node needs to be a member, and the caller needs a credential on it. For\n * a browser tab, a phone, or an agent, none of those three is available \u2014 the\n * runtime cannot compile WASM against materialized state, never received the\n * scope key that seals the deltas, and has no account on anybody's node.\n *\n * This client is the other path. The caller signs a warrant locally, the relay\n * runs the method as the *author's* principal, and the resulting delta is\n * attributed to the author's account and device \u2014 their replica slot, their\n * membership, their name in the app. The relay's key signs the envelope and\n * nothing else.\n *\n * # The three preconditions, and why they are checked in this order\n *\n * `describe()` answers the first two in one call, before anything is signed:\n * the relay's executor account (which the warrant must name) and whether it\n * holds `CAN_AUTHOR_ON_BEHALF` on the owning group. The third \u2014 that the\n * author's account is a member \u2014 only the group knows, and it surfaces as a\n * refusal.\n *\n * Checking before signing is not politeness. A warrant consumes a nonce from a\n * monotonic per-device sequence, and one minted against the wrong executor is\n * unspendable: the number is gone and the write never happened.\n */\n\nimport { signWarrant } from '../warrant/warrant.js';\nimport { HTTPError } from '../http-client/web-client.js';\nimport type { NonceSource } from './nonce-source.js';\n\n/** How long a freshly minted warrant stays presentable, in seconds. */\nconst DEFAULT_TTL_SECONDS = 300;\n\n/** Where and as whom to write, plus the key that consents. */\nexport interface RelayClientConfig {\n /**\n * The relay's base URL \u2014 the node's origin, not a path.\n *\n * Discover it from {@link CloudClient.getNamespaceRelays} for a hosted\n * namespace, or take it from the operator for a self-hosted one.\n */\n relayUrl: string;\n /**\n * The account the relay writes as, hex \u2014 a warrant's `executor`.\n *\n * An account rather than a key, so one of the relay's processes rotating its\n * signing key does not void warrants already issued to it. Left unset, the\n * first `execute` learns it from {@link RelayClient.describe}.\n */\n executorAccount?: string;\n /** The author's account, hex \u2014 whose consent the warrant carries. */\n authorAccount: string;\n /**\n * The author's `AccountProof<DeviceCert>`, hex-encoded borsh.\n *\n * Proves the key that signed the warrant is a device of the account it names.\n * The author sends only its own half; the relay attaches its own.\n */\n authorProof: string;\n /**\n * The author device's ed25519 signing secret, hex (32 bytes).\n *\n * Never transmitted. It signs in this process and only the signature leaves,\n * which is the whole reason a keyholder can author without a node.\n */\n deviceSecret: string;\n /** Where nonces come from. See {@link NonceSource} \u2014 a reset replays. */\n nonces: NonceSource;\n /**\n * Seconds a minted warrant stays valid. Defaults to 300.\n *\n * Checked by the relay against its own clock and deliberately never by peers,\n * so this bounds how long *this* request may sit in flight \u2014 not how long the\n * network will accept the delta.\n */\n ttlSeconds?: number;\n /** Injected for tests and non-browser runtimes. Defaults to global `fetch`. */\n fetch?: typeof fetch;\n timeoutMs?: number;\n}\n\n/** What a relay says about its ability to run intents in one context. */\nexport interface RelayDescription {\n /** The account a warrant must name as `executor`, hex. */\n executorAccount: string;\n /** Whether the relay holds `CAN_AUTHOR_ON_BEHALF` on the owning group. */\n canAuthorOnBehalf: boolean;\n /** The group whose admin grants that capability, hex. */\n groupId: string;\n}\n\n/** Where an accepted intent landed. */\nexport interface IntentResult<T = unknown> {\n /** The context's scope root after the run \u2014 did this change anything? */\n rootHash: string;\n /** The method's own return value. */\n returns: T | null;\n}\n\n/**\n * Thrown when a relay refuses an intent, carrying which precondition failed.\n *\n * The distinction is the whole reason this type exists. A `403` from this\n * endpoint means one of three unrelated things \u2014 no grant on the relay, the\n * author is not a member, or the nonce was already spent \u2014 and they send a\n * caller somewhere completely different: ask an admin, ask for an invitation,\n * or just retry. Collapsing them into \"forbidden\" makes a retryable replay look\n * like a permissions bug.\n */\nexport class IntentRefusedError extends Error {\n name = 'IntentRefusedError';\n\n constructor(\n /** The relay's own explanation, verbatim. */\n public readonly reason: string,\n /** `true` when re-presenting the same intent under a *fresh* warrant may work. */\n public readonly retryable: boolean,\n public readonly status: number,\n ) {\n super(`relay refused the intent (HTTP ${status}): ${reason}`);\n }\n}\n\nexport class RelayClient {\n private readonly baseUrl: string;\n private executorAccount: string | undefined;\n private readonly config: RelayClientConfig;\n private readonly fetchImpl: typeof fetch;\n private readonly timeoutMs: number;\n\n constructor(config: RelayClientConfig) {\n this.config = config;\n this.baseUrl = config.relayUrl.replace(/\\/+$/, '');\n this.executorAccount = config.executorAccount;\n const injected = config.fetch;\n this.fetchImpl = injected\n ? (input: RequestInfo | URL, init?: RequestInit) => injected(input, init)\n : (input: RequestInfo | URL, init?: RequestInit) => globalThis.fetch(input, init);\n this.timeoutMs = config.timeoutMs ?? 10_000;\n }\n\n /**\n * Ask the relay what it can do in `contextId`.\n *\n * Cheap and unauthenticated on a relay that serves delegated execution\n * publicly, which is what makes it usable as a precondition check rather than\n * as diagnostics after a failure.\n */\n async describe(contextId: string): Promise<RelayDescription> {\n const body = await this.json<{\n data: { executorAccount: string; canAuthorOnBehalf: boolean; groupId: string };\n }>('GET', `/admin-api/contexts/${encodeURIComponent(contextId)}/intents`);\n // Learned, not merely returned: a client that called `describe` should not\n // then have to pass the account back in to `execute`.\n this.executorAccount = body.data.executorAccount;\n return body.data;\n }\n\n /**\n * Mint a warrant for `method(args)` and present it to the relay.\n *\n * One intent, once: the warrant authorizes exactly this method and these\n * arguments in exactly this context, and its nonce is spent by the network on\n * apply. Nothing accumulates and nothing is reusable.\n */\n async execute<T = unknown>(\n contextId: string,\n method: string,\n argsJson: unknown = {},\n ): Promise<IntentResult<T>> {\n const executor = this.executorAccount ?? (await this.describe(contextId)).executorAccount;\n\n const nonce = await this.config.nonces.next();\n const ttl = this.config.ttlSeconds ?? DEFAULT_TTL_SECONDS;\n const warrant = await signWarrant({\n context: contextId,\n authorAccount: this.config.authorAccount,\n executor,\n method,\n argsJson,\n nonce,\n notAfter: BigInt(Math.floor(Date.now() / 1000)) + BigInt(ttl),\n deviceSecret: this.config.deviceSecret,\n });\n\n const body = await this.json<{ data: { rootHash: string; returns: T | null } }>(\n 'POST',\n `/admin-api/contexts/${encodeURIComponent(contextId)}/intents`,\n { method, argsJson, warrant, authorProof: this.config.authorProof },\n );\n return { rootHash: body.data.rootHash, returns: body.data.returns ?? null };\n }\n\n private async json<T>(method: string, path: string, body?: unknown): Promise<T> {\n const headers: Record<string, string> = { Accept: 'application/json' };\n if (body !== undefined) headers['Content-Type'] = 'application/json';\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n let response: Response;\n try {\n response = await this.fetchImpl(`${this.baseUrl}${path}`, {\n method,\n headers,\n body: body === undefined ? undefined : JSON.stringify(body),\n signal: controller.signal,\n });\n } catch (err) {\n throw new HTTPError(\n 0,\n err instanceof Error ? err.name : 'NetworkError',\n `${this.baseUrl}${path}`,\n new Headers(),\n err instanceof Error ? err.message : String(err),\n );\n } finally {\n clearTimeout(timer);\n }\n\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n // 400 and 403 are both caller preconditions and core separates them\n // deliberately: 400 means re-sending the same bytes cannot help, 403\n // means the bytes are genuine but authority is missing. Only the spent\n // nonce is worth retrying, and only under a fresh warrant.\n if (response.status === 400 || response.status === 403) {\n const reason = extractReason(text);\n throw new IntentRefusedError(reason, /nonce/i.test(reason), response.status);\n }\n throw new HTTPError(\n response.status,\n response.statusText,\n `${this.baseUrl}${path}`,\n response.headers,\n text,\n );\n }\n\n return (await response.json()) as T;\n }\n}\n\n/** Pull the relay's explanation out of its error body, or fall back to the raw text. */\nfunction extractReason(bodyText: string): string {\n if (!bodyText) return 'no reason given';\n try {\n const parsed = JSON.parse(bodyText) as { error?: unknown; message?: unknown };\n for (const candidate of [parsed.error, parsed.message]) {\n if (typeof candidate === 'string' && candidate) return candidate;\n }\n } catch {\n // Not JSON \u2014 the text itself is the best available explanation.\n }\n return bodyText;\n}\n", "/**\n * Where a warrant's nonce comes from.\n *\n * # Why this is a named concept and not a counter in the relay client\n *\n * A warrant's nonce is spent, once, per `(context, author device)` on every\n * node that applies the delta. So the sequence a client emits is not a local\n * detail \u2014 it is state the network remembers, and the client is the only party\n * that can keep it.\n *\n * The receiving ledger is a **sliding window** 64 wide, not a high-water mark,\n * which is what makes the two failure modes so different:\n *\n * - **Skipping** numbers is free. Gossip gives no ordering, so the window\n * exists precisely to accept whatever unseen nonce arrives.\n * - **Restarting** the sequence is fatal. A tab that reloads and resumes at `1`\n * re-presents nonces the network has already spent, and every one of those\n * writes is refused as a replay \u2014 indistinguishable, to the user, from the\n * app silently not saving.\n *\n * That asymmetry is why persistence is the default here and an in-memory source\n * is the one you have to ask for. It is also why a source may jump: reserving a\n * block and losing the tail is the correct trade.\n */\n\n/** Produces the next nonce for one author device. Must never go backwards. */\nexport interface NonceSource {\n next(): Promise<bigint>;\n}\n\n/**\n * A counter in memory, starting at `start`.\n *\n * Correct only for a process whose lifetime is the whole sequence \u2014 a script, a\n * server-side worker that owns its own device key, a test. In a browser tab it\n * resets on reload and replays; use {@link createLocalStorageNonceSource}\n * there.\n */\nexport function createMemoryNonceSource(start: number | bigint = 1): NonceSource {\n let next = BigInt(start);\n if (next < 1n) {\n throw new Error('nonce sequence starts at 1');\n }\n return {\n next(): Promise<bigint> {\n const value = next;\n next += 1n;\n return Promise.resolve(value);\n },\n };\n}\n\n/**\n * A counter persisted in `localStorage`, so a reload continues the sequence.\n *\n * Key it per author **device**, not per account: two devices of one account are\n * independent replicas with independent sequences, and sharing a counter would\n * have them refusing each other's warrants.\n *\n * **Reserve-then-hand-out.** The stored value is advanced *before* the nonce is\n * returned, so a crash between the two loses a number rather than reusing one.\n * Losing a number costs nothing (the window accepts gaps); reusing one costs a\n * write.\n *\n * Concurrent tabs are the case this cannot fully solve, because `localStorage`\n * has no atomic read-modify-write. Two tabs racing can hand out the same nonce,\n * and the loser's write is refused as a replay rather than silently\n * misattributed \u2014 a visible error, not corruption. An app that genuinely writes\n * from several tabs at once should hold a Web Lock around `next()` or give each\n * tab its own device.\n */\nexport function createLocalStorageNonceSource(\n key: string,\n storage?: { getItem(k: string): string | null; setItem(k: string, v: string): void },\n): NonceSource {\n const store =\n storage ?? (globalThis as unknown as { localStorage?: typeof storage }).localStorage;\n if (!store) {\n throw new Error(\n 'no localStorage in this runtime: pass a storage implementation, or use createMemoryNonceSource for a process that owns its whole sequence',\n );\n }\n return {\n next(): Promise<bigint> {\n const raw = store.getItem(key);\n // A missing, empty, or corrupted value means \"no sequence recorded\", and\n // the safe reading of that is not 1 \u2014 a cleared storage on a device that\n // has already written would replay. But the client cannot know, and 1 is\n // the only defensible start, so it is what a fresh key gets. This is why\n // the doc above tells apps to key per device: a device whose storage was\n // cleared should be re-paired rather than resumed.\n let current = 0n;\n if (raw !== null && raw !== '') {\n try {\n const parsed = BigInt(raw);\n if (parsed > 0n) current = parsed;\n } catch {\n current = 0n;\n }\n }\n const value = current + 1n;\n store.setItem(key, value.toString());\n return Promise.resolve(value);\n },\n };\n}\n", "/**\n * The second way to log in: sign in to Calimero Cloud instead of connecting to\n * a node.\n *\n * # Two connection shapes, one SDK\n *\n * `createMeroJs({ baseUrl })` is the node connection: point at a node, hold a\n * credential on it, and drive its admin API and JSON-RPC. It assumes the caller\n * has a node \u2014 their own, or one they have an account on.\n *\n * `connectCloud(...)` is for the caller who has neither. They sign in with the\n * identity they already use (Google, through the cloud), and the cloud answers\n * with an attested TEE relay serving their namespace. Writes then go through\n * delegated execution: signed here, run there, attributed here.\n *\n * The two are not alternatives to be picked at random \u2014 they answer different\n * questions. \"Which node do I talk to?\" has an answer for a desktop app and no\n * answer at all for a web app whose user has never installed anything. This\n * function is that missing answer, which is why the login step it replaces is\n * the *node URL prompt* rather than the authentication.\n *\n * # What it does not do\n *\n * It does not read state. A relay writes on the author's behalf; reads still\n * come from a node the client can query, or from the app's own projection of\n * the events it receives. `connectCloud` is deliberately narrow about this\n * rather than presenting a half-working `MeroJs` whose `admin` and `rpc` would\n * need a credential nobody holds.\n */\n\nimport { CloudClient } from './cloud-client.js';\nimport type { CloudClientConfig, CloudNamespace, CloudRelay } from './cloud-client.js';\nimport { RelayClient } from '../relay/relay-client.js';\nimport type { IntentResult, NonceSource } from '../relay/index.js';\nimport { createLocalStorageNonceSource, createMemoryNonceSource } from '../relay/nonce-source.js';\nimport { derivePublicKey, hex } from '../crypto/internal.js';\n\nexport interface ConnectCloudOptions {\n /** Defaults to the hosted cloud. */\n cloudBaseUrl?: string;\n /** A stored MDMA session token. Provide this or `googleIdToken`. */\n sessionToken?: string;\n /** A Google ID token to exchange for a session. Provide this or `sessionToken`. */\n googleIdToken?: string;\n /** Persist a new or rolling-refreshed session. See {@link CloudClientConfig.onSession}. */\n onSession?: CloudClientConfig['onSession'];\n\n /** The author's account, hex \u2014 whose writes these will be. */\n authorAccount: string;\n /** The author's `AccountProof<DeviceCert>`, hex-encoded borsh. */\n authorProof: string;\n /** The author device's ed25519 signing secret, hex. Never transmitted. */\n deviceSecret: string;\n\n /**\n * Which namespace to write in.\n *\n * Optional only when the user owns exactly one: guessing among several would\n * pick a tenant for them, and the failure would be a write landing in the\n * wrong place rather than an error.\n */\n namespaceId?: string;\n\n /**\n * Where nonces come from.\n *\n * Defaults to `localStorage`, keyed by the author's device public key, so a\n * reload continues the sequence instead of replaying it. Pass\n * {@link createMemoryNonceSource} explicitly for a process that owns its\n * whole sequence, or your own source to coordinate across tabs.\n */\n nonces?: NonceSource;\n /** Seconds a minted warrant stays presentable. Defaults to 300. */\n ttlSeconds?: number;\n fetch?: typeof fetch;\n timeoutMs?: number;\n}\n\n/** A signed-in cloud session with a relay ready to write through. */\nexport interface CloudConnection {\n /** The cloud API, for namespaces, billing, HA and sign-out. */\n cloud: CloudClient;\n /** The relay chosen for this namespace. */\n relay: RelayClient;\n /** The namespace writes will land in. */\n namespaceId: string;\n namespace: CloudNamespace;\n /** What the cloud reported about the chosen relay. */\n relayInfo: CloudRelay;\n /** Run one method in one context, on the author's behalf. */\n execute<T = unknown>(\n contextId: string,\n method: string,\n argsJson?: unknown,\n ): Promise<IntentResult<T>>;\n}\n\n/**\n * Sign in to the cloud and return a connection that can write.\n *\n * Throws rather than returning a half-usable connection, and the message says\n * which step is missing \u2014 no namespace, several to choose between, HA not\n * enabled, or no relay holding the authorship grant. Every one of those is\n * something the user has to go and do, and a client that reports them alike\n * cannot tell them what.\n */\nexport async function connectCloud(options: ConnectCloudOptions): Promise<CloudConnection> {\n if (!options.sessionToken && !options.googleIdToken) {\n throw new Error('connectCloud needs either a sessionToken or a googleIdToken');\n }\n\n const cloud = new CloudClient({\n cloudBaseUrl: options.cloudBaseUrl,\n sessionToken: options.sessionToken,\n onSession: options.onSession,\n fetch: options.fetch,\n timeoutMs: options.timeoutMs,\n });\n\n if (!options.sessionToken && options.googleIdToken) {\n await cloud.signInWithGoogle(options.googleIdToken);\n }\n\n const namespaces = await cloud.getMyNamespaces();\n const namespace = pickNamespace(namespaces, options.namespaceId);\n\n // One read, used for both the choice and the diagnostic. `findExecutingRelay`\n // would fetch again to explain itself, and a second call can disagree with the\n // first \u2014 reporting \"waiting for the grant\" about a relay that was already\n // usable a moment ago.\n const relays = await cloud.getNamespaceRelays(namespace.namespaceId);\n const relayInfo =\n relays.find((r) => r.authorshipReady && r.relayUrl !== null && r.executorAccount !== null) ??\n null;\n if (!relayInfo) {\n throw new Error(explainNoRelay(namespace, relays));\n }\n\n const relay = new RelayClient({\n // Checked by `findExecutingRelay`, which is the only thing that returns a\n // relay \u2014 narrowed here rather than re-validated, so the invariant lives in\n // one place.\n relayUrl: relayInfo.relayUrl as string,\n executorAccount: relayInfo.executorAccount as string,\n authorAccount: options.authorAccount,\n authorProof: options.authorProof,\n deviceSecret: options.deviceSecret,\n nonces: options.nonces ?? (await defaultNonceSource(options.deviceSecret)),\n ttlSeconds: options.ttlSeconds,\n fetch: options.fetch,\n timeoutMs: options.timeoutMs,\n });\n\n return {\n cloud,\n relay,\n namespaceId: namespace.namespaceId,\n namespace,\n relayInfo,\n execute: (contextId, method, argsJson) => relay.execute(contextId, method, argsJson),\n };\n}\n\n/** The one namespace to write in, or an error naming the actual ambiguity. */\nfunction pickNamespace(namespaces: CloudNamespace[], requested?: string): CloudNamespace {\n if (requested) {\n const found = namespaces.find((n) => n.namespaceId === requested);\n if (!found) {\n throw new Error(\n `this account owns no namespace ${requested}; it owns: ${\n namespaces.map((n) => n.namespaceId).join(', ') || '(none)'\n }`,\n );\n }\n return found;\n }\n if (namespaces.length === 0) {\n throw new Error(\n 'this account owns no namespaces in the cloud: claim one first, then enable HA on it so a relay is assigned',\n );\n }\n if (namespaces.length > 1) {\n throw new Error(\n `this account owns ${namespaces.length} namespaces \u2014 pass namespaceId to say which: ${namespaces\n .map((n) => n.namespaceId)\n .join(', ')}`,\n );\n }\n return namespaces[0];\n}\n\n/**\n * Why no relay can write here \u2014 the three states, kept apart.\n *\n * They are three different asks of the user (turn HA on, wait, or get an admin\n * to grant a capability) and one message for all of them would send them to\n * the wrong one.\n */\nfunction explainNoRelay(namespace: CloudNamespace, relays: CloudRelay[]): string {\n if (relays.length === 0) {\n return namespace.haStatus === 'enabled'\n ? `namespace ${namespace.namespaceId} has HA enabled but no relay has been assigned to it yet \u2014 retry shortly`\n : `namespace ${namespace.namespaceId} has no relays: enable HA on it in the cloud to have an attested node assigned`;\n }\n const waitingOnGrant = relays.filter((r) => !r.authorshipReady);\n if (waitingOnGrant.length === relays.length) {\n return (\n `every relay on namespace ${namespace.namespaceId} is waiting for the authorship grant: ` +\n `an admin of the namespace must grant CAN_AUTHOR_ON_BEHALF to ${\n waitingOnGrant.map((r) => r.executorAccount ?? r.peerId).join(', ') || 'the relay account'\n }`\n );\n }\n return `namespace ${namespace.namespaceId} has ${relays.length} relay(s), but none reported both a URL and an executor account yet \u2014 retry shortly`;\n}\n\n/**\n * A persisted nonce source keyed by the author's device public key.\n *\n * The key is the *public* key, derived locally: a per-device key is required\n * (two devices of one account are independent replicas) and the secret must\n * never end up in a storage key an extension or another script can enumerate.\n *\n * Falls back to memory where there is no `localStorage` \u2014 Node, a worker, an\n * edge runtime. Those are processes that own their whole sequence, which is\n * exactly the case a memory counter is correct for.\n */\nasync function defaultNonceSource(deviceSecret: string): Promise<NonceSource> {\n const key = `mero-js:warrant-nonce:${hex(await derivePublicKey(deviceSecret))}`;\n try {\n return createLocalStorageNonceSource(key);\n } catch {\n return createMemoryNonceSource(1);\n }\n}\n", "/**\n * Minting and certifying a device offline, with a key that never reaches a node.\n *\n * This is the second half of the keyholder story. `signWarrant` lets an account\n * with no node *write*; this lets one exist in the first place \u2014 an account root\n * certifies a device, and the resulting credential is what a joiner presents.\n *\n * As with the warrant signer, the risk is that this reproduces core's encoding\n * and has to keep doing so. The answer is the same: a golden vector here, and an\n * e2e that diffs this output against `merod account sign-cert` byte for byte.\n *\n * Everything below is derived from core:\n *\n * - `DeviceCert::signing_payload` \u2014 `crates/account/src/device.rs`\n * - `DeviceId::mint` \u2014 `crates/primitives/src/identity.rs`\n * - `AccountProof` / `AccountGenesis` borsh layout \u2014 `crates/account/src/{signed,account}.rs`\n */\nimport {\n concat,\n derivePublicKey,\n domainHash,\n fromHex,\n hex,\n importSigningKey,\n u32le,\n} from '../crypto/internal.js';\n\nconst CERT_DOMAIN = new TextEncoder().encode('calimero.device.cert.v1');\nconst ACCOUNT_ID_DOMAIN = new TextEncoder().encode('calimero.account.genesis.v1');\nconst DEVICE_ID_DOMAIN = new TextEncoder().encode('calimero.device.id.v1');\n\n/** `AccountGenesis::version`, which the credential's borsh encoding leads with. */\n/**\n * Core's `ACCOUNT_GENESIS_VERSION`. It is part of the `AccountId` preimage, so\n * this value decides which account a root key names \u2014 a mismatch does not fail\n * as a version error at the edge, it silently derives a different account and\n * core refuses the credential as unverifiable.\n *\n * `2` since the genesis dropped its per-namespace nonce. This was `1`, which\n * produced credentials current core rejects outright; the shape was already v2,\n * only the tag was stale.\n */\nconst ACCOUNT_GENESIS_VERSION = 2;\n\n/** What a root certifies about one device. */\nexport interface DeviceCertInput {\n /** The account root's signing secret, 64 hex. Signs the certificate. */\n rootSecret: string;\n /** The device being certified, 64 hex \u2014 see {@link mintDeviceId}. */\n device: string;\n /** The key that device signs with, 64 hex. */\n signPublicKey: string;\n /** The key the group key is delivered to, 64 hex (X25519). */\n kemPublicKey: string;\n /**\n * Must strictly exceed any epoch already folded for this device.\n *\n * The projection refuses a link that does not advance it, so a re-issued\n * certificate reusing an epoch is inert rather than a rollback.\n */\n deviceEpoch: number;\n}\n\n/**\n * Mint a device id: `H(DEVICE_ID_DOMAIN, account \u2016 nonce)`.\n *\n * Derived from the account and a fresh nonce rather than from the device's keys,\n * so rotating a keypair keeps the replica identity \u2014 and with it the counter\n * slots and HLC lineage \u2014 intact.\n */\nexport async function mintDeviceId(\n account: string,\n nonce: Uint8Array,\n): Promise<string> {\n if (nonce.length !== 16) {\n throw new Error(`nonce must be 16 bytes, got ${nonce.length}`);\n }\n const accountBytes = fromHex(account, 'account', 32);\n return hex(await domainHash(DEVICE_ID_DOMAIN, [accountBytes, nonce]));\n}\n\n/**\n * The 32 bytes a root signs to certify a device.\n *\n * Both keys are covered, so neither the signing key nor the delivery key can be\n * substituted into a certificate that otherwise verifies \u2014 which is what stops a\n * relay carrying someone's credential from making itself the reader.\n */\nexport async function deviceCertPayload(input: {\n account: string;\n device: string;\n signPublicKey: string;\n kemPublicKey: string;\n keyEpoch: number;\n deviceEpoch: number;\n}): Promise<Uint8Array> {\n return domainHash(CERT_DOMAIN, [\n fromHex(input.account, 'account', 32),\n fromHex(input.device, 'device', 32),\n fromHex(input.signPublicKey, 'signPublicKey', 32),\n fromHex(input.kemPublicKey, 'kemPublicKey', 32),\n u32le(input.keyEpoch),\n u32le(input.deviceEpoch),\n ]);\n}\n\n/**\n * Borsh-encode an `AccountProof<DeviceCert>` \u2014 what core calls a\n * `JoinAccountCredential`.\n *\n * Extracted so the device-cert path and the namespace-op signer encode this from\n * one implementation. Two copies of a borsh layout drift silently: the encoding\n * is only checked by a peer rejecting a signature, which points at the signature\n * rather than at whichever copy went stale.\n *\n * Layout is `AccountProof { genesis, chain, statement }`:\n * `AccountGenesis` (version u8 + root pk 32) + `chain` (empty Vec, u32 len) +\n * `DeviceCert` (account 32 + device 32 + sign pk 32 + kem pk 32 + key_epoch u32\n * + device_epoch u32 + signature 64) = 237 bytes with an empty chain.\n */\nexport function accountProofBytes(input: {\n rootPublicKey: Uint8Array;\n account: string;\n device: string;\n signPublicKey: string;\n kemPublicKey: string;\n keyEpoch: number;\n deviceEpoch: number;\n signature: Uint8Array;\n}): Uint8Array {\n return concat(\n new Uint8Array([ACCOUNT_GENESIS_VERSION]),\n input.rootPublicKey,\n u32le(0),\n fromHex(input.account, 'account', 32),\n fromHex(input.device, 'device', 32),\n fromHex(input.signPublicKey, 'signPublicKey', 32),\n fromHex(input.kemPublicKey, 'kemPublicKey', 32),\n u32le(input.keyEpoch),\n u32le(input.deviceEpoch),\n input.signature,\n );\n}\n\n/**\n * Certify a device, returning the hex credential `merod account sign-cert`\n * prints \u2014 a borsh-encoded `AccountProof<DeviceCert>`.\n *\n * The layout, field for field, is core's:\n *\n * ```\n * AccountProof { genesis: AccountGenesis, chain: Vec<RootKeyHandoff>, statement: DeviceCert }\n * AccountGenesis { version: u8, root_sign_pk: [u8; 32] }\n * chain \u2192 u32-LE count, then that many handoffs\n * DeviceCert { account, device, sign_pk, kem_pk: [u8; 32] x4,\n * key_epoch: u32, device_epoch: u32, signature: [u8; 64] }\n * ```\n *\n * Borsh for plain fixed-width data is concatenation; the only variable part is\n * the chain's length prefix. `chain` is empty here for the same reason it is in\n * `sign-cert`: a root that has never been handed off signs directly, and a\n * handoff chain is only needed once it has.\n *\n * `keyEpoch` is 0 for the same reason \u2014 it names the root epoch that signed, and\n * an un-rotated root is at 0. Re-signing after a handoff is a separate flow that\n * needs the chain, so this deliberately does not take it as an argument rather\n * than accepting a value it would then have to ignore.\n */\nexport async function signDeviceCert(input: DeviceCertInput): Promise<string> {\n const rootPublicKey = await derivePublicKey(input.rootSecret);\n const account = hex(\n await domainHash(ACCOUNT_ID_DOMAIN, [\n concat(new Uint8Array([ACCOUNT_GENESIS_VERSION]), rootPublicKey),\n ]),\n );\n\n const keyEpoch = 0;\n const payload = await deviceCertPayload({\n account,\n device: input.device,\n signPublicKey: input.signPublicKey,\n kemPublicKey: input.kemPublicKey,\n keyEpoch,\n deviceEpoch: input.deviceEpoch,\n });\n\n const key = await importSigningKey(input.rootSecret);\n const signature = new Uint8Array(\n await crypto.subtle.sign('Ed25519', key, payload),\n );\n\n const credential = accountProofBytes({\n rootPublicKey,\n account,\n device: input.device,\n signPublicKey: input.signPublicKey,\n kemPublicKey: input.kemPublicKey,\n keyEpoch,\n deviceEpoch: input.deviceEpoch,\n signature,\n });\n\n return hex(credential);\n}\n\n/** The account this root owns \u2014 the content address of its genesis. */\nexport async function accountForRoot(rootSecret: string): Promise<string> {\n const rootPublicKey = await derivePublicKey(rootSecret);\n return hex(\n await domainHash(ACCOUNT_ID_DOMAIN, [\n concat(new Uint8Array([ACCOUNT_GENESIS_VERSION]), rootPublicKey),\n ]),\n );\n}\n", "/**\n * Sign a namespace governance op from the SDK \u2014 specifically the membership op a\n * keyholder needs to join without running a node.\n *\n * `admitJoin` carries an already-signed op to a node the inviter named as an\n * admitter. Producing that op is the piece a keyholder could not do before: the\n * op must be signed by the device key in the credential it carries, because every\n * peer checks `signer == credential.statement.sign_pk` when applying a join. An\n * admitter can relay it and can never author it.\n *\n * The encoding is borsh, hand-written to match core's structs. Correctness is not\n * asserted against bytes recorded here \u2014 a layout transcribed by eye is exactly\n * how a golden ends up confidently wrong. It is asserted by a node accepting the\n * op, which is what the e2e does.\n */\nimport type { SignedGroupOpenInvitation } from '../admin-api/admin-types.js';\nimport {\n concat,\n derivePublicKey,\n fromHex,\n hex,\n importSigningKey,\n u32le,\n u64le,\n} from '../crypto/internal.js';\n\n/** Core's `SIGNED_NAMESPACE_OP_SCHEMA_VERSION`. A node refuses any other value. */\nexport const SIGNED_NAMESPACE_OP_SCHEMA_VERSION = 8;\n\n/** Domain prefixed to the signable bytes; core's `NAMESPACE_GOVERNANCE_SIGN_DOMAIN`. */\nconst NAMESPACE_SIGN_DOMAIN = new TextEncoder().encode('calimero.namespace.v1');\n\n/** `NamespaceOp::Root` is the first variant. */\nconst NAMESPACE_OP_ROOT = 0;\n\n/**\n * `RootOp` discriminants, in declaration order. Only the two join variants are\n * emitted here; the rest are listed so the numbering is checkable against core\n * rather than inferred from the two in use.\n */\nconst ROOT_OP = {\n GroupCreated: 0,\n GroupReparented: 1,\n GroupDeleted: 2,\n AdminChanged: 3,\n PolicyUpdated: 4,\n MemberJoined: 5,\n KeyDelivery: 6,\n MemberJoinedOpen: 7,\n MemberJoinedAt: 8,\n NamespaceCreated: 9,\n MemberJoinedViaTeeAttestation: 10,\n} as const;\n\n/** A required `[u8; 32]`, as JSON carries it: 32 byte values. */\nfunction bytes32(value: readonly number[], label: string): Uint8Array {\n if (value.length !== 32) {\n throw new Error(`${label} must be 32 bytes, got ${value.length}`);\n }\n return new Uint8Array(value);\n}\n\n/**\n * Borsh `Option<[u8; 32]>` from the byte array JSON carries it as.\n *\n * `[u8; 32]` crosses JSON as 32 numbers, not as hex \u2014 the hex spelling belongs to\n * `AccountId`, which has its own representation. Encoding one of these from a hex\n * string would silently produce the wrong 32 bytes.\n */\nfunction optionalBytes32(\n value: readonly number[] | null | undefined,\n label: string,\n): Uint8Array {\n if (value === null || value === undefined) {\n return new Uint8Array([0]);\n }\n if (value.length !== 32) {\n throw new Error(`${label} must be 32 bytes, got ${value.length}`);\n }\n return concat(new Uint8Array([1]), new Uint8Array(value));\n}\n\n/** Borsh `String`: u32 length then UTF-8 bytes. */\nfunction borshString(value: string): Uint8Array {\n const bytes = new TextEncoder().encode(value);\n return concat(u32le(bytes.length), bytes);\n}\n\n\n/**\n * Borsh-encode a `SignedGroupOpenInvitation`.\n *\n * Re-encoded rather than passed through, because it has to go inside the op that\n * gets signed. That makes this function version-locked to core: a field added to\n * the invitation and omitted here produces an op whose inner invitation no longer\n * matches the inviter's signature over it. That exact drift, in client-py, broke\n * 93 scenarios \u2014 the failure surfaces as `invalid invitation signature` and points\n * nowhere near the encoder.\n */\nexport function encodeSignedInvitation(signed: SignedGroupOpenInvitation): Uint8Array {\n const body = signed.invitation;\n const admitters = body.admitters ?? [];\n const admitterAddrs = signed.admitter_addrs ?? [];\n\n return concat(\n // GroupInvitationFromAdmin.\n //\n // `SignerId` and `ContextGroupId` cross JSON as 32 numbers; `AccountId`\n // crosses as hex. Same width, different spelling, and reading either the\n // wrong way yields 32 bytes that encode cleanly and verify as nothing.\n bytes32(body.inviter_identity, 'inviter_identity'),\n bytes32(body.group_id, 'group_id'),\n u64le(body.expiration_timestamp),\n bytes32(body.secret_salt, 'secret_salt'),\n new Uint8Array([body.invited_role]),\n u32le(admitters.length),\n ...admitters.map((a, i) => fromHex(a, `admitters[${i}]`, 32)),\n // ...then the enclosing SignedGroupOpenInvitation, in declaration order.\n // `inviter_account` sits between the signature and the addresses; putting it\n // anywhere else still encodes 32 bytes and still verifies as nothing.\n borshString(signed.inviter_signature),\n signed.inviter_account\n ? concat(new Uint8Array([1]), fromHex(signed.inviter_account, 'inviter_account', 32))\n : new Uint8Array([0]),\n // A `Vec<String>`, so each entry is a bare borsh string. This carried an\n // enum until core dropped the URL variant, and an enum writes a\n // discriminant byte ahead of each entry \u2014 encoding one here now would shift\n // every following byte and fail as `invalid invitation signature`, pointing\n // nowhere near this line.\n u32le(admitterAddrs.length),\n ...admitterAddrs.map(borshString),\n optionalBytes32(signed.application_id, 'application_id'),\n // Borsh order follows core's field order, where this is `bytecode_id`; the\n // JSON key is `app_key`, a rename covering both directions that core pins in\n // a test. Encoding by the Rust name would read `undefined` and emit a None\n // where the inviter signed a Some.\n optionalBytes32(signed.app_key, 'app_key'),\n );\n}\n\nexport interface SignMemberJoinInput {\n /** The namespace being joined, 64 hex. */\n readonly namespaceId: string;\n /** The account joining, 64 hex \u2014 the subject of the credential. */\n readonly member: string;\n /** The invitation, as the admin API returned it. */\n readonly invitation: SignedGroupOpenInvitation;\n /**\n * The joiner's `AccountProof<DeviceCert>`, hex \u2014 from `signDeviceCert`.\n *\n * Its `sign_pk` must be the public key of `deviceSecret`; a peer checks that\n * when applying the join and refuses otherwise.\n */\n readonly credential: string;\n /** The device signing secret, 64 hex. Must match the credential's `sign_pk`. */\n readonly deviceSecret: string;\n /**\n * Heads this op is written against. Empty means \"signed against an empty head\"\n * \u2014 which is NOT the same as genesis, and a node with a non-empty head will\n * reject it as stale rather than treat it as a first op.\n */\n readonly parentOpHashes?: readonly string[];\n /** Anti-replay nonce; a node keeps a window per signer. */\n readonly nonce: number | bigint;\n /**\n * When the join happened, unix seconds. Defaults to now.\n *\n * Carried only by `MemberJoinedAt`, which is the variant used whenever the\n * invitation expires \u2014 and since core clamps every invitation to\n * `MAX_INVITATION_VALIDITY_SECS`, that is every invitation. The variant is\n * inferred from the invitation rather than selected by a flag: an expiring\n * invitation joined with plain `MemberJoined` is refused at apply with\n * \"expiration is set but joined_at is absent\", which is not a mistake worth\n * leaving available.\n */\n readonly joinedAt?: number | bigint;\n}\n\n/**\n * Sign a `MemberJoined` (or `MemberJoinedAt`) namespace op and return it\n * borsh-encoded and hex \u2014 the `signedOp` that `admitJoin` takes.\n */\nexport async function signMemberJoinOp(input: SignMemberJoinInput): Promise<string> {\n const parents = input.parentOpHashes ?? [];\n const credential = fromHex(input.credential, 'credential', input.credential.length / 2);\n\n // An invitation that expires must be claimed with `MemberJoinedAt`, which\n // carries `joined_at` between the invitation and the credential. Choosing the\n // variant from the invitation keeps the two in step: the discriminant and the\n // presence of that field are one decision, and splitting them produces bytes\n // that decode into the wrong shape rather than failing to decode.\n const expires = BigInt(input.invitation.invitation.expiration_timestamp ?? 0) !== 0n;\n const joinedAt =\n input.joinedAt ?? BigInt(Math.floor(Date.now() / 1000));\n\n const rootOp = expires\n ? concat(\n new Uint8Array([ROOT_OP.MemberJoinedAt]),\n fromHex(input.member, 'member', 32),\n encodeSignedInvitation(input.invitation),\n u64le(joinedAt),\n credential,\n )\n : concat(\n new Uint8Array([ROOT_OP.MemberJoined]),\n fromHex(input.member, 'member', 32),\n encodeSignedInvitation(input.invitation),\n credential,\n );\n\n const op = concat(new Uint8Array([NAMESPACE_OP_ROOT]), rootOp);\n\n const key = await importSigningKey(input.deviceSecret);\n const signer = await derivePublicKey(input.deviceSecret);\n\n const signable = concat(\n new Uint8Array([SIGNED_NAMESPACE_OP_SCHEMA_VERSION]),\n fromHex(input.namespaceId, 'namespaceId', 32),\n u32le(parents.length),\n ...parents.map((p, i) => fromHex(p, `parentOpHashes[${i}]`, 32)),\n signer,\n u64le(input.nonce),\n op,\n );\n\n const signature = new Uint8Array(\n await crypto.subtle.sign('Ed25519', key, concat(NAMESPACE_SIGN_DOMAIN, signable)),\n );\n\n // The signed struct repeats the signable fields, then the signature, then the\n // admitter endorsement. The domain is a signing prefix only and is never part\n // of the encoded op.\n //\n // The endorsement is written as borsh `None` \u2014 a single `0x00` \u2014 and that is\n // the correct value from here, not a placeholder. It authorises the membership\n // and can only be signed by an account the invitation named as an admitter,\n // which a keyholder is not. The admitter attaches its own as it relays the op\n // through `admitJoin`.\n //\n // It sits outside `signable`, so it is outside this signature and outside the\n // op's id. That is what makes attaching it possible: the admitter changes\n // neither what was signed here nor which op this is.\n const unendorsed = new Uint8Array([0]);\n\n return hex(concat(signable, signature, unendorsed));\n}\n", "/**\n * Sign the statement a device key presents to obtain a session on a node.\n *\n * This is the half of password-free login that has to run where the device key\n * lives, and for the case delegated execution exists for that is a browser tab.\n * Until this module, the only thing that could produce a login statement was\n * `merod account login-statement` \u2014 which is to say, a client had to hold a node\n * to ask a node for a session.\n *\n * **What this gets you, and what it does not.** A statement proves a device key\n * asked for this session. It says nothing about which account that device\n * belongs to: that is the `AccountProof` travelling beside it, which the node\n * checks separately. Signing here and presenting no proof gets a 401 that looks\n * exactly like a bad signature.\n *\n * **The session key is minted by the caller, not here.** The device key signs\n * once, over a short-lived key the caller generates and keeps; that key does the\n * talking for the rest of the session, which is what keeps the device key off\n * the wire. Passing a key you do not hold the private half of produces a session\n * you cannot speak on.\n *\n * **`node` must come from something you pinned.** Not from the challenge\n * response, and not from any field the node itself chose \u2014 an attacker who can\n * answer on the node's behalf would otherwise pick what your device signs about,\n * which is the whole reason the field exists. Read it out of band from the node\n * operator.\n *\n * **The byte contract is pinned in core**, at\n * `crates/account/src/tests/login_wire_fixture.rs`, for the same reason the\n * warrant one is: `AUTH_LOGIN_SIGN_DOMAIN` is `pub(crate)` there and the field\n * order is implicit in a `derive`, so nothing on that side forces anyone to\n * notice this file depends on both. This module's test asserts the same vectors.\n */\n\nimport {\n concat,\n derivePublicKey,\n domainHash,\n fromHex,\n hex,\n importSigningKey,\n u32le,\n u64le,\n} from '../crypto/internal.js';\n\nconst SIGN_DOMAIN = new TextEncoder().encode('calimero.auth.login.v1');\n\n/**\n * The client surface a session is bound to.\n *\n * A session minted for one surface cannot be presented from another, so a single\n * compromised surface does not yield sessions usable everywhere.\n */\nexport type Audience =\n | {\n /**\n * A browser origin, spelled exactly as the browser spells it\n * (`https://host:port`, no trailing slash).\n *\n * Compared byte for byte by the node. Do not normalize it here: two\n * spellings of one origin would mean a verifier that disagrees with the\n * browser about which one a token was for. `location.origin` is already\n * the spelling you want.\n */\n kind: 'webOrigin';\n origin: string;\n }\n | {\n /** A signed native client, named by its code-signing identity. */\n kind: 'codeSigningId';\n id: string;\n }\n | {\n /**\n * A command-line client, which has no origin and no signing identity.\n *\n * Carries no payload deliberately: a string here would be an audience that\n * binds nothing while looking like it binds something.\n */\n kind: 'cli';\n };\n\n/** The borsh enum tag for each variant, in core's declaration order. */\nconst AUDIENCE_TAG: Record<Audience['kind'], number> = {\n webOrigin: 0,\n codeSigningId: 1,\n cli: 2,\n};\n\n/** The variant's payload as UTF-8 \u2014 empty for the payload-free `cli`. */\nfunction audienceBody(audience: Audience): Uint8Array {\n const encoder = new TextEncoder();\n switch (audience.kind) {\n case 'webOrigin':\n return encoder.encode(audience.origin);\n case 'codeSigningId':\n return encoder.encode(audience.id);\n case 'cli':\n return new Uint8Array(0);\n }\n}\n\n/**\n * What the audience contributes to the **signing preimage**: tag then body, with\n * no length between them.\n *\n * `domainHash` length-prefixes every part it is handed, so a length written here\n * would be counted twice and the preimage would verify nowhere. This is the one\n * field spelled differently in the two encodings \u2014 see {@link audienceWire}.\n */\nfunction audienceSigningBytes(audience: Audience): Uint8Array {\n return concat(\n Uint8Array.from([AUDIENCE_TAG[audience.kind]]),\n audienceBody(audience),\n );\n}\n\n/**\n * What the audience contributes to the **wire encoding**: the borsh enum tag,\n * then for the two payload-carrying variants a borsh `String` \u2014 its own `u32`\n * little-endian length, then the UTF-8.\n *\n * `cli` is a bare tag. Writing a `u32` zero after it instead produces four extra\n * bytes that a node reads as the start of the challenge, so the statement fails\n * as a bad signature rather than as a malformed one.\n */\nfunction audienceWire(audience: Audience): Uint8Array {\n const tag = Uint8Array.from([AUDIENCE_TAG[audience.kind]]);\n if (audience.kind === 'cli') {\n return tag;\n }\n const body = audienceBody(audience);\n return concat(tag, u32le(body.length), body);\n}\n\n/** What a device is asking for. */\nexport interface LoginStatementInput {\n /**\n * The node this session is for, hex (32 bytes) \u2014 its identity public key, as\n * you pinned it. See the module note: this must not come from the node.\n */\n node: string;\n /** The client surface the session is bound to. */\n audience: Audience;\n /** The challenge this node issued, hex (32 bytes). Proves freshness. */\n challenge: string;\n /**\n * The public half of the ephemeral key this session will speak with, hex (32\n * bytes). Minted per session by the caller and thrown away with it.\n */\n sessionKey: string;\n /** Unix seconds at signing. */\n issuedAt: number | bigint;\n /** Unix seconds after which the node must refuse it. */\n expiresAt: number | bigint;\n /**\n * The device's ed25519 signing secret, hex (32 bytes).\n *\n * Never sent anywhere. It signs locally and only the signature travels, which\n * is what lets a statement be minted by something holding no node.\n */\n deviceSecret: string;\n}\n\n/**\n * Sign a login statement and return it hex-encoded, ready to present with an\n * account proof.\n *\n * Returns the encoding rather than an object for the reason `signWarrant` does:\n * the signature covers exactly these bytes, and a caller that rebuilt the fields\n * from JSON would have a second spelling able to disagree with what was signed.\n */\nexport async function signLoginStatement(\n input: LoginStatementInput,\n): Promise<string> {\n const node = fromHex(input.node, 'node', 32);\n const challenge = fromHex(input.challenge, 'challenge', 32);\n const sessionKey = fromHex(input.sessionKey, 'sessionKey', 32);\n\n const key = await importSigningKey(input.deviceSecret);\n const deviceKey = await derivePublicKey(input.deviceSecret);\n\n const issuedAt = u64le(input.issuedAt);\n const expiresAt = u64le(input.expiresAt);\n\n const preimage = await domainHash(SIGN_DOMAIN, [\n node,\n audienceSigningBytes(input.audience),\n challenge,\n sessionKey,\n deviceKey,\n issuedAt,\n expiresAt,\n ]);\n\n const signature = new Uint8Array(\n await crypto.subtle.sign({ name: 'Ed25519' }, key, preimage),\n );\n\n return hex(\n concat(\n node,\n audienceWire(input.audience),\n challenge,\n sessionKey,\n deviceKey,\n issuedAt,\n expiresAt,\n signature,\n ),\n );\n}\n", "/**\n * Obtain a session on a node using only a device key \u2014 the handshake around\n * {@link signLoginStatement}.\n *\n * Signing a statement was never the whole job. A client also has to fetch a\n * challenge, mint a session keypair, assemble a request body whose shape it\n * cannot see from here, and read a token out of the reply. Until now every\n * consumer wrote those two HTTP calls by hand, which is how the same three\n * mistakes kept being available to make:\n *\n * 1. **Asking for permissions.** `POST /auth/token` takes an optional\n * `permissions` list. Left unset, the node grants the account-proof\n * provider's own scopes \u2014 `context:intent`, `context:query`,\n * `context:subscribe` \u2014 which are the whole delegated surface and\n * deliberately nothing above it. This module never sends the field.\n * `authenticate()` in this same package hardcodes `['admin']` (#84); a\n * device-key session would be refused for that and should never ask.\n * 2. **Learning the node's key from the node.** {@link LoginConfig.node} is\n * required and has no default, because a value read from the challenge\n * response would let whoever answered choose what the device signs about.\n * That is the whole attack the field exists to stop, so the awkwardness of\n * having to supply it is the point rather than something to smooth away.\n * 3. **Losing the refresh token.** A browser tab outlives a short-lived\n * session, so both tokens are returned. Nothing here refreshes on a timer\n * (#87, #88 track that); this only makes it possible without a second\n * breaking change.\n *\n * **The session key never leaves.** It is minted here, the device key signs\n * over it once, and the secret half is handed back to the caller. That is what\n * keeps a device key off the wire for the life of a session: a leaked token\n * cannot be escalated into use of the key that authorised it.\n */\n\nimport { HTTPError } from '../http-client/web-client.js';\nimport { derivePublicKey, hex } from '../crypto/internal.js';\nimport { signLoginStatement, type Audience } from './login.js';\n\n/** Seconds a statement stays valid unless told otherwise. */\nconst DEFAULT_TTL_SECONDS = 300;\n\n/** A freshly minted ephemeral keypair, hex-encoded. */\nexport interface SessionKeyPair {\n /** The public half \u2014 what the statement is signed over. */\n publicKey: string;\n /** The private half. Held by the caller; never sent anywhere. */\n secret: string;\n}\n\n/**\n * Mint the ephemeral keypair a session speaks with.\n *\n * An ed25519 secret *is* 32 random bytes, so this needs no key generation\n * ceremony \u2014 `getRandomValues` and the same derivation every other signer here\n * uses. Exported because a caller that wants to persist a session across a page\n * reload needs to mint the pair itself and keep the secret.\n */\nexport async function generateSessionKey(): Promise<SessionKeyPair> {\n const secret = hex(crypto.getRandomValues(new Uint8Array(32)));\n return { publicKey: hex(await derivePublicKey(secret)), secret };\n}\n\n/** What a device needs in order to ask for a session. */\nexport interface LoginConfig {\n /** The node's base URL, e.g. `https://node.example`. */\n nodeUrl: string;\n /**\n * The node's device signing key, hex (32 bytes), **as this client pinned it**.\n *\n * Learn it out of band \u2014 from the node's operator, or a certificate you\n * already trust. Never from the node you are about to log in to: see the\n * module note.\n */\n node: string;\n /** The device's ed25519 signing secret, hex (32 bytes). Never sent. */\n deviceSecret: string;\n /**\n * The device's account proof, hex \u2014 the credential certifying that this\n * device belongs to its account.\n *\n * Travels beside the statement and is what settles *which account* is asking.\n * The statement alone proves only that a device key asked, so logging in\n * without this yields a 401 that looks exactly like a bad signature.\n */\n accountProof: string;\n /** The client surface this session is bound to. */\n audience: Audience;\n /**\n * How this client names itself to the node. Defaults to the audience's own\n * spelling, which is the honest answer: a session bound to an origin should\n * say that origin.\n */\n clientName?: string;\n /** Seconds the statement stays valid. Defaults to {@link DEFAULT_TTL_SECONDS}. */\n ttlSeconds?: number;\n /** Injectable for tests and non-browser runtimes. */\n fetch?: typeof fetch;\n /** Per-request timeout. Defaults to 10s. */\n timeoutMs?: number;\n}\n\n/** A session minted without a password. */\nexport interface DelegatedSession {\n /** Bearer token for the delegated surface. */\n accessToken: string;\n /** Presented to renew the access token. See #87/#88 \u2014 nothing here schedules it. */\n refreshToken: string;\n /** The session's public half, as the node knows it. */\n sessionKey: string;\n /** The session's private half. The caller keeps this; it was never sent. */\n sessionSecret: string;\n}\n\n/** The audience's own spelling, used as the default client name. */\nfunction audienceLabel(audience: Audience): string {\n switch (audience.kind) {\n case 'webOrigin':\n return audience.origin;\n case 'codeSigningId':\n return audience.id;\n case 'cli':\n return 'cli';\n }\n}\n\n/**\n * Log in with a device key and return the session.\n *\n * The challenge is fetched immediately before signing on purpose: it is\n * single-use and short-lived, so a statement minted against a stale one is\n * refused before any signature work is done.\n *\n * @throws {HTTPError} if the node refuses the challenge or the token request.\n */\nexport async function login(config: LoginConfig): Promise<DelegatedSession> {\n const baseUrl = config.nodeUrl.replace(/\\/+$/, '');\n const doFetch = config.fetch ?? globalThis.fetch;\n const timeoutMs = config.timeoutMs ?? 10_000;\n\n const request = async (path: string, init?: RequestInit): Promise<unknown> => {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n let response: Response;\n try {\n response = await doFetch(`${baseUrl}${path}`, {\n ...init,\n signal: controller.signal,\n });\n } catch (err) {\n throw new HTTPError(\n 0,\n err instanceof Error ? err.name : 'NetworkError',\n `${baseUrl}${path}`,\n new Headers(),\n err instanceof Error ? err.message : String(err),\n );\n } finally {\n clearTimeout(timer);\n }\n const text = await response.text().catch(() => '');\n if (!response.ok) {\n throw new HTTPError(\n response.status,\n response.statusText,\n `${baseUrl}${path}`,\n response.headers,\n text,\n );\n }\n return text ? (JSON.parse(text) as unknown) : {};\n };\n\n const challengeBody = (await request('/auth/challenge', {\n method: 'GET',\n headers: { Accept: 'application/json' },\n })) as { challenge?: string; data?: { challenge?: string } };\n // The node has spelled this both bare and wrapped in `data`; accept either\n // rather than couple a login to one envelope revision.\n const challenge = challengeBody.challenge ?? challengeBody.data?.challenge;\n if (!challenge) {\n throw new Error('the node issued no challenge');\n }\n\n const session = await generateSessionKey();\n const issuedAt = Math.floor(Date.now() / 1000);\n const statement = await signLoginStatement({\n node: config.node,\n audience: config.audience,\n challenge,\n sessionKey: session.publicKey,\n issuedAt,\n expiresAt: issuedAt + (config.ttlSeconds ?? DEFAULT_TTL_SECONDS),\n deviceSecret: config.deviceSecret,\n });\n\n // `timestamp` is required and the request refuses unknown fields, so a body\n // missing it is rejected during deserialization \u2014 before the provider runs,\n // and with an error that names the request shape rather than the login.\n //\n // `permissions` is omitted, not empty: see the module note.\n const tokenBody = (await request('/auth/token', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Accept: 'application/json' },\n body: JSON.stringify({\n auth_method: 'account_proof',\n public_key: session.publicKey,\n client_name: config.clientName ?? audienceLabel(config.audience),\n timestamp: issuedAt,\n provider_data: {\n challenge,\n login_statement: statement,\n account_proof: config.accountProof,\n },\n }),\n })) as {\n access_token?: string;\n refresh_token?: string;\n data?: { access_token?: string; refresh_token?: string };\n };\n\n const accessToken = tokenBody.access_token ?? tokenBody.data?.access_token;\n const refreshToken = tokenBody.refresh_token ?? tokenBody.data?.refresh_token;\n if (!accessToken) {\n throw new Error('the node minted no session');\n }\n\n return {\n accessToken,\n refreshToken: refreshToken ?? '',\n sessionKey: session.publicKey,\n sessionSecret: session.secret,\n };\n}\n", "// Member capability bitmask constants \u2014 mirrors core's `MemberCapabilities`\n// (crates/context/config/src/lib.rs). The value stored per-member is a u32\n// bitmask. Core currently assigns bits 0..=9; bits 10 and above are unassigned\n// and may be claimed by future core versions, so an application MUST NOT\n// assume any particular bit is safe for its own use unless core documents it\n// as reserved for applications.\n\n/**\n * Capability bits as defined by core's `MemberCapabilities`.\n *\n * The per-member value is a u32 bitmask. Core currently assigns bits 0..=9\n * (the entries below); bits 10 and above are unassigned \u2014 do not repurpose\n * them for application data, as a future core release may claim them.\n */\nexport const CAPABILITIES = {\n CAN_CREATE_CONTEXT: 1 << 0,\n CAN_INVITE_MEMBERS: 1 << 1,\n CAN_JOIN_OPEN_SUBGROUPS: 1 << 2,\n MANAGE_MEMBERS: 1 << 3,\n MANAGE_APPLICATION: 1 << 4,\n CAN_CREATE_SUBGROUP: 1 << 5,\n CAN_DELETE_SUBGROUP: 1 << 6,\n CAN_MANAGE_VISIBILITY: 1 << 7,\n CAN_MANAGE_METADATA: 1 << 8,\n /**\n * Publish writes attributed to ANOTHER member, under a warrant that member\n * signed \u2014 the grant delegated execution runs on.\n *\n * Implied by nothing: not by membership, not by admin, and not propagated by\n * the subgroup-admit cascade. So every group is authorship-closed until an\n * admin sets this bit, and a relay without it is refused at\n * `performIntent` before anything executes. That is why it is worth naming\n * here rather than leaving callers to write `1 << 9`: a client granting it\n * has to be able to say what it is granting.\n */\n CAN_AUTHOR_ON_BEHALF: 1 << 9,\n} as const;\n\nexport type CapabilityName = keyof typeof CAPABILITIES;\nexport type CapabilityBit = (typeof CAPABILITIES)[CapabilityName];\n\n/**\n * Returns true if `mask` has every bit of `cap` set. Both operands are\n * coerced to unsigned 32-bit (`>>> 0`) before comparing so a high bit such\n * as `1 << 31` doesn't fall foul of `&` yielding a signed result.\n */\nexport function hasCap(mask: number, cap: number): boolean {\n const capU32 = cap >>> 0;\n return ((mask & capU32) >>> 0) === capU32;\n}\n\n/** Returns `mask` with every bit of `cap` set (u32-normalized). */\nexport function withCap(mask: number, cap: number): number {\n return (mask | cap) >>> 0;\n}\n\n/** Returns `mask` with every bit of `cap` cleared (u32-normalized). */\nexport function withoutCap(mask: number, cap: number): number {\n return (mask & ~cap) >>> 0;\n}\n", "/**\n * Local-node discovery.\n *\n * Calimero dev/desktop nodes expose a public, unauthenticated health endpoint\n * at `GET {nodeUrl}/admin-api/health` that returns `{ \"data\": { \"status\":\n * \"alive\" } }`. The most common local layouts run on a small, well-known set of\n * ports, so instead of forcing the user to type a URL we probe those ports and\n * offer whatever is actually running.\n */\n\n/**\n * Default ports probed when discovering local nodes. Covers the two-node dev\n * stacks used across the Calimero apps (RPC + alt ports for node1 / node2).\n */\nexport const DEFAULT_LOCAL_NODE_PORTS = [2428, 2429, 2528, 2529] as const;\n\n/** Host used to build local candidate URLs. */\nconst LOCAL_HOST = 'localhost';\n\n/** Per-probe timeout. A reachable local node answers almost instantly; a\n * closed port rejects fast, but a firewalled/black-holed one can hang, so we\n * cap each probe. */\nconst DEFAULT_PROBE_TIMEOUT_MS = 2000;\n\nexport interface DiscoverLocalNodesOptions {\n /** Ports to probe. Defaults to {@link DEFAULT_LOCAL_NODE_PORTS}. */\n ports?: readonly number[];\n /** Per-probe timeout in ms. Defaults to 2000. */\n timeoutMs?: number;\n /** Abort the whole discovery (e.g. when the modal closes). */\n signal?: AbortSignal;\n}\n\n/** Build the canonical base URL for a local node on the given port. */\nexport function localNodeUrl(port: number): string {\n return `http://${LOCAL_HOST}:${port}`;\n}\n\n/**\n * Resolve an API `path` against a node `baseUrl`. Ensures the base ends with a\n * slash first, so a base that carries a path prefix (e.g. a `NODE_PATH_PREFIX`\n * deployment like `http://host/node1`) keeps that segment instead of having it\n * stripped by relative URL resolution.\n */\nexport function nodeEndpoint(baseUrl: string, path: string): string {\n const base = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;\n return new URL(path, base).toString();\n}\n\n/**\n * Probe a single node's health endpoint. Resolves `true` only when the node\n * answers with a 2xx and (when the body is JSON) reports a non-dead status.\n * Any network error, timeout, or non-ok response resolves `false` \u2014 never\n * throws (except on an external abort, which is swallowed as `false`).\n */\nexport async function probeNodeHealth(\n baseUrl: string,\n options: { timeoutMs?: number; signal?: AbortSignal } = {},\n): Promise<boolean> {\n const { timeoutMs = DEFAULT_PROBE_TIMEOUT_MS, signal } = options;\n\n // Already cancelled before we start \u2014 don't fetch, and don't register a\n // timer or listener that would then need cleanup.\n if (signal?.aborted) return false;\n\n // Per-probe timeout, also linked to the caller's abort signal so closing the\n // modal cancels every in-flight probe. Bind the signal to a local so the\n // cleanup below stays symmetric with registration without re-narrowing.\n const controller = new AbortController();\n const onAbort = () => controller.abort();\n const abortSignal = signal;\n if (abortSignal) abortSignal.addEventListener('abort', onAbort, { once: true });\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n const url = nodeEndpoint(baseUrl, 'admin-api/health');\n const res = await fetch(url, {\n method: 'GET',\n signal: controller.signal,\n });\n\n if (!res.ok) return false;\n\n // Health body is `{ data: { status: \"alive\" } }`, but tolerate plain\n // `{ status }` and non-JSON 2xx responses. A *missing* status is treated as\n // alive (the 2xx is enough); a status that is present but not \"alive\"\n // (including an explicit `null`) is treated as unhealthy.\n try {\n const body = (await res.json()) as\n | { data?: { status?: string | null }; status?: string | null }\n | undefined;\n const status =\n body?.data?.status !== undefined ? body?.data?.status : body?.status;\n if (status === undefined) return true;\n return typeof status === 'string' && status.toLowerCase() === 'alive';\n } catch {\n return true;\n }\n } catch {\n return false;\n } finally {\n clearTimeout(timer);\n if (abortSignal) abortSignal.removeEventListener('abort', onAbort);\n }\n}\n\n/**\n * Probe the configured local ports in parallel and return the base URLs that\n * responded as healthy, in the same order as the `ports` argument (which\n * defaults to ascending). Returns an empty array when nothing local is running.\n */\nexport async function discoverLocalNodes(\n options: DiscoverLocalNodesOptions = {},\n): Promise<string[]> {\n const { ports = DEFAULT_LOCAL_NODE_PORTS, timeoutMs, signal } = options;\n\n const results = await Promise.all(\n ports.map(async (port) => {\n const url = localNodeUrl(port);\n const ok = await probeNodeHealth(url, { timeoutMs, signal });\n return ok ? url : null;\n }),\n );\n\n return results.filter((url): url is string => url !== null);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["TERMINAL_AUTH_ERRORS", "SIGN_DOMAIN", "DEFAULT_TTL_SECONDS"]
|
|
7
7
|
}
|