Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src-docs/shared_state/conflicts.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ both a Total Order of messages and a "single source of truth" can not be assumed
Many webxdc applications are incapable of producing conflicts,
either because they do not use the network communication APIs,
or because any given data structure can only have one writer.
Alternatively, an application can designate a "central" authority
by checking [`webxdc.appSenderAddr`](../spec/selfAddr_and_selfName.html#appsenderaddr)
to identify the user who shared the app.
This peer could then authoritatively resolve conflicts or coordinate state updates.
However, developers should be aware that if the app depends entirely on the sender being online,
the app's availability will be limited when the sender is offline.

For example, many of the available [webxdc games](https://webxdc.org/apps/) offer a high-score table
and how users scored will typically be reported back to the chat.
Such a gaming app will simply post their user's highscore
Expand Down
4 changes: 3 additions & 1 deletion src-docs/shared_state/crdts.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,13 @@ This enables peers to queue updates while entirely offline,
and to merge their local state with others' when they are once again able to communicate.
While this behaviour can be very helpful for application developers,
it may not free you entirely from having to think about network conditions.
_Eventually-consistent_ application state should generally be treated as
subjective, which can be a significant shift if you are used to having a server acting as an authority.
While you can use [`webxdc.appSenderAddr`](../spec/selfAddr_and_selfName.html#appsenderaddr) to nominate a peer
(the app sender) to act as a kind of server, this introduces a dependency on that peer being online.
That means that conditional behaviour that you'd usually treat as _yes_ and _no_,
may instead behave more like _currently_ and _not yet_.


This section has discussed attributes of CRDTs that are mostly theoretical.
The next section will give more concrete examples using **Yjs**,
with a particular focus on how it can be used to accomplish common
Expand Down
20 changes: 20 additions & 0 deletions src-docs/shared_state/practical.md
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,26 @@ As for the matter of duplicate ids in the `order` array,
the rendering code which constructs the app's UI from this data
could ignore repeated elements when iterating over them.

## Centralized coordination

While CRDTs are designed for peer-to-peer operation,
you may sometimes want to designate one client as a "coordinator".
By comparing [`webxdc.appSenderAddr`](../spec/selfAddr_and_selfName.html#appsenderaddr)
with `webxdc.selfAddr`,
an app can identify whether it is running for the peer
that initially shared the app.
This "sender" instance can then take on special roles,
such as authoritatively resolving state conflicts,
for example by letting the app sender's updates always win.

However, use this model with care:
if your app logic requires the sender to be online to function,
it will be unusable whenever the sender is offline or has left the chat.
One further complication occurs if the app sender
has multiple devices running the app simultaneously,
with each device possibly regarding itself as the central coordinator
and producing conflicting application states.

## Learning more

Many more examples can be found throughout
Expand Down
6 changes: 6 additions & 0 deletions src-docs/spec/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## [1.4] - 2026-04-16

### New APIs

- add `webxdc.appSenderAddr` and `webxdc.canOnlySendUpdatesToAppSender`
to allow apps to determine their role and their ability to send updates.
## [1.3] - 2026-02-11

### Other changes
Expand Down
3 changes: 3 additions & 0 deletions src-docs/spec/messenger.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ When starting a web view for a webxdc app to run, messenger implementors

- MUST support `<meta name="viewport" ...>` is useful especially as webviews from different platforms have different defaults

- MUST support `window.webxdc.appSenderAddr` and `window.webxdc.canOnlySendUpdatesToAppSender`
to allow apps to determine their role and their ability to send updates.

- MUST support `<input type="file">` to allow importing of files;
see [`sendToChat()`](../spec/sendToChat.md) for a way to export files.

Expand Down
27 changes: 27 additions & 0 deletions src-docs/spec/selfAddr_and_selfName.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,33 @@ Note that `selfAddr`
- should not be shown in the user interface of the webxdc application
(use `selfName` instead).

## appSenderAddr

```js
window.webxdc.appSenderAddr
```

`appSenderAddr` is the address of the peer who initially shared the webxdc application in the chat.
It can be compared to `webxdc.selfAddr` to determine whether the app is running
for the sender or a receiver.
This supports a common development model where a "central" app instance
(the sender's) processes all updates and distributes the resulting state
back to all peers.

## canOnlySendUpdatesToAppSender

```js
window.webxdc.canOnlySendUpdatesToAppSender
```

`canOnlySendUpdatesToAppSender` is a boolean that is `true` if updates sent
by the local user will only be seen by the app sender.
If it is `false` or `undefined`, the local user can send [updates](./sendUpdate.md) to everyone in the chat.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is false also for one-to-one chats, maybe worth to say that explicit.

if true, question pops up if SELF is seeing the update - there are few situations where SELF do not get updates already today, eg. if one cannot sent in a chat, on chat requests. as the state comes from the channel owner only, it might be better here as well. but not sure, just mentioning

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assumed that

All receiving peers, including the sending one, will receive the update

in sendUpdate.md implied that you get your own updates even if you are not sender, maybe I was wrong in my review on the core PR


On some platforms, such as "broadcast channels," it is technically impossible
for subscribers to discover or send updates to each other directly.
In those cases, only the app sender can distribute updates globally.



## Example using selfAddr and selfName
Expand Down
8 changes: 6 additions & 2 deletions src-docs/spec/sendUpdate.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@
window.webxdc.sendUpdate(update, descr);
```

Send an update to all peers.
Send an update to peers.
If `webxdc.canOnlySendUpdatesToAppSender` is false, the update is sent to all peers.
If `webxdc.canOnlySendUpdatesToAppSender` is true, the update is only sent to the app sender
(the peer with the address `webxdc.appSenderAddr`).

All peers, including the sending one,

All receiving peers, including the sending one,
will receive the update by the callback given to [`setUpdateListener()`](./setUpdateListener.html).

There are situations where the user cannot send messages to a chat,
Expand Down
5 changes: 5 additions & 0 deletions src-docs/webxdc.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ interface Webxdc<T> {
selfAddr: string;
/** Returns the peer's own name. This is name chosen by the user in their settings, if there is nothing set, that defaults to the peer's address. */
selfName: string;
/** The address of the peer who initially shared this webxdc app. */
appSenderAddr: string;
/** True if updates sent by this peer will only be received by the app sender.
* If false, the current user can send updates to all peers. */
canOnlySendUpdatesToAppSender: boolean;
/**
* set a listener for new status updates.
* The "serial" specifies the last serial that you know about (defaults to 0).
Expand Down
Loading