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,68 @@
1
+ import { Console, Effect } from "effect";
2
+ import { Command, Flag } from "effect/unstable/cli";
3
+ import { AuthService } from "../auth/auth-service.js";
4
+ import { CliInputError } from "../errors.js";
5
+ import { printSuccess } from "../output.js";
6
+ import { jsonFlag, reportFailure } from "./shared.js";
7
+ const renderStatus = (status) => {
8
+ if (!status.authenticated) {
9
+ return `Not logged in\nAPI URL: ${status.apiUrl}`;
10
+ }
11
+ return [
12
+ "Logged in",
13
+ `API URL: ${status.apiUrl}`,
14
+ `Scopes: ${status.scopes?.join(", ") ?? "none"}`,
15
+ `Access token expires: ${status.expiresAt ?? "unknown"}`
16
+ ].join("\n");
17
+ };
18
+ const printStatus = (status, json) => printSuccess({
19
+ data: status,
20
+ json,
21
+ renderHuman: renderStatus
22
+ });
23
+ const login = Command.make("login", {
24
+ write: Flag.Boolean("write").pipe(Flag.withDescription("Request read and write access (now the default)"), Flag.withDefault(false)),
25
+ readOnly: Flag.Boolean("read-only").pipe(Flag.withDescription("Request read access only"), Flag.withDefault(false)),
26
+ noBrowser: Flag.Boolean("no-browser").pipe(Flag.withDescription("Print the authorization URL without opening a browser"), Flag.withDefault(false)),
27
+ json: jsonFlag
28
+ }, Effect.fn(function* ({ write, readOnly, noBrowser, json }) {
29
+ if (write && readOnly) {
30
+ return yield* reportFailure(Effect.fail(new CliInputError({
31
+ message: "Choose either --read-only or --write, not both"
32
+ })), json);
33
+ }
34
+ const auth = yield* AuthService;
35
+ const status = yield* reportFailure(auth.login({
36
+ write: !readOnly,
37
+ noBrowser,
38
+ onAuthorizationUrl: (url) => Console.error(`Authorize AllSquare CLI:\n${url}`),
39
+ onBrowserOpenError: (error) => Console.error(`Could not open your browser automatically: ${error.message}`)
40
+ }), json);
41
+ if (!json && status.replacedSessionRevocation === "unconfirmed") {
42
+ yield* Console.error("Could not confirm revocation of the previous session; revoke older CLI access in AllSquare settings if needed.");
43
+ }
44
+ yield* printStatus(status, json);
45
+ })).pipe(Command.withDescription("Log in with OAuth authorization code and PKCE"));
46
+ const status = Command.make("status", { json: jsonFlag }, Effect.fn(function* ({ json }) {
47
+ const auth = yield* AuthService;
48
+ const current = yield* reportFailure(auth.status, json);
49
+ yield* printStatus(current, json);
50
+ })).pipe(Command.withDescription("Show the current authentication status"));
51
+ const refresh = Command.make("refresh", { json: jsonFlag }, Effect.fn(function* ({ json }) {
52
+ const auth = yield* AuthService;
53
+ const current = yield* reportFailure(auth.refresh, json);
54
+ yield* printStatus(current, json);
55
+ })).pipe(Command.withDescription("Refresh the current OAuth session"));
56
+ const logout = Command.make("logout", { json: jsonFlag }, Effect.fn(function* ({ json }) {
57
+ const auth = yield* AuthService;
58
+ const current = yield* reportFailure(auth.logout, json);
59
+ yield* printSuccess({
60
+ data: current,
61
+ json,
62
+ renderHuman: () => current.revocation === "unconfirmed"
63
+ ? "Logged out locally. Server revocation could not be confirmed; revoke this connection in AllSquare settings if needed."
64
+ : "Logged out"
65
+ });
66
+ })).pipe(Command.withDescription("Revoke the current OAuth session and log out"));
67
+ export const authCommand = Command.make("auth").pipe(Command.withDescription("Manage OAuth authentication"), Command.withSubcommands([login, status, refresh, logout]));
68
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.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 balancesCommand: Command.Command<"balances", {}, {}, CliInputError | import("../api/client.js").ApiClientError, ApiClient>;
5
+ //# sourceMappingURL=balances.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"balances.d.ts","sourceRoot":"","sources":["../../src/commands/balances.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,OAAO,EAAQ,MAAM,qBAAqB,CAAA;AAE7D,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAS5C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AA2I5C,eAAO,MAAM,eAAe,2GAG3B,CAAA"}
@@ -0,0 +1,106 @@
1
+ import { Effect, Option } from "effect";
2
+ import { Argument, Command, Flag } from "effect/unstable/cli";
3
+ import { ApiClient } from "../api/client.js";
4
+ import { GetAllBalancesResponse, GetGroupBalancesResponse } from "../api/model.js";
5
+ import { CliInputError } from "../errors.js";
6
+ import { formatTable, printSuccess } from "../output.js";
7
+ import { isCurrency } from "./expense-input.js";
8
+ import { jsonFlag, reportFailure } from "./shared.js";
9
+ const currencyFlag = Flag.String("currency").pipe(Flag.withMetavar("CODE"), Flag.withDescription("Convert balances to USD, CAD, EUR, or GBP"), Flag.map((currency) => currency.toUpperCase()), Flag.optional);
10
+ const validateCurrency = (currency) => Option.match(currency, {
11
+ onNone: () => Effect.succeed(Option.none()),
12
+ onSome: (value) => isCurrency(value)
13
+ ? Effect.succeed(Option.some(value))
14
+ : Effect.fail(new CliInputError({
15
+ message: "currency must be one of USD, CAD, EUR, GBP"
16
+ }))
17
+ });
18
+ const currencyQuery = (currency) => ({
19
+ currency: Option.getOrUndefined(currency)
20
+ });
21
+ const renderAllBalances = (balances) => {
22
+ const totals = Object.entries(balances.totalsByCurrency);
23
+ const sections = [];
24
+ if (totals.length > 0) {
25
+ sections.push(formatTable(["CURRENCY", "YOU OWE", "OWED TO YOU", "NET"], totals.map(([currency, value]) => [
26
+ currency,
27
+ String(value.youOwe),
28
+ String(value.youAreOwed),
29
+ String(value.net)
30
+ ])));
31
+ }
32
+ const people = balances.groups.flatMap((group) => [
33
+ ...group.youOwe.map((entry) => [
34
+ group.groupName ?? group.groupId,
35
+ entry.name,
36
+ "you owe",
37
+ String(entry.amount),
38
+ group.currency
39
+ ]),
40
+ ...group.youAreOwed.map((entry) => [
41
+ group.groupName ?? group.groupId,
42
+ entry.name,
43
+ "owes you",
44
+ String(entry.amount),
45
+ group.currency
46
+ ])
47
+ ]);
48
+ if (people.length > 0) {
49
+ sections.push(formatTable(["GROUP", "PERSON", "DIRECTION", "AMOUNT", "CURRENCY"], people));
50
+ }
51
+ return sections.length === 0 ? "No open balances." : sections.join("\n\n");
52
+ };
53
+ const renderGroupBalances = (balances) => {
54
+ const rows = [
55
+ ...balances.youOwe.map((entry) => [
56
+ entry.name,
57
+ "you owe",
58
+ entry.amount,
59
+ entry.currency
60
+ ]),
61
+ ...balances.youAreOwed.map((entry) => [
62
+ entry.name,
63
+ "owes you",
64
+ entry.amount,
65
+ entry.currency
66
+ ])
67
+ ];
68
+ const detail = rows.length === 0
69
+ ? "No open balances."
70
+ : formatTable(["PERSON", "DIRECTION", "AMOUNT", "CURRENCY"], rows);
71
+ return `Total spent: ${balances.totalSpent} ${balances.currency}\n\n${detail}`;
72
+ };
73
+ const list = Command.make("list", { currency: currencyFlag, json: jsonFlag }, Effect.fn(function* ({ currency, json }) {
74
+ const api = yield* ApiClient;
75
+ const validatedCurrency = yield* reportFailure(validateCurrency(currency), json);
76
+ const response = yield* reportFailure(api.get({
77
+ path: "/balances",
78
+ query: currencyQuery(validatedCurrency),
79
+ schema: GetAllBalancesResponse
80
+ }), json);
81
+ yield* printSuccess({
82
+ data: response,
83
+ json,
84
+ renderHuman: renderAllBalances
85
+ });
86
+ })).pipe(Command.withDescription("List open balances across all groups"));
87
+ const show = Command.make("show", {
88
+ groupId: Argument.String("group-id"),
89
+ currency: currencyFlag,
90
+ json: jsonFlag
91
+ }, Effect.fn(function* ({ groupId, currency, json }) {
92
+ const api = yield* ApiClient;
93
+ const validatedCurrency = yield* reportFailure(validateCurrency(currency), json);
94
+ const response = yield* reportFailure(api.get({
95
+ path: `/groups/${encodeURIComponent(groupId)}/balances`,
96
+ query: currencyQuery(validatedCurrency),
97
+ schema: GetGroupBalancesResponse
98
+ }), json);
99
+ yield* printSuccess({
100
+ data: response,
101
+ json,
102
+ renderHuman: renderGroupBalances
103
+ });
104
+ })).pipe(Command.withDescription("Show open balances for one group"));
105
+ export const balancesCommand = Command.make("balances").pipe(Command.withDescription("Inspect open balances"), Command.withSubcommands([list, show]));
106
+ //# sourceMappingURL=balances.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"balances.js","sourceRoot":"","sources":["../../src/commands/balances.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { Command } from "effect/unstable/cli";
2
+ import { CliConfig } from "../config.js";
3
+ export declare const configCommand: Command.Command<"config", {}, {}, import("../errors.js").CliConfigError, CliConfig>;
4
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAE7C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAqBxC,eAAO,MAAM,aAAa,qFAGzB,CAAA"}
@@ -0,0 +1,16 @@
1
+ import { Effect } from "effect";
2
+ import { Command } from "effect/unstable/cli";
3
+ import { CliConfig } from "../config.js";
4
+ import { printSuccess } from "../output.js";
5
+ import { jsonFlag, reportFailure } from "./shared.js";
6
+ const show = Command.make("show", { json: jsonFlag }, Effect.fn(function* ({ json }) {
7
+ const config = yield* CliConfig;
8
+ const apiUrl = yield* reportFailure(config.apiUrl, json);
9
+ yield* printSuccess({
10
+ data: { apiUrl },
11
+ json,
12
+ renderHuman: ({ apiUrl }) => `API URL: ${apiUrl}`
13
+ });
14
+ })).pipe(Command.withDescription("Show the resolved CLI configuration"));
15
+ export const configCommand = Command.make("config").pipe(Command.withDescription("Inspect CLI configuration"), Command.withSubcommands([show]));
16
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAE7C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAErD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CACvB,MAAM,EACN,EAAE,IAAI,EAAE,QAAQ,EAAE,EAClB,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAC,EAAE,IAAI,EAAE;IAC1B,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,SAAS,CAAA;IAC/B,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;IAExD,KAAK,CAAC,CAAC,YAAY,CAAC;QAClB,IAAI,EAAE,EAAE,MAAM,EAAE;QAChB,IAAI;QACJ,WAAW,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,YAAY,MAAM,EAAE;KAClD,CAAC,CAAA;AACJ,CAAC,CAAC,CACH,CAAC,IAAI,CACJ,OAAO,CAAC,eAAe,CAAC,qCAAqC,CAAC,CAC/D,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CACtD,OAAO,CAAC,eAAe,CAAC,2BAA2B,CAAC,EACpD,OAAO,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,CAChC,CAAA"}
@@ -0,0 +1,17 @@
1
+ import { Effect, Option } from "effect";
2
+ import { SUPPORTED_CURRENCIES } from "../api/model.js";
3
+ import { CliInputError } from "../errors.js";
4
+ export declare const failInput: (message: string) => Effect.Effect<never, CliInputError>;
5
+ export declare const localCalendarDate: (now?: Date) => string;
6
+ export type Currency = (typeof SUPPORTED_CURRENCIES)[number];
7
+ export declare const isCurrency: (value: string) => value is Currency;
8
+ export declare const parseCurrency: (raw: string) => Effect.Effect<Currency, CliInputError>;
9
+ export declare const parseOptionalCurrency: (raw: Option.Option<string>) => Effect.Effect<Currency | undefined, CliInputError>;
10
+ export declare const validateDate: (name: string, value: Option.Option<string>) => Effect.Effect<void, CliInputError>;
11
+ export declare const parseMoney: (name: string, value: string) => Effect.Effect<number, CliInputError>;
12
+ export declare const parseOptionalMoney: (name: string, value: Option.Option<string>) => Effect.Effect<number | undefined, CliInputError>;
13
+ export declare const validateIdempotencyKey: (value: string | undefined) => Effect.Effect<void, CliInputError>;
14
+ export declare const parseAllocations: (name: string, values: ReadonlyArray<string>, parseValue: (value: string) => Effect.Effect<number, CliInputError>) => Effect.Effect<Readonly<Record<string, number>>, CliInputError>;
15
+ export declare const parsePercentage: (value: string) => Effect.Effect<number, CliInputError>;
16
+ export declare const validateDistinctIds: (name: string, values: ReadonlyArray<string>) => Effect.Effect<void, CliInputError>;
17
+ //# sourceMappingURL=expense-input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expense-input.d.ts","sourceRoot":"","sources":["../../src/commands/expense-input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAEvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAM5C,eAAO,MAAM,SAAS,GACpB,SAAS,MAAM,KACd,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,aAAa,CACQ,CAAA;AAW7C,eAAO,MAAM,iBAAiB,GAAI,MAAK,IAAiB,KAAG,MAG1D,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAA;AAI5D,eAAO,MAAM,UAAU,GAAI,OAAO,MAAM,KAAG,KAAK,IAAI,QACa,CAAA;AAEjE,eAAO,MAAM,aAAa,GAAI,KAAK,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,aAAa,CAGhF,CAAA;AAED,eAAO,MAAM,qBAAqB,GAChC,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KACzB,MAAM,CAAC,MAAM,CAAC,QAAQ,GAAG,SAAS,EAAE,aAAa,CAIhD,CAAA;AAEJ,eAAO,MAAM,YAAY,GACvB,MAAM,MAAM,EACZ,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAC3B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,CAMhC,CAAA;AAEJ,eAAO,MAAM,UAAU,GACrB,MAAM,MAAM,EACZ,OAAO,MAAM,KACZ,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAQrC,CAAA;AAED,eAAO,MAAM,kBAAkB,GAC7B,MAAM,MAAM,EACZ,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAC3B,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,SAAS,EAAE,aAAa,CAI9C,CAAA;AAEJ,eAAO,MAAM,sBAAsB,GACjC,OAAO,MAAM,GAAG,SAAS,KACxB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,CAM7B,CAAA;AAEP,eAAO,MAAM,gBAAgB,GAC3B,MAAM,MAAM,EACZ,QAAQ,aAAa,CAAC,MAAM,CAAC,EAC7B,YAAY,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,KAClE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,aAAa,CAkB5D,CAAA;AAEJ,eAAO,MAAM,eAAe,GAC1B,OAAO,MAAM,KACZ,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAKrC,CAAA;AAED,eAAO,MAAM,mBAAmB,GAC9B,MAAM,MAAM,EACZ,QAAQ,aAAa,CAAC,MAAM,CAAC,KAC5B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,CAG4B,CAAA"}
@@ -0,0 +1,78 @@
1
+ import { Effect, Option } from "effect";
2
+ import { SUPPORTED_CURRENCIES } from "../api/model.js";
3
+ import { CliInputError } from "../errors.js";
4
+ const datePattern = /^\d{4}-\d{2}-\d{2}$/;
5
+ const moneyPattern = /^(?:0|[1-9]\d*)(?:\.\d{1,2})?$/;
6
+ const idempotencyKeyPattern = /^[A-Za-z0-9._:-]+$/;
7
+ export const failInput = (message) => Effect.fail(new CliInputError({ message }));
8
+ const isIsoCalendarDate = (value) => {
9
+ if (!datePattern.test(value))
10
+ return false;
11
+ const parsed = new Date(`${value}T00:00:00.000Z`);
12
+ return !Number.isNaN(parsed.getTime()) &&
13
+ parsed.toISOString().slice(0, 10) === value;
14
+ };
15
+ // The server cannot know the user's time zone and defaults to the UTC date,
16
+ // which is already tomorrow on a US evening. Send the local calendar date.
17
+ export const localCalendarDate = (now = new Date()) => {
18
+ const pad = (value) => String(value).padStart(2, "0");
19
+ return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;
20
+ };
21
+ const currencyMessage = `currency must be one of ${SUPPORTED_CURRENCIES.join(", ")}`;
22
+ export const isCurrency = (value) => SUPPORTED_CURRENCIES.includes(value);
23
+ export const parseCurrency = (raw) => {
24
+ const currency = raw.trim().toUpperCase();
25
+ return isCurrency(currency) ? Effect.succeed(currency) : failInput(currencyMessage);
26
+ };
27
+ export const parseOptionalCurrency = (raw) => Option.match(raw, {
28
+ onNone: () => Effect.succeed(undefined),
29
+ onSome: parseCurrency
30
+ });
31
+ export const validateDate = (name, value) => Option.match(value, {
32
+ onNone: () => Effect.void,
33
+ onSome: (date) => isIsoCalendarDate(date)
34
+ ? Effect.void
35
+ : failInput(`${name} must be a valid YYYY-MM-DD date`)
36
+ });
37
+ export const parseMoney = (name, value) => {
38
+ if (!moneyPattern.test(value)) {
39
+ return failInput(`${name} must be a positive amount with at most two decimal places`);
40
+ }
41
+ const amount = Number(value);
42
+ return amount > 0
43
+ ? Effect.succeed(amount)
44
+ : failInput(`${name} must be greater than zero`);
45
+ };
46
+ export const parseOptionalMoney = (name, value) => Option.match(value, {
47
+ onNone: () => Effect.succeed(undefined),
48
+ onSome: (amount) => parseMoney(name, amount)
49
+ });
50
+ export const validateIdempotencyKey = (value) => value === undefined ||
51
+ (value.length <= 200 && idempotencyKeyPattern.test(value))
52
+ ? Effect.void
53
+ : failInput("idempotency-key must contain 1 to 200 letters, numbers, dots, underscores, colons, or hyphens");
54
+ export const parseAllocations = (name, values, parseValue) => Effect.gen(function* () {
55
+ const allocations = new Map();
56
+ for (const entry of values) {
57
+ const separator = entry.indexOf("=");
58
+ if (separator <= 0 || separator === entry.length - 1) {
59
+ return yield* failInput(`${name} must use MEMBER_ID=VALUE`);
60
+ }
61
+ const memberId = entry.slice(0, separator);
62
+ if (allocations.has(memberId)) {
63
+ return yield* failInput(`${name} repeats member ID ${memberId}`);
64
+ }
65
+ allocations.set(memberId, yield* parseValue(entry.slice(separator + 1)));
66
+ }
67
+ return Object.fromEntries(allocations);
68
+ });
69
+ export const parsePercentage = (value) => {
70
+ const percentage = Number(value);
71
+ return Number.isFinite(percentage) && percentage >= 0 && percentage <= 100
72
+ ? Effect.succeed(percentage)
73
+ : failInput("percentage values must be numbers from 0 through 100");
74
+ };
75
+ export const validateDistinctIds = (name, values) => new Set(values).size === values.length
76
+ ? Effect.void
77
+ : failInput(`${name} must not contain duplicate member IDs`);
78
+ //# sourceMappingURL=expense-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expense-input.js","sourceRoot":"","sources":["../../src/commands/expense-input.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { Command, Prompt } from "effect/unstable/cli";
2
+ import { ApiClient } from "../api/client.js";
3
+ import { CliInputError } from "../errors.js";
4
+ export declare const expensesCommand: Command.Command<"expenses", {}, {}, CliInputError | import("../api/client.js").ApiClientError | import("effect/Terminal").QuitError, ApiClient | Prompt.Environment>;
5
+ //# sourceMappingURL=expenses.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expenses.d.ts","sourceRoot":"","sources":["../../src/commands/expenses.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,OAAO,EAAQ,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAErE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAkB5C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAuwB5C,eAAO,MAAM,eAAe,sKAG3B,CAAA"}