SWIP-XXXX: Swarm Provider API (window.swarm)#94
Conversation
…provements Add Security Considerations section (origin trust, resource exhaustion, iframe behavior, feed key material, temp artifacts). Add Future Extensions section (swarm_listFeeds, capabilitiesChanged, preferredIdentityMode, specVersion promotion path). Promote convenience methods and re-prompting from SHOULD to MUST. Add specVersion (SHOULD) to swarm_getCapabilities. Document UTF-8 string encoding, session-scoped tag ownership, feed update failure semantics, and bzz:// URI scheme status. Add edge-case test cases. Fix stale branch links. Rename file to match repo conventions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…eedEntry Two coordinated updates reflecting the implemented behavior in Freedom Browser (PR ethersphere#19): 1. New method: swarm_listFeeds() - Origin-scoped introspection returning the calling origin's previously created feed records — name, topic, owner, manifestReference, bzzUrl, createdAt, lastUpdated, lastReference. - No permission required: feed coordinates are deterministic given (origin, name) and the metadata persists across permission revocation by design, so gating it would be friction without security benefit. - Returns [] for origins with no feeds (never an error). - Removed from the Future Extensions list since it now ships in 1.0. 2. Permission correction for swarm_readFeedEntry - The 1.0 draft previously required connection permission. That was wrong — feeds are public Swarm data readable from any Bee gateway without auth, and forcing requestAccess broke passive use cases like profile pages displaying on-chain-discovered activity feeds. - Method now requires NO permission grant. Updated description, errors (4100 removed), behavior bullets, permission lifecycle item 4, and the corresponding test case ("Without Feed Grant" → "Without Any Permission" with stronger assertions). - Permission lifecycle item 5 (disconnection) clarified that permission-free reads MUST continue to function after revocation. Other touches: - Method count in the abstract bumped from "nine" to "ten". - Convenience method list extended with window.swarm.listFeeds(). - Implementation reference updated: removed the broken docs/swarm-provider-test link (the file moved to research/ and is no longer tracked); Swarmit's method usage list extended to include writeFeedEntry / readFeedEntry / listFeeds. Net diff: +83 / -14 lines. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reflects implementation findings from the iOS Freedom Browser provider:
- USTAR tar's 100-byte name field caps file paths far below the prior
256-char wording. Replace the hardcoded limit with a capability-advertised
maxPathBytes (normative floor of 100, recommended default 100 UTF-8 bytes)
so future PAX-supporting implementations can advertise more.
- Bee's GET /feeds/{owner}/{topic}?index=N is at-or-before, not exact-match,
which silently breaks writeFeedEntry's overwrite protection on sparse
writes and corrupts readFeedEntry's explicit-index contract. Add normative
exact-match requirements on both methods plus an informative section
documenting the SOC-address derivation (GET /chunks/{socAddress}) and the
big-endian/little-endian endianness trap.
- Clarify that the 4 KB SOC body limit is internal to the storage envelope,
not a writeFeedEntry payload cap; the dApp-visible cap is maxDataBytes.
|
It would be good if chunk level operations were supported in the API, because with those every higher level Swarm APIs can be implemented (feeds, manifest, ACT etc.), even ones that are not supported at the moment by Bee (e.g. epoch feeds). The API could be Similarly there would be a There are also Single-Owner Chunks. Currently Swarm does not have a way to distinguish different chunk types, and it does it with heuristics, but there are documented issues and discrepancies about it.
If this could be fixed at the Swarm level, then |
…ission model In response to PR review (agazso, ethersphere#94): - New low-level chunk methods: swarm_publishChunk, swarm_readChunk, swarm_writeSingleOwnerChunk, swarm_readSingleOwnerChunk. Type is declared by method name to sidestep Bee's CAC/SOC heuristic (SWIP-67, bee#5445). Reads MUST validate by recomputing the type-specific address; mismatch returns chunk_type_mismatch. - New swarm_getSigningIdentity for pre-write SOC address derivation; also serves as feed-permission bootstrap path. - Permission model: prompt-rejection is 4001 across both publish and feed tiers; 4100 reserved for missing connection or un-promptable contexts. 4100 description broadened to match. - Permission-free reads (readFeedEntry, readChunk, readSingleOwnerChunk, listFeeds) now MUST be per-origin rate/bandwidth limited; new rate_limited reason and dedicated security section. - span widened to number | bigint for u64 safety. - Capability advertises maxChunkPayloadBytes = 4096. - Design Goal scoped to writes/signing/resource-consuming ops to match the permission-free read tier. - Implementation section honestly scopes Freedom/Swarmit coverage to the original high-level surface. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Thanks @agazso — this ended up being very useful feedback. The latest push ( Chunk methods added: Type validation on reads: providers must verify returned bytes against the requested chunk type: BMT/address validation for CACs, and SOC signature recovery plus Signing identity discovery: added
SOC mutability wording corrected: same A few related changes fell out of this: permission-free reads now have mandatory per-origin rate/bandwidth limits with a I also looked at SwarmID while shaping this. My current read is that Reference implementations for the new chunk tier and |
|
Hi @agazso, quick follow-up: we implemented the chunk-level provider API discussed here in Freedom Browser. Implementation PR: solardev-xyz/freedom-browser#81 It includes:
We also smoke-tested the CAC and SOC paths against Bee. The smoke test caught an SOC upload endpoint issue, which is now fixed: SOC writes use Bee's Thanks for the idea that led to this amendment; it translated cleanly into the provider implementation. |
|
Quick additional follow-up: we also built a first experimental consumer library on top of the chunk-level API: https://github.com/solardev-xyz/swarm-kit The interesting part is that this validates the original reason for adding raw CAC/SOC access: higher-level Swarm data structures can now be implemented outside the provider/Bee API surface.
The playground and compliance harness have been smoke-tested in Freedom Browser against the implemented This is still experimental, but it is a useful data point for the SWIP: the chunk tier does seem to move many future Swarm patterns from “new provider/Bee method needed” into “library-level convention.” |
Brings the mobile window.swarm provider up to the current SWIP draft (ethersphere/SWIPs#94), matching the desktop implementation (solardev-xyz/freedom-browser#81). The mobile side had only the original ten high-level methods; dapps using the newer surface failed with "Method not supported: swarm_getSigningIdentity". New methods: - swarm_publishChunk / swarm_readChunk (CAC tier, publish permission / permission-free) - swarm_writeSingleOwnerChunk / swarm_readSingleOwnerChunk (SOC tier, feed-permission signing / permission-free) - swarm_getSigningIdentity (feed-permission tier; no-prompt fast path once granted, sheet-bootstrapped first grant) Spec-mandated behaviors that came with the update: - chunk-type validation on reads (BMT recompute for CACs, signature recovery + address re-derivation for SOCs) → chunk_type_mismatch - per-origin rate/bandwidth budgets on the four permission-free read methods (600 req / 5 MB connected, 120 req / 512 KB anonymous, 60 s windows) → rate_limited - structured reasons: invalid_reference, invalid_identifier, invalid_span, chunk_not_found, chunk_type_mismatch, unsupported_option, rate_limited - span as number | bigint across the JS bridge (bigint → decimal string → u64; read replies convert back) - capabilities: maxChunkPayloadBytes (4096), publisherIdentityModes, extensions.publisherSigning - owner fields normalized to EIP-55 checksummed 0x form across createFeed / listFeeds / writeSingleOwnerChunk / getSigningIdentity (spec requires one identical owner string; matches desktop) Verification: 821 unit tests green, including a new end-to-end test that runs swarm-kit's runSwarmProviderCompliance harness inside a real WKWebView against the real preload + bridge + vault signing (12/12 compliance cases pass). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds swip-draft_provider_api_messaging.md — a requires-extension to the provider API adding real-time messaging: swarm_subscribe/unsubscribe (the first streaming surface, EIP-1193 'message'-event style), swarm_sendPss, swarm_sendGsoc, and swarm_getMessagingIdentity. New messaging permission tier, feature detection via getCapabilities().features, best-effort/ unordered/at-least-once delivery semantics.
|
I've pushed a companion draft to this branch — Why an extension: the v1 surface is entirely request/response — there's no way for a dApp to receive asynchronous data (the only push signals are What it adds (four methods + one event):
It reuses the core spec's consent model (a new messaging permission tier), origin-scoping, base64 payload encoding, and error format, and is purely additive — feature-detected via A few design points I'd especially value feedback on:
This isn't speculative — it's designed against a working light-node PSS/GSOC implementation (send and receive on a light node, interop-tested against bee and verified on mainnet), and an informative "Reference Endpoints" section maps each method onto the gateway endpoints that back it. Happy to split it into its own PR if that's cleaner for review; I kept it here since it directly extends this spec. |
…losure, error/table fixes - GSOC topic→address: determinism is now scoped honestly to a single implementation; cross-provider convergence requires a derivation profile (identifier, target, mining order, proximity) that is deferred to Future Work. Cross-provider apps exchange the resolved address and use the raw address param. Test case relabeled accordingly. - getMessagingIdentity no longer discloses the full node overlay (a node-global, cross-origin correlation handle that pinpoints the node's neighborhood); it returns a truncated pssTarget prefix (<= maxTargetDepth bytes) instead. sendPss targets is now required and documented as the recipient's pssTarget. New Security Considerations entry on cross-origin identity correlation. - Add missing invalid_target row to the -32602 reason table (was referenced by swarm_sendPss but never defined). - Mid-stream failure text no longer suggests emitting an error inside the message event (whose schema has no error variant); implementations MUST document degraded-pipeline behavior, normative signalling stays in Future Work. - Dedup note: byte-identical sends on the same key are indistinguishable at the transport layer and MAY coalesce; apps needing distinguishable repeats include a nonce/sequence. - features/limits MUST (not MAY) be available pre-grant, matching the core spec's permission-free getCapabilities; SHOULD-level per-origin send rate cap under auto-approve.
|
A self-review pass on the messaging draft turned up a few things worth fixing before anyone else hit them — pushed as 49eab20:
None of this changes the four methods or the streaming shape — it tightens claims to what the mechanics actually guarantee. |
Two gaps surfaced by hardening the reference light-node implementation: - Empty payloads: swarm_sendGsoc data is now 1..maxMessageBytes with a new invalid_payload reason — a GSOC update is a single-owner chunk and bee's chunk layer rejects an empty SOC payload, so the provider must not sign a chunk the network refuses. swarm_sendPss explicitly ALLOWS empty data (the trojan framing carries an explicit length; zero-byte pings are well-formed). Test cases added for both. - Node capacity != per-origin cap: receive pipelines are a node-wide pool (the reference implementation bounds distinct concurrently- pulled neighborhoods across ALL origins), so subscribe can fail because OTHER origins hold the slots. That case MUST surface as a retryable 4900 naming subscription capacity — not too_many_subscriptions, which stays reserved for the per-origin maxSubscriptions the dApp itself can fix by unsubscribing. Limits table notes why the aggregate bound is not advertised per-origin.
|
Small follow-up to the messaging draft (19cfb9d): hardening the reference light-node implementation surfaced two spec gaps worth closing before they bite an implementer.
Both came out of adversarial review of the implementation rather than armchair speculation, which is exactly the feedback loop this draft is meant to have with running code. |
Summary
This PR proposes a new draft SWIP defining a standard JavaScript provider API —
window.swarm— that lets web pages request access to a user's Swarm (Bee) node for publishing data, uploading files, managing mutable feeds, reading and writing indexed feed entries, and introspecting their own feed records. It follows the request/response pattern established by EIP-1193 for Ethereum providers, adapted for Swarm's publishing and feed primitives.The draft lives at
SWIPs/swip-draft_provider_api.mdand will be renamed toswip-XXXX.mdonce a number is assigned.Motivation
Today, publishing to Swarm from a web app requires either:
localhost, orNeither is acceptable for a user-sovereign web. Users need a way to grant web apps controlled, permissioned access to Swarm publishing — the way
window.ethereumlets pages interact with a wallet without exposing private keys. Without a standard, every Swarm-enabled browser or extension will invent its own API, fragmenting the ecosystem.What the SWIP specifies
window.swarm) injected beforeDOMContentLoaded, withrequest(), convenience wrappers, and an event interface.swarm_requestAccess), capability discovery (swarm_getCapabilities), publishing (swarm_publishData,swarm_publishFiles,swarm_getUploadStatus), mutable feeds (swarm_createFeed,swarm_updateFeed), indexed feed entries (swarm_writeFeedEntry,swarm_readFeedEntry), and origin-scoped feed introspection (swarm_listFeeds).127.0.0.1doesn't collapse into one permission scope), and app-scoped feed identities (each origin's feeds signed by a per-origin derived key, so dApps can't impersonate the user's main wallet).GET /feeds/{owner}/{topic}at-or-before semantics and the SOC-address fallback) so overwrite protection and explicit-index reads are safe.maxDataBytes,maxPathBytes) so future implementations supporting PAX tar can advertise larger paths without breaking the spec.capabilitiesChangedevent,preferredIdentityMode, encoding parameter for reads, promotion path forspecVersion).Reference implementations
This is not a paper spec — both sides of the API are already implemented and exercise the full surface:
window.swarminto webview contexts, with main-process IPC enforcement, origin normalization, app-scoped feed keys, and per-origin permissions.swarm_requestAccess,swarm_publishData,swarm_createFeed,swarm_writeFeedEntry,swarm_readFeedEntry, andswarm_listFeedsfor its full publishing and profile-discovery pipeline.The implementation work surfaced several spec issues that have already been folded back into this draft (USTAR tar's 100-byte path limit, Bee's at-or-before feed lookup semantics, the SOC-address endianness trap, permission gating for public reads).
Status
swip-draft_provider_api.mdtoswip-XXXX.mdonce a number is assigned.