@rubytech/create-maxy-code 0.1.331 → 0.1.333
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/__tests__/watchdog-deferred-arming.test.js +62 -0
- package/dist/index.js +82 -11
- package/package.json +1 -1
- package/payload/platform/lib/mcp-spawn-tee/dist/index.d.ts +24 -24
- package/payload/platform/lib/mcp-spawn-tee/dist/index.js +109 -75
- package/payload/platform/lib/mcp-spawn-tee/dist/index.js.map +1 -1
- package/payload/platform/lib/mcp-spawn-tee/src/__tests__/spawn-tee.test.ts +56 -19
- package/payload/platform/lib/mcp-spawn-tee/src/index.ts +112 -77
- package/payload/platform/neo4j/schema.cypher +58 -4
- package/payload/platform/plugins/admin/lib/mcp-spawn-tee/index.js +109 -75
- package/payload/platform/plugins/aeo/lib/mcp-spawn-tee/index.js +109 -75
- package/payload/platform/plugins/browser/lib/mcp-spawn-tee/index.js +109 -75
- package/payload/platform/plugins/contacts/lib/mcp-spawn-tee/index.js +109 -75
- package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/group-create.test.d.ts +2 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/group-create.test.d.ts.map +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/group-create.test.js +112 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/group-create.test.js.map +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/group-manage.test.d.ts +2 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/group-manage.test.d.ts.map +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/group-manage.test.js +102 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/group-manage.test.js.map +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.d.ts.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.js +7 -2
- package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.js.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/group-manage.d.ts.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/group-manage.js +5 -4
- package/payload/platform/plugins/contacts/mcp/dist/tools/group-manage.js.map +1 -1
- package/payload/platform/plugins/email/lib/mcp-spawn-tee/index.js +109 -75
- package/payload/platform/plugins/memory/lib/mcp-spawn-tee/index.js +109 -75
- package/payload/platform/plugins/memory/references/schema-estate-agent.md +17 -5
- package/payload/platform/plugins/outlook/lib/mcp-spawn-tee/index.js +109 -75
- package/payload/platform/plugins/quickbooks/lib/mcp-spawn-tee/index.js +109 -75
- package/payload/platform/plugins/replicate/lib/mcp-spawn-tee/index.js +109 -75
- package/payload/platform/plugins/scheduling/lib/mcp-spawn-tee/index.js +109 -75
- package/payload/platform/plugins/telegram/lib/mcp-spawn-tee/index.js +109 -75
- package/payload/platform/plugins/url-get/lib/mcp-spawn-tee/index.js +109 -75
- package/payload/platform/plugins/whatsapp/lib/mcp-spawn-tee/index.js +109 -75
- package/payload/platform/plugins/work/lib/mcp-spawn-tee/index.js +109 -75
- package/payload/platform/plugins/workflows/lib/mcp-spawn-tee/index.js +109 -75
- package/payload/platform/scripts/seed-neo4j.sh +18 -0
- package/payload/premium-plugins/writer-craft/lib/mcp-spawn-tee/index.js +109 -75
- package/payload/server/server.js +291 -213
package/payload/server/server.js
CHANGED
|
@@ -5276,7 +5276,53 @@ function composePublicSessionTitle(input) {
|
|
|
5276
5276
|
return segments.join(" \xB7 ");
|
|
5277
5277
|
}
|
|
5278
5278
|
|
|
5279
|
+
// app/lib/webchat/persist-customer-inbound.ts
|
|
5280
|
+
var TAG15 = "[channel-house]";
|
|
5281
|
+
async function persistCustomerWebchatInbound(input) {
|
|
5282
|
+
if (!input.text) return null;
|
|
5283
|
+
try {
|
|
5284
|
+
const conv = await ensureConversation(
|
|
5285
|
+
input.houseAccountId,
|
|
5286
|
+
"public",
|
|
5287
|
+
input.sessionKey,
|
|
5288
|
+
input.visitorId,
|
|
5289
|
+
input.agentSlug,
|
|
5290
|
+
void 0,
|
|
5291
|
+
"webchat",
|
|
5292
|
+
input.sessionKey
|
|
5293
|
+
);
|
|
5294
|
+
if (!conv.sessionId) {
|
|
5295
|
+
console.error(
|
|
5296
|
+
`${TAG15} op=persist-skip reason=conversation-merge-failed accountId=${input.houseAccountId} key=${input.sessionKey}`
|
|
5297
|
+
);
|
|
5298
|
+
return null;
|
|
5299
|
+
}
|
|
5300
|
+
const messageId = await persistMessage(
|
|
5301
|
+
conv.sessionId,
|
|
5302
|
+
"user",
|
|
5303
|
+
input.text,
|
|
5304
|
+
input.houseAccountId
|
|
5305
|
+
);
|
|
5306
|
+
if (!messageId) {
|
|
5307
|
+
console.error(
|
|
5308
|
+
`${TAG15} op=persist-skip reason=message-write-failed accountId=${input.houseAccountId} sessionId=${conv.sessionId.slice(0, 8)}`
|
|
5309
|
+
);
|
|
5310
|
+
return null;
|
|
5311
|
+
}
|
|
5312
|
+
console.error(
|
|
5313
|
+
`${TAG15} op=persist accountId=${input.houseAccountId} sessionId=${conv.sessionId.slice(0, 8)} messageId=${messageId.slice(0, 8)} bytes=${Buffer.byteLength(input.text, "utf8")}`
|
|
5314
|
+
);
|
|
5315
|
+
return { sessionId: conv.sessionId, messageId };
|
|
5316
|
+
} catch (err) {
|
|
5317
|
+
console.error(
|
|
5318
|
+
`${TAG15} op=persist-fail accountId=${input.houseAccountId} key=${input.sessionKey} reason=${err instanceof Error ? err.message : String(err)}`
|
|
5319
|
+
);
|
|
5320
|
+
return null;
|
|
5321
|
+
}
|
|
5322
|
+
}
|
|
5323
|
+
|
|
5279
5324
|
// server/routes/chat.ts
|
|
5325
|
+
var MANAGED_SERVICE_ACK = "Thanks, we've received your message and someone will be in touch shortly.";
|
|
5280
5326
|
var WEBCHAT_TAG = "[webchat-adaptor]";
|
|
5281
5327
|
var SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
5282
5328
|
function webchatTurnTimeoutMs() {
|
|
@@ -5452,6 +5498,38 @@ ${result.result.text}` : result.result.text;
|
|
|
5452
5498
|
console.error(
|
|
5453
5499
|
`${WEBCHAT_TAG} inbound from=${sk} bytes=${Buffer.byteLength(fullMessage, "utf8")} attachments=${attachmentCount} accountId=${account.accountId}`
|
|
5454
5500
|
);
|
|
5501
|
+
if (isCustomerTurnSuppressed("public", isHouseManagedService())) {
|
|
5502
|
+
if (!isGreeting) {
|
|
5503
|
+
await persistCustomerWebchatInbound({
|
|
5504
|
+
houseAccountId: account.accountId,
|
|
5505
|
+
sessionKey: session_key,
|
|
5506
|
+
text: message,
|
|
5507
|
+
...agentSlug ? { agentSlug } : {},
|
|
5508
|
+
...visitorId ? { visitorId } : {}
|
|
5509
|
+
});
|
|
5510
|
+
console.error(
|
|
5511
|
+
`[channel-house] op=inbound from=${sk} accountId=${account.accountId} autoReply=suppressed`
|
|
5512
|
+
);
|
|
5513
|
+
}
|
|
5514
|
+
const ackStream = new ReadableStream({
|
|
5515
|
+
start(controller) {
|
|
5516
|
+
if (!isGreeting) {
|
|
5517
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify({ text: MANAGED_SERVICE_ACK })}
|
|
5518
|
+
|
|
5519
|
+
`));
|
|
5520
|
+
}
|
|
5521
|
+
controller.enqueue(encoder.encode("data: [DONE]\n\n"));
|
|
5522
|
+
controller.close();
|
|
5523
|
+
}
|
|
5524
|
+
});
|
|
5525
|
+
return new Response(ackStream, {
|
|
5526
|
+
headers: {
|
|
5527
|
+
"Content-Type": "text/event-stream",
|
|
5528
|
+
"Cache-Control": "no-cache",
|
|
5529
|
+
Connection: "keep-alive"
|
|
5530
|
+
}
|
|
5531
|
+
});
|
|
5532
|
+
}
|
|
5455
5533
|
const readable = new ReadableStream({
|
|
5456
5534
|
async start(controller) {
|
|
5457
5535
|
try {
|
|
@@ -5528,7 +5606,7 @@ import { randomUUID as randomUUID6 } from "crypto";
|
|
|
5528
5606
|
// app/lib/whatsapp/config-persist.ts
|
|
5529
5607
|
import { readFileSync as readFileSync8, writeFileSync as writeFileSync4, existsSync as existsSync4 } from "fs";
|
|
5530
5608
|
import { resolve as resolve7, join as join6 } from "path";
|
|
5531
|
-
var
|
|
5609
|
+
var TAG16 = "[whatsapp:config]";
|
|
5532
5610
|
function configPath(accountDir) {
|
|
5533
5611
|
return resolve7(accountDir, "account.json");
|
|
5534
5612
|
}
|
|
@@ -5545,9 +5623,9 @@ function reloadManagerConfig(accountDir) {
|
|
|
5545
5623
|
try {
|
|
5546
5624
|
const config = readConfig(accountDir);
|
|
5547
5625
|
reloadConfig(config);
|
|
5548
|
-
console.error(`${
|
|
5626
|
+
console.error(`${TAG16} reloaded manager config`);
|
|
5549
5627
|
} catch (err) {
|
|
5550
|
-
console.error(`${
|
|
5628
|
+
console.error(`${TAG16} manager config reload failed: ${String(err)}`);
|
|
5551
5629
|
}
|
|
5552
5630
|
}
|
|
5553
5631
|
var E164_PATTERN = /^\+\d{7,15}$/;
|
|
@@ -5573,25 +5651,25 @@ function persistAfterPairing(accountDir, accountId, selfPhone) {
|
|
|
5573
5651
|
const adminPhones = wa.adminPhones;
|
|
5574
5652
|
if (!adminPhones.includes(normalized)) {
|
|
5575
5653
|
adminPhones.push(normalized);
|
|
5576
|
-
console.error(`${
|
|
5654
|
+
console.error(`${TAG16} added selfPhone=${normalized} to adminPhones`);
|
|
5577
5655
|
}
|
|
5578
5656
|
} else {
|
|
5579
|
-
console.error(`${
|
|
5657
|
+
console.error(`${TAG16} skipping adminPhones \u2014 selfPhone is null account=${accountId}`);
|
|
5580
5658
|
}
|
|
5581
5659
|
const parsed = WhatsAppConfigSchema.safeParse(wa);
|
|
5582
5660
|
if (!parsed.success) {
|
|
5583
5661
|
const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
|
|
5584
|
-
console.error(`${
|
|
5662
|
+
console.error(`${TAG16} validation failed after pairing: ${msg}`);
|
|
5585
5663
|
return { ok: false, error: `Validation failed: ${msg}` };
|
|
5586
5664
|
}
|
|
5587
5665
|
config.whatsapp = parsed.data;
|
|
5588
5666
|
writeConfig(accountDir, config);
|
|
5589
|
-
console.error(`${
|
|
5667
|
+
console.error(`${TAG16} persisted after pairing account=${accountId} phone=${selfPhone ?? "null"}`);
|
|
5590
5668
|
reloadManagerConfig(accountDir);
|
|
5591
5669
|
return { ok: true };
|
|
5592
5670
|
} catch (err) {
|
|
5593
5671
|
const msg = err instanceof Error ? err.message : String(err);
|
|
5594
|
-
console.error(`${
|
|
5672
|
+
console.error(`${TAG16} persist failed account=${accountId}: ${msg}`);
|
|
5595
5673
|
return { ok: false, error: msg };
|
|
5596
5674
|
}
|
|
5597
5675
|
}
|
|
@@ -5621,12 +5699,12 @@ function addAdminPhone(accountDir, phone) {
|
|
|
5621
5699
|
}
|
|
5622
5700
|
config.whatsapp = parsed.data;
|
|
5623
5701
|
writeConfig(accountDir, config);
|
|
5624
|
-
console.error(`${
|
|
5702
|
+
console.error(`${TAG16} added admin phone=${normalized}`);
|
|
5625
5703
|
reloadManagerConfig(accountDir);
|
|
5626
5704
|
return { ok: true, message: `Added ${normalized} as admin phone. Messages from this number will route to the admin agent.` };
|
|
5627
5705
|
} catch (err) {
|
|
5628
5706
|
const msg = err instanceof Error ? err.message : String(err);
|
|
5629
|
-
console.error(`${
|
|
5707
|
+
console.error(`${TAG16} addAdminPhone failed: ${msg}`);
|
|
5630
5708
|
return { ok: false, error: msg };
|
|
5631
5709
|
}
|
|
5632
5710
|
}
|
|
@@ -5654,12 +5732,12 @@ function removeAdminPhone(accountDir, phone) {
|
|
|
5654
5732
|
}
|
|
5655
5733
|
config.whatsapp = parsed.data;
|
|
5656
5734
|
writeConfig(accountDir, config);
|
|
5657
|
-
console.error(`${
|
|
5735
|
+
console.error(`${TAG16} removed admin phone=${normalized}`);
|
|
5658
5736
|
reloadManagerConfig(accountDir);
|
|
5659
5737
|
return { ok: true, message: `Removed ${normalized} from admin phones. Messages from this number will now route to the public agent.` };
|
|
5660
5738
|
} catch (err) {
|
|
5661
5739
|
const msg = err instanceof Error ? err.message : String(err);
|
|
5662
|
-
console.error(`${
|
|
5740
|
+
console.error(`${TAG16} removeAdminPhone failed: ${msg}`);
|
|
5663
5741
|
return { ok: false, error: msg };
|
|
5664
5742
|
}
|
|
5665
5743
|
}
|
|
@@ -5697,12 +5775,12 @@ function setPublicAgent(accountDir, slug) {
|
|
|
5697
5775
|
}
|
|
5698
5776
|
config.whatsapp = parsed.data;
|
|
5699
5777
|
writeConfig(accountDir, config);
|
|
5700
|
-
console.error(`${
|
|
5778
|
+
console.error(`${TAG16} publicAgent set to ${trimmed}`);
|
|
5701
5779
|
reloadManagerConfig(accountDir);
|
|
5702
5780
|
return { ok: true, message: `Public agent set to "${trimmed}". WhatsApp messages from non-admin phones will be handled by this agent.` };
|
|
5703
5781
|
} catch (err) {
|
|
5704
5782
|
const msg = err instanceof Error ? err.message : String(err);
|
|
5705
|
-
console.error(`${
|
|
5783
|
+
console.error(`${TAG16} setPublicAgent failed: ${msg}`);
|
|
5706
5784
|
return { ok: false, error: msg };
|
|
5707
5785
|
}
|
|
5708
5786
|
}
|
|
@@ -5743,17 +5821,17 @@ function updateConfig(accountDir, fields) {
|
|
|
5743
5821
|
const parsed = WhatsAppConfigSchema.safeParse(wa);
|
|
5744
5822
|
if (!parsed.success) {
|
|
5745
5823
|
const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
|
|
5746
|
-
console.error(`${
|
|
5824
|
+
console.error(`${TAG16} update validation failed: ${msg}`);
|
|
5747
5825
|
return { ok: false, error: `Validation failed: ${msg}` };
|
|
5748
5826
|
}
|
|
5749
5827
|
config.whatsapp = parsed.data;
|
|
5750
5828
|
writeConfig(accountDir, config);
|
|
5751
|
-
console.error(`${
|
|
5829
|
+
console.error(`${TAG16} updated fields=[${fieldNames.join(",")}]`);
|
|
5752
5830
|
reloadManagerConfig(accountDir);
|
|
5753
5831
|
return { ok: true, message: `Updated WhatsApp config: ${fieldNames.join(", ")}.` };
|
|
5754
5832
|
} catch (err) {
|
|
5755
5833
|
const msg = err instanceof Error ? err.message : String(err);
|
|
5756
|
-
console.error(`${
|
|
5834
|
+
console.error(`${TAG16} updateConfig failed: ${msg}`);
|
|
5757
5835
|
return { ok: false, error: msg };
|
|
5758
5836
|
}
|
|
5759
5837
|
}
|
|
@@ -5790,17 +5868,17 @@ function migrateRemovedConfigKeys(accountDir) {
|
|
|
5790
5868
|
}
|
|
5791
5869
|
writeConfig(accountDir, config);
|
|
5792
5870
|
console.error(
|
|
5793
|
-
`${
|
|
5871
|
+
`${TAG16} migration: stripped unknown keys=[${result.droppedKeys.join(",")}] from account.json`
|
|
5794
5872
|
);
|
|
5795
5873
|
return { dropped: result.droppedKeys };
|
|
5796
5874
|
} catch (err) {
|
|
5797
|
-
console.error(`${
|
|
5875
|
+
console.error(`${TAG16} migration failed: ${String(err)}`);
|
|
5798
5876
|
return { dropped: [] };
|
|
5799
5877
|
}
|
|
5800
5878
|
}
|
|
5801
5879
|
|
|
5802
5880
|
// app/lib/whatsapp/login.ts
|
|
5803
|
-
var
|
|
5881
|
+
var TAG17 = "[whatsapp:login]";
|
|
5804
5882
|
function maskPhone(digits) {
|
|
5805
5883
|
if (digits.length <= 4) return "*".repeat(digits.length);
|
|
5806
5884
|
return digits.slice(0, 2) + "*".repeat(digits.length - 4) + digits.slice(-2);
|
|
@@ -5811,7 +5889,7 @@ function closeSocket(sock) {
|
|
|
5811
5889
|
try {
|
|
5812
5890
|
sock.ws?.close?.();
|
|
5813
5891
|
} catch (err) {
|
|
5814
|
-
console.warn(`${
|
|
5892
|
+
console.warn(`${TAG17} socket close error during cleanup: ${String(err)}`);
|
|
5815
5893
|
}
|
|
5816
5894
|
}
|
|
5817
5895
|
function resetActiveLogin(accountId) {
|
|
@@ -5838,18 +5916,18 @@ async function runPostPairing(login) {
|
|
|
5838
5916
|
const masked = selfPhone ? `${selfPhone.slice(0, 4)}***` : "null";
|
|
5839
5917
|
console.error(`[whatsapp-persist] wa-persist-on-connect account=${login.accountId} phone=${masked}`);
|
|
5840
5918
|
} else {
|
|
5841
|
-
console.error(`${
|
|
5919
|
+
console.error(`${TAG17} wa-persist-on-connect FAILED account=${login.accountId}: ${result.error}`);
|
|
5842
5920
|
}
|
|
5843
5921
|
} catch (err) {
|
|
5844
|
-
console.error(`${
|
|
5922
|
+
console.error(`${TAG17} wa-persist-on-connect error account=${login.accountId}: ${String(err)}`);
|
|
5845
5923
|
}
|
|
5846
5924
|
} else {
|
|
5847
|
-
console.error(`${
|
|
5925
|
+
console.error(`${TAG17} wa-persist-on-connect skipped \u2014 no accountDir account=${login.accountId}`);
|
|
5848
5926
|
}
|
|
5849
5927
|
try {
|
|
5850
5928
|
await registerLoginSocket(login.accountId, login.sock, login.authDir);
|
|
5851
5929
|
} catch (err) {
|
|
5852
|
-
console.error(`${
|
|
5930
|
+
console.error(`${TAG17} registerLoginSocket failed account=${login.accountId}: ${String(err)}`);
|
|
5853
5931
|
}
|
|
5854
5932
|
}
|
|
5855
5933
|
async function loginConnectionLoop(accountId, login) {
|
|
@@ -5861,7 +5939,7 @@ async function loginConnectionLoop(accountId, login) {
|
|
|
5861
5939
|
if (current?.id === login.id) {
|
|
5862
5940
|
await runPostPairing(current);
|
|
5863
5941
|
current.connected = true;
|
|
5864
|
-
console.error(`${
|
|
5942
|
+
console.error(`${TAG17} loginConnectionLoop: connected account=${accountId} attempt=${attempt} configPersisted=${current.configPersisted}`);
|
|
5865
5943
|
}
|
|
5866
5944
|
return;
|
|
5867
5945
|
} catch (err) {
|
|
@@ -5871,7 +5949,7 @@ async function loginConnectionLoop(accountId, login) {
|
|
|
5871
5949
|
if (!classification.shouldRetry || attempt >= LOGIN_MAX_RECONNECTS) {
|
|
5872
5950
|
if (attempt >= LOGIN_MAX_RECONNECTS) {
|
|
5873
5951
|
console.error(
|
|
5874
|
-
`${
|
|
5952
|
+
`${TAG17} login reconnect attempts exhausted (${attempt}/${LOGIN_MAX_RECONNECTS}) \u2014 surfacing error to agent`
|
|
5875
5953
|
);
|
|
5876
5954
|
current.error = `Login failed after ${attempt} reconnect attempts: ${formatError(err)}`;
|
|
5877
5955
|
} else {
|
|
@@ -5883,7 +5961,7 @@ async function loginConnectionLoop(accountId, login) {
|
|
|
5883
5961
|
attempt++;
|
|
5884
5962
|
const delay = LOGIN_RECONNECT_DELAYS[attempt - 1] ?? 8e3;
|
|
5885
5963
|
console.error(
|
|
5886
|
-
`${
|
|
5964
|
+
`${TAG17} status=${classification.statusCode ?? "unknown"} restart required \u2014 reconnecting with saved creds (attempt ${attempt}/${LOGIN_MAX_RECONNECTS}) delay=${delay}ms`
|
|
5887
5965
|
);
|
|
5888
5966
|
closeSocket(current.sock);
|
|
5889
5967
|
await new Promise((r) => setTimeout(r, delay));
|
|
@@ -5894,7 +5972,7 @@ async function loginConnectionLoop(accountId, login) {
|
|
|
5894
5972
|
current.sock = newSock;
|
|
5895
5973
|
} catch (sockErr) {
|
|
5896
5974
|
console.error(
|
|
5897
|
-
`${
|
|
5975
|
+
`${TAG17} reconnect socket creation failed (attempt ${attempt}/${LOGIN_MAX_RECONNECTS}): ${String(sockErr)}`
|
|
5898
5976
|
);
|
|
5899
5977
|
current.error = `Reconnection failed: ${String(sockErr)}`;
|
|
5900
5978
|
return;
|
|
@@ -5908,7 +5986,7 @@ async function startLogin(opts) {
|
|
|
5908
5986
|
const hasAuth = await authExists(authDir);
|
|
5909
5987
|
const selfId = readSelfId(authDir);
|
|
5910
5988
|
console.error(
|
|
5911
|
-
`${
|
|
5989
|
+
`${TAG17} startLogin account=${accountId} force=${!!force} hasAuth=${hasAuth}` + (existing0 ? ` activeLogin={id=${existing0.id.slice(0, 8)},age=${Math.round((Date.now() - existing0.startedAt) / 1e3)}s,hasCode=${!!existing0.pairingCode}}` : " activeLogin=none")
|
|
5912
5990
|
);
|
|
5913
5991
|
if (hasAuth && !force) {
|
|
5914
5992
|
const who = selfId.e164 ?? selfId.jid ?? "unknown";
|
|
@@ -5923,7 +6001,7 @@ async function startLogin(opts) {
|
|
|
5923
6001
|
}
|
|
5924
6002
|
const existing = activeLogins.get(accountId);
|
|
5925
6003
|
if (existing && isLoginFresh(existing) && existing.pairingCode && !force) {
|
|
5926
|
-
console.error(`${
|
|
6004
|
+
console.error(`${TAG17} startLogin account=${accountId} guard: returning existing pairing code (age=${Math.round((Date.now() - existing.startedAt) / 1e3)}s)`);
|
|
5927
6005
|
return {
|
|
5928
6006
|
pairingCode: existing.pairingCode,
|
|
5929
6007
|
phone: existing.phone,
|
|
@@ -5931,7 +6009,7 @@ async function startLogin(opts) {
|
|
|
5931
6009
|
};
|
|
5932
6010
|
}
|
|
5933
6011
|
if (existing) {
|
|
5934
|
-
console.error(`${
|
|
6012
|
+
console.error(`${TAG17} startLogin account=${accountId} ${force ? "force override" : "stale/no-code"}, resetting active login`);
|
|
5935
6013
|
}
|
|
5936
6014
|
resetActiveLogin(accountId);
|
|
5937
6015
|
await clearAuth(authDir);
|
|
@@ -5961,7 +6039,7 @@ async function startLogin(opts) {
|
|
|
5961
6039
|
const current = activeLogins.get(accountId);
|
|
5962
6040
|
if (current?.id !== login.id) return;
|
|
5963
6041
|
if (!current.pairingCode) current.pairingCode = code;
|
|
5964
|
-
console.error(`${
|
|
6042
|
+
console.error(`${TAG17} pairing-code-issued account=${accountId} phone=${maskPhone(digits)} codeLen=${code.length}`);
|
|
5965
6043
|
resolveCode?.(code);
|
|
5966
6044
|
}).catch((err) => {
|
|
5967
6045
|
clearTimeout(codeTimer);
|
|
@@ -5990,7 +6068,7 @@ async function startLogin(opts) {
|
|
|
5990
6068
|
const ttlTimer = setTimeout(() => {
|
|
5991
6069
|
const current = activeLogins.get(accountId);
|
|
5992
6070
|
if (current?.id === login.id && !current.connected) {
|
|
5993
|
-
console.error(`${
|
|
6071
|
+
console.error(`${TAG17} pairing-window-elapsed account=${accountId} (ttl sweep)`);
|
|
5994
6072
|
resetActiveLogin(accountId);
|
|
5995
6073
|
}
|
|
5996
6074
|
}, ACTIVE_LOGIN_TTL_MS);
|
|
@@ -5998,7 +6076,7 @@ async function startLogin(opts) {
|
|
|
5998
6076
|
ttlTimer.unref();
|
|
5999
6077
|
}
|
|
6000
6078
|
loginConnectionLoop(accountId, login).catch((err) => {
|
|
6001
|
-
console.error(`${
|
|
6079
|
+
console.error(`${TAG17} loginConnectionLoop unexpected error: ${String(err)}`);
|
|
6002
6080
|
const current = activeLogins.get(accountId);
|
|
6003
6081
|
if (current?.id === login.id) {
|
|
6004
6082
|
current.error = `Unexpected login error: ${String(err)}`;
|
|
@@ -6023,13 +6101,13 @@ async function waitForLogin(opts) {
|
|
|
6023
6101
|
const { accountId, timeoutMs = 6e4 } = opts;
|
|
6024
6102
|
const login = activeLogins.get(accountId);
|
|
6025
6103
|
console.error(
|
|
6026
|
-
`${
|
|
6104
|
+
`${TAG17} waitForLogin account=${accountId} timeout=${timeoutMs}ms` + (login ? ` login={id=${login.id.slice(0, 8)},age=${Math.round((Date.now() - login.startedAt) / 1e3)}s,connected=${login.connected},hasCode=${!!login.pairingCode}}` : " login=none")
|
|
6027
6105
|
);
|
|
6028
6106
|
if (!login) {
|
|
6029
6107
|
return { connected: false, message: "No active WhatsApp login in progress.", configPersisted: false };
|
|
6030
6108
|
}
|
|
6031
6109
|
if (!isLoginFresh(login)) {
|
|
6032
|
-
console.error(`${
|
|
6110
|
+
console.error(`${TAG17} pairing-window-elapsed account=${accountId}`);
|
|
6033
6111
|
resetActiveLogin(accountId);
|
|
6034
6112
|
return { connected: false, message: "The pairing window expired. Ask me to generate a new code.", configPersisted: false };
|
|
6035
6113
|
}
|
|
@@ -6037,8 +6115,8 @@ async function waitForLogin(opts) {
|
|
|
6037
6115
|
while (Date.now() < deadline) {
|
|
6038
6116
|
if (login.connected) {
|
|
6039
6117
|
const selfId = readSelfId(login.authDir);
|
|
6040
|
-
console.error(`${
|
|
6041
|
-
console.error(`${
|
|
6118
|
+
console.error(`${TAG17} pairing-connected account=${accountId} phone=${selfId.e164 ?? "unknown"}`);
|
|
6119
|
+
console.error(`${TAG17} login complete for account=${accountId} phone=${selfId.e164 ?? "unknown"} configPersisted=${login.configPersisted}`);
|
|
6042
6120
|
const configPersisted = login.configPersisted;
|
|
6043
6121
|
activeLogins.delete(accountId);
|
|
6044
6122
|
return {
|
|
@@ -6056,7 +6134,7 @@ async function waitForLogin(opts) {
|
|
|
6056
6134
|
await new Promise((r) => setTimeout(r, 1e3));
|
|
6057
6135
|
}
|
|
6058
6136
|
const elapsed = Math.round((Date.now() - (deadline - timeoutMs)) / 1e3);
|
|
6059
|
-
console.error(`${
|
|
6137
|
+
console.error(`${TAG17} waitForLogin poll timeout account=${accountId} elapsed=${elapsed}s \u2014 login kept alive (pairing code still valid)`);
|
|
6060
6138
|
return { connected: false, message: "Still waiting for you to enter the pairing code. The code is still valid \u2014 ask me to keep waiting, or request a new code.", configPersisted: false };
|
|
6061
6139
|
}
|
|
6062
6140
|
|
|
@@ -6064,7 +6142,7 @@ async function waitForLogin(opts) {
|
|
|
6064
6142
|
import { realpathSync as realpathSync3 } from "fs";
|
|
6065
6143
|
import { readFile, stat as stat2 } from "fs/promises";
|
|
6066
6144
|
import { resolve as resolve8, basename } from "path";
|
|
6067
|
-
var
|
|
6145
|
+
var TAG18 = "[whatsapp:outbound]";
|
|
6068
6146
|
var WHATSAPP_DOCUMENT_MAX_BYTES = 100 * 1024 * 1024;
|
|
6069
6147
|
var lastDocumentOutboundAt = /* @__PURE__ */ new Map();
|
|
6070
6148
|
var lastRouteDocumentOutboundAt = /* @__PURE__ */ new Map();
|
|
@@ -6098,16 +6176,16 @@ async function sendWhatsAppDocument(input) {
|
|
|
6098
6176
|
const accountResolved = realpathSync3(accountDir);
|
|
6099
6177
|
if (!resolvedPath.startsWith(accountResolved + "/")) {
|
|
6100
6178
|
const sanitised = filePath.replace(accountDir, "<account>/");
|
|
6101
|
-
console.error(`${
|
|
6179
|
+
console.error(`${TAG18} document REJECTED path=${sanitised} reason=outside_account_directory`);
|
|
6102
6180
|
return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
|
|
6103
6181
|
}
|
|
6104
6182
|
} catch (err) {
|
|
6105
6183
|
const code = err.code;
|
|
6106
6184
|
if (code === "ENOENT") {
|
|
6107
|
-
console.error(`${
|
|
6185
|
+
console.error(`${TAG18} document ENOENT path=${filePath}`);
|
|
6108
6186
|
return { ok: false, status: 404, error: `File not found: ${filePath}` };
|
|
6109
6187
|
}
|
|
6110
|
-
console.error(`${
|
|
6188
|
+
console.error(`${TAG18} document path error: ${String(err)}`);
|
|
6111
6189
|
return { ok: false, status: 500, error: String(err) };
|
|
6112
6190
|
}
|
|
6113
6191
|
const fileStat = await stat2(resolvedPath);
|
|
@@ -6122,7 +6200,7 @@ async function sendWhatsAppDocument(input) {
|
|
|
6122
6200
|
const jid = normalizeJid2(to);
|
|
6123
6201
|
const sock = getSocket(accountId);
|
|
6124
6202
|
if (!sock) {
|
|
6125
|
-
console.error(`${
|
|
6203
|
+
console.error(`${TAG18} sent document to=${jid} file=${filename} bytes=${fileStat.size} ok=false reason=not-connected`);
|
|
6126
6204
|
return { ok: false, status: 503, error: `WhatsApp account "${accountId}" is not connected` };
|
|
6127
6205
|
}
|
|
6128
6206
|
const buffer = Buffer.from(await readFile(resolvedPath));
|
|
@@ -6134,7 +6212,7 @@ async function sendWhatsAppDocument(input) {
|
|
|
6134
6212
|
{ accountId }
|
|
6135
6213
|
);
|
|
6136
6214
|
console.error(
|
|
6137
|
-
`${
|
|
6215
|
+
`${TAG18} sent document to=${jid} file=${filename} bytes=${fileStat.size} ok=${result.success}` + (result.messageId ? ` id=${result.messageId}` : "")
|
|
6138
6216
|
);
|
|
6139
6217
|
if (result.success) {
|
|
6140
6218
|
recordDocumentOutbound(to);
|
|
@@ -6254,7 +6332,7 @@ function serializeWhatsAppSchema() {
|
|
|
6254
6332
|
// app/lib/whatsapp/status-reconcile.ts
|
|
6255
6333
|
import { readdirSync as readdirSync2 } from "fs";
|
|
6256
6334
|
import { join as join7 } from "path";
|
|
6257
|
-
var
|
|
6335
|
+
var TAG19 = "[whatsapp:reconcile]";
|
|
6258
6336
|
function listCredsAccountIds(credsRoot) {
|
|
6259
6337
|
try {
|
|
6260
6338
|
return readdirSync2(credsRoot, { withFileTypes: true }).filter((e) => e.isDirectory() && hasCredsSync(join7(credsRoot, e.name))).map((e) => e.name);
|
|
@@ -6276,14 +6354,14 @@ function reconcileCredsOnDisk(opts) {
|
|
|
6276
6354
|
const selfPhone = readSelfId(authDir).e164 ?? void 0;
|
|
6277
6355
|
const configured = accountDir ? isAccountConfigured(accountDir, accountId) : false;
|
|
6278
6356
|
console.error(
|
|
6279
|
-
`${
|
|
6357
|
+
`${TAG19} wa-link-unconfigured account=${accountId} creds=present config=${configured ? "present" : "absent"}`
|
|
6280
6358
|
);
|
|
6281
6359
|
if (!configured && accountDir) {
|
|
6282
6360
|
const result = persistAfterPairing(accountDir, accountId, selfPhone ?? null);
|
|
6283
6361
|
if (result.ok) {
|
|
6284
|
-
console.error(`${
|
|
6362
|
+
console.error(`${TAG19} self-healed account=${accountId}`);
|
|
6285
6363
|
} else {
|
|
6286
|
-
console.error(`${
|
|
6364
|
+
console.error(`${TAG19} self-heal FAILED account=${accountId}: ${result.error}`);
|
|
6287
6365
|
}
|
|
6288
6366
|
}
|
|
6289
6367
|
entries.push({ accountId, selfPhone, connected: false, linkedUnconfigured: !configured });
|
|
@@ -6292,7 +6370,7 @@ function reconcileCredsOnDisk(opts) {
|
|
|
6292
6370
|
}
|
|
6293
6371
|
|
|
6294
6372
|
// server/routes/whatsapp.ts
|
|
6295
|
-
var
|
|
6373
|
+
var TAG20 = "[whatsapp:api]";
|
|
6296
6374
|
var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
6297
6375
|
var app2 = new Hono();
|
|
6298
6376
|
app2.get("/status", (c) => {
|
|
@@ -6304,10 +6382,10 @@ app2.get("/status", (c) => {
|
|
|
6304
6382
|
const reconciled = reconcileCredsOnDisk({ credsRoot, accountDir, liveAccountIds: liveIds });
|
|
6305
6383
|
const accounts = [...live, ...reconciled];
|
|
6306
6384
|
const summary = accounts.map((a) => `${a.accountId}:${a.connected ? "up" : a.linkedUnconfigured ? "linked-unconfigured" : "down"}`).join(", ");
|
|
6307
|
-
console.error(`${
|
|
6385
|
+
console.error(`${TAG20} status accounts=${accounts.length} [${summary}]`);
|
|
6308
6386
|
return c.json({ accounts });
|
|
6309
6387
|
} catch (err) {
|
|
6310
|
-
console.error(`${
|
|
6388
|
+
console.error(`${TAG20} status error: ${String(err)}`);
|
|
6311
6389
|
return c.json({ error: String(err) }, 500);
|
|
6312
6390
|
}
|
|
6313
6391
|
});
|
|
@@ -6323,10 +6401,10 @@ app2.post("/login/start", async (c) => {
|
|
|
6323
6401
|
const authDir = join8(MAXY_DIR, "credentials", "whatsapp", accountId);
|
|
6324
6402
|
const accountDir = resolveAccount()?.accountDir ?? null;
|
|
6325
6403
|
const result = await startLogin({ accountId, authDir, phone, accountDir, force });
|
|
6326
|
-
console.error(`${
|
|
6404
|
+
console.error(`${TAG20} login/start result account=${accountId} hasCode=${!!result.pairingCode}${result.selfPhone ? ` phone=${result.selfPhone}` : ""}`);
|
|
6327
6405
|
return c.json(result);
|
|
6328
6406
|
} catch (err) {
|
|
6329
|
-
console.error(`${
|
|
6407
|
+
console.error(`${TAG20} login/start error: ${String(err)}`);
|
|
6330
6408
|
return c.json({ error: String(err) }, 500);
|
|
6331
6409
|
}
|
|
6332
6410
|
});
|
|
@@ -6336,7 +6414,7 @@ app2.post("/login/wait", async (c) => {
|
|
|
6336
6414
|
const accountId = validateAccountId(body.accountId);
|
|
6337
6415
|
const timeoutMs = body.timeoutMs ?? 6e4;
|
|
6338
6416
|
const result = await waitForLogin({ accountId, timeoutMs });
|
|
6339
|
-
console.error(`${
|
|
6417
|
+
console.error(`${TAG20} login/wait result account=${accountId} connected=${result.connected}${result.selfPhone ? ` phone=${result.selfPhone}` : ""} configPersisted=${result.configPersisted}`);
|
|
6340
6418
|
return c.json({
|
|
6341
6419
|
connected: result.connected,
|
|
6342
6420
|
message: result.message,
|
|
@@ -6344,7 +6422,7 @@ app2.post("/login/wait", async (c) => {
|
|
|
6344
6422
|
configPersisted: result.configPersisted
|
|
6345
6423
|
});
|
|
6346
6424
|
} catch (err) {
|
|
6347
|
-
console.error(`${
|
|
6425
|
+
console.error(`${TAG20} login/wait error: ${String(err)}`);
|
|
6348
6426
|
return c.json({ error: String(err) }, 500);
|
|
6349
6427
|
}
|
|
6350
6428
|
});
|
|
@@ -6355,7 +6433,7 @@ app2.post("/disconnect", async (c) => {
|
|
|
6355
6433
|
await stopConnection(accountId);
|
|
6356
6434
|
return c.json({ disconnected: true, accountId });
|
|
6357
6435
|
} catch (err) {
|
|
6358
|
-
console.error(`${
|
|
6436
|
+
console.error(`${TAG20} disconnect error: ${String(err)}`);
|
|
6359
6437
|
return c.json({ error: String(err) }, 500);
|
|
6360
6438
|
}
|
|
6361
6439
|
});
|
|
@@ -6366,7 +6444,7 @@ app2.post("/reconnect", async (c) => {
|
|
|
6366
6444
|
await startConnection(accountId);
|
|
6367
6445
|
return c.json({ reconnecting: true, accountId });
|
|
6368
6446
|
} catch (err) {
|
|
6369
|
-
console.error(`${
|
|
6447
|
+
console.error(`${TAG20} reconnect error: ${String(err)}`);
|
|
6370
6448
|
return c.json({ error: String(err) }, 500);
|
|
6371
6449
|
}
|
|
6372
6450
|
});
|
|
@@ -6387,7 +6465,7 @@ app2.post("/config", async (c) => {
|
|
|
6387
6465
|
return c.json({ ok: false, error: 'Missing required field "phone" (E.164 format, e.g. +441234567890).' }, 400);
|
|
6388
6466
|
}
|
|
6389
6467
|
const result = addAdminPhone(account.accountDir, phone);
|
|
6390
|
-
console.error(`${
|
|
6468
|
+
console.error(`${TAG20} config action=add-admin-phone phone=${phone} ok=${result.ok}`);
|
|
6391
6469
|
return c.json(result, result.ok ? 200 : 400);
|
|
6392
6470
|
}
|
|
6393
6471
|
case "remove-admin-phone": {
|
|
@@ -6395,12 +6473,12 @@ app2.post("/config", async (c) => {
|
|
|
6395
6473
|
return c.json({ ok: false, error: 'Missing required field "phone".' }, 400);
|
|
6396
6474
|
}
|
|
6397
6475
|
const result = removeAdminPhone(account.accountDir, phone);
|
|
6398
|
-
console.error(`${
|
|
6476
|
+
console.error(`${TAG20} config action=remove-admin-phone phone=${phone} ok=${result.ok}`);
|
|
6399
6477
|
return c.json(result, result.ok ? 200 : 400);
|
|
6400
6478
|
}
|
|
6401
6479
|
case "list-admin-phones": {
|
|
6402
6480
|
const phones = readAdminPhones(account.accountDir);
|
|
6403
|
-
console.error(`${
|
|
6481
|
+
console.error(`${TAG20} config action=list-admin-phones count=${phones.length}`);
|
|
6404
6482
|
return c.json({ ok: true, phones });
|
|
6405
6483
|
}
|
|
6406
6484
|
case "set-public-agent": {
|
|
@@ -6408,13 +6486,13 @@ app2.post("/config", async (c) => {
|
|
|
6408
6486
|
return c.json({ ok: false, error: 'Missing required field "slug" (the agent directory name, e.g. "my-agent").' }, 400);
|
|
6409
6487
|
}
|
|
6410
6488
|
const result = setPublicAgent(account.accountDir, slug);
|
|
6411
|
-
console.error(`${
|
|
6489
|
+
console.error(`${TAG20} config action=set-public-agent slug=${slug} ok=${result.ok}`);
|
|
6412
6490
|
return c.json(result, result.ok ? 200 : 400);
|
|
6413
6491
|
}
|
|
6414
6492
|
case "get-public-agent": {
|
|
6415
6493
|
const targetAccount = typeof accountId === "string" && accountId.trim() ? accountId.trim() : "default";
|
|
6416
6494
|
const resolved = resolvePublicAgent(account.accountDir, { accountId: targetAccount });
|
|
6417
|
-
console.error(`${
|
|
6495
|
+
console.error(`${TAG20} config action=get-public-agent accountId=${targetAccount} slug=${resolved?.slug ?? "none"} source=${resolved?.source ?? "none"}`);
|
|
6418
6496
|
return c.json({ ok: true, slug: resolved?.slug ?? null, source: resolved?.source ?? null });
|
|
6419
6497
|
}
|
|
6420
6498
|
case "list-public-agents": {
|
|
@@ -6431,26 +6509,26 @@ app2.post("/config", async (c) => {
|
|
|
6431
6509
|
const config = JSON.parse(readFileSync9(configPath2, "utf-8"));
|
|
6432
6510
|
agents.push({ slug: entry.name, displayName: config.displayName ?? entry.name });
|
|
6433
6511
|
} catch {
|
|
6434
|
-
console.error(`${
|
|
6512
|
+
console.error(`${TAG20} config action=list-public-agents error="failed to parse config.json for agent ${entry.name}" \u2014 skipping`);
|
|
6435
6513
|
}
|
|
6436
6514
|
}
|
|
6437
6515
|
} catch (err) {
|
|
6438
|
-
console.error(`${
|
|
6516
|
+
console.error(`${TAG20} config action=list-public-agents error="failed to scan agents directory: ${String(err)}"`);
|
|
6439
6517
|
}
|
|
6440
6518
|
}
|
|
6441
|
-
console.error(`${
|
|
6519
|
+
console.error(`${TAG20} config action=list-public-agents count=${agents.length}`);
|
|
6442
6520
|
return c.json({ ok: true, agents });
|
|
6443
6521
|
}
|
|
6444
6522
|
case "schema": {
|
|
6445
6523
|
const text = serializeWhatsAppSchema();
|
|
6446
|
-
console.error(`${
|
|
6524
|
+
console.error(`${TAG20} config action=schema`);
|
|
6447
6525
|
return c.json({ ok: true, text });
|
|
6448
6526
|
}
|
|
6449
6527
|
case "list-groups": {
|
|
6450
6528
|
const groupAccountId = accountId ?? "default";
|
|
6451
6529
|
const sock = getSocket(groupAccountId);
|
|
6452
6530
|
if (!sock) {
|
|
6453
|
-
console.error(`${
|
|
6531
|
+
console.error(`${TAG20} config action=list-groups error="not connected" accountId=${groupAccountId}`);
|
|
6454
6532
|
return c.json({ ok: false, error: `WhatsApp account "${groupAccountId}" is not connected. Connect first, then retry.` });
|
|
6455
6533
|
}
|
|
6456
6534
|
try {
|
|
@@ -6460,10 +6538,10 @@ app2.post("/config", async (c) => {
|
|
|
6460
6538
|
name: g.subject ?? g.id,
|
|
6461
6539
|
participantCount: Array.isArray(g.participants) ? g.participants.length : 0
|
|
6462
6540
|
}));
|
|
6463
|
-
console.error(`${
|
|
6541
|
+
console.error(`${TAG20} config action=list-groups count=${groups.length} accountId=${groupAccountId}`);
|
|
6464
6542
|
return c.json({ ok: true, groups });
|
|
6465
6543
|
} catch (err) {
|
|
6466
|
-
console.error(`${
|
|
6544
|
+
console.error(`${TAG20} config action=list-groups error="${String(err)}" accountId=${groupAccountId}`);
|
|
6467
6545
|
return c.json({ ok: false, error: `Failed to fetch groups: ${String(err)}` });
|
|
6468
6546
|
}
|
|
6469
6547
|
}
|
|
@@ -6473,12 +6551,12 @@ app2.post("/config", async (c) => {
|
|
|
6473
6551
|
}
|
|
6474
6552
|
const result = updateConfig(account.accountDir, fields);
|
|
6475
6553
|
const fieldNames = Object.keys(fields);
|
|
6476
|
-
console.error(`${
|
|
6554
|
+
console.error(`${TAG20} config action=update-config fields=[${fieldNames.join(",")}] ok=${result.ok}`);
|
|
6477
6555
|
return c.json(result, result.ok ? 200 : 400);
|
|
6478
6556
|
}
|
|
6479
6557
|
case "get-config": {
|
|
6480
6558
|
const waConfig = getConfig(account.accountDir);
|
|
6481
|
-
console.error(`${
|
|
6559
|
+
console.error(`${TAG20} config action=get-config`);
|
|
6482
6560
|
return c.json({ ok: true, config: waConfig });
|
|
6483
6561
|
}
|
|
6484
6562
|
default:
|
|
@@ -6488,7 +6566,7 @@ app2.post("/config", async (c) => {
|
|
|
6488
6566
|
);
|
|
6489
6567
|
}
|
|
6490
6568
|
} catch (err) {
|
|
6491
|
-
console.error(`${
|
|
6569
|
+
console.error(`${TAG20} config error: ${String(err)}`);
|
|
6492
6570
|
return c.json({ ok: false, error: String(err) }, 500);
|
|
6493
6571
|
}
|
|
6494
6572
|
});
|
|
@@ -6509,7 +6587,7 @@ app2.post("/send-document", async (c) => {
|
|
|
6509
6587
|
recordRouteDocumentOutbound(to, filePath);
|
|
6510
6588
|
return c.json({ success: true, messageId: result.messageId });
|
|
6511
6589
|
} catch (err) {
|
|
6512
|
-
console.error(`${
|
|
6590
|
+
console.error(`${TAG20} send-document error: ${String(err)}`);
|
|
6513
6591
|
return c.json({ error: String(err) }, 500);
|
|
6514
6592
|
}
|
|
6515
6593
|
});
|
|
@@ -6519,11 +6597,11 @@ app2.get("/activity", (c) => {
|
|
|
6519
6597
|
const result = getChannelActivity(accountId);
|
|
6520
6598
|
const total = result.accounts.reduce((sum, a) => sum + a.total, 0);
|
|
6521
6599
|
console.error(
|
|
6522
|
-
`${
|
|
6600
|
+
`${TAG20} activity accounts=${result.accounts.length} total=${total} recentEvents=${result.recentEvents.length}` + (accountId ? ` filter=${accountId}` : "")
|
|
6523
6601
|
);
|
|
6524
6602
|
return c.json(result);
|
|
6525
6603
|
} catch (err) {
|
|
6526
|
-
console.error(`${
|
|
6604
|
+
console.error(`${TAG20} activity error: ${String(err)}`);
|
|
6527
6605
|
return c.json({ error: String(err) }, 500);
|
|
6528
6606
|
}
|
|
6529
6607
|
});
|
|
@@ -6542,10 +6620,10 @@ app2.get("/conversations", (c) => {
|
|
|
6542
6620
|
};
|
|
6543
6621
|
});
|
|
6544
6622
|
conversations.sort((a, b) => (b.lastMessageTimestamp ?? 0) - (a.lastMessageTimestamp ?? 0));
|
|
6545
|
-
console.error(`${
|
|
6623
|
+
console.error(`${TAG20} conversations account=${accountId} count=${conversations.length}`);
|
|
6546
6624
|
return c.json({ conversations });
|
|
6547
6625
|
} catch (err) {
|
|
6548
|
-
console.error(`${
|
|
6626
|
+
console.error(`${TAG20} conversations error: ${String(err)}`);
|
|
6549
6627
|
return c.json({ error: String(err) }, 500);
|
|
6550
6628
|
}
|
|
6551
6629
|
});
|
|
@@ -6560,10 +6638,10 @@ app2.get("/messages", (c) => {
|
|
|
6560
6638
|
const limit = limitParam ? parseInt(limitParam, 10) : void 0;
|
|
6561
6639
|
const effectiveLimit = limit && !Number.isNaN(limit) && limit > 0 ? limit : void 0;
|
|
6562
6640
|
const messages = getMessages(accountId, jid, effectiveLimit);
|
|
6563
|
-
console.error(`${
|
|
6641
|
+
console.error(`${TAG20} messages account=${accountId} jid=${jid} limit=${effectiveLimit ?? "all"} returned=${messages.length}`);
|
|
6564
6642
|
return c.json({ messages });
|
|
6565
6643
|
} catch (err) {
|
|
6566
|
-
console.error(`${
|
|
6644
|
+
console.error(`${TAG20} messages error: ${String(err)}`);
|
|
6567
6645
|
return c.json({ error: String(err) }, 500);
|
|
6568
6646
|
}
|
|
6569
6647
|
});
|
|
@@ -6644,7 +6722,7 @@ app2.get("/conversation-graph-state", async (c) => {
|
|
|
6644
6722
|
}
|
|
6645
6723
|
} catch (err) {
|
|
6646
6724
|
const msg = err instanceof Error ? err.message : String(err);
|
|
6647
|
-
console.error(`${
|
|
6725
|
+
console.error(`${TAG20} conversation-graph-state ERR cacheKey=${cacheKey} reason=${msg}`);
|
|
6648
6726
|
return c.json({ error: `Graph query failed: ${msg}`, cacheKey, cypher: cypher.trim() }, 500);
|
|
6649
6727
|
}
|
|
6650
6728
|
const ms = Date.now() - t0;
|
|
@@ -6657,7 +6735,7 @@ app2.get("/conversation-graph-state", async (c) => {
|
|
|
6657
6735
|
ms
|
|
6658
6736
|
});
|
|
6659
6737
|
} catch (err) {
|
|
6660
|
-
console.error(`${
|
|
6738
|
+
console.error(`${TAG20} conversation-graph-state error: ${String(err)}`);
|
|
6661
6739
|
return c.json({ error: String(err) }, 500);
|
|
6662
6740
|
}
|
|
6663
6741
|
});
|
|
@@ -6669,12 +6747,12 @@ app2.get("/group-info", async (c) => {
|
|
|
6669
6747
|
return c.json({ error: "Missing required parameter: jid" }, 400);
|
|
6670
6748
|
}
|
|
6671
6749
|
if (!isGroupJid(jid)) {
|
|
6672
|
-
console.error(`${
|
|
6750
|
+
console.error(`${TAG20} group-info error="not a group JID" jid=${jid} account=${accountId}`);
|
|
6673
6751
|
return c.json({ error: `"${jid}" is not a group JID. Group JIDs end with @g.us.` }, 400);
|
|
6674
6752
|
}
|
|
6675
6753
|
const sock = getSocket(accountId);
|
|
6676
6754
|
if (!sock) {
|
|
6677
|
-
console.error(`${
|
|
6755
|
+
console.error(`${TAG20} group-info error="not connected" account=${accountId}`);
|
|
6678
6756
|
return c.json({ error: `WhatsApp account "${accountId}" is not connected. Connect first, then retry.` }, 400);
|
|
6679
6757
|
}
|
|
6680
6758
|
const meta = await sock.groupMetadata(jid);
|
|
@@ -6687,10 +6765,10 @@ app2.get("/group-info", async (c) => {
|
|
|
6687
6765
|
participantCount: meta.participants.length,
|
|
6688
6766
|
participants: meta.participants.map((p) => ({ jid: p.id, admin: p.admin ?? null }))
|
|
6689
6767
|
};
|
|
6690
|
-
console.error(`${
|
|
6768
|
+
console.error(`${TAG20} group-info jid=${jid} subject="${meta.subject}" participants=${meta.participants.length} account=${accountId}`);
|
|
6691
6769
|
return c.json(result);
|
|
6692
6770
|
} catch (err) {
|
|
6693
|
-
console.error(`${
|
|
6771
|
+
console.error(`${TAG20} group-info error="${String(err)}" jid=${jid} account=${accountId}`);
|
|
6694
6772
|
return c.json({ error: `Failed to fetch group info: ${String(err)}` }, 500);
|
|
6695
6773
|
}
|
|
6696
6774
|
});
|
|
@@ -7773,7 +7851,7 @@ function resolveOpenVisitorSession(rows, visitorId, agentSlug) {
|
|
|
7773
7851
|
|
|
7774
7852
|
// server/routes/public-reader.ts
|
|
7775
7853
|
var app5 = new Hono();
|
|
7776
|
-
var
|
|
7854
|
+
var TAG21 = "[public-webchat]";
|
|
7777
7855
|
function parseAccessSessionId(cookieHeader) {
|
|
7778
7856
|
if (!cookieHeader) return null;
|
|
7779
7857
|
const part = cookieHeader.split(";").map((p) => p.trim()).find((p) => p.startsWith("__access_session="));
|
|
@@ -7821,7 +7899,7 @@ function enumeratePublicRows() {
|
|
|
7821
7899
|
app5.get("/session", (c) => {
|
|
7822
7900
|
const visitor = resolveVisitor(c);
|
|
7823
7901
|
if (!visitor) {
|
|
7824
|
-
console.error(`${
|
|
7902
|
+
console.error(`${TAG21} op=reader-refused reason=no-anchor path=/session`);
|
|
7825
7903
|
return c.json({ error: "gate-required" }, 401);
|
|
7826
7904
|
}
|
|
7827
7905
|
const rows = enumeratePublicRows();
|
|
@@ -7840,11 +7918,11 @@ app5.get("/session", (c) => {
|
|
|
7840
7918
|
found = effectiveSlug ? resolveOpenVisitorSession(rows, visitor.visitorId, effectiveSlug) : null;
|
|
7841
7919
|
}
|
|
7842
7920
|
if (found) {
|
|
7843
|
-
console.log(`${
|
|
7921
|
+
console.log(`${TAG21} op=session-resume anchor=${visitor.kind} key=${(found.senderId ?? "").slice(0, 8)} sessionId=${found.sessionId.slice(0, 8)}`);
|
|
7844
7922
|
return c.json({ sessionId: found.sessionId, projectDir: found.projectDir, sessionKey: found.senderId });
|
|
7845
7923
|
}
|
|
7846
7924
|
const sessionKey = crypto.randomUUID();
|
|
7847
|
-
console.log(`${
|
|
7925
|
+
console.log(`${TAG21} op=session-new anchor=${visitor.kind} key=${sessionKey.slice(0, 8)}`);
|
|
7848
7926
|
return c.json({ sessionId: null, projectDir: null, sessionKey });
|
|
7849
7927
|
});
|
|
7850
7928
|
function publicUploadsDir(accountId, sessionId) {
|
|
@@ -7873,7 +7951,7 @@ function readFrom2(path2, from) {
|
|
|
7873
7951
|
app5.get("/stream", (c) => {
|
|
7874
7952
|
const visitor = resolveVisitor(c);
|
|
7875
7953
|
if (!visitor) {
|
|
7876
|
-
console.error(`${
|
|
7954
|
+
console.error(`${TAG21} op=reader-refused reason=no-anchor path=/stream`);
|
|
7877
7955
|
return c.json({ error: "gate-required" }, 401);
|
|
7878
7956
|
}
|
|
7879
7957
|
const sessionId = c.req.query("sessionId") ?? "";
|
|
@@ -7891,12 +7969,12 @@ app5.get("/stream", (c) => {
|
|
|
7891
7969
|
const isPublicWebchat = meta.role === "public" && meta.channel === "webchat";
|
|
7892
7970
|
const owns = visitor.kind === "person" ? meta.personId === visitor.personId : meta.personId === null && meta.visitorId === visitor.visitorId;
|
|
7893
7971
|
if (!(isPublicWebchat && owns)) {
|
|
7894
|
-
console.error(`${
|
|
7972
|
+
console.error(`${TAG21} op=reader-refused reason=not-owner anchor=${visitor.kind} sessionId=${sessionId.slice(0, 8)}`);
|
|
7895
7973
|
return c.json({ error: "forbidden" }, 403);
|
|
7896
7974
|
}
|
|
7897
7975
|
const senderShort = (meta.senderId ?? "").slice(0, 8);
|
|
7898
7976
|
const encoder = new TextEncoder();
|
|
7899
|
-
console.log(`${
|
|
7977
|
+
console.log(`${TAG21} op=reader-open anchor=${visitor.kind} key=${senderShort} mode=delivered-only sessionId=${sessionId.slice(0, 8)}`);
|
|
7900
7978
|
const send = (controller, turn, id) => controller.enqueue(encoder.encode(`id: ${id}
|
|
7901
7979
|
data: ${JSON.stringify(turn)}
|
|
7902
7980
|
|
|
@@ -7911,7 +7989,7 @@ data: ${JSON.stringify(turn)}
|
|
|
7911
7989
|
const { turns, dropped } = filterDeliveredFrames(lines);
|
|
7912
7990
|
if (uploadsDir) enrichPublicAttachments(turns, listSessionAttachmentsInDir(uploadsDir), attachmentCursor);
|
|
7913
7991
|
for (const turn of turns) send(controller, turn, offset);
|
|
7914
|
-
if (dropped > 0) console.log(`${
|
|
7992
|
+
if (dropped > 0) console.log(`${TAG21} op=reader-filtered key=${senderShort} dropped=${dropped}`);
|
|
7915
7993
|
};
|
|
7916
7994
|
try {
|
|
7917
7995
|
const { buf, end } = readFrom2(jsonlPath, 0);
|
|
@@ -7946,7 +8024,7 @@ data: ${JSON.stringify(turn)}
|
|
|
7946
8024
|
watcher?.close();
|
|
7947
8025
|
clearInterval(poll);
|
|
7948
8026
|
clearInterval(heartbeat);
|
|
7949
|
-
console.log(`${
|
|
8027
|
+
console.log(`${TAG21} op=reader-close key=${senderShort}`);
|
|
7950
8028
|
try {
|
|
7951
8029
|
controller.close();
|
|
7952
8030
|
} catch {
|
|
@@ -9051,7 +9129,7 @@ function classifyTimeout(ndjson, writeAtMs) {
|
|
|
9051
9129
|
|
|
9052
9130
|
// app/lib/channel-pty-bridge/public-session-end-review.ts
|
|
9053
9131
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
9054
|
-
var
|
|
9132
|
+
var TAG22 = "[public-session-review]";
|
|
9055
9133
|
var CONSUMED_CAP = 500;
|
|
9056
9134
|
var consumed = /* @__PURE__ */ new Set();
|
|
9057
9135
|
function consumeOnce(sessionId) {
|
|
@@ -9078,7 +9156,7 @@ async function fetchJsonl(sessionId) {
|
|
|
9078
9156
|
return await res.text();
|
|
9079
9157
|
} catch (err) {
|
|
9080
9158
|
console.error(
|
|
9081
|
-
`${
|
|
9159
|
+
`${TAG22} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
|
|
9082
9160
|
);
|
|
9083
9161
|
return null;
|
|
9084
9162
|
}
|
|
@@ -9102,7 +9180,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
9102
9180
|
const res = await fetch(url);
|
|
9103
9181
|
if (!res.ok) {
|
|
9104
9182
|
console.error(
|
|
9105
|
-
`${
|
|
9183
|
+
`${TAG22} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
|
|
9106
9184
|
);
|
|
9107
9185
|
return [];
|
|
9108
9186
|
}
|
|
@@ -9110,7 +9188,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
9110
9188
|
return Array.isArray(body.writes) ? body.writes : [];
|
|
9111
9189
|
} catch (err) {
|
|
9112
9190
|
console.error(
|
|
9113
|
-
`${
|
|
9191
|
+
`${TAG22} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
9114
9192
|
);
|
|
9115
9193
|
return [];
|
|
9116
9194
|
}
|
|
@@ -9139,7 +9217,7 @@ function composeInitialMessage(input) {
|
|
|
9139
9217
|
}
|
|
9140
9218
|
async function dispatchReviewer(input, initialMessage) {
|
|
9141
9219
|
const sessionId = randomUUID7();
|
|
9142
|
-
console.log(`${
|
|
9220
|
+
console.log(`${TAG22} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
|
|
9143
9221
|
const spawned = await managerRcSpawn({
|
|
9144
9222
|
sessionId,
|
|
9145
9223
|
initialMessage,
|
|
@@ -9159,21 +9237,21 @@ async function firePublicSessionEndReview(input) {
|
|
|
9159
9237
|
const dispatchedAt = Date.now();
|
|
9160
9238
|
if (consumed.has(input.sessionId)) {
|
|
9161
9239
|
console.log(
|
|
9162
|
-
`${
|
|
9240
|
+
`${TAG22} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
9163
9241
|
);
|
|
9164
9242
|
return;
|
|
9165
9243
|
}
|
|
9166
9244
|
const jsonl = await fetchJsonl(input.sessionId);
|
|
9167
9245
|
if (!jsonl) {
|
|
9168
9246
|
console.log(
|
|
9169
|
-
`${
|
|
9247
|
+
`${TAG22} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
|
|
9170
9248
|
);
|
|
9171
9249
|
return;
|
|
9172
9250
|
}
|
|
9173
9251
|
const operatorTurns = countOperatorTurns(jsonl);
|
|
9174
9252
|
if (operatorTurns === 0) {
|
|
9175
9253
|
console.log(
|
|
9176
|
-
`${
|
|
9254
|
+
`${TAG22} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
|
|
9177
9255
|
);
|
|
9178
9256
|
return;
|
|
9179
9257
|
}
|
|
@@ -9187,19 +9265,19 @@ async function firePublicSessionEndReview(input) {
|
|
|
9187
9265
|
});
|
|
9188
9266
|
if (!consumeOnce(input.sessionId)) {
|
|
9189
9267
|
console.log(
|
|
9190
|
-
`${
|
|
9268
|
+
`${TAG22} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
9191
9269
|
);
|
|
9192
9270
|
return;
|
|
9193
9271
|
}
|
|
9194
9272
|
const dispatched = await dispatchReviewer(input, initialMessage);
|
|
9195
9273
|
if (!dispatched.ok) {
|
|
9196
9274
|
console.error(
|
|
9197
|
-
`${
|
|
9275
|
+
`${TAG22} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
|
|
9198
9276
|
);
|
|
9199
9277
|
return;
|
|
9200
9278
|
}
|
|
9201
9279
|
console.log(
|
|
9202
|
-
`${
|
|
9280
|
+
`${TAG22} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=dispatched managerSessionId=${dispatched.managerSessionId} operatorTurns=${operatorTurns} priorWrites=${priorWrites.length} ms=${Date.now() - dispatchedAt}`
|
|
9203
9281
|
);
|
|
9204
9282
|
}
|
|
9205
9283
|
|
|
@@ -9413,7 +9491,7 @@ function makeFileDelivery(opts) {
|
|
|
9413
9491
|
}
|
|
9414
9492
|
|
|
9415
9493
|
// app/lib/whatsapp/inbound/file-delivery-bridge.ts
|
|
9416
|
-
var
|
|
9494
|
+
var TAG23 = "[whatsapp-adaptor]";
|
|
9417
9495
|
var SEND_USER_FILE2 = "SendUserFile";
|
|
9418
9496
|
var WHATSAPP_SEND_DOCUMENT = "whatsapp-send-document";
|
|
9419
9497
|
function platformRoot() {
|
|
@@ -9426,7 +9504,7 @@ function makeWhatsAppSendFile(entry) {
|
|
|
9426
9504
|
maxyAccountId = resolvePlatformAccountId();
|
|
9427
9505
|
} catch (err) {
|
|
9428
9506
|
console.error(
|
|
9429
|
-
`${
|
|
9507
|
+
`${TAG23} file-delivery reject reason=account-unresolved sender=${entry.senderId} message=${err instanceof Error ? err.message : String(err)}`
|
|
9430
9508
|
);
|
|
9431
9509
|
return { ok: false, error: "account-unresolved" };
|
|
9432
9510
|
}
|
|
@@ -9440,7 +9518,7 @@ function makeWhatsAppSendFile(entry) {
|
|
|
9440
9518
|
});
|
|
9441
9519
|
if (result.ok) return { ok: true };
|
|
9442
9520
|
console.error(
|
|
9443
|
-
`${
|
|
9521
|
+
`${TAG23} file-delivery reject reason=send-failed sender=${entry.senderId} status=${result.status} message=${result.error}`
|
|
9444
9522
|
);
|
|
9445
9523
|
return { ok: false, error: result.error };
|
|
9446
9524
|
};
|
|
@@ -9448,7 +9526,7 @@ function makeWhatsAppSendFile(entry) {
|
|
|
9448
9526
|
function makeWhatsAppFileDelivery(entry) {
|
|
9449
9527
|
const shared = makeFileDelivery({
|
|
9450
9528
|
entry,
|
|
9451
|
-
tag:
|
|
9529
|
+
tag: TAG23,
|
|
9452
9530
|
channel: "whatsapp",
|
|
9453
9531
|
sendFile: makeWhatsAppSendFile(entry)
|
|
9454
9532
|
});
|
|
@@ -9483,7 +9561,7 @@ function makeWhatsAppFileDelivery(entry) {
|
|
|
9483
9561
|
if (!delivered) {
|
|
9484
9562
|
const fileField = call.filePath !== void 0 ? ` file=${call.filePath}` : "";
|
|
9485
9563
|
console.error(
|
|
9486
|
-
`${
|
|
9564
|
+
`${TAG23} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
|
|
9487
9565
|
);
|
|
9488
9566
|
}
|
|
9489
9567
|
}
|
|
@@ -9495,7 +9573,7 @@ function makeWhatsAppFileDelivery(entry) {
|
|
|
9495
9573
|
import { realpathSync as realpathSync4 } from "fs";
|
|
9496
9574
|
import { readFile as readFile2, stat as stat3 } from "fs/promises";
|
|
9497
9575
|
import { resolve as resolve14, basename as basename5 } from "path";
|
|
9498
|
-
var
|
|
9576
|
+
var TAG24 = "[telegram:outbound]";
|
|
9499
9577
|
var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
|
|
9500
9578
|
async function sendTelegramDocument(input) {
|
|
9501
9579
|
const { botToken, chatId, filePath, caption, maxyAccountId, platformRoot: platformRoot4 } = input;
|
|
@@ -9511,16 +9589,16 @@ async function sendTelegramDocument(input) {
|
|
|
9511
9589
|
resolvedPath = realpathSync4(filePath);
|
|
9512
9590
|
const accountResolved = realpathSync4(accountDir);
|
|
9513
9591
|
if (!resolvedPath.startsWith(accountResolved + "/")) {
|
|
9514
|
-
console.error(`${
|
|
9592
|
+
console.error(`${TAG24} document REJECTED reason=outside_account_directory`);
|
|
9515
9593
|
return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
|
|
9516
9594
|
}
|
|
9517
9595
|
} catch (err) {
|
|
9518
9596
|
const code = err.code;
|
|
9519
9597
|
if (code === "ENOENT") {
|
|
9520
|
-
console.error(`${
|
|
9598
|
+
console.error(`${TAG24} document ENOENT path=${filePath}`);
|
|
9521
9599
|
return { ok: false, status: 404, error: `File not found: ${filePath}` };
|
|
9522
9600
|
}
|
|
9523
|
-
console.error(`${
|
|
9601
|
+
console.error(`${TAG24} document path error: ${String(err)}`);
|
|
9524
9602
|
return { ok: false, status: 500, error: String(err) };
|
|
9525
9603
|
}
|
|
9526
9604
|
const fileStat = await stat3(resolvedPath);
|
|
@@ -9553,13 +9631,13 @@ async function sendTelegramDocument(input) {
|
|
|
9553
9631
|
error = e instanceof Error ? e.message : String(e);
|
|
9554
9632
|
}
|
|
9555
9633
|
console.error(
|
|
9556
|
-
`${
|
|
9634
|
+
`${TAG24} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok}` + (messageId !== void 0 ? ` id=${messageId}` : "")
|
|
9557
9635
|
);
|
|
9558
9636
|
return ok ? { ok: true, messageId } : { ok: false, status: 500, error };
|
|
9559
9637
|
}
|
|
9560
9638
|
|
|
9561
9639
|
// app/lib/telegram/outbound/file-delivery.ts
|
|
9562
|
-
var
|
|
9640
|
+
var TAG25 = "[telegram:outbound]";
|
|
9563
9641
|
function platformRoot2() {
|
|
9564
9642
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
9565
9643
|
}
|
|
@@ -9571,11 +9649,11 @@ function makeTelegramSendFile(entry) {
|
|
|
9571
9649
|
botToken = (entry.role === "admin" ? tg?.adminBotToken : tg?.publicBotToken) ?? null;
|
|
9572
9650
|
}
|
|
9573
9651
|
if (!botToken) {
|
|
9574
|
-
console.error(`${
|
|
9652
|
+
console.error(`${TAG25} file-delivery reject reason=no-bot-token sender=${entry.senderId} role=${entry.role}`);
|
|
9575
9653
|
return { ok: false, error: "no-bot-token" };
|
|
9576
9654
|
}
|
|
9577
9655
|
if (entry.replyTarget == null) {
|
|
9578
|
-
console.error(`${
|
|
9656
|
+
console.error(`${TAG25} file-delivery reject reason=no-reply-target sender=${entry.senderId} role=${entry.role}`);
|
|
9579
9657
|
return { ok: false, error: "no-reply-target" };
|
|
9580
9658
|
}
|
|
9581
9659
|
let maxyAccountId;
|
|
@@ -9583,7 +9661,7 @@ function makeTelegramSendFile(entry) {
|
|
|
9583
9661
|
maxyAccountId = resolvePlatformAccountId();
|
|
9584
9662
|
} catch (err) {
|
|
9585
9663
|
console.error(
|
|
9586
|
-
`${
|
|
9664
|
+
`${TAG25} file-delivery reject reason=account-unresolved sender=${entry.senderId} message=${err instanceof Error ? err.message : String(err)}`
|
|
9587
9665
|
);
|
|
9588
9666
|
return { ok: false, error: "account-unresolved" };
|
|
9589
9667
|
}
|
|
@@ -9601,7 +9679,7 @@ function makeTelegramSendFile(entry) {
|
|
|
9601
9679
|
function makeTelegramFileDelivery(entry) {
|
|
9602
9680
|
return makeFileDelivery({
|
|
9603
9681
|
entry,
|
|
9604
|
-
tag:
|
|
9682
|
+
tag: TAG25,
|
|
9605
9683
|
channel: "telegram",
|
|
9606
9684
|
sendFile: makeTelegramSendFile(entry)
|
|
9607
9685
|
});
|
|
@@ -9610,7 +9688,7 @@ function makeTelegramFileDelivery(entry) {
|
|
|
9610
9688
|
// app/lib/webchat/file-delivery.ts
|
|
9611
9689
|
import { realpathSync as realpathSync5 } from "fs";
|
|
9612
9690
|
import { resolve as resolve15 } from "path";
|
|
9613
|
-
var
|
|
9691
|
+
var TAG26 = "[webchat-adaptor]";
|
|
9614
9692
|
function platformRoot3() {
|
|
9615
9693
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
9616
9694
|
}
|
|
@@ -9621,7 +9699,7 @@ function makeWebchatSendFile(entry) {
|
|
|
9621
9699
|
maxyAccountId = resolvePlatformAccountId();
|
|
9622
9700
|
} catch (err) {
|
|
9623
9701
|
console.error(
|
|
9624
|
-
`${
|
|
9702
|
+
`${TAG26} file-delivery reject reason=account-unresolved sender=${entry.senderId} message=${err instanceof Error ? err.message : String(err)}`
|
|
9625
9703
|
);
|
|
9626
9704
|
return { ok: false, error: "account-unresolved" };
|
|
9627
9705
|
}
|
|
@@ -9630,14 +9708,14 @@ function makeWebchatSendFile(entry) {
|
|
|
9630
9708
|
const resolved = realpathSync5(filePath);
|
|
9631
9709
|
const accountResolved = realpathSync5(accountDir);
|
|
9632
9710
|
if (!resolved.startsWith(accountResolved + "/")) {
|
|
9633
|
-
console.error(`${
|
|
9711
|
+
console.error(`${TAG26} file-delivery reject reason=outside_account_directory sender=${entry.senderId}`);
|
|
9634
9712
|
return { ok: false, error: "outside-account" };
|
|
9635
9713
|
}
|
|
9636
9714
|
return { ok: true };
|
|
9637
9715
|
} catch (err) {
|
|
9638
9716
|
const code = err.code;
|
|
9639
9717
|
console.error(
|
|
9640
|
-
`${
|
|
9718
|
+
`${TAG26} file-delivery reject reason=${code === "ENOENT" ? "not-found" : "path-error"} sender=${entry.senderId}`
|
|
9641
9719
|
);
|
|
9642
9720
|
return { ok: false, error: code === "ENOENT" ? "not-found" : "path-error" };
|
|
9643
9721
|
}
|
|
@@ -9646,7 +9724,7 @@ function makeWebchatSendFile(entry) {
|
|
|
9646
9724
|
function makeWebchatFileDelivery(entry) {
|
|
9647
9725
|
return makeFileDelivery({
|
|
9648
9726
|
entry,
|
|
9649
|
-
tag:
|
|
9727
|
+
tag: TAG26,
|
|
9650
9728
|
channel: "webchat",
|
|
9651
9729
|
sendFile: makeWebchatSendFile(entry)
|
|
9652
9730
|
});
|
|
@@ -10014,7 +10092,7 @@ function routeTelegramUpdate(input) {
|
|
|
10014
10092
|
}
|
|
10015
10093
|
|
|
10016
10094
|
// server/routes/telegram.ts
|
|
10017
|
-
var
|
|
10095
|
+
var TAG27 = "[telegram-inbound]";
|
|
10018
10096
|
var DISPATCH_TIMEOUT_MS = 12e4;
|
|
10019
10097
|
function configDirName() {
|
|
10020
10098
|
const platformRoot4 = process.env.MAXY_PLATFORM_ROOT ?? resolve17(process.cwd(), "..");
|
|
@@ -10049,18 +10127,18 @@ app7.post("/", async (c) => {
|
|
|
10049
10127
|
const botParam = c.req.query("bot");
|
|
10050
10128
|
const botType = botParam === "admin" ? "admin" : botParam === "public" ? "public" : null;
|
|
10051
10129
|
if (!botType) {
|
|
10052
|
-
console.error(`${
|
|
10130
|
+
console.error(`${TAG27} op=reject reason=missing-bot-param`);
|
|
10053
10131
|
return c.json({ ok: false }, 400);
|
|
10054
10132
|
}
|
|
10055
10133
|
const sp = secretPath(botType);
|
|
10056
10134
|
if (!existsSync11(sp)) {
|
|
10057
|
-
console.error(`${
|
|
10135
|
+
console.error(`${TAG27} op=reject reason=no-secret-file botType=${botType}`);
|
|
10058
10136
|
return c.json({ ok: false }, 401);
|
|
10059
10137
|
}
|
|
10060
10138
|
const expected = readFileSync19(sp, "utf-8").trim();
|
|
10061
10139
|
const got = c.req.header("x-telegram-bot-api-secret-token") ?? "";
|
|
10062
10140
|
if (got !== expected) {
|
|
10063
|
-
console.error(`${
|
|
10141
|
+
console.error(`${TAG27} op=reject reason=bad-secret botType=${botType}`);
|
|
10064
10142
|
return c.json({ ok: false }, 401);
|
|
10065
10143
|
}
|
|
10066
10144
|
let update;
|
|
@@ -10071,25 +10149,25 @@ app7.post("/", async (c) => {
|
|
|
10071
10149
|
}
|
|
10072
10150
|
const account = resolveAccount();
|
|
10073
10151
|
if (!account) {
|
|
10074
|
-
console.error(`${
|
|
10152
|
+
console.error(`${TAG27} op=reject reason=no-account`);
|
|
10075
10153
|
return c.json({ ok: true }, 200);
|
|
10076
10154
|
}
|
|
10077
10155
|
const decision = routeTelegramUpdate({ update, botType, config: account.config.telegram ?? {} });
|
|
10078
10156
|
if (decision.kind === "ignore") {
|
|
10079
|
-
console.error(`${
|
|
10157
|
+
console.error(`${TAG27} op=ignore reason=${decision.reason}`);
|
|
10080
10158
|
return c.json({ ok: true }, 200);
|
|
10081
10159
|
}
|
|
10082
10160
|
if (decision.kind === "denied") {
|
|
10083
|
-
console.error(`${
|
|
10161
|
+
console.error(`${TAG27} op=denied reason=${decision.reason} agentType=${decision.agentType}`);
|
|
10084
10162
|
return c.json({ ok: true }, 200);
|
|
10085
10163
|
}
|
|
10086
10164
|
const role = decision.agentType === "admin" ? "admin" : "public";
|
|
10087
10165
|
const agentSlug = role === "admin" ? "admin" : resolveDefaultAgentSlug(account.accountDir);
|
|
10088
10166
|
if (!agentSlug) {
|
|
10089
|
-
console.error(`${
|
|
10167
|
+
console.error(`${TAG27} op=reject reason=no-default-agent`);
|
|
10090
10168
|
return c.json({ ok: true }, 200);
|
|
10091
10169
|
}
|
|
10092
|
-
console.error(`${
|
|
10170
|
+
console.error(`${TAG27} op=update accountId=${account.accountId} from=${decision.senderId}`);
|
|
10093
10171
|
const botToken = botType === "admin" ? account.config.telegram?.adminBotToken : account.config.telegram?.publicBotToken;
|
|
10094
10172
|
const { senderId, chatId, text } = decision;
|
|
10095
10173
|
void (async () => {
|
|
@@ -10106,16 +10184,16 @@ app7.post("/", async (c) => {
|
|
|
10106
10184
|
timeoutMs: DISPATCH_TIMEOUT_MS
|
|
10107
10185
|
});
|
|
10108
10186
|
if ("error" in result) {
|
|
10109
|
-
console.error(`${
|
|
10187
|
+
console.error(`${TAG27} op=dispatch-failed from=${senderId} error=${result.error}`);
|
|
10110
10188
|
return;
|
|
10111
10189
|
}
|
|
10112
10190
|
if (!botToken) {
|
|
10113
10191
|
const reason = account.config.telegram ? "no-bot-token" : "no-telegram-config";
|
|
10114
|
-
console.error(`${
|
|
10192
|
+
console.error(`${TAG27} op=reply-dropped reason=${reason} botType=${botType}`);
|
|
10115
10193
|
return;
|
|
10116
10194
|
}
|
|
10117
10195
|
const sent = await sendTelegram(botToken, chatId, result.turnText);
|
|
10118
|
-
console.error(`${
|
|
10196
|
+
console.error(`${TAG27} op=reply-sent from=${senderId} ok=${sent.ok}${sent.ok ? "" : ` error=${sent.error}`}`);
|
|
10119
10197
|
})();
|
|
10120
10198
|
return c.json({ ok: true }, 200);
|
|
10121
10199
|
});
|
|
@@ -10124,7 +10202,7 @@ var telegram_default = app7;
|
|
|
10124
10202
|
// server/routes/quickbooks.ts
|
|
10125
10203
|
import { join as join19 } from "path";
|
|
10126
10204
|
import { existsSync as existsSync12, readFileSync as readFileSync20, writeFileSync as writeFileSync8, mkdirSync as mkdirSync3, rmSync, renameSync as renameSync4 } from "fs";
|
|
10127
|
-
var
|
|
10205
|
+
var TAG28 = "[quickbooks]";
|
|
10128
10206
|
var INTUIT_TOKEN_URL = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer";
|
|
10129
10207
|
var STATE_RE = /^[A-Za-z0-9_-]+$/;
|
|
10130
10208
|
function pendingPath(accountDir, state) {
|
|
@@ -10137,14 +10215,14 @@ async function completeConsent(args) {
|
|
|
10137
10215
|
const { accountDir, code, realmId } = args;
|
|
10138
10216
|
const state = args.state;
|
|
10139
10217
|
if (!state || !STATE_RE.test(state) || !existsSync12(pendingPath(accountDir, state))) {
|
|
10140
|
-
console.error(`${
|
|
10218
|
+
console.error(`${TAG28} op=callback state=${state ?? ""} stateValid=false realmId=${realmId ?? ""}`);
|
|
10141
10219
|
return { ok: false, status: 400, message: "Invalid or unknown authorization state.", stateValid: false };
|
|
10142
10220
|
}
|
|
10143
10221
|
const claimFile = `${pendingPath(accountDir, state)}.claimed`;
|
|
10144
10222
|
try {
|
|
10145
10223
|
renameSync4(pendingPath(accountDir, state), claimFile);
|
|
10146
10224
|
} catch {
|
|
10147
|
-
console.error(`${
|
|
10225
|
+
console.error(`${TAG28} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
|
|
10148
10226
|
return { ok: false, status: 400, message: "Invalid or unknown authorization state.", stateValid: false };
|
|
10149
10227
|
}
|
|
10150
10228
|
try {
|
|
@@ -10152,14 +10230,14 @@ async function completeConsent(args) {
|
|
|
10152
10230
|
try {
|
|
10153
10231
|
pending = JSON.parse(readFileSync20(claimFile, "utf-8"));
|
|
10154
10232
|
} catch {
|
|
10155
|
-
console.error(`${
|
|
10233
|
+
console.error(`${TAG28} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
|
|
10156
10234
|
return { ok: false, status: 400, message: "Authorization state could not be read.", stateValid: false };
|
|
10157
10235
|
}
|
|
10158
10236
|
if (Date.now() > pending.expiresAt) {
|
|
10159
|
-
console.error(`${
|
|
10237
|
+
console.error(`${TAG28} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
|
|
10160
10238
|
return { ok: false, status: 400, message: "Authorization request expired. Generate a new consent link.", stateValid: false };
|
|
10161
10239
|
}
|
|
10162
|
-
console.error(`${
|
|
10240
|
+
console.error(`${TAG28} op=callback state=${state} stateValid=true realmId=${realmId ?? ""}`);
|
|
10163
10241
|
if (!code || !realmId) {
|
|
10164
10242
|
return { ok: false, status: 400, message: "Missing code or realmId in the callback.", stateValid: true };
|
|
10165
10243
|
}
|
|
@@ -10183,12 +10261,12 @@ async function completeConsent(args) {
|
|
|
10183
10261
|
});
|
|
10184
10262
|
const text = await res.text();
|
|
10185
10263
|
if (!res.ok) {
|
|
10186
|
-
console.error(`${
|
|
10264
|
+
console.error(`${TAG28} op=token-exchange realmId=${realmId} persisted=false`);
|
|
10187
10265
|
return { ok: false, status: 502, message: `Token exchange failed (${res.status}). Generate a new consent link to retry.`, stateValid: true };
|
|
10188
10266
|
}
|
|
10189
10267
|
const body = JSON.parse(text);
|
|
10190
10268
|
if (!body.refresh_token) {
|
|
10191
|
-
console.error(`${
|
|
10269
|
+
console.error(`${TAG28} op=token-exchange realmId=${realmId} persisted=false`);
|
|
10192
10270
|
return { ok: false, status: 502, message: "Token exchange returned no refresh token.", stateValid: true };
|
|
10193
10271
|
}
|
|
10194
10272
|
const now = Date.now();
|
|
@@ -10201,7 +10279,7 @@ async function completeConsent(args) {
|
|
|
10201
10279
|
mkdirSync3(join19(accountDir, "secrets"), { recursive: true });
|
|
10202
10280
|
writeFileSync8(storePath(accountDir), JSON.stringify(store2, null, 2), { mode: 384 });
|
|
10203
10281
|
const persisted = JSON.parse(readFileSync20(storePath(accountDir), "utf-8")).connections?.[realmId]?.refreshToken === body.refresh_token;
|
|
10204
|
-
console.error(`${
|
|
10282
|
+
console.error(`${TAG28} op=token-exchange realmId=${realmId} persisted=${persisted}`);
|
|
10205
10283
|
return { ok: persisted, status: persisted ? 200 : 500, message: persisted ? `Connected company ${realmId}.` : "Failed to persist the connection.", stateValid: true };
|
|
10206
10284
|
} finally {
|
|
10207
10285
|
rmSync(claimFile, { force: true });
|
|
@@ -10214,7 +10292,7 @@ var app8 = new Hono();
|
|
|
10214
10292
|
app8.get("/callback", async (c) => {
|
|
10215
10293
|
const account = resolveAccount();
|
|
10216
10294
|
if (!account) {
|
|
10217
|
-
console.error(`${
|
|
10295
|
+
console.error(`${TAG28} op=callback stateValid=false realmId= reason=no-account`);
|
|
10218
10296
|
return c.html(page("QuickBooks", "This install has no account configured."), 500);
|
|
10219
10297
|
}
|
|
10220
10298
|
const result = await completeConsent({
|
|
@@ -12287,7 +12365,7 @@ function resolveTunnelUrl() {
|
|
|
12287
12365
|
if (!state) return null;
|
|
12288
12366
|
return `https://${hostname2}.${state.domain}`;
|
|
12289
12367
|
}
|
|
12290
|
-
var
|
|
12368
|
+
var TAG29 = "[claude-session-manager:wrapper]";
|
|
12291
12369
|
async function refuseIfClaudeAuthDead(c, route, sessionId) {
|
|
12292
12370
|
const auth = await ensureAuth();
|
|
12293
12371
|
if (auth.status !== "dead" && auth.status !== "missing") return null;
|
|
@@ -12305,12 +12383,12 @@ async function performSpawnWithInitialMessage(args) {
|
|
|
12305
12383
|
const aboutOwner = await resolveOwnerProfileBlock(args.senderId, args.userId);
|
|
12306
12384
|
const ownerMs = Date.now() - ownerStart;
|
|
12307
12385
|
const aboutOwnerStatus = aboutOwner == null ? "absent" : "ok" in aboutOwner && aboutOwner.ok === false ? `unresolved:${aboutOwner.reason}` : "ok";
|
|
12308
|
-
console.log(`${
|
|
12386
|
+
console.log(`${TAG29} about-owner-resolved status=${aboutOwnerStatus} ms=${ownerMs}`);
|
|
12309
12387
|
const dormantPlugins = computeDormantPlugins(args.senderId);
|
|
12310
12388
|
const activePlugins = computeActivePlugins(args.senderId);
|
|
12311
12389
|
const specialistDomains = computeSpecialistDomains(args.senderId);
|
|
12312
12390
|
const tunnelUrl = resolveTunnelUrl();
|
|
12313
|
-
console.log(`${
|
|
12391
|
+
console.log(`${TAG29} tunnel-url-resolved value=${tunnelUrl ?? "null"}`);
|
|
12314
12392
|
const upstreamPayload = JSON.stringify({
|
|
12315
12393
|
senderId: args.senderId,
|
|
12316
12394
|
// Task 205 — pass userId through to the manager so it lands as
|
|
@@ -12337,24 +12415,24 @@ async function performSpawnWithInitialMessage(args) {
|
|
|
12337
12415
|
// unshapely values.
|
|
12338
12416
|
conversationNodeId: args.conversationNodeId
|
|
12339
12417
|
});
|
|
12340
|
-
console.log(`${
|
|
12418
|
+
console.log(`${TAG29} forward-spawn-start managerBase=${managerBase("claude-session-manager:wrapper")} bytes=${upstreamPayload.length} hidden=${args.hidden} specialist=${args.specialist ?? "none"}`);
|
|
12341
12419
|
const forwardStart = Date.now();
|
|
12342
12420
|
const upstream = await fetch(`${managerBase("claude-session-manager:wrapper")}/public-spawn`, {
|
|
12343
12421
|
method: "POST",
|
|
12344
12422
|
headers: { "content-type": "application/json" },
|
|
12345
12423
|
body: upstreamPayload
|
|
12346
12424
|
}).catch((err) => {
|
|
12347
|
-
console.error(`${
|
|
12425
|
+
console.error(`${TAG29} fetch-failed op=spawn message=${err instanceof Error ? err.message : String(err)} ms=${Date.now() - forwardStart}`);
|
|
12348
12426
|
return null;
|
|
12349
12427
|
});
|
|
12350
12428
|
if (!upstream) return {
|
|
12351
12429
|
response: new Response(JSON.stringify({ error: "manager-unreachable" }), { status: 503, headers: { "content-type": "application/json" } }),
|
|
12352
12430
|
claudeSessionId: null
|
|
12353
12431
|
};
|
|
12354
|
-
console.log(`${
|
|
12432
|
+
console.log(`${TAG29} forward-spawn-done status=${upstream.status} ms=${Date.now() - forwardStart}`);
|
|
12355
12433
|
if (args.initialMessage) {
|
|
12356
12434
|
const inputBytes = Buffer.byteLength(args.initialMessage, "utf8");
|
|
12357
|
-
console.log(`${
|
|
12435
|
+
console.log(`${TAG29} initial-message-inlined bytes=${inputBytes}`);
|
|
12358
12436
|
}
|
|
12359
12437
|
const bodyText = await upstream.text().catch(() => "");
|
|
12360
12438
|
let claudeSessionId = null;
|
|
@@ -12389,7 +12467,7 @@ app17.post("/", async (c) => {
|
|
|
12389
12467
|
if (refusal) return refusal;
|
|
12390
12468
|
const senderId = getAccountIdForSession(cacheKey) ?? "";
|
|
12391
12469
|
if (!senderId) {
|
|
12392
|
-
console.error(`${
|
|
12470
|
+
console.error(`${TAG29} reject reason=no-account-id cacheKey-prefix=${cacheKey.slice(0, 8)}`);
|
|
12393
12471
|
return c.json({ error: "admin-account-not-resolved" }, 500);
|
|
12394
12472
|
}
|
|
12395
12473
|
const userId = getUserIdForSession(cacheKey) ?? void 0;
|
|
@@ -12398,7 +12476,7 @@ app17.post("/", async (c) => {
|
|
|
12398
12476
|
const permissionMode = typeof body.permissionMode === "string" ? body.permissionMode : void 0;
|
|
12399
12477
|
const specialist = typeof body.specialist === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(body.specialist) ? body.specialist : void 0;
|
|
12400
12478
|
const model = typeof body.model === "string" && /^[A-Za-z0-9._-]{1,64}$/.test(body.model) ? body.model : void 0;
|
|
12401
|
-
console.log(`${
|
|
12479
|
+
console.log(`${TAG29} spawn-request-in surface=cookie accountId=${senderId.slice(0, 8)} userId=${userId ? userId.slice(0, 8) : "absent"} channel=${channel} permissionMode=${permissionMode ?? "default"} specialist=${specialist ?? "none"} model=${model ?? "default"} initialMessage=${initialMessage ? "yes" : "no"}`);
|
|
12402
12480
|
const conversationNodeId = cacheKey ? getSessionIdForSession(cacheKey) : void 0;
|
|
12403
12481
|
const { response, claudeSessionId } = await performSpawnWithInitialMessage({
|
|
12404
12482
|
senderId,
|
|
@@ -12417,13 +12495,13 @@ app17.post("/", async (c) => {
|
|
|
12417
12495
|
claudeSessionId,
|
|
12418
12496
|
senderId
|
|
12419
12497
|
);
|
|
12420
|
-
console.log(`${
|
|
12498
|
+
console.log(`${TAG29} route-done surface=cookie status=${response.status} route-ms=${Date.now() - routeStart}`);
|
|
12421
12499
|
return response;
|
|
12422
12500
|
});
|
|
12423
12501
|
var claude_sessions_default = app17;
|
|
12424
12502
|
|
|
12425
12503
|
// server/routes/admin/log-ingest.ts
|
|
12426
|
-
var
|
|
12504
|
+
var TAG30 = "[log-ingest]";
|
|
12427
12505
|
var TAG_PATTERN = /^[A-Za-z0-9_:-]{1,32}$/;
|
|
12428
12506
|
var LEVELS = /* @__PURE__ */ new Set(["debug", "info", "warn", "error"]);
|
|
12429
12507
|
var MAX_LINE_BYTES = 4096;
|
|
@@ -12434,7 +12512,7 @@ function isLoopbackAddr(addr) {
|
|
|
12434
12512
|
app18.post("/", async (c) => {
|
|
12435
12513
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
12436
12514
|
if (!isLoopbackAddr(remoteAddr)) {
|
|
12437
|
-
console.error(`${
|
|
12515
|
+
console.error(`${TAG30} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
12438
12516
|
return c.json({ error: "log-ingest-loopback-only" }, 403);
|
|
12439
12517
|
}
|
|
12440
12518
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -12443,7 +12521,7 @@ app18.post("/", async (c) => {
|
|
|
12443
12521
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
12444
12522
|
const offender = tokens.find((t) => !isLoopbackAddr(t));
|
|
12445
12523
|
if (offender !== void 0) {
|
|
12446
|
-
console.error(`${
|
|
12524
|
+
console.error(`${TAG30} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
12447
12525
|
return c.json({ error: "log-ingest-loopback-only" }, 403);
|
|
12448
12526
|
}
|
|
12449
12527
|
}
|
|
@@ -12485,18 +12563,18 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
|
12485
12563
|
]);
|
|
12486
12564
|
var app19 = new Hono();
|
|
12487
12565
|
app19.post("/", async (c) => {
|
|
12488
|
-
const
|
|
12566
|
+
const TAG39 = "[admin:events]";
|
|
12489
12567
|
let body;
|
|
12490
12568
|
try {
|
|
12491
12569
|
body = await c.req.json();
|
|
12492
12570
|
} catch (err) {
|
|
12493
12571
|
const detail = err instanceof Error ? err.message : String(err);
|
|
12494
|
-
console.error(`${
|
|
12572
|
+
console.error(`${TAG39} reject reason=body-not-json detail=${detail}`);
|
|
12495
12573
|
return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
|
|
12496
12574
|
}
|
|
12497
12575
|
const event = typeof body.event === "string" ? body.event : "";
|
|
12498
12576
|
if (!ALLOWED_EVENTS.has(event)) {
|
|
12499
|
-
console.error(`${
|
|
12577
|
+
console.error(`${TAG39} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
|
|
12500
12578
|
return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
|
|
12501
12579
|
}
|
|
12502
12580
|
const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
|
|
@@ -16680,7 +16758,7 @@ var health_default2 = app35;
|
|
|
16680
16758
|
|
|
16681
16759
|
// server/routes/admin/linkedin-ingest.ts
|
|
16682
16760
|
import { randomUUID as randomUUID13 } from "crypto";
|
|
16683
|
-
var
|
|
16761
|
+
var TAG31 = "[linkedin-ingest-route]";
|
|
16684
16762
|
var UUID2 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
16685
16763
|
var ISO = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
16686
16764
|
var LINKEDIN_URL = /^https:\/\/www\.linkedin\.com\//;
|
|
@@ -16784,29 +16862,29 @@ app36.post("/", requireAdminSession, async (c) => {
|
|
|
16784
16862
|
try {
|
|
16785
16863
|
body = await c.req.json();
|
|
16786
16864
|
} catch {
|
|
16787
|
-
console.error(
|
|
16865
|
+
console.error(TAG31 + " rejected status=400 reason=schema:body-not-json");
|
|
16788
16866
|
return c.json({ ok: false, error: "schema", reason: "body-not-json" }, 400);
|
|
16789
16867
|
}
|
|
16790
16868
|
const v = validate(body);
|
|
16791
16869
|
if (!v.ok) {
|
|
16792
|
-
console.error(
|
|
16870
|
+
console.error(TAG31 + " rejected status=" + v.status + " reason=" + v.reason + " missing=" + v.missing.join(","));
|
|
16793
16871
|
return c.json({ ok: false, error: v.error, reason: v.reason, missing: v.missing }, v.status);
|
|
16794
16872
|
}
|
|
16795
16873
|
const envelope = v.envelope;
|
|
16796
16874
|
const cacheKey = c.var.cacheKey ?? "";
|
|
16797
16875
|
const senderId = getAccountIdForSession(cacheKey) ?? "";
|
|
16798
16876
|
if (!senderId) {
|
|
16799
|
-
console.error(
|
|
16877
|
+
console.error(TAG31 + " rejected status=500 reason=admin-account-not-resolved");
|
|
16800
16878
|
return c.json({ ok: false, error: "admin-account-not-resolved" }, 500);
|
|
16801
16879
|
}
|
|
16802
16880
|
const payloadBytes = JSON.stringify(envelope).length;
|
|
16803
16881
|
console.log(
|
|
16804
|
-
|
|
16882
|
+
TAG31 + " received kind=" + envelope.kind + " account=" + senderId.slice(0, 8) + " pageUrl=" + envelope.pageUrl + " dispatchId=" + envelope.dispatchId + " payloadBytes=" + payloadBytes
|
|
16805
16883
|
);
|
|
16806
16884
|
const initialMessage = buildInitialMessage(envelope);
|
|
16807
16885
|
const spawnStart = Date.now();
|
|
16808
16886
|
const sessionId = randomUUID13();
|
|
16809
|
-
console.log(
|
|
16887
|
+
console.log(TAG31 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
|
|
16810
16888
|
const spawned = await managerRcSpawn({
|
|
16811
16889
|
sessionId,
|
|
16812
16890
|
initialMessage,
|
|
@@ -16815,12 +16893,12 @@ app36.post("/", requireAdminSession, async (c) => {
|
|
|
16815
16893
|
});
|
|
16816
16894
|
if ("error" in spawned) {
|
|
16817
16895
|
console.error(
|
|
16818
|
-
|
|
16896
|
+
TAG31 + " dispatch-failed dispatchId=" + envelope.dispatchId + " status=" + spawned.status + " ms=" + (Date.now() - spawnStart) + " message=" + spawned.error
|
|
16819
16897
|
);
|
|
16820
16898
|
return c.json({ ok: false, error: "dispatch-failed", upstreamStatus: spawned.status, detail: spawned.error }, 502);
|
|
16821
16899
|
}
|
|
16822
16900
|
console.log(
|
|
16823
|
-
|
|
16901
|
+
TAG31 + " dispatched dispatchId=" + envelope.dispatchId + " taskId=" + spawned.sessionId + " ms=" + (Date.now() - spawnStart)
|
|
16824
16902
|
);
|
|
16825
16903
|
return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: spawned.sessionId }, 202);
|
|
16826
16904
|
});
|
|
@@ -16828,7 +16906,7 @@ var linkedin_ingest_default = app36;
|
|
|
16828
16906
|
|
|
16829
16907
|
// server/routes/admin/post-turn-context.ts
|
|
16830
16908
|
import neo4j3 from "neo4j-driver";
|
|
16831
|
-
var
|
|
16909
|
+
var TAG32 = "[post-turn-context]";
|
|
16832
16910
|
var STRIPPED_PROPERTIES2 = /* @__PURE__ */ new Set([
|
|
16833
16911
|
"embedding",
|
|
16834
16912
|
"passwordHash",
|
|
@@ -16870,7 +16948,7 @@ var app37 = new Hono();
|
|
|
16870
16948
|
app37.get("/", async (c) => {
|
|
16871
16949
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
16872
16950
|
if (!isLoopbackAddr2(remoteAddr)) {
|
|
16873
|
-
console.error(`${
|
|
16951
|
+
console.error(`${TAG32} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
16874
16952
|
return c.json({ error: "post-turn-context-loopback-only" }, 403);
|
|
16875
16953
|
}
|
|
16876
16954
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -16879,7 +16957,7 @@ app37.get("/", async (c) => {
|
|
|
16879
16957
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
16880
16958
|
const offender = tokens.find((t) => !isLoopbackAddr2(t));
|
|
16881
16959
|
if (offender !== void 0) {
|
|
16882
|
-
console.error(`${
|
|
16960
|
+
console.error(`${TAG32} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
16883
16961
|
return c.json({ error: "post-turn-context-loopback-only" }, 403);
|
|
16884
16962
|
}
|
|
16885
16963
|
}
|
|
@@ -16911,7 +16989,7 @@ app37.get("/", async (c) => {
|
|
|
16911
16989
|
writes.sort((a, b) => a.sortKey.localeCompare(b.sortKey));
|
|
16912
16990
|
const total = Date.now() - started;
|
|
16913
16991
|
console.log(
|
|
16914
|
-
`${
|
|
16992
|
+
`${TAG32} sessionId=${sessionId} accountId=${accountId} writes=${writes.length} ms=${total}`
|
|
16915
16993
|
);
|
|
16916
16994
|
return c.json({
|
|
16917
16995
|
writes: writes.map(({ elementId, labels, properties }) => ({ elementId, labels, properties }))
|
|
@@ -16920,7 +16998,7 @@ app37.get("/", async (c) => {
|
|
|
16920
16998
|
const elapsed = Date.now() - started;
|
|
16921
16999
|
const message = err instanceof Error ? err.message : String(err);
|
|
16922
17000
|
console.error(
|
|
16923
|
-
`${
|
|
17001
|
+
`${TAG32} neo4j-unreachable sessionId=${sessionId} ms=${elapsed} err="${message}"`
|
|
16924
17002
|
);
|
|
16925
17003
|
return c.json({ error: `post-turn-context unavailable: ${message}` }, 503);
|
|
16926
17004
|
} finally {
|
|
@@ -17033,7 +17111,7 @@ function formatPreviousContext(writes) {
|
|
|
17033
17111
|
}
|
|
17034
17112
|
|
|
17035
17113
|
// server/routes/admin/public-session-context.ts
|
|
17036
|
-
var
|
|
17114
|
+
var TAG33 = "[public-session-context]";
|
|
17037
17115
|
function isLoopbackAddr3(addr) {
|
|
17038
17116
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
17039
17117
|
}
|
|
@@ -17041,7 +17119,7 @@ var app38 = new Hono();
|
|
|
17041
17119
|
app38.get("/", async (c) => {
|
|
17042
17120
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
17043
17121
|
if (!isLoopbackAddr3(remoteAddr)) {
|
|
17044
|
-
console.error(`${
|
|
17122
|
+
console.error(`${TAG33} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
17045
17123
|
return c.json({ error: "public-session-context-loopback-only" }, 403);
|
|
17046
17124
|
}
|
|
17047
17125
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -17050,7 +17128,7 @@ app38.get("/", async (c) => {
|
|
|
17050
17128
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
17051
17129
|
const offender = tokens.find((t) => !isLoopbackAddr3(t));
|
|
17052
17130
|
if (offender !== void 0) {
|
|
17053
|
-
console.error(`${
|
|
17131
|
+
console.error(`${TAG33} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
17054
17132
|
return c.json({ error: "public-session-context-loopback-only" }, 403);
|
|
17055
17133
|
}
|
|
17056
17134
|
}
|
|
@@ -17064,14 +17142,14 @@ app38.get("/", async (c) => {
|
|
|
17064
17142
|
const writes = await fetchSliceWrites(session, sliceToken, accountId);
|
|
17065
17143
|
const total = Date.now() - started;
|
|
17066
17144
|
console.log(
|
|
17067
|
-
`${
|
|
17145
|
+
`${TAG33} sliceToken=${sliceToken.slice(0, 8)} writes=${writes.length} ms=${total}`
|
|
17068
17146
|
);
|
|
17069
17147
|
return c.json({ writes });
|
|
17070
17148
|
} catch (err) {
|
|
17071
17149
|
const elapsed = Date.now() - started;
|
|
17072
17150
|
const message = err instanceof Error ? err.message : String(err);
|
|
17073
17151
|
console.error(
|
|
17074
|
-
`${
|
|
17152
|
+
`${TAG33} neo4j-unreachable sliceToken=${sliceToken.slice(0, 8)} ms=${elapsed} err="${message}"`
|
|
17075
17153
|
);
|
|
17076
17154
|
return c.json({ error: `public-session-context unavailable: ${message}` }, 503);
|
|
17077
17155
|
} finally {
|
|
@@ -17081,7 +17159,7 @@ app38.get("/", async (c) => {
|
|
|
17081
17159
|
var public_session_context_default = app38;
|
|
17082
17160
|
|
|
17083
17161
|
// server/routes/admin/public-session-exit.ts
|
|
17084
|
-
var
|
|
17162
|
+
var TAG34 = "[public-session-exit-route]";
|
|
17085
17163
|
function isLoopbackAddr4(addr) {
|
|
17086
17164
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
17087
17165
|
}
|
|
@@ -17089,7 +17167,7 @@ var app39 = new Hono();
|
|
|
17089
17167
|
app39.post("/", async (c) => {
|
|
17090
17168
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
17091
17169
|
if (!isLoopbackAddr4(remoteAddr)) {
|
|
17092
|
-
console.error(`${
|
|
17170
|
+
console.error(`${TAG34} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
17093
17171
|
return c.json({ error: "public-session-exit-loopback-only" }, 403);
|
|
17094
17172
|
}
|
|
17095
17173
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -17098,7 +17176,7 @@ app39.post("/", async (c) => {
|
|
|
17098
17176
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
17099
17177
|
const offender = tokens.find((t) => !isLoopbackAddr4(t));
|
|
17100
17178
|
if (offender !== void 0) {
|
|
17101
|
-
console.error(`${
|
|
17179
|
+
console.error(`${TAG34} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
17102
17180
|
return c.json({ error: "public-session-exit-loopback-only" }, 403);
|
|
17103
17181
|
}
|
|
17104
17182
|
}
|
|
@@ -17116,7 +17194,7 @@ app39.post("/", async (c) => {
|
|
|
17116
17194
|
var public_session_exit_default = app39;
|
|
17117
17195
|
|
|
17118
17196
|
// server/routes/admin/access-session-evict.ts
|
|
17119
|
-
var
|
|
17197
|
+
var TAG35 = "[access-session-evict]";
|
|
17120
17198
|
function isLoopbackAddr5(addr) {
|
|
17121
17199
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
17122
17200
|
}
|
|
@@ -17124,7 +17202,7 @@ var app40 = new Hono();
|
|
|
17124
17202
|
app40.post("/", async (c) => {
|
|
17125
17203
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
17126
17204
|
if (!isLoopbackAddr5(remoteAddr)) {
|
|
17127
|
-
console.error(`${
|
|
17205
|
+
console.error(`${TAG35} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
17128
17206
|
return c.json({ error: "access-session-evict-loopback-only" }, 403);
|
|
17129
17207
|
}
|
|
17130
17208
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -17133,7 +17211,7 @@ app40.post("/", async (c) => {
|
|
|
17133
17211
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
17134
17212
|
const offender = tokens.find((t) => !isLoopbackAddr5(t));
|
|
17135
17213
|
if (offender !== void 0) {
|
|
17136
|
-
console.error(`${
|
|
17214
|
+
console.error(`${TAG35} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
17137
17215
|
return c.json({ error: "access-session-evict-loopback-only" }, 403);
|
|
17138
17216
|
}
|
|
17139
17217
|
}
|
|
@@ -17146,13 +17224,13 @@ app40.post("/", async (c) => {
|
|
|
17146
17224
|
const grantId = typeof body.grantId === "string" ? body.grantId.trim() : "";
|
|
17147
17225
|
if (!grantId) return c.json({ error: "grantId required" }, 400);
|
|
17148
17226
|
const dropped = evictAccessSessionsByGrant(grantId);
|
|
17149
|
-
console.log(`${
|
|
17227
|
+
console.log(`${TAG35} grantId=${grantId} dropped=${dropped}`);
|
|
17150
17228
|
return c.json({ ok: true, dropped });
|
|
17151
17229
|
});
|
|
17152
17230
|
var access_session_evict_default = app40;
|
|
17153
17231
|
|
|
17154
17232
|
// server/routes/admin/enrol-person.ts
|
|
17155
|
-
var
|
|
17233
|
+
var TAG36 = "[enrol]";
|
|
17156
17234
|
function isLoopbackAddr6(addr) {
|
|
17157
17235
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
17158
17236
|
}
|
|
@@ -17161,7 +17239,7 @@ var app41 = new Hono();
|
|
|
17161
17239
|
app41.post("/", async (c) => {
|
|
17162
17240
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
17163
17241
|
if (!isLoopbackAddr6(remoteAddr)) {
|
|
17164
|
-
console.error(`${
|
|
17242
|
+
console.error(`${TAG36} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
17165
17243
|
return c.json({ error: "enrol-person-loopback-only" }, 403);
|
|
17166
17244
|
}
|
|
17167
17245
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -17170,7 +17248,7 @@ app41.post("/", async (c) => {
|
|
|
17170
17248
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
17171
17249
|
const offender = tokens.find((t) => !isLoopbackAddr6(t));
|
|
17172
17250
|
if (offender !== void 0) {
|
|
17173
|
-
console.error(`${
|
|
17251
|
+
console.error(`${TAG36} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
17174
17252
|
return c.json({ error: "enrol-person-loopback-only" }, 403);
|
|
17175
17253
|
}
|
|
17176
17254
|
}
|
|
@@ -17195,7 +17273,7 @@ app41.post("/", async (c) => {
|
|
|
17195
17273
|
}
|
|
17196
17274
|
const accountId = process.env.ACCOUNT_ID ?? "";
|
|
17197
17275
|
if (!accountId) {
|
|
17198
|
-
console.error(`${
|
|
17276
|
+
console.error(`${TAG36} op=person result=no-account-id`);
|
|
17199
17277
|
return c.json({ error: "no-account-id" }, 500);
|
|
17200
17278
|
}
|
|
17201
17279
|
let personId;
|
|
@@ -17203,7 +17281,7 @@ app41.post("/", async (c) => {
|
|
|
17203
17281
|
personId = await enrolPerson({ accountId, phone, email, agentSlug });
|
|
17204
17282
|
} catch (err) {
|
|
17205
17283
|
console.error(
|
|
17206
|
-
`${
|
|
17284
|
+
`${TAG36} op=person result=write-failed agentSlug=${agentSlug} contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
17207
17285
|
);
|
|
17208
17286
|
return c.json({ error: "enrol-failed" }, 500);
|
|
17209
17287
|
}
|
|
@@ -17213,11 +17291,11 @@ app41.post("/", async (c) => {
|
|
|
17213
17291
|
if (g) grant = { grantId: g.grantId, status: g.status, contactValue: g.contactValue };
|
|
17214
17292
|
} catch (err) {
|
|
17215
17293
|
console.error(
|
|
17216
|
-
`${
|
|
17294
|
+
`${TAG36} op=person result=grant-lookup-failed contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
17217
17295
|
);
|
|
17218
17296
|
}
|
|
17219
17297
|
console.log(
|
|
17220
|
-
`${
|
|
17298
|
+
`${TAG36} op=person personId=${personId} account=${accountId} agentSlug=${agentSlug} contact=${maskContact(email)}`
|
|
17221
17299
|
);
|
|
17222
17300
|
return c.json({ personId, grant }, 200);
|
|
17223
17301
|
});
|
|
@@ -17293,7 +17371,7 @@ app43.route("/enrol-person", enrol_person_default);
|
|
|
17293
17371
|
var admin_default = app43;
|
|
17294
17372
|
|
|
17295
17373
|
// server/routes/access/verify-token.ts
|
|
17296
|
-
var
|
|
17374
|
+
var TAG37 = "[access-verify]";
|
|
17297
17375
|
var MINT_TAG = "[access-session-mint]";
|
|
17298
17376
|
var COOKIE_NAME = "__access_session";
|
|
17299
17377
|
var app44 = new Hono();
|
|
@@ -17312,39 +17390,39 @@ app44.post("/", async (c) => {
|
|
|
17312
17390
|
}
|
|
17313
17391
|
const rateMsg = checkAccessRateLimit(ip, agentSlug);
|
|
17314
17392
|
if (rateMsg) {
|
|
17315
|
-
console.error(`${
|
|
17393
|
+
console.error(`${TAG37} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
|
|
17316
17394
|
return c.json({ error: rateMsg }, 429);
|
|
17317
17395
|
}
|
|
17318
17396
|
const grant = await findGrantByMagicToken(token);
|
|
17319
17397
|
if (!grant) {
|
|
17320
17398
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
17321
|
-
console.error(`${
|
|
17399
|
+
console.error(`${TAG37} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
|
|
17322
17400
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
17323
17401
|
}
|
|
17324
17402
|
if (grant.agentSlug !== agentSlug) {
|
|
17325
17403
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
17326
17404
|
console.error(
|
|
17327
|
-
`${
|
|
17405
|
+
`${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
|
|
17328
17406
|
);
|
|
17329
17407
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
17330
17408
|
}
|
|
17331
17409
|
if (grant.status === "expired" || grant.status === "revoked") {
|
|
17332
17410
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
17333
17411
|
console.error(
|
|
17334
|
-
`${
|
|
17412
|
+
`${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
|
|
17335
17413
|
);
|
|
17336
17414
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
17337
17415
|
}
|
|
17338
17416
|
if (grant.expiresAt !== null && grant.expiresAt < Date.now()) {
|
|
17339
17417
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
17340
17418
|
console.error(
|
|
17341
|
-
`${
|
|
17419
|
+
`${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
|
|
17342
17420
|
);
|
|
17343
17421
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
17344
17422
|
}
|
|
17345
17423
|
if (!grant.sliceToken) {
|
|
17346
17424
|
console.error(
|
|
17347
|
-
`${
|
|
17425
|
+
`${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
|
|
17348
17426
|
);
|
|
17349
17427
|
return c.json({ error: "grant-misconfigured" }, 500);
|
|
17350
17428
|
}
|
|
@@ -17360,12 +17438,12 @@ app44.post("/", async (c) => {
|
|
|
17360
17438
|
await consumeMagicTokenAndActivate(grant.grantId);
|
|
17361
17439
|
} catch (err) {
|
|
17362
17440
|
console.error(
|
|
17363
|
-
`${
|
|
17441
|
+
`${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
17364
17442
|
);
|
|
17365
17443
|
return c.json({ error: "verification-failed" }, 500);
|
|
17366
17444
|
}
|
|
17367
17445
|
clearAccessRateLimit(ip, agentSlug);
|
|
17368
|
-
console.log(`${
|
|
17446
|
+
console.log(`${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
|
|
17369
17447
|
console.log(
|
|
17370
17448
|
`${MINT_TAG} grantId=${grant.grantId} sliceToken=${grant.sliceToken.slice(0, 8)} agentSlug=${agentSlug} personId=${grant.personId ?? "none"}`
|
|
17371
17449
|
);
|
|
@@ -17441,7 +17519,7 @@ async function sendMagicLinkEmail(payload) {
|
|
|
17441
17519
|
}
|
|
17442
17520
|
|
|
17443
17521
|
// server/routes/access/request-magic-link.ts
|
|
17444
|
-
var
|
|
17522
|
+
var TAG38 = "[access-request-link]";
|
|
17445
17523
|
var app45 = new Hono();
|
|
17446
17524
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
17447
17525
|
app45.post("/", async (c) => {
|
|
@@ -17458,18 +17536,18 @@ app45.post("/", async (c) => {
|
|
|
17458
17536
|
}
|
|
17459
17537
|
const rateMsg = checkRequestLinkRateLimit(contactValue);
|
|
17460
17538
|
if (rateMsg) {
|
|
17461
|
-
console.error(`${
|
|
17539
|
+
console.error(`${TAG38} contactValue=${maskContact(contactValue)} result=rate-limited`);
|
|
17462
17540
|
return c.json({ error: rateMsg }, 429);
|
|
17463
17541
|
}
|
|
17464
17542
|
recordRequestLinkAttempt(contactValue);
|
|
17465
17543
|
const accountId = process.env.ACCOUNT_ID ?? "";
|
|
17466
17544
|
if (!accountId) {
|
|
17467
|
-
console.error(`${
|
|
17545
|
+
console.error(`${TAG38} contactValue=${maskContact(contactValue)} result=no-account-id`);
|
|
17468
17546
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
17469
17547
|
}
|
|
17470
17548
|
const grant = await findActiveGrantByContact(contactValue, agentSlug, accountId);
|
|
17471
17549
|
if (!grant) {
|
|
17472
|
-
console.log(`${
|
|
17550
|
+
console.log(`${TAG38} contactValue=${maskContact(contactValue)} result=notfound`);
|
|
17473
17551
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
17474
17552
|
}
|
|
17475
17553
|
let token;
|
|
@@ -17477,7 +17555,7 @@ app45.post("/", async (c) => {
|
|
|
17477
17555
|
token = await generateNewMagicToken(grant.grantId);
|
|
17478
17556
|
} catch (err) {
|
|
17479
17557
|
console.error(
|
|
17480
|
-
`${
|
|
17558
|
+
`${TAG38} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
17481
17559
|
);
|
|
17482
17560
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
17483
17561
|
}
|
|
@@ -17509,12 +17587,12 @@ app45.post("/", async (c) => {
|
|
|
17509
17587
|
});
|
|
17510
17588
|
if (!sendResult.ok) {
|
|
17511
17589
|
console.error(
|
|
17512
|
-
`${
|
|
17590
|
+
`${TAG38} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
|
|
17513
17591
|
);
|
|
17514
17592
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
17515
17593
|
}
|
|
17516
17594
|
console.log(
|
|
17517
|
-
`${
|
|
17595
|
+
`${TAG38} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
|
|
17518
17596
|
);
|
|
17519
17597
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
17520
17598
|
});
|