@stephendolan/ynab-cli 1.0.4 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -202,9 +202,11 @@ Use the YNAB web or mobile app for these operations.
202
202
 
203
203
  ## API Rate Limits
204
204
 
205
- - 200 requests per hour per access token
206
- - Rolling window
207
- - Returns HTTP 429 when exceeded
205
+ The YNAB API enforces a rate limit of **200 requests per hour** per access token. When exceeded, the API returns HTTP 429 errors.
206
+
207
+ **If you hit the rate limit:**
208
+ - Wait 5-10 minutes before retrying (the limit uses a rolling 60-minute window)
209
+ - For batch operations, add delays between requests: `sleep 20` in shell loops ensures ~180 requests/hour
208
210
 
209
211
  ## References
210
212
 
package/dist/cli.js CHANGED
@@ -15,30 +15,24 @@ function isInteractive() {
15
15
  return process.stdin.isTTY === true;
16
16
  }
17
17
  function convertMilliunitsToAmounts(data) {
18
- if (data === null || data === void 0) {
19
- return data;
20
- }
21
- if (Array.isArray(data)) {
22
- return data.map((item) => convertMilliunitsToAmounts(item));
23
- }
24
- if (typeof data === "object") {
25
- const converted = {};
26
- for (const [key, value] of Object.entries(data)) {
27
- if (isAmountField(key) && typeof value === "number") {
28
- converted[key] = milliunitsToAmount(value);
29
- } else if (isDebtAmountMapField(key) && typeof value === "object" && value !== null && !Array.isArray(value)) {
30
- const convertedMap = {};
31
- for (const [dateKey, amountValue] of Object.entries(value)) {
32
- convertedMap[dateKey] = typeof amountValue === "number" ? milliunitsToAmount(amountValue) : amountValue;
33
- }
34
- converted[key] = convertedMap;
35
- } else {
36
- converted[key] = convertMilliunitsToAmounts(value);
18
+ if (data === null || data === void 0) return data;
19
+ if (Array.isArray(data)) return data.map(convertMilliunitsToAmounts);
20
+ if (typeof data !== "object") return data;
21
+ const converted = {};
22
+ for (const [key, value] of Object.entries(data)) {
23
+ if (isAmountField(key) && typeof value === "number") {
24
+ converted[key] = milliunitsToAmount(value);
25
+ } else if (isDebtAmountMapField(key) && typeof value === "object" && value !== null && !Array.isArray(value)) {
26
+ const convertedMap = {};
27
+ for (const [dateKey, amountValue] of Object.entries(value)) {
28
+ convertedMap[dateKey] = typeof amountValue === "number" ? milliunitsToAmount(amountValue) : amountValue;
37
29
  }
30
+ converted[key] = convertedMap;
31
+ } else {
32
+ converted[key] = convertMilliunitsToAmounts(value);
38
33
  }
39
- return converted;
40
34
  }
41
- return data;
35
+ return converted;
42
36
  }
43
37
  function isAmountField(fieldName) {
44
38
  const amountFields = [
@@ -133,9 +127,6 @@ function outputJson(data, options = {}) {
133
127
  const jsonString = mergedOptions.compact ? JSON.stringify(convertedData) : JSON.stringify(convertedData, null, 2);
134
128
  console.log(jsonString);
135
129
  }
136
- function outputSuccess(data, options = {}) {
137
- outputJson(data, options);
138
- }
139
130
 
140
131
  // src/commands/auth.ts
141
132
  import { Command } from "commander";
@@ -329,8 +320,14 @@ function sanitizeApiError(error) {
329
320
  id: apiError.id
330
321
  };
331
322
  }
323
+ function enhanceRateLimitMessage(detail) {
324
+ return `${detail}
325
+
326
+ YNAB API limit: 200 requests/hour (rolling window). Wait a few minutes and retry.`;
327
+ }
332
328
  function formatErrorResponse(name, detail, statusCode) {
333
- outputJson({ error: { name, detail, statusCode } });
329
+ const enhancedDetail = name === "too_many_requests" ? enhanceRateLimitMessage(detail) : detail;
330
+ outputJson({ error: { name, detail: enhancedDetail, statusCode } });
334
331
  process.exit(1);
335
332
  }
336
333
  function handleYnabError(error) {
@@ -359,7 +356,7 @@ import dotenv from "dotenv";
359
356
  dotenv.config();
360
357
  var YnabClient = class {
361
358
  api = null;
362
- hasShownEnvVarWarning = false;
359
+ envVarWarningShown = false;
363
360
  async getApi() {
364
361
  if (this.api) {
365
362
  return this.api;
@@ -372,11 +369,11 @@ var YnabClient = class {
372
369
  401
373
370
  );
374
371
  }
375
- if (!keychainToken && process.env.YNAB_API_KEY && !this.hasShownEnvVarWarning) {
372
+ if (!keychainToken && process.env.YNAB_API_KEY && !this.envVarWarningShown) {
376
373
  console.warn(
377
374
  "\x1B[33m\u26A0\uFE0F WARNING: Using YNAB_API_KEY environment variable.\nEnvironment variables may be visible to other processes.\nFor better security, use: ynab auth login\x1B[0m\n"
378
375
  );
379
- this.hasShownEnvVarWarning = true;
376
+ this.envVarWarningShown = true;
380
377
  }
381
378
  this.api = new ynab.API(accessToken);
382
379
  return this.api;
@@ -804,7 +801,7 @@ async function confirmDelete(itemType, skipConfirmation = false) {
804
801
  `Are you sure you want to delete this ${itemType}?`
805
802
  );
806
803
  if (!confirmed) {
807
- outputSuccess({ message: "Operation cancelled" });
804
+ outputJson({ message: "Operation cancelled" });
808
805
  return false;
809
806
  }
810
807
  return true;
@@ -828,7 +825,7 @@ function createAuthCommand() {
828
825
  await auth.setAccessToken(token);
829
826
  try {
830
827
  const user = await client.getUser();
831
- outputSuccess({
828
+ outputJson({
832
829
  message: "Successfully authenticated",
833
830
  user: { id: user?.id }
834
831
  });
@@ -845,14 +842,14 @@ function createAuthCommand() {
845
842
  }
846
843
  try {
847
844
  const user = await client.getUser();
848
- outputSuccess({ authenticated: true, user: { id: user?.id } });
845
+ outputJson({ authenticated: true, user: { id: user?.id } });
849
846
  } catch (error) {
850
847
  outputJson({ authenticated: false, message: "Token exists but is invalid" });
851
848
  }
852
849
  }));
853
850
  cmd.command("logout").description("Remove stored credentials").action(withErrorHandling(async () => {
854
851
  await auth.logout();
855
- outputSuccess({ message: "Successfully logged out" });
852
+ outputJson({ message: "Successfully logged out" });
856
853
  }));
857
854
  return cmd;
858
855
  }
@@ -863,7 +860,7 @@ function createUserCommand() {
863
860
  const cmd = new Command2("user").description("User information");
864
861
  cmd.command("info").description("Get authenticated user information").action(withErrorHandling(async () => {
865
862
  const user = await client.getUser();
866
- outputSuccess(user);
863
+ outputJson(user);
867
864
  }));
868
865
  return cmd;
869
866
  }
@@ -874,15 +871,15 @@ function createBudgetsCommand() {
874
871
  const cmd = new Command3("budgets").description("Budget operations");
875
872
  cmd.command("list").description("List all budgets").option("--include-accounts", "Include accounts in response").action(withErrorHandling(async (options) => {
876
873
  const result = await client.getBudgets(options.includeAccounts);
877
- outputSuccess(result?.budgets);
874
+ outputJson(result?.budgets);
878
875
  }));
879
876
  cmd.command("view").description("View budget details (uses default if no id provided)").argument("[id]", "Budget ID").action(withErrorHandling(async (id) => {
880
877
  const result = await client.getBudget(id);
881
- outputSuccess(result?.budget);
878
+ outputJson(result?.budget);
882
879
  }));
883
880
  cmd.command("settings").description("View budget settings").argument("[id]", "Budget ID").action(withErrorHandling(async (id) => {
884
881
  const settings = await client.getBudgetSettings(id);
885
- outputSuccess(settings);
882
+ outputJson(settings);
886
883
  }));
887
884
  cmd.command("set-default").description("Set default budget for commands").argument("<id>", "Budget ID").action(withErrorHandling(async (id) => {
888
885
  const result = await client.getBudgets();
@@ -891,7 +888,7 @@ function createBudgetsCommand() {
891
888
  throw new YnabCliError(`Budget with ID ${id} not found`, 404);
892
889
  }
893
890
  config.setDefaultBudget(id);
894
- outputSuccess({
891
+ outputJson({
895
892
  message: "Default budget set",
896
893
  budget: { id: budget.id, name: budget.name }
897
894
  });
@@ -905,11 +902,11 @@ function createAccountsCommand() {
905
902
  const cmd = new Command4("accounts").description("Account operations");
906
903
  cmd.command("list").description("List all accounts").option("-b, --budget <id>", "Budget ID").action(withErrorHandling(async (options) => {
907
904
  const result = await client.getAccounts(options.budget);
908
- outputSuccess(result?.accounts);
905
+ outputJson(result?.accounts);
909
906
  }));
910
907
  cmd.command("view").description("View account details").argument("<id>", "Account ID").option("-b, --budget <id>", "Budget ID").action(withErrorHandling(async (id, options) => {
911
908
  const account = await client.getAccount(id, options.budget);
912
- outputSuccess(account);
909
+ outputJson(account);
913
910
  }));
914
911
  cmd.command("transactions").description("List transactions for account").argument("<id>", "Account ID").option("-b, --budget <id>", "Budget ID").option("--since <date>", "Filter transactions since date (YYYY-MM-DD)").option("--type <type>", "Filter by transaction type").action(withErrorHandling(async (id, options) => {
915
912
  const result = await client.getTransactionsByAccount(id, {
@@ -917,7 +914,7 @@ function createAccountsCommand() {
917
914
  sinceDate: options.since,
918
915
  type: options.type
919
916
  });
920
- outputSuccess(result?.transactions);
917
+ outputJson(result?.transactions);
921
918
  }));
922
919
  return cmd;
923
920
  }
@@ -928,11 +925,11 @@ function createCategoriesCommand() {
928
925
  const cmd = new Command5("categories").description("Category operations");
929
926
  cmd.command("list").description("List all categories").option("-b, --budget <id>", "Budget ID").option("--last-knowledge <number>", "Last knowledge of server", parseInt).action(withErrorHandling(async (options) => {
930
927
  const result = await client.getCategories(options.budget, options.lastKnowledge);
931
- outputSuccess(result?.category_groups);
928
+ outputJson(result?.category_groups);
932
929
  }));
933
930
  cmd.command("view").description("View category details").argument("<id>", "Category ID").option("-b, --budget <id>", "Budget ID").action(withErrorHandling(async (id, options) => {
934
931
  const category = await client.getCategory(id, options.budget);
935
- outputSuccess(category);
932
+ outputJson(category);
936
933
  }));
937
934
  cmd.command("budget").description("Set category budgeted amount for a month (overrides existing amount)").argument("<id>", "Category ID").requiredOption("--month <month>", "Month in YYYY-MM-DD format (e.g., 2025-07-01)").requiredOption("--amount <amount>", "Total budgeted amount to set (e.g., 100.50)", parseFloat).option("-b, --budget <id>", "Budget ID").action(withErrorHandling(async (id, options) => {
938
935
  if (isNaN(options.amount)) {
@@ -945,7 +942,7 @@ function createCategoriesCommand() {
945
942
  { category: { budgeted: milliunits } },
946
943
  options.budget
947
944
  );
948
- outputSuccess(category);
945
+ outputJson(category);
949
946
  }));
950
947
  cmd.command("transactions").description("List transactions for category").argument("<id>", "Category ID").option("-b, --budget <id>", "Budget ID").option("--since <date>", "Filter transactions since date (YYYY-MM-DD)").option("--type <type>", "Filter by transaction type").option("--last-knowledge <number>", "Last knowledge of server", parseInt).action(withErrorHandling(async (id, options) => {
951
948
  const result = await client.getTransactionsByCategory(id, {
@@ -954,7 +951,7 @@ function createCategoriesCommand() {
954
951
  type: options.type,
955
952
  lastKnowledgeOfServer: options.lastKnowledge
956
953
  });
957
- outputSuccess(result?.transactions);
954
+ outputJson(result?.transactions);
958
955
  }));
959
956
  return cmd;
960
957
  }
@@ -1023,11 +1020,11 @@ function createTransactionsCommand() {
1023
1020
  maxAmount: options.maxAmount
1024
1021
  });
1025
1022
  const selected = applyFieldSelection(filtered, options.fields);
1026
- outputSuccess(selected);
1023
+ outputJson(selected);
1027
1024
  }));
1028
1025
  cmd.command("view").description("View single transaction").argument("<id>", "Transaction ID").option("-b, --budget <id>", "Budget ID").action(withErrorHandling(async (id, options) => {
1029
1026
  const transaction = await client.getTransaction(id, options.budget);
1030
- outputSuccess(transaction);
1027
+ outputJson(transaction);
1031
1028
  }));
1032
1029
  cmd.command("create").description("Create transaction").option("-b, --budget <id>", "Budget ID").option("--account <id>", "Account ID").option("--date <date>", "Date (YYYY-MM-DD)").option("--amount <amount>", "Amount in currency units (e.g., 10.50)", parseFloat).option("--payee-name <name>", "Payee name").option("--payee-id <id>", "Payee ID").option("--category-id <id>", "Category ID").option("--memo <memo>", "Memo").option("--cleared <status>", "Cleared status (cleared, uncleared, reconciled)").option("--approved", "Mark as approved").action(withErrorHandling(async (options) => {
1033
1030
  const shouldPrompt = isInteractive() && !options.account && !options.amount;
@@ -1036,7 +1033,7 @@ function createTransactionsCommand() {
1036
1033
  { transaction: transactionData },
1037
1034
  options.budget
1038
1035
  );
1039
- outputSuccess(transaction);
1036
+ outputJson(transaction);
1040
1037
  }));
1041
1038
  cmd.command("update").description("Update transaction").argument("<id>", "Transaction ID").option("-b, --budget <id>", "Budget ID").option("--account <id>", "Account ID").option("--date <date>", "Date (YYYY-MM-DD)").option("--amount <amount>", "Amount in currency units", parseFloat).option("--payee-name <name>", "Payee name").option("--payee-id <id>", "Payee ID").option("--category-id <id>", "Category ID").option("--memo <memo>", "Memo").option("--cleared <status>", "Cleared status").option("--approved", "Mark as approved").action(withErrorHandling(async (id, options) => {
1042
1039
  const transactionData = buildUpdateObject(options, {
@@ -1057,20 +1054,20 @@ function createTransactionsCommand() {
1057
1054
  { transaction: transactionData },
1058
1055
  options.budget
1059
1056
  );
1060
- outputSuccess(transaction);
1057
+ outputJson(transaction);
1061
1058
  }));
1062
1059
  cmd.command("delete").description("Delete transaction").argument("<id>", "Transaction ID").option("-b, --budget <id>", "Budget ID").option("-y, --yes", "Skip confirmation").action(withErrorHandling(async (id, options) => {
1063
1060
  if (!await confirmDelete("transaction", options.yes)) {
1064
1061
  return;
1065
1062
  }
1066
1063
  const transaction = await client.deleteTransaction(id, options.budget);
1067
- outputSuccess({ message: "Transaction deleted", transaction });
1064
+ outputJson({ message: "Transaction deleted", transaction });
1068
1065
  }));
1069
1066
  cmd.command("import").description("Import transactions").option("-b, --budget <id>", "Budget ID").action(withErrorHandling(async (options) => {
1070
1067
  const transactionIds = await client.importTransactions(options.budget);
1071
- outputSuccess({ transaction_ids: transactionIds });
1068
+ outputJson({ transaction_ids: transactionIds });
1072
1069
  }));
1073
- cmd.command("split").description("Split transaction into multiple categories").argument("<id>", "Transaction ID").requiredOption("--splits <json>", 'JSON array of splits: [{"amount": -21400, "category_id": "xxx", "memo": "..."}]').option("-b, --budget <id>", "Budget ID").action(withErrorHandling(async (id, options) => {
1070
+ cmd.command("split").description("Split transaction into multiple categories. Amounts should be in dollars (e.g., 10.50).").argument("<id>", "Transaction ID").requiredOption("--splits <json>", 'JSON array of splits with dollar amounts: [{"amount": -21.40, "category_id": "xxx", "memo": "..."}]').option("-b, --budget <id>", "Budget ID").option("-f, --force", "Force update of already-split transactions by deleting and recreating").action(withErrorHandling(async (id, options) => {
1074
1071
  let parsedSplits;
1075
1072
  try {
1076
1073
  parsedSplits = JSON.parse(options.splits);
@@ -1078,17 +1075,53 @@ function createTransactionsCommand() {
1078
1075
  throw new YnabCliError("Invalid JSON in --splits parameter", 400);
1079
1076
  }
1080
1077
  const splits = validateJson(parsedSplits, TransactionSplitSchema, "transaction splits");
1081
- const transaction = await client.updateTransaction(
1082
- id,
1083
- {
1084
- transaction: {
1085
- category_id: null,
1086
- subtransactions: splits
1087
- }
1088
- },
1089
- options.budget
1090
- );
1091
- outputSuccess(transaction);
1078
+ const splitsInMilliunits = splits.map((split) => ({
1079
+ ...split,
1080
+ amount: amountToMilliunits(split.amount)
1081
+ }));
1082
+ const existingTransaction = await client.getTransaction(id, options.budget);
1083
+ const isAlreadySplit = existingTransaction.subtransactions && existingTransaction.subtransactions.length > 0;
1084
+ if (isAlreadySplit && !options.force) {
1085
+ throw new YnabCliError(
1086
+ "Transaction is already split. YNAB API does not support updating split transactions. Use --force to delete and recreate the transaction with new splits.",
1087
+ 400
1088
+ );
1089
+ }
1090
+ if (isAlreadySplit && options.force) {
1091
+ await client.deleteTransaction(id, options.budget);
1092
+ const recreatedTransaction = await client.createTransaction(
1093
+ {
1094
+ transaction: {
1095
+ account_id: existingTransaction.account_id,
1096
+ date: existingTransaction.date,
1097
+ amount: existingTransaction.amount,
1098
+ payee_id: existingTransaction.payee_id,
1099
+ payee_name: existingTransaction.payee_name,
1100
+ category_id: null,
1101
+ memo: existingTransaction.memo,
1102
+ cleared: existingTransaction.cleared,
1103
+ approved: existingTransaction.approved,
1104
+ flag_color: existingTransaction.flag_color,
1105
+ import_id: existingTransaction.import_id,
1106
+ subtransactions: splitsInMilliunits
1107
+ }
1108
+ },
1109
+ options.budget
1110
+ );
1111
+ outputJson(recreatedTransaction);
1112
+ } else {
1113
+ const transaction = await client.updateTransaction(
1114
+ id,
1115
+ {
1116
+ transaction: {
1117
+ category_id: null,
1118
+ subtransactions: splitsInMilliunits
1119
+ }
1120
+ },
1121
+ options.budget
1122
+ );
1123
+ outputJson(transaction);
1124
+ }
1092
1125
  }));
1093
1126
  cmd.command("search").description("Search transactions").option("-b, --budget <id>", "Budget ID").option("--memo <text>", "Search in memo field").option("--payee-name <name>", "Search in payee name").option("--amount <amount>", "Search for exact amount in currency units", parseFloat).option("--since <date>", "Search transactions since date (YYYY-MM-DD)").option("--until <date>", "Search transactions until date (YYYY-MM-DD)").option("--approved <value>", "Filter by approval status: true or false").option("--status <statuses>", "Filter by cleared status: cleared, uncleared, reconciled (comma-separated)").option("--fields <fields>", "Comma-separated list of fields to include").action(withErrorHandling(async (options) => {
1094
1127
  if (!options.memo && !options.payeeName && options.amount === void 0) {
@@ -1122,7 +1155,7 @@ function createTransactionsCommand() {
1122
1155
  status: options.status
1123
1156
  });
1124
1157
  const filteredTransactions = applyFieldSelection(transactions, options.fields);
1125
- outputSuccess(filteredTransactions);
1158
+ outputJson(filteredTransactions);
1126
1159
  }));
1127
1160
  return cmd;
1128
1161
  }
@@ -1133,18 +1166,18 @@ function createScheduledCommand() {
1133
1166
  const cmd = new Command7("scheduled").description("Scheduled transaction operations");
1134
1167
  cmd.command("list").description("List all scheduled transactions").option("-b, --budget <id>", "Budget ID").option("--last-knowledge <number>", "Last knowledge of server", parseInt).action(withErrorHandling(async (options) => {
1135
1168
  const result = await client.getScheduledTransactions(options.budget, options.lastKnowledge);
1136
- outputSuccess(result?.scheduled_transactions);
1169
+ outputJson(result?.scheduled_transactions);
1137
1170
  }));
1138
1171
  cmd.command("view").description("View scheduled transaction").argument("<id>", "Scheduled transaction ID").option("-b, --budget <id>", "Budget ID").action(withErrorHandling(async (id, options) => {
1139
1172
  const scheduledTransaction = await client.getScheduledTransaction(id, options.budget);
1140
- outputSuccess(scheduledTransaction);
1173
+ outputJson(scheduledTransaction);
1141
1174
  }));
1142
1175
  cmd.command("delete").description("Delete scheduled transaction").argument("<id>", "Scheduled transaction ID").option("-b, --budget <id>", "Budget ID").option("-y, --yes", "Skip confirmation").action(withErrorHandling(async (id, options) => {
1143
1176
  if (!await confirmDelete("scheduled transaction", options.yes)) {
1144
1177
  return;
1145
1178
  }
1146
1179
  const scheduledTransaction = await client.deleteScheduledTransaction(id, options.budget);
1147
- outputSuccess({
1180
+ outputJson({
1148
1181
  message: "Scheduled transaction deleted",
1149
1182
  scheduled_transaction: scheduledTransaction
1150
1183
  });
@@ -1158,11 +1191,11 @@ function createPayeesCommand() {
1158
1191
  const cmd = new Command8("payees").description("Payee operations");
1159
1192
  cmd.command("list").description("List all payees").option("-b, --budget <id>", "Budget ID").option("--last-knowledge <number>", "Last knowledge of server", parseInt).action(withErrorHandling(async (options) => {
1160
1193
  const result = await client.getPayees(options.budget, options.lastKnowledge);
1161
- outputSuccess(result?.payees);
1194
+ outputJson(result?.payees);
1162
1195
  }));
1163
1196
  cmd.command("view").description("View payee details").argument("<id>", "Payee ID").option("-b, --budget <id>", "Budget ID").action(withErrorHandling(async (id, options) => {
1164
1197
  const payee = await client.getPayee(id, options.budget);
1165
- outputSuccess(payee);
1198
+ outputJson(payee);
1166
1199
  }));
1167
1200
  cmd.command("update").description("Rename payee").argument("<id>", "Payee ID").requiredOption("--name <name>", "New payee name").option("-b, --budget <id>", "Budget ID").action(withErrorHandling(async (id, options) => {
1168
1201
  if (!options.name?.trim()) {
@@ -1173,11 +1206,11 @@ function createPayeesCommand() {
1173
1206
  { payee: { name: options.name } },
1174
1207
  options.budget
1175
1208
  );
1176
- outputSuccess(payee);
1209
+ outputJson(payee);
1177
1210
  }));
1178
1211
  cmd.command("locations").description("List locations for payee").argument("<id>", "Payee ID").option("-b, --budget <id>", "Budget ID").action(withErrorHandling(async (id, options) => {
1179
1212
  const locations = await client.getPayeeLocationsByPayee(id, options.budget);
1180
- outputSuccess(locations);
1213
+ outputJson(locations);
1181
1214
  }));
1182
1215
  cmd.command("transactions").description("List transactions for payee").argument("<id>", "Payee ID").option("-b, --budget <id>", "Budget ID").option("--since <date>", "Filter transactions since date (YYYY-MM-DD)").option("--type <type>", "Filter by transaction type").option("--last-knowledge <number>", "Last knowledge of server", parseInt).action(withErrorHandling(async (id, options) => {
1183
1216
  const result = await client.getTransactionsByPayee(id, {
@@ -1186,7 +1219,7 @@ function createPayeesCommand() {
1186
1219
  type: options.type,
1187
1220
  lastKnowledgeOfServer: options.lastKnowledge
1188
1221
  });
1189
- outputSuccess(result?.transactions);
1222
+ outputJson(result?.transactions);
1190
1223
  }));
1191
1224
  return cmd;
1192
1225
  }
@@ -1197,11 +1230,11 @@ function createMonthsCommand() {
1197
1230
  const cmd = new Command9("months").description("Monthly budget operations");
1198
1231
  cmd.command("list").description("List all budget months").option("-b, --budget <id>", "Budget ID").option("--last-knowledge <number>", "Last knowledge of server", parseInt).action(withErrorHandling(async (options) => {
1199
1232
  const result = await client.getBudgetMonths(options.budget, options.lastKnowledge);
1200
- outputSuccess(result?.months);
1233
+ outputJson(result?.months);
1201
1234
  }));
1202
1235
  cmd.command("view").description("View specific month details").argument("<month>", "Month in YYYY-MM-DD format (e.g., 2025-07-01)").option("-b, --budget <id>", "Budget ID").action(withErrorHandling(async (month, options) => {
1203
1236
  const monthData = await client.getBudgetMonth(month, options.budget);
1204
- outputSuccess(monthData);
1237
+ outputJson(monthData);
1205
1238
  }));
1206
1239
  return cmd;
1207
1240
  }
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/lib/utils.ts","../src/lib/output.ts","../src/commands/auth.ts","../src/lib/config.ts","../src/lib/auth.ts","../src/lib/prompts.ts","../src/lib/api-client.ts","../src/lib/errors.ts","../src/lib/command-utils.ts","../src/commands/user.ts","../src/commands/budgets.ts","../src/commands/accounts.ts","../src/commands/categories.ts","../src/commands/transactions.ts","../src/lib/schemas.ts","../src/commands/scheduled.ts","../src/commands/payees.ts","../src/commands/months.ts","../src/commands/api.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport { setOutputOptions } from './lib/output.js';\nimport { createAuthCommand } from './commands/auth.js';\nimport { createUserCommand } from './commands/user.js';\nimport { createBudgetsCommand } from './commands/budgets.js';\nimport { createAccountsCommand } from './commands/accounts.js';\nimport { createCategoriesCommand } from './commands/categories.js';\nimport { createTransactionsCommand } from './commands/transactions.js';\nimport { createScheduledCommand } from './commands/scheduled.js';\nimport { createPayeesCommand } from './commands/payees.js';\nimport { createMonthsCommand } from './commands/months.js';\nimport { createApiCommand } from './commands/api.js';\n\nconst program = new Command();\n\nprogram\n .name('ynab')\n .description('A command-line interface for You Need a Budget (YNAB)')\n .version('1.0.0')\n .option('-c, --compact', 'Minified JSON output (single line)')\n .hook('preAction', (thisCommand) => {\n const options = thisCommand.opts();\n setOutputOptions({\n compact: options.compact,\n });\n });\n\nprogram.addCommand(createAuthCommand());\nprogram.addCommand(createUserCommand());\nprogram.addCommand(createBudgetsCommand());\nprogram.addCommand(createAccountsCommand());\nprogram.addCommand(createCategoriesCommand());\nprogram.addCommand(createTransactionsCommand());\nprogram.addCommand(createScheduledCommand());\nprogram.addCommand(createPayeesCommand());\nprogram.addCommand(createMonthsCommand());\nprogram.addCommand(createApiCommand());\n\nprogram.parse();\n","import { format, parseISO } from 'date-fns';\n\nexport function milliunitsToAmount(milliunits: number): number {\n return milliunits / 1000;\n}\n\nexport function amountToMilliunits(amount: number): number {\n return Math.round(amount * 1000);\n}\n\nexport function formatCurrency(milliunits: number, currencySymbol = '$'): string {\n const amount = milliunitsToAmount(milliunits);\n return `${currencySymbol}${amount.toFixed(2)}`;\n}\n\nexport function formatDate(isoDate: string, formatString = 'yyyy-MM-dd'): string {\n return format(parseISO(isoDate), formatString);\n}\n\nexport function parseDate(dateString: string): string {\n const date = parseISO(dateString);\n return format(date, 'yyyy-MM-dd');\n}\n\nexport function isInteractive(): boolean {\n return process.stdin.isTTY === true;\n}\n\nexport function convertMilliunitsToAmounts(data: unknown): unknown {\n if (data === null || data === undefined) {\n return data;\n }\n\n if (Array.isArray(data)) {\n return data.map(item => convertMilliunitsToAmounts(item));\n }\n\n if (typeof data === 'object') {\n const converted: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n if (isAmountField(key) && typeof value === 'number') {\n converted[key] = milliunitsToAmount(value);\n } else if (isDebtAmountMapField(key) && typeof value === 'object' && value !== null && !Array.isArray(value)) {\n const convertedMap: Record<string, unknown> = {};\n for (const [dateKey, amountValue] of Object.entries(value)) {\n convertedMap[dateKey] = typeof amountValue === 'number' ? milliunitsToAmount(amountValue) : amountValue;\n }\n converted[key] = convertedMap;\n } else {\n converted[key] = convertMilliunitsToAmounts(value);\n }\n }\n return converted;\n }\n\n return data;\n}\n\nfunction isAmountField(fieldName: string): boolean {\n const amountFields = [\n 'amount',\n 'balance',\n 'cleared_balance',\n 'uncleared_balance',\n 'budgeted',\n 'activity',\n 'available',\n 'goal_target',\n 'goal_under_funded',\n 'goal_overall_funded',\n 'goal_overall_left',\n 'income',\n 'to_be_budgeted',\n 'debt_original_balance',\n ];\n\n return amountFields.includes(fieldName) || fieldName.endsWith('_amount');\n}\n\nfunction isDebtAmountMapField(fieldName: string): boolean {\n const debtAmountMapFields = [\n 'debt_minimum_payments',\n 'debt_escrow_amounts',\n 'debt_interest_rates',\n ];\n\n return debtAmountMapFields.includes(fieldName);\n}\n\nexport function parseApprovedFilter(value: string): boolean {\n const normalized = value.toLowerCase();\n if (normalized !== 'true' && normalized !== 'false') {\n throw new Error(`--approved must be 'true' or 'false', got '${value}'`);\n }\n return normalized === 'true';\n}\n\nexport function parseStatusFilter(value: string): string[] {\n const statuses = value.split(',').map(s => s.trim().toLowerCase());\n const validStatuses = ['cleared', 'uncleared', 'reconciled'];\n\n for (const status of statuses) {\n if (!validStatuses.includes(status)) {\n throw new Error(`Invalid status '${status}'. Must be one of: ${validStatuses.join(', ')}`);\n }\n }\n\n return statuses;\n}\n\nexport type TransactionLike = {\n date: string;\n amount: number;\n approved: boolean;\n cleared: string;\n};\n\nexport function applyTransactionFilters<T extends TransactionLike>(transactions: T[], filters: {\n until?: string;\n approved?: string;\n status?: string;\n minAmount?: number;\n maxAmount?: number;\n}): T[] {\n let filtered = transactions;\n\n if (filters.until) {\n filtered = filtered.filter(t => t.date <= filters.until!);\n }\n\n if (filters.approved !== undefined) {\n const approvedValue = parseApprovedFilter(filters.approved);\n filtered = filtered.filter(t => t.approved === approvedValue);\n }\n\n if (filters.status) {\n const statuses = parseStatusFilter(filters.status);\n filtered = filtered.filter(t => statuses.includes(t.cleared.toLowerCase()));\n }\n\n if (filters.minAmount !== undefined) {\n const minMilliunits = amountToMilliunits(filters.minAmount);\n filtered = filtered.filter(t => t.amount >= minMilliunits);\n }\n\n if (filters.maxAmount !== undefined) {\n const maxMilliunits = amountToMilliunits(filters.maxAmount);\n filtered = filtered.filter(t => t.amount <= maxMilliunits);\n }\n\n return filtered;\n}\n\nexport function applyFieldSelection<T>(items: T[], fields?: string): Partial<T>[] {\n if (!fields) return items;\n\n const fieldList = fields.split(',').map(f => f.trim());\n return items.map(item => {\n const filtered: Partial<T> = {};\n const itemRecord = item as Record<string, unknown>;\n fieldList.forEach(field => {\n if (field in itemRecord) {\n (filtered as Record<string, unknown>)[field] = itemRecord[field];\n }\n });\n return filtered;\n });\n}\n","import type { OutputOptions } from '../types/index.js';\nimport { convertMilliunitsToAmounts } from './utils.js';\n\nlet globalOutputOptions: OutputOptions = {};\n\nexport function setOutputOptions(options: OutputOptions): void {\n globalOutputOptions = options;\n}\n\nexport function outputJson(data: unknown, options: OutputOptions = {}): void {\n const convertedData = convertMilliunitsToAmounts(data);\n\n const mergedOptions = { ...globalOutputOptions, ...options };\n const jsonString = mergedOptions.compact\n ? JSON.stringify(convertedData)\n : JSON.stringify(convertedData, null, 2);\n\n console.log(jsonString);\n}\n\nexport function outputSuccess(data: unknown, options: OutputOptions = {}): void {\n outputJson(data, options);\n}\n","import { Command } from 'commander';\nimport { auth } from '../lib/auth.js';\nimport { promptForAccessToken } from '../lib/prompts.js';\nimport { outputJson, outputSuccess } from '../lib/output.js';\nimport { client } from '../lib/api-client.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\n\nexport function createAuthCommand(): Command {\n const cmd = new Command('auth').description('Authentication management');\n\n cmd\n .command('login')\n .description('Configure access token')\n .action(withErrorHandling(async () => {\n const token = await promptForAccessToken();\n await auth.setAccessToken(token);\n\n try {\n const user = await client.getUser();\n outputSuccess({\n message: 'Successfully authenticated',\n user: { id: user?.id },\n });\n } catch (error) {\n await auth.deleteAccessToken();\n throw error;\n }\n }));\n\n cmd\n .command('status')\n .description('Check authentication status')\n .action(withErrorHandling(async () => {\n const isAuthenticated = await auth.isAuthenticated();\n\n if (!isAuthenticated) {\n outputJson({ authenticated: false, message: 'Not authenticated' });\n return;\n }\n\n try {\n const user = await client.getUser();\n outputSuccess({ authenticated: true, user: { id: user?.id } });\n } catch (error) {\n outputJson({ authenticated: false, message: 'Token exists but is invalid' });\n }\n }));\n\n cmd\n .command('logout')\n .description('Remove stored credentials')\n .action(withErrorHandling(async () => {\n await auth.logout();\n outputSuccess({ message: 'Successfully logged out' });\n }));\n\n return cmd;\n}\n","import Conf from 'conf';\nimport type { Config } from '../types/index.js';\n\nclass ConfigManager {\n private conf: Conf<Config>;\n\n constructor() {\n this.conf = new Conf<Config>({\n projectName: 'ynab-cli',\n schema: {\n defaultBudget: { type: 'string' },\n version: { type: 'string', default: '1.0.0' },\n },\n defaults: { version: '1.0.0' },\n });\n }\n\n getDefaultBudget(): string | undefined {\n return this.conf.get('defaultBudget');\n }\n\n setDefaultBudget(budgetId: string): void {\n this.conf.set('defaultBudget', budgetId);\n }\n\n clearDefaultBudget(): void {\n this.conf.delete('defaultBudget');\n }\n\n clear(): void {\n this.conf.clear();\n }\n}\n\nexport const config = new ConfigManager();\n","import { config } from './config.js';\n\nconst SERVICE_NAME = 'ynab-cli';\nconst ACCOUNT_NAME = 'access-token';\n\nconst KEYTAR_UNAVAILABLE_ERROR =\n 'Keychain storage unavailable. Cannot store credentials securely.\\n' +\n 'On Linux, install libsecret: sudo apt-get install libsecret-1-dev\\n' +\n 'Then reinstall: npm install -g @stephendolan/ynab-cli\\n' +\n 'Alternatively, use the YNAB_API_KEY environment variable.';\n\nlet keytar: typeof import('keytar') | undefined;\n\ntry {\n keytar = await import('keytar');\n} catch (error) {\n if (process.env.NODE_ENV !== 'test') {\n console.error(\n 'Warning: Keychain storage unavailable. Credentials will not be stored securely.\\n' +\n 'On Linux, install libsecret: sudo apt-get install libsecret-1-dev\\n' +\n 'Falling back to environment variable only (YNAB_API_KEY).\\n'\n );\n }\n}\n\nexport class AuthManager {\n async getAccessToken(): Promise<string | null> {\n if (keytar) {\n return keytar.getPassword(SERVICE_NAME, ACCOUNT_NAME);\n }\n return null;\n }\n\n async setAccessToken(token: string): Promise<void> {\n if (keytar) {\n await keytar.setPassword(SERVICE_NAME, ACCOUNT_NAME, token);\n } else {\n throw new Error(KEYTAR_UNAVAILABLE_ERROR);\n }\n }\n\n async deleteAccessToken(): Promise<boolean> {\n if (keytar) {\n return keytar.deletePassword(SERVICE_NAME, ACCOUNT_NAME);\n }\n return false;\n }\n\n async isAuthenticated(): Promise<boolean> {\n return (await this.getAccessToken()) !== null;\n }\n\n async logout(): Promise<void> {\n await this.deleteAccessToken();\n config.clearDefaultBudget();\n }\n}\n\nexport const auth = new AuthManager();\n","import inquirer from 'inquirer';\nimport { amountToMilliunits } from './utils.js';\n\nexport async function promptForAccessToken(): Promise<string> {\n const { token } = await inquirer.prompt([\n {\n type: 'password',\n name: 'token',\n message: 'Enter your YNAB Personal Access Token:',\n validate: (input: string) => !!input.trim() || 'Access token is required',\n },\n ]);\n return token;\n}\n\nexport async function promptForBudget(\n budgets: Array<{ id: string; name: string }>,\n): Promise<string> {\n const { budgetId } = await inquirer.prompt([\n {\n type: 'list',\n name: 'budgetId',\n message: 'Select a budget:',\n choices: budgets.map((b) => ({ name: b.name, value: b.id })),\n },\n ]);\n return budgetId;\n}\n\nexport async function promptForConfirmation(message: string): Promise<boolean> {\n const { confirmed } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'confirmed',\n message,\n default: false,\n },\n ]);\n return confirmed;\n}\n\nexport async function promptForTransaction(): Promise<Record<string, unknown>> {\n const answers = await inquirer.prompt([\n {\n type: 'input',\n name: 'date',\n message: 'Date (YYYY-MM-DD):',\n default: new Date().toISOString().split('T')[0],\n },\n {\n type: 'input',\n name: 'amount',\n message: 'Amount (in currency units, e.g., 10.50):',\n validate: (input: string) => !isNaN(parseFloat(input)) || 'Amount must be a valid number',\n },\n {\n type: 'input',\n name: 'payee_name',\n message: 'Payee name (optional):',\n },\n {\n type: 'input',\n name: 'memo',\n message: 'Memo (optional):',\n },\n ]);\n\n return {\n date: answers.date,\n amount: amountToMilliunits(parseFloat(answers.amount)),\n payee_name: answers.payee_name || undefined,\n memo: answers.memo || undefined,\n };\n}\n","import * as ynab from 'ynab';\nimport { config } from './config.js';\nimport { YnabCliError, handleYnabError, sanitizeApiError } from './errors.js';\nimport { auth } from './auth.js';\nimport dotenv from 'dotenv';\n\ndotenv.config();\n\ntype TransactionTypeFilter = 'uncategorized' | 'unapproved' | undefined;\n\nexport class YnabClient {\n private api: ynab.API | null = null;\n private hasShownEnvVarWarning = false;\n\n async getApi(): Promise<ynab.API> {\n if (this.api) {\n return this.api;\n }\n\n const keychainToken = await auth.getAccessToken();\n const accessToken = keychainToken || process.env.YNAB_API_KEY || null;\n\n if (!accessToken) {\n throw new YnabCliError(\n 'Not authenticated. Please run: ynab auth login or set YNAB_API_KEY environment variable',\n 401,\n );\n }\n\n if (!keychainToken && process.env.YNAB_API_KEY && !this.hasShownEnvVarWarning) {\n console.warn(\n '\\x1b[33m⚠️ WARNING: Using YNAB_API_KEY environment variable.\\n' +\n 'Environment variables may be visible to other processes.\\n' +\n 'For better security, use: ynab auth login\\x1b[0m\\n'\n );\n this.hasShownEnvVarWarning = true;\n }\n\n this.api = new ynab.API(accessToken);\n return this.api;\n }\n\n async getBudgetId(budgetIdOrDefault?: string): Promise<string> {\n const budgetId =\n budgetIdOrDefault || config.getDefaultBudget() || process.env.YNAB_BUDGET_ID;\n\n if (!budgetId) {\n throw new YnabCliError(\n 'No budget specified. Use --budget flag, set default with \"ynab budgets set-default\", or set YNAB_BUDGET_ID environment variable',\n 400,\n );\n }\n\n return budgetId;\n }\n\n private async withErrorHandling<T>(fn: () => Promise<T>): Promise<T> {\n try {\n return await fn();\n } catch (error) {\n handleYnabError(error);\n }\n }\n\n async getUser() {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const response = await api.user.getUser();\n return response.data.user;\n });\n }\n\n async getBudgets(includeAccounts = false) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const response = await api.budgets.getBudgets(includeAccounts);\n return {\n budgets: response.data.budgets,\n server_knowledge: 0,\n };\n });\n }\n\n async getBudget(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.budgets.getBudgetById(id, lastKnowledgeOfServer);\n return {\n budget: response.data.budget,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getBudgetSettings(budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.budgets.getBudgetSettingsById(id);\n return response.data.settings;\n });\n }\n\n async getAccounts(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.accounts.getAccounts(id, lastKnowledgeOfServer);\n return {\n accounts: response.data.accounts,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getAccount(accountId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.accounts.getAccountById(id, accountId);\n return response.data.account;\n });\n }\n\n async createAccount(accountData: ynab.PostAccountWrapper, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.accounts.createAccount(id, accountData);\n return response.data.account;\n });\n }\n\n async getCategories(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.categories.getCategories(id, lastKnowledgeOfServer);\n return {\n category_groups: response.data.category_groups,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getCategory(categoryId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.categories.getCategoryById(id, categoryId);\n return response.data.category;\n });\n }\n\n async updateCategory(\n categoryId: string,\n data: ynab.PatchCategoryWrapper,\n budgetId?: string,\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.categories.updateCategory(id, categoryId, data);\n return response.data.category;\n });\n }\n\n async getMonthCategory(month: string, categoryId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.categories.getMonthCategoryById(id, month, categoryId);\n return response.data.category;\n });\n }\n\n async updateMonthCategory(\n month: string,\n categoryId: string,\n data: ynab.PatchMonthCategoryWrapper,\n budgetId?: string,\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.categories.updateMonthCategory(id, month, categoryId, data);\n return response.data.category;\n });\n }\n\n async getPayees(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.payees.getPayees(id, lastKnowledgeOfServer);\n return {\n payees: response.data.payees,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getPayee(payeeId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.payees.getPayeeById(id, payeeId);\n return response.data.payee;\n });\n }\n\n async updatePayee(payeeId: string, data: ynab.PatchPayeeWrapper, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.payees.updatePayee(id, payeeId, data);\n return response.data.payee;\n });\n }\n\n async getPayeeLocations(budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.payeeLocations.getPayeeLocations(id);\n return response.data.payee_locations;\n });\n }\n\n async getPayeeLocation(payeeLocationId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.payeeLocations.getPayeeLocationById(id, payeeLocationId);\n return response.data.payee_location;\n });\n }\n\n async getPayeeLocationsByPayee(payeeId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.payeeLocations.getPayeeLocationsByPayee(id, payeeId);\n return response.data.payee_locations;\n });\n }\n\n async getBudgetMonths(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.months.getBudgetMonths(id, lastKnowledgeOfServer);\n return {\n months: response.data.months,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getBudgetMonth(month: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.months.getBudgetMonth(id, month);\n return response.data.month;\n });\n }\n\n async getTransactions(params: {\n budgetId?: string;\n sinceDate?: string;\n type?: string;\n lastKnowledgeOfServer?: number;\n }) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(params.budgetId);\n const response = await api.transactions.getTransactions(\n id,\n params.sinceDate,\n params.type as TransactionTypeFilter,\n params.lastKnowledgeOfServer,\n );\n return {\n transactions: response.data.transactions,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getTransactionsByAccount(accountId: string, params: {\n budgetId?: string;\n sinceDate?: string;\n type?: string;\n lastKnowledgeOfServer?: number;\n }) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(params.budgetId);\n const response = await api.transactions.getTransactionsByAccount(\n id,\n accountId,\n params.sinceDate,\n params.type as TransactionTypeFilter,\n params.lastKnowledgeOfServer,\n );\n return {\n transactions: response.data.transactions,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getTransactionsByCategory(categoryId: string, params: {\n budgetId?: string;\n sinceDate?: string;\n type?: string;\n lastKnowledgeOfServer?: number;\n }) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(params.budgetId);\n const response = await api.transactions.getTransactionsByCategory(\n id,\n categoryId,\n params.sinceDate,\n params.type as TransactionTypeFilter,\n params.lastKnowledgeOfServer,\n );\n return {\n transactions: response.data.transactions,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getTransactionsByPayee(payeeId: string, params: {\n budgetId?: string;\n sinceDate?: string;\n type?: string;\n lastKnowledgeOfServer?: number;\n }) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(params.budgetId);\n const response = await api.transactions.getTransactionsByPayee(\n id,\n payeeId,\n params.sinceDate,\n params.type as TransactionTypeFilter,\n params.lastKnowledgeOfServer,\n );\n return {\n transactions: response.data.transactions,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getTransaction(transactionId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.getTransactionById(id, transactionId);\n return response.data.transaction;\n });\n }\n\n async createTransaction(\n transactionData: ynab.PutTransactionWrapper,\n budgetId?: string,\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.createTransaction(id, transactionData);\n return response.data.transaction;\n });\n }\n\n async createTransactions(\n transactionsData: ynab.PostTransactionsWrapper,\n budgetId?: string,\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.createTransactions(id, transactionsData);\n return response.data;\n });\n }\n\n async updateTransaction(\n transactionId: string,\n transactionData: ynab.PutTransactionWrapper,\n budgetId?: string,\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.updateTransaction(\n id,\n transactionId,\n transactionData,\n );\n return response.data.transaction;\n });\n }\n\n async updateTransactions(\n transactionsData: ynab.PatchTransactionsWrapper,\n budgetId?: string,\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.updateTransactions(id, transactionsData);\n return response.data;\n });\n }\n\n async deleteTransaction(transactionId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.deleteTransaction(id, transactionId);\n return response.data.transaction;\n });\n }\n\n async importTransactions(budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.importTransactions(id);\n return response.data.transaction_ids;\n });\n }\n\n async getScheduledTransactions(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.scheduledTransactions.getScheduledTransactions(\n id,\n lastKnowledgeOfServer,\n );\n return {\n scheduled_transactions: response.data.scheduled_transactions,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getScheduledTransaction(scheduledTransactionId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.scheduledTransactions.getScheduledTransactionById(\n id,\n scheduledTransactionId,\n );\n return response.data.scheduled_transaction;\n });\n }\n\n async createScheduledTransaction(\n data: ynab.PostScheduledTransactionWrapper,\n budgetId?: string,\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.scheduledTransactions.createScheduledTransaction(id, data);\n return response.data.scheduled_transaction;\n });\n }\n\n async updateScheduledTransaction(\n scheduledTransactionId: string,\n data: ynab.PutScheduledTransactionWrapper,\n budgetId?: string,\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.scheduledTransactions.updateScheduledTransaction(\n id,\n scheduledTransactionId,\n data,\n );\n return response.data.scheduled_transaction;\n });\n }\n\n async deleteScheduledTransaction(scheduledTransactionId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.scheduledTransactions.deleteScheduledTransaction(\n id,\n scheduledTransactionId,\n );\n return response.data.scheduled_transaction;\n });\n }\n\n async rawApiCall(method: string, path: string, data?: unknown, budgetId?: string) {\n return this.withErrorHandling(async () => {\n await this.getApi();\n\n const fullPath = path.includes('{budget_id}')\n ? path.replace('{budget_id}', await this.getBudgetId(budgetId))\n : path;\n\n const url = `https://api.ynab.com/v1${fullPath}`;\n const headers = {\n Authorization: `Bearer ${await auth.getAccessToken()}`,\n 'Content-Type': 'application/json',\n };\n\n const httpMethod = method.toUpperCase();\n const hasBody = ['POST', 'PUT', 'PATCH'].includes(httpMethod);\n\n if (!['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(httpMethod)) {\n throw new YnabCliError(`Unsupported HTTP method: ${method}`, 400);\n }\n\n const response = await fetch(url, {\n method: httpMethod,\n headers,\n ...(hasBody && { body: JSON.stringify(data) }),\n });\n\n if (!response.ok) {\n const errorData = await response.json() as Record<string, unknown>;\n throw { error: sanitizeApiError(errorData.error || errorData) };\n }\n\n return await response.json();\n });\n }\n}\n\nexport const client = new YnabClient();\n","import type { YnabError } from '../types/index.js';\nimport { outputJson } from './output.js';\n\nexport class YnabCliError extends Error {\n constructor(\n message: string,\n public statusCode?: number,\n ) {\n super(message);\n this.name = 'YnabCliError';\n }\n}\n\nconst ERROR_STATUS_CODES: Record<string, number> = {\n bad_request: 400,\n not_authorized: 401,\n subscription_lapsed: 403,\n trial_expired: 403,\n unauthorized_scope: 403,\n data_limit_reached: 403,\n not_found: 404,\n resource_not_found: 404,\n conflict: 409,\n too_many_requests: 429,\n internal_server_error: 500,\n service_unavailable: 503,\n};\n\nexport function sanitizeErrorMessage(message: string): string {\n const sensitivePatterns = [\n /Bearer\\s+[\\w\\-._~+/]+=*/gi,\n /token[=:]\\s*[\\w\\-._~+/]+=*/gi,\n /api[_-]?key[=:]\\s*[\\w\\-._~+/]+=*/gi,\n /authorization:\\s*bearer\\s+[\\w\\-._~+/]+=*/gi,\n ];\n\n let sanitized = message;\n for (const pattern of sensitivePatterns) {\n sanitized = sanitized.replace(pattern, '[REDACTED]');\n }\n\n return sanitized.length > 500 ? sanitized.substring(0, 500) + '...' : sanitized;\n}\n\ninterface YnabApiError {\n name?: string;\n detail?: string;\n message?: string;\n id?: string;\n}\n\nfunction isErrorObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nexport function sanitizeApiError(error: unknown): YnabError {\n if (!isErrorObject(error)) {\n return {\n name: 'api_error',\n detail: 'An error occurred',\n id: undefined,\n };\n }\n\n const apiError = error as YnabApiError;\n const detail = sanitizeErrorMessage(\n String(apiError.detail || apiError.message || 'An error occurred')\n );\n\n return {\n name: apiError.name || 'api_error',\n detail,\n id: apiError.id,\n };\n}\n\nfunction formatErrorResponse(name: string, detail: string, statusCode: number): never {\n outputJson({ error: { name, detail, statusCode } });\n process.exit(1);\n}\n\nexport function handleYnabError(error: unknown): never {\n if (!isErrorObject(error)) {\n formatErrorResponse('unknown_error', 'An unexpected error occurred', 1);\n }\n\n const errorObj = error as { error?: unknown; message?: string };\n\n if (errorObj.error) {\n const ynabError: YnabError = sanitizeApiError(errorObj.error);\n formatErrorResponse(\n ynabError.name,\n ynabError.detail,\n ERROR_STATUS_CODES[ynabError.name] || 500,\n );\n }\n\n if (error instanceof YnabCliError) {\n const sanitized = sanitizeErrorMessage(error.message);\n formatErrorResponse('cli_error', sanitized, error.statusCode || 1);\n }\n\n const sanitized = sanitizeErrorMessage(errorObj.message || 'An unexpected error occurred');\n formatErrorResponse('unknown_error', sanitized, 1);\n}\n","import { handleYnabError } from './errors.js';\nimport { promptForConfirmation } from './prompts.js';\nimport { isInteractive } from './utils.js';\nimport { outputSuccess } from './output.js';\n\nexport function withErrorHandling<TArgs extends unknown[], R>(\n fn: (...args: TArgs) => Promise<R>,\n): (...args: TArgs) => Promise<void> {\n return async (...args: TArgs) => {\n try {\n await fn(...args);\n } catch (error) {\n handleYnabError(error);\n }\n };\n}\n\nexport async function confirmDelete(\n itemType: string,\n skipConfirmation: boolean = false,\n): Promise<boolean> {\n if (skipConfirmation || !isInteractive()) {\n return true;\n }\n\n const confirmed = await promptForConfirmation(\n `Are you sure you want to delete this ${itemType}?`,\n );\n\n if (!confirmed) {\n outputSuccess({ message: 'Operation cancelled' });\n return false;\n }\n\n return true;\n}\n\nexport function buildUpdateObject<T>(\n options: T,\n mapping: Record<string, string>,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const optionsRecord = options as Record<string, unknown>;\n\n for (const [optionKey, targetKey] of Object.entries(mapping)) {\n if (optionsRecord[optionKey] !== undefined) {\n result[targetKey] = optionsRecord[optionKey];\n }\n }\n\n return result;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputSuccess } from '../lib/output.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\n\nexport function createUserCommand(): Command {\n const cmd = new Command('user').description('User information');\n\n cmd\n .command('info')\n .description('Get authenticated user information')\n .action(withErrorHandling(async () => {\n const user = await client.getUser();\n outputSuccess(user);\n }));\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { config } from '../lib/config.js';\nimport { outputSuccess } from '../lib/output.js';\nimport { YnabCliError } from '../lib/errors.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\n\nexport function createBudgetsCommand(): Command {\n const cmd = new Command('budgets').description('Budget operations');\n\n cmd\n .command('list')\n .description('List all budgets')\n .option('--include-accounts', 'Include accounts in response')\n .action(withErrorHandling(async (options: { includeAccounts?: boolean }) => {\n const result = await client.getBudgets(options.includeAccounts);\n outputSuccess(result?.budgets);\n }));\n\n cmd\n .command('view')\n .description('View budget details (uses default if no id provided)')\n .argument('[id]', 'Budget ID')\n .action(withErrorHandling(async (id: string | undefined) => {\n const result = await client.getBudget(id);\n outputSuccess(result?.budget);\n }));\n\n cmd\n .command('settings')\n .description('View budget settings')\n .argument('[id]', 'Budget ID')\n .action(withErrorHandling(async (id: string | undefined) => {\n const settings = await client.getBudgetSettings(id);\n outputSuccess(settings);\n }));\n\n cmd\n .command('set-default')\n .description('Set default budget for commands')\n .argument('<id>', 'Budget ID')\n .action(withErrorHandling(async (id: string) => {\n const result = await client.getBudgets();\n const budget = result?.budgets.find((b) => b.id === id);\n\n if (!budget) {\n throw new YnabCliError(`Budget with ID ${id} not found`, 404);\n }\n\n config.setDefaultBudget(id);\n outputSuccess({\n message: 'Default budget set',\n budget: { id: budget.id, name: budget.name },\n });\n }));\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputSuccess } from '../lib/output.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\nimport type { CommandOptions } from '../types/index.js';\n\nexport function createAccountsCommand(): Command {\n const cmd = new Command('accounts').description('Account operations');\n\n cmd\n .command('list')\n .description('List all accounts')\n .option('-b, --budget <id>', 'Budget ID')\n .action(withErrorHandling(async (options: CommandOptions) => {\n const result = await client.getAccounts(options.budget);\n outputSuccess(result?.accounts);\n }));\n\n cmd\n .command('view')\n .description('View account details')\n .argument('<id>', 'Account ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(withErrorHandling(async (id: string, options: CommandOptions) => {\n const account = await client.getAccount(id, options.budget);\n outputSuccess(account);\n }));\n\n cmd\n .command('transactions')\n .description('List transactions for account')\n .argument('<id>', 'Account ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--since <date>', 'Filter transactions since date (YYYY-MM-DD)')\n .option('--type <type>', 'Filter by transaction type')\n .action(withErrorHandling(async (\n id: string,\n options: {\n budget?: string;\n since?: string;\n type?: string;\n } & CommandOptions,\n ) => {\n const result = await client.getTransactionsByAccount(id, {\n budgetId: options.budget,\n sinceDate: options.since,\n type: options.type,\n });\n outputSuccess(result?.transactions);\n }));\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputSuccess } from '../lib/output.js';\nimport { YnabCliError } from '../lib/errors.js';\nimport { amountToMilliunits } from '../lib/utils.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\nimport type { CommandOptions } from '../types/index.js';\n\nexport function createCategoriesCommand(): Command {\n const cmd = new Command('categories').description('Category operations');\n\n cmd\n .command('list')\n .description('List all categories')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(withErrorHandling(async (options: { budget?: string; lastKnowledge?: number } & CommandOptions) => {\n const result = await client.getCategories(options.budget, options.lastKnowledge);\n outputSuccess(result?.category_groups);\n }));\n\n cmd\n .command('view')\n .description('View category details')\n .argument('<id>', 'Category ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(withErrorHandling(async (id: string, options: CommandOptions) => {\n const category = await client.getCategory(id, options.budget);\n outputSuccess(category);\n }));\n\n cmd\n .command('budget')\n .description('Set category budgeted amount for a month (overrides existing amount)')\n .argument('<id>', 'Category ID')\n .requiredOption('--month <month>', 'Month in YYYY-MM-DD format (e.g., 2025-07-01)')\n .requiredOption('--amount <amount>', 'Total budgeted amount to set (e.g., 100.50)', parseFloat)\n .option('-b, --budget <id>', 'Budget ID')\n .action(withErrorHandling(async (\n id: string,\n options: {\n month: string;\n amount: number;\n budget?: string;\n } & CommandOptions,\n ) => {\n if (isNaN(options.amount)) {\n throw new YnabCliError('Amount must be a valid number', 400);\n }\n\n const milliunits = amountToMilliunits(options.amount);\n const category = await client.updateMonthCategory(\n options.month,\n id,\n { category: { budgeted: milliunits } },\n options.budget,\n );\n outputSuccess(category);\n }));\n\n cmd\n .command('transactions')\n .description('List transactions for category')\n .argument('<id>', 'Category ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--since <date>', 'Filter transactions since date (YYYY-MM-DD)')\n .option('--type <type>', 'Filter by transaction type')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(withErrorHandling(async (\n id: string,\n options: {\n budget?: string;\n since?: string;\n type?: string;\n lastKnowledge?: number;\n } & CommandOptions,\n ) => {\n const result = await client.getTransactionsByCategory(id, {\n budgetId: options.budget,\n sinceDate: options.since,\n type: options.type,\n lastKnowledgeOfServer: options.lastKnowledge,\n });\n outputSuccess(result?.transactions);\n }));\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputSuccess } from '../lib/output.js';\nimport { YnabCliError } from '../lib/errors.js';\nimport { promptForTransaction } from '../lib/prompts.js';\nimport { isInteractive, amountToMilliunits, applyTransactionFilters, applyFieldSelection, type TransactionLike } from '../lib/utils.js';\nimport { withErrorHandling, confirmDelete, buildUpdateObject } from '../lib/command-utils.js';\nimport { validateJson, TransactionSplitSchema } from '../lib/schemas.js';\nimport type { CommandOptions } from '../types/index.js';\n\ninterface TransactionOptions {\n account?: string;\n date?: string;\n amount?: number;\n payeeName?: string;\n payeeId?: string;\n categoryId?: string;\n memo?: string;\n cleared?: string;\n approved?: boolean;\n}\n\nfunction buildTransactionData(options: TransactionOptions): Record<string, unknown> {\n if (!options.account) {\n throw new YnabCliError('--account is required in non-interactive mode', 400);\n }\n if (options.amount === undefined) {\n throw new YnabCliError('--amount is required in non-interactive mode', 400);\n }\n\n return {\n account_id: options.account,\n date: options.date || new Date().toISOString().split('T')[0],\n amount: amountToMilliunits(options.amount),\n payee_name: options.payeeName,\n payee_id: options.payeeId,\n category_id: options.categoryId,\n memo: options.memo,\n cleared: options.cleared,\n approved: options.approved,\n };\n}\n\nexport function createTransactionsCommand(): Command {\n const cmd = new Command('transactions').description('Transaction operations');\n\n cmd\n .command('list')\n .description('List transactions')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--account <id>', 'Filter by account ID')\n .option('--category <id>', 'Filter by category ID')\n .option('--payee <id>', 'Filter by payee ID')\n .option('--since <date>', 'Filter transactions since date (YYYY-MM-DD)')\n .option('--until <date>', 'Filter transactions until date (YYYY-MM-DD)')\n .option('--type <type>', 'Filter by transaction type')\n .option('--approved <value>', 'Filter by approval status: true or false')\n .option('--status <statuses>', 'Filter by cleared status: cleared, uncleared, reconciled (comma-separated for multiple)')\n .option('--min-amount <amount>', 'Minimum amount in currency units (e.g., 10.50)', parseFloat)\n .option('--max-amount <amount>', 'Maximum amount in currency units (e.g., 100.00)', parseFloat)\n .option('--fields <fields>', 'Comma-separated list of fields to include (e.g., id,date,amount,memo)')\n .action(withErrorHandling(async (options: {\n budget?: string;\n account?: string;\n category?: string;\n payee?: string;\n since?: string;\n until?: string;\n type?: string;\n approved?: string;\n status?: string;\n minAmount?: number;\n maxAmount?: number;\n fields?: string;\n } & CommandOptions) => {\n const params = {\n budgetId: options.budget,\n sinceDate: options.since,\n type: options.type,\n };\n\n const result = options.account\n ? await client.getTransactionsByAccount(options.account, params)\n : options.category\n ? await client.getTransactionsByCategory(options.category, params)\n : options.payee\n ? await client.getTransactionsByPayee(options.payee, params)\n : await client.getTransactions(params);\n\n const transactions = result?.transactions || [];\n\n const filtered = applyTransactionFilters(transactions as TransactionLike[], {\n until: options.until,\n approved: options.approved,\n status: options.status,\n minAmount: options.minAmount,\n maxAmount: options.maxAmount,\n });\n\n const selected = applyFieldSelection(filtered, options.fields);\n\n outputSuccess(selected);\n }));\n\n cmd\n .command('view')\n .description('View single transaction')\n .argument('<id>', 'Transaction ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(withErrorHandling(async (id: string, options: CommandOptions) => {\n const transaction = await client.getTransaction(id, options.budget);\n outputSuccess(transaction);\n }));\n\n cmd\n .command('create')\n .description('Create transaction')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--account <id>', 'Account ID')\n .option('--date <date>', 'Date (YYYY-MM-DD)')\n .option('--amount <amount>', 'Amount in currency units (e.g., 10.50)', parseFloat)\n .option('--payee-name <name>', 'Payee name')\n .option('--payee-id <id>', 'Payee ID')\n .option('--category-id <id>', 'Category ID')\n .option('--memo <memo>', 'Memo')\n .option('--cleared <status>', 'Cleared status (cleared, uncleared, reconciled)')\n .option('--approved', 'Mark as approved')\n .action(withErrorHandling(async (options: {\n budget?: string;\n account?: string;\n date?: string;\n amount?: number;\n payeeName?: string;\n payeeId?: string;\n categoryId?: string;\n memo?: string;\n cleared?: string;\n approved?: boolean;\n } & CommandOptions) => {\n const shouldPrompt = isInteractive() && !options.account && !options.amount;\n const transactionData = shouldPrompt\n ? await promptForTransaction()\n : buildTransactionData(options);\n\n const transaction = await client.createTransaction(\n { transaction: transactionData },\n options.budget,\n );\n outputSuccess(transaction);\n }));\n\n cmd\n .command('update')\n .description('Update transaction')\n .argument('<id>', 'Transaction ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--account <id>', 'Account ID')\n .option('--date <date>', 'Date (YYYY-MM-DD)')\n .option('--amount <amount>', 'Amount in currency units', parseFloat)\n .option('--payee-name <name>', 'Payee name')\n .option('--payee-id <id>', 'Payee ID')\n .option('--category-id <id>', 'Category ID')\n .option('--memo <memo>', 'Memo')\n .option('--cleared <status>', 'Cleared status')\n .option('--approved', 'Mark as approved')\n .action(withErrorHandling(async (\n id: string,\n options: TransactionOptions & { budget?: string } & CommandOptions,\n ) => {\n const transactionData = buildUpdateObject(options, {\n account: 'account_id',\n date: 'date',\n payeeName: 'payee_name',\n payeeId: 'payee_id',\n categoryId: 'category_id',\n memo: 'memo',\n cleared: 'cleared',\n approved: 'approved',\n });\n\n if (options.amount !== undefined) {\n transactionData.amount = amountToMilliunits(options.amount);\n }\n\n const transaction = await client.updateTransaction(\n id,\n { transaction: transactionData },\n options.budget,\n );\n outputSuccess(transaction);\n }));\n\n cmd\n .command('delete')\n .description('Delete transaction')\n .argument('<id>', 'Transaction ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('-y, --yes', 'Skip confirmation')\n .action(withErrorHandling(async (id: string, options: { budget?: string; yes?: boolean } & CommandOptions) => {\n if (!await confirmDelete('transaction', options.yes)) {\n return;\n }\n\n const transaction = await client.deleteTransaction(id, options.budget);\n outputSuccess({ message: 'Transaction deleted', transaction });\n }));\n\n cmd\n .command('import')\n .description('Import transactions')\n .option('-b, --budget <id>', 'Budget ID')\n .action(withErrorHandling(async (options: CommandOptions) => {\n const transactionIds = await client.importTransactions(options.budget);\n outputSuccess({ transaction_ids: transactionIds });\n }));\n\n cmd\n .command('split')\n .description('Split transaction into multiple categories')\n .argument('<id>', 'Transaction ID')\n .requiredOption('--splits <json>', 'JSON array of splits: [{\"amount\": -21400, \"category_id\": \"xxx\", \"memo\": \"...\"}]')\n .option('-b, --budget <id>', 'Budget ID')\n .action(withErrorHandling(async (\n id: string,\n options: { splits: string; budget?: string } & CommandOptions,\n ) => {\n let parsedSplits;\n try {\n parsedSplits = JSON.parse(options.splits);\n } catch (error) {\n throw new YnabCliError('Invalid JSON in --splits parameter', 400);\n }\n\n const splits = validateJson(parsedSplits, TransactionSplitSchema, 'transaction splits');\n\n const transaction = await client.updateTransaction(\n id,\n {\n transaction: {\n category_id: null,\n subtransactions: splits,\n },\n },\n options.budget,\n );\n outputSuccess(transaction);\n }));\n\n cmd\n .command('search')\n .description('Search transactions')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--memo <text>', 'Search in memo field')\n .option('--payee-name <name>', 'Search in payee name')\n .option('--amount <amount>', 'Search for exact amount in currency units', parseFloat)\n .option('--since <date>', 'Search transactions since date (YYYY-MM-DD)')\n .option('--until <date>', 'Search transactions until date (YYYY-MM-DD)')\n .option('--approved <value>', 'Filter by approval status: true or false')\n .option('--status <statuses>', 'Filter by cleared status: cleared, uncleared, reconciled (comma-separated)')\n .option('--fields <fields>', 'Comma-separated list of fields to include')\n .action(withErrorHandling(async (options: {\n budget?: string;\n memo?: string;\n payeeName?: string;\n amount?: number;\n since?: string;\n until?: string;\n approved?: string;\n status?: string;\n fields?: string;\n } & CommandOptions) => {\n if (!options.memo && !options.payeeName && options.amount === undefined) {\n throw new YnabCliError('At least one search criteria required: --memo, --payee-name, or --amount', 400);\n }\n\n const params = {\n budgetId: options.budget,\n sinceDate: options.since,\n };\n\n const result = await client.getTransactions(params);\n let transactions = result?.transactions || [];\n\n if (options.memo) {\n const searchTerm = options.memo.toLowerCase();\n transactions = transactions.filter(t =>\n t.memo?.toLowerCase().includes(searchTerm)\n );\n }\n\n if (options.payeeName) {\n const searchTerm = options.payeeName.toLowerCase();\n transactions = transactions.filter(t =>\n t.payee_name?.toLowerCase().includes(searchTerm)\n );\n }\n\n if (options.amount !== undefined) {\n const amountMilliunits = amountToMilliunits(options.amount);\n transactions = transactions.filter(t => t.amount === amountMilliunits);\n }\n\n transactions = applyTransactionFilters(transactions, {\n until: options.until,\n approved: options.approved,\n status: options.status,\n });\n\n const filteredTransactions = applyFieldSelection(transactions, options.fields);\n\n outputSuccess(filteredTransactions);\n }));\n\n return cmd;\n}\n","import { z } from 'zod';\nimport { YnabCliError } from './errors.js';\n\nexport const TransactionSplitSchema = z.array(\n z.object({\n amount: z.number(),\n category_id: z.string().nullable().optional(),\n memo: z.string().optional(),\n payee_id: z.string().optional(),\n })\n);\n\nexport const ApiDataSchema = z.record(z.any());\n\nexport function validateJson<T>(\n data: unknown,\n schema: z.ZodSchema<T>,\n fieldName: string\n): T {\n try {\n return schema.parse(data);\n } catch (error) {\n if (error instanceof z.ZodError) {\n const issues = error.issues\n .map(i => `${i.path.join('.')}: ${i.message}`)\n .join(', ');\n throw new YnabCliError(`Invalid ${fieldName}: ${issues}`, 400);\n }\n throw error;\n }\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputSuccess } from '../lib/output.js';\nimport { withErrorHandling, confirmDelete } from '../lib/command-utils.js';\nimport type { CommandOptions } from '../types/index.js';\n\nexport function createScheduledCommand(): Command {\n const cmd = new Command('scheduled').description('Scheduled transaction operations');\n\n cmd\n .command('list')\n .description('List all scheduled transactions')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(withErrorHandling(async (options: { budget?: string; lastKnowledge?: number } & CommandOptions) => {\n const result = await client.getScheduledTransactions(options.budget, options.lastKnowledge);\n outputSuccess(result?.scheduled_transactions);\n }));\n\n cmd\n .command('view')\n .description('View scheduled transaction')\n .argument('<id>', 'Scheduled transaction ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(withErrorHandling(async (id: string, options: CommandOptions) => {\n const scheduledTransaction = await client.getScheduledTransaction(id, options.budget);\n outputSuccess(scheduledTransaction);\n }));\n\n cmd\n .command('delete')\n .description('Delete scheduled transaction')\n .argument('<id>', 'Scheduled transaction ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('-y, --yes', 'Skip confirmation')\n .action(withErrorHandling(async (id: string, options: { budget?: string; yes?: boolean } & CommandOptions) => {\n if (!await confirmDelete('scheduled transaction', options.yes)) {\n return;\n }\n\n const scheduledTransaction = await client.deleteScheduledTransaction(id, options.budget);\n outputSuccess({\n message: 'Scheduled transaction deleted',\n scheduled_transaction: scheduledTransaction,\n });\n }));\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputSuccess } from '../lib/output.js';\nimport { YnabCliError } from '../lib/errors.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\nimport type { CommandOptions } from '../types/index.js';\n\nexport function createPayeesCommand(): Command {\n const cmd = new Command('payees').description('Payee operations');\n\n cmd\n .command('list')\n .description('List all payees')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(withErrorHandling(async (options: { budget?: string; lastKnowledge?: number } & CommandOptions) => {\n const result = await client.getPayees(options.budget, options.lastKnowledge);\n outputSuccess(result?.payees);\n }));\n\n cmd\n .command('view')\n .description('View payee details')\n .argument('<id>', 'Payee ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(withErrorHandling(async (id: string, options: CommandOptions) => {\n const payee = await client.getPayee(id, options.budget);\n outputSuccess(payee);\n }));\n\n cmd\n .command('update')\n .description('Rename payee')\n .argument('<id>', 'Payee ID')\n .requiredOption('--name <name>', 'New payee name')\n .option('-b, --budget <id>', 'Budget ID')\n .action(withErrorHandling(async (id: string, options: { name: string; budget?: string } & CommandOptions) => {\n if (!options.name?.trim()) {\n throw new YnabCliError('Name cannot be empty', 400);\n }\n\n const payee = await client.updatePayee(\n id,\n { payee: { name: options.name } },\n options.budget,\n );\n outputSuccess(payee);\n }));\n\n cmd\n .command('locations')\n .description('List locations for payee')\n .argument('<id>', 'Payee ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(withErrorHandling(async (id: string, options: CommandOptions) => {\n const locations = await client.getPayeeLocationsByPayee(id, options.budget);\n outputSuccess(locations);\n }));\n\n cmd\n .command('transactions')\n .description('List transactions for payee')\n .argument('<id>', 'Payee ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--since <date>', 'Filter transactions since date (YYYY-MM-DD)')\n .option('--type <type>', 'Filter by transaction type')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(withErrorHandling(async (\n id: string,\n options: {\n budget?: string;\n since?: string;\n type?: string;\n lastKnowledge?: number;\n } & CommandOptions,\n ) => {\n const result = await client.getTransactionsByPayee(id, {\n budgetId: options.budget,\n sinceDate: options.since,\n type: options.type,\n lastKnowledgeOfServer: options.lastKnowledge,\n });\n outputSuccess(result?.transactions);\n }));\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputSuccess } from '../lib/output.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\nimport type { CommandOptions } from '../types/index.js';\n\nexport function createMonthsCommand(): Command {\n const cmd = new Command('months').description('Monthly budget operations');\n\n cmd\n .command('list')\n .description('List all budget months')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(withErrorHandling(async (options: { budget?: string; lastKnowledge?: number } & CommandOptions) => {\n const result = await client.getBudgetMonths(options.budget, options.lastKnowledge);\n outputSuccess(result?.months);\n }));\n\n cmd\n .command('view')\n .description('View specific month details')\n .argument('<month>', 'Month in YYYY-MM-DD format (e.g., 2025-07-01)')\n .option('-b, --budget <id>', 'Budget ID')\n .action(withErrorHandling(async (month: string, options: CommandOptions) => {\n const monthData = await client.getBudgetMonth(month, options.budget);\n outputSuccess(monthData);\n }));\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { YnabCliError } from '../lib/errors.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\nimport { validateJson, ApiDataSchema } from '../lib/schemas.js';\nimport type { CommandOptions } from '../types/index.js';\n\nconst VALID_HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];\n\nexport function createApiCommand(): Command {\n const cmd = new Command('api').description('Raw API access');\n\n cmd\n .argument('<method>', 'HTTP method (GET, POST, PUT, PATCH, DELETE)')\n .argument('<path>', 'API path (e.g., /budgets or /budgets/{budget_id}/transactions)')\n .option('-b, --budget <id>', 'Budget ID (used to replace {budget_id} in path)')\n .option('--data <json>', 'JSON data for POST/PUT/PATCH requests')\n .description('Make raw API calls to YNAB')\n .action(withErrorHandling(async (\n method: string,\n path: string,\n options: { budget?: string; data?: string } & CommandOptions,\n ) => {\n const upperMethod = method.toUpperCase();\n\n if (!VALID_HTTP_METHODS.includes(upperMethod)) {\n throw new YnabCliError(\n `Invalid HTTP method: ${method}. Must be one of: ${VALID_HTTP_METHODS.join(', ')}`,\n 400,\n );\n }\n\n let data: Record<string, unknown> | undefined;\n if (options.data) {\n try {\n const parsedData = JSON.parse(options.data);\n data = validateJson(parsedData, ApiDataSchema, 'API data');\n } catch (error) {\n throw new YnabCliError('Invalid JSON in --data parameter', 400);\n }\n }\n\n const result = await client.rawApiCall(upperMethod, path, data, options.budget);\n outputJson(result);\n }));\n\n return cmd;\n}\n"],"mappings":"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","names":["Command","sanitized","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/lib/utils.ts","../src/lib/output.ts","../src/commands/auth.ts","../src/lib/config.ts","../src/lib/auth.ts","../src/lib/prompts.ts","../src/lib/api-client.ts","../src/lib/errors.ts","../src/lib/command-utils.ts","../src/commands/user.ts","../src/commands/budgets.ts","../src/commands/accounts.ts","../src/commands/categories.ts","../src/commands/transactions.ts","../src/lib/schemas.ts","../src/commands/scheduled.ts","../src/commands/payees.ts","../src/commands/months.ts","../src/commands/api.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport { setOutputOptions } from './lib/output.js';\nimport { createAuthCommand } from './commands/auth.js';\nimport { createUserCommand } from './commands/user.js';\nimport { createBudgetsCommand } from './commands/budgets.js';\nimport { createAccountsCommand } from './commands/accounts.js';\nimport { createCategoriesCommand } from './commands/categories.js';\nimport { createTransactionsCommand } from './commands/transactions.js';\nimport { createScheduledCommand } from './commands/scheduled.js';\nimport { createPayeesCommand } from './commands/payees.js';\nimport { createMonthsCommand } from './commands/months.js';\nimport { createApiCommand } from './commands/api.js';\n\nconst program = new Command();\n\nprogram\n .name('ynab')\n .description('A command-line interface for You Need a Budget (YNAB)')\n .version('1.0.0')\n .option('-c, --compact', 'Minified JSON output (single line)')\n .hook('preAction', (thisCommand) => {\n const options = thisCommand.opts();\n setOutputOptions({\n compact: options.compact,\n });\n });\n\nprogram.addCommand(createAuthCommand());\nprogram.addCommand(createUserCommand());\nprogram.addCommand(createBudgetsCommand());\nprogram.addCommand(createAccountsCommand());\nprogram.addCommand(createCategoriesCommand());\nprogram.addCommand(createTransactionsCommand());\nprogram.addCommand(createScheduledCommand());\nprogram.addCommand(createPayeesCommand());\nprogram.addCommand(createMonthsCommand());\nprogram.addCommand(createApiCommand());\n\nprogram.parse();\n","import { format, parseISO } from 'date-fns';\n\nexport function milliunitsToAmount(milliunits: number): number {\n return milliunits / 1000;\n}\n\nexport function amountToMilliunits(amount: number): number {\n return Math.round(amount * 1000);\n}\n\nexport function formatCurrency(milliunits: number, currencySymbol = '$'): string {\n const amount = milliunitsToAmount(milliunits);\n return `${currencySymbol}${amount.toFixed(2)}`;\n}\n\nexport function formatDate(isoDate: string, formatString = 'yyyy-MM-dd'): string {\n return format(parseISO(isoDate), formatString);\n}\n\nexport function parseDate(dateString: string): string {\n const date = parseISO(dateString);\n return format(date, 'yyyy-MM-dd');\n}\n\nexport function isInteractive(): boolean {\n return process.stdin.isTTY === true;\n}\n\nexport function convertMilliunitsToAmounts(data: unknown): unknown {\n if (data === null || data === undefined) return data;\n if (Array.isArray(data)) return data.map(convertMilliunitsToAmounts);\n if (typeof data !== 'object') return data;\n\n const converted: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n if (isAmountField(key) && typeof value === 'number') {\n converted[key] = milliunitsToAmount(value);\n } else if (isDebtAmountMapField(key) && typeof value === 'object' && value !== null && !Array.isArray(value)) {\n const convertedMap: Record<string, unknown> = {};\n for (const [dateKey, amountValue] of Object.entries(value)) {\n convertedMap[dateKey] = typeof amountValue === 'number' ? milliunitsToAmount(amountValue) : amountValue;\n }\n converted[key] = convertedMap;\n } else {\n converted[key] = convertMilliunitsToAmounts(value);\n }\n }\n return converted;\n}\n\nfunction isAmountField(fieldName: string): boolean {\n const amountFields = [\n 'amount',\n 'balance',\n 'cleared_balance',\n 'uncleared_balance',\n 'budgeted',\n 'activity',\n 'available',\n 'goal_target',\n 'goal_under_funded',\n 'goal_overall_funded',\n 'goal_overall_left',\n 'income',\n 'to_be_budgeted',\n 'debt_original_balance',\n ];\n\n return amountFields.includes(fieldName) || fieldName.endsWith('_amount');\n}\n\nfunction isDebtAmountMapField(fieldName: string): boolean {\n const debtAmountMapFields = [\n 'debt_minimum_payments',\n 'debt_escrow_amounts',\n 'debt_interest_rates',\n ];\n\n return debtAmountMapFields.includes(fieldName);\n}\n\nexport function parseApprovedFilter(value: string): boolean {\n const normalized = value.toLowerCase();\n if (normalized !== 'true' && normalized !== 'false') {\n throw new Error(`--approved must be 'true' or 'false', got '${value}'`);\n }\n return normalized === 'true';\n}\n\nexport function parseStatusFilter(value: string): string[] {\n const statuses = value.split(',').map(s => s.trim().toLowerCase());\n const validStatuses = ['cleared', 'uncleared', 'reconciled'];\n\n for (const status of statuses) {\n if (!validStatuses.includes(status)) {\n throw new Error(`Invalid status '${status}'. Must be one of: ${validStatuses.join(', ')}`);\n }\n }\n\n return statuses;\n}\n\nexport type TransactionLike = {\n date: string;\n amount: number;\n approved: boolean;\n cleared: string;\n};\n\nexport function applyTransactionFilters<T extends TransactionLike>(transactions: T[], filters: {\n until?: string;\n approved?: string;\n status?: string;\n minAmount?: number;\n maxAmount?: number;\n}): T[] {\n let filtered = transactions;\n\n if (filters.until) {\n filtered = filtered.filter(t => t.date <= filters.until!);\n }\n\n if (filters.approved !== undefined) {\n const approvedValue = parseApprovedFilter(filters.approved);\n filtered = filtered.filter(t => t.approved === approvedValue);\n }\n\n if (filters.status) {\n const statuses = parseStatusFilter(filters.status);\n filtered = filtered.filter(t => statuses.includes(t.cleared.toLowerCase()));\n }\n\n if (filters.minAmount !== undefined) {\n const minMilliunits = amountToMilliunits(filters.minAmount);\n filtered = filtered.filter(t => t.amount >= minMilliunits);\n }\n\n if (filters.maxAmount !== undefined) {\n const maxMilliunits = amountToMilliunits(filters.maxAmount);\n filtered = filtered.filter(t => t.amount <= maxMilliunits);\n }\n\n return filtered;\n}\n\nexport function applyFieldSelection<T>(items: T[], fields?: string): Partial<T>[] {\n if (!fields) return items;\n\n const fieldList = fields.split(',').map(f => f.trim());\n return items.map(item => {\n const filtered: Partial<T> = {};\n const itemRecord = item as Record<string, unknown>;\n fieldList.forEach(field => {\n if (field in itemRecord) {\n (filtered as Record<string, unknown>)[field] = itemRecord[field];\n }\n });\n return filtered;\n });\n}\n","import type { OutputOptions } from '../types/index.js';\nimport { convertMilliunitsToAmounts } from './utils.js';\n\nlet globalOutputOptions: OutputOptions = {};\n\nexport function setOutputOptions(options: OutputOptions): void {\n globalOutputOptions = options;\n}\n\nexport function outputJson(data: unknown, options: OutputOptions = {}): void {\n const convertedData = convertMilliunitsToAmounts(data);\n const mergedOptions = { ...globalOutputOptions, ...options };\n const jsonString = mergedOptions.compact\n ? JSON.stringify(convertedData)\n : JSON.stringify(convertedData, null, 2);\n\n console.log(jsonString);\n}\n","import { Command } from 'commander';\nimport { auth } from '../lib/auth.js';\nimport { promptForAccessToken } from '../lib/prompts.js';\nimport { outputJson } from '../lib/output.js';\nimport { client } from '../lib/api-client.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\n\nexport function createAuthCommand(): Command {\n const cmd = new Command('auth').description('Authentication management');\n\n cmd\n .command('login')\n .description('Configure access token')\n .action(withErrorHandling(async () => {\n const token = await promptForAccessToken();\n await auth.setAccessToken(token);\n\n try {\n const user = await client.getUser();\n outputJson({\n message: 'Successfully authenticated',\n user: { id: user?.id },\n });\n } catch (error) {\n await auth.deleteAccessToken();\n throw error;\n }\n }));\n\n cmd\n .command('status')\n .description('Check authentication status')\n .action(withErrorHandling(async () => {\n const isAuthenticated = await auth.isAuthenticated();\n\n if (!isAuthenticated) {\n outputJson({ authenticated: false, message: 'Not authenticated' });\n return;\n }\n\n try {\n const user = await client.getUser();\n outputJson({ authenticated: true, user: { id: user?.id } });\n } catch (error) {\n outputJson({ authenticated: false, message: 'Token exists but is invalid' });\n }\n }));\n\n cmd\n .command('logout')\n .description('Remove stored credentials')\n .action(withErrorHandling(async () => {\n await auth.logout();\n outputJson({ message: 'Successfully logged out' });\n }));\n\n return cmd;\n}\n","import Conf from 'conf';\nimport type { Config } from '../types/index.js';\n\nclass ConfigManager {\n private conf: Conf<Config>;\n\n constructor() {\n this.conf = new Conf<Config>({\n projectName: 'ynab-cli',\n schema: {\n defaultBudget: { type: 'string' },\n version: { type: 'string', default: '1.0.0' },\n },\n defaults: { version: '1.0.0' },\n });\n }\n\n getDefaultBudget(): string | undefined {\n return this.conf.get('defaultBudget');\n }\n\n setDefaultBudget(budgetId: string): void {\n this.conf.set('defaultBudget', budgetId);\n }\n\n clearDefaultBudget(): void {\n this.conf.delete('defaultBudget');\n }\n\n clear(): void {\n this.conf.clear();\n }\n}\n\nexport const config = new ConfigManager();\n","import { config } from './config.js';\n\nconst SERVICE_NAME = 'ynab-cli';\nconst ACCOUNT_NAME = 'access-token';\n\nconst KEYTAR_UNAVAILABLE_ERROR =\n 'Keychain storage unavailable. Cannot store credentials securely.\\n' +\n 'On Linux, install libsecret: sudo apt-get install libsecret-1-dev\\n' +\n 'Then reinstall: npm install -g @stephendolan/ynab-cli\\n' +\n 'Alternatively, use the YNAB_API_KEY environment variable.';\n\nlet keytar: typeof import('keytar') | undefined;\n\ntry {\n keytar = await import('keytar');\n} catch (error) {\n if (process.env.NODE_ENV !== 'test') {\n console.error(\n 'Warning: Keychain storage unavailable. Credentials will not be stored securely.\\n' +\n 'On Linux, install libsecret: sudo apt-get install libsecret-1-dev\\n' +\n 'Falling back to environment variable only (YNAB_API_KEY).\\n'\n );\n }\n}\n\nexport class AuthManager {\n async getAccessToken(): Promise<string | null> {\n if (keytar) {\n return keytar.getPassword(SERVICE_NAME, ACCOUNT_NAME);\n }\n return null;\n }\n\n async setAccessToken(token: string): Promise<void> {\n if (keytar) {\n await keytar.setPassword(SERVICE_NAME, ACCOUNT_NAME, token);\n } else {\n throw new Error(KEYTAR_UNAVAILABLE_ERROR);\n }\n }\n\n async deleteAccessToken(): Promise<boolean> {\n if (keytar) {\n return keytar.deletePassword(SERVICE_NAME, ACCOUNT_NAME);\n }\n return false;\n }\n\n async isAuthenticated(): Promise<boolean> {\n return (await this.getAccessToken()) !== null;\n }\n\n async logout(): Promise<void> {\n await this.deleteAccessToken();\n config.clearDefaultBudget();\n }\n}\n\nexport const auth = new AuthManager();\n","import inquirer from 'inquirer';\nimport { amountToMilliunits } from './utils.js';\n\nexport async function promptForAccessToken(): Promise<string> {\n const { token } = await inquirer.prompt([\n {\n type: 'password',\n name: 'token',\n message: 'Enter your YNAB Personal Access Token:',\n validate: (input: string) => !!input.trim() || 'Access token is required',\n },\n ]);\n return token;\n}\n\nexport async function promptForBudget(\n budgets: Array<{ id: string; name: string }>,\n): Promise<string> {\n const { budgetId } = await inquirer.prompt([\n {\n type: 'list',\n name: 'budgetId',\n message: 'Select a budget:',\n choices: budgets.map((b) => ({ name: b.name, value: b.id })),\n },\n ]);\n return budgetId;\n}\n\nexport async function promptForConfirmation(message: string): Promise<boolean> {\n const { confirmed } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'confirmed',\n message,\n default: false,\n },\n ]);\n return confirmed;\n}\n\nexport async function promptForTransaction(): Promise<Record<string, unknown>> {\n const answers = await inquirer.prompt([\n {\n type: 'input',\n name: 'date',\n message: 'Date (YYYY-MM-DD):',\n default: new Date().toISOString().split('T')[0],\n },\n {\n type: 'input',\n name: 'amount',\n message: 'Amount (in currency units, e.g., 10.50):',\n validate: (input: string) => !isNaN(parseFloat(input)) || 'Amount must be a valid number',\n },\n {\n type: 'input',\n name: 'payee_name',\n message: 'Payee name (optional):',\n },\n {\n type: 'input',\n name: 'memo',\n message: 'Memo (optional):',\n },\n ]);\n\n return {\n date: answers.date,\n amount: amountToMilliunits(parseFloat(answers.amount)),\n payee_name: answers.payee_name || undefined,\n memo: answers.memo || undefined,\n };\n}\n","import * as ynab from 'ynab';\nimport { config } from './config.js';\nimport { YnabCliError, handleYnabError, sanitizeApiError } from './errors.js';\nimport { auth } from './auth.js';\nimport dotenv from 'dotenv';\n\ndotenv.config();\n\ntype TransactionTypeFilter = 'uncategorized' | 'unapproved' | undefined;\n\nexport class YnabClient {\n private api: ynab.API | null = null;\n private envVarWarningShown = false;\n\n async getApi(): Promise<ynab.API> {\n if (this.api) {\n return this.api;\n }\n\n const keychainToken = await auth.getAccessToken();\n const accessToken = keychainToken || process.env.YNAB_API_KEY || null;\n\n if (!accessToken) {\n throw new YnabCliError(\n 'Not authenticated. Please run: ynab auth login or set YNAB_API_KEY environment variable',\n 401,\n );\n }\n\n if (!keychainToken && process.env.YNAB_API_KEY && !this.envVarWarningShown) {\n console.warn(\n '\\x1b[33m⚠️ WARNING: Using YNAB_API_KEY environment variable.\\n' +\n 'Environment variables may be visible to other processes.\\n' +\n 'For better security, use: ynab auth login\\x1b[0m\\n'\n );\n this.envVarWarningShown = true;\n }\n\n this.api = new ynab.API(accessToken);\n return this.api;\n }\n\n async getBudgetId(budgetIdOrDefault?: string): Promise<string> {\n const budgetId =\n budgetIdOrDefault || config.getDefaultBudget() || process.env.YNAB_BUDGET_ID;\n\n if (!budgetId) {\n throw new YnabCliError(\n 'No budget specified. Use --budget flag, set default with \"ynab budgets set-default\", or set YNAB_BUDGET_ID environment variable',\n 400,\n );\n }\n\n return budgetId;\n }\n\n private async withErrorHandling<T>(fn: () => Promise<T>): Promise<T> {\n try {\n return await fn();\n } catch (error) {\n handleYnabError(error);\n }\n }\n\n async getUser() {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const response = await api.user.getUser();\n return response.data.user;\n });\n }\n\n async getBudgets(includeAccounts = false) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const response = await api.budgets.getBudgets(includeAccounts);\n return {\n budgets: response.data.budgets,\n server_knowledge: 0,\n };\n });\n }\n\n async getBudget(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.budgets.getBudgetById(id, lastKnowledgeOfServer);\n return {\n budget: response.data.budget,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getBudgetSettings(budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.budgets.getBudgetSettingsById(id);\n return response.data.settings;\n });\n }\n\n async getAccounts(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.accounts.getAccounts(id, lastKnowledgeOfServer);\n return {\n accounts: response.data.accounts,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getAccount(accountId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.accounts.getAccountById(id, accountId);\n return response.data.account;\n });\n }\n\n async createAccount(accountData: ynab.PostAccountWrapper, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.accounts.createAccount(id, accountData);\n return response.data.account;\n });\n }\n\n async getCategories(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.categories.getCategories(id, lastKnowledgeOfServer);\n return {\n category_groups: response.data.category_groups,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getCategory(categoryId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.categories.getCategoryById(id, categoryId);\n return response.data.category;\n });\n }\n\n async updateCategory(\n categoryId: string,\n data: ynab.PatchCategoryWrapper,\n budgetId?: string,\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.categories.updateCategory(id, categoryId, data);\n return response.data.category;\n });\n }\n\n async getMonthCategory(month: string, categoryId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.categories.getMonthCategoryById(id, month, categoryId);\n return response.data.category;\n });\n }\n\n async updateMonthCategory(\n month: string,\n categoryId: string,\n data: ynab.PatchMonthCategoryWrapper,\n budgetId?: string,\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.categories.updateMonthCategory(id, month, categoryId, data);\n return response.data.category;\n });\n }\n\n async getPayees(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.payees.getPayees(id, lastKnowledgeOfServer);\n return {\n payees: response.data.payees,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getPayee(payeeId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.payees.getPayeeById(id, payeeId);\n return response.data.payee;\n });\n }\n\n async updatePayee(payeeId: string, data: ynab.PatchPayeeWrapper, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.payees.updatePayee(id, payeeId, data);\n return response.data.payee;\n });\n }\n\n async getPayeeLocations(budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.payeeLocations.getPayeeLocations(id);\n return response.data.payee_locations;\n });\n }\n\n async getPayeeLocation(payeeLocationId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.payeeLocations.getPayeeLocationById(id, payeeLocationId);\n return response.data.payee_location;\n });\n }\n\n async getPayeeLocationsByPayee(payeeId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.payeeLocations.getPayeeLocationsByPayee(id, payeeId);\n return response.data.payee_locations;\n });\n }\n\n async getBudgetMonths(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.months.getBudgetMonths(id, lastKnowledgeOfServer);\n return {\n months: response.data.months,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getBudgetMonth(month: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.months.getBudgetMonth(id, month);\n return response.data.month;\n });\n }\n\n async getTransactions(params: {\n budgetId?: string;\n sinceDate?: string;\n type?: string;\n lastKnowledgeOfServer?: number;\n }) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(params.budgetId);\n const response = await api.transactions.getTransactions(\n id,\n params.sinceDate,\n params.type as TransactionTypeFilter,\n params.lastKnowledgeOfServer,\n );\n return {\n transactions: response.data.transactions,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getTransactionsByAccount(accountId: string, params: {\n budgetId?: string;\n sinceDate?: string;\n type?: string;\n lastKnowledgeOfServer?: number;\n }) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(params.budgetId);\n const response = await api.transactions.getTransactionsByAccount(\n id,\n accountId,\n params.sinceDate,\n params.type as TransactionTypeFilter,\n params.lastKnowledgeOfServer,\n );\n return {\n transactions: response.data.transactions,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getTransactionsByCategory(categoryId: string, params: {\n budgetId?: string;\n sinceDate?: string;\n type?: string;\n lastKnowledgeOfServer?: number;\n }) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(params.budgetId);\n const response = await api.transactions.getTransactionsByCategory(\n id,\n categoryId,\n params.sinceDate,\n params.type as TransactionTypeFilter,\n params.lastKnowledgeOfServer,\n );\n return {\n transactions: response.data.transactions,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getTransactionsByPayee(payeeId: string, params: {\n budgetId?: string;\n sinceDate?: string;\n type?: string;\n lastKnowledgeOfServer?: number;\n }) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(params.budgetId);\n const response = await api.transactions.getTransactionsByPayee(\n id,\n payeeId,\n params.sinceDate,\n params.type as TransactionTypeFilter,\n params.lastKnowledgeOfServer,\n );\n return {\n transactions: response.data.transactions,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getTransaction(transactionId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.getTransactionById(id, transactionId);\n return response.data.transaction;\n });\n }\n\n async createTransaction(\n transactionData: ynab.PostTransactionsWrapper,\n budgetId?: string,\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.createTransaction(id, transactionData);\n return response.data.transaction;\n });\n }\n\n async createTransactions(\n transactionsData: ynab.PostTransactionsWrapper,\n budgetId?: string,\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.createTransactions(id, transactionsData);\n return response.data;\n });\n }\n\n async updateTransaction(\n transactionId: string,\n transactionData: ynab.PutTransactionWrapper,\n budgetId?: string,\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.updateTransaction(\n id,\n transactionId,\n transactionData,\n );\n return response.data.transaction;\n });\n }\n\n async updateTransactions(\n transactionsData: ynab.PatchTransactionsWrapper,\n budgetId?: string,\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.updateTransactions(id, transactionsData);\n return response.data;\n });\n }\n\n async deleteTransaction(transactionId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.deleteTransaction(id, transactionId);\n return response.data.transaction;\n });\n }\n\n async importTransactions(budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.importTransactions(id);\n return response.data.transaction_ids;\n });\n }\n\n async getScheduledTransactions(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.scheduledTransactions.getScheduledTransactions(\n id,\n lastKnowledgeOfServer,\n );\n return {\n scheduled_transactions: response.data.scheduled_transactions,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getScheduledTransaction(scheduledTransactionId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.scheduledTransactions.getScheduledTransactionById(\n id,\n scheduledTransactionId,\n );\n return response.data.scheduled_transaction;\n });\n }\n\n async createScheduledTransaction(\n data: ynab.PostScheduledTransactionWrapper,\n budgetId?: string,\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.scheduledTransactions.createScheduledTransaction(id, data);\n return response.data.scheduled_transaction;\n });\n }\n\n async updateScheduledTransaction(\n scheduledTransactionId: string,\n data: ynab.PutScheduledTransactionWrapper,\n budgetId?: string,\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.scheduledTransactions.updateScheduledTransaction(\n id,\n scheduledTransactionId,\n data,\n );\n return response.data.scheduled_transaction;\n });\n }\n\n async deleteScheduledTransaction(scheduledTransactionId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.scheduledTransactions.deleteScheduledTransaction(\n id,\n scheduledTransactionId,\n );\n return response.data.scheduled_transaction;\n });\n }\n\n async rawApiCall(method: string, path: string, data?: unknown, budgetId?: string) {\n return this.withErrorHandling(async () => {\n await this.getApi();\n\n const fullPath = path.includes('{budget_id}')\n ? path.replace('{budget_id}', await this.getBudgetId(budgetId))\n : path;\n\n const url = `https://api.ynab.com/v1${fullPath}`;\n const headers = {\n Authorization: `Bearer ${await auth.getAccessToken()}`,\n 'Content-Type': 'application/json',\n };\n\n const httpMethod = method.toUpperCase();\n const hasBody = ['POST', 'PUT', 'PATCH'].includes(httpMethod);\n\n if (!['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(httpMethod)) {\n throw new YnabCliError(`Unsupported HTTP method: ${method}`, 400);\n }\n\n const response = await fetch(url, {\n method: httpMethod,\n headers,\n ...(hasBody && { body: JSON.stringify(data) }),\n });\n\n if (!response.ok) {\n const errorData = await response.json() as Record<string, unknown>;\n throw { error: sanitizeApiError(errorData.error || errorData) };\n }\n\n return await response.json();\n });\n }\n}\n\nexport const client = new YnabClient();\n","import type { YnabError } from '../types/index.js';\nimport { outputJson } from './output.js';\n\nexport class YnabCliError extends Error {\n constructor(\n message: string,\n public statusCode?: number,\n ) {\n super(message);\n this.name = 'YnabCliError';\n }\n}\n\nconst ERROR_STATUS_CODES: Record<string, number> = {\n bad_request: 400,\n not_authorized: 401,\n subscription_lapsed: 403,\n trial_expired: 403,\n unauthorized_scope: 403,\n data_limit_reached: 403,\n not_found: 404,\n resource_not_found: 404,\n conflict: 409,\n too_many_requests: 429,\n internal_server_error: 500,\n service_unavailable: 503,\n};\n\nexport function sanitizeErrorMessage(message: string): string {\n const sensitivePatterns = [\n /Bearer\\s+[\\w\\-._~+/]+=*/gi,\n /token[=:]\\s*[\\w\\-._~+/]+=*/gi,\n /api[_-]?key[=:]\\s*[\\w\\-._~+/]+=*/gi,\n /authorization:\\s*bearer\\s+[\\w\\-._~+/]+=*/gi,\n ];\n\n let sanitized = message;\n for (const pattern of sensitivePatterns) {\n sanitized = sanitized.replace(pattern, '[REDACTED]');\n }\n\n return sanitized.length > 500 ? sanitized.substring(0, 500) + '...' : sanitized;\n}\n\ninterface YnabApiError {\n name?: string;\n detail?: string;\n message?: string;\n id?: string;\n}\n\nfunction isErrorObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nexport function sanitizeApiError(error: unknown): YnabError {\n if (!isErrorObject(error)) {\n return {\n name: 'api_error',\n detail: 'An error occurred',\n id: undefined,\n };\n }\n\n const apiError = error as YnabApiError;\n const detail = sanitizeErrorMessage(\n String(apiError.detail || apiError.message || 'An error occurred')\n );\n\n return {\n name: apiError.name || 'api_error',\n detail,\n id: apiError.id,\n };\n}\n\nfunction enhanceRateLimitMessage(detail: string): string {\n return `${detail}\\n\\nYNAB API limit: 200 requests/hour (rolling window). Wait a few minutes and retry.`;\n}\n\nfunction formatErrorResponse(name: string, detail: string, statusCode: number): never {\n const enhancedDetail = name === 'too_many_requests'\n ? enhanceRateLimitMessage(detail)\n : detail;\n\n outputJson({ error: { name, detail: enhancedDetail, statusCode } });\n process.exit(1);\n}\n\nexport function handleYnabError(error: unknown): never {\n if (!isErrorObject(error)) {\n formatErrorResponse('unknown_error', 'An unexpected error occurred', 1);\n }\n\n const errorObj = error as { error?: unknown; message?: string };\n\n if (errorObj.error) {\n const ynabError: YnabError = sanitizeApiError(errorObj.error);\n formatErrorResponse(\n ynabError.name,\n ynabError.detail,\n ERROR_STATUS_CODES[ynabError.name] || 500,\n );\n }\n\n if (error instanceof YnabCliError) {\n const sanitized = sanitizeErrorMessage(error.message);\n formatErrorResponse('cli_error', sanitized, error.statusCode || 1);\n }\n\n const sanitized = sanitizeErrorMessage(errorObj.message || 'An unexpected error occurred');\n formatErrorResponse('unknown_error', sanitized, 1);\n}\n","import { handleYnabError } from './errors.js';\nimport { promptForConfirmation } from './prompts.js';\nimport { isInteractive } from './utils.js';\nimport { outputJson } from './output.js';\n\nexport function withErrorHandling<TArgs extends unknown[], R>(\n fn: (...args: TArgs) => Promise<R>,\n): (...args: TArgs) => Promise<void> {\n return async (...args: TArgs) => {\n try {\n await fn(...args);\n } catch (error) {\n handleYnabError(error);\n }\n };\n}\n\nexport async function confirmDelete(\n itemType: string,\n skipConfirmation: boolean = false,\n): Promise<boolean> {\n if (skipConfirmation || !isInteractive()) {\n return true;\n }\n\n const confirmed = await promptForConfirmation(\n `Are you sure you want to delete this ${itemType}?`,\n );\n\n if (!confirmed) {\n outputJson({ message: 'Operation cancelled' });\n return false;\n }\n\n return true;\n}\n\nexport function buildUpdateObject<T>(\n options: T,\n mapping: Record<string, string>,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const optionsRecord = options as Record<string, unknown>;\n\n for (const [optionKey, targetKey] of Object.entries(mapping)) {\n if (optionsRecord[optionKey] !== undefined) {\n result[targetKey] = optionsRecord[optionKey];\n }\n }\n\n return result;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\n\nexport function createUserCommand(): Command {\n const cmd = new Command('user').description('User information');\n\n cmd\n .command('info')\n .description('Get authenticated user information')\n .action(withErrorHandling(async () => {\n const user = await client.getUser();\n outputJson(user);\n }));\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { config } from '../lib/config.js';\nimport { outputJson } from '../lib/output.js';\nimport { YnabCliError } from '../lib/errors.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\n\nexport function createBudgetsCommand(): Command {\n const cmd = new Command('budgets').description('Budget operations');\n\n cmd\n .command('list')\n .description('List all budgets')\n .option('--include-accounts', 'Include accounts in response')\n .action(withErrorHandling(async (options: { includeAccounts?: boolean }) => {\n const result = await client.getBudgets(options.includeAccounts);\n outputJson(result?.budgets);\n }));\n\n cmd\n .command('view')\n .description('View budget details (uses default if no id provided)')\n .argument('[id]', 'Budget ID')\n .action(withErrorHandling(async (id: string | undefined) => {\n const result = await client.getBudget(id);\n outputJson(result?.budget);\n }));\n\n cmd\n .command('settings')\n .description('View budget settings')\n .argument('[id]', 'Budget ID')\n .action(withErrorHandling(async (id: string | undefined) => {\n const settings = await client.getBudgetSettings(id);\n outputJson(settings);\n }));\n\n cmd\n .command('set-default')\n .description('Set default budget for commands')\n .argument('<id>', 'Budget ID')\n .action(withErrorHandling(async (id: string) => {\n const result = await client.getBudgets();\n const budget = result?.budgets.find((b) => b.id === id);\n\n if (!budget) {\n throw new YnabCliError(`Budget with ID ${id} not found`, 404);\n }\n\n config.setDefaultBudget(id);\n outputJson({\n message: 'Default budget set',\n budget: { id: budget.id, name: budget.name },\n });\n }));\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\nimport type { CommandOptions } from '../types/index.js';\n\nexport function createAccountsCommand(): Command {\n const cmd = new Command('accounts').description('Account operations');\n\n cmd\n .command('list')\n .description('List all accounts')\n .option('-b, --budget <id>', 'Budget ID')\n .action(withErrorHandling(async (options: CommandOptions) => {\n const result = await client.getAccounts(options.budget);\n outputJson(result?.accounts);\n }));\n\n cmd\n .command('view')\n .description('View account details')\n .argument('<id>', 'Account ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(withErrorHandling(async (id: string, options: CommandOptions) => {\n const account = await client.getAccount(id, options.budget);\n outputJson(account);\n }));\n\n cmd\n .command('transactions')\n .description('List transactions for account')\n .argument('<id>', 'Account ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--since <date>', 'Filter transactions since date (YYYY-MM-DD)')\n .option('--type <type>', 'Filter by transaction type')\n .action(withErrorHandling(async (\n id: string,\n options: {\n budget?: string;\n since?: string;\n type?: string;\n } & CommandOptions,\n ) => {\n const result = await client.getTransactionsByAccount(id, {\n budgetId: options.budget,\n sinceDate: options.since,\n type: options.type,\n });\n outputJson(result?.transactions);\n }));\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { YnabCliError } from '../lib/errors.js';\nimport { amountToMilliunits } from '../lib/utils.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\nimport type { CommandOptions } from '../types/index.js';\n\nexport function createCategoriesCommand(): Command {\n const cmd = new Command('categories').description('Category operations');\n\n cmd\n .command('list')\n .description('List all categories')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(withErrorHandling(async (options: { budget?: string; lastKnowledge?: number } & CommandOptions) => {\n const result = await client.getCategories(options.budget, options.lastKnowledge);\n outputJson(result?.category_groups);\n }));\n\n cmd\n .command('view')\n .description('View category details')\n .argument('<id>', 'Category ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(withErrorHandling(async (id: string, options: CommandOptions) => {\n const category = await client.getCategory(id, options.budget);\n outputJson(category);\n }));\n\n cmd\n .command('budget')\n .description('Set category budgeted amount for a month (overrides existing amount)')\n .argument('<id>', 'Category ID')\n .requiredOption('--month <month>', 'Month in YYYY-MM-DD format (e.g., 2025-07-01)')\n .requiredOption('--amount <amount>', 'Total budgeted amount to set (e.g., 100.50)', parseFloat)\n .option('-b, --budget <id>', 'Budget ID')\n .action(withErrorHandling(async (\n id: string,\n options: {\n month: string;\n amount: number;\n budget?: string;\n } & CommandOptions,\n ) => {\n if (isNaN(options.amount)) {\n throw new YnabCliError('Amount must be a valid number', 400);\n }\n\n const milliunits = amountToMilliunits(options.amount);\n const category = await client.updateMonthCategory(\n options.month,\n id,\n { category: { budgeted: milliunits } },\n options.budget,\n );\n outputJson(category);\n }));\n\n cmd\n .command('transactions')\n .description('List transactions for category')\n .argument('<id>', 'Category ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--since <date>', 'Filter transactions since date (YYYY-MM-DD)')\n .option('--type <type>', 'Filter by transaction type')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(withErrorHandling(async (\n id: string,\n options: {\n budget?: string;\n since?: string;\n type?: string;\n lastKnowledge?: number;\n } & CommandOptions,\n ) => {\n const result = await client.getTransactionsByCategory(id, {\n budgetId: options.budget,\n sinceDate: options.since,\n type: options.type,\n lastKnowledgeOfServer: options.lastKnowledge,\n });\n outputJson(result?.transactions);\n }));\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { YnabCliError } from '../lib/errors.js';\nimport { promptForTransaction } from '../lib/prompts.js';\nimport { isInteractive, amountToMilliunits, applyTransactionFilters, applyFieldSelection, type TransactionLike } from '../lib/utils.js';\nimport { withErrorHandling, confirmDelete, buildUpdateObject } from '../lib/command-utils.js';\nimport { validateJson, TransactionSplitSchema } from '../lib/schemas.js';\nimport type { CommandOptions } from '../types/index.js';\n\ninterface TransactionOptions {\n account?: string;\n date?: string;\n amount?: number;\n payeeName?: string;\n payeeId?: string;\n categoryId?: string;\n memo?: string;\n cleared?: string;\n approved?: boolean;\n}\n\nfunction buildTransactionData(options: TransactionOptions): Record<string, unknown> {\n if (!options.account) {\n throw new YnabCliError('--account is required in non-interactive mode', 400);\n }\n if (options.amount === undefined) {\n throw new YnabCliError('--amount is required in non-interactive mode', 400);\n }\n\n return {\n account_id: options.account,\n date: options.date || new Date().toISOString().split('T')[0],\n amount: amountToMilliunits(options.amount),\n payee_name: options.payeeName,\n payee_id: options.payeeId,\n category_id: options.categoryId,\n memo: options.memo,\n cleared: options.cleared,\n approved: options.approved,\n };\n}\n\nexport function createTransactionsCommand(): Command {\n const cmd = new Command('transactions').description('Transaction operations');\n\n cmd\n .command('list')\n .description('List transactions')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--account <id>', 'Filter by account ID')\n .option('--category <id>', 'Filter by category ID')\n .option('--payee <id>', 'Filter by payee ID')\n .option('--since <date>', 'Filter transactions since date (YYYY-MM-DD)')\n .option('--until <date>', 'Filter transactions until date (YYYY-MM-DD)')\n .option('--type <type>', 'Filter by transaction type')\n .option('--approved <value>', 'Filter by approval status: true or false')\n .option('--status <statuses>', 'Filter by cleared status: cleared, uncleared, reconciled (comma-separated for multiple)')\n .option('--min-amount <amount>', 'Minimum amount in currency units (e.g., 10.50)', parseFloat)\n .option('--max-amount <amount>', 'Maximum amount in currency units (e.g., 100.00)', parseFloat)\n .option('--fields <fields>', 'Comma-separated list of fields to include (e.g., id,date,amount,memo)')\n .action(withErrorHandling(async (options: {\n budget?: string;\n account?: string;\n category?: string;\n payee?: string;\n since?: string;\n until?: string;\n type?: string;\n approved?: string;\n status?: string;\n minAmount?: number;\n maxAmount?: number;\n fields?: string;\n } & CommandOptions) => {\n const params = {\n budgetId: options.budget,\n sinceDate: options.since,\n type: options.type,\n };\n\n const result = options.account\n ? await client.getTransactionsByAccount(options.account, params)\n : options.category\n ? await client.getTransactionsByCategory(options.category, params)\n : options.payee\n ? await client.getTransactionsByPayee(options.payee, params)\n : await client.getTransactions(params);\n\n const transactions = result?.transactions || [];\n\n const filtered = applyTransactionFilters(transactions as TransactionLike[], {\n until: options.until,\n approved: options.approved,\n status: options.status,\n minAmount: options.minAmount,\n maxAmount: options.maxAmount,\n });\n\n const selected = applyFieldSelection(filtered, options.fields);\n\n outputJson(selected);\n }));\n\n cmd\n .command('view')\n .description('View single transaction')\n .argument('<id>', 'Transaction ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(withErrorHandling(async (id: string, options: CommandOptions) => {\n const transaction = await client.getTransaction(id, options.budget);\n outputJson(transaction);\n }));\n\n cmd\n .command('create')\n .description('Create transaction')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--account <id>', 'Account ID')\n .option('--date <date>', 'Date (YYYY-MM-DD)')\n .option('--amount <amount>', 'Amount in currency units (e.g., 10.50)', parseFloat)\n .option('--payee-name <name>', 'Payee name')\n .option('--payee-id <id>', 'Payee ID')\n .option('--category-id <id>', 'Category ID')\n .option('--memo <memo>', 'Memo')\n .option('--cleared <status>', 'Cleared status (cleared, uncleared, reconciled)')\n .option('--approved', 'Mark as approved')\n .action(withErrorHandling(async (options: {\n budget?: string;\n account?: string;\n date?: string;\n amount?: number;\n payeeName?: string;\n payeeId?: string;\n categoryId?: string;\n memo?: string;\n cleared?: string;\n approved?: boolean;\n } & CommandOptions) => {\n const shouldPrompt = isInteractive() && !options.account && !options.amount;\n const transactionData = shouldPrompt\n ? await promptForTransaction()\n : buildTransactionData(options);\n\n const transaction = await client.createTransaction(\n { transaction: transactionData },\n options.budget,\n );\n outputJson(transaction);\n }));\n\n cmd\n .command('update')\n .description('Update transaction')\n .argument('<id>', 'Transaction ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--account <id>', 'Account ID')\n .option('--date <date>', 'Date (YYYY-MM-DD)')\n .option('--amount <amount>', 'Amount in currency units', parseFloat)\n .option('--payee-name <name>', 'Payee name')\n .option('--payee-id <id>', 'Payee ID')\n .option('--category-id <id>', 'Category ID')\n .option('--memo <memo>', 'Memo')\n .option('--cleared <status>', 'Cleared status')\n .option('--approved', 'Mark as approved')\n .action(withErrorHandling(async (\n id: string,\n options: TransactionOptions & { budget?: string } & CommandOptions,\n ) => {\n const transactionData = buildUpdateObject(options, {\n account: 'account_id',\n date: 'date',\n payeeName: 'payee_name',\n payeeId: 'payee_id',\n categoryId: 'category_id',\n memo: 'memo',\n cleared: 'cleared',\n approved: 'approved',\n });\n\n if (options.amount !== undefined) {\n transactionData.amount = amountToMilliunits(options.amount);\n }\n\n const transaction = await client.updateTransaction(\n id,\n { transaction: transactionData },\n options.budget,\n );\n outputJson(transaction);\n }));\n\n cmd\n .command('delete')\n .description('Delete transaction')\n .argument('<id>', 'Transaction ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('-y, --yes', 'Skip confirmation')\n .action(withErrorHandling(async (id: string, options: { budget?: string; yes?: boolean } & CommandOptions) => {\n if (!await confirmDelete('transaction', options.yes)) {\n return;\n }\n\n const transaction = await client.deleteTransaction(id, options.budget);\n outputJson({ message: 'Transaction deleted', transaction });\n }));\n\n cmd\n .command('import')\n .description('Import transactions')\n .option('-b, --budget <id>', 'Budget ID')\n .action(withErrorHandling(async (options: CommandOptions) => {\n const transactionIds = await client.importTransactions(options.budget);\n outputJson({ transaction_ids: transactionIds });\n }));\n\n cmd\n .command('split')\n .description('Split transaction into multiple categories. Amounts should be in dollars (e.g., 10.50).')\n .argument('<id>', 'Transaction ID')\n .requiredOption('--splits <json>', 'JSON array of splits with dollar amounts: [{\"amount\": -21.40, \"category_id\": \"xxx\", \"memo\": \"...\"}]')\n .option('-b, --budget <id>', 'Budget ID')\n .option('-f, --force', 'Force update of already-split transactions by deleting and recreating')\n .action(withErrorHandling(async (\n id: string,\n options: { splits: string; budget?: string; force?: boolean } & CommandOptions,\n ) => {\n let parsedSplits;\n try {\n parsedSplits = JSON.parse(options.splits);\n } catch (error) {\n throw new YnabCliError('Invalid JSON in --splits parameter', 400);\n }\n\n const splits = validateJson(parsedSplits, TransactionSplitSchema, 'transaction splits');\n\n const splitsInMilliunits = splits.map(split => ({\n ...split,\n amount: amountToMilliunits(split.amount),\n }));\n\n const existingTransaction = await client.getTransaction(id, options.budget);\n const isAlreadySplit = existingTransaction.subtransactions && existingTransaction.subtransactions.length > 0;\n\n if (isAlreadySplit && !options.force) {\n throw new YnabCliError(\n 'Transaction is already split. YNAB API does not support updating split transactions. ' +\n 'Use --force to delete and recreate the transaction with new splits.',\n 400\n );\n }\n\n if (isAlreadySplit && options.force) {\n await client.deleteTransaction(id, options.budget);\n\n const recreatedTransaction = await client.createTransaction(\n {\n transaction: {\n account_id: existingTransaction.account_id,\n date: existingTransaction.date,\n amount: existingTransaction.amount,\n payee_id: existingTransaction.payee_id,\n payee_name: existingTransaction.payee_name,\n category_id: null,\n memo: existingTransaction.memo,\n cleared: existingTransaction.cleared,\n approved: existingTransaction.approved,\n flag_color: existingTransaction.flag_color,\n import_id: existingTransaction.import_id,\n subtransactions: splitsInMilliunits,\n },\n },\n options.budget,\n );\n outputJson(recreatedTransaction);\n } else {\n const transaction = await client.updateTransaction(\n id,\n {\n transaction: {\n category_id: null,\n subtransactions: splitsInMilliunits,\n },\n },\n options.budget,\n );\n outputJson(transaction);\n }\n }));\n\n cmd\n .command('search')\n .description('Search transactions')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--memo <text>', 'Search in memo field')\n .option('--payee-name <name>', 'Search in payee name')\n .option('--amount <amount>', 'Search for exact amount in currency units', parseFloat)\n .option('--since <date>', 'Search transactions since date (YYYY-MM-DD)')\n .option('--until <date>', 'Search transactions until date (YYYY-MM-DD)')\n .option('--approved <value>', 'Filter by approval status: true or false')\n .option('--status <statuses>', 'Filter by cleared status: cleared, uncleared, reconciled (comma-separated)')\n .option('--fields <fields>', 'Comma-separated list of fields to include')\n .action(withErrorHandling(async (options: {\n budget?: string;\n memo?: string;\n payeeName?: string;\n amount?: number;\n since?: string;\n until?: string;\n approved?: string;\n status?: string;\n fields?: string;\n } & CommandOptions) => {\n if (!options.memo && !options.payeeName && options.amount === undefined) {\n throw new YnabCliError('At least one search criteria required: --memo, --payee-name, or --amount', 400);\n }\n\n const params = {\n budgetId: options.budget,\n sinceDate: options.since,\n };\n\n const result = await client.getTransactions(params);\n let transactions = result?.transactions || [];\n\n if (options.memo) {\n const searchTerm = options.memo.toLowerCase();\n transactions = transactions.filter(t =>\n t.memo?.toLowerCase().includes(searchTerm)\n );\n }\n\n if (options.payeeName) {\n const searchTerm = options.payeeName.toLowerCase();\n transactions = transactions.filter(t =>\n t.payee_name?.toLowerCase().includes(searchTerm)\n );\n }\n\n if (options.amount !== undefined) {\n const amountMilliunits = amountToMilliunits(options.amount);\n transactions = transactions.filter(t => t.amount === amountMilliunits);\n }\n\n transactions = applyTransactionFilters(transactions, {\n until: options.until,\n approved: options.approved,\n status: options.status,\n });\n\n const filteredTransactions = applyFieldSelection(transactions, options.fields);\n\n outputJson(filteredTransactions);\n }));\n\n return cmd;\n}\n","import { z } from 'zod';\nimport { YnabCliError } from './errors.js';\n\nexport const TransactionSplitSchema = z.array(\n z.object({\n amount: z.number(),\n category_id: z.string().nullable().optional(),\n memo: z.string().optional(),\n payee_id: z.string().optional(),\n })\n);\n\nexport const ApiDataSchema = z.record(z.any());\n\nexport function validateJson<T>(\n data: unknown,\n schema: z.ZodSchema<T>,\n fieldName: string\n): T {\n try {\n return schema.parse(data);\n } catch (error) {\n if (error instanceof z.ZodError) {\n const issues = error.issues\n .map(i => `${i.path.join('.')}: ${i.message}`)\n .join(', ');\n throw new YnabCliError(`Invalid ${fieldName}: ${issues}`, 400);\n }\n throw error;\n }\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling, confirmDelete } from '../lib/command-utils.js';\nimport type { CommandOptions } from '../types/index.js';\n\nexport function createScheduledCommand(): Command {\n const cmd = new Command('scheduled').description('Scheduled transaction operations');\n\n cmd\n .command('list')\n .description('List all scheduled transactions')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(withErrorHandling(async (options: { budget?: string; lastKnowledge?: number } & CommandOptions) => {\n const result = await client.getScheduledTransactions(options.budget, options.lastKnowledge);\n outputJson(result?.scheduled_transactions);\n }));\n\n cmd\n .command('view')\n .description('View scheduled transaction')\n .argument('<id>', 'Scheduled transaction ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(withErrorHandling(async (id: string, options: CommandOptions) => {\n const scheduledTransaction = await client.getScheduledTransaction(id, options.budget);\n outputJson(scheduledTransaction);\n }));\n\n cmd\n .command('delete')\n .description('Delete scheduled transaction')\n .argument('<id>', 'Scheduled transaction ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('-y, --yes', 'Skip confirmation')\n .action(withErrorHandling(async (id: string, options: { budget?: string; yes?: boolean } & CommandOptions) => {\n if (!await confirmDelete('scheduled transaction', options.yes)) {\n return;\n }\n\n const scheduledTransaction = await client.deleteScheduledTransaction(id, options.budget);\n outputJson({\n message: 'Scheduled transaction deleted',\n scheduled_transaction: scheduledTransaction,\n });\n }));\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { YnabCliError } from '../lib/errors.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\nimport type { CommandOptions } from '../types/index.js';\n\nexport function createPayeesCommand(): Command {\n const cmd = new Command('payees').description('Payee operations');\n\n cmd\n .command('list')\n .description('List all payees')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(withErrorHandling(async (options: { budget?: string; lastKnowledge?: number } & CommandOptions) => {\n const result = await client.getPayees(options.budget, options.lastKnowledge);\n outputJson(result?.payees);\n }));\n\n cmd\n .command('view')\n .description('View payee details')\n .argument('<id>', 'Payee ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(withErrorHandling(async (id: string, options: CommandOptions) => {\n const payee = await client.getPayee(id, options.budget);\n outputJson(payee);\n }));\n\n cmd\n .command('update')\n .description('Rename payee')\n .argument('<id>', 'Payee ID')\n .requiredOption('--name <name>', 'New payee name')\n .option('-b, --budget <id>', 'Budget ID')\n .action(withErrorHandling(async (id: string, options: { name: string; budget?: string } & CommandOptions) => {\n if (!options.name?.trim()) {\n throw new YnabCliError('Name cannot be empty', 400);\n }\n\n const payee = await client.updatePayee(\n id,\n { payee: { name: options.name } },\n options.budget,\n );\n outputJson(payee);\n }));\n\n cmd\n .command('locations')\n .description('List locations for payee')\n .argument('<id>', 'Payee ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(withErrorHandling(async (id: string, options: CommandOptions) => {\n const locations = await client.getPayeeLocationsByPayee(id, options.budget);\n outputJson(locations);\n }));\n\n cmd\n .command('transactions')\n .description('List transactions for payee')\n .argument('<id>', 'Payee ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--since <date>', 'Filter transactions since date (YYYY-MM-DD)')\n .option('--type <type>', 'Filter by transaction type')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(withErrorHandling(async (\n id: string,\n options: {\n budget?: string;\n since?: string;\n type?: string;\n lastKnowledge?: number;\n } & CommandOptions,\n ) => {\n const result = await client.getTransactionsByPayee(id, {\n budgetId: options.budget,\n sinceDate: options.since,\n type: options.type,\n lastKnowledgeOfServer: options.lastKnowledge,\n });\n outputJson(result?.transactions);\n }));\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\nimport type { CommandOptions } from '../types/index.js';\n\nexport function createMonthsCommand(): Command {\n const cmd = new Command('months').description('Monthly budget operations');\n\n cmd\n .command('list')\n .description('List all budget months')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(withErrorHandling(async (options: { budget?: string; lastKnowledge?: number } & CommandOptions) => {\n const result = await client.getBudgetMonths(options.budget, options.lastKnowledge);\n outputJson(result?.months);\n }));\n\n cmd\n .command('view')\n .description('View specific month details')\n .argument('<month>', 'Month in YYYY-MM-DD format (e.g., 2025-07-01)')\n .option('-b, --budget <id>', 'Budget ID')\n .action(withErrorHandling(async (month: string, options: CommandOptions) => {\n const monthData = await client.getBudgetMonth(month, options.budget);\n outputJson(monthData);\n }));\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { YnabCliError } from '../lib/errors.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\nimport { validateJson, ApiDataSchema } from '../lib/schemas.js';\nimport type { CommandOptions } from '../types/index.js';\n\nconst VALID_HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];\n\nexport function createApiCommand(): Command {\n const cmd = new Command('api').description('Raw API access');\n\n cmd\n .argument('<method>', 'HTTP method (GET, POST, PUT, PATCH, DELETE)')\n .argument('<path>', 'API path (e.g., /budgets or /budgets/{budget_id}/transactions)')\n .option('-b, --budget <id>', 'Budget ID (used to replace {budget_id} in path)')\n .option('--data <json>', 'JSON data for POST/PUT/PATCH requests')\n .description('Make raw API calls to YNAB')\n .action(withErrorHandling(async (\n method: string,\n path: string,\n options: { budget?: string; data?: string } & CommandOptions,\n ) => {\n const upperMethod = method.toUpperCase();\n\n if (!VALID_HTTP_METHODS.includes(upperMethod)) {\n throw new YnabCliError(\n `Invalid HTTP method: ${method}. Must be one of: ${VALID_HTTP_METHODS.join(', ')}`,\n 400,\n );\n }\n\n let data: Record<string, unknown> | undefined;\n if (options.data) {\n try {\n const parsedData = JSON.parse(options.data);\n data = validateJson(parsedData, ApiDataSchema, 'API data');\n } catch (error) {\n throw new YnabCliError('Invalid JSON in --data parameter', 400);\n }\n }\n\n const result = await client.rawApiCall(upperMethod, path, data, options.budget);\n outputJson(result);\n }));\n\n return cmd;\n}\n"],"mappings":"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","names":["Command","sanitized","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stephendolan/ynab-cli",
3
- "version": "1.0.4",
3
+ "version": "1.1.0",
4
4
  "description": "A command-line interface for You Need a Budget (YNAB)",
5
5
  "type": "module",
6
6
  "main": "./dist/cli.js",