From 2ff30551bf3ced57724c5e48f6fa24fed8f6833c Mon Sep 17 00:00:00 2001 From: Attila Gazso <230163+agazso@users.noreply.github.com> Date: Sat, 9 Sep 2023 14:24:08 +0200 Subject: [PATCH] feat: external object props (#21) * feat: external object props * chore: cleanup * chore: update lockfile --- objects/sandbox-example/src/App.svelte | 37 +++++++++++++++++++++++--- packages/adapter/src/index.ts | 28 ++++++++++++++----- packages/adapter/src/types.ts | 13 ++++++--- pnpm-lock.yaml | 4 +++ 4 files changed, 69 insertions(+), 13 deletions(-) diff --git a/objects/sandbox-example/src/App.svelte b/objects/sandbox-example/src/App.svelte index 5aa24a6..0bf506a 100644 --- a/objects/sandbox-example/src/App.svelte +++ b/objects/sandbox-example/src/App.svelte @@ -1,9 +1,38 @@ -
+
+ +
diff --git a/packages/adapter/src/index.ts b/packages/adapter/src/index.ts index d3ecd13..61c39d4 100644 --- a/packages/adapter/src/index.ts +++ b/packages/adapter/src/index.ts @@ -1,5 +1,5 @@ import pDefer, { DeferredPromise } from "p-defer"; -import { DataMessage, JSONSerializable, Token, TokenSchema, TransactionSchema, TransactionStateSchema, WakuObjectAdapter, WakuObjectArgs, WakuObjectContext, WakuObjectState } from './types' +import { DataMessage, JSONSerializable, Token, TokenSchema, TransactionSchema, TransactionStateSchema, WakuObjectAdapter, WakuObjectArgs, WakuObjectContext, WakuObjectContextProps, WakuObjectState } from './types' import { Contract } from "ethers"; interface AdapterRequestMessage { @@ -31,11 +31,13 @@ export interface IframeDataMessage { type: 'iframe-data-message' message: DataMessage state: WakuObjectState + context: WakuObjectContextProps } -export interface IframeStartMessage { - type: 'iframe-start-message' +export interface IframeContextChange { + type: 'iframe-context-change' state: WakuObjectState + context: WakuObjectContextProps } // Store @@ -72,6 +74,10 @@ function isIframeDataMessage(message: any): message is IframeDataMessage { return typeof message == "object" && message?.type === "iframe-data-message" } +function isIframeContextChange(message: any): message is IframeContextChange { + return typeof message == "object" && message?.type === 'iframe-context-change' +} + const isAdapterResponseMessage = (message: any): message is AdapterResponseMessage => { return typeof message == "object" && message?.type === "adapter" && typeof message?.id === 'string'; }; @@ -166,7 +172,7 @@ export function makeWakuObjectAdapter(): WakuObjectAdapter { } } -export function makeWakuObjectContext(adapter: WakuObjectAdapter): WakuObjectContext { +export function makeWakuObjectContext(adapter: WakuObjectAdapter, contextProps?: Partial): WakuObjectContext { async function send(data: JSONSerializable) { const response = await adapterFunction('send')(JSON.stringify(data)) if (!response) { @@ -189,6 +195,7 @@ export function makeWakuObjectContext(adapter: WakuObjectAdapter): WakuObjectCon return { ...adapter, + ...contextProps, send, updateStore, onViewChange, @@ -197,12 +204,12 @@ export function makeWakuObjectContext(adapter: WakuObjectAdapter): WakuObjectCon interface EventListenerOptions { onDataMessage: (dataMessage: DataMessage, args: WakuObjectArgs) => Promise + onContextChange: (state: WakuObjectState, context: WakuObjectContextProps) => Promise } export function startEventListener(options: Partial) { // Start listener window.addEventListener("message", (event) => { - console.debug('adapter sdk', { event }) // Check if the message came from the parent (chat app) /* if (event.origin !== "null" || event.source !== parent.contentWindow) { @@ -215,7 +222,7 @@ export function startEventListener(options: Partial) { if (isIframeDataMessage(data)) { const message = data.message as DataMessage const adapter = makeWakuObjectAdapter() - const context = makeWakuObjectContext(adapter) + const context = makeWakuObjectContext(adapter, data.context) const args: WakuObjectArgs = { ...context, ...data.state @@ -226,6 +233,12 @@ export function startEventListener(options: Partial) { return } + if (isIframeContextChange(data)) { + if (options.onContextChange) { + options.onContextChange(data.state, data.context) + } + } + if (!isAdapterResponseMessage(data)) { return; } @@ -245,4 +258,7 @@ export function startEventListener(options: Partial) { defer.resolve(data.result.value); }); + // send `init` message after object side initialization is complete + // the host application will respond with the updated context + parent.postMessage({ type: 'init' }, '*') } diff --git a/packages/adapter/src/types.ts b/packages/adapter/src/types.ts index 310cac0..d5f8528 100644 --- a/packages/adapter/src/types.ts +++ b/packages/adapter/src/types.ts @@ -69,7 +69,7 @@ export interface JSONArray extends Array {} export type JSONValue = JSONPrimitive | JSONObject | JSONArray -export type JSONSerializable = JSONValue +export type JSONSerializable = JSONValue export interface WakuObjectState { readonly chatId: string @@ -83,24 +83,29 @@ export interface WakuObjectState { type StoreType = JSONSerializable type DataMessageType = JSONSerializable -export interface WakuObjectContext extends WakuObjectAdapter { +export interface WakuObjectContextProps { readonly store?: StoreType + readonly view?: string +} + +export interface WakuObjectContext extends WakuObjectContextProps, WakuObjectAdapter { updateStore: (updater: (state?: StoreType) => StoreType) => void send: (data: DataMessageType) => Promise - readonly view?: string onViewChange: (view: string) => void } export interface WakuObjectArgs extends WakuObjectContext, WakuObjectState {} -export interface WakuObjectDescriptor { +interface WakuObjectMetadata { readonly objectId: string readonly name: string readonly description: string readonly logo: string +} +export interface WakuObjectDescriptor extends WakuObjectMetadata { onMessage?: (message: DataMessage, args: WakuObjectArgs) => Promise } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9bdd2aa..380c606 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,5 +1,9 @@ lockfileVersion: '6.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + importers: .: