@flowselections/mailbox-orders 1.0.47 → 1.0.50
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-lib/components/MailboxProposalsPage.d.ts.map +1 -1
- package/dist-lib/components/MailboxProposalsPage.js +4 -3
- package/dist-lib/components/MailboxSkippedPage.d.ts.map +1 -1
- package/dist-lib/components/MailboxSkippedPage.js +5 -3
- package/dist-lib/components/MailboxStatusLine.d.ts +5 -0
- package/dist-lib/components/MailboxStatusLine.d.ts.map +1 -0
- package/dist-lib/components/MailboxStatusLine.js +23 -0
- package/dist-lib/integrations/supabase/types.d.ts +3364 -122
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.js +1 -0
- package/dist-lib/lib/mailbox-filter-settings.functions.d.ts.map +1 -1
- package/dist-lib/lib/mailbox-filter-settings.functions.js +3 -0
- package/dist-lib/lib/mailbox-folders.d.ts +25 -0
- package/dist-lib/lib/mailbox-folders.d.ts.map +1 -0
- package/dist-lib/lib/mailbox-folders.js +73 -0
- package/dist-lib/lib/mailbox-ingest.server.d.ts +5 -0
- package/dist-lib/lib/mailbox-ingest.server.d.ts.map +1 -1
- package/dist-lib/lib/mailbox-ingest.server.js +338 -109
- package/dist-lib/lib/mailbox.functions.d.ts +29 -0
- package/dist-lib/lib/mailbox.functions.d.ts.map +1 -1
- package/dist-lib/lib/mailbox.functions.js +106 -2
- package/package.json +2 -2
|
@@ -140,6 +140,7 @@ export const listProposals = createServerFn({ method: "GET" })
|
|
|
140
140
|
.inputValidator((input) => z.object({ status: z.enum(["pending", "approved", "rejected"]).optional() }).parse(input ?? {}))
|
|
141
141
|
.handler(async ({ data }) => {
|
|
142
142
|
const { supabaseAdmin } = await import("../integrations/supabase/client.server.js");
|
|
143
|
+
await ensureMailboxDefaults(supabaseAdmin);
|
|
143
144
|
// Alleen de kolommen die de lijstweergave toont. De mailtekst (body_text /
|
|
144
145
|
// body_html) en de bestelregels zijn bewust NIET opgenomen: die worden pas
|
|
145
146
|
// opgehaald zodra een voorstel geopend wordt (`getProposalDetail`).
|
|
@@ -148,7 +149,7 @@ export const listProposals = createServerFn({ method: "GET" })
|
|
|
148
149
|
.from("mailbox_order_proposals")
|
|
149
150
|
.select(sel("id, status, created_at, reviewed_at, matched_customer_id, ai_ok, customer_reference, " +
|
|
150
151
|
"readiness:parsed_payload->>readiness, duplicate:parsed_payload->duplicate_of, " +
|
|
151
|
-
"mailbox_messages(subject, from_email, from_name, received_at, connection_id, preview), " +
|
|
152
|
+
"mailbox_messages(subject, from_email, from_name, received_at, connection_id, account_email, preview), " +
|
|
152
153
|
"mailbox_proposal_field_values(field_key, value, needs_review)"))
|
|
153
154
|
.order("created_at", { ascending: false })
|
|
154
155
|
.limit(200);
|
|
@@ -202,7 +203,7 @@ export const getProposalDetail = createServerFn({ method: "GET" })
|
|
|
202
203
|
const sel = (s) => s;
|
|
203
204
|
const { data: row, error } = await supabaseAdmin
|
|
204
205
|
.from("mailbox_order_proposals")
|
|
205
|
-
.select(sel("*, mailbox_messages(subject, from_email, from_name, body_text, body_html, received_at, connection_id, to_recipients, cc_recipients, attachments, has_attachments), " +
|
|
206
|
+
.select(sel("*, mailbox_messages(subject, from_email, from_name, body_text, body_html, received_at, connection_id, account_email, to_recipients, cc_recipients, attachments, has_attachments), " +
|
|
206
207
|
"mailbox_proposal_lines(*), mailbox_proposal_field_values(*)"))
|
|
207
208
|
.eq("id", data.proposalId)
|
|
208
209
|
.maybeSingle();
|
|
@@ -1192,6 +1193,7 @@ export const listSkippedMessages = createServerFn({ method: "GET" })
|
|
|
1192
1193
|
.middleware([requireSupabaseAuth])
|
|
1193
1194
|
.handler(async () => {
|
|
1194
1195
|
const { supabaseAdmin } = await import("../integrations/supabase/client.server.js");
|
|
1196
|
+
await ensureMailboxDefaults(supabaseAdmin);
|
|
1195
1197
|
const { data, error } = await supabaseAdmin
|
|
1196
1198
|
.from("mailbox_messages")
|
|
1197
1199
|
.select("id, from_email, from_name, subject, received_at, preview, filter_outcome, filter_reason, analysis_state, analysis_note, mailbox_order_proposals(id)")
|
|
@@ -1256,3 +1258,105 @@ export const getStickerDefaults = createServerFn({ method: "POST" })
|
|
|
1256
1258
|
defaults[id] = defaultNeedsSticker(list, data.customerId, id);
|
|
1257
1259
|
return { available: true, defaults };
|
|
1258
1260
|
});
|
|
1261
|
+
// ─── Standaardinstellingen + statusregel ───────────────────────────────────
|
|
1262
|
+
/** Maakt ontbrekende singleton-instellingen aan (overschrijft nooit iets). Faalt nooit hard. */
|
|
1263
|
+
export async function ensureMailboxDefaults(admin) {
|
|
1264
|
+
try {
|
|
1265
|
+
await admin.rpc("mailbox_ensure_defaults");
|
|
1266
|
+
}
|
|
1267
|
+
catch {
|
|
1268
|
+
/* functie ontbreekt nog in deze database */
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
export const ensureMailboxDefaultsFn = createServerFn({ method: "POST" })
|
|
1272
|
+
.middleware([requireSupabaseAuth])
|
|
1273
|
+
.handler(async () => {
|
|
1274
|
+
const { supabaseAdmin } = await import("../integrations/supabase/client.server.js");
|
|
1275
|
+
await ensureMailboxDefaults(supabaseAdmin);
|
|
1276
|
+
return { ok: true };
|
|
1277
|
+
});
|
|
1278
|
+
export const getMailboxStatus = createServerFn({ method: "GET" })
|
|
1279
|
+
.middleware([requireSupabaseAuth])
|
|
1280
|
+
.handler(async () => {
|
|
1281
|
+
const { supabaseAdmin } = await import("../integrations/supabase/client.server.js");
|
|
1282
|
+
const admin = supabaseAdmin;
|
|
1283
|
+
await ensureMailboxDefaults(admin);
|
|
1284
|
+
const { data: active } = await admin.rpc("email_auth_for_purpose", { _purpose: "orders", _direction: "receive" });
|
|
1285
|
+
const activeRows = (Array.isArray(active) ? active : []);
|
|
1286
|
+
const activeIds = activeRows.map((r) => r.id).filter(Boolean);
|
|
1287
|
+
const [okRes, failRes] = await Promise.all([
|
|
1288
|
+
admin.from("mailbox_ingest_runs").select("started_at").eq("status", "ok").order("started_at", { ascending: false }).limit(1).maybeSingle(),
|
|
1289
|
+
admin.from("mailbox_ingest_runs").select("started_at, reason").eq("status", "fout").order("started_at", { ascending: false }).limit(1).maybeSingle(),
|
|
1290
|
+
]);
|
|
1291
|
+
const lastOkAt = okRes?.data?.started_at ?? null;
|
|
1292
|
+
const lastFailAt = failRes?.data?.started_at ?? null;
|
|
1293
|
+
const lastFailReason = failRes?.data?.reason ?? null;
|
|
1294
|
+
let pendingEvents = 0;
|
|
1295
|
+
if (activeIds.length > 0) {
|
|
1296
|
+
const { count } = await admin.from("email_auth_events").select("id", { count: "exact", head: true })
|
|
1297
|
+
.in("connection_id", activeIds).is("consumed_at", null);
|
|
1298
|
+
pendingEvents = count ?? 0;
|
|
1299
|
+
}
|
|
1300
|
+
const { count: waitingAi } = await admin.from("mailbox_messages").select("id", { count: "exact", head: true }).eq("analysis_state", "wacht");
|
|
1301
|
+
const since = new Date(Date.now() - 7 * 86400000).toISOString();
|
|
1302
|
+
const countIgnored = async (reason) => {
|
|
1303
|
+
const { count } = await admin.from("mailbox_ignored_events").select("id", { count: "exact", head: true })
|
|
1304
|
+
.eq("reason", reason).gte("created_at", since);
|
|
1305
|
+
return count ?? 0;
|
|
1306
|
+
};
|
|
1307
|
+
const [ignoredNotFollowed, ignoredUnknown] = await Promise.all([
|
|
1308
|
+
countIgnored("niet uit een gevolgde map"),
|
|
1309
|
+
countIgnored("map onbekend"),
|
|
1310
|
+
]);
|
|
1311
|
+
// Ontkoppelde adressen met onverwerkte events.
|
|
1312
|
+
// Events vóór de laatste ronde van die koppeling worden nog verwerkt; alleen de rest telt.
|
|
1313
|
+
let q = admin.from("email_auth_events").select("connection_id, received_at").is("consumed_at", null).limit(1000);
|
|
1314
|
+
if (activeIds.length > 0)
|
|
1315
|
+
q = q.not("connection_id", "in", `(${activeIds.join(",")})`);
|
|
1316
|
+
const { data: leftRows } = await q;
|
|
1317
|
+
const rowsLeft = (Array.isArray(leftRows) ? leftRows : []);
|
|
1318
|
+
const cutoffs = new Map();
|
|
1319
|
+
for (const id of new Set(rowsLeft.map((r) => r.connection_id).filter(Boolean))) {
|
|
1320
|
+
const { data: last } = await admin.from("mailbox_ingest_runs").select("started_at").eq("connection_id", id)
|
|
1321
|
+
.order("started_at", { ascending: false }).limit(1).maybeSingle();
|
|
1322
|
+
cutoffs.set(id, last?.started_at ?? null);
|
|
1323
|
+
}
|
|
1324
|
+
const leftCount = new Map();
|
|
1325
|
+
for (const r of rowsLeft) {
|
|
1326
|
+
if (!r.connection_id)
|
|
1327
|
+
continue;
|
|
1328
|
+
const cut = cutoffs.get(r.connection_id) ?? null;
|
|
1329
|
+
if (cut && r.received_at && r.received_at <= cut)
|
|
1330
|
+
continue;
|
|
1331
|
+
leftCount.set(r.connection_id, (leftCount.get(r.connection_id) ?? 0) + 1);
|
|
1332
|
+
}
|
|
1333
|
+
const disconnected = [];
|
|
1334
|
+
if (leftCount.size > 0) {
|
|
1335
|
+
const { data: cs } = await admin.from("email_auth_connections").select("id, account_email").in("id", [...leftCount.keys()]);
|
|
1336
|
+
const emailOf = new Map((Array.isArray(cs) ? cs : []).map((c) => [c.id, c.account_email ?? "onbekend adres"]));
|
|
1337
|
+
for (const [id, count] of leftCount)
|
|
1338
|
+
disconnected.push({ email: String(emailOf.get(id) ?? "onbekend adres"), count });
|
|
1339
|
+
}
|
|
1340
|
+
const { currentAiFingerprint } = await import("./mailbox-ai.server.js");
|
|
1341
|
+
const aiAgent = (await currentAiFingerprint(admin).catch(() => null)) !== null;
|
|
1342
|
+
const failNewer = !!lastFailAt && (!lastOkAt || lastFailAt > lastOkAt);
|
|
1343
|
+
let problem = null;
|
|
1344
|
+
if (failNewer)
|
|
1345
|
+
problem = `Er komen mails binnen, maar ze worden niet verwerkt: ${lastFailReason ?? "onbekende reden"}`;
|
|
1346
|
+
else if (pendingEvents > 0 && lastOkAt && Date.now() - Date.parse(lastOkAt) > 10 * 60000)
|
|
1347
|
+
problem = "Er komen mails binnen, maar ze worden niet verwerkt: de laatste geslaagde ronde is langer dan 10 minuten geleden.";
|
|
1348
|
+
else if (pendingEvents > 0 && !lastOkAt)
|
|
1349
|
+
problem = "Er komen mails binnen, maar ze worden niet verwerkt: er is nog geen enkele ronde geslaagd.";
|
|
1350
|
+
return {
|
|
1351
|
+
lastOkAt,
|
|
1352
|
+
lastFailAt,
|
|
1353
|
+
lastFailReason,
|
|
1354
|
+
problem,
|
|
1355
|
+
waiting: pendingEvents + (waitingAi ?? 0),
|
|
1356
|
+
aiAgent,
|
|
1357
|
+
addresses: activeRows.map((r) => String(r.account_email ?? "")).filter(Boolean),
|
|
1358
|
+
ignoredNotFollowed,
|
|
1359
|
+
ignoredUnknown,
|
|
1360
|
+
disconnected,
|
|
1361
|
+
};
|
|
1362
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowselections/mailbox-orders",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.50",
|
|
4
4
|
"private": false,
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"type": "module",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@cloudflare/vite-plugin": "^1.25.5",
|
|
52
52
|
"@eslint/js": "^9.32.0",
|
|
53
|
-
"@flowselections/core": "1.0.
|
|
53
|
+
"@flowselections/core": "1.0.35",
|
|
54
54
|
"@lovable.dev/vite-tanstack-config": "2.26.5",
|
|
55
55
|
"@rsbuild/core": "^1.0.0",
|
|
56
56
|
"@tailwindcss/vite": "^4.2.1",
|