@netless/app-embedded-page-sdk

SDK for storing shared replayable states and sending/receiving replayable events inside @netless/app-embedded-page.

Usage no npm install needed!

<script type="module">
  import netlessAppEmbeddedPageSdk from 'https://cdn.skypack.dev/@netless/app-embedded-page-sdk';
</script>

README

@netless/app-embedded-page-sdk

SDK for storing shared replayable states and sending/receiving replayable events inside @netless/app-embedded-page.

中文

Install

npm add @netless/app-embedded-page-sdk

Example

More examples here.

import { createEmbeddedApp } from "@netless/app-embedded-page-sdk";

interface State {
  count: number;
}

type Message = {
  type: "click";
  payload: { id: string };
};

const app = await createEmbeddedApp<State, Message>();

app.ensureState({ count: 0 });

app.state; // => { count: 0 }
app.setState({ count: 2 });
app.onStateChanged.addListener(diff => {
  if (diff.count) {
    // count: 0 -> 2
    console.log("count:", diff.count.oldValue, "->", diff.count.newValue);
    console.log(diff.count.newValue === app.state.count);
  }
});

app.sendMessage({ type: "click", payload: { id: "item1" } });
app.onMessage.addListener(({ type, payload }) => {
  if (type === "click") {
    click(payload.id);
  }
});

API

  • createEmbeddedApp()

    Creates an embedded app instance.

    Returns: Promise<EmbeddedApp<State, Message>>

    const app = await createEmbeddedApp();
    
  • app.appId

    Type: string

    App ID. Each app is assigned with a unique ID on creation and will keep the same ID until destroyed.

  • app.state

    Type: State
    Default: initialState

    The synchronized state across all clients. To change it, call app.setState().

  • app.page

    Type: string | undefined

    Current whiteboard scene. It works only if scenePath has been set when calling addApp. To switch between pages, call app.setPage()

  • app.isWritable

    Type: boolean

    When it is false, calling app.setState(), app.setPage(), app.sendMessage() has no effect.

  • app.meta

    Type: { sessionUID: number; uid: string; roomUUID?: string; userPayload: unknown }

    Room information, including

    • sessionUID: a unique number of current session. will change after refreshing.
    • uid: a unique id of current user passed in when calling joinRoom().
    • roomUUID: current room's UUID.
    • userPayload: the object passed in when calling joinRoom().
  • app.roomMembers

    Type: ReadonlyArray<{ sessionUID: number; uid: string; userPayload: unknown }>

    All members in the room.

    • sessionUID: a unique number of current session. will change after refreshing.
    • uid: a unique id of current user passed in when calling joinRoom().
    • userPayload: the object passed in when calling joinRoom().
  • app.ensureState(partialState)

    Make sure app.state has some initial values, work as if:

    // this code won't work because app.state is readonly
    app.state = { ...partialState, ...app.state };
    

    partialState

    Type: Partial<State>

    app.state; // { a: 1 }
    app.ensureState({ a: 0, b: 0 });
    app.state; // { a: 1, b: 0 }
    
  • app.setState(partialState)

    Works like React's setState, it updates app.state and synchronize it to other clients.

    When some field's value is undefined, it will be removed from app.state.

    Important: Do not rely on the order of state changes:

    • app.setState() alters app.state synchronously but onStateChanged will wait until the data is successfully synced.
    • State syncing time span varies due to network status and data size. It is recommended to store only necessary data in the store.

    partialState

    Type: Partial<State>

    app.state; //=> { count: 0, a: 1 }
    app.setState({ count: app.state.count + 1, a: undefined, b: 2 });
    app.state; //=> { count: 1, b: 2 }
    
  • app.setPage(page)

    Change the whiteboard scene on top of your page.

    page

    Type: string

    Important: This argument must not include /.

    app.setPage("1");
    
  • app.sendMessage(message)

    Broadcast a message to other clients.

    message

    Type: anything that can be serialized in JSON.

    app.sendMessage("hello, world!");
    
  • app.moveCamera(partialCameraState)

    Change the whiteboard scene's position on top of your page.

    partialCameraState

    Type: Partial<{ x: number, y: number, scale: number }>

    The default camera state is { x: 0, y: 0, scale: 1 }, at the center of your page.

    app.moveCamera({ scale: 0.5 });
    
  • app.onStateChanged

    It fires after someone called app.setState() (including the app itself).

    Type: Emitter<{ [key: string]: { oldValue?, newValue? } }>

    app.onStateChanged.addListener(diff => {
      console.log("state changed", app.state);
    });
    
  • app.onPageChanged

    It fires after someone called app.setPage() (including the app itself).

    Type: Emitter<{ oldValue?: string, newValue?: string }>

    app.onPageChanged.addListener(diff => {
      console.log("switch page to", app.page);
    });
    
  • app.onWritableChanged

    It fires when app writable state changes.

    Type: Emitter<{ oldValue?: boolean, newValue?: boolean }>

    app.onWritableChanged.addListener(diff => {
      console.log("my writable becomes", app.isWritable);
    });
    
  • app.onRoomMembersChanged

    It fires when room members changes.

    Type: Emitter<{ oldValue?: RoomMember[], newValue?: RoomMember[] }>

    interface RoomMember {
      sessionUID: number;
      uid: string;
      userPayload: unknown;
    }
    
    app.onRoomMembersChanged.addListener(diff => {
      console.log("room members changed", app.roomMembers);
    });
    
  • app.onMessage

    It fires when receiving messages from other clients (when other clients called app.sendMessage()).

    Note: Won't receive app.sendMessage() messages sent by itself.

    Type: Emitter<any>

    app.onMessage.addListener(message => {
      console.log("received message", message);
    });
    

Licence

MIT @ netless