@elizaos/plugin-finances 2.0.3-beta.6 → 2.0.3-beta.7
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/dist/actions/finances.d.ts +38 -0
- package/dist/actions/finances.d.ts.map +1 -0
- package/dist/actions/finances.js +368 -0
- package/dist/actions/finances.js.map +1 -0
- package/dist/components/finances/FinancesSpatialView.d.ts +80 -0
- package/dist/components/finances/FinancesSpatialView.d.ts.map +1 -0
- package/dist/components/finances/FinancesSpatialView.js +157 -0
- package/dist/components/finances/FinancesSpatialView.js.map +1 -0
- package/dist/components/finances/FinancesView.d.ts +97 -0
- package/dist/components/finances/FinancesView.d.ts.map +1 -0
- package/dist/components/finances/FinancesView.js +231 -0
- package/dist/components/finances/FinancesView.js.map +1 -0
- package/dist/components/finances/finances-view-bundle.d.ts +10 -0
- package/dist/components/finances/finances-view-bundle.d.ts.map +1 -0
- package/dist/components/finances/finances-view-bundle.js +5 -0
- package/dist/components/finances/finances-view-bundle.js.map +1 -0
- package/dist/db/finances-repository.d.ts +51 -0
- package/dist/db/finances-repository.d.ts.map +1 -0
- package/dist/db/finances-repository.js +521 -0
- package/dist/db/finances-repository.js.map +1 -0
- package/dist/db/index.d.ts +3 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +6 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/schema.d.ts +2615 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +133 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/db/sql.d.ts +65 -0
- package/dist/db/sql.d.ts.map +1 -0
- package/dist/db/sql.js +182 -0
- package/dist/db/sql.js.map +1 -0
- package/dist/finance-normalize.d.ts +24 -0
- package/dist/finance-normalize.d.ts.map +1 -0
- package/dist/finance-normalize.js +66 -0
- package/dist/finance-normalize.js.map +1 -0
- package/dist/finances-service.d.ts +179 -0
- package/dist/finances-service.d.ts.map +1 -0
- package/dist/finances-service.js +1122 -0
- package/dist/finances-service.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +109 -0
- package/dist/index.js.map +1 -0
- package/dist/payment-csv-import.d.ts +23 -0
- package/dist/payment-csv-import.d.ts.map +1 -0
- package/dist/payment-csv-import.js +271 -0
- package/dist/payment-csv-import.js.map +1 -0
- package/dist/payment-recurrence.d.ts +14 -0
- package/dist/payment-recurrence.d.ts.map +1 -0
- package/dist/payment-recurrence.js +190 -0
- package/dist/payment-recurrence.js.map +1 -0
- package/dist/payment-types.d.ts +158 -0
- package/dist/payment-types.d.ts.map +1 -0
- package/dist/payment-types.js +1 -0
- package/dist/payment-types.js.map +1 -0
- package/dist/plugin.d.ts +15 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +31 -0
- package/dist/plugin.js.map +1 -0
- package/dist/register-terminal-view.d.ts +15 -0
- package/dist/register-terminal-view.d.ts.map +1 -0
- package/dist/register-terminal-view.js +21 -0
- package/dist/register-terminal-view.js.map +1 -0
- package/dist/register.d.ts +9 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +5 -0
- package/dist/register.js.map +1 -0
- package/dist/services/browser-bridge-seam.d.ts +40 -0
- package/dist/services/browser-bridge-seam.d.ts.map +1 -0
- package/dist/services/browser-bridge-seam.js +39 -0
- package/dist/services/browser-bridge-seam.js.map +1 -0
- package/dist/services/gmail-seam.d.ts +40 -0
- package/dist/services/gmail-seam.d.ts.map +1 -0
- package/dist/services/gmail-seam.js +208 -0
- package/dist/services/gmail-seam.js.map +1 -0
- package/dist/services/migration.d.ts +65 -0
- package/dist/services/migration.d.ts.map +1 -0
- package/dist/services/migration.js +116 -0
- package/dist/services/migration.js.map +1 -0
- package/dist/services/subscriptions-service.d.ts +76 -0
- package/dist/services/subscriptions-service.d.ts.map +1 -0
- package/dist/services/subscriptions-service.js +1002 -0
- package/dist/services/subscriptions-service.js.map +1 -0
- package/dist/subscriptions-playbooks.d.ts +79 -0
- package/dist/subscriptions-playbooks.d.ts.map +1 -0
- package/dist/subscriptions-playbooks.js +871 -0
- package/dist/subscriptions-playbooks.js.map +1 -0
- package/dist/subscriptions-types.d.ts +80 -0
- package/dist/subscriptions-types.d.ts.map +1 -0
- package/dist/subscriptions-types.js +1 -0
- package/dist/subscriptions-types.js.map +1 -0
- package/dist/token-encryption.d.ts +42 -0
- package/dist/token-encryption.d.ts.map +1 -0
- package/dist/token-encryption.js +96 -0
- package/dist/token-encryption.js.map +1 -0
- package/dist/types.d.ts +55 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +18 -0
- package/dist/types.js.map +1 -0
- package/dist/views/bundle.js +411 -0
- package/dist/views/bundle.js.map +1 -0
- package/package.json +11 -11
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
import { client as e } from "@elizaos/ui";
|
|
2
|
+
import { Button as t, Card as n, HStack as r, List as i, SpatialSurface as a, Text as o, VStack as s } from "@elizaos/ui/spatial";
|
|
3
|
+
import { useCallback as c, useEffect as l, useMemo as u, useRef as d, useState as f } from "react";
|
|
4
|
+
import { Fragment as p, jsx as m, jsxs as h } from "react/jsx-runtime";
|
|
5
|
+
var g = {
|
|
6
|
+
state: "loading",
|
|
7
|
+
balance: {
|
|
8
|
+
net: "",
|
|
9
|
+
negative: !1,
|
|
10
|
+
income: "",
|
|
11
|
+
outflow: "",
|
|
12
|
+
asOf: ""
|
|
13
|
+
},
|
|
14
|
+
transactions: [],
|
|
15
|
+
recurring: [],
|
|
16
|
+
note: ""
|
|
17
|
+
};
|
|
18
|
+
function _({ snapshot: e, onAction: t }) {
|
|
19
|
+
let r = (e) => () => t?.(e);
|
|
20
|
+
return /* @__PURE__ */ m(n, {
|
|
21
|
+
gap: 1,
|
|
22
|
+
padding: 1,
|
|
23
|
+
children: e.state === "loading" ? /* @__PURE__ */ m(o, {
|
|
24
|
+
tone: "muted",
|
|
25
|
+
align: "center",
|
|
26
|
+
style: "caption",
|
|
27
|
+
children: "Loading"
|
|
28
|
+
}) : e.state === "error" ? /* @__PURE__ */ m(v, {
|
|
29
|
+
snapshot: e,
|
|
30
|
+
dispatch: r
|
|
31
|
+
}) : e.state === "empty" ? /* @__PURE__ */ m(y, { dispatch: r }) : /* @__PURE__ */ m(b, {
|
|
32
|
+
snapshot: e,
|
|
33
|
+
dispatch: r
|
|
34
|
+
})
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
function v({ snapshot: e, dispatch: n }) {
|
|
38
|
+
return /* @__PURE__ */ h(p, { children: [
|
|
39
|
+
/* @__PURE__ */ m(o, {
|
|
40
|
+
bold: !0,
|
|
41
|
+
children: "Could not load finances"
|
|
42
|
+
}),
|
|
43
|
+
/* @__PURE__ */ m(o, {
|
|
44
|
+
tone: "danger",
|
|
45
|
+
style: "caption",
|
|
46
|
+
children: e.error ?? "Could not load finances."
|
|
47
|
+
}),
|
|
48
|
+
/* @__PURE__ */ m(r, {
|
|
49
|
+
gap: 1,
|
|
50
|
+
children: /* @__PURE__ */ m(t, {
|
|
51
|
+
agent: "retry",
|
|
52
|
+
onPress: n("retry"),
|
|
53
|
+
children: "Retry"
|
|
54
|
+
})
|
|
55
|
+
})
|
|
56
|
+
] });
|
|
57
|
+
}
|
|
58
|
+
function y({ dispatch: e }) {
|
|
59
|
+
return /* @__PURE__ */ h(p, { children: [/* @__PURE__ */ m(o, {
|
|
60
|
+
bold: !0,
|
|
61
|
+
children: "None"
|
|
62
|
+
}), /* @__PURE__ */ m(r, {
|
|
63
|
+
gap: 1,
|
|
64
|
+
children: /* @__PURE__ */ m(t, {
|
|
65
|
+
agent: "connect",
|
|
66
|
+
onPress: e("connect"),
|
|
67
|
+
children: "Connect"
|
|
68
|
+
})
|
|
69
|
+
})] });
|
|
70
|
+
}
|
|
71
|
+
function b({ snapshot: e, dispatch: t }) {
|
|
72
|
+
return /* @__PURE__ */ h(p, { children: [
|
|
73
|
+
e.note ? /* @__PURE__ */ m(o, {
|
|
74
|
+
tone: "warning",
|
|
75
|
+
style: "caption",
|
|
76
|
+
children: e.note
|
|
77
|
+
}) : null,
|
|
78
|
+
/* @__PURE__ */ m(x, { balance: e.balance }),
|
|
79
|
+
/* @__PURE__ */ m(S, {
|
|
80
|
+
transactions: e.transactions,
|
|
81
|
+
dispatch: t
|
|
82
|
+
}),
|
|
83
|
+
/* @__PURE__ */ m(C, {
|
|
84
|
+
recurring: e.recurring,
|
|
85
|
+
dispatch: t
|
|
86
|
+
})
|
|
87
|
+
] });
|
|
88
|
+
}
|
|
89
|
+
function x({ balance: e }) {
|
|
90
|
+
return /* @__PURE__ */ h(p, { children: [
|
|
91
|
+
/* @__PURE__ */ m(o, {
|
|
92
|
+
style: "caption",
|
|
93
|
+
tone: "muted",
|
|
94
|
+
children: "Balance"
|
|
95
|
+
}),
|
|
96
|
+
/* @__PURE__ */ m(o, {
|
|
97
|
+
bold: !0,
|
|
98
|
+
tone: e.negative ? "danger" : "primary",
|
|
99
|
+
wrap: !1,
|
|
100
|
+
children: e.net
|
|
101
|
+
}),
|
|
102
|
+
/* @__PURE__ */ h(r, {
|
|
103
|
+
gap: 1,
|
|
104
|
+
width: "100%",
|
|
105
|
+
children: [/* @__PURE__ */ h(o, {
|
|
106
|
+
style: "caption",
|
|
107
|
+
tone: "muted",
|
|
108
|
+
wrap: !1,
|
|
109
|
+
children: ["In ", e.income]
|
|
110
|
+
}), /* @__PURE__ */ h(o, {
|
|
111
|
+
style: "caption",
|
|
112
|
+
tone: "muted",
|
|
113
|
+
wrap: !1,
|
|
114
|
+
children: ["Out ", e.outflow]
|
|
115
|
+
})]
|
|
116
|
+
}),
|
|
117
|
+
e.asOf ? /* @__PURE__ */ h(o, {
|
|
118
|
+
style: "caption",
|
|
119
|
+
tone: "muted",
|
|
120
|
+
wrap: !1,
|
|
121
|
+
children: ["As of ", e.asOf]
|
|
122
|
+
}) : null
|
|
123
|
+
] });
|
|
124
|
+
}
|
|
125
|
+
function S({ transactions: e, dispatch: n }) {
|
|
126
|
+
return /* @__PURE__ */ h(p, { children: [/* @__PURE__ */ h(o, {
|
|
127
|
+
style: "caption",
|
|
128
|
+
tone: "muted",
|
|
129
|
+
children: [
|
|
130
|
+
"Transactions (",
|
|
131
|
+
e.length,
|
|
132
|
+
")"
|
|
133
|
+
]
|
|
134
|
+
}), e.length === 0 ? /* @__PURE__ */ m(o, {
|
|
135
|
+
tone: "muted",
|
|
136
|
+
style: "caption",
|
|
137
|
+
children: "None"
|
|
138
|
+
}) : /* @__PURE__ */ m(i, {
|
|
139
|
+
gap: 0,
|
|
140
|
+
children: e.map((e) => /* @__PURE__ */ h(r, {
|
|
141
|
+
gap: 1,
|
|
142
|
+
align: "center",
|
|
143
|
+
width: "100%",
|
|
144
|
+
agent: `txn-${e.id}`,
|
|
145
|
+
children: [
|
|
146
|
+
/* @__PURE__ */ h(s, {
|
|
147
|
+
gap: 0,
|
|
148
|
+
grow: 1,
|
|
149
|
+
children: [/* @__PURE__ */ m(o, {
|
|
150
|
+
bold: !0,
|
|
151
|
+
wrap: !1,
|
|
152
|
+
children: e.description
|
|
153
|
+
}), /* @__PURE__ */ m(o, {
|
|
154
|
+
style: "caption",
|
|
155
|
+
tone: "muted",
|
|
156
|
+
wrap: !1,
|
|
157
|
+
children: e.meta
|
|
158
|
+
})]
|
|
159
|
+
}),
|
|
160
|
+
/* @__PURE__ */ m(o, {
|
|
161
|
+
tone: e.outflow ? "danger" : "primary",
|
|
162
|
+
wrap: !1,
|
|
163
|
+
children: e.amount
|
|
164
|
+
}),
|
|
165
|
+
/* @__PURE__ */ m(t, {
|
|
166
|
+
agent: `open-txn-${e.id}`,
|
|
167
|
+
onPress: n(`txn-${e.id}`),
|
|
168
|
+
children: "›"
|
|
169
|
+
})
|
|
170
|
+
]
|
|
171
|
+
}, e.id))
|
|
172
|
+
})] });
|
|
173
|
+
}
|
|
174
|
+
function C({ recurring: e, dispatch: n }) {
|
|
175
|
+
return /* @__PURE__ */ h(p, { children: [/* @__PURE__ */ h(o, {
|
|
176
|
+
style: "caption",
|
|
177
|
+
tone: "muted",
|
|
178
|
+
children: [
|
|
179
|
+
"Recurring (",
|
|
180
|
+
e.length,
|
|
181
|
+
")"
|
|
182
|
+
]
|
|
183
|
+
}), e.length === 0 ? /* @__PURE__ */ m(o, {
|
|
184
|
+
tone: "muted",
|
|
185
|
+
style: "caption",
|
|
186
|
+
children: "None"
|
|
187
|
+
}) : /* @__PURE__ */ m(i, {
|
|
188
|
+
gap: 0,
|
|
189
|
+
children: e.map((e) => /* @__PURE__ */ h(r, {
|
|
190
|
+
gap: 1,
|
|
191
|
+
align: "center",
|
|
192
|
+
width: "100%",
|
|
193
|
+
agent: `bill-${e.id}`,
|
|
194
|
+
children: [
|
|
195
|
+
/* @__PURE__ */ h(s, {
|
|
196
|
+
gap: 0,
|
|
197
|
+
grow: 1,
|
|
198
|
+
children: [/* @__PURE__ */ m(o, {
|
|
199
|
+
bold: !0,
|
|
200
|
+
wrap: !1,
|
|
201
|
+
children: e.label
|
|
202
|
+
}), /* @__PURE__ */ m(o, {
|
|
203
|
+
style: "caption",
|
|
204
|
+
tone: "muted",
|
|
205
|
+
wrap: !1,
|
|
206
|
+
children: e.meta
|
|
207
|
+
})]
|
|
208
|
+
}),
|
|
209
|
+
/* @__PURE__ */ m(o, {
|
|
210
|
+
wrap: !1,
|
|
211
|
+
children: e.amount
|
|
212
|
+
}),
|
|
213
|
+
/* @__PURE__ */ m(t, {
|
|
214
|
+
agent: `open-bill-${e.id}`,
|
|
215
|
+
onPress: n(`bill-${e.id}`),
|
|
216
|
+
children: "›"
|
|
217
|
+
})
|
|
218
|
+
]
|
|
219
|
+
}, e.id))
|
|
220
|
+
})] });
|
|
221
|
+
}
|
|
222
|
+
//#endregion
|
|
223
|
+
//#region src/components/finances/FinancesView.tsx
|
|
224
|
+
async function w(t) {
|
|
225
|
+
let n = await fetch(`${e.getBaseUrl()}${t}`);
|
|
226
|
+
if (!n.ok) throw Error(`Money request failed (${n.status}): ${t}`);
|
|
227
|
+
return await n.json();
|
|
228
|
+
}
|
|
229
|
+
var T = {
|
|
230
|
+
fetchDashboard: () => w("/api/lifeops/money/dashboard"),
|
|
231
|
+
fetchSources: () => w("/api/lifeops/money/sources"),
|
|
232
|
+
fetchTransactions: () => w("/api/lifeops/money/transactions"),
|
|
233
|
+
fetchRecurring: () => w("/api/lifeops/money/recurring")
|
|
234
|
+
}, E = "USD";
|
|
235
|
+
function D(e) {
|
|
236
|
+
return Math.round(e * 100);
|
|
237
|
+
}
|
|
238
|
+
function O(e) {
|
|
239
|
+
let { spending: t } = e;
|
|
240
|
+
return {
|
|
241
|
+
netBalanceMinor: D(t.netUsd),
|
|
242
|
+
currency: E,
|
|
243
|
+
monthlyIncomeMinor: D(t.totalIncomeUsd),
|
|
244
|
+
monthlyOutflowMinor: D(t.totalSpendUsd),
|
|
245
|
+
asOf: e.generatedAt
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
function k(e) {
|
|
249
|
+
let t = e.direction === "debit" ? -e.amountUsd : e.amountUsd, n = e.description ?? e.merchantDisplay ?? e.merchantNormalized ?? "Transaction";
|
|
250
|
+
return {
|
|
251
|
+
id: e.id,
|
|
252
|
+
occurredAt: e.postedAt,
|
|
253
|
+
amountMinor: D(t),
|
|
254
|
+
currency: e.currency || E,
|
|
255
|
+
description: n,
|
|
256
|
+
category: e.category,
|
|
257
|
+
merchant: e.merchantDisplay ?? e.merchantNormalized ?? null,
|
|
258
|
+
status: "posted",
|
|
259
|
+
source: null
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
var A = new Set([
|
|
263
|
+
"daily",
|
|
264
|
+
"weekly",
|
|
265
|
+
"monthly",
|
|
266
|
+
"quarterly",
|
|
267
|
+
"yearly"
|
|
268
|
+
]);
|
|
269
|
+
function j(e) {
|
|
270
|
+
let t = e.cadence === "annual" ? "yearly" : A.has(e.cadence) ? e.cadence : "monthly";
|
|
271
|
+
return {
|
|
272
|
+
id: e.merchantNormalized,
|
|
273
|
+
label: e.merchantDisplay || e.merchantNormalized,
|
|
274
|
+
amountMinor: D(e.averageAmountUsd),
|
|
275
|
+
currency: E,
|
|
276
|
+
cadence: t,
|
|
277
|
+
nextChargeAt: e.nextExpectedAt,
|
|
278
|
+
merchant: e.merchantDisplay || e.merchantNormalized,
|
|
279
|
+
active: !0
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
function M(e, t) {
|
|
283
|
+
let n = e / 100;
|
|
284
|
+
try {
|
|
285
|
+
return new Intl.NumberFormat(void 0, {
|
|
286
|
+
style: "currency",
|
|
287
|
+
currency: t
|
|
288
|
+
}).format(n);
|
|
289
|
+
} catch {
|
|
290
|
+
return `${n.toFixed(2)} ${t}`;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
function N(e) {
|
|
294
|
+
if (!e) return "";
|
|
295
|
+
let t = new Date(e);
|
|
296
|
+
return Number.isNaN(t.getTime()) ? e : t.toLocaleDateString();
|
|
297
|
+
}
|
|
298
|
+
function P(e, t, n = Date.now()) {
|
|
299
|
+
if (e.netBalanceMinor < 0) return `Balance is negative (${M(e.netBalanceMinor, e.currency)}).`;
|
|
300
|
+
let r = n + 10080 * 60 * 1e3, i = t.filter((e) => {
|
|
301
|
+
if (!e.nextChargeAt) return !1;
|
|
302
|
+
let t = new Date(e.nextChargeAt).getTime();
|
|
303
|
+
return !Number.isNaN(t) && t >= n && t <= r;
|
|
304
|
+
}).length;
|
|
305
|
+
return i > 0 ? `${i} bill${i === 1 ? "" : "s"} due this week.` : "";
|
|
306
|
+
}
|
|
307
|
+
function F(e) {
|
|
308
|
+
return {
|
|
309
|
+
net: M(e.netBalanceMinor, e.currency),
|
|
310
|
+
negative: e.netBalanceMinor < 0,
|
|
311
|
+
income: M(e.monthlyIncomeMinor, e.currency),
|
|
312
|
+
outflow: M(e.monthlyOutflowMinor, e.currency),
|
|
313
|
+
asOf: N(e.asOf)
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
function I(e) {
|
|
317
|
+
let t = N(e.occurredAt), n = e.category ? `${t} • ${e.category}` : t;
|
|
318
|
+
return {
|
|
319
|
+
id: e.id,
|
|
320
|
+
description: e.description,
|
|
321
|
+
meta: n,
|
|
322
|
+
amount: M(e.amountMinor, e.currency),
|
|
323
|
+
outflow: e.amountMinor < 0
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
function L(e) {
|
|
327
|
+
let t = N(e.nextChargeAt), n = t ? `${e.cadence} • next ${t}` : e.cadence;
|
|
328
|
+
return {
|
|
329
|
+
id: e.id,
|
|
330
|
+
label: e.label,
|
|
331
|
+
meta: n,
|
|
332
|
+
amount: M(e.amountMinor, e.currency)
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
var R = 3e4;
|
|
336
|
+
function z() {
|
|
337
|
+
let t = e.sendChatMessage;
|
|
338
|
+
t?.("Connect a payment source so you can track my money.");
|
|
339
|
+
}
|
|
340
|
+
function B(t = {}) {
|
|
341
|
+
let n = t.fetchers ?? T, [r, i] = f({ kind: "loading" }), o = d(n);
|
|
342
|
+
o.current = n;
|
|
343
|
+
let s = c((e = !1) => {
|
|
344
|
+
let t = !1;
|
|
345
|
+
return e || i({ kind: "loading" }), Promise.all([
|
|
346
|
+
o.current.fetchDashboard(),
|
|
347
|
+
o.current.fetchSources(),
|
|
348
|
+
o.current.fetchTransactions(),
|
|
349
|
+
o.current.fetchRecurring()
|
|
350
|
+
]).then(([e, n, r, a]) => {
|
|
351
|
+
t || i({
|
|
352
|
+
kind: "ready",
|
|
353
|
+
data: {
|
|
354
|
+
hasSource: n.sources.some((e) => e.status !== "disconnected"),
|
|
355
|
+
balance: O(e),
|
|
356
|
+
transactions: r.transactions.map(k),
|
|
357
|
+
recurring: a.charges.map(j)
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
}).catch((n) => {
|
|
361
|
+
t || e || i({
|
|
362
|
+
kind: "error",
|
|
363
|
+
message: n instanceof Error ? n.message : "Could not load finances."
|
|
364
|
+
});
|
|
365
|
+
}), () => {
|
|
366
|
+
t = !0;
|
|
367
|
+
};
|
|
368
|
+
}, []);
|
|
369
|
+
return l(() => s(), [s]), l(() => {
|
|
370
|
+
let e = setInterval(() => s(!0), R);
|
|
371
|
+
return () => clearInterval(e);
|
|
372
|
+
}, [s]), /* @__PURE__ */ m(a, { children: /* @__PURE__ */ m(_, {
|
|
373
|
+
snapshot: u(() => {
|
|
374
|
+
if (r.kind === "loading") return g;
|
|
375
|
+
if (r.kind === "error") return {
|
|
376
|
+
...g,
|
|
377
|
+
state: "error",
|
|
378
|
+
error: r.message
|
|
379
|
+
};
|
|
380
|
+
let { hasSource: e, balance: t, transactions: n, recurring: i } = r.data;
|
|
381
|
+
return e ? {
|
|
382
|
+
state: "ready",
|
|
383
|
+
balance: F(t),
|
|
384
|
+
transactions: n.map(I),
|
|
385
|
+
recurring: i.map(L),
|
|
386
|
+
note: P(t, i)
|
|
387
|
+
} : {
|
|
388
|
+
...g,
|
|
389
|
+
state: "empty"
|
|
390
|
+
};
|
|
391
|
+
}, [r]),
|
|
392
|
+
onAction: c((t) => {
|
|
393
|
+
if (t === "retry") {
|
|
394
|
+
s();
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
if (t === "connect") {
|
|
398
|
+
z();
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
if (t.startsWith("txn-") || t.startsWith("bill-")) {
|
|
402
|
+
let n = e.sendChatMessage;
|
|
403
|
+
n?.(`Show me the details for ${t}.`);
|
|
404
|
+
}
|
|
405
|
+
}, [s])
|
|
406
|
+
}) });
|
|
407
|
+
}
|
|
408
|
+
//#endregion
|
|
409
|
+
export { B as FinancesView };
|
|
410
|
+
|
|
411
|
+
//# sourceMappingURL=bundle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundle.js","names":[],"sources":["../../src/components/finances/FinancesSpatialView.tsx","../../src/components/finances/FinancesView.tsx"],"sourcesContent":["/**\n * FinancesSpatialView — the owner finance dashboard authored once with the\n * spatial vocabulary, so it renders correctly wherever it is displayed:\n *\n * - GUI / XR — mounted in `<SpatialSurface>` (DOM; XR scales up).\n * - TUI — rendered to real terminal lines by the agent terminal, via\n * `registerSpatialTerminalView` (see `register-terminal-view.tsx`).\n *\n * It is purely presentational (a snapshot + an action callback in, primitives\n * out) and imports only the cross-modality primitives, so it is safe to render\n * in the Node agent process where the terminal lives (no browser/client import).\n *\n * The balance, transactions, and recurring charges — including every currency\n * amount — arrive ALREADY FORMATTED as display strings from the data wrapper\n * ({@link ./FinancesView.tsx}); this component never fetches, computes a total,\n * or runs financial math. It displays the snapshot and dispatches actions.\n */\n\nimport { Button, Card, HStack, List, Text, VStack } from \"@elizaos/ui/spatial\";\n\n/** Which render state the dashboard is in. */\nexport type FinancesViewState = \"loading\" | \"error\" | \"empty\" | \"ready\";\n\n/** A balance summary row, already projected to display strings by the wrapper. */\nexport interface FinanceBalanceCard {\n /** Pre-formatted net balance (e.g. \"$2,765.50\"). */\n net: string;\n /** True when the net balance is below zero (drives tone, no math here). */\n negative: boolean;\n /** Pre-formatted money in over the window (e.g. \"$4,000.00\"). */\n income: string;\n /** Pre-formatted money out over the window (e.g. \"$1,234.50\"). */\n outflow: string;\n /** Pre-formatted \"as of\" date label, or empty. */\n asOf: string;\n}\n\n/** One transaction row, already projected to display strings by the wrapper. */\nexport interface FinanceTransactionCard {\n id: string;\n description: string;\n /** Pre-formatted secondary line (date + optional category). */\n meta: string;\n /** Pre-formatted signed amount (e.g. \"-$42.50\"). */\n amount: string;\n /** True when the amount is an outflow (drives tone, no math here). */\n outflow: boolean;\n}\n\n/** One recurring-charge row, already projected to display strings. */\nexport interface FinanceRecurringCard {\n id: string;\n label: string;\n /** Pre-formatted secondary line (cadence + next-charge date). */\n meta: string;\n /** Pre-formatted amount (e.g. \"$15.99\"). */\n amount: string;\n}\n\nexport interface FinancesSnapshot {\n /** The dashboard state machine. */\n state: FinancesViewState;\n /** Balance summary (only meaningful when state === \"ready\"). */\n balance: FinanceBalanceCard;\n /** Recent transactions (only meaningful when state === \"ready\"). */\n transactions: FinanceTransactionCard[];\n /** Recurring charges (only meaningful when state === \"ready\"). */\n recurring: FinanceRecurringCard[];\n /** One quiet proactive line, or empty when there is no genuine signal. */\n note: string;\n /** Error message when state === \"error\". */\n error?: string;\n}\n\nconst EMPTY_BALANCE: FinanceBalanceCard = {\n net: \"\",\n negative: false,\n income: \"\",\n outflow: \"\",\n asOf: \"\",\n};\n\nexport const EMPTY_FINANCES_SNAPSHOT: FinancesSnapshot = {\n state: \"loading\",\n balance: EMPTY_BALANCE,\n transactions: [],\n recurring: [],\n note: \"\",\n};\n\nexport interface FinancesSpatialViewProps {\n snapshot: FinancesSnapshot;\n /**\n * Dispatch by agent id:\n * `retry` reload after an error,\n * `connect` route a connect-a-source request to chat,\n * `txn-<id>` open a transaction,\n * `bill-<id>` open a recurring charge.\n */\n onAction?: (action: string) => void;\n}\n\nexport function FinancesSpatialView({\n snapshot,\n onAction,\n}: FinancesSpatialViewProps) {\n const dispatch = (action: string) => () => onAction?.(action);\n\n return (\n <Card gap={1} padding={1}>\n {snapshot.state === \"loading\" ? (\n <Text tone=\"muted\" align=\"center\" style=\"caption\">\n Loading\n </Text>\n ) : snapshot.state === \"error\" ? (\n <FinancesErrorBody snapshot={snapshot} dispatch={dispatch} />\n ) : snapshot.state === \"empty\" ? (\n <FinancesEmptyBody dispatch={dispatch} />\n ) : (\n <FinancesReadyBody snapshot={snapshot} dispatch={dispatch} />\n )}\n </Card>\n );\n}\n\nfunction FinancesErrorBody({\n snapshot,\n dispatch,\n}: {\n snapshot: FinancesSnapshot;\n dispatch: (action: string) => () => void;\n}) {\n return (\n <>\n <Text bold>Could not load finances</Text>\n <Text tone=\"danger\" style=\"caption\">\n {snapshot.error ?? \"Could not load finances.\"}\n </Text>\n <HStack gap={1}>\n <Button agent=\"retry\" onPress={dispatch(\"retry\")}>\n Retry\n </Button>\n </HStack>\n </>\n );\n}\n\nfunction FinancesEmptyBody({\n dispatch,\n}: {\n dispatch: (action: string) => () => void;\n}) {\n return (\n <>\n <Text bold>None</Text>\n <HStack gap={1}>\n <Button agent=\"connect\" onPress={dispatch(\"connect\")}>\n Connect\n </Button>\n </HStack>\n </>\n );\n}\n\nfunction FinancesReadyBody({\n snapshot,\n dispatch,\n}: {\n snapshot: FinancesSnapshot;\n dispatch: (action: string) => () => void;\n}) {\n return (\n <>\n {snapshot.note ? (\n <Text tone=\"warning\" style=\"caption\">\n {snapshot.note}\n </Text>\n ) : null}\n <BalanceSection balance={snapshot.balance} />\n <TransactionsSection\n transactions={snapshot.transactions}\n dispatch={dispatch}\n />\n <RecurringSection recurring={snapshot.recurring} dispatch={dispatch} />\n </>\n );\n}\n\nfunction BalanceSection({ balance }: { balance: FinanceBalanceCard }) {\n return (\n <>\n <Text style=\"caption\" tone=\"muted\">\n Balance\n </Text>\n <Text bold tone={balance.negative ? \"danger\" : \"primary\"} wrap={false}>\n {balance.net}\n </Text>\n <HStack gap={1} width=\"100%\">\n <Text style=\"caption\" tone=\"muted\" wrap={false}>\n In {balance.income}\n </Text>\n <Text style=\"caption\" tone=\"muted\" wrap={false}>\n Out {balance.outflow}\n </Text>\n </HStack>\n {balance.asOf ? (\n <Text style=\"caption\" tone=\"muted\" wrap={false}>\n As of {balance.asOf}\n </Text>\n ) : null}\n </>\n );\n}\n\nfunction TransactionsSection({\n transactions,\n dispatch,\n}: {\n transactions: FinanceTransactionCard[];\n dispatch: (action: string) => () => void;\n}) {\n return (\n <>\n <Text style=\"caption\" tone=\"muted\">\n Transactions ({transactions.length})\n </Text>\n {transactions.length === 0 ? (\n <Text tone=\"muted\" style=\"caption\">\n None\n </Text>\n ) : (\n <List gap={0}>\n {transactions.map((tx) => (\n <HStack\n key={tx.id}\n gap={1}\n align=\"center\"\n width=\"100%\"\n agent={`txn-${tx.id}`}\n >\n <VStack gap={0} grow={1}>\n <Text bold wrap={false}>\n {tx.description}\n </Text>\n <Text style=\"caption\" tone=\"muted\" wrap={false}>\n {tx.meta}\n </Text>\n </VStack>\n <Text tone={tx.outflow ? \"danger\" : \"primary\"} wrap={false}>\n {tx.amount}\n </Text>\n <Button\n agent={`open-txn-${tx.id}`}\n onPress={dispatch(`txn-${tx.id}`)}\n >\n ›\n </Button>\n </HStack>\n ))}\n </List>\n )}\n </>\n );\n}\n\nfunction RecurringSection({\n recurring,\n dispatch,\n}: {\n recurring: FinanceRecurringCard[];\n dispatch: (action: string) => () => void;\n}) {\n return (\n <>\n <Text style=\"caption\" tone=\"muted\">\n Recurring ({recurring.length})\n </Text>\n {recurring.length === 0 ? (\n <Text tone=\"muted\" style=\"caption\">\n None\n </Text>\n ) : (\n <List gap={0}>\n {recurring.map((row) => (\n <HStack\n key={row.id}\n gap={1}\n align=\"center\"\n width=\"100%\"\n agent={`bill-${row.id}`}\n >\n <VStack gap={0} grow={1}>\n <Text bold wrap={false}>\n {row.label}\n </Text>\n <Text style=\"caption\" tone=\"muted\" wrap={false}>\n {row.meta}\n </Text>\n </VStack>\n <Text wrap={false}>{row.amount}</Text>\n <Button\n agent={`open-bill-${row.id}`}\n onPress={dispatch(`bill-${row.id}`)}\n >\n ›\n </Button>\n </HStack>\n ))}\n </List>\n )}\n </>\n );\n}\n","/**\n * FinancesView — the single GUI/XR data wrapper for the owner finance dashboard.\n *\n * It owns the live money data (the fetcher seams over the four read-only\n * endpoints PA serves, the quiet background poll, wire->display mapping, the\n * USD-float->minor-units boundary, and the proactive signal) and renders the one\n * presentational {@link FinancesSpatialView} inside a {@link SpatialSurface}.\n * Omitting the `modality` prop lets `SpatialSurface` auto-detect GUI vs XR, so\n * the SAME component serves both surfaces; the TUI surface renders the same\n * `FinancesSpatialView` through the terminal registry (see\n * `../../register-terminal-view.tsx`).\n *\n * Data sources (PA owns the persistence; this plugin only reads):\n * GET {base}/api/lifeops/money/dashboard (balance summary)\n * GET {base}/api/lifeops/money/sources (connected-vs-disconnected)\n * GET {base}/api/lifeops/money/transactions (recent transactions)\n * GET {base}/api/lifeops/money/recurring (recurring charges)\n *\n * The client DISPLAYS, never COMPUTES: every total, sign, and currency amount is\n * resolved HERE into a pre-formatted string and handed to the spatial view as a\n * snapshot. The owner actions are `connect` (route a connect-a-source request\n * through the assistant chat — no fabricated balances) and `retry` (reload after\n * an error). This plugin MUST NOT import from @elizaos/plugin-personal-assistant;\n * the wire DTOs below are declared locally to match the JSON shape PA emits.\n */\n\nimport { client } from \"@elizaos/ui\";\nimport { SpatialSurface } from \"@elizaos/ui/spatial\";\nimport type { ReactNode } from \"react\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type {\n FinanceBalanceSummaryDTO,\n FinanceTransactionDTO,\n RecurringChargeDTO,\n} from \"../../types.ts\";\nimport {\n EMPTY_FINANCES_SNAPSHOT,\n type FinanceBalanceCard,\n type FinanceRecurringCard,\n type FinancesSnapshot,\n FinancesSpatialView,\n type FinanceTransactionCard,\n} from \"./FinancesSpatialView.tsx\";\n\n// ---------------------------------------------------------------------------\n// Wire DTOs — local mirror of the JSON shape served by the PA money routes.\n// Amounts are USD floats on the wire; never import PA types here.\n// ---------------------------------------------------------------------------\n\ninterface MoneySpendingWire {\n windowDays: number;\n fromDate: string;\n toDate: string;\n totalSpendUsd: number;\n totalIncomeUsd: number;\n netUsd: number;\n transactionCount: number;\n}\n\ninterface MoneyDashboardWire {\n spending: MoneySpendingWire;\n generatedAt: string;\n}\n\ntype MoneySourceStatusWire = \"active\" | \"disconnected\" | \"needs_attention\";\n\ninterface MoneySourceWire {\n id: string;\n kind: string;\n label: string;\n institution: string | null;\n status: MoneySourceStatusWire;\n}\n\ninterface MoneySourcesWire {\n sources: MoneySourceWire[];\n}\n\ntype MoneyDirectionWire = \"debit\" | \"credit\";\n\ninterface MoneyTransactionWire {\n id: string;\n postedAt: string;\n amountUsd: number;\n direction: MoneyDirectionWire;\n merchantDisplay?: string | null;\n merchantNormalized: string;\n merchantRaw: string;\n description: string | null;\n category: string | null;\n currency: string;\n}\n\ninterface MoneyTransactionsWire {\n transactions: MoneyTransactionWire[];\n}\n\ninterface MoneyRecurringWire {\n merchantNormalized: string;\n merchantDisplay: string;\n cadence: string;\n averageAmountUsd: number;\n nextExpectedAt: string | null;\n category: string | null;\n}\n\ninterface MoneyRecurringChargesWire {\n charges: MoneyRecurringWire[];\n}\n\n// ---------------------------------------------------------------------------\n// Fetcher seams — default to real GETs; tests inject offline fakes.\n// ---------------------------------------------------------------------------\n\nexport interface FinancesFetchers {\n fetchDashboard: () => Promise<MoneyDashboardWire>;\n fetchSources: () => Promise<MoneySourcesWire>;\n fetchTransactions: () => Promise<MoneyTransactionsWire>;\n fetchRecurring: () => Promise<MoneyRecurringChargesWire>;\n}\n\nasync function getJson<T>(path: string): Promise<T> {\n const response = await fetch(`${client.getBaseUrl()}${path}`);\n if (!response.ok) {\n throw new Error(`Money request failed (${response.status}): ${path}`);\n }\n return (await response.json()) as T;\n}\n\nconst defaultFetchers: FinancesFetchers = {\n fetchDashboard: () =>\n getJson<MoneyDashboardWire>(\"/api/lifeops/money/dashboard\"),\n fetchSources: () => getJson<MoneySourcesWire>(\"/api/lifeops/money/sources\"),\n fetchTransactions: () =>\n getJson<MoneyTransactionsWire>(\"/api/lifeops/money/transactions\"),\n fetchRecurring: () =>\n getJson<MoneyRecurringChargesWire>(\"/api/lifeops/money/recurring\"),\n};\n\nexport interface FinancesViewProps {\n /** Owner display name (host injection seam). */\n ownerName?: string;\n /** Test/host injection seam. Defaults to real `/api/lifeops/money/*` GETs. */\n fetchers?: FinancesFetchers;\n}\n\n// ---------------------------------------------------------------------------\n// Wire -> display DTO mapping (USD float -> minor units at the boundary).\n// ---------------------------------------------------------------------------\n\nconst USD = \"USD\";\n\nfunction usdToMinor(amountUsd: number): number {\n return Math.round(amountUsd * 100);\n}\n\nfunction mapBalance(dashboard: MoneyDashboardWire): FinanceBalanceSummaryDTO {\n const { spending } = dashboard;\n return {\n netBalanceMinor: usdToMinor(spending.netUsd),\n currency: USD,\n monthlyIncomeMinor: usdToMinor(spending.totalIncomeUsd),\n monthlyOutflowMinor: usdToMinor(spending.totalSpendUsd),\n asOf: dashboard.generatedAt,\n };\n}\n\nfunction mapTransaction(tx: MoneyTransactionWire): FinanceTransactionDTO {\n // A debit is money leaving the account: render as a negative (outflow). The\n // wire amount is unsigned, so the direction carries the sign.\n const signedUsd = tx.direction === \"debit\" ? -tx.amountUsd : tx.amountUsd;\n const description =\n tx.description ??\n tx.merchantDisplay ??\n tx.merchantNormalized ??\n \"Transaction\";\n return {\n id: tx.id,\n occurredAt: tx.postedAt,\n amountMinor: usdToMinor(signedUsd),\n currency: tx.currency || USD,\n description,\n category: tx.category,\n merchant: tx.merchantDisplay ?? tx.merchantNormalized ?? null,\n status: \"posted\",\n source: null,\n };\n}\n\nconst RECURRING_CADENCES = new Set([\n \"daily\",\n \"weekly\",\n \"monthly\",\n \"quarterly\",\n \"yearly\",\n]);\n\nfunction mapRecurring(charge: MoneyRecurringWire): RecurringChargeDTO {\n // The wire cadence has more variants (biweekly/annual/irregular) than the\n // display enum; normalize annual -> yearly and fall back to monthly for the\n // ones the display enum cannot represent. Display only — no math.\n const normalized =\n charge.cadence === \"annual\"\n ? \"yearly\"\n : RECURRING_CADENCES.has(charge.cadence)\n ? charge.cadence\n : \"monthly\";\n return {\n id: charge.merchantNormalized,\n label: charge.merchantDisplay || charge.merchantNormalized,\n amountMinor: usdToMinor(charge.averageAmountUsd),\n currency: USD,\n cadence: normalized as RecurringChargeDTO[\"cadence\"],\n nextChargeAt: charge.nextExpectedAt,\n merchant: charge.merchantDisplay || charge.merchantNormalized,\n active: true,\n };\n}\n\n/**\n * Load-bearing render boundary: minor units (cents) -> grouped currency string.\n * Kept here (not in a util) because format-minor.test.ts pins it to this file.\n */\nexport function formatMinor(amountMinor: number, currency: string): string {\n const value = amountMinor / 100;\n try {\n return new Intl.NumberFormat(undefined, {\n style: \"currency\",\n currency,\n }).format(value);\n } catch {\n return `${value.toFixed(2)} ${currency}`;\n }\n}\n\nfunction formatDate(value: string | null): string {\n if (!value) return \"\";\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? value : date.toLocaleDateString();\n}\n\n/**\n * One quiet line of proactive agent context (design law 10): surface a single\n * genuine, actionable money signal — never a placeholder. Precedence:\n * 1. a negative net balance (overdrawn), then\n * 2. recurring bills landing within the next 7 days.\n * Returns \"\" when neither holds, so the line renders nothing on no signal.\n * Computed entirely from data the view already loads; no new imports.\n */\nfunction proactiveNote(\n balance: FinanceBalanceSummaryDTO,\n recurring: RecurringChargeDTO[],\n now: number = Date.now(),\n): string {\n if (balance.netBalanceMinor < 0) {\n return `Balance is negative (${formatMinor(\n balance.netBalanceMinor,\n balance.currency,\n )}).`;\n }\n const weekFromNow = now + 7 * 24 * 60 * 60 * 1000;\n const dueSoon = recurring.filter((row) => {\n if (!row.nextChargeAt) return false;\n const due = new Date(row.nextChargeAt).getTime();\n return !Number.isNaN(due) && due >= now && due <= weekFromNow;\n }).length;\n if (dueSoon > 0) {\n return `${dueSoon} bill${dueSoon === 1 ? \"\" : \"s\"} due this week.`;\n }\n return \"\";\n}\n\n// ---------------------------------------------------------------------------\n// Display-DTO -> spatial-card projection (pre-format every string HERE).\n// ---------------------------------------------------------------------------\n\nfunction toBalanceCard(balance: FinanceBalanceSummaryDTO): FinanceBalanceCard {\n return {\n net: formatMinor(balance.netBalanceMinor, balance.currency),\n negative: balance.netBalanceMinor < 0,\n income: formatMinor(balance.monthlyIncomeMinor, balance.currency),\n outflow: formatMinor(balance.monthlyOutflowMinor, balance.currency),\n asOf: formatDate(balance.asOf),\n };\n}\n\nfunction toTransactionCard(tx: FinanceTransactionDTO): FinanceTransactionCard {\n const date = formatDate(tx.occurredAt);\n const meta = tx.category ? `${date} • ${tx.category}` : date;\n return {\n id: tx.id,\n description: tx.description,\n meta,\n amount: formatMinor(tx.amountMinor, tx.currency),\n outflow: tx.amountMinor < 0,\n };\n}\n\nfunction toRecurringCard(row: RecurringChargeDTO): FinanceRecurringCard {\n const next = formatDate(row.nextChargeAt);\n const meta = next ? `${row.cadence} • next ${next}` : row.cadence;\n return {\n id: row.id,\n label: row.label,\n meta,\n amount: formatMinor(row.amountMinor, row.currency),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Fetch-driven state machine.\n// ---------------------------------------------------------------------------\n\nconst POLL_INTERVAL_MS = 30_000;\n\ninterface FinancesData {\n hasSource: boolean;\n balance: FinanceBalanceSummaryDTO;\n transactions: FinanceTransactionDTO[];\n recurring: RecurringChargeDTO[];\n}\n\ntype LoadState =\n | { kind: \"loading\" }\n | { kind: \"error\"; message: string }\n | { kind: \"ready\"; data: FinancesData };\n\nfunction requestConnectSource(): void {\n // The connect-a-source affordance routes through the assistant chat. `client`\n // does not type `sendChatMessage`, so read it through a narrow optional-method\n // view and call it only when present — no fabricated balances.\n const send = (client as { sendChatMessage?: (text: string) => void })\n .sendChatMessage;\n send?.(\"Connect a payment source so you can track my money.\");\n}\n\nexport function FinancesView(props: FinancesViewProps = {}): ReactNode {\n const fetchers = props.fetchers ?? defaultFetchers;\n const [state, setState] = useState<LoadState>({ kind: \"loading\" });\n\n const fetchersRef = useRef(fetchers);\n fetchersRef.current = fetchers;\n\n const load = useCallback((quiet = false) => {\n let cancelled = false;\n if (!quiet) setState({ kind: \"loading\" });\n Promise.all([\n fetchersRef.current.fetchDashboard(),\n fetchersRef.current.fetchSources(),\n fetchersRef.current.fetchTransactions(),\n fetchersRef.current.fetchRecurring(),\n ])\n .then(([dashboard, sources, transactions, recurring]) => {\n if (cancelled) return;\n const connected = sources.sources.some(\n (source) => source.status !== \"disconnected\",\n );\n setState({\n kind: \"ready\",\n data: {\n hasSource: connected,\n balance: mapBalance(dashboard),\n transactions: transactions.transactions.map(mapTransaction),\n recurring: recurring.charges.map(mapRecurring),\n },\n });\n })\n .catch((error: unknown) => {\n if (cancelled || quiet) return;\n setState({\n kind: \"error\",\n message:\n error instanceof Error ? error.message : \"Could not load finances.\",\n });\n });\n return () => {\n cancelled = true;\n };\n }, []);\n\n useEffect(() => load(), [load]);\n\n // Poll quietly every 30s so the dashboard stays fresh without a manual\n // refresh. Transient poll failures are ignored — the explicit Retry path is\n // what surfaces errors to the user.\n useEffect(() => {\n const id = setInterval(() => load(true), POLL_INTERVAL_MS);\n return () => clearInterval(id);\n }, [load]);\n\n const snapshot = useMemo<FinancesSnapshot>(() => {\n if (state.kind === \"loading\") {\n return EMPTY_FINANCES_SNAPSHOT;\n }\n if (state.kind === \"error\") {\n return {\n ...EMPTY_FINANCES_SNAPSHOT,\n state: \"error\",\n error: state.message,\n };\n }\n const { hasSource, balance, transactions, recurring } = state.data;\n if (!hasSource) {\n return { ...EMPTY_FINANCES_SNAPSHOT, state: \"empty\" };\n }\n return {\n state: \"ready\",\n balance: toBalanceCard(balance),\n transactions: transactions.map(toTransactionCard),\n recurring: recurring.map(toRecurringCard),\n note: proactiveNote(balance, recurring),\n };\n }, [state]);\n\n const onAction = useCallback(\n (action: string) => {\n if (action === \"retry\") {\n load();\n return;\n }\n if (action === \"connect\") {\n requestConnectSource();\n return;\n }\n // `txn-<id>` / `bill-<id>` open affordances route to chat; PA owns the\n // detail surface, so this view never fabricates a drill-down.\n if (action.startsWith(\"txn-\") || action.startsWith(\"bill-\")) {\n const send = (client as { sendChatMessage?: (text: string) => void })\n .sendChatMessage;\n send?.(`Show me the details for ${action}.`);\n }\n },\n [load],\n );\n\n return (\n <SpatialSurface>\n <FinancesSpatialView snapshot={snapshot} onAction={onAction} />\n </SpatialSurface>\n );\n}\n\nexport default FinancesView;\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elizaos/plugin-finances",
|
|
3
|
-
"version": "2.0.3-beta.
|
|
3
|
+
"version": "2.0.3-beta.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Owner finances overlay app: finance dashboard, transactions, recurring charges. Hooks into other finance providers later.",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -49,19 +49,19 @@
|
|
|
49
49
|
}
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@elizaos/agent": "2.0.3-beta.
|
|
53
|
-
"@elizaos/app-core": "2.0.3-beta.
|
|
54
|
-
"@elizaos/core": "2.0.3-beta.
|
|
55
|
-
"@elizaos/plugin-browser": "2.0.3-beta.
|
|
56
|
-
"@elizaos/plugin-elizacloud": "2.0.3-beta.
|
|
57
|
-
"@elizaos/plugin-google": "2.0.3-beta.
|
|
58
|
-
"@elizaos/shared": "2.0.3-beta.
|
|
59
|
-
"@elizaos/ui": "2.0.3-beta.
|
|
52
|
+
"@elizaos/agent": "2.0.3-beta.7",
|
|
53
|
+
"@elizaos/app-core": "2.0.3-beta.7",
|
|
54
|
+
"@elizaos/core": "2.0.3-beta.7",
|
|
55
|
+
"@elizaos/plugin-browser": "2.0.3-beta.7",
|
|
56
|
+
"@elizaos/plugin-elizacloud": "2.0.3-beta.7",
|
|
57
|
+
"@elizaos/plugin-google": "2.0.3-beta.7",
|
|
58
|
+
"@elizaos/shared": "2.0.3-beta.7",
|
|
59
|
+
"@elizaos/ui": "2.0.3-beta.7",
|
|
60
60
|
"drizzle-orm": "^0.45.1",
|
|
61
61
|
"lucide-react": "^1.0.0"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
|
-
"@elizaos/plugin-sql": "2.0.3-beta.
|
|
64
|
+
"@elizaos/plugin-sql": "2.0.3-beta.7",
|
|
65
65
|
"react": "^19.0.0",
|
|
66
66
|
"react-dom": "^19.0.0"
|
|
67
67
|
},
|
|
@@ -91,5 +91,5 @@
|
|
|
91
91
|
"vite": "^8.0.0",
|
|
92
92
|
"vitest": "^4.0.17"
|
|
93
93
|
},
|
|
94
|
-
"gitHead": "
|
|
94
|
+
"gitHead": "61094f10458d11055c75b3dd0bae374e3f66bac5"
|
|
95
95
|
}
|