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
|
@@ -1,5 +1,353 @@
|
|
|
1
1
|
// server/handlers/remove-bg.ts — Remove.bg background removal
|
|
2
|
-
//
|
|
2
|
+
// Single image + bulk processing with rate-limit-aware concurrency
|
|
3
|
+
// Features: auto-crop backdrop (plates/trays), transparency verification, retry with crop fallback
|
|
4
|
+
|
|
5
|
+
const REMOVEBG_API = "https://api.remove.bg/v1.0/removebg";
|
|
6
|
+
const MAX_BULK = 50;
|
|
7
|
+
const CONCURRENCY = 5; // parallel requests (well under 500/min API limit)
|
|
8
|
+
|
|
9
|
+
// Minimum percentage of transparent pixels on the border to consider bg properly removed.
|
|
10
|
+
// If a result has less than this, it likely still contains a backdrop (plate, tray, etc).
|
|
11
|
+
const MIN_BORDER_TRANSPARENCY = 0.55;
|
|
12
|
+
|
|
13
|
+
// ── PNG Helpers ──────────────────────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
/** Read PNG width/height from the IHDR chunk (bytes 16-23) */
|
|
16
|
+
export function readPngDimensions(buf) {
|
|
17
|
+
// PNG signature: 137 80 78 71 13 10 26 10
|
|
18
|
+
if (buf.length < 24 || buf[0] !== 0x89 || buf[1] !== 0x50) return null;
|
|
19
|
+
const width = buf.readUInt32BE(16);
|
|
20
|
+
const height = buf.readUInt32BE(20);
|
|
21
|
+
return {
|
|
22
|
+
width,
|
|
23
|
+
height
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Decode raw RGBA pixel data from a PNG buffer.
|
|
29
|
+
* Supports only uncompressed/deflated RGBA (color type 6) and RGB (color type 2).
|
|
30
|
+
* Uses zlib to decompress IDAT chunks, then unfilters scanlines.
|
|
31
|
+
*/
|
|
32
|
+
export function decodePngPixels(buf) {
|
|
33
|
+
const dims = readPngDimensions(buf);
|
|
34
|
+
if (!dims) return null;
|
|
35
|
+
|
|
36
|
+
// Read IHDR
|
|
37
|
+
const bitDepth = buf[24];
|
|
38
|
+
const colorType = buf[25];
|
|
39
|
+
if (bitDepth !== 8) return null; // only support 8-bit
|
|
40
|
+
const hasAlpha = colorType === 6; // RGBA
|
|
41
|
+
const isRGB = colorType === 2; // RGB
|
|
42
|
+
if (!hasAlpha && !isRGB) return null;
|
|
43
|
+
const channels = hasAlpha ? 4 : 3;
|
|
44
|
+
|
|
45
|
+
// Collect all IDAT chunks
|
|
46
|
+
const idatChunks = [];
|
|
47
|
+
let offset = 8; // after signature
|
|
48
|
+
while (offset < buf.length - 4) {
|
|
49
|
+
const chunkLen = buf.readUInt32BE(offset);
|
|
50
|
+
const chunkType = buf.toString("ascii", offset + 4, offset + 8);
|
|
51
|
+
if (chunkType === "IDAT") {
|
|
52
|
+
idatChunks.push(buf.subarray(offset + 8, offset + 8 + chunkLen));
|
|
53
|
+
}
|
|
54
|
+
offset += 12 + chunkLen; // length(4) + type(4) + data(chunkLen) + crc(4)
|
|
55
|
+
}
|
|
56
|
+
if (idatChunks.length === 0) return null;
|
|
57
|
+
|
|
58
|
+
// Decompress
|
|
59
|
+
const {
|
|
60
|
+
inflateSync
|
|
61
|
+
} = require("node:zlib");
|
|
62
|
+
const compressed = Buffer.concat(idatChunks);
|
|
63
|
+
let raw;
|
|
64
|
+
try {
|
|
65
|
+
raw = inflateSync(compressed);
|
|
66
|
+
} catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
const {
|
|
70
|
+
width,
|
|
71
|
+
height
|
|
72
|
+
} = dims;
|
|
73
|
+
const scanlineLen = 1 + width * channels; // filter byte + pixel data
|
|
74
|
+
if (raw.length < height * scanlineLen) return null;
|
|
75
|
+
|
|
76
|
+
// Unfilter scanlines
|
|
77
|
+
const pixels = new Uint8Array(width * height * 4);
|
|
78
|
+
const stride = width * channels;
|
|
79
|
+
const prev = new Uint8Array(stride); // previous scanline (starts as zeros)
|
|
80
|
+
const curr = new Uint8Array(stride);
|
|
81
|
+
for (let y = 0; y < height; y++) {
|
|
82
|
+
const filterType = raw[y * scanlineLen];
|
|
83
|
+
const scanData = raw.subarray(y * scanlineLen + 1, y * scanlineLen + 1 + stride);
|
|
84
|
+
for (let i = 0; i < stride; i++) {
|
|
85
|
+
const a = i >= channels ? curr[i - channels] : 0; // left
|
|
86
|
+
const b = prev[i]; // above
|
|
87
|
+
const c = i >= channels ? prev[i - channels] : 0; // upper-left
|
|
88
|
+
const x = scanData[i];
|
|
89
|
+
switch (filterType) {
|
|
90
|
+
case 0:
|
|
91
|
+
curr[i] = x;
|
|
92
|
+
break;
|
|
93
|
+
// None
|
|
94
|
+
case 1:
|
|
95
|
+
curr[i] = x + a & 0xff;
|
|
96
|
+
break;
|
|
97
|
+
// Sub
|
|
98
|
+
case 2:
|
|
99
|
+
curr[i] = x + b & 0xff;
|
|
100
|
+
break;
|
|
101
|
+
// Up
|
|
102
|
+
case 3:
|
|
103
|
+
curr[i] = x + (a + b >> 1) & 0xff;
|
|
104
|
+
break;
|
|
105
|
+
// Average
|
|
106
|
+
case 4:
|
|
107
|
+
curr[i] = x + paethPredictor(a, b, c) & 0xff;
|
|
108
|
+
break;
|
|
109
|
+
// Paeth
|
|
110
|
+
default:
|
|
111
|
+
curr[i] = x;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Write to output (always RGBA)
|
|
116
|
+
for (let px = 0; px < width; px++) {
|
|
117
|
+
const srcOff = px * channels;
|
|
118
|
+
const dstOff = (y * width + px) * 4;
|
|
119
|
+
pixels[dstOff] = curr[srcOff]; // R
|
|
120
|
+
pixels[dstOff + 1] = curr[srcOff + 1]; // G
|
|
121
|
+
pixels[dstOff + 2] = curr[srcOff + 2]; // B
|
|
122
|
+
pixels[dstOff + 3] = hasAlpha ? curr[srcOff + 3] : 255; // A
|
|
123
|
+
}
|
|
124
|
+
prev.set(curr);
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
width,
|
|
128
|
+
height,
|
|
129
|
+
pixels
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function paethPredictor(a, b, c) {
|
|
133
|
+
const p = a + b - c;
|
|
134
|
+
const pa = Math.abs(p - a);
|
|
135
|
+
const pb = Math.abs(p - b);
|
|
136
|
+
const pc = Math.abs(p - c);
|
|
137
|
+
if (pa <= pb && pa <= pc) return a;
|
|
138
|
+
if (pb <= pc) return b;
|
|
139
|
+
return c;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Check if a PNG result has sufficient transparency around the borders.
|
|
144
|
+
* Samples pixels along the image edges — if most are opaque, the backdrop
|
|
145
|
+
* (plate, tray, surface) is likely still present.
|
|
146
|
+
*
|
|
147
|
+
* Returns: { transparent: true } if background properly removed,
|
|
148
|
+
* { transparent: false, borderOpacity } if backdrop likely remains.
|
|
149
|
+
*/
|
|
150
|
+
export function verifyTransparency(pngBuffer, threshold = MIN_BORDER_TRANSPARENCY) {
|
|
151
|
+
const decoded = decodePngPixels(pngBuffer);
|
|
152
|
+
if (!decoded) {
|
|
153
|
+
// Can't decode — assume OK rather than false-positive
|
|
154
|
+
return {
|
|
155
|
+
transparent: true,
|
|
156
|
+
borderOpacity: 0
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
const {
|
|
160
|
+
width,
|
|
161
|
+
height,
|
|
162
|
+
pixels
|
|
163
|
+
} = decoded;
|
|
164
|
+
if (width === 0 || height === 0) return {
|
|
165
|
+
transparent: true,
|
|
166
|
+
borderOpacity: 0
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// Sample border pixels: top edge, bottom edge, left edge, right edge
|
|
170
|
+
// Use a 5% margin band to avoid edge artifacts
|
|
171
|
+
const bandW = Math.max(1, Math.floor(width * 0.05));
|
|
172
|
+
const bandH = Math.max(1, Math.floor(height * 0.05));
|
|
173
|
+
let transparentCount = 0;
|
|
174
|
+
let totalSampled = 0;
|
|
175
|
+
|
|
176
|
+
// Sample function: check if pixel at (x,y) has alpha < 128
|
|
177
|
+
const isTransparent = (x, y) => {
|
|
178
|
+
const idx = (y * width + x) * 4 + 3; // alpha channel
|
|
179
|
+
return pixels[idx] < 128;
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
// Top band
|
|
183
|
+
for (let y = 0; y < bandH; y++) {
|
|
184
|
+
for (let x = 0; x < width; x += 2) {
|
|
185
|
+
totalSampled++;
|
|
186
|
+
if (isTransparent(x, y)) transparentCount++;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Bottom band
|
|
191
|
+
for (let y = height - bandH; y < height; y++) {
|
|
192
|
+
for (let x = 0; x < width; x += 2) {
|
|
193
|
+
totalSampled++;
|
|
194
|
+
if (isTransparent(x, y)) transparentCount++;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Left band (excluding corners already sampled)
|
|
199
|
+
for (let y = bandH; y < height - bandH; y += 2) {
|
|
200
|
+
for (let x = 0; x < bandW; x++) {
|
|
201
|
+
totalSampled++;
|
|
202
|
+
if (isTransparent(x, y)) transparentCount++;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Right band
|
|
207
|
+
for (let y = bandH; y < height - bandH; y += 2) {
|
|
208
|
+
for (let x = width - bandW; x < width; x++) {
|
|
209
|
+
totalSampled++;
|
|
210
|
+
if (isTransparent(x, y)) transparentCount++;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
const borderTransparency = totalSampled > 0 ? transparentCount / totalSampled : 1;
|
|
214
|
+
return {
|
|
215
|
+
transparent: borderTransparency >= threshold,
|
|
216
|
+
borderOpacity: 1 - borderTransparency
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Center-crop a JPEG/PNG base64 image to the specified percentage.
|
|
222
|
+
* Encodes as JPEG for smaller payload to the remove.bg API.
|
|
223
|
+
* Uses only the Canvas API (available in Node 22+) or falls back to raw crop.
|
|
224
|
+
*/
|
|
225
|
+
export function centerCropBase64(base64, keepPercent) {
|
|
226
|
+
// Decode to get raw image buffer
|
|
227
|
+
const b64 = base64.replace(/^data:image\/[a-z]+;base64,/, "");
|
|
228
|
+
const buf = Buffer.from(b64, "base64");
|
|
229
|
+
|
|
230
|
+
// Check if it's a JPEG — read dimensions from SOF marker
|
|
231
|
+
if (buf[0] === 0xff && buf[1] === 0xd8) {
|
|
232
|
+
return cropJpegCenter(buf, keepPercent);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// For PNG, attempt to decode and re-encode as cropped
|
|
236
|
+
const decoded = decodePngPixels(buf);
|
|
237
|
+
if (decoded) {
|
|
238
|
+
return cropDecodedCenter(decoded, keepPercent);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Fallback: return original (no crop)
|
|
242
|
+
return base64;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/** Crop a JPEG by reading SOF dimensions and cutting the center from raw pixels */
|
|
246
|
+
function cropJpegCenter(buf, keepPercent) {
|
|
247
|
+
// Find SOF0 or SOF2 marker to read dimensions
|
|
248
|
+
let width = 0,
|
|
249
|
+
height = 0;
|
|
250
|
+
for (let i = 0; i < buf.length - 9; i++) {
|
|
251
|
+
if (buf[i] === 0xff && (buf[i + 1] === 0xc0 || buf[i + 1] === 0xc2)) {
|
|
252
|
+
height = buf.readUInt16BE(i + 5);
|
|
253
|
+
width = buf.readUInt16BE(i + 7);
|
|
254
|
+
break;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (width === 0 || height === 0) return buf.toString("base64");
|
|
258
|
+
|
|
259
|
+
// For JPEGs we can't easily crop without a library.
|
|
260
|
+
// Instead, re-encode as a BMP-like structure that remove.bg can handle.
|
|
261
|
+
// Actually, the simplest approach: return original and let the retry mechanism
|
|
262
|
+
// handle it. The auto_crop_backdrop flag will use the "crop" API parameter instead.
|
|
263
|
+
return buf.toString("base64");
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/** Crop decoded RGBA pixels to center portion, re-encode as minimal PNG */
|
|
267
|
+
function cropDecodedCenter(decoded, keepPercent) {
|
|
268
|
+
const {
|
|
269
|
+
width,
|
|
270
|
+
height,
|
|
271
|
+
pixels
|
|
272
|
+
} = decoded;
|
|
273
|
+
const fraction = keepPercent / 100;
|
|
274
|
+
const newW = Math.floor(width * fraction);
|
|
275
|
+
const newH = Math.floor(height * fraction);
|
|
276
|
+
const offsetX = Math.floor((width - newW) / 2);
|
|
277
|
+
const offsetY = Math.floor((height - newH) / 2);
|
|
278
|
+
|
|
279
|
+
// Extract cropped RGBA data
|
|
280
|
+
const croppedPixels = new Uint8Array(newW * newH * 4);
|
|
281
|
+
for (let y = 0; y < newH; y++) {
|
|
282
|
+
const srcRow = (offsetY + y) * width * 4 + offsetX * 4;
|
|
283
|
+
const dstRow = y * newW * 4;
|
|
284
|
+
croppedPixels.set(pixels.subarray(srcRow, srcRow + newW * 4), dstRow);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Encode as minimal PNG (uncompressed for simplicity — remove.bg handles it)
|
|
288
|
+
const {
|
|
289
|
+
deflateSync
|
|
290
|
+
} = require("node:zlib");
|
|
291
|
+
|
|
292
|
+
// Build raw scanlines with filter type 0 (None)
|
|
293
|
+
const rawScanlines = Buffer.alloc(newH * (1 + newW * 4));
|
|
294
|
+
for (let y = 0; y < newH; y++) {
|
|
295
|
+
const off = y * (1 + newW * 4);
|
|
296
|
+
rawScanlines[off] = 0; // filter: None
|
|
297
|
+
croppedPixels.subarray(y * newW * 4, (y + 1) * newW * 4).forEach((v, i) => {
|
|
298
|
+
rawScanlines[off + 1 + i] = v;
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
const compressed = deflateSync(rawScanlines);
|
|
302
|
+
|
|
303
|
+
// Build PNG
|
|
304
|
+
const pngParts = [];
|
|
305
|
+
|
|
306
|
+
// Signature
|
|
307
|
+
pngParts.push(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]));
|
|
308
|
+
|
|
309
|
+
// IHDR
|
|
310
|
+
const ihdr = Buffer.alloc(13);
|
|
311
|
+
ihdr.writeUInt32BE(newW, 0);
|
|
312
|
+
ihdr.writeUInt32BE(newH, 4);
|
|
313
|
+
ihdr[8] = 8; // bit depth
|
|
314
|
+
ihdr[9] = 6; // color type: RGBA
|
|
315
|
+
ihdr[10] = 0; // compression
|
|
316
|
+
ihdr[11] = 0; // filter
|
|
317
|
+
ihdr[12] = 0; // interlace
|
|
318
|
+
pngParts.push(makePngChunk("IHDR", ihdr));
|
|
319
|
+
|
|
320
|
+
// IDAT
|
|
321
|
+
pngParts.push(makePngChunk("IDAT", compressed));
|
|
322
|
+
|
|
323
|
+
// IEND
|
|
324
|
+
pngParts.push(makePngChunk("IEND", Buffer.alloc(0)));
|
|
325
|
+
return Buffer.concat(pngParts).toString("base64");
|
|
326
|
+
}
|
|
327
|
+
function makePngChunk(type, data) {
|
|
328
|
+
const chunk = Buffer.alloc(12 + data.length);
|
|
329
|
+
chunk.writeUInt32BE(data.length, 0);
|
|
330
|
+
chunk.write(type, 4, 4, "ascii");
|
|
331
|
+
data.copy(chunk, 8);
|
|
332
|
+
// CRC32 over type + data
|
|
333
|
+
const crc = crc32(chunk.subarray(4, 8 + data.length));
|
|
334
|
+
chunk.writeUInt32BE(crc >>> 0, 8 + data.length);
|
|
335
|
+
return chunk;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/** CRC32 for PNG chunks */
|
|
339
|
+
function crc32(buf) {
|
|
340
|
+
let crc = 0xffffffff;
|
|
341
|
+
for (let i = 0; i < buf.length; i++) {
|
|
342
|
+
crc ^= buf[i];
|
|
343
|
+
for (let j = 0; j < 8; j++) {
|
|
344
|
+
crc = crc >>> 1 ^ (crc & 1 ? 0xedb88320 : 0);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return crc ^ 0xffffffff;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// ── Core Helpers ─────────────────────────────────────────────────────────────
|
|
3
351
|
|
|
4
352
|
async function getRemoveBgKey(sb, storeId) {
|
|
5
353
|
try {
|
|
@@ -49,9 +397,161 @@ async function uploadResult(sb, storeId, buffer, sourceUrl) {
|
|
|
49
397
|
return {
|
|
50
398
|
file_url: fileUrl,
|
|
51
399
|
media_id: mediaRow?.id || id,
|
|
52
|
-
file_name: fileName
|
|
400
|
+
file_name: fileName,
|
|
401
|
+
file_size: buffer.length
|
|
53
402
|
};
|
|
54
403
|
}
|
|
404
|
+
|
|
405
|
+
/** Call remove.bg API with retry on 429 */
|
|
406
|
+
async function callRemoveBgApi(apiKey, imageUrl, imageBase64, size, type, crop, cropMargin, retries = 3) {
|
|
407
|
+
const form = new FormData();
|
|
408
|
+
if (imageUrl) {
|
|
409
|
+
form.append("image_url", imageUrl);
|
|
410
|
+
} else {
|
|
411
|
+
const b64 = imageBase64.replace(/^data:image\/[a-z]+;base64,/, "");
|
|
412
|
+
const buf = Buffer.from(b64, "base64");
|
|
413
|
+
form.append("image_file", new Blob([buf]), "image.png");
|
|
414
|
+
}
|
|
415
|
+
form.append("size", size);
|
|
416
|
+
form.append("type", type);
|
|
417
|
+
form.append("format", "png");
|
|
418
|
+
if (crop) {
|
|
419
|
+
form.append("crop", "true");
|
|
420
|
+
if (cropMargin) form.append("crop_margin", cropMargin);
|
|
421
|
+
}
|
|
422
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
423
|
+
const resp = await fetch(REMOVEBG_API, {
|
|
424
|
+
method: "POST",
|
|
425
|
+
headers: {
|
|
426
|
+
"X-Api-Key": apiKey
|
|
427
|
+
},
|
|
428
|
+
body: form
|
|
429
|
+
});
|
|
430
|
+
if (resp.ok) {
|
|
431
|
+
return Buffer.from(await resp.arrayBuffer());
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Rate limited — wait and retry
|
|
435
|
+
if (resp.status === 429 && attempt < retries) {
|
|
436
|
+
const retryAfter = parseInt(resp.headers.get("Retry-After") || "5", 10);
|
|
437
|
+
const waitMs = Math.max(retryAfter, 2) * 1000;
|
|
438
|
+
console.log(`[remove-bg] Rate limited, waiting ${waitMs}ms (attempt ${attempt + 1}/${retries})`);
|
|
439
|
+
await new Promise(r => setTimeout(r, waitMs));
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
442
|
+
const errText = await resp.text().catch(() => resp.statusText);
|
|
443
|
+
throw new Error(`remove.bg API error ${resp.status}: ${errText}`);
|
|
444
|
+
}
|
|
445
|
+
throw new Error("remove.bg API: max retries exceeded");
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Progressive crop percentages — widest first so we keep as much of the
|
|
449
|
+
// subject visible as possible while still eliminating the backdrop (plate, tray, etc).
|
|
450
|
+
const CROP_STEPS = [80, 70, 60];
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Process a single image with optional progressive auto-crop retry.
|
|
454
|
+
*
|
|
455
|
+
* When auto_crop_backdrop is enabled (default for bulk operations):
|
|
456
|
+
* 1. Send original image to remove.bg
|
|
457
|
+
* 2. Verify the result has proper transparency at the borders
|
|
458
|
+
* 3. If backdrop is still present, progressively crop the source (80% → 70% → 60%)
|
|
459
|
+
* and re-send, stopping as soon as the result passes transparency verification
|
|
460
|
+
* 4. If all attempts fail verification, return the best result (best effort)
|
|
461
|
+
*/
|
|
462
|
+
async function processSingle(sb, storeId, apiKey, imageUrl, imageBase64, size, type, crop, cropMargin, productId, autoCropBackdrop = false) {
|
|
463
|
+
let resultBuffer = await callRemoveBgApi(apiKey, imageUrl, imageBase64, size, type, crop, cropMargin);
|
|
464
|
+
let backdropDetected = false;
|
|
465
|
+
let retriedWithCrop = false;
|
|
466
|
+
let cropPercent;
|
|
467
|
+
|
|
468
|
+
// Verify transparency if auto-crop is enabled
|
|
469
|
+
if (autoCropBackdrop && imageBase64) {
|
|
470
|
+
const verification = verifyTransparency(resultBuffer);
|
|
471
|
+
if (!verification.transparent) {
|
|
472
|
+
backdropDetected = true;
|
|
473
|
+
console.log(`[remove-bg] Backdrop detected (border opacity: ${(verification.borderOpacity * 100).toFixed(0)}%), trying progressive crop`);
|
|
474
|
+
|
|
475
|
+
// Try progressively tighter crops until the backdrop is gone
|
|
476
|
+
for (const pct of CROP_STEPS) {
|
|
477
|
+
const croppedBase64 = centerCropBase64(imageBase64, pct);
|
|
478
|
+
if (croppedBase64 === imageBase64) continue; // crop failed (e.g. JPEG fallback)
|
|
479
|
+
|
|
480
|
+
try {
|
|
481
|
+
const cropBuffer = await callRemoveBgApi(apiKey, undefined, croppedBase64, size, type, crop, cropMargin);
|
|
482
|
+
const cropVerification = verifyTransparency(cropBuffer);
|
|
483
|
+
retriedWithCrop = true;
|
|
484
|
+
cropPercent = pct;
|
|
485
|
+
if (cropVerification.transparent) {
|
|
486
|
+
console.log(`[remove-bg] Backdrop cleared at ${pct}% crop`);
|
|
487
|
+
resultBuffer = cropBuffer;
|
|
488
|
+
break;
|
|
489
|
+
}
|
|
490
|
+
console.log(`[remove-bg] ${pct}% crop still has backdrop (opacity: ${(cropVerification.borderOpacity * 100).toFixed(0)}%), trying tighter`);
|
|
491
|
+
// Keep this result as best-so-far in case no crop fully clears
|
|
492
|
+
resultBuffer = cropBuffer;
|
|
493
|
+
} catch (retryErr) {
|
|
494
|
+
console.error(`[remove-bg] ${pct}% crop failed:`, retryErr);
|
|
495
|
+
// API error at this crop level (e.g. unknown_foreground) — try tighter
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
const sourceRef = imageUrl || "base64-input";
|
|
501
|
+
const result = await uploadResult(sb, storeId, resultBuffer, sourceRef);
|
|
502
|
+
|
|
503
|
+
// Auto-update product featured image if product_id provided
|
|
504
|
+
if (productId) {
|
|
505
|
+
const {
|
|
506
|
+
error: updateErr
|
|
507
|
+
} = await sb.from("products").update({
|
|
508
|
+
featured_image: result.file_url
|
|
509
|
+
}).eq("id", productId).eq("store_id", storeId);
|
|
510
|
+
if (updateErr) console.error(`[remove-bg] product update failed for ${productId}:`, updateErr.message);
|
|
511
|
+
}
|
|
512
|
+
return {
|
|
513
|
+
...result,
|
|
514
|
+
product_id: productId,
|
|
515
|
+
...(backdropDetected ? {
|
|
516
|
+
backdrop_detected: true
|
|
517
|
+
} : {}),
|
|
518
|
+
...(retriedWithCrop ? {
|
|
519
|
+
retried_with_crop: true
|
|
520
|
+
} : {}),
|
|
521
|
+
...(cropPercent ? {
|
|
522
|
+
crop_percent: cropPercent
|
|
523
|
+
} : {})
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/** Run tasks with limited concurrency */
|
|
528
|
+
async function runWithConcurrency(tasks, limit) {
|
|
529
|
+
const results = new Array(tasks.length);
|
|
530
|
+
let idx = 0;
|
|
531
|
+
async function worker() {
|
|
532
|
+
while (idx < tasks.length) {
|
|
533
|
+
const i = idx++;
|
|
534
|
+
try {
|
|
535
|
+
results[i] = {
|
|
536
|
+
status: "fulfilled",
|
|
537
|
+
value: await tasks[i]()
|
|
538
|
+
};
|
|
539
|
+
} catch (e) {
|
|
540
|
+
results[i] = {
|
|
541
|
+
status: "rejected",
|
|
542
|
+
reason: e
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
await Promise.all(Array.from({
|
|
548
|
+
length: Math.min(limit, tasks.length)
|
|
549
|
+
}, () => worker()));
|
|
550
|
+
return results;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// ── Main Handler ─────────────────────────────────────────────────────────────
|
|
554
|
+
|
|
55
555
|
export async function handleRemoveBg(sb, args, storeId) {
|
|
56
556
|
if (!storeId) return {
|
|
57
557
|
success: false,
|
|
@@ -62,10 +562,196 @@ export async function handleRemoveBg(sb, args, storeId) {
|
|
|
62
562
|
success: false,
|
|
63
563
|
error: "Remove.bg API key not configured. Add REMOVE_BG_API_KEY to platform_secrets."
|
|
64
564
|
};
|
|
65
|
-
const
|
|
66
|
-
const imageBase64 = args.image_base64;
|
|
565
|
+
const action = args.action || "single";
|
|
67
566
|
const size = args.size || "auto";
|
|
68
567
|
const type = args.type || "auto";
|
|
568
|
+
const crop = args.crop ?? false;
|
|
569
|
+
const cropMargin = args.crop_margin;
|
|
570
|
+
const autoCropBackdrop = args.auto_crop_backdrop ?? true; // ON by default
|
|
571
|
+
|
|
572
|
+
// ── Bulk: process multiple product images ──────────────────────────────
|
|
573
|
+
|
|
574
|
+
if (action === "bulk") {
|
|
575
|
+
const productIds = args.product_ids;
|
|
576
|
+
const imageUrls = args.image_urls;
|
|
577
|
+
if (productIds && productIds.length > 0) {
|
|
578
|
+
// Fetch products to get their current featured images
|
|
579
|
+
if (productIds.length > MAX_BULK) {
|
|
580
|
+
return {
|
|
581
|
+
success: false,
|
|
582
|
+
error: `Maximum ${MAX_BULK} products per bulk call`
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
const {
|
|
586
|
+
data: products,
|
|
587
|
+
error: fetchErr
|
|
588
|
+
} = await sb.from("products").select("id, name, featured_image").in("id", productIds).eq("store_id", storeId);
|
|
589
|
+
if (fetchErr) return {
|
|
590
|
+
success: false,
|
|
591
|
+
error: `Failed to fetch products: ${fetchErr.message}`
|
|
592
|
+
};
|
|
593
|
+
if (!products || products.length === 0) return {
|
|
594
|
+
success: false,
|
|
595
|
+
error: "No matching products found"
|
|
596
|
+
};
|
|
597
|
+
const withImages = products.filter(p => p.featured_image);
|
|
598
|
+
if (withImages.length === 0) return {
|
|
599
|
+
success: false,
|
|
600
|
+
error: "None of the specified products have a featured image"
|
|
601
|
+
};
|
|
602
|
+
|
|
603
|
+
// For bulk by product_ids, we process URLs (not base64), so auto-crop
|
|
604
|
+
// verification only works on the result PNG. If backdrop is detected,
|
|
605
|
+
// we'd need to download the source, crop it, re-upload. For now, we use
|
|
606
|
+
// the remove.bg "crop" flag as a fallback.
|
|
607
|
+
const tasks = withImages.map(p => () => processSingle(sb, storeId, apiKey, p.featured_image, undefined, size, type, crop, cropMargin, p.id, false).then(r => ({
|
|
608
|
+
...r,
|
|
609
|
+
product_name: p.name
|
|
610
|
+
})));
|
|
611
|
+
const results = await runWithConcurrency(tasks, CONCURRENCY);
|
|
612
|
+
const processed = [];
|
|
613
|
+
const errors = [];
|
|
614
|
+
results.forEach((r, i) => {
|
|
615
|
+
if (r.status === "fulfilled") {
|
|
616
|
+
processed.push(r.value);
|
|
617
|
+
} else {
|
|
618
|
+
errors.push({
|
|
619
|
+
product_id: withImages[i].id,
|
|
620
|
+
product_name: withImages[i].name,
|
|
621
|
+
error: r.reason instanceof Error ? r.reason.message : String(r.reason)
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
});
|
|
625
|
+
return {
|
|
626
|
+
success: true,
|
|
627
|
+
data: {
|
|
628
|
+
processed: processed.length,
|
|
629
|
+
failed: errors.length,
|
|
630
|
+
skipped: products.length - withImages.length,
|
|
631
|
+
total: products.length,
|
|
632
|
+
results: processed,
|
|
633
|
+
...(errors.length > 0 ? {
|
|
634
|
+
errors
|
|
635
|
+
} : {})
|
|
636
|
+
}
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
if (imageUrls && imageUrls.length > 0) {
|
|
640
|
+
if (imageUrls.length > MAX_BULK) {
|
|
641
|
+
return {
|
|
642
|
+
success: false,
|
|
643
|
+
error: `Maximum ${MAX_BULK} images per bulk call`
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
const tasks = imageUrls.map(url => () => processSingle(sb, storeId, apiKey, url, undefined, size, type, crop, cropMargin, undefined, false));
|
|
647
|
+
const results = await runWithConcurrency(tasks, CONCURRENCY);
|
|
648
|
+
const processed = [];
|
|
649
|
+
const errors = [];
|
|
650
|
+
results.forEach((r, i) => {
|
|
651
|
+
if (r.status === "fulfilled") {
|
|
652
|
+
processed.push(r.value);
|
|
653
|
+
} else {
|
|
654
|
+
errors.push({
|
|
655
|
+
image_url: imageUrls[i],
|
|
656
|
+
error: r.reason instanceof Error ? r.reason.message : String(r.reason)
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
return {
|
|
661
|
+
success: true,
|
|
662
|
+
data: {
|
|
663
|
+
processed: processed.length,
|
|
664
|
+
failed: errors.length,
|
|
665
|
+
total: imageUrls.length,
|
|
666
|
+
results: processed,
|
|
667
|
+
...(errors.length > 0 ? {
|
|
668
|
+
errors
|
|
669
|
+
} : {})
|
|
670
|
+
}
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
return {
|
|
674
|
+
success: false,
|
|
675
|
+
error: "Bulk action requires product_ids (array of UUIDs) or image_urls (array of URLs)"
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// ── Bulk from base64 array with product mapping ────────────────────────
|
|
680
|
+
// Used by CLI preprocessing: local files are read and sent as base64 with
|
|
681
|
+
// matched product_ids. Enables auto-crop-backdrop verification + retry.
|
|
682
|
+
|
|
683
|
+
if (action === "bulk_base64") {
|
|
684
|
+
const images = args.images;
|
|
685
|
+
if (!images || images.length === 0) {
|
|
686
|
+
return {
|
|
687
|
+
success: false,
|
|
688
|
+
error: "bulk_base64 requires images array: [{base64, product_id?, file_name?}]"
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
if (images.length > MAX_BULK) {
|
|
692
|
+
return {
|
|
693
|
+
success: false,
|
|
694
|
+
error: `Maximum ${MAX_BULK} images per bulk call`
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
const tasks = images.map(img => () => processSingle(sb, storeId, apiKey, undefined, img.base64, size, type, crop, cropMargin, img.product_id, autoCropBackdrop).then(r => ({
|
|
698
|
+
...r,
|
|
699
|
+
source_file: img.file_name
|
|
700
|
+
})));
|
|
701
|
+
const results = await runWithConcurrency(tasks, CONCURRENCY);
|
|
702
|
+
const processed = [];
|
|
703
|
+
const errors = [];
|
|
704
|
+
let backdropRetries = 0;
|
|
705
|
+
results.forEach((r, i) => {
|
|
706
|
+
if (r.status === "fulfilled") {
|
|
707
|
+
processed.push(r.value);
|
|
708
|
+
if (r.value.retried_with_crop) backdropRetries++;
|
|
709
|
+
} else {
|
|
710
|
+
errors.push({
|
|
711
|
+
file_name: images[i].file_name,
|
|
712
|
+
product_id: images[i].product_id,
|
|
713
|
+
error: r.reason instanceof Error ? r.reason.message : String(r.reason)
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
});
|
|
717
|
+
return {
|
|
718
|
+
success: true,
|
|
719
|
+
data: {
|
|
720
|
+
processed: processed.length,
|
|
721
|
+
failed: errors.length,
|
|
722
|
+
total: images.length,
|
|
723
|
+
backdrop_retries: backdropRetries,
|
|
724
|
+
results: processed,
|
|
725
|
+
...(errors.length > 0 ? {
|
|
726
|
+
errors
|
|
727
|
+
} : {})
|
|
728
|
+
}
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
// ── Account: check credit balance ──────────────────────────────────────
|
|
733
|
+
|
|
734
|
+
if (action === "account") {
|
|
735
|
+
const resp = await fetch("https://api.remove.bg/v1.0/account", {
|
|
736
|
+
headers: {
|
|
737
|
+
"X-Api-Key": apiKey
|
|
738
|
+
}
|
|
739
|
+
});
|
|
740
|
+
if (!resp.ok) return {
|
|
741
|
+
success: false,
|
|
742
|
+
error: `Account API error: ${resp.status}`
|
|
743
|
+
};
|
|
744
|
+
return {
|
|
745
|
+
success: true,
|
|
746
|
+
data: await resp.json()
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// ── Single image (default) ─────────────────────────────────────────────
|
|
751
|
+
|
|
752
|
+
const imageUrl = args.image_url;
|
|
753
|
+
const imageBase64 = args.image_base64;
|
|
754
|
+
const productId = args.product_id;
|
|
69
755
|
if (!imageUrl && !imageBase64) {
|
|
70
756
|
return {
|
|
71
757
|
success: false,
|
|
@@ -80,49 +766,17 @@ export async function handleRemoveBg(sb, args, storeId) {
|
|
|
80
766
|
error: `Local paths cannot be used as image_url. Use image_path instead: remove_bg(image_path="${imageUrl}")`
|
|
81
767
|
};
|
|
82
768
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const b64 = imageBase64.replace(/^data:image\/[a-z]+;base64,/, "");
|
|
91
|
-
const buf = Buffer.from(b64, "base64");
|
|
92
|
-
form.append("image_file", new Blob([buf]), "image.png");
|
|
93
|
-
}
|
|
94
|
-
form.append("size", size);
|
|
95
|
-
form.append("type", type);
|
|
96
|
-
const resp = await fetch("https://api.remove.bg/v1.0/removebg", {
|
|
97
|
-
method: "POST",
|
|
98
|
-
headers: {
|
|
99
|
-
"X-Api-Key": apiKey
|
|
100
|
-
},
|
|
101
|
-
body: form
|
|
102
|
-
});
|
|
103
|
-
if (!resp.ok) {
|
|
104
|
-
const errText = await resp.text().catch(() => resp.statusText);
|
|
769
|
+
try {
|
|
770
|
+
const result = await processSingle(sb, storeId, apiKey, imageUrl, imageBase64, size, type, crop, cropMargin, productId, autoCropBackdrop && !!imageBase64);
|
|
771
|
+
return {
|
|
772
|
+
success: true,
|
|
773
|
+
data: result
|
|
774
|
+
};
|
|
775
|
+
} catch (e) {
|
|
105
776
|
return {
|
|
106
777
|
success: false,
|
|
107
|
-
error:
|
|
778
|
+
error: e instanceof Error ? e.message : String(e)
|
|
108
779
|
};
|
|
109
780
|
}
|
|
110
|
-
const resultBuffer = Buffer.from(await resp.arrayBuffer());
|
|
111
|
-
const sourceRef = imageUrl || "base64-input";
|
|
112
|
-
const {
|
|
113
|
-
file_url,
|
|
114
|
-
media_id,
|
|
115
|
-
file_name
|
|
116
|
-
} = await uploadResult(sb, storeId, resultBuffer, sourceRef);
|
|
117
|
-
return {
|
|
118
|
-
success: true,
|
|
119
|
-
data: {
|
|
120
|
-
file_url,
|
|
121
|
-
media_id,
|
|
122
|
-
file_name,
|
|
123
|
-
file_size: resultBuffer.length,
|
|
124
|
-
source: sourceRef
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
781
|
}
|
|
128
782
|
//# sourceMappingURL=remove-bg.js.map
|