From 269c5a1e486a1b044dbb2af46937c67d059c804b Mon Sep 17 00:00:00 2001 From: Joel Jeremy Marquez Date: Thu, 19 Mar 2026 15:36:36 -0700 Subject: [PATCH] Use javascript proxy to encapsulate the calls to loot core server via connection package's `send` --- .../src/components/ManageRules.tsx | 4 +- .../mobile/payees/MobilePayeeEditPage.tsx | 4 +- .../mobile/payees/MobilePayeesPage.tsx | 6 +- .../modals/MergeUnusedPayeesModal.tsx | 4 +- .../payees/ManagePayeesWithData.tsx | 6 +- .../src/payees/location-adapters.ts | 10 ++-- .../desktop-client/src/payees/mutations.ts | 4 +- packages/desktop-client/src/payees/queries.ts | 10 ++-- packages/loot-core/src/mocks/budget.ts | 2 +- .../platform/client/connection/index-types.ts | 13 +++- .../client/connection/index.browser.ts | 43 +++++++++++-- .../src/platform/client/connection/index.ts | 34 ++++++++++- packages/loot-core/src/server/api.ts | 22 +++---- packages/loot-core/src/server/app.ts | 27 ++++++--- .../loot-core/src/server/importers/ynab5.ts | 2 +- packages/loot-core/src/server/payees/app.ts | 60 +++++++++---------- packages/loot-core/src/types/handlers.ts | 4 +- 17 files changed, 166 insertions(+), 89 deletions(-) diff --git a/packages/desktop-client/src/components/ManageRules.tsx b/packages/desktop-client/src/components/ManageRules.tsx index 482379419e..5d73533e83 100644 --- a/packages/desktop-client/src/components/ManageRules.tsx +++ b/packages/desktop-client/src/components/ManageRules.tsx @@ -10,7 +10,7 @@ import { Text } from '@actual-app/components/text'; import { theme } from '@actual-app/components/theme'; import { View } from '@actual-app/components/view'; -import { send } from 'loot-core/platform/client/connection'; +import { send, server } from 'loot-core/platform/client/connection'; import * as undo from 'loot-core/platform/client/undo'; import { getNormalisedString } from 'loot-core/shared/normalisation'; import { q } from 'loot-core/shared/query'; @@ -176,7 +176,7 @@ export function ManageRules({ let loadedRules = null; if (payeeId) { - loadedRules = await send('payees-get-rules', { + loadedRules = await server.getPayeeRules({ id: payeeId, }); } else { diff --git a/packages/desktop-client/src/components/mobile/payees/MobilePayeeEditPage.tsx b/packages/desktop-client/src/components/mobile/payees/MobilePayeeEditPage.tsx index 9c83e38240..642cd02d4d 100644 --- a/packages/desktop-client/src/components/mobile/payees/MobilePayeeEditPage.tsx +++ b/packages/desktop-client/src/components/mobile/payees/MobilePayeeEditPage.tsx @@ -8,7 +8,7 @@ import { Text } from '@actual-app/components/text'; import { theme } from '@actual-app/components/theme'; import { View } from '@actual-app/components/view'; -import { send } from 'loot-core/platform/client/connection'; +import { server } from 'loot-core/platform/client/connection'; import type { PayeeEntity } from 'loot-core/types/models'; import { MobileBackButton } from '@desktop-client/components/mobile/MobileBackButton'; @@ -58,7 +58,7 @@ export function MobilePayeeEditPage() { } try { - await send('payees-batch-change', { + await server.batchChangePayees({ updated: [{ id: payee.id, name: editedPayeeName.trim() }], }); showUndoNotification({ diff --git a/packages/desktop-client/src/components/mobile/payees/MobilePayeesPage.tsx b/packages/desktop-client/src/components/mobile/payees/MobilePayeesPage.tsx index f9c575bc6b..a7ed768d8e 100644 --- a/packages/desktop-client/src/components/mobile/payees/MobilePayeesPage.tsx +++ b/packages/desktop-client/src/components/mobile/payees/MobilePayeesPage.tsx @@ -5,7 +5,7 @@ import { styles } from '@actual-app/components/styles'; import { theme } from '@actual-app/components/theme'; import { View } from '@actual-app/components/view'; -import { send } from 'loot-core/platform/client/connection'; +import { server } from 'loot-core/platform/client/connection'; import { getNormalisedString } from 'loot-core/shared/normalisation'; import type { PayeeEntity, RuleEntity } from 'loot-core/types/models'; @@ -52,7 +52,7 @@ export function MobilePayeesPage() { // View associated rules for the payee if ((ruleCounts.get(payee.id) ?? 0) > 0) { try { - const associatedRules: RuleEntity[] = await send('payees-get-rules', { + const associatedRules: RuleEntity[] = await server.getPayeeRules({ id: payee.id, }); const ruleIds = associatedRules.map(rule => rule.id).join(','); @@ -88,7 +88,7 @@ export function MobilePayeesPage() { const handlePayeeDelete = useCallback( async (payee: PayeeEntity) => { try { - await send('payees-batch-change', { deleted: [{ id: payee.id }] }); + await server.batchChangePayees({ deleted: [{ id: payee.id }] }); showUndoNotification({ message: t('Payee "{{name}}" deleted successfully', { name: payee.name, diff --git a/packages/desktop-client/src/components/modals/MergeUnusedPayeesModal.tsx b/packages/desktop-client/src/components/modals/MergeUnusedPayeesModal.tsx index 2960e35618..7c13177e33 100644 --- a/packages/desktop-client/src/components/modals/MergeUnusedPayeesModal.tsx +++ b/packages/desktop-client/src/components/modals/MergeUnusedPayeesModal.tsx @@ -7,7 +7,7 @@ import { Text } from '@actual-app/components/text'; import { theme } from '@actual-app/components/theme'; import { View } from '@actual-app/components/view'; -import { send } from 'loot-core/platform/client/connection'; +import { send, server } from 'loot-core/platform/client/connection'; import type { PayeeEntity } from 'loot-core/types/models'; import type { TransObjectLiteral } from 'loot-core/types/util'; @@ -59,7 +59,7 @@ export function MergeUnusedPayeesModal({ const onMerge = useCallback( async (targetPayee: PayeeEntity) => { - await send('payees-merge', { + await server.mergePayees({ targetId: targetPayee.id, mergeIds: payees.map(payee => payee.id), }); diff --git a/packages/desktop-client/src/components/payees/ManagePayeesWithData.tsx b/packages/desktop-client/src/components/payees/ManagePayeesWithData.tsx index de7186622b..23a45f7b84 100644 --- a/packages/desktop-client/src/components/payees/ManagePayeesWithData.tsx +++ b/packages/desktop-client/src/components/payees/ManagePayeesWithData.tsx @@ -2,7 +2,7 @@ import React, { useEffect } from 'react'; import { useQueryClient } from '@tanstack/react-query'; -import { listen, send } from 'loot-core/platform/client/connection'; +import { listen, server } from 'loot-core/platform/client/connection'; import * as undo from 'loot-core/platform/client/undo'; import type { UndoState } from 'loot-core/server/undo'; import { applyChanges } from 'loot-core/shared/util'; @@ -112,14 +112,14 @@ export function ManagePayeesWithData({ orphanedPayees={orphanedPayees} initialSelectedIds={initialSelectedIds} onBatchChange={async (changes: Diff) => { - await send('payees-batch-change', changes); + await server.batchChangePayees(changes); queryClient.setQueryData( payeeQueries.listOrphaned().queryKey, existing => applyChanges(changes, existing ?? []), ); }} onMerge={async ([targetId, ...mergeIds]) => { - await send('payees-merge', { targetId, mergeIds }); + await server.mergePayees({ targetId, mergeIds }); const targetIdIsOrphan = orphanedPayees .map(o => o.id) diff --git a/packages/desktop-client/src/payees/location-adapters.ts b/packages/desktop-client/src/payees/location-adapters.ts index ae86ba4468..6c6722e21c 100644 --- a/packages/desktop-client/src/payees/location-adapters.ts +++ b/packages/desktop-client/src/payees/location-adapters.ts @@ -1,4 +1,4 @@ -import { send } from 'loot-core/platform/client/connection'; +import { server } from 'loot-core/platform/client/connection'; import type { LocationCoordinates } from 'loot-core/shared/location-utils'; import type { NearbyPayeeEntity, @@ -68,7 +68,7 @@ export class SendApiLocationClient implements LocationApiClient { payeeId: string, coordinates: LocationCoordinates, ): Promise { - return await send('payee-location-create', { + return await server.createPayeeLocation({ payeeId, latitude: coordinates.latitude, longitude: coordinates.longitude, @@ -76,18 +76,18 @@ export class SendApiLocationClient implements LocationApiClient { } async getLocations(payeeId: string): Promise { - return await send('payee-locations-get', { payeeId }); + return await server.getPayeeLocations({ payeeId }); } async deleteLocation(locationId: string): Promise { - await send('payee-location-delete', { id: locationId }); + await server.deletePayeeLocation({ id: locationId }); } async getNearbyPayees( coordinates: LocationCoordinates, maxDistance: number, ): Promise { - const result = await send('payees-get-nearby', { + const result = await server.getNearbyPayees({ latitude: coordinates.latitude, longitude: coordinates.longitude, maxDistance, diff --git a/packages/desktop-client/src/payees/mutations.ts b/packages/desktop-client/src/payees/mutations.ts index 23ddca1ad3..b262f6ce65 100644 --- a/packages/desktop-client/src/payees/mutations.ts +++ b/packages/desktop-client/src/payees/mutations.ts @@ -4,7 +4,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import type { QueryClient, QueryKey } from '@tanstack/react-query'; import { v4 as uuidv4 } from 'uuid'; -import { send } from 'loot-core/platform/client/connection'; +import { server } from 'loot-core/platform/client/connection'; import type { PayeeEntity } from 'loot-core/types/models'; import { locationService } from './location'; @@ -99,7 +99,7 @@ export function useCreatePayeeMutation() { return useMutation({ mutationFn: async ({ name }: CreatePayeePayload) => { - const id: PayeeEntity['id'] = await send('payee-create', { + const id: PayeeEntity['id'] = await server.createPayee({ name: name.trim(), }); return id; diff --git a/packages/desktop-client/src/payees/queries.ts b/packages/desktop-client/src/payees/queries.ts index eeef259bd4..99200e9cbc 100644 --- a/packages/desktop-client/src/payees/queries.ts +++ b/packages/desktop-client/src/payees/queries.ts @@ -2,7 +2,7 @@ import { queryOptions } from '@tanstack/react-query'; import { t } from 'i18next'; import memoizeOne from 'memoize-one'; -import { send } from 'loot-core/platform/client/connection'; +import { server } from 'loot-core/platform/client/connection'; import { groupById } from 'loot-core/shared/util'; import type { AccountEntity, @@ -21,7 +21,7 @@ export const payeeQueries = { queryOptions({ queryKey: [...payeeQueries.lists()], queryFn: async () => { - const payees: PayeeEntity[] = (await send('payees-get')) ?? []; + const payees: PayeeEntity[] = (await server.getPayees()) ?? []; return translatePayees(payees); }, placeholderData: [], @@ -32,7 +32,7 @@ export const payeeQueries = { queryOptions({ queryKey: [...payeeQueries.lists(), 'common'], queryFn: async () => { - const payees: PayeeEntity[] = (await send('common-payees-get')) ?? []; + const payees: PayeeEntity[] = (await server.getCommonPayees()) ?? []; return translatePayees(payees); }, placeholderData: [], @@ -44,7 +44,7 @@ export const payeeQueries = { queryKey: [...payeeQueries.lists(), 'orphaned'], queryFn: async () => { const payees: Pick[] = - (await send('payees-get-orphaned')) ?? []; + (await server.getOrphanedPayees()) ?? []; return payees; }, placeholderData: [], @@ -55,7 +55,7 @@ export const payeeQueries = { queryOptions>({ queryKey: [...payeeQueries.lists(), 'ruleCounts'], queryFn: async () => { - const counts = await send('payees-get-rule-counts'); + const counts = await server.getPayeeRuleCounts(); return new Map(Object.entries(counts ?? {})); }, placeholderData: new Map(), diff --git a/packages/loot-core/src/mocks/budget.ts b/packages/loot-core/src/mocks/budget.ts index 67d6be5da8..8ba8671bec 100644 --- a/packages/loot-core/src/mocks/budget.ts +++ b/packages/loot-core/src/mocks/budget.ts @@ -642,7 +642,7 @@ export async function createTestBudget(handlers: Handlers) { await runMutator(() => batchMessages(async () => { for (const newPayee of newPayees) { - const id = await handlers['payee-create']({ name: newPayee.name }); + const id = await handlers['createPayee']({ name: newPayee.name }); payees.push({ id, name: newPayee.name, diff --git a/packages/loot-core/src/platform/client/connection/index-types.ts b/packages/loot-core/src/platform/client/connection/index-types.ts index 5601523e7e..fb62aed618 100644 --- a/packages/loot-core/src/platform/client/connection/index-types.ts +++ b/packages/loot-core/src/platform/client/connection/index-types.ts @@ -1,7 +1,18 @@ import type { Handlers } from '../../../types/handlers'; import type { ServerEvents } from '../../../types/server-events'; -export declare function init(): Promise; +/** + * Loot core server proxy. + */ +export type ServerProxy = { + [K in keyof Handlers]: ( + args?: Parameters[0], + ) => ReturnType; +}; + +export declare const server: ServerProxy; + +export declare function init(): Promise; export type Init = typeof init; /** diff --git a/packages/loot-core/src/platform/client/connection/index.browser.ts b/packages/loot-core/src/platform/client/connection/index.browser.ts index ed6c93ef24..27989e4d9a 100644 --- a/packages/loot-core/src/platform/client/connection/index.browser.ts +++ b/packages/loot-core/src/platform/client/connection/index.browser.ts @@ -12,6 +12,7 @@ const listeners = new Map(); let messageQueue = []; let globalWorker = null; +let initPromise: Promise | null = null; class ReconstructedError extends Error { url: string; @@ -83,6 +84,31 @@ function handleMessage(msg) { } } +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export const server: T.ServerProxy = new Proxy({} as T.ServerProxy, { + get(_target, prop: string | symbol) { + if (typeof prop === 'symbol') { + return undefined; + } + + // Returning undefined for 'then' prevents the proxy from being + // treated as a thenable when awaited, which would cause Promise + // machinery to call server.then(resolve, reject) with native functions. + if (prop === 'then') { + return undefined; + } + + if (!initPromise) { + throw new Error( + `Cannot use server proxy before init() has been called`, + ); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return (args?: any) => send(prop as any, args); + }, +}); + // Note that this does not support retry. If the worker // dies, it will permanently be disconnected. That should be OK since // I don't think a worker should ever die due to a system error. @@ -107,7 +133,7 @@ function connectWorker(worker, onOpen, onError) { globalWorker.postMessage({ name: 'client-connected-to-backend', }); - onOpen(); + onOpen(server); } else if (msg.type === 'app-init-failure') { globalWorker.postMessage({ name: '__app-init-failure-acknowledged', @@ -149,11 +175,16 @@ function connectWorker(worker, onOpen, onError) { } } -export const init: T.Init = async function () { - const worker = await global.Actual.getServerSocket(); - return new Promise((resolve, reject) => - connectWorker(worker, resolve, reject), - ); +export const init: T.Init = function () { + if (!initPromise) { + initPromise = global.Actual.getServerSocket().then( + worker => + new Promise((resolve, reject) => + connectWorker(worker, resolve, reject), + ), + ); + } + return initPromise; }; export const send: T.Send = function ( diff --git a/packages/loot-core/src/platform/client/connection/index.ts b/packages/loot-core/src/platform/client/connection/index.ts index 6a76fdfaad..d420c9e9f3 100644 --- a/packages/loot-core/src/platform/client/connection/index.ts +++ b/packages/loot-core/src/platform/client/connection/index.ts @@ -9,6 +9,31 @@ const replyHandlers = new Map(); const listeners = new Map(); let messageQueue = []; let socketClient = null; +let initPromise: Promise | null = null; + +export const server: T.ServerProxy = new Proxy({} as T.ServerProxy, { + get(_target, prop: string | symbol) { + if (typeof prop === 'symbol') { + return undefined; + } + + // Returning undefined for 'then' prevents the proxy from being + // treated as a thenable when awaited, which would cause Promise + // machinery to call server.then(resolve, reject) with native functions. + if (prop === 'then') { + return undefined; + } + + if (!initPromise) { + throw new Error( + `Cannot use server proxy before init() has been called`, + ); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return (args?: any) => send(prop as any, args); + }, +}); function connectSocket(onOpen) { global.Actual.ipcConnect(function (client) { @@ -72,12 +97,15 @@ function connectSocket(onOpen) { messageQueue = []; } - onOpen(); + onOpen(server); }); } -export const init: T.Init = async function () { - return new Promise(connectSocket); +export const init: T.Init = function () { + if (!initPromise) { + initPromise = new Promise(connectSocket); + } + return initPromise; }; export const send: T.Send = function ( diff --git a/packages/loot-core/src/server/api.ts b/packages/loot-core/src/server/api.ts index fbb94dcbab..13d9a53931 100644 --- a/packages/loot-core/src/server/api.ts +++ b/packages/loot-core/src/server/api.ts @@ -705,31 +705,31 @@ handlers['api/category-delete'] = withMutation(async function ({ handlers['api/common-payees-get'] = async function () { checkFileOpen(); - const payees = await handlers['common-payees-get'](); + const payees = await handlers['getCommonPayees'](); return payees.map(payee => payeeModel.toExternal(payee)); }; handlers['api/payees-get'] = async function () { checkFileOpen(); - const payees = await handlers['payees-get'](); + const payees = await handlers['getPayees'](); return payees.map(payee => payeeModel.toExternal(payee)); }; handlers['api/payee-create'] = withMutation(async function ({ payee }) { checkFileOpen(); - return handlers['payee-create']({ name: payee.name }); + return handlers['createPayee']({ name: payee.name }); }); handlers['api/payee-update'] = withMutation(async function ({ id, fields }) { checkFileOpen(); - return handlers['payees-batch-change']({ + return handlers['batchChangePayees']({ updated: [{ id, ...payeeModel.fromExternal(fields) }], }); }); handlers['api/payee-delete'] = withMutation(async function ({ id }) { checkFileOpen(); - return handlers['payees-batch-change']({ deleted: [{ id }] }); + return handlers['batchChangePayees']({ deleted: [{ id }] }); }); handlers['api/payees-merge'] = withMutation(async function ({ @@ -737,7 +737,7 @@ handlers['api/payees-merge'] = withMutation(async function ({ mergeIds, }) { checkFileOpen(); - return handlers['payees-merge']({ targetId, mergeIds }); + return handlers['mergePayees']({ targetId, mergeIds }); }); handlers['api/tags-get'] = async function () { @@ -772,17 +772,17 @@ handlers['api/payee-location-create'] = withMutation(async function ({ longitude, }) { checkFileOpen(); - return handlers['payee-location-create']({ payeeId, latitude, longitude }); + return handlers['createPayeeLocation']({ payeeId, latitude, longitude }); }); handlers['api/payee-locations-get'] = async function ({ payeeId }) { checkFileOpen(); - return handlers['payee-locations-get']({ payeeId }); + return handlers['getPayeeLocations']({ payeeId }); }; handlers['api/payee-location-delete'] = withMutation(async function ({ id }) { checkFileOpen(); - return handlers['payee-location-delete']({ id }); + return handlers['deletePayeeLocation']({ id }); }); handlers['api/payees-get-nearby'] = async function ({ @@ -791,7 +791,7 @@ handlers['api/payees-get-nearby'] = async function ({ maxDistance, }) { checkFileOpen(); - return handlers['payees-get-nearby']({ latitude, longitude, maxDistance }); + return handlers['getNearbyPayees']({ latitude, longitude, maxDistance }); }; handlers['api/rules-get'] = async function () { @@ -801,7 +801,7 @@ handlers['api/rules-get'] = async function () { handlers['api/payee-rules-get'] = async function ({ id }) { checkFileOpen(); - return handlers['payees-get-rules']({ id }); + return handlers['getPayeeRules']({ id }); }; handlers['api/rule-create'] = withMutation(async function ({ rule }) { diff --git a/packages/loot-core/src/server/app.ts b/packages/loot-core/src/server/app.ts index 2896f0c6e4..5405d538d7 100644 --- a/packages/loot-core/src/server/app.ts +++ b/packages/loot-core/src/server/app.ts @@ -18,22 +18,31 @@ type Events = { type UnlistenService = () => void; type Service = () => UnlistenService; -class App { +class App { events: Emitter; - handlers: Handlers; + handlers: THandlers; services: Service[]; unlistenServices: UnlistenService[]; - constructor() { - this.handlers = {} as Handlers; + constructor(handlers?: THandlers) { + this.handlers = {} as THandlers; this.services = []; this.events = mitt(); this.unlistenServices = []; + + if (handlers) { + for (const [name, func] of Object.entries(handlers)) { + this.method( + name as string & keyof THandlers, + func as THandlers[string & keyof THandlers], + ); + } + } } - method( + method( name: Name, - func: Handlers[Name], + func: THandlers[Name], ) { if (this.handlers[name] != null) { throw new Error( @@ -50,7 +59,7 @@ class App { combine(...apps) { for (const app of apps) { Object.keys(app.handlers).forEach(name => { - this.method(name as string & keyof Handlers, app.handlers[name]); + this.method(name as string & keyof THandlers, app.handlers[name]); }); app.services.forEach(service => { @@ -86,6 +95,6 @@ class App { } } -export function createApp() { - return new App(); +export function createApp(handlers?: THandlers): App { + return new App(handlers); } diff --git a/packages/loot-core/src/server/importers/ynab5.ts b/packages/loot-core/src/server/importers/ynab5.ts index 9fc7676b66..47fa98fbef 100644 --- a/packages/loot-core/src/server/importers/ynab5.ts +++ b/packages/loot-core/src/server/importers/ynab5.ts @@ -498,7 +498,7 @@ async function importPayeeLocations( try { // Create the payee location in Actual - await send('payee-location-create', { + await send('createPayeeLocation', { payeeId: actualPayeeId, latitude, longitude, diff --git a/packages/loot-core/src/server/payees/app.ts b/packages/loot-core/src/server/payees/app.ts index 80b8431bbc..3015ec69ac 100644 --- a/packages/loot-core/src/server/payees/app.ts +++ b/packages/loot-core/src/server/payees/app.ts @@ -14,44 +14,42 @@ import { batchMessages } from '../sync'; import * as rules from '../transactions/transaction-rules'; import { undoable } from '../undo'; -export type PayeesHandlers = { - 'payee-create': typeof createPayee; - 'common-payees-get': typeof getCommonPayees; - 'payees-get': typeof getPayees; - 'payees-get-orphaned': typeof getOrphanedPayees; - 'payees-get-rule-counts': typeof getPayeeRuleCounts; - 'payees-merge': typeof mergePayees; - 'payees-batch-change': typeof batchChangePayees; - 'payees-check-orphaned': typeof checkOrphanedPayees; - 'payees-get-rules': typeof getPayeeRules; - 'payee-location-create': typeof createPayeeLocation; - 'payee-locations-get': typeof getPayeeLocations; - 'payee-location-delete': typeof deletePayeeLocation; - 'payees-get-nearby': typeof getNearbyPayees; +export type PayeeHandlers = { + createPayee: typeof createPayee; + getCommonPayees: typeof getCommonPayees; + getPayees: typeof getPayees; + getOrphanedPayees: typeof getOrphanedPayees; + getPayeeRuleCounts: typeof getPayeeRuleCounts; + mergePayees: typeof mergePayees; + batchChangePayees: typeof batchChangePayees; + checkOrphanedPayees: typeof checkOrphanedPayees; + getPayeeRules: typeof getPayeeRules; + createPayeeLocation: typeof createPayeeLocation; + getPayeeLocations: typeof getPayeeLocations; + deletePayeeLocation: typeof deletePayeeLocation; + getNearbyPayees: typeof getNearbyPayees; }; -export const app = createApp(); -app.method('payee-create', mutator(undoable(createPayee))); -app.method('common-payees-get', getCommonPayees); -app.method('payees-get', getPayees); -app.method('payees-get-orphaned', getOrphanedPayees); -app.method('payees-get-rule-counts', getPayeeRuleCounts); -app.method( - 'payees-merge', - mutator( +export const app = createApp({ + createPayee: mutator(undoable(createPayee)), + batchChangePayees: mutator(undoable(batchChangePayees)), + createPayeeLocation: mutator(createPayeeLocation), + deletePayeeLocation: mutator(deletePayeeLocation), + mergePayees: mutator( undoable(mergePayees, args => ({ mergeIds: args.mergeIds, targetId: args.targetId, })), ), -); -app.method('payees-batch-change', mutator(undoable(batchChangePayees))); -app.method('payees-check-orphaned', checkOrphanedPayees); -app.method('payees-get-rules', getPayeeRules); -app.method('payee-location-create', mutator(createPayeeLocation)); -app.method('payee-locations-get', getPayeeLocations); -app.method('payee-location-delete', mutator(deletePayeeLocation)); -app.method('payees-get-nearby', getNearbyPayees); + getCommonPayees, + getPayees, + getOrphanedPayees, + getPayeeRuleCounts, + checkOrphanedPayees, + getPayeeRules, + getPayeeLocations, + getNearbyPayees, +}); async function createPayee({ name }: { name: PayeeEntity['name'] }) { return db.insertPayee({ name }); diff --git a/packages/loot-core/src/types/handlers.ts b/packages/loot-core/src/types/handlers.ts index 37bd9d623f..a90e85b79b 100644 --- a/packages/loot-core/src/types/handlers.ts +++ b/packages/loot-core/src/types/handlers.ts @@ -7,7 +7,7 @@ import type { DashboardHandlers } from '../server/dashboard/app'; import type { EncryptionHandlers } from '../server/encryption/app'; import type { FiltersHandlers } from '../server/filters/app'; import type { NotesHandlers } from '../server/notes/app'; -import type { PayeesHandlers } from '../server/payees/app'; +import type { PayeeHandlers } from '../server/payees/app'; import type { PreferencesHandlers } from '../server/preferences/app'; import type { ReportsHandlers } from '../server/reports/app'; import type { RulesHandlers } from '../server/rules/app'; @@ -35,7 +35,7 @@ export type Handlers = {} & ServerHandlers & AdminHandlers & ToolsHandlers & AccountHandlers & - PayeesHandlers & + PayeeHandlers & SpreadsheetHandlers & SyncHandlers & BudgetFileHandlers &