diff --git a/app/libs/package.json b/app/libs/package.json index 230003ad..b67be60e 100644 --- a/app/libs/package.json +++ b/app/libs/package.json @@ -1,7 +1,7 @@ { "name": "@metapages/metapage", "public": true, - "version": "1.0.12", + "version": "1.0.13", "description": "Connect web pages together", "repository": "https://github.com/metapages/metapage", "homepage": "https://metapage.io/", diff --git a/app/libs/src/metapage/Metaframe.ts b/app/libs/src/metapage/Metaframe.ts index 58d4b285..b34b2fb6 100644 --- a/app/libs/src/metapage/Metaframe.ts +++ b/app/libs/src/metapage/Metaframe.ts @@ -350,12 +350,14 @@ export class Metaframe extends EventEmitter< async setInternalInputsAndNotify(inputs: MetaframeInputMap) { // this is where we deserialize the inputs - + if (this.isInputOutputBlobSerialization) { inputs = await deserializeInputs(inputs); } - if (!merge(this._inputPipeValues, inputs)) { + const originalInputs = inputs; + this._inputPipeValues = merge(this._inputPipeValues, inputs); + if (this._inputPipeValues === originalInputs) { return; } @@ -403,9 +405,13 @@ export class Metaframe extends EventEmitter< if (this.isInputOutputBlobSerialization) { outputs = await serializeInputs(outputs); } - if (!merge(this._outputPipeValues, outputs)) { + + const originalOutputs = outputs; + this._outputPipeValues = merge(this._outputPipeValues, outputs); + if (this._outputPipeValues === originalOutputs) { return; } + this.sendRpc(JsonRpcMethodsFromChild.OutputsUpdate, outputs); } diff --git a/app/libs/src/metapage/MetapageIFrameRpcClient.ts b/app/libs/src/metapage/MetapageIFrameRpcClient.ts index 9ff5073e..1e2df0a8 100644 --- a/app/libs/src/metapage/MetapageIFrameRpcClient.ts +++ b/app/libs/src/metapage/MetapageIFrameRpcClient.ts @@ -250,9 +250,13 @@ export class MetapageIFrameRpcClient extends EventEmitter< }; public setInputs(maybeNewInputs: MetaframeInputMap): MetapageIFrameRpcClient { this.log({ m: "MetapageIFrameRpcClient", inputs: maybeNewInputs }); - if (!merge(this.inputs, maybeNewInputs)) { + + const originalInputs = maybeNewInputs; + this.inputs = merge(this.inputs, maybeNewInputs); + if (this.inputs === originalInputs) { return this; } + if (!this._loaded) { this._sendInputsAfterRegistration = true; } @@ -291,9 +295,13 @@ export class MetapageIFrameRpcClient extends EventEmitter< inputs: null, }; public setOutputs(maybeNewOutputs: MetaframeInputMap) { - if (!merge(this.outputs, maybeNewOutputs)) { - return; + + const originalOutputs = maybeNewOutputs; + this.outputs = merge(this.outputs, maybeNewOutputs); + if (this.outputs === originalOutputs) { + return this; } + this.emit(MetapageEvents.Outputs, maybeNewOutputs); if (this._metapage.listenerCount(MetapageEvents.Outputs) > 0) { diff --git a/app/libs/src/metapage/MetapageTools.ts b/app/libs/src/metapage/MetapageTools.ts index 167c6608..d8e1114c 100644 --- a/app/libs/src/metapage/MetapageTools.ts +++ b/app/libs/src/metapage/MetapageTools.ts @@ -1,5 +1,5 @@ import stringify from 'fast-json-stable-stringify'; - +import { create } from 'mutative'; import { MetapageHashParams } from './Shared.js'; import { MetaframeId, @@ -12,32 +12,31 @@ import { MetaframeInputMap, } from './v0_4/index.js'; /** - * Merges new values into the current object. + * Merges new values into the a new object. * Does NOT check if there are actually new keys. * Does NOT check values against each other. This means you * can keep sending the same value, and the message will * be passed in. - * Returns true if the original map was modified. + * Returns the original map if nothing modified. */ export const merge = ( current: MetaframeInputMap, newInputs: MetaframeInputMap -): boolean => { +): MetaframeInputMap => { if (!newInputs) { - return false; + return current; } - let modified = false; - Object.keys(newInputs).forEach((pipeId: string) => { - modified = true; - // undefined means remove the key - // null means keep the key, but set to null - if (newInputs[pipeId] === undefined) { - delete current[pipeId]; - } else { - current[pipeId] = newInputs[pipeId]; - } + return create(current, (draft: MetaframeInputMap) => { + Object.keys(newInputs).forEach((pipeId: string) => { + // undefined means remove the key + // null means keep the key, but set to null + if (newInputs[pipeId] === undefined) { + delete draft[pipeId]; + } else { + draft[pipeId] = newInputs[pipeId]; + } + }); }); - return modified; }; export const getUrlParam = (key: MetapageHashParams): string | null => { diff --git a/app/libs/src/metapage/data.ts b/app/libs/src/metapage/data.ts index 956e4928..0341864a 100644 --- a/app/libs/src/metapage/data.ts +++ b/app/libs/src/metapage/data.ts @@ -1,5 +1,6 @@ import { MetaframeInputMap } from "./v0_4"; import { encode, decode } from "base64-arraybuffer"; +import { create } from 'mutative'; /** * Modifies in place!!! @@ -10,12 +11,13 @@ export const serializeInputs = async ( inputs: MetaframeInputMap ): Promise => { // only serialize one level deep - for (const key of Object.keys(inputs)) { - const maybeNewObject = await possiblySerializeValueToDataref(inputs[key]); - inputs[key] = maybeNewObject; - } - - return inputs; + return create(inputs, async (draft: MetaframeInputMap) => { + for (const key of Object.keys(inputs)) { + const maybeNewObject = await possiblySerializeValueToDataref(inputs[key]); + draft[key] = maybeNewObject; + return draft; + } + }); }; /** diff --git a/app/worker/test/src/run-tests-in-astral.ts b/app/worker/test/src/run-tests-in-astral.ts index a540eac3..31f61232 100644 --- a/app/worker/test/src/run-tests-in-astral.ts +++ b/app/worker/test/src/run-tests-in-astral.ts @@ -197,7 +197,7 @@ const getMetapageVersions = async () :Promise => { let allVersions = await getMetapageVersions(); if (!nolocalBuild) { - allVersions.push("latest"); + allVersions.unshift("latest"); } console.log(`🍳👉 allVersions ${allVersions}`); const maxTimeAllTests = timePerTest * allVersions.length ** 2;