whale-code 6.5.10 → 6.6.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/cli/chat/ChatApp.js +7 -11
- package/dist/cli/chat/ChatApp.js.map +1 -1
- package/dist/cli/chat/ChatInput.js +7 -3
- package/dist/cli/chat/ChatInput.js.map +1 -1
- package/dist/cli/chat/MessageList.js +5 -6
- package/dist/cli/chat/MessageList.js.map +1 -1
- package/dist/cli/chat/StatusBar.d.ts +2 -2
- package/dist/cli/chat/StatusBar.js +90 -160
- package/dist/cli/chat/StatusBar.js.map +1 -1
- package/dist/cli/chat/components/LiveArea.js +78 -115
- package/dist/cli/chat/components/LiveArea.js.map +1 -1
- package/dist/cli/chat/components/StaticMessages.js +60 -79
- package/dist/cli/chat/components/StaticMessages.js.map +1 -1
- package/dist/cli/chat/hooks/useAgentLoop.js +45 -37
- package/dist/cli/chat/hooks/useAgentLoop.js.map +1 -1
- package/dist/cli/chat/store.d.ts +12 -0
- package/dist/cli/chat/store.js +19 -0
- package/dist/cli/chat/store.js.map +1 -1
- package/dist/cli/commands/doctor.js +1 -6
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/services/agent-loop-tools.js +11 -2
- package/dist/cli/services/agent-loop-tools.js.map +1 -1
- package/dist/cli/services/agent-loop.js +1 -1
- package/dist/cli/services/agent-loop.js.map +1 -1
- package/dist/cli/services/cli-agent-loop.js +3 -2
- package/dist/cli/services/cli-agent-loop.js.map +1 -1
- package/dist/cli/services/config-store.d.ts +8 -10
- package/dist/cli/services/config-store.js +14 -13
- package/dist/cli/services/config-store.js.map +1 -1
- package/dist/cli/services/memory-manager.js +2 -2
- package/dist/cli/services/memory-manager.js.map +1 -1
- package/dist/cli/services/permission-modes.js +14 -10
- package/dist/cli/services/permission-modes.js.map +1 -1
- package/dist/cli/services/session-client.js +2 -1
- package/dist/cli/services/session-client.js.map +1 -1
- package/dist/cli/services/session-persistence.js +14 -6
- package/dist/cli/services/session-persistence.js.map +1 -1
- package/dist/cli/setup/SetupApp.d.ts +2 -2
- package/dist/cli/setup/SetupApp.js +91 -254
- package/dist/cli/setup/SetupApp.js.map +1 -1
- package/dist/cli/shared/SpinnerSlot.js +4 -1
- package/dist/cli/shared/SpinnerSlot.js.map +1 -1
- package/dist/cli/status/StatusApp.js +3 -3
- package/dist/cli/status/StatusApp.js.map +1 -1
- package/dist/index.js +13 -3
- package/dist/index.js.map +1 -1
- package/dist/server/handlers/browser-lifecycle.js +10 -0
- package/dist/server/handlers/browser-lifecycle.js.map +1 -1
- package/dist/server/handlers/browser.js +16 -1
- package/dist/server/handlers/browser.js.map +1 -1
- package/dist/server/handlers/campaigns.js +11 -0
- package/dist/server/handlers/campaigns.js.map +1 -1
- package/dist/server/handlers/catalog-products.js +19 -5
- package/dist/server/handlers/catalog-products.js.map +1 -1
- package/dist/server/handlers/catalog.js +42 -8
- package/dist/server/handlers/catalog.js.map +1 -1
- package/dist/server/handlers/clickhouse.js +4 -4
- package/dist/server/handlers/clickhouse.js.map +1 -1
- package/dist/server/handlers/comms-email.js +70 -8
- package/dist/server/handlers/comms-email.js.map +1 -1
- package/dist/server/handlers/comms.js +63 -21
- package/dist/server/handlers/comms.js.map +1 -1
- package/dist/server/handlers/coupons.js +141 -77
- package/dist/server/handlers/coupons.js.map +1 -1
- package/dist/server/handlers/google-ads.js +280 -8
- package/dist/server/handlers/google-ads.js.map +1 -1
- package/dist/server/handlers/remove-bg.d.ts +33 -0
- package/dist/server/handlers/remove-bg.js +698 -44
- package/dist/server/handlers/remove-bg.js.map +1 -1
- package/dist/server/handlers/supply-chain.js +93 -1
- package/dist/server/handlers/supply-chain.js.map +1 -1
- package/dist/server/handlers/workflow-steps-types.d.ts +1 -1
- package/dist/server/handlers/workflow-steps-types.js +7 -1
- package/dist/server/handlers/workflow-steps-types.js.map +1 -1
- package/dist/server/handlers/workflow-steps.js +1 -1
- package/dist/server/handlers/workflow-steps.js.map +1 -1
- package/dist/server/index.js +122 -29
- package/dist/server/index.js.map +1 -1
- package/dist/server/lib/agent-loop-turn.js +33 -3
- package/dist/server/lib/agent-loop-turn.js.map +1 -1
- package/dist/server/lib/agent-loop-types.d.ts +6 -2
- package/dist/server/lib/agent-loop-types.js +14 -2
- package/dist/server/lib/agent-loop-types.js.map +1 -1
- package/dist/server/lib/clickhouse-client.js +4 -2
- package/dist/server/lib/clickhouse-client.js.map +1 -1
- package/dist/server/lib/code-worker.js +4 -1
- package/dist/server/lib/code-worker.js.map +1 -1
- package/dist/server/providers/anthropic.js +103 -33
- package/dist/server/providers/anthropic.js.map +1 -1
- package/dist/server/server-chat.js +2 -2
- package/dist/server/server-chat.js.map +1 -1
- package/dist/server/server-helpers.d.ts +8 -1
- package/dist/server/server-helpers.js +17 -3
- package/dist/server/server-helpers.js.map +1 -1
- package/dist/server/server-persist.js +34 -21
- package/dist/server/server-persist.js.map +1 -1
- package/dist/server/server-rate-limit.d.ts +0 -1
- package/dist/server/server-rate-limit.js +5 -5
- package/dist/server/server-rate-limit.js.map +1 -1
- package/dist/server/server-routes-approvals.js +2 -2
- package/dist/server/server-routes-approvals.js.map +1 -1
- package/dist/server/server-routes-auth.js +2 -2
- package/dist/server/server-routes-auth.js.map +1 -1
- package/dist/server/server-routes-events.js +2 -2
- package/dist/server/server-routes-events.js.map +1 -1
- package/dist/server/server-routes-public.js +4 -4
- package/dist/server/server-routes-public.js.map +1 -1
- package/dist/server/server-routes-webchat.js +3 -3
- package/dist/server/server-routes-webchat.js.map +1 -1
- package/dist/server/server-store-circuit-breaker.js +1 -1
- package/dist/server/server-store-circuit-breaker.js.map +1 -1
- package/dist/server/tool-router.js +7 -4
- package/dist/server/tool-router.js.map +1 -1
- package/dist/server/validation.js +11 -0
- package/dist/server/validation.js.map +1 -1
- package/dist/setup.js +5 -25
- package/dist/setup.js.map +1 -1
- package/dist/shared/api-client.js +38 -11
- package/dist/shared/api-client.js.map +1 -1
- package/package.json +12 -10
- package/vendor/ink/build/ink.js +68 -24
- package/vendor/ink/node_modules/react-devtools-core/README.md +152 -0
- package/vendor/ink/node_modules/react-devtools-core/backend.js +1 -0
- package/vendor/ink/node_modules/react-devtools-core/dist/648.chunk.js +2 -0
- package/vendor/ink/node_modules/react-devtools-core/dist/648.chunk.js.map +1 -0
- package/vendor/ink/node_modules/react-devtools-core/dist/backend.js +15691 -0
- package/vendor/ink/node_modules/react-devtools-core/dist/backend.js.map +1 -0
- package/vendor/ink/node_modules/react-devtools-core/dist/importFile.worker.worker.js +2 -0
- package/vendor/ink/node_modules/react-devtools-core/dist/importFile.worker.worker.js.map +1 -0
- package/vendor/ink/node_modules/react-devtools-core/dist/parseSourceAndMetadata.worker.worker.js +14 -0
- package/vendor/ink/node_modules/react-devtools-core/dist/parseSourceAndMetadata.worker.worker.js.map +1 -0
- package/vendor/ink/node_modules/react-devtools-core/dist/standalone.js +2 -0
- package/vendor/ink/node_modules/react-devtools-core/dist/standalone.js.map +1 -0
- package/vendor/ink/node_modules/react-devtools-core/node_modules/ws/LICENSE +21 -0
- package/vendor/ink/node_modules/react-devtools-core/node_modules/ws/README.md +495 -0
- package/vendor/ink/node_modules/react-devtools-core/node_modules/ws/browser.js +8 -0
- package/vendor/ink/node_modules/react-devtools-core/node_modules/ws/index.js +10 -0
- package/vendor/ink/node_modules/react-devtools-core/node_modules/ws/lib/buffer-util.js +129 -0
- package/vendor/ink/node_modules/react-devtools-core/node_modules/ws/lib/constants.js +10 -0
- package/vendor/ink/node_modules/react-devtools-core/node_modules/ws/lib/event-target.js +184 -0
- package/vendor/ink/node_modules/react-devtools-core/node_modules/ws/lib/extension.js +223 -0
- package/vendor/ink/node_modules/react-devtools-core/node_modules/ws/lib/limiter.js +55 -0
- package/vendor/ink/node_modules/react-devtools-core/node_modules/ws/lib/permessage-deflate.js +518 -0
- package/vendor/ink/node_modules/react-devtools-core/node_modules/ws/lib/receiver.js +607 -0
- package/vendor/ink/node_modules/react-devtools-core/node_modules/ws/lib/sender.js +409 -0
- package/vendor/ink/node_modules/react-devtools-core/node_modules/ws/lib/stream.js +180 -0
- package/vendor/ink/node_modules/react-devtools-core/node_modules/ws/lib/validation.js +104 -0
- package/vendor/ink/node_modules/react-devtools-core/node_modules/ws/lib/websocket-server.js +449 -0
- package/vendor/ink/node_modules/react-devtools-core/node_modules/ws/lib/websocket.js +1197 -0
- package/vendor/ink/node_modules/react-devtools-core/node_modules/ws/package.json +56 -0
- package/vendor/ink/node_modules/react-devtools-core/package.json +38 -0
- package/vendor/ink/node_modules/react-devtools-core/standalone.js +1 -0
- package/dist/cli/__tests__/print-mode-streaming.test.js +0 -270
- package/dist/cli/__tests__/print-mode.basic-output.test.js +0 -230
- package/dist/cli/__tests__/print-mode.session-errors.test.js +0 -252
- package/dist/cli/__tests__/print-mode.test.js +0 -273
- package/dist/cli/__tests__/serve-mode-messages.test.js +0 -338
- package/dist/cli/__tests__/serve-mode.messages.part2.test.js +0 -266
- package/dist/cli/__tests__/serve-mode.messages.test.js +0 -277
- package/dist/cli/__tests__/serve-mode.startup-http.test.js +0 -279
- package/dist/cli/__tests__/serve-mode.test.js +0 -345
- package/dist/cli/chat/NodeManager.d.ts +0 -30
- package/dist/cli/chat/NodeManager.js +0 -66
- package/dist/cli/chat/NodeManager.js.map +0 -1
- package/dist/cli/chat/chat-input-menu-handler.d.ts +0 -32
- package/dist/cli/chat/hooks/slash-imsg-handlers.js +0 -148
- package/dist/cli/chat/hooks/slash-imsg-handlers.js.map +0 -1
- package/dist/cli/chat/hooks/useStreamingReducer.d.ts +0 -66
- package/dist/cli/commands/__tests__/config-cmd.test.js +0 -270
- package/dist/cli/commands/__tests__/doctor.test.js +0 -257
- package/dist/cli/commands/__tests__/imsg-node-bridge.test.js +0 -99
- package/dist/cli/commands/__tests__/imsg-utils.test.js +0 -73
- package/dist/cli/commands/__tests__/init.test.js +0 -214
- package/dist/cli/commands/__tests__/mcp.test.js +0 -287
- package/dist/cli/commands/imsg-watcher-helpers.d.ts +0 -40
- package/dist/cli/commands/imsg-watcher-helpers.js +0 -184
- package/dist/cli/commands/imsg-watcher-helpers.js.map +0 -1
- package/dist/cli/commands/imsg-watcher.d.ts +0 -11
- package/dist/cli/commands/imsg-watcher.js +0 -230
- package/dist/cli/commands/imsg-watcher.js.map +0 -1
- package/dist/cli/services/__tests__/agent-definitions.test.js +0 -153
- package/dist/cli/services/__tests__/agent-events-global.test.js +0 -39
- package/dist/cli/services/__tests__/agent-events.part2.test.js +0 -113
- package/dist/cli/services/__tests__/agent-events.test.js +0 -157
- package/dist/cli/services/__tests__/agent-loop-auth.test.js +0 -392
- package/dist/cli/services/__tests__/agent-loop-budget.test.js +0 -389
- package/dist/cli/services/__tests__/agent-loop-tools-lifecycle.test.js +0 -430
- package/dist/cli/services/__tests__/agent-loop-tools-maxturns.test.js +0 -486
- package/dist/cli/services/__tests__/agent-loop-utils-execution.test.js +0 -528
- package/dist/cli/services/__tests__/agent-loop-utils-helpers.test.js +0 -466
- package/dist/cli/services/__tests__/agent-worker-base-execute.test.js +0 -257
- package/dist/cli/services/__tests__/agent-worker-base-helpers.test.js +0 -198
- package/dist/cli/services/__tests__/agent-worker-base.test.js +0 -278
- package/dist/cli/services/__tests__/auth-service-exports.test.js +0 -41
- package/dist/cli/services/__tests__/auth-service.part2.test.js +0 -169
- package/dist/cli/services/__tests__/auth-service.test.js +0 -242
- package/dist/cli/services/__tests__/background-processes.test.js +0 -282
- package/dist/cli/services/__tests__/claude-md-loader.test.js +0 -134
- package/dist/cli/services/__tests__/config-store.test.js +0 -247
- package/dist/cli/services/__tests__/debug-log.test.js +0 -199
- package/dist/cli/services/__tests__/edge-cases-caching.test.js +0 -174
- package/dist/cli/services/__tests__/edge-cases-compaction-core.test.js +0 -226
- package/dist/cli/services/__tests__/edge-cases-compaction-openai.test.js +0 -152
- package/dist/cli/services/__tests__/edge-cases-compaction-shapes.test.js +0 -53
- package/dist/cli/services/__tests__/edge-cases-compaction-thinking.test.js +0 -226
- package/dist/cli/services/__tests__/edge-cases-compaction.test.js +0 -131
- package/dist/cli/services/__tests__/edge-cases-paths.test.js +0 -86
- package/dist/cli/services/__tests__/error-logger-messages.test.js +0 -81
- package/dist/cli/services/__tests__/error-logger-transport.test.js +0 -119
- package/dist/cli/services/__tests__/error-logger.test.js +0 -264
- package/dist/cli/services/__tests__/file-history.test.js +0 -136
- package/dist/cli/services/__tests__/git-context-cache-reset.test.js +0 -223
- package/dist/cli/services/__tests__/git-context.test.js +0 -241
- package/dist/cli/services/__tests__/interactive-tools-execute.test.js +0 -166
- package/dist/cli/services/__tests__/interactive-tools-plan.test.js +0 -197
- package/dist/cli/services/__tests__/interactive-tools.part2.test.js +0 -168
- package/dist/cli/services/__tests__/interactive-tools.test.js +0 -179
- package/dist/cli/services/__tests__/keybinding-manager.test.js +0 -205
- package/dist/cli/services/__tests__/local-tools-dispatch.test.js +0 -404
- package/dist/cli/services/__tests__/local-tools.test.js +0 -238
- package/dist/cli/services/__tests__/lsp-manager.test.js +0 -364
- package/dist/cli/services/__tests__/mcp-client-connect-disconnect.test.js +0 -310
- package/dist/cli/services/__tests__/mcp-client.test.js +0 -93
- package/dist/cli/services/__tests__/memory-manager.test.js +0 -154
- package/dist/cli/services/__tests__/model-manager-utils.test.js +0 -154
- package/dist/cli/services/__tests__/model-manager.test.js +0 -175
- package/dist/cli/services/__tests__/permission-modes.test.js +0 -222
- package/dist/cli/services/__tests__/ripgrep.test.js +0 -328
- package/dist/cli/services/__tests__/server-tools-execute.test.js +0 -317
- package/dist/cli/services/__tests__/server-tools.test.js +0 -272
- package/dist/cli/services/__tests__/session-persistence.test.js +0 -245
- package/dist/cli/services/__tests__/subagent-basic.test.js +0 -489
- package/dist/cli/services/__tests__/subagent-edge.test.js +0 -545
- package/dist/cli/services/__tests__/subagent-prompts.test.js +0 -558
- package/dist/cli/services/__tests__/subagent-worker-errors.test.js +0 -255
- package/dist/cli/services/__tests__/subagent-worker.test.js +0 -242
- package/dist/cli/services/__tests__/system-prompt.test.js +0 -210
- package/dist/cli/services/__tests__/team-lead-comms-messaging.test.js +0 -250
- package/dist/cli/services/__tests__/team-lead-comms-result.test.js +0 -232
- package/dist/cli/services/__tests__/team-lead-comms-stop.test.js +0 -344
- package/dist/cli/services/__tests__/team-lead-comms.test.js +0 -285
- package/dist/cli/services/__tests__/team-lead-create.test.js +0 -327
- package/dist/cli/services/__tests__/team-lead-run.test.js +0 -318
- package/dist/cli/services/__tests__/team-lead-stop.test.js +0 -199
- package/dist/cli/services/__tests__/team-state-comms.test.js +0 -240
- package/dist/cli/services/__tests__/team-state-core.test.js +0 -230
- package/dist/cli/services/__tests__/team-state-tasks-complete-fail-available.test.js +0 -224
- package/dist/cli/services/__tests__/team-state-tasks.test.js +0 -184
- package/dist/cli/services/__tests__/telemetry-ai-metadata.test.js +0 -116
- package/dist/cli/services/__tests__/telemetry.part2.test.js +0 -195
- package/dist/cli/services/__tests__/telemetry.test.js +0 -176
- package/dist/cli/services/agent-loop-iteration.d.ts +0 -13
- package/dist/cli/services/agent-loop-setup.d.ts +0 -32
- package/dist/cli/services/agent-worker-base-api.d.ts +0 -19
- package/dist/cli/services/agent-worker-base-helpers.d.ts +0 -27
- package/dist/cli/services/agent-worker-base-tools.d.ts +0 -16
- package/dist/cli/services/agent-worker-base-types.d.ts +0 -81
- package/dist/cli/services/background-agents.d.ts +0 -26
- package/dist/cli/services/background-processes-ops.d.ts +0 -24
- package/dist/cli/services/background-tool-defs.d.ts +0 -50
- package/dist/cli/services/config-modules-model.test.js +0 -133
- package/dist/cli/services/config-modules-permission.test.js +0 -85
- package/dist/cli/services/config-modules-permissions.test.js +0 -85
- package/dist/cli/services/config-modules-session.test.js +0 -297
- package/dist/cli/services/format-server-response-columns.test.js +0 -265
- package/dist/cli/services/format-server-response-fallback.test.js +0 -65
- package/dist/cli/services/format-server-response-primitives-basic.test.js +0 -261
- package/dist/cli/services/format-server-response-primitives-nested.test.js +0 -188
- package/dist/cli/services/format-server-response-primitives.test.js +0 -300
- package/dist/cli/services/format-server-response-realworld.test.js +0 -248
- package/dist/cli/services/format-server-response-values.test.js +0 -247
- package/dist/cli/services/hooks-runners.test.js +0 -184
- package/dist/cli/services/hooks.glob-load.test.js +0 -233
- package/dist/cli/services/hooks.run-hooks.test.js +0 -184
- package/dist/cli/services/hooks.test.js +0 -233
- package/dist/cli/services/ink-incremental.d.ts +0 -19
- package/dist/cli/services/ink-incremental.js +0 -59
- package/dist/cli/services/ink-incremental.js.map +0 -1
- package/dist/cli/services/ink-resize-fix.d.ts +0 -18
- package/dist/cli/services/ink-resize-fix.js +0 -76
- package/dist/cli/services/ink-resize-fix.js.map +0 -1
- package/dist/cli/services/ink-sync-output.d.ts +0 -12
- package/dist/cli/services/ink-sync-output.js +0 -16
- package/dist/cli/services/ink-sync-output.js.map +0 -1
- package/dist/cli/services/interactive-tool-defs.d.ts +0 -80
- package/dist/cli/services/local-tools-definitions.d.ts +0 -6
- package/dist/cli/services/local-tools-files.test.js +0 -256
- package/dist/cli/services/local-tools-read-many.d.ts +0 -6
- package/dist/cli/services/model-router.test.js +0 -245
- package/dist/cli/services/rewind-rewindTo.test.js +0 -202
- package/dist/cli/services/rewind.test.js +0 -175
- package/dist/cli/services/sandbox.test.js +0 -198
- package/dist/cli/services/subagent-execution.d.ts +0 -12
- package/dist/cli/services/team-lead-auto.d.ts +0 -11
- package/dist/cli/services/team-lead-execution.d.ts +0 -28
- package/dist/cli/services/teammate-loop.js +0 -557
- package/dist/cli/services/teammate-loop.js.map +0 -1
- package/dist/cli/services/tools/__tests__/agent-tools-tasks-teams.test.js +0 -250
- package/dist/cli/services/tools/__tests__/agent-tools-teams.test.js +0 -200
- package/dist/cli/services/tools/__tests__/agent-tools.test.js +0 -340
- package/dist/cli/services/tools/__tests__/file-ops-cache.test.js +0 -152
- package/dist/cli/services/tools/__tests__/file-ops-notebook.test.js +0 -249
- package/dist/cli/services/tools/__tests__/file-ops-read.test.js +0 -261
- package/dist/cli/services/tools/__tests__/file-ops-write.test.js +0 -292
- package/dist/cli/services/tools/__tests__/search-tools-rg.test.js +0 -92
- package/dist/cli/services/tools/__tests__/search-tools.part2.test.js +0 -174
- package/dist/cli/services/tools/__tests__/search-tools.test.js +0 -227
- package/dist/cli/services/tools/__tests__/shell-exec-allowed-core.test.js +0 -163
- package/dist/cli/services/tools/__tests__/shell-exec-allowed-extended.test.js +0 -220
- package/dist/cli/services/tools/__tests__/shell-exec-allowed.part2.test.js +0 -215
- package/dist/cli/services/tools/__tests__/shell-exec-allowed.test.js +0 -154
- package/dist/cli/services/tools/__tests__/shell-exec-blocked.test.js +0 -132
- package/dist/cli/services/tools/__tests__/shell-exec-execution.test.js +0 -245
- package/dist/cli/services/tools/__tests__/task-manager-create.test.js +0 -110
- package/dist/cli/services/tools/__tests__/task-manager-crud.test.js +0 -339
- package/dist/cli/services/tools/__tests__/task-manager-list-get.test.js +0 -343
- package/dist/cli/services/tools/__tests__/task-manager-query.test.js +0 -346
- package/dist/cli/services/tools/__tests__/task-manager-routing.test.js +0 -58
- package/dist/cli/services/tools/__tests__/task-manager-update.test.js +0 -224
- package/dist/cli/services/tools/__tests__/task-manager.test.js +0 -159
- package/dist/cli/services/tools/__tests__/web-tools-html-search.test.js +0 -227
- package/dist/cli/services/tools/__tests__/web-tools.test.js +0 -285
- package/dist/cli/services/tools/shell-exec.test.js +0 -148
- package/dist/cli/shared/SharedTick.d.ts +0 -10
- package/dist/cli/shared/__tests__/markdown.test.js +0 -188
- package/dist/local-agent/__tests__/connection-disconnect.test.js +0 -201
- package/dist/local-agent/__tests__/connection-lifecycle.test.js +0 -289
- package/dist/local-agent/__tests__/connection-msghandling.test.js +0 -311
- package/dist/local-agent/__tests__/connection-reconnect.test.js +0 -230
- package/dist/local-agent/__tests__/connection-toolexec.test.js +0 -253
- package/dist/local-agent/__tests__/discovery.test.js +0 -328
- package/dist/local-agent/__tests__/executor-background.test.js +0 -219
- package/dist/local-agent/__tests__/executor-exec.test.js +0 -221
- package/dist/local-agent/__tests__/executor-jobs-sessions.test.js +0 -220
- package/dist/local-agent/__tests__/executor-system-info.test.js +0 -133
- package/dist/local-agent/__tests__/executor-systeminfo.test.js +0 -109
- package/dist/local-agent/__tests__/executor.test.js +0 -235
- package/dist/local-agent/__tests__/index.test.js +0 -139
- package/dist/node/__tests__/cli-channels.test.js +0 -293
- package/dist/node/__tests__/cli-config-edge.test.js +0 -154
- package/dist/node/__tests__/cli-config.test.js +0 -215
- package/dist/node/__tests__/config.test.js +0 -292
- package/dist/node/__tests__/runtime-heartbeat.test.js +0 -153
- package/dist/node/__tests__/runtime-lifecycle-init.test.js +0 -263
- package/dist/node/__tests__/runtime-lifecycle-stats.test.js +0 -180
- package/dist/node/__tests__/runtime-lifecycle.test.js +0 -305
- package/dist/node/__tests__/runtime-relay.test.js +0 -341
- package/dist/node/adapters/__tests__/base.test.js +0 -286
- package/dist/node/adapters/__tests__/discord.test.js +0 -284
- package/dist/node/adapters/__tests__/email-send.test.js +0 -295
- package/dist/node/adapters/__tests__/email.inbound-send.test.js +0 -217
- package/dist/node/adapters/__tests__/email.lifecycle.test.js +0 -211
- package/dist/node/adapters/__tests__/email.test.js +0 -290
- package/dist/node/adapters/__tests__/email.webhook-send.test.js +0 -251
- package/dist/node/adapters/__tests__/imessage-filter.test.js +0 -183
- package/dist/node/adapters/__tests__/imessage-lifecycle.test.js +0 -215
- package/dist/node/adapters/__tests__/imessage-send-restart.test.js +0 -227
- package/dist/node/adapters/__tests__/slack.part2.test.js +0 -135
- package/dist/node/adapters/__tests__/slack.test.js +0 -241
- package/dist/node/adapters/__tests__/sms-extras.test.js +0 -108
- package/dist/node/adapters/__tests__/sms-lifecycle.test.js +0 -203
- package/dist/node/adapters/__tests__/sms-messaging.test.js +0 -266
- package/dist/node/adapters/__tests__/sms.part2.test.js +0 -174
- package/dist/node/adapters/__tests__/sms.test.js +0 -253
- package/dist/node/adapters/__tests__/telegram-polling.test.js +0 -256
- package/dist/node/adapters/__tests__/telegram-send.test.js +0 -166
- package/dist/node/adapters/__tests__/webchat-inbound.test.js +0 -188
- package/dist/node/adapters/__tests__/webchat-outbound.test.js +0 -178
- package/dist/node/adapters/__tests__/whatsapp-inbound.test.js +0 -200
- package/dist/node/adapters/__tests__/whatsapp-send.test.js +0 -212
- package/dist/node/adapters/__tests__/whatsapp.test.js +0 -280
- package/dist/server/__tests__/gateway-fast-fail.test.js +0 -160
- package/dist/server/__tests__/local-agent-gateway.test.js +0 -186
- package/dist/server/__tests__/proxy-handlers-delegation.test.js +0 -240
- package/dist/server/__tests__/proxy-handlers-validation.test.js +0 -211
- package/dist/server/__tests__/proxy-handlers.part2.test.js +0 -240
- package/dist/server/__tests__/proxy-handlers.test.js +0 -213
- package/dist/server/__tests__/strip-base64-e2e.test.js +0 -303
- package/dist/server/__tests__/strip-base64.test.js +0 -256
- package/dist/server/__tests__/tool-router-agent-tools.test.js +0 -324
- package/dist/server/__tests__/tool-router-execute-core.test.js +0 -357
- package/dist/server/__tests__/tool-router-execute-permissions.test.js +0 -332
- package/dist/server/__tests__/tool-router-execute.test.js +0 -348
- package/dist/server/__tests__/tool-router-load.test.js +0 -432
- package/dist/server/__tests__/tool-router-permissions.test.js +0 -359
- package/dist/server/__tests__/tool-router-registry-cache.test.js +0 -383
- package/dist/server/__tests__/tool-router-registry-handlers.test.js +0 -272
- package/dist/server/__tests__/tool-router-registry.test.js +0 -331
- package/dist/server/__tests__/validation-inventory.test.js +0 -250
- package/dist/server/__tests__/validation-misc.test.js +0 -243
- package/dist/server/__tests__/validation-supply-chain.test.js +0 -188
- package/dist/server/__tests__/worker.test.js +0 -265
- package/dist/server/handlers/__tests__/conversation-lock.test.js +0 -117
- package/dist/server/handlers/__tests__/e2e/auth-cross-platform-login.e2e.test.js +0 -268
- package/dist/server/handlers/__tests__/e2e/auth-cross-platform-tokens.e2e.test.js +0 -264
- package/dist/server/handlers/__tests__/e2e/email-pipeline-send.e2e.test.js +0 -214
- package/dist/server/handlers/__tests__/e2e/email-pipeline-threads.e2e.test.js +0 -168
- package/dist/server/handlers/__tests__/e2e/error-logging-pipeline-dedup.e2e.test.js +0 -229
- package/dist/server/handlers/__tests__/e2e/error-logging-pipeline.e2e.test.js +0 -239
- package/dist/server/handlers/__tests__/e2e/error-logging-rate-limit.e2e.test.js +0 -150
- package/dist/server/handlers/__tests__/e2e/inventory-sync-guards.e2e.test.js +0 -177
- package/dist/server/handlers/__tests__/e2e/inventory-sync.e2e.test.js +0 -228
- package/dist/server/handlers/__tests__/e2e/inventory-sync.part2.e2e.test.js +0 -188
- package/dist/server/handlers/__tests__/e2e/order-lifecycle-fulfillment.e2e.test.js +0 -295
- package/dist/server/handlers/__tests__/e2e/order-lifecycle.e2e.test.js +0 -277
- package/dist/server/handlers/__tests__/e2e/order-lifecycle.fulfillment.e2e.test.js +0 -307
- package/dist/server/handlers/__tests__/e2e/order-lifecycle.setup.e2e.test.js +0 -177
- package/dist/server/handlers/__tests__/e2e/storefront-checkout-cart.e2e.test.js +0 -255
- package/dist/server/handlers/__tests__/e2e/storefront-checkout-webhook.e2e.test.js +0 -231
- package/dist/server/handlers/__tests__/e2e/workflow-execution-failures.e2e.test.js +0 -235
- package/dist/server/handlers/__tests__/e2e/workflow-execution.e2e.test.js +0 -294
- package/dist/server/handlers/__tests__/e2e/workflow-security.e2e.test.js +0 -311
- package/dist/server/handlers/__tests__/e2e/workflow-security.part2.e2e.test.js +0 -267
- package/dist/server/handlers/__tests__/workflow-cache.test.js +0 -237
- package/dist/server/handlers/analytics-errors-edge.test.js +0 -173
- package/dist/server/handlers/analytics.test.js +0 -280
- package/dist/server/handlers/api-docs-examples-ext.d.ts +0 -9
- package/dist/server/handlers/api-docs-examples-ext.js +0 -278
- package/dist/server/handlers/api-docs-examples-ext.js.map +0 -1
- package/dist/server/handlers/api-docs-examples.d.ts +0 -8
- package/dist/server/handlers/api-docs-examples.js +0 -221
- package/dist/server/handlers/api-docs-examples.js.map +0 -1
- package/dist/server/handlers/api-docs-sections-ext.d.ts +0 -2
- package/dist/server/handlers/api-docs-sections-ext.js +0 -497
- package/dist/server/handlers/api-docs-sections-ext.js.map +0 -1
- package/dist/server/handlers/api-docs-sections.d.ts +0 -21
- package/dist/server/handlers/api-docs-sections.js +0 -293
- package/dist/server/handlers/api-docs-sections.js.map +0 -1
- package/dist/server/handlers/api-keys.part2.test.js +0 -157
- package/dist/server/handlers/api-keys.test.js +0 -161
- package/dist/server/handlers/billing-routes.test.js +0 -123
- package/dist/server/handlers/billing.test.js +0 -215
- package/dist/server/handlers/browser-actions-errors.test.js +0 -94
- package/dist/server/handlers/browser-actions.part2.test.js +0 -190
- package/dist/server/handlers/browser-actions.test.js +0 -190
- package/dist/server/handlers/browser-validation.test.js +0 -257
- package/dist/server/handlers/catalog.test.js +0 -297
- package/dist/server/handlers/comms.test.js +0 -289
- package/dist/server/handlers/creations-advanced-collections.test.js +0 -214
- package/dist/server/handlers/creations-advanced-generate.test.js +0 -142
- package/dist/server/handlers/creations-advanced.test.js +0 -171
- package/dist/server/handlers/creations-collections-preview.test.js +0 -214
- package/dist/server/handlers/creations-crud.test.js +0 -260
- package/dist/server/handlers/creations-mutations.test.js +0 -197
- package/dist/server/handlers/crm.test.js +0 -179
- package/dist/server/handlers/discovery-advertise.test.js +0 -185
- package/dist/server/handlers/discovery-scan.test.js +0 -233
- package/dist/server/handlers/embeddings-embed-search.test.js +0 -196
- package/dist/server/handlers/embeddings-index-delete-stats.test.js +0 -140
- package/dist/server/handlers/embeddings-search.test.js +0 -221
- package/dist/server/handlers/embeddings.test.js +0 -137
- package/dist/server/handlers/enrichment-breach.d.ts +0 -8
- package/dist/server/handlers/enrichment-breach.js +0 -266
- package/dist/server/handlers/enrichment-breach.js.map +0 -1
- package/dist/server/handlers/enrichment-data.d.ts +0 -13
- package/dist/server/handlers/enrichment-data.js +0 -145
- package/dist/server/handlers/enrichment-data.js.map +0 -1
- package/dist/server/handlers/enrichment-mutations.test.js +0 -240
- package/dist/server/handlers/enrichment-queries.test.js +0 -181
- package/dist/server/handlers/enrichment-validation.test.js +0 -177
- package/dist/server/handlers/enrichment-writes.d.ts +0 -16
- package/dist/server/handlers/enrichment-writes.js +0 -226
- package/dist/server/handlers/enrichment-writes.js.map +0 -1
- package/dist/server/handlers/image-gen.test.js +0 -205
- package/dist/server/handlers/inventory.test.js +0 -380
- package/dist/server/handlers/kali-background.test.js +0 -222
- package/dist/server/handlers/kali-errors.test.js +0 -92
- package/dist/server/handlers/kali-validation.test.js +0 -234
- package/dist/server/handlers/llm-providers-actions.test.js +0 -220
- package/dist/server/handlers/llm-providers-anthropic.test.js +0 -239
- package/dist/server/handlers/llm-providers-failover.test.js +0 -232
- package/dist/server/handlers/llm-providers-providers.test.js +0 -300
- package/dist/server/handlers/llm-providers-validation.test.js +0 -239
- package/dist/server/handlers/local-agent-tools.test.js +0 -224
- package/dist/server/handlers/local-agent.test.js +0 -198
- package/dist/server/handlers/local-agent.tools-status.test.js +0 -204
- package/dist/server/handlers/local-agent.validation-exec.test.js +0 -182
- package/dist/server/handlers/meta-ads-audience-rules.test.js +0 -243
- package/dist/server/handlers/meta-ads-audience-targeting.test.js +0 -205
- package/dist/server/handlers/meta-ads-audiences-targeting.test.js +0 -383
- package/dist/server/handlers/meta-ads-crud-ads.test.js +0 -136
- package/dist/server/handlers/meta-ads-crud-campaigns.test.js +0 -189
- package/dist/server/handlers/meta-ads-crud-create.test.js +0 -303
- package/dist/server/handlers/meta-ads-crud-list-update.test.js +0 -259
- package/dist/server/handlers/meta-ads-delete-publish-sync.test.js +0 -282
- package/dist/server/handlers/meta-ads-insights.test.js +0 -80
- package/dist/server/handlers/meta-ads-list-get.test.js +0 -237
- package/dist/server/handlers/meta-ads-publish-delete.test.js +0 -254
- package/dist/server/handlers/meta-ads-publish-helpers.js +0 -117
- package/dist/server/handlers/meta-ads-publish-helpers.js.map +0 -1
- package/dist/server/handlers/meta-ads-publish-sync.test.js +0 -205
- package/dist/server/handlers/meta-ads-publish.test.js +0 -254
- package/dist/server/handlers/meta-ads-sync-insights.test.js +0 -184
- package/dist/server/handlers/meta-ads-update.test.js +0 -117
- package/dist/server/handlers/nodes-channels.test.js +0 -413
- package/dist/server/handlers/nodes-events.test.js +0 -131
- package/dist/server/handlers/nodes-list-delete.test.js +0 -171
- package/dist/server/handlers/nodes-messages-delivery.test.js +0 -208
- package/dist/server/handlers/nodes-messages.test.js +0 -211
- package/dist/server/handlers/nodes-register.test.js +0 -277
- package/dist/server/handlers/nodes.test.js +0 -353
- package/dist/server/handlers/operations.test.js +0 -136
- package/dist/server/handlers/platform-telemetry.test.js +0 -200
- package/dist/server/handlers/platform-websearch.test.js +0 -160
- package/dist/server/handlers/storefront.test.js +0 -329
- package/dist/server/handlers/supply-chain.test.js +0 -347
- package/dist/server/handlers/transcription.test.js +0 -118
- package/dist/server/handlers/video-gen-veo.js +0 -114
- package/dist/server/handlers/video-gen-veo.js.map +0 -1
- package/dist/server/handlers/video-gen.test.js +0 -146
- package/dist/server/handlers/voice.test.js +0 -153
- package/dist/server/handlers/workflow-steps.test.js +0 -330
- package/dist/server/handlers/workflows-extras.test.js +0 -65
- package/dist/server/handlers/workflows.part2.test.js +0 -170
- package/dist/server/handlers/workflows.test.js +0 -281
- package/dist/server/lib/__tests__/batch-client-conversion-jsonl.test.js +0 -171
- package/dist/server/lib/__tests__/batch-client-polling.test.js +0 -292
- package/dist/server/lib/__tests__/batch-client-queue.test.js +0 -270
- package/dist/server/lib/__tests__/clickhouse-buffer.test.js +0 -236
- package/dist/server/lib/__tests__/code-worker-edge-cases.test.js +0 -118
- package/dist/server/lib/__tests__/code-worker-pool-execute.test.js +0 -193
- package/dist/server/lib/__tests__/code-worker-pool-execution.test.js +0 -165
- package/dist/server/lib/__tests__/code-worker-pool-init.test.js +0 -131
- package/dist/server/lib/__tests__/code-worker-pool.test.js +0 -194
- package/dist/server/lib/__tests__/code-worker-sandbox-ops.test.js +0 -123
- package/dist/server/lib/__tests__/code-worker-sandbox.test.js +0 -217
- package/dist/server/lib/__tests__/code-worker.test.js +0 -179
- package/dist/server/lib/__tests__/compaction-service-generate.test.js +0 -229
- package/dist/server/lib/__tests__/compaction-service.test.js +0 -319
- package/dist/server/lib/__tests__/otel.test.js +0 -146
- package/dist/server/lib/__tests__/prompt-sanitizer-validation.test.js +0 -165
- package/dist/server/lib/__tests__/prompt-sanitizer.sanitize.test.js +0 -343
- package/dist/server/lib/__tests__/prompt-sanitizer.test.js +0 -328
- package/dist/server/lib/__tests__/prompt-sanitizer.validate-tool.test.js +0 -145
- package/dist/server/lib/__tests__/provider-capabilities.test.js +0 -263
- package/dist/server/lib/__tests__/provider-failover-routing.test.js +0 -145
- package/dist/server/lib/__tests__/provider-failover-state.test.js +0 -131
- package/dist/server/lib/__tests__/rate-limiter-budgets.test.js +0 -216
- package/dist/server/lib/__tests__/rate-limiter.budgets-tools.test.js +0 -113
- package/dist/server/lib/__tests__/rate-limiter.check-request.test.js +0 -141
- package/dist/server/lib/__tests__/rate-limiter.stats-lifecycle.test.js +0 -135
- package/dist/server/lib/__tests__/rate-limiter.test.js +0 -207
- package/dist/server/lib/__tests__/server-agent-loop-abort-conditions.test.js +0 -544
- package/dist/server/lib/__tests__/server-agent-loop-abort.part2.test.js +0 -504
- package/dist/server/lib/__tests__/server-agent-loop-abort.test.js +0 -396
- package/dist/server/lib/__tests__/server-agent-loop-compaction.test.js +0 -397
- package/dist/server/lib/__tests__/server-agent-loop-failover.test.js +0 -356
- package/dist/server/lib/__tests__/server-agent-loop-features-caching.test.js +0 -519
- package/dist/server/lib/__tests__/server-agent-loop-features-edges.test.js +0 -512
- package/dist/server/lib/__tests__/server-subagent-bailout.test.js +0 -194
- package/dist/server/lib/__tests__/server-subagent-basics.test.js +0 -348
- package/dist/server/lib/__tests__/server-subagent-errors-abort.test.js +0 -319
- package/dist/server/lib/__tests__/server-subagent-errors-progress.test.js +0 -253
- package/dist/server/lib/__tests__/server-subagent-errors.part2.test.js +0 -253
- package/dist/server/lib/__tests__/server-subagent-errors.test.js +0 -319
- package/dist/server/lib/__tests__/session-checkpoint-load.test.js +0 -275
- package/dist/server/lib/__tests__/session-checkpoint-save.test.js +0 -159
- package/dist/server/lib/__tests__/ssrf-guard.test.js +0 -93
- package/dist/server/lib/__tests__/supabase-client.test.js +0 -111
- package/dist/server/lib/__tests__/template-resolver.test.js +0 -317
- package/dist/server/lib/__tests__/utils-timeout.test.js +0 -49
- package/dist/server/lib/__tests__/utils.test.js +0 -322
- package/dist/server/providers/__tests__/anthropic-adapter.test.js +0 -228
- package/dist/server/providers/__tests__/anthropic-betas-toolchoice.test.js +0 -257
- package/dist/server/providers/__tests__/anthropic-errors.test.js +0 -262
- package/dist/server/providers/__tests__/anthropic-stream-core.test.js +0 -275
- package/dist/server/providers/__tests__/anthropic-streaming-betas.test.js +0 -247
- package/dist/server/providers/__tests__/anthropic-streaming-core.test.js +0 -275
- package/dist/server/providers/__tests__/bedrock-config.test.js +0 -177
- package/dist/server/providers/__tests__/bedrock-stream-behavior-streaming.test.js +0 -272
- package/dist/server/providers/__tests__/bedrock-stream-behavior-toolchoice.test.js +0 -214
- package/dist/server/providers/__tests__/bedrock-stream-behavior.part2.test.js +0 -165
- package/dist/server/providers/__tests__/bedrock-stream-behavior.test.js +0 -309
- package/dist/server/providers/__tests__/bedrock-stream-body-credentials.test.js +0 -170
- package/dist/server/providers/__tests__/bedrock-stream-body-extras.test.js +0 -183
- package/dist/server/providers/__tests__/bedrock-stream-body-request.test.js +0 -305
- package/dist/server/providers/__tests__/bedrock-stream-body.part2.test.js +0 -305
- package/dist/server/providers/__tests__/bedrock-stream-body.test.js +0 -175
- package/dist/server/providers/__tests__/bedrock-stream-errors.test.js +0 -165
- package/dist/server/providers/__tests__/gemini-config-methods.test.js +0 -182
- package/dist/server/providers/__tests__/gemini-config-streaming.test.js +0 -257
- package/dist/server/providers/__tests__/gemini-conversion-messages.test.js +0 -247
- package/dist/server/providers/__tests__/gemini-conversion-schema.test.js +0 -365
- package/dist/server/providers/__tests__/gemini-tools-choice.test.js +0 -221
- package/dist/server/providers/__tests__/gemini-tools-fn.test.js +0 -252
- package/dist/server/providers/__tests__/openai-config.test.js +0 -194
- package/dist/server/providers/__tests__/openai-conversion.test.js +0 -276
- package/dist/server/providers/__tests__/openai-messages.test.js +0 -261
- package/dist/server/providers/__tests__/openai-streaming.test.js +0 -394
- package/dist/server/providers/__tests__/openai-tools-cache.test.js +0 -227
- package/dist/server/providers/__tests__/registry.test.js +0 -183
- package/dist/server/providers/__tests__/shared.test.js +0 -297
- package/dist/shared/agent-core-config.test.js +0 -132
- package/dist/shared/agent-core-context-thinking.test.js +0 -293
- package/dist/shared/agent-core-loop-calls.test.js +0 -174
- package/dist/shared/agent-core-loop-detector-bail.test.js +0 -201
- package/dist/shared/agent-core-loop-detector.test.js +0 -195
- package/dist/shared/agent-core-loop-errors.test.js +0 -258
- package/dist/shared/agent-core-pricing.test.js +0 -191
- package/dist/shared/agent-core-sanitize-retry.test.js +0 -129
- package/dist/shared/api-client-build-request.test.js +0 -228
- package/dist/shared/api-client-build-system-caching.test.js +0 -107
- package/dist/shared/api-client-build.test.js +0 -223
- package/dist/shared/api-client-config.d.ts +0 -21
- package/dist/shared/api-client-helpers.d.ts +0 -57
- package/dist/shared/api-client-helpers.test.js +0 -261
- package/dist/shared/api-client-proxy-happy.test.js +0 -255
- package/dist/shared/api-client-proxy-retry.test.js +0 -307
- package/dist/shared/api-client-proxy.d.ts +0 -26
- package/dist/shared/api-client-proxy.test.js +0 -255
- package/dist/shared/api-client-retry.test.js +0 -307
- package/dist/shared/api-client-system-trimming.test.js +0 -261
- package/dist/shared/api-client-trimming.d.ts +0 -36
- package/dist/shared/api-client.test.js +0 -228
- package/dist/shared/compaction-thinking.test.js +0 -315
- package/dist/shared/compaction-trimming.test.js +0 -223
- package/dist/shared/sse-parser-callbacks.test.js +0 -422
- package/dist/shared/sse-parser-collect.test.js +0 -252
- package/dist/shared/sse-parser-e2e.test.js +0 -558
- package/dist/shared/sse-parser-parse.test.js +0 -253
- package/dist/shared/tool-dispatch-advanced-batch-build.test.js +0 -405
- package/dist/shared/tool-dispatch-advanced.test.js +0 -320
- package/dist/shared/tool-dispatch-basic.test.js +0 -278
- package/dist/shared/tool-dispatch-content.d.ts +0 -14
- package/dist/shared/tool-dispatch-parallel.test.js +0 -378
- package/dist/webchat/__tests__/widget-messaging.test.js +0 -323
- package/dist/webchat/__tests__/widget.test.js +0 -273
|
@@ -6,7 +6,7 @@ import { randomUUID } from "node:crypto";
|
|
|
6
6
|
import { createLogger } from "./lib/logger.js";
|
|
7
7
|
import { getServiceClient } from "./lib/supabase-client.js";
|
|
8
8
|
import { checkPlanLimits, incrementUsage } from "./handlers/billing.js";
|
|
9
|
-
import { jsonResponse, readBody } from "./server-helpers.js";
|
|
9
|
+
import { jsonResponse, readBody, getClientIp } from "./server-helpers.js";
|
|
10
10
|
import { sendIpRateLimit } from "./server-rate-limit.js";
|
|
11
11
|
const log = createLogger("server-routes-webchat");
|
|
12
12
|
|
|
@@ -33,7 +33,7 @@ export async function handleWebchatMessage(req, res, ctx) {
|
|
|
33
33
|
};
|
|
34
34
|
const webchatMsgMatch = pathname.match(/^\/webchat\/channels\/([a-f0-9-]+)\/messages$/);
|
|
35
35
|
if (!(webchatMsgMatch && req.method === "POST")) return false;
|
|
36
|
-
const clientIp = req
|
|
36
|
+
const clientIp = getClientIp(req);
|
|
37
37
|
if (sendIpRateLimit(res, clientIp, webchatCors)) return true;
|
|
38
38
|
let rawBody;
|
|
39
39
|
try {
|
|
@@ -201,7 +201,7 @@ export async function handleWebchatHistory(req, res, ctx) {
|
|
|
201
201
|
};
|
|
202
202
|
const webchatHistoryMatch = pathname.match(/^\/webchat\/channels\/([a-f0-9-]+)\/history$/);
|
|
203
203
|
if (!(webchatHistoryMatch && req.method === "GET")) return false;
|
|
204
|
-
const clientIp = req
|
|
204
|
+
const clientIp = getClientIp(req);
|
|
205
205
|
if (sendIpRateLimit(res, clientIp, webchatCors)) return true;
|
|
206
206
|
const channelId = webchatHistoryMatch[1];
|
|
207
207
|
const params = url.searchParams;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-routes-webchat.js","names":["randomUUID","createLogger","getServiceClient","checkPlanLimits","incrementUsage","jsonResponse","readBody","sendIpRateLimit","log","webchatAgentInvoker","setWebchatAgentInvoker","invoker","handleWebchatMessage","req","res","ctx","pathname","corsHeaders","webchatCors","webchatMsgMatch","match","method","clientIp","headers","toString","split","trim","socket","remoteAddress","rawBody","error","channelId","wcBody","JSON","parse","content","length","supabase","data","channel","from","select","eq","single","planCheck","store_id","allowed","reason","senderId","sender_id","conversationId","conversation_id","thirtyMinAgo","Date","now","toISOString","recent","gt","not","order","ascending","limit","message","msgErr","insert","channel_id","direction","sender_name","content_type","metadata","source","ip","widget_version","agent_id","messages_in","catch","rpc","p_channel_id","agentResponse","result","success","response","outMsg","auto_response","messages_out","agent_invocations","err","agent_response","handleWebchatHistory","url","webchatHistoryMatch","params","searchParams","get","reqConvId","wcChannel","query","test","in","messages","histErr","handleWebchatWidget","fs","path","possiblePaths","join","import","meta","dirname","__dirname","process","cwd","widgetJs","p","readFileSync","writeHead","end"],"sources":["../../src/server/server-routes-webchat.ts"],"sourcesContent":["// server/server-routes-webchat.ts — Webchat route handlers\n// Anonymous access for embedded chat widgets\n// Extracted from index.ts for domain-based modularity.\n\nimport http from \"node:http\";\nimport { randomUUID } from \"node:crypto\";\nimport type { SupabaseClient } from \"@supabase/supabase-js\";\nimport { createLogger } from \"./lib/logger.js\";\nimport { getServiceClient } from \"./lib/supabase-client.js\";\nimport { checkPlanLimits, incrementUsage } from \"./handlers/billing.js\";\nimport { jsonResponse, readBody, type ServerContext } from \"./server-helpers.js\";\nimport { sendIpRateLimit } from \"./server-rate-limit.js\";\nimport type { SenderContext } from \"./handlers/nodes.js\";\n\nconst log = createLogger(\"server-routes-webchat\");\n\n// Webchat agent invoker — set later to avoid circular deps\nlet webchatAgentInvoker: ((\n supabase: SupabaseClient,\n agentId: string,\n message: string,\n storeId: string,\n conversationId: string,\n senderContext?: SenderContext,\n) => Promise<{ success: boolean; response?: string; error?: string }>) | null = null;\n\nexport function setWebchatAgentInvoker(invoker: typeof webchatAgentInvoker): void {\n webchatAgentInvoker = invoker;\n}\n\n// ============================================================================\n// POST /webchat/channels/:id/messages — Send message (+ agent auto-reply)\n// ============================================================================\n\nexport async function handleWebchatMessage(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n ctx: ServerContext,\n): Promise<boolean> {\n const { pathname, corsHeaders } = ctx;\n\n // Webchat CORS: allow any origin (widget is embedded on customer sites)\n const webchatCors = { ...corsHeaders, \"Access-Control-Allow-Origin\": \"*\" };\n\n const webchatMsgMatch = pathname.match(/^\\/webchat\\/channels\\/([a-f0-9-]+)\\/messages$/);\n if (!(webchatMsgMatch && req.method === \"POST\")) return false;\n\n const clientIp = req.headers[\"x-forwarded-for\"]?.toString().split(\",\")[0]?.trim() || req.socket.remoteAddress || \"unknown\";\n if (sendIpRateLimit(res, clientIp, webchatCors)) return true;\n\n let rawBody: string;\n try { rawBody = await readBody(req); } catch {\n jsonResponse(res, 413, { error: \"Request body too large\" }, webchatCors);\n return true;\n }\n\n const channelId = webchatMsgMatch[1];\n let wcBody: any;\n try { wcBody = JSON.parse(rawBody); } catch {\n jsonResponse(res, 400, { error: \"Invalid JSON\" }, webchatCors);\n return true;\n }\n\n if (!wcBody.content || typeof wcBody.content !== \"string\") {\n jsonResponse(res, 400, { error: \"content (string) is required\" }, webchatCors);\n return true;\n }\n if (wcBody.content.length > 5000) {\n jsonResponse(res, 400, { error: \"Message too long (max 5000 characters)\" }, webchatCors);\n return true;\n }\n\n const supabase = getServiceClient();\n\n // Verify channel exists and is a webchat channel\n const { data: channel } = await supabase\n .from(\"channels\")\n .select(\"id, store_id, node_id, agent_id, type, config\")\n .eq(\"id\", channelId)\n .eq(\"type\", \"webchat\")\n .single();\n if (!channel) {\n jsonResponse(res, 404, { error: \"Webchat channel not found\" }, webchatCors);\n return true;\n }\n\n // Rate limit per store (best-effort)\n try {\n const planCheck = await checkPlanLimits(supabase, channel.store_id, \"message\");\n if (!planCheck.allowed) {\n jsonResponse(res, 429, { error: planCheck.reason || \"Plan limit reached\" }, webchatCors);\n return true;\n }\n } catch { /* billing tables may not exist yet */ }\n\n const senderId = (wcBody.sender_id as string) || \"anonymous\";\n\n // Resolve conversation: reuse if sender had activity < 30 min ago, else new UUID\n let conversationId: string = (wcBody.conversation_id as string) || \"\";\n if (!conversationId) {\n const thirtyMinAgo = new Date(Date.now() - 30 * 60 * 1000).toISOString();\n const { data: recent } = await supabase\n .from(\"channel_messages\")\n .select(\"conversation_id\")\n .eq(\"channel_id\", channelId)\n .eq(\"sender_id\", senderId)\n .gt(\"created_at\", thirtyMinAgo)\n .not(\"conversation_id\", \"is\", null)\n .order(\"created_at\", { ascending: false })\n .limit(1);\n conversationId = (recent?.length && recent[0].conversation_id) || randomUUID();\n }\n\n // Insert inbound message\n const { data: message, error: msgErr } = await supabase\n .from(\"channel_messages\")\n .insert({\n store_id: channel.store_id,\n channel_id: channelId,\n direction: \"inbound\",\n sender_id: senderId,\n sender_name: wcBody.sender_name || \"Visitor\",\n content: wcBody.content,\n content_type: \"text\",\n metadata: { source: \"webchat\", ip: clientIp, widget_version: \"1.0.0\" },\n agent_id: channel.agent_id,\n conversation_id: conversationId,\n })\n .select(\"id, direction, content, conversation_id, created_at\")\n .single();\n\n if (msgErr) {\n jsonResponse(res, 500, { error: msgErr.message }, webchatCors);\n return true;\n }\n\n // Track usage + channel stats (best-effort)\n incrementUsage(supabase, channel.store_id, { messages_in: 1 }).catch(() => {});\n try { await supabase.rpc(\"increment_channel_stats\", { p_channel_id: channelId }); } catch { /* ok */ }\n\n // Auto-invoke agent if assigned\n let agentResponse: any = null;\n if (channel.agent_id && webchatAgentInvoker) {\n try {\n const result = await webchatAgentInvoker(supabase, channel.agent_id, wcBody.content, channel.store_id, conversationId);\n if (result.success && result.response) {\n const { data: outMsg } = await supabase\n .from(\"channel_messages\")\n .insert({\n store_id: channel.store_id,\n channel_id: channelId,\n direction: \"outbound\",\n sender_id: \"agent\",\n sender_name: \"AI Agent\",\n content: result.response,\n content_type: \"text\",\n metadata: { agent_id: channel.agent_id, auto_response: true, source: \"webchat\" },\n agent_id: channel.agent_id,\n conversation_id: conversationId,\n })\n .select(\"id, direction, content, conversation_id, created_at\")\n .single();\n agentResponse = outMsg;\n incrementUsage(supabase, channel.store_id, { messages_out: 1, agent_invocations: 1 }).catch(() => {});\n }\n } catch (err) {\n log.error({ err: (err as Error).message }, \"webchat agent error\");\n }\n }\n\n jsonResponse(res, 201, { success: true, message, agent_response: agentResponse, conversation_id: conversationId }, webchatCors);\n return true;\n}\n\n// ============================================================================\n// GET /webchat/channels/:id/history — Load conversation history for widget\n// ============================================================================\n\nexport async function handleWebchatHistory(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n ctx: ServerContext,\n): Promise<boolean> {\n const { pathname, url, corsHeaders } = ctx;\n\n const webchatCors = { ...corsHeaders, \"Access-Control-Allow-Origin\": \"*\" };\n\n const webchatHistoryMatch = pathname.match(/^\\/webchat\\/channels\\/([a-f0-9-]+)\\/history$/);\n if (!(webchatHistoryMatch && req.method === \"GET\")) return false;\n\n const clientIp = req.headers[\"x-forwarded-for\"]?.toString().split(\",\")[0]?.trim() || req.socket.remoteAddress || \"unknown\";\n if (sendIpRateLimit(res, clientIp, webchatCors)) return true;\n\n const channelId = webchatHistoryMatch[1];\n const params = url.searchParams;\n const senderId = params.get(\"sender_id\") || \"\";\n const reqConvId = params.get(\"conversation_id\") || \"\";\n\n if (!senderId) {\n jsonResponse(res, 400, { error: \"sender_id query parameter required\" }, webchatCors);\n return true;\n }\n\n const supabase = getServiceClient();\n\n // Verify channel is webchat type\n const { data: wcChannel } = await supabase\n .from(\"channels\")\n .select(\"id, type\")\n .eq(\"id\", channelId)\n .eq(\"type\", \"webchat\")\n .single();\n if (!wcChannel) {\n jsonResponse(res, 404, { error: \"Webchat channel not found\" }, webchatCors);\n return true;\n }\n\n // Get messages — by conversation_id if available, or by sender\n // P0 FIX: Always filter by sender_id to prevent cross-sender data leak\n let query = supabase\n .from(\"channel_messages\")\n .select(\"id, direction, sender_id, sender_name, content, content_type, created_at\")\n .eq(\"channel_id\", channelId);\n\n // P0 FIX: Validate senderId against strict pattern to prevent PostgREST filter injection\n // Only allow alphanumeric characters, hyphens, and underscores (blocks .eq., .neq., dots, etc.)\n if (!/^[a-zA-Z0-9_-]+$/.test(senderId)) {\n jsonResponse(res, 400, { error: \"Invalid sender_id format\" }, webchatCors);\n return true;\n }\n if (reqConvId) {\n // P0 FIX: Use parameterized .in() filter instead of string interpolation in .or()\n query = query.eq(\"conversation_id\", reqConvId)\n .in(\"sender_id\", [senderId, \"agent\"]);\n } else {\n query = query.in(\"sender_id\", [senderId, \"agent\"]);\n }\n\n const { data: messages, error: histErr } = await query\n .order(\"created_at\", { ascending: true })\n .limit(50);\n\n if (histErr) {\n jsonResponse(res, 500, { error: histErr.message }, webchatCors);\n return true;\n }\n\n jsonResponse(res, 200, { success: true, messages: messages || [] }, webchatCors);\n return true;\n}\n\n// ============================================================================\n// GET /webchat/widget.js — Serve compiled widget JavaScript\n// ============================================================================\n\nexport async function handleWebchatWidget(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n ctx: ServerContext,\n): Promise<boolean> {\n const { pathname, corsHeaders } = ctx;\n\n if (!(pathname === \"/webchat/widget.js\" && req.method === \"GET\")) return false;\n\n const webchatCors = { ...corsHeaders, \"Access-Control-Allow-Origin\": \"*\" };\n\n const fs = await import(\"node:fs\");\n const path = await import(\"node:path\");\n // Try multiple possible locations for the built widget file\n const possiblePaths = [\n path.join(import.meta.dirname || __dirname, \"../../dist/webchat/widget.js\"),\n path.join(import.meta.dirname || __dirname, \"../../../dist/webchat/widget.js\"),\n path.join(process.cwd(), \"dist/webchat/widget.js\"),\n ];\n\n let widgetJs: string | null = null;\n for (const p of possiblePaths) {\n try {\n widgetJs = fs.readFileSync(p, \"utf-8\");\n break;\n } catch { /* try next */ }\n }\n\n if (widgetJs) {\n res.writeHead(200, {\n \"Content-Type\": \"application/javascript\",\n \"Cache-Control\": \"public, max-age=3600\",\n ...webchatCors,\n });\n res.end(widgetJs);\n } else {\n res.writeHead(200, {\n \"Content-Type\": \"application/javascript\",\n ...webchatCors,\n });\n res.end('console.warn(\"[WhaleChat] Widget JS not built. Run: npx esbuild src/webchat/widget.ts --bundle --minify --outfile=dist/webchat/widget.js\");');\n }\n return true;\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"server-routes-webchat.js","names":["randomUUID","createLogger","getServiceClient","checkPlanLimits","incrementUsage","jsonResponse","readBody","getClientIp","sendIpRateLimit","log","webchatAgentInvoker","setWebchatAgentInvoker","invoker","handleWebchatMessage","req","res","ctx","pathname","corsHeaders","webchatCors","webchatMsgMatch","match","method","clientIp","rawBody","error","channelId","wcBody","JSON","parse","content","length","supabase","data","channel","from","select","eq","single","planCheck","store_id","allowed","reason","senderId","sender_id","conversationId","conversation_id","thirtyMinAgo","Date","now","toISOString","recent","gt","not","order","ascending","limit","message","msgErr","insert","channel_id","direction","sender_name","content_type","metadata","source","ip","widget_version","agent_id","messages_in","catch","rpc","p_channel_id","agentResponse","result","success","response","outMsg","auto_response","messages_out","agent_invocations","err","agent_response","handleWebchatHistory","url","webchatHistoryMatch","params","searchParams","get","reqConvId","wcChannel","query","test","in","messages","histErr","handleWebchatWidget","fs","path","possiblePaths","join","import","meta","dirname","__dirname","process","cwd","widgetJs","p","readFileSync","writeHead","end"],"sources":["../../src/server/server-routes-webchat.ts"],"sourcesContent":["// server/server-routes-webchat.ts — Webchat route handlers\n// Anonymous access for embedded chat widgets\n// Extracted from index.ts for domain-based modularity.\n\nimport http from \"node:http\";\nimport { randomUUID } from \"node:crypto\";\nimport type { SupabaseClient } from \"@supabase/supabase-js\";\nimport { createLogger } from \"./lib/logger.js\";\nimport { getServiceClient } from \"./lib/supabase-client.js\";\nimport { checkPlanLimits, incrementUsage } from \"./handlers/billing.js\";\nimport { jsonResponse, readBody, getClientIp, type ServerContext } from \"./server-helpers.js\";\nimport { sendIpRateLimit } from \"./server-rate-limit.js\";\nimport type { SenderContext } from \"./handlers/nodes.js\";\n\nconst log = createLogger(\"server-routes-webchat\");\n\n// Webchat agent invoker — set later to avoid circular deps\nlet webchatAgentInvoker: ((\n supabase: SupabaseClient,\n agentId: string,\n message: string,\n storeId: string,\n conversationId: string,\n senderContext?: SenderContext,\n) => Promise<{ success: boolean; response?: string; error?: string }>) | null = null;\n\nexport function setWebchatAgentInvoker(invoker: typeof webchatAgentInvoker): void {\n webchatAgentInvoker = invoker;\n}\n\n// ============================================================================\n// POST /webchat/channels/:id/messages — Send message (+ agent auto-reply)\n// ============================================================================\n\nexport async function handleWebchatMessage(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n ctx: ServerContext,\n): Promise<boolean> {\n const { pathname, corsHeaders } = ctx;\n\n // Webchat CORS: allow any origin (widget is embedded on customer sites)\n const webchatCors = { ...corsHeaders, \"Access-Control-Allow-Origin\": \"*\" };\n\n const webchatMsgMatch = pathname.match(/^\\/webchat\\/channels\\/([a-f0-9-]+)\\/messages$/);\n if (!(webchatMsgMatch && req.method === \"POST\")) return false;\n\n const clientIp = getClientIp(req);\n if (sendIpRateLimit(res, clientIp, webchatCors)) return true;\n\n let rawBody: string;\n try { rawBody = await readBody(req); } catch {\n jsonResponse(res, 413, { error: \"Request body too large\" }, webchatCors);\n return true;\n }\n\n const channelId = webchatMsgMatch[1];\n let wcBody: any;\n try { wcBody = JSON.parse(rawBody); } catch {\n jsonResponse(res, 400, { error: \"Invalid JSON\" }, webchatCors);\n return true;\n }\n\n if (!wcBody.content || typeof wcBody.content !== \"string\") {\n jsonResponse(res, 400, { error: \"content (string) is required\" }, webchatCors);\n return true;\n }\n if (wcBody.content.length > 5000) {\n jsonResponse(res, 400, { error: \"Message too long (max 5000 characters)\" }, webchatCors);\n return true;\n }\n\n const supabase = getServiceClient();\n\n // Verify channel exists and is a webchat channel\n const { data: channel } = await supabase\n .from(\"channels\")\n .select(\"id, store_id, node_id, agent_id, type, config\")\n .eq(\"id\", channelId)\n .eq(\"type\", \"webchat\")\n .single();\n if (!channel) {\n jsonResponse(res, 404, { error: \"Webchat channel not found\" }, webchatCors);\n return true;\n }\n\n // Rate limit per store (best-effort)\n try {\n const planCheck = await checkPlanLimits(supabase, channel.store_id, \"message\");\n if (!planCheck.allowed) {\n jsonResponse(res, 429, { error: planCheck.reason || \"Plan limit reached\" }, webchatCors);\n return true;\n }\n } catch { /* billing tables may not exist yet */ }\n\n const senderId = (wcBody.sender_id as string) || \"anonymous\";\n\n // Resolve conversation: reuse if sender had activity < 30 min ago, else new UUID\n let conversationId: string = (wcBody.conversation_id as string) || \"\";\n if (!conversationId) {\n const thirtyMinAgo = new Date(Date.now() - 30 * 60 * 1000).toISOString();\n const { data: recent } = await supabase\n .from(\"channel_messages\")\n .select(\"conversation_id\")\n .eq(\"channel_id\", channelId)\n .eq(\"sender_id\", senderId)\n .gt(\"created_at\", thirtyMinAgo)\n .not(\"conversation_id\", \"is\", null)\n .order(\"created_at\", { ascending: false })\n .limit(1);\n conversationId = (recent?.length && recent[0].conversation_id) || randomUUID();\n }\n\n // Insert inbound message\n const { data: message, error: msgErr } = await supabase\n .from(\"channel_messages\")\n .insert({\n store_id: channel.store_id,\n channel_id: channelId,\n direction: \"inbound\",\n sender_id: senderId,\n sender_name: wcBody.sender_name || \"Visitor\",\n content: wcBody.content,\n content_type: \"text\",\n metadata: { source: \"webchat\", ip: clientIp, widget_version: \"1.0.0\" },\n agent_id: channel.agent_id,\n conversation_id: conversationId,\n })\n .select(\"id, direction, content, conversation_id, created_at\")\n .single();\n\n if (msgErr) {\n jsonResponse(res, 500, { error: msgErr.message }, webchatCors);\n return true;\n }\n\n // Track usage + channel stats (best-effort)\n incrementUsage(supabase, channel.store_id, { messages_in: 1 }).catch(() => {});\n try { await supabase.rpc(\"increment_channel_stats\", { p_channel_id: channelId }); } catch { /* ok */ }\n\n // Auto-invoke agent if assigned\n let agentResponse: any = null;\n if (channel.agent_id && webchatAgentInvoker) {\n try {\n const result = await webchatAgentInvoker(supabase, channel.agent_id, wcBody.content, channel.store_id, conversationId);\n if (result.success && result.response) {\n const { data: outMsg } = await supabase\n .from(\"channel_messages\")\n .insert({\n store_id: channel.store_id,\n channel_id: channelId,\n direction: \"outbound\",\n sender_id: \"agent\",\n sender_name: \"AI Agent\",\n content: result.response,\n content_type: \"text\",\n metadata: { agent_id: channel.agent_id, auto_response: true, source: \"webchat\" },\n agent_id: channel.agent_id,\n conversation_id: conversationId,\n })\n .select(\"id, direction, content, conversation_id, created_at\")\n .single();\n agentResponse = outMsg;\n incrementUsage(supabase, channel.store_id, { messages_out: 1, agent_invocations: 1 }).catch(() => {});\n }\n } catch (err) {\n log.error({ err: (err as Error).message }, \"webchat agent error\");\n }\n }\n\n jsonResponse(res, 201, { success: true, message, agent_response: agentResponse, conversation_id: conversationId }, webchatCors);\n return true;\n}\n\n// ============================================================================\n// GET /webchat/channels/:id/history — Load conversation history for widget\n// ============================================================================\n\nexport async function handleWebchatHistory(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n ctx: ServerContext,\n): Promise<boolean> {\n const { pathname, url, corsHeaders } = ctx;\n\n const webchatCors = { ...corsHeaders, \"Access-Control-Allow-Origin\": \"*\" };\n\n const webchatHistoryMatch = pathname.match(/^\\/webchat\\/channels\\/([a-f0-9-]+)\\/history$/);\n if (!(webchatHistoryMatch && req.method === \"GET\")) return false;\n\n const clientIp = getClientIp(req);\n if (sendIpRateLimit(res, clientIp, webchatCors)) return true;\n\n const channelId = webchatHistoryMatch[1];\n const params = url.searchParams;\n const senderId = params.get(\"sender_id\") || \"\";\n const reqConvId = params.get(\"conversation_id\") || \"\";\n\n if (!senderId) {\n jsonResponse(res, 400, { error: \"sender_id query parameter required\" }, webchatCors);\n return true;\n }\n\n const supabase = getServiceClient();\n\n // Verify channel is webchat type\n const { data: wcChannel } = await supabase\n .from(\"channels\")\n .select(\"id, type\")\n .eq(\"id\", channelId)\n .eq(\"type\", \"webchat\")\n .single();\n if (!wcChannel) {\n jsonResponse(res, 404, { error: \"Webchat channel not found\" }, webchatCors);\n return true;\n }\n\n // Get messages — by conversation_id if available, or by sender\n // P0 FIX: Always filter by sender_id to prevent cross-sender data leak\n let query = supabase\n .from(\"channel_messages\")\n .select(\"id, direction, sender_id, sender_name, content, content_type, created_at\")\n .eq(\"channel_id\", channelId);\n\n // P0 FIX: Validate senderId against strict pattern to prevent PostgREST filter injection\n // Only allow alphanumeric characters, hyphens, and underscores (blocks .eq., .neq., dots, etc.)\n if (!/^[a-zA-Z0-9_-]+$/.test(senderId)) {\n jsonResponse(res, 400, { error: \"Invalid sender_id format\" }, webchatCors);\n return true;\n }\n if (reqConvId) {\n // P0 FIX: Use parameterized .in() filter instead of string interpolation in .or()\n query = query.eq(\"conversation_id\", reqConvId)\n .in(\"sender_id\", [senderId, \"agent\"]);\n } else {\n query = query.in(\"sender_id\", [senderId, \"agent\"]);\n }\n\n const { data: messages, error: histErr } = await query\n .order(\"created_at\", { ascending: true })\n .limit(50);\n\n if (histErr) {\n jsonResponse(res, 500, { error: histErr.message }, webchatCors);\n return true;\n }\n\n jsonResponse(res, 200, { success: true, messages: messages || [] }, webchatCors);\n return true;\n}\n\n// ============================================================================\n// GET /webchat/widget.js — Serve compiled widget JavaScript\n// ============================================================================\n\nexport async function handleWebchatWidget(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n ctx: ServerContext,\n): Promise<boolean> {\n const { pathname, corsHeaders } = ctx;\n\n if (!(pathname === \"/webchat/widget.js\" && req.method === \"GET\")) return false;\n\n const webchatCors = { ...corsHeaders, \"Access-Control-Allow-Origin\": \"*\" };\n\n const fs = await import(\"node:fs\");\n const path = await import(\"node:path\");\n // Try multiple possible locations for the built widget file\n const possiblePaths = [\n path.join(import.meta.dirname || __dirname, \"../../dist/webchat/widget.js\"),\n path.join(import.meta.dirname || __dirname, \"../../../dist/webchat/widget.js\"),\n path.join(process.cwd(), \"dist/webchat/widget.js\"),\n ];\n\n let widgetJs: string | null = null;\n for (const p of possiblePaths) {\n try {\n widgetJs = fs.readFileSync(p, \"utf-8\");\n break;\n } catch { /* try next */ }\n }\n\n if (widgetJs) {\n res.writeHead(200, {\n \"Content-Type\": \"application/javascript\",\n \"Cache-Control\": \"public, max-age=3600\",\n ...webchatCors,\n });\n res.end(widgetJs);\n } else {\n res.writeHead(200, {\n \"Content-Type\": \"application/javascript\",\n ...webchatCors,\n });\n res.end('console.warn(\"[WhaleChat] Widget JS not built. Run: npx esbuild src/webchat/widget.ts --bundle --minify --outfile=dist/webchat/widget.js\");');\n }\n return true;\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -39,7 +39,7 @@ setInterval(() => {
|
|
|
39
39
|
breakers.delete(storeId);
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
-
}, 60_000);
|
|
42
|
+
}, 60_000).unref();
|
|
43
43
|
function evictOldest() {
|
|
44
44
|
if (breakers.size <= MAX_ENTRIES) return;
|
|
45
45
|
const entries = [...breakers.entries()].sort((a, b) => a[1].lastAccessed - b[1].lastAccessed);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-store-circuit-breaker.js","names":["createLogger","queueSpan","auditRowToSpan","log","FAILURE_THRESHOLD","WINDOW_MS","COOLDOWN_MS","MAX_ENTRIES","breakers","Map","setInterval","now","Date","storeId","breaker","state","failures","length","lastAccessed","delete","trippedAt","evictOldest","size","entries","sort","a","b","excess","i","getOrCreate","get","set","pruneFailures","cutoff","filter","ts","checkStoreCircuitBreaker","allowed","elapsed","retryInSec","Math","ceil","error","info","recordStoreOutcome","success","push","warn","emitTelemetry","getStoreBreakerState","getCircuitBreakerStats","open","halfOpen","values","total","failureCount","action","severity","store_id","resource_type","resource_id","source","service_name","span_kind","status_code","start_time","toISOString","end_time","details","threshold","window_ms"],"sources":["../../src/server/server-store-circuit-breaker.ts"],"sourcesContent":["// server/server-store-circuit-breaker.ts — Per-store circuit breaker\n// Prevents a misconfigured or abusive store from overwhelming the system.\n// In-memory sliding window: trips after FAILURE_THRESHOLD failures within WINDOW_MS.\n// Half-open state allows a single probe request after cooldown expires.\n\nimport { createLogger } from \"./lib/logger.js\";\nimport { queueSpan, auditRowToSpan } from \"./lib/clickhouse-buffer.js\";\n\nconst log = createLogger(\"store-circuit-breaker\");\n\n// ============================================================================\n// CONFIGURATION\n// ============================================================================\n\nconst FAILURE_THRESHOLD = 5; // failures to trip the breaker\nconst WINDOW_MS = 5 * 60_000; // 5-minute sliding window\nconst COOLDOWN_MS = 2 * 60_000; // 2-minute cooldown before half-open\nconst MAX_ENTRIES = 500; // cap Map size to prevent unbounded growth\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ntype BreakerState = \"closed\" | \"open\" | \"half_open\";\n\ninterface StoreBreaker {\n state: BreakerState;\n /** Timestamps of failures within the sliding window */\n failures: number[];\n /** When the breaker tripped (only set when state=open) */\n trippedAt: number;\n /** Last time this entry was accessed (for eviction) */\n lastAccessed: number;\n}\n\nexport interface StoreBreakerCheckResult {\n allowed: boolean;\n state: BreakerState;\n error?: string;\n}\n\n// ============================================================================\n// STATE\n// ============================================================================\n\nconst breakers = new Map<string, StoreBreaker>();\n\n// Periodic cleanup of stale entries\nsetInterval(() => {\n const now = Date.now();\n for (const [storeId, breaker] of breakers) {\n // Remove entries with no recent failures and in closed state\n if (breaker.state === \"closed\" && breaker.failures.length === 0 && now - breaker.lastAccessed > WINDOW_MS * 2) {\n breakers.delete(storeId);\n }\n // Remove expired open breakers that have been idle\n if (breaker.state === \"open\" && now - breaker.trippedAt > COOLDOWN_MS * 3) {\n breakers.delete(storeId);\n }\n }\n}, 60_000);\n\nfunction evictOldest(): void {\n if (breakers.size <= MAX_ENTRIES) return;\n const entries = [...breakers.entries()].sort((a, b) => a[1].lastAccessed - b[1].lastAccessed);\n const excess = breakers.size - MAX_ENTRIES;\n for (let i = 0; i < excess; i++) {\n breakers.delete(entries[i][0]);\n }\n}\n\nfunction getOrCreate(storeId: string): StoreBreaker {\n let breaker = breakers.get(storeId);\n if (!breaker) {\n breaker = { state: \"closed\", failures: [], trippedAt: 0, lastAccessed: Date.now() };\n breakers.set(storeId, breaker);\n evictOldest();\n }\n breaker.lastAccessed = Date.now();\n return breaker;\n}\n\n/** Prune failures outside the sliding window */\nfunction pruneFailures(breaker: StoreBreaker): void {\n const cutoff = Date.now() - WINDOW_MS;\n breaker.failures = breaker.failures.filter(ts => ts > cutoff);\n}\n\n// ============================================================================\n// PUBLIC API\n// ============================================================================\n\n/**\n * Check if a store's circuit breaker allows a new request.\n * - closed: always allowed\n * - open: blocked until cooldown expires, then transitions to half_open\n * - half_open: allows exactly one probe request\n */\nexport function checkStoreCircuitBreaker(storeId: string): StoreBreakerCheckResult {\n const breaker = getOrCreate(storeId);\n\n if (breaker.state === \"closed\") {\n return { allowed: true, state: \"closed\" };\n }\n\n if (breaker.state === \"open\") {\n const elapsed = Date.now() - breaker.trippedAt;\n if (elapsed < COOLDOWN_MS) {\n const retryInSec = Math.ceil((COOLDOWN_MS - elapsed) / 1000);\n return {\n allowed: false,\n state: \"open\",\n error: `Store circuit breaker open due to repeated errors. Retry in ${retryInSec}s.`,\n };\n }\n // Cooldown expired — transition to half_open\n breaker.state = \"half_open\";\n log.info({ storeId }, \"store circuit breaker half_open (probe allowed)\");\n return { allowed: true, state: \"half_open\" };\n }\n\n // half_open — allow the probe request\n return { allowed: true, state: \"half_open\" };\n}\n\n/**\n * Record a request outcome for a store.\n * On success: resets the breaker to closed.\n * On failure: adds to the sliding window; trips if threshold exceeded.\n */\nexport function recordStoreOutcome(storeId: string, success: boolean): void {\n const breaker = getOrCreate(storeId);\n\n if (success) {\n if (breaker.state === \"half_open\") {\n log.info({ storeId }, \"store circuit breaker closed (probe succeeded)\");\n }\n breaker.state = \"closed\";\n breaker.failures = [];\n return;\n }\n\n // Failure\n const now = Date.now();\n breaker.failures.push(now);\n pruneFailures(breaker);\n\n if (breaker.state === \"half_open\") {\n // Probe failed — trip again immediately\n breaker.state = \"open\";\n breaker.trippedAt = now;\n log.warn({ storeId }, \"store circuit breaker re-tripped (probe failed)\");\n emitTelemetry(storeId, breaker.failures.length);\n return;\n }\n\n if (breaker.failures.length >= FAILURE_THRESHOLD) {\n breaker.state = \"open\";\n breaker.trippedAt = now;\n log.warn({ storeId, failures: breaker.failures.length }, \"store circuit breaker tripped\");\n emitTelemetry(storeId, breaker.failures.length);\n }\n}\n\n/**\n * Get the current breaker state for a store (for health/debug endpoints).\n */\nexport function getStoreBreakerState(storeId: string): BreakerState {\n const breaker = breakers.get(storeId);\n return breaker?.state || \"closed\";\n}\n\n/**\n * Get summary stats for all breakers (for /health endpoint).\n */\nexport function getCircuitBreakerStats(): { total: number; open: number; halfOpen: number } {\n let open = 0;\n let halfOpen = 0;\n for (const breaker of breakers.values()) {\n if (breaker.state === \"open\") open++;\n if (breaker.state === \"half_open\") halfOpen++;\n }\n return { total: breakers.size, open, halfOpen };\n}\n\n// ============================================================================\n// TELEMETRY\n// ============================================================================\n\nfunction emitTelemetry(storeId: string, failureCount: number): void {\n queueSpan(auditRowToSpan({\n action: \"store.circuit_breaker.tripped\",\n severity: \"warning\",\n store_id: storeId,\n resource_type: \"store\",\n resource_id: storeId,\n source: \"agent-server\",\n service_name: \"agent-server\",\n span_kind: \"INTERNAL\",\n status_code: \"OK\",\n start_time: new Date().toISOString(),\n end_time: new Date().toISOString(),\n details: { failures: failureCount, threshold: FAILURE_THRESHOLD, window_ms: WINDOW_MS },\n }));\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"server-store-circuit-breaker.js","names":["createLogger","queueSpan","auditRowToSpan","log","FAILURE_THRESHOLD","WINDOW_MS","COOLDOWN_MS","MAX_ENTRIES","breakers","Map","setInterval","now","Date","storeId","breaker","state","failures","length","lastAccessed","delete","trippedAt","unref","evictOldest","size","entries","sort","a","b","excess","i","getOrCreate","get","set","pruneFailures","cutoff","filter","ts","checkStoreCircuitBreaker","allowed","elapsed","retryInSec","Math","ceil","error","info","recordStoreOutcome","success","push","warn","emitTelemetry","getStoreBreakerState","getCircuitBreakerStats","open","halfOpen","values","total","failureCount","action","severity","store_id","resource_type","resource_id","source","service_name","span_kind","status_code","start_time","toISOString","end_time","details","threshold","window_ms"],"sources":["../../src/server/server-store-circuit-breaker.ts"],"sourcesContent":["// server/server-store-circuit-breaker.ts — Per-store circuit breaker\n// Prevents a misconfigured or abusive store from overwhelming the system.\n// In-memory sliding window: trips after FAILURE_THRESHOLD failures within WINDOW_MS.\n// Half-open state allows a single probe request after cooldown expires.\n\nimport { createLogger } from \"./lib/logger.js\";\nimport { queueSpan, auditRowToSpan } from \"./lib/clickhouse-buffer.js\";\n\nconst log = createLogger(\"store-circuit-breaker\");\n\n// ============================================================================\n// CONFIGURATION\n// ============================================================================\n\nconst FAILURE_THRESHOLD = 5; // failures to trip the breaker\nconst WINDOW_MS = 5 * 60_000; // 5-minute sliding window\nconst COOLDOWN_MS = 2 * 60_000; // 2-minute cooldown before half-open\nconst MAX_ENTRIES = 500; // cap Map size to prevent unbounded growth\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ntype BreakerState = \"closed\" | \"open\" | \"half_open\";\n\ninterface StoreBreaker {\n state: BreakerState;\n /** Timestamps of failures within the sliding window */\n failures: number[];\n /** When the breaker tripped (only set when state=open) */\n trippedAt: number;\n /** Last time this entry was accessed (for eviction) */\n lastAccessed: number;\n}\n\nexport interface StoreBreakerCheckResult {\n allowed: boolean;\n state: BreakerState;\n error?: string;\n}\n\n// ============================================================================\n// STATE\n// ============================================================================\n\nconst breakers = new Map<string, StoreBreaker>();\n\n// Periodic cleanup of stale entries\nsetInterval(() => {\n const now = Date.now();\n for (const [storeId, breaker] of breakers) {\n // Remove entries with no recent failures and in closed state\n if (breaker.state === \"closed\" && breaker.failures.length === 0 && now - breaker.lastAccessed > WINDOW_MS * 2) {\n breakers.delete(storeId);\n }\n // Remove expired open breakers that have been idle\n if (breaker.state === \"open\" && now - breaker.trippedAt > COOLDOWN_MS * 3) {\n breakers.delete(storeId);\n }\n }\n}, 60_000).unref();\n\nfunction evictOldest(): void {\n if (breakers.size <= MAX_ENTRIES) return;\n const entries = [...breakers.entries()].sort((a, b) => a[1].lastAccessed - b[1].lastAccessed);\n const excess = breakers.size - MAX_ENTRIES;\n for (let i = 0; i < excess; i++) {\n breakers.delete(entries[i][0]);\n }\n}\n\nfunction getOrCreate(storeId: string): StoreBreaker {\n let breaker = breakers.get(storeId);\n if (!breaker) {\n breaker = { state: \"closed\", failures: [], trippedAt: 0, lastAccessed: Date.now() };\n breakers.set(storeId, breaker);\n evictOldest();\n }\n breaker.lastAccessed = Date.now();\n return breaker;\n}\n\n/** Prune failures outside the sliding window */\nfunction pruneFailures(breaker: StoreBreaker): void {\n const cutoff = Date.now() - WINDOW_MS;\n breaker.failures = breaker.failures.filter(ts => ts > cutoff);\n}\n\n// ============================================================================\n// PUBLIC API\n// ============================================================================\n\n/**\n * Check if a store's circuit breaker allows a new request.\n * - closed: always allowed\n * - open: blocked until cooldown expires, then transitions to half_open\n * - half_open: allows exactly one probe request\n */\nexport function checkStoreCircuitBreaker(storeId: string): StoreBreakerCheckResult {\n const breaker = getOrCreate(storeId);\n\n if (breaker.state === \"closed\") {\n return { allowed: true, state: \"closed\" };\n }\n\n if (breaker.state === \"open\") {\n const elapsed = Date.now() - breaker.trippedAt;\n if (elapsed < COOLDOWN_MS) {\n const retryInSec = Math.ceil((COOLDOWN_MS - elapsed) / 1000);\n return {\n allowed: false,\n state: \"open\",\n error: `Store circuit breaker open due to repeated errors. Retry in ${retryInSec}s.`,\n };\n }\n // Cooldown expired — transition to half_open\n breaker.state = \"half_open\";\n log.info({ storeId }, \"store circuit breaker half_open (probe allowed)\");\n return { allowed: true, state: \"half_open\" };\n }\n\n // half_open — allow the probe request\n return { allowed: true, state: \"half_open\" };\n}\n\n/**\n * Record a request outcome for a store.\n * On success: resets the breaker to closed.\n * On failure: adds to the sliding window; trips if threshold exceeded.\n */\nexport function recordStoreOutcome(storeId: string, success: boolean): void {\n const breaker = getOrCreate(storeId);\n\n if (success) {\n if (breaker.state === \"half_open\") {\n log.info({ storeId }, \"store circuit breaker closed (probe succeeded)\");\n }\n breaker.state = \"closed\";\n breaker.failures = [];\n return;\n }\n\n // Failure\n const now = Date.now();\n breaker.failures.push(now);\n pruneFailures(breaker);\n\n if (breaker.state === \"half_open\") {\n // Probe failed — trip again immediately\n breaker.state = \"open\";\n breaker.trippedAt = now;\n log.warn({ storeId }, \"store circuit breaker re-tripped (probe failed)\");\n emitTelemetry(storeId, breaker.failures.length);\n return;\n }\n\n if (breaker.failures.length >= FAILURE_THRESHOLD) {\n breaker.state = \"open\";\n breaker.trippedAt = now;\n log.warn({ storeId, failures: breaker.failures.length }, \"store circuit breaker tripped\");\n emitTelemetry(storeId, breaker.failures.length);\n }\n}\n\n/**\n * Get the current breaker state for a store (for health/debug endpoints).\n */\nexport function getStoreBreakerState(storeId: string): BreakerState {\n const breaker = breakers.get(storeId);\n return breaker?.state || \"closed\";\n}\n\n/**\n * Get summary stats for all breakers (for /health endpoint).\n */\nexport function getCircuitBreakerStats(): { total: number; open: number; halfOpen: number } {\n let open = 0;\n let halfOpen = 0;\n for (const breaker of breakers.values()) {\n if (breaker.state === \"open\") open++;\n if (breaker.state === \"half_open\") halfOpen++;\n }\n return { total: breakers.size, open, halfOpen };\n}\n\n// ============================================================================\n// TELEMETRY\n// ============================================================================\n\nfunction emitTelemetry(storeId: string, failureCount: number): void {\n queueSpan(auditRowToSpan({\n action: \"store.circuit_breaker.tripped\",\n severity: \"warning\",\n store_id: storeId,\n resource_type: \"store\",\n resource_id: storeId,\n source: \"agent-server\",\n service_name: \"agent-server\",\n span_kind: \"INTERNAL\",\n status_code: \"OK\",\n start_time: new Date().toISOString(),\n end_time: new Date().toISOString(),\n details: { failures: failureCount, threshold: FAILURE_THRESHOLD, window_ms: WINDOW_MS },\n }));\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -446,7 +446,7 @@ export const TOOL_HANDLERS = {
|
|
|
446
446
|
},
|
|
447
447
|
remove_bg: {
|
|
448
448
|
handler: handleRemoveBg,
|
|
449
|
-
timeout:
|
|
449
|
+
timeout: 300_000,
|
|
450
450
|
requiresStore: true
|
|
451
451
|
},
|
|
452
452
|
media: {
|
|
@@ -1023,6 +1023,7 @@ async function executeSupplyChain(supabase, args, storeId, traceId, userId, user
|
|
|
1023
1023
|
list: "po_list",
|
|
1024
1024
|
get: "po_get",
|
|
1025
1025
|
add_items: "po_add_items",
|
|
1026
|
+
update_items: "po_update_items",
|
|
1026
1027
|
approve: "po_approve",
|
|
1027
1028
|
mark_ordered: "po_mark_ordered",
|
|
1028
1029
|
receive: "po_receive",
|
|
@@ -1049,7 +1050,7 @@ async function executeSupplyChain(supabase, args, storeId, traceId, userId, user
|
|
|
1049
1050
|
}
|
|
1050
1051
|
return {
|
|
1051
1052
|
success: false,
|
|
1052
|
-
error: `Unknown supply_chain action: ${scAction}. Use po_create, po_list, po_get, po_approve, po_receive, po_cancel, transfer_create, transfer_list, transfer_approve, transfer_ship, transfer_receive, transfer_cancel, find_suppliers.`
|
|
1053
|
+
error: `Unknown supply_chain action: ${scAction}. Use po_create, po_list, po_get, po_add_items, po_update_items, po_approve, po_receive, po_cancel, transfer_create, transfer_list, transfer_approve, transfer_ship, transfer_receive, transfer_cancel, find_suppliers.`
|
|
1053
1054
|
};
|
|
1054
1055
|
}
|
|
1055
1056
|
|
|
@@ -1080,8 +1081,10 @@ skipAudit) {
|
|
|
1080
1081
|
};
|
|
1081
1082
|
}
|
|
1082
1083
|
|
|
1083
|
-
// Permission enforcement — check agent flags before tool execution
|
|
1084
|
-
|
|
1084
|
+
// Permission enforcement — check agent flags before tool execution.
|
|
1085
|
+
// Skip for whale-code CLI: it's a developer tool with full access.
|
|
1086
|
+
// Agent permissions only apply to customer-facing surfaces (webchat, channels, workflows).
|
|
1087
|
+
if (agentId && source !== "whale-code") {
|
|
1085
1088
|
const {
|
|
1086
1089
|
data: agentFlags
|
|
1087
1090
|
} = await supabase.from("ai_agent_config").select("can_query, can_modify").eq("id", agentId).single();
|