@rubytech/create-maxy-code 0.1.432 → 0.1.433
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/package.json +1 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +2 -2
- package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
- package/payload/server/public/assets/AdminLoginScreens-CH-kznsr.js +1 -0
- package/payload/server/public/assets/AdminShell-DzgrZYpX.js +2 -0
- package/payload/server/public/assets/{Checkbox-BC0c_gbn.js → Checkbox-ChPx3-af.js} +1 -1
- package/payload/server/public/assets/admin-VHYR1DAp.js +1 -0
- package/payload/server/public/assets/{arc-qKfXIt8v.js → arc-Bm9oSOth.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-Bbnxm4F4.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-DkVrGn7G.js → architectureDiagram-Q4EWVU46-C2dK88g3.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DqavswGH.js → blockDiagram-DXYQGD6D-DfLSsjCJ.js} +1 -1
- package/payload/server/public/assets/{browser-CvZxNdKw.js → browser-DkTz3Atj.js} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-B7fyKiXe.js → c4Diagram-AHTNJAMY-Bxkmp6OL.js} +1 -1
- package/payload/server/public/assets/{calendar-DXxLMF2J.js → calendar-DlQUywFC.js} +1 -1
- package/payload/server/public/assets/channel-CatPTq-5.js +1 -0
- package/payload/server/public/assets/chat-CPOGOzmQ.js +1 -0
- package/payload/server/public/assets/chevron-left-Ch2-JhmS.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-DsgMtGkv.js → chunk-2KRD3SAO-BVNDFwNH.js} +1 -1
- package/payload/server/public/assets/{chunk-336JU56O-CkdISfNt.js → chunk-336JU56O-Daz6nMta.js} +2 -2
- package/payload/server/public/assets/chunk-426QAEUC-CqLMwOdA.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-CYpiF2bl.js → chunk-4BX2VUAB-DTldfvwP.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-CWyc_F7v.js → chunk-4TB4RGXK-DhM8pwRG.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-BbzKMw2Z.js → chunk-55IACEB6-CzTsbIHo.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-u19Nai9e.js → chunk-5FUZZQ4R-BrcObZhe.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-Ba8by6Uy.js → chunk-5PVQY5BW-SFqTuS11.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-BwUuxtyb.js → chunk-67CJDMHE-EIbrSGOo.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-BRH9iM9L.js → chunk-7N4EOEYR-B1D4Jorr.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-BGoztgLL.js → chunk-AA7GKIK3-BKHiX4cC.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-C5GDAZTl.js → chunk-BSJP7CBP-xBzu29m7.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-ChY32VPS.js → chunk-CIAEETIT-x2x0gMpL.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-CPSD3p6p.js → chunk-EDXVE4YY-D5UkD28M.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-D1oL-iUr.js → chunk-ENJZ2VHE-Dbz67a7E.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-CPvYEr54.js → chunk-FMBD7UC4-XfWvuu2F.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-9Yyj7Vbz.js → chunk-FOC6F5B3-DfOEDS4q.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-BaYgh8FR.js → chunk-ICPOFSXX-D_WEZZvg.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-5ucpeRvm.js → chunk-K5T4RW27-7O627Xi1.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-DW-FHk7T.js → chunk-KGLVRYIC-BXI3XDP9.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-CGGVfAyG.js → chunk-LIHQZDEY-B9cFNN0l.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-Bv8EUa5d.js → chunk-ORNJ4GCN-BR3UNDTn.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-C1mXJnyw.js → chunk-OYMX7WX6-2wKIEtFZ.js} +1 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-CjWy8NJ7.js +1 -0
- package/payload/server/public/assets/{chunk-U2HBQHQK-PwSQz6EP.js → chunk-U2HBQHQK-augM3AXB.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP--NPHTBlU.js → chunk-X2U36JSP-BAM9q9ZQ.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-Bbc7Da32.js → chunk-XPW4576I-DxPpji5P.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-D-9v8e--.js → chunk-YZCP3GAM-BD3ClFXP.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-CMPg670Q.js → chunk-ZZ45TVLE-CqxhLPep.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-DHhR5rdN.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DH4pAdfu.js +1 -0
- package/payload/server/public/assets/clone-DCKzwjWW.js +1 -0
- package/payload/server/public/assets/{cose-bilkent-S5V4N54A-NVSb1Bhy.js → cose-bilkent-S5V4N54A-xywWX-9i.js} +1 -1
- package/payload/server/public/assets/{dagre-QfLcO-1j.js → dagre-BaHjDQ-8.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-V2Ai1DFl.js → dagre-KV5264BT-ChRpqqiH.js} +1 -1
- package/payload/server/public/assets/data-Ppxc3gvy.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-Caw21693.js → diagram-5BDNPKRD-KjwTpyBi.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-CgwVkT2q.js → diagram-G4DWMVQ6-DZO9njAF.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-DFUrLZhs.js → diagram-MMDJMWI5-Bus-U-TI.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-CEEiEuZJ.js → diagram-TYMM5635-CfJodFgq.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-CG10NrT3.js → erDiagram-SMLLAGMA-Bt5zqWiW.js} +1 -1
- package/payload/server/public/assets/{file-download-B2B2DTar.js → file-download-CX16TB7C.js} +1 -1
- package/payload/server/public/assets/{flatten-DAO0sfCM.js → flatten-Bpu1L63d.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-BqkV9Okv.js → flowDiagram-DWJPFMVM-B64Q590S.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-DRiCDQF6.js → ganttDiagram-T4ZO3ILL-BWdgCEpH.js} +1 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-Ps5HDzLh.js +1 -0
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-BZV2voyy.js → gitGraphDiagram-UUTBAWPF-Djq2B0WT.js} +1 -1
- package/payload/server/public/assets/{graph-DRNzDBTV.js → graph-DPqvHCZ4.js} +3 -3
- package/payload/server/public/assets/{graph-labels-DxqDdO7G.js → graph-labels-D_0uou0Z.js} +1 -1
- package/payload/server/public/assets/{graphlib-DGPThX8M.js → graphlib-CNJh9_lx.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-gtlpwIig.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-CPrWlrsa.js +2 -0
- package/payload/server/public/assets/{isEmpty-Cb_U81C6.js → isEmpty-DkDEVnMZ.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-BKsAxSvp.js → ishikawaDiagram-UXIWVN3A-V3ACkWCW.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-CmliuOd-.js → journeyDiagram-VCZTEJTY-9T0qZeH3.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-DAlElMb-.js → kanban-definition-6JOO6SKY-CxZ0ukx3.js} +1 -1
- package/payload/server/public/assets/{line-DKZqLKAC.js → line-DUHKCQZT.js} +1 -1
- package/payload/server/public/assets/{linear-CbSGdh1x.js → linear-BgIBblun.js} +1 -1
- package/payload/server/public/assets/{maximize-2-DKx6OBKv.js → maximize-2-BTHbMSfz.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-DFvbao9C.js → mermaid-parser.core-CyHygs0-.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-C0vEBxDm.js → mermaid.core-L55fJBSx.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-CShASUKd.js → mindmap-definition-QFDTVHPH-DczaUX_E.js} +1 -1
- package/payload/server/public/assets/operator-BCZ7UoWU.js +1 -0
- package/payload/server/public/assets/{ordinal-H0tVmBDP.js → ordinal-DK3QISRR.js} +1 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-DrSn1e0n.js +1 -0
- package/payload/server/public/assets/page-BObPPwJr.js +32 -0
- package/payload/server/public/assets/page-CqN6MkYM.js +1 -0
- package/payload/server/public/assets/{pdf-render-jAQU0nXt.js → pdf-render-COLA4aPx.js} +1 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-C09i6N-g.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-CBZHpDAJ.js → pieDiagram-DEJITSTG-Da5TdnNt.js} +1 -1
- package/payload/server/public/assets/{play-DHttF4fl.js → play-Bw1WkeRC.js} +1 -1
- package/payload/server/public/assets/public-DI5OCw9V.js +1 -0
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-n3bB3K91.js → quadrantDiagram-34T5L4WZ-DX7J81uh.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-CMZN2KQH.js +1 -0
- package/payload/server/public/assets/{reduce-DAvwat-a.js → reduce-uzWdoyL7.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-DiDvQK3c.js → requirementDiagram-MS252O5E-DJQGrZPG.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-DWDQQZmd.js → sankeyDiagram-XADWPNL6-Ba8fGz96.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-DmAqRlBT.js → sequenceDiagram-FGHM5R23-BmDPC7qx.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-D4R-n6bZ.js → stateDiagram-FHFEXIEX-1VkptYFz.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BdgkPHuh.js +1 -0
- package/payload/server/public/assets/tasks-Bj03-1M6.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-CjiHGP4l.js → timeline-definition-GMOUNBTQ-B92U3T_f.js} +1 -1
- package/payload/server/public/assets/treeView-SZITEDCU-CeuUM5oL.js +1 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-C--fAaJv.js +1 -0
- package/payload/server/public/assets/{useCopyFeedback-CPEOUSGU.js → useCopyFeedback-8b1gtbRz.js} +1 -1
- package/payload/server/public/assets/useSubAccountSwitcher-Cmbcd72K.js +9 -0
- package/payload/server/public/assets/{useSubAccountSwitcher-CdS1CorH.css → useSubAccountSwitcher-DRRuGtGS.css} +1 -1
- package/payload/server/public/assets/useVoiceRecorder-D9Qa7Eua.js +2 -0
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-CBdDQ7c-.js → vennDiagram-DHZGUBPP-Y6Wkihrs.js} +1 -1
- package/payload/server/public/assets/wardley-RL74JXVD-4WPJ2UA9.js +1 -0
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-BlIQPKLb.js → wardleyDiagram-NUSXRM2D-iJpfal2z.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-CslKgh9B.js → xychartDiagram-5P7HB3ND-S0bv7oH0.js} +1 -1
- package/payload/server/public/browser.html +5 -6
- package/payload/server/public/calendar.html +6 -7
- package/payload/server/public/chat.html +12 -13
- package/payload/server/public/data.html +10 -10
- package/payload/server/public/graph.html +10 -11
- package/payload/server/public/index.html +13 -14
- package/payload/server/public/operator.html +14 -15
- package/payload/server/public/public.html +12 -13
- package/payload/server/public/tasks.html +4 -5
- package/payload/server/server.js +292 -109
- package/payload/server/public/assets/AdminLoginScreens-BM45lL5G.js +0 -1
- package/payload/server/public/assets/AdminShell-BfLQQ27Z.js +0 -2
- package/payload/server/public/assets/admin-B8Eb9Wbj.js +0 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-FPHT7s-C.js +0 -1
- package/payload/server/public/assets/audio-attachment-mime-Cx5d3Jls.js +0 -2
- package/payload/server/public/assets/channel-j70eMvcL.js +0 -1
- package/payload/server/public/assets/chat-LEEUAJOG.js +0 -1
- package/payload/server/public/assets/chevron-left-CLPxfjDV.js +0 -1
- package/payload/server/public/assets/chunk-426QAEUC-D-NcAlTW.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-CAwbQBtf.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-Ct6Rn0vt.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-B_2XCIFv.js +0 -1
- package/payload/server/public/assets/clone-DjPWA_NH.js +0 -1
- package/payload/server/public/assets/data-CKojMQSz.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-B8Hx7f-D.js +0 -1
- package/payload/server/public/assets/info-OMHHGYJF-BicCJTqU.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-tf-8rOez.js +0 -2
- package/payload/server/public/assets/operator-OwY_sWTH.js +0 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-Ckn_5hq0.js +0 -1
- package/payload/server/public/assets/page-B7nCws9K.js +0 -1
- package/payload/server/public/assets/page-C3L6-Ufk.js +0 -32
- package/payload/server/public/assets/pie-ZZUOXDRM-DzlGQW3J.js +0 -1
- package/payload/server/public/assets/public-CSLXSSy5.js +0 -1
- package/payload/server/public/assets/radar-PYXPWWZC-BHo2YD8b.js +0 -1
- package/payload/server/public/assets/square-CHcQHtK8.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BcFRbGRu.js +0 -1
- package/payload/server/public/assets/tasks-ClfJU1CK.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-BtRr5vXp.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-D8p0sbyo.js +0 -1
- package/payload/server/public/assets/useSubAccountSwitcher-DyjTbzQR.js +0 -9
- package/payload/server/public/assets/wardley-RL74JXVD-DgMn-9ZJ.js +0 -1
- /package/payload/server/public/assets/{_baseFor-D3BqAOBr.js → _baseFor-Q4DeIqQC.js} +0 -0
- /package/payload/server/public/assets/{array-iYP9fzJp.js → array-WaOTgZu7.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-BQSBzPsB.js → cytoscape.esm-CMmjo4hO.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-BrdA1gDi.js → defaultLocale-BxqJVxq5.js} +0 -0
- /package/payload/server/public/assets/{dist-Cvgxm7qv.js → dist-Dx-cpU53.js} +0 -0
- /package/payload/server/public/assets/{init-Bx0S6pkp.js → init-DX7c5Edh.js} +0 -0
- /package/payload/server/public/assets/{katex-BsiH_a6d.js → katex-B2dtGfSp.js} +0 -0
- /package/payload/server/public/assets/{path-BLSgTy3w.js → path-CnSyroar.js} +0 -0
- /package/payload/server/public/assets/{preload-helper-ClBMtM1g.js → preload-helper-DqboRNgS.js} +0 -0
- /package/payload/server/public/assets/{rough.esm-BMOtDaaS.js → rough.esm-eLccZ4OJ.js} +0 -0
- /package/payload/server/public/assets/{src-DV4LKv2E.js → src-Dqs1wlnb.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -2368,28 +2368,14 @@ function computeBackoff(attempt, config = {}) {
|
|
|
2368
2368
|
|
|
2369
2369
|
// app/lib/whatsapp/init-queries.ts
|
|
2370
2370
|
import { inspect as inspect2 } from "util";
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
var INSPECT_OPTS2 = {
|
|
2374
|
-
depth: null,
|
|
2375
|
-
breakLength: Infinity,
|
|
2376
|
-
compact: true,
|
|
2377
|
-
maxArrayLength: 50
|
|
2378
|
-
};
|
|
2379
|
-
function formatErr(err) {
|
|
2380
|
-
if (err instanceof Error) {
|
|
2381
|
-
const base = `${err.name}: ${err.message}`;
|
|
2382
|
-
const inspected = inspect2(err, INSPECT_OPTS2);
|
|
2383
|
-
return `${base}
|
|
2384
|
-
${inspected}`;
|
|
2385
|
-
}
|
|
2386
|
-
return inspect2(err, INSPECT_OPTS2);
|
|
2387
|
-
}
|
|
2371
|
+
|
|
2372
|
+
// app/lib/whatsapp/with-timeout.ts
|
|
2388
2373
|
function withTimeout(label, promise, timeoutMs) {
|
|
2389
2374
|
return new Promise((resolve34, reject) => {
|
|
2390
2375
|
const timer2 = setTimeout(() => {
|
|
2391
2376
|
reject(new Error(`${label} timed out after ${timeoutMs}ms`));
|
|
2392
2377
|
}, timeoutMs);
|
|
2378
|
+
timer2.unref?.();
|
|
2393
2379
|
promise.then(
|
|
2394
2380
|
(value) => {
|
|
2395
2381
|
clearTimeout(timer2);
|
|
@@ -2402,6 +2388,25 @@ function withTimeout(label, promise, timeoutMs) {
|
|
|
2402
2388
|
);
|
|
2403
2389
|
});
|
|
2404
2390
|
}
|
|
2391
|
+
|
|
2392
|
+
// app/lib/whatsapp/init-queries.ts
|
|
2393
|
+
var TAG3 = "[whatsapp:init]";
|
|
2394
|
+
var DEFAULT_QUERY_TIMEOUT_MS = 15e3;
|
|
2395
|
+
var INSPECT_OPTS2 = {
|
|
2396
|
+
depth: null,
|
|
2397
|
+
breakLength: Infinity,
|
|
2398
|
+
compact: true,
|
|
2399
|
+
maxArrayLength: 50
|
|
2400
|
+
};
|
|
2401
|
+
function formatErr(err) {
|
|
2402
|
+
if (err instanceof Error) {
|
|
2403
|
+
const base = `${err.name}: ${err.message}`;
|
|
2404
|
+
const inspected = inspect2(err, INSPECT_OPTS2);
|
|
2405
|
+
return `${base}
|
|
2406
|
+
${inspected}`;
|
|
2407
|
+
}
|
|
2408
|
+
return inspect2(err, INSPECT_OPTS2);
|
|
2409
|
+
}
|
|
2405
2410
|
async function runInitQueries(sock, ctx) {
|
|
2406
2411
|
const startedAt = Date.now();
|
|
2407
2412
|
const queryTimeoutMs = ctx.queryTimeoutMs ?? DEFAULT_QUERY_TIMEOUT_MS;
|
|
@@ -2712,6 +2717,10 @@ function extractMessage(msg) {
|
|
|
2712
2717
|
}
|
|
2713
2718
|
return result;
|
|
2714
2719
|
}
|
|
2720
|
+
function mediaFallbackBody(extracted) {
|
|
2721
|
+
if (extracted.text) return extracted.text;
|
|
2722
|
+
return extracted.mediaType ? `[${extracted.mediaType}]` : "";
|
|
2723
|
+
}
|
|
2715
2724
|
|
|
2716
2725
|
// app/lib/whatsapp/managed-account.ts
|
|
2717
2726
|
function normalizeEntry(v) {
|
|
@@ -3231,14 +3240,23 @@ function getChannelActivity(accountId) {
|
|
|
3231
3240
|
|
|
3232
3241
|
// app/lib/whatsapp/outbound/send.ts
|
|
3233
3242
|
var TAG6 = "[whatsapp:outbound]";
|
|
3243
|
+
function buildQuoted(q) {
|
|
3244
|
+
return {
|
|
3245
|
+
key: {
|
|
3246
|
+
remoteJid: q.remoteJid,
|
|
3247
|
+
id: q.id,
|
|
3248
|
+
fromMe: q.fromMe,
|
|
3249
|
+
...q.participant ? { participant: q.participant } : {}
|
|
3250
|
+
},
|
|
3251
|
+
message: { conversation: q.body ?? "" }
|
|
3252
|
+
};
|
|
3253
|
+
}
|
|
3234
3254
|
async function sendTextMessage(sock, to, text, opts) {
|
|
3235
3255
|
try {
|
|
3236
3256
|
const jid = to.includes("@") ? to : toWhatsappJid(to);
|
|
3237
3257
|
const payload = { text };
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
}
|
|
3241
|
-
const result = await sock.sendMessage(jid, payload);
|
|
3258
|
+
const options = opts?.quoted ? { quoted: buildQuoted(opts.quoted) } : void 0;
|
|
3259
|
+
const result = await sock.sendMessage(jid, payload, options);
|
|
3242
3260
|
const messageId = result?.key?.id;
|
|
3243
3261
|
if (messageId) {
|
|
3244
3262
|
trackAgentSentMessage(messageId);
|
|
@@ -3314,7 +3332,8 @@ async function sendMediaMessage(sock, to, media, opts) {
|
|
|
3314
3332
|
};
|
|
3315
3333
|
break;
|
|
3316
3334
|
}
|
|
3317
|
-
const
|
|
3335
|
+
const options = opts?.quoted ? { quoted: buildQuoted(opts.quoted) } : void 0;
|
|
3336
|
+
const result = await sock.sendMessage(jid, payload, options);
|
|
3318
3337
|
const messageId = result?.key?.id;
|
|
3319
3338
|
if (messageId) {
|
|
3320
3339
|
trackAgentSentMessage(messageId);
|
|
@@ -4134,6 +4153,7 @@ async function storeComponentArtefact(accountId, attachmentId, mimeType, content
|
|
|
4134
4153
|
// app/lib/whatsapp/inbound/media.ts
|
|
4135
4154
|
var TAG9 = "[whatsapp:media]";
|
|
4136
4155
|
var MEDIA_DIR = "/tmp/maxy-media";
|
|
4156
|
+
var DOWNLOAD_TIMEOUT_MS = 45e3;
|
|
4137
4157
|
function deterministicAttachmentId(seed) {
|
|
4138
4158
|
const h = createHash("sha256").update(seed).digest("hex");
|
|
4139
4159
|
return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20, 32)}`;
|
|
@@ -4204,43 +4224,50 @@ async function downloadInboundMediaBuffer(msg, sock, opts) {
|
|
|
4204
4224
|
return void 0;
|
|
4205
4225
|
}
|
|
4206
4226
|
const maxBytes = opts?.maxBytes ?? 50 * 1024 * 1024;
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
"
|
|
4211
|
-
{
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4227
|
+
const timeoutMs = opts?.timeoutMs ?? DOWNLOAD_TIMEOUT_MS;
|
|
4228
|
+
try {
|
|
4229
|
+
return await withTimeout(
|
|
4230
|
+
`whatsapp media download (${mimetype ?? "unknown"})`,
|
|
4231
|
+
(async () => {
|
|
4232
|
+
let buffer = await downloadMediaMessage(
|
|
4233
|
+
msg,
|
|
4234
|
+
"buffer",
|
|
4235
|
+
{},
|
|
4236
|
+
{
|
|
4237
|
+
reuploadRequest: sock.updateMediaMessage,
|
|
4238
|
+
logger: sock.logger
|
|
4239
|
+
}
|
|
4240
|
+
);
|
|
4241
|
+
if (!buffer || buffer.length === 0) {
|
|
4242
|
+
console.error(`${TAG9} primary download returned empty, trying direct fallback`);
|
|
4243
|
+
const downloadable = getDownloadableContent(content);
|
|
4244
|
+
if (downloadable) {
|
|
4245
|
+
try {
|
|
4246
|
+
const stream2 = await downloadContentFromMessage(downloadable.downloadable, downloadable.mediaType);
|
|
4247
|
+
buffer = await streamToBuffer(stream2);
|
|
4248
|
+
} catch (fallbackErr) {
|
|
4249
|
+
console.error(`${TAG9} direct download fallback failed: ${String(fallbackErr)}`);
|
|
4250
|
+
}
|
|
4251
|
+
}
|
|
4226
4252
|
}
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4253
|
+
if (!buffer || buffer.length === 0) {
|
|
4254
|
+
console.error(`${TAG9} download failed: empty buffer for ${mimetype ?? "unknown"}`);
|
|
4255
|
+
return void 0;
|
|
4256
|
+
}
|
|
4257
|
+
if (buffer.length > maxBytes) {
|
|
4258
|
+
const sizeMB = (buffer.length / (1024 * 1024)).toFixed(1);
|
|
4259
|
+
const limitMB = (maxBytes / (1024 * 1024)).toFixed(0);
|
|
4260
|
+
console.error(`${TAG9} media too large type=${mimetype ?? "unknown"} size=${sizeMB}MB limit=${limitMB}MB`);
|
|
4261
|
+
return void 0;
|
|
4262
|
+
}
|
|
4263
|
+
return {
|
|
4264
|
+
buffer,
|
|
4265
|
+
mimetype: mimetype ?? "application/octet-stream",
|
|
4266
|
+
filename: inner.documentMessage?.fileName ?? void 0
|
|
4267
|
+
};
|
|
4268
|
+
})(),
|
|
4269
|
+
timeoutMs
|
|
4270
|
+
);
|
|
4244
4271
|
} catch (err) {
|
|
4245
4272
|
console.error(`${TAG9} media download failed type=${mimetype ?? "unknown"} error=${String(err)}`);
|
|
4246
4273
|
return void 0;
|
|
@@ -4276,6 +4303,40 @@ async function storeInboundMediaServable(msg, sock, accountId, seed, opts) {
|
|
|
4276
4303
|
}
|
|
4277
4304
|
}
|
|
4278
4305
|
|
|
4306
|
+
// app/lib/whatsapp/inbound/bounded-queue.ts
|
|
4307
|
+
function createBoundedQueue(limit, opts) {
|
|
4308
|
+
if (!Number.isInteger(limit) || limit < 1) {
|
|
4309
|
+
throw new Error(`createBoundedQueue: limit must be a positive integer, got ${limit}`);
|
|
4310
|
+
}
|
|
4311
|
+
const maxPending = opts?.maxPending ?? Infinity;
|
|
4312
|
+
if (maxPending !== Infinity && (!Number.isInteger(maxPending) || maxPending < 1)) {
|
|
4313
|
+
throw new Error(`createBoundedQueue: maxPending must be a positive integer or omitted, got ${maxPending}`);
|
|
4314
|
+
}
|
|
4315
|
+
const queue = [];
|
|
4316
|
+
let running = 0;
|
|
4317
|
+
const pump = () => {
|
|
4318
|
+
while (running < limit && queue.length > 0) {
|
|
4319
|
+
const task = queue.shift();
|
|
4320
|
+
running++;
|
|
4321
|
+
void Promise.resolve().then(task).catch(() => {
|
|
4322
|
+
}).finally(() => {
|
|
4323
|
+
running--;
|
|
4324
|
+
pump();
|
|
4325
|
+
});
|
|
4326
|
+
}
|
|
4327
|
+
};
|
|
4328
|
+
return {
|
|
4329
|
+
schedule(task) {
|
|
4330
|
+
if (queue.length >= maxPending) return false;
|
|
4331
|
+
queue.push(task);
|
|
4332
|
+
pump();
|
|
4333
|
+
return true;
|
|
4334
|
+
},
|
|
4335
|
+
active: () => running,
|
|
4336
|
+
pending: () => queue.length
|
|
4337
|
+
};
|
|
4338
|
+
}
|
|
4339
|
+
|
|
4279
4340
|
// app/lib/whatsapp/inbound/debounce.ts
|
|
4280
4341
|
var TAG10 = "[whatsapp:debounce]";
|
|
4281
4342
|
var STT_TAG = "[whatsapp:stt-await]";
|
|
@@ -4605,6 +4666,11 @@ var WaReplyError = class extends Error {
|
|
|
4605
4666
|
var TAG13 = "[whatsapp:manager]";
|
|
4606
4667
|
var MAX_RECONNECT_ATTEMPTS = 10;
|
|
4607
4668
|
var MESSAGE_STORE_MAX = 500;
|
|
4669
|
+
var APPEND_MEDIA_CONCURRENCY = 3;
|
|
4670
|
+
var APPEND_MEDIA_MAX_PENDING = 24;
|
|
4671
|
+
var appendMediaQueue = createBoundedQueue(APPEND_MEDIA_CONCURRENCY, {
|
|
4672
|
+
maxPending: APPEND_MEDIA_MAX_PENDING
|
|
4673
|
+
});
|
|
4608
4674
|
var connections = /* @__PURE__ */ new Map();
|
|
4609
4675
|
var configDir = null;
|
|
4610
4676
|
var whatsAppConfig = {};
|
|
@@ -5104,6 +5170,7 @@ function monitorInbound(conn) {
|
|
|
5104
5170
|
const remoteJid = msg.key.remoteJid;
|
|
5105
5171
|
if (!remoteJid || remoteJid === "status@broadcast") continue;
|
|
5106
5172
|
if (!msg.message) continue;
|
|
5173
|
+
let receiptDeferredToWorker = false;
|
|
5107
5174
|
const extracted = extractMessage(msg);
|
|
5108
5175
|
const mediaServable = !!(extracted.mediaType && extracted.mimetype && isSupportedMime(extracted.mimetype));
|
|
5109
5176
|
if (extracted.text || mediaServable) {
|
|
@@ -5160,18 +5227,10 @@ function monitorInbound(conn) {
|
|
|
5160
5227
|
remoteJid,
|
|
5161
5228
|
conn.lidMapping
|
|
5162
5229
|
);
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
msg,
|
|
5168
|
-
conn.sock,
|
|
5169
|
-
conn.platformAccountId,
|
|
5170
|
-
`whatsapp-live:${conn.accountId}:${canonicalRemoteJid}:${msg.key.id}`,
|
|
5171
|
-
{ maxBytes: maxMb * 1024 * 1024 }
|
|
5172
|
-
) ?? void 0;
|
|
5173
|
-
}
|
|
5174
|
-
await persistWhatsAppMessage({
|
|
5230
|
+
const wantsServableMedia = mediaServable && !fromMe && !!conn.sock;
|
|
5231
|
+
const mediaSeed = `whatsapp-live:${conn.accountId}:${canonicalRemoteJid}:${msg.key.id}`;
|
|
5232
|
+
const maxBytes = (whatsAppConfig.mediaMaxMb ?? 50) * 1024 * 1024;
|
|
5233
|
+
const basePersist = {
|
|
5175
5234
|
accountId: conn.accountId,
|
|
5176
5235
|
platformAccountId: conn.platformAccountId,
|
|
5177
5236
|
remoteJid,
|
|
@@ -5182,13 +5241,6 @@ function monitorInbound(conn) {
|
|
|
5182
5241
|
fromMe,
|
|
5183
5242
|
senderPhone,
|
|
5184
5243
|
selfPhone: conn.selfPhone,
|
|
5185
|
-
// A stored media message persists the human caption (or empty) plus
|
|
5186
|
-
// the attachment id — the reader shows the inline media, never the
|
|
5187
|
-
// synthetic `[document: …]` / `[sticker]` line. If the store failed
|
|
5188
|
-
// (no id), fall back to the extracted text so a document/sticker
|
|
5189
|
-
// still shows its placeholder rather than a blank bubble.
|
|
5190
|
-
body: mediaAttachmentId ? extracted.caption ?? "" : extracted.text,
|
|
5191
|
-
attachmentId: mediaAttachmentId,
|
|
5192
5244
|
timestamp: ts,
|
|
5193
5245
|
pushName: msg.pushName ?? void 0,
|
|
5194
5246
|
quoted: extracted.quotedMessage ? {
|
|
@@ -5196,13 +5248,64 @@ function monitorInbound(conn) {
|
|
|
5196
5248
|
body: extracted.quotedMessage.text,
|
|
5197
5249
|
sender: extracted.quotedMessage.sender
|
|
5198
5250
|
} : void 0
|
|
5199
|
-
}
|
|
5251
|
+
};
|
|
5252
|
+
if (wantsServableMedia && upsert.type === "append") {
|
|
5253
|
+
const sock2 = conn.sock;
|
|
5254
|
+
const platformAccountId = conn.platformAccountId;
|
|
5255
|
+
const caption = extracted.caption ?? "";
|
|
5256
|
+
const fallbackBody = mediaFallbackBody(extracted);
|
|
5257
|
+
const msgKeyId = msg.key.id;
|
|
5258
|
+
const participant = isGroupJid(remoteJid) ? msg.key.participant ?? void 0 : void 0;
|
|
5259
|
+
const sendReceipts = whatsAppConfig.accounts?.[conn.accountId]?.sendReadReceipts ?? whatsAppConfig.sendReadReceipts ?? true;
|
|
5260
|
+
const sendAppendReceipt = () => {
|
|
5261
|
+
if (sendReceipts && msgKeyId) {
|
|
5262
|
+
sendReadReceipt(sock2, remoteJid, [msgKeyId], participant);
|
|
5263
|
+
}
|
|
5264
|
+
};
|
|
5265
|
+
const accepted = appendMediaQueue.schedule(async () => {
|
|
5266
|
+
const id = await storeInboundMediaServable(msg, sock2, platformAccountId, mediaSeed, { maxBytes }) ?? void 0;
|
|
5267
|
+
const persisted = await persistWhatsAppMessage({
|
|
5268
|
+
...basePersist,
|
|
5269
|
+
body: id ? caption : fallbackBody,
|
|
5270
|
+
attachmentId: id
|
|
5271
|
+
});
|
|
5272
|
+
if (persisted) sendAppendReceipt();
|
|
5273
|
+
});
|
|
5274
|
+
receiptDeferredToWorker = true;
|
|
5275
|
+
if (!accepted) {
|
|
5276
|
+
console.error(
|
|
5277
|
+
`${TAG13} append-media overflow account=${conn.platformAccountId} msgKey=${msgKeyId ?? "?"} \u2014 pending cap ${APPEND_MEDIA_MAX_PENDING} reached, text-fallback persist, inline media shed`
|
|
5278
|
+
);
|
|
5279
|
+
const persisted = await persistWhatsAppMessage({
|
|
5280
|
+
...basePersist,
|
|
5281
|
+
body: fallbackBody,
|
|
5282
|
+
attachmentId: void 0
|
|
5283
|
+
});
|
|
5284
|
+
if (persisted) sendAppendReceipt();
|
|
5285
|
+
}
|
|
5286
|
+
} else {
|
|
5287
|
+
let mediaAttachmentId;
|
|
5288
|
+
if (wantsServableMedia) {
|
|
5289
|
+
mediaAttachmentId = await storeInboundMediaServable(
|
|
5290
|
+
msg,
|
|
5291
|
+
conn.sock,
|
|
5292
|
+
conn.platformAccountId,
|
|
5293
|
+
mediaSeed,
|
|
5294
|
+
{ maxBytes }
|
|
5295
|
+
) ?? void 0;
|
|
5296
|
+
}
|
|
5297
|
+
await persistWhatsAppMessage({
|
|
5298
|
+
...basePersist,
|
|
5299
|
+
body: mediaAttachmentId ? extracted.caption ?? "" : extracted.text,
|
|
5300
|
+
attachmentId: mediaAttachmentId
|
|
5301
|
+
});
|
|
5302
|
+
}
|
|
5200
5303
|
}
|
|
5201
5304
|
}
|
|
5202
5305
|
}
|
|
5203
5306
|
if (upsert.type === "append") {
|
|
5204
5307
|
const sendReceipts = whatsAppConfig.accounts?.[conn.accountId]?.sendReadReceipts ?? whatsAppConfig.sendReadReceipts ?? true;
|
|
5205
|
-
if (sendReceipts && msg.key.id) {
|
|
5308
|
+
if (sendReceipts && msg.key.id && !receiptDeferredToWorker) {
|
|
5206
5309
|
sendReadReceipt(
|
|
5207
5310
|
sock,
|
|
5208
5311
|
remoteJid,
|
|
@@ -9302,15 +9405,28 @@ app4.get("/store-stream", requireAdminSession, (c) => {
|
|
|
9302
9405
|
const startedAt = Date.now();
|
|
9303
9406
|
const lastEventId = c.req.header("Last-Event-ID");
|
|
9304
9407
|
const uploadsBase = resolve12(DATA_ROOT, "accounts", accountId, "uploads");
|
|
9408
|
+
const byMsgKeyId = /* @__PURE__ */ new Map();
|
|
9305
9409
|
const toTurn = (r) => {
|
|
9306
|
-
|
|
9410
|
+
if (!r.body && !r.attachmentId) {
|
|
9411
|
+
console.log(`[wa-reader] op=store-row msgKeyId=${r.msgKeyId} kind=empty textLen=0`);
|
|
9412
|
+
}
|
|
9413
|
+
let turn = {
|
|
9307
9414
|
kind: "whatsapp-persisted",
|
|
9308
9415
|
text: r.body,
|
|
9309
9416
|
ts: r.dateSent,
|
|
9310
9417
|
fromMe: r.fromMe,
|
|
9311
9418
|
senderName: r.senderName,
|
|
9312
|
-
origin: r.origin
|
|
9419
|
+
origin: r.origin,
|
|
9420
|
+
msgKeyId: r.msgKeyId
|
|
9313
9421
|
};
|
|
9422
|
+
if (r.quotedId) {
|
|
9423
|
+
const q = byMsgKeyId.get(r.quotedId);
|
|
9424
|
+
turn = {
|
|
9425
|
+
...turn,
|
|
9426
|
+
quoted: q ? { body: q.body, sender: q.senderName ?? (q.fromMe ? null : q.senderTelephone || null), fromMe: q.fromMe } : { body: "", sender: r.quotedSender, fromMe: false }
|
|
9427
|
+
};
|
|
9428
|
+
console.log(`[wa-reader] op=store-quote msgId=${r.msgKeyId} quoted=${!!q}`);
|
|
9429
|
+
}
|
|
9314
9430
|
if (r.attachmentId) {
|
|
9315
9431
|
const meta = readAttachmentMeta(join14(uploadsBase, r.attachmentId));
|
|
9316
9432
|
if (meta) return { ...turn, attachments: [meta] };
|
|
@@ -9353,6 +9469,7 @@ data: ${JSON.stringify(turn)}
|
|
|
9353
9469
|
}
|
|
9354
9470
|
records.sort((a, b) => a.dateSent.localeCompare(b.dateSent));
|
|
9355
9471
|
const scope = records.length ? records[records.length - 1].scope : "none";
|
|
9472
|
+
for (const m of records) byMsgKeyId.set(m.msgKeyId, m);
|
|
9356
9473
|
for (const m of records) send(toTurn(m), offset);
|
|
9357
9474
|
console.log(
|
|
9358
9475
|
`[wa-reader] op=open remoteJid=${remoteJid} scope=${scope} messages=${records.length} source=store`
|
|
@@ -9373,6 +9490,7 @@ data: ${JSON.stringify(turn)}
|
|
|
9373
9490
|
} catch {
|
|
9374
9491
|
continue;
|
|
9375
9492
|
}
|
|
9493
|
+
byMsgKeyId.set(rec.msgKeyId, rec);
|
|
9376
9494
|
send(toTurn(rec), offset);
|
|
9377
9495
|
n++;
|
|
9378
9496
|
}
|
|
@@ -9425,6 +9543,8 @@ app4.post("/reply", requireAdminSession, async (c) => {
|
|
|
9425
9543
|
let remoteJid;
|
|
9426
9544
|
let text;
|
|
9427
9545
|
let files = [];
|
|
9546
|
+
let fileRefs = [];
|
|
9547
|
+
let quotedId;
|
|
9428
9548
|
if (ct.includes("multipart/form-data")) {
|
|
9429
9549
|
const form = await c.req.formData();
|
|
9430
9550
|
accountIdRaw = form.get("accountId")?.toString();
|
|
@@ -9432,22 +9552,26 @@ app4.post("/reply", requireAdminSession, async (c) => {
|
|
|
9432
9552
|
const t = form.get("text")?.toString();
|
|
9433
9553
|
text = t && t.trim().length ? t : void 0;
|
|
9434
9554
|
files = form.getAll("files").filter((f) => f instanceof File);
|
|
9555
|
+
fileRefs = form.getAll("fileRefs").filter((r) => typeof r === "string" && r.length > 0);
|
|
9556
|
+
quotedId = form.get("quotedId")?.toString() || void 0;
|
|
9435
9557
|
} else {
|
|
9436
9558
|
const body = await c.req.json().catch(() => ({}));
|
|
9437
9559
|
accountIdRaw = typeof body.accountId === "string" ? body.accountId : void 0;
|
|
9438
9560
|
remoteJid = typeof body.remoteJid === "string" ? body.remoteJid : void 0;
|
|
9439
9561
|
text = typeof body.text === "string" && body.text.trim().length ? body.text : void 0;
|
|
9562
|
+
fileRefs = Array.isArray(body.fileRefs) ? body.fileRefs.filter((r) => typeof r === "string" && r.length > 0) : [];
|
|
9563
|
+
quotedId = typeof body.quotedId === "string" && body.quotedId ? body.quotedId : void 0;
|
|
9440
9564
|
}
|
|
9441
|
-
console.log(`${MANUAL_TAG} op=request sendId=${sendId} accountId=${accountIdRaw ?? ""} remoteJid=${remoteJid ?? ""} textLen=${text?.length ?? 0} fileCount=${files.length}`);
|
|
9565
|
+
console.log(`${MANUAL_TAG} op=request sendId=${sendId} accountId=${accountIdRaw ?? ""} remoteJid=${remoteJid ?? ""} textLen=${text?.length ?? 0} fileCount=${files.length} fileRefCount=${fileRefs.length} quoted=${quotedId ?? ""}`);
|
|
9442
9566
|
if (!accountIdRaw || !remoteJid) {
|
|
9443
9567
|
exit("rejected");
|
|
9444
9568
|
return c.json({ error: "accountId and remoteJid are required" }, 400);
|
|
9445
9569
|
}
|
|
9446
|
-
if (!text && files.length === 0) {
|
|
9570
|
+
if (!text && files.length === 0 && fileRefs.length === 0) {
|
|
9447
9571
|
exit("rejected");
|
|
9448
9572
|
return c.json({ error: "nothing to send: provide text or attachments" }, 400);
|
|
9449
9573
|
}
|
|
9450
|
-
if (files.length > MAX_ATTACHMENTS) {
|
|
9574
|
+
if (files.length + fileRefs.length > MAX_ATTACHMENTS) {
|
|
9451
9575
|
exit("rejected");
|
|
9452
9576
|
return c.json({ error: `at most ${MAX_ATTACHMENTS} attachments` }, 400);
|
|
9453
9577
|
}
|
|
@@ -9482,6 +9606,10 @@ app4.post("/reply", requireAdminSession, async (c) => {
|
|
|
9482
9606
|
return c.json({ error: "no existing conversation with this contact", reason: "no-existing-conversation" }, 403);
|
|
9483
9607
|
}
|
|
9484
9608
|
const template = convo[convo.length - 1];
|
|
9609
|
+
const quoteTarget = quotedId ? convo.find((r) => r.msgKeyId === quotedId) : void 0;
|
|
9610
|
+
const replyQuoted = quotedId ? { id: quotedId, remoteJid, fromMe: quoteTarget?.fromMe ?? false, body: quoteTarget?.body ?? "" } : void 0;
|
|
9611
|
+
const quotedSenderForRecord = quoteTarget?.senderName ?? null;
|
|
9612
|
+
if (quotedId) console.log(`${MANUAL_TAG} op=reply-quote sendId=${sendId} target=${quotedId} present=${!!quoteTarget}`);
|
|
9485
9613
|
for (const f of files) {
|
|
9486
9614
|
if (!isMimeAdmitted(f.type, SUPPORTED_MIME_SET)) {
|
|
9487
9615
|
exit("rejected");
|
|
@@ -9492,6 +9620,38 @@ app4.post("/reply", requireAdminSession, async (c) => {
|
|
|
9492
9620
|
return c.json({ error: `"${f.name}" exceeds the 50 MB limit` }, 400);
|
|
9493
9621
|
}
|
|
9494
9622
|
}
|
|
9623
|
+
const resolvedRefs = [];
|
|
9624
|
+
for (const ref of fileRefs) {
|
|
9625
|
+
const resolved = resolveDataPath(ref);
|
|
9626
|
+
const withinOwn = resolved.ok && !crossesForeignAccountPartition(resolved.relative, accountId) && isWithinOwnAccountPartition(resolved.relative, accountId);
|
|
9627
|
+
let absolute = "";
|
|
9628
|
+
let size = -1;
|
|
9629
|
+
if (withinOwn) {
|
|
9630
|
+
absolute = resolved.absolute;
|
|
9631
|
+
try {
|
|
9632
|
+
const st = statSync5(absolute);
|
|
9633
|
+
size = st.isFile() ? st.size : -1;
|
|
9634
|
+
} catch {
|
|
9635
|
+
size = -1;
|
|
9636
|
+
}
|
|
9637
|
+
}
|
|
9638
|
+
const ok = size >= 0;
|
|
9639
|
+
console.log(`${MANUAL_TAG} op=reply-file-ref sendId=${sendId} path=${ref} resolved=${absolute} ok=${ok}`);
|
|
9640
|
+
if (!ok) {
|
|
9641
|
+
exit("rejected");
|
|
9642
|
+
return c.json({ error: `device file not found: ${ref}`, reason: "file-ref-unresolved" }, 404);
|
|
9643
|
+
}
|
|
9644
|
+
if (size > MAX_FILE_BYTES) {
|
|
9645
|
+
exit("rejected");
|
|
9646
|
+
return c.json({ error: `"${basename5(absolute)}" exceeds the 50 MB limit` }, 400);
|
|
9647
|
+
}
|
|
9648
|
+
const mime = detectMimeType(absolute);
|
|
9649
|
+
if (!isMimeAdmitted(mime, SUPPORTED_MIME_SET)) {
|
|
9650
|
+
exit("rejected");
|
|
9651
|
+
return c.json({ error: `unsupported file type: ${mime}` }, 400);
|
|
9652
|
+
}
|
|
9653
|
+
resolvedRefs.push({ absolute, mime });
|
|
9654
|
+
}
|
|
9495
9655
|
const res = resolveSocket(accountId);
|
|
9496
9656
|
if (!res.ok) {
|
|
9497
9657
|
console.log(`${MANUAL_TAG} op=socket sendId=${sendId} accountId=${accountId} result=${res.reason} presentKeys=${res.presentKeys.join(",") || "none"}`);
|
|
@@ -9512,8 +9672,10 @@ app4.post("/reply", requireAdminSession, async (c) => {
|
|
|
9512
9672
|
senderName: null,
|
|
9513
9673
|
remoteJid,
|
|
9514
9674
|
msgKeyId: waMessageId,
|
|
9515
|
-
|
|
9516
|
-
|
|
9675
|
+
// Task 1541 item 8 — persist the quote so it survives reload; toTurn
|
|
9676
|
+
// resolves quotedId to the referenced message's body/sender for render.
|
|
9677
|
+
quotedId: quotedId ?? null,
|
|
9678
|
+
quotedSender: quotedSenderForRecord,
|
|
9517
9679
|
scope: template.scope,
|
|
9518
9680
|
origin: "operator-manual",
|
|
9519
9681
|
createdAt: nowIso,
|
|
@@ -9527,42 +9689,58 @@ app4.post("/reply", requireAdminSession, async (c) => {
|
|
|
9527
9689
|
console.log(`${MANUAL_TAG} op=recorded sendId=${sendId} waMessageId=${waMessageId} present=${present} attachment=${attachmentId ? "yes" : "no"}`);
|
|
9528
9690
|
};
|
|
9529
9691
|
let sent = 0;
|
|
9530
|
-
|
|
9531
|
-
const
|
|
9532
|
-
|
|
9533
|
-
console.log(`${MANUAL_TAG} op=send-fail sendId=${sendId} kind=text error=${r.error ?? ""}`);
|
|
9534
|
-
exit("error");
|
|
9535
|
-
return c.json({ error: r.error ?? "send failed" }, 500);
|
|
9536
|
-
}
|
|
9537
|
-
console.log(`${MANUAL_TAG} op=sent sendId=${sendId} kind=text waMessageId=${r.messageId ?? ""}`);
|
|
9538
|
-
if (r.messageId) record(r.messageId, text);
|
|
9539
|
-
sent++;
|
|
9540
|
-
}
|
|
9541
|
-
for (let i = 0; i < files.length; i++) {
|
|
9542
|
-
const stored = await storeAttachment(accountId, files[i]);
|
|
9543
|
-
console.log(`${MANUAL_TAG} op=staged sendId=${sendId} idx=${i} bytes=${stored.sizeBytes} mime=${stored.mimeType}`);
|
|
9692
|
+
const sendStagedFile = async (file, label) => {
|
|
9693
|
+
const stored = await storeAttachment(accountId, file);
|
|
9694
|
+
console.log(`${MANUAL_TAG} op=staged sendId=${sendId} ${label} bytes=${stored.sizeBytes} mime=${stored.mimeType}`);
|
|
9544
9695
|
const kind = mediaTypeForMime(stored.mimeType);
|
|
9545
9696
|
let mid;
|
|
9546
9697
|
if (kind) {
|
|
9547
|
-
const buffer = Buffer.from(await
|
|
9548
|
-
const r = await sendMediaMessage(res.sock, remoteJid, { type: kind, buffer, mimetype: stored.mimeType, filename: stored.filename, ptt: kind === "audio" }, { accountId: res.accountId });
|
|
9698
|
+
const buffer = Buffer.from(await file.arrayBuffer());
|
|
9699
|
+
const r = await sendMediaMessage(res.sock, remoteJid, { type: kind, buffer, mimetype: stored.mimeType, filename: stored.filename, ptt: kind === "audio" }, { accountId: res.accountId, quoted: replyQuoted });
|
|
9549
9700
|
if (!r.success) {
|
|
9550
|
-
console.log(`${MANUAL_TAG} op=send-fail sendId=${sendId} kind=${kind}
|
|
9551
|
-
|
|
9552
|
-
return c.json({ error: r.error ?? "media send failed" }, 500);
|
|
9701
|
+
console.log(`${MANUAL_TAG} op=send-fail sendId=${sendId} kind=${kind} ${label} error=${r.error ?? ""}`);
|
|
9702
|
+
return { ok: false, status: 500, error: r.error ?? "media send failed" };
|
|
9553
9703
|
}
|
|
9554
9704
|
mid = r.messageId;
|
|
9555
9705
|
} else {
|
|
9556
9706
|
const r = await sendWhatsAppDocument({ to: remoteJid, filePath: stored.storagePath, accountId: res.accountId, maxyAccountId: accountId, platformRoot: PLATFORM_ROOT });
|
|
9557
9707
|
if (!r.ok) {
|
|
9558
|
-
console.log(`${MANUAL_TAG} op=send-fail sendId=${sendId} kind=document
|
|
9559
|
-
|
|
9560
|
-
return c.json({ error: r.error }, r.status);
|
|
9708
|
+
console.log(`${MANUAL_TAG} op=send-fail sendId=${sendId} kind=document ${label} error=${r.error}`);
|
|
9709
|
+
return { ok: false, status: r.status, error: r.error };
|
|
9561
9710
|
}
|
|
9562
9711
|
mid = r.messageId;
|
|
9563
9712
|
}
|
|
9564
|
-
console.log(`${MANUAL_TAG} op=sent sendId=${sendId} kind=${kind ?? "document"}
|
|
9713
|
+
console.log(`${MANUAL_TAG} op=sent sendId=${sendId} kind=${kind ?? "document"} ${label} waMessageId=${mid ?? ""}`);
|
|
9565
9714
|
if (mid) record(mid, "", stored.attachmentId);
|
|
9715
|
+
return { ok: true };
|
|
9716
|
+
};
|
|
9717
|
+
if (text) {
|
|
9718
|
+
const r = await sendTextMessage(res.sock, remoteJid, text, { accountId: res.accountId, quoted: replyQuoted });
|
|
9719
|
+
if (!r.success) {
|
|
9720
|
+
console.log(`${MANUAL_TAG} op=send-fail sendId=${sendId} kind=text error=${r.error ?? ""}`);
|
|
9721
|
+
exit("error");
|
|
9722
|
+
return c.json({ error: r.error ?? "send failed" }, 500);
|
|
9723
|
+
}
|
|
9724
|
+
console.log(`${MANUAL_TAG} op=sent sendId=${sendId} kind=text waMessageId=${r.messageId ?? ""}`);
|
|
9725
|
+
if (r.messageId) record(r.messageId, text);
|
|
9726
|
+
sent++;
|
|
9727
|
+
}
|
|
9728
|
+
for (let i = 0; i < files.length; i++) {
|
|
9729
|
+
const out = await sendStagedFile(files[i], `idx=${i}`);
|
|
9730
|
+
if (!out.ok) {
|
|
9731
|
+
exit("error");
|
|
9732
|
+
return c.json({ error: out.error }, out.status);
|
|
9733
|
+
}
|
|
9734
|
+
sent++;
|
|
9735
|
+
}
|
|
9736
|
+
for (let i = 0; i < resolvedRefs.length; i++) {
|
|
9737
|
+
const { absolute, mime } = resolvedRefs[i];
|
|
9738
|
+
const file = new File([readFileSync15(absolute)], basename5(absolute), { type: mime });
|
|
9739
|
+
const out = await sendStagedFile(file, `ref=${i}`);
|
|
9740
|
+
if (!out.ok) {
|
|
9741
|
+
exit("error");
|
|
9742
|
+
return c.json({ error: out.error }, out.status);
|
|
9743
|
+
}
|
|
9566
9744
|
sent++;
|
|
9567
9745
|
}
|
|
9568
9746
|
exit("delivered");
|
|
@@ -25449,6 +25627,11 @@ app60.get("/data", (c) => {
|
|
|
25449
25627
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
25450
25628
|
return c.html(cachedHtml("data.html"));
|
|
25451
25629
|
});
|
|
25630
|
+
app60.get("/tasks", (c) => {
|
|
25631
|
+
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
25632
|
+
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
25633
|
+
return c.html(cachedHtml("tasks.html"));
|
|
25634
|
+
});
|
|
25452
25635
|
app60.get("/calendar", (c) => {
|
|
25453
25636
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
25454
25637
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{o as e}from"./chunk-Ck5AOu5v.js";import{_ as t,b as n,h as r,w as i,y as a}from"./useSubAccountSwitcher-DyjTbzQR.js";import{C as o}from"./audio-attachment-mime-Cx5d3Jls.js";import{b as s,y as c}from"./AdminShell-BfLQQ27Z.js";import{t as l}from"./Checkbox-BC0c_gbn.js";var u=`admin-landing-redirected`,d=`/graph`;function f(e){return e.variant===`operator`?!1:e.appState===`chat`&&!e.alreadyRedirected}var p=e(i(),1);function m(e=`admin`){let[t,r]=(0,p.useState)(`loading`),[i,a]=(0,p.useState)(``),[c,l]=(0,p.useState)(``),[m,h]=(0,p.useState)(``),[g,_]=(0,p.useState)(!1),[v,y]=(0,p.useState)(!1),[b,x]=(0,p.useState)(!1),[S,C]=(0,p.useState)(!1),[w,T]=(0,p.useState)(!1),[E,D]=(0,p.useState)(null),[O,k]=(0,p.useState)(null),[A,j]=(0,p.useState)(void 0),[M,N]=(0,p.useState)(null),[P,F]=(0,p.useState)(void 0),[I,L]=(0,p.useState)(null),[R,z]=(0,p.useState)(null),[B,V]=(0,p.useState)(void 0),H=(0,p.useRef)(void 0),[U,W]=(0,p.useState)(!1),[G,K]=(0,p.useState)(!0);(0,p.useEffect)(()=>{typeof window>`u`||fetch(`/api/remote-auth/status`).then(e=>e.ok?e.json():null).then(e=>{e?.configured&&W(!0)}).catch(()=>{})},[]);let q=(0,p.useRef)(null),J=(0,p.useRef)(null);(0,p.useEffect)(()=>{async function e(){let e=null;try{e=sessionStorage.getItem(`maxy-admin-session-key`)}catch{}if(!e)return!1;try{let t=await fetch(`/api/admin/session?session_key=${encodeURIComponent(e)}`);if(t.status===401){try{sessionStorage.removeItem(`maxy-admin-session-key`)}catch{}return!1}if(!t.ok)return!1;let n=await t.json();D(n.session_key),z(n.sessionId??null),j(n.businessName),N(n.role??null),F(n.userName===void 0?null:n.userName),L(n.avatar??null);let i=o(n.thinkingView);return H.current=i,V(i),r(`chat`),!0}catch(e){return console.error(`[admin] session restore failed:`,e),!1}}async function t(n=2){try{let i=await fetch(`/api/health`);if(!i.ok){if(n>0)return await new Promise(e=>setTimeout(e,1500)),t(n-1);console.error(`[admin] health check returned ${i.status} after retries`),r(`set-pin`);return}let a=await i.json();if(!a.pin_configured){r(`set-pin`);return}K(!!a.claude_authenticated);let o=!1;try{o=new URLSearchParams(window.location.search).get(`connect`)===`claude`}catch{}if(o){try{let e=new URL(window.location.href);e.searchParams.delete(`connect`),window.history.replaceState(null,``,e.pathname+e.search+e.hash)}catch{}if(!a.claude_authenticated){r(`connect-claude`);return}}if(await e())return;r(`enter-pin`)}catch(e){if(n>0)return await new Promise(e=>setTimeout(e,1500)),t(n-1);console.error(`[admin] health check failed:`,e),r(`set-pin`)}}t()},[]),(0,p.useEffect)(()=>{t===`chat`&&fetch(`/api/admin/claude-info`).then(e=>{if(e.ok)return e.json()}).then(e=>{e&&k(e)}).catch(()=>{})},[t]),(0,p.useEffect)(()=>{if(typeof window>`u`)return;let n=!1;try{n=sessionStorage.getItem(u)===`1`}catch{}if(f({appState:t,alreadyRedirected:n,variant:e})){try{sessionStorage.setItem(u,`1`)}catch{}console.info(`[admin-ui] landing-redirect target=${d}`),window.location.replace(d)}},[t,e]);let Y=(0,p.useRef)(null);(0,p.useEffect)(()=>{if(t!==`chat`)return;let e=setInterval(async()=>{try{let e=await fetch(`/api/health`);if(e.ok){let t=await e.json();K(t.auth_status!==`dead`&&t.auth_status!==`missing`)}}catch{}if(E)try{let e=await fetch(`/api/admin/session?session_key=${encodeURIComponent(E)}`);if(e.status!==401)return;let t=(await e.clone().json().catch(()=>null))?.code??`unknown-401`;if(t===`remote-auth-required`){n(`heartbeat`,`/api/admin/session`);return}console.warn(`[admin-auth] outcome=heartbeat-detected-expiry code=${t}`),Y.current?.()}catch{}},300*1e3);return()=>clearInterval(e)},[t,E]),(0,p.useEffect)(()=>{t===`connect-claude`&&fetch(`/api/health`).then(e=>e.ok?e.json():null).then(e=>{e?.claude_authenticated&&(K(!0),r(`enter-pin`))}).catch(()=>{})},[t]);async function X(e,t){y(!0);try{let i=await fetch(`/api/admin/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:e,...t?{accountId:t}:{}})});if(!i.ok){let e=await i.json().catch(()=>({}));if(i.status===401&&e?.code===`remote-auth-required`){n(`enter-pin`,`/api/admin/session`);return}h(e.error||`Invalid PIN`);return}let s=await i.json();D(s.session_key),z(s.sessionId??null),j(s.businessName),N(s.role??null),F(s.userName===void 0?null:s.userName),L(s.avatar??null);let c=o(s.thinkingView);H.current=c,V(c);try{sessionStorage.setItem(`maxy-admin-session-key`,s.session_key)}catch{}a(``),r(`chat`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1)}}let Z=(0,p.useCallback)(async e=>{if(e.preventDefault(),v)return;h(``);let t=c.trim();if(!t){h(`Please enter your name.`);return}if(i.length<4){h(`PIN must be at least 4 characters.`);return}let o=i;y(!0);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:o,name:t})});if(!e.ok){let t=await e.json().catch(()=>({}));if(e.status===401&&t?.code===`remote-auth-required`){n(`set-pin`,`/api/onboarding/set-pin`);return}if(e.status===409){console.log(`[admin] PIN already configured — re-checking health`);try{let e=await fetch(`/api/health`);if(e.ok){let n=await e.json();n.pin_configured&&n.claude_authenticated?r(`enter-pin`):n.pin_configured?r(`connect-claude`):h(t.error||`Failed to set PIN.`)}else r(`enter-pin`)}catch{r(`enter-pin`)}return}h(t.error||`Failed to set PIN.`);return}let i=await fetch(`/api/health`);if((i.ok?await i.json():null)?.claude_authenticated){await X(o);return}a(``),r(`connect-claude`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1)}},[i,v,c]),Q=(0,p.useCallback)(async e=>{e.preventDefault(),h(``),await X(i)},[i]),ee=(0,p.useCallback)(async()=>{T(!0);try{if(!await s())return console.warn(`[admin-ui] claude-disconnect not verified — credentials may persist; staying put`),!1;K(!1),D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(u)}catch{}return r(`connect-claude`),!0}finally{T(!1)}},[]),$=(0,p.useCallback)(()=>{D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(u)}catch{}a(``),h(``),r(`enter-pin`)},[]);return(0,p.useEffect)(()=>{Y.current=$},[$]),{appState:t,setAppState:r,pin:i,setPin:a,operatorName:c,setOperatorName:l,pinError:m,setPinError:h,showPin:g,setShowPin:_,pinLoading:v,authPolling:b,setAuthPolling:x,authLoading:S,setAuthLoading:C,disconnecting:w,cacheKey:E,setCacheKey:D,claudeInfo:O,setClaudeInfo:k,businessName:A,role:M,userName:P,userAvatar:I,sessionId:R,setSessionId:z,expandAll:B,setExpandAll:V,expandAllDefaultRef:H,remoteAuthEnabled:U,claudeConnected:G,pinInputRef:q,setPinFormRef:J,handleSetPin:Z,handleLogin:Q,handleDisconnect:ee,handleLogout:$}}var h=a();function g({inputRef:e,value:t,onChange:n,onComplete:r,showPin:i,autoFocus:a}){let o=(0,p.useRef)([]);function s(e,r){r.key===`Backspace`?(r.preventDefault(),t[e]?n(t.slice(0,e)+t.slice(e+1)):e>0&&(n(t.slice(0,e-1)+t.slice(e)),o.current[e-1]?.focus())):r.key===`ArrowLeft`&&e>0?o.current[e-1]?.focus():r.key===`ArrowRight`&&e<5?o.current[e+1]?.focus():r.key===`Enter`&&(r.preventDefault(),r.currentTarget.form?.requestSubmit())}function c(e,i){let a=i.nativeEvent.data;if(!a||!/^\d$/.test(a))return;let s=t.split(``);for(s[e]=a;s.length<e;)s.push(``);let c=s.join(``).replace(/\D/g,``).slice(0,6);n(c),c.length===6?r?.(c):e<5&&o.current[e+1]?.focus()}function l(e){e.preventDefault();let t=e.clipboardData.getData(`text`).replace(/\D/g,``).slice(0,6);t&&(n(t),t.length===6?r?.(t):o.current[t.length]?.focus())}return(0,h.jsx)(`div`,{className:`pin-field`,children:Array.from({length:6}).map((n,r)=>(0,h.jsx)(`input`,{ref:t=>{o.current[r]=t,r===0&&e&&(e.current=t)},type:`text`,inputMode:`numeric`,className:`pin-box${t[r]?` pin-box-filled`:``}`,value:t[r]?i?t[r]:`•`:``,onKeyDown:e=>s(r,e),onInput:e=>c(r,e),onPaste:l,onFocus:e=>e.target.select(),autoFocus:a&&r===0,autoComplete:`off`,maxLength:1,"aria-label":`PIN digit ${r+1}`},r))})}function _(e){let{pin:n,setPin:i,showPin:a,setShowPin:o,pinLoading:s,pinError:u,pinInputRef:d,setPinFormRef:f,onSubmit:p,operatorName:m,setOperatorName:_}=e;return(0,h.jsx)(`div`,{className:`connect-page`,children:(0,h.jsxs)(`div`,{className:`connect-content`,children:[(0,h.jsx)(`img`,{src:t,alt:r.productName,className:`connect-logo connect-logo--maxy`}),!r.logoContainsName&&(0,h.jsxs)(`h1`,{className:`connect-title`,children:[`Welcome to `,r.productName]}),(0,h.jsxs)(`p`,{className:`connect-subtitle`,children:[`Tell `,r.productName,` who you are, then choose a PIN.`]}),(0,h.jsxs)(`form`,{ref:f,onSubmit:p,className:`connect-pin-form`,children:[(0,h.jsxs)(`div`,{className:`pin-input-row`,children:[(0,h.jsx)(`input`,{type:`text`,className:`connect-name-input`,placeholder:`Your full name`,value:m,onChange:e=>_(e.target.value),autoComplete:`name`,autoFocus:!0,required:!0,"aria-label":`Your full name`}),(0,h.jsx)(`div`,{style:{width:38,flexShrink:0},"aria-hidden":`true`})]}),(0,h.jsxs)(`div`,{className:`pin-input-row`,children:[(0,h.jsx)(g,{inputRef:d,value:n,onChange:i,onComplete:()=>{},showPin:a}),(0,h.jsx)(c,{variant:`send`,type:`submit`,disabled:!n||!m.trim(),loading:s,"aria-label":`Set PIN`,children:(0,h.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,h.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,h.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,h.jsx)(l,{checked:a,onChange:()=>o(e=>!e),label:`Show PIN`})]}),u&&(0,h.jsx)(`p`,{className:`admin-pin-error`,children:u})]})})}function v(e){let{pin:n,setPin:i,showPin:a,setShowPin:o,pinLoading:s,pinError:u,pinInputRef:d,onSubmit:f,remoteAuthEnabled:p,onSignOutRemote:m}=e;return(0,h.jsxs)(`div`,{className:`connect-page`,children:[p&&m&&(0,h.jsx)(`button`,{type:`button`,className:`connect-signout`,onClick:m,children:`Sign out`}),(0,h.jsxs)(`div`,{className:`connect-content`,children:[(0,h.jsx)(`img`,{src:t,alt:r.productName,className:`connect-logo connect-logo--maxy`}),!r.logoContainsName&&(0,h.jsx)(`h1`,{className:`connect-title`,children:r.productName}),(0,h.jsxs)(`form`,{onSubmit:f,className:`connect-pin-form`,children:[(0,h.jsxs)(`div`,{className:`pin-input-row`,children:[(0,h.jsx)(g,{inputRef:d,value:n,onChange:i,onComplete:()=>{},showPin:a,autoFocus:!0}),(0,h.jsx)(c,{variant:`send`,type:`submit`,disabled:!n,loading:s,children:(0,h.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,h.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,h.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,h.jsx)(`div`,{className:`pin-options`,children:(0,h.jsx)(l,{checked:a,onChange:()=>o(e=>!e),label:`Show PIN`})})]}),u&&(0,h.jsx)(`p`,{className:`admin-pin-error`,children:u})]})]})}function y(e){let{authPolling:n,setAuthPolling:i,authLoading:a,setAuthLoading:o,pinError:s,setPinError:l,setAppState:u}=e,[d,f]=(0,p.useState)(!1),[m,g]=(0,p.useState)(!1),[_,v]=(0,p.useState)(``),[y,b]=(0,p.useState)(``),[x,S]=(0,p.useState)(``);async function C(){S(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`paste-code`,code:y})})).json();e.accepted?(S(`Code submitted. Finishing sign-in…`),b(``)):S(e.error||`Could not submit code.`)}catch(e){console.error(`[admin] paste-code error:`,e),S(`Could not submit code.`)}}async function w(){g(!0),l(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`launch-browser`})})).json();e.launched?f(!0):e.error&&l(e.error)}catch(e){console.error(`[admin] browser launch error:`,e),l(`Could not launch browser.`)}g(!1)}async function T(){o(!0),l(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`})).json();if(e.started){i(!0),f(!0),o(!1),v(e.transport||``);for(let e=0;e<120;e++)if(await new Promise(e=>setTimeout(e,2e3)),(await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`wait`})})).json()).authenticated){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),u(`enter-pin`);return}l(`Timed out waiting for sign-in. Try again.`),i(!1)}else e.error&&l(e.error)}catch(e){console.error(`[admin] auth flow error:`,e),l(`Could not start auth flow.`)}o(!1)}async function E(){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),i(!1),l(``)}return n||d?(0,h.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100dvh`,overflow:`auto`},children:[(0,h.jsxs)(`header`,{className:`chat-header`,style:{paddingBottom:`12px`,flexShrink:0,position:`relative`,maxWidth:`680px`,width:`100%`,margin:`0 auto`,padding:`24px 20px 12px`},children:[n?(0,h.jsx)(`button`,{onClick:E,style:{position:`absolute`,top:`12px`,right:`12px`,background:`none`,border:`none`,color:`#999`,fontSize:`13px`,cursor:`pointer`,padding:`4px 8px`},"aria-label":`Cancel`,children:`✕`}):(0,h.jsx)(`button`,{onClick:()=>f(!1),style:{position:`absolute`,top:`12px`,right:`12px`,background:`none`,border:`none`,color:`#999`,fontSize:`13px`,cursor:`pointer`,padding:`4px 8px`},"aria-label":`Close browser`,children:`✕`}),(0,h.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`chat-logo`}),(0,h.jsx)(`h1`,{className:`chat-tagline`,children:`Connect Claude`}),(0,h.jsx)(`p`,{className:`chat-intro`,children:n?`Sign in and authorize in the browser below.`:`Open your email or prepare your accounts, then sign in.`}),!n&&(0,h.jsx)(`div`,{style:{marginTop:`12px`},children:(0,h.jsx)(c,{variant:`primary`,onClick:T,disabled:a,children:a?(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`})}),n&&_===`native`&&(0,h.jsxs)(`div`,{style:{marginTop:`14px`,maxWidth:`420px`,margin:`14px auto 0`,display:`flex`,flexDirection:`column`,gap:`8px`},children:[(0,h.jsx)(`label`,{style:{fontSize:`12px`,color:`#999`,lineHeight:1.4},children:`If the browser didn't finish sign-in, paste the code or full redirect URL from Claude's page:`}),(0,h.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,h.jsx)(`input`,{type:`text`,value:y,onChange:e=>b(e.target.value),placeholder:`Paste code or redirect URL`,style:{flex:1,padding:`8px 10px`,fontSize:`13px`,border:`1px solid #ccc`,borderRadius:`6px`}}),(0,h.jsx)(c,{variant:`primary`,onClick:C,disabled:!y.trim(),children:`Submit`})]}),x&&(0,h.jsx)(`p`,{style:{fontSize:`12px`,color:`#999`,margin:0},children:x})]})]}),(0,h.jsx)(`div`,{style:{flex:1,display:`flex`,flexDirection:`column`,minHeight:0,gap:`10px`,padding:`0 0 16px`},children:(0,h.jsx)(`iframe`,{src:`/vnc-viewer.html`,style:{flex:1,width:`100%`,minHeight:0,border:`none`,background:`#111`,display:`block`},title:`Claude Sign-in`})}),s&&(0,h.jsx)(`p`,{className:`admin-pin-error`,style:{textAlign:`center`,padding:`0 20px 16px`},children:s})]}):(0,h.jsx)(`div`,{className:`connect-page`,children:(0,h.jsxs)(`div`,{className:`connect-content`,children:[(0,h.jsxs)(`div`,{className:`connect-logos`,children:[(0,h.jsx)(`div`,{className:`connect-logo-wrap`,children:(0,h.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`connect-logo`})}),(0,h.jsx)(`svg`,{className:`connect-arrow`,viewBox:`0 0 48 24`,fill:`none`,xmlns:`http://www.w3.org/2000/svg`,children:(0,h.jsx)(`path`,{d:`M0 12h44m0 0l-8-8m8 8l-8 8`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`})}),(0,h.jsxs)(`div`,{className:`connect-logo-wrap`,children:[(0,h.jsx)(`img`,{src:t,alt:r.productName,className:`connect-logo connect-logo--maxy`}),!r.logoContainsName&&(0,h.jsx)(`span`,{className:`connect-logo-label`,children:r.productName})]})]}),(0,h.jsxs)(`h1`,{className:`connect-title`,children:[`Connect Claude to power `,r.productName]}),(0,h.jsx)(`p`,{className:`connect-subtitle`,children:`Sign in with your Anthropic account to get started.`}),(0,h.jsx)(c,{variant:`primary`,onClick:T,disabled:a,children:a?(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`}),(0,h.jsx)(`p`,{style:{marginTop:`6px`,fontSize:`11px`,color:`#999`,maxWidth:`300px`,textAlign:`center`,lineHeight:`1.4`},children:`First time? You may need to sign into your email and Anthropic account in the browser before connecting.`}),(0,h.jsx)(`button`,{onClick:w,disabled:m,style:{marginTop:`12px`,background:`none`,border:`none`,color:`var(--color-primary, #666)`,fontSize:`13px`,cursor:`pointer`,textDecoration:`underline`,textUnderlineOffset:`3px`},children:m?`Launching…`:`Open browser first`}),s&&(0,h.jsx)(`p`,{className:`admin-pin-error`,children:s})]})})}function b({auth:e}){return e.appState===`loading`?(0,h.jsx)(`div`,{className:`connect-page`}):e.appState===`set-pin`?(0,h.jsx)(_,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,setPinFormRef:e.setPinFormRef,onSubmit:e.handleSetPin,operatorName:e.operatorName,setOperatorName:e.setOperatorName}):e.appState===`connect-claude`?(0,h.jsx)(y,{authPolling:e.authPolling,setAuthPolling:e.setAuthPolling,authLoading:e.authLoading,setAuthLoading:e.setAuthLoading,pinError:e.pinError,setPinError:e.setPinError,setAppState:e.setAppState}):e.appState===`enter-pin`?(0,h.jsx)(v,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,onSubmit:e.handleLogin,remoteAuthEnabled:e.remoteAuthEnabled,onSignOutRemote:()=>{console.info(`[admin-ui] remote-auth sign-out → /__remote-auth/logout`),window.location.href=`/__remote-auth/logout`}}):null}export{m as n,b as t};
|