@solarpunkltd/swarm-id 0.9.0 → 0.10.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"swarm-id.esm.js","sources":["../src/utils/collection.ts","../src/swarm-id-client.ts","../src/proxy/manifest-builder.ts"],"sourcesContent":["// Copyright 2026 The Swarm Authors. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * A file's path inside the folder it was picked with. `webkitdirectory` and a\n * dropped directory prefix every path with the folder's own name; that segment\n * goes, so `index.html` sits at the manifest root — the rule bee-js applies.\n */\nexport function collectionPath(\n file: Pick<File, \"name\" | \"webkitRelativePath\">,\n): string {\n const relative = file.webkitRelativePath\n return relative ? relative.replace(/^[^/]*\\//, \"\") : file.name\n}\n","// Copyright 2026 The Swarm Authors. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { SwarmIdError } from \"./errors\"\nimport type {\n ClientOptions,\n ConnectOptions,\n AuthStatus,\n Avatar,\n ConnectionInfo,\n UploadResult,\n FileData,\n UploadOptions,\n UploadFilesOptions,\n CollectionFileInput,\n CollectionEntry,\n UploadProgress,\n ActUploadOptions,\n DownloadOptions,\n RequestOptions,\n Reference,\n SOCReader,\n SOCWriter,\n SingleOwnerChunk,\n SocRawUploadResult,\n SocRawUploadResponseMessage,\n SocRawUploadMessage,\n SocGetOwnerMessage,\n SocGetOwnerResponseMessage,\n FeedReaderOptions,\n FeedWriterOptions,\n FeedReader,\n FeedWriter,\n EpochFeedDownloadReferenceMessage,\n EpochFeedDownloadReferenceResponseMessage,\n EpochFeedUploadReferenceMessage,\n EpochFeedUploadReferenceResponseMessage,\n FeedGetOwnerMessage,\n FeedGetOwnerResponseMessage,\n EpochFeedDownloadOptions,\n EpochFeedDownloadPayloadResult,\n EpochFeedDownloadReferenceResult,\n EpochFeedUploadOptions,\n EpochFeedUploadResult,\n SequentialFeedReaderOptions,\n SequentialFeedWriterOptions,\n SequentialFeedUpdateOptions,\n SequentialFeedUploadOptions,\n SequentialFeedDownloadRawOptions,\n SequentialFeedUploadRawOptions,\n SequentialFeedPayloadResult,\n SequentialFeedReferenceResult,\n SequentialFeedUploadResult,\n SequentialFeedReader,\n SequentialFeedWriter,\n SequentialFeedGetOwnerMessage,\n SequentialFeedGetOwnerResponseMessage,\n SequentialFeedDownloadPayloadMessage,\n SequentialFeedDownloadPayloadResponseMessage,\n SequentialFeedDownloadRawPayloadMessage,\n SequentialFeedDownloadRawPayloadResponseMessage,\n SequentialFeedDownloadReferenceMessage,\n SequentialFeedDownloadReferenceResponseMessage,\n SequentialFeedUploadPayloadMessage,\n SequentialFeedUploadPayloadResponseMessage,\n SequentialFeedUploadRawPayloadMessage,\n SequentialFeedUploadRawPayloadResponseMessage,\n SequentialFeedUploadReferenceMessage,\n SequentialFeedUploadReferenceResponseMessage,\n CreateFeedManifestMessage,\n CreateFeedManifestResponseMessage,\n SocDownloadMessage,\n SocDownloadResponseMessage,\n SocRawDownloadMessage,\n SocRawDownloadResponseMessage,\n SocUploadResult,\n SocUploadResponseMessage,\n StampChunkInput,\n StampChunkRequest,\n StampChunkResponseMessage,\n StampedChunk,\n SocUploadMessage,\n ParentToIframeMessage,\n IframeToParentMessage,\n AppMetadata,\n ButtonAction,\n ButtonConfig,\n MountButtonOptions,\n MountedButton,\n ParentToButtonMessage,\n PostageBatch,\n} from \"./types\"\nimport {\n BUTTON_FRAME_LOADED,\n ButtonActionSchema,\n ButtonConfigSchema,\n ButtonToParentMessageSchema,\n IframeToParentMessageSchema,\n ParentToIframeMessageSchema,\n AppMetadataSchema,\n} from \"./types\"\nimport { EthAddress, Identifier, PrivateKey, Topic } from \"@ethersphere/bee-js\"\nimport { generatedAvatar } from \"./utils/avatar\"\nimport { uint8ArrayToHex } from \"./utils/hex\"\nimport { collectionPath } from \"./utils/collection\"\nimport { buildAuthUrl, isBeeApiUrl } from \"./utils/url\"\nimport { TimeoutError, withTimeout } from \"./utils/promise\"\n\nconst DEFAULT_TIMEOUT_MS = 30000\n/** The largest delay `setTimeout` honours; past it, it fires almost at once. */\nconst MAX_TIMER_DELAY_MS = 2 ** 31 - 1\nconst DEFAULT_INITIALIZATION_TIMEOUT_MS = 30000\n\n/**\n * {@link withTimeout} for one of `initialize()`'s waits: a missed deadline\n * rejects as `init-failed`, the `TimeoutError` kept as its cause, so every\n * way `initialize()` fails to come up carries the same code.\n */\nfunction initDeadline(\n work: Promise<void>,\n ms: number,\n message: string,\n): Promise<void> {\n return withTimeout(work, ms, message).catch((error: unknown) => {\n throw error instanceof TimeoutError\n ? new SwarmIdError(\"init-failed\", error.message, { cause: error })\n : error\n })\n}\n\n/**\n * A button's look, refused here rather than by the frame, which drops a\n * message it cannot parse, so a bad value would leave the button unshown or\n * an update unapplied with nothing said on the site's side.\n */\nfunction checkedButtonConfig(\n config: ButtonConfig | undefined,\n): ButtonConfig | undefined {\n if (config === undefined) return undefined\n const parsed = ButtonConfigSchema.safeParse(config)\n if (parsed.success) return parsed.data\n const issue = parsed.error.issues[0]\n throw new SwarmIdError(\n \"invalid-request\",\n `Invalid button config at ${[\"config\", ...issue.path].join(\".\")}: ${issue.message}`,\n { cause: parsed.error },\n )\n}\n\nfunction checkedButtonAction(action: ButtonAction): ButtonAction {\n if (ButtonActionSchema.safeParse(action).success) return action\n throw new SwarmIdError(\n \"invalid-request\",\n `Invalid button action: ${JSON.stringify(action)}`,\n )\n}\n\n/**\n * The site's Bee address, refused here rather than by the outgoing message\n * check, so a bad one never reaches the frame and the error says what is\n * wrong. The value is left out of the message, since a refused one may carry\n * credentials.\n */\nfunction parseBeeApiUrl(url: string): string {\n if (!isBeeApiUrl(url)) {\n throw new SwarmIdError(\n \"invalid-request\",\n \"Invalid beeApiUrl: must be an http(s) URL, optionally with a path, and no credentials, query or fragment\",\n )\n }\n return url\n}\n\n/**\n * Main client library for integrating Swarm ID authentication and storage capabilities\n * into web applications.\n *\n * SwarmIdClient enables parent windows to interact with a Swarm ID iframe proxy,\n * providing secure authentication, identity management, and data upload/download\n * functionality to the Swarm decentralized storage network.\n *\n * @example\n * ```typescript\n * const client = new SwarmIdClient({\n * iframeOrigin: 'https://swarm-id.example.com',\n * metadata: {\n * name: 'My App',\n * description: 'A decentralized application'\n * },\n * onConnectionChange: (info) => {\n * console.log('Connection changed:', info.identity?.name, info.canUpload)\n * }\n * })\n *\n * await client.initialize()\n *\n * // Check canUpload — an authenticated user can still lack upload capability\n * // when they have no postage stamp and no subsidised gateway is configured.\n * if (client.connectionInfo.identity && client.connectionInfo.canUpload) {\n * const result = await client.uploadData(new Uint8Array([1, 2, 3]))\n * console.log('Uploaded with reference:', result.reference)\n * }\n * ```\n */\nexport class SwarmIdClient {\n private iframe: HTMLIFrameElement | undefined\n private iframeOrigin: string\n private iframePath: string\n private timeout: number\n private initializationTimeout: number\n private onConnectionChange?: (info: ConnectionInfo) => void\n private lastConnectionInfo: ConnectionInfo | undefined\n private firstConnectionInfoPromise: Promise<void> | undefined\n private firstConnectionInfoResolve?: () => void\n private firstConnectionInfoReject?: (error: SwarmIdError) => void\n private iframeLoadReject?: (error: SwarmIdError) => void\n private popupMode: \"popup\" | \"window\"\n private metadata: AppMetadata\n /** Each mounted button, with what removes its frame at once */\n private mountedButtons = new Map<MountedButton, () => void>()\n private subsidisedGatewayUrl?: string\n private beeApiUrl?: string\n private ready: boolean = false\n /**\n * Whether the proxy iframe can read the trusted domain's first-party store,\n * as reported on `proxyReady`. Decides which transport `connect()` uses\n * (#613); undefined against a proxy that predates the field, which reads as\n * \"not proven shared\".\n */\n private storageShared: boolean | undefined\n private readyPromise: Promise<void> | undefined\n private readyResolve?: () => void\n private readyReject?: (error: SwarmIdError) => void\n private pendingRequests: Map<\n string,\n {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n resolve: (value: any) => void\n reject: (error: Error) => void\n timeoutId: NodeJS.Timeout\n }\n > = new Map()\n /**\n * Progress callbacks of in-flight uploads, by request id. Dispatched from\n * the one window listener, so progress passes the same source and origin\n * checks as every other message from the iframe.\n */\n private progressListeners: Map<string, (progress: UploadProgress) => void> =\n new Map()\n private requestIdCounter = 0\n private messageListener: ((event: MessageEvent) => void) | undefined\n private proxyInitializedPromise: Promise<void> | undefined\n private proxyInitializedResolve?: () => void\n private proxyInitializedReject?: (error: SwarmIdError) => void\n\n /**\n * Creates a new SwarmIdClient instance.\n *\n * @param options - Configuration options for the client\n * @param options.iframeOrigin - The origin URL where the Swarm ID proxy iframe is hosted\n * @param options.iframePath - The path to the proxy iframe (defaults to \"/proxy\")\n * @param options.timeout - Request timeout in milliseconds (defaults to 30000). Bounds each call's whole round trip through the iframe; a call's own `requestOptions.timeout` replaces it for that call\n * @param options.onConnectionChange - Callback invoked when the dApp-visible ConnectionInfo changes (identity, stamp, account type, auth)\n * @param options.popupMode - How the connect window opens, from {@link connect} or a mounted button: \"popup\" or \"window\" (defaults to \"window\")\n * @param options.metadata - Application metadata shown to users during authentication\n * @param options.metadata.name - Application name (1-100 characters)\n * @param options.metadata.description - Optional application description (max 500 characters)\n * @param options.metadata.icon - Optional application icon as a data URL (SVG or PNG, max 4KB)\n * @param options.subsidisedGatewayUrl - A gateway that stamps uploads for a person with no drive of their own (optional)\n * @param options.beeApiUrl - The Bee node this site's content reads and stamped uploads go through, in place of the person's own setting. Their account and device coordination stay on their own node. Change it later with {@link setBeeApiUrl} (optional)\n * @throws {Error} If constructed where there is no `window` (a server render)\n * @throws {SwarmIdError} `invalid-request` if the provided app metadata is invalid, or `beeApiUrl` is not an http(s) URL without credentials, query or fragment\n */\n constructor(options: ClientOptions) {\n // Before anything touches `window`: a server render reached\n // `setupMessageListener` and threw a bare `ReferenceError` from what, in\n // the published build, is minified code (#778). Name the package and the\n // fix instead.\n if (typeof window === \"undefined\") {\n throw new Error(\n \"@solarpunkltd/swarm-id runs in the browser only: construct SwarmIdClient in code that runs there (an effect, onMount, or behind `typeof window !== 'undefined'`), not in a server render\",\n )\n }\n this.iframeOrigin = options.iframeOrigin\n this.iframePath = options.iframePath || \"/proxy\"\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS\n this.initializationTimeout =\n options.initializationTimeout ?? DEFAULT_INITIALIZATION_TIMEOUT_MS\n this.onConnectionChange = options.onConnectionChange\n this.popupMode = options.popupMode || \"window\"\n this.metadata = options.metadata\n this.subsidisedGatewayUrl = options.subsidisedGatewayUrl\n if (options.beeApiUrl !== undefined) {\n this.beeApiUrl = parseBeeApiUrl(options.beeApiUrl)\n }\n\n // Validate metadata\n try {\n AppMetadataSchema.parse(this.metadata)\n } catch (error) {\n throw new SwarmIdError(\n \"invalid-request\",\n `Invalid app metadata: ${error}`,\n { cause: error },\n )\n }\n\n // Note: `readyPromise`, `proxyInitializedPromise`, and\n // `firstConnectionInfoPromise` (with their timeouts) are all created in\n // `initialize()`, not here — starting the timers at construction would\n // make them expire on consumers that instantiate the client and call\n // `initialize()` later (or never, in tests), and leak an armed timer plus\n // an unguarded rejection in the meantime.\n\n this.setupMessageListener()\n }\n\n /**\n * Initializes the client by creating and embedding the proxy iframe.\n *\n * This method must be called before using any other client methods.\n * It creates a hidden iframe, waits for the proxy to initialize,\n * identifies the parent application to the proxy, and waits for\n * the proxy to signal readiness.\n *\n * @returns A promise that resolves when the client is fully initialized\n * @throws {SwarmIdError} `invalid-state` if the client is already initialized, or `destroy()` runs before it resolves\n * @throws {SwarmIdError} `init-failed` if the iframe fails to load, origin validation fails on the proxy side, or the proxy does not respond within `initializationTimeout` (30 seconds by default)\n *\n * @example\n * ```typescript\n * const client = new SwarmIdClient({ ... })\n * try {\n * await client.initialize()\n * console.log('Client ready')\n * } catch (error) {\n * console.error('Failed to initialize:', error)\n * }\n * ```\n */\n async initialize(): Promise<void> {\n if (this.iframe) {\n throw new SwarmIdError(\n \"invalid-state\",\n \"SwarmIdClient already initialized\",\n )\n }\n\n // Set up the first-snapshot wait now (not in the constructor) so the\n // timeout starts when initialization actually begins, not when the\n // client object is created. The proxy emits `connectionInfoChanged`\n // unconditionally right after `proxyReady`; we race that against the\n // initializationTimeout so a buggy or version-mismatched proxy can't\n // wedge initialization indefinitely.\n //\n // The `resolve` callback is stashed in an instance field\n // (deferred-style) because it has to be called later, from\n // `handleIframeMessage` when the `connectionInfoChanged` arrives — not\n // from this executor. ES2024's `Promise.withResolvers()` would express\n // the same shape more directly. The `reject` is stashed for `destroy()`.\n this.firstConnectionInfoPromise = initDeadline(\n new Promise<void>((resolve, reject) => {\n this.firstConnectionInfoResolve = resolve\n this.firstConnectionInfoReject = reject\n }),\n this.initializationTimeout,\n `Proxy initialization timeout - proxy did not send initial connectionInfoChanged within ${this.initializationTimeout}ms`,\n )\n // Attach a no-op handler so the rejection isn't surfaced as\n // \"unhandled\" if the timeout fires before we reach the awaiting line\n // below (e.g. because an earlier `await` in this method hung first).\n // The original promise is still rejected; the `await` at the end of this\n // method re-throws it normally.\n this.firstConnectionInfoPromise.catch(() => {})\n\n // Same deferred+timeout pattern for the proxyReady handshake and the\n // iframe-ready signal: created here (not the constructor) so the timers\n // start when init begins and `withTimeout` clears them on settle. The\n // stashed resolve/reject are invoked later from `handleIframeMessage`.\n this.proxyInitializedPromise = initDeadline(\n new Promise<void>((resolve, reject) => {\n this.proxyInitializedResolve = resolve\n this.proxyInitializedReject = reject\n }),\n this.initializationTimeout,\n `Proxy initialization timeout - proxy did not signal readiness within ${this.initializationTimeout}ms`,\n )\n this.proxyInitializedPromise.catch(() => {})\n\n this.readyPromise = initDeadline(\n new Promise<void>((resolve, reject) => {\n this.readyResolve = resolve\n this.readyReject = reject\n }),\n this.initializationTimeout,\n `Proxy initialization timeout - proxy did not respond within ${this.initializationTimeout}ms`,\n )\n this.readyPromise.catch(() => {})\n\n // Create iframe for proxy\n this.iframe = document.createElement(\"iframe\")\n this.iframe.src = `${this.iframeOrigin}${this.iframePath}`\n\n // The session frame shows nothing. A button the person clicks is a\n // frame of its own (`mountButton`), so a site can remove it and keep the\n // session.\n this.iframe.style.display = \"none\"\n\n // Wait for iframe to load. The `reject` is stashed for `destroy()` while\n // the load is pending: a removed iframe never fires `load`, and nothing\n // else would settle this.\n await new Promise<void>((resolve, reject) => {\n this.iframeLoadReject = reject\n this.iframe!.onload = () => resolve()\n this.iframe!.onerror = () =>\n reject(\n new SwarmIdError(\"init-failed\", \"Failed to load Swarm ID iframe\"),\n )\n\n document.body.appendChild(this.iframe!)\n })\n this.iframeLoadReject = undefined\n\n // Wait for proxy to signal it's ready\n await this.proxyInitializedPromise\n\n // Identify ourselves to the iframe\n this.sendMessage({\n type: \"parentIdentify\",\n requestId: this.generateRequestId(),\n metadata: this.metadata,\n subsidisedGatewayUrl: this.subsidisedGatewayUrl,\n beeApiUrl: this.beeApiUrl,\n })\n\n // Wait for iframe to be ready\n await this.readyPromise\n\n // Wait for the initial ConnectionInfo snapshot (sent right after proxyReady)\n // so `client.connectionInfo` is populated by the time `initialize()` resolves.\n await this.firstConnectionInfoPromise\n }\n\n /**\n * Setup message listener for iframe responses\n */\n private setupMessageListener(): void {\n this.messageListener = (event: MessageEvent) => {\n // Source first, and silently: `window` carries every message the page\n // sends itself — devtools, HMR, wallet extensions — and none of it was\n // addressed to this client, so dropping it is routine rather than a\n // security event and must not reach the console. Before the iframe\n // exists there is no window a message of ours could have come from.\n // This is also what keeps a sibling or parent frame on the identity\n // origin from spoofing a push event like `connectionInfoChanged` or\n // `authSuccess`.\n if (!this.iframe || event.source !== this.iframe.contentWindow) {\n return\n }\n\n // `proxyInitialized` is sent the moment the iframe loads, with a\n // wildcard target origin, so it is answered before the origin check.\n if (event.data?.type === \"proxyInitialized\") {\n if (this.proxyInitializedResolve) {\n this.proxyInitializedResolve()\n this.proxyInitializedResolve = undefined // Prevent double resolution\n }\n return\n }\n\n // Our own iframe with an origin other than the configured identity one\n // is worth reporting: the frame is serving something unexpected.\n // (Extract just the origin part, ignoring any path in iframeOrigin.)\n const expectedOrigin = new URL(this.iframeOrigin).origin\n if (event.origin !== expectedOrigin) {\n console.warn(\n \"[SwarmIdClient] Rejected message from unauthorized origin:\",\n event.origin,\n )\n return\n }\n\n // Parse and validate message\n let message: IframeToParentMessage\n try {\n message = IframeToParentMessageSchema.parse(event.data)\n } catch (error) {\n console.warn(\n \"[SwarmIdClient] Invalid message format:\",\n event.data,\n error,\n )\n return\n }\n\n this.handleIframeMessage(message)\n }\n\n window.addEventListener(\"message\", this.messageListener)\n }\n\n /**\n * Handle messages from iframe\n */\n private handleIframeMessage(message: IframeToParentMessage): void {\n switch (message.type) {\n case \"proxyReady\":\n this.ready = true\n // Which transport `connect()` can use, known before the first click\n // (#613). Undefined against a proxy older than that field.\n this.storageShared = message.storageShared\n if (this.readyResolve) {\n this.readyResolve()\n }\n break\n\n case \"connectionInfoChanged\": {\n const info: ConnectionInfo = {\n canUpload: message.canUpload,\n storagePartitioned: message.storagePartitioned,\n uploadMode: message.uploadMode,\n uploadUnavailableReason: message.uploadUnavailableReason,\n identity: message.identity,\n appKey: message.appKey,\n partition: message.partition,\n chatBinding: message.chatBinding,\n beeApiUrl: message.beeApiUrl,\n postageBatchId: message.postageBatchId,\n }\n this.lastConnectionInfo = info\n if (this.firstConnectionInfoResolve) {\n this.firstConnectionInfoResolve()\n this.firstConnectionInfoResolve = undefined\n }\n if (this.onConnectionChange) {\n this.onConnectionChange(info)\n }\n break\n }\n\n case \"initError\":\n // Initialization error from proxy (e.g., origin validation failed)\n console.error(\n \"[SwarmIdClient] Proxy initialization error:\",\n message.error,\n )\n if (this.readyReject) {\n this.readyReject(new SwarmIdError(\"init-failed\", message.error))\n }\n break\n\n case \"disconnectResponse\":\n // Handle as response if there's a matching request\n if (\"requestId\" in message) {\n const pending = this.pendingRequests.get(message.requestId)\n if (pending) {\n clearTimeout(pending.timeoutId)\n this.pendingRequests.delete(message.requestId)\n pending.resolve(message)\n }\n }\n break\n\n case \"error\": {\n const pending = this.pendingRequests.get(message.requestId)\n if (pending) {\n clearTimeout(pending.timeoutId)\n this.pendingRequests.delete(message.requestId)\n pending.reject(SwarmIdError.fromWire(message))\n }\n break\n }\n\n case \"uploadProgress\":\n // Report to the upload's callback, if it registered one. Don't resolve\n // the pending request - the response does that\n this.progressListeners.get(message.requestId)?.({\n total: message.total,\n processed: message.processed,\n })\n break\n\n default:\n // Handle response messages with requestId\n if (\"requestId\" in message) {\n const pending = this.pendingRequests.get(message.requestId)\n if (pending) {\n clearTimeout(pending.timeoutId)\n this.pendingRequests.delete(message.requestId)\n pending.resolve(message)\n }\n }\n }\n }\n\n /**\n * Send message to iframe\n */\n private sendMessage(message: ParentToIframeMessage): void {\n if (!this.iframe || !this.iframe.contentWindow) {\n throw new SwarmIdError(\"invalid-state\", \"Iframe not initialized\")\n }\n\n // Validate message before sending\n try {\n ParentToIframeMessageSchema.parse(message)\n } catch (error) {\n throw new SwarmIdError(\n \"invalid-request\",\n `Invalid message format: ${error}`,\n { cause: error },\n )\n }\n\n this.iframe.contentWindow.postMessage(message, this.iframeOrigin)\n }\n\n /**\n * Send request and wait for response\n */\n private async sendRequest<\n TResponse,\n TRequest extends ParentToIframeMessage & { requestId: string } =\n ParentToIframeMessage & {\n requestId: string\n },\n >(message: TRequest): Promise<TResponse> {\n // A per-call `requestOptions.timeout` bounds this whole round trip, not\n // only the Bee request the proxy makes with it: a caller raising it for a\n // large upload must not be cut off at the constructor default (#775).\n const timeout = this.roundTripTimeout(\n (message as { requestOptions?: RequestOptions }).requestOptions?.timeout,\n )\n return new Promise((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n this.pendingRequests.delete(message.requestId)\n reject(\n new SwarmIdError(\"timeout\", `Request timeout after ${timeout}ms`),\n )\n }, timeout)\n\n this.pendingRequests.set(message.requestId, {\n resolve,\n reject,\n timeoutId,\n })\n\n this.sendMessage(message)\n })\n }\n\n /**\n * The round-trip bound for one call, from its own `requestOptions.timeout`.\n *\n * Only a value `setTimeout` can honour is taken. Zero and negatives mean\n * \"no timeout\" to Bee, which is where this option went before it also bound\n * the round trip — taken literally here they would reject on the next tick,\n * the opposite of what the caller asked, so they fall back to the client\n * default and still reach Bee unchanged. A value past the 32-bit timer\n * ceiling means \"as long as it takes\", and `setTimeout` would wrap it into\n * firing almost at once, so it clamps to the ceiling instead. `Infinity` and\n * `NaN` never get this far: `z.number()` rejects them on the way out.\n */\n private roundTripTimeout(perCall: number | undefined): number {\n if (perCall === undefined || perCall <= 0) {\n return this.timeout\n }\n return Math.min(perCall, MAX_TIMER_DELAY_MS)\n }\n\n /**\n * Generate unique request ID\n */\n private generateRequestId(): string {\n return `req-${++this.requestIdCounter}-${Date.now()}`\n }\n\n private normalizeSocIdentifier(\n identifier: Identifier | Uint8Array | string,\n ): string {\n if (identifier instanceof Identifier) {\n return identifier.toHex()\n }\n if (identifier instanceof Uint8Array) {\n return uint8ArrayToHex(identifier)\n }\n return identifier\n }\n\n private normalizeSocKey(key: Uint8Array | string): string {\n if (key instanceof Uint8Array) {\n return uint8ArrayToHex(key)\n }\n return key\n }\n\n private normalizeFeedTopic(\n topic: Topic | Identifier | Uint8Array | string,\n ): string {\n if (topic instanceof Topic) {\n return uint8ArrayToHex(topic.toUint8Array())\n }\n if (topic instanceof Identifier) {\n return topic.toHex()\n }\n if (topic instanceof Uint8Array) {\n return uint8ArrayToHex(topic)\n }\n return topic\n }\n\n private normalizeReference(reference: Uint8Array | string): string {\n if (reference instanceof Uint8Array) {\n return uint8ArrayToHex(reference)\n }\n return reference\n }\n\n private normalizeFeedTimestamp(value: bigint | number | string): string {\n if (typeof value === \"bigint\") {\n return value.toString()\n }\n if (typeof value === \"number\") {\n return BigInt(Math.floor(value)).toString()\n }\n return value\n }\n\n private normalizeFeedIndex(value: bigint | number | string): string {\n if (typeof value === \"bigint\") {\n return value.toString()\n }\n if (typeof value === \"number\") {\n return BigInt(Math.floor(value)).toString()\n }\n return value\n }\n\n private normalizePayload(data: Uint8Array | string): Uint8Array {\n if (data instanceof Uint8Array) {\n return data\n }\n return new TextEncoder().encode(data)\n }\n\n private socChunkFromResponse(response: {\n data: Uint8Array\n identifier: string\n signature: string\n span: number\n payload: Uint8Array\n address: Reference\n owner: string\n }): SingleOwnerChunk {\n return {\n data: response.data,\n identifier: response.identifier,\n signature: response.signature,\n span: response.span,\n payload: response.payload,\n address: response.address,\n owner: response.owner,\n }\n }\n\n /**\n * Ensure client is initialized\n */\n private ensureReady(): void {\n if (!this.ready) {\n throw new SwarmIdError(\n \"invalid-state\",\n \"SwarmIdClient not initialized. Call initialize() first.\",\n )\n }\n }\n\n // ============================================================================\n // Authentication Methods\n // ============================================================================\n\n /**\n * Checks the current authentication status with the Swarm ID proxy.\n *\n * @returns A promise resolving to the authentication status object\n * @returns return.authenticated - Whether the user is currently authenticated\n * @returns return.origin - The origin that authenticated (if authenticated)\n * @returns return.beeApiUrl - The Bee node this site gave, if it gave one. The person's own node is never reported\n * @throws {Error} If the client is not initialized\n * @throws {Error} If the request times out\n *\n * @example\n * ```typescript\n * const status = await client.checkAuthStatus()\n * if (status.authenticated) {\n * console.log('Authenticated from:', status.origin)\n * }\n * ```\n */\n async checkAuthStatus(): Promise<AuthStatus> {\n this.ensureReady()\n const requestId = this.generateRequestId()\n\n const response = await this.sendRequest<{\n type: \"authStatusResponse\"\n requestId: string\n authenticated: boolean\n origin?: string\n beeApiUrl?: string\n }>({\n type: \"checkAuth\",\n requestId,\n })\n\n return {\n authenticated: response.authenticated,\n origin: response.origin,\n beeApiUrl: response.beeApiUrl,\n }\n }\n\n /**\n * Changes the Bee node this site's content reads and stamped uploads go\n * through, without a reload, for example when the viewer picks another source. It\n * replaces the `beeApiUrl` given at construction, and takes over from the\n * person's own Bee setting on this site if none was given. Every other site,\n * and Swarm ID itself, keep the person's setting. The checks and writes\n * that coordinate the person's account and devices always use their own\n * node. Nothing is stored: the next page load starts from the\n * constructor's `beeApiUrl` again.\n *\n * Works signed in or not. A subsidised gateway the person's own custom node\n * had switched off comes back once the site names its node.\n *\n * @param url - An http(s) URL, optionally with a path, without credentials, query or fragment\n * @throws {SwarmIdError} `invalid-request` if `url` is not such a URL, and nothing is sent\n * @throws {SwarmIdError} `invalid-state` if the client is not initialized\n * @throws {SwarmIdError} `timeout` if the request times out\n *\n * @example\n * ```typescript\n * await client.setBeeApiUrl('https://bee.example.com/')\n * console.log(client.connectionInfo.beeApiUrl)\n * ```\n */\n async setBeeApiUrl(url: string): Promise<void> {\n const beeApiUrl = parseBeeApiUrl(url)\n this.ensureReady()\n await this.sendRequest<{\n type: \"setBeeApiUrlResponse\"\n requestId: string\n beeApiUrl: string\n }>({\n type: \"setBeeApiUrl\",\n requestId: this.generateRequestId(),\n beeApiUrl,\n })\n this.beeApiUrl = beeApiUrl\n }\n\n /**\n * Gets the current postage batch for the authenticated identity.\n *\n * Returns information about the postage stamp associated with the\n * connected identity, including batch ID, utilization, depth, and TTL.\n *\n * @returns A promise resolving to the PostageBatch or undefined if none is configured\n * @throws {Error} If the client is not initialized\n * @throws {Error} If the request times out\n *\n * @example\n * ```typescript\n * const batch = await client.getPostageBatch()\n * if (batch) {\n * console.log('Batch ID:', batch.batchID)\n * console.log('Utilization:', batch.utilization)\n * console.log('Depth:', batch.depth)\n * console.log('TTL:', batch.batchTTL)\n * } else {\n * console.log('No postage batch configured')\n * }\n * ```\n */\n async getPostageBatch(): Promise<PostageBatch | undefined> {\n this.ensureReady()\n const requestId = this.generateRequestId()\n\n const response = await this.sendRequest<{\n type: \"getPostageBatchResponse\"\n requestId: string\n postageBatch?: PostageBatch\n }>({\n type: \"getPostageBatch\",\n requestId,\n })\n\n return response.postageBatch\n }\n\n /**\n * Disconnects the current session and clears authentication data.\n *\n * After disconnection, the user will need to re-authenticate to perform\n * uploads or access identity-related features. The\n * {@link ClientOptions.onConnectionChange} callback will fire with an\n * un-authenticated snapshot.\n *\n * @returns A promise that resolves when disconnection is complete\n * @throws {SwarmIdError} `invalid-state` if the client is not initialized\n * @throws {SwarmIdError} `internal` if the proxy reports the disconnect failed\n * @throws {SwarmIdError} `timeout` if the request times out\n *\n * @example\n * ```typescript\n * await client.disconnect()\n * console.log('User logged out')\n * ```\n */\n async disconnect(): Promise<void> {\n this.ensureReady()\n const requestId = this.generateRequestId()\n\n const response = await this.sendRequest<{\n type: \"disconnectResponse\"\n requestId: string\n success: boolean\n }>({\n type: \"disconnect\",\n requestId,\n })\n\n if (!response.success) {\n throw new SwarmIdError(\"internal\", \"Failed to disconnect\")\n }\n }\n\n /**\n * Opens the Swarm ID connect window from the site's own control, where the\n * session frame shares Swarm ID's storage: a site on the same site as Swarm\n * ID, such as a self-hosted copy on the site's own domain. The window\n * writes the connection to that storage and the session frame picks it up.\n *\n * Anywhere else the browser partitions the session frame's storage, and the\n * session can reach it only through a window a Swarm ID frame opened from a\n * click inside it. A window opened from here would end on \"Connected\" with\n * the site still signed out, so this refuses instead and the site shows\n * {@link mountButton}'s button. `connectionInfo.storagePartitioned` and the\n * error's code tell the two apart. The button works in both cases, so a\n * site that always mounts it never needs this.\n *\n * @param options - Configuration options for the connect flow\n * @throws {SwarmIdError} `invalid-state` if the client is not initialized\n * @throws {SwarmIdError} `button-required` if the session frame's storage is partitioned, or not proven shared\n * @throws {SwarmIdError} `popup-blocked` if the browser blocks the window\n *\n * @example\n * ```typescript\n * try {\n * await client.connect()\n * } catch (error) {\n * if (error instanceof SwarmIdError && error.code === 'button-required') {\n * client.mountButton(container, { action: 'sign-in' })\n * }\n * }\n * ```\n */\n async connect(options: ConnectOptions = {}): Promise<void> {\n this.ensureReady()\n if (this.storageShared !== true) {\n throw new SwarmIdError(\n \"button-required\",\n \"Swarm ID's frame cannot read Swarm ID's storage here, so a window opened from this page cannot sign it in. Sign in through the button from client.mountButton().\",\n )\n }\n // Checked, not discarded: a blocked popup opens nothing, and a\n // `connect()` that resolved anyway would report a connect in progress\n // that no window is running.\n if (!this.openAuthWindow(options)) {\n throw new SwarmIdError(\n \"popup-blocked\",\n \"Failed to open authentication popup\",\n )\n }\n }\n\n /**\n * Shows a Swarm ID button in `container`: a small frame of Swarm ID's own,\n * apart from the hidden session frame, that fills the container. Its click\n * opens the connect window, which hands the session to the site's Swarm ID\n * frames, and the site hears of it on {@link ClientOptions.onConnectionChange} as from\n * any sign-in. This is how a person signs in, or changes the stamp the\n * site uses, wherever the site and Swarm ID are on different sites.\n *\n * Unmounting removes only the button, at any time. The session stays, and\n * signing out stays {@link disconnect}. A button unmounted while its window\n * is open stays hidden until the window closes, because the window reads\n * from it, as it opens, where to hand the session. Unmounting it, or\n * removing its container, in the moment between the click and the window\n * opening loses that sign-in, and the person signs in again.\n *\n * @param container - The element the button fills. Give it the size the button should have\n * @param options.action - `sign-in`, or `change-stamp` for a person signed in\n * @param options.config - The label, its busy and disabled states, colours and typography\n * @param options.onWindowChange - Called with `open`, `closed` or `blocked` for the button's connect window\n * @returns The button: `ready`, `update()` and `unmount()`, where `update()` refuses a bad value the same way\n * @throws {SwarmIdError} `invalid-state` if the client is not initialized\n * @throws {SwarmIdError} `invalid-request` if `action` or a `config` value is not one the button takes, naming the field\n *\n * @example\n * ```typescript\n * const button = client.mountButton(document.getElementById('sign-in')!, {\n * action: 'sign-in',\n * config: { text: 'Sign in', backgroundColor: '#000', borderRadius: '6px' },\n * })\n * await button.ready\n * // later, closing the panel it sits in\n * button.unmount()\n * ```\n */\n mountButton(\n container: HTMLElement,\n options: MountButtonOptions,\n ): MountedButton {\n this.ensureReady()\n const iframeOrigin = this.iframeOrigin\n const expectedOrigin = new URL(iframeOrigin).origin\n let action: ButtonAction = checkedButtonAction(options.action)\n let config: ButtonConfig | undefined = checkedButtonConfig(options.config)\n let loaded = false\n let settled = false\n let windowOpen = false\n let unmounted = false\n\n const frame = document.createElement(\"iframe\")\n frame.src = `${iframeOrigin}${this.iframePath.replace(/\\/proxy$/, \"\")}/button`\n frame.title = \"Swarm ID\"\n Object.assign(frame.style, {\n border: \"none\",\n backgroundColor: \"transparent\",\n width: \"100%\",\n height: \"100%\",\n display: \"block\",\n borderRadius: config?.borderRadius ?? \"0\",\n })\n\n let resolveReady!: () => void\n let rejectReady!: (error: SwarmIdError) => void\n const ready = initDeadline(\n new Promise<void>((resolve, reject) => {\n resolveReady = resolve\n rejectReady = reject\n }),\n this.initializationTimeout,\n `Swarm ID button did not show within ${this.initializationTimeout}ms`,\n )\n ready.then(\n () => (settled = true),\n () => (settled = true),\n )\n\n const post = (message: ParentToButtonMessage) =>\n frame.contentWindow?.postMessage(message, iframeOrigin)\n\n const listener = (event: MessageEvent) => {\n if (event.source !== frame.contentWindow) return\n if (event.data?.type === BUTTON_FRAME_LOADED) {\n loaded = true\n post({\n type: \"buttonIdentify\",\n action,\n config,\n metadata: this.metadata,\n popupMode: this.popupMode,\n })\n return\n }\n if (event.origin !== expectedOrigin) return\n const parsed = ButtonToParentMessageSchema.safeParse(event.data)\n if (!parsed.success) return\n const message = parsed.data\n if (message.type === \"buttonReady\") resolveReady()\n else if (message.type === \"buttonInitError\")\n rejectReady(new SwarmIdError(\"init-failed\", message.error))\n else {\n windowOpen = message.state === \"open\"\n if (unmounted) {\n if (!windowOpen) remove()\n } else {\n options.onWindowChange?.(message.state)\n }\n }\n }\n const remove = () => {\n this.mountedButtons.delete(mounted)\n window.removeEventListener(\"message\", listener)\n frame.remove()\n if (!settled) {\n rejectReady(\n new SwarmIdError(\"invalid-state\", \"Swarm ID button unmounted\"),\n )\n }\n }\n window.addEventListener(\"message\", listener)\n container.appendChild(frame)\n\n const mounted: MountedButton = {\n ready,\n update: (next) => {\n if (unmounted) return\n action =\n next.action === undefined ? action : checkedButtonAction(next.action)\n config =\n next.config === undefined ? config : checkedButtonConfig(next.config)\n frame.style.borderRadius = config?.borderRadius ?? \"0\"\n if (loaded) post({ type: \"buttonUpdate\", action, config })\n },\n // The connect window reads which frames to hand the session to from\n // this frame, its opener, as it opens, so while it is open the frame\n // stays, hidden, and goes once the window closes.\n unmount: () => {\n if (unmounted || !this.mountedButtons.has(mounted)) return\n unmounted = true\n if (windowOpen) frame.style.display = \"none\"\n else remove()\n },\n }\n this.mountedButtons.set(mounted, remove)\n return mounted\n }\n\n /**\n * Open the connect window from the site's page, for a session frame that\n * shares Swarm ID's storage.\n *\n * Carries no challenge: a window opened here has the site's page as its\n * `window.opener`, so there is nothing for a handover to attach to, and the\n * window writes the connection to the storage the session frame reads.\n *\n * @returns whether the popup opened — a blocked one returns null, which the\n * caller must not report as a connect in progress.\n */\n private openAuthWindow(options: ConnectOptions): boolean {\n const basePath = this.iframePath.replace(/\\/proxy$/, \"\")\n const authUrl = buildAuthUrl(\n this.iframeOrigin + basePath,\n window.location.origin,\n this.metadata,\n )\n\n const effectivePopupMode = options.popupMode ?? this.popupMode\n const popup =\n effectivePopupMode === \"popup\"\n ? window.open(authUrl, \"_blank\", \"width=500,height=600\")\n : window.open(authUrl, \"_blank\")\n return Boolean(popup)\n }\n\n /**\n * Current dApp-visible {@link ConnectionInfo} snapshot — identity, app key,\n * upload capability, and upload mode. Populated by the proxy as soon as it\n * is ready and refreshed whenever any of those derived fields change.\n * Subscribe to {@link ClientOptions.onConnectionChange} to react to updates.\n *\n * @throws {SwarmIdError} `invalid-state` if {@link initialize} has not resolved yet\n *\n * @example\n * ```typescript\n * await client.initialize()\n * const info = client.connectionInfo\n * if (info.canUpload) {\n * console.log('Ready to upload as:', info.identity?.name)\n * }\n * ```\n */\n get connectionInfo(): ConnectionInfo {\n this.ensureReady()\n if (!this.lastConnectionInfo) {\n // `ready` flips true on `proxyReady`, which the proxy sends before its\n // first `connectionInfoChanged`, so a read before `initialize()`\n // resolves can land here.\n throw new SwarmIdError(\n \"invalid-state\",\n \"SwarmIdClient connectionInfo not yet available.\",\n )\n }\n return this.lastConnectionInfo\n }\n\n /**\n * Avatar of the connected identity at a specific size.\n *\n * Most callers want `connectionInfo.identity.avatar` instead — it is already\n * resolved on every snapshot and needs no call. Reach for this only to\n * render at a size the default does not suit. Async so that honouring a size\n * may involve fetching, which anything but the generated avatar would.\n *\n * @param options.size - Width and height in pixels\n * @returns The avatar, or `undefined` when no identity is connected\n */\n async getAvatar(\n options: { size?: number } = {},\n ): Promise<Avatar | undefined> {\n const { identity } = this.connectionInfo\n if (!identity) {\n return undefined\n }\n // Only a generated avatar can be re-rendered from the id; any other kind\n // is served as-is.\n return options.size !== undefined && identity.avatar.source === \"generated\"\n ? generatedAvatar(identity.id, options.size)\n : identity.avatar\n }\n\n // ============================================================================\n // Bee Connectivity Methods\n // ============================================================================\n\n /**\n * Checks whether the Bee node is reachable.\n *\n * This method never throws an exception. If the client is not initialized,\n * the request times out, or any other error occurs, it returns `false`.\n *\n * @returns A promise resolving to `true` if the Bee node is reachable, `false` otherwise\n *\n * @example\n * ```typescript\n * const connected = await client.isBeeConnected()\n * if (connected) {\n * console.log('Bee node is online')\n * } else {\n * console.log('Bee node is offline')\n * }\n * ```\n */\n async isBeeConnected(): Promise<boolean> {\n try {\n this.ensureReady()\n const requestId = this.generateRequestId()\n\n const response = await this.sendRequest<{\n type: \"isConnectedResponse\"\n requestId: string\n connected: boolean\n }>({\n type: \"isConnected\",\n requestId,\n })\n\n return response.connected\n } catch {\n return false\n }\n }\n\n /**\n * Gets information about the Bee node configuration.\n *\n * Needs a real Bee node: the public gateway has no `/node` endpoint, so this\n * rejects there. Do not gate uploads on it — it exists to detect a dev-mode\n * node, where deferred uploads are required.\n *\n * This method retrieves the current Bee node's operating mode and feature flags.\n * Use this to determine if deferred uploads are required (dev mode) or if direct\n * uploads are available (production modes).\n *\n * @returns A promise resolving to the node info object\n * @returns return.beeMode - The Bee node operating mode (\"dev\", \"light\", \"full\", \"ultra-light\")\n * @returns return.chequebookEnabled - Whether the chequebook is enabled\n * @returns return.swapEnabled - Whether SWAP is enabled\n * @throws {Error} If the client is not initialized\n * @throws {Error} If the Bee node is not reachable\n * @throws {Error} If the request times out\n *\n * @example\n * ```typescript\n * const nodeInfo = await client.getNodeInfo()\n * if (nodeInfo.beeMode === 'dev') {\n * // Dev mode requires deferred uploads\n * await client.uploadData(data, { deferred: true })\n * } else {\n * // Production modes can use direct uploads\n * await client.uploadData(data, { deferred: false })\n * }\n * ```\n */\n async getNodeInfo(): Promise<{\n beeMode: string\n chequebookEnabled: boolean\n swapEnabled: boolean\n }> {\n this.ensureReady()\n const requestId = this.generateRequestId()\n\n const response = await this.sendRequest<{\n type: \"getNodeInfoResponse\"\n requestId: string\n beeMode: string\n chequebookEnabled: boolean\n swapEnabled: boolean\n }>({\n type: \"getNodeInfo\",\n requestId,\n })\n\n return {\n beeMode: response.beeMode,\n chequebookEnabled: response.chequebookEnabled,\n swapEnabled: response.swapEnabled,\n }\n }\n\n // ============================================================================\n // Data Upload/Download Methods\n // ============================================================================\n\n /**\n * Uploads raw binary data to the Swarm network.\n *\n * Read the returned reference back with {@link downloadData}, or from a\n * gateway at `/bytes/<reference>`. It carries no manifest, so\n * {@link downloadFile} and `/bzz/` cannot resolve it.\n *\n * The data is uploaded using the authenticated user's postage stamp.\n * Progress can be tracked via the optional callback.\n *\n * @param data - The binary data to upload as a Uint8Array\n * @param options - Optional upload configuration\n * @param options.pin - Whether to pin the data locally (defaults to false; ignored on a subsidised gateway)\n * @param options.encrypt - Whether to encrypt the data (defaults to false)\n * @param options.tag - Tag ID for tracking upload progress\n * @param options.deferred - Whether to use deferred upload (defaults to false)\n * @param options.onProgress - Optional callback for tracking upload progress\n * @param requestOptions - Optional request configuration (timeout, headers, endlesslyRetry). `timeout` replaces the client default for this call's whole round trip, not only the Bee request\n * @returns A promise resolving to the upload result\n * @returns return.reference - The Swarm reference (hash) of the uploaded data\n * @returns return.tagUid - The tag UID if a tag was created\n * @throws {Error} If the client is not initialized\n * @throws {Error} If the user is not authenticated or cannot upload\n * @throws {Error} If the request times out\n *\n * @example\n * ```typescript\n * const data = new TextEncoder().encode('Hello, Swarm!')\n * const result = await client.uploadData(data, {\n * encrypt: true,\n * onProgress: (progress) => {\n * console.log(`Progress: ${progress.processed}/${progress.total}`)\n * },\n * })\n * console.log('Reference:', result.reference)\n * ```\n */\n async uploadData(\n data: Uint8Array,\n options?: UploadOptions,\n requestOptions?: RequestOptions,\n ): Promise<UploadResult> {\n this.ensureReady()\n const requestId = this.generateRequestId()\n const {\n onProgress,\n useWebSocket,\n useWorkers,\n workerCount,\n concurrency,\n ...serializableOptions\n } = options ?? {}\n\n const stopProgress = this.listenForProgress(requestId, onProgress)\n try {\n const response = await this.sendRequest<{\n type: \"uploadDataResponse\"\n requestId: string\n reference: Reference\n tagUid?: number\n }>({\n type: \"uploadData\",\n requestId,\n data: new Uint8Array(data),\n options: serializableOptions,\n requestOptions,\n enableProgress: !!onProgress,\n useWebSocket,\n useWorkers,\n workerCount,\n concurrency,\n })\n\n return {\n reference: response.reference,\n tagUid: response.tagUid,\n }\n } finally {\n stopProgress()\n }\n }\n\n /**\n * Downloads raw binary data from the Swarm network: the counterpart of\n * {@link uploadData}. Pass an encrypted (128-hex) reference here rather\n * than putting it in a gateway URL — it contains the decryption key.\n *\n * @param reference - The Swarm reference (hash) of the data to download.\n * Can be 64 hex chars (32 bytes) or 128 hex chars (64 bytes for encrypted)\n * @param options - Optional download configuration\n * @param options.redundancyStrategy - Strategy for handling redundancy (0-3)\n * @param options.fallback - Whether to use fallback retrieval\n * @param options.timeoutMs - Download timeout in milliseconds\n * @param options.actPublisher - ACT publisher for encrypted content\n * @param options.actHistoryAddress - ACT history address for encrypted content\n * @param options.actTimestamp - ACT timestamp for encrypted content\n * @param requestOptions - Optional request configuration (timeout, headers, endlesslyRetry). `timeout` replaces the client default for this call's whole round trip, not only the Bee request\n * @returns A promise resolving to the downloaded data as a Uint8Array\n * @throws {Error} If the client is not initialized\n * @throws {Error} If the reference is not found\n * @throws {Error} If the request times out\n *\n * @example\n * ```typescript\n * const data = await client.downloadData('a1b2c3...') // 64 char hex reference\n * const text = new TextDecoder().decode(data)\n * console.log('Downloaded:', text)\n * ```\n */\n async downloadData(\n reference: Reference,\n options?: DownloadOptions,\n requestOptions?: RequestOptions,\n ): Promise<Uint8Array> {\n this.ensureReady()\n const requestId = this.generateRequestId()\n\n const response = await this.sendRequest<{\n type: \"downloadDataResponse\"\n requestId: string\n data: Uint8Array\n }>({\n type: \"downloadData\",\n requestId,\n reference,\n options,\n requestOptions,\n })\n\n return response.data\n }\n\n /**\n * Derive a stable, app-scoped secret for this identity + app origin.\n *\n * Computes `HMAC(appSecret, label)` inside the iframe, where `appSecret` is the\n * app-specific secret that never leaves the trusted context. The result is\n * deterministic — the same identity, app origin, and label always yield the\n * same bytes across sessions and devices — yet unguessable to anyone without\n * the identity. Use it to seed feed topics or other app material without\n * exposing the recoverable app public key (#520).\n *\n * @param label - Application-chosen domain separator (e.g. `\"state-feed\"`)\n * @returns A promise resolving to the 32-byte derived secret\n * @throws {Error} If the client is not initialized or not authenticated\n *\n * @example\n * ```typescript\n * const seed = await client.deriveAppSecret('state-feed')\n * const topic = keccak256(seed) // an unguessable, stable feed topic\n * ```\n */\n async deriveAppSecret(label: string): Promise<Uint8Array> {\n this.ensureReady()\n const requestId = this.generateRequestId()\n\n const response = await this.sendRequest<{\n type: \"deriveAppSecretResponse\"\n requestId: string\n secret: Uint8Array\n }>({\n type: \"deriveAppSecret\",\n requestId,\n label,\n })\n\n return response.secret\n }\n\n /**\n * The site's chat key: the private key this site's chat signs messages\n * with, whose address `connectionInfo.chatBinding` names as the account's\n * chat address on this site (docs/Chat-Binding.md).\n *\n * It is derived inside the iframe from the app secret, which never leaves\n * it, and is the same for this account and this site on every device. The\n * library keeps it in memory only and never writes it to storage. Hold it no\n * longer than the chat needs it, and never publish it.\n *\n * @returns A promise resolving to the 32-byte secp256k1 private key\n * @throws {SwarmIdError} If the client is not initialized, or with code\n * `not-authenticated` when no account is connected\n *\n * @example\n * ```typescript\n * const chatKey = await client.getChatKey()\n * const signer = new PrivateKey(chatKey) // its address is the binding's chat address\n * ```\n */\n async getChatKey(): Promise<Uint8Array> {\n this.ensureReady()\n const requestId = this.generateRequestId()\n\n const response = await this.sendRequest<{\n type: \"getChatKeyResponse\"\n requestId: string\n chatKey: Uint8Array\n }>({\n type: \"getChatKey\",\n requestId,\n })\n\n return response.chatKey\n }\n\n /**\n * Stamp a chunk with the account's own postage stamp and get the stamp back,\n * to send the chunk through whatever Swarm access the app chose: a gateway,\n * its own Bee node or a browser node.\n *\n * The frame computes the chunk's address itself, so the whole chunk goes in,\n * never an address. A content chunk is stamped as it is. A single-owner chunk\n * is signed by the frame in this same call, with the app's own secret\n * (`signer: \"app\"`) or a private key the app supplies, such as a chat's\n * shared GSOC inbox key. A pre-signed chunk is refused, and so is one owned\n * by any of the account's own keys.\n *\n * The stamp is returned only once the bucket counter it spent is saved and,\n * for an account shared between devices, published, as an upload is\n * acknowledged. Two calls never return the same bucket slot.\n *\n * @param chunk - The chunk: `data` is the 8-byte little-endian span followed\n * by the payload, 8 to 4104 bytes\n * @returns The chunk address, the stamp as the `swarm-postage-stamp` header\n * value, and for a single-owner chunk its owner and signature\n * @throws {SwarmIdError} `upload-unavailable` with reason `subsidised` when\n * the account is in subsidised mode, where the gateway stamps and there is\n * no stamp of the account's to return, and `invalid-request` for a chunk of the\n * wrong shape or an owner that is one of the account's keys\n *\n * @example\n * ```typescript\n * const { address, stamp } = await client.stampChunk({ kind: 'content', data })\n * await fetch(`${gateway}/chunks`, {\n * method: 'POST',\n * headers: { 'swarm-postage-stamp': stamp },\n * body: data,\n * })\n * ```\n */\n async stampChunk(chunk: StampChunkInput): Promise<StampedChunk> {\n this.ensureReady()\n const requestId = this.generateRequestId()\n\n // Spread rather than rebuilt, so a field the frame refuses (an address, a\n // signature) still reaches the schema check and is refused here.\n const wireChunk =\n chunk.kind === \"soc\"\n ? {\n ...chunk,\n identifier: this.normalizeSocIdentifier(chunk.identifier),\n signer:\n chunk.signer === \"app\"\n ? chunk.signer\n : {\n ...chunk.signer,\n privateKey: this.normalizeSocKey(chunk.signer.privateKey),\n },\n }\n : chunk\n\n const response = await this.sendRequest<StampChunkResponseMessage>({\n type: \"stampChunk\",\n requestId,\n chunk: wireChunk as StampChunkRequest,\n })\n\n return {\n address: response.address,\n stamp: response.stamp,\n ...(response.owner !== undefined && { owner: response.owner }),\n ...(response.signature !== undefined && {\n signature: response.signature,\n }),\n }\n }\n\n // ============================================================================\n // File Upload/Download Methods\n // ============================================================================\n\n /**\n * Uploads a file to the Swarm network, wrapped in a manifest that carries\n * its name and content type. Read the reference back with\n * {@link downloadFile}. A gateway's `/bzz/<reference>/` is only for a plain\n * reference, uploaded with `encrypt: false`.\n *\n * Accepts either a File object (from file input) or raw Uint8Array data.\n * When using a File object, the filename is automatically extracted unless\n * explicitly overridden.\n *\n * Content is encrypted unless `options.encrypt` is `false`, and the\n * manifest too — a 64-byte reference that carries the key — unless\n * `options.encrypt` or `options.encryptManifest` is `false`. The same rule\n * as {@link uploadFiles}.\n *\n * @param file - The file to upload (File object or Uint8Array)\n * @param name - Optional filename (extracted from File object if not provided)\n * @param options - Optional upload configuration\n * @param options.pin - Whether to pin the file locally (defaults to false; ignored on a subsidised gateway)\n * @param options.encrypt - Whether to encrypt the file content (defaults to true); `false` also leaves the manifest plain\n * @param options.encryptManifest - Whether to encrypt the manifest too (defaults to true); `false` gives a 32-byte reference over encrypted content\n * @param options.tag - Tag ID for tracking upload progress\n * @param options.deferred - Whether to use deferred upload (defaults to false)\n * @param requestOptions - Optional request configuration (timeout, headers, endlesslyRetry). `timeout` replaces the client default for this call's whole round trip, not only the Bee request\n * @returns A promise resolving to the upload result\n * @returns return.reference - The Swarm reference (hash) of the uploaded file\n * @returns return.tagUid - The tag UID if a tag was created\n * @throws {Error} If the client is not initialized\n * @throws {Error} If the user is not authenticated or cannot upload\n * @throws {Error} If the request times out\n *\n * @example\n * ```typescript\n * // From file input\n * const fileInput = document.querySelector('input[type=\"file\"]')\n * const file = fileInput.files[0]\n * const result = await client.uploadFile(file)\n *\n * // From Uint8Array with custom name\n * const data = new Uint8Array([...])\n * const result = await client.uploadFile(data, 'document.pdf')\n * ```\n */\n async uploadFile(\n file: File | Uint8Array,\n name?: string,\n options?: UploadOptions,\n requestOptions?: RequestOptions,\n ): Promise<UploadResult> {\n this.ensureReady()\n const requestId = this.generateRequestId()\n const {\n onProgress,\n useWebSocket,\n useWorkers,\n workerCount,\n concurrency,\n ...serializableOptions\n } = options ?? {}\n\n let data: Uint8Array\n let fileName: string | undefined = name\n\n if (file instanceof File) {\n const buffer = await file.arrayBuffer()\n data = new Uint8Array(buffer)\n fileName = fileName || file.name\n } else {\n data = new Uint8Array(\n file.buffer.slice(0),\n file.byteOffset,\n file.byteLength,\n )\n }\n\n const stopProgress = this.listenForProgress(requestId, onProgress)\n try {\n const response = await this.sendRequest<{\n type: \"uploadFileResponse\"\n requestId: string\n reference: Reference\n tagUid?: number\n }>({\n type: \"uploadFile\",\n requestId,\n data,\n name: fileName,\n options: serializableOptions,\n requestOptions,\n enableProgress: !!onProgress,\n useWebSocket,\n useWorkers,\n workerCount,\n concurrency,\n })\n\n return {\n reference: response.reference,\n tagUid: response.tagUid,\n }\n } finally {\n stopProgress()\n }\n }\n\n /**\n * Downloads a file from the Swarm network: the counterpart of\n * {@link uploadFile}. It resolves a manifest, so a reference produced by\n * {@link uploadData} fails here inside the manifest parser; use\n * {@link downloadData} for those.\n *\n * Returns both the file data and its original filename (if available).\n * For manifest references, an optional path can be specified to retrieve\n * a specific file from the manifest.\n *\n * @param reference - The Swarm reference (hash) of the file to download\n * @param path - Optional path within a manifest to retrieve a specific file\n * @param options - Optional download configuration\n * @param options.redundancyStrategy - Strategy for handling redundancy (0-3)\n * @param options.fallback - Whether to use fallback retrieval\n * @param options.timeoutMs - Download timeout in milliseconds\n * @param options.actPublisher - ACT publisher for encrypted content\n * @param options.actHistoryAddress - ACT history address for encrypted content\n * @param options.actTimestamp - ACT timestamp for encrypted content\n * @param requestOptions - Optional request configuration (timeout, headers, endlesslyRetry). `timeout` replaces the client default for this call's whole round trip, not only the Bee request\n * @returns A promise resolving to the file data object\n * @returns return.name - The filename\n * @returns return.data - The file contents as a Uint8Array\n * @throws {Error} If the client is not initialized\n * @throws {Error} If the reference is not found\n * @throws {Error} If the request times out\n *\n * @example\n * ```typescript\n * const file = await client.downloadFile('a1b2c3...')\n * console.log('Filename:', file.name)\n *\n * // Create download link\n * const blob = new Blob([file.data])\n * const url = URL.createObjectURL(blob)\n * ```\n */\n async downloadFile(\n reference: Reference,\n path?: string,\n options?: DownloadOptions,\n requestOptions?: RequestOptions,\n ): Promise<FileData> {\n this.ensureReady()\n const requestId = this.generateRequestId()\n\n const response = await this.sendRequest<{\n type: \"downloadFileResponse\"\n requestId: string\n name: string\n data: number[]\n }>({\n type: \"downloadFile\",\n requestId,\n reference,\n path,\n options,\n requestOptions,\n })\n\n return {\n name: response.name,\n data: new Uint8Array(response.data),\n }\n }\n\n /**\n * Uploads a folder as one manifest (#750): a fork per file with its path and\n * content type, which a gateway serves at `/bzz/<reference>/<path>` when the\n * folder is plain (`encrypt: false`). Takes what bee-js takes — the\n * `FileList` of a `webkitdirectory` input or a dropped directory, a `File[]`,\n * or `{ path, file }` pairs for a folder the app assembled itself. A `File`'s\n * path is its `webkitRelativePath` minus the picked folder's own name, or its\n * name.\n *\n * Content is encrypted unless `options.encrypt` is `false`, and the\n * manifest too — a 64-byte root reference — unless `options.encrypt` or\n * `options.encryptManifest` is `false`. Name `options.indexDocument` for\n * the bare `/bzz/<reference>/` to serve a file. Read a folder back with\n * {@link listFiles} and {@link downloadData} per entry, or one file with\n * {@link downloadFile} and its path.\n *\n * Every file is read into memory before the upload starts; for folders\n * larger than that, upload the files with {@link uploadData} and build the\n * manifest with `@ethersphere/core-sdk`.\n *\n * @param files - The folder's files\n * @param options - Optional upload configuration; `onProgress` counts files, `useWorkers` / `workerCount` stamp in a pool as with {@link uploadData}\n * @param requestOptions - Optional request configuration (timeout, headers, endlesslyRetry). `timeout` replaces the client default for this call's whole round trip, not only the Bee request\n * @returns A promise resolving to the upload result\n * @returns return.reference - The Swarm reference of the manifest\n * @returns return.tagUid - The tag UID if a tag was created\n * @throws {Error} If the client is not initialized\n * @throws {Error} If the user is not authenticated or cannot upload\n * @throws {Error} If two files share a path\n * @throws {Error} If the request times out\n *\n * @example\n * ```typescript\n * // <input type=\"file\" webkitdirectory>\n * const { reference } = await client.uploadFiles(input.files, {\n * indexDocument: 'index.html',\n * })\n * // or assembled by the app\n * await client.uploadFiles([{ path: 'a/b.txt', file: new Blob(['hi']) }])\n * ```\n */\n async uploadFiles(\n files: FileList | Iterable<File | CollectionFileInput>,\n options?: UploadFilesOptions,\n requestOptions?: RequestOptions,\n ): Promise<UploadResult> {\n this.ensureReady()\n const requestId = this.generateRequestId()\n const { onProgress, useWorkers, workerCount, ...serializableOptions } =\n options ?? {}\n\n const entries = await Promise.all(\n Array.from(files, async (item) => {\n const { path, file } =\n item instanceof File\n ? { path: collectionPath(item), file: item }\n : item\n return {\n path,\n data: new Uint8Array(await file.arrayBuffer()),\n contentType: file.type || undefined,\n }\n }),\n )\n\n const stopProgress = this.listenForProgress(requestId, onProgress)\n try {\n const response = await this.sendRequest<{\n type: \"uploadFilesResponse\"\n requestId: string\n reference: Reference\n tagUid?: number\n }>({\n type: \"uploadFiles\",\n requestId,\n files: entries,\n options: serializableOptions,\n requestOptions,\n enableProgress: !!onProgress,\n useWorkers,\n workerCount,\n })\n return { reference: response.reference, tagUid: response.tagUid }\n } finally {\n stopProgress()\n }\n }\n\n /**\n * Lists the files of a manifest uploaded with {@link uploadFiles} (or any\n * manifest): each entry's path, content type, and the reference of its\n * content, which {@link downloadData} reads.\n *\n * @param reference - The Swarm reference of the manifest\n * @param requestOptions - Optional request configuration (timeout, headers, endlesslyRetry)\n * @returns A promise resolving to the entries, the index-document fork excluded\n * @throws {Error} If the client is not initialized\n * @throws {Error} If the reference is not a manifest or is not found\n * @throws {Error} If the request times out\n *\n * @example\n * ```typescript\n * for (const { path, reference } of await client.listFiles(root)) {\n * const data = await client.downloadData(reference)\n * }\n * ```\n */\n async listFiles(\n reference: Reference,\n requestOptions?: RequestOptions,\n ): Promise<CollectionEntry[]> {\n this.ensureReady()\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<{\n type: \"listFilesResponse\"\n requestId: string\n entries: CollectionEntry[]\n }>({ type: \"listFiles\", requestId, reference, requestOptions })\n return response.entries\n }\n\n /**\n * Forward the proxy's `uploadProgress` messages for one request to a\n * callback, through the window listener's checks. Returns the function that\n * stops forwarding; a no-op without a callback.\n */\n private listenForProgress(\n requestId: string,\n onProgress: ((progress: UploadProgress) => void) | undefined,\n ): () => void {\n if (!onProgress) return () => {}\n this.progressListeners.set(requestId, onProgress)\n return () => {\n this.progressListeners.delete(requestId)\n }\n }\n\n // ============================================================================\n // Chunk Upload/Download Methods\n // ============================================================================\n\n /**\n * Uploads a single chunk to the Swarm network.\n *\n * Chunks are the fundamental unit of storage in Swarm (4KB each).\n * This method is useful for low-level operations or when implementing\n * custom chunking strategies.\n *\n * `data` is the chunk's payload, not a finished chunk: the proxy builds the\n * content-addressed chunk around it (span header, BMT address) and returns\n * that address. A chunk that already carries its span header is wrapped a\n * second time and stored under an address nothing else computes (#774). To\n * store a folder as a manifest, use {@link uploadFiles}; to save a Mantaray\n * tree of your own, use `saveMantarayTreeRecursively` with {@link uploadData}.\n *\n * @param data - The chunk payload, 1 to 4096 bytes\n * @param options - Optional upload configuration\n * @param options.pin - Whether to pin the chunk locally (defaults to false; ignored on a subsidised gateway)\n * @param options.encrypt - Whether to encrypt the chunk (defaults to false)\n * @param options.tag - Tag ID for tracking upload progress\n * @param options.deferred - Whether to use deferred upload (defaults to false)\n * @param requestOptions - Optional request configuration (timeout, headers, endlesslyRetry). `timeout` replaces the client default for this call's whole round trip, not only the Bee request\n * @returns A promise resolving to the upload result\n * @returns return.reference - The Swarm reference (hash) of the uploaded chunk\n * @throws {Error} If the client is not initialized\n * @throws {Error} If the user is not authenticated or cannot upload\n * @throws {Error} If the request times out\n *\n * @example\n * ```typescript\n * const chunk = new Uint8Array(4096) // 4KB chunk\n * chunk.fill(0x42) // Fill with data\n * const result = await client.uploadChunk(chunk)\n * console.log('Chunk reference:', result.reference)\n * ```\n */\n async uploadChunk(\n data: Uint8Array,\n options?: UploadOptions,\n requestOptions?: RequestOptions,\n ): Promise<UploadResult> {\n this.ensureReady()\n const requestId = this.generateRequestId()\n const { onProgress: _onProgress, ...serializableOptions } = options ?? {}\n\n const response = await this.sendRequest<{\n type: \"uploadChunkResponse\"\n requestId: string\n reference: Reference\n }>({\n type: \"uploadChunk\",\n requestId,\n data: data as Uint8Array,\n options: serializableOptions,\n requestOptions,\n })\n\n return {\n reference: response.reference,\n }\n }\n\n /**\n * Downloads a single chunk from the Swarm network.\n *\n * Retrieves a chunk by its reference hash. This method is useful for\n * low-level operations or when implementing custom retrieval strategies.\n *\n * @param reference - The Swarm reference (hash) of the chunk to download\n * @param options - Optional download configuration\n * @param options.redundancyStrategy - Strategy for handling redundancy (0-3)\n * @param options.fallback - Whether to use fallback retrieval\n * @param options.timeoutMs - Download timeout in milliseconds\n * @param options.actPublisher - ACT publisher for encrypted content\n * @param options.actHistoryAddress - ACT history address for encrypted content\n * @param options.actTimestamp - ACT timestamp for encrypted content\n * @param requestOptions - Optional request configuration (timeout, headers, endlesslyRetry). `timeout` replaces the client default for this call's whole round trip, not only the Bee request\n * @returns A promise resolving to the chunk data as a Uint8Array\n * @throws {Error} If the client is not initialized\n * @throws {Error} If the reference is not found\n * @throws {Error} If the request times out\n *\n * @example\n * ```typescript\n * const chunk = await client.downloadChunk('a1b2c3...')\n * console.log('Chunk size:', chunk.length)\n * ```\n */\n async downloadChunk(\n reference: Reference,\n options?: DownloadOptions,\n requestOptions?: RequestOptions,\n ): Promise<Uint8Array> {\n this.ensureReady()\n const requestId = this.generateRequestId()\n\n const response = await this.sendRequest<{\n type: \"downloadChunkResponse\"\n requestId: string\n data: number[]\n }>({\n type: \"downloadChunk\",\n requestId,\n reference,\n options,\n requestOptions,\n })\n\n return new Uint8Array(response.data)\n }\n\n // ============================================================================\n // SOC (Single Owner Chunk) Methods\n // ============================================================================\n\n /**\n * Returns an object for reading single owner chunks (SOC).\n *\n * @param ownerAddress - Ethereum address of the SOC owner\n * @param requestOptions - Optional request configuration (timeout, headers, endlesslyRetry). `timeout` replaces the client default for this call's whole round trip, not only the Bee request\n * @returns SOCReader with `download` (encrypted) and `rawDownload` (unencrypted)\n * @throws {Error} If the client is not initialized\n * @throws {Error} If the request times out\n *\n * @example\n * ```typescript\n * const reader = client.makeSOCReader(owner)\n * const soc = await reader.download(identifier, encryptionKey)\n * console.log('Payload:', new TextDecoder().decode(soc.payload))\n * ```\n */\n makeSOCReader(\n ownerAddress: EthAddress | Uint8Array | string,\n requestOptions?: RequestOptions,\n ): SOCReader {\n this.ensureReady()\n const owner = new EthAddress(ownerAddress).toHex()\n\n const sendSocDownload = async (\n identifier: Identifier | Uint8Array | string,\n encryptionKey: Uint8Array | string,\n ): Promise<SingleOwnerChunk> => {\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n SocDownloadResponseMessage,\n SocDownloadMessage\n >({\n type: \"socDownload\",\n requestId,\n owner,\n identifier: this.normalizeSocIdentifier(identifier),\n encryptionKey: this.normalizeSocKey(encryptionKey),\n requestOptions,\n })\n\n return this.socChunkFromResponse(response)\n }\n\n const sendRawSocDownload = async (\n identifier: Identifier | Uint8Array | string,\n encryptionKey?: Uint8Array | string,\n ): Promise<SingleOwnerChunk> => {\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n SocRawDownloadResponseMessage,\n SocRawDownloadMessage\n >({\n type: \"socRawDownload\",\n requestId,\n owner,\n identifier: this.normalizeSocIdentifier(identifier),\n encryptionKey: encryptionKey\n ? this.normalizeSocKey(encryptionKey)\n : undefined,\n requestOptions,\n })\n\n return this.socChunkFromResponse(response)\n }\n\n return {\n getOwner: async () => owner,\n rawDownload: (identifier, encryptionKey) =>\n sendRawSocDownload(identifier, encryptionKey),\n download: (identifier, encryptionKey) =>\n sendSocDownload(identifier, encryptionKey),\n }\n }\n\n /**\n * Returns an object for reading and writing single owner chunks (SOC).\n *\n * Uploads are encrypted by default. Use `rawUpload` for unencrypted SOCs.\n *\n * @param signer - Optional SOC signer private key. If omitted, the proxy uses the app signer.\n * @param requestOptions - Optional request configuration (timeout, headers, endlesslyRetry). `timeout` replaces the client default for this call's whole round trip, not only the Bee request\n * @returns SOCWriter with `upload`, `rawUpload`, `download`, and `rawDownload`\n * @throws {Error} If the client is not initialized\n * @throws {Error} If the request times out\n *\n * @example\n * ```typescript\n * const writer = client.makeSOCWriter()\n * const upload = await writer.upload(identifier, payload)\n * const soc = await writer.download(identifier, upload.encryptionKey)\n * ```\n */\n makeSOCWriter(\n signer?: PrivateKey | Uint8Array | string,\n requestOptions?: RequestOptions,\n ): SOCWriter {\n this.ensureReady()\n const signerObj = signer ? new PrivateKey(signer) : undefined\n const signerKey = signerObj ? signerObj.toHex() : undefined\n let owner: string | undefined = signerObj\n ? signerObj.publicKey().address().toHex()\n : undefined\n\n const resolveOwner = async (): Promise<string> => {\n if (owner) {\n return owner\n }\n\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n SocGetOwnerResponseMessage,\n SocGetOwnerMessage\n >({\n type: \"socGetOwner\",\n requestId,\n })\n\n owner = response.owner\n return owner\n }\n\n const sendSocDownload = async (\n identifier: Identifier | Uint8Array | string,\n encryptionKey: Uint8Array | string,\n ): Promise<SingleOwnerChunk> => {\n const requestId = this.generateRequestId()\n\n const response = await this.sendRequest<\n SocDownloadResponseMessage,\n SocDownloadMessage\n >({\n type: \"socDownload\",\n requestId,\n owner,\n identifier: this.normalizeSocIdentifier(identifier),\n encryptionKey: this.normalizeSocKey(encryptionKey),\n requestOptions,\n })\n\n return this.socChunkFromResponse(response)\n }\n\n const sendRawSocDownload = async (\n identifier: Identifier | Uint8Array | string,\n encryptionKey?: Uint8Array | string,\n ): Promise<SingleOwnerChunk> => {\n const requestId = this.generateRequestId()\n\n const response = await this.sendRequest<\n SocRawDownloadResponseMessage,\n SocRawDownloadMessage\n >({\n type: \"socRawDownload\",\n requestId,\n owner,\n identifier: this.normalizeSocIdentifier(identifier),\n encryptionKey: encryptionKey\n ? this.normalizeSocKey(encryptionKey)\n : undefined,\n requestOptions,\n })\n\n return this.socChunkFromResponse(response)\n }\n\n const sendSocUpload = async (\n identifier: Identifier | Uint8Array | string,\n data: Uint8Array,\n options?: UploadOptions,\n ): Promise<SocUploadResult> => {\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n SocUploadResponseMessage,\n SocUploadMessage\n >({\n type: \"socUpload\",\n requestId,\n identifier: this.normalizeSocIdentifier(identifier),\n data: new Uint8Array(data),\n signer: signerKey,\n options,\n requestOptions,\n })\n\n owner = response.owner\n\n return {\n reference: response.reference,\n tagUid: response.tagUid,\n encryptionKey: response.encryptionKey,\n owner: response.owner,\n }\n }\n\n const sendRawSocUpload = async (\n identifier: Identifier | Uint8Array | string,\n data: Uint8Array,\n options?: UploadOptions,\n ): Promise<SocRawUploadResult> => {\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n SocRawUploadResponseMessage,\n SocRawUploadMessage\n >({\n type: \"socRawUpload\",\n requestId,\n identifier: this.normalizeSocIdentifier(identifier),\n data: new Uint8Array(data),\n signer: signerKey,\n options,\n requestOptions,\n })\n\n owner = response.owner\n\n return {\n reference: response.reference,\n tagUid: response.tagUid,\n encryptionKey: response.encryptionKey,\n owner: response.owner,\n }\n }\n\n return {\n getOwner: resolveOwner,\n rawDownload: (identifier, encryptionKey) =>\n sendRawSocDownload(identifier, encryptionKey),\n download: (identifier, encryptionKey) =>\n sendSocDownload(identifier, encryptionKey),\n upload: (identifier, data, options) =>\n sendSocUpload(identifier, data, options),\n rawUpload: (identifier, data, options) =>\n sendRawSocUpload(identifier, data, options),\n }\n }\n\n /**\n * Returns an object for reading epoch-based feeds.\n *\n * @param options - Feed reader options\n * @param options.topic - Feed topic (32 bytes)\n * @param options.owner - Optional feed owner address\n * @param requestOptions - Optional request configuration (timeout, headers, endlesslyRetry). `timeout` replaces the client default for this call's whole round trip, not only the Bee request\n * @returns FeedReader with `getOwner`, `downloadReference`, and `downloadPayload`\n * @throws {Error} If the client is not initialized\n * @throws {Error} If the request times out\n */\n makeEpochFeedReader(\n options: FeedReaderOptions,\n requestOptions?: RequestOptions,\n ): FeedReader {\n this.ensureReady()\n const topic = this.normalizeFeedTopic(options.topic)\n let owner: string | undefined = options.owner\n ? new EthAddress(options.owner).toHex()\n : undefined\n\n const resolveOwner = async (): Promise<string> => {\n if (owner) {\n return owner\n }\n\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n FeedGetOwnerResponseMessage,\n FeedGetOwnerMessage\n >({\n type: \"feedGetOwner\",\n requestId,\n })\n\n owner = response.owner\n return owner\n }\n\n const downloadReference = async (\n options?: EpochFeedDownloadOptions,\n ): Promise<EpochFeedDownloadReferenceResult> => {\n const atValue =\n options?.at !== undefined\n ? options.at\n : BigInt(Math.floor(Date.now() / 1000))\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n EpochFeedDownloadReferenceResponseMessage,\n EpochFeedDownloadReferenceMessage\n >({\n type: \"epochFeedDownloadReference\",\n requestId,\n topic,\n owner,\n at: this.normalizeFeedTimestamp(atValue),\n after:\n options?.after !== undefined\n ? this.normalizeFeedTimestamp(options.after)\n : undefined,\n encryptionKey:\n options?.encryptionKey !== undefined\n ? this.normalizeSocKey(options.encryptionKey)\n : undefined,\n requestOptions,\n })\n const reference = response.reference\n const cleanRef =\n reference && reference.startsWith(\"0x\") ? reference.slice(2) : reference\n const encryptionKey =\n cleanRef && cleanRef.length === 128 ? cleanRef.slice(64) : undefined\n return { reference, encryptionKey }\n }\n\n const downloadPayload = async (\n options?: EpochFeedDownloadOptions,\n ): Promise<EpochFeedDownloadPayloadResult> => {\n const result = await downloadReference(options)\n if (!result.reference) {\n return {\n reference: undefined,\n payload: undefined,\n encryptionKey: undefined,\n }\n }\n const payload = await this.downloadData(\n result.reference,\n undefined,\n requestOptions,\n )\n return {\n reference: result.reference,\n payload,\n encryptionKey: result.encryptionKey,\n }\n }\n\n const downloadRawReference = async (\n options?: Omit<EpochFeedDownloadOptions, \"encryptionKey\">,\n ): Promise<EpochFeedDownloadReferenceResult> => {\n const atValue =\n options?.at !== undefined\n ? options.at\n : BigInt(Math.floor(Date.now() / 1000))\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n EpochFeedDownloadReferenceResponseMessage,\n EpochFeedDownloadReferenceMessage\n >({\n type: \"epochFeedDownloadReference\",\n requestId,\n topic,\n owner,\n at: this.normalizeFeedTimestamp(atValue),\n after:\n options?.after !== undefined\n ? this.normalizeFeedTimestamp(options.after)\n : undefined,\n encryptionKey: undefined, // No encryption for raw download\n requestOptions,\n })\n const reference = response.reference\n return { reference, encryptionKey: undefined }\n }\n\n const downloadRawPayload = async (\n options?: Omit<EpochFeedDownloadOptions, \"encryptionKey\">,\n ): Promise<EpochFeedDownloadPayloadResult> => {\n const result = await downloadRawReference(options)\n if (!result.reference) {\n return {\n reference: undefined,\n payload: undefined,\n encryptionKey: undefined,\n }\n }\n const payload = await this.downloadData(\n result.reference,\n undefined,\n requestOptions,\n )\n return {\n reference: result.reference,\n payload,\n encryptionKey: undefined,\n }\n }\n\n return {\n getOwner: resolveOwner,\n downloadReference,\n downloadPayload,\n downloadRawReference,\n downloadRawPayload,\n }\n }\n\n /**\n * Returns an object for reading and writing epoch-based feeds.\n *\n * @param options - Feed writer options\n * @param options.topic - Feed topic (32 bytes)\n * @param options.signer - Optional feed signer private key. If omitted, the proxy uses the app signer.\n * @param requestOptions - Optional request configuration (timeout, headers, endlesslyRetry). `timeout` replaces the client default for this call's whole round trip, not only the Bee request\n * @returns FeedWriter with `getOwner`, `downloadReference`, `downloadPayload`, `uploadPayload`, and `uploadReference`\n * @throws {Error} If the client is not initialized\n * @throws {Error} If the request times out\n */\n makeEpochFeedWriter(\n options: FeedWriterOptions,\n requestOptions?: RequestOptions,\n ): FeedWriter {\n this.ensureReady()\n const topic = this.normalizeFeedTopic(options.topic)\n const signerObj = options.signer\n ? new PrivateKey(options.signer)\n : undefined\n const signerKey = signerObj ? signerObj.toHex() : undefined\n let owner: string | undefined = signerObj\n ? signerObj.publicKey().address().toHex()\n : undefined\n\n const resolveOwner = async (): Promise<string> => {\n if (owner) {\n return owner\n }\n\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n FeedGetOwnerResponseMessage,\n FeedGetOwnerMessage\n >({\n type: \"feedGetOwner\",\n requestId,\n })\n\n owner = response.owner\n return owner\n }\n\n const downloadReference = async (\n options?: EpochFeedDownloadOptions,\n ): Promise<EpochFeedDownloadReferenceResult> => {\n const atValue =\n options?.at !== undefined\n ? options.at\n : BigInt(Math.floor(Date.now() / 1000))\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n EpochFeedDownloadReferenceResponseMessage,\n EpochFeedDownloadReferenceMessage\n >({\n type: \"epochFeedDownloadReference\",\n requestId,\n topic,\n owner,\n at: this.normalizeFeedTimestamp(atValue),\n after:\n options?.after !== undefined\n ? this.normalizeFeedTimestamp(options.after)\n : undefined,\n encryptionKey:\n options?.encryptionKey !== undefined\n ? this.normalizeSocKey(options.encryptionKey)\n : undefined,\n requestOptions,\n })\n const reference = response.reference\n const cleanRef =\n reference && reference.startsWith(\"0x\") ? reference.slice(2) : reference\n const encryptionKey =\n cleanRef && cleanRef.length === 128 ? cleanRef.slice(64) : undefined\n return { reference, encryptionKey }\n }\n\n const downloadPayload = async (\n options?: EpochFeedDownloadOptions,\n ): Promise<EpochFeedDownloadPayloadResult> => {\n const result = await downloadReference(options)\n if (!result.reference) {\n return {\n reference: undefined,\n payload: undefined,\n encryptionKey: undefined,\n }\n }\n const payload = await this.downloadData(\n result.reference,\n undefined,\n requestOptions,\n )\n return {\n reference: result.reference,\n payload,\n encryptionKey: result.encryptionKey,\n }\n }\n\n const uploadReference = async (\n reference: Uint8Array | string,\n options?: EpochFeedUploadOptions,\n ): Promise<EpochFeedUploadResult> => {\n const atValue =\n options?.at !== undefined\n ? options.at\n : BigInt(Math.floor(Date.now() / 1000))\n const normalizedRef = this.normalizeReference(reference)\n const cleanRef = normalizedRef.startsWith(\"0x\")\n ? normalizedRef.slice(2)\n : normalizedRef\n const derivedKey =\n cleanRef.length === 128 ? cleanRef.slice(64) : undefined\n const feedKey = options?.encryptionKey ?? derivedKey\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n EpochFeedUploadReferenceResponseMessage,\n EpochFeedUploadReferenceMessage\n >({\n type: \"epochFeedUploadReference\",\n requestId,\n topic,\n signer: signerKey,\n at: this.normalizeFeedTimestamp(atValue),\n reference: normalizedRef,\n encryptionKey:\n feedKey !== undefined ? this.normalizeSocKey(feedKey) : undefined,\n hints: options?.hints,\n requestOptions,\n })\n const socAddress = response.socAddress\n const encryptionKey = derivedKey\n return {\n socAddress,\n reference: normalizedRef,\n encryptionKey,\n epoch: response.epoch,\n timestamp: response.timestamp,\n }\n }\n\n const uploadPayload = async (\n data: Uint8Array | string,\n options?: EpochFeedUploadOptions,\n ): Promise<EpochFeedUploadResult> => {\n const atValue =\n options?.at !== undefined\n ? options.at\n : BigInt(Math.floor(Date.now() / 1000))\n const encrypt = options?.encrypt !== false\n const uploadResult = await this.uploadData(\n this.normalizePayload(data),\n { ...options?.uploadOptions, encrypt },\n requestOptions,\n )\n const cleanRef = uploadResult.reference.startsWith(\"0x\")\n ? uploadResult.reference.slice(2)\n : uploadResult.reference\n const derivedKey =\n cleanRef.length === 128 ? cleanRef.slice(64) : undefined\n const feedKey = options?.encryptionKey ?? derivedKey\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n EpochFeedUploadReferenceResponseMessage,\n EpochFeedUploadReferenceMessage\n >({\n type: \"epochFeedUploadReference\",\n requestId,\n topic,\n signer: signerKey,\n at: this.normalizeFeedTimestamp(atValue),\n reference: uploadResult.reference,\n encryptionKey:\n feedKey !== undefined ? this.normalizeSocKey(feedKey) : undefined,\n hints: options?.hints,\n requestOptions,\n })\n const socAddress = response.socAddress\n const encryptionKey = derivedKey\n return {\n socAddress,\n reference: uploadResult.reference,\n encryptionKey,\n epoch: response.epoch,\n timestamp: response.timestamp,\n }\n }\n\n const downloadRawReference = async (\n options?: Omit<EpochFeedDownloadOptions, \"encryptionKey\">,\n ): Promise<EpochFeedDownloadReferenceResult> => {\n const atValue =\n options?.at !== undefined\n ? options.at\n : BigInt(Math.floor(Date.now() / 1000))\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n EpochFeedDownloadReferenceResponseMessage,\n EpochFeedDownloadReferenceMessage\n >({\n type: \"epochFeedDownloadReference\",\n requestId,\n topic,\n owner,\n at: this.normalizeFeedTimestamp(atValue),\n after:\n options?.after !== undefined\n ? this.normalizeFeedTimestamp(options.after)\n : undefined,\n encryptionKey: undefined, // No encryption for raw download\n requestOptions,\n })\n const reference = response.reference\n return { reference, encryptionKey: undefined }\n }\n\n const downloadRawPayload = async (\n options?: Omit<EpochFeedDownloadOptions, \"encryptionKey\">,\n ): Promise<EpochFeedDownloadPayloadResult> => {\n const result = await downloadRawReference(options)\n if (!result.reference) {\n return {\n reference: undefined,\n payload: undefined,\n encryptionKey: undefined,\n }\n }\n const payload = await this.downloadData(\n result.reference,\n undefined,\n requestOptions,\n )\n return {\n reference: result.reference,\n payload,\n encryptionKey: undefined,\n }\n }\n\n const uploadRawReference = async (\n reference: Uint8Array | string,\n options?: Omit<EpochFeedUploadOptions, \"encryptionKey\">,\n ): Promise<EpochFeedUploadResult> => {\n const atValue =\n options?.at !== undefined\n ? options.at\n : BigInt(Math.floor(Date.now() / 1000))\n const normalizedRef = this.normalizeReference(reference)\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n EpochFeedUploadReferenceResponseMessage,\n EpochFeedUploadReferenceMessage\n >({\n type: \"epochFeedUploadReference\",\n requestId,\n topic,\n signer: signerKey,\n at: this.normalizeFeedTimestamp(atValue),\n reference: normalizedRef,\n encryptionKey: undefined, // No encryption for raw upload\n hints: options?.hints,\n requestOptions,\n })\n const socAddress = response.socAddress\n return {\n socAddress,\n reference: normalizedRef,\n encryptionKey: undefined,\n epoch: response.epoch,\n timestamp: response.timestamp,\n }\n }\n\n const uploadRawPayload = async (\n data: Uint8Array | string,\n options?: Omit<EpochFeedUploadOptions, \"encryptionKey\" | \"encrypt\">,\n ): Promise<EpochFeedUploadResult> => {\n const atValue =\n options?.at !== undefined\n ? options.at\n : BigInt(Math.floor(Date.now() / 1000))\n // Upload with encrypt: false for raw payload\n const uploadResult = await this.uploadData(\n this.normalizePayload(data),\n { ...options?.uploadOptions, encrypt: false },\n requestOptions,\n )\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n EpochFeedUploadReferenceResponseMessage,\n EpochFeedUploadReferenceMessage\n >({\n type: \"epochFeedUploadReference\",\n requestId,\n topic,\n signer: signerKey,\n at: this.normalizeFeedTimestamp(atValue),\n reference: uploadResult.reference,\n encryptionKey: undefined, // No encryption for raw upload\n hints: options?.hints,\n requestOptions,\n })\n const socAddress = response.socAddress\n return {\n socAddress,\n reference: uploadResult.reference,\n encryptionKey: undefined,\n epoch: response.epoch,\n timestamp: response.timestamp,\n }\n }\n\n return {\n getOwner: resolveOwner,\n downloadReference,\n downloadPayload,\n downloadRawReference,\n downloadRawPayload,\n uploadReference,\n uploadPayload,\n uploadRawReference,\n uploadRawPayload,\n }\n }\n\n /**\n * Returns a sequential feed reader (chunk API only).\n *\n * @param options - Sequential feed reader options\n * @param options.topic - Feed topic (32 bytes)\n * @param options.owner - Optional feed owner address\n * @param requestOptions - Optional request configuration (timeout, headers, endlesslyRetry). `timeout` replaces the client default for this call's whole round trip, not only the Bee request\n * @returns SequentialFeedReader with payload/reference download helpers\n */\n makeSequentialFeedReader(\n options: SequentialFeedReaderOptions,\n requestOptions?: RequestOptions,\n ): SequentialFeedReader {\n this.ensureReady()\n const topic = this.normalizeFeedTopic(options.topic)\n let owner: string | undefined = options.owner\n ? new EthAddress(options.owner).toHex()\n : undefined\n\n const resolveOwner = async (): Promise<string> => {\n if (owner) {\n return owner\n }\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n SequentialFeedGetOwnerResponseMessage,\n SequentialFeedGetOwnerMessage\n >({\n type: \"seqFeedGetOwner\",\n requestId,\n })\n owner = response.owner\n return owner\n }\n\n const downloadPayload = async (\n encryptionKey: Uint8Array | string,\n options?: SequentialFeedUpdateOptions,\n ): Promise<SequentialFeedPayloadResult> => {\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n SequentialFeedDownloadPayloadResponseMessage,\n SequentialFeedDownloadPayloadMessage\n >({\n type: \"seqFeedDownloadPayload\",\n requestId,\n topic,\n owner,\n index:\n options?.index !== undefined\n ? this.normalizeFeedIndex(options.index as bigint | number | string)\n : undefined,\n at:\n options?.at !== undefined\n ? this.normalizeFeedTimestamp(\n options.at as bigint | number | string,\n )\n : undefined,\n hasTimestamp: options?.hasTimestamp,\n lookupTimeoutMs: options?.lookupTimeoutMs,\n encryptionKey: this.normalizeSocKey(encryptionKey),\n requestOptions,\n })\n\n return {\n payload: response.payload,\n timestamp: response.timestamp,\n feedIndex: response.feedIndex,\n feedIndexNext: response.feedIndexNext,\n }\n }\n\n const downloadRawPayload = async (\n options?: SequentialFeedDownloadRawOptions,\n ): Promise<SequentialFeedPayloadResult> => {\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n SequentialFeedDownloadRawPayloadResponseMessage,\n SequentialFeedDownloadRawPayloadMessage\n >({\n type: \"seqFeedDownloadRawPayload\",\n requestId,\n topic,\n owner,\n index:\n options?.index !== undefined\n ? this.normalizeFeedIndex(options.index as bigint | number | string)\n : undefined,\n at:\n options?.at !== undefined\n ? this.normalizeFeedTimestamp(\n options.at as bigint | number | string,\n )\n : undefined,\n hasTimestamp: options?.hasTimestamp,\n lookupTimeoutMs: options?.lookupTimeoutMs,\n encryptionKey: options?.encryptionKey\n ? this.normalizeSocKey(options.encryptionKey)\n : undefined,\n requestOptions,\n })\n\n return {\n payload: response.payload,\n timestamp: response.timestamp,\n feedIndex: response.feedIndex,\n feedIndexNext: response.feedIndexNext,\n }\n }\n\n const downloadReference = async (\n encryptionKey: Uint8Array | string,\n options?: SequentialFeedUpdateOptions,\n ): Promise<SequentialFeedReferenceResult> => {\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n SequentialFeedDownloadReferenceResponseMessage,\n SequentialFeedDownloadReferenceMessage\n >({\n type: \"seqFeedDownloadReference\",\n requestId,\n topic,\n owner,\n index:\n options?.index !== undefined\n ? this.normalizeFeedIndex(options.index as bigint | number | string)\n : undefined,\n at:\n options?.at !== undefined\n ? this.normalizeFeedTimestamp(\n options.at as bigint | number | string,\n )\n : undefined,\n hasTimestamp: options?.hasTimestamp,\n lookupTimeoutMs: options?.lookupTimeoutMs,\n encryptionKey: this.normalizeSocKey(encryptionKey),\n requestOptions,\n })\n\n return {\n reference: response.reference,\n feedIndex: response.feedIndex,\n feedIndexNext: response.feedIndexNext,\n }\n }\n\n return {\n getOwner: resolveOwner,\n downloadPayload,\n downloadRawPayload,\n downloadReference,\n }\n }\n\n /**\n * Returns a sequential feed writer (chunk API only).\n *\n * @param options - Sequential feed writer options\n * @param options.topic - Feed topic (32 bytes)\n * @param options.signer - Optional signer private key. If omitted, proxy uses app signer.\n * @param requestOptions - Optional request configuration (timeout, headers, endlesslyRetry). `timeout` replaces the client default for this call's whole round trip, not only the Bee request\n * @returns SequentialFeedWriter with payload/reference upload helpers\n */\n makeSequentialFeedWriter(\n options: SequentialFeedWriterOptions,\n requestOptions?: RequestOptions,\n ): SequentialFeedWriter {\n this.ensureReady()\n const topic = this.normalizeFeedTopic(options.topic)\n const signerObj = options.signer\n ? new PrivateKey(options.signer)\n : undefined\n const signerKey = signerObj ? signerObj.toHex() : undefined\n let owner: string | undefined = signerObj\n ? signerObj.publicKey().address().toHex()\n : undefined\n\n const resolveOwner = async (): Promise<string> => {\n if (owner) {\n return owner\n }\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n SequentialFeedGetOwnerResponseMessage,\n SequentialFeedGetOwnerMessage\n >({\n type: \"seqFeedGetOwner\",\n requestId,\n })\n owner = response.owner\n return owner\n }\n\n const downloadPayload = async (\n encryptionKey: Uint8Array | string,\n options?: SequentialFeedUpdateOptions,\n ): Promise<SequentialFeedPayloadResult> => {\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n SequentialFeedDownloadPayloadResponseMessage,\n SequentialFeedDownloadPayloadMessage\n >({\n type: \"seqFeedDownloadPayload\",\n requestId,\n topic,\n owner,\n index:\n options?.index !== undefined\n ? this.normalizeFeedIndex(options.index as bigint | number | string)\n : undefined,\n at:\n options?.at !== undefined\n ? this.normalizeFeedTimestamp(\n options.at as bigint | number | string,\n )\n : undefined,\n hasTimestamp: options?.hasTimestamp,\n encryptionKey: this.normalizeSocKey(encryptionKey),\n requestOptions,\n })\n\n return {\n payload: response.payload,\n timestamp: response.timestamp,\n feedIndex: response.feedIndex,\n feedIndexNext: response.feedIndexNext,\n }\n }\n\n const downloadRawPayload = async (\n options?: SequentialFeedDownloadRawOptions,\n ): Promise<SequentialFeedPayloadResult> => {\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n SequentialFeedDownloadRawPayloadResponseMessage,\n SequentialFeedDownloadRawPayloadMessage\n >({\n type: \"seqFeedDownloadRawPayload\",\n requestId,\n topic,\n owner,\n index:\n options?.index !== undefined\n ? this.normalizeFeedIndex(options.index as bigint | number | string)\n : undefined,\n at:\n options?.at !== undefined\n ? this.normalizeFeedTimestamp(\n options.at as bigint | number | string,\n )\n : undefined,\n hasTimestamp: options?.hasTimestamp,\n encryptionKey: options?.encryptionKey\n ? this.normalizeSocKey(options.encryptionKey)\n : undefined,\n requestOptions,\n })\n\n return {\n payload: response.payload,\n timestamp: response.timestamp,\n feedIndex: response.feedIndex,\n feedIndexNext: response.feedIndexNext,\n }\n }\n\n const downloadReference = async (\n encryptionKey: Uint8Array | string,\n options?: SequentialFeedUpdateOptions,\n ): Promise<SequentialFeedReferenceResult> => {\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n SequentialFeedDownloadReferenceResponseMessage,\n SequentialFeedDownloadReferenceMessage\n >({\n type: \"seqFeedDownloadReference\",\n requestId,\n topic,\n owner,\n index:\n options?.index !== undefined\n ? this.normalizeFeedIndex(options.index as bigint | number | string)\n : undefined,\n at:\n options?.at !== undefined\n ? this.normalizeFeedTimestamp(\n options.at as bigint | number | string,\n )\n : undefined,\n hasTimestamp: options?.hasTimestamp,\n encryptionKey: this.normalizeSocKey(encryptionKey),\n requestOptions,\n })\n\n return {\n reference: response.reference,\n feedIndex: response.feedIndex,\n feedIndexNext: response.feedIndexNext,\n }\n }\n\n const uploadPayload = async (\n data: Uint8Array | string,\n options?: SequentialFeedUploadOptions,\n ): Promise<SequentialFeedUploadResult> => {\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n SequentialFeedUploadPayloadResponseMessage,\n SequentialFeedUploadPayloadMessage\n >({\n type: \"seqFeedUploadPayload\",\n requestId,\n topic,\n signer: signerKey,\n data: this.normalizePayload(data),\n index:\n options?.index !== undefined\n ? this.normalizeFeedIndex(options.index as bigint | number | string)\n : undefined,\n at:\n options?.at !== undefined\n ? this.normalizeFeedTimestamp(\n options.at as bigint | number | string,\n )\n : undefined,\n hasTimestamp: options?.hasTimestamp,\n lookupTimeoutMs: options?.lookupTimeoutMs,\n options,\n requestOptions,\n })\n\n owner = response.owner\n\n return {\n reference: response.reference,\n feedIndex: response.feedIndex,\n owner: response.owner,\n encryptionKey: response.encryptionKey,\n tagUid: response.tagUid,\n }\n }\n\n const uploadRawPayload = async (\n data: Uint8Array | string,\n options?: SequentialFeedUploadRawOptions,\n ): Promise<SequentialFeedUploadResult> => {\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n SequentialFeedUploadRawPayloadResponseMessage,\n SequentialFeedUploadRawPayloadMessage\n >({\n type: \"seqFeedUploadRawPayload\",\n requestId,\n topic,\n signer: signerKey,\n data: this.normalizePayload(data),\n index:\n options?.index !== undefined\n ? this.normalizeFeedIndex(options.index as bigint | number | string)\n : undefined,\n at:\n options?.at !== undefined\n ? this.normalizeFeedTimestamp(\n options.at as bigint | number | string,\n )\n : undefined,\n hasTimestamp: options?.hasTimestamp,\n lookupTimeoutMs: options?.lookupTimeoutMs,\n encryptionKey: options?.encryptionKey\n ? this.normalizeSocKey(options.encryptionKey)\n : undefined,\n options,\n requestOptions,\n })\n\n owner = response.owner\n\n return {\n reference: response.reference,\n feedIndex: response.feedIndex,\n owner: response.owner,\n encryptionKey: response.encryptionKey,\n tagUid: response.tagUid,\n }\n }\n\n const uploadReference = async (\n reference: Uint8Array | string,\n options?: SequentialFeedUploadOptions,\n ): Promise<SequentialFeedUploadResult> => {\n const requestId = this.generateRequestId()\n const response = await this.sendRequest<\n SequentialFeedUploadReferenceResponseMessage,\n SequentialFeedUploadReferenceMessage\n >({\n type: \"seqFeedUploadReference\",\n requestId,\n topic,\n signer: signerKey,\n reference: this.normalizeReference(reference),\n index:\n options?.index !== undefined\n ? this.normalizeFeedIndex(options.index as bigint | number | string)\n : undefined,\n at:\n options?.at !== undefined\n ? this.normalizeFeedTimestamp(\n options.at as bigint | number | string,\n )\n : undefined,\n hasTimestamp: options?.hasTimestamp,\n lookupTimeoutMs: options?.lookupTimeoutMs,\n options,\n requestOptions,\n })\n\n owner = response.owner\n\n return {\n reference: response.reference,\n feedIndex: response.feedIndex,\n owner: response.owner,\n encryptionKey: response.encryptionKey,\n tagUid: response.tagUid,\n }\n }\n\n return {\n getOwner: resolveOwner,\n downloadPayload,\n downloadRawPayload,\n downloadReference,\n uploadPayload,\n uploadRawPayload,\n uploadReference,\n }\n }\n\n // ============================================================================\n // Feed Manifest Methods\n // ============================================================================\n\n /**\n * Creates a feed manifest for accessing feed content via URL.\n *\n * A feed manifest enables accessing the latest feed content via a URL path\n * (e.g., `/bzz/{manifest-reference}/`). The manifest stores metadata about\n * the feed including owner, topic, and type.\n *\n * @param topic - Feed topic (32-byte hex string)\n * @param options - Optional configuration\n * @param options.owner - Feed owner address; if omitted, uses app signer\n * @param options.uploadOptions - Upload configuration (pin, deferred, etc.)\n * @param requestOptions - Request configuration (timeout, headers). `timeout` replaces the client default for this call's whole round trip, not only the Bee request\n * @returns Promise resolving to the manifest reference\n * @throws {Error} If the client is not initialized\n * @throws {Error} If no owner is provided and no app signer is available\n * @throws {Error} If the request times out\n *\n * @example\n * ```typescript\n * // Create manifest for a feed (uses app signer as owner)\n * const manifestRef = await client.createFeedManifest(topic)\n * console.log('Feed accessible at /bzz/' + manifestRef)\n *\n * // Create manifest with explicit owner\n * const manifestRef = await client.createFeedManifest(topic, {\n * owner: '0x1234...',\n * })\n * ```\n */\n async createFeedManifest(\n topic: string,\n options?: {\n owner?: string\n /** Feed type: \"Sequence\" for sequential feeds, \"Epoch\" for epoch feeds. Default: \"Sequence\" */\n feedType?: \"Sequence\" | \"Epoch\"\n uploadOptions?: UploadOptions\n },\n requestOptions?: RequestOptions,\n ): Promise<string> {\n this.ensureReady()\n const normalizedTopic = this.normalizeFeedTopic(topic)\n const requestId = this.generateRequestId()\n\n const response = await this.sendRequest<\n CreateFeedManifestResponseMessage,\n CreateFeedManifestMessage\n >({\n type: \"createFeedManifest\",\n requestId,\n topic: normalizedTopic,\n owner: options?.owner,\n feedType: options?.feedType,\n uploadOptions: options?.uploadOptions,\n requestOptions,\n })\n\n return response.reference\n }\n\n // ============================================================================\n // GSOC Methods\n // ============================================================================\n\n /**\n * Mines a private key whose SOC address is proximate to a target overlay.\n *\n * This is a synchronous, pure computation that does not require authentication.\n * The mined signer can be used with {@link gsocSend} to send GSOC messages\n * that route to the target overlay node.\n *\n * @param targetOverlay - The target overlay address to mine proximity for\n * @param identifier - The GSOC identifier\n * @param proximity - Optional proximity depth (defaults to 12 in bee-js)\n * @returns A promise resolving to the mined signer as a hex string (private key)\n * @throws {Error} If the client is not initialized\n * @throws {Error} If no valid signer can be mined\n * @throws {Error} If the request times out\n *\n * @example\n * ```typescript\n * const signer = await client.gsocMine(targetOverlay, identifier)\n * // Use signer with gsocSend\n * await client.gsocSend(signer, identifier, data)\n * ```\n */\n async gsocMine(\n targetOverlay: string,\n identifier: string,\n proximity?: number,\n ): Promise<string> {\n this.ensureReady()\n const requestId = this.generateRequestId()\n\n const response = await this.sendRequest<{\n type: \"gsocMineResponse\"\n requestId: string\n signer: string\n }>({\n type: \"gsocMine\",\n requestId,\n targetOverlay,\n identifier,\n proximity,\n })\n\n return response.signer\n }\n\n /**\n * Sends a GSOC (Global Single Owner Chunk) message using a mined signer.\n *\n * The signer should be obtained from {@link gsocMine}. The message is sent\n * using the proxy's stored postage batch ID.\n *\n * @param signer - The mined signer as a hex string (from gsocMine)\n * @param identifier - The GSOC identifier\n * @param data - The message data to send\n * @param options - Optional upload configuration\n * @param requestOptions - Optional request configuration (timeout, headers, endlesslyRetry). `timeout` replaces the client default for this call's whole round trip, not only the Bee request\n * @returns A promise resolving to the upload result with reference and optional tagUid\n * @throws {Error} If the client is not initialized\n * @throws {Error} If the user is not authenticated\n * @throws {Error} If no postage batch ID is available\n * @throws {Error} If the request times out\n *\n * @example\n * ```typescript\n * const signer = await client.gsocMine(targetOverlay, identifier)\n * const result = await client.gsocSend(signer, identifier, new TextEncoder().encode('Hello!'))\n * console.log('GSOC reference:', result.reference)\n * ```\n */\n async gsocSend(\n signer: string,\n identifier: string,\n data: Uint8Array,\n options?: UploadOptions,\n requestOptions?: RequestOptions,\n ): Promise<UploadResult> {\n this.ensureReady()\n const requestId = this.generateRequestId()\n\n const response = await this.sendRequest<{\n type: \"gsocSendResponse\"\n requestId: string\n reference: Reference\n tagUid?: number\n }>({\n type: \"gsocSend\",\n requestId,\n signer,\n identifier,\n data: new Uint8Array(data),\n options,\n requestOptions,\n })\n\n return {\n reference: response.reference,\n tagUid: response.tagUid,\n }\n }\n\n // ============================================================================\n // ACT (Access Control Tries) Methods\n // ============================================================================\n\n /**\n * Uploads data with ACT (Access Control Tries) protection.\n *\n * This method encrypts the data and creates an ACT that controls who can decrypt it.\n * Only the specified grantees (and the publisher) can decrypt and access the data.\n *\n * @param data - The binary data to upload as a Uint8Array\n * @param grantees - Array of grantee public keys as compressed hex strings (33 bytes = 66 hex chars).\n * A grantee is either another user's `appKey.publicKey` (that user in this app origin only) or\n * their `identity.sharingPublicKey` (that user in every app they connect, #519)\n * @param options - Optional upload configuration\n * @param options.publisher - `\"app\"` (default) publishes with this origin's app key; `\"identity\"`\n * publishes with the account-wide sharing key, so any of the user's apps can manage the grantees later\n * @param options.pin - Whether to pin the data locally (defaults to false; ignored on a subsidised gateway)\n * @param options.tag - Tag ID for tracking upload progress\n * @param options.deferred - Whether to use deferred upload (defaults to false)\n * @param options.onProgress - Optional callback for tracking upload progress\n * @param requestOptions - Optional request configuration (timeout, headers, endlesslyRetry). `timeout` replaces the client default for this call's whole round trip, not only the Bee request\n * @returns A promise resolving to the ACT upload result\n * @returns return.encryptedReference - The encrypted reference that must be stored with the ACT\n * @returns return.actReference - The Swarm reference (hash) of the ACT manifest\n * @returns return.historyReference - The Swarm reference of the history manifest (use for future operations)\n * @returns return.granteeListReference - The Swarm reference of the encrypted grantee list\n * @returns return.publisherPubKey - The publisher's compressed public key (share with grantees)\n * @returns return.tagUid - The tag UID if a tag was created\n * @throws {Error} If the client is not initialized\n * @throws {Error} If the user is not authenticated or cannot upload\n * @throws {Error} If the request times out\n *\n * @example\n * ```typescript\n * const data = new TextEncoder().encode('Secret message')\n * const grantees = ['03a1b2c3...'] // Compressed public keys of allowed readers\n * const result = await client.actUploadData(data, grantees, {\n * onProgress: (progress) => {\n * console.log(`Progress: ${progress.processed}/${progress.total}`)\n * },\n * })\n * console.log('History Reference:', result.historyReference)\n * console.log('Encrypted Reference:', result.encryptedReference)\n * console.log('Publisher Public Key:', result.publisherPubKey)\n * ```\n */\n async actUploadData(\n data: Uint8Array,\n grantees: string[],\n options?: ActUploadOptions,\n requestOptions?: RequestOptions,\n ): Promise<{\n encryptedReference: string\n historyReference: string\n granteeListReference: string\n publisherPubKey: string\n actReference: string\n tagUid?: number\n }> {\n this.ensureReady()\n const requestId = this.generateRequestId()\n const { onProgress, ...serializableOptions } = options ?? {}\n\n const stopProgress = this.listenForProgress(requestId, onProgress)\n try {\n const response = await this.sendRequest<{\n type: \"actUploadDataResponse\"\n requestId: string\n encryptedReference: string\n historyReference: string\n granteeListReference: string\n publisherPubKey: string\n actReference: string\n tagUid?: number\n }>({\n type: \"actUploadData\",\n requestId,\n data: new Uint8Array(data),\n grantees,\n options: serializableOptions,\n requestOptions,\n enableProgress: !!onProgress,\n })\n\n return {\n encryptedReference: response.encryptedReference,\n historyReference: response.historyReference,\n granteeListReference: response.granteeListReference,\n publisherPubKey: response.publisherPubKey,\n actReference: response.actReference,\n tagUid: response.tagUid,\n }\n } finally {\n stopProgress()\n }\n }\n\n /**\n * Downloads ACT-protected data from the Swarm network.\n *\n * This method decrypts the ACT to recover the content reference,\n * then downloads and returns the decrypted data. Only authorized\n * grantees (including the publisher) can successfully decrypt.\n *\n * @param encryptedReference - The encrypted reference from actUploadData\n * @param historyReference - The history reference from actUploadData\n * @param publisherPubKey - The publisher's compressed public key from actUploadData\n * @param timestamp - Optional timestamp to look up a specific ACT version\n * @param requestOptions - Optional request configuration (timeout, headers, endlesslyRetry). `timeout` replaces the client default for this call's whole round trip, not only the Bee request\n * @returns A promise resolving to the decrypted data as a Uint8Array\n * @throws {Error} If the client is not initialized\n * @throws {Error} If the user is not authorized to decrypt the ACT\n * @throws {Error} If the references are not found\n * @throws {Error} If the request times out\n *\n * @example\n * ```typescript\n * // Using the references from actUploadData\n * const data = await client.actDownloadData(\n * encryptedReference,\n * historyReference,\n * publisherPubKey\n * )\n * const text = new TextDecoder().decode(data)\n * console.log('Decrypted:', text)\n * ```\n */\n async actDownloadData(\n encryptedReference: string,\n historyReference: string,\n publisherPubKey: string,\n timestamp?: number,\n requestOptions?: RequestOptions,\n ): Promise<Uint8Array> {\n this.ensureReady()\n const requestId = this.generateRequestId()\n\n const response = await this.sendRequest<{\n type: \"actDownloadDataResponse\"\n requestId: string\n data: Uint8Array\n }>({\n type: \"actDownloadData\",\n requestId,\n encryptedReference,\n historyReference,\n publisherPubKey,\n timestamp,\n requestOptions,\n })\n\n return response.data\n }\n\n /**\n * Adds new grantees to an existing ACT.\n *\n * This method adds new public keys to the ACT's access list.\n * Only the publisher (original uploader) can add grantees.\n * Returns new references since Swarm content is immutable.\n *\n * @param historyReference - The current history reference\n * @param grantees - Array of new grantee public keys as compressed hex strings\n * @param requestOptions - Optional request configuration (timeout, headers, endlesslyRetry). `timeout` replaces the client default for this call's whole round trip, not only the Bee request\n * @returns A promise resolving to the new references\n * @returns return.historyReference - The new history reference after adding grantees\n * @returns return.granteeListReference - The new grantee list reference\n * @returns return.actReference - The new ACT reference\n * @throws {Error} If the client is not initialized\n * @throws {Error} If the user is not the publisher\n * @throws {Error} If the request times out\n *\n * @example\n * ```typescript\n * const newGrantees = ['03d4e5f6...'] // New public keys to grant access\n * const result = await client.actAddGrantees(historyReference, newGrantees)\n * console.log('New History Reference:', result.historyReference)\n * // The encrypted reference remains the same\n * ```\n */\n async actAddGrantees(\n historyReference: string,\n grantees: string[],\n requestOptions?: RequestOptions,\n ): Promise<{\n historyReference: string\n granteeListReference: string\n actReference: string\n }> {\n this.ensureReady()\n const requestId = this.generateRequestId()\n\n const response = await this.sendRequest<{\n type: \"actAddGranteesResponse\"\n requestId: string\n historyReference: string\n granteeListReference: string\n actReference: string\n }>({\n type: \"actAddGrantees\",\n requestId,\n historyReference,\n grantees,\n requestOptions,\n })\n\n return {\n historyReference: response.historyReference,\n granteeListReference: response.granteeListReference,\n actReference: response.actReference,\n }\n }\n\n /**\n * Revokes grantees from an existing ACT.\n *\n * This method removes public keys from the ACT's access list, producing a new\n * ACT/history without the revoked entries.\n *\n * IMPORTANT: Revocation cannot un-share already-published content. A former\n * grantee kept the access key while granted and the reference lives in\n * immutable history, so they can still decrypt content published before\n * revocation. Revocation only stops access to content published afterwards.\n * The returned `encryptedReference` is unchanged — it is NOT re-encrypted, as\n * that would leak the keystream to former grantees (#496).\n *\n * @param historyReference - The current history reference\n * @param encryptedReference - The current encrypted reference\n * @param revokeGrantees - Array of grantee public keys to revoke as compressed hex strings\n * @param requestOptions - Optional request configuration (timeout, headers, endlesslyRetry). `timeout` replaces the client default for this call's whole round trip, not only the Bee request\n * @returns A promise resolving to the new references after revocation\n * @returns return.encryptedReference - The content reference, unchanged\n * @returns return.historyReference - The new history reference after revocation\n * @returns return.granteeListReference - The new grantee list reference\n * @returns return.actReference - The new ACT reference after revocation\n * @throws {Error} If the client is not initialized\n * @throws {Error} If the user is not the publisher\n * @throws {Error} If the request times out\n *\n * @example\n * ```typescript\n * const revokeKeys = ['03a1b2c3...'] // Public keys to revoke\n * const result = await client.actRevokeGrantees(historyReference, encryptedReference, revokeKeys)\n * console.log('New History Reference:', result.historyReference)\n * // encryptedReference is unchanged; historyReference/actReference are new\n * ```\n */\n async actRevokeGrantees(\n historyReference: string,\n encryptedReference: string,\n revokeGrantees: string[],\n requestOptions?: RequestOptions,\n ): Promise<{\n encryptedReference: string\n historyReference: string\n granteeListReference: string\n actReference: string\n }> {\n this.ensureReady()\n const requestId = this.generateRequestId()\n\n const response = await this.sendRequest<{\n type: \"actRevokeGranteesResponse\"\n requestId: string\n encryptedReference: string\n historyReference: string\n granteeListReference: string\n actReference: string\n }>({\n type: \"actRevokeGrantees\",\n requestId,\n historyReference,\n encryptedReference,\n revokeGrantees,\n requestOptions,\n })\n\n return {\n encryptedReference: response.encryptedReference,\n historyReference: response.historyReference,\n granteeListReference: response.granteeListReference,\n actReference: response.actReference,\n }\n }\n\n /**\n * Retrieves the list of grantees from an ACT.\n *\n * Only the publisher (original uploader) can view the grantee list,\n * as it is encrypted with the publisher's key.\n *\n * @param historyReference - The history reference\n * @param requestOptions - Optional request configuration (timeout, headers, endlesslyRetry). `timeout` replaces the client default for this call's whole round trip, not only the Bee request\n * @returns A promise resolving to an array of grantee public keys as compressed hex strings\n * @throws {Error} If the client is not initialized\n * @throws {Error} If the user is not the publisher\n * @throws {Error} If the request times out\n *\n * @example\n * ```typescript\n * const grantees = await client.actGetGrantees(historyReference)\n * console.log('Current grantees:', grantees.length)\n * grantees.forEach(pubKey => console.log(' -', pubKey))\n * ```\n */\n async actGetGrantees(\n historyReference: string,\n requestOptions?: RequestOptions,\n ): Promise<string[]> {\n this.ensureReady()\n const requestId = this.generateRequestId()\n\n const response = await this.sendRequest<{\n type: \"actGetGranteesResponse\"\n requestId: string\n grantees: string[]\n }>({\n type: \"actGetGrantees\",\n requestId,\n historyReference,\n requestOptions,\n })\n\n return response.grantees\n }\n\n // ============================================================================\n // Cleanup\n // ============================================================================\n\n /**\n * Destroys the client and releases all resources.\n *\n * This method should be called when the client is no longer needed.\n * It performs the following cleanup:\n * - Rejects every pending request, and a pending `initialize()`, with a\n * `SwarmIdError` of code `invalid-state`\n * - Removes the message event listener\n * - Removes the iframe from the DOM\n * - Resets the client to an uninitialized state\n *\n * After calling destroy(), the client instance cannot be reused.\n * Create a new instance if you need to reconnect.\n *\n * @example\n * ```typescript\n * // Clean up when component unmounts\n * useEffect(() => {\n * const client = new SwarmIdClient({ ... })\n * client.initialize()\n *\n * return () => {\n * client.destroy()\n * }\n * }, [])\n * ```\n */\n destroy(): void {\n const destroyed = () =>\n new SwarmIdError(\"invalid-state\", \"Client destroyed\")\n\n for (const remove of [...this.mountedButtons.values()]) remove()\n\n // Clear pending requests\n this.pendingRequests.forEach((pending) => {\n clearTimeout(pending.timeoutId)\n pending.reject(destroyed())\n })\n this.pendingRequests.clear()\n this.progressListeners.clear()\n\n // Remove message listener\n if (this.messageListener) {\n window.removeEventListener(\"message\", this.messageListener)\n this.messageListener = undefined\n }\n\n // Remove iframe\n if (this.iframe && this.iframe.parentNode) {\n this.iframe.parentNode.removeChild(this.iframe)\n this.iframe = undefined\n }\n\n // Reject every still-pending init wait. Whichever one `initialize()` is\n // awaiting rejects it, so a destroy mid-initialize settles it instead of\n // leaving it on an iframe that will never load or a proxy that is gone;\n // and the deadline-bound ones clear their `withTimeout` timers now\n // instead of lingering the full initializationTimeout. The\n // `.catch(() => {})` guards attached in initialize() keep these from\n // surfacing as unhandled when nothing is awaiting.\n this.iframeLoadReject?.(destroyed())\n this.proxyInitializedReject?.(destroyed())\n this.readyReject?.(destroyed())\n this.firstConnectionInfoReject?.(destroyed())\n this.iframeLoadReject = undefined\n this.readyResolve = undefined\n this.readyReject = undefined\n this.proxyInitializedResolve = undefined\n this.proxyInitializedReject = undefined\n this.firstConnectionInfoResolve = undefined\n this.firstConnectionInfoReject = undefined\n this.readyPromise = undefined\n this.proxyInitializedPromise = undefined\n this.firstConnectionInfoPromise = undefined\n\n this.ready = false\n }\n}\n","// Copyright 2026 The Swarm Authors. All rights reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { Reference, NULL_ADDRESS } from \"@ethersphere/bee-js\"\nimport { MantarayNode } from \"@ethersphere/core-sdk\"\nimport { makeContentAddressedChunk } from \"../chunk\"\nimport { hexToUint8Array } from \"../utils/hex\"\n\n/**\n * Mantaray v0.2 version hash (31 bytes).\n * From bee-js: the first 31 bytes of keccak256(\"mantaray:0.2\")\n */\nconst MANTARAY_VERSION_HASH = new Uint8Array([\n 0x57, 0x68, 0xb3, 0xb6, 0xa7, 0xdb, 0x56, 0xd2, 0x1d, 0x1a, 0xbf, 0xf4, 0x0d,\n 0x41, 0xce, 0xbf, 0xc8, 0x34, 0x48, 0xfe, 0xd8, 0xd7, 0xe9, 0xb0, 0x6e, 0xc0,\n 0xd3, 0xb0, 0x73, 0xf2, 0x8f,\n])\n\n/**\n * Fork flags for Mantaray format.\n */\nconst FORK_FLAG_VALUE_TYPE = 0x02 // TYPE_VALUE: has targetAddress (matches bee-js)\nconst FORK_FLAG_HAS_METADATA = 0x10 // TYPE_WITH_METADATA: has metadata bytes (matches bee-js)\n\n/**\n * Result of building a /bzz/-compatible manifest.\n *\n * This is a FLAT manifest with no child nodes - just the root manifest.\n * Bee's /bzz/ endpoint can directly resolve paths from this structure.\n *\n * IMPORTANT: The `data` field contains RAW manifest bytes (without span prefix).\n * When uploaded via `uploadData()`, span will be added and the resulting address\n * will match the pre-computed `address` field.\n */\nexport interface BzzCompatibleManifestResult {\n /** The manifest chunk to upload. Raw bytes, no span. */\n manifestChunk: {\n data: Uint8Array\n address: string\n }\n}\n\n/**\n * Build a /bzz/-compatible flat manifest with VALUE forks.\n *\n * Creates a flat manifest with two VALUE forks at root level:\n * - \"/\" → VALUE fork with website-index-document metadata pointing to NULL\n * - \"index.bin\" → VALUE fork pointing directly to content reference\n *\n * This is built manually because bee-js MantarayNode always creates EDGE forks\n * with child nodes, which causes Bee to fail to resolve the content.\n *\n * When Bee accesses /bzz/manifest/:\n * 1. Finds \"/\" fork, reads website-index-document metadata\n * 2. Looks up \"index.bin\" fork at root level\n * 3. \"index.bin\" is VALUE type → serves content directly\n *\n * Binary format (Mantaray v0.2):\n * - obfuscationKey (32 bytes): All zeros for no obfuscation\n * - versionHash (31 bytes): MANTARAY_VERSION_HASH\n * - refBytesCount (1 byte): 32\n * - entry (32 bytes): All zeros (root has no entry)\n * - indexBitmap (32 bytes): Bits set for '/' (47) and 'i' (105)\n * - fork1 (64+ bytes): \"/\" fork with metadata\n * - fork2 (64+ bytes): \"index.bin\" fork with metadata\n *\n * @param contentReference - Reference to the actual content (32 bytes / 64 hex chars)\n * @returns Single manifest chunk to upload\n */\nexport async function buildBzzCompatibleManifest(\n contentReference: string | Uint8Array,\n): Promise<BzzCompatibleManifestResult> {\n const refBytes =\n contentReference instanceof Uint8Array\n ? contentReference\n : new Reference(contentReference).toUint8Array()\n\n if (refBytes.length !== 32) {\n throw new Error(\n `Invalid content reference length: ${refBytes.length} (expected 32 bytes)`,\n )\n }\n\n // Prepare metadata JSON for both forks\n const slashMetadata =\n JSON.stringify({ \"website-index-document\": \"index.bin\" }) + \"\\n\"\n const indexMetadata =\n JSON.stringify({\n \"Content-Type\": \"application/octet-stream\",\n Filename: \"index.bin\",\n }) + \"\\n\"\n\n const slashMetadataBytes = new TextEncoder().encode(slashMetadata)\n const indexMetadataBytes = new TextEncoder().encode(indexMetadata)\n\n // Calculate sizes\n // Header: 32 + 31 + 1 + 32 + 32 = 128 bytes\n // Fork \"/\" : flags(1) + prefixLen(1) + prefix(30) + reference(32) + metaLen(2) + meta\n // Fork \"index.bin\": flags(1) + prefixLen(1) + prefix(30) + reference(32) + metaLen(2) + meta\n const HEADER_SIZE = 128\n const FORK_BASE_SIZE = 66 // 1 + 1 + 30 + 32 + 2\n const TOTAL_SIZE =\n HEADER_SIZE +\n FORK_BASE_SIZE +\n slashMetadataBytes.length +\n FORK_BASE_SIZE +\n indexMetadataBytes.length\n\n const manifest = new Uint8Array(TOTAL_SIZE)\n let offset = 0\n\n // 1. Obfuscation key (32 bytes) - all zeros for no obfuscation\n offset += 32\n\n // 2. Version hash (31 bytes)\n manifest.set(MANTARAY_VERSION_HASH, offset)\n offset += 31\n\n // 3. refBytesCount (1 byte) - 32 for standard reference size\n manifest[offset] = 32\n offset += 1\n\n // 4. Entry (32 bytes) - all zeros for root node\n offset += 32\n\n // 5. Index bitmap (32 bytes)\n // Bit 47 set for '/' and bit 105 set for 'i' (start of \"index.bin\")\n // Byte 47/8 = 5, bit 47%8 = 7 → byte 5 = 0x80\n // Byte 105/8 = 13, bit 105%8 = 1 → byte 13 = 0x02\n manifest[offset + 5] = 0x80 // '/' at position 47\n manifest[offset + 13] = 0x02 // 'i' at position 105\n offset += 32\n\n // Forks are ordered by their first byte value\n // '/' = 47 comes before 'i' = 105\n\n // 6. Fork entry for '/' (first because 47 < 105)\n // Flags: TYPE_WITH_METADATA only (0x10) - NO VALUE since reference is NULL\n // The \"/\" fork is just a metadata carrier for website-index-document\n manifest[offset] = FORK_FLAG_HAS_METADATA\n offset += 1\n\n // Prefix length\n manifest[offset] = 1\n offset += 1\n\n // Prefix (30 bytes padded)\n manifest[offset] = 0x2f // '/'\n offset += 30\n\n // Reference (32 bytes) - NULL_ADDRESS (all zeros) because \"/\" just has metadata\n // Already zeros, just advance\n offset += 32\n\n // Metadata length (2 bytes big-endian)\n manifest[offset] = (slashMetadataBytes.length >> 8) & 0xff\n manifest[offset + 1] = slashMetadataBytes.length & 0xff\n offset += 2\n\n // Metadata content\n manifest.set(slashMetadataBytes, offset)\n offset += slashMetadataBytes.length\n\n // 7. Fork entry for 'index.bin'\n // Flags: TYPE_VALUE (0x02) + TYPE_WITH_METADATA (0x10) = 0x12\n manifest[offset] = FORK_FLAG_VALUE_TYPE | FORK_FLAG_HAS_METADATA\n offset += 1\n\n // Prefix length - \"index.bin\" = 9 characters\n manifest[offset] = 9\n offset += 1\n\n // Prefix (30 bytes padded)\n const indexBinBytes = new TextEncoder().encode(\"index.bin\")\n manifest.set(indexBinBytes, offset)\n offset += 30\n\n // Reference (32 bytes) - the actual content reference\n manifest.set(refBytes, offset)\n offset += 32\n\n // Metadata length (2 bytes big-endian)\n manifest[offset] = (indexMetadataBytes.length >> 8) & 0xff\n manifest[offset + 1] = indexMetadataBytes.length & 0xff\n offset += 2\n\n // Metadata content\n manifest.set(indexMetadataBytes, offset)\n offset += indexMetadataBytes.length\n\n // Calculate manifest address\n const rootChunk = makeContentAddressedChunk(manifest)\n\n return {\n manifestChunk: {\n data: manifest,\n address: rootChunk.address.toHex(),\n },\n }\n}\n\n/**\n * Result of building a /bzz/-compatible MantarayNode manifest.\n */\nexport interface BzzManifestNodeResult {\n /** The MantarayNode to be uploaded with saveMantarayTreeRecursively */\n manifestNode: MantarayNode\n}\n\n/**\n * Build a /bzz/-compatible manifest as a MantarayNode.\n *\n * This function creates a MantarayNode with the proper structure for /bzz/ access:\n * - \"/\" fork with website-index-document metadata pointing to \"index.bin\"\n * - \"index.bin\" fork pointing to the actual content reference\n *\n * IMPORTANT: After calling this function, use saveMantarayTreeRecursively() to\n * upload the manifest. This ensures all child nodes are uploaded bottom-up and\n * their addresses are correctly set from Bee's responses.\n *\n * Usage:\n * ```typescript\n * const { manifestNode } = buildBzzManifestNode(contentReference)\n * const result = await saveMantarayTreeRecursively(manifestNode, async (data, isRoot) => {\n * const uploadResult = await uploadData(bee, stamper, data, uploadOptions)\n * return { reference: uploadResult.reference }\n * })\n * // result.rootReference is the /bzz/ compatible manifest address\n * ```\n *\n * @param contentReference - Reference to the actual content (32 bytes / 64 hex chars)\n * @returns MantarayNode ready for upload with saveMantarayTreeRecursively\n */\nexport function buildBzzManifestNode(\n contentReference: string | Uint8Array,\n): BzzManifestNodeResult {\n const refBytes =\n contentReference instanceof Uint8Array\n ? contentReference\n : hexToUint8Array(contentReference)\n\n if (refBytes.length !== 32) {\n throw new Error(\n `Invalid content reference length: ${refBytes.length} (expected 32 bytes)`,\n )\n }\n\n const manifest = new MantarayNode()\n\n // Add \"/\" fork with website-index-document metadata\n // This tells Bee to look for \"index.bin\" when accessing the root path\n manifest.addFork(\"/\", NULL_ADDRESS, {\n \"website-index-document\": \"index.bin\",\n })\n\n // Add \"index.bin\" fork pointing to the actual content\n manifest.addFork(\"index.bin\", refBytes, {\n \"Content-Type\": \"application/octet-stream\",\n Filename: \"index.bin\",\n })\n\n return { manifestNode: manifest }\n}\n\n/**\n * @deprecated Use buildBzzManifestNode() with saveMantarayTreeRecursively() instead.\n * This function manually builds binary format but doesn't upload child nodes,\n * which causes Bee to fail to resolve content via /bzz/.\n */\n\n/**\n * @deprecated Use buildBzzCompatibleManifest() for /bzz/ compatibility.\n * This function creates a manifest that won't work with Bee's /bzz/ endpoint\n * because it embeds the content reference directly in the manifest instead\n * of using the proper two-level structure (root → child → content).\n *\n * Build a minimal mantaray manifest for /bzz/ feed compatibility.\n *\n * This creates a manifest with a single \"/\" fork pointing to a content reference.\n * The manifest is built manually (not using bee-js MantarayNode.marshal()) because\n * bee-js doesn't embed the targetAddress correctly for value-type nodes.\n *\n * Binary format (Mantaray v0.2):\n * - obfuscationKey (32 bytes): All zeros for no obfuscation\n * - versionHash (31 bytes): MANTARAY_VERSION_HASH\n * - refBytesCount (1 byte): 32 (size of entry reference)\n * - entry (32 bytes): All zeros (root has no entry)\n * - indexBitmap (32 bytes): Bitmap with bit 47 set (for '/')\n * - fork (64+ bytes): flags + prefixLen + prefix(30) + reference(32) + metadata\n *\n * @param contentReference - Reference to the actual content (32 bytes / 64 hex chars)\n * @returns Marshaled manifest bytes\n */\nexport function buildMinimalManifest(\n contentReference: string | Uint8Array,\n): Uint8Array {\n // Normalize reference to Uint8Array\n const refBytes =\n contentReference instanceof Uint8Array\n ? contentReference\n : new Reference(contentReference).toUint8Array()\n\n if (refBytes.length !== 32) {\n throw new Error(\n `Invalid content reference length: ${refBytes.length} (expected 32 bytes)`,\n )\n }\n\n // Calculate total size\n // Header: 32 + 31 + 1 + 32 + 32 = 128 bytes\n // Fork: 1 + 1 + 30 + 32 = 64 bytes (no metadata for simplicity)\n // Total: 192 bytes\n const HEADER_SIZE = 128\n const FORK_SIZE = 64\n const TOTAL_SIZE = HEADER_SIZE + FORK_SIZE\n\n const manifest = new Uint8Array(TOTAL_SIZE)\n let offset = 0\n\n // 1. Obfuscation key (32 bytes) - all zeros for no obfuscation\n offset += 32\n\n // 2. Version hash (31 bytes)\n manifest.set(MANTARAY_VERSION_HASH, offset)\n offset += 31\n\n // 3. refBytesCount (1 byte) - 32 for standard reference size\n manifest[offset] = 32\n offset += 1\n\n // 4. Entry (32 bytes) - all zeros for root node\n offset += 32\n\n // 5. Index bitmap (32 bytes) - bit 47 set for '/'\n // Byte index = 47 / 8 = 5, bit position = 47 % 8 = 7 (MSB)\n // So we set byte 5 to 0x80 (bit 7 set)\n manifest[offset + 5] = 0x80\n offset += 32\n\n // 6. Fork entry for '/'\n // Flags: VALUE_TYPE (reference is the target)\n manifest[offset] = FORK_FLAG_VALUE_TYPE\n offset += 1\n\n // Prefix length\n manifest[offset] = 1\n offset += 1\n\n // Prefix (30 bytes padded)\n manifest[offset] = 0x2f // '/'\n offset += 30\n\n // Reference (32 bytes) - the actual content reference\n manifest.set(refBytes, offset)\n offset += 32\n\n return manifest\n}\n\n/**\n * Extract content reference from a minimal mantaray manifest.\n *\n * This is the reverse of buildMinimalManifest() - it parses the manifest\n * binary format and extracts the \"/\" fork's targetAddress.\n *\n * Binary format (Mantaray v0.2):\n * - Offset 0-31: obfuscationKey\n * - Offset 32-62: versionHash (31 bytes)\n * - Offset 63: refBytesCount\n * - Offset 64-95: entry (refBytesCount bytes, assuming 32)\n * - Offset 96-127: indexBitmap\n * - Offset 128+: forks (flags + prefixLen + prefix + reference + metadata)\n *\n * For a minimal manifest with just \"/\" fork:\n * - Fork flags at offset 128\n * - Prefix length at offset 129\n * - Prefix (30 bytes) at offset 130\n * - Reference (32 bytes) at offset 160\n *\n * @param manifestData - Raw manifest bytes (from feed payload)\n * @returns Content reference as 64 hex characters\n */\nexport function extractReferenceFromManifest(manifestData: Uint8Array): string {\n // Minimum size check: header (128) + minimal fork (64)\n if (manifestData.length < 192) {\n throw new Error(\n `Manifest too small: ${manifestData.length} bytes (expected at least 192)`,\n )\n }\n\n // Header offsets (for reference)\n // Offset 0-31: obfuscationKey\n // Offset 32-62: versionHash (31 bytes)\n // Offset 63: refBytesCount\n // Offset 64-95: entry (refBytesCount bytes, assuming 32)\n // Offset 96-127: indexBitmap\n // Offset 128+: forks\n const REF_BYTES_COUNT_OFFSET = 63\n const INDEX_BITMAP_OFFSET = 96\n const FORKS_OFFSET = 128\n\n // Read refBytesCount to determine entry size\n const refBytesCount = manifestData[REF_BYTES_COUNT_OFFSET]\n if (refBytesCount !== 32) {\n console.warn(\n `[ManifestBuilder] Unexpected refBytesCount: ${refBytesCount} (expected 32)`,\n )\n }\n\n // Verify \"/\" fork exists in index bitmap\n // Byte 5, bit 7 should be set for '/' (byte value 47)\n // Bit ordering: value N is at byte N/8, bit N%8\n // So value 47 is at byte 5, bit 7 (mask 0x80)\n const indexBitmap = manifestData.slice(\n INDEX_BITMAP_OFFSET,\n INDEX_BITMAP_OFFSET + 32,\n )\n const slashByteIndex = Math.floor(47 / 8) // = 5\n const slashBitMask = 1 << (47 % 8) // = 0x80\n\n if ((indexBitmap[slashByteIndex] & slashBitMask) === 0) {\n throw new Error('Manifest does not contain \"/\" fork')\n }\n\n // Count forks before \"/\" to find its offset\n // We need to count all set bits for byte values less than 47\n let forkIndex = 0\n // Count all bits in bytes 0-4\n for (let byte = 0; byte < slashByteIndex; byte++) {\n forkIndex += popcount8(indexBitmap[byte])\n }\n // Count bits in byte 5 for values 40-46 (bits 0-6)\n for (let bit = 0; bit < 47 % 8; bit++) {\n if (indexBitmap[slashByteIndex] & (1 << bit)) {\n forkIndex++\n }\n }\n\n // Calculate fork offset\n // Each fork is: flags(1) + prefixLen(1) + prefix(30) + reference(32) + metadata(variable)\n // For simplicity, assume all forks before \"/\" have the same minimal structure\n // In a minimal manifest, \"/\" should be the first (and only) fork\n\n let forkOffset = FORKS_OFFSET\n\n // Skip previous forks if any\n for (let i = 0; i < forkIndex; i++) {\n // Read flags to check if metadata exists\n const flags = manifestData[forkOffset]\n const hasMetadata = (flags & FORK_FLAG_HAS_METADATA) !== 0\n\n forkOffset += 1 + 1 + 30 + 32 // flags + prefixLen + prefix + reference\n\n if (hasMetadata) {\n // Read metadata length (2 bytes big-endian)\n const metadataLen =\n (manifestData[forkOffset] << 8) | manifestData[forkOffset + 1]\n forkOffset += 2 + metadataLen\n }\n }\n\n // Now at the \"/\" fork\n const prefixLen = manifestData[forkOffset + 1]\n\n // Verify it's actually \"/\"\n if (prefixLen !== 1 || manifestData[forkOffset + 2] !== 0x2f) {\n throw new Error(\n `Expected \"/\" prefix, got length ${prefixLen} and byte 0x${manifestData[forkOffset + 2].toString(16)}`,\n )\n }\n\n // Reference is at offset: forkOffset + 1 (flags) + 1 (prefixLen) + 30 (prefix) = forkOffset + 32\n const referenceOffset = forkOffset + 32\n const reference = manifestData.slice(referenceOffset, referenceOffset + 32)\n\n if (isAllZeros(reference)) {\n throw new Error('Manifest \"/\" fork has zero reference')\n }\n\n const hexRef = new Reference(reference).toHex()\n\n return hexRef\n}\n\n/**\n * Count number of set bits in a byte (population count).\n */\nfunction popcount8(n: number): number {\n let count = 0\n while (n) {\n count += n & 1\n n >>>= 1\n }\n return count\n}\n\n/**\n * Check if a Uint8Array is all zeros.\n */\nfunction isAllZeros(arr: Uint8Array): boolean {\n for (let i = 0; i < arr.length; i++) {\n if (arr[i] !== 0) return false\n }\n return true\n}\n\n/**\n * Extract entry (targetAddress) from a leaf manifest node.\n *\n * In Mantaray v0.2, leaf nodes store their targetAddress in the entry field\n * (bytes 64-95), not in a fork. This is used for the second level of parsing\n * when using buildBzzCompatibleManifest().\n *\n * Binary format (Mantaray v0.2):\n * - Offset 0-31: obfuscationKey\n * - Offset 32-62: versionHash (31 bytes)\n * - Offset 63: refBytesCount\n * - Offset 64-95: entry (32 bytes) ← targetAddress for leaf nodes\n * - Offset 96-127: indexBitmap\n * - Offset 128+: forks\n *\n * @param manifestData - Raw manifest bytes (child chunk data from two-level structure)\n * @returns Content reference as 64 hex characters\n */\nexport function extractEntryFromManifest(manifestData: Uint8Array): string {\n if (manifestData.length < 96) {\n throw new Error(\n `Manifest too small: ${manifestData.length} bytes (expected at least 96)`,\n )\n }\n\n const ENTRY_OFFSET = 64\n const entry = manifestData.slice(ENTRY_OFFSET, ENTRY_OFFSET + 32)\n\n if (isAllZeros(entry)) {\n throw new Error(\"Manifest entry is zero\")\n }\n\n const hexRef = new Reference(entry).toHex()\n\n return hexRef\n}\n\n/**\n * Extract content reference from a flat /bzz/-compatible manifest.\n *\n * In the flat structure, the manifest has:\n * - \"/\" fork with NULL_ADDRESS and website-index-document metadata\n * - \"index.bin\" fork with VALUE type pointing to content reference\n *\n * This function looks for the \"index.bin\" fork ('i' = ASCII 105) and\n * extracts its reference.\n *\n * @param manifestData - Raw manifest bytes (flat manifest)\n * @returns Content reference as 64 hex characters\n */\nexport function extractContentFromFlatManifest(\n manifestData: Uint8Array,\n): string {\n if (manifestData.length < 192) {\n throw new Error(\n `Manifest too small: ${manifestData.length} bytes (expected at least 192)`,\n )\n }\n\n const INDEX_BITMAP_OFFSET = 96\n const FORKS_OFFSET = 128\n\n // Look for 'i' (105) in the index bitmap\n // Byte index = 105 / 8 = 13, bit position = 105 % 8 = 1\n const indexBitmap = manifestData.slice(\n INDEX_BITMAP_OFFSET,\n INDEX_BITMAP_OFFSET + 32,\n )\n const iByteIndex = Math.floor(105 / 8) // = 13\n const iBitMask = 1 << (105 % 8) // = 0x02\n\n if ((indexBitmap[iByteIndex] & iBitMask) === 0) {\n throw new Error('Manifest does not contain \"index.bin\" fork')\n }\n\n // Count forks before 'i' to find its offset\n let forkIndex = 0\n for (let byte = 0; byte < iByteIndex; byte++) {\n forkIndex += popcount8(indexBitmap[byte])\n }\n // Count bits in byte 13 for values less than 105\n for (let bit = 0; bit < 105 % 8; bit++) {\n if (indexBitmap[iByteIndex] & (1 << bit)) {\n forkIndex++\n }\n }\n\n // Navigate to the correct fork by skipping previous forks\n let forkOffset = FORKS_OFFSET\n for (let i = 0; i < forkIndex; i++) {\n const flags = manifestData[forkOffset]\n const hasMetadata = (flags & FORK_FLAG_HAS_METADATA) !== 0\n forkOffset += 1 + 1 + 30 + 32 // flags + prefixLen + prefix + reference\n\n if (hasMetadata) {\n const metadataLen =\n (manifestData[forkOffset] << 8) | manifestData[forkOffset + 1]\n forkOffset += 2 + metadataLen\n }\n }\n\n // Now at the \"index.bin\" fork\n const forkFlags = manifestData[forkOffset]\n const prefixLen = manifestData[forkOffset + 1]\n\n // Verify it starts with 'i' (index.bin)\n if (manifestData[forkOffset + 2] !== 0x69) {\n // 'i'\n throw new Error(\n `Expected \"index.bin\" prefix, got byte 0x${manifestData[forkOffset + 2].toString(16)}`,\n )\n }\n\n // Optionally verify full prefix \"index.bin\" (9 bytes)\n if (prefixLen >= 9) {\n const prefixBytes = manifestData.slice(forkOffset + 2, forkOffset + 2 + 9)\n const expectedPrefix = new TextEncoder().encode(\"index.bin\")\n const prefixMatches = prefixBytes.every((b, i) => b === expectedPrefix[i])\n if (!prefixMatches) {\n console.warn('[ManifestBuilder] Prefix does not fully match \"index.bin\"')\n }\n }\n\n // Check if this is a value type (reference is the target)\n const isValueType = (forkFlags & FORK_FLAG_VALUE_TYPE) !== 0\n if (!isValueType) {\n throw new Error('\"index.bin\" fork is not a VALUE type')\n }\n\n // Reference is at offset: forkOffset + 1 (flags) + 1 (prefixLen) + 30 (prefix) = forkOffset + 32\n const referenceOffset = forkOffset + 32\n const reference = manifestData.slice(referenceOffset, referenceOffset + 32)\n\n if (isAllZeros(reference)) {\n throw new Error('Manifest \"index.bin\" fork has zero reference')\n }\n\n const hexRef = new Reference(reference).toHex()\n\n return hexRef\n}\n"],"names":["collectionPath","file","relative","webkitRelativePath","replace","name","initDeadline","work","ms","message","withTimeout","catch","error","TimeoutError","SwarmIdError","cause","checkedButtonConfig","config","undefined","parsed","ButtonConfigSchema","safeParse","success","data","issue","issues","path","join","checkedButtonAction","action","ButtonActionSchema","JSON","stringify","parseBeeApiUrl","url","isBeeApiUrl","SwarmIdClient","constructor","options","this","mountedButtons","Map","ready","pendingRequests","progressListeners","requestIdCounter","window","Error","iframeOrigin","iframePath","timeout","initializationTimeout","onConnectionChange","popupMode","metadata","subsidisedGatewayUrl","beeApiUrl","AppMetadataSchema","parse","setupMessageListener","initialize","iframe","firstConnectionInfoPromise","Promise","resolve","reject","firstConnectionInfoResolve","firstConnectionInfoReject","proxyInitializedPromise","proxyInitializedResolve","proxyInitializedReject","readyPromise","readyResolve","readyReject","document","createElement","src","style","display","iframeLoadReject","onload","onerror","body","appendChild","sendMessage","type","requestId","generateRequestId","messageListener","event","source","contentWindow","expectedOrigin","URL","origin","console","warn","IframeToParentMessageSchema","handleIframeMessage","addEventListener","storageShared","info","canUpload","storagePartitioned","uploadMode","uploadUnavailableReason","identity","appKey","partition","chatBinding","postageBatchId","lastConnectionInfo","pending","get","clearTimeout","timeoutId","delete","fromWire","total","processed","ParentToIframeMessageSchema","postMessage","sendRequest","roundTripTimeout","requestOptions","setTimeout","set","perCall","Math","min","Date","now","normalizeSocIdentifier","identifier","Identifier","toHex","Uint8Array","uint8ArrayToHex","normalizeSocKey","key","normalizeFeedTopic","topic","Topic","toUint8Array","normalizeReference","reference","normalizeFeedTimestamp","value","toString","BigInt","floor","normalizeFeedIndex","normalizePayload","TextEncoder","encode","socChunkFromResponse","response","signature","span","payload","address","owner","ensureReady","checkAuthStatus","authenticated","setBeeApiUrl","getPostageBatch","postageBatch","disconnect","connect","openAuthWindow","mountButton","container","loaded","settled","windowOpen","unmounted","frame","resolveReady","rejectReady","title","Object","assign","border","backgroundColor","width","height","borderRadius","then","post","listener","BUTTON_FRAME_LOADED","ButtonToParentMessageSchema","state","remove","onWindowChange","mounted","removeEventListener","update","next","unmount","has","basePath","authUrl","buildAuthUrl","location","popup","open","Boolean","connectionInfo","getAvatar","size","avatar","generatedAvatar","id","isBeeConnected","connected","getNodeInfo","beeMode","chequebookEnabled","swapEnabled","uploadData","onProgress","useWebSocket","useWorkers","workerCount","concurrency","serializableOptions","stopProgress","listenForProgress","enableProgress","tagUid","downloadData","deriveAppSecret","label","secret","getChatKey","chatKey","stampChunk","chunk","wireChunk","kind","signer","privateKey","stamp","uploadFile","fileName","File","buffer","arrayBuffer","slice","byteOffset","byteLength","downloadFile","uploadFiles","files","entries","all","Array","from","async","item","contentType","listFiles","uploadChunk","_onProgress","downloadChunk","makeSOCReader","ownerAddress","EthAddress","sendSocDownload","encryptionKey","sendRawSocDownload","getOwner","rawDownload","download","makeSOCWriter","signerObj","PrivateKey","signerKey","publicKey","sendSocUpload","sendRawSocUpload","upload","rawUpload","makeEpochFeedReader","downloadReference","atValue","at","after","cleanRef","startsWith","length","downloadRawReference","downloadPayload","result","downloadRawPayload","makeEpochFeedWriter","uploadReference","normalizedRef","derivedKey","feedKey","hints","socAddress","epoch","timestamp","uploadPayload","encrypt","uploadResult","uploadOptions","uploadRawReference","uploadRawPayload","makeSequentialFeedReader","index","hasTimestamp","lookupTimeoutMs","feedIndex","feedIndexNext","makeSequentialFeedWriter","createFeedManifest","normalizedTopic","feedType","gsocMine","targetOverlay","proximity","gsocSend","actUploadData","grantees","encryptedReference","historyReference","granteeListReference","publisherPubKey","actReference","actDownloadData","actAddGrantees","actRevokeGrantees","revokeGrantees","actGetGrantees","destroy","destroyed","values","forEach","clear","parentNode","removeChild","buildBzzManifestNode","contentReference","refBytes","hexToUint8Array","manifest","MantarayNode","addFork","NULL_ADDRESS","Filename","manifestNode","popcount8","n","count","isAllZeros","arr","i","extractEntryFromManifest","manifestData","entry","ENTRY_OFFSET","Reference","extractContentFromFlatManifest","indexBitmap","INDEX_BITMAP_OFFSET","iByteIndex","forkIndex","byte","bit","forkOffset","flags","forkFlags","prefixLen","prefixBytes","expectedPrefix","every","b","referenceOffset"],"mappings":"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"}
1
+ {"version":3,"file":"swarm-id.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -17,15 +17,11 @@
17
17
  */
18
18
  import { Bee, BatchId, EthAddress, PrivateKey, Topic } from "@ethersphere/bee-js";
19
19
  import { z } from "zod";
20
- import { type AccountStateSnapshot, type ConnectedApp, type Device, type PostageStamp } from "../schemas";
20
+ import { type AccountSettings, type AccountStateSnapshot, type ConnectedApp, type Device, type PostageStamp } from "../schemas";
21
+ import type { WalletLink } from "../utils/wallet-link";
21
22
  import { type UploadTarget } from "../proxy/upload";
22
23
  import type { SyncResult } from "./types";
23
24
  export declare const DEVICE_STATE_TOPIC_PREFIX = "swarm-id-devstate-v1";
24
- /** Account settings carried in a device view (mirrors `account.settings`). */
25
- declare const SettingsSchema: z.ZodObject<{
26
- appSessionDuration: z.ZodOptional<z.ZodNumber>;
27
- }, z.core.$strip>;
28
- export type AccountSettings = z.infer<typeof SettingsSchema>;
29
25
  /**
30
26
  * One device's view of the account. `connectedApps`/`postageStamps` carry their
31
27
  * Phase 1 LWW/tombstone clocks; scalars carry their own per-field `at`.
@@ -85,6 +81,14 @@ export declare const DeviceStateSnapshotSchemaV1: z.ZodObject<{
85
81
  }, z.core.$strip>>;
86
82
  at: z.ZodNumber;
87
83
  }, z.core.$strip>;
84
+ walletLink: z.ZodDefault<z.ZodObject<{
85
+ value: z.ZodOptional<z.ZodObject<{
86
+ message: z.ZodString;
87
+ walletSignature: z.ZodString;
88
+ accountSignature: z.ZodString;
89
+ }, z.core.$strip>>;
90
+ at: z.ZodNumber;
91
+ }, z.core.$strip>>;
88
92
  accountPublicKey: z.ZodString;
89
93
  accountCreatedAt: z.ZodNumber;
90
94
  partitionCount: z.ZodDefault<z.ZodNumber>;
@@ -106,6 +110,10 @@ export interface DeviceStateView {
106
110
  value: AccountSettings | undefined;
107
111
  at: number;
108
112
  };
113
+ walletLink: {
114
+ value: WalletLink | undefined;
115
+ at: number;
116
+ };
109
117
  accountPublicKey: string;
110
118
  accountCreatedAt: number;
111
119
  partitionCount: number;
@@ -118,9 +126,11 @@ export interface FoldedAccount {
118
126
  accountName: string;
119
127
  defaultPostageStampBatchID: BatchId | undefined;
120
128
  settings: AccountSettings | undefined;
129
+ walletLink: WalletLink | undefined;
121
130
  accountNameAt: number;
122
131
  defaultStampAt: number;
123
132
  settingsAt: number;
133
+ walletLinkAt: number;
124
134
  createdAt: number;
125
135
  publicKey: string;
126
136
  partitionCount: number;
@@ -197,4 +207,3 @@ export declare function readLatestDeviceState(opts: {
197
207
  * unchanged from Phase 1.
198
208
  */
199
209
  export declare function foldAccount(views: DeviceStateSnapshot[], rosterDevices: Device[], accountId: string): FoldedAccount;
200
- export {};
@@ -3,7 +3,8 @@ export { mergeSnapshotWithRemote, mergeConnectedApps, mergePostageStamps, mergeD
3
3
  export { createSyncAccount } from "./sync-account";
4
4
  export type { SyncAccountOptions, SyncAccountFunction } from "./sync-account";
5
5
  export { deviceStateTopic, accountStateToDeviceView, writeDeviceState, publishDeviceState, readLatestDeviceState, foldAccount, deserializeDeviceState, DeviceStateSnapshotSchemaV1, DEVICE_STATE_TOPIC_PREFIX, } from "./device-state";
6
- export type { DeviceStateSnapshot, DeviceStateView, FoldedAccount, AccountSettings, } from "./device-state";
6
+ export type { DeviceStateSnapshot, DeviceStateView, FoldedAccount, } from "./device-state";
7
+ export type { AccountSettings } from "../schemas";
7
8
  export { rosterTopic, readRoster, ensureInRoster, ROSTER_TOPIC_PREFIX, } from "./device-roster";
8
9
  export { foldAccountFromSwarm, foldedToSyncedAccount, } from "./fold-account-from-swarm";
9
10
  export type { FoldAccountResult } from "./fold-account-from-swarm";
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The wallet link as the account last published it (docs/Wallet-Link.md).
3
+ *
4
+ * "Show my ENS name on sites" reaches an open site's frame over the account
5
+ * bus, and the bus keeps no mailbox. A change made while no page of a site was
6
+ * open is written only to Swarm, so a site's frame restored on its next load
7
+ * reads it here. The read is the restored-session check's own fold, which
8
+ * `foldAccountFromSwarm` shares between the two while both are in flight.
9
+ */
10
+ import type { Bee } from "@ethersphere/bee-js";
11
+ import type { WalletLink } from "../utils/wallet-link";
12
+ export interface PublishedWalletLink {
13
+ /** Absent when the setting was last turned off */
14
+ walletLink: WalletLink | undefined;
15
+ /** The link's own last-writer-wins clock */
16
+ walletLinkAt: number;
17
+ }
18
+ /**
19
+ * Answers `undefined` for an account that never published and for a Swarm
20
+ * that could not be read. Neither says anything about the setting, so the
21
+ * frame keeps what it holds.
22
+ */
23
+ export declare function readPublishedWalletLink(opts: {
24
+ bee: Bee;
25
+ derivationKey: string;
26
+ accountId: string;
27
+ }): Promise<PublishedWalletLink | undefined>;
@@ -16,6 +16,16 @@
16
16
  * is treated as inconclusive (see each caller's sentinel handling).
17
17
  */
18
18
  export declare const SYNC_READ_TIMEOUT_MS = 2500;
19
+ /**
20
+ * Client-side timeout for a single device-roster slot read. Longer than
21
+ * {@link SYNC_READ_TIMEOUT_MS}, because the roster is read through the account's
22
+ * gateway, by default the public one, and an empty roster can only be confirmed
23
+ * by a miss: the public gateway answers an absent chunk with Bee's own 404 after
24
+ * 3.4 to 4.8 s (measured 2026-10-18), and does not route `GET /soc`, so a shorter
25
+ * limit made every empty roster inconclusive. No device then ever wrote its first
26
+ * entry, and signing in on another device always failed.
27
+ */
28
+ export declare const ROSTER_READ_TIMEOUT_MS = 10000;
19
29
  /**
20
30
  * Partition-lease lifetime. A device holds its partition for this long before
21
31
  * the lease must be refreshed; if it crashes without refreshing, peers can