diff --git a/packages/frontend/src/pizzax.ts b/packages/frontend/src/pizzax.ts index be89644cb6..6908b87596 100644 --- a/packages/frontend/src/pizzax.ts +++ b/packages/frontend/src/pizzax.ts @@ -22,7 +22,7 @@ type PizzaxEvent> = { export class Pizzax> extends EventEmitter> { /** - * static の略 (static が予約語のため) + * static / state の略 (static が予約語のため) */ public s = {} as { [K in keyof Data]: Data[K]; diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index edbd7da608..2171abb60f 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -20,6 +20,7 @@ import * as idb from '@/utility/idb-proxy.js'; import { misskeyApi } from '@/utility/misskey-api.js'; import { useStream } from '@/stream.js'; import { deepMerge } from '@/utility/merge.js'; +import { deepClone } from '@/utility/clone.js'; type StateDef = Record = { [K in keyof T]: T[K]['default']; }; -type ArrayElement = A extends readonly (infer T)[] ? T : never; - type PizzaxChannelMessage = { where: 'device' | 'deviceAccount'; key: keyof T; @@ -79,6 +78,55 @@ class Store extends Pizzax> { this.pizzaxChannel = new BroadcastChannel(`pizzax::${key}`); this.ready = this.init(); this.loaded = this.ready.then(() => this.load()); + + this.addListener('updated', ({ key, value }) => { + // IndexedDBやBroadcastChannelで扱うために単純なオブジェクトにする + // (JSON.parse(JSON.stringify(value))の代わり) + const rawValue = deepClone(value); + + this.r[key].value = this.s[key] = rawValue; + + return this.addIdbSetJob(async () => { + switch (this.def[key].where) { + case 'device': { + this.pizzaxChannel.postMessage({ + where: 'device', + key, + value: rawValue, + }); + const deviceState = await idb.get(this.deviceStateKeyName) || {}; + deviceState[key] = rawValue; + await idb.set(this.deviceStateKeyName, deviceState); + break; + } + case 'deviceAccount': { + if ($i == null) break; + this.pizzaxChannel.postMessage({ + where: 'deviceAccount', + key, + value: rawValue, + userId: $i.id, + }); + const deviceAccountState = await idb.get(this.deviceAccountStateKeyName) || {}; + deviceAccountState[key] = rawValue; + await idb.set(this.deviceAccountStateKeyName, deviceAccountState); + break; + } + case 'account': { + if ($i == null) break; + const cache = await idb.get(this.registryCacheKeyName) || {}; + cache[key] = rawValue; + await idb.set(this.registryCacheKeyName, cache); + await misskeyApi('i/registry/set', { + scope: ['client', this.key], + key: key.toString(), + value: rawValue, + }); + break; + } + } + }); + }); } private async init(): Promise {