mirror of
https://github.com/actualbudget/actual.git
synced 2026-04-28 18:40:34 -05:00
Compare commits
13 Commits
master
...
claude/bro
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03ed7d88a3 | ||
|
|
1d34d15f12 | ||
|
|
e512ff7312 | ||
|
|
f0470a37de | ||
|
|
b662205691 | ||
|
|
4a5b572baf | ||
|
|
5b179b0672 | ||
|
|
645623a6c9 | ||
|
|
1442747896 | ||
|
|
3e2303e5dc | ||
|
|
332db28e2e | ||
|
|
6d6e032429 | ||
|
|
399e59c088 |
25
packages/api/index.browser.ts
Normal file
25
packages/api/index.browser.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { init as initLootCore } from '@actual-app/core/server/main';
|
||||||
|
import type { InitConfig, lib } from '@actual-app/core/server/main';
|
||||||
|
|
||||||
|
export * from './methods';
|
||||||
|
export * as utils from './utils';
|
||||||
|
|
||||||
|
let internal: typeof lib | null = null;
|
||||||
|
|
||||||
|
export async function init(config: InitConfig = {}) {
|
||||||
|
internal = await initLootCore(config);
|
||||||
|
return internal;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function shutdown() {
|
||||||
|
if (internal) {
|
||||||
|
try {
|
||||||
|
await internal.send('sync');
|
||||||
|
} catch {
|
||||||
|
// most likely that no budget is loaded, so the sync failed
|
||||||
|
}
|
||||||
|
|
||||||
|
await internal.send('close-budget');
|
||||||
|
internal = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,24 +8,42 @@
|
|||||||
"dist"
|
"dist"
|
||||||
],
|
],
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
|
"module": "dist/browser.js",
|
||||||
"types": "@types/index.d.ts",
|
"types": "@types/index.d.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"development": "./index.ts",
|
"development": "./index.ts",
|
||||||
"default": "./dist/index.js"
|
"browser": {
|
||||||
}
|
"types": "./@types/index.d.ts",
|
||||||
},
|
"default": "./dist/browser.js"
|
||||||
"publishConfig": {
|
},
|
||||||
"exports": {
|
"default": {
|
||||||
".": {
|
|
||||||
"types": "./@types/index.d.ts",
|
"types": "./@types/index.d.ts",
|
||||||
"default": "./dist/index.js"
|
"default": "./dist/index.js"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"browser": {
|
||||||
|
"types": "./@types/index.d.ts",
|
||||||
|
"default": "./dist/browser.js"
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"types": "./@types/index.d.ts",
|
||||||
|
"default": "./dist/index.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vite build",
|
"build": "npm-run-all -cp 'build:*'",
|
||||||
"test": "vitest --run",
|
"build:node": "vite build",
|
||||||
|
"build:browser": "vite build --config vite.browser.config.ts",
|
||||||
|
"test": "npm-run-all -cp 'test:*'",
|
||||||
|
"test:node": "vitest --run",
|
||||||
|
"test:browser": "vitest --run -c vite.browser.config.ts",
|
||||||
"typecheck": "tsgo -b && tsc-strict"
|
"typecheck": "tsgo -b && tsc-strict"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -38,6 +56,8 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@typescript/native-preview": "^7.0.0-dev.20260309.1",
|
"@typescript/native-preview": "^7.0.0-dev.20260309.1",
|
||||||
|
"fake-indexeddb": "^6.2.5",
|
||||||
|
"npm-run-all": "^4.1.5",
|
||||||
"rollup-plugin-visualizer": "^6.0.11",
|
"rollup-plugin-visualizer": "^6.0.11",
|
||||||
"typescript-strict-plugin": "^2.4.4",
|
"typescript-strict-plugin": "^2.4.4",
|
||||||
"vite": "^8.0.0",
|
"vite": "^8.0.0",
|
||||||
|
|||||||
@@ -1,67 +1,15 @@
|
|||||||
import * as fs from 'fs/promises';
|
|
||||||
import * as path from 'path';
|
|
||||||
|
|
||||||
import { vi } from 'vitest';
|
|
||||||
|
|
||||||
import type { RuleEntity } from '@actual-app/core/types/models';
|
import type { RuleEntity } from '@actual-app/core/types/models';
|
||||||
|
|
||||||
import * as api from './index';
|
if (!globalThis.__test_api) {
|
||||||
|
throw new Error(
|
||||||
// In tests we run from source; loot-core's API fs uses __dirname (for the built dist/).
|
'Test setup did not run — __test_api is not defined. ' +
|
||||||
// Mock the fs so path constants point at loot-core package root where migrations live.
|
'Ensure a setupFile (setup.node.ts or setup.browser.ts) is configured.',
|
||||||
vi.mock(
|
|
||||||
'../loot-core/src/platform/server/fs/index.api',
|
|
||||||
async importOriginal => {
|
|
||||||
const actual = (await importOriginal()) as Record<string, unknown>;
|
|
||||||
const pathMod = await import('path');
|
|
||||||
const lootCoreRoot = pathMod.join(__dirname, '..', 'loot-core');
|
|
||||||
return {
|
|
||||||
...actual,
|
|
||||||
migrationsPath: pathMod.join(lootCoreRoot, 'migrations'),
|
|
||||||
bundledDatabasePath: pathMod.join(lootCoreRoot, 'default-db.sqlite'),
|
|
||||||
demoBudgetPath: pathMod.join(lootCoreRoot, 'demo-budget'),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const budgetName = 'test-budget';
|
|
||||||
|
|
||||||
global.IS_TESTING = true;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
const budgetPath = path.join(__dirname, '/mocks/budgets/', budgetName);
|
|
||||||
await fs.rm(budgetPath, { force: true, recursive: true });
|
|
||||||
|
|
||||||
await createTestBudget('default-budget-template', budgetName);
|
|
||||||
await api.init({
|
|
||||||
dataDir: path.join(__dirname, '/mocks/budgets/'),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
global.currentMonth = null;
|
|
||||||
await api.shutdown();
|
|
||||||
});
|
|
||||||
|
|
||||||
async function createTestBudget(templateName: string, name: string) {
|
|
||||||
const templatePath = path.join(
|
|
||||||
__dirname,
|
|
||||||
'/../loot-core/src/mocks/files',
|
|
||||||
templateName,
|
|
||||||
);
|
|
||||||
const budgetPath = path.join(__dirname, '/mocks/budgets/', name);
|
|
||||||
|
|
||||||
await fs.mkdir(budgetPath);
|
|
||||||
await fs.copyFile(
|
|
||||||
path.join(templatePath, 'metadata.json'),
|
|
||||||
path.join(budgetPath, 'metadata.json'),
|
|
||||||
);
|
|
||||||
await fs.copyFile(
|
|
||||||
path.join(templatePath, 'db.sqlite'),
|
|
||||||
path.join(budgetPath, 'db.sqlite'),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const api = globalThis.__test_api;
|
||||||
|
const budgetName = globalThis.__test_budget_name;
|
||||||
|
|
||||||
describe('API setup and teardown', () => {
|
describe('API setup and teardown', () => {
|
||||||
// apis: loadBudget, getBudgetMonths
|
// apis: loadBudget, getBudgetMonths
|
||||||
test('successfully loads budget', async () => {
|
test('successfully loads budget', async () => {
|
||||||
@@ -93,7 +41,7 @@ describe('API CRUD operations', () => {
|
|||||||
// apis: getCategoryGroups, createCategoryGroup, updateCategoryGroup, deleteCategoryGroup
|
// apis: getCategoryGroups, createCategoryGroup, updateCategoryGroup, deleteCategoryGroup
|
||||||
test('CategoryGroups: successfully update category groups', async () => {
|
test('CategoryGroups: successfully update category groups', async () => {
|
||||||
const month = '2023-10';
|
const month = '2023-10';
|
||||||
global.currentMonth = month;
|
globalThis.currentMonth = month;
|
||||||
|
|
||||||
// get existing category groups
|
// get existing category groups
|
||||||
const groups = await api.getCategoryGroups();
|
const groups = await api.getCategoryGroups();
|
||||||
@@ -164,7 +112,7 @@ describe('API CRUD operations', () => {
|
|||||||
// apis: createCategory, getCategories, updateCategory, deleteCategory
|
// apis: createCategory, getCategories, updateCategory, deleteCategory
|
||||||
test('Categories: successfully update categories', async () => {
|
test('Categories: successfully update categories', async () => {
|
||||||
const month = '2023-10';
|
const month = '2023-10';
|
||||||
global.currentMonth = month;
|
globalThis.currentMonth = month;
|
||||||
|
|
||||||
// create our test category group
|
// create our test category group
|
||||||
const mainGroupId = await api.createCategoryGroup({
|
const mainGroupId = await api.createCategoryGroup({
|
||||||
@@ -246,7 +194,7 @@ describe('API CRUD operations', () => {
|
|||||||
// apis: setBudgetAmount, setBudgetCarryover, getBudgetMonth
|
// apis: setBudgetAmount, setBudgetCarryover, getBudgetMonth
|
||||||
test('Budgets: successfully update budgets', async () => {
|
test('Budgets: successfully update budgets', async () => {
|
||||||
const month = '2023-10';
|
const month = '2023-10';
|
||||||
global.currentMonth = month;
|
globalThis.currentMonth = month;
|
||||||
|
|
||||||
// create some new categories to test with
|
// create some new categories to test with
|
||||||
const groupId = await api.createCategoryGroup({
|
const groupId = await api.createCategoryGroup({
|
||||||
12
packages/api/test/globals.d.ts
vendored
Normal file
12
packages/api/test/globals.d.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import type * as BrowserApi from '../index.browser';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
// oxlint-disable-next-line no-var
|
||||||
|
var __test_api: typeof BrowserApi;
|
||||||
|
// oxlint-disable-next-line no-var
|
||||||
|
var __test_budget_name: string;
|
||||||
|
// oxlint-disable-next-line no-var
|
||||||
|
var IS_TESTING: boolean;
|
||||||
|
// oxlint-disable-next-line no-var
|
||||||
|
var currentMonth: string | null;
|
||||||
|
}
|
||||||
92
packages/api/test/setup.browser.ts
Normal file
92
packages/api/test/setup.browser.ts
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
import 'fake-indexeddb/auto';
|
||||||
|
import * as nodeFs from 'fs/promises';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
import { afterEach, beforeAll, vi } from 'vitest';
|
||||||
|
|
||||||
|
import type * as BrowserFs from '@actual-app/core/platform/server/fs';
|
||||||
|
|
||||||
|
import * as api from '../index.browser';
|
||||||
|
|
||||||
|
const budgetName = 'test-budget';
|
||||||
|
const lootCoreRoot = path.join(__dirname, '..', '..', 'loot-core');
|
||||||
|
|
||||||
|
globalThis.IS_TESTING = true;
|
||||||
|
|
||||||
|
// Populate the emscripten virtual FS with migration files and default-db.sqlite
|
||||||
|
// (normally done by populateDefaultFilesystem() which is skipped in test mode).
|
||||||
|
async function populateDefaultFiles(fs: typeof BrowserFs) {
|
||||||
|
if (!(await fs.exists('/migrations'))) {
|
||||||
|
await fs.mkdir('/migrations');
|
||||||
|
}
|
||||||
|
|
||||||
|
const migrationsDir = path.join(lootCoreRoot, 'migrations');
|
||||||
|
const migrationFiles = await nodeFs.readdir(migrationsDir);
|
||||||
|
for (const file of migrationFiles) {
|
||||||
|
if (file.endsWith('.sql') || file.endsWith('.js')) {
|
||||||
|
const contents = await nodeFs.readFile(path.join(migrationsDir, file));
|
||||||
|
await fs.writeFile(`/migrations/${file}`, new Uint8Array(contents));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultDb = await nodeFs.readFile(
|
||||||
|
path.join(lootCoreRoot, 'default-db.sqlite'),
|
||||||
|
);
|
||||||
|
await fs.writeFile('/default-db.sqlite', new Uint8Array(defaultDb));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the test budget template into the virtual FS.
|
||||||
|
async function writeBudgetFiles(fs: typeof BrowserFs) {
|
||||||
|
const templatePath = path.join(
|
||||||
|
lootCoreRoot,
|
||||||
|
'src/mocks/files/default-budget-template',
|
||||||
|
);
|
||||||
|
const metadataContents = await nodeFs.readFile(
|
||||||
|
path.join(templatePath, 'metadata.json'),
|
||||||
|
'utf8',
|
||||||
|
);
|
||||||
|
const dbContents = await nodeFs.readFile(
|
||||||
|
path.join(templatePath, 'db.sqlite'),
|
||||||
|
);
|
||||||
|
|
||||||
|
const budgetDir = `/documents/${budgetName}`;
|
||||||
|
await fs.mkdir(budgetDir);
|
||||||
|
await fs.writeFile(`${budgetDir}/metadata.json`, metadataContents);
|
||||||
|
await fs.writeFile(`${budgetDir}/db.sqlite`, new Uint8Array(dbContents));
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const baseURL = `${__dirname}/../../../node_modules/@jlongster/sql.js/dist/`;
|
||||||
|
process.env.PUBLIC_URL = baseURL;
|
||||||
|
|
||||||
|
// Patch fetch so sql.js WASM loader reads from disk instead of HTTP
|
||||||
|
vi.spyOn(global, 'fetch').mockImplementation(async input => {
|
||||||
|
const url =
|
||||||
|
typeof input === 'string'
|
||||||
|
? input
|
||||||
|
: input instanceof URL
|
||||||
|
? input.href
|
||||||
|
: input.url;
|
||||||
|
if (url.startsWith(baseURL)) {
|
||||||
|
return new Response(new Uint8Array(await nodeFs.readFile(url)), {
|
||||||
|
status: 200,
|
||||||
|
statusText: 'OK',
|
||||||
|
headers: { 'Content-Type': 'application/wasm' },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(`fetch not mocked for ${url}`));
|
||||||
|
});
|
||||||
|
|
||||||
|
await api.init({ dataDir: '/documents' });
|
||||||
|
|
||||||
|
const fs = await import('@actual-app/core/platform/server/fs');
|
||||||
|
await populateDefaultFiles(fs);
|
||||||
|
await writeBudgetFiles(fs);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
globalThis.currentMonth = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
globalThis.__test_api = api;
|
||||||
|
globalThis.__test_budget_name = budgetName;
|
||||||
64
packages/api/test/setup.node.ts
Normal file
64
packages/api/test/setup.node.ts
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import * as fs from 'fs/promises';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
import { afterEach, beforeEach, vi } from 'vitest';
|
||||||
|
|
||||||
|
import * as api from '../index';
|
||||||
|
|
||||||
|
// In tests we run from source; loot-core's API fs uses __dirname (for the built dist/).
|
||||||
|
// Mock the fs so path constants point at loot-core package root where migrations live.
|
||||||
|
vi.mock(
|
||||||
|
'../../loot-core/src/platform/server/fs/index.api',
|
||||||
|
async importOriginal => {
|
||||||
|
const actual = (await importOriginal()) as Record<string, unknown>;
|
||||||
|
const pathMod = await import('path');
|
||||||
|
const lootCoreRoot = pathMod.join(__dirname, '..', '..', 'loot-core');
|
||||||
|
return {
|
||||||
|
...actual,
|
||||||
|
migrationsPath: pathMod.join(lootCoreRoot, 'migrations'),
|
||||||
|
bundledDatabasePath: pathMod.join(lootCoreRoot, 'default-db.sqlite'),
|
||||||
|
demoBudgetPath: pathMod.join(lootCoreRoot, 'demo-budget'),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const budgetName = 'test-budget';
|
||||||
|
|
||||||
|
globalThis.IS_TESTING = true;
|
||||||
|
|
||||||
|
async function createTestBudget(templateName: string, name: string) {
|
||||||
|
const templatePath = path.join(
|
||||||
|
__dirname,
|
||||||
|
'/../../loot-core/src/mocks/files',
|
||||||
|
templateName,
|
||||||
|
);
|
||||||
|
const budgetPath = path.join(__dirname, '/../mocks/budgets/', name);
|
||||||
|
|
||||||
|
await fs.mkdir(budgetPath);
|
||||||
|
await fs.copyFile(
|
||||||
|
path.join(templatePath, 'metadata.json'),
|
||||||
|
path.join(budgetPath, 'metadata.json'),
|
||||||
|
);
|
||||||
|
await fs.copyFile(
|
||||||
|
path.join(templatePath, 'db.sqlite'),
|
||||||
|
path.join(budgetPath, 'db.sqlite'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const budgetPath = path.join(__dirname, '/../mocks/budgets/', budgetName);
|
||||||
|
await fs.rm(budgetPath, { force: true, recursive: true });
|
||||||
|
|
||||||
|
await createTestBudget('default-budget-template', budgetName);
|
||||||
|
await api.init({
|
||||||
|
dataDir: path.join(__dirname, '/../mocks/budgets/'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
globalThis.currentMonth = null;
|
||||||
|
await api.shutdown();
|
||||||
|
});
|
||||||
|
|
||||||
|
globalThis.__test_api = api;
|
||||||
|
globalThis.__test_budget_name = budgetName;
|
||||||
@@ -18,5 +18,5 @@
|
|||||||
},
|
},
|
||||||
"references": [{ "path": "../crdt" }, { "path": "../loot-core" }],
|
"references": [{ "path": "../crdt" }, { "path": "../loot-core" }],
|
||||||
"include": ["."],
|
"include": ["."],
|
||||||
"exclude": ["**/node_modules/*", "dist", "@types", "*.test.ts", "*.config.ts"]
|
"exclude": ["**/node_modules/*", "dist", "@types"]
|
||||||
}
|
}
|
||||||
|
|||||||
1
packages/api/typings/vite-plugin-peggy-loader.d.ts
vendored
Normal file
1
packages/api/typings/vite-plugin-peggy-loader.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
declare module 'vite-plugin-peggy-loader';
|
||||||
33
packages/api/vite.browser.config.ts
Normal file
33
packages/api/vite.browser.config.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
import peggyLoader from 'vite-plugin-peggy-loader';
|
||||||
|
import { defineConfig } from 'vitest/config';
|
||||||
|
|
||||||
|
const distDir = path.resolve(__dirname, 'dist');
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
build: {
|
||||||
|
target: 'esnext',
|
||||||
|
outDir: distDir,
|
||||||
|
emptyOutDir: false,
|
||||||
|
sourcemap: true,
|
||||||
|
lib: {
|
||||||
|
entry: path.resolve(__dirname, 'index.browser.ts'),
|
||||||
|
formats: ['es'],
|
||||||
|
fileName: () => 'browser.js',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [peggyLoader()],
|
||||||
|
resolve: {
|
||||||
|
// Default extensions — picks up browser implementations (index.ts)
|
||||||
|
// instead of .api.ts (which resolves to Node.js/Electron code)
|
||||||
|
extensions: ['.js', '.ts', '.tsx', '.json'],
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
environment: 'jsdom',
|
||||||
|
globals: true,
|
||||||
|
setupFiles: ['./test/setup.browser.ts'],
|
||||||
|
include: ['test/**/*.test.ts'],
|
||||||
|
maxWorkers: 2,
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -2,9 +2,9 @@ import fs from 'fs';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
import { visualizer } from 'rollup-plugin-visualizer';
|
import { visualizer } from 'rollup-plugin-visualizer';
|
||||||
import { defineConfig } from 'vite';
|
|
||||||
import dts from 'vite-plugin-dts';
|
import dts from 'vite-plugin-dts';
|
||||||
import peggyLoader from 'vite-plugin-peggy-loader';
|
import peggyLoader from 'vite-plugin-peggy-loader';
|
||||||
|
import { defineConfig } from 'vitest/config';
|
||||||
|
|
||||||
const lootCoreRoot = path.resolve(__dirname, '../loot-core');
|
const lootCoreRoot = path.resolve(__dirname, '../loot-core');
|
||||||
const distDir = path.resolve(__dirname, 'dist');
|
const distDir = path.resolve(__dirname, 'dist');
|
||||||
@@ -84,6 +84,8 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
test: {
|
test: {
|
||||||
globals: true,
|
globals: true,
|
||||||
|
setupFiles: ['./test/setup.node.ts'],
|
||||||
|
include: ['test/**/*.test.ts'],
|
||||||
onConsoleLog(log: string, type: 'stdout' | 'stderr'): boolean | void {
|
onConsoleLog(log: string, type: 'stdout' | 'stderr'): boolean | void {
|
||||||
// print only console.error
|
// print only console.error
|
||||||
return type === 'stderr';
|
return type === 'stderr';
|
||||||
|
|||||||
@@ -304,7 +304,7 @@ export function registerQueryCommand(program: Command) {
|
|||||||
? buildQueryFromFile(parsed, cmdOpts.table)
|
? buildQueryFromFile(parsed, cmdOpts.table)
|
||||||
: buildQueryFromFlags(cmdOpts);
|
: buildQueryFromFlags(cmdOpts);
|
||||||
|
|
||||||
const result = await api.aqlQuery(queryObj);
|
const result = (await api.aqlQuery(queryObj)) as { data: unknown };
|
||||||
|
|
||||||
if (cmdOpts.count) {
|
if (cmdOpts.count) {
|
||||||
printOutput({ count: result.data }, opts.format);
|
printOutput({ count: result.data }, opts.format);
|
||||||
|
|||||||
@@ -55,6 +55,7 @@
|
|||||||
"./platform/server/connection": "./src/platform/server/connection/index.ts",
|
"./platform/server/connection": "./src/platform/server/connection/index.ts",
|
||||||
"./platform/server/fetch": "./src/platform/server/fetch/index.ts",
|
"./platform/server/fetch": "./src/platform/server/fetch/index.ts",
|
||||||
"./platform/server/fs": "./src/platform/server/fs/index.ts",
|
"./platform/server/fs": "./src/platform/server/fs/index.ts",
|
||||||
|
"./platform/server/indexeddb": "./src/platform/server/indexeddb/index.ts",
|
||||||
"./platform/server/log": "./src/platform/server/log/index.ts",
|
"./platform/server/log": "./src/platform/server/log/index.ts",
|
||||||
"./platform/server/sqlite": "./src/platform/server/sqlite/index.ts",
|
"./platform/server/sqlite": "./src/platform/server/sqlite/index.ts",
|
||||||
"./server/budget/types/*": "./src/server/budget/types/*.d.ts",
|
"./server/budget/types/*": "./src/server/budget/types/*.d.ts",
|
||||||
|
|||||||
6
upcoming-release-notes/7247.md
Normal file
6
upcoming-release-notes/7247.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
category: Enhancements
|
||||||
|
authors: [MatissJanis]
|
||||||
|
---
|
||||||
|
|
||||||
|
api: add browser support
|
||||||
@@ -28,7 +28,9 @@ __metadata:
|
|||||||
"@typescript/native-preview": "npm:^7.0.0-dev.20260309.1"
|
"@typescript/native-preview": "npm:^7.0.0-dev.20260309.1"
|
||||||
better-sqlite3: "npm:^12.6.2"
|
better-sqlite3: "npm:^12.6.2"
|
||||||
compare-versions: "npm:^6.1.1"
|
compare-versions: "npm:^6.1.1"
|
||||||
|
fake-indexeddb: "npm:^6.2.5"
|
||||||
node-fetch: "npm:^3.3.2"
|
node-fetch: "npm:^3.3.2"
|
||||||
|
npm-run-all: "npm:^4.1.5"
|
||||||
rollup-plugin-visualizer: "npm:^6.0.11"
|
rollup-plugin-visualizer: "npm:^6.0.11"
|
||||||
typescript-strict-plugin: "npm:^2.4.4"
|
typescript-strict-plugin: "npm:^2.4.4"
|
||||||
uuid: "npm:^13.0.0"
|
uuid: "npm:^13.0.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user