allsquare 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/LICENSE +21 -0
  3. package/README.md +234 -0
  4. package/dist/api/client.d.ts +46 -0
  5. package/dist/api/client.d.ts.map +1 -0
  6. package/dist/api/client.js +162 -0
  7. package/dist/api/client.js.map +1 -0
  8. package/dist/api/contract.d.ts +549 -0
  9. package/dist/api/contract.d.ts.map +1 -0
  10. package/dist/api/contract.js +49 -0
  11. package/dist/api/contract.js.map +1 -0
  12. package/dist/api/model.d.ts +627 -0
  13. package/dist/api/model.d.ts.map +1 -0
  14. package/dist/api/model.js +378 -0
  15. package/dist/api/model.js.map +1 -0
  16. package/dist/auth/auth-service.d.ts +34 -0
  17. package/dist/auth/auth-service.d.ts.map +1 -0
  18. package/dist/auth/auth-service.js +221 -0
  19. package/dist/auth/auth-service.js.map +1 -0
  20. package/dist/auth/browser.d.ts +12 -0
  21. package/dist/auth/browser.d.ts.map +1 -0
  22. package/dist/auth/browser.js +50 -0
  23. package/dist/auth/browser.js.map +1 -0
  24. package/dist/auth/credential-store.d.ts +28 -0
  25. package/dist/auth/credential-store.d.ts.map +1 -0
  26. package/dist/auth/credential-store.js +75 -0
  27. package/dist/auth/credential-store.js.map +1 -0
  28. package/dist/auth/installation-store.d.ts +14 -0
  29. package/dist/auth/installation-store.d.ts.map +1 -0
  30. package/dist/auth/installation-store.js +122 -0
  31. package/dist/auth/installation-store.js.map +1 -0
  32. package/dist/auth/model.d.ts +54 -0
  33. package/dist/auth/model.d.ts.map +1 -0
  34. package/dist/auth/model.js +24 -0
  35. package/dist/auth/model.js.map +1 -0
  36. package/dist/auth/oauth-callback.d.ts +17 -0
  37. package/dist/auth/oauth-callback.d.ts.map +1 -0
  38. package/dist/auth/oauth-callback.js +94 -0
  39. package/dist/auth/oauth-callback.js.map +1 -0
  40. package/dist/auth/oauth-client.d.ts +43 -0
  41. package/dist/auth/oauth-client.d.ts.map +1 -0
  42. package/dist/auth/oauth-client.js +191 -0
  43. package/dist/auth/oauth-client.js.map +1 -0
  44. package/dist/auth/pkce.d.ts +9 -0
  45. package/dist/auth/pkce.d.ts.map +1 -0
  46. package/dist/auth/pkce.js +12 -0
  47. package/dist/auth/pkce.js.map +1 -0
  48. package/dist/command.d.ts +3 -0
  49. package/dist/command.d.ts.map +1 -0
  50. package/dist/command.js +24 -0
  51. package/dist/command.js.map +1 -0
  52. package/dist/commands/agent-guide.d.ts +5 -0
  53. package/dist/commands/agent-guide.d.ts.map +1 -0
  54. package/dist/commands/agent-guide.js +226 -0
  55. package/dist/commands/agent-guide.js.map +1 -0
  56. package/dist/commands/auth.d.ts +5 -0
  57. package/dist/commands/auth.d.ts.map +1 -0
  58. package/dist/commands/auth.js +68 -0
  59. package/dist/commands/auth.js.map +1 -0
  60. package/dist/commands/balances.d.ts +5 -0
  61. package/dist/commands/balances.d.ts.map +1 -0
  62. package/dist/commands/balances.js +106 -0
  63. package/dist/commands/balances.js.map +1 -0
  64. package/dist/commands/config.d.ts +4 -0
  65. package/dist/commands/config.d.ts.map +1 -0
  66. package/dist/commands/config.js +16 -0
  67. package/dist/commands/config.js.map +1 -0
  68. package/dist/commands/expense-input.d.ts +17 -0
  69. package/dist/commands/expense-input.d.ts.map +1 -0
  70. package/dist/commands/expense-input.js +78 -0
  71. package/dist/commands/expense-input.js.map +1 -0
  72. package/dist/commands/expenses.d.ts +5 -0
  73. package/dist/commands/expenses.d.ts.map +1 -0
  74. package/dist/commands/expenses.js +419 -0
  75. package/dist/commands/expenses.js.map +1 -0
  76. package/dist/commands/groups.d.ts +5 -0
  77. package/dist/commands/groups.d.ts.map +1 -0
  78. package/dist/commands/groups.js +149 -0
  79. package/dist/commands/groups.js.map +1 -0
  80. package/dist/commands/recurring-expenses.d.ts +5 -0
  81. package/dist/commands/recurring-expenses.d.ts.map +1 -0
  82. package/dist/commands/recurring-expenses.js +416 -0
  83. package/dist/commands/recurring-expenses.js.map +1 -0
  84. package/dist/commands/settlements.d.ts +5 -0
  85. package/dist/commands/settlements.d.ts.map +1 -0
  86. package/dist/commands/settlements.js +225 -0
  87. package/dist/commands/settlements.js.map +1 -0
  88. package/dist/commands/shared.d.ts +6 -0
  89. package/dist/commands/shared.d.ts.map +1 -0
  90. package/dist/commands/shared.js +35 -0
  91. package/dist/commands/shared.js.map +1 -0
  92. package/dist/commands/spend-summary.d.ts +5 -0
  93. package/dist/commands/spend-summary.d.ts.map +1 -0
  94. package/dist/commands/spend-summary.js +107 -0
  95. package/dist/commands/spend-summary.js.map +1 -0
  96. package/dist/commands/update.d.ts +9 -0
  97. package/dist/commands/update.d.ts.map +1 -0
  98. package/dist/commands/update.js +78 -0
  99. package/dist/commands/update.js.map +1 -0
  100. package/dist/config.d.ts +14 -0
  101. package/dist/config.d.ts.map +1 -0
  102. package/dist/config.js +52 -0
  103. package/dist/config.js.map +1 -0
  104. package/dist/errors.d.ts +87 -0
  105. package/dist/errors.d.ts.map +1 -0
  106. package/dist/errors.js +183 -0
  107. package/dist/errors.js.map +1 -0
  108. package/dist/index.d.ts +3 -0
  109. package/dist/index.d.ts.map +1 -0
  110. package/dist/index.js +43 -0
  111. package/dist/index.js.map +1 -0
  112. package/dist/interaction.d.ts +16 -0
  113. package/dist/interaction.d.ts.map +1 -0
  114. package/dist/interaction.js +14 -0
  115. package/dist/interaction.js.map +1 -0
  116. package/dist/layers.d.ts +13 -0
  117. package/dist/layers.d.ts.map +1 -0
  118. package/dist/layers.js +17 -0
  119. package/dist/layers.js.map +1 -0
  120. package/dist/output.d.ts +31 -0
  121. package/dist/output.d.ts.map +1 -0
  122. package/dist/output.js +26 -0
  123. package/dist/output.js.map +1 -0
  124. package/dist/update/update-service.d.ts +41 -0
  125. package/dist/update/update-service.d.ts.map +1 -0
  126. package/dist/update/update-service.js +231 -0
  127. package/dist/update/update-service.js.map +1 -0
  128. package/dist/version.d.ts +3 -0
  129. package/dist/version.d.ts.map +1 -0
  130. package/dist/version.js +3 -0
  131. package/dist/version.js.map +1 -0
  132. package/package.json +41 -0
@@ -0,0 +1,419 @@
1
+ import { Console, Effect, Option } from "effect";
2
+ import { Argument, Command, Flag, Prompt } from "effect/unstable/cli";
3
+ import { ApiClient } from "../api/client.js";
4
+ import { CreateExpenseRequest, CreateExpenseResponse, DeleteExpenseRequest, DeleteExpenseResponse, GetExpenseResponse, ListExpensesResponse, UpdateExpenseRequest, UpdateExpenseResponse } from "../api/model.js";
5
+ import { API_WRITE_SCOPE } from "../auth/model.js";
6
+ import { CliInputError } from "../errors.js";
7
+ import { formatTable, printSuccess } from "../output.js";
8
+ import { failInput, parseAllocations, parseMoney, parseOptionalMoney, parsePercentage, localCalendarDate, parseCurrency, parseOptionalCurrency, validateDate, validateDistinctIds, validateIdempotencyKey } from "./expense-input.js";
9
+ import { jsonFlag, reportFailure } from "./shared.js";
10
+ const groupIdFlag = Flag.String("group-id").pipe(Flag.withMetavar("ID"), Flag.withDescription("Only include expenses from this group"), Flag.optional);
11
+ const queryFlag = Flag.String("query").pipe(Flag.withMetavar("TEXT"), Flag.withDescription("Match expense descriptions (maximum 200 characters)"), Flag.optional);
12
+ const fromFlag = Flag.String("from").pipe(Flag.withMetavar("YYYY-MM-DD"), Flag.withDescription("Include expenses on or after this date"), Flag.optional);
13
+ const toFlag = Flag.String("to").pipe(Flag.withMetavar("YYYY-MM-DD"), Flag.withDescription("Include expenses on or before this date"), Flag.optional);
14
+ const paidByIdFlag = Flag.String("paid-by-id").pipe(Flag.withMetavar("MEMBER_ID"), Flag.withDescription("Only include expenses paid by this member"), Flag.optional);
15
+ const isRecurringFlag = Flag.Literals("is-recurring", ["true", "false"]).pipe(Flag.withMetavar("true|false"), Flag.withDescription("Include only recurring-generated or non-recurring expenses"), Flag.map((value) => value === "true"), Flag.optional);
16
+ const isSettledFlag = Flag.Literals("is-settled", ["true", "false"]).pipe(Flag.withMetavar("true|false"), Flag.withDescription("Include only settled or open expenses"), Flag.map((value) => value === "true"), Flag.optional);
17
+ const limitFlag = Flag.Int("limit").pipe(Flag.withMetavar("COUNT"), Flag.withDescription("Return 1 to 50 expenses (default: 20)"), Flag.optional);
18
+ const cursorFlag = Flag.String("cursor").pipe(Flag.withMetavar("CURSOR"), Flag.withDescription("Continue from a previous response's nextCursor"), Flag.optional);
19
+ const createDescriptionFlag = Flag.String("description").pipe(Flag.withMetavar("TEXT"), Flag.withDescription("Expense description (maximum 200 characters)"));
20
+ const createAmountFlag = Flag.String("amount").pipe(Flag.withMetavar("DECIMAL"), Flag.withDescription("Positive amount with no more than two decimal places"));
21
+ const createCurrencyFlag = Flag.String("currency").pipe(Flag.withMetavar("CODE"), Flag.withDescription("Currency: USD, CAD, EUR, or GBP; required to avoid implicit currency"));
22
+ const createPaidByIdFlag = Flag.String("paid-by-id").pipe(Flag.withMetavar("MEMBER_ID"), Flag.withDescription("Member who paid (defaults to the authenticated user)"), Flag.optional);
23
+ const createSplitWithFlag = Flag.String("split-with").pipe(Flag.withMetavar("MEMBER_ID"), Flag.withDescription("Member included in the split; repeat for multiple members (the payer is always included; in a two-person group the other member is used when omitted)"), Flag.between(0, 100));
24
+ const createSplitTypeFlag = Flag.Literals("split-type", ["amount", "percentage", "exact"]).pipe(Flag.withMetavar("amount|percentage|exact"), Flag.withDescription("amount = split equally; percentage; or exact amounts"), Flag.withDefault("amount"));
25
+ const createDateFlag = Flag.String("date").pipe(Flag.withMetavar("YYYY-MM-DD"), Flag.withDescription("Expense date (defaults to today in your local time zone)"), Flag.optional);
26
+ const percentageSplitFlag = Flag.String("percentage-split").pipe(Flag.withMetavar("MEMBER_ID=PERCENT"), Flag.withDescription("Percentage allocation; repeat and ensure the total is 100. Every named member is included in the split"), Flag.between(0, 100));
27
+ const exactSplitFlag = Flag.String("exact-split").pipe(Flag.withMetavar("MEMBER_ID=AMOUNT"), Flag.withDescription("Exact allocation; repeat and ensure the total equals --amount. Every named member is included in the split"), Flag.between(0, 100));
28
+ const idempotencyKeyFlag = Flag.String("idempotency-key").pipe(Flag.withMetavar("KEY"), Flag.withDescription("Reuse a stable key only when retrying the same write"), Flag.optional);
29
+ const updateDescriptionFlag = createDescriptionFlag.pipe(Flag.optional);
30
+ const updateAmountFlag = createAmountFlag.pipe(Flag.optional);
31
+ // Update flags describe changes; create-only defaults do not apply to them.
32
+ const updateCurrencyFlag = Flag.String("currency").pipe(Flag.withMetavar("CODE"), Flag.withDescription("Change the currency: USD, CAD, EUR, or GBP"), Flag.optional);
33
+ const updatePaidByIdFlag = Flag.String("paid-by-id").pipe(Flag.withMetavar("MEMBER_ID"), Flag.withDescription("Change who paid"), Flag.optional);
34
+ const updateSplitWithFlag = Flag.String("split-with").pipe(Flag.withMetavar("MEMBER_ID"), Flag.withDescription("When changing the split, repeat for every member in it besides the payer"), Flag.between(0, 100));
35
+ const updateDateFlag = Flag.String("date").pipe(Flag.withMetavar("YYYY-MM-DD"), Flag.withDescription("Change the expense date (left unchanged when omitted)"), Flag.optional);
36
+ const updateSplitTypeFlag = Flag.Literals("split-type", ["amount", "percentage", "exact"]).pipe(Flag.withMetavar("amount|percentage|exact"), Flag.withDescription("Replace the split mode (amount = split equally) and participant list"), Flag.optional);
37
+ const yesFlag = Flag.Boolean("yes").pipe(Flag.withDescription("Confirm deletion without an interactive prompt"), Flag.withDefault(false));
38
+ const optionalString = (value) => Option.getOrUndefined(value);
39
+ const optionalBoolean = (value) => Option.match(value, {
40
+ onNone: () => undefined,
41
+ onSome: String
42
+ });
43
+ const optionalNumber = (value) => Option.match(value, {
44
+ onNone: () => undefined,
45
+ onSome: String
46
+ });
47
+ const validateOptionalText = (name, value, maximumLength) => Option.match(value, {
48
+ onNone: () => Effect.void,
49
+ onSome: (text) => {
50
+ if (text.length === 0)
51
+ return failInput(`${name} must not be empty`);
52
+ if (maximumLength !== undefined && text.length > maximumLength) {
53
+ return failInput(`${name} must be at most ${maximumLength} characters`);
54
+ }
55
+ return Effect.void;
56
+ }
57
+ });
58
+ const expenseQuery = (filters) => Effect.gen(function* () {
59
+ yield* validateOptionalText("group ID", filters.groupId);
60
+ yield* validateOptionalText("query", filters.query, 200);
61
+ yield* validateDate("from", filters.from);
62
+ yield* validateDate("to", filters.to);
63
+ yield* validateOptionalText("payer ID", filters.paidById);
64
+ yield* validateOptionalText("cursor", filters.cursor);
65
+ const from = optionalString(filters.from);
66
+ const to = optionalString(filters.to);
67
+ if (from !== undefined && to !== undefined && from > to) {
68
+ return yield* failInput("from must be on or before to");
69
+ }
70
+ const limit = Option.getOrUndefined(filters.limit);
71
+ if (limit !== undefined && (limit < 1 || limit > 50)) {
72
+ return yield* failInput("limit must be between 1 and 50");
73
+ }
74
+ return {
75
+ groupId: optionalString(filters.groupId),
76
+ query: optionalString(filters.query),
77
+ from,
78
+ to,
79
+ paidById: optionalString(filters.paidById),
80
+ isRecurring: optionalBoolean(filters.isRecurring),
81
+ isSettled: optionalBoolean(filters.isSettled),
82
+ limit: optionalNumber(filters.limit),
83
+ cursor: optionalString(filters.cursor)
84
+ };
85
+ });
86
+ const expenseStatus = (expense) => expense.isSettled ? "settled" : "open";
87
+ const renderExpensePage = (page) => {
88
+ const content = page.expenses.length === 0
89
+ ? "No expenses found."
90
+ : formatTable(["ID", "DATE", "DESCRIPTION", "GROUP", "PAID BY", "AMOUNT", "STATUS"], page.expenses.map((expense) => [
91
+ expense.id,
92
+ expense.date ?? "—",
93
+ expense.description,
94
+ expense.groupName ?? expense.groupId,
95
+ expense.payer.name,
96
+ `${expense.amount} ${expense.currency}`,
97
+ expenseStatus(expense)
98
+ ]));
99
+ return page.nextCursor === null
100
+ ? content
101
+ : `${content}\n\nNext cursor: ${page.nextCursor}`;
102
+ };
103
+ const renderExpenseDetail = ({ expense }) => {
104
+ const summary = formatTable(["FIELD", "VALUE"], [
105
+ ["ID", expense.id],
106
+ ["Description", expense.description],
107
+ ["Group", expense.groupName ?? expense.groupId],
108
+ ["Date", expense.date ?? "—"],
109
+ ["Amount", `${expense.amount} ${expense.currency}`],
110
+ ["Paid by", expense.payer.name],
111
+ ["Status", expenseStatus(expense)],
112
+ ["Recurring", expense.isRecurring ? "yes" : "no"]
113
+ ]);
114
+ const splits = expense.splits.length === 0
115
+ ? "No splits found."
116
+ : formatTable(["MEMBER", "AMOUNT", "PERCENTAGE", "TYPE"], expense.splits.map((split) => [
117
+ split.name,
118
+ split.amount === null ? "—" : `${split.amount} ${expense.currency}`,
119
+ split.percentage === null ? "—" : `${split.percentage}%`,
120
+ split.splitType
121
+ ]));
122
+ return `${summary}\n\nSplits\n${splits}`;
123
+ };
124
+ const renderCreatedExpense = ({ expense }) => formatTable(["FIELD", "VALUE"], [
125
+ ["ID", expense.id],
126
+ ["Description", expense.description],
127
+ ["Group", expense.groupId],
128
+ ["Date", expense.date],
129
+ ["Amount", `${expense.amount} ${expense.currency}`]
130
+ ]);
131
+ const renderDeletedExpense = ({ expense }) => `Deleted expense ${expense.id}: ${expense.description} (${expense.amount} ${expense.currency})`;
132
+ const list = Command.make("list", {
133
+ groupId: groupIdFlag,
134
+ query: queryFlag,
135
+ from: fromFlag,
136
+ to: toFlag,
137
+ paidById: paidByIdFlag,
138
+ isRecurring: isRecurringFlag,
139
+ isSettled: isSettledFlag,
140
+ limit: limitFlag,
141
+ cursor: cursorFlag,
142
+ json: jsonFlag
143
+ }, Effect.fn(function* (filters) {
144
+ const api = yield* ApiClient;
145
+ const query = yield* reportFailure(expenseQuery(filters), filters.json);
146
+ const response = yield* reportFailure(api.get({
147
+ path: "/expenses",
148
+ query,
149
+ schema: ListExpensesResponse
150
+ }), filters.json);
151
+ yield* printSuccess({
152
+ data: response,
153
+ json: filters.json,
154
+ renderHuman: renderExpensePage
155
+ });
156
+ })).pipe(Command.withDescription("Search and page through expense history"));
157
+ const get = Command.make("get", {
158
+ expenseId: Argument.String("expense-id"),
159
+ json: jsonFlag
160
+ }, Effect.fn(function* ({ expenseId, json }) {
161
+ const api = yield* ApiClient;
162
+ const response = yield* reportFailure(api.get({
163
+ path: `/expenses/${encodeURIComponent(expenseId)}`,
164
+ schema: GetExpenseResponse
165
+ }), json);
166
+ yield* printSuccess({
167
+ data: response,
168
+ json,
169
+ renderHuman: renderExpenseDetail
170
+ });
171
+ })).pipe(Command.withDescription("Get one expense and its split details"));
172
+ const create = Command.make("create", {
173
+ groupId: Argument.String("group-id"),
174
+ description: createDescriptionFlag,
175
+ amount: createAmountFlag,
176
+ currency: createCurrencyFlag,
177
+ paidById: createPaidByIdFlag,
178
+ splitWith: createSplitWithFlag,
179
+ splitType: createSplitTypeFlag,
180
+ date: createDateFlag,
181
+ percentageSplits: percentageSplitFlag,
182
+ exactSplits: exactSplitFlag,
183
+ idempotencyKey: idempotencyKeyFlag,
184
+ json: jsonFlag
185
+ }, Effect.fn(function* (options) {
186
+ const description = options.description.trim();
187
+ if (description.length === 0 || description.length > 200) {
188
+ return yield* reportFailure(failInput("description must contain 1 to 200 characters"), options.json);
189
+ }
190
+ const amount = yield* reportFailure(parseMoney("amount", options.amount), options.json);
191
+ const currency = yield* reportFailure(parseCurrency(options.currency), options.json);
192
+ yield* reportFailure(validateDate("date", options.date), options.json);
193
+ yield* reportFailure(validateDistinctIds("split-with", options.splitWith), options.json);
194
+ if (options.splitWith.some((id) => id.length === 0)) {
195
+ return yield* reportFailure(failInput("split-with member IDs must not be empty"), options.json);
196
+ }
197
+ const paidById = Option.getOrUndefined(options.paidById);
198
+ if (paidById !== undefined && paidById.length === 0) {
199
+ return yield* reportFailure(failInput("paid-by-id must not be empty"), options.json);
200
+ }
201
+ const suppliedKey = Option.getOrUndefined(options.idempotencyKey);
202
+ yield* reportFailure(validateIdempotencyKey(suppliedKey), options.json);
203
+ const percentageSplits = yield* reportFailure(parseAllocations("percentage-split", options.percentageSplits, parsePercentage), options.json);
204
+ const exactSplits = yield* reportFailure(parseAllocations("exact-split", options.exactSplits, (value) => parseMoney("exact split amount", value)), options.json);
205
+ if (options.splitType === "amount" &&
206
+ (options.percentageSplits.length > 0 || options.exactSplits.length > 0)) {
207
+ return yield* reportFailure(failInput("amount splits do not accept percentage-split or exact-split"), options.json);
208
+ }
209
+ if (options.splitType === "percentage") {
210
+ if (options.percentageSplits.length === 0) {
211
+ return yield* reportFailure(failInput("percentage splits require at least one percentage-split"), options.json);
212
+ }
213
+ if (options.exactSplits.length > 0) {
214
+ return yield* reportFailure(failInput("percentage splits do not accept exact-split"), options.json);
215
+ }
216
+ const total = Object.values(percentageSplits).reduce((sum, value) => sum + value, 0);
217
+ if (Math.abs(total - 100) > 0.01) {
218
+ return yield* reportFailure(failInput("percentage-split values must total 100"), options.json);
219
+ }
220
+ }
221
+ if (options.splitType === "exact") {
222
+ if (options.exactSplits.length === 0) {
223
+ return yield* reportFailure(failInput("exact splits require at least one exact-split"), options.json);
224
+ }
225
+ if (options.percentageSplits.length > 0) {
226
+ return yield* reportFailure(failInput("exact splits do not accept percentage-split"), options.json);
227
+ }
228
+ const totalInCents = Object.values(exactSplits).reduce((sum, value) => sum + Math.round(value * 100), 0);
229
+ if (totalInCents !== Math.round(amount * 100)) {
230
+ return yield* reportFailure(failInput("exact-split values must total the expense amount"), options.json);
231
+ }
232
+ }
233
+ const api = yield* ApiClient;
234
+ const { data: response, replayed } = yield* reportFailure(api.post({
235
+ path: `/groups/${encodeURIComponent(options.groupId)}/expenses`,
236
+ scope: API_WRITE_SCOPE,
237
+ body: {
238
+ description,
239
+ amount,
240
+ currency,
241
+ splitWith: [...options.splitWith],
242
+ splitType: options.splitType,
243
+ ...(paidById === undefined ? {} : { paidById }),
244
+ date: Option.getOrElse(options.date, () => localCalendarDate()),
245
+ ...(options.splitType === "percentage" ? { percentageSplits } : {}),
246
+ ...(options.splitType === "exact" ? { exactSplits } : {})
247
+ },
248
+ bodySchema: CreateExpenseRequest,
249
+ schema: CreateExpenseResponse,
250
+ ...(suppliedKey === undefined ? {} : { idempotencyKey: suppliedKey })
251
+ }), options.json);
252
+ yield* printSuccess({
253
+ data: response,
254
+ replayed,
255
+ json: options.json,
256
+ renderHuman: renderCreatedExpense
257
+ });
258
+ })).pipe(Command.withDescription("Create an expense in a group"));
259
+ const update = Command.make("update", {
260
+ expenseId: Argument.String("expense-id"),
261
+ description: updateDescriptionFlag,
262
+ amount: updateAmountFlag,
263
+ currency: updateCurrencyFlag,
264
+ paidById: updatePaidByIdFlag,
265
+ splitWith: updateSplitWithFlag,
266
+ splitType: updateSplitTypeFlag,
267
+ date: updateDateFlag,
268
+ percentageSplits: percentageSplitFlag,
269
+ exactSplits: exactSplitFlag,
270
+ idempotencyKey: idempotencyKeyFlag,
271
+ json: jsonFlag
272
+ }, Effect.fn(function* (options) {
273
+ const rawDescription = Option.getOrUndefined(options.description);
274
+ const description = rawDescription?.trim();
275
+ if (description !== undefined &&
276
+ (description.length === 0 || description.length > 200)) {
277
+ return yield* reportFailure(failInput("description must contain 1 to 200 characters"), options.json);
278
+ }
279
+ const amount = yield* reportFailure(parseOptionalMoney("amount", options.amount), options.json);
280
+ const currency = yield* reportFailure(parseOptionalCurrency(options.currency), options.json);
281
+ yield* reportFailure(validateDate("date", options.date), options.json);
282
+ yield* reportFailure(validateDistinctIds("split-with", options.splitWith), options.json);
283
+ const paidById = Option.getOrUndefined(options.paidById);
284
+ if (paidById !== undefined && paidById.length === 0) {
285
+ return yield* reportFailure(failInput("paid-by-id must not be empty"), options.json);
286
+ }
287
+ const suppliedKey = Option.getOrUndefined(options.idempotencyKey);
288
+ yield* reportFailure(validateIdempotencyKey(suppliedKey), options.json);
289
+ const percentageSplits = yield* reportFailure(parseAllocations("percentage-split", options.percentageSplits, parsePercentage), options.json);
290
+ const exactSplits = yield* reportFailure(parseAllocations("exact-split", options.exactSplits, (value) => parseMoney("exact split amount", value)), options.json);
291
+ const splitType = Option.getOrUndefined(options.splitType);
292
+ const touchesSplit = splitType !== undefined ||
293
+ options.splitWith.length > 0 ||
294
+ options.percentageSplits.length > 0 ||
295
+ options.exactSplits.length > 0;
296
+ if (touchesSplit && splitType === undefined) {
297
+ return yield* reportFailure(failInput("split updates require split-type and the complete participant list"), options.json);
298
+ }
299
+ if (splitType === "amount" &&
300
+ (options.percentageSplits.length > 0 || options.exactSplits.length > 0)) {
301
+ return yield* reportFailure(failInput("amount splits do not accept percentage-split or exact-split"), options.json);
302
+ }
303
+ if (splitType === "percentage") {
304
+ if (options.percentageSplits.length === 0) {
305
+ return yield* reportFailure(failInput("percentage splits require at least one percentage-split"), options.json);
306
+ }
307
+ if (options.exactSplits.length > 0) {
308
+ return yield* reportFailure(failInput("percentage splits do not accept exact-split"), options.json);
309
+ }
310
+ const total = Object.values(percentageSplits).reduce((sum, value) => sum + value, 0);
311
+ if (Math.abs(total - 100) > 0.01) {
312
+ return yield* reportFailure(failInput("percentage-split values must total 100"), options.json);
313
+ }
314
+ }
315
+ if (splitType === "exact" && options.exactSplits.length === 0) {
316
+ return yield* reportFailure(failInput("exact splits require at least one exact-split"), options.json);
317
+ }
318
+ if (splitType === "exact" && options.percentageSplits.length > 0) {
319
+ return yield* reportFailure(failInput("exact splits do not accept percentage-split"), options.json);
320
+ }
321
+ const date = Option.getOrUndefined(options.date);
322
+ const body = {
323
+ ...(description === undefined ? {} : { description }),
324
+ ...(amount === undefined ? {} : { amount }),
325
+ ...(currency === undefined ? {} : { currency }),
326
+ ...(paidById === undefined ? {} : { paidById }),
327
+ ...(date === undefined ? {} : { date }),
328
+ ...(splitType === undefined
329
+ ? {}
330
+ : { splitType, splitWith: [...options.splitWith] }),
331
+ ...(splitType === "percentage" ? { percentageSplits } : {}),
332
+ ...(splitType === "exact" ? { exactSplits } : {})
333
+ };
334
+ if (Object.keys(body).length === 0) {
335
+ return yield* reportFailure(failInput("provide at least one field to update"), options.json);
336
+ }
337
+ const api = yield* ApiClient;
338
+ if (splitType === "exact") {
339
+ const current = yield* reportFailure(api.get({
340
+ path: `/expenses/${encodeURIComponent(options.expenseId)}`,
341
+ schema: GetExpenseResponse
342
+ }), options.json);
343
+ const expectedInCents = Math.round((amount ?? current.expense.amount) * 100);
344
+ const totalInCents = Object.values(exactSplits).reduce((sum, value) => sum + Math.round(value * 100), 0);
345
+ if (totalInCents !== expectedInCents) {
346
+ return yield* reportFailure(failInput("exact-split values must total the updated expense amount"), options.json);
347
+ }
348
+ }
349
+ const { data: response, replayed } = yield* reportFailure(api.patch({
350
+ path: `/expenses/${encodeURIComponent(options.expenseId)}`,
351
+ body,
352
+ bodySchema: UpdateExpenseRequest,
353
+ schema: UpdateExpenseResponse,
354
+ ...(suppliedKey === undefined ? {} : { idempotencyKey: suppliedKey })
355
+ }), options.json);
356
+ yield* printSuccess({
357
+ data: response,
358
+ replayed,
359
+ json: options.json,
360
+ renderHuman: renderExpenseDetail
361
+ });
362
+ })).pipe(Command.withDescription("Update an expense"));
363
+ const deleteExpense = Command.make("delete", {
364
+ expenseId: Argument.String("expense-id"),
365
+ yes: yesFlag,
366
+ idempotencyKey: idempotencyKeyFlag,
367
+ json: jsonFlag
368
+ }, Effect.fn(function* ({ expenseId, yes, idempotencyKey, json }) {
369
+ if (!yes && (json || !process.stdin.isTTY)) {
370
+ return yield* reportFailure(failInput("expense deletion requires --yes in non-interactive mode"), json);
371
+ }
372
+ const suppliedKey = Option.getOrUndefined(idempotencyKey);
373
+ yield* reportFailure(validateIdempotencyKey(suppliedKey), json);
374
+ const api = yield* ApiClient;
375
+ const targetResult = yield* Effect.result(api.get({
376
+ path: `/expenses/${encodeURIComponent(expenseId)}`,
377
+ schema: GetExpenseResponse
378
+ }));
379
+ // A retry after a lost response finds the expense already gone. With the
380
+ // original idempotency key, send the delete anyway: the server returns the
381
+ // original result for that key, or a genuine NOT_FOUND.
382
+ const retryingDeletedTarget = targetResult._tag === "Failure" &&
383
+ suppliedKey !== undefined &&
384
+ targetResult.failure._tag === "ApiRequestError" &&
385
+ targetResult.failure.status === 404;
386
+ if (targetResult._tag === "Failure" && !retryingDeletedTarget) {
387
+ return yield* reportFailure(Effect.fail(targetResult.failure), json);
388
+ }
389
+ const target = targetResult._tag === "Success" ? targetResult.success : undefined;
390
+ if (!yes && target !== undefined) {
391
+ yield* Console.log(`About to delete:\n${renderExpenseDetail(target)}`);
392
+ const confirmed = yield* Prompt.run(Prompt.Confirm({
393
+ message: `Permanently delete expense ${target.expense.id}?`,
394
+ initial: false
395
+ }));
396
+ if (!confirmed) {
397
+ yield* Console.log("Deletion cancelled.");
398
+ return;
399
+ }
400
+ }
401
+ const { data: response, replayed } = yield* reportFailure(api.delete({
402
+ path: `/expenses/${encodeURIComponent(expenseId)}`,
403
+ body: {
404
+ confirmed: true,
405
+ userIntent: `Delete expense ${expenseId} via AllSquare CLI after explicit confirmation`
406
+ },
407
+ bodySchema: DeleteExpenseRequest,
408
+ schema: DeleteExpenseResponse,
409
+ ...(suppliedKey === undefined ? {} : { idempotencyKey: suppliedKey })
410
+ }), json);
411
+ yield* printSuccess({
412
+ data: response,
413
+ replayed,
414
+ json,
415
+ renderHuman: renderDeletedExpense
416
+ });
417
+ })).pipe(Command.withDescription("Delete an expense after explicit confirmation"));
418
+ export const expensesCommand = Command.make("expenses").pipe(Command.withDescription("Inspect and manage expenses"), Command.withSubcommands([list, get, create, update, deleteExpense]));
419
+ //# sourceMappingURL=expenses.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expenses.js","sourceRoot":"","sources":["../../src/commands/expenses.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { Command } from "effect/unstable/cli";
2
+ import { ApiClient } from "../api/client.js";
3
+ import { CliInputError } from "../errors.js";
4
+ export declare const groupsCommand: Command.Command<"groups", {}, {}, CliInputError | import("../api/client.js").ApiClientError, ApiClient>;
5
+ //# sourceMappingURL=groups.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"groups.d.ts","sourceRoot":"","sources":["../../src/commands/groups.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,OAAO,EAAQ,MAAM,qBAAqB,CAAA;AAE7D,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAc5C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAoP5C,eAAO,MAAM,aAAa,yGAGzB,CAAA"}
@@ -0,0 +1,149 @@
1
+ import { Effect, Option } from "effect";
2
+ import { Argument, Command, Flag } from "effect/unstable/cli";
3
+ import { ApiClient } from "../api/client.js";
4
+ import { AddGroupMemberRequest, AddGroupMemberResponse, CreateGroupRequest, CreateGroupResponse, ListGroupMembersResponse, ListGroupsResponse } from "../api/model.js";
5
+ import { API_WRITE_SCOPE } from "../auth/model.js";
6
+ import { CliInputError } from "../errors.js";
7
+ import { formatTable, printSuccess } from "../output.js";
8
+ import { parseCurrency } from "./expense-input.js";
9
+ import { jsonFlag, reportFailure } from "./shared.js";
10
+ const nameFlag = Flag.String("name").pipe(Flag.withMetavar("TEXT"), Flag.withDescription("Group name (maximum 100 characters)"));
11
+ const currencyFlag = Flag.String("currency").pipe(Flag.withMetavar("CODE"), Flag.withDescription("Default currency: USD, CAD, EUR, or GBP"));
12
+ const memberEmailFlag = Flag.String("member-email").pipe(Flag.withMetavar("EMAIL"), Flag.withDescription("Initial member to add or invite; repeat for up to 20 addresses"), Flag.between(0, 20));
13
+ const emailFlag = Flag.String("email").pipe(Flag.withMetavar("EMAIL"), Flag.withDescription("Existing account or invitation email address"));
14
+ const idempotencyKeyFlag = Flag.String("idempotency-key").pipe(Flag.withMetavar("KEY"), Flag.withDescription("Reuse a stable key only when retrying the same write"), Flag.optional);
15
+ const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
16
+ const idempotencyKeyPattern = /^[A-Za-z0-9._:-]+$/;
17
+ const failInput = (message) => Effect.fail(new CliInputError({ message }));
18
+ const normalizeEmail = (email) => {
19
+ const normalized = email.trim().toLowerCase();
20
+ return normalized.length <= 254 && emailPattern.test(normalized)
21
+ ? Effect.succeed(normalized)
22
+ : failInput(`invalid email address: ${email}`);
23
+ };
24
+ const validateIdempotencyKey = (value) => value === undefined ||
25
+ (value.length <= 200 && idempotencyKeyPattern.test(value))
26
+ ? Effect.void
27
+ : failInput("idempotency-key must contain 1 to 200 letters, numbers, dots, underscores, colons, or hyphens");
28
+ const normalizeMemberEmails = (emails) => Effect.gen(function* () {
29
+ const normalized = [];
30
+ for (const email of emails)
31
+ normalized.push(yield* normalizeEmail(email));
32
+ if (new Set(normalized).size !== normalized.length) {
33
+ return yield* failInput("member-email must not contain duplicate addresses");
34
+ }
35
+ return normalized;
36
+ });
37
+ const renderCreatedGroup = ({ group, membersAdded, membersNotified, invitationsCreated, invitationEmailsSent }) => formatTable(["FIELD", "VALUE"], [
38
+ ["ID", group.id],
39
+ ["Name", group.name],
40
+ ["Default currency", group.defaultCurrency],
41
+ ["Members added", String(membersAdded)],
42
+ ["Member notifications sent", String(membersNotified)],
43
+ ["Invitations created", String(invitationsCreated)],
44
+ ["Invitation emails sent", String(invitationEmailsSent)]
45
+ ]);
46
+ const renderAddedGroupMember = (response) => formatTable(["FIELD", "VALUE"], [
47
+ ["Status", response.status],
48
+ ["Group", response.groupId],
49
+ ["Email", response.email],
50
+ ...(response.status === "invited"
51
+ ? [["Invitation expires", response.expiresAt]]
52
+ : [["User ID", response.userId]]),
53
+ ["Email sent", response.emailSent ? "yes" : "no"]
54
+ ]);
55
+ const list = Command.make("list", { json: jsonFlag }, Effect.fn(function* ({ json }) {
56
+ const api = yield* ApiClient;
57
+ const response = yield* reportFailure(api.get({ path: "/groups", schema: ListGroupsResponse }), json);
58
+ yield* printSuccess({
59
+ data: response,
60
+ json,
61
+ renderHuman: ({ groups }) => groups.length === 0
62
+ ? "No groups found."
63
+ : formatTable(["ID", "NAME", "CURRENCY"], groups.map((group) => [group.id, group.name, group.defaultCurrency]))
64
+ });
65
+ })).pipe(Command.withDescription("List groups you can access"));
66
+ const members = Command.make("members", {
67
+ groupId: Argument.String("group-id"),
68
+ json: jsonFlag
69
+ }, Effect.fn(function* ({ groupId, json }) {
70
+ const api = yield* ApiClient;
71
+ const response = yield* reportFailure(api.get({
72
+ path: `/groups/${encodeURIComponent(groupId)}/members`,
73
+ schema: ListGroupMembersResponse
74
+ }), json);
75
+ yield* printSuccess({
76
+ data: response,
77
+ json,
78
+ renderHuman: ({ members }) => members.length === 0
79
+ ? "No members found."
80
+ : formatTable(["ID", "NAME", "EMAIL", "CURRENT USER"], members.map((member) => [
81
+ member.id,
82
+ member.name,
83
+ member.email ?? "—",
84
+ member.isCurrentUser ? "yes" : ""
85
+ ]))
86
+ });
87
+ })).pipe(Command.withDescription("List members of a group"));
88
+ const create = Command.make("create", {
89
+ name: nameFlag,
90
+ currency: currencyFlag,
91
+ memberEmails: memberEmailFlag,
92
+ idempotencyKey: idempotencyKeyFlag,
93
+ json: jsonFlag
94
+ }, Effect.fn(function* (options) {
95
+ const name = options.name.trim();
96
+ if (name.length === 0 || name.length > 100) {
97
+ return yield* reportFailure(failInput("name must contain 1 to 100 characters"), options.json);
98
+ }
99
+ const currency = yield* reportFailure(parseCurrency(options.currency), options.json);
100
+ const memberEmails = yield* reportFailure(normalizeMemberEmails(options.memberEmails), options.json);
101
+ const suppliedKey = Option.getOrUndefined(options.idempotencyKey);
102
+ yield* reportFailure(validateIdempotencyKey(suppliedKey), options.json);
103
+ const api = yield* ApiClient;
104
+ const { data: response, replayed } = yield* reportFailure(api.post({
105
+ path: "/groups",
106
+ scope: API_WRITE_SCOPE,
107
+ body: {
108
+ name,
109
+ currency,
110
+ ...(memberEmails.length === 0 ? {} : { memberEmails: [...memberEmails] })
111
+ },
112
+ bodySchema: CreateGroupRequest,
113
+ schema: CreateGroupResponse,
114
+ ...(suppliedKey === undefined ? {} : { idempotencyKey: suppliedKey })
115
+ }), options.json);
116
+ yield* printSuccess({
117
+ data: response,
118
+ replayed,
119
+ json: options.json,
120
+ renderHuman: renderCreatedGroup
121
+ });
122
+ })).pipe(Command.withDescription("Create a group and optionally add or invite members"));
123
+ const addMember = Command.make("add-member", {
124
+ groupId: Argument.String("group-id"),
125
+ email: emailFlag,
126
+ idempotencyKey: idempotencyKeyFlag,
127
+ json: jsonFlag
128
+ }, Effect.fn(function* ({ groupId, email, idempotencyKey, json }) {
129
+ const normalizedEmail = yield* reportFailure(normalizeEmail(email), json);
130
+ const suppliedKey = Option.getOrUndefined(idempotencyKey);
131
+ yield* reportFailure(validateIdempotencyKey(suppliedKey), json);
132
+ const api = yield* ApiClient;
133
+ const { data: response, replayed } = yield* reportFailure(api.post({
134
+ path: `/groups/${encodeURIComponent(groupId)}/members`,
135
+ scope: API_WRITE_SCOPE,
136
+ body: { email: normalizedEmail },
137
+ bodySchema: AddGroupMemberRequest,
138
+ schema: AddGroupMemberResponse,
139
+ ...(suppliedKey === undefined ? {} : { idempotencyKey: suppliedKey })
140
+ }), json);
141
+ yield* printSuccess({
142
+ data: response,
143
+ replayed,
144
+ json,
145
+ renderHuman: renderAddedGroupMember
146
+ });
147
+ })).pipe(Command.withDescription("Add an existing user or invite an email address"));
148
+ export const groupsCommand = Command.make("groups").pipe(Command.withDescription("Inspect and manage groups and membership"), Command.withSubcommands([list, members, create, addMember]));
149
+ //# sourceMappingURL=groups.js.map