@rudderhq/server 0.3.6-canary.9 → 0.4.0
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/register-api-routes.d.ts.map +1 -1
- package/dist/bootstrap/register-api-routes.js +2 -0
- package/dist/bootstrap/register-api-routes.js.map +1 -1
- package/dist/bundled-plugins/plugin-linear/dist/worker.js +35 -2
- package/dist/bundled-plugins/plugin-linear/dist/worker.js.map +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +103 -26
- package/dist/index.js.map +1 -1
- package/dist/routes/activity.d.ts +1 -1
- package/dist/routes/activity.d.ts.map +1 -1
- package/dist/routes/activity.js +21 -5
- package/dist/routes/activity.js.map +1 -1
- package/dist/routes/agents.d.ts.map +1 -1
- package/dist/routes/agents.js +254 -4
- package/dist/routes/agents.js.map +1 -1
- package/dist/routes/agents.management-routes.d.ts.map +1 -1
- package/dist/routes/agents.management-routes.js +132 -40
- package/dist/routes/agents.management-routes.js.map +1 -1
- package/dist/routes/automations.d.ts +8 -0
- package/dist/routes/automations.d.ts.map +1 -1
- package/dist/routes/automations.js.map +1 -1
- package/dist/routes/chats.d.ts.map +1 -1
- package/dist/routes/chats.js +228 -115
- package/dist/routes/chats.js.map +1 -1
- package/dist/routes/chats.stream-routes.d.ts.map +1 -1
- package/dist/routes/chats.stream-routes.js +94 -5
- package/dist/routes/chats.stream-routes.js.map +1 -1
- package/dist/routes/issues.comments-attachments.d.ts.map +1 -1
- package/dist/routes/issues.comments-attachments.js +72 -83
- package/dist/routes/issues.comments-attachments.js.map +1 -1
- package/dist/routes/issues.d.ts +8 -0
- package/dist/routes/issues.d.ts.map +1 -1
- package/dist/routes/issues.js +0 -4
- package/dist/routes/issues.js.map +1 -1
- package/dist/routes/issues.mutations.d.ts.map +1 -1
- package/dist/routes/issues.mutations.js +2 -26
- package/dist/routes/issues.mutations.js.map +1 -1
- package/dist/routes/messenger.d.ts.map +1 -1
- package/dist/routes/messenger.js +33 -1
- package/dist/routes/messenger.js.map +1 -1
- package/dist/routes/orgs.d.ts.map +1 -1
- package/dist/routes/orgs.js +16 -0
- package/dist/routes/orgs.js.map +1 -1
- package/dist/routes/plugin-ui-static.d.ts +4 -4
- package/dist/routes/plugin-ui-static.js +5 -5
- package/dist/routes/plugin-ui-static.js.map +1 -1
- package/dist/routes/plugins.d.ts +4 -4
- package/dist/routes/plugins.js +10 -10
- package/dist/routes/plugins.operations-routes.d.ts +1 -1
- package/dist/routes/plugins.operations-routes.js +2 -2
- package/dist/routes/plugins.operations-routes.js.map +1 -1
- package/dist/routes/run-intelligence.js +5 -5
- package/dist/routes/run-intelligence.js.map +1 -1
- package/dist/routes/website-metadata.d.ts +8 -0
- package/dist/routes/website-metadata.d.ts.map +1 -0
- package/dist/routes/website-metadata.js +67 -0
- package/dist/routes/website-metadata.js.map +1 -0
- package/dist/services/activity.d.ts.map +1 -1
- package/dist/services/activity.js +1 -1
- package/dist/services/activity.js.map +1 -1
- package/dist/services/agent-instructions.d.ts +1 -0
- package/dist/services/agent-instructions.d.ts.map +1 -1
- package/dist/services/agent-instructions.js +57 -6
- package/dist/services/agent-instructions.js.map +1 -1
- package/dist/services/agent-run-context.d.ts +3 -1
- package/dist/services/agent-run-context.d.ts.map +1 -1
- package/dist/services/agent-run-context.js +7 -0
- package/dist/services/agent-run-context.js.map +1 -1
- package/dist/services/agent-startup-context.d.ts +2 -1
- package/dist/services/agent-startup-context.d.ts.map +1 -1
- package/dist/services/agent-startup-context.js +6 -26
- package/dist/services/agent-startup-context.js.map +1 -1
- package/dist/services/agents.d.ts +9 -1
- package/dist/services/agents.d.ts.map +1 -1
- package/dist/services/agents.js.map +1 -1
- package/dist/services/approvals.d.ts +8 -0
- package/dist/services/approvals.d.ts.map +1 -1
- package/dist/services/approvals.js.map +1 -1
- package/dist/services/automation-chat-output.d.ts +1 -1
- package/dist/services/automations.d.ts +4 -4
- package/dist/services/automations.d.ts.map +1 -1
- package/dist/services/automations.js +12 -0
- package/dist/services/automations.js.map +1 -1
- package/dist/services/budgets.d.ts +8 -0
- package/dist/services/budgets.d.ts.map +1 -1
- package/dist/services/budgets.js.map +1 -1
- package/dist/services/calendar.d.ts +2 -2
- package/dist/services/calendar.js +3 -3
- package/dist/services/calendar.js.map +1 -1
- package/dist/services/chat-agent-runs.d.ts +2 -0
- package/dist/services/chat-agent-runs.d.ts.map +1 -1
- package/dist/services/chat-agent-runs.js +6 -0
- package/dist/services/chat-agent-runs.js.map +1 -1
- package/dist/services/chat-assistant.d.ts.map +1 -1
- package/dist/services/chat-assistant.helpers.d.ts +1 -0
- package/dist/services/chat-assistant.helpers.d.ts.map +1 -1
- package/dist/services/chat-assistant.helpers.js +7 -10
- package/dist/services/chat-assistant.helpers.js.map +1 -1
- package/dist/services/chat-assistant.js +23 -6
- package/dist/services/chat-assistant.js.map +1 -1
- package/dist/services/chat-generation-locks.d.ts +6 -1
- package/dist/services/chat-generation-locks.d.ts.map +1 -1
- package/dist/services/chat-generation-locks.js +20 -2
- package/dist/services/chat-generation-locks.js.map +1 -1
- package/dist/services/chat-title-generation.d.ts +36 -0
- package/dist/services/chat-title-generation.d.ts.map +1 -0
- package/dist/services/chat-title-generation.js +107 -0
- package/dist/services/chat-title-generation.js.map +1 -0
- package/dist/services/chats.d.ts +471 -25
- package/dist/services/chats.d.ts.map +1 -1
- package/dist/services/chats.helpers.d.ts +2 -2
- package/dist/services/chats.js +651 -35
- package/dist/services/chats.js.map +1 -1
- package/dist/services/costs.d.ts +1 -1
- package/dist/services/finance.d.ts +2 -2
- package/dist/services/finance.js +1 -1
- package/dist/services/finance.js.map +1 -1
- package/dist/services/goals.d.ts +8 -0
- package/dist/services/goals.d.ts.map +1 -1
- package/dist/services/goals.js.map +1 -1
- package/dist/services/heartbeat-run-reference.d.ts +1 -0
- package/dist/services/heartbeat-run-reference.d.ts.map +1 -1
- package/dist/services/heartbeat-run-reference.js +3 -2
- package/dist/services/heartbeat-run-reference.js.map +1 -1
- package/dist/services/integrations/agent-integrations.d.ts +19 -0
- package/dist/services/integrations/agent-integrations.d.ts.map +1 -1
- package/dist/services/integrations/agent-integrations.js +30 -0
- package/dist/services/integrations/agent-integrations.js.map +1 -1
- package/dist/services/integrations/feishu/app-registration.d.ts +74 -0
- package/dist/services/integrations/feishu/app-registration.d.ts.map +1 -0
- package/dist/services/integrations/feishu/app-registration.js +226 -0
- package/dist/services/integrations/feishu/app-registration.js.map +1 -0
- package/dist/services/integrations/feishu/inbound-dispatcher-db.d.ts +4 -0
- package/dist/services/integrations/feishu/inbound-dispatcher-db.d.ts.map +1 -1
- package/dist/services/integrations/feishu/inbound-dispatcher-db.js +35 -5
- package/dist/services/integrations/feishu/inbound-dispatcher-db.js.map +1 -1
- package/dist/services/integrations/feishu/inbound-dispatcher.d.ts +2 -0
- package/dist/services/integrations/feishu/inbound-dispatcher.d.ts.map +1 -1
- package/dist/services/integrations/feishu/inbound-dispatcher.js.map +1 -1
- package/dist/services/integrations/feishu/runtime-registry.d.ts +20 -0
- package/dist/services/integrations/feishu/runtime-registry.d.ts.map +1 -0
- package/dist/services/integrations/feishu/runtime-registry.js +41 -0
- package/dist/services/integrations/feishu/runtime-registry.js.map +1 -0
- package/dist/services/integrations/feishu/runtime.d.ts +21 -23
- package/dist/services/integrations/feishu/runtime.d.ts.map +1 -1
- package/dist/services/integrations/feishu/runtime.js +135 -45
- package/dist/services/integrations/feishu/runtime.js.map +1 -1
- package/dist/services/integrations/feishu/user-bindings.d.ts +22 -0
- package/dist/services/integrations/feishu/user-bindings.d.ts.map +1 -0
- package/dist/services/integrations/feishu/user-bindings.js +57 -0
- package/dist/services/integrations/feishu/user-bindings.js.map +1 -0
- package/dist/services/issue-approvals.d.ts +2 -2
- package/dist/services/issue-review-wakeup.js +1 -1
- package/dist/services/issue-review-wakeup.js.map +1 -1
- package/dist/services/issues.comments-attachments.d.ts +3 -3
- package/dist/services/issues.d.ts +14 -6
- package/dist/services/issues.d.ts.map +1 -1
- package/dist/services/issues.helpers.d.ts +9 -1
- package/dist/services/issues.helpers.d.ts.map +1 -1
- package/dist/services/issues.helpers.js +8 -0
- package/dist/services/issues.helpers.js.map +1 -1
- package/dist/services/issues.js +1 -1
- package/dist/services/issues.js.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.catalog.d.ts +1 -1
- package/dist/services/library-entries.d.ts +8 -0
- package/dist/services/library-entries.d.ts.map +1 -1
- package/dist/services/library-entries.js +8 -0
- package/dist/services/library-entries.js.map +1 -1
- package/dist/services/messenger.d.ts +19 -4
- package/dist/services/messenger.d.ts.map +1 -1
- package/dist/services/messenger.js +136 -18
- package/dist/services/messenger.js.map +1 -1
- package/dist/services/plugin-capability-validator.d.ts +1 -1
- package/dist/services/plugin-capability-validator.js +2 -2
- package/dist/services/plugin-dev-watcher.js +1 -1
- package/dist/services/plugin-event-bus.d.ts +3 -3
- package/dist/services/plugin-event-bus.js +3 -3
- package/dist/services/plugin-job-coordinator.d.ts +1 -1
- package/dist/services/plugin-job-coordinator.js +1 -1
- package/dist/services/plugin-job-scheduler.d.ts +1 -1
- package/dist/services/plugin-job-scheduler.js +1 -1
- package/dist/services/plugin-job-store.d.ts +2 -2
- package/dist/services/plugin-job-store.js +2 -2
- package/dist/services/plugin-lifecycle.d.ts +4 -4
- package/dist/services/plugin-lifecycle.js +3 -3
- package/dist/services/plugin-loader.core.d.ts +4 -4
- package/dist/services/plugin-loader.core.js +2 -2
- package/dist/services/plugin-loader.core.js.map +1 -1
- package/dist/services/plugin-loader.d.ts +3 -3
- package/dist/services/plugin-loader.helpers.d.ts +26 -25
- package/dist/services/plugin-loader.helpers.d.ts.map +1 -1
- package/dist/services/plugin-loader.helpers.js +10 -9
- package/dist/services/plugin-loader.helpers.js.map +1 -1
- package/dist/services/plugin-loader.js +3 -3
- package/dist/services/plugin-loader.worker-paths.d.ts +3 -3
- package/dist/services/plugin-manifest-validator.d.ts +2 -2
- package/dist/services/plugin-registry.d.ts +9 -9
- package/dist/services/plugin-registry.js +1 -1
- package/dist/services/plugin-secrets-handler.d.ts +2 -2
- package/dist/services/plugin-secrets-handler.js +2 -2
- package/dist/services/plugin-state-store.d.ts +3 -3
- package/dist/services/plugin-state-store.js +3 -3
- package/dist/services/plugin-stream-bus.d.ts +1 -1
- package/dist/services/plugin-stream-bus.js +1 -1
- package/dist/services/plugin-tool-dispatcher.d.ts +2 -2
- package/dist/services/plugin-tool-dispatcher.js +2 -2
- package/dist/services/plugin-tool-registry.d.ts +2 -2
- package/dist/services/plugin-tool-registry.js +2 -2
- package/dist/services/plugin-worker-manager.d.ts +4 -4
- package/dist/services/plugin-worker-manager.d.ts.map +1 -1
- package/dist/services/plugin-worker-manager.js +8 -7
- package/dist/services/plugin-worker-manager.js.map +1 -1
- package/dist/services/run-intelligence.js +3 -3
- package/dist/services/run-intelligence.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.core.d.ts +9 -1
- package/dist/services/runtime-kernel/heartbeat.core.d.ts.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.core.js +16 -5
- package/dist/services/runtime-kernel/heartbeat.core.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.d.ts +3 -3
- package/dist/services/runtime-kernel/heartbeat.execute.d.ts.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.execute.js +17 -3
- package/dist/services/runtime-kernel/heartbeat.execute.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.misc.js +1 -1
- package/dist/services/runtime-kernel/heartbeat.recovery.d.ts +1 -1
- package/dist/services/runtime-kernel/heartbeat.recovery.js +7 -7
- package/dist/services/runtime-kernel/heartbeat.recovery.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.release.js +4 -4
- package/dist/services/runtime-kernel/heartbeat.release.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.wakeup.js +1 -1
- package/dist/services/sidebar-badges.d.ts.map +1 -1
- package/dist/services/sidebar-badges.js +13 -1
- package/dist/services/sidebar-badges.js.map +1 -1
- package/dist/services/title-generation.d.ts +13 -0
- package/dist/services/title-generation.d.ts.map +1 -0
- package/dist/services/title-generation.js +77 -0
- package/dist/services/title-generation.js.map +1 -0
- package/dist/services/website-metadata.d.ts +17 -0
- package/dist/services/website-metadata.d.ts.map +1 -0
- package/dist/services/website-metadata.js +293 -0
- package/dist/services/website-metadata.js.map +1 -0
- package/dist/services/workspace-backups.d.ts +22 -0
- package/dist/services/workspace-backups.d.ts.map +1 -1
- package/dist/services/workspace-backups.js +161 -5
- package/dist/services/workspace-backups.js.map +1 -1
- package/dist/services/workspace-runtime.services.d.ts +1 -1
- package/package.json +14 -13
- package/resources/bundled-skills/rudder/SKILL.md +7 -6
- package/resources/bundled-skills/rudder/references/cli-reference.md +3 -3
- package/resources/bundled-skills/rudder-create-plugin/SKILL.md +2 -2
- package/skills/rudder/SKILL.md +7 -6
- package/skills/rudder/references/cli-reference.md +3 -3
- package/skills/rudder-create-plugin/SKILL.md +2 -2
- package/ui-dist/assets/{_basePickBy-CM0XatHw.js → _basePickBy-CyhMvFCw.js} +1 -1
- package/ui-dist/assets/{_baseUniq-CdBBmdoP.js → _baseUniq-k3x-egdv.js} +1 -1
- package/ui-dist/assets/{arc-DSTtxyJ9.js → arc-DVwZMGLR.js} +1 -1
- package/ui-dist/assets/{architectureDiagram-2XIMDMQ5-BkHMYb5I.js → architectureDiagram-2XIMDMQ5-BvKp7DHW.js} +1 -1
- package/ui-dist/assets/{blockDiagram-WCTKOSBZ-EYczZxwW.js → blockDiagram-WCTKOSBZ-CQ0KLoGd.js} +1 -1
- package/ui-dist/assets/{c4Diagram-IC4MRINW-Xo9qijMi.js → c4Diagram-IC4MRINW-BY44eeD7.js} +1 -1
- package/ui-dist/assets/channel-Cb8ybYSt.js +1 -0
- package/ui-dist/assets/{chunk-4BX2VUAB-CKzta1FF.js → chunk-4BX2VUAB-D7D6PuZU.js} +1 -1
- package/ui-dist/assets/{chunk-55IACEB6-BxxUB0ww.js → chunk-55IACEB6-CraDwywJ.js} +1 -1
- package/ui-dist/assets/{chunk-FMBD7UC4-0F4oxVtY.js → chunk-FMBD7UC4-BGYh4kbq.js} +1 -1
- package/ui-dist/assets/{chunk-JSJVCQXG-CVMPMlVD.js → chunk-JSJVCQXG-DndeOLp_.js} +1 -1
- package/ui-dist/assets/{chunk-KX2RTZJC-lPrAWT94.js → chunk-KX2RTZJC-Cx0eOadl.js} +1 -1
- package/ui-dist/assets/{chunk-NQ4KR5QH-Bufcm7Iv.js → chunk-NQ4KR5QH-PNVbQ_36.js} +1 -1
- package/ui-dist/assets/{chunk-QZHKN3VN-CucmdWnl.js → chunk-QZHKN3VN-DKsTZ1-C.js} +1 -1
- package/ui-dist/assets/{chunk-WL4C6EOR-Dz0oYQrJ.js → chunk-WL4C6EOR-B4aSDSws.js} +1 -1
- package/ui-dist/assets/classDiagram-VBA2DB6C-US2diuPm.js +1 -0
- package/ui-dist/assets/classDiagram-v2-RAHNMMFH-US2diuPm.js +1 -0
- package/ui-dist/assets/clone-CbFoFrhF.js +1 -0
- package/ui-dist/assets/{cose-bilkent-S5V4N54A-DzyX-Er8.js → cose-bilkent-S5V4N54A-DwgS7_iT.js} +1 -1
- package/ui-dist/assets/{dagre-KLK3FWXG-BbZzCKuN.js → dagre-KLK3FWXG-CGMeHr1L.js} +1 -1
- package/ui-dist/assets/{diagram-E7M64L7V-B5Rb7Bm4.js → diagram-E7M64L7V-1AVTOsRS.js} +1 -1
- package/ui-dist/assets/{diagram-IFDJBPK2-Cpu1Xc8G.js → diagram-IFDJBPK2-hfbRtuHq.js} +1 -1
- package/ui-dist/assets/{diagram-P4PSJMXO-kLfHqRlk.js → diagram-P4PSJMXO-BypSVEur.js} +1 -1
- package/ui-dist/assets/{erDiagram-INFDFZHY-rCnUyQUb.js → erDiagram-INFDFZHY-DWMZC8pq.js} +1 -1
- package/ui-dist/assets/{flowDiagram-PKNHOUZH-BhOz8cvV.js → flowDiagram-PKNHOUZH-C4ODl03j.js} +1 -1
- package/ui-dist/assets/{ganttDiagram-A5KZAMGK-Csg9g3hz.js → ganttDiagram-A5KZAMGK-K0UbcKpB.js} +1 -1
- package/ui-dist/assets/{gitGraphDiagram-K3NZZRJ6-DLPnSlRs.js → gitGraphDiagram-K3NZZRJ6-CEtw8QBQ.js} +1 -1
- package/ui-dist/assets/{graph-BrxYh68N.js → graph-D-YEM3eO.js} +1 -1
- package/ui-dist/assets/{index-DMkClCka.js → index--e_5aFtV.js} +1 -1
- package/ui-dist/assets/{index-G_y-oBne.js → index--wGHASfH.js} +1 -1
- package/ui-dist/assets/index-2sHXDbqQ.css +1 -0
- package/ui-dist/assets/{index-BQW242nS.js → index-8D4SrlCZ.js} +1 -1
- package/ui-dist/assets/{index-DpdsNIGb.js → index-B9FglFcf.js} +1 -1
- package/ui-dist/assets/{index-D4FFno9t.js → index-BOLNi_9C.js} +1 -1
- package/ui-dist/assets/{index-COBwmF-C.js → index-BVSwDm4x.js} +1 -1
- package/ui-dist/assets/{index-BkzdTp2b.js → index-C4vZZ0jB.js} +1 -1
- package/ui-dist/assets/{index-Br07RRw1.js → index-CMZ9kRE0.js} +1 -1
- package/ui-dist/assets/{index-mOyLwPeE.js → index-CZb2W71E.js} +1 -1
- package/ui-dist/assets/{index-DiMeST8g.js → index-Cfp9ooqM.js} +1 -1
- package/ui-dist/assets/{index-BeZv_Z0b.js → index-CyWWtF_x.js} +1 -1
- package/ui-dist/assets/{index-CsraICzz.js → index-CzQXnPD8.js} +1 -1
- package/ui-dist/assets/{index-Bw8MgLaM.js → index-D2uGk78l.js} +446 -446
- package/ui-dist/assets/{index-Cb2qts0o.js → index-DVl9xsgP.js} +1 -1
- package/ui-dist/assets/{index-D0rP99dj.js → index-T4jxRzoA.js} +1 -1
- package/ui-dist/assets/{index-B6_gFYNj.js → index-V0iKRmt7.js} +1 -1
- package/ui-dist/assets/{index-Dj72ldIc.js → index-byosaKUg.js} +1 -1
- package/ui-dist/assets/{index-D_06pAuN.js → index-nUtypsmU.js} +1 -1
- package/ui-dist/assets/{infoDiagram-LFFYTUFH-CRBKgiEf.js → infoDiagram-LFFYTUFH-C6TFdmXf.js} +1 -1
- package/ui-dist/assets/{ishikawaDiagram-PHBUUO56-DI3jquVE.js → ishikawaDiagram-PHBUUO56-DyiJqs9l.js} +1 -1
- package/ui-dist/assets/{journeyDiagram-4ABVD52K-DDFZ2Q6D.js → journeyDiagram-4ABVD52K-A-q8eZgk.js} +1 -1
- package/ui-dist/assets/{kanban-definition-K7BYSVSG-yL5u3cXV.js → kanban-definition-K7BYSVSG-B_1rE7-5.js} +1 -1
- package/ui-dist/assets/{layout-DDZaRkp7.js → layout-kMGiiRYg.js} +1 -1
- package/ui-dist/assets/{linear-CWngWuQa.js → linear-PdbwVMlL.js} +1 -1
- package/ui-dist/assets/{mermaid.core-CQuYoq9K.js → mermaid.core-Cev3K7jk.js} +4 -4
- package/ui-dist/assets/{mindmap-definition-YRQLILUH-BwSsHtTO.js → mindmap-definition-YRQLILUH-C8xkWcsS.js} +1 -1
- package/ui-dist/assets/{pieDiagram-SKSYHLDU-BasUkvwH.js → pieDiagram-SKSYHLDU-D2I_J-RQ.js} +1 -1
- package/ui-dist/assets/{quadrantDiagram-337W2JSQ-D0D2xp36.js → quadrantDiagram-337W2JSQ-B6BBePuG.js} +1 -1
- package/ui-dist/assets/{requirementDiagram-Z7DCOOCP-CztN9kDh.js → requirementDiagram-Z7DCOOCP-BUl7tTbs.js} +1 -1
- package/ui-dist/assets/{sankeyDiagram-WA2Y5GQK-2xDqN9ox.js → sankeyDiagram-WA2Y5GQK-Dus4b_vo.js} +1 -1
- package/ui-dist/assets/{sequenceDiagram-2WXFIKYE-CO3OUPIJ.js → sequenceDiagram-2WXFIKYE-DnwzyMvt.js} +1 -1
- package/ui-dist/assets/{stateDiagram-RAJIS63D-DuQ1QZcT.js → stateDiagram-RAJIS63D-CWYWUh48.js} +1 -1
- package/ui-dist/assets/stateDiagram-v2-FVOUBMTO-yRuBqnCA.js +1 -0
- package/ui-dist/assets/{timeline-definition-YZTLITO2-CnOxbQeb.js → timeline-definition-YZTLITO2-D7vwtWgR.js} +1 -1
- package/ui-dist/assets/{treemap-KZPCXAKY-DD77IFOl.js → treemap-KZPCXAKY-CGCh4N8D.js} +1 -1
- package/ui-dist/assets/{vennDiagram-LZ73GAT5-DOXTGJn1.js → vennDiagram-LZ73GAT5-Bq1y4idx.js} +1 -1
- package/ui-dist/assets/{xychartDiagram-JWTSCODW-DWkrcdri.js → xychartDiagram-JWTSCODW-CMFdYJaJ.js} +1 -1
- package/ui-dist/index.html +2 -2
- package/ui-dist/assets/channel-BRnz7pSY.js +0 -1
- package/ui-dist/assets/classDiagram-VBA2DB6C-Q3YuI9dv.js +0 -1
- package/ui-dist/assets/classDiagram-v2-RAHNMMFH-Q3YuI9dv.js +0 -1
- package/ui-dist/assets/clone-C1exIyAN.js +0 -1
- package/ui-dist/assets/index-Dz8xxyqB.css +0 -1
- package/ui-dist/assets/stateDiagram-v2-FVOUBMTO-DQbZqbl9.js +0 -1
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import { JSDOM } from "jsdom";
|
|
2
|
+
import { lookup } from "node:dns/promises";
|
|
3
|
+
import { isIP } from "node:net";
|
|
4
|
+
const MAX_HTML_BYTES = 256 * 1024;
|
|
5
|
+
const MAX_ICON_BYTES = 512 * 1024;
|
|
6
|
+
const FETCH_TIMEOUT_MS = 5_000;
|
|
7
|
+
const MAX_REDIRECTS = 5;
|
|
8
|
+
const SUCCESS_CACHE_TTL_MS = 30 * 60_000;
|
|
9
|
+
const FAILURE_CACHE_TTL_MS = 5 * 60_000;
|
|
10
|
+
const IMAGE_CONTENT_TYPES = new Set([
|
|
11
|
+
"image/gif",
|
|
12
|
+
"image/jpeg",
|
|
13
|
+
"image/jpg",
|
|
14
|
+
"image/png",
|
|
15
|
+
"image/svg+xml",
|
|
16
|
+
"image/vnd.microsoft.icon",
|
|
17
|
+
"image/webp",
|
|
18
|
+
"image/x-icon",
|
|
19
|
+
]);
|
|
20
|
+
function isPrivateIpAddress(value) {
|
|
21
|
+
const normalized = value.replace(/^\[|\]$/gu, "").toLowerCase();
|
|
22
|
+
const ipv4Mapped = normalized.match(/^::ffff:(\d{1,3}(?:\.\d{1,3}){3})$/u);
|
|
23
|
+
if (ipv4Mapped)
|
|
24
|
+
return isPrivateIpAddress(ipv4Mapped[1]);
|
|
25
|
+
if (normalized === "::1" || normalized.startsWith("fe80:") || normalized.startsWith("fc") || normalized.startsWith("fd"))
|
|
26
|
+
return true;
|
|
27
|
+
const parts = normalized.split(".");
|
|
28
|
+
if (parts.length !== 4)
|
|
29
|
+
return false;
|
|
30
|
+
const octets = parts.map((part) => Number(part));
|
|
31
|
+
if (octets.some((octet) => !Number.isInteger(octet) || octet < 0 || octet > 255))
|
|
32
|
+
return false;
|
|
33
|
+
const [a, b] = octets;
|
|
34
|
+
if (a === 10 || a === 127 || a === 0)
|
|
35
|
+
return true;
|
|
36
|
+
if (a === 100 && b >= 64 && b <= 127)
|
|
37
|
+
return true;
|
|
38
|
+
if (a === 169 && b === 254)
|
|
39
|
+
return true;
|
|
40
|
+
if (a === 172 && b >= 16 && b <= 31)
|
|
41
|
+
return true;
|
|
42
|
+
if (a === 192 && b === 0)
|
|
43
|
+
return true;
|
|
44
|
+
if (a === 192 && b === 168)
|
|
45
|
+
return true;
|
|
46
|
+
if (a === 198 && (b === 18 || b === 19))
|
|
47
|
+
return true;
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
function isPrivateHostname(hostname) {
|
|
51
|
+
const normalized = hostname.replace(/^\[|\]$/gu, "").toLowerCase();
|
|
52
|
+
if (normalized === "localhost" || normalized.endsWith(".localhost"))
|
|
53
|
+
return true;
|
|
54
|
+
if (isIP(normalized))
|
|
55
|
+
return isPrivateIpAddress(normalized);
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
export function parsePublicHttpUrl(value, options = {}) {
|
|
59
|
+
const parsed = new URL(value);
|
|
60
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
61
|
+
throw new Error("Only http and https URLs can be inspected");
|
|
62
|
+
}
|
|
63
|
+
if (!options.allowPrivateHosts && isPrivateHostname(parsed.hostname)) {
|
|
64
|
+
throw new Error("Private network URLs cannot be inspected");
|
|
65
|
+
}
|
|
66
|
+
parsed.hash = "";
|
|
67
|
+
return parsed;
|
|
68
|
+
}
|
|
69
|
+
async function assertPublicResolvedHost(url, options) {
|
|
70
|
+
if (options.allowPrivateHosts || options.fetchImpl || isIP(url.hostname.replace(/^\[|\]$/gu, "")))
|
|
71
|
+
return;
|
|
72
|
+
const addresses = await lookup(url.hostname, { all: true, verbatim: true });
|
|
73
|
+
if (addresses.some((address) => isPrivateIpAddress(address.address))) {
|
|
74
|
+
throw new Error("Private network URLs cannot be inspected");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async function fetchWithTimeout(url, options, init) {
|
|
78
|
+
let currentUrl = parsePublicHttpUrl(url.href, options);
|
|
79
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
80
|
+
for (let redirectCount = 0; redirectCount <= MAX_REDIRECTS; redirectCount += 1) {
|
|
81
|
+
await assertPublicResolvedHost(currentUrl, options);
|
|
82
|
+
const controller = new AbortController();
|
|
83
|
+
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
84
|
+
try {
|
|
85
|
+
const response = await fetchImpl(currentUrl.href, {
|
|
86
|
+
redirect: "manual",
|
|
87
|
+
...init,
|
|
88
|
+
signal: controller.signal,
|
|
89
|
+
headers: {
|
|
90
|
+
accept: "text/html,application/xhtml+xml,image/avif,image/webp,image/png,image/svg+xml,image/*,*/*;q=0.8",
|
|
91
|
+
"user-agent": "RudderWebsiteMetadata/1.0",
|
|
92
|
+
...(init?.headers ?? {}),
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
if (response.status < 300 || response.status >= 400)
|
|
96
|
+
return { response, url: currentUrl };
|
|
97
|
+
const location = response.headers.get("location");
|
|
98
|
+
if (!location)
|
|
99
|
+
return { response, url: currentUrl };
|
|
100
|
+
currentUrl = parsePublicHttpUrl(new URL(location, currentUrl).href, options);
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
clearTimeout(timeout);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
throw new Error("Website metadata redirect limit exceeded");
|
|
107
|
+
}
|
|
108
|
+
function metadataCacheKey(url) {
|
|
109
|
+
return url.href;
|
|
110
|
+
}
|
|
111
|
+
const metadataCache = new Map();
|
|
112
|
+
const metadataInflight = new Map();
|
|
113
|
+
async function readLimitedBuffer(response, maxBytes) {
|
|
114
|
+
const body = response.body;
|
|
115
|
+
if (!body)
|
|
116
|
+
return Buffer.alloc(0);
|
|
117
|
+
const reader = body.getReader();
|
|
118
|
+
const chunks = [];
|
|
119
|
+
let total = 0;
|
|
120
|
+
try {
|
|
121
|
+
while (true) {
|
|
122
|
+
const { value, done } = await reader.read();
|
|
123
|
+
if (done)
|
|
124
|
+
break;
|
|
125
|
+
if (!value)
|
|
126
|
+
continue;
|
|
127
|
+
total += value.byteLength;
|
|
128
|
+
if (total > maxBytes) {
|
|
129
|
+
throw new Error("Response exceeds metadata size limit");
|
|
130
|
+
}
|
|
131
|
+
chunks.push(Buffer.from(value));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
finally {
|
|
135
|
+
reader.releaseLock();
|
|
136
|
+
}
|
|
137
|
+
return Buffer.concat(chunks);
|
|
138
|
+
}
|
|
139
|
+
function contentTypeBase(value) {
|
|
140
|
+
return value?.split(";")[0]?.trim().toLowerCase() ?? "";
|
|
141
|
+
}
|
|
142
|
+
function absolutizeHref(href, baseUrl, options) {
|
|
143
|
+
const trimmed = href?.trim();
|
|
144
|
+
if (!trimmed)
|
|
145
|
+
return null;
|
|
146
|
+
try {
|
|
147
|
+
const parsed = parsePublicHttpUrl(new URL(trimmed, baseUrl).href, options);
|
|
148
|
+
parsed.hash = "";
|
|
149
|
+
return parsed.href;
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
function linkRelTokens(element) {
|
|
156
|
+
return (element.getAttribute("rel") ?? "")
|
|
157
|
+
.split(/\s+/u)
|
|
158
|
+
.map((token) => token.trim().toLowerCase())
|
|
159
|
+
.filter(Boolean);
|
|
160
|
+
}
|
|
161
|
+
function readSiteName(document) {
|
|
162
|
+
const selectors = [
|
|
163
|
+
'meta[property="og:site_name"]',
|
|
164
|
+
'meta[name="application-name"]',
|
|
165
|
+
'meta[name="apple-mobile-web-app-title"]',
|
|
166
|
+
];
|
|
167
|
+
for (const selector of selectors) {
|
|
168
|
+
const value = document.querySelector(selector)?.getAttribute("content")?.trim();
|
|
169
|
+
if (value)
|
|
170
|
+
return value;
|
|
171
|
+
}
|
|
172
|
+
const title = document.querySelector("title")?.textContent?.trim();
|
|
173
|
+
return title || null;
|
|
174
|
+
}
|
|
175
|
+
function iconPriority(element) {
|
|
176
|
+
const rel = new Set(linkRelTokens(element));
|
|
177
|
+
if (rel.has("icon") && rel.has("shortcut"))
|
|
178
|
+
return 0;
|
|
179
|
+
if (rel.has("icon"))
|
|
180
|
+
return 1;
|
|
181
|
+
if (rel.has("apple-touch-icon"))
|
|
182
|
+
return 2;
|
|
183
|
+
if (rel.has("apple-touch-icon-precomposed"))
|
|
184
|
+
return 3;
|
|
185
|
+
if (rel.has("mask-icon"))
|
|
186
|
+
return 4;
|
|
187
|
+
return 10;
|
|
188
|
+
}
|
|
189
|
+
function findDeclaredIcon(document, baseUrl, options) {
|
|
190
|
+
const candidates = Array.from(document.querySelectorAll("link[rel][href]"))
|
|
191
|
+
.filter((element) => {
|
|
192
|
+
const rel = new Set(linkRelTokens(element));
|
|
193
|
+
return rel.has("icon")
|
|
194
|
+
|| rel.has("apple-touch-icon")
|
|
195
|
+
|| rel.has("apple-touch-icon-precomposed")
|
|
196
|
+
|| rel.has("mask-icon");
|
|
197
|
+
})
|
|
198
|
+
.sort((left, right) => iconPriority(left) - iconPriority(right));
|
|
199
|
+
for (const candidate of candidates) {
|
|
200
|
+
const href = absolutizeHref(candidate.getAttribute("href"), baseUrl, options);
|
|
201
|
+
if (href)
|
|
202
|
+
return href;
|
|
203
|
+
}
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
async function validateIconUrl(iconHref, options) {
|
|
207
|
+
try {
|
|
208
|
+
const { response, url } = await fetchWithTimeout(parsePublicHttpUrl(iconHref, options), options, { method: "GET" });
|
|
209
|
+
if (!response.ok)
|
|
210
|
+
return null;
|
|
211
|
+
const contentType = contentTypeBase(response.headers.get("content-type"));
|
|
212
|
+
if (!IMAGE_CONTENT_TYPES.has(contentType))
|
|
213
|
+
return null;
|
|
214
|
+
await readLimitedBuffer(response, MAX_ICON_BYTES);
|
|
215
|
+
return url.href;
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
async function findImplicitFavicon(baseUrl, options) {
|
|
222
|
+
const faviconUrl = new URL("/favicon.ico", baseUrl);
|
|
223
|
+
return validateIconUrl(faviconUrl.href, options);
|
|
224
|
+
}
|
|
225
|
+
async function resolveWebsiteMetadataUncached(value, options) {
|
|
226
|
+
const pageUrl = parsePublicHttpUrl(value, options);
|
|
227
|
+
const { response, url: finalPageUrl } = await fetchWithTimeout(pageUrl, options);
|
|
228
|
+
if (!response.ok) {
|
|
229
|
+
return { url: finalPageUrl.href, siteName: null, iconUrl: null };
|
|
230
|
+
}
|
|
231
|
+
const contentType = contentTypeBase(response.headers.get("content-type"));
|
|
232
|
+
if (contentType && contentType !== "text/html" && contentType !== "application/xhtml+xml") {
|
|
233
|
+
return { url: finalPageUrl.href, siteName: null, iconUrl: null };
|
|
234
|
+
}
|
|
235
|
+
const html = (await readLimitedBuffer(response, MAX_HTML_BYTES)).toString("utf8");
|
|
236
|
+
const dom = new JSDOM(html, { url: finalPageUrl.href });
|
|
237
|
+
try {
|
|
238
|
+
const document = dom.window.document;
|
|
239
|
+
const declaredIcon = findDeclaredIcon(document, finalPageUrl, options);
|
|
240
|
+
return {
|
|
241
|
+
url: finalPageUrl.href,
|
|
242
|
+
siteName: readSiteName(document),
|
|
243
|
+
iconUrl: (declaredIcon ? await validateIconUrl(declaredIcon, options) : null) ?? await findImplicitFavicon(finalPageUrl, options),
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
finally {
|
|
247
|
+
dom.window.close();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
export async function resolveWebsiteMetadata(value, options = {}) {
|
|
251
|
+
const pageUrl = parsePublicHttpUrl(value, options);
|
|
252
|
+
const key = metadataCacheKey(pageUrl);
|
|
253
|
+
if (!options.allowPrivateHosts && !options.fetchImpl) {
|
|
254
|
+
const cached = metadataCache.get(key);
|
|
255
|
+
if (cached && cached.expiresAt > Date.now())
|
|
256
|
+
return cached.value;
|
|
257
|
+
const inflight = metadataInflight.get(key);
|
|
258
|
+
if (inflight)
|
|
259
|
+
return inflight;
|
|
260
|
+
const request = resolveWebsiteMetadataUncached(pageUrl.href, options)
|
|
261
|
+
.then((metadata) => {
|
|
262
|
+
metadataCache.set(key, {
|
|
263
|
+
expiresAt: Date.now() + (metadata.iconUrl ? SUCCESS_CACHE_TTL_MS : FAILURE_CACHE_TTL_MS),
|
|
264
|
+
value: metadata,
|
|
265
|
+
});
|
|
266
|
+
return metadata;
|
|
267
|
+
})
|
|
268
|
+
.finally(() => {
|
|
269
|
+
metadataInflight.delete(key);
|
|
270
|
+
});
|
|
271
|
+
metadataInflight.set(key, request);
|
|
272
|
+
return request;
|
|
273
|
+
}
|
|
274
|
+
return resolveWebsiteMetadataUncached(pageUrl.href, options);
|
|
275
|
+
}
|
|
276
|
+
export async function fetchWebsiteIcon(value, options = {}) {
|
|
277
|
+
const iconUrl = parsePublicHttpUrl(value, options);
|
|
278
|
+
const { response } = await fetchWithTimeout(iconUrl, options);
|
|
279
|
+
if (!response.ok)
|
|
280
|
+
return null;
|
|
281
|
+
const contentType = contentTypeBase(response.headers.get("content-type"));
|
|
282
|
+
if (!IMAGE_CONTENT_TYPES.has(contentType))
|
|
283
|
+
return null;
|
|
284
|
+
const body = await readLimitedBuffer(response, MAX_ICON_BYTES);
|
|
285
|
+
if (body.length <= 0)
|
|
286
|
+
return null;
|
|
287
|
+
return { contentType, body };
|
|
288
|
+
}
|
|
289
|
+
export function __clearWebsiteMetadataCacheForTests() {
|
|
290
|
+
metadataCache.clear();
|
|
291
|
+
metadataInflight.clear();
|
|
292
|
+
}
|
|
293
|
+
//# sourceMappingURL=website-metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"website-metadata.js","sourceRoot":"","sources":["../../src/services/website-metadata.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,11 +15,31 @@ type WorkspaceBackupArtifactMigrationSkip = {
|
|
|
15
15
|
to: string;
|
|
16
16
|
reason: string;
|
|
17
17
|
};
|
|
18
|
+
export type WorkspaceBackupDownload = {
|
|
19
|
+
artifactRef: string;
|
|
20
|
+
filename: string;
|
|
21
|
+
contentType: "application/json";
|
|
22
|
+
byteSize: number;
|
|
23
|
+
archiveSha256: string | null;
|
|
24
|
+
content: Buffer;
|
|
25
|
+
};
|
|
26
|
+
export type SparseWorkspaceRecoveryResult = {
|
|
27
|
+
orgId: string;
|
|
28
|
+
recovered: boolean;
|
|
29
|
+
backupId: string | null;
|
|
30
|
+
currentFileCount: number;
|
|
31
|
+
backupFileCount: number;
|
|
32
|
+
restoredFileCount: number;
|
|
33
|
+
skippedConflictingFiles: string[];
|
|
34
|
+
reason: string | null;
|
|
35
|
+
error: string | null;
|
|
36
|
+
};
|
|
18
37
|
export declare function reconcileWorkspaceBackupArtifactStorage(db: Db, liveOrgIds: readonly string[]): Promise<{
|
|
19
38
|
migrated: WorkspaceBackupArtifactMigration[];
|
|
20
39
|
skipped: WorkspaceBackupArtifactMigrationSkip[];
|
|
21
40
|
}>;
|
|
22
41
|
export declare function workspaceBackupService(db: Db): {
|
|
42
|
+
recoverSparseWorkspaceFromLatestBackup: (orgId: string) => Promise<SparseWorkspaceRecoveryResult>;
|
|
23
43
|
list(orgId: string): Promise<WorkspaceBackupSummary[]>;
|
|
24
44
|
create(input: {
|
|
25
45
|
orgId: string;
|
|
@@ -30,6 +50,7 @@ export declare function workspaceBackupService(db: Db): {
|
|
|
30
50
|
}): Promise<WorkspaceBackupSummary>;
|
|
31
51
|
listFiles(orgId: string, backupId: string, directoryPath?: string): Promise<OrganizationWorkspaceFileList>;
|
|
32
52
|
readFile(orgId: string, backupId: string, filePath: string): Promise<OrganizationWorkspaceFileDetail>;
|
|
53
|
+
getDownload(orgId: string, backupId: string): Promise<WorkspaceBackupDownload>;
|
|
33
54
|
remove(orgId: string, backupId: string): Promise<WorkspaceBackupSummary>;
|
|
34
55
|
pruneExpired(now?: Date): Promise<WorkspaceBackupSummary[]>;
|
|
35
56
|
runScheduledBackups(input?: {
|
|
@@ -40,6 +61,7 @@ export declare function workspaceBackupService(db: Db): {
|
|
|
40
61
|
created: WorkspaceBackupSummary[];
|
|
41
62
|
failed: WorkspaceBackupSummary[];
|
|
42
63
|
deleted: WorkspaceBackupSummary[];
|
|
64
|
+
sparseRecoveries: SparseWorkspaceRecoveryResult[];
|
|
43
65
|
skipped: number;
|
|
44
66
|
errors: Array<{
|
|
45
67
|
orgId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-backups.d.ts","sourceRoot":"","sources":["../../src/services/workspace-backups.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,EAAE,EACR,MAAM,cAAc,CAAC;AACtB,OAAO,EAGL,KAAK,+BAA+B,EAEpC,KAAK,6BAA6B,EAClC,KAAK,4BAA4B,EACjC,KAAK,sBAAsB,EAC3B,KAAK,4BAA4B,EAClC,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"workspace-backups.d.ts","sourceRoot":"","sources":["../../src/services/workspace-backups.ts"],"names":[],"mappings":"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"}
|
|
@@ -34,6 +34,9 @@ const WORKSPACE_BACKUP_RUNNING_TIMEOUT_MS = 2 * 60 * 60 * 1000;
|
|
|
34
34
|
const MAX_BACKUP_FILE_BYTES = 5 * 1024 * 1024;
|
|
35
35
|
const MAX_BACKUP_TOTAL_BYTES = 100 * 1024 * 1024;
|
|
36
36
|
const MAX_WARNING_COUNT = 200;
|
|
37
|
+
const SPARSE_WORKSPACE_RECOVERY_MAX_CURRENT_FILES = 25;
|
|
38
|
+
const SPARSE_WORKSPACE_RECOVERY_MAX_RATIO = 0.25;
|
|
39
|
+
const SPARSE_WORKSPACE_RECOVERY_MIN_BACKUP_FILES = 10;
|
|
37
40
|
function timestamp(date = new Date()) {
|
|
38
41
|
const pad = (value) => String(value).padStart(2, "0");
|
|
39
42
|
return `${date.getFullYear()}${pad(date.getMonth() + 1)}${pad(date.getDate())}-${pad(date.getHours())}${pad(date.getMinutes())}${pad(date.getSeconds())}`;
|
|
@@ -306,6 +309,17 @@ async function fileExists(filePath) {
|
|
|
306
309
|
throw error;
|
|
307
310
|
}
|
|
308
311
|
}
|
|
312
|
+
async function pathExists(targetPath) {
|
|
313
|
+
try {
|
|
314
|
+
return await fs.lstat(targetPath);
|
|
315
|
+
}
|
|
316
|
+
catch (error) {
|
|
317
|
+
if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") {
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
throw error;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
309
323
|
async function walkWorkspace(rootPath, currentPath, warnings, entries = [], state = { byteSize: 0 }) {
|
|
310
324
|
const dirents = await fs.readdir(currentPath, { withFileTypes: true });
|
|
311
325
|
for (const dirent of dirents) {
|
|
@@ -374,6 +388,48 @@ function buildManifest(input) {
|
|
|
374
388
|
warnings: input.artifact.warnings,
|
|
375
389
|
};
|
|
376
390
|
}
|
|
391
|
+
async function restoreMissingArtifactFiles(input) {
|
|
392
|
+
let restoredFileCount = 0;
|
|
393
|
+
const skippedConflictingFiles = [];
|
|
394
|
+
const blockedDirectoryPrefixes = [];
|
|
395
|
+
const directories = input.artifact.entries.filter((entry) => entry.kind === "directory");
|
|
396
|
+
const files = input.artifact.entries.filter((entry) => entry.kind === "file");
|
|
397
|
+
for (const entry of directories) {
|
|
398
|
+
const { resolvedTarget } = resolveWithinRoot(input.workspaceRoot, entry.path);
|
|
399
|
+
const existing = await pathExists(resolvedTarget);
|
|
400
|
+
if (existing && !existing.isDirectory()) {
|
|
401
|
+
skippedConflictingFiles.push(entry.path);
|
|
402
|
+
blockedDirectoryPrefixes.push(`${entry.path}/`);
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
await fs.mkdir(resolvedTarget, { recursive: true });
|
|
406
|
+
}
|
|
407
|
+
for (const entry of files) {
|
|
408
|
+
if (blockedDirectoryPrefixes.some((prefix) => entry.path.startsWith(prefix))) {
|
|
409
|
+
skippedConflictingFiles.push(entry.path);
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
412
|
+
const { resolvedTarget } = resolveWithinRoot(input.workspaceRoot, entry.path);
|
|
413
|
+
const existing = await pathExists(resolvedTarget);
|
|
414
|
+
if (existing) {
|
|
415
|
+
if (!existing.isFile()) {
|
|
416
|
+
skippedConflictingFiles.push(entry.path);
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
if (entry.sha256) {
|
|
420
|
+
const current = await fs.readFile(resolvedTarget);
|
|
421
|
+
if (sha256Buffer(current) !== entry.sha256) {
|
|
422
|
+
skippedConflictingFiles.push(entry.path);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
continue;
|
|
426
|
+
}
|
|
427
|
+
await fs.mkdir(path.dirname(resolvedTarget), { recursive: true });
|
|
428
|
+
await fs.writeFile(resolvedTarget, Buffer.from(entry.dataBase64 ?? "", "base64"), { mode: entry.mode ?? 0o600 });
|
|
429
|
+
restoredFileCount += 1;
|
|
430
|
+
}
|
|
431
|
+
return { restoredFileCount, skippedConflictingFiles };
|
|
432
|
+
}
|
|
377
433
|
export function workspaceBackupService(db) {
|
|
378
434
|
const orgs = organizationService(db);
|
|
379
435
|
async function getBackupRow(orgId, backupId) {
|
|
@@ -393,23 +449,27 @@ export function workspaceBackupService(db) {
|
|
|
393
449
|
throw unprocessable(row.error ? `Workspace backup failed: ${row.error}` : "Workspace backup failed");
|
|
394
450
|
}
|
|
395
451
|
}
|
|
396
|
-
async function
|
|
452
|
+
async function readArtifactPayload(row) {
|
|
397
453
|
assertReadableBackup(row);
|
|
398
454
|
if (!(await fileExists(row.artifactRef))) {
|
|
399
455
|
throw notFound("Workspace backup artifact not found");
|
|
400
456
|
}
|
|
401
|
-
const raw = await fs.readFile(row.artifactRef
|
|
457
|
+
const raw = await fs.readFile(row.artifactRef);
|
|
402
458
|
if (row.archiveSha256 && sha256Buffer(raw) !== row.archiveSha256) {
|
|
403
459
|
throw unprocessable("Workspace backup artifact checksum does not match the recorded backup metadata");
|
|
404
460
|
}
|
|
405
|
-
const parsed = JSON.parse(raw);
|
|
461
|
+
const parsed = JSON.parse(raw.toString("utf8"));
|
|
406
462
|
if (parsed.version !== ARTIFACT_VERSION || parsed.orgId !== row.orgId || !Array.isArray(parsed.entries)) {
|
|
407
463
|
throw unprocessable("Workspace backup artifact is invalid");
|
|
408
464
|
}
|
|
409
465
|
for (const entry of parsed.entries) {
|
|
410
466
|
assertSafeRelativePath(entry.path);
|
|
411
467
|
}
|
|
412
|
-
return parsed;
|
|
468
|
+
return { raw, artifact: parsed };
|
|
469
|
+
}
|
|
470
|
+
async function readArtifact(row) {
|
|
471
|
+
const payload = await readArtifactPayload(row);
|
|
472
|
+
return payload.artifact;
|
|
413
473
|
}
|
|
414
474
|
async function countActiveRuns(orgId) {
|
|
415
475
|
const [row] = await db
|
|
@@ -433,7 +493,79 @@ export function workspaceBackupService(db) {
|
|
|
433
493
|
.returning();
|
|
434
494
|
return rows.map(mapBackupRow);
|
|
435
495
|
}
|
|
496
|
+
async function recoverSparseWorkspaceFromLatestBackup(orgId) {
|
|
497
|
+
const layout = await ensureOrganizationWorkspaceLayout(orgId);
|
|
498
|
+
const warnings = [];
|
|
499
|
+
const currentEntries = await walkWorkspace(layout.root, layout.root, warnings);
|
|
500
|
+
const currentFileCount = currentEntries.filter((entry) => entry.kind === "file").length;
|
|
501
|
+
if (currentFileCount > SPARSE_WORKSPACE_RECOVERY_MAX_CURRENT_FILES) {
|
|
502
|
+
return {
|
|
503
|
+
orgId,
|
|
504
|
+
recovered: false,
|
|
505
|
+
backupId: null,
|
|
506
|
+
currentFileCount,
|
|
507
|
+
backupFileCount: 0,
|
|
508
|
+
restoredFileCount: 0,
|
|
509
|
+
skippedConflictingFiles: [],
|
|
510
|
+
reason: "workspace is not sparse",
|
|
511
|
+
error: null,
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
const rows = await db
|
|
515
|
+
.select()
|
|
516
|
+
.from(workspaceBackups)
|
|
517
|
+
.where(and(eq(workspaceBackups.orgId, orgId), or(eq(workspaceBackups.status, "succeeded"), eq(workspaceBackups.status, "restored"))))
|
|
518
|
+
.orderBy(desc(workspaceBackups.fileCount), desc(workspaceBackups.createdAt));
|
|
519
|
+
const candidates = rows.filter((backup) => backup.fileCount >= SPARSE_WORKSPACE_RECOVERY_MIN_BACKUP_FILES
|
|
520
|
+
&& currentFileCount <= Math.floor(backup.fileCount * SPARSE_WORKSPACE_RECOVERY_MAX_RATIO));
|
|
521
|
+
if (candidates.length === 0) {
|
|
522
|
+
return {
|
|
523
|
+
orgId,
|
|
524
|
+
recovered: false,
|
|
525
|
+
backupId: null,
|
|
526
|
+
currentFileCount,
|
|
527
|
+
backupFileCount: 0,
|
|
528
|
+
restoredFileCount: 0,
|
|
529
|
+
skippedConflictingFiles: [],
|
|
530
|
+
reason: "no richer backup candidate",
|
|
531
|
+
error: null,
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
let lastError = null;
|
|
535
|
+
for (const candidate of candidates) {
|
|
536
|
+
try {
|
|
537
|
+
const artifact = await readArtifact(candidate);
|
|
538
|
+
const restored = await restoreMissingArtifactFiles({ artifact, workspaceRoot: layout.root });
|
|
539
|
+
return {
|
|
540
|
+
orgId,
|
|
541
|
+
recovered: restored.restoredFileCount > 0,
|
|
542
|
+
backupId: candidate.id,
|
|
543
|
+
currentFileCount,
|
|
544
|
+
backupFileCount: candidate.fileCount,
|
|
545
|
+
restoredFileCount: restored.restoredFileCount,
|
|
546
|
+
skippedConflictingFiles: restored.skippedConflictingFiles,
|
|
547
|
+
reason: restored.restoredFileCount > 0 ? null : "no missing files restored",
|
|
548
|
+
error: null,
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
catch (error) {
|
|
552
|
+
lastError = error instanceof Error ? error.message : String(error);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
return {
|
|
556
|
+
orgId,
|
|
557
|
+
recovered: false,
|
|
558
|
+
backupId: candidates[0]?.id ?? null,
|
|
559
|
+
currentFileCount,
|
|
560
|
+
backupFileCount: candidates[0]?.fileCount ?? 0,
|
|
561
|
+
restoredFileCount: 0,
|
|
562
|
+
skippedConflictingFiles: [],
|
|
563
|
+
reason: "richer backup recovery failed",
|
|
564
|
+
error: lastError,
|
|
565
|
+
};
|
|
566
|
+
}
|
|
436
567
|
const service = {
|
|
568
|
+
recoverSparseWorkspaceFromLatestBackup,
|
|
437
569
|
async list(orgId) {
|
|
438
570
|
const organization = await orgs.getById(orgId);
|
|
439
571
|
if (!organization)
|
|
@@ -595,6 +727,18 @@ export function workspaceBackupService(db) {
|
|
|
595
727
|
truncated,
|
|
596
728
|
};
|
|
597
729
|
},
|
|
730
|
+
async getDownload(orgId, backupId) {
|
|
731
|
+
const row = await getBackupRow(orgId, backupId);
|
|
732
|
+
const payload = await readArtifactPayload(row);
|
|
733
|
+
return {
|
|
734
|
+
artifactRef: row.artifactRef,
|
|
735
|
+
filename: path.basename(row.artifactRef),
|
|
736
|
+
contentType: "application/json",
|
|
737
|
+
byteSize: payload.raw.byteLength,
|
|
738
|
+
archiveSha256: row.archiveSha256,
|
|
739
|
+
content: payload.raw,
|
|
740
|
+
};
|
|
741
|
+
},
|
|
598
742
|
async remove(orgId, backupId) {
|
|
599
743
|
const row = await getBackupRow(orgId, backupId);
|
|
600
744
|
await fs.rm(row.artifactRef, { force: true });
|
|
@@ -630,6 +774,7 @@ export function workspaceBackupService(db) {
|
|
|
630
774
|
const created = [];
|
|
631
775
|
const failed = [...staleFailed];
|
|
632
776
|
const errors = [];
|
|
777
|
+
const sparseRecoveries = [];
|
|
633
778
|
let skipped = 0;
|
|
634
779
|
for (const organization of organizations) {
|
|
635
780
|
try {
|
|
@@ -643,6 +788,17 @@ export function workspaceBackupService(db) {
|
|
|
643
788
|
skipped += 1;
|
|
644
789
|
continue;
|
|
645
790
|
}
|
|
791
|
+
const sparseRecovery = await recoverSparseWorkspaceFromLatestBackup(organization.id);
|
|
792
|
+
if (sparseRecovery.recovered || sparseRecovery.error) {
|
|
793
|
+
sparseRecoveries.push(sparseRecovery);
|
|
794
|
+
}
|
|
795
|
+
if (sparseRecovery.error) {
|
|
796
|
+
errors.push({
|
|
797
|
+
orgId: organization.id,
|
|
798
|
+
message: `Sparse workspace recovery failed before scheduled backup: ${sparseRecovery.error}`,
|
|
799
|
+
});
|
|
800
|
+
continue;
|
|
801
|
+
}
|
|
646
802
|
const backup = await service.create({
|
|
647
803
|
orgId: organization.id,
|
|
648
804
|
triggerSource: "scheduled",
|
|
@@ -660,7 +816,7 @@ export function workspaceBackupService(db) {
|
|
|
660
816
|
});
|
|
661
817
|
}
|
|
662
818
|
}
|
|
663
|
-
return { created, failed, deleted, skipped, errors };
|
|
819
|
+
return { created, failed, deleted, sparseRecoveries, skipped, errors };
|
|
664
820
|
},
|
|
665
821
|
async restore(orgId, backupId, input) {
|
|
666
822
|
const row = await getBackupRow(orgId, backupId);
|