@actual-app/api 6.6.0 → 6.7.1

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.
@@ -12051,6 +12051,47 @@
12051
12051
  }
12052
12052
  /***/
12053
12053
  }),
12054
+ /***/ "./node_modules/date-fns/esm/differenceInMilliseconds/index.js":
12055
+ /*!*********************************************************************!*\
12056
+ !*** ./node_modules/date-fns/esm/differenceInMilliseconds/index.js ***!
12057
+ \*********************************************************************/
12058
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
12059
+ "use strict";
12060
+ __webpack_require__.r(__webpack_exports__);
12061
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
12062
+ /* harmony export */ "default": () => ( /* binding */differenceInMilliseconds)
12063
+ /* harmony export */
12064
+ });
12065
+ /* harmony import */ var _toDate_index_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../toDate/index.js */ "./node_modules/date-fns/esm/toDate/index.js");
12066
+ /* harmony import */ var _lib_requiredArgs_index_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../_lib/requiredArgs/index.js */ "./node_modules/date-fns/esm/_lib/requiredArgs/index.js");
12067
+ /**
12068
+ * @name differenceInMilliseconds
12069
+ * @category Millisecond Helpers
12070
+ * @summary Get the number of milliseconds between the given dates.
12071
+ *
12072
+ * @description
12073
+ * Get the number of milliseconds between the given dates.
12074
+ *
12075
+ * @param {Date|Number} dateLeft - the later date
12076
+ * @param {Date|Number} dateRight - the earlier date
12077
+ * @returns {Number} the number of milliseconds
12078
+ * @throws {TypeError} 2 arguments required
12079
+ *
12080
+ * @example
12081
+ * // How many milliseconds are between
12082
+ * // 2 July 2014 12:30:20.600 and 2 July 2014 12:30:21.700?
12083
+ * const result = differenceInMilliseconds(
12084
+ * new Date(2014, 6, 2, 12, 30, 21, 700),
12085
+ * new Date(2014, 6, 2, 12, 30, 20, 600)
12086
+ * )
12087
+ * //=> 1100
12088
+ */
12089
+ function differenceInMilliseconds(dateLeft, dateRight) {
12090
+ (0, _lib_requiredArgs_index_js__WEBPACK_IMPORTED_MODULE_0__["default"])(2, arguments);
12091
+ return (0, _toDate_index_js__WEBPACK_IMPORTED_MODULE_1__["default"])(dateLeft).getTime() - (0, _toDate_index_js__WEBPACK_IMPORTED_MODULE_1__["default"])(dateRight).getTime();
12092
+ }
12093
+ /***/
12094
+ }),
12054
12095
  /***/ "./node_modules/date-fns/esm/endOfMonth/index.js":
12055
12096
  /*!*******************************************************!*\
12056
12097
  !*** ./node_modules/date-fns/esm/endOfMonth/index.js ***!
@@ -12092,6 +12133,66 @@
12092
12133
  }
12093
12134
  /***/
12094
12135
  }),
12136
+ /***/ "./node_modules/date-fns/esm/endOfWeek/index.js":
12137
+ /*!******************************************************!*\
12138
+ !*** ./node_modules/date-fns/esm/endOfWeek/index.js ***!
12139
+ \******************************************************/
12140
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
12141
+ "use strict";
12142
+ __webpack_require__.r(__webpack_exports__);
12143
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
12144
+ /* harmony export */ "default": () => ( /* binding */endOfWeek)
12145
+ /* harmony export */
12146
+ });
12147
+ /* harmony import */ var _lib_defaultOptions_index_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../_lib/defaultOptions/index.js */ "./node_modules/date-fns/esm/_lib/defaultOptions/index.js");
12148
+ /* harmony import */ var _toDate_index_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../toDate/index.js */ "./node_modules/date-fns/esm/toDate/index.js");
12149
+ /* harmony import */ var _lib_toInteger_index_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../_lib/toInteger/index.js */ "./node_modules/date-fns/esm/_lib/toInteger/index.js");
12150
+ /* harmony import */ var _lib_requiredArgs_index_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../_lib/requiredArgs/index.js */ "./node_modules/date-fns/esm/_lib/requiredArgs/index.js");
12151
+ /**
12152
+ * @name endOfWeek
12153
+ * @category Week Helpers
12154
+ * @summary Return the end of a week for the given date.
12155
+ *
12156
+ * @description
12157
+ * Return the end of a week for the given date.
12158
+ * The result will be in the local timezone.
12159
+ *
12160
+ * @param {Date|Number} date - the original date
12161
+ * @param {Object} [options] - an object with options.
12162
+ * @param {Locale} [options.locale=defaultLocale] - the locale object. See [Locale]{@link https://date-fns.org/docs/Locale}
12163
+ * @param {0|1|2|3|4|5|6} [options.weekStartsOn=0] - the index of the first day of the week (0 - Sunday)
12164
+ * @returns {Date} the end of a week
12165
+ * @throws {TypeError} 1 argument required
12166
+ * @throws {RangeError} `options.weekStartsOn` must be between 0 and 6
12167
+ *
12168
+ * @example
12169
+ * // The end of a week for 2 September 2014 11:55:00:
12170
+ * const result = endOfWeek(new Date(2014, 8, 2, 11, 55, 0))
12171
+ * //=> Sat Sep 06 2014 23:59:59.999
12172
+ *
12173
+ * @example
12174
+ * // If the week starts on Monday, the end of the week for 2 September 2014 11:55:00:
12175
+ * const result = endOfWeek(new Date(2014, 8, 2, 11, 55, 0), { weekStartsOn: 1 })
12176
+ * //=> Sun Sep 07 2014 23:59:59.999
12177
+ */
12178
+ function endOfWeek(dirtyDate, options) {
12179
+ var _ref, _ref2, _ref3, _options$weekStartsOn, _options$locale, _options$locale$optio, _defaultOptions$local, _defaultOptions$local2;
12180
+ (0, _lib_requiredArgs_index_js__WEBPACK_IMPORTED_MODULE_0__["default"])(1, arguments);
12181
+ var defaultOptions = (0, _lib_defaultOptions_index_js__WEBPACK_IMPORTED_MODULE_1__.getDefaultOptions)();
12182
+ var weekStartsOn = (0, _lib_toInteger_index_js__WEBPACK_IMPORTED_MODULE_2__["default"])((_ref = (_ref2 = (_ref3 = (_options$weekStartsOn = options === null || options === void 0 ? void 0 : options.weekStartsOn) !== null && _options$weekStartsOn !== void 0 ? _options$weekStartsOn : options === null || options === void 0 ? void 0 : (_options$locale = options.locale) === null || _options$locale === void 0 ? void 0 : (_options$locale$optio = _options$locale.options) === null || _options$locale$optio === void 0 ? void 0 : _options$locale$optio.weekStartsOn) !== null && _ref3 !== void 0 ? _ref3 : defaultOptions.weekStartsOn) !== null && _ref2 !== void 0 ? _ref2 : (_defaultOptions$local = defaultOptions.locale) === null || _defaultOptions$local === void 0 ? void 0 : (_defaultOptions$local2 = _defaultOptions$local.options) === null || _defaultOptions$local2 === void 0 ? void 0 : _defaultOptions$local2.weekStartsOn) !== null && _ref !== void 0 ? _ref : 0);
12183
+ // Test if weekStartsOn is between 0 and 6 _and_ is not NaN
12184
+ if (!(weekStartsOn >= 0 && weekStartsOn <= 6)) {
12185
+ throw new RangeError('weekStartsOn must be between 0 and 6 inclusively');
12186
+ }
12187
+ var date = (0, _toDate_index_js__WEBPACK_IMPORTED_MODULE_3__["default"])(dirtyDate);
12188
+ var day = date.getDay();
12189
+ var diff = (day < weekStartsOn ? -7 : 0) + 6 - (day - weekStartsOn);
12190
+ date.setDate(date.getDate() + diff);
12191
+ date.setHours(23, 59, 59, 999);
12192
+ return date;
12193
+ }
12194
+ /***/
12195
+ }),
12095
12196
  /***/ "./node_modules/date-fns/esm/format/index.js":
12096
12197
  /*!***************************************************!*\
12097
12198
  !*** ./node_modules/date-fns/esm/format/index.js ***!
@@ -17318,6 +17419,66 @@
17318
17419
  }
17319
17420
  /***/
17320
17421
  }),
17422
+ /***/ "./node_modules/date-fns/esm/startOfWeek/index.js":
17423
+ /*!********************************************************!*\
17424
+ !*** ./node_modules/date-fns/esm/startOfWeek/index.js ***!
17425
+ \********************************************************/
17426
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
17427
+ "use strict";
17428
+ __webpack_require__.r(__webpack_exports__);
17429
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
17430
+ /* harmony export */ "default": () => ( /* binding */startOfWeek)
17431
+ /* harmony export */
17432
+ });
17433
+ /* harmony import */ var _toDate_index_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../toDate/index.js */ "./node_modules/date-fns/esm/toDate/index.js");
17434
+ /* harmony import */ var _lib_toInteger_index_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../_lib/toInteger/index.js */ "./node_modules/date-fns/esm/_lib/toInteger/index.js");
17435
+ /* harmony import */ var _lib_requiredArgs_index_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../_lib/requiredArgs/index.js */ "./node_modules/date-fns/esm/_lib/requiredArgs/index.js");
17436
+ /* harmony import */ var _lib_defaultOptions_index_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../_lib/defaultOptions/index.js */ "./node_modules/date-fns/esm/_lib/defaultOptions/index.js");
17437
+ /**
17438
+ * @name startOfWeek
17439
+ * @category Week Helpers
17440
+ * @summary Return the start of a week for the given date.
17441
+ *
17442
+ * @description
17443
+ * Return the start of a week for the given date.
17444
+ * The result will be in the local timezone.
17445
+ *
17446
+ * @param {Date|Number} date - the original date
17447
+ * @param {Object} [options] - an object with options.
17448
+ * @param {Locale} [options.locale=defaultLocale] - the locale object. See [Locale]{@link https://date-fns.org/docs/Locale}
17449
+ * @param {0|1|2|3|4|5|6} [options.weekStartsOn=0] - the index of the first day of the week (0 - Sunday)
17450
+ * @returns {Date} the start of a week
17451
+ * @throws {TypeError} 1 argument required
17452
+ * @throws {RangeError} `options.weekStartsOn` must be between 0 and 6
17453
+ *
17454
+ * @example
17455
+ * // The start of a week for 2 September 2014 11:55:00:
17456
+ * const result = startOfWeek(new Date(2014, 8, 2, 11, 55, 0))
17457
+ * //=> Sun Aug 31 2014 00:00:00
17458
+ *
17459
+ * @example
17460
+ * // If the week starts on Monday, the start of the week for 2 September 2014 11:55:00:
17461
+ * const result = startOfWeek(new Date(2014, 8, 2, 11, 55, 0), { weekStartsOn: 1 })
17462
+ * //=> Mon Sep 01 2014 00:00:00
17463
+ */
17464
+ function startOfWeek(dirtyDate, options) {
17465
+ var _ref, _ref2, _ref3, _options$weekStartsOn, _options$locale, _options$locale$optio, _defaultOptions$local, _defaultOptions$local2;
17466
+ (0, _lib_requiredArgs_index_js__WEBPACK_IMPORTED_MODULE_0__["default"])(1, arguments);
17467
+ var defaultOptions = (0, _lib_defaultOptions_index_js__WEBPACK_IMPORTED_MODULE_1__.getDefaultOptions)();
17468
+ var weekStartsOn = (0, _lib_toInteger_index_js__WEBPACK_IMPORTED_MODULE_2__["default"])((_ref = (_ref2 = (_ref3 = (_options$weekStartsOn = options === null || options === void 0 ? void 0 : options.weekStartsOn) !== null && _options$weekStartsOn !== void 0 ? _options$weekStartsOn : options === null || options === void 0 ? void 0 : (_options$locale = options.locale) === null || _options$locale === void 0 ? void 0 : (_options$locale$optio = _options$locale.options) === null || _options$locale$optio === void 0 ? void 0 : _options$locale$optio.weekStartsOn) !== null && _ref3 !== void 0 ? _ref3 : defaultOptions.weekStartsOn) !== null && _ref2 !== void 0 ? _ref2 : (_defaultOptions$local = defaultOptions.locale) === null || _defaultOptions$local === void 0 ? void 0 : (_defaultOptions$local2 = _defaultOptions$local.options) === null || _defaultOptions$local2 === void 0 ? void 0 : _defaultOptions$local2.weekStartsOn) !== null && _ref !== void 0 ? _ref : 0);
17469
+ // Test if weekStartsOn is between 0 and 6 _and_ is not NaN
17470
+ if (!(weekStartsOn >= 0 && weekStartsOn <= 6)) {
17471
+ throw new RangeError('weekStartsOn must be between 0 and 6 inclusively');
17472
+ }
17473
+ var date = (0, _toDate_index_js__WEBPACK_IMPORTED_MODULE_3__["default"])(dirtyDate);
17474
+ var day = date.getDay();
17475
+ var diff = (day < weekStartsOn ? 7 : 0) + day - weekStartsOn;
17476
+ date.setDate(date.getDate() - diff);
17477
+ date.setHours(0, 0, 0, 0);
17478
+ return date;
17479
+ }
17480
+ /***/
17481
+ }),
17321
17482
  /***/ "./node_modules/date-fns/esm/subDays/index.js":
17322
17483
  /*!****************************************************!*\
17323
17484
  !*** ./node_modules/date-fns/esm/subDays/index.js ***!
@@ -27249,6 +27410,7 @@
27249
27410
  /* harmony export */ getBudgetMonth: () => ( /* binding */getBudgetMonth),
27250
27411
  /* harmony export */ getBudgetMonths: () => ( /* binding */getBudgetMonths),
27251
27412
  /* harmony export */ getCategories: () => ( /* binding */getCategories),
27413
+ /* harmony export */ getCategoryGroups: () => ( /* binding */getCategoryGroups),
27252
27414
  /* harmony export */ getPayees: () => ( /* binding */getPayees),
27253
27415
  /* harmony export */ getTransactions: () => ( /* binding */getTransactions),
27254
27416
  /* harmony export */ importTransactions: () => ( /* binding */importTransactions),
@@ -27660,6 +27822,9 @@
27660
27822
  id: id
27661
27823
  });
27662
27824
  }
27825
+ function getCategoryGroups() {
27826
+ return send("api/category-groups-get");
27827
+ }
27663
27828
  function createCategoryGroup(group) {
27664
27829
  return send("api/category-group-create", {
27665
27830
  group: group
@@ -31181,124 +31346,27 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
31181
31346
  "use strict";
31182
31347
  __webpack_require__.r(__webpack_exports__);
31183
31348
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
31184
- /* harmony export */ addAccounts: () => ( /* binding */addAccounts),
31185
- /* harmony export */ addGoCardlessAccounts: () => ( /* binding */addGoCardlessAccounts),
31186
- /* harmony export */ findOrCreateBank: () => ( /* binding */findOrCreateBank),
31187
- /* harmony export */ handoffPublicToken: () => ( /* binding */handoffPublicToken)
31349
+ /* harmony export */ findOrCreateBank: () => ( /* binding */findOrCreateBank)
31188
31350
  /* harmony export */
31189
31351
  });
31190
- /* harmony import */ var uuid__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! uuid */ "./node_modules/uuid/dist/esm-node/v4.js");
31191
- /* harmony import */ var _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../platform/server/asyncStorage */ "./packages/loot-core/src/platform/server/asyncStorage/index.electron.ts");
31192
- /* harmony import */ var _shared_util__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../shared/util */ "./packages/loot-core/src/shared/util.ts");
31193
- /* harmony import */ var _db__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../db */ "./packages/loot-core/src/server/db/index.ts");
31194
- /* harmony import */ var _mutators__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../mutators */ "./packages/loot-core/src/server/mutators.ts");
31195
- /* harmony import */ var _post__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../post */ "./packages/loot-core/src/server/post.ts");
31196
- /* harmony import */ var _server_config__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../server-config */ "./packages/loot-core/src/server/server-config.ts");
31197
- /* harmony import */ var _sync__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./sync */ "./packages/loot-core/src/server/accounts/sync.ts");
31352
+ /* harmony import */ var uuid__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! uuid */ "./node_modules/uuid/dist/esm-node/v4.js");
31353
+ /* harmony import */ var _db__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../db */ "./packages/loot-core/src/server/db/index.ts");
31198
31354
  // @ts-strict-ignore
31199
- async function handoffPublicToken(institution, publicToken) {
31200
- const [[, userId], [, key]] = await _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_0__.multiGet([
31201
- 'user-id',
31202
- 'user-key'
31203
- ]);
31204
- if (institution == null || !institution.institution_id || !institution.name) {
31205
- throw new Error('Invalid institution object');
31206
- }
31207
- const id = (0, uuid__WEBPACK_IMPORTED_MODULE_7__["default"])();
31208
- // Make sure to generate an access token first before inserting it
31209
- // into our local database in case it fails
31210
- await (0, _post__WEBPACK_IMPORTED_MODULE_4__.post)((0, _server_config__WEBPACK_IMPORTED_MODULE_5__.getServer)().PLAID_SERVER + '/handoff_public_token', {
31211
- userId,
31212
- key,
31213
- item_id: id,
31214
- public_token: publicToken
31215
- });
31216
- await (0, _mutators__WEBPACK_IMPORTED_MODULE_3__.runMutator)(() => _db__WEBPACK_IMPORTED_MODULE_2__.insertWithUUID('banks', {
31217
- id,
31218
- bank_id: institution.institution_id,
31219
- name: institution.name
31220
- }));
31221
- return id;
31222
- }
31223
31355
  async function findOrCreateBank(institution, requisitionId) {
31224
- const bank = await _db__WEBPACK_IMPORTED_MODULE_2__.first('SELECT id, bank_id, name FROM banks WHERE bank_id = ?', [
31356
+ const bank = await _db__WEBPACK_IMPORTED_MODULE_0__.first('SELECT id, bank_id, name FROM banks WHERE bank_id = ?', [
31225
31357
  requisitionId
31226
31358
  ]);
31227
31359
  if (bank) {
31228
31360
  return bank;
31229
31361
  }
31230
31362
  const bankData = {
31231
- id: (0, uuid__WEBPACK_IMPORTED_MODULE_7__["default"])(),
31363
+ id: (0, uuid__WEBPACK_IMPORTED_MODULE_1__["default"])(),
31232
31364
  bank_id: requisitionId,
31233
31365
  name: institution.name
31234
31366
  };
31235
- await _db__WEBPACK_IMPORTED_MODULE_2__.insertWithUUID('banks', bankData);
31367
+ await _db__WEBPACK_IMPORTED_MODULE_0__.insertWithUUID('banks', bankData);
31236
31368
  return bankData;
31237
31369
  }
31238
- async function addAccounts(bankId, accountIds, offbudgetIds = []) {
31239
- const [[, userId], [, userKey]] = await _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_0__.multiGet([
31240
- 'user-id',
31241
- 'user-key'
31242
- ]);
31243
- // Get all the available accounts
31244
- let accounts = await _sync__WEBPACK_IMPORTED_MODULE_6__.getAccounts(userId, userKey, bankId);
31245
- // Only add the selected accounts
31246
- accounts = accounts.filter((acct) => accountIds.includes(acct.account_id));
31247
- return Promise.all(accounts.map(async (acct) => {
31248
- const id = await (0, _mutators__WEBPACK_IMPORTED_MODULE_3__.runMutator)(async () => {
31249
- const id = await _db__WEBPACK_IMPORTED_MODULE_2__.insertAccount({
31250
- account_id: acct.account_id,
31251
- name: acct.name,
31252
- official_name: acct.official_name,
31253
- balance_current: (0, _shared_util__WEBPACK_IMPORTED_MODULE_1__.amountToInteger)(acct.balances.current),
31254
- mask: acct.mask,
31255
- bank: bankId,
31256
- offbudget: offbudgetIds.includes(acct.account_id) ? 1 : 0
31257
- });
31258
- // Create a transfer payee
31259
- await _db__WEBPACK_IMPORTED_MODULE_2__.insertPayee({
31260
- name: '',
31261
- transfer_acct: id
31262
- });
31263
- return id;
31264
- });
31265
- // Do an initial sync
31266
- await _sync__WEBPACK_IMPORTED_MODULE_6__.syncAccount(userId, userKey, id, acct.account_id, bankId);
31267
- return id;
31268
- }));
31269
- }
31270
- async function addGoCardlessAccounts(bankId, accountIds, offbudgetIds = []) {
31271
- const [[, userId], [, userKey]] = await _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_0__.multiGet([
31272
- 'user-id',
31273
- 'user-key'
31274
- ]);
31275
- // Get all the available accounts
31276
- let accounts = await _sync__WEBPACK_IMPORTED_MODULE_6__.getGoCardlessAccounts(userId, userKey, bankId);
31277
- // Only add the selected accounts
31278
- accounts = accounts.filter((acct) => accountIds.includes(acct.account_id));
31279
- return Promise.all(accounts.map(async (acct) => {
31280
- const id = await (0, _mutators__WEBPACK_IMPORTED_MODULE_3__.runMutator)(async () => {
31281
- const id = await _db__WEBPACK_IMPORTED_MODULE_2__.insertAccount({
31282
- account_id: acct.account_id,
31283
- name: acct.name,
31284
- official_name: acct.official_name,
31285
- balance_current: (0, _shared_util__WEBPACK_IMPORTED_MODULE_1__.amountToInteger)(acct.balances.current),
31286
- mask: acct.mask,
31287
- bank: bankId,
31288
- offbudget: offbudgetIds.includes(acct.account_id) ? 1 : 0
31289
- });
31290
- // Create a transfer payee
31291
- await _db__WEBPACK_IMPORTED_MODULE_2__.insertPayee({
31292
- name: '',
31293
- transfer_acct: id
31294
- });
31295
- return id;
31296
- });
31297
- // Do an initial sync
31298
- await _sync__WEBPACK_IMPORTED_MODULE_6__.syncExternalAccount(userId, userKey, id, acct.account_id, bankId);
31299
- return id;
31300
- }));
31301
- }
31302
31370
  /***/
31303
31371
  }),
31304
31372
  /***/ "./packages/loot-core/src/server/accounts/ofx2json.ts":
@@ -31538,7 +31606,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
31538
31606
  payee_name: trans.payee,
31539
31607
  imported_payee: trans.payee,
31540
31608
  notes: trans.memo || null
31541
- }))
31609
+ })).filter((trans) => trans.date != null && trans.amount != null)
31542
31610
  };
31543
31611
  }
31544
31612
  async function parseOFX(filepath, options) {
@@ -31564,7 +31632,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
31564
31632
  errors,
31565
31633
  transactions: data.transactions.map((trans) => {
31566
31634
  return {
31567
- amount: trans.amount,
31635
+ amount: Number(trans.amount),
31568
31636
  imported_id: trans.fitId,
31569
31637
  date: trans.date,
31570
31638
  payee_name: trans.name || (useMemoFallback ? trans.memo : null),
@@ -32239,7 +32307,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
32239
32307
  update = (0, _shared_transactions__WEBPACK_IMPORTED_MODULE_3__.recalculateSplit)(update);
32240
32308
  }
32241
32309
  }
32242
- // The split index 0 is reserved for "Before split" actions.
32310
+ // The split index 0 is reserved for "Apply to all" actions.
32243
32311
  // Remove that entry from the subtransactions.
32244
32312
  update.subtransactions = update.subtransactions.slice(1);
32245
32313
  return update;
@@ -32550,18 +32618,14 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
32550
32618
  __webpack_require__.r(__webpack_exports__);
32551
32619
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
32552
32620
  /* harmony export */ addTransactions: () => ( /* binding */addTransactions),
32553
- /* harmony export */ fromPlaid: () => ( /* binding */fromPlaid),
32554
- /* harmony export */ getAccounts: () => ( /* binding */getAccounts),
32555
32621
  /* harmony export */ getGoCardlessAccounts: () => ( /* binding */getGoCardlessAccounts),
32556
- /* harmony export */ reconcileExternalTransactions: () => ( /* binding */reconcileExternalTransactions),
32557
32622
  /* harmony export */ reconcileTransactions: () => ( /* binding */reconcileTransactions),
32558
- /* harmony export */ syncAccount: () => ( /* binding */syncAccount),
32559
- /* harmony export */ syncExternalAccount: () => ( /* binding */syncExternalAccount)
32623
+ /* harmony export */ syncAccount: () => ( /* binding */syncAccount)
32560
32624
  /* harmony export */
32561
32625
  });
32562
- /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/max/index.js");
32563
- /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/format/index.js");
32564
- /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/parseISO/index.js");
32626
+ /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/differenceInMilliseconds/index.js");
32627
+ /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/parseISO/index.js");
32628
+ /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/max/index.js");
32565
32629
  /* harmony import */ var uuid__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! uuid */ "./node_modules/uuid/dist/esm-node/v4.js");
32566
32630
  /* harmony import */ var _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../platform/server/asyncStorage */ "./packages/loot-core/src/platform/server/asyncStorage/index.electron.ts");
32567
32631
  /* harmony import */ var _shared_months__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../shared/months */ "./packages/loot-core/src/shared/months.ts");
@@ -32577,8 +32641,6 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
32577
32641
  /* harmony import */ var _transaction_rules__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./transaction-rules */ "./packages/loot-core/src/server/accounts/transaction-rules.ts");
32578
32642
  /* harmony import */ var _transactions__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./transactions */ "./packages/loot-core/src/server/accounts/transactions.ts");
32579
32643
  // @ts-strict-ignore
32580
- // Plaid article about API options:
32581
- // https://support.plaid.com/customer/en/portal/articles/2612155-transactions-returned-per-request
32582
32644
  function BankSyncError(type, code) {
32583
32645
  return {
32584
32646
  type: 'BankSyncError',
@@ -32617,18 +32679,6 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
32617
32679
  id
32618
32680
  ]);
32619
32681
  }
32620
- async function getAccounts(userId, userKey, id) {
32621
- const res = await (0, _post__WEBPACK_IMPORTED_MODULE_6__.post)((0, _server_config__WEBPACK_IMPORTED_MODULE_7__.getServer)().PLAID_SERVER + '/accounts', {
32622
- userId,
32623
- key: userKey,
32624
- item_id: id
32625
- });
32626
- const { accounts } = res;
32627
- accounts.forEach((acct) => {
32628
- acct.balances.current = getAccountBalance(acct);
32629
- });
32630
- return accounts;
32631
- }
32632
32682
  async function getGoCardlessAccounts(userId, userKey, id) {
32633
32683
  const userToken = await _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_0__.getItem('user-token');
32634
32684
  if (!userToken)
@@ -32646,59 +32696,11 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
32646
32696
  });
32647
32697
  return accounts;
32648
32698
  }
32649
- function fromPlaid(trans) {
32650
- return {
32651
- imported_id: trans.transaction_id,
32652
- payee_name: trans.name,
32653
- imported_payee: trans.name,
32654
- amount: -(0, _shared_util__WEBPACK_IMPORTED_MODULE_3__.amountToInteger)(trans.amount),
32655
- date: trans.date
32656
- };
32657
- }
32658
- async function downloadTransactions(userId, userKey, acctId, bankId, since, count) {
32659
- let allTransactions = [];
32660
- let accountBalance = null;
32661
- const pageSize = 100;
32662
- let offset = 0;
32663
- let numDownloaded = 0;
32664
- while (1) {
32665
- const endDate = _shared_months__WEBPACK_IMPORTED_MODULE_1__.currentDay();
32666
- const res = await (0, _post__WEBPACK_IMPORTED_MODULE_6__.post)((0, _server_config__WEBPACK_IMPORTED_MODULE_7__.getServer)().PLAID_SERVER + '/transactions', {
32667
- userId,
32668
- key: userKey,
32669
- item_id: '' + bankId,
32670
- account_id: acctId,
32671
- start_date: since,
32672
- end_date: endDate,
32673
- count: pageSize,
32674
- offset
32675
- });
32676
- if (res.error_code) {
32677
- throw BankSyncError(res.error_type, res.error_code);
32678
- }
32679
- if (res.transactions.length === 0) {
32680
- break;
32681
- }
32682
- numDownloaded += res.transactions.length;
32683
- // Remove pending transactions for now - we will handle them in
32684
- // the future.
32685
- allTransactions = allTransactions.concat(res.transactions.filter((t) => !t.pending));
32686
- accountBalance = getAccountBalance(res.accounts[0]);
32687
- if (numDownloaded === res.total_transactions || count != null && allTransactions.length >= count) {
32688
- break;
32689
- }
32690
- offset += pageSize;
32691
- }
32692
- allTransactions = count != null ? allTransactions.slice(0, count) : allTransactions;
32693
- return {
32694
- transactions: allTransactions.map(fromPlaid),
32695
- accountBalance
32696
- };
32697
- }
32698
32699
  async function downloadGoCardlessTransactions(userId, userKey, acctId, bankId, since) {
32699
32700
  const userToken = await _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_0__.getItem('user-token');
32700
32701
  if (!userToken)
32701
32702
  return;
32703
+ console.log('Pulling transactions from GoCardless');
32702
32704
  const res = await (0, _post__WEBPACK_IMPORTED_MODULE_6__.post)((0, _server_config__WEBPACK_IMPORTED_MODULE_7__.getServer)().GOCARDLESS_SERVER + '/transactions', {
32703
32705
  userId,
32704
32706
  key: userKey,
@@ -32712,6 +32714,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
32712
32714
  throw BankSyncError(res.error_type, res.error_code);
32713
32715
  }
32714
32716
  const { transactions: { all }, balances, startingBalance } = res;
32717
+ console.log('Response:', res);
32715
32718
  return {
32716
32719
  transactions: all,
32717
32720
  accountBalance: balances,
@@ -32722,6 +32725,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
32722
32725
  const userToken = await _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_0__.getItem('user-token');
32723
32726
  if (!userToken)
32724
32727
  return;
32728
+ console.log('Pulling transactions from SimpleFin');
32725
32729
  const res = await (0, _post__WEBPACK_IMPORTED_MODULE_6__.post)((0, _server_config__WEBPACK_IMPORTED_MODULE_7__.getServer)().SIMPLEFIN_SERVER + '/transactions', {
32726
32730
  accountId: acctId,
32727
32731
  startDate: since
@@ -32732,6 +32736,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
32732
32736
  throw BankSyncError(res.error_type, res.error_code);
32733
32737
  }
32734
32738
  const { transactions: { all }, balances, startingBalance } = res;
32739
+ console.log('Response:', res);
32735
32740
  return {
32736
32741
  transactions: all,
32737
32742
  accountBalance: balances,
@@ -32804,7 +32809,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
32804
32809
  payeesToCreate
32805
32810
  };
32806
32811
  }
32807
- async function normalizeExternalTransactions(transactions, acctId) {
32812
+ async function normalizeBankSyncTransactions(transactions, acctId) {
32808
32813
  const payeesToCreate = new Map();
32809
32814
  const normalized = [];
32810
32815
  for (const trans of transactions) {
@@ -32882,11 +32887,13 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
32882
32887
  }
32883
32888
  });
32884
32889
  }
32885
- async function reconcileExternalTransactions(acctId, transactions) {
32890
+ async function reconcileTransactions(acctId, transactions, isBankSyncAccount = false) {
32891
+ console.log('Performing transaction reconciliation');
32886
32892
  const hasMatched = new Set();
32887
32893
  const updated = [];
32888
32894
  const added = [];
32889
- const { normalized, payeesToCreate } = await normalizeExternalTransactions(transactions, acctId);
32895
+ const transactionNormalization = isBankSyncAccount ? normalizeBankSyncTransactions : normalizeTransactions;
32896
+ const { normalized, payeesToCreate } = await transactionNormalization(transactions, acctId);
32890
32897
  // The first pass runs the rules, and preps data for fuzzy matching
32891
32898
  const transactionsStep1 = [];
32892
32899
  for (const { payee_name, trans: originalTrans, subtransactions } of normalized) {
@@ -32919,6 +32926,15 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
32919
32926
  trans.amount || 0,
32920
32927
  acctId
32921
32928
  ]);
32929
+ // Sort the matched transactions according to the distance from the original
32930
+ // transactions date. i.e. if the original transaction is in 21-02-2024 and
32931
+ // the matched transactions are: 20-02-2024, 21-02-2024, 29-02-2024 then
32932
+ // the resulting data-set should be: 21-02-2024, 20-02-2024, 29-02-2024.
32933
+ fuzzyDataset = fuzzyDataset.sort((a, b) => {
32934
+ const aDistance = Math.abs(date_fns__WEBPACK_IMPORTED_MODULE_14__["default"](date_fns__WEBPACK_IMPORTED_MODULE_15__["default"](trans.date), date_fns__WEBPACK_IMPORTED_MODULE_15__["default"](_db__WEBPACK_IMPORTED_MODULE_4__.fromDateRepr(a.date))));
32935
+ const bDistance = Math.abs(date_fns__WEBPACK_IMPORTED_MODULE_14__["default"](date_fns__WEBPACK_IMPORTED_MODULE_15__["default"](trans.date), date_fns__WEBPACK_IMPORTED_MODULE_15__["default"](_db__WEBPACK_IMPORTED_MODULE_4__.fromDateRepr(b.date))));
32936
+ return aDistance > bDistance ? 1 : -1;
32937
+ });
32922
32938
  }
32923
32939
  transactionsStep1.push({
32924
32940
  payee_name,
@@ -32949,7 +32965,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
32949
32965
  });
32950
32966
  // The final fuzzy matching pass. This is the lowest fidelity
32951
32967
  // matching: it just find the first transaction that hasn't been
32952
- // matched yet. Remember the the dataset only contains transactions
32968
+ // matched yet. Remember the dataset only contains transactions
32953
32969
  // around the same date with the same amount.
32954
32970
  const transactionsStep3 = transactionsStep2.map((data) => {
32955
32971
  if (!data.match && data.fuzzyDataset) {
@@ -32979,6 +32995,9 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
32979
32995
  };
32980
32996
  // Update the transaction
32981
32997
  const updates = {
32998
+ ...isBankSyncAccount ? {} : {
32999
+ date: trans.date
33000
+ },
32982
33001
  imported_id: trans.imported_id || null,
32983
33002
  payee: existing.payee || trans.payee || null,
32984
33003
  category: existing.category || trans.category || null,
@@ -33028,155 +33047,10 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
33028
33047
  added,
33029
33048
  updated
33030
33049
  });
33031
- return {
33032
- added: added.map((trans) => trans.id),
33033
- updated: updated.map((trans) => trans.id)
33034
- };
33035
- }
33036
- async function reconcileTransactions(acctId, transactions) {
33037
- const hasMatched = new Set();
33038
- const updated = [];
33039
- const added = [];
33040
- const { normalized, payeesToCreate } = await normalizeTransactions(transactions, acctId);
33041
- // The first pass runs the rules, and preps data for fuzzy matching
33042
- const transactionsStep1 = [];
33043
- for (const { payee_name, trans: originalTrans, subtransactions } of normalized) {
33044
- // Run the rules
33045
- const trans = (0, _transaction_rules__WEBPACK_IMPORTED_MODULE_11__.runRules)(originalTrans);
33046
- let match = null;
33047
- let fuzzyDataset = null;
33048
- // First, match with an existing transaction's imported_id. This
33049
- // is the highest fidelity match and should always be attempted
33050
- // first.
33051
- if (trans.imported_id) {
33052
- match = await _db__WEBPACK_IMPORTED_MODULE_4__.first('SELECT * FROM v_transactions WHERE imported_id = ? AND account = ?', [
33053
- trans.imported_id,
33054
- acctId
33055
- ]);
33056
- if (match) {
33057
- hasMatched.add(match.id);
33058
- }
33059
- }
33060
- // If it didn't match, query data needed for fuzzy matching
33061
- if (!match) {
33062
- // Look 7 days ahead and 7 days back when fuzzy matching. This
33063
- // needs to select all fields that need to be read from the
33064
- // matched transaction. See the final pass below for the needed
33065
- // fields.
33066
- fuzzyDataset = await _db__WEBPACK_IMPORTED_MODULE_4__.all(`SELECT id, is_parent, date, imported_id, payee, category, notes, reconciled FROM v_transactions
33067
- WHERE date >= ? AND date <= ? AND amount = ? AND account = ?`, [
33068
- _db__WEBPACK_IMPORTED_MODULE_4__.toDateRepr(_shared_months__WEBPACK_IMPORTED_MODULE_1__.subDays(trans.date, 7)),
33069
- _db__WEBPACK_IMPORTED_MODULE_4__.toDateRepr(_shared_months__WEBPACK_IMPORTED_MODULE_1__.addDays(trans.date, 7)),
33070
- trans.amount || 0,
33071
- acctId
33072
- ]);
33073
- }
33074
- transactionsStep1.push({
33075
- payee_name,
33076
- trans,
33077
- subtransactions: trans.subtransactions || subtransactions,
33078
- match,
33079
- fuzzyDataset
33080
- });
33081
- }
33082
- // Next, do the fuzzy matching. This first pass matches based on the
33083
- // payee id. We do this in multiple passes so that higher fidelity
33084
- // matching always happens first, i.e. a transaction should match
33085
- // match with low fidelity if a later transaction is going to match
33086
- // the same one with high fidelity.
33087
- const transactionsStep2 = transactionsStep1.map((data) => {
33088
- if (!data.match && data.fuzzyDataset) {
33089
- // Try to find one where the payees match.
33090
- const match = data.fuzzyDataset.find((row) => !hasMatched.has(row.id) && data.trans.payee === row.payee);
33091
- if (match) {
33092
- hasMatched.add(match.id);
33093
- return {
33094
- ...data,
33095
- match
33096
- };
33097
- }
33098
- }
33099
- return data;
33100
- });
33101
- // The final fuzzy matching pass. This is the lowest fidelity
33102
- // matching: it just find the first transaction that hasn't been
33103
- // matched yet. Remember the the dataset only contains transactions
33104
- // around the same date with the same amount.
33105
- const transactionsStep3 = transactionsStep2.map((data) => {
33106
- if (!data.match && data.fuzzyDataset) {
33107
- const match = data.fuzzyDataset.find((row) => !hasMatched.has(row.id));
33108
- if (match) {
33109
- hasMatched.add(match.id);
33110
- return {
33111
- ...data,
33112
- match
33113
- };
33114
- }
33115
- }
33116
- return data;
33117
- });
33118
- // Finally, generate & commit the changes
33119
- for (const { trans, subtransactions, match } of transactionsStep3) {
33120
- if (match) {
33121
- // Skip updating already reconciled (locked) transactions
33122
- if (match.reconciled) {
33123
- continue;
33124
- }
33125
- // TODO: change the above sql query to use aql
33126
- const existing = {
33127
- ...match,
33128
- cleared: match.cleared === 1,
33129
- date: _db__WEBPACK_IMPORTED_MODULE_4__.fromDateRepr(match.date)
33130
- };
33131
- // Update the transaction
33132
- const updates = {
33133
- date: trans.date,
33134
- imported_id: trans.imported_id || null,
33135
- payee: existing.payee || trans.payee || null,
33136
- category: existing.category || trans.category || null,
33137
- imported_payee: trans.imported_payee || null,
33138
- notes: existing.notes || trans.notes || null,
33139
- cleared: trans.cleared != null ? trans.cleared : true
33140
- };
33141
- if ((0, _shared_util__WEBPACK_IMPORTED_MODULE_3__.hasFieldsChanged)(existing, updates, Object.keys(updates))) {
33142
- updated.push({
33143
- id: existing.id,
33144
- ...updates
33145
- });
33146
- }
33147
- if (existing.is_parent && existing.cleared !== updates.cleared) {
33148
- const children = await _db__WEBPACK_IMPORTED_MODULE_4__.all('SELECT id FROM v_transactions WHERE parent_id = ?', [
33149
- existing.id
33150
- ]);
33151
- for (const child of children) {
33152
- updated.push({
33153
- id: child.id,
33154
- cleared: updates.cleared
33155
- });
33156
- }
33157
- }
33158
- }
33159
- else {
33160
- // Insert a new transaction
33161
- const finalTransaction = {
33162
- ...trans,
33163
- id: (0, uuid__WEBPACK_IMPORTED_MODULE_13__["default"])(),
33164
- category: trans.category || null,
33165
- cleared: trans.cleared != null ? trans.cleared : true
33166
- };
33167
- if (subtransactions && subtransactions.length > 0) {
33168
- added.push(...makeSplitTransaction(finalTransaction, subtransactions));
33169
- }
33170
- else {
33171
- added.push(finalTransaction);
33172
- }
33173
- }
33174
- }
33175
- await createNewPayees(payeesToCreate, [
33176
- ...added,
33177
- ...updated
33178
- ]);
33179
- await (0, _transactions__WEBPACK_IMPORTED_MODULE_12__.batchUpdateTransactions)({
33050
+ console.log('Debug data for the operations:', {
33051
+ transactionsStep1,
33052
+ transactionsStep2,
33053
+ transactionsStep3,
33180
33054
  added,
33181
33055
  updated
33182
33056
  });
@@ -33227,7 +33101,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
33227
33101
  }
33228
33102
  return newTransactions;
33229
33103
  }
33230
- async function syncExternalAccount(userId, userKey, id, acctId, bankId) {
33104
+ async function syncAccount(userId, userKey, id, acctId, bankId) {
33231
33105
  // TODO: Handle the case where transactions exist in the future
33232
33106
  // (that will make start date after end date)
33233
33107
  const latestTransaction = await _db__WEBPACK_IMPORTED_MODULE_4__.first('SELECT * FROM v_transactions WHERE account = ? ORDER BY date DESC LIMIT 1', [
@@ -33238,13 +33112,14 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
33238
33112
  const startingTransaction = await _db__WEBPACK_IMPORTED_MODULE_4__.first('SELECT date FROM v_transactions WHERE account = ? ORDER BY date ASC LIMIT 1', [
33239
33113
  id
33240
33114
  ]);
33241
- const startingDate = _shared_months__WEBPACK_IMPORTED_MODULE_1__.parseDate(_db__WEBPACK_IMPORTED_MODULE_4__.fromDateRepr(startingTransaction.date));
33242
- const startDate = _shared_months__WEBPACK_IMPORTED_MODULE_1__.dayFromDate(date_fns__WEBPACK_IMPORTED_MODULE_14__["default"]([
33115
+ const startingDate = _db__WEBPACK_IMPORTED_MODULE_4__.fromDateRepr(startingTransaction.date);
33116
+ // assert(startingTransaction)
33117
+ const startDate = _shared_months__WEBPACK_IMPORTED_MODULE_1__.dayFromDate(date_fns__WEBPACK_IMPORTED_MODULE_16__["default"]([
33243
33118
  // Many GoCardless integrations do not support getting more than 90 days
33244
33119
  // worth of data, so make that the earliest possible limit.
33245
33120
  _shared_months__WEBPACK_IMPORTED_MODULE_1__.parseDate(_shared_months__WEBPACK_IMPORTED_MODULE_1__.subDays(_shared_months__WEBPACK_IMPORTED_MODULE_1__.currentDay(), 90)),
33246
33121
  // Never download transactions before the starting date.
33247
- startingDate
33122
+ _shared_months__WEBPACK_IMPORTED_MODULE_1__.parseDate(startingDate)
33248
33123
  ]));
33249
33124
  let download;
33250
33125
  if (acctRow.account_sync_source === 'simpleFin') {
@@ -33253,6 +33128,9 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
33253
33128
  else if (acctRow.account_sync_source === 'goCardless') {
33254
33129
  download = await downloadGoCardlessTransactions(userId, userKey, acctId, bankId, startDate);
33255
33130
  }
33131
+ else {
33132
+ throw new Error(`Unrecognized bank-sync provider: ${acctRow.account_sync_source}`);
33133
+ }
33256
33134
  const { transactions: originalTransactions, accountBalance } = download;
33257
33135
  if (originalTransactions.length === 0) {
33258
33136
  return {
@@ -33265,25 +33143,25 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
33265
33143
  account: id
33266
33144
  }));
33267
33145
  return (0, _mutators__WEBPACK_IMPORTED_MODULE_5__.runMutator)(async () => {
33268
- const result = await reconcileExternalTransactions(id, transactions);
33146
+ const result = await reconcileTransactions(id, transactions, true);
33269
33147
  await updateAccountBalance(id, accountBalance);
33270
33148
  return result;
33271
33149
  });
33272
33150
  }
33273
33151
  else {
33152
+ let download;
33274
33153
  // Otherwise, download transaction for the past 90 days
33275
33154
  const startingDay = _shared_months__WEBPACK_IMPORTED_MODULE_1__.subDays(_shared_months__WEBPACK_IMPORTED_MODULE_1__.currentDay(), 90);
33276
- let download;
33277
33155
  if (acctRow.account_sync_source === 'simpleFin') {
33278
33156
  download = await downloadSimpleFinTransactions(acctId, startingDay);
33279
33157
  }
33280
33158
  else if (acctRow.account_sync_source === 'goCardless') {
33281
33159
  download = await downloadGoCardlessTransactions(userId, userKey, acctId, bankId, startingDay);
33282
33160
  }
33283
- const { transactions, startingBalance } = download;
33284
- let balanceToUse = startingBalance;
33161
+ const { transactions } = download;
33162
+ let balanceToUse = download.startingBalance;
33285
33163
  if (acctRow.account_sync_source === 'simpleFin') {
33286
- const currentBalance = startingBalance;
33164
+ const currentBalance = download.startingBalance;
33287
33165
  const previousBalance = transactions.reduce((total, trans) => {
33288
33166
  return total - parseInt(trans.transactionAmount.amount.replace('.', ''));
33289
33167
  }, currentBalance);
@@ -33302,86 +33180,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
33302
33180
  cleared: true,
33303
33181
  starting_balance_flag: true
33304
33182
  });
33305
- const result = await reconcileExternalTransactions(id, transactions);
33306
- return {
33307
- ...result,
33308
- added: [
33309
- initialId,
33310
- ...result.added
33311
- ]
33312
- };
33313
- });
33314
- }
33315
- }
33316
- async function syncAccount(userId, userKey, id, acctId, bankId) {
33317
- // TODO: Handle the case where transactions exist in the future
33318
- // (that will make start date after end date)
33319
- const latestTransaction = await _db__WEBPACK_IMPORTED_MODULE_4__.first('SELECT * FROM v_transactions WHERE account = ? ORDER BY date DESC LIMIT 1', [
33320
- id
33321
- ]);
33322
- if (latestTransaction) {
33323
- const startingTransaction = await _db__WEBPACK_IMPORTED_MODULE_4__.first('SELECT date FROM v_transactions WHERE account = ? ORDER BY date ASC LIMIT 1', [
33324
- id
33325
- ]);
33326
- const startingDate = _db__WEBPACK_IMPORTED_MODULE_4__.fromDateRepr(startingTransaction.date);
33327
- // assert(startingTransaction)
33328
- // Get all transactions since the latest transaction, plus any 5
33329
- // days before the latest transaction. This gives us a chance to
33330
- // resolve any transactions that were entered manually.
33331
- //
33332
- // TODO: What this really should do is query the last imported_id
33333
- // and since then
33334
- let date = _shared_months__WEBPACK_IMPORTED_MODULE_1__.subDays(_db__WEBPACK_IMPORTED_MODULE_4__.fromDateRepr(latestTransaction.date), 31);
33335
- // Never download transactions before the starting date. This was
33336
- // when the account was added to the system.
33337
- if (date < startingDate) {
33338
- date = startingDate;
33339
- }
33340
- const { transactions: originalTransactions, accountBalance } = await downloadTransactions(userId, userKey, acctId, bankId, date);
33341
- if (originalTransactions.length === 0) {
33342
- return {
33343
- added: [],
33344
- updated: []
33345
- };
33346
- }
33347
- const transactions = originalTransactions.map((trans) => ({
33348
- ...trans,
33349
- account: id
33350
- }));
33351
- return (0, _mutators__WEBPACK_IMPORTED_MODULE_5__.runMutator)(async () => {
33352
- const result = await reconcileTransactions(id, transactions);
33353
- await updateAccountBalance(id, accountBalance);
33354
- return result;
33355
- });
33356
- }
33357
- else {
33358
- const acctRow = await _db__WEBPACK_IMPORTED_MODULE_4__.select('accounts', id);
33359
- // Otherwise, download transaction for the last few days if it's an
33360
- // on-budget account, or for the past 30 days if off-budget
33361
- const startingDay = _shared_months__WEBPACK_IMPORTED_MODULE_1__.subDays(_shared_months__WEBPACK_IMPORTED_MODULE_1__.currentDay(), acctRow.offbudget === 0 ? 1 : 30);
33362
- const { transactions } = await downloadTransactions(userId, userKey, acctId, bankId, date_fns__WEBPACK_IMPORTED_MODULE_15__["default"](date_fns__WEBPACK_IMPORTED_MODULE_16__["default"](startingDay), 'yyyy-MM-dd'));
33363
- // We need to add a transaction that represents the starting
33364
- // balance for everything to balance out. In order to get balance
33365
- // before the first imported transaction, we need to get the
33366
- // current balance from the accounts table and subtract all the
33367
- // imported transactions.
33368
- const currentBalance = acctRow.balance_current;
33369
- const previousBalance = transactions.reduce((total, trans) => {
33370
- return total - trans.amount;
33371
- }, currentBalance);
33372
- const oldestDate = transactions.length > 0 ? transactions[transactions.length - 1].date : _shared_months__WEBPACK_IMPORTED_MODULE_1__.currentDay();
33373
- const payee = await (0, _payees__WEBPACK_IMPORTED_MODULE_9__.getStartingBalancePayee)();
33374
- return (0, _mutators__WEBPACK_IMPORTED_MODULE_5__.runMutator)(async () => {
33375
- const initialId = await _db__WEBPACK_IMPORTED_MODULE_4__.insertTransaction({
33376
- account: id,
33377
- amount: previousBalance,
33378
- category: acctRow.offbudget === 0 ? payee.category : null,
33379
- payee: payee.id,
33380
- date: oldestDate,
33381
- cleared: true,
33382
- starting_balance_flag: true
33383
- });
33384
- const result = await reconcileTransactions(id, transactions);
33183
+ const result = await reconcileTransactions(id, transactions, true);
33385
33184
  return {
33386
33185
  ...result,
33387
33186
  added: [
@@ -35252,6 +35051,10 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
35252
35051
  const result = await handlers['get-categories']();
35253
35052
  return grouped ? result.grouped.map(_api_models__WEBPACK_IMPORTED_MODULE_8__.categoryGroupModel.toExternal) : result.list.map(_api_models__WEBPACK_IMPORTED_MODULE_8__.categoryModel.toExternal);
35254
35053
  };
35054
+ handlers['api/category-groups-get'] = async function () {
35055
+ checkFileOpen();
35056
+ return handlers['get-category-groups']();
35057
+ };
35255
35058
  handlers['api/category-group-create'] = withMutation(async function ({ group }) {
35256
35059
  checkFileOpen();
35257
35060
  return handlers['category-group-create']({
@@ -35977,6 +35780,11 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
35977
35780
  return typed(val(state, args[0]), args[0].type);
35978
35781
  }
35979
35782
  // date functions
35783
+ case '$day':
35784
+ {
35785
+ validateArgLength(args, 1);
35786
+ return castInput(state, args[0], 'date');
35787
+ }
35980
35788
  case '$month':
35981
35789
  {
35982
35790
  validateArgLength(args, 1);
@@ -38509,6 +38317,83 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
38509
38317
  function cleanupTemplate({ month }) {
38510
38318
  return processCleanup(month);
38511
38319
  }
38320
+ async function applyGroupCleanups(month, sourceGroups, sinkGroups, generalGroups) {
38321
+ const sheetName = _shared_months__WEBPACK_IMPORTED_MODULE_0__.sheetForMonth(month);
38322
+ const warnings = [];
38323
+ const db_month = parseInt(month.replace('-', ''));
38324
+ let groupLength = sourceGroups.length;
38325
+ while (groupLength > 0) {
38326
+ //function for each unique group
38327
+ const groupName = sourceGroups[0].group;
38328
+ const tempSourceGroups = sourceGroups.filter((c) => c.group === groupName);
38329
+ const sinkGroup = sinkGroups.filter((c) => c.group === groupName);
38330
+ const generalGroup = generalGroups.filter((c) => c.group === groupName);
38331
+ let total_weight = 0;
38332
+ if (sinkGroup.length > 0 || generalGroup.length > 0) {
38333
+ //only return group source funds to To Budget if there are corresponding sinking groups or underfunded included groups
38334
+ for (let ii = 0; ii < tempSourceGroups.length; ii++) {
38335
+ const balance = await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.getSheetValue)(sheetName, `leftover-${tempSourceGroups[ii].category}`);
38336
+ const budgeted = await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.getSheetValue)(sheetName, `budget-${tempSourceGroups[ii].category}`);
38337
+ await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.setBudget)({
38338
+ category: tempSourceGroups[ii].category,
38339
+ month,
38340
+ amount: budgeted - balance
38341
+ });
38342
+ }
38343
+ //calculate total weight for sinking funds
38344
+ for (let ii = 0; ii < sinkGroup.length; ii++) {
38345
+ total_weight += sinkGroup[ii].weight;
38346
+ }
38347
+ //fill underfunded categories within the group first
38348
+ for (let ii = 0; ii < generalGroup.length; ii++) {
38349
+ const budgetAvailable = await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.getSheetValue)(sheetName, `to-budget`);
38350
+ const balance = await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.getSheetValue)(sheetName, `leftover-${generalGroup[ii].category}`);
38351
+ const budgeted = await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.getSheetValue)(sheetName, `budget-${generalGroup[ii].category}`);
38352
+ const to_budget = budgeted + Math.abs(balance);
38353
+ const categoryId = generalGroup[ii].category;
38354
+ let carryover = await _db__WEBPACK_IMPORTED_MODULE_1__.first(`SELECT carryover FROM zero_budgets WHERE month = ? and category = ?`, [
38355
+ db_month,
38356
+ categoryId
38357
+ ]);
38358
+ if (carryover === null) {
38359
+ carryover = {
38360
+ carryover: 0
38361
+ };
38362
+ }
38363
+ if (balance < 0 && Math.abs(balance) <= budgetAvailable && !generalGroup[ii].category.is_income && carryover.carryover === 0) {
38364
+ await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.setBudget)({
38365
+ category: generalGroup[ii].category,
38366
+ month,
38367
+ amount: to_budget
38368
+ });
38369
+ }
38370
+ else if (balance < 0 && !generalGroup[ii].category.is_income && carryover.carryover === 0 && Math.abs(balance) > budgetAvailable) {
38371
+ await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.setBudget)({
38372
+ category: generalGroup[ii].category,
38373
+ month,
38374
+ amount: budgeted + budgetAvailable
38375
+ });
38376
+ }
38377
+ }
38378
+ const budgetAvailable = await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.getSheetValue)(sheetName, `to-budget`);
38379
+ for (let ii = 0; ii < sinkGroup.length; ii++) {
38380
+ const budgeted = await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.getSheetValue)(sheetName, `budget-${sinkGroup[ii].category}`);
38381
+ const to_budget = budgeted + Math.round(sinkGroup[ii].weight / total_weight * budgetAvailable);
38382
+ await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.setBudget)({
38383
+ category: sinkGroup[ii].category,
38384
+ month,
38385
+ amount: to_budget
38386
+ });
38387
+ }
38388
+ }
38389
+ else {
38390
+ warnings.push(groupName + ' has no matching sink categories.');
38391
+ }
38392
+ sourceGroups = sourceGroups.filter((c) => c.group !== groupName);
38393
+ groupLength = sourceGroups.length;
38394
+ }
38395
+ return warnings;
38396
+ }
38512
38397
  async function processCleanup(month) {
38513
38398
  let num_sources = 0;
38514
38399
  let num_sinks = 0;
@@ -38521,15 +38406,52 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
38521
38406
  const category_templates = await getCategoryTemplates();
38522
38407
  const categories = await _db__WEBPACK_IMPORTED_MODULE_1__.all('SELECT * FROM v_categories WHERE tombstone = 0');
38523
38408
  const sheetName = _shared_months__WEBPACK_IMPORTED_MODULE_0__.sheetForMonth(month);
38409
+ const groupSource = [];
38410
+ const groupSink = [];
38411
+ const groupGeneral = [];
38412
+ //filter out category groups
38413
+ for (let c = 0; c < categories.length; c++) {
38414
+ const category = categories[c];
38415
+ const template = category_templates[category.id];
38416
+ //filter out source and sink groups for processing
38417
+ if (template) {
38418
+ if (template.filter((t) => t.type === 'source' && t.group !== null).length > 0) {
38419
+ groupSource.push({
38420
+ category: category.id,
38421
+ group: template.filter((t) => t.type === 'source' && t.group !== null)[0].group
38422
+ });
38423
+ }
38424
+ if (template.filter((t) => t.type === 'sink' && t.group !== null).length > 0) {
38425
+ //only supports 1 sink reference per category. Need more?
38426
+ groupSink.push({
38427
+ category: category.id,
38428
+ group: template.filter((t) => t.type === 'sink' && t.group !== null)[0].group,
38429
+ weight: template.filter((t) => t.type === 'sink' && t.group !== null)[0].weight
38430
+ });
38431
+ }
38432
+ if (template.filter((t) => t.type === null && t.group !== null).length > 0) {
38433
+ groupGeneral.push({
38434
+ category: category.id,
38435
+ group: template[0].group
38436
+ });
38437
+ }
38438
+ }
38439
+ }
38440
+ //run category groups
38441
+ const newWarnings = await applyGroupCleanups(month, groupSource, groupSink, groupGeneral);
38442
+ warnings.splice(1, 0, ...newWarnings);
38524
38443
  for (let c = 0; c < categories.length; c++) {
38525
38444
  const category = categories[c];
38526
38445
  const template = category_templates[category.id];
38527
38446
  if (template) {
38528
- if (template.filter((t) => t.type === 'source').length > 0) {
38447
+ if (template.filter((t) => t.type === 'source' && t.group === null).length > 0) {
38529
38448
  const balance = await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.getSheetValue)(sheetName, `leftover-${category.id}`);
38530
38449
  const budgeted = await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.getSheetValue)(sheetName, `budget-${category.id}`);
38531
38450
  if (balance >= 0) {
38532
- const spent = await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.getSheetValue)(sheetName, `sum-amount-${category.id}`);
38451
+ // const spent = await getSheetValue(
38452
+ // sheetName,
38453
+ // `sum-amount-${category.id}`,
38454
+ // );
38533
38455
  await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.setBudget)({
38534
38456
  category: category.id,
38535
38457
  month,
@@ -38538,7 +38460,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
38538
38460
  await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.setGoal)({
38539
38461
  category: category.id,
38540
38462
  month,
38541
- goal: -spent
38463
+ goal: budgeted - balance
38542
38464
  });
38543
38465
  num_sources += 1;
38544
38466
  }
@@ -38559,7 +38481,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
38559
38481
  }
38560
38482
  }
38561
38483
  }
38562
- if (template.filter((t) => t.type === 'sink').length > 0) {
38484
+ if (template.filter((t) => t.type === 'sink' && t.group === null).length > 0) {
38563
38485
  sinkCategory.push({
38564
38486
  cat: category,
38565
38487
  temp: template
@@ -38601,42 +38523,11 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
38601
38523
  });
38602
38524
  }
38603
38525
  }
38604
- //fund rollover categories after non-rollover categories
38605
- for (let c = 0; c < categories.length; c++) {
38606
- const category = categories[c];
38607
- const budgetAvailable = await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.getSheetValue)(sheetName, `to-budget`);
38608
- const balance = await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.getSheetValue)(sheetName, `leftover-${category.id}`);
38609
- const budgeted = await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.getSheetValue)(sheetName, `budget-${category.id}`);
38610
- const to_budget = budgeted + Math.abs(balance);
38611
- const categoryId = category.id;
38612
- let carryover = await _db__WEBPACK_IMPORTED_MODULE_1__.first(`SELECT carryover FROM zero_budgets WHERE month = ? and category = ?`, [
38613
- db_month,
38614
- categoryId
38615
- ]);
38616
- if (carryover === null) {
38617
- carryover = {
38618
- carryover: 0
38619
- };
38620
- }
38621
- if (balance < 0 && Math.abs(balance) <= budgetAvailable && !category.is_income && carryover.carryover === 1) {
38622
- await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.setBudget)({
38623
- category: category.id,
38624
- month,
38625
- amount: to_budget
38626
- });
38627
- }
38628
- else if (balance < 0 && !category.is_income && carryover.carryover === 1 && Math.abs(balance) > budgetAvailable) {
38629
- await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.setBudget)({
38630
- category: category.id,
38631
- month,
38632
- amount: budgeted + budgetAvailable
38633
- });
38634
- }
38635
- }
38636
38526
  const budgetAvailable = await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.getSheetValue)(sheetName, `to-budget`);
38637
38527
  if (budgetAvailable <= 0) {
38638
- warnings.push('No funds are available to reallocate.');
38528
+ warnings.push('Global: No funds are available to reallocate.');
38639
38529
  }
38530
+ //fill sinking categories
38640
38531
  for (let c = 0; c < sinkCategory.length; c++) {
38641
38532
  const budgeted = await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.getSheetValue)(sheetName, `budget-${sinkCategory[c].cat.id}`);
38642
38533
  const categoryId = sinkCategory[c].cat.id;
@@ -38666,7 +38557,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
38666
38557
  else if (warnings.length) {
38667
38558
  return {
38668
38559
  type: 'warning',
38669
- message: 'Funds not available:',
38560
+ message: 'Global: Funds not available:',
38670
38561
  pre: warnings.join('\n\n')
38671
38562
  };
38672
38563
  }
@@ -38686,6 +38577,13 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
38686
38577
  pre: errors.join('\n\n')
38687
38578
  };
38688
38579
  }
38580
+ else if (warnings.length) {
38581
+ return {
38582
+ type: 'warning',
38583
+ message: 'Global: Funds not available:',
38584
+ pre: warnings.join('\n\n')
38585
+ };
38586
+ }
38689
38587
  else {
38690
38588
  return {
38691
38589
  type: 'message',
@@ -38726,6 +38624,47 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
38726
38624
  }
38727
38625
  /***/
38728
38626
  }),
38627
+ /***/ "./packages/loot-core/src/server/budget/goals/goalsAverage.ts":
38628
+ /*!********************************************************************!*\
38629
+ !*** ./packages/loot-core/src/server/budget/goals/goalsAverage.ts ***!
38630
+ \********************************************************************/
38631
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
38632
+ "use strict";
38633
+ __webpack_require__.r(__webpack_exports__);
38634
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
38635
+ /* harmony export */ goalsAverage: () => ( /* binding */goalsAverage)
38636
+ /* harmony export */
38637
+ });
38638
+ /* harmony import */ var _shared_months__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../../shared/months */ "./packages/loot-core/src/shared/months.ts");
38639
+ /* harmony import */ var _actions__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../actions */ "./packages/loot-core/src/server/budget/actions.ts");
38640
+ // @ts-strict-ignore
38641
+ async function goalsAverage(template, month, category, errors, to_budget) {
38642
+ // simple has an 'amount' param
38643
+ let increment = 0;
38644
+ if (template.amount) {
38645
+ let sum = 0;
38646
+ for (let i = 1; i <= template.amount; i++) {
38647
+ // add up other months
38648
+ const sheetName = _shared_months__WEBPACK_IMPORTED_MODULE_0__.sheetForMonth(_shared_months__WEBPACK_IMPORTED_MODULE_0__.subMonths(month, i));
38649
+ sum += await (0, _actions__WEBPACK_IMPORTED_MODULE_1__.getSheetValue)(sheetName, `sum-amount-${category.id}`);
38650
+ }
38651
+ increment = sum / template.amount;
38652
+ }
38653
+ else {
38654
+ errors.push('Number of months to average is not valid');
38655
+ return {
38656
+ to_budget,
38657
+ errors
38658
+ };
38659
+ }
38660
+ to_budget += -Math.round(increment);
38661
+ return {
38662
+ to_budget,
38663
+ errors
38664
+ };
38665
+ }
38666
+ /***/
38667
+ }),
38729
38668
  /***/ "./packages/loot-core/src/server/budget/goals/goalsBy.ts":
38730
38669
  /*!***************************************************************!*\
38731
38670
  !*** ./packages/loot-core/src/server/budget/goals/goalsBy.ts ***!
@@ -39019,8 +38958,9 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
39019
38958
  //in the case of multiple templates per category, schedules may have wrong priority level
39020
38959
  const t = await createScheduleList(template, current_month, category);
39021
38960
  errors = errors.concat(t.errors);
39022
- const t_payMonthOf = t.t.filter((c) => c.full || c.target_frequency === 'monthly' && c.target_interval === 1 && c.num_months === 0 || c.target_frequency === 'weekly' && c.target_interval >= 0 && c.num_months === 0 || c.target_frequency === 'daily' || (0, _actions__WEBPACK_IMPORTED_MODULE_4__.isReflectBudget)());
39023
- const t_sinking = t.t.filter((c) => !c.full && c.target_frequency === 'monthly' && c.target_interval > 1 || !c.full && c.target_frequency === 'monthly' && c.num_months > 0 && c.target_interval === 1 || !c.full && c.target_frequency === 'yearly' || !c.full && c.target_frequency === undefined).sort((a, b) => a.next_date_string.localeCompare(b.next_date_string));
38961
+ const isPayMonthOf = (c) => c.full || c.target_frequency === 'monthly' && c.target_interval === 1 && c.num_months === 0 || c.target_frequency === 'weekly' && c.target_interval >= 0 && c.num_months === 0 || c.target_frequency === 'daily' || (0, _actions__WEBPACK_IMPORTED_MODULE_4__.isReflectBudget)();
38962
+ const t_payMonthOf = t.t.filter(isPayMonthOf);
38963
+ const t_sinking = t.t.filter((c) => !isPayMonthOf(c)).sort((a, b) => a.next_date_string.localeCompare(b.next_date_string));
39024
38964
  const totalPayMonthOf = await getPayMonthOfTotal(t_payMonthOf);
39025
38965
  const totalSinking = await getSinkingTotal(t_sinking);
39026
38966
  const totalSinkingBaseContribution = await getSinkingBaseContributionTotal(t_sinking);
@@ -39029,7 +38969,12 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
39029
38969
  }
39030
38970
  else {
39031
38971
  const totalSinkingContribution = await getSinkingContributionTotal(t_sinking, remainder, last_month_balance);
39032
- to_budget += Math.round(totalPayMonthOf + totalSinkingContribution);
38972
+ if (t_sinking.length === 0) {
38973
+ to_budget += Math.round(totalPayMonthOf + totalSinkingContribution) - last_month_balance;
38974
+ }
38975
+ else {
38976
+ to_budget += Math.round(totalPayMonthOf + totalSinkingContribution);
38977
+ }
39033
38978
  }
39034
38979
  }
39035
38980
  return {
@@ -39054,7 +38999,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
39054
38999
  });
39055
39000
  /* harmony import */ var _shared_util__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../../shared/util */ "./packages/loot-core/src/shared/util.ts");
39056
39001
  // @ts-strict-ignore
39057
- async function goalsSimple(template, limitCheck, errors, limit, hold, to_budget) {
39002
+ async function goalsSimple(template, limitCheck, errors, limit, hold, to_budget, last_month_balance) {
39058
39003
  // simple has 'monthly' and/or 'limit' params
39059
39004
  if (template.limit != null) {
39060
39005
  if (limitCheck) {
@@ -39079,7 +39024,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
39079
39024
  increment = monthly;
39080
39025
  }
39081
39026
  else {
39082
- increment = limit;
39027
+ increment = limit - last_month_balance;
39083
39028
  }
39084
39029
  to_budget += increment;
39085
39030
  return {
@@ -39224,13 +39169,14 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
39224
39169
  /* harmony import */ var _actions__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./actions */ "./packages/loot-core/src/server/budget/actions.ts");
39225
39170
  /* harmony import */ var _goal_template_pegjs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./goal-template.pegjs */ "./packages/loot-core/src/server/budget/goal-template.pegjs");
39226
39171
  /* harmony import */ var _goal_template_pegjs__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/ __webpack_require__.n(_goal_template_pegjs__WEBPACK_IMPORTED_MODULE_5__);
39227
- /* harmony import */ var _goals_goalsBy__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./goals/goalsBy */ "./packages/loot-core/src/server/budget/goals/goalsBy.ts");
39228
- /* harmony import */ var _goals_goalsPercentage__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./goals/goalsPercentage */ "./packages/loot-core/src/server/budget/goals/goalsPercentage.ts");
39229
- /* harmony import */ var _goals_goalsRemainder__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./goals/goalsRemainder */ "./packages/loot-core/src/server/budget/goals/goalsRemainder.ts");
39230
- /* harmony import */ var _goals_goalsSchedule__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./goals/goalsSchedule */ "./packages/loot-core/src/server/budget/goals/goalsSchedule.ts");
39231
- /* harmony import */ var _goals_goalsSimple__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./goals/goalsSimple */ "./packages/loot-core/src/server/budget/goals/goalsSimple.ts");
39232
- /* harmony import */ var _goals_goalsSpend__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./goals/goalsSpend */ "./packages/loot-core/src/server/budget/goals/goalsSpend.ts");
39233
- /* harmony import */ var _goals_goalsWeek__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./goals/goalsWeek */ "./packages/loot-core/src/server/budget/goals/goalsWeek.ts");
39172
+ /* harmony import */ var _goals_goalsAverage__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./goals/goalsAverage */ "./packages/loot-core/src/server/budget/goals/goalsAverage.ts");
39173
+ /* harmony import */ var _goals_goalsBy__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./goals/goalsBy */ "./packages/loot-core/src/server/budget/goals/goalsBy.ts");
39174
+ /* harmony import */ var _goals_goalsPercentage__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./goals/goalsPercentage */ "./packages/loot-core/src/server/budget/goals/goalsPercentage.ts");
39175
+ /* harmony import */ var _goals_goalsRemainder__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./goals/goalsRemainder */ "./packages/loot-core/src/server/budget/goals/goalsRemainder.ts");
39176
+ /* harmony import */ var _goals_goalsSchedule__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./goals/goalsSchedule */ "./packages/loot-core/src/server/budget/goals/goalsSchedule.ts");
39177
+ /* harmony import */ var _goals_goalsSimple__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./goals/goalsSimple */ "./packages/loot-core/src/server/budget/goals/goalsSimple.ts");
39178
+ /* harmony import */ var _goals_goalsSpend__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./goals/goalsSpend */ "./packages/loot-core/src/server/budget/goals/goalsSpend.ts");
39179
+ /* harmony import */ var _goals_goalsWeek__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./goals/goalsWeek */ "./packages/loot-core/src/server/budget/goals/goalsWeek.ts");
39234
39180
  // @ts-strict-ignore
39235
39181
  async function applyTemplate({ month }) {
39236
39182
  await storeTemplates();
@@ -39418,7 +39364,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
39418
39364
  priority_list = priority_list.sort(function (a, b) {
39419
39365
  return a - b;
39420
39366
  }).filter((item, index, curr) => curr.indexOf(item) === index);
39421
- const { remainder_found, remainder_priority, remainder_weight_total } = (0, _goals_goalsRemainder__WEBPACK_IMPORTED_MODULE_8__.findRemainder)(priority_list, categories, category_templates);
39367
+ const { remainder_found, remainder_priority, remainder_weight_total } = (0, _goals_goalsRemainder__WEBPACK_IMPORTED_MODULE_9__.findRemainder)(priority_list, categories, category_templates);
39422
39368
  if (remainder_found)
39423
39369
  priority_list.push(remainder_priority);
39424
39370
  const sheetName = _shared_months__WEBPACK_IMPORTED_MODULE_0__.sheetForMonth(month);
@@ -39646,7 +39592,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
39646
39592
  switch (template.type) {
39647
39593
  case 'simple':
39648
39594
  {
39649
- const goalsReturn = await (0, _goals_goalsSimple__WEBPACK_IMPORTED_MODULE_10__.goalsSimple)(template, limitCheck, errors, limit, hold, to_budget);
39595
+ const goalsReturn = await (0, _goals_goalsSimple__WEBPACK_IMPORTED_MODULE_11__.goalsSimple)(template, limitCheck, errors, limit, hold, to_budget, last_month_balance);
39650
39596
  to_budget = goalsReturn.to_budget;
39651
39597
  errors = goalsReturn.errors;
39652
39598
  limit = goalsReturn.limit;
@@ -39656,7 +39602,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
39656
39602
  }
39657
39603
  case 'by':
39658
39604
  {
39659
- const goalsReturn = await (0, _goals_goalsBy__WEBPACK_IMPORTED_MODULE_6__.goalsBy)(template_lines, current_month, template, l, remainder, last_month_balance, to_budget, errors);
39605
+ const goalsReturn = await (0, _goals_goalsBy__WEBPACK_IMPORTED_MODULE_7__.goalsBy)(template_lines, current_month, template, l, remainder, last_month_balance, to_budget, errors);
39660
39606
  to_budget = goalsReturn.to_budget;
39661
39607
  errors = goalsReturn.errors;
39662
39608
  remainder = goalsReturn.remainder;
@@ -39664,7 +39610,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
39664
39610
  }
39665
39611
  case 'week':
39666
39612
  {
39667
- const goalsReturn = await (0, _goals_goalsWeek__WEBPACK_IMPORTED_MODULE_12__.goalsWeek)(template, limit, limitCheck, hold, current_month, to_budget, errors);
39613
+ const goalsReturn = await (0, _goals_goalsWeek__WEBPACK_IMPORTED_MODULE_13__.goalsWeek)(template, limit, limitCheck, hold, current_month, to_budget, errors);
39668
39614
  to_budget = goalsReturn.to_budget;
39669
39615
  errors = goalsReturn.errors;
39670
39616
  limit = goalsReturn.limit;
@@ -39674,21 +39620,21 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
39674
39620
  }
39675
39621
  case 'spend':
39676
39622
  {
39677
- const goalsReturn = await (0, _goals_goalsSpend__WEBPACK_IMPORTED_MODULE_11__.goalsSpend)(template, last_month_balance, current_month, to_budget, errors, category);
39623
+ const goalsReturn = await (0, _goals_goalsSpend__WEBPACK_IMPORTED_MODULE_12__.goalsSpend)(template, last_month_balance, current_month, to_budget, errors, category);
39678
39624
  to_budget = goalsReturn.to_budget;
39679
39625
  errors = goalsReturn.errors;
39680
39626
  break;
39681
39627
  }
39682
39628
  case 'percentage':
39683
39629
  {
39684
- const goalsReturn = await (0, _goals_goalsPercentage__WEBPACK_IMPORTED_MODULE_7__.goalsPercentage)(template, month, available_start, sheetName, to_budget, errors);
39630
+ const goalsReturn = await (0, _goals_goalsPercentage__WEBPACK_IMPORTED_MODULE_8__.goalsPercentage)(template, month, available_start, sheetName, to_budget, errors);
39685
39631
  to_budget = goalsReturn.to_budget;
39686
39632
  errors = goalsReturn.errors;
39687
39633
  break;
39688
39634
  }
39689
39635
  case 'schedule':
39690
39636
  {
39691
- const goalsReturn = await (0, _goals_goalsSchedule__WEBPACK_IMPORTED_MODULE_9__.goalsSchedule)(scheduleFlag, template_lines, current_month, balance, remainder, last_month_balance, to_budget, errors, category);
39637
+ const goalsReturn = await (0, _goals_goalsSchedule__WEBPACK_IMPORTED_MODULE_10__.goalsSchedule)(scheduleFlag, template_lines, current_month, balance, remainder, last_month_balance, to_budget, errors, category);
39692
39638
  to_budget = goalsReturn.to_budget;
39693
39639
  errors = goalsReturn.errors;
39694
39640
  remainder = goalsReturn.remainder;
@@ -39697,10 +39643,17 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
39697
39643
  }
39698
39644
  case 'remainder':
39699
39645
  {
39700
- const goalsReturn = await (0, _goals_goalsRemainder__WEBPACK_IMPORTED_MODULE_8__.goalsRemainder)(template, budgetAvailable, remainder_scale, to_budget);
39646
+ const goalsReturn = await (0, _goals_goalsRemainder__WEBPACK_IMPORTED_MODULE_9__.goalsRemainder)(template, budgetAvailable, remainder_scale, to_budget);
39701
39647
  to_budget = goalsReturn.to_budget;
39702
39648
  break;
39703
39649
  }
39650
+ case 'average':
39651
+ {
39652
+ const goalsReturn = await (0, _goals_goalsAverage__WEBPACK_IMPORTED_MODULE_6__.goalsAverage)(template, current_month, category, errors, to_budget);
39653
+ to_budget = goalsReturn.to_budget;
39654
+ errors = goalsReturn.errors;
39655
+ break;
39656
+ }
39704
39657
  case 'error':
39705
39658
  return {
39706
39659
  errors
@@ -39730,16 +39683,24 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
39730
39683
  const category_templates = await getCategoryTemplates(null);
39731
39684
  const errors = [];
39732
39685
  const categories = await _db__WEBPACK_IMPORTED_MODULE_2__.all('SELECT * FROM v_categories WHERE tombstone = 0');
39686
+ let all_schedule_names = await _db__WEBPACK_IMPORTED_MODULE_2__.all('SELECT name from schedules WHERE name NOT NULL AND tombstone = 0');
39687
+ all_schedule_names = all_schedule_names.map((v) => v.name);
39733
39688
  // run through each line and see if its an error
39734
39689
  for (let c = 0; c < categories.length; c++) {
39735
39690
  const category = categories[c];
39736
39691
  const template = category_templates[category.id];
39737
39692
  if (template) {
39738
39693
  for (let l = 0; l < template.length; l++) {
39694
+ //check for basic error
39739
39695
  if (template[l].type === 'error') {
39740
- //return { type: 'message', message: "found a bad one",};
39741
39696
  errors.push(category.name + ': ' + template[l].line);
39742
39697
  }
39698
+ // check schedule name error
39699
+ if (template[l].type === 'schedule') {
39700
+ if (!all_schedule_names.includes(template[l].name)) {
39701
+ errors.push(category.name + ': Schedule “' + template[l].name + '” does not exist');
39702
+ }
39703
+ }
39743
39704
  }
39744
39705
  }
39745
39706
  }
@@ -41942,7 +41903,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
41942
41903
  category: isOffBudget(entityIdMap.get(accountId)) ? null : getCategory(transaction.categoryId),
41943
41904
  date: transaction.date,
41944
41905
  notes: transaction.memo || null,
41945
- cleared: transaction.cleared === 'Cleared',
41906
+ cleared: transaction.cleared === 'Cleared' || transaction.cleared === 'Reconciled',
41907
+ reconciled: transaction.cleared === 'Reconciled',
41946
41908
  ...transferProperties(transaction),
41947
41909
  subtransactions: transaction.subTransactions && transaction.subTransactions.map((t) => {
41948
41910
  return {
@@ -42243,14 +42205,121 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
42243
42205
  payee
42244
42206
  ]);
42245
42207
  const payeeTransferAcctHashMap = new Map(payeesByTransferAcct);
42208
+ const orphanTransferMap = new Map();
42209
+ const orphanSubtransfer = [];
42210
+ const orphanSubtransferTrxId = [];
42211
+ const orphanSubtransferAcctIdByTrxIdMap = new Map();
42212
+ const orphanSubtransferDateByTrxIdMap = new Map();
42246
42213
  // Go ahead and generate ids for all of the transactions so we can
42247
42214
  // reliably resolve transfers
42248
- for (const transaction of data.transactions) {
42215
+ // Also identify orphan transfer transactions and subtransactions.
42216
+ for (const transaction of data.subtransactions) {
42249
42217
  entityIdMap.set(transaction.id, (0, uuid__WEBPACK_IMPORTED_MODULE_3__["default"])());
42218
+ if (transaction.transfer_account_id) {
42219
+ orphanSubtransfer.push(transaction);
42220
+ orphanSubtransferTrxId.push(transaction.transaction_id);
42221
+ }
42250
42222
  }
42251
- for (const transaction of data.subtransactions) {
42223
+ for (const transaction of data.transactions) {
42252
42224
  entityIdMap.set(transaction.id, (0, uuid__WEBPACK_IMPORTED_MODULE_3__["default"])());
42225
+ if (transaction.transfer_account_id && !transaction.transfer_transaction_id) {
42226
+ const key = transaction.account_id + '#' + transaction.transfer_account_id;
42227
+ if (!orphanTransferMap.has(key)) {
42228
+ orphanTransferMap.set(key, [
42229
+ transaction
42230
+ ]);
42231
+ }
42232
+ else {
42233
+ orphanTransferMap.get(key).push(transaction);
42234
+ }
42235
+ }
42236
+ if (orphanSubtransferTrxId.includes(transaction.id)) {
42237
+ orphanSubtransferAcctIdByTrxIdMap.set(transaction.id, transaction.account_id);
42238
+ orphanSubtransferDateByTrxIdMap.set(transaction.id, transaction.date);
42239
+ }
42253
42240
  }
42241
+ // Compute link between subtransaction transfers and orphaned transaction
42242
+ // transfers. The goal is to match each transfer subtransaction to the related
42243
+ // transfer transaction according to the accounts, date, amount and memo.
42244
+ const orphanSubtransferMap = orphanSubtransfer.reduce((map, subtransaction) => {
42245
+ const key = subtransaction.transfer_account_id + '#' + orphanSubtransferAcctIdByTrxIdMap.get(subtransaction.transaction_id);
42246
+ if (!map.has(key)) {
42247
+ map.set(key, [
42248
+ subtransaction
42249
+ ]);
42250
+ }
42251
+ else {
42252
+ map.get(key).push(subtransaction);
42253
+ }
42254
+ return map;
42255
+ }, new Map());
42256
+ // The comparator will be used to order transfer transactions and their
42257
+ // corresponding tranfer subtransaction in two aligned list. Hopefully
42258
+ // for every list index in the transactions list, the related subtransaction
42259
+ // will be at the same index.
42260
+ const orphanTransferComparator = (a, b) => {
42261
+ // a and b can be a YNAB5.Transaction (having a date attribute) or a
42262
+ // YNAB5.Subtransaction (missing that date attribute)
42263
+ const date_a = 'date' in a ? a.date : orphanSubtransferDateByTrxIdMap.get(a.transaction_id);
42264
+ const date_b = 'date' in b ? b.date : orphanSubtransferDateByTrxIdMap.get(b.transaction_id);
42265
+ // A transaction and the related subtransaction have inverted amounts.
42266
+ // To have those in the same order, the subtransaction has to be reversed
42267
+ // to have the same amount.
42268
+ const amount_a = 'date' in a ? a.amount : -a.amount;
42269
+ const amount_b = 'date' in b ? b.amount : -b.amount;
42270
+ // Transaction are ordered first by date, then by amount, and lastly by memo
42271
+ if (date_a > date_b)
42272
+ return 1;
42273
+ if (date_a < date_b)
42274
+ return -1;
42275
+ if (amount_a > amount_b)
42276
+ return 1;
42277
+ if (amount_a < amount_b)
42278
+ return -1;
42279
+ if (a.memo > b.memo)
42280
+ return 1;
42281
+ if (a.memo < b.memo)
42282
+ return -1;
42283
+ return 0;
42284
+ };
42285
+ const orphanTrxIdSubtrxIdMap = new Map();
42286
+ orphanTransferMap.forEach((transactions, key) => {
42287
+ const subtransactions = orphanSubtransferMap.get(key);
42288
+ if (subtransactions) {
42289
+ transactions.sort(orphanTransferComparator);
42290
+ subtransactions.sort(orphanTransferComparator);
42291
+ // Iterate on the two sorted lists transactions and subtransactions and
42292
+ // find matching data to identify the related transaction ids.
42293
+ let transactionIdx = 0;
42294
+ let subtransactionIdx = 0;
42295
+ do {
42296
+ switch (orphanTransferComparator(transactions[transactionIdx], subtransactions[subtransactionIdx])) {
42297
+ case 0:
42298
+ // The current list indexes are matching: the transaction and
42299
+ // subtransaction are related (same date, amount and memo)
42300
+ orphanTrxIdSubtrxIdMap.set(transactions[transactionIdx].id, entityIdMap.get(subtransactions[subtransactionIdx].id));
42301
+ orphanTrxIdSubtrxIdMap.set(subtransactions[subtransactionIdx].id, entityIdMap.get(transactions[transactionIdx].id));
42302
+ transactionIdx++;
42303
+ subtransactionIdx++;
42304
+ break;
42305
+ case -1:
42306
+ // The current list indexes are not matching:
42307
+ // The current transaction is "smaller" than the current subtransaction
42308
+ // (earlier date, smaller amount, memo value sorted before)
42309
+ // So we advance to the next transaction and see if it match with
42310
+ // the current subtransaction
42311
+ transactionIdx++;
42312
+ break;
42313
+ case 1:
42314
+ // Inverse of the previous case:
42315
+ // The current subtransaction is "smaller" than the current transaction
42316
+ // So we advance to the next subtransaction
42317
+ subtransactionIdx++;
42318
+ break;
42319
+ }
42320
+ } while (transactionIdx < transactions.length && subtransactionIdx < subtransactions.length);
42321
+ }
42322
+ });
42254
42323
  await Promise.all([
42255
42324
  ...transactionsGrouped.keys()
42256
42325
  ].map(async (accountId) => {
@@ -42271,33 +42340,41 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
42271
42340
  'cleared',
42272
42341
  'reconciled'
42273
42342
  ].includes(transaction.cleared),
42343
+ reconciled: transaction.cleared === 'reconciled',
42274
42344
  notes: transaction.memo || null,
42275
42345
  imported_id: transaction.import_id || null,
42276
- transfer_id: entityIdMap.get(transaction.transfer_transaction_id) || null,
42346
+ transfer_id: entityIdMap.get(transaction.transfer_transaction_id) || orphanTrxIdSubtrxIdMap.get(transaction.id) || null,
42277
42347
  subtransactions: subtransactions ? subtransactions.map((subtrans) => {
42278
- let payee = null;
42279
- if (subtrans.transfer_account_id) {
42280
- const mappedTransferAccountId = entityIdMap.get(subtrans.transfer_account_id);
42281
- payee = payeeTransferAcctHashMap.get(mappedTransferAccountId)?.id;
42282
- }
42283
42348
  return {
42284
42349
  id: entityIdMap.get(subtrans.id),
42285
42350
  amount: amountFromYnab(subtrans.amount),
42286
42351
  category: entityIdMap.get(subtrans.category_id) || null,
42287
42352
  notes: subtrans.memo,
42288
- payee
42353
+ transfer_id: orphanTrxIdSubtrxIdMap.get(subtrans.id) || null,
42354
+ payee: null,
42355
+ imported_payee: null
42289
42356
  };
42290
42357
  }) : null,
42291
42358
  payee: null,
42292
42359
  imported_payee: null
42293
42360
  };
42294
- // Handle transfer payee
42295
- if (transaction.transfer_account_id) {
42296
- newTransaction.payee = payees.find((p) => p.transfer_acct === entityIdMap.get(transaction.transfer_account_id)).id;
42297
- }
42298
- else {
42299
- newTransaction.payee = entityIdMap.get(transaction.payee_id);
42300
- newTransaction.imported_payee = data.payees.find((p) => !p.deleted && p.id === transaction.payee_id)?.name;
42361
+ // Handle transactions and subtransactions payee
42362
+ const transactionPayeeUpdate = (trx, newTrx) => {
42363
+ if (trx.transfer_account_id) {
42364
+ const mappedTransferAccountId = entityIdMap.get(trx.transfer_account_id);
42365
+ newTrx.payee = payeeTransferAcctHashMap.get(mappedTransferAccountId)?.id;
42366
+ }
42367
+ else {
42368
+ newTrx.payee = entityIdMap.get(trx.payee_id);
42369
+ newTrx.imported_payee = data.payees.find((p) => !p.deleted && p.id === trx.payee_id)?.name;
42370
+ }
42371
+ };
42372
+ transactionPayeeUpdate(transaction, newTransaction);
42373
+ if (newTransaction.subtransactions) {
42374
+ subtransactions.forEach((subtrans) => {
42375
+ const newSubtransaction = newTransaction.subtransactions.find((newSubtrans) => newSubtrans.id === entityIdMap.get(subtrans.id));
42376
+ transactionPayeeUpdate(subtrans, newSubtransaction);
42377
+ });
42301
42378
  }
42302
42379
  // Handle starting balances
42303
42380
  if (transaction.payee_id === startingPayeeYNAB && entityIdMap.get(transaction.category_id) === incomeCatId) {
@@ -42730,6 +42807,9 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
42730
42807
  return result;
42731
42808
  });
42732
42809
  });
42810
+ handlers['get-category-groups'] = async function () {
42811
+ return await _db__WEBPACK_IMPORTED_MODULE_27__.getCategoriesGrouped();
42812
+ };
42733
42813
  handlers['category-group-create'] = (0, _mutators__WEBPACK_IMPORTED_MODULE_34__.mutator)(async function ({ name, isIncome }) {
42734
42814
  return (0, _undo__WEBPACK_IMPORTED_MODULE_48__.withUndo)(async () => {
42735
42815
  return _db__WEBPACK_IMPORTED_MODULE_27__.insertCategoryGroup({
@@ -42900,21 +42980,6 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
42900
42980
  }
42901
42981
  return (0, _aql__WEBPACK_IMPORTED_MODULE_22__.runQuery)(query);
42902
42982
  };
42903
- handlers['bank-delete'] = async function ({ id }) {
42904
- const accts = await _db__WEBPACK_IMPORTED_MODULE_27__.runQuery('SELECT * FROM accounts WHERE bank = ?', [
42905
- id
42906
- ], true);
42907
- await _db__WEBPACK_IMPORTED_MODULE_27__.delete_('banks', id);
42908
- await Promise.all(accts.map(async (acct) => {
42909
- // TODO: This will not sync across devices because we are bypassing
42910
- // the "recorded" functions
42911
- await _db__WEBPACK_IMPORTED_MODULE_27__.runQuery('DELETE FROM transactions WHERE acct = ?', [
42912
- acct.id
42913
- ]);
42914
- await _db__WEBPACK_IMPORTED_MODULE_27__.delete_('accounts', acct.id);
42915
- }));
42916
- return 'ok';
42917
- };
42918
42983
  handlers['account-update'] = (0, _mutators__WEBPACK_IMPORTED_MODULE_34__.mutator)(async function ({ id, name }) {
42919
42984
  return (0, _undo__WEBPACK_IMPORTED_MODULE_48__.withUndo)(async () => {
42920
42985
  await _db__WEBPACK_IMPORTED_MODULE_27__.update('accounts', {
@@ -42939,34 +43004,6 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
42939
43004
  numTransactions: count
42940
43005
  };
42941
43006
  };
42942
- handlers['accounts-link'] = async function ({ institution, publicToken, accountId, upgradingId }) {
42943
- const bankId = await _accounts_link__WEBPACK_IMPORTED_MODULE_15__.handoffPublicToken(institution, publicToken);
42944
- const [[, userId], [, userKey]] = await _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_5__.multiGet([
42945
- 'user-id',
42946
- 'user-key'
42947
- ]);
42948
- // Get all the available accounts and find the selected one
42949
- const accounts = await _accounts_sync__WEBPACK_IMPORTED_MODULE_18__.getGoCardlessAccounts(userId, userKey, bankId);
42950
- const account = accounts.find((acct) => acct.account_id === accountId);
42951
- await _db__WEBPACK_IMPORTED_MODULE_27__.update('accounts', {
42952
- id: upgradingId,
42953
- account_id: account.account_id,
42954
- official_name: account.official_name,
42955
- balance_current: (0, _shared_util__WEBPACK_IMPORTED_MODULE_13__.amountToInteger)(account.balances.current),
42956
- balance_available: (0, _shared_util__WEBPACK_IMPORTED_MODULE_13__.amountToInteger)(account.balances.available),
42957
- balance_limit: (0, _shared_util__WEBPACK_IMPORTED_MODULE_13__.amountToInteger)(account.balances.limit),
42958
- mask: account.mask,
42959
- bank: bankId
42960
- });
42961
- await _accounts_sync__WEBPACK_IMPORTED_MODULE_18__.syncAccount(userId, userKey, upgradingId, account.account_id, bankId);
42962
- _platform_server_connection__WEBPACK_IMPORTED_MODULE_6__.send('sync-event', {
42963
- type: 'success',
42964
- tables: [
42965
- 'transactions'
42966
- ]
42967
- });
42968
- return 'ok';
42969
- };
42970
43007
  handlers['gocardless-accounts-link'] = async function ({ requisitionId, account, upgradingId }) {
42971
43008
  let id;
42972
43009
  const bank = await _accounts_link__WEBPACK_IMPORTED_MODULE_15__.findOrCreateBank(account.institution, requisitionId);
@@ -42998,7 +43035,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
42998
43035
  transfer_acct: id
42999
43036
  });
43000
43037
  }
43001
- await _accounts_sync__WEBPACK_IMPORTED_MODULE_18__.syncExternalAccount(undefined, undefined, id, account.account_id, bank.bank_id);
43038
+ await _accounts_sync__WEBPACK_IMPORTED_MODULE_18__.syncAccount(undefined, undefined, id, account.account_id, bank.bank_id);
43002
43039
  _platform_server_connection__WEBPACK_IMPORTED_MODULE_6__.send('sync-event', {
43003
43040
  type: 'success',
43004
43041
  tables: [
@@ -43040,7 +43077,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
43040
43077
  transfer_acct: id
43041
43078
  });
43042
43079
  }
43043
- await _accounts_sync__WEBPACK_IMPORTED_MODULE_18__.syncExternalAccount(undefined, undefined, id, externalAccount.account_id, bank.bank_id);
43080
+ await _accounts_sync__WEBPACK_IMPORTED_MODULE_18__.syncAccount(undefined, undefined, id, externalAccount.account_id, bank.bank_id);
43044
43081
  await _platform_server_connection__WEBPACK_IMPORTED_MODULE_6__.send('sync-event', {
43045
43082
  type: 'success',
43046
43083
  tables: [
@@ -43049,16 +43086,6 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
43049
43086
  });
43050
43087
  return 'ok';
43051
43088
  };
43052
- handlers['accounts-connect'] = async function ({ institution, publicToken, accountIds, offbudgetIds }) {
43053
- const bankId = await _accounts_link__WEBPACK_IMPORTED_MODULE_15__.handoffPublicToken(institution, publicToken);
43054
- const ids = await _accounts_link__WEBPACK_IMPORTED_MODULE_15__.addAccounts(bankId, accountIds, offbudgetIds);
43055
- return ids;
43056
- };
43057
- handlers['gocardless-accounts-connect'] = async function ({ institution, publicToken, accountIds, offbudgetIds }) {
43058
- const bankId = await _accounts_link__WEBPACK_IMPORTED_MODULE_15__.handoffPublicToken(institution, publicToken);
43059
- const ids = await _accounts_link__WEBPACK_IMPORTED_MODULE_15__.addGoCardlessAccounts(bankId, accountIds, offbudgetIds);
43060
- return ids;
43061
- };
43062
43089
  handlers['account-create'] = (0, _mutators__WEBPACK_IMPORTED_MODULE_34__.mutator)(async function ({ name, balance, offBudget, closed }) {
43063
43090
  return (0, _undo__WEBPACK_IMPORTED_MODULE_48__.withUndo)(async () => {
43064
43091
  const id = await _db__WEBPACK_IMPORTED_MODULE_27__.insertAccount({
@@ -43086,8 +43113,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
43086
43113
  });
43087
43114
  });
43088
43115
  handlers['account-close'] = (0, _mutators__WEBPACK_IMPORTED_MODULE_34__.mutator)(async function ({ id, transferAccountId, categoryId, forced }) {
43089
- // Unlink the account if it's linked. This makes sure to remove it
43090
- // from Plaid. (This should not be undo-able, as it mutates the
43116
+ // Unlink the account if it's linked. This makes sure to remove it from
43117
+ // bank-sync providers. (This should not be undo-able, as it mutates the
43091
43118
  // remote server and the user will have to link the account again)
43092
43119
  await handlers['account-unlink']({
43093
43120
  id
@@ -43184,127 +43211,6 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
43184
43211
  });
43185
43212
  });
43186
43213
  let stopPolling = false;
43187
- handlers['poll-web-token'] = async function ({ token }) {
43188
- const [[, userId], [, key]] = await _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_5__.multiGet([
43189
- 'user-id',
43190
- 'user-key'
43191
- ]);
43192
- const startTime = Date.now();
43193
- stopPolling = false;
43194
- async function getData(cb) {
43195
- if (stopPolling) {
43196
- return;
43197
- }
43198
- if (Date.now() - startTime >= 1000 * 60 * 10) {
43199
- cb('timeout');
43200
- return;
43201
- }
43202
- const data = await (0, _post__WEBPACK_IMPORTED_MODULE_37__.post)((0, _server_config__WEBPACK_IMPORTED_MODULE_42__.getServer)().PLAID_SERVER + '/get-web-token-contents', {
43203
- userId,
43204
- key,
43205
- token
43206
- });
43207
- if (data) {
43208
- if (data.error) {
43209
- cb('unknown');
43210
- }
43211
- else {
43212
- cb(null, data);
43213
- }
43214
- }
43215
- else {
43216
- setTimeout(() => getData(cb), 3000);
43217
- }
43218
- }
43219
- return new Promise((resolve) => {
43220
- getData((error, data) => {
43221
- if (error) {
43222
- resolve({
43223
- error
43224
- });
43225
- }
43226
- else {
43227
- resolve({
43228
- data
43229
- });
43230
- }
43231
- });
43232
- });
43233
- };
43234
- handlers['poll-web-token-stop'] = async function () {
43235
- stopPolling = true;
43236
- return 'ok';
43237
- };
43238
- handlers['accounts-sync'] = async function ({ id }) {
43239
- const [[, userId], [, userKey]] = await _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_5__.multiGet([
43240
- 'user-id',
43241
- 'user-key'
43242
- ]);
43243
- let accounts = await _db__WEBPACK_IMPORTED_MODULE_27__.runQuery(`SELECT a.*, b.id as bankId FROM accounts a
43244
- LEFT JOIN banks b ON a.bank = b.id
43245
- WHERE a.tombstone = 0 AND a.closed = 0`, [], true);
43246
- if (id) {
43247
- accounts = accounts.filter((acct) => acct.id === id);
43248
- }
43249
- const errors = [];
43250
- let newTransactions = [];
43251
- let matchedTransactions = [];
43252
- let updatedAccounts = [];
43253
- for (let i = 0; i < accounts.length; i++) {
43254
- const acct = accounts[i];
43255
- if (acct.bankId) {
43256
- try {
43257
- const res = await _accounts_sync__WEBPACK_IMPORTED_MODULE_18__.syncAccount(userId, userKey, acct.id, acct.account_id, acct.bankId);
43258
- const { added, updated } = res;
43259
- newTransactions = newTransactions.concat(added);
43260
- matchedTransactions = matchedTransactions.concat(updated);
43261
- if (added.length > 0 || updated.length > 0) {
43262
- updatedAccounts = updatedAccounts.concat(acct.id);
43263
- }
43264
- }
43265
- catch (err) {
43266
- if (err.type === 'BankSyncError') {
43267
- errors.push({
43268
- type: 'SyncError',
43269
- accountId: acct.id,
43270
- message: 'Failed syncing account “' + acct.name + '.”',
43271
- category: err.category,
43272
- code: err.code
43273
- });
43274
- }
43275
- else if (err instanceof _errors__WEBPACK_IMPORTED_MODULE_30__.PostError && err.reason !== 'internal') {
43276
- errors.push({
43277
- accountId: acct.id,
43278
- message: `Account “${acct.name}” is not linked properly. Please link it again`
43279
- });
43280
- }
43281
- else {
43282
- errors.push({
43283
- accountId: acct.id,
43284
- message: 'There was an internal error. Please get in touch https://actualbudget.org/contact for support.',
43285
- internal: err.stack
43286
- });
43287
- err.message = 'Failed syncing account: ' + err.message;
43288
- (0, _platform_exceptions__WEBPACK_IMPORTED_MODULE_4__.captureException)(err);
43289
- }
43290
- }
43291
- }
43292
- }
43293
- if (updatedAccounts.length > 0) {
43294
- _platform_server_connection__WEBPACK_IMPORTED_MODULE_6__.send('sync-event', {
43295
- type: 'success',
43296
- tables: [
43297
- 'transactions'
43298
- ]
43299
- });
43300
- }
43301
- return {
43302
- errors,
43303
- newTransactions,
43304
- matchedTransactions,
43305
- updatedAccounts
43306
- };
43307
- };
43308
43214
  handlers['secret-set'] = async function ({ name, value }) {
43309
43215
  const userToken = await _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_5__.getItem('user-token');
43310
43216
  if (!userToken) {
@@ -43474,12 +43380,11 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
43474
43380
  'user-id',
43475
43381
  'user-key'
43476
43382
  ]);
43477
- let accounts = await _db__WEBPACK_IMPORTED_MODULE_27__.runQuery(`SELECT a.*, b.bank_id as bankId FROM accounts a
43383
+ const accounts = await _db__WEBPACK_IMPORTED_MODULE_27__.runQuery(`SELECT a.*, b.bank_id as bankId FROM accounts a
43478
43384
  LEFT JOIN banks b ON a.bank = b.id
43479
- WHERE a.tombstone = 0 AND a.closed = 0`, [], true);
43480
- if (id) {
43481
- accounts = accounts.filter((acct) => acct.id === id);
43482
- }
43385
+ WHERE a.tombstone = 0 AND a.closed = 0 AND a.id = ?`, [
43386
+ id
43387
+ ], true);
43483
43388
  const errors = [];
43484
43389
  let newTransactions = [];
43485
43390
  let matchedTransactions = [];
@@ -43488,7 +43393,9 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
43488
43393
  const acct = accounts[i];
43489
43394
  if (acct.bankId) {
43490
43395
  try {
43491
- const res = await _accounts_sync__WEBPACK_IMPORTED_MODULE_18__.syncExternalAccount(userId, userKey, acct.id, acct.account_id, acct.bankId);
43396
+ console.group('Bank Sync operation');
43397
+ const res = await _accounts_sync__WEBPACK_IMPORTED_MODULE_18__.syncAccount(userId, userKey, acct.id, acct.account_id, acct.bankId);
43398
+ console.groupEnd();
43492
43399
  const { added, updated } = res;
43493
43400
  newTransactions = newTransactions.concat(added);
43494
43401
  matchedTransactions = matchedTransactions.concat(updated);
@@ -43614,27 +43521,6 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
43614
43521
  }
43615
43522
  return 'ok';
43616
43523
  });
43617
- handlers['make-plaid-public-token'] = async function ({ bankId }) {
43618
- const [[, userId], [, userKey]] = await _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_5__.multiGet([
43619
- 'user-id',
43620
- 'user-key'
43621
- ]);
43622
- const data = await (0, _post__WEBPACK_IMPORTED_MODULE_37__.post)((0, _server_config__WEBPACK_IMPORTED_MODULE_42__.getServer)().PLAID_SERVER + '/make-public-token', {
43623
- userId,
43624
- key: userKey,
43625
- item_id: '' + bankId
43626
- });
43627
- if (data.error_code) {
43628
- return {
43629
- error: '',
43630
- code: data.error_code,
43631
- type: data.error_type
43632
- };
43633
- }
43634
- return {
43635
- linkToken: data.link_token
43636
- };
43637
- };
43638
43524
  handlers['save-global-prefs'] = async function (prefs) {
43639
43525
  if ('maxMonths' in prefs) {
43640
43526
  await _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_5__.setItem('max-months', '' + prefs.maxMonths);
@@ -43674,7 +43560,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
43674
43560
  autoUpdate: autoUpdate == null || autoUpdate === 'true' ? true : false,
43675
43561
  documentDir: documentDir || getDefaultDocumentDir(),
43676
43562
  keyId: encryptKey && JSON.parse(encryptKey).id,
43677
- theme: theme === 'light' || theme === 'dark' || theme === 'auto' || theme === 'development' || theme === 'midnight' ? theme : 'light'
43563
+ theme: theme === 'light' || theme === 'dark' || theme === 'auto' || theme === 'development' || theme === 'midnight' ? theme : 'auto'
43678
43564
  };
43679
43565
  };
43680
43566
  handlers['save-prefs'] = async function (prefsToSet) {
@@ -43920,16 +43806,22 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
43920
43806
  return {};
43921
43807
  };
43922
43808
  handlers['subscribe-sign-in'] = async function ({ password }) {
43923
- const res = await (0, _post__WEBPACK_IMPORTED_MODULE_37__.post)((0, _server_config__WEBPACK_IMPORTED_MODULE_42__.getServer)().SIGNUP_SERVER + '/login', {
43924
- password
43925
- });
43926
- if (res.token) {
43927
- await _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_5__.setItem('user-token', res.token);
43928
- return {};
43809
+ let res;
43810
+ try {
43811
+ res = await (0, _post__WEBPACK_IMPORTED_MODULE_37__.post)((0, _server_config__WEBPACK_IMPORTED_MODULE_42__.getServer)().SIGNUP_SERVER + '/login', {
43812
+ password
43813
+ });
43929
43814
  }
43930
- return {
43931
- error: 'invalid-password'
43932
- };
43815
+ catch (err) {
43816
+ return {
43817
+ error: err.reason || 'network-failure'
43818
+ };
43819
+ }
43820
+ if (!res.token) {
43821
+ throw new Error('login: User token not set');
43822
+ }
43823
+ await _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_5__.setItem('user-token', res.token);
43824
+ return {};
43933
43825
  };
43934
43826
  handlers['subscribe-sign-out'] = async function () {
43935
43827
  _encryption__WEBPACK_IMPORTED_MODULE_29__.unloadAllKeys();
@@ -44011,8 +43903,12 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
44011
43903
  if (name !== DEMO_BUDGET_ID) {
44012
43904
  return {
44013
43905
  id: name,
44014
- cloudFileId: prefs.cloudFileId,
44015
- groupId: prefs.groupId,
43906
+ ...prefs.cloudFileId ? {
43907
+ cloudFileId: prefs.cloudFileId
43908
+ } : {},
43909
+ ...prefs.groupId ? {
43910
+ groupId: prefs.groupId
43911
+ } : {},
44016
43912
  name: prefs.budgetName || '(no name)'
44017
43913
  };
44018
43914
  }
@@ -46306,7 +46202,6 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
46306
46202
  BASE_SERVER: url,
46307
46203
  SYNC_SERVER: joinURL(url, '/sync'),
46308
46204
  SIGNUP_SERVER: joinURL(url, '/account'),
46309
- PLAID_SERVER: joinURL(url, '/plaid'),
46310
46205
  GOCARDLESS_SERVER: joinURL(url, '/gocardless'),
46311
46206
  SIMPLEFIN_SERVER: joinURL(url, '/simplefin')
46312
46207
  };
@@ -48729,6 +48624,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
48729
48624
  "use strict";
48730
48625
  __webpack_require__.r(__webpack_exports__);
48731
48626
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
48627
+ /* harmony export */ LazyLoadFailedError: () => ( /* binding */LazyLoadFailedError),
48732
48628
  /* harmony export */ getCreateKeyError: () => ( /* binding */getCreateKeyError),
48733
48629
  /* harmony export */ getDownloadError: () => ( /* binding */getDownloadError),
48734
48630
  /* harmony export */ getSyncError: () => ( /* binding */getSyncError),
@@ -48803,6 +48699,16 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
48803
48699
  return `We had an unknown problem opening “${id}”.`;
48804
48700
  }
48805
48701
  }
48702
+ class LazyLoadFailedError extends Error {
48703
+ constructor(name) {
48704
+ super(`Error: failed loading lazy-loaded module ${name}`);
48705
+ this.type = 'app-init-failure';
48706
+ this.meta = {};
48707
+ this.meta = {
48708
+ name
48709
+ };
48710
+ }
48711
+ }
48806
48712
  /***/
48807
48713
  }),
48808
48714
  /***/ "./packages/loot-core/src/shared/months.ts":
@@ -48816,13 +48722,18 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
48816
48722
  /* harmony export */ _dayRange: () => ( /* binding */_dayRange),
48817
48723
  /* harmony export */ _parse: () => ( /* binding */_parse),
48818
48724
  /* harmony export */ _range: () => ( /* binding */_range),
48725
+ /* harmony export */ _weekRange: () => ( /* binding */_weekRange),
48726
+ /* harmony export */ _yearRange: () => ( /* binding */_yearRange),
48819
48727
  /* harmony export */ addDays: () => ( /* binding */addDays),
48820
48728
  /* harmony export */ addMonths: () => ( /* binding */addMonths),
48821
48729
  /* harmony export */ addWeeks: () => ( /* binding */addWeeks),
48730
+ /* harmony export */ addYears: () => ( /* binding */addYears),
48822
48731
  /* harmony export */ bounds: () => ( /* binding */bounds),
48823
48732
  /* harmony export */ currentDate: () => ( /* binding */currentDate),
48824
48733
  /* harmony export */ currentDay: () => ( /* binding */currentDay),
48825
48734
  /* harmony export */ currentMonth: () => ( /* binding */currentMonth),
48735
+ /* harmony export */ currentWeek: () => ( /* binding */currentWeek),
48736
+ /* harmony export */ currentYear: () => ( /* binding */currentYear),
48826
48737
  /* harmony export */ dayFromDate: () => ( /* binding */dayFromDate),
48827
48738
  /* harmony export */ dayRange: () => ( /* binding */dayRange),
48828
48739
  /* harmony export */ dayRangeInclusive: () => ( /* binding */dayRangeInclusive),
@@ -48830,15 +48741,18 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
48830
48741
  /* harmony export */ differenceInCalendarMonths: () => ( /* binding */differenceInCalendarMonths),
48831
48742
  /* harmony export */ format: () => ( /* binding */format),
48832
48743
  /* harmony export */ getDateFormatRegex: () => ( /* binding */getDateFormatRegex),
48744
+ /* harmony export */ getDay: () => ( /* binding */getDay),
48833
48745
  /* harmony export */ getDayMonthFormat: () => ( /* binding */getDayMonthFormat),
48834
48746
  /* harmony export */ getDayMonthRegex: () => ( /* binding */getDayMonthRegex),
48835
48747
  /* harmony export */ getMonth: () => ( /* binding */getMonth),
48748
+ /* harmony export */ getMonthEnd: () => ( /* binding */getMonthEnd),
48836
48749
  /* harmony export */ getMonthFromIndex: () => ( /* binding */getMonthFromIndex),
48837
48750
  /* harmony export */ getMonthIndex: () => ( /* binding */getMonthIndex),
48838
48751
  /* harmony export */ getMonthYearFormat: () => ( /* binding */getMonthYearFormat),
48839
48752
  /* harmony export */ getMonthYearRegex: () => ( /* binding */getMonthYearRegex),
48840
48753
  /* harmony export */ getShortYearFormat: () => ( /* binding */getShortYearFormat),
48841
48754
  /* harmony export */ getShortYearRegex: () => ( /* binding */getShortYearRegex),
48755
+ /* harmony export */ getWeekEnd: () => ( /* binding */getWeekEnd),
48842
48756
  /* harmony export */ getYear: () => ( /* binding */getYear),
48843
48757
  /* harmony export */ getYearEnd: () => ( /* binding */getYearEnd),
48844
48758
  /* harmony export */ getYearStart: () => ( /* binding */getYearStart),
@@ -48855,23 +48769,33 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
48855
48769
  /* harmony export */ sheetForMonth: () => ( /* binding */sheetForMonth),
48856
48770
  /* harmony export */ subDays: () => ( /* binding */subDays),
48857
48771
  /* harmony export */ subMonths: () => ( /* binding */subMonths),
48858
- /* harmony export */ yearFromDate: () => ( /* binding */yearFromDate)
48772
+ /* harmony export */ subWeeks: () => ( /* binding */subWeeks),
48773
+ /* harmony export */ subYears: () => ( /* binding */subYears),
48774
+ /* harmony export */ weekFromDate: () => ( /* binding */weekFromDate),
48775
+ /* harmony export */ weekRangeInclusive: () => ( /* binding */weekRangeInclusive),
48776
+ /* harmony export */ yearFromDate: () => ( /* binding */yearFromDate),
48777
+ /* harmony export */ yearRangeInclusive: () => ( /* binding */yearRangeInclusive)
48859
48778
  /* harmony export */
48860
48779
  });
48861
48780
  /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/format/index.js");
48862
- /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/parse/index.js");
48863
- /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/addMonths/index.js");
48864
- /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/subMonths/index.js");
48865
- /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/addWeeks/index.js");
48866
- /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/differenceInCalendarMonths/index.js");
48867
- /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/differenceInCalendarDays/index.js");
48868
- /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/addDays/index.js");
48869
- /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/subDays/index.js");
48870
- /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/isBefore/index.js");
48871
- /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/isAfter/index.js");
48872
- /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/startOfMonth/index.js");
48873
- /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/endOfMonth/index.js");
48874
- /* harmony import */ var memoize_one__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! memoize-one */ "./node_modules/memoize-one/dist/memoize-one.esm.js");
48781
+ /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/startOfWeek/index.js");
48782
+ /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/parse/index.js");
48783
+ /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/addMonths/index.js");
48784
+ /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/subMonths/index.js");
48785
+ /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/addYears/index.js");
48786
+ /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/addWeeks/index.js");
48787
+ /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/differenceInCalendarMonths/index.js");
48788
+ /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/differenceInCalendarDays/index.js");
48789
+ /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/subWeeks/index.js");
48790
+ /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/subYears/index.js");
48791
+ /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/addDays/index.js");
48792
+ /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/subDays/index.js");
48793
+ /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/isBefore/index.js");
48794
+ /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/isAfter/index.js");
48795
+ /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/startOfMonth/index.js");
48796
+ /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/endOfMonth/index.js");
48797
+ /* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/endOfWeek/index.js");
48798
+ /* harmony import */ var memoize_one__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! memoize-one */ "./node_modules/memoize-one/dist/memoize-one.esm.js");
48875
48799
  /* harmony import */ var _client_platform__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../client/platform */ "./packages/loot-core/src/client/platform.electron.ts");
48876
48800
  // @ts-strict-ignore
48877
48801
  function _parse(value) {
@@ -48952,6 +48876,12 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
48952
48876
  function monthFromDate(date) {
48953
48877
  return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](_parse(date), 'yyyy-MM');
48954
48878
  }
48879
+ function weekFromDate(date, firstDayOfWeekIdx) {
48880
+ const converted = parseInt(firstDayOfWeekIdx || '0');
48881
+ return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](_parse(date_fns__WEBPACK_IMPORTED_MODULE_2__["default"](_parse(date), {
48882
+ weekStartsOn: converted
48883
+ })), 'yyyy-MM-dd');
48884
+ }
48955
48885
  function dayFromDate(date) {
48956
48886
  return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](_parse(date), 'yyyy-MM-dd');
48957
48887
  }
@@ -48963,9 +48893,28 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
48963
48893
  return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](new Date(), 'yyyy-MM');
48964
48894
  }
48965
48895
  }
48896
+ function currentWeek(firstDayOfWeekIdx) {
48897
+ if (global.IS_TESTING || _client_platform__WEBPACK_IMPORTED_MODULE_0__.isPlaywright) {
48898
+ return global.currentWeek || '2017-01-01';
48899
+ }
48900
+ else {
48901
+ const converted = parseInt(firstDayOfWeekIdx || '0');
48902
+ return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](_parse(date_fns__WEBPACK_IMPORTED_MODULE_2__["default"](new Date(), {
48903
+ weekStartsOn: converted
48904
+ })), 'yyyy-MM-dd');
48905
+ }
48906
+ }
48907
+ function currentYear() {
48908
+ if (global.IS_TESTING || _client_platform__WEBPACK_IMPORTED_MODULE_0__.isPlaywright) {
48909
+ return global.currentMonth || '2017';
48910
+ }
48911
+ else {
48912
+ return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](new Date(), 'yyyy');
48913
+ }
48914
+ }
48966
48915
  function currentDate() {
48967
48916
  if (global.IS_TESTING || _client_platform__WEBPACK_IMPORTED_MODULE_0__.isPlaywright) {
48968
- return date_fns__WEBPACK_IMPORTED_MODULE_2__["default"](currentDay(), 'yyyy-MM-dd', new Date());
48917
+ return date_fns__WEBPACK_IMPORTED_MODULE_3__["default"](currentDay(), 'yyyy-MM-dd', new Date());
48969
48918
  }
48970
48919
  return new Date();
48971
48920
  }
@@ -48978,53 +48927,92 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
48978
48927
  }
48979
48928
  }
48980
48929
  function nextMonth(month) {
48981
- return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](date_fns__WEBPACK_IMPORTED_MODULE_3__["default"](_parse(month), 1), 'yyyy-MM');
48930
+ return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](date_fns__WEBPACK_IMPORTED_MODULE_4__["default"](_parse(month), 1), 'yyyy-MM');
48982
48931
  }
48983
48932
  function prevYear(month) {
48984
- return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](date_fns__WEBPACK_IMPORTED_MODULE_4__["default"](_parse(month), 12), 'yyyy-MM');
48933
+ return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](date_fns__WEBPACK_IMPORTED_MODULE_5__["default"](_parse(month), 12), 'yyyy-MM');
48985
48934
  }
48986
48935
  function prevMonth(month) {
48987
- return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](date_fns__WEBPACK_IMPORTED_MODULE_4__["default"](_parse(month), 1), 'yyyy-MM');
48936
+ return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](date_fns__WEBPACK_IMPORTED_MODULE_5__["default"](_parse(month), 1), 'yyyy-MM');
48937
+ }
48938
+ function addYears(year, n) {
48939
+ return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](date_fns__WEBPACK_IMPORTED_MODULE_6__["default"](_parse(year), n), 'yyyy');
48988
48940
  }
48989
48941
  function addMonths(month, n) {
48990
- return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](date_fns__WEBPACK_IMPORTED_MODULE_3__["default"](_parse(month), n), 'yyyy-MM');
48942
+ return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](date_fns__WEBPACK_IMPORTED_MODULE_4__["default"](_parse(month), n), 'yyyy-MM');
48991
48943
  }
48992
48944
  function addWeeks(date, n) {
48993
- return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](date_fns__WEBPACK_IMPORTED_MODULE_5__["default"](_parse(date), n), 'yyyy-MM-dd');
48945
+ return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](date_fns__WEBPACK_IMPORTED_MODULE_7__["default"](_parse(date), n), 'yyyy-MM-dd');
48994
48946
  }
48995
48947
  function differenceInCalendarMonths(month1, month2) {
48996
- return date_fns__WEBPACK_IMPORTED_MODULE_6__["default"](_parse(month1), _parse(month2));
48948
+ return date_fns__WEBPACK_IMPORTED_MODULE_8__["default"](_parse(month1), _parse(month2));
48997
48949
  }
48998
48950
  function differenceInCalendarDays(month1, month2) {
48999
- return date_fns__WEBPACK_IMPORTED_MODULE_7__["default"](_parse(month1), _parse(month2));
48951
+ return date_fns__WEBPACK_IMPORTED_MODULE_9__["default"](_parse(month1), _parse(month2));
49000
48952
  }
49001
48953
  function subMonths(month, n) {
49002
- return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](date_fns__WEBPACK_IMPORTED_MODULE_4__["default"](_parse(month), n), 'yyyy-MM');
48954
+ return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](date_fns__WEBPACK_IMPORTED_MODULE_5__["default"](_parse(month), n), 'yyyy-MM');
48955
+ }
48956
+ function subWeeks(date, n) {
48957
+ return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](date_fns__WEBPACK_IMPORTED_MODULE_10__["default"](_parse(date), n), 'yyyy-MM-dd');
48958
+ }
48959
+ function subYears(year, n) {
48960
+ return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](date_fns__WEBPACK_IMPORTED_MODULE_11__["default"](_parse(year), n), 'yyyy');
49003
48961
  }
49004
48962
  function addDays(day, n) {
49005
- return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](date_fns__WEBPACK_IMPORTED_MODULE_8__["default"](_parse(day), n), 'yyyy-MM-dd');
48963
+ return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](date_fns__WEBPACK_IMPORTED_MODULE_12__["default"](_parse(day), n), 'yyyy-MM-dd');
49006
48964
  }
49007
48965
  function subDays(day, n) {
49008
- return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](date_fns__WEBPACK_IMPORTED_MODULE_9__["default"](_parse(day), n), 'yyyy-MM-dd');
48966
+ return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](date_fns__WEBPACK_IMPORTED_MODULE_13__["default"](_parse(day), n), 'yyyy-MM-dd');
49009
48967
  }
49010
48968
  function isBefore(month1, month2) {
49011
- return date_fns__WEBPACK_IMPORTED_MODULE_10__["default"](_parse(month1), _parse(month2));
48969
+ return date_fns__WEBPACK_IMPORTED_MODULE_14__["default"](_parse(month1), _parse(month2));
49012
48970
  }
49013
48971
  function isAfter(month1, month2) {
49014
- return date_fns__WEBPACK_IMPORTED_MODULE_11__["default"](_parse(month1), _parse(month2));
48972
+ return date_fns__WEBPACK_IMPORTED_MODULE_15__["default"](_parse(month1), _parse(month2));
49015
48973
  }
49016
48974
  // TODO: This doesn't really fit in this module anymore, should
49017
48975
  // probably live elsewhere
49018
48976
  function bounds(month) {
49019
48977
  return {
49020
- start: parseInt(date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](date_fns__WEBPACK_IMPORTED_MODULE_12__["default"](_parse(month)), 'yyyyMMdd')),
49021
- end: parseInt(date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](date_fns__WEBPACK_IMPORTED_MODULE_13__["default"](_parse(month)), 'yyyyMMdd'))
48978
+ start: parseInt(date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](date_fns__WEBPACK_IMPORTED_MODULE_16__["default"](_parse(month)), 'yyyyMMdd')),
48979
+ end: parseInt(date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](date_fns__WEBPACK_IMPORTED_MODULE_17__["default"](_parse(month)), 'yyyyMMdd'))
49022
48980
  };
49023
48981
  }
48982
+ function _yearRange(start, end, inclusive = false) {
48983
+ const years = [];
48984
+ let year = yearFromDate(start);
48985
+ while (date_fns__WEBPACK_IMPORTED_MODULE_14__["default"](_parse(year), _parse(end))) {
48986
+ years.push(year);
48987
+ year = addYears(year, 1);
48988
+ }
48989
+ if (inclusive) {
48990
+ years.push(year);
48991
+ }
48992
+ return years;
48993
+ }
48994
+ function yearRangeInclusive(start, end) {
48995
+ return _yearRange(start, end, true);
48996
+ }
48997
+ function _weekRange(start, end, inclusive = false, firstDayOfWeekIdx) {
48998
+ const weeks = [];
48999
+ let week = weekFromDate(start, firstDayOfWeekIdx);
49000
+ while (date_fns__WEBPACK_IMPORTED_MODULE_14__["default"](_parse(week), _parse(end))) {
49001
+ weeks.push(week);
49002
+ week = addWeeks(week, 1);
49003
+ }
49004
+ if (inclusive) {
49005
+ weeks.push(week);
49006
+ }
49007
+ return weeks;
49008
+ }
49009
+ function weekRangeInclusive(start, end, firstDayOfWeekIdx) {
49010
+ return _weekRange(start, end, true, firstDayOfWeekIdx);
49011
+ }
49024
49012
  function _range(start, end, inclusive = false) {
49025
49013
  const months = [];
49026
49014
  let month = monthFromDate(start);
49027
- while (date_fns__WEBPACK_IMPORTED_MODULE_10__["default"](_parse(month), _parse(end))) {
49015
+ while (date_fns__WEBPACK_IMPORTED_MODULE_14__["default"](_parse(month), _parse(end))) {
49028
49016
  months.push(month);
49029
49017
  month = addMonths(month, 1);
49030
49018
  }
@@ -49042,7 +49030,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
49042
49030
  function _dayRange(start, end, inclusive = false) {
49043
49031
  const days = [];
49044
49032
  let day = start;
49045
- while (date_fns__WEBPACK_IMPORTED_MODULE_10__["default"](_parse(day), _parse(end))) {
49033
+ while (date_fns__WEBPACK_IMPORTED_MODULE_14__["default"](_parse(day), _parse(end))) {
49046
49034
  days.push(dayFromDate(day));
49047
49035
  day = addDays(day, 1);
49048
49036
  }
@@ -49070,6 +49058,18 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
49070
49058
  function getMonth(day) {
49071
49059
  return day.slice(0, 7);
49072
49060
  }
49061
+ function getDay(day) {
49062
+ return Number(date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](_parse(day), 'dd'));
49063
+ }
49064
+ function getMonthEnd(day) {
49065
+ return subDays(nextMonth(day.slice(0, 7)) + '-01', 1);
49066
+ }
49067
+ function getWeekEnd(date, firstDayOfWeekIdx) {
49068
+ const converted = parseInt(firstDayOfWeekIdx || '0');
49069
+ return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](_parse(date_fns__WEBPACK_IMPORTED_MODULE_18__["default"](_parse(date), {
49070
+ weekStartsOn: converted
49071
+ })), 'yyyy-MM-dd');
49072
+ }
49073
49073
  function getYearStart(month) {
49074
49074
  return getYear(month) + '-01';
49075
49075
  }
@@ -49080,33 +49080,32 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
49080
49080
  return 'budget' + month.replace('-', '');
49081
49081
  }
49082
49082
  function nameForMonth(month) {
49083
- // eslint-disable-next-line rulesdir/typography
49084
- return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](_parse(month), "MMMM 'yy");
49083
+ return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](_parse(month), 'MMMM ‘yy');
49085
49084
  }
49086
49085
  function format(month, str) {
49087
49086
  return date_fns__WEBPACK_IMPORTED_MODULE_1__["default"](_parse(month), str);
49088
49087
  }
49089
- const getDateFormatRegex = (0, memoize_one__WEBPACK_IMPORTED_MODULE_14__["default"])((format) => {
49088
+ const getDateFormatRegex = (0, memoize_one__WEBPACK_IMPORTED_MODULE_19__["default"])((format) => {
49090
49089
  return new RegExp(format.replace(/d+/g, '\\d{1,2}').replace(/M+/g, '\\d{1,2}').replace(/y+/g, '\\d{4}'));
49091
49090
  });
49092
- const getDayMonthFormat = (0, memoize_one__WEBPACK_IMPORTED_MODULE_14__["default"])((format) => {
49091
+ const getDayMonthFormat = (0, memoize_one__WEBPACK_IMPORTED_MODULE_19__["default"])((format) => {
49093
49092
  return format.replace(/y+/g, '').replace(/[^\w]$/, '').replace(/^[^\w]/, '');
49094
49093
  });
49095
- const getDayMonthRegex = (0, memoize_one__WEBPACK_IMPORTED_MODULE_14__["default"])((format) => {
49094
+ const getDayMonthRegex = (0, memoize_one__WEBPACK_IMPORTED_MODULE_19__["default"])((format) => {
49096
49095
  const regex = format.replace(/y+/g, '').replace(/[^\w]$/, '').replace(/^[^\w]/, '').replace(/d+/g, '\\d{1,2}').replace(/M+/g, '\\d{1,2}');
49097
49096
  return new RegExp('^' + regex + '$');
49098
49097
  });
49099
- const getMonthYearFormat = (0, memoize_one__WEBPACK_IMPORTED_MODULE_14__["default"])((format) => {
49098
+ const getMonthYearFormat = (0, memoize_one__WEBPACK_IMPORTED_MODULE_19__["default"])((format) => {
49100
49099
  return format.replace(/d+/g, '').replace(/[^\w]$/, '').replace(/^[^\w]/, '').replace(/\/\//, '/').replace(/\.\./, '.').replace(/--/, '-');
49101
49100
  });
49102
- const getMonthYearRegex = (0, memoize_one__WEBPACK_IMPORTED_MODULE_14__["default"])((format) => {
49101
+ const getMonthYearRegex = (0, memoize_one__WEBPACK_IMPORTED_MODULE_19__["default"])((format) => {
49103
49102
  const regex = format.replace(/d+/g, '').replace(/[^\w]$/, '').replace(/^[^\w]/, '').replace(/\/\//, '/').replace(/M+/g, '\\d{1,2}').replace(/y+/g, '\\d{2,4}');
49104
49103
  return new RegExp('^' + regex + '$');
49105
49104
  });
49106
- const getShortYearFormat = (0, memoize_one__WEBPACK_IMPORTED_MODULE_14__["default"])((format) => {
49105
+ const getShortYearFormat = (0, memoize_one__WEBPACK_IMPORTED_MODULE_19__["default"])((format) => {
49107
49106
  return format.replace(/y+/g, 'yy');
49108
49107
  });
49109
- const getShortYearRegex = (0, memoize_one__WEBPACK_IMPORTED_MODULE_14__["default"])((format) => {
49108
+ const getShortYearRegex = (0, memoize_one__WEBPACK_IMPORTED_MODULE_19__["default"])((format) => {
49110
49109
  const regex = format.replace(/[^\w]$/, '').replace(/^[^\w]/, '').replace(/d+/g, '\\d{1,2}').replace(/M+/g, '\\d{1,2}').replace(/y+/g, '\\d{2}');
49111
49110
  return new RegExp('^' + regex + '$');
49112
49111
  });
@@ -49918,6 +49917,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
49918
49917
  /* harmony export */ deleteTransaction: () => ( /* binding */deleteTransaction),
49919
49918
  /* harmony export */ groupTransaction: () => ( /* binding */groupTransaction),
49920
49919
  /* harmony export */ isPreviewId: () => ( /* binding */isPreviewId),
49920
+ /* harmony export */ isTemporaryId: () => ( /* binding */isTemporaryId),
49921
49921
  /* harmony export */ makeChild: () => ( /* binding */makeChild),
49922
49922
  /* harmony export */ realizeTempTransactions: () => ( /* binding */realizeTempTransactions),
49923
49923
  /* harmony export */ recalculateSplit: () => ( /* binding */recalculateSplit),
@@ -49929,7 +49929,9 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
49929
49929
  });
49930
49930
  /* harmony import */ var uuid__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! uuid */ "./node_modules/uuid/dist/esm-node/v4.js");
49931
49931
  /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./util */ "./packages/loot-core/src/shared/util.ts");
49932
- // @ts-strict-ignore
49932
+ function isTemporaryId(id) {
49933
+ return id.indexOf('temp') !== -1;
49934
+ }
49933
49935
  function isPreviewId(id) {
49934
49936
  return id.indexOf('preview/') !== -1;
49935
49937
  }
@@ -49950,11 +49952,13 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
49950
49952
  return {
49951
49953
  amount: 0,
49952
49954
  ...data,
49953
- payee: data.payee || parent.payee,
49954
- id: data.id ? data.id : prefix + (0, uuid__WEBPACK_IMPORTED_MODULE_1__["default"])(),
49955
+ category: 'category' in data ? data.category : parent.category,
49956
+ payee: 'payee' in data ? data.payee : parent.payee,
49957
+ id: 'id' in data ? data.id : prefix + (0, uuid__WEBPACK_IMPORTED_MODULE_1__["default"])(),
49955
49958
  account: parent.account,
49956
49959
  date: parent.date,
49957
49960
  cleared: parent.cleared != null ? parent.cleared : null,
49961
+ reconciled: 'reconciled' in data ? data.reconciled : parent.reconciled,
49958
49962
  starting_balance_flag: parent.starting_balance_flag != null ? parent.starting_balance_flag : null,
49959
49963
  is_child: true,
49960
49964
  parent_id: parent.id,
@@ -49964,7 +49968,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
49964
49968
  function recalculateSplit(trans) {
49965
49969
  // Calculate the new total of split transactions and make sure
49966
49970
  // that it equals the parent amount
49967
- const total = trans.subtransactions.reduce((acc, t) => acc + num(t.amount), 0);
49971
+ const total = (trans.subtransactions || []).reduce((acc, t) => acc + num(t.amount), 0);
49968
49972
  return {
49969
49973
  ...trans,
49970
49974
  error: total === num(trans.amount) ? null : SplitTransactionError(total, trans)
@@ -50059,7 +50063,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
50059
50063
  updated: []
50060
50064
  };
50061
50065
  grouped = {
50062
- id: split[0].id,
50066
+ ...split[0],
50063
50067
  _deleted: true
50064
50068
  };
50065
50069
  transactionsCopy.splice(parentIndex, split.length);
@@ -50084,7 +50088,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
50084
50088
  return {
50085
50089
  data: transactionsCopy,
50086
50090
  newTransaction: grouped || {
50087
- id: trans.id,
50091
+ ...trans,
50088
50092
  _deleted: true
50089
50093
  },
50090
50094
  diff: (0, _util__WEBPACK_IMPORTED_MODULE_0__.diffItems)([
@@ -50144,7 +50148,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
50144
50148
  else if (trans.subtransactions?.length === 1) {
50145
50149
  return {
50146
50150
  ...trans,
50147
- subtransactions: null,
50151
+ subtransactions: undefined,
50148
50152
  is_parent: false,
50149
50153
  error: null
50150
50154
  };
@@ -50181,9 +50185,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
50181
50185
  });
50182
50186
  }
50183
50187
  function realizeTempTransactions(transactions) {
50184
- let parent = transactions.find((t) => !t.is_child);
50185
- parent = {
50186
- ...parent,
50188
+ const parent = {
50189
+ ...transactions.find((t) => !t.is_child),
50187
50190
  id: (0, uuid__WEBPACK_IMPORTED_MODULE_1__["default"])()
50188
50191
  };
50189
50192
  const children = transactions.filter((t) => t.is_child);
@@ -50535,7 +50538,14 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
50535
50538
  // currencies. We extract out the numbers and just ignore separators.
50536
50539
  function looselyParseAmount(amount) {
50537
50540
  function safeNumber(v) {
50538
- return isNaN(v) ? null : v;
50541
+ if (isNaN(v)) {
50542
+ return null;
50543
+ }
50544
+ const value = v * 100;
50545
+ if (value > MAX_SAFE_NUMBER || value < MIN_SAFE_NUMBER) {
50546
+ return null;
50547
+ }
50548
+ return v;
50539
50549
  }
50540
50550
  function extractNumbers(v) {
50541
50551
  return v.replace(/[^0-9-]/g, '');
@@ -50543,7 +50553,9 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
50543
50553
  if (amount.startsWith('(') && amount.endsWith(')')) {
50544
50554
  amount = amount.replace('(', '-').replace(')', '');
50545
50555
  }
50546
- const m = amount.match(/[.,][^.,]{1,2}$/);
50556
+ //look for a decimal marker, then look for either 5 or 1-2 decimal places.
50557
+ // This avoids matching against 3 places which may not actually be decimal
50558
+ const m = amount.match(/[.,]([^.,]{5}|[^.,]{1,2})$/);
50547
50559
  if (!m || m.index === undefined || m.index === 0) {
50548
50560
  return safeNumber(parseFloat(extractNumbers(amount)));
50549
50561
  }
@@ -55511,6 +55523,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
55511
55523
  var peg$c0 = "source";
55512
55524
  var peg$c1 = "sink";
55513
55525
  var peg$c2 = " ";
55526
+ var peg$c3 = " source";
55527
+ var peg$c4 = " sink";
55514
55528
  var peg$r0 = /^[0-9]/;
55515
55529
  var peg$e0 = peg$literalExpectation("source", false);
55516
55530
  var peg$e1 = peg$literalExpectation("sink", false);
@@ -55519,9 +55533,16 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
55519
55533
  var peg$e4 = peg$otherExpectation("digit");
55520
55534
  var peg$e5 = peg$classExpectation([["0", "9"]], false, false);
55521
55535
  var peg$e6 = peg$otherExpectation("weight");
55522
- var peg$f0 = function () { return { type: 'source' }; };
55523
- var peg$f1 = function (weight) { return { type: 'sink', weight: +weight || 1 }; };
55524
- var peg$f2 = function (weight) { return +weight; };
55536
+ var peg$e7 = peg$otherExpectation("Name");
55537
+ var peg$e8 = peg$literalExpectation(" source", false);
55538
+ var peg$e9 = peg$anyExpectation();
55539
+ var peg$e10 = peg$literalExpectation(" sink", false);
55540
+ var peg$f0 = function () { return { group: null, type: 'source' }; };
55541
+ var peg$f1 = function (weight) { return { type: 'sink', weight: +weight || 1, group: null }; };
55542
+ var peg$f2 = function (group) { return { group: group || null, type: 'source' }; };
55543
+ var peg$f3 = function (group, weight) { return { type: 'sink', weight: +weight || 1, group: group || null }; };
55544
+ var peg$f4 = function (group) { return { group: group, type: null }; };
55545
+ var peg$f5 = function (weight) { return +weight; };
55525
55546
  var peg$currPos = 0;
55526
55547
  var peg$savedPos = 0;
55527
55548
  var peg$posDetailsCache = [{ line: 1, column: 1 }];
@@ -55647,7 +55668,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
55647
55668
  return new peg$SyntaxError(peg$SyntaxError.buildMessage(expected, found), expected, found, location);
55648
55669
  }
55649
55670
  function peg$parseexpr() {
55650
- var s0, s1, s2, s3;
55671
+ var s0, s1, s2, s3, s4, s5;
55651
55672
  s0 = peg$currPos;
55652
55673
  s1 = peg$parsesource();
55653
55674
  if (s1 !== peg$FAILED) {
@@ -55674,6 +55695,55 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
55674
55695
  peg$currPos = s0;
55675
55696
  s0 = peg$FAILED;
55676
55697
  }
55698
+ if (s0 === peg$FAILED) {
55699
+ s0 = peg$currPos;
55700
+ s1 = peg$parsesourcegroup();
55701
+ s2 = peg$parse_();
55702
+ if (s2 === peg$FAILED) {
55703
+ s2 = null;
55704
+ }
55705
+ s3 = peg$parsesource();
55706
+ if (s3 !== peg$FAILED) {
55707
+ peg$savedPos = s0;
55708
+ s0 = peg$f2(s1);
55709
+ }
55710
+ else {
55711
+ peg$currPos = s0;
55712
+ s0 = peg$FAILED;
55713
+ }
55714
+ if (s0 === peg$FAILED) {
55715
+ s0 = peg$currPos;
55716
+ s1 = peg$parsesinkgroup();
55717
+ s2 = peg$parse_();
55718
+ if (s2 === peg$FAILED) {
55719
+ s2 = null;
55720
+ }
55721
+ s3 = peg$parsesink();
55722
+ if (s3 !== peg$FAILED) {
55723
+ s4 = peg$parse_();
55724
+ if (s4 === peg$FAILED) {
55725
+ s4 = null;
55726
+ }
55727
+ s5 = peg$parseweight();
55728
+ if (s5 === peg$FAILED) {
55729
+ s5 = null;
55730
+ }
55731
+ peg$savedPos = s0;
55732
+ s0 = peg$f3(s1, s5);
55733
+ }
55734
+ else {
55735
+ peg$currPos = s0;
55736
+ s0 = peg$FAILED;
55737
+ }
55738
+ if (s0 === peg$FAILED) {
55739
+ s0 = peg$currPos;
55740
+ s1 = peg$parsesourcegroup();
55741
+ peg$savedPos = s0;
55742
+ s1 = peg$f4(s1);
55743
+ s0 = s1;
55744
+ }
55745
+ }
55746
+ }
55677
55747
  }
55678
55748
  return s0;
55679
55749
  }
@@ -55792,7 +55862,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
55792
55862
  }
55793
55863
  if (s1 !== peg$FAILED) {
55794
55864
  peg$savedPos = s0;
55795
- s1 = peg$f2(s1);
55865
+ s1 = peg$f5(s1);
55796
55866
  }
55797
55867
  s0 = s1;
55798
55868
  peg$silentFails--;
@@ -55804,6 +55874,218 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
55804
55874
  }
55805
55875
  return s0;
55806
55876
  }
55877
+ function peg$parsesourcegroup() {
55878
+ var s0, s1, s2, s3, s4;
55879
+ peg$silentFails++;
55880
+ s0 = peg$currPos;
55881
+ s1 = [];
55882
+ s2 = peg$currPos;
55883
+ s3 = peg$currPos;
55884
+ peg$silentFails++;
55885
+ if (input.substr(peg$currPos, 7) === peg$c3) {
55886
+ s4 = peg$c3;
55887
+ peg$currPos += 7;
55888
+ }
55889
+ else {
55890
+ s4 = peg$FAILED;
55891
+ if (peg$silentFails === 0) {
55892
+ peg$fail(peg$e8);
55893
+ }
55894
+ }
55895
+ peg$silentFails--;
55896
+ if (s4 === peg$FAILED) {
55897
+ s3 = undefined;
55898
+ }
55899
+ else {
55900
+ peg$currPos = s3;
55901
+ s3 = peg$FAILED;
55902
+ }
55903
+ if (s3 !== peg$FAILED) {
55904
+ if (input.length > peg$currPos) {
55905
+ s4 = input.charAt(peg$currPos);
55906
+ peg$currPos++;
55907
+ }
55908
+ else {
55909
+ s4 = peg$FAILED;
55910
+ if (peg$silentFails === 0) {
55911
+ peg$fail(peg$e9);
55912
+ }
55913
+ }
55914
+ if (s4 !== peg$FAILED) {
55915
+ s3 = [s3, s4];
55916
+ s2 = s3;
55917
+ }
55918
+ else {
55919
+ peg$currPos = s2;
55920
+ s2 = peg$FAILED;
55921
+ }
55922
+ }
55923
+ else {
55924
+ peg$currPos = s2;
55925
+ s2 = peg$FAILED;
55926
+ }
55927
+ while (s2 !== peg$FAILED) {
55928
+ s1.push(s2);
55929
+ s2 = peg$currPos;
55930
+ s3 = peg$currPos;
55931
+ peg$silentFails++;
55932
+ if (input.substr(peg$currPos, 7) === peg$c3) {
55933
+ s4 = peg$c3;
55934
+ peg$currPos += 7;
55935
+ }
55936
+ else {
55937
+ s4 = peg$FAILED;
55938
+ if (peg$silentFails === 0) {
55939
+ peg$fail(peg$e8);
55940
+ }
55941
+ }
55942
+ peg$silentFails--;
55943
+ if (s4 === peg$FAILED) {
55944
+ s3 = undefined;
55945
+ }
55946
+ else {
55947
+ peg$currPos = s3;
55948
+ s3 = peg$FAILED;
55949
+ }
55950
+ if (s3 !== peg$FAILED) {
55951
+ if (input.length > peg$currPos) {
55952
+ s4 = input.charAt(peg$currPos);
55953
+ peg$currPos++;
55954
+ }
55955
+ else {
55956
+ s4 = peg$FAILED;
55957
+ if (peg$silentFails === 0) {
55958
+ peg$fail(peg$e9);
55959
+ }
55960
+ }
55961
+ if (s4 !== peg$FAILED) {
55962
+ s3 = [s3, s4];
55963
+ s2 = s3;
55964
+ }
55965
+ else {
55966
+ peg$currPos = s2;
55967
+ s2 = peg$FAILED;
55968
+ }
55969
+ }
55970
+ else {
55971
+ peg$currPos = s2;
55972
+ s2 = peg$FAILED;
55973
+ }
55974
+ }
55975
+ s0 = input.substring(s0, peg$currPos);
55976
+ peg$silentFails--;
55977
+ s1 = peg$FAILED;
55978
+ if (peg$silentFails === 0) {
55979
+ peg$fail(peg$e7);
55980
+ }
55981
+ return s0;
55982
+ }
55983
+ function peg$parsesinkgroup() {
55984
+ var s0, s1, s2, s3, s4;
55985
+ peg$silentFails++;
55986
+ s0 = peg$currPos;
55987
+ s1 = [];
55988
+ s2 = peg$currPos;
55989
+ s3 = peg$currPos;
55990
+ peg$silentFails++;
55991
+ if (input.substr(peg$currPos, 5) === peg$c4) {
55992
+ s4 = peg$c4;
55993
+ peg$currPos += 5;
55994
+ }
55995
+ else {
55996
+ s4 = peg$FAILED;
55997
+ if (peg$silentFails === 0) {
55998
+ peg$fail(peg$e10);
55999
+ }
56000
+ }
56001
+ peg$silentFails--;
56002
+ if (s4 === peg$FAILED) {
56003
+ s3 = undefined;
56004
+ }
56005
+ else {
56006
+ peg$currPos = s3;
56007
+ s3 = peg$FAILED;
56008
+ }
56009
+ if (s3 !== peg$FAILED) {
56010
+ if (input.length > peg$currPos) {
56011
+ s4 = input.charAt(peg$currPos);
56012
+ peg$currPos++;
56013
+ }
56014
+ else {
56015
+ s4 = peg$FAILED;
56016
+ if (peg$silentFails === 0) {
56017
+ peg$fail(peg$e9);
56018
+ }
56019
+ }
56020
+ if (s4 !== peg$FAILED) {
56021
+ s3 = [s3, s4];
56022
+ s2 = s3;
56023
+ }
56024
+ else {
56025
+ peg$currPos = s2;
56026
+ s2 = peg$FAILED;
56027
+ }
56028
+ }
56029
+ else {
56030
+ peg$currPos = s2;
56031
+ s2 = peg$FAILED;
56032
+ }
56033
+ while (s2 !== peg$FAILED) {
56034
+ s1.push(s2);
56035
+ s2 = peg$currPos;
56036
+ s3 = peg$currPos;
56037
+ peg$silentFails++;
56038
+ if (input.substr(peg$currPos, 5) === peg$c4) {
56039
+ s4 = peg$c4;
56040
+ peg$currPos += 5;
56041
+ }
56042
+ else {
56043
+ s4 = peg$FAILED;
56044
+ if (peg$silentFails === 0) {
56045
+ peg$fail(peg$e10);
56046
+ }
56047
+ }
56048
+ peg$silentFails--;
56049
+ if (s4 === peg$FAILED) {
56050
+ s3 = undefined;
56051
+ }
56052
+ else {
56053
+ peg$currPos = s3;
56054
+ s3 = peg$FAILED;
56055
+ }
56056
+ if (s3 !== peg$FAILED) {
56057
+ if (input.length > peg$currPos) {
56058
+ s4 = input.charAt(peg$currPos);
56059
+ peg$currPos++;
56060
+ }
56061
+ else {
56062
+ s4 = peg$FAILED;
56063
+ if (peg$silentFails === 0) {
56064
+ peg$fail(peg$e9);
56065
+ }
56066
+ }
56067
+ if (s4 !== peg$FAILED) {
56068
+ s3 = [s3, s4];
56069
+ s2 = s3;
56070
+ }
56071
+ else {
56072
+ peg$currPos = s2;
56073
+ s2 = peg$FAILED;
56074
+ }
56075
+ }
56076
+ else {
56077
+ peg$currPos = s2;
56078
+ s2 = peg$FAILED;
56079
+ }
56080
+ }
56081
+ s0 = input.substring(s0, peg$currPos);
56082
+ peg$silentFails--;
56083
+ s1 = peg$FAILED;
56084
+ if (peg$silentFails === 0) {
56085
+ peg$fail(peg$e7);
56086
+ }
56087
+ return s0;
56088
+ }
55807
56089
  peg$result = peg$startRuleFunction();
55808
56090
  if (peg$result !== peg$FAILED && peg$currPos === input.length) {
55809
56091
  return peg$result;
@@ -55991,73 +56273,75 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
55991
56273
  var peg$source = options.grammarSource;
55992
56274
  var peg$startRuleFunctions = { expr: peg$parseexpr };
55993
56275
  var peg$startRuleFunction = peg$parseexpr;
55994
- var peg$c0 = "month";
56276
+ var peg$c0 = "average";
55995
56277
  var peg$c1 = "months";
55996
- var peg$c2 = "year";
55997
- var peg$c3 = "years";
55998
- var peg$c4 = "hold";
55999
- var peg$c5 = "previous";
56000
- var peg$c6 = "spend";
56001
- var peg$c7 = "from";
56002
- var peg$c8 = "week";
56003
- var peg$c9 = "weeks";
56004
- var peg$c10 = "by";
56005
- var peg$c11 = "of";
56006
- var peg$c12 = "repeat";
56007
- var peg$c13 = "every";
56008
- var peg$c14 = "starting";
56009
- var peg$c15 = "up";
56010
- var peg$c16 = "to";
56011
- var peg$c17 = "schedule";
56012
- var peg$c18 = "full";
56013
- var peg$c19 = "-";
56014
- var peg$c20 = "remainder";
56015
- var peg$c21 = " ";
56016
- var peg$c22 = ".";
56017
- var peg$c23 = "%";
56278
+ var peg$c2 = "month";
56279
+ var peg$c3 = "year";
56280
+ var peg$c4 = "years";
56281
+ var peg$c5 = "hold";
56282
+ var peg$c6 = "previous";
56283
+ var peg$c7 = "spend";
56284
+ var peg$c8 = "from";
56285
+ var peg$c9 = "week";
56286
+ var peg$c10 = "weeks";
56287
+ var peg$c11 = "by";
56288
+ var peg$c12 = "of";
56289
+ var peg$c13 = "repeat";
56290
+ var peg$c14 = "every";
56291
+ var peg$c15 = "starting";
56292
+ var peg$c16 = "up";
56293
+ var peg$c17 = "to";
56294
+ var peg$c18 = "schedule";
56295
+ var peg$c19 = "full";
56296
+ var peg$c20 = "-";
56297
+ var peg$c21 = "remainder";
56298
+ var peg$c22 = " ";
56299
+ var peg$c23 = ".";
56300
+ var peg$c24 = "%";
56018
56301
  var peg$r0 = /^[0-9]/;
56019
56302
  var peg$r1 = /^[1-9]/;
56020
56303
  var peg$r2 = /^[^\r\n\t]/;
56021
- var peg$e0 = peg$otherExpectation("repeat interval");
56022
- var peg$e1 = peg$literalExpectation("month", true);
56023
- var peg$e2 = peg$literalExpectation("months", true);
56024
- var peg$e3 = peg$literalExpectation("year", true);
56025
- var peg$e4 = peg$literalExpectation("years", true);
56026
- var peg$e5 = peg$literalExpectation("hold", true);
56027
- var peg$e6 = peg$literalExpectation("previous", true);
56028
- var peg$e7 = peg$literalExpectation("spend", true);
56029
- var peg$e8 = peg$literalExpectation("from", true);
56030
- var peg$e9 = peg$literalExpectation("week", true);
56031
- var peg$e10 = peg$literalExpectation("weeks", true);
56032
- var peg$e11 = peg$literalExpectation("by", true);
56033
- var peg$e12 = peg$literalExpectation("of", true);
56034
- var peg$e13 = peg$literalExpectation("repeat", true);
56035
- var peg$e14 = peg$literalExpectation("every", true);
56036
- var peg$e15 = peg$literalExpectation("starting", true);
56037
- var peg$e16 = peg$literalExpectation("up", true);
56038
- var peg$e17 = peg$literalExpectation("to", true);
56039
- var peg$e18 = peg$literalExpectation("schedule", true);
56040
- var peg$e19 = peg$literalExpectation("full", true);
56041
- var peg$e20 = peg$literalExpectation("-", true);
56042
- var peg$e21 = peg$literalExpectation("remainder", true);
56043
- var peg$e22 = peg$otherExpectation("space");
56044
- var peg$e23 = peg$literalExpectation(" ", false);
56045
- var peg$e24 = peg$otherExpectation("digit");
56046
- var peg$e25 = peg$classExpectation([["0", "9"]], false, false);
56047
- var peg$e26 = peg$otherExpectation("number");
56048
- var peg$e27 = peg$classExpectation([["1", "9"]], false, false);
56049
- var peg$e28 = peg$otherExpectation("amount");
56050
- var peg$e29 = peg$literalExpectation(".", false);
56051
- var peg$e30 = peg$otherExpectation("percentage");
56052
- var peg$e31 = peg$literalExpectation("%", false);
56053
- var peg$e32 = peg$otherExpectation("year");
56054
- var peg$e33 = peg$otherExpectation("month");
56055
- var peg$e34 = peg$literalExpectation("-", false);
56056
- var peg$e35 = peg$otherExpectation("day");
56057
- var peg$e36 = peg$otherExpectation("currency symbol");
56058
- var peg$e37 = peg$anyExpectation();
56059
- var peg$e38 = peg$otherExpectation("Name");
56060
- var peg$e39 = peg$classExpectation(["\r", "\n", "\t"], true, false);
56304
+ var peg$e0 = peg$literalExpectation("average", true);
56305
+ var peg$e1 = peg$literalExpectation("months", true);
56306
+ var peg$e2 = peg$otherExpectation("repeat interval");
56307
+ var peg$e3 = peg$literalExpectation("month", true);
56308
+ var peg$e4 = peg$literalExpectation("year", true);
56309
+ var peg$e5 = peg$literalExpectation("years", true);
56310
+ var peg$e6 = peg$literalExpectation("hold", true);
56311
+ var peg$e7 = peg$literalExpectation("previous", true);
56312
+ var peg$e8 = peg$literalExpectation("spend", true);
56313
+ var peg$e9 = peg$literalExpectation("from", true);
56314
+ var peg$e10 = peg$literalExpectation("week", true);
56315
+ var peg$e11 = peg$literalExpectation("weeks", true);
56316
+ var peg$e12 = peg$literalExpectation("by", true);
56317
+ var peg$e13 = peg$literalExpectation("of", true);
56318
+ var peg$e14 = peg$literalExpectation("repeat", true);
56319
+ var peg$e15 = peg$literalExpectation("every", true);
56320
+ var peg$e16 = peg$literalExpectation("starting", true);
56321
+ var peg$e17 = peg$literalExpectation("up", true);
56322
+ var peg$e18 = peg$literalExpectation("to", true);
56323
+ var peg$e19 = peg$literalExpectation("schedule", true);
56324
+ var peg$e20 = peg$literalExpectation("full", true);
56325
+ var peg$e21 = peg$literalExpectation("-", true);
56326
+ var peg$e22 = peg$literalExpectation("remainder", true);
56327
+ var peg$e23 = peg$otherExpectation("space");
56328
+ var peg$e24 = peg$literalExpectation(" ", false);
56329
+ var peg$e25 = peg$otherExpectation("digit");
56330
+ var peg$e26 = peg$classExpectation([["0", "9"]], false, false);
56331
+ var peg$e27 = peg$otherExpectation("number");
56332
+ var peg$e28 = peg$classExpectation([["1", "9"]], false, false);
56333
+ var peg$e29 = peg$otherExpectation("amount");
56334
+ var peg$e30 = peg$literalExpectation(".", false);
56335
+ var peg$e31 = peg$otherExpectation("percentage");
56336
+ var peg$e32 = peg$literalExpectation("%", false);
56337
+ var peg$e33 = peg$otherExpectation("year");
56338
+ var peg$e34 = peg$otherExpectation("month");
56339
+ var peg$e35 = peg$literalExpectation("-", false);
56340
+ var peg$e36 = peg$otherExpectation("day");
56341
+ var peg$e37 = peg$otherExpectation("currency symbol");
56342
+ var peg$e38 = peg$anyExpectation();
56343
+ var peg$e39 = peg$otherExpectation("Name");
56344
+ var peg$e40 = peg$classExpectation(["\r", "\n", "\t"], true, false);
56061
56345
  var peg$f0 = function (priority, percentOf, category) { return { type: 'percentage', percent: +percentOf.percent, previous: percentOf.prev, category, priority: +priority }; };
56062
56346
  var peg$f1 = function (priority, amount, weeks, starting, limit) { return { type: 'week', amount, weeks, starting, limit, priority: +priority }; };
56063
56347
  var peg$f2 = function (priority, amount, month, from, repeat) {
@@ -56074,23 +56358,24 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
56074
56358
  var peg$f4 = function (priority, limit) { return { type: 'simple', limit, priority: +priority }; };
56075
56359
  var peg$f5 = function (priority, full, name) { return { type: 'schedule', name, priority: +priority, full }; };
56076
56360
  var peg$f6 = function (priority, remainder) { return { type: 'remainder', priority: null, weight: remainder }; };
56077
- var peg$f7 = function () { return { annual: false }; };
56078
- var peg$f8 = function (months) { return { annual: false, repeat: +months }; };
56079
- var peg$f9 = function () { return { annual: true }; };
56080
- var peg$f10 = function (years) { return { annual: true, repeat: +years }; };
56081
- var peg$f11 = function (amount) { return { amount: amount, hold: true }; };
56082
- var peg$f12 = function (amount) { return { amount: amount, hold: false }; };
56083
- var peg$f13 = function (percent) { return { percent: percent, prev: true }; };
56084
- var peg$f14 = function (percent) { return { percent: percent, prev: false }; };
56085
- var peg$f15 = function () { return null; };
56086
- var peg$f16 = function (n) { return +n; };
56087
- var peg$f17 = function (month) { return month; };
56088
- var peg$f18 = function () { return true; };
56089
- var peg$f19 = function (number) { return number; };
56090
- var peg$f20 = function (weight) { return +weight || 1; };
56091
- var peg$f21 = function (amount) { return +amount; };
56092
- var peg$f22 = function (percent) { return +percent; };
56093
- var peg$f23 = function (symbol) { return /\p{Sc}/u.test(symbol); };
56361
+ var peg$f7 = function (priority, amount) { return { type: 'average', amount: +amount, priority: +priority }; };
56362
+ var peg$f8 = function () { return { annual: false }; };
56363
+ var peg$f9 = function (months) { return { annual: false, repeat: +months }; };
56364
+ var peg$f10 = function () { return { annual: true }; };
56365
+ var peg$f11 = function (years) { return { annual: true, repeat: +years }; };
56366
+ var peg$f12 = function (amount) { return { amount: amount, hold: true }; };
56367
+ var peg$f13 = function (amount) { return { amount: amount, hold: false }; };
56368
+ var peg$f14 = function (percent) { return { percent: percent, prev: true }; };
56369
+ var peg$f15 = function (percent) { return { percent: percent, prev: false }; };
56370
+ var peg$f16 = function () { return null; };
56371
+ var peg$f17 = function (n) { return +n; };
56372
+ var peg$f18 = function (month) { return month; };
56373
+ var peg$f19 = function () { return true; };
56374
+ var peg$f20 = function (number) { return number; };
56375
+ var peg$f21 = function (weight) { return +weight || 1; };
56376
+ var peg$f22 = function (amount) { return +amount; };
56377
+ var peg$f23 = function (percent) { return +percent; };
56378
+ var peg$f24 = function (symbol) { return /\p{Sc}/u.test(symbol); };
56094
56379
  var peg$currPos = 0;
56095
56380
  var peg$savedPos = 0;
56096
56381
  var peg$posDetailsCache = [{ line: 1, column: 1 }];
@@ -56504,6 +56789,69 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
56504
56789
  peg$currPos = s0;
56505
56790
  s0 = peg$FAILED;
56506
56791
  }
56792
+ if (s0 === peg$FAILED) {
56793
+ s0 = peg$currPos;
56794
+ s1 = peg$parsepriority();
56795
+ if (s1 === peg$FAILED) {
56796
+ s1 = null;
56797
+ }
56798
+ s2 = peg$parse_();
56799
+ if (s2 === peg$FAILED) {
56800
+ s2 = null;
56801
+ }
56802
+ if (input.substr(peg$currPos, 7).toLowerCase() === peg$c0) {
56803
+ s3 = input.substr(peg$currPos, 7);
56804
+ peg$currPos += 7;
56805
+ }
56806
+ else {
56807
+ s3 = peg$FAILED;
56808
+ if (peg$silentFails === 0) {
56809
+ peg$fail(peg$e0);
56810
+ }
56811
+ }
56812
+ if (s3 !== peg$FAILED) {
56813
+ s4 = peg$parse_();
56814
+ if (s4 !== peg$FAILED) {
56815
+ s5 = peg$parsepositive();
56816
+ if (s5 !== peg$FAILED) {
56817
+ s6 = peg$parse_();
56818
+ if (s6 !== peg$FAILED) {
56819
+ if (input.substr(peg$currPos, 6).toLowerCase() === peg$c1) {
56820
+ s7 = input.substr(peg$currPos, 6);
56821
+ peg$currPos += 6;
56822
+ }
56823
+ else {
56824
+ s7 = peg$FAILED;
56825
+ if (peg$silentFails === 0) {
56826
+ peg$fail(peg$e1);
56827
+ }
56828
+ }
56829
+ if (s7 === peg$FAILED) {
56830
+ s7 = null;
56831
+ }
56832
+ peg$savedPos = s0;
56833
+ s0 = peg$f7(s1, s5);
56834
+ }
56835
+ else {
56836
+ peg$currPos = s0;
56837
+ s0 = peg$FAILED;
56838
+ }
56839
+ }
56840
+ else {
56841
+ peg$currPos = s0;
56842
+ s0 = peg$FAILED;
56843
+ }
56844
+ }
56845
+ else {
56846
+ peg$currPos = s0;
56847
+ s0 = peg$FAILED;
56848
+ }
56849
+ }
56850
+ else {
56851
+ peg$currPos = s0;
56852
+ s0 = peg$FAILED;
56853
+ }
56854
+ }
56507
56855
  }
56508
56856
  }
56509
56857
  }
@@ -56516,19 +56864,19 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
56516
56864
  var s0, s1, s2, s3;
56517
56865
  peg$silentFails++;
56518
56866
  s0 = peg$currPos;
56519
- if (input.substr(peg$currPos, 5).toLowerCase() === peg$c0) {
56867
+ if (input.substr(peg$currPos, 5).toLowerCase() === peg$c2) {
56520
56868
  s1 = input.substr(peg$currPos, 5);
56521
56869
  peg$currPos += 5;
56522
56870
  }
56523
56871
  else {
56524
56872
  s1 = peg$FAILED;
56525
56873
  if (peg$silentFails === 0) {
56526
- peg$fail(peg$e1);
56874
+ peg$fail(peg$e3);
56527
56875
  }
56528
56876
  }
56529
56877
  if (s1 !== peg$FAILED) {
56530
56878
  peg$savedPos = s0;
56531
- s1 = peg$f7();
56879
+ s1 = peg$f8();
56532
56880
  }
56533
56881
  s0 = s1;
56534
56882
  if (s0 === peg$FAILED) {
@@ -56544,12 +56892,12 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
56544
56892
  else {
56545
56893
  s3 = peg$FAILED;
56546
56894
  if (peg$silentFails === 0) {
56547
- peg$fail(peg$e2);
56895
+ peg$fail(peg$e1);
56548
56896
  }
56549
56897
  }
56550
56898
  if (s3 !== peg$FAILED) {
56551
56899
  peg$savedPos = s0;
56552
- s0 = peg$f8(s1);
56900
+ s0 = peg$f9(s1);
56553
56901
  }
56554
56902
  else {
56555
56903
  peg$currPos = s0;
@@ -56567,19 +56915,19 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
56567
56915
  }
56568
56916
  if (s0 === peg$FAILED) {
56569
56917
  s0 = peg$currPos;
56570
- if (input.substr(peg$currPos, 4).toLowerCase() === peg$c2) {
56918
+ if (input.substr(peg$currPos, 4).toLowerCase() === peg$c3) {
56571
56919
  s1 = input.substr(peg$currPos, 4);
56572
56920
  peg$currPos += 4;
56573
56921
  }
56574
56922
  else {
56575
56923
  s1 = peg$FAILED;
56576
56924
  if (peg$silentFails === 0) {
56577
- peg$fail(peg$e3);
56925
+ peg$fail(peg$e4);
56578
56926
  }
56579
56927
  }
56580
56928
  if (s1 !== peg$FAILED) {
56581
56929
  peg$savedPos = s0;
56582
- s1 = peg$f9();
56930
+ s1 = peg$f10();
56583
56931
  }
56584
56932
  s0 = s1;
56585
56933
  if (s0 === peg$FAILED) {
@@ -56588,19 +56936,19 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
56588
56936
  if (s1 !== peg$FAILED) {
56589
56937
  s2 = peg$parse_();
56590
56938
  if (s2 !== peg$FAILED) {
56591
- if (input.substr(peg$currPos, 5).toLowerCase() === peg$c3) {
56939
+ if (input.substr(peg$currPos, 5).toLowerCase() === peg$c4) {
56592
56940
  s3 = input.substr(peg$currPos, 5);
56593
56941
  peg$currPos += 5;
56594
56942
  }
56595
56943
  else {
56596
56944
  s3 = peg$FAILED;
56597
56945
  if (peg$silentFails === 0) {
56598
- peg$fail(peg$e4);
56946
+ peg$fail(peg$e5);
56599
56947
  }
56600
56948
  }
56601
56949
  if (s3 !== peg$FAILED) {
56602
56950
  peg$savedPos = s0;
56603
- s0 = peg$f10(s1);
56951
+ s0 = peg$f11(s1);
56604
56952
  }
56605
56953
  else {
56606
56954
  peg$currPos = s0;
@@ -56623,7 +56971,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
56623
56971
  if (s0 === peg$FAILED) {
56624
56972
  s1 = peg$FAILED;
56625
56973
  if (peg$silentFails === 0) {
56626
- peg$fail(peg$e0);
56974
+ peg$fail(peg$e2);
56627
56975
  }
56628
56976
  }
56629
56977
  return s0;
@@ -56643,19 +56991,19 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
56643
56991
  if (s4 !== peg$FAILED) {
56644
56992
  s5 = peg$parse_();
56645
56993
  if (s5 !== peg$FAILED) {
56646
- if (input.substr(peg$currPos, 4).toLowerCase() === peg$c4) {
56994
+ if (input.substr(peg$currPos, 4).toLowerCase() === peg$c5) {
56647
56995
  s6 = input.substr(peg$currPos, 4);
56648
56996
  peg$currPos += 4;
56649
56997
  }
56650
56998
  else {
56651
56999
  s6 = peg$FAILED;
56652
57000
  if (peg$silentFails === 0) {
56653
- peg$fail(peg$e5);
57001
+ peg$fail(peg$e6);
56654
57002
  }
56655
57003
  }
56656
57004
  if (s6 !== peg$FAILED) {
56657
57005
  peg$savedPos = s0;
56658
- s0 = peg$f11(s4);
57006
+ s0 = peg$f12(s4);
56659
57007
  }
56660
57008
  else {
56661
57009
  peg$currPos = s0;
@@ -56694,7 +57042,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
56694
57042
  s4 = peg$parseamount();
56695
57043
  if (s4 !== peg$FAILED) {
56696
57044
  peg$savedPos = s0;
56697
- s0 = peg$f12(s4);
57045
+ s0 = peg$f13(s4);
56698
57046
  }
56699
57047
  else {
56700
57048
  peg$currPos = s0;
@@ -56724,21 +57072,21 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
56724
57072
  if (s3 !== peg$FAILED) {
56725
57073
  s4 = peg$parse_();
56726
57074
  if (s4 !== peg$FAILED) {
56727
- if (input.substr(peg$currPos, 8).toLowerCase() === peg$c5) {
57075
+ if (input.substr(peg$currPos, 8).toLowerCase() === peg$c6) {
56728
57076
  s5 = input.substr(peg$currPos, 8);
56729
57077
  peg$currPos += 8;
56730
57078
  }
56731
57079
  else {
56732
57080
  s5 = peg$FAILED;
56733
57081
  if (peg$silentFails === 0) {
56734
- peg$fail(peg$e6);
57082
+ peg$fail(peg$e7);
56735
57083
  }
56736
57084
  }
56737
57085
  if (s5 !== peg$FAILED) {
56738
57086
  s6 = peg$parse_();
56739
57087
  if (s6 !== peg$FAILED) {
56740
57088
  peg$savedPos = s0;
56741
- s0 = peg$f13(s1);
57089
+ s0 = peg$f14(s1);
56742
57090
  }
56743
57091
  else {
56744
57092
  peg$currPos = s0;
@@ -56780,7 +57128,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
56780
57128
  s4 = peg$parse_();
56781
57129
  if (s4 !== peg$FAILED) {
56782
57130
  peg$savedPos = s0;
56783
- s0 = peg$f14(s1);
57131
+ s0 = peg$f15(s1);
56784
57132
  }
56785
57133
  else {
56786
57134
  peg$currPos = s0;
@@ -56810,7 +57158,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
56810
57158
  s1 = peg$parseweek();
56811
57159
  if (s1 !== peg$FAILED) {
56812
57160
  peg$savedPos = s0;
56813
- s1 = peg$f15();
57161
+ s1 = peg$f16();
56814
57162
  }
56815
57163
  s0 = s1;
56816
57164
  if (s0 === peg$FAILED) {
@@ -56822,7 +57170,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
56822
57170
  s3 = peg$parseweeks();
56823
57171
  if (s3 !== peg$FAILED) {
56824
57172
  peg$savedPos = s0;
56825
- s0 = peg$f16(s1);
57173
+ s0 = peg$f17(s1);
56826
57174
  }
56827
57175
  else {
56828
57176
  peg$currPos = s0;
@@ -56846,27 +57194,27 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
56846
57194
  s0 = peg$currPos;
56847
57195
  s1 = peg$parse_();
56848
57196
  if (s1 !== peg$FAILED) {
56849
- if (input.substr(peg$currPos, 5).toLowerCase() === peg$c6) {
57197
+ if (input.substr(peg$currPos, 5).toLowerCase() === peg$c7) {
56850
57198
  s2 = input.substr(peg$currPos, 5);
56851
57199
  peg$currPos += 5;
56852
57200
  }
56853
57201
  else {
56854
57202
  s2 = peg$FAILED;
56855
57203
  if (peg$silentFails === 0) {
56856
- peg$fail(peg$e7);
57204
+ peg$fail(peg$e8);
56857
57205
  }
56858
57206
  }
56859
57207
  if (s2 !== peg$FAILED) {
56860
57208
  s3 = peg$parse_();
56861
57209
  if (s3 !== peg$FAILED) {
56862
- if (input.substr(peg$currPos, 4).toLowerCase() === peg$c7) {
57210
+ if (input.substr(peg$currPos, 4).toLowerCase() === peg$c8) {
56863
57211
  s4 = input.substr(peg$currPos, 4);
56864
57212
  peg$currPos += 4;
56865
57213
  }
56866
57214
  else {
56867
57215
  s4 = peg$FAILED;
56868
57216
  if (peg$silentFails === 0) {
56869
- peg$fail(peg$e8);
57217
+ peg$fail(peg$e9);
56870
57218
  }
56871
57219
  }
56872
57220
  if (s4 !== peg$FAILED) {
@@ -56875,7 +57223,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
56875
57223
  s6 = peg$parsemonth();
56876
57224
  if (s6 !== peg$FAILED) {
56877
57225
  peg$savedPos = s0;
56878
- s0 = peg$f17(s6);
57226
+ s0 = peg$f18(s6);
56879
57227
  }
56880
57228
  else {
56881
57229
  peg$currPos = s0;
@@ -56910,56 +57258,56 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
56910
57258
  }
56911
57259
  function peg$parseweek() {
56912
57260
  var s0;
56913
- if (input.substr(peg$currPos, 4).toLowerCase() === peg$c8) {
57261
+ if (input.substr(peg$currPos, 4).toLowerCase() === peg$c9) {
56914
57262
  s0 = input.substr(peg$currPos, 4);
56915
57263
  peg$currPos += 4;
56916
57264
  }
56917
57265
  else {
56918
57266
  s0 = peg$FAILED;
56919
57267
  if (peg$silentFails === 0) {
56920
- peg$fail(peg$e9);
57268
+ peg$fail(peg$e10);
56921
57269
  }
56922
57270
  }
56923
57271
  return s0;
56924
57272
  }
56925
57273
  function peg$parseweeks() {
56926
57274
  var s0;
56927
- if (input.substr(peg$currPos, 5).toLowerCase() === peg$c9) {
57275
+ if (input.substr(peg$currPos, 5).toLowerCase() === peg$c10) {
56928
57276
  s0 = input.substr(peg$currPos, 5);
56929
57277
  peg$currPos += 5;
56930
57278
  }
56931
57279
  else {
56932
57280
  s0 = peg$FAILED;
56933
57281
  if (peg$silentFails === 0) {
56934
- peg$fail(peg$e10);
57282
+ peg$fail(peg$e11);
56935
57283
  }
56936
57284
  }
56937
57285
  return s0;
56938
57286
  }
56939
57287
  function peg$parseby() {
56940
57288
  var s0;
56941
- if (input.substr(peg$currPos, 2).toLowerCase() === peg$c10) {
57289
+ if (input.substr(peg$currPos, 2).toLowerCase() === peg$c11) {
56942
57290
  s0 = input.substr(peg$currPos, 2);
56943
57291
  peg$currPos += 2;
56944
57292
  }
56945
57293
  else {
56946
57294
  s0 = peg$FAILED;
56947
57295
  if (peg$silentFails === 0) {
56948
- peg$fail(peg$e11);
57296
+ peg$fail(peg$e12);
56949
57297
  }
56950
57298
  }
56951
57299
  return s0;
56952
57300
  }
56953
57301
  function peg$parseof() {
56954
57302
  var s0;
56955
- if (input.substr(peg$currPos, 2).toLowerCase() === peg$c11) {
57303
+ if (input.substr(peg$currPos, 2).toLowerCase() === peg$c12) {
56956
57304
  s0 = input.substr(peg$currPos, 2);
56957
57305
  peg$currPos += 2;
56958
57306
  }
56959
57307
  else {
56960
57308
  s0 = peg$FAILED;
56961
57309
  if (peg$silentFails === 0) {
56962
- peg$fail(peg$e12);
57310
+ peg$fail(peg$e13);
56963
57311
  }
56964
57312
  }
56965
57313
  return s0;
@@ -56967,27 +57315,27 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
56967
57315
  function peg$parserepeatEvery() {
56968
57316
  var s0, s1, s2, s3;
56969
57317
  s0 = peg$currPos;
56970
- if (input.substr(peg$currPos, 6).toLowerCase() === peg$c12) {
57318
+ if (input.substr(peg$currPos, 6).toLowerCase() === peg$c13) {
56971
57319
  s1 = input.substr(peg$currPos, 6);
56972
57320
  peg$currPos += 6;
56973
57321
  }
56974
57322
  else {
56975
57323
  s1 = peg$FAILED;
56976
57324
  if (peg$silentFails === 0) {
56977
- peg$fail(peg$e13);
57325
+ peg$fail(peg$e14);
56978
57326
  }
56979
57327
  }
56980
57328
  if (s1 !== peg$FAILED) {
56981
57329
  s2 = peg$parse_();
56982
57330
  if (s2 !== peg$FAILED) {
56983
- if (input.substr(peg$currPos, 5).toLowerCase() === peg$c13) {
57331
+ if (input.substr(peg$currPos, 5).toLowerCase() === peg$c14) {
56984
57332
  s3 = input.substr(peg$currPos, 5);
56985
57333
  peg$currPos += 5;
56986
57334
  }
56987
57335
  else {
56988
57336
  s3 = peg$FAILED;
56989
57337
  if (peg$silentFails === 0) {
56990
- peg$fail(peg$e14);
57338
+ peg$fail(peg$e15);
56991
57339
  }
56992
57340
  }
56993
57341
  if (s3 !== peg$FAILED) {
@@ -57012,14 +57360,14 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57012
57360
  }
57013
57361
  function peg$parsestarting() {
57014
57362
  var s0;
57015
- if (input.substr(peg$currPos, 8).toLowerCase() === peg$c14) {
57363
+ if (input.substr(peg$currPos, 8).toLowerCase() === peg$c15) {
57016
57364
  s0 = input.substr(peg$currPos, 8);
57017
57365
  peg$currPos += 8;
57018
57366
  }
57019
57367
  else {
57020
57368
  s0 = peg$FAILED;
57021
57369
  if (peg$silentFails === 0) {
57022
- peg$fail(peg$e15);
57370
+ peg$fail(peg$e16);
57023
57371
  }
57024
57372
  }
57025
57373
  return s0;
@@ -57027,27 +57375,27 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57027
57375
  function peg$parseupTo() {
57028
57376
  var s0, s1, s2, s3;
57029
57377
  s0 = peg$currPos;
57030
- if (input.substr(peg$currPos, 2).toLowerCase() === peg$c15) {
57378
+ if (input.substr(peg$currPos, 2).toLowerCase() === peg$c16) {
57031
57379
  s1 = input.substr(peg$currPos, 2);
57032
57380
  peg$currPos += 2;
57033
57381
  }
57034
57382
  else {
57035
57383
  s1 = peg$FAILED;
57036
57384
  if (peg$silentFails === 0) {
57037
- peg$fail(peg$e16);
57385
+ peg$fail(peg$e17);
57038
57386
  }
57039
57387
  }
57040
57388
  if (s1 !== peg$FAILED) {
57041
57389
  s2 = peg$parse_();
57042
57390
  if (s2 !== peg$FAILED) {
57043
- if (input.substr(peg$currPos, 2).toLowerCase() === peg$c16) {
57391
+ if (input.substr(peg$currPos, 2).toLowerCase() === peg$c17) {
57044
57392
  s3 = input.substr(peg$currPos, 2);
57045
57393
  peg$currPos += 2;
57046
57394
  }
57047
57395
  else {
57048
57396
  s3 = peg$FAILED;
57049
57397
  if (peg$silentFails === 0) {
57050
- peg$fail(peg$e17);
57398
+ peg$fail(peg$e18);
57051
57399
  }
57052
57400
  }
57053
57401
  if (s3 !== peg$FAILED) {
@@ -57072,14 +57420,14 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57072
57420
  }
57073
57421
  function peg$parseschedule() {
57074
57422
  var s0;
57075
- if (input.substr(peg$currPos, 8).toLowerCase() === peg$c17) {
57423
+ if (input.substr(peg$currPos, 8).toLowerCase() === peg$c18) {
57076
57424
  s0 = input.substr(peg$currPos, 8);
57077
57425
  peg$currPos += 8;
57078
57426
  }
57079
57427
  else {
57080
57428
  s0 = peg$FAILED;
57081
57429
  if (peg$silentFails === 0) {
57082
- peg$fail(peg$e18);
57430
+ peg$fail(peg$e19);
57083
57431
  }
57084
57432
  }
57085
57433
  return s0;
@@ -57087,21 +57435,21 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57087
57435
  function peg$parsefull() {
57088
57436
  var s0, s1, s2;
57089
57437
  s0 = peg$currPos;
57090
- if (input.substr(peg$currPos, 4).toLowerCase() === peg$c18) {
57438
+ if (input.substr(peg$currPos, 4).toLowerCase() === peg$c19) {
57091
57439
  s1 = input.substr(peg$currPos, 4);
57092
57440
  peg$currPos += 4;
57093
57441
  }
57094
57442
  else {
57095
57443
  s1 = peg$FAILED;
57096
57444
  if (peg$silentFails === 0) {
57097
- peg$fail(peg$e19);
57445
+ peg$fail(peg$e20);
57098
57446
  }
57099
57447
  }
57100
57448
  if (s1 !== peg$FAILED) {
57101
57449
  s2 = peg$parse_();
57102
57450
  if (s2 !== peg$FAILED) {
57103
57451
  peg$savedPos = s0;
57104
- s0 = peg$f18();
57452
+ s0 = peg$f19();
57105
57453
  }
57106
57454
  else {
57107
57455
  peg$currPos = s0;
@@ -57117,14 +57465,14 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57117
57465
  function peg$parsepriority() {
57118
57466
  var s0, s1, s2, s3;
57119
57467
  s0 = peg$currPos;
57120
- if (input.substr(peg$currPos, 1).toLowerCase() === peg$c19) {
57468
+ if (input.substr(peg$currPos, 1).toLowerCase() === peg$c20) {
57121
57469
  s1 = input.charAt(peg$currPos);
57122
57470
  peg$currPos++;
57123
57471
  }
57124
57472
  else {
57125
57473
  s1 = peg$FAILED;
57126
57474
  if (peg$silentFails === 0) {
57127
- peg$fail(peg$e20);
57475
+ peg$fail(peg$e21);
57128
57476
  }
57129
57477
  }
57130
57478
  if (s1 !== peg$FAILED) {
@@ -57133,7 +57481,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57133
57481
  s3 = peg$parse_();
57134
57482
  if (s3 !== peg$FAILED) {
57135
57483
  peg$savedPos = s0;
57136
- s0 = peg$f19(s2);
57484
+ s0 = peg$f20(s2);
57137
57485
  }
57138
57486
  else {
57139
57487
  peg$currPos = s0;
@@ -57154,14 +57502,14 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57154
57502
  function peg$parseremainder() {
57155
57503
  var s0, s1, s2, s3;
57156
57504
  s0 = peg$currPos;
57157
- if (input.substr(peg$currPos, 9).toLowerCase() === peg$c20) {
57505
+ if (input.substr(peg$currPos, 9).toLowerCase() === peg$c21) {
57158
57506
  s1 = input.substr(peg$currPos, 9);
57159
57507
  peg$currPos += 9;
57160
57508
  }
57161
57509
  else {
57162
57510
  s1 = peg$FAILED;
57163
57511
  if (peg$silentFails === 0) {
57164
- peg$fail(peg$e21);
57512
+ peg$fail(peg$e22);
57165
57513
  }
57166
57514
  }
57167
57515
  if (s1 !== peg$FAILED) {
@@ -57174,7 +57522,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57174
57522
  s3 = null;
57175
57523
  }
57176
57524
  peg$savedPos = s0;
57177
- s0 = peg$f20(s3);
57525
+ s0 = peg$f21(s3);
57178
57526
  }
57179
57527
  else {
57180
57528
  peg$currPos = s0;
@@ -57187,26 +57535,26 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57187
57535
  peg$silentFails++;
57188
57536
  s0 = [];
57189
57537
  if (input.charCodeAt(peg$currPos) === 32) {
57190
- s1 = peg$c21;
57538
+ s1 = peg$c22;
57191
57539
  peg$currPos++;
57192
57540
  }
57193
57541
  else {
57194
57542
  s1 = peg$FAILED;
57195
57543
  if (peg$silentFails === 0) {
57196
- peg$fail(peg$e23);
57544
+ peg$fail(peg$e24);
57197
57545
  }
57198
57546
  }
57199
57547
  if (s1 !== peg$FAILED) {
57200
57548
  while (s1 !== peg$FAILED) {
57201
57549
  s0.push(s1);
57202
57550
  if (input.charCodeAt(peg$currPos) === 32) {
57203
- s1 = peg$c21;
57551
+ s1 = peg$c22;
57204
57552
  peg$currPos++;
57205
57553
  }
57206
57554
  else {
57207
57555
  s1 = peg$FAILED;
57208
57556
  if (peg$silentFails === 0) {
57209
- peg$fail(peg$e23);
57557
+ peg$fail(peg$e24);
57210
57558
  }
57211
57559
  }
57212
57560
  }
@@ -57218,7 +57566,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57218
57566
  if (s0 === peg$FAILED) {
57219
57567
  s1 = peg$FAILED;
57220
57568
  if (peg$silentFails === 0) {
57221
- peg$fail(peg$e22);
57569
+ peg$fail(peg$e23);
57222
57570
  }
57223
57571
  }
57224
57572
  return s0;
@@ -57233,14 +57581,14 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57233
57581
  else {
57234
57582
  s0 = peg$FAILED;
57235
57583
  if (peg$silentFails === 0) {
57236
- peg$fail(peg$e25);
57584
+ peg$fail(peg$e26);
57237
57585
  }
57238
57586
  }
57239
57587
  peg$silentFails--;
57240
57588
  if (s0 === peg$FAILED) {
57241
57589
  s1 = peg$FAILED;
57242
57590
  if (peg$silentFails === 0) {
57243
- peg$fail(peg$e24);
57591
+ peg$fail(peg$e25);
57244
57592
  }
57245
57593
  }
57246
57594
  return s0;
@@ -57270,7 +57618,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57270
57618
  if (s0 === peg$FAILED) {
57271
57619
  s1 = peg$FAILED;
57272
57620
  if (peg$silentFails === 0) {
57273
- peg$fail(peg$e26);
57621
+ peg$fail(peg$e27);
57274
57622
  }
57275
57623
  }
57276
57624
  return s0;
@@ -57286,7 +57634,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57286
57634
  else {
57287
57635
  s2 = peg$FAILED;
57288
57636
  if (peg$silentFails === 0) {
57289
- peg$fail(peg$e27);
57637
+ peg$fail(peg$e28);
57290
57638
  }
57291
57639
  }
57292
57640
  if (s2 !== peg$FAILED) {
@@ -57298,7 +57646,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57298
57646
  else {
57299
57647
  s4 = peg$FAILED;
57300
57648
  if (peg$silentFails === 0) {
57301
- peg$fail(peg$e25);
57649
+ peg$fail(peg$e26);
57302
57650
  }
57303
57651
  }
57304
57652
  while (s4 !== peg$FAILED) {
@@ -57310,7 +57658,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57310
57658
  else {
57311
57659
  s4 = peg$FAILED;
57312
57660
  if (peg$silentFails === 0) {
57313
- peg$fail(peg$e25);
57661
+ peg$fail(peg$e26);
57314
57662
  }
57315
57663
  }
57316
57664
  }
@@ -57357,13 +57705,13 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57357
57705
  if (s5 !== peg$FAILED) {
57358
57706
  s6 = peg$currPos;
57359
57707
  if (input.charCodeAt(peg$currPos) === 46) {
57360
- s7 = peg$c22;
57708
+ s7 = peg$c23;
57361
57709
  peg$currPos++;
57362
57710
  }
57363
57711
  else {
57364
57712
  s7 = peg$FAILED;
57365
57713
  if (peg$silentFails === 0) {
57366
- peg$fail(peg$e29);
57714
+ peg$fail(peg$e30);
57367
57715
  }
57368
57716
  }
57369
57717
  if (s7 !== peg$FAILED) {
@@ -57409,7 +57757,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57409
57757
  }
57410
57758
  if (s3 !== peg$FAILED) {
57411
57759
  peg$savedPos = s0;
57412
- s0 = peg$f21(s3);
57760
+ s0 = peg$f22(s3);
57413
57761
  }
57414
57762
  else {
57415
57763
  peg$currPos = s0;
@@ -57419,25 +57767,70 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57419
57767
  if (s0 === peg$FAILED) {
57420
57768
  s1 = peg$FAILED;
57421
57769
  if (peg$silentFails === 0) {
57422
- peg$fail(peg$e28);
57770
+ peg$fail(peg$e29);
57423
57771
  }
57424
57772
  }
57425
57773
  return s0;
57426
57774
  }
57427
57775
  function peg$parsepercent() {
57428
- var s0, s1, s2, s3;
57776
+ var s0, s1, s2, s3, s4, s5, s6, s7;
57429
57777
  peg$silentFails++;
57430
57778
  s0 = peg$currPos;
57431
57779
  s1 = peg$currPos;
57432
- s2 = [];
57433
- s3 = peg$parsed();
57780
+ s2 = peg$currPos;
57781
+ s3 = [];
57782
+ s4 = peg$parsed();
57783
+ if (s4 !== peg$FAILED) {
57784
+ while (s4 !== peg$FAILED) {
57785
+ s3.push(s4);
57786
+ s4 = peg$parsed();
57787
+ }
57788
+ }
57789
+ else {
57790
+ s3 = peg$FAILED;
57791
+ }
57434
57792
  if (s3 !== peg$FAILED) {
57435
- while (s3 !== peg$FAILED) {
57436
- s2.push(s3);
57437
- s3 = peg$parsed();
57793
+ s4 = peg$currPos;
57794
+ if (input.charCodeAt(peg$currPos) === 46) {
57795
+ s5 = peg$c23;
57796
+ peg$currPos++;
57438
57797
  }
57798
+ else {
57799
+ s5 = peg$FAILED;
57800
+ if (peg$silentFails === 0) {
57801
+ peg$fail(peg$e30);
57802
+ }
57803
+ }
57804
+ if (s5 !== peg$FAILED) {
57805
+ s6 = [];
57806
+ s7 = peg$parsed();
57807
+ if (s7 !== peg$FAILED) {
57808
+ while (s7 !== peg$FAILED) {
57809
+ s6.push(s7);
57810
+ s7 = peg$parsed();
57811
+ }
57812
+ }
57813
+ else {
57814
+ s6 = peg$FAILED;
57815
+ }
57816
+ if (s6 === peg$FAILED) {
57817
+ s6 = null;
57818
+ }
57819
+ s5 = [s5, s6];
57820
+ s4 = s5;
57821
+ }
57822
+ else {
57823
+ peg$currPos = s4;
57824
+ s4 = peg$FAILED;
57825
+ }
57826
+ if (s4 === peg$FAILED) {
57827
+ s4 = null;
57828
+ }
57829
+ s3 = [s3, s4];
57830
+ s2 = s3;
57439
57831
  }
57440
57832
  else {
57833
+ peg$currPos = s2;
57441
57834
  s2 = peg$FAILED;
57442
57835
  }
57443
57836
  if (s2 !== peg$FAILED) {
@@ -57452,18 +57845,18 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57452
57845
  s2 = null;
57453
57846
  }
57454
57847
  if (input.charCodeAt(peg$currPos) === 37) {
57455
- s3 = peg$c23;
57848
+ s3 = peg$c24;
57456
57849
  peg$currPos++;
57457
57850
  }
57458
57851
  else {
57459
57852
  s3 = peg$FAILED;
57460
57853
  if (peg$silentFails === 0) {
57461
- peg$fail(peg$e31);
57854
+ peg$fail(peg$e32);
57462
57855
  }
57463
57856
  }
57464
57857
  if (s3 !== peg$FAILED) {
57465
57858
  peg$savedPos = s0;
57466
- s0 = peg$f22(s1);
57859
+ s0 = peg$f23(s1);
57467
57860
  }
57468
57861
  else {
57469
57862
  peg$currPos = s0;
@@ -57478,7 +57871,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57478
57871
  if (s0 === peg$FAILED) {
57479
57872
  s1 = peg$FAILED;
57480
57873
  if (peg$silentFails === 0) {
57481
- peg$fail(peg$e30);
57874
+ peg$fail(peg$e31);
57482
57875
  }
57483
57876
  }
57484
57877
  return s0;
@@ -57528,7 +57921,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57528
57921
  if (s0 === peg$FAILED) {
57529
57922
  s1 = peg$FAILED;
57530
57923
  if (peg$silentFails === 0) {
57531
- peg$fail(peg$e32);
57924
+ peg$fail(peg$e33);
57532
57925
  }
57533
57926
  }
57534
57927
  return s0;
@@ -57541,13 +57934,13 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57541
57934
  s2 = peg$parseyear();
57542
57935
  if (s2 !== peg$FAILED) {
57543
57936
  if (input.charCodeAt(peg$currPos) === 45) {
57544
- s3 = peg$c19;
57937
+ s3 = peg$c20;
57545
57938
  peg$currPos++;
57546
57939
  }
57547
57940
  else {
57548
57941
  s3 = peg$FAILED;
57549
57942
  if (peg$silentFails === 0) {
57550
- peg$fail(peg$e34);
57943
+ peg$fail(peg$e35);
57551
57944
  }
57552
57945
  }
57553
57946
  if (s3 !== peg$FAILED) {
@@ -57587,7 +57980,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57587
57980
  if (s0 === peg$FAILED) {
57588
57981
  s1 = peg$FAILED;
57589
57982
  if (peg$silentFails === 0) {
57590
- peg$fail(peg$e33);
57983
+ peg$fail(peg$e34);
57591
57984
  }
57592
57985
  }
57593
57986
  return s0;
@@ -57623,7 +58016,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57623
58016
  if (s0 === peg$FAILED) {
57624
58017
  s1 = peg$FAILED;
57625
58018
  if (peg$silentFails === 0) {
57626
- peg$fail(peg$e35);
58019
+ peg$fail(peg$e36);
57627
58020
  }
57628
58021
  }
57629
58022
  return s0;
@@ -57635,13 +58028,13 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57635
58028
  s2 = peg$parsemonth();
57636
58029
  if (s2 !== peg$FAILED) {
57637
58030
  if (input.charCodeAt(peg$currPos) === 45) {
57638
- s3 = peg$c19;
58031
+ s3 = peg$c20;
57639
58032
  peg$currPos++;
57640
58033
  }
57641
58034
  else {
57642
58035
  s3 = peg$FAILED;
57643
58036
  if (peg$silentFails === 0) {
57644
- peg$fail(peg$e34);
58037
+ peg$fail(peg$e35);
57645
58038
  }
57646
58039
  }
57647
58040
  if (s3 !== peg$FAILED) {
@@ -57683,12 +58076,12 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57683
58076
  else {
57684
58077
  s1 = peg$FAILED;
57685
58078
  if (peg$silentFails === 0) {
57686
- peg$fail(peg$e37);
58079
+ peg$fail(peg$e38);
57687
58080
  }
57688
58081
  }
57689
58082
  if (s1 !== peg$FAILED) {
57690
58083
  peg$savedPos = peg$currPos;
57691
- s2 = peg$f23(s1);
58084
+ s2 = peg$f24(s1);
57692
58085
  if (s2) {
57693
58086
  s2 = undefined;
57694
58087
  }
@@ -57712,7 +58105,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57712
58105
  if (s0 === peg$FAILED) {
57713
58106
  s1 = peg$FAILED;
57714
58107
  if (peg$silentFails === 0) {
57715
- peg$fail(peg$e36);
58108
+ peg$fail(peg$e37);
57716
58109
  }
57717
58110
  }
57718
58111
  return s0;
@@ -57729,7 +58122,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57729
58122
  else {
57730
58123
  s2 = peg$FAILED;
57731
58124
  if (peg$silentFails === 0) {
57732
- peg$fail(peg$e39);
58125
+ peg$fail(peg$e40);
57733
58126
  }
57734
58127
  }
57735
58128
  if (s2 !== peg$FAILED) {
@@ -57742,7 +58135,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57742
58135
  else {
57743
58136
  s2 = peg$FAILED;
57744
58137
  if (peg$silentFails === 0) {
57745
- peg$fail(peg$e39);
58138
+ peg$fail(peg$e40);
57746
58139
  }
57747
58140
  }
57748
58141
  }
@@ -57760,7 +58153,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
57760
58153
  if (s0 === peg$FAILED) {
57761
58154
  s1 = peg$FAILED;
57762
58155
  if (peg$silentFails === 0) {
57763
- peg$fail(peg$e38);
58156
+ peg$fail(peg$e39);
57764
58157
  }
57765
58158
  }
57766
58159
  return s0;