import type { Thread } from '@wovin/core' import type { Applog, ApplogForInsertOptionalAgent } from '@wovin/core/applog' import type { ArrayOrSingle } from '@wovin/core/types' import type { ThreadIDB } from './datalog/local-applog-idb' import { withoutDeleted } from '@wovin/core' import { hasAg } from '@wovin/core/applog' import { action } from '@wovin/core/mobx' import { arrayIfSingle } from '@wovin/core/types' import { Logger } from 'besonders-logger' import { initUseAgent } from './lazy-agent' import { loadAppThread, sanityCheck } from './loadAppThread' const { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO) // eslint-disable-line unused-imports/no-unused-vars // let applogDB: DatalogDB export type AppThread = ThreadIDB // prep for tagged type let applogDB: ThreadIDB | null | true let useAgent: Awaited> export async function initApplogDB() { if (applogDB) { if (applogDB === true) { // = initializing if (import.meta.env.DEV) window.location.reload() // HACK can't be bothered to fix HMR throw ERROR('concurrent attempts to initApplogDB') } WARN('[initApplogDB] already initialized') // happens on HMR return applogDB } applogDB = true // to trigger the above while we're initializing useAgent = await initUseAgent() // saturate from IDB // @ts-expect-error not sure how to do this right applogDB = await loadAppThread() as Omit & { filters: [] } if (typeof window != 'undefined') { // @ts-expect-error because window window.db = applogDB // @ts-expect-error because window window.appThread = applogDB // @ts-expect-error because window window.thread = applogDB // it's nice to be able to copy-paste into devtools // @ts-expect-error because window window.currentThread = withoutDeleted(lastWriteWins(applogDB)) // @ts-expect-error because window window.insertApplogs = insertApplogs } return applogDB as ThreadIDB } export function getApplogDB() { if (!applogDB) { if (import.meta.hot) { window.location.reload() // HACK to work around HMR issue } throw new Error(`Uninitizalized`) } if (applogDB === true) { throw new Error(`ApplogDB init not done yet`) } return applogDB } export const addAgentToApplog = function addAgentToApplog(log: ApplogForInsertOptionalAgent, ag?: string) { ag = ag ?? useAgent?.().ag if (!ag) throw ERROR(`missing agentHash`) return hasAg(log) ? log : ({ ...log, ag }) /* , vl: log.vl //? was this a brain fart or still relevant */ } export const addAgentToApplogs = function addAgentToApplogs(applogs: readonly ApplogForInsertOptionalAgent[]) { const ag = useAgent?.().ag if (!ag) throw ERROR(`missing agentHash`) return applogs.filter(log => !!log).map(log => addAgentToApplog(log, ag)) // filter is to purge falsy logs } export const insertApplogs = action(function insertApplogs(thread: Thread, applogs: ArrayOrSingle) { return thread.insert(addAgentToApplogs(arrayIfSingle(applogs))) }) export const insertApplogsInAppDB = action(function insertApplogsInAppDB(applogs: ArrayOrSingle) { return getApplogDB().insert(addAgentToApplogs(arrayIfSingle(applogs))) }) export const insertCompleteApplogsInAppDBifMissing = action( function insertApplogsInAppDB(applogs: ArrayOrSingle) { const missingApplogs = arrayIfSingle(applogs).filter(log => !(getApplogDB().hasApplog(log, false))) return getApplogDB().insert(sanityCheck(missingApplogs)) }, ) if (import.meta.hot) { import.meta.hot.accept((module) => { // You may use the new module instance to decide whether to invalidate. // if (cannotHandleUpdate(module)) { LOG(`HMR applogDB - invalidated `, import.meta.hot, module) import.meta.hot.invalidate() // } }) // void initApplogDB() }