Skip to content

Commit

Permalink
Bundle loot-core types into the API
Browse files Browse the repository at this point in the history
So we can have loot-core be the source of truth
for some types that get passed through

- Improves downstream development with API by including types
- Use path aliases for dist vs dev tsconfigs
- Convert api index to typescript as example
- Permit ts-ignore for issues with our version of typescript
  • Loading branch information
twk3 committed Jan 17, 2024
1 parent 7d1a895 commit ab03b4d
Show file tree
Hide file tree
Showing 19 changed files with 197 additions and 63 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
packages/api/app/bundle.api.js
packages/api/dist
packages/api/@types
packages/api/migrations

packages/crdt/dist
Expand Down
5 changes: 5 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,11 @@ module.exports = {
{ patterns: [...restrictedImportPatterns, ...restrictedImportColors] },
],

'@typescript-eslint/ban-ts-comment': [
'error',
{ 'ts-ignore': 'allow-with-description' },
],

// Rules disable during TS migration
'@typescript-eslint/no-var-requires': 'off',
'prefer-const': 'warn',
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
!data/.gitkeep
/data2
packages/api/dist
packages/api/@types
packages/crdt/dist
packages/desktop-electron/client-build
packages/desktop-electron/.electron-symbols
Expand Down
38 changes: 0 additions & 38 deletions packages/api/index.js

This file was deleted.

55 changes: 55 additions & 0 deletions packages/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// @ts-ignore: false-positive commonjs module error on build until typescript 5.3
import type {
RequestInfo as FetchRequestInfo,
RequestInit as FetchRequestInit,
} from 'node-fetch'; // with { 'resolution-mode': 'import' };

// loot-core types
import type { initConfig } from 'loot-core/server/main';

// eslint-disable-next-line import/extensions
import * as bundle from './app/bundle.api.js';

Check failure on line 11 in packages/api/index.ts

View workflow job for this annotation

GitHub Actions / typecheck

Cannot find module './app/bundle.api.js' or its corresponding type declarations.
import * as injected from './injected';
import { validateNodeVersion } from './validateNodeVersion';

let actualApp: null | typeof bundle.lib;
export const internal = bundle.lib;

// DEPRECATED: remove the next line in @actual-app/api v7
export * as methods from './methods';

export * from './methods';
export * as utils from './utils';

export async function init(config: initConfig = {}) {
if (actualApp) {
return;
}

validateNodeVersion();

if (!globalThis.fetch) {
globalThis.fetch = (url: URL | RequestInfo, init?: RequestInit) => {
return import('node-fetch').then(({ default: fetch }) =>
fetch(
url as unknown as FetchRequestInfo,
init as unknown as FetchRequestInit,
),
) as unknown as Promise<Response>;
};
}

await bundle.init(config);
actualApp = bundle.lib;

injected.override(bundle.lib.send);
return bundle.lib;
}

export async function shutdown() {
if (actualApp) {
await actualApp.send('sync');
await actualApp.send('close-budget');
actualApp = null;
}
}
18 changes: 12 additions & 6 deletions packages/api/methods.js → packages/api/methods.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
// @ts-strict-ignore
import type { Handlers } from 'loot-core/src/types/handlers';

import * as injected from './injected';

export { q } from './app/query';

function send(name, args) {
function send<K extends keyof Handlers, T extends Handlers[K]>(
name: K,
args?: Parameters<T>[0],
): Promise<Awaited<ReturnType<T>>> {
return injected.send(name, args);
}

Expand All @@ -21,7 +27,7 @@ export async function loadBudget(budgetId) {
return send('api/load-budget', { id: budgetId });
}

export async function downloadBudget(syncId, { password } = {}) {
export async function downloadBudget(syncId, password?) {
return send('api/download-budget', { syncId, password });
}

Expand Down Expand Up @@ -95,15 +101,15 @@ export function getAccounts() {
return send('api/accounts-get');
}

export function createAccount(account, initialBalance) {
export function createAccount(account, initialBalance?) {
return send('api/account-create', { account, initialBalance });
}

export function updateAccount(id, fields) {
return send('api/account-update', { id, fields });
}

export function closeAccount(id, transferAccountId, transferCategoryId) {
export function closeAccount(id, transferAccountId?, transferCategoryId?) {
return send('api/account-close', {
id,
transferAccountId,
Expand All @@ -127,7 +133,7 @@ export function updateCategoryGroup(id, fields) {
return send('api/category-group-update', { id, fields });
}

export function deleteCategoryGroup(id, transferCategoryId) {
export function deleteCategoryGroup(id, transferCategoryId?) {
return send('api/category-group-delete', { id, transferCategoryId });
}

Expand All @@ -143,7 +149,7 @@ export function updateCategory(id, fields) {
return send('api/category-update', { id, fields });
}

export function deleteCategory(id, transferCategoryId) {
export function deleteCategory(id, transferCategoryId?) {
return send('api/category-delete', { id, transferCategoryId });
}

Expand Down
10 changes: 6 additions & 4 deletions packages/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@
"node": ">=18.12.0"
},
"main": "dist/index.js",
"types": "dist/index.d.ts",
"types": "@types/index.d.ts",
"files": [
"dist"
],
"scripts": {
"build:app": "yarn workspace loot-core build:api",
"build:node": "tsc --p tsconfig.dist.json",
"build:node": "tsc --p tsconfig.dist.json && tsc-alias -p tsconfig.dist.json",
"build:migrations": "cp migrations/*.sql dist/migrations",
"build:default-db": "cp default-db.sqlite dist/",
"build": "rm -rf dist && yarn run build:app && yarn run build:node && yarn run build:migrations && yarn run build:default-db",
"test": "yarn run build:app && jest -c jest.config.js"
"build": "yarn run clean && yarn run build:app && yarn run build:node && yarn run build:migrations && yarn run build:default-db",
"test": "yarn run build:app && jest -c jest.config.js",
"clean": "rm -rf dist @types"
},
"dependencies": {
"better-sqlite3": "^9.2.2",
Expand All @@ -31,6 +32,7 @@
"@types/jest": "^27.5.0",
"@types/uuid": "^9.0.2",
"jest": "^27.0.0",
"tsc-alias": "^1.8.8",
"typescript": "^5.0.2"
}
}
8 changes: 6 additions & 2 deletions packages/api/tsconfig.dist.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@
"moduleResolution": "Node16",
"noEmit": false,
"declaration": true,
"outDir": "dist"
"outDir": "dist",
"declarationDir": "@types",
"paths": {
"loot-core/*": ["./@types/loot-core/*"],
}
},
"include": ["."],
"exclude": ["dist"]
"exclude": ["**/node_modules/*", "dist", "@types"]
}
21 changes: 21 additions & 0 deletions packages/loot-core/bin/build-api
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash

set -euo pipefail

cd "$(dirname "$0")/.." || exit 1
ROOT="$(pwd -P)"

yarn tsc -p tsconfig.api.json --outDir ../api/@types/loot-core/
# Copy existing handwritten .d.ts files, as tsc doesn't move them for us
dest="../../api/@types/loot-core"
cd src
find . -type f -name "*.d.ts" | while read -r f
do
d=$(dirname "${f}")
d="${dest}/${d}"
mkdir -p "${d}"
cp "${f}" "${d}"
done
cd "$ROOT"
yarn webpack --config ./webpack/webpack.api.config.js;
./bin/copy-migrations ../api
2 changes: 1 addition & 1 deletion packages/loot-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"scripts": {
"build:node": "cross-env NODE_ENV=production webpack --config ./webpack/webpack.desktop.config.js",
"watch:node": "cross-env NODE_ENV=development webpack --config ./webpack/webpack.desktop.config.js --watch",
"build:api": "cross-env NODE_ENV=development webpack --config ./webpack/webpack.api.config.js; ./bin/copy-migrations ../api",
"build:api": "cross-env NODE_ENV=development ./bin/build-api",
"build:browser": "cross-env NODE_ENV=production ./bin/build-browser",
"watch:browser": "cross-env NODE_ENV=development ./bin/build-browser",
"test": "npm-run-all -cp 'test:*'",
Expand Down
4 changes: 2 additions & 2 deletions packages/loot-core/src/server/importers/ynab5.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,8 @@ async function importTransactions(
);

const payeesByTransferAcct = payees
.filter((payee: YNAB5.Payee) => payee?.transfer_acct)
.map((payee: YNAB5.Payee) => [payee.transfer_acct, payee]);
.filter(payee => payee?.transfer_acct)
.map(payee => [payee.transfer_acct, payee] as [string, YNAB5.Payee]);
const payeeTransferAcctHashMap = new Map<string, YNAB5.Payee>(
payeesByTransferAcct,
);
Expand Down
8 changes: 7 additions & 1 deletion packages/loot-core/src/server/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2251,8 +2251,14 @@ export async function initApp(isDev, socketName) {
}
}

export type initConfig = {
dataDir?: string;
serverURL?: string;
password?: string;
};

// eslint-disable-next-line import/no-unused-modules
export async function init(config) {
export async function init(config: initConfig) {
// Get from build

let dataDir, serverURL;
Expand Down
6 changes: 4 additions & 2 deletions packages/loot-core/src/server/mutators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ export async function runHandler<T extends Handlers[keyof Handlers]>(
}

if (mutatingMethods.has(handler)) {
return runMutator(() => handler(args), { undoTag });
return runMutator(() => handler(args), { undoTag }) as Promise<
ReturnType<T>
>;
}

// When closing a file, it clears out all global state for the file. That
Expand All @@ -67,7 +69,7 @@ export async function runHandler<T extends Handlers[keyof Handlers]>(
promise.then(() => {
runningMethods.delete(promise);
});
return promise;
return promise as Promise<ReturnType<T>>;
}

// These are useful for tests. Only use them in tests.
Expand Down
8 changes: 7 additions & 1 deletion packages/loot-core/src/shared/schedules.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
// @ts-strict-ignore
import type { IRuleOptions } from '@rschedule/core';
// eslint-disable-next-line import/no-duplicates
import type { IByHourOfDayRuleRuleOptions } from '@rschedule/core/rules/ByHourOfDay';
// eslint-disable-next-line import/no-duplicates
import type { IFrequencyRuleOptions } from '@rschedule/core/rules/Frequency';

import * as monthUtils from './months';
import { q } from './query';
Expand Down Expand Up @@ -183,7 +187,9 @@ export function getRecurringDescription(config, dateFormat) {
}

export function recurConfigToRSchedule(config) {
const base: IRuleOptions = {
const base: IRuleOptions &
IFrequencyRuleOptions &
IByHourOfDayRuleRuleOptions = {
start: monthUtils.parseDate(config.start),
frequency: config.frequency.toUpperCase(),
byHourOfDay: [12],
Expand Down
9 changes: 5 additions & 4 deletions packages/loot-core/src/types/api-handlers.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,11 @@ export interface ApiHandlers {
payees;
}) => Promise<unknown>;

'api/transactions-import': (arg: {
accountId;
transactions;
}) => Promise<unknown>;
'api/transactions-import': (arg: { accountId; transactions }) => Promise<{
errors?: { message: string }[];
added;
updated;
}>;

'api/transactions-add': (arg: {
accountId;
Expand Down
12 changes: 12 additions & 0 deletions packages/loot-core/tsconfig.api.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"declaration": true,
"emitDeclarationOnly": true,
"allowJs": false,
"noEmit": false,
},
"include": ["./typings", "./src/server/*"],
"exclude": ["**/node_modules/*", "**/build/*", "**/lib-dist/*", "./src/server/bench.ts"],
}
4 changes: 4 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
"module": "ES2022",
// Until/if we build using tsc
"noEmit": true,
"paths": {
// until we turn on composite/references
"loot-core/*": ["./packages/loot-core/src/*"],
},
"plugins": [
{
"name": "typescript-strict-plugin",
Expand Down
6 changes: 6 additions & 0 deletions upcoming-release-notes/2053.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
category: Maintenance
authors: [twk3]
---

Bundle loot-core types into the API
Loading

0 comments on commit ab03b4d

Please sign in to comment.