@actual-app/core 26.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.swcrc +11 -0
- package/bin/build-browser +40 -0
- package/bin/copy-migrations +9 -0
- package/db.sqlite +0 -0
- package/default-db.sqlite +0 -0
- package/migrations/.force-copy-windows +0 -0
- package/migrations/1548957970627_remove-db-version.sql +5 -0
- package/migrations/1550601598648_payees.sql +23 -0
- package/migrations/1555786194328_remove_category_group_unique.sql +25 -0
- package/migrations/1561751833510_indexes.sql +7 -0
- package/migrations/1567699552727_budget.sql +38 -0
- package/migrations/1582384163573_cleared.sql +6 -0
- package/migrations/1597756566448_rules.sql +10 -0
- package/migrations/1608652596043_parent_field.sql +13 -0
- package/migrations/1608652596044_trans_views.sql +56 -0
- package/migrations/1612625548236_optimize.sql +7 -0
- package/migrations/1614782639336_trans_views2.sql +33 -0
- package/migrations/1615745967948_meta.sql +10 -0
- package/migrations/1616167010796_accounts_order.sql +5 -0
- package/migrations/1618975177358_schedules.sql +28 -0
- package/migrations/1632571489012_remove_cache.js +136 -0
- package/migrations/1679728867040_rules_conditions.sql +5 -0
- package/migrations/1681115033845_add_schedule_name.sql +5 -0
- package/migrations/1682974838138_remove_payee_rules.sql +5 -0
- package/migrations/1685007876842_add_category_hidden.sql +6 -0
- package/migrations/1686139660866_remove_account_type.sql +5 -0
- package/migrations/1688749527273_transaction_filters.sql +10 -0
- package/migrations/1688841238000_add_account_type.sql +5 -0
- package/migrations/1691233396000_add_schedule_next_date_tombstone.sql +5 -0
- package/migrations/1694438752000_add_goal_targets.sql +7 -0
- package/migrations/1697046240000_add_reconciled.sql +5 -0
- package/migrations/1704572023730_add_account_sync_source.sql +5 -0
- package/migrations/1704572023731_add_missing_goCardless_sync_source.sql +9 -0
- package/migrations/1707267033000_reports.sql +28 -0
- package/migrations/1712784523000_unhide_input_group.sql +8 -0
- package/migrations/1716359441000_include_current.sql +5 -0
- package/migrations/1720310586000_link_transfer_schedules.sql +19 -0
- package/migrations/1720664867241_add_payee_favorite.sql +5 -0
- package/migrations/1720665000000_goal_context.sql +6 -0
- package/migrations/1722717601000_reports_move_selected_categories.js +55 -0
- package/migrations/1722804019000_create_dashboard_table.js +69 -0
- package/migrations/1723665565000_prefs.js +59 -0
- package/migrations/1730744182000_fix_dashboard_table.sql +7 -0
- package/migrations/1736640000000_custom_report_sorting.sql +7 -0
- package/migrations/1737158400000_add_learn_categories_to_payees.sql +5 -0
- package/migrations/1738491452000_sorting_rename.sql +13 -0
- package/migrations/1739139550000_bank_sync_page.sql +7 -0
- package/migrations/1740506588539_add_last_reconciled_at.sql +5 -0
- package/migrations/1745425408000_update_budgetType_pref.sql +7 -0
- package/migrations/1749799110000_add_tags.sql +10 -0
- package/migrations/1749799110001_tags_tombstone.sql +5 -0
- package/migrations/1754611200000_add_category_template_settings.sql +5 -0
- package/migrations/1759260219000_add_trim_interval_report_setting.sql +6 -0
- package/migrations/1759842823172_add_isGlobal_to_preferences.sql +1 -0
- package/migrations/1762178745667_rename_csv_skip_lines_pref.sql +8 -0
- package/migrations/1765518577215_multiple_dashboards.js +30 -0
- package/migrations/1768872504000_add_payee_locations.sql +21 -0
- package/package.json +128 -0
- package/src/mocks/arbitrary-schema.ts +162 -0
- package/src/mocks/budget.ts +901 -0
- package/src/mocks/files/8859-1.qfx +63 -0
- package/src/mocks/files/best.data-ever$.QFX +124 -0
- package/src/mocks/files/big.data.QiF +91 -0
- package/src/mocks/files/budgets/.commit-to-git +0 -0
- package/src/mocks/files/camt/camt.053.payee-memo.xml +127 -0
- package/src/mocks/files/camt/camt.053.xml +463 -0
- package/src/mocks/files/credit-card.ofx +11 -0
- package/src/mocks/files/data-multi-decimal.ofx +64 -0
- package/src/mocks/files/data-payee-memo.ofx +75 -0
- package/src/mocks/files/data-payee-memo.qif +17 -0
- package/src/mocks/files/data.ofx +124 -0
- package/src/mocks/files/data.qfx +124 -0
- package/src/mocks/files/data.qif +91 -0
- package/src/mocks/files/default-budget-template/db.sqlite +0 -0
- package/src/mocks/files/default-budget-template/metadata.json +6 -0
- package/src/mocks/files/html-vals.qfx +17 -0
- package/src/mocks/index.ts +221 -0
- package/src/mocks/migrations/1508717984291_up_add-poop.sql +13 -0
- package/src/mocks/migrations/1508718036311_up_modify-poop.sql +2 -0
- package/src/mocks/migrations/1508727787513_remove-is_income.sql +15 -0
- package/src/mocks/random.ts +16 -0
- package/src/mocks/setup.ts +180 -0
- package/src/mocks/spreadsheet.ts +101 -0
- package/src/mocks/util.ts +82 -0
- package/src/platform/client/connection/README.md +3 -0
- package/src/platform/client/connection/__mocks__/index.ts +67 -0
- package/src/platform/client/connection/index-types.ts +95 -0
- package/src/platform/client/connection/index.browser.ts +213 -0
- package/src/platform/client/connection/index.ts +155 -0
- package/src/platform/client/undo/index.ts +59 -0
- package/src/platform/exceptions/__mocks__/index.ts +7 -0
- package/src/platform/exceptions/index.ts +9 -0
- package/src/platform/server/asyncStorage/__mocks__/index.ts +50 -0
- package/src/platform/server/asyncStorage/index-types.ts +35 -0
- package/src/platform/server/asyncStorage/index.api.ts +2 -0
- package/src/platform/server/asyncStorage/index.electron.ts +88 -0
- package/src/platform/server/asyncStorage/index.ts +126 -0
- package/src/platform/server/connection/README.md +3 -0
- package/src/platform/server/connection/__mocks__/index.ts +15 -0
- package/src/platform/server/connection/index-types.ts +20 -0
- package/src/platform/server/connection/index.api.ts +13 -0
- package/src/platform/server/connection/index.electron.ts +102 -0
- package/src/platform/server/connection/index.ts +154 -0
- package/src/platform/server/fetch/__mocks__/index.ts +3 -0
- package/src/platform/server/fetch/index.api.ts +1 -0
- package/src/platform/server/fetch/index.electron.ts +18 -0
- package/src/platform/server/fetch/index.ts +20 -0
- package/src/platform/server/fs/index.api.ts +198 -0
- package/src/platform/server/fs/index.electron.ts +208 -0
- package/src/platform/server/fs/index.test.ts +117 -0
- package/src/platform/server/fs/index.ts +416 -0
- package/src/platform/server/fs/path-join.api.ts +1 -0
- package/src/platform/server/fs/path-join.electron.ts +1 -0
- package/src/platform/server/fs/path-join.ts +97 -0
- package/src/platform/server/fs/shared.ts +33 -0
- package/src/platform/server/indexeddb/index.ts +115 -0
- package/src/platform/server/log/index.ts +43 -0
- package/src/platform/server/sqlite/index.api.ts +2 -0
- package/src/platform/server/sqlite/index.electron.ts +134 -0
- package/src/platform/server/sqlite/index.test.ts +108 -0
- package/src/platform/server/sqlite/index.ts +241 -0
- package/src/platform/server/sqlite/normalise.ts +9 -0
- package/src/platform/server/sqlite/unicodeLike.test.ts +58 -0
- package/src/platform/server/sqlite/unicodeLike.ts +31 -0
- package/src/server/__mocks__/post.ts +9 -0
- package/src/server/__snapshots__/main.test.ts.snap +199 -0
- package/src/server/__snapshots__/sheet.test.ts.snap +9 -0
- package/src/server/accounts/__snapshots__/sync.test.ts.snap +136 -0
- package/src/server/accounts/app-bank-sync.test.ts +136 -0
- package/src/server/accounts/app.ts +1294 -0
- package/src/server/accounts/link.ts +25 -0
- package/src/server/accounts/payees.ts +36 -0
- package/src/server/accounts/sync.test.ts +679 -0
- package/src/server/accounts/sync.ts +1168 -0
- package/src/server/accounts/title/index.ts +60 -0
- package/src/server/accounts/title/lower-case.ts +93 -0
- package/src/server/accounts/title/specials.ts +21 -0
- package/src/server/admin/app.ts +241 -0
- package/src/server/api-models.ts +244 -0
- package/src/server/api.test.ts +36 -0
- package/src/server/api.ts +1030 -0
- package/src/server/app.ts +91 -0
- package/src/server/aql/compiler.test.ts +966 -0
- package/src/server/aql/compiler.ts +1222 -0
- package/src/server/aql/exec.test.ts +289 -0
- package/src/server/aql/exec.ts +128 -0
- package/src/server/aql/index.ts +41 -0
- package/src/server/aql/schema/executors.test.ts +420 -0
- package/src/server/aql/schema/executors.ts +345 -0
- package/src/server/aql/schema/index.test.ts +67 -0
- package/src/server/aql/schema/index.ts +409 -0
- package/src/server/aql/schema-helpers.test.ts +242 -0
- package/src/server/aql/schema-helpers.ts +208 -0
- package/src/server/aql/views.test.ts +62 -0
- package/src/server/aql/views.ts +57 -0
- package/src/server/auth/app.ts +387 -0
- package/src/server/bench.ts +29 -0
- package/src/server/budget/actions.ts +686 -0
- package/src/server/budget/app.ts +469 -0
- package/src/server/budget/base.test.ts +340 -0
- package/src/server/budget/base.ts +339 -0
- package/src/server/budget/category-template-context.test.ts +1658 -0
- package/src/server/budget/category-template-context.ts +862 -0
- package/src/server/budget/cleanup-template.pegjs +27 -0
- package/src/server/budget/cleanup-template.ts +408 -0
- package/src/server/budget/envelope.ts +403 -0
- package/src/server/budget/goal-template.pegjs +110 -0
- package/src/server/budget/goal-template.ts +309 -0
- package/src/server/budget/report.ts +308 -0
- package/src/server/budget/schedule-template.test.ts +184 -0
- package/src/server/budget/schedule-template.ts +351 -0
- package/src/server/budget/statements.ts +60 -0
- package/src/server/budget/template-notes.test.ts +393 -0
- package/src/server/budget/template-notes.ts +323 -0
- package/src/server/budget/util.ts +25 -0
- package/src/server/budgetfiles/__snapshots__/backups.test.ts.snap +101 -0
- package/src/server/budgetfiles/app.ts +672 -0
- package/src/server/budgetfiles/backups.test.ts +79 -0
- package/src/server/budgetfiles/backups.ts +251 -0
- package/src/server/cloud-storage.ts +467 -0
- package/src/server/dashboard/app.ts +373 -0
- package/src/server/db/__snapshots__/index.test.ts.snap +271 -0
- package/src/server/db/index.test.ts +300 -0
- package/src/server/db/index.ts +855 -0
- package/src/server/db/mappings.ts +59 -0
- package/src/server/db/sort.ts +58 -0
- package/src/server/db/types/index.ts +342 -0
- package/src/server/db/util.ts +36 -0
- package/src/server/encryption/app.ts +133 -0
- package/src/server/encryption/encryption-internals.api.ts +2 -0
- package/src/server/encryption/encryption-internals.electron.ts +89 -0
- package/src/server/encryption/encryption-internals.ts +109 -0
- package/src/server/encryption/encryption.test.ts +19 -0
- package/src/server/encryption/index.test.ts +19 -0
- package/src/server/encryption/index.ts +89 -0
- package/src/server/errors.ts +110 -0
- package/src/server/filters/app.ts +191 -0
- package/src/server/importers/actual.ts +49 -0
- package/src/server/importers/index.ts +58 -0
- package/src/server/importers/ynab4-types.ts +163 -0
- package/src/server/importers/ynab4.ts +470 -0
- package/src/server/importers/ynab5-types.ts +290 -0
- package/src/server/importers/ynab5.ts +1193 -0
- package/src/server/main-app.ts +25 -0
- package/src/server/main.test.ts +392 -0
- package/src/server/main.ts +336 -0
- package/src/server/migrate/__snapshots__/migrations.test.ts.snap +17 -0
- package/src/server/migrate/cli.ts +100 -0
- package/src/server/migrate/migrations.test.ts +81 -0
- package/src/server/migrate/migrations.ts +192 -0
- package/src/server/models.ts +184 -0
- package/src/server/mutators.ts +139 -0
- package/src/server/notes/app.ts +18 -0
- package/src/server/payees/app.ts +351 -0
- package/src/server/polyfills.ts +26 -0
- package/src/server/post.ts +219 -0
- package/src/server/preferences/app.ts +249 -0
- package/src/server/prefs.ts +91 -0
- package/src/server/reports/app.ts +187 -0
- package/src/server/rules/action.ts +344 -0
- package/src/server/rules/app.ts +193 -0
- package/src/server/rules/condition.ts +436 -0
- package/src/server/rules/customFunctions.ts +61 -0
- package/src/server/rules/formula-action.test.ts +175 -0
- package/src/server/rules/handlebars-helpers.ts +131 -0
- package/src/server/rules/index.test.ts +1095 -0
- package/src/server/rules/index.ts +22 -0
- package/src/server/rules/rule-indexer.ts +89 -0
- package/src/server/rules/rule-utils.ts +274 -0
- package/src/server/rules/rule.ts +193 -0
- package/src/server/schedules/app.test.ts +502 -0
- package/src/server/schedules/app.ts +644 -0
- package/src/server/schedules/find-schedules.ts +391 -0
- package/src/server/server-config.ts +59 -0
- package/src/server/sheet.test.ts +101 -0
- package/src/server/sheet.ts +280 -0
- package/src/server/spreadsheet/__snapshots__/spreadsheet.test.ts.snap +5 -0
- package/src/server/spreadsheet/app.ts +54 -0
- package/src/server/spreadsheet/globals.ts +13 -0
- package/src/server/spreadsheet/graph-data-structure.ts +165 -0
- package/src/server/spreadsheet/scratch +60 -0
- package/src/server/spreadsheet/spreadsheet.test.ts +191 -0
- package/src/server/spreadsheet/spreadsheet.ts +523 -0
- package/src/server/spreadsheet/util.ts +15 -0
- package/src/server/sql/init.sql +88 -0
- package/src/server/sync/__snapshots__/sync.test.ts.snap +31 -0
- package/src/server/sync/app.ts +29 -0
- package/src/server/sync/encoder.ts +129 -0
- package/src/server/sync/index.ts +820 -0
- package/src/server/sync/make-test-message.ts +19 -0
- package/src/server/sync/migrate.test.ts +169 -0
- package/src/server/sync/migrate.ts +48 -0
- package/src/server/sync/repair.ts +39 -0
- package/src/server/sync/reset.ts +91 -0
- package/src/server/sync/sync.property.test.ts +385 -0
- package/src/server/sync/sync.test.ts +349 -0
- package/src/server/sync/utils.ts +3 -0
- package/src/server/tags/app.ts +101 -0
- package/src/server/tests/mockData.json +9352 -0
- package/src/server/tests/mockSyncServer.ts +119 -0
- package/src/server/tools/app.ts +152 -0
- package/src/server/transactions/__snapshots__/transaction-rules.test.ts.snap +173 -0
- package/src/server/transactions/__snapshots__/transfer.test.ts.snap +655 -0
- package/src/server/transactions/app.ts +136 -0
- package/src/server/transactions/export/export-to-csv.ts +132 -0
- package/src/server/transactions/import/__snapshots__/parse-file.test.ts.snap +1582 -0
- package/src/server/transactions/import/ofx2json.test.ts +33 -0
- package/src/server/transactions/import/ofx2json.ts +157 -0
- package/src/server/transactions/import/parse-file.test.ts +224 -0
- package/src/server/transactions/import/parse-file.ts +286 -0
- package/src/server/transactions/import/qif2json.ts +110 -0
- package/src/server/transactions/import/xmlcamt2json.ts +168 -0
- package/src/server/transactions/index.ts +196 -0
- package/src/server/transactions/merge.test.ts +370 -0
- package/src/server/transactions/merge.ts +139 -0
- package/src/server/transactions/transaction-rules.test.ts +994 -0
- package/src/server/transactions/transaction-rules.ts +1038 -0
- package/src/server/transactions/transfer.test.ts +221 -0
- package/src/server/transactions/transfer.ts +173 -0
- package/src/server/undo.ts +271 -0
- package/src/server/update.ts +37 -0
- package/src/server/util/budget-name.ts +61 -0
- package/src/server/util/custom-sync-mapping.ts +48 -0
- package/src/server/util/rschedule.ts +9 -0
- package/src/shared/__mocks__/platform.ts +7 -0
- package/src/shared/__snapshots__/months.test.ts.snap +21 -0
- package/src/shared/arithmetic.test.ts +112 -0
- package/src/shared/arithmetic.ts +170 -0
- package/src/shared/async.test.ts +135 -0
- package/src/shared/async.ts +76 -0
- package/src/shared/constants.ts +5 -0
- package/src/shared/currencies.ts +70 -0
- package/src/shared/dashboard.ts +260 -0
- package/src/shared/environment.ts +18 -0
- package/src/shared/errors.ts +195 -0
- package/src/shared/locale.ts +27 -0
- package/src/shared/location-utils.test.ts +69 -0
- package/src/shared/location-utils.ts +49 -0
- package/src/shared/months.test.ts +5 -0
- package/src/shared/months.ts +485 -0
- package/src/shared/normalisation.ts +6 -0
- package/src/shared/platform.electron.ts +21 -0
- package/src/shared/platform.ts +20 -0
- package/src/shared/query.ts +176 -0
- package/src/shared/rules.test.ts +56 -0
- package/src/shared/rules.ts +371 -0
- package/src/shared/schedules.test.ts +570 -0
- package/src/shared/schedules.ts +560 -0
- package/src/shared/test-helpers.ts +156 -0
- package/src/shared/transactions.test.ts +275 -0
- package/src/shared/transactions.ts +433 -0
- package/src/shared/transfer.test.ts +75 -0
- package/src/shared/transfer.ts +16 -0
- package/src/shared/user.ts +4 -0
- package/src/shared/util.test.ts +240 -0
- package/src/shared/util.ts +633 -0
- package/src/types/api-handlers.ts +287 -0
- package/src/types/budget.ts +8 -0
- package/src/types/file.ts +47 -0
- package/src/types/handlers.ts +46 -0
- package/src/types/models/account.ts +24 -0
- package/src/types/models/bank-sync.ts +23 -0
- package/src/types/models/bank.ts +6 -0
- package/src/types/models/category-group.ts +11 -0
- package/src/types/models/category.ts +13 -0
- package/src/types/models/dashboard.ts +199 -0
- package/src/types/models/gocardless.ts +84 -0
- package/src/types/models/import-transaction.ts +56 -0
- package/src/types/models/index.ts +23 -0
- package/src/types/models/nearby-payee.ts +7 -0
- package/src/types/models/note.ts +4 -0
- package/src/types/models/openid.ts +8 -0
- package/src/types/models/payee-location.ts +8 -0
- package/src/types/models/payee.ts +10 -0
- package/src/types/models/pluggyai.ts +19 -0
- package/src/types/models/reports.ts +144 -0
- package/src/types/models/rule.ts +174 -0
- package/src/types/models/schedule.ts +49 -0
- package/src/types/models/simplefin.ts +28 -0
- package/src/types/models/tags.ts +6 -0
- package/src/types/models/templates.ts +135 -0
- package/src/types/models/transaction-filter.ts +9 -0
- package/src/types/models/transaction.ts +39 -0
- package/src/types/models/user-access.ts +10 -0
- package/src/types/models/user.ts +25 -0
- package/src/types/prefs.ts +167 -0
- package/src/types/server-events.ts +86 -0
- package/src/types/server-handlers.ts +27 -0
- package/src/types/util.ts +26 -0
- package/tsconfig.json +34 -0
- package/typings/pegjs.ts +1 -0
- package/typings/process-worker.ts +12 -0
- package/typings/vite-plugin-peggy-loader.ts +1 -0
- package/typings/window.ts +62 -0
- package/vite.config.ts +109 -0
- package/vite.desktop.config.ts +59 -0
- package/vitest.config.ts +43 -0
- package/vitest.web.config.ts +38 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import { DEFAULT_MAX_DISTANCE_METERS } from '#shared/constants';
|
|
2
|
+
import type { Diff } from '../../shared/util';
|
|
3
|
+
import type {
|
|
4
|
+
NearbyPayeeEntity,
|
|
5
|
+
PayeeEntity,
|
|
6
|
+
PayeeLocationEntity,
|
|
7
|
+
RuleEntity,
|
|
8
|
+
} from '../../types/models';
|
|
9
|
+
import { createApp } from '../app';
|
|
10
|
+
import * as db from '../db';
|
|
11
|
+
import { payeeModel } from '../models';
|
|
12
|
+
import { mutator } from '../mutators';
|
|
13
|
+
import { batchMessages } from '../sync';
|
|
14
|
+
import * as rules from '../transactions/transaction-rules';
|
|
15
|
+
import { undoable } from '../undo';
|
|
16
|
+
|
|
17
|
+
export type PayeesHandlers = {
|
|
18
|
+
'payee-create': typeof createPayee;
|
|
19
|
+
'common-payees-get': typeof getCommonPayees;
|
|
20
|
+
'payees-get': typeof getPayees;
|
|
21
|
+
'payees-get-orphaned': typeof getOrphanedPayees;
|
|
22
|
+
'payees-get-rule-counts': typeof getPayeeRuleCounts;
|
|
23
|
+
'payees-merge': typeof mergePayees;
|
|
24
|
+
'payees-batch-change': typeof batchChangePayees;
|
|
25
|
+
'payees-check-orphaned': typeof checkOrphanedPayees;
|
|
26
|
+
'payees-get-rules': typeof getPayeeRules;
|
|
27
|
+
'payee-location-create': typeof createPayeeLocation;
|
|
28
|
+
'payee-locations-get': typeof getPayeeLocations;
|
|
29
|
+
'payee-location-delete': typeof deletePayeeLocation;
|
|
30
|
+
'payees-get-nearby': typeof getNearbyPayees;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const app = createApp<PayeesHandlers>();
|
|
34
|
+
app.method('payee-create', mutator(undoable(createPayee)));
|
|
35
|
+
app.method('common-payees-get', getCommonPayees);
|
|
36
|
+
app.method('payees-get', getPayees);
|
|
37
|
+
app.method('payees-get-orphaned', getOrphanedPayees);
|
|
38
|
+
app.method('payees-get-rule-counts', getPayeeRuleCounts);
|
|
39
|
+
app.method(
|
|
40
|
+
'payees-merge',
|
|
41
|
+
mutator(
|
|
42
|
+
undoable(mergePayees, args => ({
|
|
43
|
+
mergeIds: args.mergeIds,
|
|
44
|
+
targetId: args.targetId,
|
|
45
|
+
})),
|
|
46
|
+
),
|
|
47
|
+
);
|
|
48
|
+
app.method('payees-batch-change', mutator(undoable(batchChangePayees)));
|
|
49
|
+
app.method('payees-check-orphaned', checkOrphanedPayees);
|
|
50
|
+
app.method('payees-get-rules', getPayeeRules);
|
|
51
|
+
app.method('payee-location-create', mutator(createPayeeLocation));
|
|
52
|
+
app.method('payee-locations-get', getPayeeLocations);
|
|
53
|
+
app.method('payee-location-delete', mutator(deletePayeeLocation));
|
|
54
|
+
app.method('payees-get-nearby', getNearbyPayees);
|
|
55
|
+
|
|
56
|
+
async function createPayee({ name }: { name: PayeeEntity['name'] }) {
|
|
57
|
+
return db.insertPayee({ name });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function getCommonPayees(): Promise<PayeeEntity[]> {
|
|
61
|
+
// TODO: Update to an AQL query. Server must return AQL entities not the raw DB data.
|
|
62
|
+
return (await db.getCommonPayees()).map(p => payeeModel.fromDb(p));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function getPayees(): Promise<PayeeEntity[]> {
|
|
66
|
+
// TODO: Update to an AQL query. Server must return AQL entities not the raw DB data.
|
|
67
|
+
return (await db.getPayees()).map(p => payeeModel.fromDb(p));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function getOrphanedPayees(): Promise<Array<Pick<PayeeEntity, 'id'>>> {
|
|
71
|
+
return await db.syncGetOrphanedPayees();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function getPayeeRuleCounts() {
|
|
75
|
+
const payeeCounts: Record<PayeeEntity['id'], number> = {};
|
|
76
|
+
|
|
77
|
+
rules.iterateIds(rules.getRules(), 'payee', (rule, id) => {
|
|
78
|
+
if (payeeCounts[id] == null) {
|
|
79
|
+
payeeCounts[id] = 0;
|
|
80
|
+
}
|
|
81
|
+
payeeCounts[id]++;
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
return payeeCounts;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function mergePayees({
|
|
88
|
+
targetId,
|
|
89
|
+
mergeIds,
|
|
90
|
+
}: {
|
|
91
|
+
targetId: PayeeEntity['id'];
|
|
92
|
+
mergeIds: Array<PayeeEntity['id']>;
|
|
93
|
+
}) {
|
|
94
|
+
await db.mergePayees(targetId, mergeIds);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function batchChangePayees({
|
|
98
|
+
added,
|
|
99
|
+
deleted,
|
|
100
|
+
updated,
|
|
101
|
+
}: Partial<Diff<PayeeEntity>>): Promise<void> {
|
|
102
|
+
await batchMessages(async () => {
|
|
103
|
+
if (deleted) {
|
|
104
|
+
await Promise.all(
|
|
105
|
+
deleted.map(p => ({ id: p.id })).map(p => db.deletePayee(p)),
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (added) {
|
|
110
|
+
await Promise.all(
|
|
111
|
+
added.map(p => payeeModel.toDb(p)).map(p => db.insertPayee(p)),
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (updated) {
|
|
116
|
+
await Promise.all(
|
|
117
|
+
updated
|
|
118
|
+
.map(p => payeeModel.toDb(p as PayeeEntity, { update: true }))
|
|
119
|
+
.map(p => db.updatePayee(p)),
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function checkOrphanedPayees({
|
|
126
|
+
ids,
|
|
127
|
+
}: {
|
|
128
|
+
ids: Array<PayeeEntity['id']>;
|
|
129
|
+
}): Promise<Array<PayeeEntity['id']>> {
|
|
130
|
+
const orphaned = new Set(await db.getOrphanedPayees());
|
|
131
|
+
return ids.filter(id => orphaned.has(id));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function getPayeeRules({
|
|
135
|
+
id,
|
|
136
|
+
}: {
|
|
137
|
+
id: PayeeEntity['id'];
|
|
138
|
+
}): Promise<RuleEntity[]> {
|
|
139
|
+
return rules.getRulesForPayee(id).map(rule => rule.serialize());
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async function createPayeeLocation({
|
|
143
|
+
payeeId,
|
|
144
|
+
latitude,
|
|
145
|
+
longitude,
|
|
146
|
+
}: {
|
|
147
|
+
payeeId: PayeeEntity['id'];
|
|
148
|
+
latitude: number;
|
|
149
|
+
longitude: number;
|
|
150
|
+
}): Promise<PayeeLocationEntity['id']> {
|
|
151
|
+
const created_at = Date.now();
|
|
152
|
+
|
|
153
|
+
if (
|
|
154
|
+
!Number.isFinite(latitude) ||
|
|
155
|
+
!Number.isFinite(longitude) ||
|
|
156
|
+
latitude < -90 ||
|
|
157
|
+
latitude > 90 ||
|
|
158
|
+
longitude < -180 ||
|
|
159
|
+
longitude > 180
|
|
160
|
+
) {
|
|
161
|
+
throw new Error(
|
|
162
|
+
'Invalid coordinates: latitude must be between -90 and 90, longitude must be between -180 and 180',
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return await db.insertWithUUID('payee_locations', {
|
|
167
|
+
payee_id: payeeId,
|
|
168
|
+
latitude,
|
|
169
|
+
longitude,
|
|
170
|
+
created_at,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async function getPayeeLocations({
|
|
175
|
+
payeeId,
|
|
176
|
+
}: {
|
|
177
|
+
payeeId?: PayeeEntity['id'];
|
|
178
|
+
} = {}): Promise<PayeeLocationEntity[]> {
|
|
179
|
+
let query = 'SELECT * FROM payee_locations WHERE tombstone IS NOT 1';
|
|
180
|
+
let params: string[] = [];
|
|
181
|
+
|
|
182
|
+
if (payeeId) {
|
|
183
|
+
query += ' AND payee_id = ?';
|
|
184
|
+
params = [payeeId];
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
query += ' ORDER BY created_at DESC';
|
|
188
|
+
|
|
189
|
+
return db.runQuery<PayeeLocationEntity>(query, params, true);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async function deletePayeeLocation({
|
|
193
|
+
id,
|
|
194
|
+
}: {
|
|
195
|
+
id: PayeeLocationEntity['id'];
|
|
196
|
+
}): Promise<void> {
|
|
197
|
+
await db.delete_('payee_locations', id);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Type for the raw query result that combines PayeeEntity and PayeeLocationEntity fields
|
|
201
|
+
type NearbyPayeeQueryResult = Pick<
|
|
202
|
+
db.DbPayee,
|
|
203
|
+
| 'id'
|
|
204
|
+
| 'name'
|
|
205
|
+
| 'transfer_acct'
|
|
206
|
+
| 'favorite'
|
|
207
|
+
| 'learn_categories'
|
|
208
|
+
| 'tombstone'
|
|
209
|
+
> &
|
|
210
|
+
Omit<PayeeLocationEntity, 'id'> & {
|
|
211
|
+
// PayeeLocationEntity's id renamed to location_id
|
|
212
|
+
location_id: PayeeLocationEntity['id'];
|
|
213
|
+
// Calculated distance from SQL
|
|
214
|
+
distance: number;
|
|
215
|
+
};
|
|
216
|
+
async function getNearbyPayees({
|
|
217
|
+
latitude,
|
|
218
|
+
longitude,
|
|
219
|
+
maxDistance = DEFAULT_MAX_DISTANCE_METERS,
|
|
220
|
+
}: {
|
|
221
|
+
latitude: number;
|
|
222
|
+
longitude: number;
|
|
223
|
+
maxDistance?: number;
|
|
224
|
+
}): Promise<NearbyPayeeEntity[]> {
|
|
225
|
+
if (
|
|
226
|
+
!Number.isFinite(latitude) ||
|
|
227
|
+
!Number.isFinite(longitude) ||
|
|
228
|
+
latitude < -90 ||
|
|
229
|
+
latitude > 90 ||
|
|
230
|
+
longitude < -180 ||
|
|
231
|
+
longitude > 180
|
|
232
|
+
) {
|
|
233
|
+
throw new Error(
|
|
234
|
+
'Invalid coordinates: latitude must be between -90 and 90, longitude must be between -180 and 180',
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (!Number.isFinite(maxDistance) || maxDistance <= 0) {
|
|
239
|
+
throw new Error(
|
|
240
|
+
'Invalid maxDistance: must be a finite positive number greater than 0',
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Get the closest location for each payee within maxDistance using window functions
|
|
245
|
+
const query = `
|
|
246
|
+
WITH payee_distances AS (
|
|
247
|
+
SELECT
|
|
248
|
+
pl.id as location_id,
|
|
249
|
+
pl.payee_id,
|
|
250
|
+
pl.latitude,
|
|
251
|
+
pl.longitude,
|
|
252
|
+
pl.created_at,
|
|
253
|
+
p.id,
|
|
254
|
+
p.name,
|
|
255
|
+
p.transfer_acct,
|
|
256
|
+
p.favorite,
|
|
257
|
+
p.learn_categories,
|
|
258
|
+
p.tombstone,
|
|
259
|
+
-- Haversine formula to calculate distance
|
|
260
|
+
((6371 * acos(
|
|
261
|
+
MIN(1, MAX(-1,
|
|
262
|
+
cos(radians(?)) * cos(radians(pl.latitude)) *
|
|
263
|
+
cos(radians(pl.longitude) - radians(?)) +
|
|
264
|
+
sin(radians(?)) * sin(radians(pl.latitude))
|
|
265
|
+
))
|
|
266
|
+
))) * 1000 as distance,
|
|
267
|
+
-- Rank locations by distance for each payee
|
|
268
|
+
ROW_NUMBER() OVER (PARTITION BY pl.payee_id ORDER BY (
|
|
269
|
+
(6371 * acos(
|
|
270
|
+
MIN(1, MAX(-1,
|
|
271
|
+
cos(radians(?)) * cos(radians(pl.latitude)) *
|
|
272
|
+
cos(radians(pl.longitude) - radians(?)) +
|
|
273
|
+
sin(radians(?)) * sin(radians(pl.latitude))
|
|
274
|
+
))
|
|
275
|
+
)) * 1000
|
|
276
|
+
)) as distance_rank
|
|
277
|
+
FROM payee_locations pl
|
|
278
|
+
JOIN payees p ON pl.payee_id = p.id
|
|
279
|
+
WHERE p.tombstone IS NOT 1
|
|
280
|
+
AND pl.tombstone IS NOT 1
|
|
281
|
+
-- Filter by distance using Haversine formula
|
|
282
|
+
AND (6371 * acos(
|
|
283
|
+
MIN(1, MAX(-1,
|
|
284
|
+
cos(radians(?)) * cos(radians(pl.latitude)) *
|
|
285
|
+
cos(radians(pl.longitude) - radians(?)) +
|
|
286
|
+
sin(radians(?)) * sin(radians(pl.latitude))
|
|
287
|
+
))
|
|
288
|
+
)) * 1000 <= ?
|
|
289
|
+
)
|
|
290
|
+
SELECT
|
|
291
|
+
location_id,
|
|
292
|
+
payee_id,
|
|
293
|
+
latitude,
|
|
294
|
+
longitude,
|
|
295
|
+
created_at,
|
|
296
|
+
id,
|
|
297
|
+
name,
|
|
298
|
+
transfer_acct,
|
|
299
|
+
favorite,
|
|
300
|
+
learn_categories,
|
|
301
|
+
tombstone,
|
|
302
|
+
distance
|
|
303
|
+
FROM payee_distances
|
|
304
|
+
WHERE distance_rank = 1
|
|
305
|
+
ORDER BY distance ASC
|
|
306
|
+
LIMIT 10
|
|
307
|
+
`;
|
|
308
|
+
|
|
309
|
+
const results = db.runQuery<NearbyPayeeQueryResult>(
|
|
310
|
+
query,
|
|
311
|
+
[
|
|
312
|
+
latitude,
|
|
313
|
+
longitude,
|
|
314
|
+
latitude, // For first distance calculation in SELECT
|
|
315
|
+
latitude,
|
|
316
|
+
longitude,
|
|
317
|
+
latitude, // For ROW_NUMBER() ordering
|
|
318
|
+
latitude,
|
|
319
|
+
longitude,
|
|
320
|
+
latitude, // For WHERE distance filter
|
|
321
|
+
maxDistance,
|
|
322
|
+
],
|
|
323
|
+
true,
|
|
324
|
+
);
|
|
325
|
+
|
|
326
|
+
// Transform results to expected format
|
|
327
|
+
const nearbyPayees: NearbyPayeeEntity[] = results.map(row => {
|
|
328
|
+
const payee = payeeModel.fromDb({
|
|
329
|
+
id: row.id,
|
|
330
|
+
name: row.name,
|
|
331
|
+
transfer_acct: row.transfer_acct,
|
|
332
|
+
favorite: row.favorite,
|
|
333
|
+
learn_categories: row.learn_categories,
|
|
334
|
+
tombstone: row.tombstone,
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
return {
|
|
338
|
+
payee,
|
|
339
|
+
location: {
|
|
340
|
+
id: row.location_id,
|
|
341
|
+
payee_id: row.payee_id,
|
|
342
|
+
latitude: row.latitude,
|
|
343
|
+
longitude: row.longitude,
|
|
344
|
+
created_at: row.created_at,
|
|
345
|
+
distance: row.distance,
|
|
346
|
+
},
|
|
347
|
+
};
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
return nearbyPayees;
|
|
351
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Polyfills for browser/web worker environment
|
|
2
|
+
import * as jspb from 'google-protobuf';
|
|
3
|
+
|
|
4
|
+
if (typeof globalThis !== 'undefined') {
|
|
5
|
+
// Add a basic require polyfill for CommonJS modules
|
|
6
|
+
if (typeof globalThis.require === 'undefined') {
|
|
7
|
+
// @ts-expect-error - we're creating a minimal require implementation
|
|
8
|
+
globalThis.require = (moduleId: string) => {
|
|
9
|
+
switch (moduleId) {
|
|
10
|
+
case 'google-protobuf':
|
|
11
|
+
return jspb;
|
|
12
|
+
default:
|
|
13
|
+
throw new Error(
|
|
14
|
+
`Module not found: ${moduleId}. Add to polyfills if needed.`,
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Also set on global for compatibility
|
|
22
|
+
if (typeof global !== 'undefined') {
|
|
23
|
+
if (typeof global.require === 'undefined') {
|
|
24
|
+
global.require = globalThis.require;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
// @ts-strict-ignore
|
|
2
|
+
import { fetch } from '../platform/server/fetch';
|
|
3
|
+
import { logger } from '../platform/server/log';
|
|
4
|
+
import * as Platform from '../shared/platform';
|
|
5
|
+
|
|
6
|
+
import { PostError } from './errors';
|
|
7
|
+
|
|
8
|
+
function throwIfNot200(res: Response, text: string) {
|
|
9
|
+
if (res.status !== 200) {
|
|
10
|
+
if (res.status === 500) {
|
|
11
|
+
throw new PostError(res.status === 500 ? 'internal' : text);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const contentType = res.headers.get('Content-Type');
|
|
15
|
+
if (contentType.toLowerCase().indexOf('application/json') !== -1) {
|
|
16
|
+
const json = JSON.parse(text);
|
|
17
|
+
throw new PostError(json.reason);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Actual Sync Server may be exposed via a tunnel (e.g. ngrok). Tunnel errors should be treated as network errors.
|
|
21
|
+
const tunnelErrorHeaders = ['ngrok-error-code'];
|
|
22
|
+
const tunnelError = tunnelErrorHeaders.some(header =>
|
|
23
|
+
res.headers.has(header),
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
if (tunnelError) {
|
|
27
|
+
// Tunnel errors are present when the tunnel is active and the server is not reachable e.g. server is offline
|
|
28
|
+
// When we experience a tunnel error we treat it as a network failure
|
|
29
|
+
throw new PostError('network-failure');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
throw new PostError(text);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function post(
|
|
37
|
+
url: RequestInfo,
|
|
38
|
+
data: unknown,
|
|
39
|
+
headers = {},
|
|
40
|
+
timeout: number | null = null,
|
|
41
|
+
) {
|
|
42
|
+
let text: string;
|
|
43
|
+
let res: Response;
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
const controller = new AbortController();
|
|
47
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
48
|
+
const signal = timeout ? controller.signal : null;
|
|
49
|
+
res = await fetch(url, {
|
|
50
|
+
method: 'POST',
|
|
51
|
+
body: JSON.stringify(data),
|
|
52
|
+
signal,
|
|
53
|
+
headers: {
|
|
54
|
+
...headers,
|
|
55
|
+
'Content-Type': 'application/json',
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
clearTimeout(timeoutId);
|
|
59
|
+
text = await res.text();
|
|
60
|
+
} catch {
|
|
61
|
+
throw new PostError('network-failure');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
throwIfNot200(res, text);
|
|
65
|
+
|
|
66
|
+
let responseData;
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
responseData = JSON.parse(text);
|
|
70
|
+
} catch {
|
|
71
|
+
// Something seriously went wrong. TODO handle errors
|
|
72
|
+
throw new PostError('parse-json', { meta: text });
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (responseData.status !== 'ok') {
|
|
76
|
+
logger.log(
|
|
77
|
+
'API call failed: ' +
|
|
78
|
+
url +
|
|
79
|
+
'\nData: ' +
|
|
80
|
+
JSON.stringify(data, null, 2) +
|
|
81
|
+
'\nResponse: ' +
|
|
82
|
+
JSON.stringify(res, null, 2),
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
throw new PostError(
|
|
86
|
+
responseData.description || responseData.reason || 'unknown',
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return responseData.data;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export async function del(url, data, headers = {}, timeout = null) {
|
|
94
|
+
let text;
|
|
95
|
+
let res;
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
const controller = new AbortController();
|
|
99
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
100
|
+
const signal = timeout ? controller.signal : null;
|
|
101
|
+
res = await fetch(url, {
|
|
102
|
+
method: 'DELETE',
|
|
103
|
+
body: JSON.stringify(data),
|
|
104
|
+
signal,
|
|
105
|
+
headers: {
|
|
106
|
+
...headers,
|
|
107
|
+
'Content-Type': 'application/json',
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
clearTimeout(timeoutId);
|
|
111
|
+
text = await res.text();
|
|
112
|
+
} catch {
|
|
113
|
+
throw new PostError('network-failure');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
throwIfNot200(res, text);
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
res = JSON.parse(text);
|
|
120
|
+
} catch {
|
|
121
|
+
// Something seriously went wrong. TODO handle errors
|
|
122
|
+
throw new PostError('parse-json', { meta: text });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (res.status !== 'ok') {
|
|
126
|
+
logger.log(
|
|
127
|
+
'API call failed: ' +
|
|
128
|
+
url +
|
|
129
|
+
'\nData: ' +
|
|
130
|
+
JSON.stringify(data, null, 2) +
|
|
131
|
+
'\nResponse: ' +
|
|
132
|
+
JSON.stringify(res, null, 2),
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
throw new PostError(res.description || res.reason || 'unknown');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return res.data;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export async function patch(url, data, headers = {}, timeout = null) {
|
|
142
|
+
let text;
|
|
143
|
+
let res;
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
const controller = new AbortController();
|
|
147
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
148
|
+
const signal = timeout ? controller.signal : null;
|
|
149
|
+
res = await fetch(url, {
|
|
150
|
+
method: 'PATCH',
|
|
151
|
+
body: JSON.stringify(data),
|
|
152
|
+
signal,
|
|
153
|
+
headers: {
|
|
154
|
+
...headers,
|
|
155
|
+
'Content-Type': 'application/json',
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
clearTimeout(timeoutId);
|
|
159
|
+
text = await res.text();
|
|
160
|
+
} catch {
|
|
161
|
+
throw new PostError('network-failure');
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
throwIfNot200(res, text);
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
res = JSON.parse(text);
|
|
168
|
+
} catch {
|
|
169
|
+
// Something seriously went wrong. TODO handle errors
|
|
170
|
+
throw new PostError('parse-json', { meta: text });
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (res.status !== 'ok') {
|
|
174
|
+
logger.log(
|
|
175
|
+
'API call failed: ' +
|
|
176
|
+
url +
|
|
177
|
+
'\nData: ' +
|
|
178
|
+
JSON.stringify(data, null, 2) +
|
|
179
|
+
'\nResponse: ' +
|
|
180
|
+
JSON.stringify(res, null, 2),
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
throw new PostError(res.description || res.reason || 'unknown');
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return res.data;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export async function postBinary(url, data, headers) {
|
|
190
|
+
let res;
|
|
191
|
+
try {
|
|
192
|
+
res = await fetch(url, {
|
|
193
|
+
method: 'POST',
|
|
194
|
+
body: Platform.isBrowser ? data : Buffer.from(data),
|
|
195
|
+
headers: {
|
|
196
|
+
'Content-Length': data.length,
|
|
197
|
+
'Content-Type': 'application/actual-sync',
|
|
198
|
+
...headers,
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
} catch {
|
|
202
|
+
throw new PostError('network-failure');
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
let buffer;
|
|
206
|
+
if (res.arrayBuffer) {
|
|
207
|
+
buffer = Buffer.from(await res.arrayBuffer());
|
|
208
|
+
} else {
|
|
209
|
+
buffer = await res.buffer();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
throwIfNot200(res, buffer.toString());
|
|
213
|
+
|
|
214
|
+
return buffer;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export function get(url, opts?) {
|
|
218
|
+
return fetch(url, opts).then(res => res.text());
|
|
219
|
+
}
|