@rudderhq/server 0.2.5-canary.9 → 0.2.5
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/bootstrap/plugin-host-runtime.d.ts +39 -39
- package/dist/bundled-plugins/plugin-linear/dist/worker.js +101 -147
- package/dist/bundled-plugins/plugin-linear/dist/worker.js.map +2 -2
- package/dist/bundled-plugins/plugin-linear/package.json +1 -1
- package/dist/routes/access-onboarding.helpers.d.ts +142 -0
- package/dist/routes/access-onboarding.helpers.d.ts.map +1 -0
- package/dist/routes/access-onboarding.helpers.js +762 -0
- package/dist/routes/access-onboarding.helpers.js.map +1 -0
- package/dist/routes/access.d.ts +2 -48
- package/dist/routes/access.d.ts.map +1 -1
- package/dist/routes/access.helpers.d.ts +109 -0
- package/dist/routes/access.helpers.d.ts.map +1 -0
- package/dist/routes/access.helpers.js +460 -0
- package/dist/routes/access.helpers.js.map +1 -0
- package/dist/routes/access.js +6 -1218
- package/dist/routes/access.js.map +1 -1
- package/dist/routes/agents.d.ts.map +1 -1
- package/dist/routes/agents.js +55 -1057
- package/dist/routes/agents.js.map +1 -1
- package/dist/routes/agents.management-routes.d.ts +12 -0
- package/dist/routes/agents.management-routes.d.ts.map +1 -0
- package/dist/routes/agents.management-routes.js +1067 -0
- package/dist/routes/agents.management-routes.js.map +1 -0
- package/dist/routes/chats.d.ts.map +1 -1
- package/dist/routes/chats.js +42 -652
- package/dist/routes/chats.js.map +1 -1
- package/dist/routes/chats.stream-routes.d.ts +12 -0
- package/dist/routes/chats.stream-routes.d.ts.map +1 -0
- package/dist/routes/chats.stream-routes.js +666 -0
- package/dist/routes/chats.stream-routes.js.map +1 -0
- package/dist/routes/issues.comments-attachments.d.ts +12 -0
- package/dist/routes/issues.comments-attachments.d.ts.map +1 -0
- package/dist/routes/issues.comments-attachments.js +511 -0
- package/dist/routes/issues.comments-attachments.js.map +1 -0
- package/dist/routes/issues.d.ts.map +1 -1
- package/dist/routes/issues.js +43 -1128
- package/dist/routes/issues.js.map +1 -1
- package/dist/routes/issues.mutations.d.ts +12 -0
- package/dist/routes/issues.mutations.d.ts.map +1 -0
- package/dist/routes/issues.mutations.js +635 -0
- package/dist/routes/issues.mutations.js.map +1 -0
- package/dist/routes/plugins.d.ts.map +1 -1
- package/dist/routes/plugins.js +14 -694
- package/dist/routes/plugins.js.map +1 -1
- package/dist/routes/plugins.operations-routes.d.ts +28 -0
- package/dist/routes/plugins.operations-routes.d.ts.map +1 -0
- package/dist/routes/plugins.operations-routes.js +720 -0
- package/dist/routes/plugins.operations-routes.js.map +1 -0
- package/dist/services/access.d.ts +21 -21
- package/dist/services/activity.d.ts +19 -19
- package/dist/services/agents.d.ts +158 -158
- package/dist/services/approvals.d.ts +29 -29
- package/dist/services/assets.d.ts +8 -8
- package/dist/services/automations.d.ts +41 -27
- package/dist/services/automations.d.ts.map +1 -1
- package/dist/services/automations.js +287 -110
- package/dist/services/automations.js.map +1 -1
- package/dist/services/automations.scheduler.d.ts +9 -0
- package/dist/services/automations.scheduler.d.ts.map +1 -0
- package/dist/services/automations.scheduler.js +101 -0
- package/dist/services/automations.scheduler.js.map +1 -0
- package/dist/services/board-auth.d.ts +32 -32
- package/dist/services/calendar.d.ts +26 -26
- package/dist/services/chat-assistant.d.ts +3 -47
- package/dist/services/chat-assistant.d.ts.map +1 -1
- package/dist/services/chat-assistant.helpers.d.ts +156 -0
- package/dist/services/chat-assistant.helpers.d.ts.map +1 -0
- package/dist/services/chat-assistant.helpers.js +862 -0
- package/dist/services/chat-assistant.helpers.js.map +1 -0
- package/dist/services/chat-assistant.js +2 -861
- package/dist/services/chat-assistant.js.map +1 -1
- package/dist/services/chats.d.ts +149 -247
- package/dist/services/chats.d.ts.map +1 -1
- package/dist/services/chats.helpers.d.ts +117 -0
- package/dist/services/chats.helpers.d.ts.map +1 -0
- package/dist/services/chats.helpers.js +285 -0
- package/dist/services/chats.helpers.js.map +1 -0
- package/dist/services/chats.js +6 -286
- package/dist/services/chats.js.map +1 -1
- package/dist/services/costs.d.ts +8 -8
- package/dist/services/finance.d.ts +18 -18
- package/dist/services/goals.d.ts +30 -30
- package/dist/services/heartbeat.d.ts +3 -1
- package/dist/services/heartbeat.d.ts.map +1 -1
- package/dist/services/heartbeat.js +3 -1
- package/dist/services/heartbeat.js.map +1 -1
- package/dist/services/issue-approvals.d.ts +4 -4
- package/dist/services/issue-review-wakeup.d.ts +3 -3
- package/dist/services/issues.comments-attachments.d.ts +141 -0
- package/dist/services/issues.comments-attachments.d.ts.map +1 -0
- package/dist/services/issues.comments-attachments.js +313 -0
- package/dist/services/issues.comments-attachments.js.map +1 -0
- package/dist/services/issues.d.ts +205 -256
- package/dist/services/issues.d.ts.map +1 -1
- package/dist/services/issues.helpers.d.ts +87 -0
- package/dist/services/issues.helpers.d.ts.map +1 -0
- package/dist/services/issues.helpers.js +270 -0
- package/dist/services/issues.helpers.js.map +1 -0
- package/dist/services/issues.js +5 -569
- package/dist/services/issues.js.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.core.d.ts +210 -0
- package/dist/services/knowledge-portability/organization-portability.core.d.ts.map +1 -0
- package/dist/services/knowledge-portability/organization-portability.core.js +997 -0
- package/dist/services/knowledge-portability/organization-portability.core.js.map +1 -0
- package/dist/services/knowledge-portability/organization-portability.d.ts +6 -28
- package/dist/services/knowledge-portability/organization-portability.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.export.d.ts +24 -0
- package/dist/services/knowledge-portability/organization-portability.export.d.ts.map +1 -0
- package/dist/services/knowledge-portability/organization-portability.export.js +607 -0
- package/dist/services/knowledge-portability/organization-portability.export.js.map +1 -0
- package/dist/services/knowledge-portability/organization-portability.files.d.ts +69 -0
- package/dist/services/knowledge-portability/organization-portability.files.d.ts.map +1 -0
- package/dist/services/knowledge-portability/organization-portability.files.js +597 -0
- package/dist/services/knowledge-portability/organization-portability.files.js.map +1 -0
- package/dist/services/knowledge-portability/organization-portability.import.d.ts +31 -0
- package/dist/services/knowledge-portability/organization-portability.import.d.ts.map +1 -0
- package/dist/services/knowledge-portability/organization-portability.import.js +575 -0
- package/dist/services/knowledge-portability/organization-portability.import.js.map +1 -0
- package/dist/services/knowledge-portability/organization-portability.js +37 -3848
- package/dist/services/knowledge-portability/organization-portability.js.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.package.d.ts +72 -0
- package/dist/services/knowledge-portability/organization-portability.package.d.ts.map +1 -0
- package/dist/services/knowledge-portability/organization-portability.package.js +749 -0
- package/dist/services/knowledge-portability/organization-portability.package.js.map +1 -0
- package/dist/services/knowledge-portability/organization-portability.preview.d.ts +18 -0
- package/dist/services/knowledge-portability/organization-portability.preview.d.ts.map +1 -0
- package/dist/services/knowledge-portability/organization-portability.preview.js +333 -0
- package/dist/services/knowledge-portability/organization-portability.preview.js.map +1 -0
- package/dist/services/knowledge-portability/organization-portability.resolve-source.d.ts +4 -0
- package/dist/services/knowledge-portability/organization-portability.resolve-source.d.ts.map +1 -0
- package/dist/services/knowledge-portability/organization-portability.resolve-source.js +86 -0
- package/dist/services/knowledge-portability/organization-portability.resolve-source.js.map +1 -0
- package/dist/services/knowledge-portability/organization-skills.catalog.d.ts +221 -0
- package/dist/services/knowledge-portability/organization-skills.catalog.d.ts.map +1 -0
- package/dist/services/knowledge-portability/organization-skills.catalog.js +999 -0
- package/dist/services/knowledge-portability/organization-skills.catalog.js.map +1 -0
- package/dist/services/knowledge-portability/organization-skills.d.ts +4 -75
- package/dist/services/knowledge-portability/organization-skills.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.js +11 -2008
- package/dist/services/knowledge-portability/organization-skills.js.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.scans.d.ts +16 -0
- package/dist/services/knowledge-portability/organization-skills.scans.d.ts.map +1 -0
- package/dist/services/knowledge-portability/organization-skills.scans.js +300 -0
- package/dist/services/knowledge-portability/organization-skills.scans.js.map +1 -0
- package/dist/services/knowledge-portability/organization-skills.sources.d.ts +68 -0
- package/dist/services/knowledge-portability/organization-skills.sources.d.ts.map +1 -0
- package/dist/services/knowledge-portability/organization-skills.sources.js +728 -0
- package/dist/services/knowledge-portability/organization-skills.sources.js.map +1 -0
- package/dist/services/messenger.d.ts +2 -2
- package/dist/services/messenger.js +2 -2
- package/dist/services/messenger.js.map +1 -1
- package/dist/services/organization-skills.d.ts +3 -1
- package/dist/services/organization-skills.d.ts.map +1 -1
- package/dist/services/organization-skills.js +3 -1
- package/dist/services/organization-skills.js.map +1 -1
- package/dist/services/orgs.d.ts +9 -9
- package/dist/services/plugin-loader.core.d.ts +14 -0
- package/dist/services/plugin-loader.core.d.ts.map +1 -0
- package/dist/services/plugin-loader.core.js +905 -0
- package/dist/services/plugin-loader.core.js.map +1 -0
- package/dist/services/plugin-loader.d.ts +3 -440
- package/dist/services/plugin-loader.d.ts.map +1 -1
- package/dist/services/plugin-loader.helpers.d.ts +468 -0
- package/dist/services/plugin-loader.helpers.d.ts.map +1 -0
- package/dist/services/plugin-loader.helpers.js +263 -0
- package/dist/services/plugin-loader.helpers.js.map +1 -0
- package/dist/services/plugin-loader.js +3 -1191
- package/dist/services/plugin-loader.js.map +1 -1
- package/dist/services/plugin-loader.worker-paths.d.ts +7 -0
- package/dist/services/plugin-loader.worker-paths.d.ts.map +1 -0
- package/dist/services/plugin-loader.worker-paths.js +85 -0
- package/dist/services/plugin-loader.worker-paths.js.map +1 -0
- package/dist/services/plugin-registry.d.ts +123 -123
- package/dist/services/projects.d.ts +8 -8
- package/dist/services/runtime-kernel/heartbeat.core.d.ts +725 -0
- package/dist/services/runtime-kernel/heartbeat.core.d.ts.map +1 -0
- package/dist/services/runtime-kernel/heartbeat.core.js +525 -0
- package/dist/services/runtime-kernel/heartbeat.core.js.map +1 -0
- package/dist/services/runtime-kernel/heartbeat.d.ts +38 -259
- package/dist/services/runtime-kernel/heartbeat.d.ts.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.execute.d.ts +5 -0
- package/dist/services/runtime-kernel/heartbeat.execute.d.ts.map +1 -0
- package/dist/services/runtime-kernel/heartbeat.execute.js +1052 -0
- package/dist/services/runtime-kernel/heartbeat.execute.js.map +1 -0
- package/dist/services/runtime-kernel/heartbeat.js +50 -4142
- package/dist/services/runtime-kernel/heartbeat.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.misc.d.ts +30 -0
- package/dist/services/runtime-kernel/heartbeat.misc.d.ts.map +1 -0
- package/dist/services/runtime-kernel/heartbeat.misc.js +483 -0
- package/dist/services/runtime-kernel/heartbeat.misc.js.map +1 -0
- package/dist/services/runtime-kernel/heartbeat.recovery.d.ts +38 -0
- package/dist/services/runtime-kernel/heartbeat.recovery.d.ts.map +1 -0
- package/dist/services/runtime-kernel/heartbeat.recovery.js +605 -0
- package/dist/services/runtime-kernel/heartbeat.recovery.js.map +1 -0
- package/dist/services/runtime-kernel/heartbeat.release.d.ts +6 -0
- package/dist/services/runtime-kernel/heartbeat.release.d.ts.map +1 -0
- package/dist/services/runtime-kernel/heartbeat.release.js +398 -0
- package/dist/services/runtime-kernel/heartbeat.release.js.map +1 -0
- package/dist/services/runtime-kernel/heartbeat.sessions.d.ts +229 -0
- package/dist/services/runtime-kernel/heartbeat.sessions.d.ts.map +1 -0
- package/dist/services/runtime-kernel/heartbeat.sessions.js +708 -0
- package/dist/services/runtime-kernel/heartbeat.sessions.js.map +1 -0
- package/dist/services/runtime-kernel/heartbeat.wakeup.d.ts +5 -0
- package/dist/services/runtime-kernel/heartbeat.wakeup.d.ts.map +1 -0
- package/dist/services/runtime-kernel/heartbeat.wakeup.js +552 -0
- package/dist/services/runtime-kernel/heartbeat.wakeup.js.map +1 -0
- package/dist/services/secrets.d.ts +25 -25
- package/dist/services/sidebar-badges.js +1 -1
- package/dist/services/sidebar-badges.js.map +1 -1
- package/dist/services/workspace-runtime.comments.d.ts +6 -0
- package/dist/services/workspace-runtime.comments.d.ts.map +1 -0
- package/dist/services/workspace-runtime.comments.js +17 -0
- package/dist/services/workspace-runtime.comments.js.map +1 -0
- package/dist/services/workspace-runtime.d.ts +4 -163
- package/dist/services/workspace-runtime.d.ts.map +1 -1
- package/dist/services/workspace-runtime.helpers.d.ts +163 -0
- package/dist/services/workspace-runtime.helpers.d.ts.map +1 -0
- package/dist/services/workspace-runtime.helpers.js +360 -0
- package/dist/services/workspace-runtime.helpers.js.map +1 -0
- package/dist/services/workspace-runtime.js +4 -1236
- package/dist/services/workspace-runtime.js.map +1 -1
- package/dist/services/workspace-runtime.lifecycle.d.ts +35 -0
- package/dist/services/workspace-runtime.lifecycle.d.ts.map +1 -0
- package/dist/services/workspace-runtime.lifecycle.js +266 -0
- package/dist/services/workspace-runtime.lifecycle.js.map +1 -0
- package/dist/services/workspace-runtime.services.d.ts +140 -0
- package/dist/services/workspace-runtime.services.d.ts.map +1 -0
- package/dist/services/workspace-runtime.services.js +606 -0
- package/dist/services/workspace-runtime.services.js.map +1 -0
- package/package.json +21 -15
- package/ui-dist/assets/{_basePickBy-B5mJzzqZ.js → _basePickBy-N8I9ml5Y.js} +1 -1
- package/ui-dist/assets/{_baseUniq-B10Ec09o.js → _baseUniq-BuSlpRSQ.js} +1 -1
- package/ui-dist/assets/{arc-Bw7wimOa.js → arc-qX-dPyA1.js} +1 -1
- package/ui-dist/assets/{architectureDiagram-2XIMDMQ5-DZr0XEvv.js → architectureDiagram-2XIMDMQ5-DhjkbXsp.js} +1 -1
- package/ui-dist/assets/{blockDiagram-WCTKOSBZ-D0jl0LgB.js → blockDiagram-WCTKOSBZ-JS-tTu3J.js} +1 -1
- package/ui-dist/assets/{c4Diagram-IC4MRINW-BEFxBnEm.js → c4Diagram-IC4MRINW-4DqwCWIx.js} +1 -1
- package/ui-dist/assets/channel-CccCW5_a.js +1 -0
- package/ui-dist/assets/{chunk-4BX2VUAB-Cbul1GoA.js → chunk-4BX2VUAB-T37SqBpp.js} +1 -1
- package/ui-dist/assets/{chunk-55IACEB6-DuouC3bT.js → chunk-55IACEB6-BSj9hdqK.js} +1 -1
- package/ui-dist/assets/{chunk-FMBD7UC4-bN1jF9xw.js → chunk-FMBD7UC4-Dkrlh0Wk.js} +1 -1
- package/ui-dist/assets/{chunk-JSJVCQXG-B0-Ij6ZF.js → chunk-JSJVCQXG-C0ZE3QdB.js} +1 -1
- package/ui-dist/assets/{chunk-KX2RTZJC-BjI3IEjI.js → chunk-KX2RTZJC-DOZQM9gW.js} +1 -1
- package/ui-dist/assets/{chunk-NQ4KR5QH-MUoGr46n.js → chunk-NQ4KR5QH-5Yr3U2k8.js} +1 -1
- package/ui-dist/assets/{chunk-QZHKN3VN-CQoI9Ouy.js → chunk-QZHKN3VN-CvKTufwF.js} +1 -1
- package/ui-dist/assets/{chunk-WL4C6EOR-DSJh3iDp.js → chunk-WL4C6EOR-IoEM0jyx.js} +1 -1
- package/ui-dist/assets/classDiagram-VBA2DB6C-JKk4tCW2.js +1 -0
- package/ui-dist/assets/classDiagram-v2-RAHNMMFH-JKk4tCW2.js +1 -0
- package/ui-dist/assets/clone-Onaweg8D.js +1 -0
- package/ui-dist/assets/{cose-bilkent-S5V4N54A-BPepglgB.js → cose-bilkent-S5V4N54A-CTvr1OFj.js} +1 -1
- package/ui-dist/assets/{dagre-KLK3FWXG-DhnHVZkt.js → dagre-KLK3FWXG-UZ-SNjVK.js} +1 -1
- package/ui-dist/assets/{diagram-E7M64L7V-DNvXtoOO.js → diagram-E7M64L7V-D7RAN0Hr.js} +1 -1
- package/ui-dist/assets/{diagram-IFDJBPK2-DhGlDTgn.js → diagram-IFDJBPK2-B4LViaFR.js} +1 -1
- package/ui-dist/assets/{diagram-P4PSJMXO-BmXEloWS.js → diagram-P4PSJMXO-CY1be7ak.js} +1 -1
- package/ui-dist/assets/{erDiagram-INFDFZHY-BTYVzaLM.js → erDiagram-INFDFZHY-Dca0KkvJ.js} +1 -1
- package/ui-dist/assets/{flowDiagram-PKNHOUZH-CqMNQUVv.js → flowDiagram-PKNHOUZH-i-qMvfwg.js} +1 -1
- package/ui-dist/assets/{ganttDiagram-A5KZAMGK-B2le_64a.js → ganttDiagram-A5KZAMGK-Wxq2lhbh.js} +1 -1
- package/ui-dist/assets/{gitGraphDiagram-K3NZZRJ6-BtxOBq5A.js → gitGraphDiagram-K3NZZRJ6-DwzgPlAY.js} +1 -1
- package/ui-dist/assets/{graph-C5E6qFfm.js → graph-BAqf89Tz.js} +1 -1
- package/ui-dist/assets/{index-Piq-IPXt.js → index-4eCzaLuY.js} +1 -1
- package/ui-dist/assets/{index-DT6UN2ec.js → index-8uu-nKqK.js} +1 -1
- package/ui-dist/assets/{index-T5NVZ3nR.js → index-B-1NEcI_.js} +1 -1
- package/ui-dist/assets/{index-D-MoarxG.js → index-B0b_3Eu5.js} +1 -1
- package/ui-dist/assets/{index-CZiP3FBQ.js → index-B8v0eZjP.js} +1 -1
- package/ui-dist/assets/{index-C1Ga66FM.js → index-BN7Moj3u.js} +1 -1
- package/ui-dist/assets/{index-xBUfBdQn.js → index-BSpxh3cY.js} +1 -1
- package/ui-dist/assets/{index-CQcMWp51.js → index-BY44RIi9.js} +1 -1
- package/ui-dist/assets/{index-3a93sZNI.js → index-BhyQJhdZ.js} +1 -1
- package/ui-dist/assets/{index-BsVDit5y.js → index-BkPL_iGU.js} +1 -1
- package/ui-dist/assets/{index-88lBSTsW.js → index-BsPfoHXS.js} +1 -1
- package/ui-dist/assets/{index-CyJtcUF0.js → index-BstW7nmv.js} +1 -1
- package/ui-dist/assets/{index-BvZ0Ptfl.js → index-BwB67Zyz.js} +1 -1
- package/ui-dist/assets/index-C2peSkmT.css +1 -0
- package/ui-dist/assets/{index-vkCrQLeX.js → index-C3ktOsS_.js} +1 -1
- package/ui-dist/assets/{index-D2hZpQJT.js → index-CMyABlS-.js} +1 -1
- package/ui-dist/assets/{index-C4WCPEY4.js → index-CyBJ8ujC.js} +1 -1
- package/ui-dist/assets/{index-Bf7NB_lK.js → index-DAxM2W3O.js} +1 -1
- package/ui-dist/assets/{index-Dq7H6-Lm.js → index-DVZXPmhk.js} +1 -1
- package/ui-dist/assets/{index-CskDu6A3.js → index-Dc19uAyw.js} +1 -1
- package/ui-dist/assets/index-DzHrwZu1.js +1511 -0
- package/ui-dist/assets/{index-B20JneLK.js → index-LJuf53Ye.js} +1 -1
- package/ui-dist/assets/{index-D6McTDMQ.js → index-Ugw5VWWz.js} +1 -1
- package/ui-dist/assets/{index-CcVGS6HJ.js → index-YGraEFR7.js} +1 -1
- package/ui-dist/assets/{infoDiagram-LFFYTUFH-BiCCZcIW.js → infoDiagram-LFFYTUFH-jLmDtFVR.js} +1 -1
- package/ui-dist/assets/{ishikawaDiagram-PHBUUO56-BiwBemM5.js → ishikawaDiagram-PHBUUO56-6OGMyLT8.js} +1 -1
- package/ui-dist/assets/{journeyDiagram-4ABVD52K-D8RGr2xl.js → journeyDiagram-4ABVD52K-yQjl6E0t.js} +1 -1
- package/ui-dist/assets/{kanban-definition-K7BYSVSG-C733Fj-E.js → kanban-definition-K7BYSVSG-DkdCeQlS.js} +1 -1
- package/ui-dist/assets/{layout-CM4c3NA_.js → layout-CqSYvZ_w.js} +1 -1
- package/ui-dist/assets/{linear-DzH21Xsf.js → linear-B8xGZaoi.js} +1 -1
- package/ui-dist/assets/{mermaid.core-Z2rpoVP2.js → mermaid.core-AKL_cdyk.js} +4 -4
- package/ui-dist/assets/{mindmap-definition-YRQLILUH-DylLLj9w.js → mindmap-definition-YRQLILUH-Zr-dXC0x.js} +1 -1
- package/ui-dist/assets/{pieDiagram-SKSYHLDU-617wI_rr.js → pieDiagram-SKSYHLDU-BvDAU-Nk.js} +1 -1
- package/ui-dist/assets/{quadrantDiagram-337W2JSQ-lxoCPJIL.js → quadrantDiagram-337W2JSQ-Dn9kM62o.js} +1 -1
- package/ui-dist/assets/{requirementDiagram-Z7DCOOCP-C5XydQ9-.js → requirementDiagram-Z7DCOOCP-GIsIh7Sd.js} +1 -1
- package/ui-dist/assets/{sankeyDiagram-WA2Y5GQK--grmq-Q8.js → sankeyDiagram-WA2Y5GQK-CUCuBkuf.js} +1 -1
- package/ui-dist/assets/{sequenceDiagram-2WXFIKYE-BS2PeYH-.js → sequenceDiagram-2WXFIKYE-MDpUY2HM.js} +1 -1
- package/ui-dist/assets/{stateDiagram-RAJIS63D-CeuZtj2z.js → stateDiagram-RAJIS63D-BymMpuUU.js} +1 -1
- package/ui-dist/assets/stateDiagram-v2-FVOUBMTO-Bi2oCU6d.js +1 -0
- package/ui-dist/assets/{timeline-definition-YZTLITO2-DxHdMpRr.js → timeline-definition-YZTLITO2-B6ofPhhy.js} +1 -1
- package/ui-dist/assets/{treemap-KZPCXAKY-Bv1ZlC5h.js → treemap-KZPCXAKY-DnLO6w1l.js} +1 -1
- package/ui-dist/assets/{vennDiagram-LZ73GAT5-DvpZSXY2.js → vennDiagram-LZ73GAT5-D0MyZIDl.js} +1 -1
- package/ui-dist/assets/{xychartDiagram-JWTSCODW-DttOu1GC.js → xychartDiagram-JWTSCODW-rADY1iUG.js} +1 -1
- package/ui-dist/index.html +2 -2
- package/ui-dist/assets/channel-DGUh6rEi.js +0 -1
- package/ui-dist/assets/classDiagram-VBA2DB6C-1ntk2IOV.js +0 -1
- package/ui-dist/assets/classDiagram-v2-RAHNMMFH-1ntk2IOV.js +0 -1
- package/ui-dist/assets/clone-BpddY88c.js +0 -1
- package/ui-dist/assets/index-C8AD6s7S.js +0 -1510
- package/ui-dist/assets/index-Ded0dPwB.css +0 -1
- package/ui-dist/assets/stateDiagram-v2-FVOUBMTO-DXq0yC5C.js +0 -1
package/dist/routes/access.js
CHANGED
|
@@ -1,1229 +1,17 @@
|
|
|
1
|
-
import { createHash, generateKeyPairSync, randomBytes, timingSafeEqual } from "node:crypto";
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
5
1
|
import { Router } from "express";
|
|
6
2
|
import { and, eq, isNull, desc } from "drizzle-orm";
|
|
7
|
-
import { agentApiKeys,
|
|
8
|
-
import { acceptInviteSchema, createCliAuthChallengeSchema, claimJoinRequestApiKeySchema, createCompanyInviteSchema, createOpenClawInvitePromptSchema, listJoinRequestsQuerySchema, resolveCliAuthChallengeSchema, updateMemberPermissionsSchema, updateUserCompanyAccessSchema
|
|
3
|
+
import { agentApiKeys, invites, joinRequests } from "@rudderhq/db";
|
|
4
|
+
import { acceptInviteSchema, createCliAuthChallengeSchema, claimJoinRequestApiKeySchema, createCompanyInviteSchema, createOpenClawInvitePromptSchema, listJoinRequestsQuerySchema, resolveCliAuthChallengeSchema, updateMemberPermissionsSchema, updateUserCompanyAccessSchema } from "@rudderhq/shared";
|
|
9
5
|
import { forbidden, conflict, notFound, unauthorized, badRequest } from "../errors.js";
|
|
10
6
|
import { logger } from "../middleware/logger.js";
|
|
11
7
|
import { validate } from "../middleware/validate.js";
|
|
12
8
|
import { accessService, agentService, boardAuthService, deduplicateAgentName, logActivity, notifyHireApproved } from "../services/index.js";
|
|
13
9
|
import { assertCompanyAccess } from "./authz.js";
|
|
14
10
|
import { claimBoardOwnership, inspectBoardClaimChallenge } from "../board-claim.js";
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const INVITE_TOKEN_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
20
|
-
const INVITE_TOKEN_SUFFIX_LENGTH = 8;
|
|
21
|
-
const INVITE_TOKEN_MAX_RETRIES = 5;
|
|
22
|
-
const COMPANY_INVITE_TTL_MS = 10 * 60 * 1000;
|
|
23
|
-
function createInviteToken() {
|
|
24
|
-
const bytes = randomBytes(INVITE_TOKEN_SUFFIX_LENGTH);
|
|
25
|
-
let suffix = "";
|
|
26
|
-
for (let idx = 0; idx < INVITE_TOKEN_SUFFIX_LENGTH; idx += 1) {
|
|
27
|
-
suffix += INVITE_TOKEN_ALPHABET[bytes[idx] % INVITE_TOKEN_ALPHABET.length];
|
|
28
|
-
}
|
|
29
|
-
return `${INVITE_TOKEN_PREFIX}${suffix}`;
|
|
30
|
-
}
|
|
31
|
-
function createClaimSecret() {
|
|
32
|
-
return `pcp_claim_${randomBytes(24).toString("hex")}`;
|
|
33
|
-
}
|
|
34
|
-
export function companyInviteExpiresAt(nowMs = Date.now()) {
|
|
35
|
-
return new Date(nowMs + COMPANY_INVITE_TTL_MS);
|
|
36
|
-
}
|
|
37
|
-
function tokenHashesMatch(left, right) {
|
|
38
|
-
const leftBytes = Buffer.from(left, "utf8");
|
|
39
|
-
const rightBytes = Buffer.from(right, "utf8");
|
|
40
|
-
return (leftBytes.length === rightBytes.length &&
|
|
41
|
-
timingSafeEqual(leftBytes, rightBytes));
|
|
42
|
-
}
|
|
43
|
-
function requestBaseUrl(req) {
|
|
44
|
-
const forwardedProto = req.header("x-forwarded-proto");
|
|
45
|
-
const proto = forwardedProto?.split(",")[0]?.trim() || req.protocol || "http";
|
|
46
|
-
const host = req.header("x-forwarded-host")?.split(",")[0]?.trim() || req.header("host");
|
|
47
|
-
if (!host)
|
|
48
|
-
return "";
|
|
49
|
-
return `${proto}://${host}`;
|
|
50
|
-
}
|
|
51
|
-
function buildCliAuthApprovalPath(challengeId, token) {
|
|
52
|
-
return `/cli-auth/${challengeId}?token=${encodeURIComponent(token)}`;
|
|
53
|
-
}
|
|
54
|
-
function readSkillMarkdown(skillName) {
|
|
55
|
-
const normalized = skillName.trim().toLowerCase();
|
|
56
|
-
if (normalized !== "rudder" &&
|
|
57
|
-
normalized !== "rudder-create-agent" &&
|
|
58
|
-
// TODO 2026-04-12 15:42:09: disabled: not used yet; will be re-enabled when plugin scaffold is ready
|
|
59
|
-
// normalized !== "rudder-create-plugin" &&
|
|
60
|
-
normalized !== "para-memory-files")
|
|
61
|
-
return null;
|
|
62
|
-
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
63
|
-
const candidates = [
|
|
64
|
-
path.resolve(moduleDir, "../../resources/bundled-skills", normalized, "SKILL.md"), // published: dist/routes/ -> server/resources/bundled-skills/
|
|
65
|
-
path.resolve(process.cwd(), "server/resources/bundled-skills", normalized, "SKILL.md"), // cwd (e.g. monorepo root)
|
|
66
|
-
path.resolve(moduleDir, "../../../server/resources/bundled-skills", normalized, "SKILL.md"), // dev: src/routes/ -> repo root/server/resources/bundled-skills/
|
|
67
|
-
path.resolve(moduleDir, "../../.agents/skills", normalized, "SKILL.md"), // legacy published fallback
|
|
68
|
-
path.resolve(process.cwd(), ".agents/skills", normalized, "SKILL.md"), // legacy cwd fallback
|
|
69
|
-
path.resolve(moduleDir, "../../../.agents/skills", normalized, "SKILL.md"), // legacy dev fallback
|
|
70
|
-
path.resolve(moduleDir, "../../skills", normalized, "SKILL.md"), // legacy fallback
|
|
71
|
-
path.resolve(process.cwd(), "skills", normalized, "SKILL.md"), // legacy fallback
|
|
72
|
-
path.resolve(moduleDir, "../../../skills", normalized, "SKILL.md"), // legacy fallback
|
|
73
|
-
];
|
|
74
|
-
for (const skillPath of candidates) {
|
|
75
|
-
try {
|
|
76
|
-
return fs.readFileSync(skillPath, "utf8");
|
|
77
|
-
}
|
|
78
|
-
catch {
|
|
79
|
-
// Continue to next candidate.
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
/** Resolve the Rudder repo skill directory (built-in / managed skills). */
|
|
85
|
-
function resolveRudderSkillsDir() {
|
|
86
|
-
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
87
|
-
const candidates = [
|
|
88
|
-
path.resolve(moduleDir, "../../resources/bundled-skills"), // published
|
|
89
|
-
path.resolve(process.cwd(), "server/resources/bundled-skills"), // cwd (monorepo root)
|
|
90
|
-
path.resolve(moduleDir, "../../../server/resources/bundled-skills"), // dev
|
|
91
|
-
path.resolve(moduleDir, "../../.agents/skills"), // legacy published fallback
|
|
92
|
-
path.resolve(process.cwd(), ".agents/skills"), // legacy cwd fallback
|
|
93
|
-
path.resolve(moduleDir, "../../../.agents/skills"), // legacy dev fallback
|
|
94
|
-
path.resolve(moduleDir, "../../skills"), // legacy fallback
|
|
95
|
-
path.resolve(process.cwd(), "skills"), // legacy fallback
|
|
96
|
-
path.resolve(moduleDir, "../../../skills"), // legacy fallback
|
|
97
|
-
];
|
|
98
|
-
for (const candidate of candidates) {
|
|
99
|
-
try {
|
|
100
|
-
if (fs.statSync(candidate).isDirectory())
|
|
101
|
-
return candidate;
|
|
102
|
-
}
|
|
103
|
-
catch { /* skip */ }
|
|
104
|
-
}
|
|
105
|
-
return null;
|
|
106
|
-
}
|
|
107
|
-
/** Parse YAML frontmatter from a SKILL.md file to extract the description. */
|
|
108
|
-
function parseSkillFrontmatter(markdown) {
|
|
109
|
-
const match = markdown.match(/^---\n([\s\S]*?)\n---/);
|
|
110
|
-
if (!match)
|
|
111
|
-
return { description: "" };
|
|
112
|
-
const yaml = match[1];
|
|
113
|
-
// Extract description — handles both single-line and multi-line YAML values
|
|
114
|
-
const descMatch = yaml.match(/^description:\s*(?:>\s*\n((?:\s{2,}[^\n]*\n?)+)|[|]\s*\n((?:\s{2,}[^\n]*\n?)+)|["']?(.*?)["']?\s*$)/m);
|
|
115
|
-
if (!descMatch)
|
|
116
|
-
return { description: "" };
|
|
117
|
-
const raw = descMatch[1] ?? descMatch[2] ?? descMatch[3] ?? "";
|
|
118
|
-
return {
|
|
119
|
-
description: raw
|
|
120
|
-
.split("\n")
|
|
121
|
-
.map((l) => l.trim())
|
|
122
|
-
.filter(Boolean)
|
|
123
|
-
.join(" ")
|
|
124
|
-
.trim(),
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
/** Discover user-installed Claude Code skills from ~/.claude/skills/. */
|
|
128
|
-
function listAvailableSkills() {
|
|
129
|
-
const homeDir = process.env.HOME || process.env.USERPROFILE || "";
|
|
130
|
-
const claudeSkillsDir = path.join(homeDir, ".claude", "skills");
|
|
131
|
-
const rudderSkillsDir = resolveRudderSkillsDir();
|
|
132
|
-
// Build set of Rudder-managed skill names
|
|
133
|
-
const rudderSkillNames = new Set();
|
|
134
|
-
if (rudderSkillsDir) {
|
|
135
|
-
try {
|
|
136
|
-
for (const entry of fs.readdirSync(rudderSkillsDir, { withFileTypes: true })) {
|
|
137
|
-
if (entry.isDirectory())
|
|
138
|
-
rudderSkillNames.add(entry.name);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
catch { /* skip */ }
|
|
142
|
-
}
|
|
143
|
-
const skills = [];
|
|
144
|
-
try {
|
|
145
|
-
const entries = fs.readdirSync(claudeSkillsDir, { withFileTypes: true });
|
|
146
|
-
for (const entry of entries) {
|
|
147
|
-
if (!entry.isDirectory() && !entry.isSymbolicLink())
|
|
148
|
-
continue;
|
|
149
|
-
if (entry.name.startsWith("."))
|
|
150
|
-
continue;
|
|
151
|
-
const skillMdPath = path.join(claudeSkillsDir, entry.name, "SKILL.md");
|
|
152
|
-
let description = "";
|
|
153
|
-
try {
|
|
154
|
-
const md = fs.readFileSync(skillMdPath, "utf8");
|
|
155
|
-
description = parseSkillFrontmatter(md).description;
|
|
156
|
-
}
|
|
157
|
-
catch { /* no SKILL.md or unreadable */ }
|
|
158
|
-
skills.push({
|
|
159
|
-
name: entry.name,
|
|
160
|
-
description,
|
|
161
|
-
isRudderManaged: rudderSkillNames.has(entry.name),
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
catch { /* ~/.claude/skills/ doesn't exist */ }
|
|
166
|
-
skills.sort((a, b) => a.name.localeCompare(b.name));
|
|
167
|
-
return skills;
|
|
168
|
-
}
|
|
169
|
-
function toJoinRequestResponse(row) {
|
|
170
|
-
const { claimSecretHash: _claimSecretHash, ...safe } = row;
|
|
171
|
-
return safe;
|
|
172
|
-
}
|
|
173
|
-
function isPlainObject(value) {
|
|
174
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
175
|
-
}
|
|
176
|
-
function isLoopbackHost(hostname) {
|
|
177
|
-
const value = hostname.trim().toLowerCase();
|
|
178
|
-
return value === "localhost" || value === "127.0.0.1" || value === "::1";
|
|
179
|
-
}
|
|
180
|
-
function normalizeHostname(value) {
|
|
181
|
-
if (!value)
|
|
182
|
-
return null;
|
|
183
|
-
const trimmed = value.trim();
|
|
184
|
-
if (!trimmed)
|
|
185
|
-
return null;
|
|
186
|
-
if (trimmed.startsWith("[")) {
|
|
187
|
-
const end = trimmed.indexOf("]");
|
|
188
|
-
return end > 1
|
|
189
|
-
? trimmed.slice(1, end).toLowerCase()
|
|
190
|
-
: trimmed.toLowerCase();
|
|
191
|
-
}
|
|
192
|
-
const firstColon = trimmed.indexOf(":");
|
|
193
|
-
if (firstColon > -1)
|
|
194
|
-
return trimmed.slice(0, firstColon).toLowerCase();
|
|
195
|
-
return trimmed.toLowerCase();
|
|
196
|
-
}
|
|
197
|
-
function normalizeHeaderValue(value, depth = 0) {
|
|
198
|
-
const direct = nonEmptyTrimmedString(value);
|
|
199
|
-
if (direct)
|
|
200
|
-
return direct;
|
|
201
|
-
if (!isPlainObject(value) || depth >= 3)
|
|
202
|
-
return null;
|
|
203
|
-
const candidateKeys = [
|
|
204
|
-
"value",
|
|
205
|
-
"token",
|
|
206
|
-
"secret",
|
|
207
|
-
"apiKey",
|
|
208
|
-
"api_key",
|
|
209
|
-
"auth",
|
|
210
|
-
"authToken",
|
|
211
|
-
"auth_token",
|
|
212
|
-
"accessToken",
|
|
213
|
-
"access_token",
|
|
214
|
-
"authorization",
|
|
215
|
-
"bearer",
|
|
216
|
-
"header",
|
|
217
|
-
"raw",
|
|
218
|
-
"text",
|
|
219
|
-
"string"
|
|
220
|
-
];
|
|
221
|
-
for (const key of candidateKeys) {
|
|
222
|
-
if (!Object.prototype.hasOwnProperty.call(value, key))
|
|
223
|
-
continue;
|
|
224
|
-
const normalized = normalizeHeaderValue(value[key], depth + 1);
|
|
225
|
-
if (normalized)
|
|
226
|
-
return normalized;
|
|
227
|
-
}
|
|
228
|
-
const entries = Object.entries(value);
|
|
229
|
-
if (entries.length === 1) {
|
|
230
|
-
const [singleKey, singleValue] = entries[0];
|
|
231
|
-
const normalizedKey = singleKey.trim().toLowerCase();
|
|
232
|
-
if (normalizedKey !== "type" &&
|
|
233
|
-
normalizedKey !== "version" &&
|
|
234
|
-
normalizedKey !== "secretid" &&
|
|
235
|
-
normalizedKey !== "secret_id") {
|
|
236
|
-
const normalized = normalizeHeaderValue(singleValue, depth + 1);
|
|
237
|
-
if (normalized)
|
|
238
|
-
return normalized;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
return null;
|
|
242
|
-
}
|
|
243
|
-
function extractHeaderEntries(input) {
|
|
244
|
-
if (isPlainObject(input)) {
|
|
245
|
-
return Object.entries(input);
|
|
246
|
-
}
|
|
247
|
-
if (!Array.isArray(input)) {
|
|
248
|
-
return [];
|
|
249
|
-
}
|
|
250
|
-
const entries = [];
|
|
251
|
-
for (const item of input) {
|
|
252
|
-
if (Array.isArray(item)) {
|
|
253
|
-
const key = nonEmptyTrimmedString(item[0]);
|
|
254
|
-
if (!key)
|
|
255
|
-
continue;
|
|
256
|
-
entries.push([key, item[1]]);
|
|
257
|
-
continue;
|
|
258
|
-
}
|
|
259
|
-
if (!isPlainObject(item))
|
|
260
|
-
continue;
|
|
261
|
-
const mapped = item;
|
|
262
|
-
const explicitKey = nonEmptyTrimmedString(mapped.key) ??
|
|
263
|
-
nonEmptyTrimmedString(mapped.name) ??
|
|
264
|
-
nonEmptyTrimmedString(mapped.header);
|
|
265
|
-
if (explicitKey) {
|
|
266
|
-
const explicitValue = Object.prototype.hasOwnProperty.call(mapped, "value")
|
|
267
|
-
? mapped.value
|
|
268
|
-
: Object.prototype.hasOwnProperty.call(mapped, "token")
|
|
269
|
-
? mapped.token
|
|
270
|
-
: Object.prototype.hasOwnProperty.call(mapped, "secret")
|
|
271
|
-
? mapped.secret
|
|
272
|
-
: mapped;
|
|
273
|
-
entries.push([explicitKey, explicitValue]);
|
|
274
|
-
continue;
|
|
275
|
-
}
|
|
276
|
-
const singleEntry = Object.entries(mapped);
|
|
277
|
-
if (singleEntry.length === 1) {
|
|
278
|
-
entries.push(singleEntry[0]);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
return entries;
|
|
282
|
-
}
|
|
283
|
-
function normalizeHeaderMap(input) {
|
|
284
|
-
const entries = extractHeaderEntries(input);
|
|
285
|
-
if (entries.length === 0)
|
|
286
|
-
return undefined;
|
|
287
|
-
const out = {};
|
|
288
|
-
for (const [key, value] of entries) {
|
|
289
|
-
const normalizedValue = normalizeHeaderValue(value);
|
|
290
|
-
if (!normalizedValue)
|
|
291
|
-
continue;
|
|
292
|
-
const trimmedKey = key.trim();
|
|
293
|
-
const trimmedValue = normalizedValue.trim();
|
|
294
|
-
if (!trimmedKey || !trimmedValue)
|
|
295
|
-
continue;
|
|
296
|
-
out[trimmedKey] = trimmedValue;
|
|
297
|
-
}
|
|
298
|
-
return Object.keys(out).length > 0 ? out : undefined;
|
|
299
|
-
}
|
|
300
|
-
function nonEmptyTrimmedString(value) {
|
|
301
|
-
if (typeof value !== "string")
|
|
302
|
-
return null;
|
|
303
|
-
const trimmed = value.trim();
|
|
304
|
-
return trimmed.length > 0 ? trimmed : null;
|
|
305
|
-
}
|
|
306
|
-
function headerMapHasKeyIgnoreCase(headers, targetKey) {
|
|
307
|
-
const normalizedTarget = targetKey.trim().toLowerCase();
|
|
308
|
-
return Object.keys(headers).some((key) => key.trim().toLowerCase() === normalizedTarget);
|
|
309
|
-
}
|
|
310
|
-
function headerMapGetIgnoreCase(headers, targetKey) {
|
|
311
|
-
const normalizedTarget = targetKey.trim().toLowerCase();
|
|
312
|
-
const key = Object.keys(headers).find((candidate) => candidate.trim().toLowerCase() === normalizedTarget);
|
|
313
|
-
if (!key)
|
|
314
|
-
return null;
|
|
315
|
-
const value = headers[key];
|
|
316
|
-
return typeof value === "string" ? value : null;
|
|
317
|
-
}
|
|
318
|
-
function tokenFromAuthorizationHeader(rawHeader) {
|
|
319
|
-
const trimmed = nonEmptyTrimmedString(rawHeader);
|
|
320
|
-
if (!trimmed)
|
|
321
|
-
return null;
|
|
322
|
-
const bearerMatch = trimmed.match(/^bearer\s+(.+)$/i);
|
|
323
|
-
if (bearerMatch?.[1]) {
|
|
324
|
-
return nonEmptyTrimmedString(bearerMatch[1]);
|
|
325
|
-
}
|
|
326
|
-
return trimmed;
|
|
327
|
-
}
|
|
328
|
-
function parseBooleanLike(value) {
|
|
329
|
-
if (typeof value === "boolean")
|
|
330
|
-
return value;
|
|
331
|
-
if (typeof value !== "string")
|
|
332
|
-
return null;
|
|
333
|
-
const normalized = value.trim().toLowerCase();
|
|
334
|
-
if (normalized === "true" || normalized === "1")
|
|
335
|
-
return true;
|
|
336
|
-
if (normalized === "false" || normalized === "0")
|
|
337
|
-
return false;
|
|
338
|
-
return null;
|
|
339
|
-
}
|
|
340
|
-
function generateEd25519PrivateKeyPem() {
|
|
341
|
-
const generated = generateKeyPairSync("ed25519");
|
|
342
|
-
return generated.privateKey
|
|
343
|
-
.export({ type: "pkcs8", format: "pem" })
|
|
344
|
-
.toString();
|
|
345
|
-
}
|
|
346
|
-
export function buildJoinDefaultsPayloadForAccept(input) {
|
|
347
|
-
if (input.agentRuntimeType !== "openclaw_gateway") {
|
|
348
|
-
return input.defaultsPayload;
|
|
349
|
-
}
|
|
350
|
-
const merged = isPlainObject(input.defaultsPayload)
|
|
351
|
-
? { ...input.defaultsPayload }
|
|
352
|
-
: {};
|
|
353
|
-
if (!nonEmptyTrimmedString(merged.rudderApiUrl)) {
|
|
354
|
-
const legacyPaperclipApiUrl = nonEmptyTrimmedString(input.paperclipApiUrl);
|
|
355
|
-
if (legacyPaperclipApiUrl)
|
|
356
|
-
merged.rudderApiUrl = legacyPaperclipApiUrl;
|
|
357
|
-
}
|
|
358
|
-
const mergedHeaders = normalizeHeaderMap(merged.headers) ?? {};
|
|
359
|
-
const inboundOpenClawAuthHeader = nonEmptyTrimmedString(input.inboundOpenClawAuthHeader);
|
|
360
|
-
const inboundOpenClawTokenHeader = nonEmptyTrimmedString(input.inboundOpenClawTokenHeader);
|
|
361
|
-
if (inboundOpenClawTokenHeader &&
|
|
362
|
-
!headerMapHasKeyIgnoreCase(mergedHeaders, "x-openclaw-token")) {
|
|
363
|
-
mergedHeaders["x-openclaw-token"] = inboundOpenClawTokenHeader;
|
|
364
|
-
}
|
|
365
|
-
if (inboundOpenClawAuthHeader &&
|
|
366
|
-
!headerMapHasKeyIgnoreCase(mergedHeaders, "x-openclaw-auth")) {
|
|
367
|
-
mergedHeaders["x-openclaw-auth"] = inboundOpenClawAuthHeader;
|
|
368
|
-
}
|
|
369
|
-
if (Object.keys(mergedHeaders).length > 0) {
|
|
370
|
-
merged.headers = mergedHeaders;
|
|
371
|
-
}
|
|
372
|
-
else {
|
|
373
|
-
delete merged.headers;
|
|
374
|
-
}
|
|
375
|
-
const discoveredToken = headerMapGetIgnoreCase(mergedHeaders, "x-openclaw-token") ??
|
|
376
|
-
headerMapGetIgnoreCase(mergedHeaders, "x-openclaw-auth") ??
|
|
377
|
-
tokenFromAuthorizationHeader(headerMapGetIgnoreCase(mergedHeaders, "authorization"));
|
|
378
|
-
if (discoveredToken &&
|
|
379
|
-
!headerMapHasKeyIgnoreCase(mergedHeaders, "x-openclaw-token")) {
|
|
380
|
-
mergedHeaders["x-openclaw-token"] = discoveredToken;
|
|
381
|
-
}
|
|
382
|
-
return Object.keys(merged).length > 0 ? merged : null;
|
|
383
|
-
}
|
|
384
|
-
export function mergeJoinDefaultsPayloadForReplay(existingDefaultsPayload, nextDefaultsPayload) {
|
|
385
|
-
if (!isPlainObject(existingDefaultsPayload) &&
|
|
386
|
-
!isPlainObject(nextDefaultsPayload)) {
|
|
387
|
-
return nextDefaultsPayload ?? existingDefaultsPayload;
|
|
388
|
-
}
|
|
389
|
-
if (!isPlainObject(existingDefaultsPayload)) {
|
|
390
|
-
return nextDefaultsPayload;
|
|
391
|
-
}
|
|
392
|
-
if (!isPlainObject(nextDefaultsPayload)) {
|
|
393
|
-
return existingDefaultsPayload;
|
|
394
|
-
}
|
|
395
|
-
const merged = {
|
|
396
|
-
...existingDefaultsPayload,
|
|
397
|
-
...nextDefaultsPayload
|
|
398
|
-
};
|
|
399
|
-
const existingHeaders = normalizeHeaderMap(existingDefaultsPayload.headers);
|
|
400
|
-
const nextHeaders = normalizeHeaderMap(nextDefaultsPayload.headers);
|
|
401
|
-
if (existingHeaders || nextHeaders) {
|
|
402
|
-
merged.headers = {
|
|
403
|
-
...(existingHeaders ?? {}),
|
|
404
|
-
...(nextHeaders ?? {})
|
|
405
|
-
};
|
|
406
|
-
}
|
|
407
|
-
else if (Object.prototype.hasOwnProperty.call(merged, "headers")) {
|
|
408
|
-
delete merged.headers;
|
|
409
|
-
}
|
|
410
|
-
return merged;
|
|
411
|
-
}
|
|
412
|
-
export function canReplayOpenClawGatewayInviteAccept(input) {
|
|
413
|
-
if (input.requestType !== "agent" ||
|
|
414
|
-
input.agentRuntimeType !== "openclaw_gateway") {
|
|
415
|
-
return false;
|
|
416
|
-
}
|
|
417
|
-
if (!input.existingJoinRequest) {
|
|
418
|
-
return false;
|
|
419
|
-
}
|
|
420
|
-
if (input.existingJoinRequest.requestType !== "agent" ||
|
|
421
|
-
input.existingJoinRequest.agentRuntimeType !== "openclaw_gateway") {
|
|
422
|
-
return false;
|
|
423
|
-
}
|
|
424
|
-
return (input.existingJoinRequest.status === "pending_approval" ||
|
|
425
|
-
input.existingJoinRequest.status === "approved");
|
|
426
|
-
}
|
|
427
|
-
function summarizeSecretForLog(value) {
|
|
428
|
-
const trimmed = nonEmptyTrimmedString(value);
|
|
429
|
-
if (!trimmed)
|
|
430
|
-
return null;
|
|
431
|
-
return {
|
|
432
|
-
present: true,
|
|
433
|
-
length: trimmed.length,
|
|
434
|
-
sha256Prefix: hashToken(trimmed).slice(0, 12)
|
|
435
|
-
};
|
|
436
|
-
}
|
|
437
|
-
function summarizeOpenClawGatewayDefaultsForLog(defaultsPayload) {
|
|
438
|
-
const defaults = isPlainObject(defaultsPayload)
|
|
439
|
-
? defaultsPayload
|
|
440
|
-
: null;
|
|
441
|
-
const headers = defaults ? normalizeHeaderMap(defaults.headers) : undefined;
|
|
442
|
-
const gatewayTokenValue = headers
|
|
443
|
-
? headerMapGetIgnoreCase(headers, "x-openclaw-token") ??
|
|
444
|
-
headerMapGetIgnoreCase(headers, "x-openclaw-auth") ??
|
|
445
|
-
tokenFromAuthorizationHeader(headerMapGetIgnoreCase(headers, "authorization"))
|
|
446
|
-
: null;
|
|
447
|
-
return {
|
|
448
|
-
present: Boolean(defaults),
|
|
449
|
-
keys: defaults ? Object.keys(defaults).sort() : [],
|
|
450
|
-
url: defaults ? nonEmptyTrimmedString(defaults.url) : null,
|
|
451
|
-
rudderApiUrl: defaults
|
|
452
|
-
? nonEmptyTrimmedString(defaults.rudderApiUrl)
|
|
453
|
-
: null,
|
|
454
|
-
headerKeys: headers ? Object.keys(headers).sort() : [],
|
|
455
|
-
sessionKeyStrategy: defaults
|
|
456
|
-
? nonEmptyTrimmedString(defaults.sessionKeyStrategy)
|
|
457
|
-
: null,
|
|
458
|
-
disableDeviceAuth: defaults
|
|
459
|
-
? parseBooleanLike(defaults.disableDeviceAuth)
|
|
460
|
-
: null,
|
|
461
|
-
waitTimeoutMs: defaults && typeof defaults.waitTimeoutMs === "number"
|
|
462
|
-
? defaults.waitTimeoutMs
|
|
463
|
-
: null,
|
|
464
|
-
devicePrivateKeyPem: defaults
|
|
465
|
-
? summarizeSecretForLog(defaults.devicePrivateKeyPem)
|
|
466
|
-
: null,
|
|
467
|
-
gatewayToken: summarizeSecretForLog(gatewayTokenValue)
|
|
468
|
-
};
|
|
469
|
-
}
|
|
470
|
-
export function normalizeAgentDefaultsForJoin(input) {
|
|
471
|
-
const fatalErrors = [];
|
|
472
|
-
const diagnostics = [];
|
|
473
|
-
if (input.agentRuntimeType !== "openclaw_gateway") {
|
|
474
|
-
const normalized = isPlainObject(input.defaultsPayload)
|
|
475
|
-
? input.defaultsPayload
|
|
476
|
-
: null;
|
|
477
|
-
return { normalized, diagnostics, fatalErrors };
|
|
478
|
-
}
|
|
479
|
-
if (!isPlainObject(input.defaultsPayload)) {
|
|
480
|
-
diagnostics.push({
|
|
481
|
-
code: "openclaw_gateway_defaults_missing",
|
|
482
|
-
level: "warn",
|
|
483
|
-
message: "No OpenClaw gateway config was provided in agentDefaultsPayload.",
|
|
484
|
-
hint: "Include agentDefaultsPayload.url and headers.x-openclaw-token for OpenClaw gateway joins."
|
|
485
|
-
});
|
|
486
|
-
fatalErrors.push("agentDefaultsPayload is required for agentRuntimeType=openclaw_gateway");
|
|
487
|
-
return {
|
|
488
|
-
normalized: null,
|
|
489
|
-
diagnostics,
|
|
490
|
-
fatalErrors
|
|
491
|
-
};
|
|
492
|
-
}
|
|
493
|
-
const defaults = input.defaultsPayload;
|
|
494
|
-
const normalized = {};
|
|
495
|
-
let gatewayUrl = null;
|
|
496
|
-
const rawGatewayUrl = nonEmptyTrimmedString(defaults.url);
|
|
497
|
-
if (!rawGatewayUrl) {
|
|
498
|
-
diagnostics.push({
|
|
499
|
-
code: "openclaw_gateway_url_missing",
|
|
500
|
-
level: "warn",
|
|
501
|
-
message: "OpenClaw gateway URL is missing.",
|
|
502
|
-
hint: "Set agentDefaultsPayload.url to ws:// or wss:// gateway URL."
|
|
503
|
-
});
|
|
504
|
-
fatalErrors.push("agentDefaultsPayload.url is required");
|
|
505
|
-
}
|
|
506
|
-
else {
|
|
507
|
-
try {
|
|
508
|
-
gatewayUrl = new URL(rawGatewayUrl);
|
|
509
|
-
if (gatewayUrl.protocol !== "ws:" && gatewayUrl.protocol !== "wss:") {
|
|
510
|
-
diagnostics.push({
|
|
511
|
-
code: "openclaw_gateway_url_protocol",
|
|
512
|
-
level: "warn",
|
|
513
|
-
message: `OpenClaw gateway URL must use ws:// or wss:// (got ${gatewayUrl.protocol}).`
|
|
514
|
-
});
|
|
515
|
-
fatalErrors.push("agentDefaultsPayload.url must use ws:// or wss:// for openclaw_gateway");
|
|
516
|
-
}
|
|
517
|
-
else {
|
|
518
|
-
normalized.url = gatewayUrl.toString();
|
|
519
|
-
diagnostics.push({
|
|
520
|
-
code: "openclaw_gateway_url_configured",
|
|
521
|
-
level: "info",
|
|
522
|
-
message: `Gateway endpoint set to ${gatewayUrl.toString()}`
|
|
523
|
-
});
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
catch {
|
|
527
|
-
diagnostics.push({
|
|
528
|
-
code: "openclaw_gateway_url_invalid",
|
|
529
|
-
level: "warn",
|
|
530
|
-
message: `Invalid OpenClaw gateway URL: ${rawGatewayUrl}`
|
|
531
|
-
});
|
|
532
|
-
fatalErrors.push("agentDefaultsPayload.url is not a valid URL");
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
const headers = normalizeHeaderMap(defaults.headers) ?? {};
|
|
536
|
-
const gatewayToken = headerMapGetIgnoreCase(headers, "x-openclaw-token") ??
|
|
537
|
-
headerMapGetIgnoreCase(headers, "x-openclaw-auth") ??
|
|
538
|
-
tokenFromAuthorizationHeader(headerMapGetIgnoreCase(headers, "authorization"));
|
|
539
|
-
if (gatewayToken && !headerMapHasKeyIgnoreCase(headers, "x-openclaw-token")) {
|
|
540
|
-
headers["x-openclaw-token"] = gatewayToken;
|
|
541
|
-
}
|
|
542
|
-
if (Object.keys(headers).length > 0) {
|
|
543
|
-
normalized.headers = headers;
|
|
544
|
-
}
|
|
545
|
-
if (!gatewayToken) {
|
|
546
|
-
diagnostics.push({
|
|
547
|
-
code: "openclaw_gateway_auth_header_missing",
|
|
548
|
-
level: "warn",
|
|
549
|
-
message: "Gateway auth token is missing from agent defaults.",
|
|
550
|
-
hint: "Set agentDefaultsPayload.headers.x-openclaw-token (or legacy x-openclaw-auth)."
|
|
551
|
-
});
|
|
552
|
-
fatalErrors.push("agentDefaultsPayload.headers.x-openclaw-token (or x-openclaw-auth) is required");
|
|
553
|
-
}
|
|
554
|
-
else if (gatewayToken.trim().length < 16) {
|
|
555
|
-
diagnostics.push({
|
|
556
|
-
code: "openclaw_gateway_auth_header_too_short",
|
|
557
|
-
level: "warn",
|
|
558
|
-
message: `Gateway auth token appears too short (${gatewayToken.trim().length} chars).`,
|
|
559
|
-
hint: "Use the full gateway auth token from ~/.openclaw/openclaw.json (typically long random string)."
|
|
560
|
-
});
|
|
561
|
-
fatalErrors.push("agentDefaultsPayload.headers.x-openclaw-token is too short; expected a full gateway token");
|
|
562
|
-
}
|
|
563
|
-
else {
|
|
564
|
-
diagnostics.push({
|
|
565
|
-
code: "openclaw_gateway_auth_header_configured",
|
|
566
|
-
level: "info",
|
|
567
|
-
message: "Gateway auth token configured."
|
|
568
|
-
});
|
|
569
|
-
}
|
|
570
|
-
if (isPlainObject(defaults.payloadTemplate)) {
|
|
571
|
-
normalized.payloadTemplate = defaults.payloadTemplate;
|
|
572
|
-
}
|
|
573
|
-
const parsedDisableDeviceAuth = parseBooleanLike(defaults.disableDeviceAuth);
|
|
574
|
-
const disableDeviceAuth = parsedDisableDeviceAuth === true;
|
|
575
|
-
if (parsedDisableDeviceAuth !== null) {
|
|
576
|
-
normalized.disableDeviceAuth = parsedDisableDeviceAuth;
|
|
577
|
-
}
|
|
578
|
-
const configuredDevicePrivateKeyPem = nonEmptyTrimmedString(defaults.devicePrivateKeyPem);
|
|
579
|
-
if (configuredDevicePrivateKeyPem) {
|
|
580
|
-
normalized.devicePrivateKeyPem = configuredDevicePrivateKeyPem;
|
|
581
|
-
diagnostics.push({
|
|
582
|
-
code: "openclaw_gateway_device_key_configured",
|
|
583
|
-
level: "info",
|
|
584
|
-
message: "Gateway device key configured. Pairing approvals should persist for this agent."
|
|
585
|
-
});
|
|
586
|
-
}
|
|
587
|
-
else if (!disableDeviceAuth) {
|
|
588
|
-
try {
|
|
589
|
-
normalized.devicePrivateKeyPem = generateEd25519PrivateKeyPem();
|
|
590
|
-
diagnostics.push({
|
|
591
|
-
code: "openclaw_gateway_device_key_generated",
|
|
592
|
-
level: "info",
|
|
593
|
-
message: "Generated persistent gateway device key for this join. Pairing approvals should persist for this agent."
|
|
594
|
-
});
|
|
595
|
-
}
|
|
596
|
-
catch (err) {
|
|
597
|
-
diagnostics.push({
|
|
598
|
-
code: "openclaw_gateway_device_key_generate_failed",
|
|
599
|
-
level: "warn",
|
|
600
|
-
message: `Failed to generate gateway device key: ${err instanceof Error ? err.message : String(err)}`,
|
|
601
|
-
hint: "Set agentDefaultsPayload.devicePrivateKeyPem explicitly or set disableDeviceAuth=true."
|
|
602
|
-
});
|
|
603
|
-
fatalErrors.push("Failed to generate gateway device key. Set devicePrivateKeyPem or disableDeviceAuth=true.");
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
const waitTimeoutMs = typeof defaults.waitTimeoutMs === "number" &&
|
|
607
|
-
Number.isFinite(defaults.waitTimeoutMs)
|
|
608
|
-
? Math.floor(defaults.waitTimeoutMs)
|
|
609
|
-
: typeof defaults.waitTimeoutMs === "string"
|
|
610
|
-
? Number.parseInt(defaults.waitTimeoutMs.trim(), 10)
|
|
611
|
-
: NaN;
|
|
612
|
-
if (Number.isFinite(waitTimeoutMs) && waitTimeoutMs > 0) {
|
|
613
|
-
normalized.waitTimeoutMs = waitTimeoutMs;
|
|
614
|
-
}
|
|
615
|
-
const timeoutSec = typeof defaults.timeoutSec === "number" && Number.isFinite(defaults.timeoutSec)
|
|
616
|
-
? Math.floor(defaults.timeoutSec)
|
|
617
|
-
: typeof defaults.timeoutSec === "string"
|
|
618
|
-
? Number.parseInt(defaults.timeoutSec.trim(), 10)
|
|
619
|
-
: NaN;
|
|
620
|
-
if (Number.isFinite(timeoutSec) && timeoutSec > 0) {
|
|
621
|
-
normalized.timeoutSec = timeoutSec;
|
|
622
|
-
}
|
|
623
|
-
const sessionKeyStrategy = nonEmptyTrimmedString(defaults.sessionKeyStrategy);
|
|
624
|
-
if (sessionKeyStrategy === "fixed" ||
|
|
625
|
-
sessionKeyStrategy === "issue" ||
|
|
626
|
-
sessionKeyStrategy === "run") {
|
|
627
|
-
normalized.sessionKeyStrategy = sessionKeyStrategy;
|
|
628
|
-
}
|
|
629
|
-
const sessionKey = nonEmptyTrimmedString(defaults.sessionKey);
|
|
630
|
-
if (sessionKey) {
|
|
631
|
-
normalized.sessionKey = sessionKey;
|
|
632
|
-
}
|
|
633
|
-
const role = nonEmptyTrimmedString(defaults.role);
|
|
634
|
-
if (role) {
|
|
635
|
-
normalized.role = role;
|
|
636
|
-
}
|
|
637
|
-
if (Array.isArray(defaults.scopes)) {
|
|
638
|
-
const scopes = defaults.scopes
|
|
639
|
-
.filter((entry) => typeof entry === "string")
|
|
640
|
-
.map((entry) => entry.trim())
|
|
641
|
-
.filter(Boolean);
|
|
642
|
-
if (scopes.length > 0) {
|
|
643
|
-
normalized.scopes = scopes;
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
const rawPaperclipApiUrl = typeof defaults.rudderApiUrl === "string"
|
|
647
|
-
? defaults.rudderApiUrl.trim()
|
|
648
|
-
: "";
|
|
649
|
-
if (rawPaperclipApiUrl) {
|
|
650
|
-
try {
|
|
651
|
-
const parsedPaperclipApiUrl = new URL(rawPaperclipApiUrl);
|
|
652
|
-
if (parsedPaperclipApiUrl.protocol !== "http:" &&
|
|
653
|
-
parsedPaperclipApiUrl.protocol !== "https:") {
|
|
654
|
-
diagnostics.push({
|
|
655
|
-
code: "openclaw_gateway_paperclip_api_url_protocol",
|
|
656
|
-
level: "warn",
|
|
657
|
-
message: `rudderApiUrl must use http:// or https:// (got ${parsedPaperclipApiUrl.protocol}).`
|
|
658
|
-
});
|
|
659
|
-
}
|
|
660
|
-
else {
|
|
661
|
-
normalized.rudderApiUrl = parsedPaperclipApiUrl.toString();
|
|
662
|
-
diagnostics.push({
|
|
663
|
-
code: "openclaw_gateway_paperclip_api_url_configured",
|
|
664
|
-
level: "info",
|
|
665
|
-
message: `rudderApiUrl set to ${parsedPaperclipApiUrl.toString()}`
|
|
666
|
-
});
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
catch {
|
|
670
|
-
diagnostics.push({
|
|
671
|
-
code: "openclaw_gateway_paperclip_api_url_invalid",
|
|
672
|
-
level: "warn",
|
|
673
|
-
message: `Invalid rudderApiUrl: ${rawPaperclipApiUrl}`
|
|
674
|
-
});
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
return { normalized, diagnostics, fatalErrors };
|
|
678
|
-
}
|
|
679
|
-
function toInviteSummaryResponse(req, token, invite) {
|
|
680
|
-
const baseUrl = requestBaseUrl(req);
|
|
681
|
-
const onboardingPath = `/api/invites/${token}/onboarding`;
|
|
682
|
-
const onboardingTextPath = `/api/invites/${token}/onboarding.txt`;
|
|
683
|
-
const inviteMessage = extractInviteMessage(invite);
|
|
684
|
-
return {
|
|
685
|
-
id: invite.id,
|
|
686
|
-
orgId: invite.orgId,
|
|
687
|
-
inviteType: invite.inviteType,
|
|
688
|
-
allowedJoinTypes: invite.allowedJoinTypes,
|
|
689
|
-
expiresAt: invite.expiresAt,
|
|
690
|
-
onboardingPath,
|
|
691
|
-
onboardingUrl: baseUrl ? `${baseUrl}${onboardingPath}` : onboardingPath,
|
|
692
|
-
onboardingTextPath,
|
|
693
|
-
onboardingTextUrl: baseUrl
|
|
694
|
-
? `${baseUrl}${onboardingTextPath}`
|
|
695
|
-
: onboardingTextPath,
|
|
696
|
-
skillIndexPath: "/api/skills/index",
|
|
697
|
-
skillIndexUrl: baseUrl
|
|
698
|
-
? `${baseUrl}/api/skills/index`
|
|
699
|
-
: "/api/skills/index",
|
|
700
|
-
inviteMessage
|
|
701
|
-
};
|
|
702
|
-
}
|
|
703
|
-
function buildOnboardingDiscoveryDiagnostics(input) {
|
|
704
|
-
const diagnostics = [];
|
|
705
|
-
let apiHost = null;
|
|
706
|
-
if (input.apiBaseUrl) {
|
|
707
|
-
try {
|
|
708
|
-
apiHost = normalizeHostname(new URL(input.apiBaseUrl).hostname);
|
|
709
|
-
}
|
|
710
|
-
catch {
|
|
711
|
-
apiHost = null;
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
const bindHost = normalizeHostname(input.bindHost);
|
|
715
|
-
const allowSet = new Set(input.allowedHostnames
|
|
716
|
-
.map((entry) => normalizeHostname(entry))
|
|
717
|
-
.filter((entry) => Boolean(entry)));
|
|
718
|
-
if (apiHost && isLoopbackHost(apiHost)) {
|
|
719
|
-
diagnostics.push({
|
|
720
|
-
code: "openclaw_onboarding_api_loopback",
|
|
721
|
-
level: "warn",
|
|
722
|
-
message: "Onboarding URL resolves to loopback hostname. Remote OpenClaw agents cannot reach localhost on your Rudder host.",
|
|
723
|
-
hint: "Use a reachable hostname/IP (for example Tailscale hostname, Docker host alias, or public domain)."
|
|
724
|
-
});
|
|
725
|
-
}
|
|
726
|
-
if (input.deploymentMode === "authenticated" &&
|
|
727
|
-
input.deploymentExposure === "private" &&
|
|
728
|
-
(!bindHost || isLoopbackHost(bindHost))) {
|
|
729
|
-
diagnostics.push({
|
|
730
|
-
code: "openclaw_onboarding_private_loopback_bind",
|
|
731
|
-
level: "warn",
|
|
732
|
-
message: "Rudder is bound to loopback in authenticated/private mode.",
|
|
733
|
-
hint: "Run with a reachable bind host or use pnpm dev --tailscale-auth for private-network onboarding."
|
|
734
|
-
});
|
|
735
|
-
}
|
|
736
|
-
if (input.deploymentMode === "authenticated" &&
|
|
737
|
-
input.deploymentExposure === "private" &&
|
|
738
|
-
apiHost &&
|
|
739
|
-
!isLoopbackHost(apiHost) &&
|
|
740
|
-
allowSet.size > 0 &&
|
|
741
|
-
!allowSet.has(apiHost)) {
|
|
742
|
-
diagnostics.push({
|
|
743
|
-
code: "openclaw_onboarding_private_host_not_allowed",
|
|
744
|
-
level: "warn",
|
|
745
|
-
message: `Onboarding host "${apiHost}" is not in allowed hostnames for authenticated/private mode.`,
|
|
746
|
-
hint: `Run pnpm rudder allowed-hostname ${apiHost}`
|
|
747
|
-
});
|
|
748
|
-
}
|
|
749
|
-
return diagnostics;
|
|
750
|
-
}
|
|
751
|
-
function buildOnboardingConnectionCandidates(input) {
|
|
752
|
-
let base = null;
|
|
753
|
-
try {
|
|
754
|
-
if (input.apiBaseUrl) {
|
|
755
|
-
base = new URL(input.apiBaseUrl);
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
catch {
|
|
759
|
-
base = null;
|
|
760
|
-
}
|
|
761
|
-
const protocol = base?.protocol ?? "http:";
|
|
762
|
-
const port = base?.port ? `:${base.port}` : "";
|
|
763
|
-
const candidates = new Set();
|
|
764
|
-
if (base) {
|
|
765
|
-
candidates.add(base.origin);
|
|
766
|
-
}
|
|
767
|
-
const bindHost = normalizeHostname(input.bindHost);
|
|
768
|
-
if (bindHost && !isLoopbackHost(bindHost)) {
|
|
769
|
-
candidates.add(`${protocol}//${bindHost}${port}`);
|
|
770
|
-
}
|
|
771
|
-
for (const rawHost of input.allowedHostnames) {
|
|
772
|
-
const host = normalizeHostname(rawHost);
|
|
773
|
-
if (!host)
|
|
774
|
-
continue;
|
|
775
|
-
candidates.add(`${protocol}//${host}${port}`);
|
|
776
|
-
}
|
|
777
|
-
if (base && isLoopbackHost(base.hostname)) {
|
|
778
|
-
candidates.add(`${protocol}//host.docker.internal${port}`);
|
|
779
|
-
}
|
|
780
|
-
return Array.from(candidates);
|
|
781
|
-
}
|
|
782
|
-
function buildInviteOnboardingManifest(req, token, invite, opts) {
|
|
783
|
-
const baseUrl = requestBaseUrl(req);
|
|
784
|
-
const skillPath = "/api/skills/rudder";
|
|
785
|
-
const skillUrl = baseUrl ? `${baseUrl}${skillPath}` : skillPath;
|
|
786
|
-
const registrationEndpointPath = `/api/invites/${token}/accept`;
|
|
787
|
-
const registrationEndpointUrl = baseUrl
|
|
788
|
-
? `${baseUrl}${registrationEndpointPath}`
|
|
789
|
-
: registrationEndpointPath;
|
|
790
|
-
const onboardingTextPath = `/api/invites/${token}/onboarding.txt`;
|
|
791
|
-
const onboardingTextUrl = baseUrl
|
|
792
|
-
? `${baseUrl}${onboardingTextPath}`
|
|
793
|
-
: onboardingTextPath;
|
|
794
|
-
const discoveryDiagnostics = buildOnboardingDiscoveryDiagnostics({
|
|
795
|
-
apiBaseUrl: baseUrl,
|
|
796
|
-
deploymentMode: opts.deploymentMode,
|
|
797
|
-
deploymentExposure: opts.deploymentExposure,
|
|
798
|
-
bindHost: opts.bindHost,
|
|
799
|
-
allowedHostnames: opts.allowedHostnames
|
|
800
|
-
});
|
|
801
|
-
const connectionCandidates = buildOnboardingConnectionCandidates({
|
|
802
|
-
apiBaseUrl: baseUrl,
|
|
803
|
-
bindHost: opts.bindHost,
|
|
804
|
-
allowedHostnames: opts.allowedHostnames
|
|
805
|
-
});
|
|
806
|
-
return {
|
|
807
|
-
invite: toInviteSummaryResponse(req, token, invite),
|
|
808
|
-
onboarding: {
|
|
809
|
-
instructions: "Join as an OpenClaw Gateway agent, save your one-time claim secret, wait for board approval, then claim your API key. Save the claim response token to ~/.openclaw/workspace/rudder-claimed-api-key.json and load RUDDER_API_KEY from that file before starting heartbeat loops. You MUST submit agentRuntimeType='openclaw_gateway', set agentDefaultsPayload.url to your ws:// or wss:// OpenClaw gateway endpoint, and include agentDefaultsPayload.headers.x-openclaw-token (or legacy x-openclaw-auth).",
|
|
810
|
-
inviteMessage: extractInviteMessage(invite),
|
|
811
|
-
recommendedAdapterType: "openclaw_gateway",
|
|
812
|
-
requiredFields: {
|
|
813
|
-
requestType: "agent",
|
|
814
|
-
agentName: "Display name for this agent",
|
|
815
|
-
agentRuntimeType: "Use 'openclaw_gateway' for OpenClaw Gateway agents",
|
|
816
|
-
capabilities: "Optional capability summary",
|
|
817
|
-
agentDefaultsPayload: "Adapter config for OpenClaw gateway. MUST include url (ws:// or wss://) and headers.x-openclaw-token (or legacy x-openclaw-auth). Optional fields: rudderApiUrl, waitTimeoutMs, sessionKeyStrategy, sessionKey, role, scopes, disableDeviceAuth, devicePrivateKeyPem."
|
|
818
|
-
},
|
|
819
|
-
registrationEndpoint: {
|
|
820
|
-
method: "POST",
|
|
821
|
-
path: registrationEndpointPath,
|
|
822
|
-
url: registrationEndpointUrl
|
|
823
|
-
},
|
|
824
|
-
claimEndpointTemplate: {
|
|
825
|
-
method: "POST",
|
|
826
|
-
path: "/api/join-requests/{requestId}/claim-api-key",
|
|
827
|
-
body: {
|
|
828
|
-
claimSecret: "one-time claim secret returned when the join request is created"
|
|
829
|
-
}
|
|
830
|
-
},
|
|
831
|
-
connectivity: {
|
|
832
|
-
deploymentMode: opts.deploymentMode,
|
|
833
|
-
deploymentExposure: opts.deploymentExposure,
|
|
834
|
-
bindHost: opts.bindHost,
|
|
835
|
-
allowedHostnames: opts.allowedHostnames,
|
|
836
|
-
connectionCandidates,
|
|
837
|
-
diagnostics: discoveryDiagnostics,
|
|
838
|
-
guidance: opts.deploymentMode === "authenticated" &&
|
|
839
|
-
opts.deploymentExposure === "private"
|
|
840
|
-
? "If OpenClaw runs on another machine, ensure the Rudder hostname is reachable and allowed via `pnpm rudder allowed-hostname <host>`."
|
|
841
|
-
: "Ensure OpenClaw can reach this Rudder API base URL for invite, claim, and skill bootstrap calls."
|
|
842
|
-
},
|
|
843
|
-
textInstructions: {
|
|
844
|
-
path: onboardingTextPath,
|
|
845
|
-
url: onboardingTextUrl,
|
|
846
|
-
contentType: "text/plain"
|
|
847
|
-
},
|
|
848
|
-
skill: {
|
|
849
|
-
name: "rudder",
|
|
850
|
-
path: skillPath,
|
|
851
|
-
url: skillUrl,
|
|
852
|
-
installPath: "~/.openclaw/skills/rudder/SKILL.md"
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
};
|
|
856
|
-
}
|
|
857
|
-
export function buildInviteOnboardingTextDocument(req, token, invite, opts) {
|
|
858
|
-
const manifest = buildInviteOnboardingManifest(req, token, invite, opts);
|
|
859
|
-
const onboarding = manifest.onboarding;
|
|
860
|
-
const diagnostics = Array.isArray(onboarding.connectivity?.diagnostics)
|
|
861
|
-
? onboarding.connectivity.diagnostics
|
|
862
|
-
: [];
|
|
863
|
-
const lines = [];
|
|
864
|
-
const appendBlock = (block) => {
|
|
865
|
-
const trimmed = block.replace(/^\n/, "").replace(/\n\s*$/, "");
|
|
866
|
-
const lineIndentation = trimmed
|
|
867
|
-
.split("\n")
|
|
868
|
-
.filter((line) => line.trim().length > 0)
|
|
869
|
-
.map((line) => line.match(/^(\s*)/)?.[0].length ?? 0);
|
|
870
|
-
const minIndent = lineIndentation.length > 0 ? Math.min(...lineIndentation) : 0;
|
|
871
|
-
for (const line of trimmed.split("\n")) {
|
|
872
|
-
lines.push(line.slice(minIndent));
|
|
873
|
-
}
|
|
874
|
-
};
|
|
875
|
-
appendBlock(`
|
|
876
|
-
# Rudder OpenClaw Gateway Onboarding
|
|
877
|
-
|
|
878
|
-
This document is meant to be readable by both humans and agents.
|
|
879
|
-
|
|
880
|
-
## Invite
|
|
881
|
-
- inviteType: ${invite.inviteType}
|
|
882
|
-
- allowedJoinTypes: ${invite.allowedJoinTypes}
|
|
883
|
-
- expiresAt: ${invite.expiresAt.toISOString()}
|
|
884
|
-
`);
|
|
885
|
-
if (onboarding.inviteMessage) {
|
|
886
|
-
appendBlock(`
|
|
887
|
-
## Message from inviter
|
|
888
|
-
${onboarding.inviteMessage}
|
|
889
|
-
`);
|
|
890
|
-
}
|
|
891
|
-
appendBlock(`
|
|
892
|
-
## Step 0
|
|
893
|
-
|
|
894
|
-
Get the OpenClaw gateway auth token (THIS MUST BE SENT)
|
|
895
|
-
Token lives in:
|
|
896
|
-
|
|
897
|
-
~/.openclaw/openclaw.json -> gateway.auth.token
|
|
898
|
-
Extract:
|
|
899
|
-
|
|
900
|
-
TOKEN="$(node -p 'require(process.env.HOME+\"/.openclaw/openclaw.json\").gateway.auth.token')"
|
|
901
|
-
test -n "$TOKEN" || (echo "Missing TOKEN" && exit 1)
|
|
902
|
-
test "\${#TOKEN}" -ge 16 || (echo "Gateway token unexpectedly short (\${#TOKEN})" && exit 1)
|
|
903
|
-
|
|
904
|
-
3) IMPORTANT: Don't accidentally drop the token when generating JSON
|
|
905
|
-
If you build JSON with Node, pass the token explicitly (argv), don't rely on an un-exported env var.
|
|
906
|
-
|
|
907
|
-
Safe payload build looks sort of like this (substitute where necessary):
|
|
908
|
-
|
|
909
|
-
BODY="$(node -e '
|
|
910
|
-
const token = process.argv[1];
|
|
911
|
-
if (!token) process.exit(2);
|
|
912
|
-
const body = {
|
|
913
|
-
requestType: "agent",
|
|
914
|
-
agentName: "OpenClaw",
|
|
915
|
-
agentRuntimeType: "openclaw_gateway",
|
|
916
|
-
capabilities: "OpenClaw agent adapter",
|
|
917
|
-
agentDefaultsPayload: {
|
|
918
|
-
url: "ws://127.0.0.1:18789",
|
|
919
|
-
rudderApiUrl: "http://host.docker.internal:3100",
|
|
920
|
-
headers: { "x-openclaw-token": token },
|
|
921
|
-
waitTimeoutMs: 120000,
|
|
922
|
-
sessionKeyStrategy: "issue",
|
|
923
|
-
role: "operator",
|
|
924
|
-
scopes: ["operator.admin"]
|
|
925
|
-
}
|
|
926
|
-
};
|
|
927
|
-
process.stdout.write(JSON.stringify(body));
|
|
928
|
-
' "$TOKEN")"
|
|
929
|
-
|
|
930
|
-
## Step 1: Submit agent join request
|
|
931
|
-
${onboarding.registrationEndpoint.method} ${onboarding.registrationEndpoint.url}
|
|
932
|
-
|
|
933
|
-
IMPORTANT: You MUST include agentDefaultsPayload.headers.x-openclaw-token with your gateway token.
|
|
934
|
-
Legacy x-openclaw-auth is also accepted, but x-openclaw-token is preferred.
|
|
935
|
-
Use agentRuntimeType "openclaw_gateway" and a ws:// or wss:// gateway URL.
|
|
936
|
-
Pairing mode requirement:
|
|
937
|
-
- Keep device auth enabled (recommended). If devicePrivateKeyPem is omitted, Rudder generates and persists one during join so pairing approvals are stable.
|
|
938
|
-
- You may set disableDeviceAuth=true only for special environments that cannot support pairing.
|
|
939
|
-
- First run may return "pairing required" once; approve the pending pairing request in OpenClaw, then retry.
|
|
940
|
-
Do NOT use /v1/responses or /hooks/* in this gateway join flow.
|
|
941
|
-
|
|
942
|
-
Body (JSON):
|
|
943
|
-
{
|
|
944
|
-
"requestType": "agent",
|
|
945
|
-
"agentName": "My OpenClaw Agent",
|
|
946
|
-
"agentRuntimeType": "openclaw_gateway",
|
|
947
|
-
"capabilities": "Optional summary",
|
|
948
|
-
"agentDefaultsPayload": {
|
|
949
|
-
"url": "wss://your-openclaw-gateway.example",
|
|
950
|
-
"rudderApiUrl": "https://rudder-hostname-your-agent-can-reach:3100",
|
|
951
|
-
"headers": { "x-openclaw-token": "replace-me" },
|
|
952
|
-
"waitTimeoutMs": 120000,
|
|
953
|
-
"sessionKeyStrategy": "issue",
|
|
954
|
-
"role": "operator",
|
|
955
|
-
"scopes": ["operator.admin"]
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
Expected response includes:
|
|
960
|
-
- request id
|
|
961
|
-
- one-time claimSecret
|
|
962
|
-
- claimApiKeyPath
|
|
963
|
-
|
|
964
|
-
## Step 2: Wait for board approval
|
|
965
|
-
The board approves the join request in Rudder before key claim is allowed.
|
|
966
|
-
|
|
967
|
-
## Step 3: Claim API key (one-time)
|
|
968
|
-
${onboarding.claimEndpointTemplate.method} /api/join-requests/{requestId}/claim-api-key
|
|
969
|
-
|
|
970
|
-
Body (JSON):
|
|
971
|
-
{
|
|
972
|
-
"claimSecret": "<one-time-claim-secret>"
|
|
973
|
-
}
|
|
974
|
-
|
|
975
|
-
On successful claim, save the full JSON response to:
|
|
976
|
-
|
|
977
|
-
- ~/.openclaw/workspace/rudder-claimed-api-key.json
|
|
978
|
-
chmod 600 ~/.openclaw/workspace/rudder-claimed-api-key.json
|
|
979
|
-
|
|
980
|
-
And set the RUDDER_API_KEY and RUDDER_API_URL in your environment variables as specified here:
|
|
981
|
-
https://docs.openclaw.ai/help/environment
|
|
982
|
-
|
|
983
|
-
e.g.
|
|
984
|
-
|
|
985
|
-
{
|
|
986
|
-
env: {
|
|
987
|
-
RUDDER_API_KEY: "...",
|
|
988
|
-
RUDDER_API_URL: "...",
|
|
989
|
-
},
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
Then set RUDDER_API_KEY and RUDDER_API_URL from the saved token field for every heartbeat run.
|
|
993
|
-
|
|
994
|
-
Important:
|
|
995
|
-
- claim secrets expire
|
|
996
|
-
- claim secrets are single-use
|
|
997
|
-
- claim fails before board approval
|
|
998
|
-
|
|
999
|
-
## Step 4: Install Rudder skill in OpenClaw
|
|
1000
|
-
GET ${onboarding.skill.url}
|
|
1001
|
-
Install path: ${onboarding.skill.installPath}
|
|
1002
|
-
|
|
1003
|
-
Be sure to prepend your RUDDER_API_URL to the top of your skill and note the path to your RUDDER_API_URL
|
|
1004
|
-
|
|
1005
|
-
## Text onboarding URL
|
|
1006
|
-
${onboarding.textInstructions.url}
|
|
1007
|
-
|
|
1008
|
-
## Connectivity guidance
|
|
1009
|
-
${onboarding.connectivity?.guidance ??
|
|
1010
|
-
"Ensure Rudder is reachable from your OpenClaw runtime."}
|
|
1011
|
-
`);
|
|
1012
|
-
const connectionCandidates = Array.isArray(onboarding.connectivity?.connectionCandidates)
|
|
1013
|
-
? onboarding.connectivity.connectionCandidates.filter((entry) => Boolean(entry))
|
|
1014
|
-
: [];
|
|
1015
|
-
if (connectionCandidates.length > 0) {
|
|
1016
|
-
lines.push("## Suggested Rudder base URLs to try");
|
|
1017
|
-
for (const candidate of connectionCandidates) {
|
|
1018
|
-
lines.push(`- ${candidate}`);
|
|
1019
|
-
}
|
|
1020
|
-
appendBlock(`
|
|
1021
|
-
|
|
1022
|
-
Test each candidate with:
|
|
1023
|
-
- GET <candidate>/api/health
|
|
1024
|
-
- set the first reachable candidate as agentDefaultsPayload.rudderApiUrl when submitting your join request
|
|
1025
|
-
|
|
1026
|
-
If none are reachable: ask your human operator for a reachable hostname/address and help them update network configuration.
|
|
1027
|
-
For authenticated/private mode, they may need:
|
|
1028
|
-
- pnpm rudder allowed-hostname <host>
|
|
1029
|
-
- then restart Rudder and retry onboarding.
|
|
1030
|
-
`);
|
|
1031
|
-
}
|
|
1032
|
-
if (diagnostics.length > 0) {
|
|
1033
|
-
lines.push("## Connectivity diagnostics");
|
|
1034
|
-
for (const diag of diagnostics) {
|
|
1035
|
-
lines.push(`- [${diag.level}] ${diag.message}`);
|
|
1036
|
-
if (diag.hint)
|
|
1037
|
-
lines.push(` hint: ${diag.hint}`);
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
appendBlock(`
|
|
1041
|
-
|
|
1042
|
-
## Helpful endpoints
|
|
1043
|
-
${onboarding.registrationEndpoint.path}
|
|
1044
|
-
${onboarding.claimEndpointTemplate.path}
|
|
1045
|
-
${onboarding.skill.path}
|
|
1046
|
-
${manifest.invite.onboardingPath}
|
|
1047
|
-
`);
|
|
1048
|
-
return `${lines.join("\n")}\n`;
|
|
1049
|
-
}
|
|
1050
|
-
function extractInviteMessage(invite) {
|
|
1051
|
-
const rawDefaults = invite.defaultsPayload;
|
|
1052
|
-
if (!rawDefaults ||
|
|
1053
|
-
typeof rawDefaults !== "object" ||
|
|
1054
|
-
Array.isArray(rawDefaults)) {
|
|
1055
|
-
return null;
|
|
1056
|
-
}
|
|
1057
|
-
const rawMessage = rawDefaults.agentMessage;
|
|
1058
|
-
if (typeof rawMessage !== "string") {
|
|
1059
|
-
return null;
|
|
1060
|
-
}
|
|
1061
|
-
const trimmed = rawMessage.trim();
|
|
1062
|
-
return trimmed.length ? trimmed : null;
|
|
1063
|
-
}
|
|
1064
|
-
function mergeInviteDefaults(defaultsPayload, agentMessage) {
|
|
1065
|
-
const merged = defaultsPayload && typeof defaultsPayload === "object"
|
|
1066
|
-
? { ...defaultsPayload }
|
|
1067
|
-
: {};
|
|
1068
|
-
if (agentMessage) {
|
|
1069
|
-
merged.agentMessage = agentMessage;
|
|
1070
|
-
}
|
|
1071
|
-
return Object.keys(merged).length ? merged : null;
|
|
1072
|
-
}
|
|
1073
|
-
function requestIp(req) {
|
|
1074
|
-
const forwarded = req.header("x-forwarded-for");
|
|
1075
|
-
if (forwarded) {
|
|
1076
|
-
const first = forwarded.split(",")[0]?.trim();
|
|
1077
|
-
if (first)
|
|
1078
|
-
return first;
|
|
1079
|
-
}
|
|
1080
|
-
return req.ip || "unknown";
|
|
1081
|
-
}
|
|
1082
|
-
function inviteExpired(invite) {
|
|
1083
|
-
return invite.expiresAt.getTime() <= Date.now();
|
|
1084
|
-
}
|
|
1085
|
-
function isLocalImplicit(req) {
|
|
1086
|
-
return req.actor.type === "board" && req.actor.source === "local_implicit";
|
|
1087
|
-
}
|
|
1088
|
-
async function resolveActorEmail(db, req) {
|
|
1089
|
-
if (isLocalImplicit(req))
|
|
1090
|
-
return "local@rudder.local";
|
|
1091
|
-
const userId = req.actor.userId;
|
|
1092
|
-
if (!userId)
|
|
1093
|
-
return null;
|
|
1094
|
-
const user = await db
|
|
1095
|
-
.select({ email: authUsers.email })
|
|
1096
|
-
.from(authUsers)
|
|
1097
|
-
.where(eq(authUsers.id, userId))
|
|
1098
|
-
.then((rows) => rows[0] ?? null);
|
|
1099
|
-
return user?.email ?? null;
|
|
1100
|
-
}
|
|
1101
|
-
function grantsFromDefaults(defaultsPayload, key) {
|
|
1102
|
-
if (!defaultsPayload || typeof defaultsPayload !== "object")
|
|
1103
|
-
return [];
|
|
1104
|
-
const scoped = defaultsPayload[key];
|
|
1105
|
-
if (!scoped || typeof scoped !== "object")
|
|
1106
|
-
return [];
|
|
1107
|
-
const grants = scoped.grants;
|
|
1108
|
-
if (!Array.isArray(grants))
|
|
1109
|
-
return [];
|
|
1110
|
-
const validPermissionKeys = new Set(PERMISSION_KEYS);
|
|
1111
|
-
const result = [];
|
|
1112
|
-
for (const item of grants) {
|
|
1113
|
-
if (!item || typeof item !== "object")
|
|
1114
|
-
continue;
|
|
1115
|
-
const record = item;
|
|
1116
|
-
if (typeof record.permissionKey !== "string")
|
|
1117
|
-
continue;
|
|
1118
|
-
if (!validPermissionKeys.has(record.permissionKey))
|
|
1119
|
-
continue;
|
|
1120
|
-
result.push({
|
|
1121
|
-
permissionKey: record.permissionKey,
|
|
1122
|
-
scope: record.scope &&
|
|
1123
|
-
typeof record.scope === "object" &&
|
|
1124
|
-
!Array.isArray(record.scope)
|
|
1125
|
-
? record.scope
|
|
1126
|
-
: null
|
|
1127
|
-
});
|
|
1128
|
-
}
|
|
1129
|
-
return result;
|
|
1130
|
-
}
|
|
1131
|
-
export function resolveJoinRequestAgentManagerId(candidates) {
|
|
1132
|
-
const ceoCandidates = candidates.filter((candidate) => candidate.role === "ceo");
|
|
1133
|
-
if (ceoCandidates.length === 0)
|
|
1134
|
-
return null;
|
|
1135
|
-
const rootCeo = ceoCandidates.find((candidate) => candidate.reportsTo === null);
|
|
1136
|
-
return (rootCeo ?? ceoCandidates[0] ?? null)?.id ?? null;
|
|
1137
|
-
}
|
|
1138
|
-
function isInviteTokenHashCollisionError(error) {
|
|
1139
|
-
const candidates = [
|
|
1140
|
-
error,
|
|
1141
|
-
error?.cause ?? null
|
|
1142
|
-
];
|
|
1143
|
-
for (const candidate of candidates) {
|
|
1144
|
-
if (!candidate || typeof candidate !== "object")
|
|
1145
|
-
continue;
|
|
1146
|
-
const code = "code" in candidate && typeof candidate.code === "string"
|
|
1147
|
-
? candidate.code
|
|
1148
|
-
: null;
|
|
1149
|
-
const message = "message" in candidate && typeof candidate.message === "string"
|
|
1150
|
-
? candidate.message
|
|
1151
|
-
: "";
|
|
1152
|
-
const constraint = "constraint" in candidate && typeof candidate.constraint === "string"
|
|
1153
|
-
? candidate.constraint
|
|
1154
|
-
: null;
|
|
1155
|
-
if (code !== "23505")
|
|
1156
|
-
continue;
|
|
1157
|
-
if (constraint === "invites_token_hash_unique_idx")
|
|
1158
|
-
return true;
|
|
1159
|
-
if (message.includes("invites_token_hash_unique_idx"))
|
|
1160
|
-
return true;
|
|
1161
|
-
}
|
|
1162
|
-
return false;
|
|
1163
|
-
}
|
|
1164
|
-
function isAbortError(error) {
|
|
1165
|
-
return error instanceof Error && error.name === "AbortError";
|
|
1166
|
-
}
|
|
1167
|
-
async function probeInviteResolutionTarget(url, timeoutMs) {
|
|
1168
|
-
const startedAt = Date.now();
|
|
1169
|
-
const controller = new AbortController();
|
|
1170
|
-
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
1171
|
-
try {
|
|
1172
|
-
const response = await fetch(url, {
|
|
1173
|
-
method: "HEAD",
|
|
1174
|
-
redirect: "manual",
|
|
1175
|
-
signal: controller.signal
|
|
1176
|
-
});
|
|
1177
|
-
const durationMs = Date.now() - startedAt;
|
|
1178
|
-
if (response.ok ||
|
|
1179
|
-
response.status === 401 ||
|
|
1180
|
-
response.status === 403 ||
|
|
1181
|
-
response.status === 404 ||
|
|
1182
|
-
response.status === 405 ||
|
|
1183
|
-
response.status === 422 ||
|
|
1184
|
-
response.status === 500 ||
|
|
1185
|
-
response.status === 501) {
|
|
1186
|
-
return {
|
|
1187
|
-
status: "reachable",
|
|
1188
|
-
method: "HEAD",
|
|
1189
|
-
durationMs,
|
|
1190
|
-
httpStatus: response.status,
|
|
1191
|
-
message: `Webhook endpoint responded to HEAD with HTTP ${response.status}.`
|
|
1192
|
-
};
|
|
1193
|
-
}
|
|
1194
|
-
return {
|
|
1195
|
-
status: "unreachable",
|
|
1196
|
-
method: "HEAD",
|
|
1197
|
-
durationMs,
|
|
1198
|
-
httpStatus: response.status,
|
|
1199
|
-
message: `Webhook endpoint probe returned HTTP ${response.status}.`
|
|
1200
|
-
};
|
|
1201
|
-
}
|
|
1202
|
-
catch (error) {
|
|
1203
|
-
const durationMs = Date.now() - startedAt;
|
|
1204
|
-
if (isAbortError(error)) {
|
|
1205
|
-
return {
|
|
1206
|
-
status: "timeout",
|
|
1207
|
-
method: "HEAD",
|
|
1208
|
-
durationMs,
|
|
1209
|
-
httpStatus: null,
|
|
1210
|
-
message: `Webhook endpoint probe timed out after ${timeoutMs}ms.`
|
|
1211
|
-
};
|
|
1212
|
-
}
|
|
1213
|
-
return {
|
|
1214
|
-
status: "unreachable",
|
|
1215
|
-
method: "HEAD",
|
|
1216
|
-
durationMs,
|
|
1217
|
-
httpStatus: null,
|
|
1218
|
-
message: error instanceof Error
|
|
1219
|
-
? error.message
|
|
1220
|
-
: "Webhook endpoint probe failed."
|
|
1221
|
-
};
|
|
1222
|
-
}
|
|
1223
|
-
finally {
|
|
1224
|
-
clearTimeout(timeout);
|
|
1225
|
-
}
|
|
1226
|
-
}
|
|
11
|
+
import { hashToken, INVITE_TOKEN_MAX_RETRIES, createInviteToken, createClaimSecret, companyInviteExpiresAt, tokenHashesMatch, requestBaseUrl, buildCliAuthApprovalPath, readSkillMarkdown, listAvailableSkills, toJoinRequestResponse, isPlainObject, buildJoinDefaultsPayloadForAccept, mergeJoinDefaultsPayloadForReplay, canReplayOpenClawGatewayInviteAccept, summarizeOpenClawGatewayDefaultsForLog } from "./access.helpers.js";
|
|
12
|
+
import { normalizeAgentDefaultsForJoin, toInviteSummaryResponse, buildInviteOnboardingManifest, buildInviteOnboardingTextDocument, mergeInviteDefaults, requestIp, inviteExpired, isLocalImplicit, resolveActorEmail, grantsFromDefaults, resolveJoinRequestAgentManagerId, isInviteTokenHashCollisionError, probeInviteResolutionTarget } from "./access-onboarding.helpers.js";
|
|
13
|
+
export { companyInviteExpiresAt, buildJoinDefaultsPayloadForAccept, mergeJoinDefaultsPayloadForReplay, canReplayOpenClawGatewayInviteAccept } from "./access.helpers.js";
|
|
14
|
+
export { normalizeAgentDefaultsForJoin, buildInviteOnboardingTextDocument, resolveJoinRequestAgentManagerId } from "./access-onboarding.helpers.js";
|
|
1227
15
|
export function accessRoutes(db, opts) {
|
|
1228
16
|
const router = Router();
|
|
1229
17
|
const access = accessService(db);
|