Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add spec for web3inbox #365

Merged
merged 14 commits into from
Dec 21, 2022
9 changes: 9 additions & 0 deletions docs/specs/meta-clients/web3inbox/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Web3Inbox SDK Overview

The Web3Inbox SDK combines functionality of
[Push](../../clients/push/README.md) and [Chat](../../clients/chat/README.md)
into one offering by giving access to the [Web3Inbox](https://web3inbox.com)
inner state and user interface.

This spec aims to model the inner "W3I proxy" state manager in Web3Inbox.com,
as well the native SDKs that will wrap it for native iOS or android experiences.
8 changes: 8 additions & 0 deletions docs/specs/meta-clients/web3inbox/data-structures.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
```typescript
// Read more: https://rxjs.dev/guide/observer
interface Observer<TObservedValue> {
jakubuid marked this conversation as resolved.
Show resolved Hide resolved
next: (val: TObservedValue) => void
error?: (error: Error) => void
complete?: () => void
}
```
144 changes: 144 additions & 0 deletions docs/specs/meta-clients/web3inbox/sdk-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# Web3Inbox SDK API

The Web3InboxSDK encompasses both [Push](../../clients/push/README.md) and
[Chat](../../clients/chat/README.md) methods and event listeners. All methods
within the class documented here are used internally by the web3inbox web
app. Internally, the state is managed through [RxJS](https://rxjs.dev/),
which allows the SDK to cleanly listen to events from anywhere. This of
course includes the Chat & Push clients in the webapp.

## Stateless Mode
In the case of the webapp being integrated in a native webview, RxJS hooks
into the `message` event on the window, receiving messages from the
`postMessage` calls. Note, this also enables communication with any parent
context (React Native, web page displaying Web3Inbox in an `iframe`, etc).

This is Web3InboxSDK's stateless mode, where it won't manage any clients and
will instead just be relaying info to the embedded Web3Inbox user interface.

```typescript

abstract class Web3InboxSDKChatFacade {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why you call it Web3InboxSDKChatFacade, to me it looks exactly like ChatClient?
do we even need to spec it here? correct me if I am wrong but it looks like a duplicate to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It has the same methods, but not the same event listeners and as of now there's no guarantee it'll always be 1:1 with the chat client, as it may have more functionality moving forward

// register a blockchain account with a public key / returns the public key
public abstract register(params: {
account: string;
private?: boolean;
}): Promise<string>;

// queries the default keyserver with a blockchain account / returns the public key
public abstract resolve(params: {
account: string;
}): Promise<string>;

// sends a chat invite to peer account / returns an invite id
public abstract invite(params: {
account: string;
invite: Invite;
}): Promise<number>;

// accepts a chat invite by id / returns thread topic
public abstract accept(params: {
inviteId: number;
}): Promise<string>;

// rejects a chat invite by id
public abstract reject(params: {
inviteId: number;
}): Promise<void>;

// sends a chat message to an active chat thread
public abstract message(params: {
topic: string;
message: string;
media?: Media
}): Promise<void>;

// ping its peer to evaluate if it's currently online
public abstract ping(params: {
bkrem marked this conversation as resolved.
Show resolved Hide resolved
topic: string;
}): Promise<void>

// leaves a chat thread and stops receiving messages
public abstract leave(params: {
topic: string;
}): Promise<void>;

// adds peer account with public key
public abstract addContact(params: {
account: string;
publicKey: string;
}): Promise<void>

// returns all invites matching an account / returns maps of invites indexed by id
public abstract getInvites(params: {
account: string;
}): Promise<Map<string, Invite>>

// returns all threads matching an account / returns map of threads indexed by topic
public abstract getThreads(params: {
account: string;
}): Promise<Map<string, Thread>>;

// returns all messages matching a thread's topic / returns array of messages
public abstract getMessages(params: {
topic: string;
}): Promise<[Message]>;

/*
Event observing.
Note: All observers return a method to stop observing.
*/
// subscribe to new chat invites received
public abstract observe("chat_invite", Observer<{ id: number, invite: Invite}>): () => void;

// subscribe to new chat thread joined
public abstract observe("chat_joined", Observer<{ topic: string }>): () => void;

// subscribe to new chat messages received
public abstract observe("chat_message", Observer<{ topic: string, payload: Message}>): () => void;

// subscribe to new chat thread left
public abstract observe("chat_left", Observer<{ topic: string }>): () => void;

}

abstract class Web3InboxSDKPushFacade {
// request push subscription
public abstract request(params: { account: string, pairingTopic: string }): Promise<{ id }>;

// send push notification message
public abstract notify(params: { topic: string, message: PushMessage }): Promise<void>

// query all active subscriptions
public abstract getActiveSubscriptions(): Promise<Record<string, PushSubscription>>;

// delete active subscription
public abstract delete(params: { topic: string }): Promise<void>;

/*
Event observing.
Note: All observers return a method to stop observing.
*/
public abstract observe("push_response", Observer<{id: number, response:{error?: Reason, subscription?: PushSubscription }>): () => void;
}

abstract class Web3InboxSDK {
Copy link
Contributor

Choose a reason for hiding this comment

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

can we call it client like we always do?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Feels off to call it a client since it technically doesn't handle any relay communication on its own

Copy link
Contributor

Choose a reason for hiding this comment

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

no hight level API client does, they all use core

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But it's not like push or chat, I really don't think we can compare web3inboxSDK to push and chat. cc @pedrouid

Copy link
Member

Choose a reason for hiding this comment

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

Yeah these SDKs are multiple clients so it wouldn't make sense to call it a client


// Note that the facade objects are not the actual clients, but a layer on top
// of them, this is so that their functionality and state can be managed
// within web3inbox.
public readonly get chat: Web3InboxSDKChatFacade
public readonly get push: Web3InboxSDKPushFacade

// If the init function does not receive `params`, Web3InboxSDK operates in a
// stateless manner where it does not maintain chat/push clients and only
// listens to external events.
public static abstract init(params?: {
relayUrl: string;
jakubuid marked this conversation as resolved.
Show resolved Hide resolved
projectId: string;
Copy link
Contributor

Choose a reason for hiding this comment

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

Chat and Push clients are dependent on CoreClient, which is responsible for handling networking. Is that the case here as well? If yes, we should inject CoreClient instead of projectId and relayUrl

Copy link
Contributor Author

Choose a reason for hiding this comment

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

W3I will manage push, chat and the core they'll depend on. In the mobile case, the clients will be handled completely externally outside w3i

castUrl?: string;
}): Promise<Web3InboxSDK>

}
```

20 changes: 20 additions & 0 deletions docs/specs/meta-clients/web3inbox/stateless-communication.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Stateless Communication

In the case of stateless mode, the parent (Eg: native app displaying a webview)
communicates using `postMessage`, sending messages one-way to the client.

The message format should be as follows, following JSON RPC:

```typescript
class EventMessage {
jsonrpc: "2.0",
method: string // eventName
params: object // eventData
id: number
}
```

Where `method`/`eventName` is 1:1 original event name from the original clients since
they are already prefixed. Eg: `chat_message`. `params`/`eventData` is the unencrypted
event data coming from the original client. Eg: `Message` coming from
`chat_message` event.
16 changes: 16 additions & 0 deletions sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,22 @@ module.exports = {
},
],
},
{
type: "category",
label: "Meta-Clients API",
items: [
{
type: "category",
label: "Web3Inbox",
items: [
{
type: "autogenerated",
dirName: "specs/meta-clients/web3inbox",
}
],
},
],
},
{
type: "category",
label: "Server APIs",
Expand Down