ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Actual Budget 官方 Node.js API 实战指南:安装、连接、数据导入与浏览器端使用

Actual Budget 官方 Node.js API 实战指南:安装、连接、数据导入与浏览器端使用 Actual Budget 官方 Node.js API 实战指南安装、连接、数据导入与浏览器端使用【免费下载链接】actualA local-first personal finance app项目地址: https://gitcode.com/GitHub_Trending/ac/actualActualActual Budget是一个 local-first本地优先的个人理财应用你的预算数据存放在服务器上但服务器并不承担分析预算细节或修改预算的功能所有查询与计算逻辑都运行在客户端本地。因此Actual 官方提供的是一个NPM 包形式的程序化 APIactual-app/api而不是 HTTP/REST 接口——这一点是理解整个 API 的出发点。本文基于仓库内 API 使用文档 与 API 参考手册完整讲解 API 的安装、连接远程服务器、浏览器端运行、错误处理、自定义数据导入以及核心方法与数据模型并辅以 API 包源码 进行底层印证。读完本文你将能够用代码以模拟用户在界面中操作的方式读写自己的预算数据编写自定义导入器或在浏览器中构建基于 Actual 数据的应用。先厘清一个关键概念这不是 HTTP API文档开篇就有一句重要的警告很多人会把 API 误解为 HTTP/REST 接口但Actual 并不对外暴露任何 HTTP 端点。它提供的是一个 NPM 包——actual-app/api——允许你以编程方式与产品交互。这个 API 给你对数据的完整程序化访问能力它可以以headless无头模式运行 UI就像用户在界面里点击操作一样。如果你是开发者可以用它从自定义来源导入交易把数据导出到 Excel 等其他应用在 Actual 之上编写任何你想要的功能。需要特别记住的架构事实Actual 与其他大多数应用不同——数据虽然存储在服务器上但服务器不具备分析预算细节或修改预算的功能。因此API 客户端包含了查询数据所需的全部代码并运行在本地副本上。当前的主要使用场景是自定义导入器和导出器。这一设计在源码中也清晰可见API 包 本质上是actual-app/coreloot-core 核心引擎的一层薄封装init会调用核心的initLootCore并返回一个可用于send的句柄所有方法最终都通过这条连接通道与本地引擎通信。快速开始安装与 TypeScript 配置官方提供了actual-app/apiNode.js 客户端目前仅支持 Node.js其他语言暂不支持。安装方式npm install --save actual-app/api或使用 yarnyarn add actual-app/api从 packages/api/package.json 可以看到该包的exports字段同时声明了browser与default两个条件出口main指向dist/index.js并内置 TypeScript 声明文件types/index.d.ts这正是浏览器构建与类型提示得以工作的基础。TypeScript 消费说明actual-app/api自带 TypeScript 声明。要正常消费这些声明你的tsconfig.json必须使用较新的moduleResolution模式{ compilerOptions: { moduleResolution: bundler } }可取值包括bundler、nodenext或node16。文档明确指出旧式的node/node10/classic解析方式在严格 TypeScript 模式下不被支持。原因是发布出去的声明文件依赖package.json的exports条件而旧解析器不识别exports条件——这与 package.json 中 exports 字段 的实现一一对应。连接远程服务器init 与 downloadBudget要访问预算文件首先需要连接到正在运行的 Actual 服务器版本。以下是官方文档给出的最小可用示例let api require(actual-app/api); (async () { await api.init({ // 预算数据会缓存在这里每个文件一个子目录 dataDir: /some/path, // 你的运行中服务器的 URL serverURL: http://localhost:5006, // 登录服务器使用的密码 password: hunter2, }); // 这是 Settings → Show advanced settings → Sync ID 中的 ID await api.downloadBudget(1cfdbb80-6274-49bf-b0c2-737235a4c81f); // 或者如果开启了端到端加密 await api.downloadBudget(1cfdbb80-6274-49bf-b0c2-737235a4c81f, { password: password1, }); let budget await api.getBudgetMonth(2019-10); console.log(budget); await api.shutdown(); })();几个要点dataDir预算数据的本地缓存目录。文档说明它在 Node.js 中默认是当前工作目录浏览器构建中则默认是/documents详见下文浏览器部分。serverURL运行中服务器的地址默认端口为5006这也是 sync-server 的默认监听端口。password登录服务器所用的密码。若提供加密密码如端到端加密场景则在downloadBudget的第二个参数中传入{ password }。shutdown脚本退出前建议调用用于关闭当前预算文件并停止其他运行中的进程。安全提醒文档原文强调不要把密码硬编码在代码里尤其是当你的代码会被 Git 跟踪时。推荐改用环境变量、从文件中读取或在脚本运行时交互式请求密码。从源码角度印证在 methods.ts 中downloadBudget(syncId, { password })实际发送的是api/download-budget消息而 index.ts 中的init会先做 Node 版本校验validateNodeVersion再调用核心的initLootCore。shutdown则会依次发送sync与close-budget确保退出前数据已同步index.ts。处理自签名 HTTPS 证书如果serverURL使用自签名或自定义 CA 证书需要额外的 Node.js 配置才能建立连接。API 与服务器通信使用 Node 内置的fetch要让 Node 信任自签名证书文档提供了三种方式NODE_EXTRA_CA_CERTS将环境变量指向一个包含公钥证书的文件路径。这是推荐做法只影响额外信任的证书。NODE_TLS_REJECT_UNAUTHORIZED0关闭 TLS 校验。不推荐——如果你的程序还要访问 Actual 服务器以外的其他端点这个设置会让所有 TLS 校验失效。OpenSSL CA 配置通过 OpenSSL 的SSL_CERT_DIR把证书加入系统信任链。具体做法取决于你的 Node.js 构建方式细节超出本文范围可参考 Node.js OpenSSL Strategy 文档作为起点。在浏览器中使用 API实验性功能actual-app/api同样提供浏览器构建版本。当你用现代打包器例如 Vite打包 Web 应用时包的browser入口会被自动选中调用方法与 Node.js 完全相同import * as api from actual-app/api; await api.init({ serverURL: https://your-server.example.com, password: hunter2, }); await api.downloadBudget(1cfdbb80-6274-49bf-b0c2-737235a4c81f); console.log(await api.getAccounts()); await api.shutdown();浏览器版本的工作原理结合 index.browser.ts 源码init会启动一个 Web Worker运行与 Actual Web 应用相同的预算引擎底层由编译为 WebAssembly 的 SQLite 支撑。预算数据存储在浏览器的 IndexedDB 中数据始终留在设备本地。浏览器中dataDir是 Worker 虚拟文件系统里的路径而非磁盘上的文件夹。它是可选的默认值为/documents若传入自定义路径会被自动创建并以同样方式持久化到 IndexedDB。构建完全自包含Web Worker、WebAssembly 及数据文件都被内联进包中源码中import InlineWorker from ./browser-worker?workerinline正是这一机制无需额外拷贝或托管任何文件也不需要打包器配置无需optimizeDeps调整无需 worker 或资源插件。导入包并调用init()即可。跨源隔离是硬性要求:::caution 引擎使用了SharedArrayBuffer因此运行 API 的页面必须以**跨源隔离cross-origin isolated**方式提供服务使用 HTTPS并携带Cross-Origin-Opener-Policy: same-origin与Cross-Origin-Embedder-Policy: require-corp响应头。这是托管/服务器层面的要求无法通过打包消除。详见 Enabling SharedArrayBuffer Access。本地开发时请在开发服务器上设置同样的响应头例如通过一个小型 Vite 中间件插件。 :::错误处理使用稳定的错误码而非错误文案当 API 方法失败时被拒绝的 error 通常带有人类可读的英文message。对于最常见的连接与下载类失败error 还会携带稳定的、机器可读的code。官方建议当你的应用需要针对特定失败类型做出响应例如展示自己的翻译文案时应匹配code而不是message文本——因为message的措辞可能随版本变化。官方示例try { await api.init({ dataDir: /some/path, serverURL: http://localhost:5006, password: hunter2, }); await api.downloadBudget(1cfdbb80-6274-49bf-b0c2-737235a4c81f); } catch (error) { switch (error.code) { case network-failure: case network: // 服务器无法访问请检查 serverURL break; case invalid-password: // 服务器密码错误 break; case budget-not-found: // 没有预算文件匹配给定的 sync ID break; default: // 回退到 message 文本 console.error(error.message); } }常见失败对应的错误码完整对照表CodeMeaningnetwork-failure服务器无法访问——serverURL错误或服务器离线/不可达。network与network-failure相同由下载与加密密钥检查上报。invalid-password传给init的服务器密码错误。token-expired传给init的会话令牌无效或已过期。unauthorized客户端未登录服务器。budget-not-found没有预算文件匹配给定的 sync ID。missing-key预算文件已端到端加密但未提供加密密码。decrypt-failure预算文件无法解密——加密密码错误。old-key-style预算文件使用了旧的、不支持的加密密钥样式。out-of-sync-migrations预算文件需要更新版本的 Actual——请升级 API 包。:::notecode只出现在上表列出的常见连接与下载失败中。其他错误可能只有message因此始终保留回退逻辑。 :::编写自定义数据导入器runImport 模式如果你正从 YNAB、Mint 等其他应用迁移数据Actual 官方已支持导入 YNAB4 数据与导入 nYNAB 数据。但如果你想把自己全部的数据预算、交易、收款方等一次性灌入 Actual可以编写自定义导入器。需要先区分两个概念文档特别强调本文的导入器不是指导入交易。如果只是想从自定义来源如银行 API新增交易应使用importTransactions。自定义导入器是把所有数据预算、交易、payees 等整体倾倒进 Actual 的一个新文件中。API 为批量导入提供了专用模式该模式下总会创建一个新文件不能批量导入到已有文件并且运行速度远快于常规方式。写法是使用runImport——它接收要创建的文件名称并运行一个函数。官方示例let api require(actual-app/api); let data require(my-data.json); async function run() { for (let account of data.accounts) { let acctId await api.createAccount(convertAccount(account)); await api.addTransactions( acctId, data.transactions .filter(t t.acctId acctId) .map(convertTransaction), ); } } api.runImport(My-Budget, run);这个示例从my-data.json取数据创建所有账户和交易convertAccount、convertTransaction等转换函数需自行实现。对象结构请参考 API 参考文档。为什么这里必须用 addTransactions 而不是 importTransactions文档给出了非常关键的使用提示批量导入原始数据时一定要用addTransactions而非importTransactions。原因addTransactions不会运行对账流程即去重也不会创建转账交易的对端以及其他自动行为——这正是导入器想要的原始数据语义。如果使用importTransactions它可能会以与你导入数据不匹配的方式调整数据。从源码看addTransactions支持两个可选标志runTransfers对指定了转账 payee 的交易创建转账默认false与learnCategories根据交易中的 category 字段更新规则默认false并直接发送api/transactions-add而importTransactionsmethods.ts发送的是api/transactions-import会走完整的导入管线。想了解真实导入器如何工作可以直接阅读仓库中的 YNAB4 导入器 与 YNAB5 导入器。核心方法详解以下是actual-app/api公开的核心方法。API 还导出了init、send、disconnect、loadBudget等底层函数供需要手动管理连接的高级用户使用可在核心引擎 main.ts 中搜索export const lib了解。init(config?)→Promisevoid在任何其他 API 方法之前调用。使用给定密码连接服务器并加载预算数据。dataDir在 Node.js 中默认当前工作目录浏览器构建中默认/documents。如果未提供serverURL则不会建立任何网络连接只能访问本地已下载的预算文件。预算 id 可以在设置页的 Advanced 部分找到。源码中init还额外做了 Node 版本校验index.ts。shutdown()→Promisevoid关闭当前预算文件并停止其他进行中的进程。脚本退出前建议调用。实现上会先尝试sync再close-budgetindex.ts。utils.amountToInteger(amount)/utils.integerToAmount(amount)amountToInteger(123.45)→12345把浮点货币金额转换为 Actual 内部使用的整数格式。integerToAmount(12345)→123.45反向转换。这正是下文金额约定的编程接口体现Actual 内部所有金额都是无小数位的整数。方法类型约定与原始数据类型在参考文档中所有 API 方法被归为四类get、create、update、delete。理解以下约定对正确使用至关重要对象可能含有仅对某类方法有效的字段。例如交易的payee字段只在create方法中可用get返回的对象里使用的是payee_id。id是特殊字段所有对象都有id但create方法不需要你指定id——所有create方法都会把生成的id返回给你。update/delete方法都接收一个id指定目标对象update的第二个参数是要更新的字段而非完整对象。即使某字段是必填的update也不必传入它。例如category必须要有group_id但updateCategory(id, { name: Food })是合法调用。必填的含义是update不能把该字段设为null且create必须包含该字段。例外updateRule要求完整Rule对象含id返回PromiseRule。原始类型Primitives名称类型说明idstringUUIDmonthstring格式YYYY-MMdatestring格式YYYY-MM-DDamountinteger无小数位的货币金额通常是value * 100取决于币种。例如 USD 的$120.30写作12030金额约定一切皆整数这是一个贯穿整个 API 的核心规则所有货币金额都表示为整数分integer cents。值美元金额5000$50.00-12350-$123.50100$1.00例如要预算 $50应传5000。这也是为什么文档和 CLI 都反复强调amount没有小数位——配合上面的utils.amountToInteger/utils.integerToAmount即可完成双向换算。各领域方法速览基于参考文档预算BudgetsgetBudgetMonths()→Promisemonth[]getBudgetMonth(month)→PromiseBudgetmonth形如2019-10setBudgetAmount(month, categoryId, value)→Promisenullvalue为整数金额setBudgetCarryover(month, categoryId, flag)→Promisenullflag为布尔值holdBudgetForNextMonth(month, value)→PromisenullresetBudgetHold(month)→Promisenull交易TransactionsTransaction对象的字段详见 types.jsxid、account必填id、date必填YYYY-MM-DD、amount、payeecreate 时覆盖payee_name、payee_namecreate 时若给定会创建/匹配对应 payee、imported_payee保留原始描述、category、notes、imported_id银行给定的唯一 id用于去重、transfer_id转账时指向对端交易、cleared、subtransactions。拆分交易Split Transactions拆分交易通过subtransactions字段指定多个子交易来分摊总额。创建时父交易至少需要amount、account、date、parent_id、is_child: true子交易还应显式设置is_parent: false。可选字段category、notes。父交易必须标记is_parent: true否则提供的subtransactions会被忽略交易被当作普通非拆分交易处理。如果子交易缺失必填字段如account、dateAPI 会返回校验错误HTTP 400。如果子交易金额之和不等于父交易总额当前 API 调用仍会成功但应用内会显示错误。创建拆分交易时通常无需为父交易提供id系统会生成父交易的amount应等于所有子交易金额之和。一个可运行的拆分交易创建示例来自参考文档{ id: parent-id, is_parent: true, subtransactions: [ { amount: 142000, account: 9c1e5de4-ecf8-41c2-8a97-4a1e8bc385c9, date: 2024-08-12, parent_id: parent-id, is_child: true, is_parent: false, category: 71376207-72f9-4b2b-ae24-0931a226f76a }, { amount: 150, account: 9c1e5de4-ecf8-41c2-8a97-4a1e8bc385c9, date: 2024-08-12, parent_id: parent-id, is_child: true, is_parent: false, category: 315d3776-d2a8-4d82-8a69-648b0d80125a } ] }转账Transfers已有的转账交易带有transfer_id字段指向另一端的交易。你不应修改它否则会导致意外行为导入时允许设置。要创建转账使用目标账户对应的 transfer payee加载 payees用 payee 的transfer_acct字段找到要转入/转出的账户然后把该 payee 赋给交易系统会创建一对双向转账交易。交易相关方法addTransactions(accountId, transactions, { runTransfers false, learnCategories false })→Promiseid[]批量添加交易不做对账返回新交易 id 数组。主要用于自定义导入器写入原始数据。importTransactions(accountId, transactions, opts)→Promise{ errors, added, updated }批量添加交易并走完整导入流程等价于导入文件或从银行下载交易会运行所有规则、对账去重、按需创建转账。opts支持defaultCleared是否标记为已清算默认true、dryRun试运行默认false、reimportDeleted默认true、payeeNameNormalizationtitle-case或original默认title-case。返回added、updated的 id 数组与errors。getTransactions(accountId, startDate, endDate)→PromiseTransaction[]取某账户在两个日期含端点之间的全部交易。updateTransaction(id, fields)、deleteTransaction(id)。mergeTransactions(ids)→Promiseid把同一账户中恰好两笔不同交易合并为一笔返回存活交易 id。合并规则导入的交易优先于手动输入否则保留日期更早的存活交易保留自身字段值并用被删交易的空字段补全任一交易已清算则标记为已清算。传入相同 id 两次、两笔交易在不同账户、金额不同或转账目标账户不同时合并会失败。交易方法官方示例// 创建一笔 $12.00 的交易。如果 Kroger payee 不存在 // 会被自动创建并赋给这笔交易。 await importTransactions(accountId, [ { date: 2019-08-20, amount: 1200, payee_name: Kroger, category: c179c3f4-28a6-4fbd-a54d-195cced07a80, }, ]); // 取某账户整个 8 月的交易即使 8 月 31 日不存在也没关系 await getTransactions(accountId, 2019-08-01, 2019-08-31); // 把 Food 分类赋给一笔交易 let categories await getCategories(); let foodCategory categories.find(cat cat.name Food); await updateTransaction(id, { category: foodCategory.id });账户AccountsAccount字段id、name必填、offbudget默认false、closed默认false、balance_current银行同步报告的当前余额默认null、account_group_id所属账户组默认null。getAccounts()→PromiseAccount[]createAccount(account, initialBalance 0)→Promiseid创建账户并设置初始余额默认 0金额同样为无小数位整数。updateAccount(id, fields)、reopenAccount(id)、deleteAccount(id)closeAccount(id, transferAccountId?, transferCategoryId?)关闭账户。避免直接设置closed属性——若账户还有余额必须用transferAccountId指定资金转入账户若从预算内账户转到预算外账户还需用transferCategoryId指定分类转账交易因为钱被移出预算必须有来源。getAccountBalance(id, cutoff?)→Promisenumber取账户余额cutoff为截止日期Date缺省时以当前日期为截止。账户组Account GroupsgetAccountGroups()、createAccountGroup(group)、updateAccountGroup(id, fields)、deleteAccountGroup(id)。账户组用于把账户组织到命名分组如 Savings、Credit Cards一个账户至多属于一个组通过account_group_id设置删除账户组后其中的账户保持未分组状态。分类Categories与分类组Category GroupsCategory字段id、name必填、group_id必填、is_income默认false。收入分类将is_income设为true且group_id应指向唯一的收入分类组。getCategories(options)默认返回所有分类options.hidden可传false仅可见、true仅隐藏或省略全部。createCategory(category)、updateCategory(id, fields)、deleteCategory(id, transferCategoryId?)。CategoryGroup字段id、name必填、is_income默认false、categories仅get返回嵌套该组下所有分类创建/更新时不可用。全系统应只有一个收入分类组。getCategoryGroups(options)默认返回每个分组及其嵌套的所有分类options.hidden同时作用于分组与嵌套分类。createCategoryGroup(group)、updateCategoryGroup(id, fields)、deleteCategoryGroup(id, transferCategoryId?)。收款方PayeesPayee字段id、name必填、category、transfer_acct若是转账 payee指向对应的账户 id。转账机制依赖 payee每个账户都有一个对应的 transfer payee其transfer_acct指向账户 id。用importTransactions创建转账交易时就是给交易指定这样的 payee。getPayees()、getCommonPayees()频繁出现在交易中的常见 payeecreatePayee(payee)、updatePayee(id, fields)、deletePayee(id)mergePayees(targetId, mergeIds)把一个或多个 payee 合并到目标 payee保留目标名称。标签TagsTag字段id、tag必填、color、description、hidden。方法getTags()、createTag(tag)、updateTag(id, fields)、deleteTag(id)。await createTag({ tag: groceries, color: #ff0000, description: Grocery shopping expenses, });规则RulesConditionOrAction字段field必填、op必填、value必填。Rule字段id、stage必填pre/default/post、conditionsOpand/or、conditions、actions。getRules()、getPayeeRules(payeeId)返回与指定 payee 关联的普通Rule对象无payee_id属性createRule(rule)→PromiseRule、updateRule(rule)→PromiseRule需要完整规则对象含id、deleteRule(id)规则创建示例{ stage: pre, conditionsOp: and, conditions: [ { field: payee, op: is, value: test-payee }, ], actions: [ { op: set, field: category, value: fc3825fd-b982-4b72-b768-5b30844cf832 }, ], }计划交易SchedulesSchedule字段id、name可选但必须唯一、rule关联的底层规则新建时自动创建不可另指、next_date、completed新建时不可提供、posts_transaction是否自动过账默认false、payee、account、amount普通为单一数字amountOp为isbetween时提供{ num1, num2 }、amountOpis | isapprox | isbetween、date必填可为日期或RecurConfig。RecurConfig字段frequency必填daily | weekly | monthly | yearly、interval默认1、patterns可选控制特定日期、skipWeekend、start必填ISO 日期、endMode必填never | after_n_occurrences | on_date、endOccurrences、endDate、weekendSolveModebefore | after。方法getSchedules()、createSchedule(schedule)、updateSchedule(id, fields, resetNextDate?)、deleteSchedule(id)。备注Notes备注可以按 ID 附加到任意实体分类、预算月份等也用于定义预算模板与储蓄目标如#template 250、#goal 1000。getNote(id)→PromiseNote | null返回指定实体 ID 的备注未设置则返回null。updateNote(id, note)→Promisevoid设置备注传空字符串清除。杂项方法与高级能力sync()将本地缓存的预算文件与服务器副本同步。runBankSync(accountId?)运行第三方银行同步GoCardless、SimpleFIN下载交易并插入账本。runImport(budgetName, func)创建指定名称的新预算文件并运行自定义导入函数。getBudgets()→PromiseBudgetFile[]列出所有本地缓存或远程服务器上的预算文件。远程文件有state字段本地文件有id字段BudgetFile完整字段见 types.jsxname、cloudFileId、groupId、hasKey、encryptKeyId、state、id。loadBudget(syncId)加载本地缓存的预算文件。downloadBudget(syncId, { password? })若文件已在本地则直接加载否则从服务器下载。importBudget(input, { type?, filename? })→Promise{ id }从导出文件导入预算并加载。input可以是文件路径或原始文件内容默认按 Actual 导出处理含db.sqlite与metadata.json的.zip传type: ynab4或ynab5可导入 YNAB 导出传原始内容时可用filename提供原文件名部分导入类型用它推导预算名。返回导入预算的 id且该预算会成为当前加载的预算。源码实现在 methods.ts。exportBudget()→PromiseUint8Array把当前加载的预算导出为 zip 格式的原始字节。可以保存为.zip文件或直接回传给importBudget恢复预算。batchBudgetUpdates(func)批量执行预算更新适合在一次服务器调用中完成多处修改。源码通过api/batch-budget-start/api/batch-budget-end包裹函数体methods.ts。runQuery(query)在打开的预算上运行任意 ActualQL 查询注意源码中该方法标注为 deprecated推荐改用aqlQuery两者都发送api/query见 methods.ts。aqlQuery(query)runQuery的替代方法。getIDByName(type, name)→Promisestring按名称查任意账户、收款方、分类或计划交易的 ID。允许的typeaccounts | schedules | categories | payees。getServerVersion()→Promise{error?} | {version}返回服务器版本或错误。getPreferences()→PromiseSyncedPrefs返回预算的同步偏好设置——跨设备同步的设置如数字格式numberFormat、hideFraction、货币defaultCurrencyCode、currencySymbolPosition、currencySpaceBetweenAmountAndSymbol、日期格式dateFormat、每周第一天firstDayOfWeekIdx。所有值都是字符串未设置时为undefined。SyncedPrefs类型从actual-app/api/models导出。深入底层方法如何真正执行把所有方法串起来看会发现一个统一的模式公开 API 方法 核心引擎消息的封装。在 methods.ts 中每个方法几乎都只是一行return send(api/xxx, payload)addTransactions→send(api/transactions-add, {...})importTransactions→send(api/transactions-import, { accountId, transactions, isPreview, opts })createAccount→send(api/account-create, { account, initialBalance })getIDByName→send(api/get-id-by-name, { type, name })getPreferences→send(preferences/get)这些消息最终由核心引擎packages/loot-core 中的 server 层处理——这正是文档所说API 客户端包含所有查询数据的代码运行在本地副本上的实现体现你在 Node 或浏览器中调用 API 时实际是让本地引擎处理请求再按需与服务器同步。想要理解最底层的消息处理逻辑可阅读核心 main.ts搜索export const lib。与 CLI 的关系延伸阅读如果你希望不写代码就从终端操作预算数据仓库还提供了actual-app/cli包见 CLI 文档它基于同一套 API 能力封装出actual accounts list、actual budgets month 2026-03、actual transactions add、actual query run等命令支持环境变量ACTUAL_SERVER_URL、ACTUAL_SYNC_ID、ACTUAL_PASSWORD、ACTUAL_SESSION_TOKEN与.actualrc配置文件并同样遵循金额为整数分的约定。CLI 文档中关于拆分交易去重、避免高频顺序请求、未分类交易的category.name为null、AQL 不支持date.month子字段等注意事项在使用 API 编写脚本时同样适用。此外API 的查询能力与 ActualQL 深度绑定——通过q(transactions).filter(...).select(...)配合runQuery/aqlQuery可以精确控制排序、字段筛选与聚合支持$eq、$lt、$lte、$gt、$gte、$ne、$oneof、$regex、$like、$notlike等运算符以及splits: inline | grouped | all的拆分交易返回策略详见 ActualQL 概览。结语actual-app/api的设计哲学很明确它不是一个远程 REST 服务而是把完整预算引擎打包进你本地进程的编程接口。从连接服务器、下载预算到用runImport批量灌入数据、用稳定的错误码处理失败再到浏览器端以内联 Web Worker WASM SQLite 的方式零配置运行——这套 API 为自定义导入器、数据导出器和基于 Actual 数据的二次开发提供了完整入口。结合 API 参考文档 中的全部方法签名与字段说明以及 API 包源码 中各方法到核心引擎消息的映射你完全可以在此基础上编写出可靠、可维护的 Actual 集成代码。【免费下载链接】actualA local-first personal finance app项目地址: https://gitcode.com/GitHub_Trending/ac/actual创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表