botmux 3.10.0 → 3.11.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/.runtime-build-id +1 -1
- package/dist/adapters/backend/herdr-backend.d.ts +4 -3
- package/dist/adapters/backend/herdr-backend.d.ts.map +1 -1
- package/dist/adapters/backend/herdr-backend.js +11 -8
- package/dist/adapters/backend/herdr-backend.js.map +1 -1
- package/dist/adapters/backend/pty-backend.d.ts +1 -1
- package/dist/adapters/backend/pty-backend.d.ts.map +1 -1
- package/dist/adapters/backend/pty-backend.js +4 -1
- package/dist/adapters/backend/pty-backend.js.map +1 -1
- package/dist/adapters/backend/riff-backend.d.ts +29 -5
- package/dist/adapters/backend/riff-backend.d.ts.map +1 -1
- package/dist/adapters/backend/riff-backend.js +302 -31
- package/dist/adapters/backend/riff-backend.js.map +1 -1
- package/dist/adapters/backend/sandbox.d.ts +6 -0
- package/dist/adapters/backend/sandbox.d.ts.map +1 -1
- package/dist/adapters/backend/sandbox.js +7 -0
- package/dist/adapters/backend/sandbox.js.map +1 -1
- package/dist/adapters/backend/tmux-backend.d.ts +1 -1
- package/dist/adapters/backend/tmux-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-backend.js +4 -1
- package/dist/adapters/backend/tmux-backend.js.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.d.ts +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.js +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -1
- package/dist/adapters/backend/types.d.ts +37 -3
- package/dist/adapters/backend/types.d.ts.map +1 -1
- package/dist/adapters/backend/types.js.map +1 -1
- package/dist/adapters/backend/zellij-backend.d.ts +3 -3
- package/dist/adapters/backend/zellij-backend.d.ts.map +1 -1
- package/dist/adapters/backend/zellij-backend.js +9 -3
- package/dist/adapters/backend/zellij-backend.js.map +1 -1
- package/dist/adapters/backend/zellij-observe-backend.d.ts +3 -3
- package/dist/adapters/backend/zellij-observe-backend.d.ts.map +1 -1
- package/dist/adapters/backend/zellij-observe-backend.js +12 -7
- package/dist/adapters/backend/zellij-observe-backend.js.map +1 -1
- package/dist/adapters/cli/codex-app.d.ts.map +1 -1
- package/dist/adapters/cli/codex-app.js +11 -2
- package/dist/adapters/cli/codex-app.js.map +1 -1
- package/dist/adapters/cli/read-isolation.d.ts +35 -2
- package/dist/adapters/cli/read-isolation.d.ts.map +1 -1
- package/dist/adapters/cli/read-isolation.js +88 -7
- package/dist/adapters/cli/read-isolation.js.map +1 -1
- package/dist/adapters/cli/runner-input.d.ts +15 -14
- package/dist/adapters/cli/runner-input.d.ts.map +1 -1
- package/dist/adapters/cli/runner-input.js +64 -26
- package/dist/adapters/cli/runner-input.js.map +1 -1
- package/dist/adapters/cli/types.d.ts +20 -5
- package/dist/adapters/cli/types.d.ts.map +1 -1
- package/dist/bot-registry.d.ts +24 -0
- package/dist/bot-registry.d.ts.map +1 -1
- package/dist/bot-registry.js +110 -5
- package/dist/bot-registry.js.map +1 -1
- package/dist/cli/fleet-shutdown.d.ts +47 -0
- package/dist/cli/fleet-shutdown.d.ts.map +1 -0
- package/dist/cli/fleet-shutdown.js +387 -0
- package/dist/cli/fleet-shutdown.js.map +1 -0
- package/dist/cli/pm2-descriptor-guard.d.ts +19 -0
- package/dist/cli/pm2-descriptor-guard.d.ts.map +1 -0
- package/dist/cli/pm2-descriptor-guard.js +122 -0
- package/dist/cli/pm2-descriptor-guard.js.map +1 -0
- package/dist/cli/pm2-exact-start.d.ts +16 -0
- package/dist/cli/pm2-exact-start.d.ts.map +1 -0
- package/dist/cli/pm2-exact-start.js +63 -0
- package/dist/cli/pm2-exact-start.js.map +1 -0
- package/dist/cli/pm2-god-admission.d.ts +8 -0
- package/dist/cli/pm2-god-admission.d.ts.map +1 -0
- package/dist/cli/pm2-god-admission.js +25 -0
- package/dist/cli/pm2-god-admission.js.map +1 -0
- package/dist/cli/pm2-jlist.d.ts +13 -0
- package/dist/cli/pm2-jlist.d.ts.map +1 -0
- package/dist/cli/pm2-jlist.js +108 -0
- package/dist/cli/pm2-jlist.js.map +1 -0
- package/dist/cli/pm2-preflight.d.ts +10 -0
- package/dist/cli/pm2-preflight.d.ts.map +1 -0
- package/dist/cli/pm2-preflight.js +23 -0
- package/dist/cli/pm2-preflight.js.map +1 -0
- package/dist/cli/pm2-shutdown-capability.d.ts +27 -0
- package/dist/cli/pm2-shutdown-capability.d.ts.map +1 -0
- package/dist/cli/pm2-shutdown-capability.js +161 -0
- package/dist/cli/pm2-shutdown-capability.js.map +1 -0
- package/dist/cli/pm2-start-transaction.d.ts +55 -0
- package/dist/cli/pm2-start-transaction.d.ts.map +1 -0
- package/dist/cli/pm2-start-transaction.js +220 -0
- package/dist/cli/pm2-start-transaction.js.map +1 -0
- package/dist/cli/send-dispatch.d.ts +12 -0
- package/dist/cli/send-dispatch.d.ts.map +1 -1
- package/dist/cli/send-dispatch.js +31 -4
- package/dist/cli/send-dispatch.js.map +1 -1
- package/dist/cli/session-list-liveness.d.ts +1 -0
- package/dist/cli/session-list-liveness.d.ts.map +1 -1
- package/dist/cli/session-list-liveness.js +6 -0
- package/dist/cli/session-list-liveness.js.map +1 -1
- package/dist/cli/session-picker-layout.d.ts +26 -0
- package/dist/cli/session-picker-layout.d.ts.map +1 -0
- package/dist/cli/session-picker-layout.js +123 -0
- package/dist/cli/session-picker-layout.js.map +1 -0
- package/dist/cli/session-picker-viewport.d.ts +49 -0
- package/dist/cli/session-picker-viewport.d.ts.map +1 -0
- package/dist/cli/session-picker-viewport.js +46 -0
- package/dist/cli/session-picker-viewport.js.map +1 -0
- package/dist/cli/supervisor-shutdown-client.d.ts +31 -0
- package/dist/cli/supervisor-shutdown-client.d.ts.map +1 -0
- package/dist/cli/supervisor-shutdown-client.js +146 -0
- package/dist/cli/supervisor-shutdown-client.js.map +1 -0
- package/dist/cli/terminal-width.d.ts +48 -0
- package/dist/cli/terminal-width.d.ts.map +1 -0
- package/dist/cli/terminal-width.js +119 -0
- package/dist/cli/terminal-width.js.map +1 -0
- package/dist/cli/vc-agent.d.ts.map +1 -1
- package/dist/cli/vc-agent.js +1 -1
- package/dist/cli/vc-agent.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2269 -716
- package/dist/cli.js.map +1 -1
- package/dist/codex-app-runner.js +1630 -125
- package/dist/codex-app-runner.js.map +1 -1
- package/dist/core/ask-api.d.ts +8 -1
- package/dist/core/ask-api.d.ts.map +1 -1
- package/dist/core/ask-api.js +18 -0
- package/dist/core/ask-api.js.map +1 -1
- package/dist/core/ask-broker.d.ts +20 -0
- package/dist/core/ask-broker.d.ts.map +1 -1
- package/dist/core/ask-broker.js +467 -47
- package/dist/core/ask-broker.js.map +1 -1
- package/dist/core/ask-persist-store.d.ts +126 -0
- package/dist/core/ask-persist-store.d.ts.map +1 -0
- package/dist/core/ask-persist-store.js +188 -0
- package/dist/core/ask-persist-store.js.map +1 -0
- package/dist/core/ask-types.d.ts +80 -0
- package/dist/core/ask-types.d.ts.map +1 -1
- package/dist/core/ask-types.js +62 -0
- package/dist/core/ask-types.js.map +1 -1
- package/dist/core/cli-session-id-publisher.d.ts +20 -0
- package/dist/core/cli-session-id-publisher.d.ts.map +1 -0
- package/dist/core/cli-session-id-publisher.js +21 -0
- package/dist/core/cli-session-id-publisher.js.map +1 -0
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +427 -255
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/cost-calculator.d.ts +13 -0
- package/dist/core/cost-calculator.d.ts.map +1 -1
- package/dist/core/cost-calculator.js +385 -26
- package/dist/core/cost-calculator.js.map +1 -1
- package/dist/core/dashboard-ipc-server.d.ts +9 -0
- package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
- package/dist/core/dashboard-ipc-server.js +842 -288
- package/dist/core/dashboard-ipc-server.js.map +1 -1
- package/dist/core/explicit-session-backing-cleanup.d.ts +49 -0
- package/dist/core/explicit-session-backing-cleanup.d.ts.map +1 -0
- package/dist/core/explicit-session-backing-cleanup.js +76 -0
- package/dist/core/explicit-session-backing-cleanup.js.map +1 -0
- package/dist/core/idle-worker-sweeper.d.ts +20 -0
- package/dist/core/idle-worker-sweeper.d.ts.map +1 -1
- package/dist/core/idle-worker-sweeper.js +18 -0
- package/dist/core/idle-worker-sweeper.js.map +1 -1
- package/dist/core/inflight-input-tracker.d.ts +10 -0
- package/dist/core/inflight-input-tracker.d.ts.map +1 -1
- package/dist/core/inflight-input-tracker.js +7 -0
- package/dist/core/inflight-input-tracker.js.map +1 -1
- package/dist/core/managed-origin-attestation.d.ts +51 -0
- package/dist/core/managed-origin-attestation.d.ts.map +1 -0
- package/dist/core/managed-origin-attestation.js +208 -0
- package/dist/core/managed-origin-attestation.js.map +1 -0
- package/dist/core/managed-origin-capability.d.ts +62 -3
- package/dist/core/managed-origin-capability.d.ts.map +1 -1
- package/dist/core/managed-origin-capability.js +419 -9
- package/dist/core/managed-origin-capability.js.map +1 -1
- package/dist/core/pending-repo-journal.d.ts +6 -0
- package/dist/core/pending-repo-journal.d.ts.map +1 -0
- package/dist/core/pending-repo-journal.js +85 -0
- package/dist/core/pending-repo-journal.js.map +1 -0
- package/dist/core/persistent-backend.d.ts +6 -1
- package/dist/core/persistent-backend.d.ts.map +1 -1
- package/dist/core/persistent-backend.js +12 -6
- package/dist/core/persistent-backend.js.map +1 -1
- package/dist/core/process-start-identity.d.ts +3 -0
- package/dist/core/process-start-identity.d.ts.map +1 -0
- package/dist/core/process-start-identity.js +62 -0
- package/dist/core/process-start-identity.js.map +1 -0
- package/dist/core/raw-command-writer.d.ts +34 -0
- package/dist/core/raw-command-writer.d.ts.map +1 -0
- package/dist/core/raw-command-writer.js +48 -0
- package/dist/core/raw-command-writer.js.map +1 -0
- package/dist/core/reply-target.d.ts +85 -22
- package/dist/core/reply-target.d.ts.map +1 -1
- package/dist/core/reply-target.js +267 -32
- package/dist/core/reply-target.js.map +1 -1
- package/dist/core/resource-monitor/runtime.d.ts.map +1 -1
- package/dist/core/resource-monitor/runtime.js +4 -1
- package/dist/core/resource-monitor/runtime.js.map +1 -1
- package/dist/core/restart-report.d.ts +6 -1
- package/dist/core/restart-report.d.ts.map +1 -1
- package/dist/core/restart-report.js +22 -4
- package/dist/core/restart-report.js.map +1 -1
- package/dist/core/riff-shutdown-detach.d.ts +164 -0
- package/dist/core/riff-shutdown-detach.d.ts.map +1 -0
- package/dist/core/riff-shutdown-detach.js +787 -0
- package/dist/core/riff-shutdown-detach.js.map +1 -0
- package/dist/core/riff-worker-shutdown-readiness.d.ts +17 -0
- package/dist/core/riff-worker-shutdown-readiness.d.ts.map +1 -0
- package/dist/core/riff-worker-shutdown-readiness.js +21 -0
- package/dist/core/riff-worker-shutdown-readiness.js.map +1 -0
- package/dist/core/session-manager.d.ts +6 -6
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +1227 -594
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-marker.d.ts +1 -1
- package/dist/core/session-marker.d.ts.map +1 -1
- package/dist/core/session-marker.js +2 -2
- package/dist/core/session-marker.js.map +1 -1
- package/dist/core/session-mutation-guard.d.ts +17 -0
- package/dist/core/session-mutation-guard.d.ts.map +1 -0
- package/dist/core/session-mutation-guard.js +33 -0
- package/dist/core/session-mutation-guard.js.map +1 -0
- package/dist/core/shutdown-budgets.d.ts +27 -0
- package/dist/core/shutdown-budgets.d.ts.map +1 -0
- package/dist/core/shutdown-budgets.js +47 -0
- package/dist/core/shutdown-budgets.js.map +1 -0
- package/dist/core/supervisor-shutdown-ipc.d.ts +10 -0
- package/dist/core/supervisor-shutdown-ipc.d.ts.map +1 -0
- package/dist/core/supervisor-shutdown-ipc.js +10 -0
- package/dist/core/supervisor-shutdown-ipc.js.map +1 -0
- package/dist/core/supervisor-shutdown-protocol.d.ts +16 -0
- package/dist/core/supervisor-shutdown-protocol.d.ts.map +1 -0
- package/dist/core/supervisor-shutdown-protocol.js +16 -0
- package/dist/core/supervisor-shutdown-protocol.js.map +1 -0
- package/dist/core/trigger-final-suppression.d.ts +4 -0
- package/dist/core/trigger-final-suppression.d.ts.map +1 -1
- package/dist/core/trigger-final-suppression.js +6 -11
- package/dist/core/trigger-final-suppression.js.map +1 -1
- package/dist/core/trigger-session.d.ts +70 -0
- package/dist/core/trigger-session.d.ts.map +1 -1
- package/dist/core/trigger-session.js +923 -145
- package/dist/core/trigger-session.js.map +1 -1
- package/dist/core/types.d.ts +94 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +9 -0
- package/dist/core/types.js.map +1 -1
- package/dist/core/worker-pool.d.ts +194 -13
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +2597 -547
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.d.ts +76 -2
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +2255 -773
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/bot-payload.d.ts +20 -0
- package/dist/dashboard/bot-payload.d.ts.map +1 -1
- package/dist/dashboard/bot-payload.js +24 -0
- package/dist/dashboard/bot-payload.js.map +1 -1
- package/dist/dashboard/feed-groups.d.ts +17 -0
- package/dist/dashboard/feed-groups.d.ts.map +1 -0
- package/dist/dashboard/feed-groups.js +75 -0
- package/dist/dashboard/feed-groups.js.map +1 -0
- package/dist/dashboard/session-card-model.d.ts +1 -1
- package/dist/dashboard/session-card-model.d.ts.map +1 -1
- package/dist/dashboard/session-card-model.js +8 -5
- package/dist/dashboard/session-card-model.js.map +1 -1
- package/dist/dashboard/web/bot-defaults-page.d.ts +4 -0
- package/dist/dashboard/web/bot-defaults-page.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults-page.js +139 -46
- package/dist/dashboard/web/bot-defaults-page.js.map +1 -1
- package/dist/dashboard/web/bot-defaults.d.ts +4 -0
- package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults.js.map +1 -1
- package/dist/dashboard/web/connectors-page.d.ts.map +1 -1
- package/dist/dashboard/web/connectors-page.js +40 -3
- package/dist/dashboard/web/connectors-page.js.map +1 -1
- package/dist/dashboard/web/groups-page.d.ts.map +1 -1
- package/dist/dashboard/web/groups-page.js +95 -2
- package/dist/dashboard/web/groups-page.js.map +1 -1
- package/dist/dashboard/web/i18n.d.ts.map +1 -1
- package/dist/dashboard/web/i18n.js +86 -40
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard/web/kanban-model.js +1 -1
- package/dist/dashboard/web/kanban-model.js.map +1 -1
- package/dist/dashboard/web/overview-page.d.ts.map +1 -1
- package/dist/dashboard/web/overview-page.js +3 -2
- package/dist/dashboard/web/overview-page.js.map +1 -1
- package/dist/dashboard/web/overview.d.ts +3 -0
- package/dist/dashboard/web/overview.d.ts.map +1 -1
- package/dist/dashboard/web/overview.js +2 -0
- package/dist/dashboard/web/overview.js.map +1 -1
- package/dist/dashboard/web/sessions-kanban.d.ts.map +1 -1
- package/dist/dashboard/web/sessions-kanban.js +2 -0
- package/dist/dashboard/web/sessions-kanban.js.map +1 -1
- package/dist/dashboard/web/sessions-page.d.ts.map +1 -1
- package/dist/dashboard/web/sessions-page.js +103 -2
- package/dist/dashboard/web/sessions-page.js.map +1 -1
- package/dist/dashboard/web/sessions.d.ts.map +1 -1
- package/dist/dashboard/web/sessions.js +3 -2
- package/dist/dashboard/web/sessions.js.map +1 -1
- package/dist/dashboard/web/ui.d.ts +8 -0
- package/dist/dashboard/web/ui.d.ts.map +1 -1
- package/dist/dashboard/web/ui.js +15 -0
- package/dist/dashboard/web/ui.js.map +1 -1
- package/dist/dashboard-web/app.js +1 -1
- package/dist/dashboard-web/chunks/bot-defaults-page-GED4FEMS.js +10 -0
- package/dist/dashboard-web/chunks/chunk-6J5LS5AU.js +51 -0
- package/dist/dashboard-web/chunks/{chunk-ZU3UUKAR.js → chunk-HK7NIBJG.js} +1 -1
- package/dist/dashboard-web/chunks/{chunk-3UE7S77S.js → chunk-KRHWZEXU.js} +1 -1
- package/dist/dashboard-web/chunks/chunk-VBXJOJFH.js +1 -0
- package/dist/dashboard-web/chunks/connectors-page-EELM66G3.js +1 -0
- package/dist/dashboard-web/chunks/groups-page-WKUV6E42.js +8 -0
- package/dist/dashboard-web/chunks/{insights-page-T2ZX2RWL.js → insights-page-54UBPPOC.js} +1 -1
- package/dist/dashboard-web/chunks/{monitor-room-YNVBAGR6.js → monitor-room-PORHVKRH.js} +1 -1
- package/dist/dashboard-web/chunks/{monitoring-page-LHM55YWN.js → monitoring-page-XGA7AXNL.js} +1 -1
- package/dist/dashboard-web/chunks/{office-page-ATXVP7PW.js → office-page-AO3AFG45.js} +1 -1
- package/dist/dashboard-web/chunks/overview-page-F5BUTYR6.js +1 -0
- package/dist/dashboard-web/chunks/{roles-page-56VWM6CD.js → roles-page-M5GIASJU.js} +1 -1
- package/dist/dashboard-web/chunks/{schedules-page-S5K6U4EO.js → schedules-page-O232WQRR.js} +1 -1
- package/dist/dashboard-web/chunks/sessions-page-YFRPSTIL.js +6 -0
- package/dist/dashboard-web/chunks/{settings-page-QUZDQARR.js → settings-page-OJAZLZQT.js} +1 -1
- package/dist/dashboard-web/chunks/{skills-page-IFY7AEND.js → skills-page-EFZQPWV4.js} +1 -1
- package/dist/dashboard-web/chunks/{team-federation-page-C7FJQPFZ.js → team-federation-page-ZJVAP7HW.js} +1 -1
- package/dist/dashboard-web/chunks/{v3-page-2LMF3WWR.js → v3-page-GYWTRGO2.js} +1 -1
- package/dist/dashboard-web/chunks/{whiteboards-page-3XC6QRMY.js → whiteboards-page-MSDAG6P7.js} +1 -1
- package/dist/dashboard-web/style.css +255 -0
- package/dist/dashboard.js +172 -7
- package/dist/dashboard.js.map +1 -1
- package/dist/desktop/renderer/app.js +21 -0
- package/dist/desktop/renderer/app.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +35 -9
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +35 -9
- package/dist/i18n/zh.js.map +1 -1
- package/dist/im/lark/ask-card.d.ts +23 -0
- package/dist/im/lark/ask-card.d.ts.map +1 -1
- package/dist/im/lark/ask-card.js +94 -4
- package/dist/im/lark/ask-card.js.map +1 -1
- package/dist/im/lark/card-builder.d.ts +6 -1
- package/dist/im/lark/card-builder.d.ts.map +1 -1
- package/dist/im/lark/card-builder.js +112 -15
- package/dist/im/lark/card-builder.js.map +1 -1
- package/dist/im/lark/card-handler.d.ts +1 -1
- package/dist/im/lark/card-handler.d.ts.map +1 -1
- package/dist/im/lark/card-handler.js +496 -310
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/client.d.ts +7 -0
- package/dist/im/lark/client.d.ts.map +1 -1
- package/dist/im/lark/client.js +39 -26
- package/dist/im/lark/client.js.map +1 -1
- package/dist/im/lark/doc-comment.d.ts +7 -4
- package/dist/im/lark/doc-comment.d.ts.map +1 -1
- package/dist/im/lark/doc-comment.js +19 -6
- package/dist/im/lark/doc-comment.js.map +1 -1
- package/dist/im/lark/event-dispatcher.d.ts +16 -0
- package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
- package/dist/im/lark/event-dispatcher.js +88 -23
- package/dist/im/lark/event-dispatcher.js.map +1 -1
- package/dist/im/lark/forward-followup-content.d.ts.map +1 -1
- package/dist/im/lark/forward-followup-content.js +9 -1
- package/dist/im/lark/forward-followup-content.js.map +1 -1
- package/dist/im/lark/grant-command.d.ts.map +1 -1
- package/dist/im/lark/grant-command.js +7 -4
- package/dist/im/lark/grant-command.js.map +1 -1
- package/dist/im/lark/md-card.d.ts +11 -0
- package/dist/im/lark/md-card.d.ts.map +1 -1
- package/dist/im/lark/md-card.js +46 -0
- package/dist/im/lark/md-card.js.map +1 -1
- package/dist/im/lark/message-parser.d.ts +23 -2
- package/dist/im/lark/message-parser.d.ts.map +1 -1
- package/dist/im/lark/message-parser.js +58 -3
- package/dist/im/lark/message-parser.js.map +1 -1
- package/dist/im/lark/overview-card.d.ts.map +1 -1
- package/dist/im/lark/overview-card.js +2 -1
- package/dist/im/lark/overview-card.js.map +1 -1
- package/dist/services/async-trigger-state.d.ts +6 -1
- package/dist/services/async-trigger-state.d.ts.map +1 -1
- package/dist/services/async-trigger-state.js +21 -0
- package/dist/services/async-trigger-state.js.map +1 -1
- package/dist/services/async-trigger-store.d.ts +23 -1
- package/dist/services/async-trigger-store.d.ts.map +1 -1
- package/dist/services/async-trigger-store.js +96 -13
- package/dist/services/async-trigger-store.js.map +1 -1
- package/dist/services/bridge-fallback-gate.d.ts +40 -0
- package/dist/services/bridge-fallback-gate.d.ts.map +1 -1
- package/dist/services/bridge-fallback-gate.js +124 -24
- package/dist/services/bridge-fallback-gate.js.map +1 -1
- package/dist/services/codex-app-runner-protocol.d.ts +8 -0
- package/dist/services/codex-app-runner-protocol.d.ts.map +1 -1
- package/dist/services/codex-app-runner-protocol.js +9 -2
- package/dist/services/codex-app-runner-protocol.js.map +1 -1
- package/dist/services/codex-bridge-queue.d.ts +1 -0
- package/dist/services/codex-bridge-queue.d.ts.map +1 -1
- package/dist/services/codex-bridge-queue.js +1 -0
- package/dist/services/codex-bridge-queue.js.map +1 -1
- package/dist/services/codex-service-tier.d.ts +2 -0
- package/dist/services/codex-service-tier.d.ts.map +1 -1
- package/dist/services/codex-service-tier.js +1 -0
- package/dist/services/codex-service-tier.js.map +1 -1
- package/dist/services/codex-transcript.d.ts +27 -0
- package/dist/services/codex-transcript.d.ts.map +1 -1
- package/dist/services/codex-transcript.js +340 -2
- package/dist/services/codex-transcript.js.map +1 -1
- package/dist/services/grant-policy.d.ts +3 -0
- package/dist/services/grant-policy.d.ts.map +1 -1
- package/dist/services/grant-policy.js +5 -0
- package/dist/services/grant-policy.js.map +1 -1
- package/dist/services/grant-prefs-store.d.ts +6 -3
- package/dist/services/grant-prefs-store.d.ts.map +1 -1
- package/dist/services/grant-prefs-store.js +42 -12
- package/dist/services/grant-prefs-store.js.map +1 -1
- package/dist/services/hook-runner.d.ts +20 -1
- package/dist/services/hook-runner.d.ts.map +1 -1
- package/dist/services/hook-runner.js +17 -13
- package/dist/services/hook-runner.js.map +1 -1
- package/dist/services/idempotency-store.d.ts +134 -0
- package/dist/services/idempotency-store.d.ts.map +1 -0
- package/dist/services/idempotency-store.js +299 -0
- package/dist/services/idempotency-store.js.map +1 -0
- package/dist/services/jsonl-cursor.d.ts +7 -3
- package/dist/services/jsonl-cursor.d.ts.map +1 -1
- package/dist/services/jsonl-cursor.js +55 -31
- package/dist/services/jsonl-cursor.js.map +1 -1
- package/dist/services/open-platform-rename.d.ts.map +1 -1
- package/dist/services/open-platform-rename.js +1 -108
- package/dist/services/open-platform-rename.js.map +1 -1
- package/dist/services/restart-intent-store.d.ts +22 -2
- package/dist/services/restart-intent-store.d.ts.map +1 -1
- package/dist/services/restart-intent-store.js +160 -18
- package/dist/services/restart-intent-store.js.map +1 -1
- package/dist/services/sandbox-store.d.ts +22 -0
- package/dist/services/sandbox-store.d.ts.map +1 -1
- package/dist/services/sandbox-store.js +37 -8
- package/dist/services/sandbox-store.js.map +1 -1
- package/dist/services/send-policy.d.ts +41 -33
- package/dist/services/send-policy.d.ts.map +1 -1
- package/dist/services/send-policy.js +39 -40
- package/dist/services/send-policy.js.map +1 -1
- package/dist/services/session-store.d.ts +66 -0
- package/dist/services/session-store.d.ts.map +1 -1
- package/dist/services/session-store.js +403 -67
- package/dist/services/session-store.js.map +1 -1
- package/dist/services/submit-notification.d.ts +3 -0
- package/dist/services/submit-notification.d.ts.map +1 -0
- package/dist/services/submit-notification.js +15 -0
- package/dist/services/submit-notification.js.map +1 -0
- package/dist/services/traex-transcript.d.ts +25 -2
- package/dist/services/traex-transcript.d.ts.map +1 -1
- package/dist/services/traex-transcript.js +133 -1
- package/dist/services/traex-transcript.js.map +1 -1
- package/dist/services/trigger-types.d.ts +13 -1
- package/dist/services/trigger-types.d.ts.map +1 -1
- package/dist/services/trigger-types.js +39 -0
- package/dist/services/trigger-types.js.map +1 -1
- package/dist/services/voice/index.d.ts +3 -2
- package/dist/services/voice/index.d.ts.map +1 -1
- package/dist/services/voice/index.js +5 -5
- package/dist/services/voice/index.js.map +1 -1
- package/dist/services/voice/openai.d.ts +2 -1
- package/dist/services/voice/openai.d.ts.map +1 -1
- package/dist/services/voice/openai.js +2 -1
- package/dist/services/voice/openai.js.map +1 -1
- package/dist/services/voice/sami.d.ts +5 -2
- package/dist/services/voice/sami.d.ts.map +1 -1
- package/dist/services/voice/sami.js +19 -4
- package/dist/services/voice/sami.js.map +1 -1
- package/dist/setup/bots-store.d.ts.map +1 -1
- package/dist/setup/bots-store.js +10 -4
- package/dist/setup/bots-store.js.map +1 -1
- package/dist/setup/lark-scopes.json +2 -0
- package/dist/setup/open-platform-automation.d.ts +9 -1
- package/dist/setup/open-platform-automation.d.ts.map +1 -1
- package/dist/setup/open-platform-automation.js +44 -15
- package/dist/setup/open-platform-automation.js.map +1 -1
- package/dist/setup/open-platform-visibility.d.ts +42 -0
- package/dist/setup/open-platform-visibility.d.ts.map +1 -0
- package/dist/setup/open-platform-visibility.js +133 -0
- package/dist/setup/open-platform-visibility.js.map +1 -0
- package/dist/setup/verify-permissions.d.ts.map +1 -1
- package/dist/setup/verify-permissions.js +6 -0
- package/dist/setup/verify-permissions.js.map +1 -1
- package/dist/skills/definitions.js +2 -2
- package/dist/types.d.ts +290 -13
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/bot-routing.d.ts +1 -0
- package/dist/utils/bot-routing.d.ts.map +1 -1
- package/dist/utils/bot-routing.js +1 -1
- package/dist/utils/bot-routing.js.map +1 -1
- package/dist/utils/child-env.d.ts +1 -1
- package/dist/utils/child-env.d.ts.map +1 -1
- package/dist/utils/child-env.js +9 -0
- package/dist/utils/child-env.js.map +1 -1
- package/dist/utils/codex-app-control.d.ts +438 -0
- package/dist/utils/codex-app-control.d.ts.map +1 -0
- package/dist/utils/codex-app-control.js +2336 -0
- package/dist/utils/codex-app-control.js.map +1 -0
- package/dist/utils/codex-app-dispatch-ledger.d.ts +78 -0
- package/dist/utils/codex-app-dispatch-ledger.d.ts.map +1 -0
- package/dist/utils/codex-app-dispatch-ledger.js +149 -0
- package/dist/utils/codex-app-dispatch-ledger.js.map +1 -0
- package/dist/utils/codex-app-turn-dispatch.d.ts +77 -0
- package/dist/utils/codex-app-turn-dispatch.d.ts.map +1 -0
- package/dist/utils/codex-app-turn-dispatch.js +141 -0
- package/dist/utils/codex-app-turn-dispatch.js.map +1 -0
- package/dist/utils/codex-app-turn-liveness.d.ts +125 -0
- package/dist/utils/codex-app-turn-liveness.d.ts.map +1 -0
- package/dist/utils/codex-app-turn-liveness.js +301 -0
- package/dist/utils/codex-app-turn-liveness.js.map +1 -0
- package/dist/utils/idle-detector.d.ts +12 -0
- package/dist/utils/idle-detector.d.ts.map +1 -1
- package/dist/utils/idle-detector.js +19 -0
- package/dist/utils/idle-detector.js.map +1 -1
- package/dist/utils/input-gate.d.ts +87 -0
- package/dist/utils/input-gate.d.ts.map +1 -1
- package/dist/utils/input-gate.js +86 -0
- package/dist/utils/input-gate.js.map +1 -1
- package/dist/utils/lark-upload.d.ts.map +1 -1
- package/dist/utils/lark-upload.js +52 -1
- package/dist/utils/lark-upload.js.map +1 -1
- package/dist/utils/pending-input-queue.d.ts +15 -0
- package/dist/utils/pending-input-queue.d.ts.map +1 -1
- package/dist/utils/pending-input-queue.js +5 -1
- package/dist/utils/pending-input-queue.js.map +1 -1
- package/dist/utils/user-token.d.ts.map +1 -1
- package/dist/utils/user-token.js +53 -2
- package/dist/utils/user-token.js.map +1 -1
- package/dist/worker-ipc-preload.d.ts +12 -0
- package/dist/worker-ipc-preload.d.ts.map +1 -0
- package/dist/worker-ipc-preload.js +44 -0
- package/dist/worker-ipc-preload.js.map +1 -0
- package/dist/worker.js +2604 -325
- package/dist/worker.js.map +1 -1
- package/dist/workflows/v3/session-relay-client.d.ts +1 -0
- package/dist/workflows/v3/session-relay-client.d.ts.map +1 -1
- package/dist/workflows/v3/session-relay-client.js +12 -3
- package/dist/workflows/v3/session-relay-client.js.map +1 -1
- package/package.json +1 -1
- package/dist/dashboard-web/chunks/bot-defaults-page-LTVOUDIS.js +0 -10
- package/dist/dashboard-web/chunks/chunk-DCS35UMD.js +0 -1
- package/dist/dashboard-web/chunks/chunk-MFQPCVHY.js +0 -51
- package/dist/dashboard-web/chunks/connectors-page-5KWDIMKC.js +0 -1
- package/dist/dashboard-web/chunks/groups-page-FHOKYXMW.js +0 -8
- package/dist/dashboard-web/chunks/overview-page-QYI3KBDD.js +0 -1
- package/dist/dashboard-web/chunks/sessions-page-WBP4N7D2.js +0 -6
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Idempotency dispatch lease keyed by a caller-provided `options.idempotencyKey`
|
|
3
|
+
* (scoped per owning bot). The lease answers exactly ONE question: "may I
|
|
4
|
+
* dispatch this turn?" — it does NOT define what a caller sees as the terminal
|
|
5
|
+
* outcome. That terminal outcome lives in async-trigger-store (pending /
|
|
6
|
+
* completed / failed:dispatch_unknown), which trigger-result reads directly.
|
|
7
|
+
* Separating the two means correctness never depends on closeSession succeeding
|
|
8
|
+
* or on a second tombstone file (see PR #776 review 4878071011).
|
|
9
|
+
*
|
|
10
|
+
* States: reserved (claimed, not yet dispatched) → attempting (durably written
|
|
11
|
+
* BEFORE any fork/worker IPC side effect — commit-unknown). There is no
|
|
12
|
+
* "dispatched"/"completed" lease state: completion is proven by async-trigger
|
|
13
|
+
* store, and an attempting lease is a permanent "do-not-redispatch" fence.
|
|
14
|
+
*
|
|
15
|
+
* CONCURRENCY. rename(2) gives an atomic REPLACE, not a compare-and-swap. Every
|
|
16
|
+
* mutation therefore runs inside withFileLockSync(recordPath) (cross-process,
|
|
17
|
+
* per-key): read → verify full immutable identity + revision/state → durable
|
|
18
|
+
* atomic write, all under the lock. `atomicWriteFileSync` (tmp+fsync+rename,
|
|
19
|
+
* failure PRESERVES the old file) is used everywhere — never unlink→link, which
|
|
20
|
+
* could erase the only commit-unknown fence on an I/O failure.
|
|
21
|
+
*
|
|
22
|
+
* OWNERSHIP. (ownerLarkAppId, key) scoping + `ownerBootId` (this daemon process)
|
|
23
|
+
* + monotonic `revision`. Cross-bot reads are rejected fail-closed. Older-boot
|
|
24
|
+
* takeover of a `reserved` lease is safe under the repo's "one daemon per bot"
|
|
25
|
+
* invariant (daemon.ts): a different ownerBootId for the same bot means the
|
|
26
|
+
* previous process, which cannot still be advancing this lease.
|
|
27
|
+
*
|
|
28
|
+
* FAIL-CLOSED. Any ambiguous I/O / corruption on the claim path THROWS — the
|
|
29
|
+
* caller rolls back the just-created session and returns 5xx before dispatch.
|
|
30
|
+
*/
|
|
31
|
+
import { readFileSync, existsSync, mkdirSync, unlinkSync, readdirSync } from 'node:fs';
|
|
32
|
+
import { join, dirname } from 'node:path';
|
|
33
|
+
import { createHash } from 'node:crypto';
|
|
34
|
+
import { config } from '../config.js';
|
|
35
|
+
import { logger } from '../utils/logger.js';
|
|
36
|
+
import { withFileLockSync } from '../utils/file-lock.js';
|
|
37
|
+
import { atomicWriteFileSync } from '../utils/atomic-write.js';
|
|
38
|
+
export class IdempotencyConflictError extends Error {
|
|
39
|
+
existing;
|
|
40
|
+
constructor(existing) {
|
|
41
|
+
super('idempotency key already used with a different request payload');
|
|
42
|
+
this.existing = existing;
|
|
43
|
+
this.name = 'IdempotencyConflictError';
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function baseDir() {
|
|
47
|
+
return join(config.session.dataDir, 'idempotency');
|
|
48
|
+
}
|
|
49
|
+
/** Per-owner subdirectory: sha256(owner). Owner-PARTITIONED layout so a boot
|
|
50
|
+
* reconcile can enumerate ONLY its own bot's leases — a foreign (other-bot)
|
|
51
|
+
* corrupt lease then lives under a different subdir and can never block this
|
|
52
|
+
* bot's startup (the filename `sha256(owner\0key)` alone can't recover the
|
|
53
|
+
* owner from unparseable JSON, so a flat dir + throwOnCorrupt was a cross-bot
|
|
54
|
+
* startup DoS — codex #776 round-4 finding #4). */
|
|
55
|
+
function ownerDir(ownerLarkAppId) {
|
|
56
|
+
const ownerHash = createHash('sha256').update(ownerLarkAppId).digest('hex');
|
|
57
|
+
return join(baseDir(), ownerHash);
|
|
58
|
+
}
|
|
59
|
+
/** Filename = <ownerDir>/sha256(owner \0 key).json. The NUL-separated key digest
|
|
60
|
+
* keeps the same collision-free filename; the owner subdir gives partitioning. */
|
|
61
|
+
function fileFor(ownerLarkAppId, key) {
|
|
62
|
+
const digest = createHash('sha256').update(ownerLarkAppId).update('\0').update(key).digest('hex');
|
|
63
|
+
return join(ownerDir(ownerLarkAppId), `${digest}.json`);
|
|
64
|
+
}
|
|
65
|
+
function ensureDirFor(fp) {
|
|
66
|
+
const dir = dirname(fp);
|
|
67
|
+
if (!existsSync(dir))
|
|
68
|
+
mkdirSync(dir, { recursive: true });
|
|
69
|
+
}
|
|
70
|
+
/** Acquire the per-key file lock, ensuring the record's OWNER subdir exists
|
|
71
|
+
* first so withFileLockSync can create its `<path>.lock` sibling there. All
|
|
72
|
+
* mutators route through here so the lock and the record live in a
|
|
73
|
+
* materialized directory. */
|
|
74
|
+
function withKeyLock(fp, fn) {
|
|
75
|
+
ensureDirFor(fp);
|
|
76
|
+
return withFileLockSync(fp, fn);
|
|
77
|
+
}
|
|
78
|
+
/** Read + validate. undefined only when ABSENT. Present-but-corrupt THROWS
|
|
79
|
+
* (on the claim path an unreadable record is NOT provably absent). */
|
|
80
|
+
function readRecord(fp) {
|
|
81
|
+
if (!existsSync(fp))
|
|
82
|
+
return undefined;
|
|
83
|
+
const data = JSON.parse(readFileSync(fp, 'utf-8'));
|
|
84
|
+
if (!data || typeof data !== 'object'
|
|
85
|
+
|| typeof data.ownerLarkAppId !== 'string'
|
|
86
|
+
|| typeof data.sessionId !== 'string'
|
|
87
|
+
|| typeof data.triggerId !== 'string'
|
|
88
|
+
|| typeof data.requestHash !== 'string'
|
|
89
|
+
|| typeof data.ownerBootId !== 'string'
|
|
90
|
+
|| typeof data.revision !== 'number'
|
|
91
|
+
|| (data.state !== 'reserved' && data.state !== 'attempting')) {
|
|
92
|
+
throw new Error(`corrupt idempotency record: ${fp}`);
|
|
93
|
+
}
|
|
94
|
+
return data;
|
|
95
|
+
}
|
|
96
|
+
function writeRecord(fp, rec) {
|
|
97
|
+
ensureDirFor(fp);
|
|
98
|
+
atomicWriteFileSync(fp, JSON.stringify(rec, null, 2), { durable: true, followTargetSymlink: false });
|
|
99
|
+
}
|
|
100
|
+
/** True iff two records share the immutable identity fields (everything a CAS
|
|
101
|
+
* must pin besides the mutable state/revision/updatedAt). */
|
|
102
|
+
function sameIdentity(a, b) {
|
|
103
|
+
return a.ownerLarkAppId === b.ownerLarkAppId
|
|
104
|
+
&& a.sessionId === b.sessionId
|
|
105
|
+
&& a.triggerId === b.triggerId
|
|
106
|
+
&& a.requestHash === b.requestHash
|
|
107
|
+
&& a.ownerBootId === b.ownerBootId;
|
|
108
|
+
}
|
|
109
|
+
/** Non-locking read for the pre-check in trigger-session (a fast reject before
|
|
110
|
+
* creating a session). Owner mismatch → undefined. Corrupt → THROWS. The
|
|
111
|
+
* authoritative decision is always re-taken under the lock in claim/takeover. */
|
|
112
|
+
export function lookup(ownerLarkAppId, key) {
|
|
113
|
+
const rec = readRecord(fileFor(ownerLarkAppId, key));
|
|
114
|
+
if (!rec)
|
|
115
|
+
return undefined;
|
|
116
|
+
if (rec.ownerLarkAppId !== ownerLarkAppId)
|
|
117
|
+
return undefined;
|
|
118
|
+
return rec;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Claim (owner, key) for a fresh `reserved` lease, or return the existing one —
|
|
122
|
+
* all inside the per-key lock (read → decide → durable write is atomic wrt other
|
|
123
|
+
* daemons/boots). Throws on corrupt/IO (fail-closed) and on payload conflict.
|
|
124
|
+
*/
|
|
125
|
+
export function claim(input) {
|
|
126
|
+
const fp = fileFor(input.ownerLarkAppId, input.key);
|
|
127
|
+
return withKeyLock(fp, () => {
|
|
128
|
+
const existing = readRecord(fp);
|
|
129
|
+
if (existing) {
|
|
130
|
+
if (existing.ownerLarkAppId !== input.ownerLarkAppId)
|
|
131
|
+
throw new Error('idempotency record owner mismatch');
|
|
132
|
+
if (existing.requestHash !== input.requestHash)
|
|
133
|
+
throw new IdempotencyConflictError(existing);
|
|
134
|
+
return { kind: 'existing', record: existing };
|
|
135
|
+
}
|
|
136
|
+
const rec = {
|
|
137
|
+
ownerLarkAppId: input.ownerLarkAppId, sessionId: input.sessionId, triggerId: input.triggerId,
|
|
138
|
+
requestHash: input.requestHash, ownerBootId: input.ownerBootId,
|
|
139
|
+
revision: 1, state: 'reserved', createdAt: input.now, updatedAt: input.now,
|
|
140
|
+
};
|
|
141
|
+
writeRecord(fp, rec);
|
|
142
|
+
return { kind: 'won', record: rec };
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Take over an OLDER-boot `reserved` lease with a fresh reserved lease (new
|
|
147
|
+
* session/trigger), OR return the existing record if it's no longer a takeover
|
|
148
|
+
* target — all under the lock, re-reading current state (never trusting the
|
|
149
|
+
* caller's stale `from`). Returns won|existing so the caller handles a loss like
|
|
150
|
+
* a claim loss (close its new session, don't fork). Throws on conflict/IO.
|
|
151
|
+
*
|
|
152
|
+
* - absent now → won (fresh claim).
|
|
153
|
+
* - present, still the SAME older-boot reserved (identity+revision match) → won (replace).
|
|
154
|
+
* - present, same payload but changed (attempting / newer revision / different
|
|
155
|
+
* boot) → existing (someone advanced it; reuse, don't take over).
|
|
156
|
+
* - present, different payload → conflict.
|
|
157
|
+
*/
|
|
158
|
+
export function takeover(input) {
|
|
159
|
+
const fp = fileFor(input.ownerLarkAppId, input.key);
|
|
160
|
+
return withKeyLock(fp, () => {
|
|
161
|
+
const current = readRecord(fp);
|
|
162
|
+
if (!current) {
|
|
163
|
+
const rec = {
|
|
164
|
+
ownerLarkAppId: input.ownerLarkAppId, sessionId: input.sessionId, triggerId: input.triggerId,
|
|
165
|
+
requestHash: input.requestHash, ownerBootId: input.ownerBootId,
|
|
166
|
+
revision: 1, state: 'reserved', createdAt: input.now, updatedAt: input.now,
|
|
167
|
+
};
|
|
168
|
+
writeRecord(fp, rec);
|
|
169
|
+
return { kind: 'won', record: rec };
|
|
170
|
+
}
|
|
171
|
+
if (current.ownerLarkAppId !== input.ownerLarkAppId)
|
|
172
|
+
throw new Error('idempotency record owner mismatch');
|
|
173
|
+
if (current.requestHash !== input.requestHash)
|
|
174
|
+
throw new IdempotencyConflictError(current);
|
|
175
|
+
// Only replace the EXACT older-boot reserved lease we saw. Anything else
|
|
176
|
+
// (advanced to attempting, bumped revision, or now owned by a live boot) is
|
|
177
|
+
// reused, not seized.
|
|
178
|
+
const stillTakeoverTarget = current.state === 'reserved'
|
|
179
|
+
&& current.revision === input.expect.revision
|
|
180
|
+
&& current.ownerBootId === input.expect.ownerBootId
|
|
181
|
+
&& current.ownerBootId !== input.ownerBootId
|
|
182
|
+
&& sameIdentity(current, input.expect);
|
|
183
|
+
if (!stillTakeoverTarget) {
|
|
184
|
+
return { kind: 'existing', record: current };
|
|
185
|
+
}
|
|
186
|
+
const rec = {
|
|
187
|
+
ownerLarkAppId: input.ownerLarkAppId, sessionId: input.sessionId, triggerId: input.triggerId,
|
|
188
|
+
requestHash: input.requestHash, ownerBootId: input.ownerBootId,
|
|
189
|
+
revision: current.revision + 1, state: 'reserved', createdAt: current.createdAt, updatedAt: input.now,
|
|
190
|
+
};
|
|
191
|
+
writeRecord(fp, rec);
|
|
192
|
+
return { kind: 'won', record: rec };
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
/** CAS a record to a new state under the lock. Verifies full identity + revision
|
|
196
|
+
* before writing (rejects a stale/foreign writer). Returns the written record. */
|
|
197
|
+
export function transition(ownerLarkAppId, key, from, patch) {
|
|
198
|
+
const fp = fileFor(ownerLarkAppId, key);
|
|
199
|
+
return withKeyLock(fp, () => {
|
|
200
|
+
const current = readRecord(fp);
|
|
201
|
+
if (!current)
|
|
202
|
+
throw new Error('idempotency transition: record vanished');
|
|
203
|
+
if (current.revision !== from.revision || !sameIdentity(current, from)) {
|
|
204
|
+
throw new Error(`idempotency CAS conflict: on-disk record changed under expected revision ${from.revision}`);
|
|
205
|
+
}
|
|
206
|
+
const next = { ...current, state: patch.state, revision: current.revision + 1, updatedAt: patch.now };
|
|
207
|
+
writeRecord(fp, next);
|
|
208
|
+
return next;
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
/** Delete a file, treating ONLY ENOENT as "already gone". EIO/EROFS/EACCES etc.
|
|
212
|
+
* mean the file may still exist — the caller must NOT proceed as if released,
|
|
213
|
+
* so we throw (finding: a swallowed unlink error left a reserved lease stuck to
|
|
214
|
+
* a closed session). */
|
|
215
|
+
function strictUnlink(fp) {
|
|
216
|
+
try {
|
|
217
|
+
unlinkSync(fp);
|
|
218
|
+
}
|
|
219
|
+
catch (err) {
|
|
220
|
+
if (err?.code !== 'ENOENT')
|
|
221
|
+
throw err;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/** Compare-and-remove: delete the lease ONLY if it still matches `expect`
|
|
225
|
+
* (identity + revision + state) under the lock. Used to release a `reserved`
|
|
226
|
+
* lease we created but abandoned before dispatch. Returns a discriminated
|
|
227
|
+
* RemoveByPathResult (removed | absent | changed) — NOT a boolean — so the
|
|
228
|
+
* barrier-release caller can tell a clean release (retryable) apart from "the
|
|
229
|
+
* disk already advanced to attempting under me" (must durably terminalize, not
|
|
230
|
+
* delete) instead of swallowing both (finding #1). A lock-internal re-read
|
|
231
|
+
* corruption or an ambiguous unlink error (EIO/EROFS/…) THROWS — the caller
|
|
232
|
+
* must be able to trust that `removed` means the lease is truly released. */
|
|
233
|
+
export function compareAndRemove(ownerLarkAppId, key, expect) {
|
|
234
|
+
return compareAndRemoveByPath(fileFor(ownerLarkAppId, key), expect);
|
|
235
|
+
}
|
|
236
|
+
/** Enumerate the leases owned by a SINGLE bot (boot reconcile is owner-scoped).
|
|
237
|
+
* Reads only `idempotency/<sha256(owner)>/` — a foreign bot's corrupt lease
|
|
238
|
+
* lives under a different subdir and is never even opened here, so it can't
|
|
239
|
+
* block this owner's startup (finding #4). By default a corrupt file under THIS
|
|
240
|
+
* owner is logged + skipped; with `throwOnCorrupt`, a corrupt OWN lease THROWS
|
|
241
|
+
* (the reconcile can't prove it converged, so it must fail-closed rather than
|
|
242
|
+
* silently skip a possibly-unconverged attempting fence). */
|
|
243
|
+
export function listAllForOwner(ownerLarkAppId, opts = {}) {
|
|
244
|
+
const dir = ownerDir(ownerLarkAppId);
|
|
245
|
+
if (!existsSync(dir))
|
|
246
|
+
return [];
|
|
247
|
+
const out = [];
|
|
248
|
+
for (const name of readdirSync(dir)) {
|
|
249
|
+
if (!name.endsWith('.json'))
|
|
250
|
+
continue;
|
|
251
|
+
const fp = join(dir, name);
|
|
252
|
+
try {
|
|
253
|
+
const rec = readRecord(fp);
|
|
254
|
+
// Defence-in-depth: the dir is already owner-partitioned, but a stray file
|
|
255
|
+
// whose stamped owner disagrees is not ours to touch — skip it.
|
|
256
|
+
if (rec && rec.ownerLarkAppId === ownerLarkAppId)
|
|
257
|
+
out.push({ file: fp, record: rec });
|
|
258
|
+
}
|
|
259
|
+
catch (err) {
|
|
260
|
+
if (opts.throwOnCorrupt)
|
|
261
|
+
throw new Error(`unreadable idempotency lease ${fp}: ${err.message}`);
|
|
262
|
+
logger.warn(`[idempotency] skipping unreadable lease ${fp}: ${err}`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return out;
|
|
266
|
+
}
|
|
267
|
+
/** Reconcile-only compare-and-remove BY PATH (reconcile enumerated the file via
|
|
268
|
+
* listAllForOwner and holds a snapshot record; the plaintext key isn't
|
|
269
|
+
* recoverable from the hashed filename). Re-reads under the lock and removes
|
|
270
|
+
* ONLY if the on-disk record still matches the snapshot's full identity +
|
|
271
|
+
* revision + state — so a stale reserved snapshot can NOT delete a fence that
|
|
272
|
+
* has since advanced to `attempting` (finding: old sweep erasing a crossed
|
|
273
|
+
* commit-unknown barrier).
|
|
274
|
+
*
|
|
275
|
+
* Returns a discriminated result rather than a boolean so the reconcile can
|
|
276
|
+
* tell "converged (removed/absent)" apart from "changed under me" and act on
|
|
277
|
+
* the latter (finding #2: a bare `false` folded both the changed case AND a
|
|
278
|
+
* lock-internal corruption into a single value the caller ignored, declaring a
|
|
279
|
+
* non-convergence a success). The `changed` result carries `sameIdentity` so
|
|
280
|
+
* the caller never mistakes a DIFFERENT winner's record for its own advanced
|
|
281
|
+
* fence (findings #2/#3). A lock-internal re-read corruption or an ambiguous
|
|
282
|
+
* unlink error THROWS (fail-closed — the reconcile aborts startup rather than
|
|
283
|
+
* bind while a lease is in an unprovable state). */
|
|
284
|
+
export function compareAndRemoveByPath(fp, expect) {
|
|
285
|
+
return withKeyLock(fp, () => {
|
|
286
|
+
const current = readRecord(fp); // corrupt now → THROWS (never blind-delete, never fold to a success)
|
|
287
|
+
if (!current)
|
|
288
|
+
return { kind: 'absent' };
|
|
289
|
+
if (current.revision !== expect.revision || current.state !== expect.state || !sameIdentity(current, expect)) {
|
|
290
|
+
// Advanced/changed under us — hand it back for reclassification, marking
|
|
291
|
+
// whether it is STILL our exact immutable identity (only the mutable
|
|
292
|
+
// state/revision moved) or a wholly different winner replaced the slot.
|
|
293
|
+
return { kind: 'changed', current, sameIdentity: sameIdentity(current, expect) };
|
|
294
|
+
}
|
|
295
|
+
strictUnlink(fp); // throws on EIO/EROFS/… (never a silent success)
|
|
296
|
+
return { kind: 'removed' };
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
//# sourceMappingURL=idempotency-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idempotency-store.js","sourceRoot":"","sources":["../../src/services/idempotency-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,10 +8,14 @@ export interface JsonlScanOptions {
|
|
|
8
8
|
onLine?: (line: string, lineStart: number) => void;
|
|
9
9
|
onError?: (error: unknown) => void;
|
|
10
10
|
}
|
|
11
|
+
/** Scan a JSONL stream from a caller-owned regular file descriptor. The fd is
|
|
12
|
+
* never closed here; ownership stays with the caller. */
|
|
13
|
+
export declare function scanJsonlFromFd(fd: number, fromOffset: number, opts?: JsonlScanOptions): JsonlCursor | null;
|
|
11
14
|
/**
|
|
12
|
-
* Scan an append-only JSONL file from `fromOffset` using
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
+
* Scan an append-only JSONL file from `fromOffset` using chunked reads. Calls
|
|
16
|
+
* `onLine` for each COMPLETE line, and returns the durable byte frontier plus
|
|
17
|
+
* any trailing partial line text left after the last newline. One logical line
|
|
18
|
+
* is accumulated linearly, so memory remains proportional to that line length.
|
|
15
19
|
*/
|
|
16
20
|
export declare function scanJsonlFromOffset(path: string, fromOffset: number, opts?: JsonlScanOptions): JsonlCursor | null;
|
|
17
21
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsonl-cursor.d.ts","sourceRoot":"","sources":["../../src/services/jsonl-cursor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"jsonl-cursor.d.ts","sourceRoot":"","sources":["../../src/services/jsonl-cursor.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC;AA4DD;0DAC0D;AAC1D,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,GAAE,gBAAqB,GAAG,WAAW,GAAG,IAAI,CAE/G;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,GAAE,gBAAqB,GAAG,WAAW,GAAG,IAAI,CAiBrH;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAmC7D"}
|
|
@@ -1,29 +1,15 @@
|
|
|
1
1
|
import { closeSync, constants, existsSync, fstatSync, openSync, readSync, statSync, } from 'node:fs';
|
|
2
|
-
import { StringDecoder } from 'node:string_decoder';
|
|
3
2
|
const TAIL_PROBE_BYTES = 64 * 1024;
|
|
4
3
|
const JSONL_SCAN_CHUNK_BYTES = 64 * 1024;
|
|
5
|
-
|
|
6
|
-
* Scan an append-only JSONL file from `fromOffset` using bounded-memory chunked
|
|
7
|
-
* reads. Calls `onLine` for each COMPLETE line, and returns the durable byte
|
|
8
|
-
* frontier plus any trailing partial line text left after the last newline.
|
|
9
|
-
*/
|
|
10
|
-
export function scanJsonlFromOffset(path, fromOffset, opts = {}) {
|
|
4
|
+
function scanJsonlFromOpenFd(fd, fromOffset, opts = {}) {
|
|
11
5
|
const endOffset = opts.endOffset;
|
|
12
6
|
const chunkSize = Math.max(1, opts.chunkSize ?? JSONL_SCAN_CHUNK_BYTES);
|
|
13
|
-
let fd = null;
|
|
14
7
|
let nextReadOffset = Math.max(0, fromOffset);
|
|
15
8
|
let lineStartOffset = nextReadOffset;
|
|
16
|
-
let
|
|
17
|
-
|
|
9
|
+
let lineBuffers = [];
|
|
10
|
+
let lineBytes = 0;
|
|
18
11
|
const buf = Buffer.alloc(chunkSize);
|
|
19
12
|
try {
|
|
20
|
-
// O_NONBLOCK prevents an untrusted transcript path swapped to a FIFO from
|
|
21
|
-
// hanging the daemon. Validate the opened fd (rather than only the path)
|
|
22
|
-
// so directories/devices and the stat→open replacement window fail closed.
|
|
23
|
-
fd = openSync(path, constants.O_RDONLY | (constants.O_NONBLOCK ?? 0));
|
|
24
|
-
if (!fstatSync(fd).isFile()) {
|
|
25
|
-
throw new Error(`JSONL source is not a regular file: ${path}`);
|
|
26
|
-
}
|
|
27
13
|
while (true) {
|
|
28
14
|
const remaining = endOffset === undefined ? chunkSize : endOffset - nextReadOffset;
|
|
29
15
|
if (remaining <= 0)
|
|
@@ -33,33 +19,71 @@ export function scanJsonlFromOffset(path, fromOffset, opts = {}) {
|
|
|
33
19
|
if (bytesRead <= 0)
|
|
34
20
|
break;
|
|
35
21
|
nextReadOffset += bytesRead;
|
|
36
|
-
const decoded = decoder.write(buf.subarray(0, bytesRead));
|
|
37
|
-
const text = carry + decoded;
|
|
38
22
|
let searchFrom = 0;
|
|
39
|
-
let
|
|
40
|
-
// carry never contains '\n', so newlines can only appear at or after
|
|
41
|
-
// carry.length — starting there avoids re-scanning a growing carry on
|
|
42
|
-
// every chunk when a single record spans many chunks.
|
|
43
|
-
let nl = text.indexOf('\n', carry.length);
|
|
23
|
+
let nl = buf.subarray(0, bytesRead).indexOf(0x0a);
|
|
44
24
|
while (nl >= 0) {
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
25
|
+
const segment = Buffer.from(buf.subarray(searchFrom, nl));
|
|
26
|
+
if (segment.length > 0) {
|
|
27
|
+
lineBuffers.push(segment);
|
|
28
|
+
lineBytes += segment.length;
|
|
29
|
+
}
|
|
30
|
+
const line = lineBuffers.length === 1
|
|
31
|
+
? lineBuffers[0]
|
|
32
|
+
: Buffer.concat(lineBuffers, lineBytes);
|
|
33
|
+
opts.onLine?.(line.toString('utf8'), lineStartOffset);
|
|
48
34
|
searchFrom = nl + 1;
|
|
49
|
-
|
|
35
|
+
lineStartOffset += lineBytes + 1;
|
|
36
|
+
lineBuffers = [];
|
|
37
|
+
lineBytes = 0;
|
|
38
|
+
nl = buf.subarray(searchFrom, bytesRead).indexOf(0x0a);
|
|
39
|
+
if (nl >= 0)
|
|
40
|
+
nl += searchFrom;
|
|
41
|
+
}
|
|
42
|
+
if (searchFrom < bytesRead) {
|
|
43
|
+
const segment = Buffer.from(buf.subarray(searchFrom, bytesRead));
|
|
44
|
+
lineBuffers.push(segment);
|
|
45
|
+
lineBytes += segment.length;
|
|
50
46
|
}
|
|
51
|
-
carry = text.slice(searchFrom);
|
|
52
|
-
lineStartOffset = currentLineStart;
|
|
53
47
|
}
|
|
54
48
|
return {
|
|
55
49
|
newOffset: lineStartOffset,
|
|
56
|
-
pendingTail:
|
|
50
|
+
pendingTail: lineBuffers.length === 0
|
|
51
|
+
? ''
|
|
52
|
+
: (lineBuffers.length === 1 ? lineBuffers[0] : Buffer.concat(lineBuffers, lineBytes)).toString('utf8'),
|
|
57
53
|
};
|
|
58
54
|
}
|
|
59
55
|
catch (error) {
|
|
60
56
|
opts.onError?.(error);
|
|
61
57
|
return null;
|
|
62
58
|
}
|
|
59
|
+
}
|
|
60
|
+
/** Scan a JSONL stream from a caller-owned regular file descriptor. The fd is
|
|
61
|
+
* never closed here; ownership stays with the caller. */
|
|
62
|
+
export function scanJsonlFromFd(fd, fromOffset, opts = {}) {
|
|
63
|
+
return scanJsonlFromOpenFd(fd, fromOffset, opts);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Scan an append-only JSONL file from `fromOffset` using chunked reads. Calls
|
|
67
|
+
* `onLine` for each COMPLETE line, and returns the durable byte frontier plus
|
|
68
|
+
* any trailing partial line text left after the last newline. One logical line
|
|
69
|
+
* is accumulated linearly, so memory remains proportional to that line length.
|
|
70
|
+
*/
|
|
71
|
+
export function scanJsonlFromOffset(path, fromOffset, opts = {}) {
|
|
72
|
+
let fd = null;
|
|
73
|
+
try {
|
|
74
|
+
// O_NONBLOCK prevents an untrusted transcript path swapped to a FIFO from
|
|
75
|
+
// hanging the daemon. Validate the opened fd (rather than only the path)
|
|
76
|
+
// so directories/devices and the stat→open replacement window fail closed.
|
|
77
|
+
fd = openSync(path, constants.O_RDONLY | (constants.O_NONBLOCK ?? 0));
|
|
78
|
+
if (!fstatSync(fd).isFile()) {
|
|
79
|
+
throw new Error(`JSONL source is not a regular file: ${path}`);
|
|
80
|
+
}
|
|
81
|
+
return scanJsonlFromOpenFd(fd, fromOffset, opts);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
opts.onError?.(error);
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
63
87
|
finally {
|
|
64
88
|
if (fd !== null)
|
|
65
89
|
closeSync(fd);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsonl-cursor.js","sourceRoot":"","sources":["../../src/services/jsonl-cursor.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,SAAS,EACT,UAAU,EACV,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,QAAQ,GACT,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"jsonl-cursor.js","sourceRoot":"","sources":["../../src/services/jsonl-cursor.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"open-platform-rename.d.ts","sourceRoot":"","sources":["../../src/services/open-platform-rename.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAUL,KAAK,wBAAwB,EAC7B,KAAK,YAAY,EAClB,MAAM,sCAAsC,CAAC;
|
|
1
|
+
{"version":3,"file":"open-platform-rename.d.ts","sourceRoot":"","sources":["../../src/services/open-platform-rename.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAUL,KAAK,wBAAwB,EAC7B,KAAK,YAAY,EAClB,MAAM,sCAAsC,CAAC;AAE9C,OAAO,EAAkB,KAAK,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAGtE,MAAM,MAAM,+BAA+B,GACvC,mBAAmB,GACnB,YAAY,GACZ,iBAAiB,GACjB,WAAW,GACX,WAAW,CAAC;AAEhB,MAAM,MAAM,wBAAwB,GAChC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,+BAA+B,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5E,8CAA8C;AAC9C,MAAM,WAAW,sBAAsB;IACrC,WAAW,CAAC,EAAE,MAAM,YAAY,EAAE,GAAG,IAAI,CAAC;IAC1C,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,OAAO,CAAC,wBAAwB,CAAC,CAAC;CAChF;AA0MD;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,KAAK,GAAG,SAAS,EACxB,IAAI,GAAE,sBAA2B,GAChC,OAAO,CAAC,wBAAwB,CAAC,CAenC;AAID,MAAM,MAAM,wBAAwB,GAChC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,+BAA+B,GAAG,eAAe,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9F;gDACgD;AAChD,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,sBAAsB,QAAkB,CAAC;AAuBtD;;kDAEkD;AAClD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAqB7F;AASD;;;;GAIG;AACH,wBAAsB,6BAA6B,CACjD,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,KAAK,GAAG,SAAS,EACxB,IAAI,GAAE,sBAA2B,GAChC,OAAO,CAAC,wBAAwB,CAAC,CAqCnC"}
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
* • api_error — 其余 console API 失败(含审核中无法建版等)
|
|
22
22
|
*/
|
|
23
23
|
import { botmuxFeishuSessionFilePath, buildAppVersionCreatePayload, bytedcliFeishuSessionFilePath, createOpenPlatformApiClient, extractVersionId, nextAppVersion, OpenPlatformApiError, readStoredCookiesFromSessionFile, } from '../setup/open-platform-automation.js';
|
|
24
|
+
import { parseOnlineVisibility } from '../setup/open-platform-visibility.js';
|
|
24
25
|
import { normalizeBrand } from '../im/lark/lark-hosts.js';
|
|
25
26
|
import { logger } from '../utils/logger.js';
|
|
26
27
|
function defaultLoadCookies() {
|
|
@@ -37,114 +38,6 @@ function isPlainRecord(value) {
|
|
|
37
38
|
function asRecord(value) {
|
|
38
39
|
return isPlainRecord(value) ? value : {};
|
|
39
40
|
}
|
|
40
|
-
// visible/online 各集合的 id 字段族:console 内部接口的条目形态没有公开契约,
|
|
41
|
-
// members 实测是 { id },departments / groups 未实测——按开放平台常见命名把
|
|
42
|
-
// 候选 key 都列上,并配合下面的 fail-closed 兜底。
|
|
43
|
-
const MEMBER_ID_KEYS = ['id', 'openId', 'open_id', 'userId', 'user_id', 'memberId', 'member_id'];
|
|
44
|
-
const DEPARTMENT_ID_KEYS = ['id', 'departmentId', 'department_id', 'openDepartmentId', 'open_department_id'];
|
|
45
|
-
const GROUP_ID_KEYS = ['id', 'groupId', 'group_id', 'chatId', 'chat_id', 'openChatId', 'open_chat_id'];
|
|
46
|
-
/** 可见范围形态未识别 —— 绝不能发布可能改变可见性的版本,fail closed。 */
|
|
47
|
-
class VisibilityParseError extends Error {
|
|
48
|
-
collection;
|
|
49
|
-
constructor(collection) {
|
|
50
|
-
super(`visible/online ${collection} 形态未识别,已中止(避免把线上可见范围发布成空/发漏)`);
|
|
51
|
-
this.collection = collection;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
function pickIdByKeys(item, keys) {
|
|
55
|
-
if (typeof item === 'string')
|
|
56
|
-
return item;
|
|
57
|
-
if (typeof item === 'number' && Number.isFinite(item))
|
|
58
|
-
return String(item);
|
|
59
|
-
const rec = asRecord(item);
|
|
60
|
-
for (const key of keys) {
|
|
61
|
-
const v = rec[key];
|
|
62
|
-
if (typeof v === 'string' && v)
|
|
63
|
-
return v;
|
|
64
|
-
if (typeof v === 'number' && Number.isFinite(v))
|
|
65
|
-
return String(v);
|
|
66
|
-
}
|
|
67
|
-
return '';
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* 条目 → id 列表。fail closed:任何一个条目解析不出 id 就抛
|
|
71
|
-
* {@link VisibilityParseError}——部分丢失同样会收窄可见范围,宁可中止
|
|
72
|
-
* 走降级路径,也不发布一个"看起来成功"但少了人的版本。
|
|
73
|
-
*/
|
|
74
|
-
function idList(value, keys, collection) {
|
|
75
|
-
if (!Array.isArray(value))
|
|
76
|
-
return [];
|
|
77
|
-
const ids = value.map((item) => pickIdByKeys(item, keys)).filter(Boolean);
|
|
78
|
-
if (ids.length < value.length)
|
|
79
|
-
throw new VisibilityParseError(collection);
|
|
80
|
-
return ids;
|
|
81
|
-
}
|
|
82
|
-
/** 集合键:只有「键不存在」允许当空(仅 legacy 顶层形态的可选 groups 会走到);
|
|
83
|
-
* 键存在则值必须是数组——null/字符串等一律 fail closed,不得静默变空集合。 */
|
|
84
|
-
function idListStrict(rec, key, keys, label) {
|
|
85
|
-
if (!(key in rec))
|
|
86
|
-
return [];
|
|
87
|
-
const value = rec[key];
|
|
88
|
-
if (!Array.isArray(value))
|
|
89
|
-
throw new VisibilityParseError(`${label}.${key}`);
|
|
90
|
-
return idList(value, keys, `${label}.${key}`);
|
|
91
|
-
}
|
|
92
|
-
const EMPTY_VISIBILITY = { departments: [], members: [], groups: [], isAll: 0 };
|
|
93
|
-
/**
|
|
94
|
-
* visible/online 的白/黑名单块 → 版本 payload 的 visibleSuggest 形态。
|
|
95
|
-
* fail closed:块必须是对象且带齐 requiredKeys(实测线上契约 whiteList/blackList
|
|
96
|
-
* 恒有 departments/groups/members/isAll 四键)——{}、null、缺键的残缺响应一律
|
|
97
|
-
* 中止,绝不默认成「空可见范围」发布出去(那会把应用从所有人面前收走;黑名单
|
|
98
|
-
* 丢失同理会把被拉黑的人放出来)。
|
|
99
|
-
*/
|
|
100
|
-
function visibilityBlock(raw, label, requiredKeys) {
|
|
101
|
-
if (!isPlainRecord(raw))
|
|
102
|
-
throw new VisibilityParseError(label);
|
|
103
|
-
for (const key of requiredKeys) {
|
|
104
|
-
if (!(key in raw))
|
|
105
|
-
throw new VisibilityParseError(`${label}.${key}(缺失)`);
|
|
106
|
-
}
|
|
107
|
-
// isAll 只认 0/1/false/true:'1'、null 等异常值可能把「全员可见」误发布成
|
|
108
|
-
// 不可见(或反之),一律 fail closed。
|
|
109
|
-
const isAllRaw = raw.isAll;
|
|
110
|
-
if (isAllRaw !== 0 && isAllRaw !== 1 && isAllRaw !== false && isAllRaw !== true) {
|
|
111
|
-
throw new VisibilityParseError(`${label}.isAll`);
|
|
112
|
-
}
|
|
113
|
-
return {
|
|
114
|
-
departments: idListStrict(raw, 'departments', DEPARTMENT_ID_KEYS, label),
|
|
115
|
-
members: idListStrict(raw, 'members', MEMBER_ID_KEYS, label),
|
|
116
|
-
groups: idListStrict(raw, 'groups', GROUP_ID_KEYS, label),
|
|
117
|
-
isAll: isAllRaw === 1 || isAllRaw === true ? 1 : 0,
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
/** 现行契约块的必备键(实测所有 app 的 whiteList/blackList 都带齐这四键)。 */
|
|
121
|
-
const BLOCK_REQUIRED_KEYS = ['departments', 'groups', 'members', 'isAll'];
|
|
122
|
-
/** 旧形态(可见范围直接铺在 data 顶层)没有 groups 容器。 */
|
|
123
|
-
const LEGACY_TOP_REQUIRED_KEYS = ['departments', 'members', 'isAll'];
|
|
124
|
-
/**
|
|
125
|
-
* 解析 visible/online 响应为 白/黑名单 suggest 对。两种已知形态:
|
|
126
|
-
* • 现行:data.whiteList + data.blackList 成对出现(成对是契约的一部分——
|
|
127
|
-
* 只认白名单会把 blackList 静默丢成空、把被拉黑的人放出来,fail closed)
|
|
128
|
-
* • 旧形态兜底:可见范围直接铺在 data 顶层(无 whiteList 容器);此形态
|
|
129
|
-
* 没有黑名单容器,blackList 缺失按空处理,出现则严格解析
|
|
130
|
-
*/
|
|
131
|
-
function parseOnlineVisibility(payload) {
|
|
132
|
-
const data = asRecord(payload).data;
|
|
133
|
-
if (!isPlainRecord(data))
|
|
134
|
-
throw new VisibilityParseError('data');
|
|
135
|
-
if ('whiteList' in data) {
|
|
136
|
-
return {
|
|
137
|
-
visibleSuggest: visibilityBlock(data.whiteList, 'whiteList', BLOCK_REQUIRED_KEYS),
|
|
138
|
-
blackVisibleSuggest: visibilityBlock(data.blackList, 'blackList', BLOCK_REQUIRED_KEYS),
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
return {
|
|
142
|
-
visibleSuggest: visibilityBlock(data, 'whiteList', LEGACY_TOP_REQUIRED_KEYS),
|
|
143
|
-
blackVisibleSuggest: data.blackList == null
|
|
144
|
-
? { ...EMPTY_VISIBILITY }
|
|
145
|
-
: visibilityBlock(data.blackList, 'blackList', BLOCK_REQUIRED_KEYS),
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
41
|
function failureFromError(err, fallbackReason = 'api_error') {
|
|
149
42
|
if (err instanceof OpenPlatformApiError) {
|
|
150
43
|
const code = asRecord(err.payload).code;
|