@stkxp/cli 0.1.2
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/README.md +273 -0
- package/bin/stkxp.mjs +198 -0
- package/package.json +97 -0
- package/src/bootstrap.mjs +37 -0
- package/src/bootstrap.test.mjs +73 -0
- package/src/deploy.mjs +145 -0
- package/src/deploy.test.mjs +131 -0
- package/src/export.mjs +30 -0
- package/src/export.test.mjs +56 -0
- package/src/secret-input.mjs +64 -0
- package/src/secret-input.test.mjs +58 -0
- package/src/serve.mjs +83 -0
- package/src/serve.test.mjs +93 -0
- package/vendor/dist-server/asyncapi/generator.js +1 -0
- package/vendor/dist-server/asyncapi/messages.js +1 -0
- package/vendor/dist-server/asyncapi/viewer.html +43 -0
- package/vendor/dist-server/core/app-config/branding.js +1 -0
- package/vendor/dist-server/core/app-config/mantine-theme.js +1 -0
- package/vendor/dist-server/core/app-config/mermaid-theme.js +2 -0
- package/vendor/dist-server/core/app-config/prompt-optimization.js +1 -0
- package/vendor/dist-server/core/app-config/settings.js +1 -0
- package/vendor/dist-server/core/config.js +1 -0
- package/vendor/dist-server/core/graph/a2a-agent-executor.js +2 -0
- package/vendor/dist-server/core/graph/app.js +120 -0
- package/vendor/dist-server/core/graph/delegated-agent-adapter.js +1 -0
- package/vendor/dist-server/core/graph/graph-builder.js +3 -0
- package/vendor/dist-server/core/graph/kibana-agent-executor.js +1 -0
- package/vendor/dist-server/core/graph/nodes/context/assistants-context.js +5 -0
- package/vendor/dist-server/core/graph/nodes/context/compare-context.js +10 -0
- package/vendor/dist-server/core/graph/nodes/context/enrich-context.js +8 -0
- package/vendor/dist-server/core/graph/nodes/context/inventory-context.js +4 -0
- package/vendor/dist-server/core/graph/nodes/context/namespace-context.js +2 -0
- package/vendor/dist-server/core/graph/nodes/context/node-types-context.js +4 -0
- package/vendor/dist-server/core/graph/nodes/context/relevant-assistants-context.js +5 -0
- package/vendor/dist-server/core/graph/nodes/context/relevant-skills-context.js +5 -0
- package/vendor/dist-server/core/graph/nodes/context/skills-context.js +8 -0
- package/vendor/dist-server/core/graph/nodes/context/state-setter.js +1 -0
- package/vendor/dist-server/core/graph/nodes/control/check-reset.js +1 -0
- package/vendor/dist-server/core/graph/nodes/control/topic-detection.js +1 -0
- package/vendor/dist-server/core/graph/nodes/governance/human-approval.js +16 -0
- package/vendor/dist-server/core/graph/nodes/index.js +1 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/suggestion-generator.js +17 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-decider.js +1 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-execution/decider-error.js +4 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-execution/decider-standalone-runner.js +1 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-execution/decider-synthesis.js +29 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-execution/pipeline-memory.js +2 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-execution/pipeline-runner.js +7 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-execution/team-assistant-utils.js +1 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-finder.js +13 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-invoker.js +3 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-parallel.js +1 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-pipeline.js +6 -0
- package/vendor/dist-server/core/graph/nodes/orchestration/team-router.js +26 -0
- package/vendor/dist-server/core/graph/nodes/reasoning/code-executor/index.js +6 -0
- package/vendor/dist-server/core/graph/nodes/reasoning/code-executor/resource-bridge.js +2 -0
- package/vendor/dist-server/core/graph/nodes/reasoning/code-executor/sandbox.js +6 -0
- package/vendor/dist-server/core/graph/nodes/reasoning/code-executor/tool-bridge.js +1 -0
- package/vendor/dist-server/core/graph/nodes/reasoning/local-extractor.js +5 -0
- package/vendor/dist-server/core/graph/nodes/reasoning/response-generator.js +47 -0
- package/vendor/dist-server/core/graph/nodes/reasoning/static-code-executor/index.js +1 -0
- package/vendor/dist-server/core/graph/nodes/reasoning/system.js +54 -0
- package/vendor/dist-server/core/graph/nodes/reasoning/tool-executor.js +9 -0
- package/vendor/dist-server/core/graph/nodes/tools/raw-output.js +4 -0
- package/vendor/dist-server/core/graph/nodes/tools/tool-cleaner.js +7 -0
- package/vendor/dist-server/core/graph/nodes/tools/tool-execution/execute-tool-calls.js +3 -0
- package/vendor/dist-server/core/graph/nodes/tools/tool-execution/invoke.js +1 -0
- package/vendor/dist-server/core/graph/nodes/tools/tool-execution/namespace-guard.js +1 -0
- package/vendor/dist-server/core/graph/nodes/tools/tool-execution/result-limits.js +3 -0
- package/vendor/dist-server/core/graph/nodes/tools/tool-invoker.js +1 -0
- package/vendor/dist-server/core/graph/nodes/tools/tool.js +4 -0
- package/vendor/dist-server/core/graph/schemas.js +1 -0
- package/vendor/dist-server/core/graph/topic-variants.js +1 -0
- package/vendor/dist-server/core/graph/types.js +1 -0
- package/vendor/dist-server/core/graph/utils/content-utils.js +17 -0
- package/vendor/dist-server/core/graph/utils/edge-jsonata-condition.js +1 -0
- package/vendor/dist-server/core/graph/utils/engine-vars.js +1 -0
- package/vendor/dist-server/core/graph/utils/logging-utils.js +4 -0
- package/vendor/dist-server/core/graph/utils/message-utils.js +5 -0
- package/vendor/dist-server/core/graph/utils/node-type-defaults-cache.js +1 -0
- package/vendor/dist-server/core/graph/utils/sandbox-catalog.js +1 -0
- package/vendor/dist-server/core/graph/utils/schema-utils.js +1 -0
- package/vendor/dist-server/core/graph/utils/team-context-policy.js +5 -0
- package/vendor/dist-server/core/graph/utils/team-node-resolvers.js +1 -0
- package/vendor/dist-server/core/graph/utils/tool-result.js +4 -0
- package/vendor/dist-server/core/graph/utils/tool-wrapper.js +14 -0
- package/vendor/dist-server/core/llm/init-indices.js +1 -0
- package/vendor/dist-server/core/llm/models/index.js +1 -0
- package/vendor/dist-server/core/llm/models/model.model.js +1 -0
- package/vendor/dist-server/core/llm/models/provider.model.js +1 -0
- package/vendor/dist-server/core/llm/models/routing-rule.model.js +1 -0
- package/vendor/dist-server/core/llm/providers.js +1 -0
- package/vendor/dist-server/core/mcp/client.js +1 -0
- package/vendor/dist-server/core/runtime/active-runs-registry.js +1 -0
- package/vendor/dist-server/core/runtime/system-prompt-cache.js +1 -0
- package/vendor/dist-server/core/runtime/trace-bus.js +1 -0
- package/vendor/dist-server/core/schema/cluster_health_report.js +1 -0
- package/vendor/dist-server/core/schema/cluster_info.js +1 -0
- package/vendor/dist-server/core/schema/cluster_license.js +5 -0
- package/vendor/dist-server/core/schema/cluster_stats.js +12 -0
- package/vendor/dist-server/core/schema/dashboard.js +1 -0
- package/vendor/dist-server/core/schema/indices_settings.js +1 -0
- package/vendor/dist-server/core/schema/indices_shards.js +1 -0
- package/vendor/dist-server/core/schema/indices_stats.js +1 -0
- package/vendor/dist-server/core/schema/nodes_info.js +2 -0
- package/vendor/dist-server/core/schema/nodes_stats.js +11 -0
- package/vendor/dist-server/core/schema/pricing.js +1 -0
- package/vendor/dist-server/core/schema/ui.js +1 -0
- package/vendor/dist-server/core/schema/zod_client.js +83 -0
- package/vendor/dist-server/core/services/a2a-client.js +2 -0
- package/vendor/dist-server/core/services/alerts-service.js +1 -0
- package/vendor/dist-server/core/services/api-keys-service.js +1 -0
- package/vendor/dist-server/core/services/assistant-resolver.js +1 -0
- package/vendor/dist-server/core/services/assistants-index-service.js +1 -0
- package/vendor/dist-server/core/services/async-conversations-service.js +22 -0
- package/vendor/dist-server/core/services/asyncapi-dispatch.js +1 -0
- package/vendor/dist-server/core/services/asyncapi-drivers/driver-manager.js +1 -0
- package/vendor/dist-server/core/services/asyncapi-drivers/driver-types.js +0 -0
- package/vendor/dist-server/core/services/asyncapi-drivers/http-driver.js +1 -0
- package/vendor/dist-server/core/services/asyncapi-drivers/nats-driver.js +1 -0
- package/vendor/dist-server/core/services/asyncapi-drivers/websocket-driver.js +1 -0
- package/vendor/dist-server/core/services/asyncapi-events-service.js +1 -0
- package/vendor/dist-server/core/services/asyncapi-reply-service.js +1 -0
- package/vendor/dist-server/core/services/asyncapi-sink.js +1 -0
- package/vendor/dist-server/core/services/asyncapi-tools-service.js +1 -0
- package/vendor/dist-server/core/services/block-repair-service.js +13 -0
- package/vendor/dist-server/core/services/chart-renderer.js +1 -0
- package/vendor/dist-server/core/services/chat-llms-service.js +1 -0
- package/vendor/dist-server/core/services/chat-runs-service.js +1 -0
- package/vendor/dist-server/core/services/chat-tools-service.js +1 -0
- package/vendor/dist-server/core/services/chat-traces-service.js +1 -0
- package/vendor/dist-server/core/services/chats-service.js +5 -0
- package/vendor/dist-server/core/services/comparison-service.js +107 -0
- package/vendor/dist-server/core/services/default-model.service.js +1 -0
- package/vendor/dist-server/core/services/elastic-stack-sync-service.js +2 -0
- package/vendor/dist-server/core/services/elasticsearch-wrapper.js +1 -0
- package/vendor/dist-server/core/services/embed-rate-limiter.js +1 -0
- package/vendor/dist-server/core/services/error-analytics-service.js +1 -0
- package/vendor/dist-server/core/services/es-field-resolver.js +1 -0
- package/vendor/dist-server/core/services/gateway-platform-types.js +1 -0
- package/vendor/dist-server/core/services/gliner-tagging-service.js +1 -0
- package/vendor/dist-server/core/services/golden-questions-scoring.js +1 -0
- package/vendor/dist-server/core/services/golden-questions-service.js +1 -0
- package/vendor/dist-server/core/services/graph-drilldown-service.js +1 -0
- package/vendor/dist-server/core/services/graph-registry-service.js +1 -0
- package/vendor/dist-server/core/services/hitl-analytics-service.js +1 -0
- package/vendor/dist-server/core/services/ingestion-jobs-service.js +1 -0
- package/vendor/dist-server/core/services/ingestion-service.js +5 -0
- package/vendor/dist-server/core/services/kibana-client-factory.js +1 -0
- package/vendor/dist-server/core/services/kibana-client.js +2 -0
- package/vendor/dist-server/core/services/kibana-dashboard-extractor.js +1 -0
- package/vendor/dist-server/core/services/kibana-service.js +1 -0
- package/vendor/dist-server/core/services/llm-analytics-service.js +1 -0
- package/vendor/dist-server/core/services/llm-client-resolver.js +1 -0
- package/vendor/dist-server/core/services/llm-models-service.js +1 -0
- package/vendor/dist-server/core/services/llm-pricing-pure.js +1 -0
- package/vendor/dist-server/core/services/llm-pricing-service.js +1 -0
- package/vendor/dist-server/core/services/llm-providers-service.js +1 -0
- package/vendor/dist-server/core/services/llm-routing-service.js +1 -0
- package/vendor/dist-server/core/services/llm-services.js +1 -0
- package/vendor/dist-server/core/services/llm-sync-service.js +1 -0
- package/vendor/dist-server/core/services/manifest-loader.js +1 -0
- package/vendor/dist-server/core/services/mcp-servers-service.js +1 -0
- package/vendor/dist-server/core/services/mcp-sync-service.js +1 -0
- package/vendor/dist-server/core/services/mcp-tools-service.js +1 -0
- package/vendor/dist-server/core/services/memories-service.js +2 -0
- package/vendor/dist-server/core/services/memory-analytics-service.js +1 -0
- package/vendor/dist-server/core/services/monitoring-analytics-service.js +1 -0
- package/vendor/dist-server/core/services/monitoring-service.js +1 -0
- package/vendor/dist-server/core/services/multi-kibana-service.js +1 -0
- package/vendor/dist-server/core/services/node-latency-service.js +1 -0
- package/vendor/dist-server/core/services/package-policy-service.js +2 -0
- package/vendor/dist-server/core/services/pdf-service.js +572 -0
- package/vendor/dist-server/core/services/plan-service.js +1 -0
- package/vendor/dist-server/core/services/platform-direction.js +1 -0
- package/vendor/dist-server/core/services/platform-secrets.js +1 -0
- package/vendor/dist-server/core/services/platforms-service.js +1 -0
- package/vendor/dist-server/core/services/policy-factory.js +1 -0
- package/vendor/dist-server/core/services/prompt-cache-service.js +1 -0
- package/vendor/dist-server/core/services/provider-rate-limits.js +1 -0
- package/vendor/dist-server/core/services/quota-service.js +1 -0
- package/vendor/dist-server/core/services/report-assets-service.js +1 -0
- package/vendor/dist-server/core/services/run-analytics-collector.js +1 -0
- package/vendor/dist-server/core/services/run-stream-sink.js +1 -0
- package/vendor/dist-server/core/services/send_mail.js +460 -0
- package/vendor/dist-server/core/services/share-service.js +1 -0
- package/vendor/dist-server/core/services/slack-signature.js +1 -0
- package/vendor/dist-server/core/services/sources-service.js +6 -0
- package/vendor/dist-server/core/services/team-mcp-result.js +4 -0
- package/vendor/dist-server/core/services/team-mcp-run-tokens.js +1 -0
- package/vendor/dist-server/core/services/team-mcp-runner.js +1 -0
- package/vendor/dist-server/core/services/team-mcp-server.js +1 -0
- package/vendor/dist-server/core/services/team-mcp-tools.js +1 -0
- package/vendor/dist-server/core/services/team-mcp-ui.js +551 -0
- package/vendor/dist-server/core/services/team-run-progress.js +1 -0
- package/vendor/dist-server/core/services/team-runner-headless.js +7 -0
- package/vendor/dist-server/core/services/team-search-service.js +1 -0
- package/vendor/dist-server/core/services/teams-service.js +1 -0
- package/vendor/dist-server/core/services/token-projection-service.js +1 -0
- package/vendor/dist-server/core/services/tool-analytics-service.js +1 -0
- package/vendor/dist-server/core/services/tool-history-service.js +1 -0
- package/vendor/dist-server/core/services/tool-metrics-service.js +1 -0
- package/vendor/dist-server/core/services/tool-scoring.js +1 -0
- package/vendor/dist-server/core/services/toolbox-import-mappers.js +1 -0
- package/vendor/dist-server/core/services/toolbox-import-service.js +1 -0
- package/vendor/dist-server/core/services/trigger-service.js +1 -0
- package/vendor/dist-server/core/services/version-snapshot-service.js +1 -0
- package/vendor/dist-server/core/services/webhook-calls-service.js +1 -0
- package/vendor/dist-server/core/tools/compare-chat.js +46 -0
- package/vendor/dist-server/core/tools/enrich-chat.js +50 -0
- package/vendor/dist-server/core/tools/variable-encoding.js +1 -0
- package/vendor/dist-server/core/types/settings.js +1 -0
- package/vendor/dist-server/core/utils/ab-evaluator.js +5 -0
- package/vendor/dist-server/core/utils/condition-evaluator.js +1 -0
- package/vendor/dist-server/core/utils/http-client.js +1 -0
- package/vendor/dist-server/core/utils/json-schema-to-form.js +1 -0
- package/vendor/dist-server/core/utils/logger.js +3 -0
- package/vendor/dist-server/core/utils/owner-scope.js +1 -0
- package/vendor/dist-server/core/utils/ownership.js +1 -0
- package/vendor/dist-server/core/utils/parallel-tool-executor.js +1 -0
- package/vendor/dist-server/core/utils/performance-tracker.js +3 -0
- package/vendor/dist-server/core/utils/prompt-optimizer.js +40 -0
- package/vendor/dist-server/core/utils/response-cache.js +1 -0
- package/vendor/dist-server/core/utils/schema-validator.js +1 -0
- package/vendor/dist-server/core/utils/streaming-optimizer.js +2 -0
- package/vendor/dist-server/core/utils/string-helpers.js +1 -0
- package/vendor/dist-server/core/utils/test-responses.js +9 -0
- package/vendor/dist-server/core/utils/text-utils.js +1 -0
- package/vendor/dist-server/core/utils/tool-form-trigger.js +1 -0
- package/vendor/dist-server/entrypoints/cli-bootstrap-run.js +1 -0
- package/vendor/dist-server/entrypoints/cli-deploy-run.js +1 -0
- package/vendor/dist-server/entrypoints/cli-deploy.js +1 -0
- package/vendor/dist-server/entrypoints/team-runner.js +1 -0
- package/vendor/dist-server/generated/toolbox-catalog.js +1 -0
- package/vendor/dist-server/index.js +2 -0
- package/vendor/dist-server/middleware/integration-logos.js +1 -0
- package/vendor/dist-server/middleware/plan-guard.js +1 -0
- package/vendor/dist-server/openapi/generator.js +1 -0
- package/vendor/dist-server/openapi/html-tool-spec.js +1 -0
- package/vendor/dist-server/routes/a2a-routes.js +1 -0
- package/vendor/dist-server/routes/a2a-server-routes.js +5 -0
- package/vendor/dist-server/routes/admin.js +1 -0
- package/vendor/dist-server/routes/assistants-routes.js +1 -0
- package/vendor/dist-server/routes/asyncapi-routes.js +1 -0
- package/vendor/dist-server/routes/auth.js +1 -0
- package/vendor/dist-server/routes/billing-routes.js +1 -0
- package/vendor/dist-server/routes/chat-llms.js +1 -0
- package/vendor/dist-server/routes/chat-tools.js +1 -0
- package/vendor/dist-server/routes/chat-traces.js +1 -0
- package/vendor/dist-server/routes/chats.js +1 -0
- package/vendor/dist-server/routes/clusters.js +1 -0
- package/vendor/dist-server/routes/compare.js +43 -0
- package/vendor/dist-server/routes/connectors-routes.js +1 -0
- package/vendor/dist-server/routes/consumptions-routes.js +1 -0
- package/vendor/dist-server/routes/data-admin-routes.js +1 -0
- package/vendor/dist-server/routes/data-transfer-routes.js +1 -0
- package/vendor/dist-server/routes/elastic-tool-execution-routes.js +1 -0
- package/vendor/dist-server/routes/geo-proxy-routes.js +1 -0
- package/vendor/dist-server/routes/golden-questions-routes.js +1 -0
- package/vendor/dist-server/routes/graph-registry.js +1 -0
- package/vendor/dist-server/routes/graph-templates-routes.js +1 -0
- package/vendor/dist-server/routes/helpdesk-routes.js +35 -0
- package/vendor/dist-server/routes/html-routes.js +1 -0
- package/vendor/dist-server/routes/index.js +1 -0
- package/vendor/dist-server/routes/indices.js +1 -0
- package/vendor/dist-server/routes/integrations-routes.js +1 -0
- package/vendor/dist-server/routes/langgraph.js +7 -0
- package/vendor/dist-server/routes/live-resources-routes.js +1 -0
- package/vendor/dist-server/routes/llm-analytics.js +1 -0
- package/vendor/dist-server/routes/llm-control-plane.js +1 -0
- package/vendor/dist-server/routes/llm.js +1 -0
- package/vendor/dist-server/routes/mcp-gateway-routes.js +1 -0
- package/vendor/dist-server/routes/mcp-query-routes.js +1 -0
- package/vendor/dist-server/routes/mcp-servers-routes.js +1 -0
- package/vendor/dist-server/routes/mcp-team-routes.js +1 -0
- package/vendor/dist-server/routes/mcp-tools-routes.js +1 -0
- package/vendor/dist-server/routes/me-routes.js +63 -0
- package/vendor/dist-server/routes/memories-routes.js +1 -0
- package/vendor/dist-server/routes/monitoring-analytics.js +12 -0
- package/vendor/dist-server/routes/monitoring.js +1 -0
- package/vendor/dist-server/routes/node-types-routes.js +171 -0
- package/vendor/dist-server/routes/nodes.js +1 -0
- package/vendor/dist-server/routes/packages.js +1 -0
- package/vendor/dist-server/routes/pdf.js +3 -0
- package/vendor/dist-server/routes/plan-routes.js +1 -0
- package/vendor/dist-server/routes/platform-requests-routes.js +1 -0
- package/vendor/dist-server/routes/platforms-routes.js +1 -0
- package/vendor/dist-server/routes/prompts-routes.js +1 -0
- package/vendor/dist-server/routes/proxy-logos.js +1 -0
- package/vendor/dist-server/routes/quality-routes.js +1 -0
- package/vendor/dist-server/routes/resources-ingest-routes.js +1 -0
- package/vendor/dist-server/routes/resources-routes.js +1 -0
- package/vendor/dist-server/routes/schema-routes.js +1 -0
- package/vendor/dist-server/routes/settings-original.js +1 -0
- package/vendor/dist-server/routes/settings.js +1 -0
- package/vendor/dist-server/routes/share-routes.js +1 -0
- package/vendor/dist-server/routes/sources-catalog-routes.js +1 -0
- package/vendor/dist-server/routes/sources-routes.js +1 -0
- package/vendor/dist-server/routes/team-optimizer-routes.js +1 -0
- package/vendor/dist-server/routes/team-schedule-routes.js +1 -0
- package/vendor/dist-server/routes/teams-routes.js +1 -0
- package/vendor/dist-server/routes/tool-analytics.js +1 -0
- package/vendor/dist-server/routes/tool-history-routes.js +1 -0
- package/vendor/dist-server/routes/tool-metrics-routes.js +1 -0
- package/vendor/dist-server/routes/toolbox-import-routes.js +1 -0
- package/vendor/dist-server/routes/tools-routes.js +5 -0
- package/vendor/dist-server/routes/transcribe-routes.js +1 -0
- package/vendor/dist-server/routes/triggers.js +1 -0
- package/vendor/dist-server/routes/versions-routes.js +1 -0
- package/vendor/dist-server/routes/webhooks-routes.js +1 -0
- package/vendor/dist-server/scripts/add-label-to-tools.js +4 -0
- package/vendor/dist-server/scripts/migrate-assistants-to-mcp.js +10 -0
- package/vendor/dist-server/scripts/migrate-chat-runs.js +8 -0
- package/vendor/dist-server/scripts/migrate-mcp-protocol.js +8 -0
- package/vendor/dist-server/scripts/migrate-mcp-to-platforms.js +15 -0
- package/vendor/dist-server/services/alert-evaluator.js +3 -0
- package/vendor/dist-server/services/auth.js +1 -0
- package/vendor/dist-server/services/billing-service.js +1 -0
- package/vendor/dist-server/services/chat-title-generator.js +12 -0
- package/vendor/dist-server/services/clone/clone-executor.js +1 -0
- package/vendor/dist-server/services/clone/closure-resolver.js +3 -0
- package/vendor/dist-server/services/clone/entity-graph.js +3 -0
- package/vendor/dist-server/services/clone/team-bundle-bootstrap.js +1 -0
- package/vendor/dist-server/services/clone/team-bundle-crypto.js +1 -0
- package/vendor/dist-server/services/clone/team-bundle-encrypted.js +1 -0
- package/vendor/dist-server/services/clone/team-bundle.js +1 -0
- package/vendor/dist-server/services/cluster-service.js +1 -0
- package/vendor/dist-server/services/connection-adapters.js +1 -0
- package/vendor/dist-server/services/connectors-service.js +10 -0
- package/vendor/dist-server/services/cost-forecast-service.js +1 -0
- package/vendor/dist-server/services/eui-ssr-renderer.js +4 -0
- package/vendor/dist-server/services/graph-canvas/full-structure-builder.js +1 -0
- package/vendor/dist-server/services/graph-templates-service.js +13 -0
- package/vendor/dist-server/services/guest-service.js +1 -0
- package/vendor/dist-server/services/html-service.js +1 -0
- package/vendor/dist-server/services/langgraph-service.js +2 -0
- package/vendor/dist-server/services/leaflet-render-service.js +80 -0
- package/vendor/dist-server/services/live-resources-service.js +16 -0
- package/vendor/dist-server/services/mcp-app-tester-package.js +1 -0
- package/vendor/dist-server/services/mcp-gateway/executors/openapi-executor.js +1 -0
- package/vendor/dist-server/services/mcp-gateway/gateway-grant-service.js +2 -0
- package/vendor/dist-server/services/team-optimizer-service.js +1 -0
- package/vendor/dist-server/services/trace-bus-sink.js +1 -0
- package/vendor/dist-server/services/user-provisioning-service.js +3 -0
- package/vendor/dist-server/templates/mcp-app-tester/src/mcp-http.js +3 -0
- package/vendor/dist-server/templates/mcp-app-tester/src/server.js +1 -0
- package/vendor/dist-server/utils.js +1 -0
- package/vendor/dist-server/ws/assistant-executor.js +7 -0
- package/vendor/dist-server/ws/classify-streamed-json-block.js +1 -0
- package/vendor/dist-server/ws/collect-response-generator-node-ids.js +1 -0
- package/vendor/dist-server/ws/extractors/blockkit-extractor.js +1 -0
- package/vendor/dist-server/ws/extractors/echarts-extractor.js +1 -0
- package/vendor/dist-server/ws/extractors/eui-extractor.js +1 -0
- package/vendor/dist-server/ws/extractors/form-extractor.js +1 -0
- package/vendor/dist-server/ws/extractors/index.js +1 -0
- package/vendor/dist-server/ws/extractors/leaflet-extractor.js +1 -0
- package/vendor/dist-server/ws/extractors/mantine-extractor.js +1 -0
- package/vendor/dist-server/ws/extractors/markdown-extractor.js +7 -0
- package/vendor/dist-server/ws/extractors/mermaid-extractor.js +1 -0
- package/vendor/dist-server/ws/extractors/recharts-extractor.js +1 -0
- package/vendor/dist-server/ws/extractors/remotion-extractor.js +1 -0
- package/vendor/dist-server/ws/handler.js +66 -0
- package/vendor/dist-server/ws/parsers/anthropic-parser.js +7 -0
- package/vendor/dist-server/ws/parsers/base-parser.js +3 -0
- package/vendor/dist-server/ws/parsers/gemini-parser.js +8 -0
- package/vendor/dist-server/ws/parsers/index.js +1 -0
- package/vendor/dist-server/ws/parsers/parse-json-blocks.js +1 -0
- package/vendor/dist-server/ws/types.js +0 -0
- package/vendor/dist-server/ws/utils.js +1 -0
- package/vendor/shared/engine-vars.ts +51 -0
- package/vendor/shared/llm-providers-config.ts +69 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createPolicyId as m,createSlug as d,generateRandomId as v}from"../utils/string-helpers";import{settingsConfig as u}from"../app-config/settings";import{BRAND_NAME as O}from"../app-config/branding";class N{defaultInterval;packageInfo;minimalPackageInfo;constructor(){this.defaultInterval=u.defaults.interval,this.packageInfo={name:"stack_expert",title:O,version:u.defaults.packageVersion},this.minimalPackageInfo={name:"stack_expert",title:"Erretegia",version:u.defaults.minimalPackageVersion}}celDatasets=["stack_expert.health_report","stack_expert.indices_ilm","stack_expert.indices_stats","stack_expert.nodes_hot_threads","stack_expert.slm_stats","stack_expert.tasks_list"];httpjsonDatasets=["stack_expert.cat_shards","stack_expert.cat_thread_pool","stack_expert.cluster_get_settings","stack_expert.cluster_stats","stack_expert.data_streams_stats","stack_expert.enrich_stats","stack_expert.ilm","stack_expert.indices_get_settings","stack_expert.info","stack_expert.ingest_pipelines","stack_expert.license_get","stack_expert.nodes_info","stack_expert.nodes_stats","stack_expert.nodes_usage","stack_expert.snapshots","stack_expert.xpack_info"];createStream(e){const t=e.split(".")[1];return{enabled:!0,data_stream:{type:"logs",dataset:e},vars:{interval:{value:this.defaultInterval,type:"text"},tags:{value:[t,"stack_expert"],type:"text"}}}}createCelInput(e){if(e.package?.config?.inputs?.cel?.streams){const t=Object.entries(e.package.config.inputs.cel.streams).filter(([o,n])=>n.enabled).map(([o,n])=>{const s=o.replace(/^stack_expert\./,""),a=`stack_expert.${s}`;return{enabled:n.enabled,data_stream:{type:"logs",dataset:a},vars:{interval:{value:n.vars?.interval||this.defaultInterval,type:"text"},tags:{value:n.vars?.tags||[s,"stack_expert"],type:"text"}}}});return{type:"cel",policy_template:"check",enabled:e.package.config.inputs.cel.enabled??!0,streams:t}}return{type:"cel",policy_template:"check",enabled:!0,streams:this.celDatasets.map(t=>this.createStream(t))}}createPackage(e){if(e.packageName&&e.packageVersion)return{name:e.packageName,version:e.packageVersion,title:e.packageTitle||e.packageName};if(e.package){const t={...e.package};return delete t.config,t}return{}}createVars(e){console.log("createVars Using custom params:",JSON.stringify(e));const t=e.package?.config?.vars||e.vars;if(t){const o={};for(const n in t)o[n]={value:t[n],type:typeof t[n]=="number"?"number":typeof t[n]=="string"&&n==="ssl"?"yaml":"text"};return console.log("res Using custom params:",JSON.stringify(o)),o}return{api_url:{value:e.api_url,type:"text"},api_key:{value:e.api_key,type:"text"},interval:{value:e.interval,type:"text"}}}createHttpJsonInput(e){if(e.package?.config?.inputs?.httpjson?.streams){const t=Object.entries(e.package.config.inputs.httpjson.streams).filter(([o,n])=>n.enabled).map(([o,n])=>{const s=o.replace(/^stack_expert\./,""),a=`stack_expert.${s}`;return{enabled:n.enabled,data_stream:{type:"logs",dataset:a},vars:{interval:{value:n.vars?.interval||this.defaultInterval,type:"text"},tags:{value:n.vars?.tags||[s,"stack_expert"],type:"text"}}}});return{type:"httpjson",policy_template:"check",enabled:e.package.config.inputs.httpjson.enabled??!0,streams:t}}return{type:"httpjson",policy_template:"check",enabled:!0,streams:this.httpjsonDatasets.map(t=>this.createStream(t))}}createDynamicInputs(e){const t=[],o=e.inputs||e.package?.config?.inputs;if(o&&Object.keys(o).length>0){console.log(`[FACTORY] Processing ${Object.keys(o).length} inputs`),console.log(`[FACTORY] Input config keys: ${Object.keys(o).join(", ")}`);for(const[s,a]of Object.entries(o)){if(!a||typeof a!="object"){console.log(`[FACTORY] Skipping invalid input type: ${s}`);continue}console.log(`[FACTORY] Processing input type: ${s}`),console.log(`[FACTORY] Input config for ${s}:`,JSON.stringify(a));const r={};if(a.vars&&typeof a.vars=="object"){console.log(`[FACTORY] Found ${Object.keys(a.vars).length} vars for input ${s}`);for(const[i,l]of Object.entries(a.vars)){let g="text";typeof l=="number"?g="integer":typeof l=="boolean"?g="bool":i.includes("password")||i.includes("secret")?g="password":(i==="ssl"||i==="resource_ssl")&&(g="yaml"),r[i]={value:l,type:g},console.log(`[FACTORY] Transformed var ${i}: type=${g}, isArray=${Array.isArray(l)}`)}console.log(`[FACTORY] Transformed vars for ${s}:`,JSON.stringify(r))}else console.log(`[FACTORY] No vars found for input ${s}`);const c=a.streams?Object.entries(a.streams).filter(([i,l])=>l.enabled).map(([i,l])=>{console.log(`[FACTORY] Processing stream: ${i}`);const g=e.packageName||e.package?.name,f=i.includes(".")?i:`${g}.${i}`,k={};if(l.vars&&typeof l.vars=="object"){console.log(`[FACTORY] Found ${Object.keys(l.vars).length} stream vars for ${i}`);for(const[_,y]of Object.entries(l.vars))k[_]={value:y,type:typeof y=="number"?"integer":typeof y=="boolean"?"bool":Array.isArray(y)?"text":_.includes("password")?"password":"text"},console.log(`[FACTORY] Transformed stream var ${_}: type=${k[_].type}, isArray=${Array.isArray(y)}`)}else console.log(`[FACTORY] No stream vars for ${i}`);return{enabled:l.enabled,data_stream:{type:"logs",dataset:f},vars:k}}):[],p={type:s,policy_template:a.policy_template||"check",enabled:a.enabled??!0,streams:c};Object.keys(r).length>0?(p.vars=r,console.log(`[FACTORY] Added ${Object.keys(r).length} transformed vars to input ${s}`)):console.log(`[FACTORY] No vars to add for input ${s}`),console.log(`[FACTORY] Created policyInput for ${s}:`,JSON.stringify(p,null,2)),t.push(p)}return console.log(`[FACTORY] Total inputs created: ${t.length}`),console.log("[FACTORY] Final inputs array:",JSON.stringify(t,null,2)),t}if((e.package?.name||e.packageName)==="cel"){console.log("\u{1F4E6} CEL package detected - creating single input with stream-level vars");const s=e.package?.config?.vars||e.vars,a=e.package?.config?.policyTemplate||"cel";if(s){const r={};for(const[c,p]of Object.entries(s))r[c]={value:p,type:typeof p=="number"?"number":typeof p=="boolean"?"bool":c==="program"||c==="xsd"?"textarea":c==="regexp"||c==="state"||c==="resource_ssl"?"yaml":c.includes("password")||c.includes("secret")?"password":"text"};return console.log(`\u2705 Created CEL input with ${Object.keys(r).length} stream vars`),[{type:"cel",policy_template:a,enabled:!0,streams:[{enabled:!0,data_stream:{type:"logs",dataset:s["data_stream.dataset"]||"cel.cel"},vars:r}]}]}}return[this.createCelInput(e),this.createHttpJsonInput(e)]}createPolicy(e,t){console.log("[POLICY-FACTORY] ========== createPolicy START =========="),console.log("[POLICY-FACTORY] Cluster:",JSON.stringify(e)),console.log("[POLICY-FACTORY] Params:",JSON.stringify(t));const o=v(),n=m(e.cluster_name,e.cluster_uuid,e.version.number),s=d(`${e.cluster_name}_${e.cluster_uuid}_${o}`),a=t.package?.name||t.packageName;console.log(`[POLICY-FACTORY] Package name: ${a}`);const r=this.createDynamicInputs(t);console.log(`[POLICY-FACTORY] Created ${r.length} inputs`);const c=t.agentPolicyId||u.fleet.policyId;console.log(`[POLICY-FACTORY] Using agent policy ID: ${c}`);const p={id:n,name:`Erretegia ${d(`${e.cluster_name}_${e.cluster_uuid}_${e.version.number}_${o}`)} policy`,description:JSON.stringify(e),namespace:s,policy_id:c,enabled:!0,policy_ids:[c],package:this.createPackage(t),inputs:r};return a!=="cel"?(p.vars=this.createVars(t),console.log(`[POLICY-FACTORY] Added package-level vars for ${a}`)):console.log("[POLICY-FACTORY] Skipped package-level vars for CEL package"),console.log("[POLICY-FACTORY] ========== FINAL POLICY =========="),console.log(JSON.stringify(p,null,2)),console.log("[POLICY-FACTORY] ========== createPolicy END =========="),p}createMinimalPolicy(e,t,o){console.log("[POLICY-FACTORY] createMinimalPolicy params:",JSON.stringify(t,null,2));const n=o||`basicauth_${Date.now()}`,s=d(`${n}_${e.cluster_name}_${e.cluster_uuid}`);let a;t.package?.config?.inputs?(console.log("[POLICY-FACTORY] Using dynamic inputs from package.config.inputs"),a=this.createDynamicInputs(t)):t.inputs?(console.log("[POLICY-FACTORY] Using inputs from params.inputs (UPDATE mode)"),a=this.createDynamicInputs(t)):(console.log("[POLICY-FACTORY] Using default stack_expert inputs"),a=[{type:"cel",policy_template:"check",enabled:!0,streams:[this.createStream("stack_expert.nodes_hot_threads"),this.createStream("stack_expert.tasks_list")]},{type:"httpjson",policy_template:"check",enabled:!0,streams:["cat_shards","cluster_get_settings","cluster_stats","health_report","ilm_policies","indices_get_settings","indices_segments","indices_stats","ingest_pipelines","license_get","mappings","nodes_info","nodes_stats","nodes_usage","slm_get_stats","slm_get_status","snapshot_status","tasks_list","watcher_stats","xpack_info","xpack_usage"].map(l=>this.createStream(`stack_expert.${l}`)),vars:{api_url:{value:[t.api_url],type:"text"},api_key:{value:t.api_key,type:"text"},interval:{value:t.interval,type:"text"},ssl:{value:t.ssl,type:"yaml"},condition:{type:"text"},scope:{value:"cluster",type:"select"}}}]);const r=t.agentPolicyId||u.fleet.policyId;console.log(`[POLICY-FACTORY] createMinimalPolicy - Using agent policy ID: ${r}`);const c=t.packageName||t.package?.name||this.minimalPackageInfo.name,p=t.packageVersion||t.package?.version||this.minimalPackageInfo.version,i={name:c,title:c.charAt(0).toUpperCase()+c.slice(1),version:p};return console.log(`[POLICY-FACTORY] createMinimalPolicy - Using package: ${i.name}@${i.version}`),{name:`Erretegia ${d(`${e.cluster_name}_${e.cluster_uuid}`)} policy by ${o}`,description:JSON.stringify(e),namespace:s,policy_id:r,enabled:!0,package:i,force:!0,vars:this.createVars(t),inputs:a}}}export{N as PolicyFactory};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Client as A}from"@elastic/elasticsearch";import{config as I}from"../config";import{getLLMPricing as x}from"./llm-pricing-service";const D=new A(I.elasticsearch),_=".stkxp_chat_llms";function B(r){return r.toISOString().slice(0,10)}async function E(r,o){const T=[{term:{username:r}}];o&&T.push({range:{createdAt:{gte:o.start,lte:o.end}}});const f=await D.search({index:_,body:{query:{bool:{must:T}},size:2e3,_source:["llms","createdAt","assistantId","assistantName"],sort:[{createdAt:"desc"}]}}),c=[];for(const e of f.hits.hits){const t=e._source,n=Date.parse(t.createdAt||new Date().toISOString()),p=Array.isArray(t.llms)?t.llms:[];for(const s of p){const P=Number(s.inputTokens||0),v=Number(s.outputTokens||0),M=Number(s.cacheCreationTokens||0),N=Number(s.cacheReadTokens||0);c.push({provider:s.provider||"unknown",model:s.modelId||"unknown",assistantId:s.assistantId||t.assistantId,assistantName:s.assistantName||t.assistantName,inputTokens:P,outputTokens:v,cacheCreationTokens:M,cacheReadTokens:N,ts:Number(s.startTime)||n})}}let l=0,i=0,R=0,u=0,a=0;for(const e of c)l+=1,i+=e.inputTokens,R+=e.outputTokens,u+=e.cacheCreationTokens,a+=e.cacheReadTokens;const g=Math.max(i-a-u,0),y=a+g>0?a/(a+g):0,d=new Map;for(const e of c){const t=`${e.provider}|${e.model}`,n=d.get(t)??{provider:e.provider,model:e.model,calls:0,inputTokens:0,cacheCreationTokens:0,cacheReadTokens:0,outputTokens:0,hitRate:0,savingsUsd:0};n.calls+=1,n.inputTokens+=e.inputTokens,n.outputTokens+=e.outputTokens,n.cacheCreationTokens+=e.cacheCreationTokens,n.cacheReadTokens+=e.cacheReadTokens,d.set(t,n)}let C=0;const m=[];for(const e of d.values()){const t=Math.max(e.inputTokens-e.cacheReadTokens-e.cacheCreationTokens,0);e.hitRate=e.cacheReadTokens+t>0?e.cacheReadTokens/(e.cacheReadTokens+t):0;const n=await x(e.provider,e.model).catch(()=>null);if(n&&e.cacheReadTokens>0&&typeof n.input=="number"&&typeof n.input_cached=="number"){const p=e.cacheReadTokens/1e6*(n.input-n.input_cached);e.savingsUsd=Math.max(p,0),C+=e.savingsUsd}m.push(e)}m.sort((e,t)=>t.cacheReadTokens-e.cacheReadTokens);const h=new Map;for(const e of c){const t=e.assistantId||"(no-assistant)",n=h.get(t)??{assistantId:t,assistantName:e.assistantName,calls:0,cacheReadTokens:0,inputTokens:0,hitRate:0};n.calls+=1,n.cacheReadTokens+=e.cacheReadTokens,n.inputTokens+=e.inputTokens,!n.assistantName&&e.assistantName&&(n.assistantName=e.assistantName),h.set(t,n)}const b=Array.from(h.values()).map(e=>{const t=Math.max(e.inputTokens-e.cacheReadTokens,0);return{...e,hitRate:e.cacheReadTokens+t>0?e.cacheReadTokens/(e.cacheReadTokens+t):0}});b.sort((e,t)=>t.cacheReadTokens-e.cacheReadTokens);const k=new Map;for(const e of c){const t=B(new Date(e.ts)),n=k.get(t)??{date:t,inputTokens:0,cacheReadTokens:0,cacheCreationTokens:0,hitRate:0};n.inputTokens+=e.inputTokens,n.cacheReadTokens+=e.cacheReadTokens,n.cacheCreationTokens+=e.cacheCreationTokens,k.set(t,n)}const w=Array.from(k.values()).map(e=>{const t=Math.max(e.inputTokens-e.cacheReadTokens-e.cacheCreationTokens,0);return{...e,hitRate:e.cacheReadTokens+t>0?e.cacheReadTokens/(e.cacheReadTokens+t):0}}).sort((e,t)=>e.date<t.date?-1:1);return{windowStart:o?.start,windowEnd:o?.end,totalCalls:l,inputTokens:i,cacheCreationTokens:u,cacheReadTokens:a,outputTokens:R,hitRate:y,savingsUsd:C,byModel:m,byAssistant:b.slice(0,15),daily:w}}export{E as getPromptCacheReport};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const n={anthropic:{default:{rpm:4e3,tpm:2e5},perModel:{"claude-opus-4-7":{rpm:1e3,tpm:8e4},"claude-opus-4-6":{rpm:1e3,tpm:8e4},"claude-sonnet-4-6":{rpm:4e3,tpm:4e5},"claude-haiku-4-5":{rpm:4e3,tpm:4e5}}},openai:{default:{rpm:1e4,tpm:2e5},perModel:{"gpt-4o":{rpm:1e4,tpm:2e6},"gpt-4o-mini":{rpm:3e4,tpm:1e7},"gpt-4-turbo":{rpm:1e4,tpm:8e5}}},google:{default:{rpm:360,tpm:4e6},perModel:{"gemini-2.0-flash":{rpm:2e3,tpm:4e6},"gemini-2.5-pro":{rpm:360,tpm:1e6}}},gemini:{default:{rpm:360,tpm:4e6}}};let t=null;function m(){if(t)return t;const r=process.env.STKXP_RATE_LIMITS_JSON;if(!r)return t={};try{const e=JSON.parse(r);t=e&&typeof e=="object"?e:{}}catch(e){console.warn(`[provider-rate-limits] failed to parse STKXP_RATE_LIMITS_JSON: ${e.message}`),t={}}return t}function a(r,e){const s=m(),o=r.toLowerCase(),i=s[o],p=n[o];return i?.perModel?.[e]?i.perModel[e]:p?.perModel?.[e]?p.perModel[e]:i?.default?i.default:p?.default?p.default:{rpm:1e3,tpm:1e5}}function d(){const r=m(),e=new Set([...Object.keys(n),...Object.keys(r)]);return Array.from(e)}export{a as getRateLimit,d as listProviders};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Client as v}from"@elastic/elasticsearch";import{config as w}from"../config";import{getRateLimit as h,listProviders as y}from"./provider-rate-limits";const d=new v(w.elasticsearch),_=".stkxp_chat_llms",T=".stkxp_chat_runs";async function k(m,r){const s=new Date(Date.now()-r).toISOString(),l=await d.search({index:_,body:{size:2e3,query:{bool:{must:[{term:{username:m}},{range:{createdAt:{gte:s}}}]}},_source:["llms","createdAt"],sort:[{createdAt:"desc"}]}}),a=[];for(const o of l.hits.hits){const n=o._source,t=Date.parse(n.createdAt||new Date().toISOString()),e=Array.isArray(n.llms)?n.llms:[];for(const i of e){const u=Number(i.startTime)||t;u<Date.now()-r||a.push({provider:(i.provider||"unknown").toLowerCase(),model:i.modelId||"unknown",inputTokens:Number(i.inputTokens||0),outputTokens:Number(i.outputTokens||0),startTime:u})}}return a}function g(m,r){const s=r/6e4,l=new Map;for(const t of m){const e=`${t.provider}|${t.model}`,i=l.get(e)??{provider:t.provider,model:t.model,calls:0,tokens:0};i.calls+=1,i.tokens+=t.inputTokens+t.outputTokens,l.set(e,i)}const a=[];for(const t of l.values()){const e=h(t.provider,t.model),i=t.calls/s,u=t.tokens/s;a.push({provider:t.provider,model:t.model,rpm:i,tpm:u,limitRpm:e.rpm,limitTpm:e.tpm,utilizationRpm:e.rpm>0?i/e.rpm:0,utilizationTpm:e.tpm>0?u/e.tpm:0})}a.sort((t,e)=>e.utilizationTpm-t.utilizationTpm);const o=new Map;for(const t of a){const e=o.get(t.provider)??{provider:t.provider,rpmTotal:0,tpmTotal:0,models:[]};e.rpmTotal+=t.rpm,e.tpmTotal+=t.tpm,e.models.push(t),o.set(t.provider,e)}const n=Array.from(o.values());return n.sort((t,e)=>e.tpmTotal-t.tpmTotal),{windowSeconds:r/1e3,perModel:a,perProvider:n}}async function S(m,r){const s=[{term:{username:m}},{term:{status:"error"}},{terms:{errorType:["llm_rate_limit","llm_auth","timeout","llm_other"]}}];r&&s.push({range:{startTime:{gte:r.start,lte:r.end}}});const a=(await d.search({index:T,body:{query:{bool:{must:s}},size:0,aggs:{byType:{terms:{field:"errorType",size:10}}}}})).aggregations?.byType?.buckets??[],o={throttling429:0,authFailures:0,timeouts:0,llmOther:0};for(const n of a)switch(n.key){case"llm_rate_limit":o.throttling429=n.doc_count;break;case"llm_auth":o.authFailures=n.doc_count;break;case"timeout":o.timeouts=n.doc_count;break;case"llm_other":o.llmOther=n.doc_count;break}return o}async function P(m,r){const s=[{term:{username:m}},{term:{status:"error"}}];return r&&s.push({range:{startTime:{gte:r.start,lte:r.end}}}),((await d.search({index:T,body:{query:{bool:{must:s}},size:0,aggs:{per_hour:{date_histogram:{field:"startTime",calendar_interval:"hour",min_doc_count:1},aggs:{throttling:{filter:{term:{errorType:"llm_rate_limit"}}}}}}}})).aggregations?.per_hour?.buckets??[]).map(o=>({date:new Date(o.key).toISOString().slice(0,13),throttling:Number(o.throttling?.doc_count||0),errors:Number(o.doc_count||0)}))}async function x(m,r){const s=await k(m,36e5),l=Date.now(),a=l-60*1e3,o=l-300*1e3,n=s.filter(c=>c.startTime>=a),t=s.filter(c=>c.startTime>=o),e=g(n,60*1e3),i=g(t,300*1e3),u=g(s,3600*1e3),[b,f]=await Promise.all([S(m,r),P(m,r)]);for(const c of y())if(!u.perProvider.find(p=>p.provider===c.toLowerCase())){const p=h(c,"");u.perProvider.push({provider:c.toLowerCase(),rpmTotal:0,tpmTotal:0,models:[{provider:c.toLowerCase(),model:"(default)",rpm:0,tpm:0,limitRpm:p.rpm,limitTpm:p.tpm,utilizationRpm:0,utilizationTpm:0}]})}return{generatedAt:new Date().toISOString(),windowStart:r?.start,windowEnd:r?.end,current:e,last5m:i,last1h:u,events:b,timelineHourly:f}}export{x as getQuotaReport};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import r from"fs/promises";import n from"path";import{fileURLToPath as p}from"url";import{randomUUID as l}from"crypto";const f=n.dirname(p(import.meta.url)),o=n.resolve(f,"../../public/report-assets"),u={"image/png":"png","image/jpeg":"jpg","image/svg+xml":"svg"},g=/^data:([\w.+-]+\/[\w.+-]+);base64,(.*)$/s;async function U(e){const t=g.exec(e);if(!t)throw new Error("saveAsset expects a base64 data: URI");const[,i,a]=t,c=u[i]??"bin";await r.mkdir(o,{recursive:!0});const s=`${l()}.${c}`;return await r.writeFile(n.join(o,s),Buffer.from(a,"base64")),`${process.env.STKXP_APP_PUBLIC_URL||""}/report-assets/${s}`}async function w(e=10080*60*1e3){let t;try{t=await r.readdir(o)}catch{return 0}const i=Date.now();let a=0;return await Promise.all(t.map(async c=>{const s=n.join(o,c);try{const m=await r.stat(s);i-m.mtimeMs>e&&(await r.unlink(s),a++)}catch{}})),a}process.env.REPORT_ASSETS_AUTO_CLEANUP!=="false"&&setInterval(()=>{w().then(e=>{e>0&&console.log(`[report-assets] Cleaned ${e} expired asset(s)`)}).catch(e=>console.error("[report-assets] Cleanup sweep failed:",e))},360*60*1e3);export{o as REPORT_ASSETS_DIR,w as cleanupOldAssets,U as saveAsset};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createChatLLMsRecord as b}from"./chat-llms-service";import{createChatToolsRecord as A}from"./chat-tools-service";import{createChatTrace as N}from"./chat-traces-service";function U(r,t={}){const s=r?.data?.output,e=s?.usage_metadata||s?.response_metadata?.usage;if(!e)return null;const a=s?.response_metadata?.model_name||s?.response_metadata?.model_id||s?.response_metadata?.model||s?.model||"unknown",n=r?.metadata||{},o=n.langgraph_node||"unknown",i=n.thread_id||"",d=t.resolveAssistant?.(i)||t.defaultAssistant||{},c=t.nodeProvider?.(o)||n.ls_provider||"unknown",g=n.ls_model_name||a||"unknown",h=e.input_token_details||{},p=Number(h.cache_creation||e.cache_creation_input_tokens||0),_=Number(h.cache_read||e.cache_read_input_tokens||0),u=e.input_tokens||0,l=e.output_tokens||0,k=e.total_tokens||u+l,I=t.routingRule?.(o),f={inputTokens:u,outputTokens:l,totalTokens:k,cacheCreationTokens:p,cacheReadTokens:_,model:g,provider:c,nodeId:o,callId:r?.run_id,assistantId:d.assistantId,assistantName:d.assistantName,routingRuleId:I?.id,routingRuleName:I?.name},m=Date.now(),T=t.startTimeMs??m,C=t.llmCallAssistant??d,w={callIndex:0,callId:r?.run_id,assistantId:C.assistantId,assistantName:C.assistantName,graphId:n.langgraph_graph_id,nodeId:o,provider:c,modelId:g,input:{},output:{},timestamp:new Date().toISOString(),status:"completed",startTime:T,endTime:m,duration:m-T,error:!1,empty:l===0,inputTokens:u,outputTokens:l,totalTokens:k,cacheCreationTokens:p,cacheReadTokens:_};return{tokenUsage:f,llmCall:w}}class R{constructor(t={}){this.opts=t}llmCalls=[];llmUsage=[];tools=[];traceEvents=[];llmStartTimes=new Map;toolStartTimes=new Map;onEvent(t){switch(t?.event){case"on_chat_model_start":{t.run_id&&this.llmStartTimes.set(t.run_id,Date.now());break}case"on_chat_model_end":{const s=t.run_id?this.llmStartTimes.get(t.run_id):void 0,e=U(t,{...this.opts,startTimeMs:s});e&&(e.llmCall.callIndex=this.llmCalls.length,this.llmCalls.push(e.llmCall),this.llmUsage.push(e.tokenUsage),this.traceEvents.push({kind:"token_usage",ts:Date.now(),inputTokens:e.tokenUsage.inputTokens,outputTokens:e.tokenUsage.outputTokens,totalTokens:e.tokenUsage.totalTokens,modelId:e.tokenUsage.model,provider:e.tokenUsage.provider,assistantName:e.tokenUsage.assistantName})),t.run_id&&this.llmStartTimes.delete(t.run_id);break}case"on_tool_start":{const s=String(t.name??"unknown_tool"),e=`${s}:${t.run_id??""}`;this.toolStartTimes.set(e,Date.now());const a=t.data?.input,n=typeof a=="string"?a:JSON.stringify(a??null);this.traceEvents.push({kind:"tool_start",ts:Date.now(),toolName:s,toolInput:n.slice(0,200)});break}case"on_tool_end":{const s=String(t.name??"unknown_tool"),e=`${s}:${t.run_id??""}`,a=this.toolStartTimes.get(e)??Date.now();this.toolStartTimes.delete(e);const n=t.data?.output,o=typeof n=="string"?n.slice(0,2e3):JSON.stringify(n??null).slice(0,2e3),i=Date.now()-a;this.tools.push({name:s,input:t.data?.input??{},output:o,timestamp:new Date().toISOString(),error:!1,duration:i}),this.traceEvents.push({kind:"tool_end",ts:Date.now(),toolName:s,toolResult:o.slice(0,300),durationMs:i});break}case"on_chain_start":case"on_chain_end":{const s=t.metadata?.langgraph_node;s&&t.name===s&&this.traceEvents.push(t.event==="on_chain_start"?{kind:"node_start",ts:Date.now(),node:s}:{kind:"node_end",ts:Date.now(),node:s});break}}}getLlmUsage(){return this.llmUsage}getLlmCalls(){return this.llmCalls}getToolEntries(){return this.tools}getUniqueToolNames(){return Array.from(new Set(this.tools.map(t=>t.name)))}getToolCallsCount(){return this.tools.length}getTraceEvents(){return this.traceEvents}hasData(){return this.llmCalls.length>0||this.tools.length>0||this.traceEvents.length>0}async persist(t){const s=new Date().toISOString();this.llmCalls.length>0&&await b({chatId:t.chatId,runId:t.runId,username:t.username,teamId:t.teamId,assistantId:t.assistantId,assistantName:t.assistantName,llms:this.llmCalls,createdAt:s}).catch(e=>console.error(`[RunAnalytics] Failed to persist LLM calls for run ${t.runId}: ${e?.message}`)),this.tools.length>0&&await A({chatId:t.chatId,runId:t.runId,username:t.username,assistantId:t.assistantId||"unknown",assistantName:t.assistantName||"unknown",tools:this.tools,metadata:t.metadata,createdAt:s}).catch(e=>console.error(`[RunAnalytics] Failed to persist tools for run ${t.runId}: ${e?.message}`)),this.traceEvents.length>0&&await N({chatId:t.chatId,runId:t.runId,username:t.username,teamId:t.teamId,events:this.traceEvents,createdAt:s}).catch(e=>console.error(`[RunAnalytics] Failed to persist trace for run ${t.runId}: ${e?.message}`))}}export{R as RunAnalyticsCollector,U as parseChatModelEndUsage};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
async function s(o,n,r){o.length!==0&&await Promise.allSettled(o.map(async t=>{const e=t[n];if(typeof e=="function")try{await e.call(t,r)}catch(a){console.warn(`[RunStreamSink] ${t.name}.${String(n)} threw: ${a?.message??a} \u2014 continuing`)}}))}function i(o){if(!o||typeof o!="object")return"";const n=o;if(Array.isArray(n.content)){const r=[];for(const t of n.content)typeof t=="string"?r.push(t):t&&typeof t=="object"&&typeof t.text=="string"&&r.push(t.text);return r.join("")}return typeof n.content=="string"?n.content:typeof n.text=="string"?n.text:""}export{i as extractTextFromStreamChunk,s as fanout};
|
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
import{Resend as x}from"resend";const d=new x(process.env.RESEND_API_KEY),o="#00BFD8",l="#5583D6",s="https://app.erretegia.com",p="contact@erretegia.com",u=(t,e)=>`
|
|
2
|
+
<!DOCTYPE html>
|
|
3
|
+
<html lang="en">
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>Activate your StackXP account</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body style="margin:0;padding:0;background-color:#F0F4F8;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;">
|
|
10
|
+
|
|
11
|
+
<!-- Wrapper -->
|
|
12
|
+
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color:#F0F4F8;padding:40px 16px;">
|
|
13
|
+
<tr>
|
|
14
|
+
<td align="center">
|
|
15
|
+
<table width="600" cellpadding="0" cellspacing="0" border="0" style="max-width:600px;width:100%;">
|
|
16
|
+
|
|
17
|
+
<!-- Header / Logo -->
|
|
18
|
+
<tr>
|
|
19
|
+
<td align="center" style="background:linear-gradient(135deg,${o} 0%,${l} 100%);border-radius:12px 12px 0 0;padding:40px 40px 32px;">
|
|
20
|
+
<p style="margin:0;font-size:32px;font-weight:800;color:#FFFFFF;letter-spacing:-0.5px;">
|
|
21
|
+
Stack<span style="opacity:0.85;">XP</span>
|
|
22
|
+
</p>
|
|
23
|
+
<p style="margin:8px 0 0;font-size:14px;color:rgba(255,255,255,0.8);letter-spacing:0.5px;text-transform:uppercase;">
|
|
24
|
+
AI-powered data analysis
|
|
25
|
+
</p>
|
|
26
|
+
</td>
|
|
27
|
+
</tr>
|
|
28
|
+
|
|
29
|
+
<!-- Body -->
|
|
30
|
+
<tr>
|
|
31
|
+
<td style="background:#FFFFFF;padding:48px 48px 40px;border-left:1px solid #E4E8EE;border-right:1px solid #E4E8EE;">
|
|
32
|
+
|
|
33
|
+
<p style="margin:0 0 8px;font-size:22px;font-weight:700;color:#1A2332;">
|
|
34
|
+
Welcome aboard, ${t}!
|
|
35
|
+
</p>
|
|
36
|
+
<p style="margin:0 0 32px;font-size:15px;color:#6B7280;line-height:1.6;">
|
|
37
|
+
Thanks for creating your StackXP account. One last step \u2014 please verify your email address to activate your account.
|
|
38
|
+
</p>
|
|
39
|
+
|
|
40
|
+
<!-- CTA Button -->
|
|
41
|
+
<table cellpadding="0" cellspacing="0" border="0" style="margin:0 auto 40px;">
|
|
42
|
+
<tr>
|
|
43
|
+
<td align="center" style="background:linear-gradient(135deg,${o} 0%,${l} 100%);border-radius:8px;">
|
|
44
|
+
<a href="${e}"
|
|
45
|
+
style="display:inline-block;padding:16px 40px;font-size:16px;font-weight:600;color:#FFFFFF;text-decoration:none;letter-spacing:0.2px;">
|
|
46
|
+
Activate my account
|
|
47
|
+
</a>
|
|
48
|
+
</td>
|
|
49
|
+
</tr>
|
|
50
|
+
</table>
|
|
51
|
+
|
|
52
|
+
<!-- Link fallback -->
|
|
53
|
+
<p style="margin:0 0 4px;font-size:12px;color:#9CA3AF;">
|
|
54
|
+
If the button doesn't work, copy and paste this link into your browser:
|
|
55
|
+
</p>
|
|
56
|
+
<p style="margin:0 0 40px;font-size:12px;word-break:break-all;">
|
|
57
|
+
<a href="${e}" style="color:${o};text-decoration:none;">${e}</a>
|
|
58
|
+
</p>
|
|
59
|
+
|
|
60
|
+
<!-- Divider -->
|
|
61
|
+
<hr style="border:none;border-top:1px solid #E9ECEF;margin:0 0 32px;" />
|
|
62
|
+
|
|
63
|
+
<!-- What you'll get -->
|
|
64
|
+
<p style="margin:0 0 16px;font-size:14px;font-weight:600;color:#374151;text-transform:uppercase;letter-spacing:0.5px;">
|
|
65
|
+
What's waiting for you
|
|
66
|
+
</p>
|
|
67
|
+
<table cellpadding="0" cellspacing="0" border="0" width="100%">
|
|
68
|
+
${[["\u26A1","Instant AI-powered analyses","Describe what you need \u2014 get results in seconds."],["\u{1F517}","200+ data integrations","Ingest signals from your entire security & observability stack."],["\u{1F4CA}","Interactive dashboards","Beautiful, actionable charts generated automatically."],["\u{1F916}","Multi-LLM support","Choose between OpenAI, Anthropic, Gemini, and more."]].map(([i,a,r])=>`
|
|
69
|
+
<tr>
|
|
70
|
+
<td style="padding:0 0 16px;vertical-align:top;width:36px;">
|
|
71
|
+
<span style="font-size:20px;">${i}</span>
|
|
72
|
+
</td>
|
|
73
|
+
<td style="padding:0 0 16px 8px;vertical-align:top;">
|
|
74
|
+
<p style="margin:0 0 2px;font-size:14px;font-weight:600;color:#1A2332;">${a}</p>
|
|
75
|
+
<p style="margin:0;font-size:13px;color:#6B7280;line-height:1.5;">${r}</p>
|
|
76
|
+
</td>
|
|
77
|
+
</tr>`).join("")}
|
|
78
|
+
</table>
|
|
79
|
+
|
|
80
|
+
</td>
|
|
81
|
+
</tr>
|
|
82
|
+
|
|
83
|
+
<!-- Security footer -->
|
|
84
|
+
<tr>
|
|
85
|
+
<td style="background:#F8FAFC;border:1px solid #E4E8EE;border-top:none;border-radius:0 0 12px 12px;padding:24px 48px;">
|
|
86
|
+
<p style="margin:0;font-size:12px;color:#9CA3AF;line-height:1.6;text-align:center;">
|
|
87
|
+
If you didn't create a StackXP account, you can safely ignore this email \u2014 no action is required.<br/>
|
|
88
|
+
This link is valid for 72 hours and can only be used once.
|
|
89
|
+
</p>
|
|
90
|
+
</td>
|
|
91
|
+
</tr>
|
|
92
|
+
|
|
93
|
+
<!-- Bottom spacer -->
|
|
94
|
+
<tr>
|
|
95
|
+
<td height="32"></td>
|
|
96
|
+
</tr>
|
|
97
|
+
<tr>
|
|
98
|
+
<td align="center">
|
|
99
|
+
<p style="margin:0;font-size:12px;color:#B0B8C4;">
|
|
100
|
+
\xA9 ${new Date().getFullYear()} StackXP \xB7 <a href="${s}" style="color:${o};text-decoration:none;">app.erretegia.com</a>
|
|
101
|
+
</p>
|
|
102
|
+
</td>
|
|
103
|
+
</tr>
|
|
104
|
+
|
|
105
|
+
</table>
|
|
106
|
+
</td>
|
|
107
|
+
</tr>
|
|
108
|
+
</table>
|
|
109
|
+
|
|
110
|
+
</body>
|
|
111
|
+
</html>
|
|
112
|
+
`,y=t=>`
|
|
113
|
+
<!DOCTYPE html>
|
|
114
|
+
<html lang="en">
|
|
115
|
+
<head>
|
|
116
|
+
<meta charset="UTF-8" />
|
|
117
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
118
|
+
<title>Registration received \u2014 StackXP</title>
|
|
119
|
+
</head>
|
|
120
|
+
<body style="margin:0;padding:0;background-color:#F0F4F8;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;">
|
|
121
|
+
|
|
122
|
+
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color:#F0F4F8;padding:40px 16px;">
|
|
123
|
+
<tr>
|
|
124
|
+
<td align="center">
|
|
125
|
+
<table width="600" cellpadding="0" cellspacing="0" border="0" style="max-width:600px;width:100%;">
|
|
126
|
+
|
|
127
|
+
<!-- Header / Logo -->
|
|
128
|
+
<tr>
|
|
129
|
+
<td align="center" style="background:linear-gradient(135deg,${o} 0%,${l} 100%);border-radius:12px 12px 0 0;padding:40px 40px 32px;">
|
|
130
|
+
<p style="margin:0;font-size:32px;font-weight:800;color:#FFFFFF;letter-spacing:-0.5px;">
|
|
131
|
+
Stack<span style="opacity:0.85;">XP</span>
|
|
132
|
+
</p>
|
|
133
|
+
<p style="margin:8px 0 0;font-size:14px;color:rgba(255,255,255,0.8);letter-spacing:0.5px;text-transform:uppercase;">
|
|
134
|
+
Registration received
|
|
135
|
+
</p>
|
|
136
|
+
</td>
|
|
137
|
+
</tr>
|
|
138
|
+
|
|
139
|
+
<!-- Body -->
|
|
140
|
+
<tr>
|
|
141
|
+
<td style="background:#FFFFFF;padding:48px 48px 40px;border-left:1px solid #E4E8EE;border-right:1px solid #E4E8EE;">
|
|
142
|
+
|
|
143
|
+
<p style="margin:0 0 8px;font-size:22px;font-weight:700;color:#1A2332;">
|
|
144
|
+
Thanks for signing up, ${t}!
|
|
145
|
+
</p>
|
|
146
|
+
<p style="margin:0 0 24px;font-size:15px;color:#6B7280;line-height:1.6;">
|
|
147
|
+
We've received your registration on StackXP. During our limited-access launch period, every new account is reviewed and activated manually by our team.
|
|
148
|
+
</p>
|
|
149
|
+
|
|
150
|
+
<!-- Status badge -->
|
|
151
|
+
<table cellpadding="0" cellspacing="0" border="0" style="margin:0 0 32px;">
|
|
152
|
+
<tr>
|
|
153
|
+
<td style="padding:14px 20px;background:#FFF8E1;border:1px solid #FFE082;border-radius:8px;">
|
|
154
|
+
<p style="margin:0;font-size:14px;color:#6B5500;line-height:1.5;">
|
|
155
|
+
<strong>What happens next?</strong><br/>
|
|
156
|
+
Our team will get back to you shortly at this email address with your activation details. No action is needed from you in the meantime.
|
|
157
|
+
</p>
|
|
158
|
+
</td>
|
|
159
|
+
</tr>
|
|
160
|
+
</table>
|
|
161
|
+
|
|
162
|
+
<hr style="border:none;border-top:1px solid #E9ECEF;margin:0 0 32px;" />
|
|
163
|
+
|
|
164
|
+
<p style="margin:0 0 16px;font-size:14px;font-weight:600;color:#374151;text-transform:uppercase;letter-spacing:0.5px;">
|
|
165
|
+
What's waiting for you once activated
|
|
166
|
+
</p>
|
|
167
|
+
<table cellpadding="0" cellspacing="0" border="0" width="100%">
|
|
168
|
+
${[["\u26A1","Instant AI-powered analyses","Describe what you need \u2014 get results in seconds."],["\u{1F517}","200+ data integrations","Ingest signals from your entire security & observability stack."],["\u{1F4CA}","Interactive dashboards","Beautiful, actionable charts generated automatically."],["\u{1F916}","Multi-LLM support","Choose between OpenAI, Anthropic, Gemini, and more."]].map(([e,i,a])=>`
|
|
169
|
+
<tr>
|
|
170
|
+
<td style="padding:0 0 16px;vertical-align:top;width:36px;">
|
|
171
|
+
<span style="font-size:20px;">${e}</span>
|
|
172
|
+
</td>
|
|
173
|
+
<td style="padding:0 0 16px 8px;vertical-align:top;">
|
|
174
|
+
<p style="margin:0 0 2px;font-size:14px;font-weight:600;color:#1A2332;">${i}</p>
|
|
175
|
+
<p style="margin:0;font-size:13px;color:#6B7280;line-height:1.5;">${a}</p>
|
|
176
|
+
</td>
|
|
177
|
+
</tr>`).join("")}
|
|
178
|
+
</table>
|
|
179
|
+
|
|
180
|
+
</td>
|
|
181
|
+
</tr>
|
|
182
|
+
|
|
183
|
+
<!-- Footer -->
|
|
184
|
+
<tr>
|
|
185
|
+
<td style="background:#F8FAFC;border:1px solid #E4E8EE;border-top:none;border-radius:0 0 12px 12px;padding:24px 48px;">
|
|
186
|
+
<p style="margin:0;font-size:12px;color:#9CA3AF;line-height:1.6;text-align:center;">
|
|
187
|
+
If you didn't sign up for StackXP, you can safely ignore this email.<br/>
|
|
188
|
+
Questions? Reach us at <a href="mailto:contact@erretegia.com" style="color:${o};text-decoration:none;">contact@erretegia.com</a>.
|
|
189
|
+
</p>
|
|
190
|
+
</td>
|
|
191
|
+
</tr>
|
|
192
|
+
|
|
193
|
+
<tr><td height="32"></td></tr>
|
|
194
|
+
<tr>
|
|
195
|
+
<td align="center">
|
|
196
|
+
<p style="margin:0;font-size:12px;color:#B0B8C4;">
|
|
197
|
+
\xA9 ${new Date().getFullYear()} StackXP \xB7 <a href="${s}" style="color:${o};text-decoration:none;">app.erretegia.com</a>
|
|
198
|
+
</p>
|
|
199
|
+
</td>
|
|
200
|
+
</tr>
|
|
201
|
+
|
|
202
|
+
</table>
|
|
203
|
+
</td>
|
|
204
|
+
</tr>
|
|
205
|
+
</table>
|
|
206
|
+
|
|
207
|
+
</body>
|
|
208
|
+
</html>
|
|
209
|
+
`,b=(t,e,i)=>{const a=i.toLocaleString("en-GB",{timeZone:"UTC",weekday:"long",year:"numeric",month:"long",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit",timeZoneName:"short"}),r=`${s}/settings`;return`
|
|
210
|
+
<!DOCTYPE html>
|
|
211
|
+
<html lang="en">
|
|
212
|
+
<head>
|
|
213
|
+
<meta charset="UTF-8" />
|
|
214
|
+
<title>New user registration \u2014 StackXP</title>
|
|
215
|
+
</head>
|
|
216
|
+
<body style="margin:0;padding:0;background-color:#F0F4F8;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;">
|
|
217
|
+
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color:#F0F4F8;padding:40px 16px;">
|
|
218
|
+
<tr>
|
|
219
|
+
<td align="center">
|
|
220
|
+
<table width="560" cellpadding="0" cellspacing="0" border="0" style="max-width:560px;width:100%;">
|
|
221
|
+
|
|
222
|
+
<!-- Header -->
|
|
223
|
+
<tr>
|
|
224
|
+
<td style="background:linear-gradient(135deg,${o} 0%,${l} 100%);border-radius:12px 12px 0 0;padding:28px 36px;">
|
|
225
|
+
<p style="margin:0;font-size:13px;font-weight:600;color:rgba(255,255,255,0.75);text-transform:uppercase;letter-spacing:1px;">
|
|
226
|
+
StackXP Admin
|
|
227
|
+
</p>
|
|
228
|
+
<p style="margin:6px 0 0;font-size:22px;font-weight:700;color:#FFFFFF;">
|
|
229
|
+
New user registration
|
|
230
|
+
</p>
|
|
231
|
+
</td>
|
|
232
|
+
</tr>
|
|
233
|
+
|
|
234
|
+
<!-- Body -->
|
|
235
|
+
<tr>
|
|
236
|
+
<td style="background:#FFFFFF;padding:36px;border-left:1px solid #E4E8EE;border-right:1px solid #E4E8EE;">
|
|
237
|
+
|
|
238
|
+
<p style="margin:0 0 24px;font-size:15px;color:#374151;line-height:1.6;">
|
|
239
|
+
A new account has just been created on StackXP. Here are the details:
|
|
240
|
+
</p>
|
|
241
|
+
|
|
242
|
+
<!-- Details table -->
|
|
243
|
+
<table cellpadding="0" cellspacing="0" border="0" width="100%"
|
|
244
|
+
style="border:1px solid #E4E8EE;border-radius:8px;overflow:hidden;">
|
|
245
|
+
${[["Username",t],["Email",e],["Registered at",a],["Account status","Pending manual activation"]].map(([n,c],g)=>`
|
|
246
|
+
<tr style="background:${g%2===0?"#FFFFFF":"#F8FAFC"};">
|
|
247
|
+
<td style="padding:14px 18px;font-size:13px;font-weight:600;color:#6B7280;width:40%;border-bottom:1px solid #E4E8EE;">
|
|
248
|
+
${n}
|
|
249
|
+
</td>
|
|
250
|
+
<td style="padding:14px 18px;font-size:13px;color:#1A2332;border-bottom:1px solid #E4E8EE;">
|
|
251
|
+
${c}
|
|
252
|
+
</td>
|
|
253
|
+
</tr>`).join("")}
|
|
254
|
+
</table>
|
|
255
|
+
|
|
256
|
+
<!-- CTA -->
|
|
257
|
+
<table cellpadding="0" cellspacing="0" border="0" style="margin:32px auto 0;">
|
|
258
|
+
<tr>
|
|
259
|
+
<td align="center" style="background:linear-gradient(135deg,${o} 0%,${l} 100%);border-radius:8px;">
|
|
260
|
+
<a href="${r}"
|
|
261
|
+
style="display:inline-block;padding:13px 32px;font-size:14px;font-weight:600;color:#FFFFFF;text-decoration:none;">
|
|
262
|
+
Open Admin Settings
|
|
263
|
+
</a>
|
|
264
|
+
</td>
|
|
265
|
+
</tr>
|
|
266
|
+
</table>
|
|
267
|
+
|
|
268
|
+
</td>
|
|
269
|
+
</tr>
|
|
270
|
+
|
|
271
|
+
<!-- Footer -->
|
|
272
|
+
<tr>
|
|
273
|
+
<td style="background:#F8FAFC;border:1px solid #E4E8EE;border-top:none;border-radius:0 0 12px 12px;padding:20px 36px;">
|
|
274
|
+
<p style="margin:0;font-size:12px;color:#9CA3AF;text-align:center;">
|
|
275
|
+
This is an automated notification from StackXP. Do not reply to this email.
|
|
276
|
+
</p>
|
|
277
|
+
</td>
|
|
278
|
+
</tr>
|
|
279
|
+
|
|
280
|
+
</table>
|
|
281
|
+
</td>
|
|
282
|
+
</tr>
|
|
283
|
+
</table>
|
|
284
|
+
</body>
|
|
285
|
+
</html>
|
|
286
|
+
`},m=(t,e)=>`
|
|
287
|
+
<!DOCTYPE html>
|
|
288
|
+
<html lang="en">
|
|
289
|
+
<head>
|
|
290
|
+
<meta charset="UTF-8" />
|
|
291
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
292
|
+
<title>Reset your StackXP password</title>
|
|
293
|
+
</head>
|
|
294
|
+
<body style="margin:0;padding:0;background-color:#F0F4F8;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;">
|
|
295
|
+
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color:#F0F4F8;padding:40px 16px;">
|
|
296
|
+
<tr>
|
|
297
|
+
<td align="center">
|
|
298
|
+
<table width="600" cellpadding="0" cellspacing="0" border="0" style="max-width:600px;width:100%;">
|
|
299
|
+
<tr>
|
|
300
|
+
<td align="center" style="background:linear-gradient(135deg,${o} 0%,${l} 100%);border-radius:12px 12px 0 0;padding:40px 40px 32px;">
|
|
301
|
+
<p style="margin:0;font-size:32px;font-weight:800;color:#FFFFFF;letter-spacing:-0.5px;">
|
|
302
|
+
Stack<span style="opacity:0.85;">XP</span>
|
|
303
|
+
</p>
|
|
304
|
+
<p style="margin:8px 0 0;font-size:14px;color:rgba(255,255,255,0.8);letter-spacing:0.5px;text-transform:uppercase;">
|
|
305
|
+
Password reset
|
|
306
|
+
</p>
|
|
307
|
+
</td>
|
|
308
|
+
</tr>
|
|
309
|
+
<tr>
|
|
310
|
+
<td style="background:#FFFFFF;padding:48px 48px 40px;border-left:1px solid #E4E8EE;border-right:1px solid #E4E8EE;">
|
|
311
|
+
<p style="margin:0 0 8px;font-size:22px;font-weight:700;color:#1A2332;">
|
|
312
|
+
Hi ${t},
|
|
313
|
+
</p>
|
|
314
|
+
<p style="margin:0 0 32px;font-size:15px;color:#6B7280;line-height:1.6;">
|
|
315
|
+
We received a request to reset your StackXP password. Click the button below to choose a new password. This link is valid for <strong>1 hour</strong>.
|
|
316
|
+
</p>
|
|
317
|
+
<table cellpadding="0" cellspacing="0" border="0" style="margin:0 auto 40px;">
|
|
318
|
+
<tr>
|
|
319
|
+
<td align="center" style="background:linear-gradient(135deg,${o} 0%,${l} 100%);border-radius:8px;">
|
|
320
|
+
<a href="${e}" style="display:inline-block;padding:16px 40px;font-size:16px;font-weight:600;color:#FFFFFF;text-decoration:none;letter-spacing:0.2px;">
|
|
321
|
+
Reset my password
|
|
322
|
+
</a>
|
|
323
|
+
</td>
|
|
324
|
+
</tr>
|
|
325
|
+
</table>
|
|
326
|
+
<p style="margin:0 0 4px;font-size:12px;color:#9CA3AF;">
|
|
327
|
+
If the button doesn't work, copy and paste this link:
|
|
328
|
+
</p>
|
|
329
|
+
<p style="margin:0 0 40px;font-size:12px;word-break:break-all;">
|
|
330
|
+
<a href="${e}" style="color:${o};text-decoration:none;">${e}</a>
|
|
331
|
+
</p>
|
|
332
|
+
<hr style="border:none;border-top:1px solid #E9ECEF;margin:0 0 32px;" />
|
|
333
|
+
<p style="margin:0;font-size:13px;color:#9CA3AF;line-height:1.6;">
|
|
334
|
+
If you didn't request a password reset, you can safely ignore this email \u2014 your password won't change.
|
|
335
|
+
</p>
|
|
336
|
+
</td>
|
|
337
|
+
</tr>
|
|
338
|
+
<tr>
|
|
339
|
+
<td style="background:#F8FAFC;border:1px solid #E4E8EE;border-top:none;border-radius:0 0 12px 12px;padding:24px 48px;">
|
|
340
|
+
<p style="margin:0;font-size:12px;color:#9CA3AF;line-height:1.6;text-align:center;">
|
|
341
|
+
This link expires in 1 hour and can only be used once.<br/>
|
|
342
|
+
\xA9 ${new Date().getFullYear()} StackXP \xB7 <a href="${s}" style="color:${o};text-decoration:none;">app.erretegia.com</a>
|
|
343
|
+
</p>
|
|
344
|
+
</td>
|
|
345
|
+
</tr>
|
|
346
|
+
</table>
|
|
347
|
+
</td>
|
|
348
|
+
</tr>
|
|
349
|
+
</table>
|
|
350
|
+
</body>
|
|
351
|
+
</html>
|
|
352
|
+
`,h=(t,e)=>`
|
|
353
|
+
<!DOCTYPE html>
|
|
354
|
+
<html lang="en">
|
|
355
|
+
<head>
|
|
356
|
+
<meta charset="UTF-8" />
|
|
357
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
358
|
+
<title>Your access link \u2014 StackXP</title>
|
|
359
|
+
</head>
|
|
360
|
+
<body style="margin:0;padding:0;background-color:#F0F4F8;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;">
|
|
361
|
+
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color:#F0F4F8;padding:40px 16px;">
|
|
362
|
+
<tr>
|
|
363
|
+
<td align="center">
|
|
364
|
+
<table width="600" cellpadding="0" cellspacing="0" border="0" style="max-width:600px;width:100%;">
|
|
365
|
+
|
|
366
|
+
<!-- Header -->
|
|
367
|
+
<tr>
|
|
368
|
+
<td align="center" style="background:linear-gradient(135deg,${o} 0%,${l} 100%);border-radius:12px 12px 0 0;padding:40px 40px 32px;">
|
|
369
|
+
<p style="margin:0;font-size:32px;font-weight:800;color:#FFFFFF;letter-spacing:-0.5px;">
|
|
370
|
+
Stack<span style="opacity:0.85;">XP</span>
|
|
371
|
+
</p>
|
|
372
|
+
<p style="margin:8px 0 0;font-size:14px;color:rgba(255,255,255,0.8);letter-spacing:0.5px;text-transform:uppercase;">
|
|
373
|
+
Shared content
|
|
374
|
+
</p>
|
|
375
|
+
</td>
|
|
376
|
+
</tr>
|
|
377
|
+
|
|
378
|
+
<!-- Body -->
|
|
379
|
+
<tr>
|
|
380
|
+
<td style="background:#FFFFFF;padding:48px 48px 40px;border-left:1px solid #E4E8EE;border-right:1px solid #E4E8EE;">
|
|
381
|
+
|
|
382
|
+
<p style="margin:0 0 8px;font-size:22px;font-weight:700;color:#1A2332;">
|
|
383
|
+
Your access link is ready
|
|
384
|
+
</p>
|
|
385
|
+
<p style="margin:0 0 8px;font-size:15px;color:#6B7280;line-height:1.6;">
|
|
386
|
+
You have been invited to access:
|
|
387
|
+
</p>
|
|
388
|
+
<p style="margin:0 0 32px;font-size:16px;font-weight:600;color:#1A2332;padding:12px 16px;background:#F8FAFC;border-left:3px solid ${o};border-radius:4px;">
|
|
389
|
+
${t}
|
|
390
|
+
</p>
|
|
391
|
+
|
|
392
|
+
<!-- CTA Button -->
|
|
393
|
+
<table cellpadding="0" cellspacing="0" border="0" style="margin:0 auto 40px;">
|
|
394
|
+
<tr>
|
|
395
|
+
<td align="center" style="background:linear-gradient(135deg,${o} 0%,${l} 100%);border-radius:8px;">
|
|
396
|
+
<a href="${e}"
|
|
397
|
+
style="display:inline-block;padding:16px 40px;font-size:16px;font-weight:600;color:#FFFFFF;text-decoration:none;letter-spacing:0.2px;">
|
|
398
|
+
Access now
|
|
399
|
+
</a>
|
|
400
|
+
</td>
|
|
401
|
+
</tr>
|
|
402
|
+
</table>
|
|
403
|
+
|
|
404
|
+
<!-- Link fallback -->
|
|
405
|
+
<p style="margin:0 0 4px;font-size:12px;color:#9CA3AF;">
|
|
406
|
+
If the button doesn't work, copy and paste this link:
|
|
407
|
+
</p>
|
|
408
|
+
<p style="margin:0 0 40px;font-size:12px;word-break:break-all;">
|
|
409
|
+
<a href="${e}" style="color:${o};text-decoration:none;">${e}</a>
|
|
410
|
+
</p>
|
|
411
|
+
|
|
412
|
+
<hr style="border:none;border-top:1px solid #E9ECEF;margin:0 0 24px;" />
|
|
413
|
+
<p style="margin:0;font-size:13px;color:#9CA3AF;line-height:1.6;">
|
|
414
|
+
This link is valid for <strong>15 minutes</strong> and can only be used once.<br/>
|
|
415
|
+
If you didn't request this link, you can safely ignore this email.
|
|
416
|
+
</p>
|
|
417
|
+
</td>
|
|
418
|
+
</tr>
|
|
419
|
+
|
|
420
|
+
<!-- Footer -->
|
|
421
|
+
<tr>
|
|
422
|
+
<td style="background:#F8FAFC;border:1px solid #E4E8EE;border-top:none;border-radius:0 0 12px 12px;padding:24px 48px;">
|
|
423
|
+
<p style="margin:0;font-size:12px;color:#9CA3AF;line-height:1.6;text-align:center;">
|
|
424
|
+
\xA9 ${new Date().getFullYear()} StackXP \xB7 <a href="${s}" style="color:${o};text-decoration:none;">app.erretegia.com</a>
|
|
425
|
+
</p>
|
|
426
|
+
</td>
|
|
427
|
+
</tr>
|
|
428
|
+
|
|
429
|
+
</table>
|
|
430
|
+
</td>
|
|
431
|
+
</tr>
|
|
432
|
+
</table>
|
|
433
|
+
</body>
|
|
434
|
+
</html>
|
|
435
|
+
`,F=async(t,e,i)=>{const a=`${s}/reset-password?token=${i}&username=${encodeURIComponent(t)}`;console.log("sendPasswordResetMail \u2192 to:",e,"| token:",i);const[r]=await Promise.allSettled([d.emails.send({from:"noreply@erretegia.com",to:e,subject:"Reset your StackXP password",html:m(t,a)})]);r.status==="fulfilled"?console.log("Password reset email sent:",JSON.stringify(r.value)):console.error("Failed to send password reset email:",r.reason)},w=async(t,e,i,a)=>{const r=`${s}/share/verify/${a}?redirect=${encodeURIComponent(i)}`;console.log("sendMagicLinkEmail \u2192 to:",t,"| token:",a);const[n]=await Promise.allSettled([d.emails.send({from:"noreply@erretegia.com",to:t,subject:`Your access link \u2014 ${e}`,html:h(e,r)})]);n.status==="fulfilled"?console.log("Magic link email sent:",JSON.stringify(n.value)):console.error("Failed to send magic link email:",n.reason)},k=async(t,e,i,a)=>{const[r]=await Promise.allSettled([d.emails.send({from:"noreply@erretegia.com",to:p,subject:`[Platform Request] ${e} \u2014 ${t}`,html:`
|
|
436
|
+
<div style="font-family:sans-serif;max-width:600px;margin:0 auto;">
|
|
437
|
+
<h2 style="color:#0077CC;">New Platform Request</h2>
|
|
438
|
+
<table style="border-collapse:collapse;width:100%;">
|
|
439
|
+
<tr>
|
|
440
|
+
<td style="padding:8px 12px;font-weight:bold;background:#f5f7fa;border:1px solid #ddd;">User</td>
|
|
441
|
+
<td style="padding:8px 12px;border:1px solid #ddd;">${t}</td>
|
|
442
|
+
</tr>
|
|
443
|
+
<tr>
|
|
444
|
+
<td style="padding:8px 12px;font-weight:bold;background:#f5f7fa;border:1px solid #ddd;">Platform Type</td>
|
|
445
|
+
<td style="padding:8px 12px;border:1px solid #ddd;">${e}</td>
|
|
446
|
+
</tr>
|
|
447
|
+
<tr>
|
|
448
|
+
<td style="padding:8px 12px;font-weight:bold;background:#f5f7fa;border:1px solid #ddd;">Daily Transactions (est.)</td>
|
|
449
|
+
<td style="padding:8px 12px;border:1px solid #ddd;">${a}</td>
|
|
450
|
+
</tr>
|
|
451
|
+
<tr>
|
|
452
|
+
<td style="padding:8px 12px;font-weight:bold;background:#f5f7fa;border:1px solid #ddd;vertical-align:top;">Description</td>
|
|
453
|
+
<td style="padding:8px 12px;border:1px solid #ddd;white-space:pre-wrap;">${i}</td>
|
|
454
|
+
</tr>
|
|
455
|
+
</table>
|
|
456
|
+
<p style="margin-top:24px;color:#6B7280;font-size:13px;">
|
|
457
|
+
Sent from <a href="https://app.erretegia.com/account#platforms-managed">app.erretegia.com</a>
|
|
458
|
+
</p>
|
|
459
|
+
</div>
|
|
460
|
+
`})]);r.status==="fulfilled"?console.log("Platform request notification sent:",JSON.stringify(r.value)):console.error("Failed to send platform request notification:",r.reason)},E=async(t,e,i)=>{const a=new Date;console.log("sendMail \u2192 pending-approval to:",e);const[r,n]=await Promise.allSettled([d.emails.send({from:"noreply@erretegia.com",to:e,subject:"We received your StackXP registration",html:y(t)}),d.emails.send({from:"noreply@erretegia.com",to:p,subject:`[StackXP] New registration \u2014 ${t} (manual activation needed)`,html:b(t,e,a)})]);r.status==="fulfilled"?console.log("Pending-approval email sent:",JSON.stringify(r.value)):console.error("Failed to send pending-approval email:",r.reason),n.status==="fulfilled"?console.log("Notification email sent:",JSON.stringify(n.value)):console.error("Failed to send notification email:",n.reason)};export{u as buildActivationEmail,w as sendMagicLinkEmail,E as sendMail,F as sendPasswordResetMail,k as sendPlatformRequestNotification};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Client as b}from"@elastic/elasticsearch";import{config as d}from"../config";import{randomUUID as w}from"node:crypto";import y from"jsonwebtoken";const s=new b(d.elasticsearch),o=".stkxp_share_links";async function k(){try{await s.indices.exists({index:o})?await s.indices.putMapping({index:o,body:{properties:{type:{type:"keyword"},allowedEmails:{type:"keyword"},dashboardLabel:{type:"keyword"},chatId:{type:"keyword"},chatTitle:{type:"keyword"},chatSnapshot:{type:"object",enabled:!1},embed:{type:"boolean"},allowedOrigins:{type:"keyword"},rateLimit:{type:"object",enabled:!1},budget:{type:"object",enabled:!1},embedUsage:{type:"object",enabled:!1}}}}).catch(()=>{}):(await s.indices.create({index:o,body:{mappings:{properties:{type:{type:"keyword"},ownerId:{type:"keyword"},label:{type:"keyword"},createdAt:{type:"date"},expiresAt:{type:"date"},maxUses:{type:"integer"},usesCount:{type:"integer"},revoked:{type:"boolean"},allowedEmails:{type:"keyword"},allowedDomains:{type:"keyword"},embed:{type:"boolean"},allowedOrigins:{type:"keyword"},rateLimit:{type:"object",enabled:!1},budget:{type:"object",enabled:!1},embedUsage:{type:"object",enabled:!1},teamId:{type:"keyword"},teamName:{type:"keyword"},dashboardLabel:{type:"keyword"},chatId:{type:"keyword"},chatTitle:{type:"keyword"},chatSnapshot:{type:"object",enabled:!1}}}}}),console.log("[ShareService] Index created:",o))}catch(e){console.error("[ShareService] Error initializing index:",e)}}k().catch(()=>{});async function _(e){const t=w(),r={...e,id:t,usesCount:0,revoked:!1,createdAt:new Date().toISOString(),allowedEmails:e.allowedEmails??[],allowedDomains:e.allowedDomains??[]};return await s.index({index:o,id:t,document:r,refresh:!0}),r}const x="https://app.erretegia.com";function U(e){return`${x}/share/run-view/${e}`}async function P(e,t,r,n){try{const a=await u(e);if(!a||a.ownerId!==t)return!1;const i={chatSnapshot:r};return n&&(i.chatTitle=n),await s.update({index:o,id:e,body:{doc:i},refresh:!0}),!0}catch(a){return console.error("[ShareService] updateRunShareSnapshot failed:",a),!1}}async function A(e,t){const r=[{term:{ownerId:e}}];return t&&r.push({term:{type:t}}),(await s.search({index:o,size:200,body:{query:{bool:{must:r}},sort:[{createdAt:{order:"desc"}}]}})).hits.hits.map(a=>({...a._source,id:a._id,allowedEmails:a._source.allowedEmails??a._source.allowedUsers??[],type:a._source.type??"team"}))}async function u(e){try{const t=await s.get({index:o,id:e}),r=t._source;return{...r,id:t._id,allowedEmails:r.allowedEmails??r.allowedUsers??[],type:r.type??"team"}}catch{return null}}async function E(e,t){try{const r=await u(e);return!r||r.ownerId!==t?!1:(await s.update({index:o,id:e,body:{doc:{revoked:!0}},refresh:!0}),!0)}catch{return!1}}async function D(e,t){try{const r=await u(e);return!r||r.ownerId!==t?!1:(await s.delete({index:o,id:e,refresh:!0}),!0)}catch{return!1}}async function R(e,t,r=!1){const n=await u(e);if(!n)return{valid:!1,error:"Share link not found"};if(n.revoked)return{valid:!1,error:"Share link has been revoked"};if(n.expiresAt&&new Date(n.expiresAt)<new Date)return{valid:!1,error:"Share link has expired"};if(n.maxUses!=null&&n.usesCount>=n.maxUses)return{valid:!1,error:"Share link has reached maximum uses"};if(r)return{valid:!0,link:n};if(n.allowedEmails.length>0){if(!n.allowedEmails.includes(t.toLowerCase()))return{valid:!1,error:"You are not authorised to use this share link"}}else if(n.allowedDomains.length>0){const a=t.includes("@")?t.split("@")[1]?.toLowerCase():null;if(!a||!n.allowedDomains.map(i=>i.toLowerCase()).includes(a))return{valid:!1,error:"Your email domain is not authorised for this share link"}}return{valid:!0,link:n}}async function T(e){try{await s.update({index:o,id:e,body:{script:{source:"ctx._source.usesCount += 1",lang:"painless"}}})}catch(t){console.error("[ShareService] Error incrementing uses count:",t)}}function p(e){if(!e)return null;try{const t=new URL(e.trim());return`${t.protocol}//${t.host}`.toLowerCase()}catch{return null}}function C(e,t){const r=p(t);return!r||!e||e.length===0?!1:e.some(n=>{const a=n.trim().toLowerCase(),i=p(a);if(i&&i===r)return!0;if(a.includes("*.")){const[h,l]=a.split("://");if(!l)return!1;const c=l.replace("*.",""),[f,m]=r.split("://");return f===h&&(m===c||m.endsWith(`.${c}`))}return!1})}function j(e){if(!e||e.length===0)return"'none'";const t=e.map(r=>r.trim()).filter(Boolean);return t.length>0?t.join(" "):"'none'"}function g(){return new Date().toISOString().slice(0,10)}function B(e){const t=e.budget;if(!t)return!0;const r=g(),n=e.embedUsage&&e.embedUsage.day===r?e.embedUsage:{day:r,tokens:0,runs:0};return!(t.maxTokensPerDay!=null&&n.tokens>=t.maxTokensPerDay||t.maxRunsPerDay!=null&&n.runs>=t.maxRunsPerDay)}async function G(e,t){const r=g();try{await s.update({index:o,id:e,body:{script:{lang:"painless",source:"def u = ctx._source.embedUsage;if (u == null || u.day != params.day) { ctx._source.embedUsage = ['day': params.day, 'tokens': 0, 'runs': 0]; }ctx._source.embedUsage.tokens += params.tokens;ctx._source.embedUsage.runs += params.runs;",params:{day:r,tokens:t.tokens??0,runs:t.runs??0}}}})}catch(n){console.error("[ShareService] consumeEmbedBudget error:",n)}}function N(e,t,r,n){const a={isGuest:!0,guestEmail:e,ownerId:t,shareLinkId:r,username:`guest:${n}`,iss:d.issuer,roles:[],enabled:!0};return y.sign(a,d.jwtSecret,{expiresIn:"1h"})}function O(e){try{const t=y.verify(e,d.jwtSecret,{issuer:d.issuer});return t?.isGuest?t:null}catch{return null}}async function $(e){try{return(await s.search({index:".stkxp_chats",size:200,body:{query:{bool:{must:[{term:{"metadata.ownerId":e}},{term:{"metadata.sharedRun":!0}}]}},sort:[{createdAt:{order:"desc"}}],_source:["metadata","createdAt"]}})).hits.hits.map(r=>({id:r._id,guestId:r._source?.metadata?.guestId,shareTokenId:r._source?.metadata?.shareTokenId,shareLinkLabel:r._source?.metadata?.shareLinkLabel,teamId:r._source?.metadata?.teamId,teamName:r._source?.metadata?.teamName,runAt:r._source?.createdAt}))}catch{return[]}}export{x as SHARE_PUBLIC_BASE_URL,U as buildRunShareUrl,B as checkEmbedBudget,G as consumeEmbedBudget,_ as createShareLink,D as deleteShareLink,j as frameAncestorsValue,$ as getGuestRunsByOwner,u as getShareLinkById,A as getShareLinksByOwner,T as incrementUsesCount,C as isEmbedOriginAllowed,N as issueGuestJWT,p as normalizeOrigin,E as revokeShareLink,P as updateRunShareSnapshot,R as validateShareToken,O as verifyGuestJWT};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createHmac as g,timingSafeEqual as l}from"crypto";function m(n,r){const e=Buffer.from(n,"utf8"),t=Buffer.from(r,"utf8");return e.length!==t.length?!1:l(e,t)}function S(n){const{rawBody:r,timestamp:e,signature:t,signingSecret:s}=n,f=n.toleranceSec??300,i=n.nowMs??Date.now();if(!e||!t||!s||!/^v0=[0-9a-f]{64}$/.test(t))return!1;const a=Number(e);if(!Number.isFinite(a)||Math.abs(Math.floor(i/1e3)-a)>f)return!1;const o=typeof r=="string"?r:r.toString("utf8"),u=`v0:${e}:${o}`,c="v0="+g("sha256",s).update(u).digest("hex");return m(c,t)}export{S as verifySlackSignature};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import{Client as J}from"@elastic/elasticsearch";import O from"js-yaml";import y from"fs/promises";import P from"path";import{randomUUID as C}from"crypto";import{config as X}from"../config";import{getToolboxIntegration as D}from"../../generated/toolbox-catalog";import{slugify as N,parametersToJsonSchema as W}from"./toolbox-import-mappers";import{createMcpClient as Y}from"../mcp/client";const m=new J(X.elasticsearch),h=".stkxp_sources",R=".stkxp_tools",S=process.env.TOOLBOX_CONFIG_FOLDER||"/root/stkxp-toolbox/configs",V=process.env.TOOLBOX_URL||"http://127.0.0.1:5002",F="\u2022\u2022\u2022\u2022\u2022\u2022";async function K(){await m.indices.exists({index:h})||await m.indices.create({index:h,mappings:{properties:{owner:{type:"keyword"},platformId:{type:"keyword"},name:{type:"keyword"},sourceKey:{type:"keyword"},slug:{type:"keyword"},sourceType:{type:"keyword"},config:{type:"object",enabled:!1},tools:{type:"object",enabled:!1},yamlFileName:{type:"keyword"},status:{type:"keyword"},statusMessage:{type:"text"},created:{type:"date"},updated:{type:"date"}}}})}function z(e){return N(e)}function A(e,o){return`${z(e)}__${N(o)}`}function G(e,o){return`${A(e,o)}.yaml`}function j(e,o){return`${e}__${N(o)}`}function I(e){const o={name:e.name,type:e.type,description:e.description&&e.description.trim()?e.description:e.name};return e.required===!1&&(o.required=!1),o}function U(e,o){if(!(!o||typeof o!="object"))for(const[r,n]of Object.entries(o))r==="type"||r==="source"||n===void 0||(e[r]=n)}function H(e){const o={type:e.toolType,source:e.sourceKey,description:e.description};return e.commands?.length?o.commands=e.commands:e.statement&&e.statement.trim()&&(e.isEsql?o.query=e.statement:o.statement=e.statement),e.parameters?.length&&(o.parameters=e.parameters),U(o,e.extra),o}function Q(e){const o=[],r=t=>{if(t&&Array.isArray(t.commands)&&t.commands.length){const s=o.push(t.commands)-1;t.commands=`__STKXP_CMDS_${s}__`}};if(e.tools&&typeof e.tools=="object")for(const t of Object.keys(e.tools))r(e.tools[t]);r(e);const n=O.dump(e,{lineWidth:120});return o.length?n.replace(/^([ \t]*)commands: __STKXP_CMDS_(\d+)__[ \t]*$/gm,(t,s,a)=>{const i=o[Number(a)].map(l=>`${s} - ${O.dump(l,{flowLevel:0,lineWidth:-1}).trim()}`).join(`
|
|
2
|
+
`);return`${s}commands:
|
|
3
|
+
${i}`}):n}function Z(e){const o={type:e.sourceType};for(const[t,s]of Object.entries(e.config))if(!(s==null||s==="")){if((t==="addresses"||t==="address")&&typeof s=="string"){o[t]=s.split(/[\n,]+/).map(a=>a.trim()).filter(Boolean);continue}o[t]=s}const r={};for(const t of e.tools||[]){const s={type:t.type,source:e.sourceKey};if(t.statement)if(/-esql$/.test(t.type))s.query=t.statement;else if(t.type==="clickhouse-sql"&&/\{(\w+):(\w+)\}/.test(t.statement)){const a=[];if(s.statement=t.statement.replace(/\{(\w+):(\w+)\}/g,(i,l)=>(a.push(l),"?")),a.length&&t.parameters?.length){const i=new Map(t.parameters.map(c=>[c.name,c])),l=a.map(c=>i.get(c)).filter(c=>!!c);l.length&&(s.parameters=l.map(I))}else a.length&&(s.parameters=a.map(i=>({name:i,description:i})))}else s.statement=t.statement;!t.statement&&t.commands?.length&&(s.commands=t.commands),s.description=t.description?.trim()||`Toolbox tool ${t.name}`,t.authRequired?.length&&(s.authRequired=t.authRequired),t.parameters?.length&&!s.parameters&&(s.parameters=t.parameters.map(I)),t.templateParameters?.length&&(s.templateParameters=t.templateParameters.map(I)),U(s,t.extra),r[j(e.sourceKey,t.name)]=s}const n={sources:{[e.sourceKey]:o}};return Object.keys(r).length&&(n.tools=r),`# AUTO-GENERATED by stkxp-app Sources \u2014 owner=${e.owner} source=${e.name}
|
|
4
|
+
# Edits here are overwritten on the next save. Manage via /account#sources.
|
|
5
|
+
${Q(n)}`}async function E(e){await y.mkdir(S,{recursive:!0});const o=P.join(S,e.yamlFileName);await y.writeFile(o,Z(e),"utf8")}async function ee(e){try{await y.unlink(P.join(S,e))}catch(o){if(o?.code!=="ENOENT")throw o}}function T(e){const o=D(e.slug),r=new Set((o?.fields||[]).filter(t=>t.secret).map(t=>t.name)),n={};for(const[t,s]of Object.entries(e.config||{}))n[t]=r.has(t)&&s?F:s;return{...e,config:n}}function b(){return new Date().toISOString()}async function he(e){return await K(),(await m.search({index:h,size:1e3,query:{term:{owner:e}},sort:[{created:{order:"desc"}}]})).hits.hits.map(r=>T({id:r._id,...r._source}))}async function k(e,o,r=!0){try{const n=await m.get({index:h,id:o}),t={id:n._id,...n._source};return t.owner!==e?null:r?T(t):t}catch(n){if(n?.meta?.statusCode===404)return null;throw n}}async function Se(e,o){await K();const r=D(o.slug);if(!r)throw new Error(`Unknown source type: ${o.slug}`);const n=A(e,o.name),t=o.fileName?.trim()||G(e,o.name),s=b(),a={id:"",owner:e,platformId:o.platformId,name:o.name,sourceKey:n,slug:r.slug,sourceType:r.sourceType,config:o.config||{},tools:[],yamlFileName:t,status:"pending",created:s,updated:s},{id:i,...l}=a,c=await m.index({index:h,document:l,refresh:!0});return a.id=c._id,await E(a),T(a)}async function xe(e,o,r){const n=await k(e,o,!1);if(!n)throw new Error("Source not found");const t=D(n.slug),s=new Set((t?.fields||[]).filter(l=>l.secret).map(l=>l.name)),a={...n.config};if(r.config)for(const[l,c]of Object.entries(r.config))s.has(l)&&c===F||(a[l]=c);const i={...n,name:r.name?.trim()||n.name,config:a,updated:b()};return await m.update({index:h,id:o,doc:{name:i.name,config:i.config,updated:i.updated},refresh:!0}),await E(i),T(i)}async function Te(e,o){const r=await k(e,o,!1);return r?(await ee(r.yamlFileName),await m.delete({index:h,id:o,refresh:!0}),!0):!1}async function te(e,o,r){const n=await k(e,o,!1);if(!n)throw new Error("Source not found");const t=(n.tools||[]).filter(s=>s.name!==r.name);return t.push(r),n.tools=t,n.updated=b(),await m.update({index:h,id:o,doc:{tools:t,updated:n.updated},refresh:!0}),await E(n),T(n)}function re(e){return W([...e.parameters||[],...e.templateParameters||[]])}async function be(e,o,r){const n=await te(e,o,r),t=j(n.sourceKey,r.name),s=b(),a={name:r.name,label:r.label||r.name,description:r.description||"",type:"mcp",source:"mcp-server",system:n.sourceKey,service:t,endpoint:t,httpMethod:"POST",inputSchema:JSON.stringify(re(r)),outputSchema:r.outputSchema||"{}",enabled:!0,owner:e,platformId:n.platformId,toolboxSourceId:o,createdAt:s,updatedAt:s,createdBy:e};let i=[];try{i=(await m.search({index:R,size:100,_source:!1,query:{bool:{filter:[{term:{owner:e}},{term:{service:t}}]}}})).hits.hits.map(g=>g._id)}catch{}if(i.length>0){const[c,...g]=i,{createdAt:_,createdBy:M,...v}=a;await m.update({index:R,id:c,doc:v,refresh:!0});for(const $ of g)try{await m.delete({index:R,id:$,refresh:!0})}catch{}return{source:n,tool:{id:c,...a}}}const l=await m.index({index:R,document:a,refresh:!0});return{source:n,tool:{id:l._id,...a}}}async function B(e){try{const r=(await m.get({index:".stkxp_platforms",id:e}))._source?.config;if(r?.url)return String(r.url).replace(/\/$/,"").replace(/\/mcp(\/sse)?$/,"")}catch{}return V}async function ke(e,o){const r=await k(e,o,!1);if(!r)throw new Error("Source not found");const n=await B(r.platformId);let t="error",s="";try{const a=new AbortController,i=setTimeout(()=>a.abort(),8e3),l=await fetch(`${n}/`,{signal:a.signal});clearTimeout(i),l.ok?(t="verified",s=r.tools.length?`Toolbox reachable; ${r.tools.length} tool(s) configured.`:"Toolbox reachable. Source installed \u2014 add tools via Create New Tool."):s=`Toolbox responded ${l.status} at ${n}/.`}catch(a){s=`Toolbox unreachable: ${a?.message||a}`}return r.status=t,r.statusMessage=s,r.updated=b(),await m.update({index:h,id:o,doc:{status:t,statusMessage:s,updated:r.updated},refresh:!0}),T(r)}function oe(e){return/^U?Int/i.test(e)?"integer":/^(Float|Double|Decimal)/i.test(e)?"number":/^Bool/i.test(e)?"boolean":"string"}function ne(e,o){const r={};for(const[n,t]of Object.entries(e)){const s=o.get(n);if(s==="integer"){const a=Number(t);r[n]=Number.isFinite(a)?Math.trunc(a):t}else if(s==="number"){const a=Number(t);r[n]=Number.isFinite(a)?a:t}else s==="boolean"?r[n]=t===!0||t==="true"||t==="1":r[n]=t}return r}function se(e,o){if(!/\{(\w+):(\w+)\}/g.test(e))return{resolvedStatement:e,resolved:!1};let n=e;for(const[t,s,a]of e.matchAll(/\{(\w+):(\w+)\}/g)){const i=o[s];if(i==null)continue;const l=/^(Int|UInt|Float|Decimal)/i.test(a);let c;if(l){const g=Number(i);c=Number.isFinite(g)?String(g):"0"}else c=`'${String(i).replace(/'/g,"''")}'`;n=n.replace(t,c)}return{resolvedStatement:n,resolved:!0}}function ae(e,o,r){const n=(t,s)=>({name:t,type:s,description:t});return e==="clickhouse-sql"?[]:/-esql$/.test(e)?[...new Set([...o.matchAll(/\?(\w+)/g)].map(([,s])=>s))].map(s=>n(s,"string")):Object.keys(r||{}).map(t=>n(t,"string"))}async function _e(e,o,r){const n=await k(e,o);if(!n)throw new Error("Source not found");try{await y.mkdir(S,{recursive:!0});const u=await y.readdir(S),w=Date.now()-120*1e3;await Promise.all(u.filter(p=>p.startsWith("_test_")&&p.endsWith(".yaml")).map(async p=>{const f=P.join(S,p);try{(await y.stat(f)).mtimeMs<w&&(await y.unlink(f),console.log(`[sources:test] removed stale temp file ${p}`))}catch{}}))}catch{}const t=`__test_${C().replace(/-/g,"").slice(0,16)}`,s=`_test_${C().replace(/-/g,"").slice(0,12)}.yaml`,a=P.join(S,s),i=/-esql$/.test(r.toolType),l=r.toolType==="clickhouse-sql";let c=r.statement??"",g=!1;if(l&&c.trim()){const{resolvedStatement:u,resolved:w}=se(c,r.params||{});w&&(c=u,g=!0)}const _=r.commands?.length?r.parameters?.length?r.parameters.map(u=>({name:u.name,type:u.type||"string",description:u.description||u.name})):Object.keys(r.params||{}).map(u=>({name:u,type:"string",description:u})):g?[]:ae(r.toolType,c,r.params),M=H({toolType:r.toolType,sourceKey:n.sourceKey,description:"Temporary test tool (auto-deleted)",statement:c,isEsql:i,commands:r.commands,parameters:_,extra:r.extra}),v=l?new Map([...r.statement?.matchAll(/\{(\w+):(\w+)\}/g)??[]].map(([,u,w])=>[u,oe(w)])):new Map(_.map(u=>[u.name,u.type])),$=O.dump({tools:{[t]:M}},{lineWidth:120}),L=`${await B(n.platformId)}/mcp`;await y.mkdir(S,{recursive:!0}),await y.writeFile(a,$,"utf8"),console.log(`[sources:test] wrote temp tool "${t}" to ${a}`),console.log(`[sources:test] MCP tool spec for "${t}" (source=${n.sourceKey}, type=${r.toolType}):`),console.log(`[sources:test] commands=${JSON.stringify(r.commands??null)} statement=${JSON.stringify(c||null)}`),console.log(`[sources:test] parameters=${JSON.stringify(_)}`),console.log(`[sources:test] temp YAML:
|
|
6
|
+
${$.trimEnd()}`);let d=null;try{const u=Date.now()+6e3;for(;Date.now()<u;){await new Promise(f=>setTimeout(f,600));try{if(d||(d=await Y(L,{timeout:5e3})),(await d.listTools()).includes(t))break}catch{if(d){try{await d.close()}catch{}d=null}}}if(!d)throw new Error("Toolbox MCP server unreachable during test");let w,p;for(let f=0;f<3;f++)try{const x=g?{}:ne(r.params||{},v);console.log(`[sources:test] \u2192 callTool "${t}" (attempt ${f+1}) args=${JSON.stringify(x)}`),w=await d.callTool(t,x),console.log(`[sources:test] \u2190 callTool "${t}" result=${JSON.stringify(w)}`),p=null;break}catch(x){if(p=x,!/does not exist|not found/i.test(x?.message||"")||f>=2)break;await new Promise(q=>setTimeout(q,500));try{if(!(await d.listTools()).includes(t))break}catch{break}}if(p)throw p;return{success:!0,data:w}}catch(u){return{success:!1,error:u?.message||String(u)}}finally{if(d)try{await d.close()}catch{}try{await y.unlink(a)}catch{}console.log(`[sources:test] cleaned up temp tool "${t}"`)}}export{V as DEFAULT_TOOLBOX_URL,S as TOOLBOX_CONFIG_FOLDER,H as assembleToolBlock,be as createSourceTool,Te as deleteSource,Q as dumpToolboxYaml,K as ensureSourcesIndex,k as getSource,Se as installSource,he as listSources,A as makeSourceKey,G as makeYamlFileName,U as mergeExtra,ke as pingSource,T as redactSource,Z as renderSourceYaml,_e as testSourceStatement,re as toolInputSchema,xe as updateSource,te as upsertSourceTool};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{getRunProgress as c}from"./team-run-progress";function i(e){if(!Array.isArray(e)||e.length===0)return;const n=[];for(const r of e){if(!r||typeof r!="object")continue;const s=typeof r.title=="string"?r.title.trim():"",o=typeof r.body=="string"?r.body.trim():typeof r.text=="string"?r.text.trim():"";s&&o?n.push(`${s}
|
|
2
|
+
${o}`):o?n.push(o):s&&n.push(s)}const t=n.join(`
|
|
3
|
+
|
|
4
|
+
`).trim();return t.length>0?t:void 0}function l(e){if(!Array.isArray(e))return{};const n=[...e].reverse().find(r=>r.role==="assistant");if(!n)return{};let t=n.content;if(typeof t=="string"){const r=t.trim();if(r.startsWith("[")||r.startsWith("{"))try{t=JSON.parse(r)}catch{}}if(Array.isArray(t))return{text:i(t),blocks:t};if(typeof t=="string")return{text:t,blocks:void 0};if(t&&typeof t=="object"){if(Array.isArray(t.blocks)||typeof t.text=="string"){const r=Array.isArray(t.blocks)?t.blocks:void 0;return{text:typeof t.text=="string"?t.text:i(r),blocks:r}}if(typeof t.type=="string")return{text:i([t]),blocks:[t]}}return{}}function g(e,n){let t;return e.status==="completed"?t=e.text??"Team run completed.":e.status==="error"?t=`Team run failed: ${e.error??"unknown error"}`:t=`The team run has started (runId=${e.runId}) and takes a couple of minutes. The interactive view above updates automatically when it finishes; no further action is needed. (To fetch it manually, call get_team_run with this runId.)`,{content:[{type:"text",text:t}],structuredContent:e,...n?{_meta:{ui:{resourceUri:n}}}:{},...e.status==="error"?{isError:!0}:{}}}const y="The team run view has been opened in the interactive card. Results will appear there automatically when the run finishes. Do not fabricate or summarise an answer yourself \u2014 the card renders the real result.";function d(e,n){return{content:[{type:"text",text:y}],structuredContent:{runToken:e.runToken,message:e.message,...e.context&&typeof e.context=="object"?{context:e.context}:{}},_meta:{ui:{resourceUri:n}}}}async function p(e,n,t){const r=await t.getChatRunByRunId(e);if(!r)return{runId:e,status:"running"};if(r.status==="error")return{runId:e,status:"error",error:r.errorMessage??"unknown error"};if(r.status==="running"){const a=c(e);return{runId:e,status:"running",text:a?.text,blocks:a?.blocks}}const s=await t.getChatById(r.chatId,n),{text:o,blocks:u}=l(s?.messages);return{runId:e,status:"completed",text:o,blocks:u}}export{y as ASK_OPEN_TEXT,i as deriveTextFromBlocks,l as extractTextAndBlocks,d as mapAskOpenToToolResult,g as mapRunResultToToolResult,p as readTeamRunResult};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const u=9e5,e=new Map;function d(t){for(const[n,r]of e)t-r.createdAt>9e5&&e.delete(n)}function a(t,n,r=()=>Date.now()){const o=r(),s=e.get(t);if(s&&o-s.createdAt<=9e5)return{entry:s,isNew:!1};const i=n(),c={runId:i.runId,chatId:i.chatId,createdAt:o};return e.set(t,c),e.size>200&&d(o),{entry:c,isNew:!0}}function f(t){t&&e.delete(t)}export{f as clearRunToken,a as getOrReserveRunToken};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{randomUUID as m}from"crypto";import{createChat as I}from"./chats-service";import{createChatRun as h}from"./chat-runs-service";import{runTeamHeadless as g}from"./team-runner-headless";import{getOrReserveRunToken as p,clearRunToken as f}from"./team-mcp-run-tokens";async function d(r){const{teamId:n,message:a,context:t,team:e,runId:s,chatId:o}=r,c=e.owner??"unknown",i={message:a,...t&&typeof t=="object"?{context:t}:{},teamContext:{teamId:n,chatId:o,name:e.name}};await I({id:o,title:`${e.name??n} \xB7 MCP`,teamId:n,teamName:e.name,status:"draft",messages:[],assistants:[],metadata:{source:"mcp",mcpMessage:String(a).slice(0,2e3)},username:c}),await h(s,o,c,{teamId:n,teamName:e.name,assistantId:"__mcp_pending__",assistantName:"MCP run (running\u2026)",graphId:e.graphId,userMessage:String(a).slice(0,2e3),source:"mcp"}),setImmediate(()=>{g({teamId:n,runId:s,chatId:o,payload:i,depth:0,channel:"mcp"}).catch(u=>{console.error(`[MCP-Team] Unexpected throw from runTeamHeadless (runId=${s}):`,u)})})}async function C(r){if(r.runToken){const{entry:t,isNew:e}=p(r.runToken,()=>({runId:m(),chatId:m()}));if(!e)return{runId:t.runId,chatId:t.chatId};try{await d({...r,runId:t.runId,chatId:t.chatId})}catch(s){throw f(r.runToken),s}return{runId:t.runId,chatId:t.chatId}}const n=m(),a=m();return await d({...r,runId:n,chatId:a}),{runId:n,chatId:a}}export{C as startMcpTeamRun};
|