mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-07-01 09:29:38 +02:00
fix: NATS pipeline bugs, add integration tests and service runners
Fix three critical bugs preventing the NATS message pipeline from working: - FlowProcessor now subscribes to config-push topic (was missing entirely), using DeliverPolicy.All to replay config on service restart - NATS streams use wildcard subjects (tg.flow.>) instead of per-topic narrow filters that caused 503 errors on publish - Subscriber dispatch loop has exponential backoff on errors to prevent tight error loops Add service runner scripts (gateway, config, LLM) and a 7-test integration suite that verifies config CRUD, WebSocket round-trip, and full LLM text-completion through the NATS pipeline. Fix Docker Compose infra: pin Tempo to v2.6.1, remove deprecated Loki config fields, add user:0 for volume permissions, remap conflicting ports (FalkorDB 6380, OTLP 4327/4328). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0042f9259c
commit
28747e1a92
15 changed files with 826 additions and 107 deletions
|
|
@ -42,7 +42,7 @@ services:
|
|||
falkordb:
|
||||
image: falkordb/falkordb:latest
|
||||
ports:
|
||||
- "6379:6379"
|
||||
- "6380:6379"
|
||||
volumes:
|
||||
- falkordb-data:/data
|
||||
networks:
|
||||
|
|
@ -111,6 +111,7 @@ services:
|
|||
|
||||
loki:
|
||||
image: grafana/loki:3.0.0
|
||||
user: "0"
|
||||
ports:
|
||||
- "3100:3100"
|
||||
volumes:
|
||||
|
|
@ -128,12 +129,13 @@ services:
|
|||
restart: unless-stopped
|
||||
|
||||
tempo:
|
||||
image: grafana/tempo:latest
|
||||
image: grafana/tempo:2.6.1
|
||||
user: "0"
|
||||
ports:
|
||||
- "3200:3200" # Tempo API
|
||||
volumes:
|
||||
- ./tempo/tempo-config.yml:/etc/tempo/config.yml:ro
|
||||
- tempo-data:/tmp/tempo
|
||||
- tempo-data:/var/tempo
|
||||
command: ["-config.file=/etc/tempo/config.yml"]
|
||||
networks:
|
||||
- trustgraph
|
||||
|
|
@ -148,8 +150,8 @@ services:
|
|||
otel-collector:
|
||||
image: otel/opentelemetry-collector-contrib:latest
|
||||
ports:
|
||||
- "4317:4317" # OTLP gRPC (apps send traces/metrics here)
|
||||
- "4318:4318" # OTLP HTTP
|
||||
- "4327:4317" # OTLP gRPC (apps send traces/metrics here)
|
||||
- "4328:4318" # OTLP HTTP
|
||||
- "8889:8889" # Prometheus exporter (scraped by Prometheus)
|
||||
volumes:
|
||||
- ./otel-collector/config.yml:/etc/otelcol-contrib/config.yaml:ro
|
||||
|
|
|
|||
|
|
@ -24,9 +24,6 @@ query_range:
|
|||
enabled: true
|
||||
max_size_mb: 100
|
||||
|
||||
limits_config:
|
||||
metric_aggregation_enabled: true
|
||||
|
||||
schema_config:
|
||||
configs:
|
||||
- from: 2024-01-01
|
||||
|
|
@ -37,16 +34,8 @@ schema_config:
|
|||
prefix: index_
|
||||
period: 24h
|
||||
|
||||
pattern_ingester:
|
||||
enabled: true
|
||||
metric_aggregation:
|
||||
loki_address: localhost:3100
|
||||
|
||||
ruler:
|
||||
alertmanager_url: http://localhost:9093
|
||||
|
||||
frontend:
|
||||
encoding: protobuf
|
||||
|
||||
analytics:
|
||||
reporting_enabled: false
|
||||
|
|
|
|||
|
|
@ -17,33 +17,10 @@ compactor:
|
|||
compaction:
|
||||
block_retention: 48h
|
||||
|
||||
metrics_generator:
|
||||
registry:
|
||||
external_labels:
|
||||
source: tempo
|
||||
cluster: trustgraph-dev
|
||||
storage:
|
||||
path: /tmp/tempo/generator/wal
|
||||
remote_write:
|
||||
- url: http://prometheus:9090/api/v1/write
|
||||
send_exemplars: true
|
||||
|
||||
storage:
|
||||
trace:
|
||||
backend: local
|
||||
wal:
|
||||
path: /tmp/tempo/wal
|
||||
path: /var/tempo/wal
|
||||
local:
|
||||
path: /tmp/tempo/blocks
|
||||
|
||||
overrides:
|
||||
defaults:
|
||||
metrics_generator:
|
||||
processors:
|
||||
- service-graphs
|
||||
- span-metrics
|
||||
|
||||
search_enabled: true
|
||||
|
||||
analytics:
|
||||
reporting_enabled: false
|
||||
path: /var/tempo/blocks
|
||||
|
|
|
|||
|
|
@ -6,9 +6,15 @@
|
|||
"dev": "turbo dev",
|
||||
"lint": "turbo lint",
|
||||
"test": "turbo test",
|
||||
"clean": "turbo clean"
|
||||
"clean": "turbo clean",
|
||||
"gateway": "tsx scripts/run-gateway.ts",
|
||||
"config-svc": "tsx scripts/run-config.ts",
|
||||
"llm:claude": "tsx scripts/run-llm-claude.ts",
|
||||
"llm:openai": "tsx scripts/run-llm-openai.ts",
|
||||
"test:pipeline": "tsx scripts/test-pipeline.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tsx": "^4.21.0",
|
||||
"turbo": "^2.5.0",
|
||||
"typescript": "^5.8.0"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -98,38 +98,28 @@ class NatsConsumer<T> implements BackendConsumer<T> {
|
|||
private readonly subject: string,
|
||||
private readonly subscription: string,
|
||||
private readonly initialPosition: "latest" | "earliest",
|
||||
private readonly streamName: string,
|
||||
) {}
|
||||
|
||||
async init(): Promise<void> {
|
||||
// Ensure stream exists
|
||||
const streamName = this.streamNameFromSubject(this.subject);
|
||||
try {
|
||||
await this.jsm.streams.info(streamName);
|
||||
} catch {
|
||||
await this.jsm.streams.add({
|
||||
name: streamName,
|
||||
subjects: [this.subject],
|
||||
});
|
||||
}
|
||||
|
||||
// Stream is already ensured by NatsBackend.ensureStream().
|
||||
// Create or bind to durable consumer.
|
||||
// Try to get an existing durable consumer first; if it doesn't exist, create it.
|
||||
try {
|
||||
this.consumer = await this.js.consumers.get(streamName, this.subscription);
|
||||
this.consumer = await this.js.consumers.get(this.streamName, this.subscription);
|
||||
} catch {
|
||||
const deliverPolicy =
|
||||
this.initialPosition === "earliest"
|
||||
? DeliverPolicy.All
|
||||
: DeliverPolicy.New;
|
||||
|
||||
await this.jsm.consumers.add(streamName, {
|
||||
await this.jsm.consumers.add(this.streamName, {
|
||||
durable_name: this.subscription,
|
||||
ack_policy: AckPolicy.Explicit,
|
||||
deliver_policy: deliverPolicy,
|
||||
filter_subject: this.subject,
|
||||
});
|
||||
|
||||
this.consumer = await this.js.consumers.get(streamName, this.subscription);
|
||||
this.consumer = await this.js.consumers.get(this.streamName, this.subscription);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -164,18 +154,13 @@ class NatsConsumer<T> implements BackendConsumer<T> {
|
|||
async close(): Promise<void> {
|
||||
this.consumer = null;
|
||||
}
|
||||
|
||||
private streamNameFromSubject(subject: string): string {
|
||||
// Convert topic like "tg.flow.text-completion" to stream name "tg_flow"
|
||||
const parts = subject.split(".");
|
||||
return parts.slice(0, 2).join("_");
|
||||
}
|
||||
}
|
||||
|
||||
export class NatsBackend implements PubSubBackend {
|
||||
private connection: NatsConnection | null = null;
|
||||
private js: JetStreamClient | null = null;
|
||||
private jsm: JetStreamManager | null = null;
|
||||
private initializedStreams = new Set<string>();
|
||||
|
||||
constructor(private readonly url: string = "nats://localhost:4222") {}
|
||||
|
||||
|
|
@ -187,19 +172,46 @@ export class NatsBackend implements PubSubBackend {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the stream for a given subject exists with a wildcard filter.
|
||||
* E.g. subject "tg.flow.config-request" → stream "tg_flow" with subjects ["tg.flow.>"]
|
||||
*/
|
||||
private async ensureStream(subject: string): Promise<string> {
|
||||
const parts = subject.split(".");
|
||||
const streamName = parts.slice(0, 2).join("_");
|
||||
|
||||
if (this.initializedStreams.has(streamName)) return streamName;
|
||||
|
||||
const wildcardSubject = `${parts.slice(0, 2).join(".")}.>`;
|
||||
|
||||
try {
|
||||
await this.jsm!.streams.info(streamName);
|
||||
} catch {
|
||||
await this.jsm!.streams.add({
|
||||
name: streamName,
|
||||
subjects: [wildcardSubject],
|
||||
});
|
||||
}
|
||||
this.initializedStreams.add(streamName);
|
||||
return streamName;
|
||||
}
|
||||
|
||||
async createProducer<T>(options: CreateProducerOptions): Promise<BackendProducer<T>> {
|
||||
await this.ensureConnected();
|
||||
await this.ensureStream(options.topic);
|
||||
return new NatsProducer<T>(this.js!, options.topic);
|
||||
}
|
||||
|
||||
async createConsumer<T>(options: CreateConsumerOptions): Promise<BackendConsumer<T>> {
|
||||
await this.ensureConnected();
|
||||
const streamName = await this.ensureStream(options.topic);
|
||||
const consumer = new NatsConsumer<T>(
|
||||
this.js!,
|
||||
this.jsm!,
|
||||
options.topic,
|
||||
options.subscription,
|
||||
options.initialPosition ?? "latest",
|
||||
streamName,
|
||||
);
|
||||
await consumer.init();
|
||||
return consumer;
|
||||
|
|
|
|||
|
|
@ -111,11 +111,14 @@ export class Subscriber<T> {
|
|||
}
|
||||
|
||||
private async dispatchLoop(): Promise<void> {
|
||||
let consecutiveErrors = 0;
|
||||
while (this.running) {
|
||||
try {
|
||||
const msg = await this.backend!.receive(2000);
|
||||
if (!msg) continue;
|
||||
|
||||
consecutiveErrors = 0;
|
||||
|
||||
const props = msg.properties();
|
||||
const id = props.id;
|
||||
const value = msg.value();
|
||||
|
|
@ -136,7 +139,15 @@ export class Subscriber<T> {
|
|||
await this.backend!.acknowledge(msg);
|
||||
} catch (err) {
|
||||
if (!this.running) break;
|
||||
console.error("[Subscriber] Error:", err);
|
||||
consecutiveErrors++;
|
||||
if (consecutiveErrors <= 3) {
|
||||
console.error("[Subscriber] Error:", err);
|
||||
} else if (consecutiveErrors === 4) {
|
||||
console.error("[Subscriber] Suppressing further errors (will retry with backoff)");
|
||||
}
|
||||
// Exponential backoff: 1s, 2s, 4s, max 10s
|
||||
const delay = Math.min(1000 * Math.pow(2, consecutiveErrors - 1), 10_000);
|
||||
await new Promise((r) => setTimeout(r, delay));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ export type ConfigHandler = (
|
|||
export abstract class AsyncProcessor {
|
||||
protected pubsub: PubSubBackend;
|
||||
protected running = false;
|
||||
private configHandlers: ConfigHandler[] = [];
|
||||
protected configHandlers: ConfigHandler[] = [];
|
||||
private shutdownCallbacks: Array<() => Promise<void>> = [];
|
||||
|
||||
constructor(protected readonly config: ProcessorConfig) {
|
||||
|
|
|
|||
|
|
@ -1,20 +1,30 @@
|
|||
/**
|
||||
* Flow-aware processor that manages dynamic flow instances.
|
||||
*
|
||||
* Subscribes to config-push topic and dynamically creates/destroys
|
||||
* flow instances based on the configuration received.
|
||||
*
|
||||
* Python reference: trustgraph-base/trustgraph/base/flow_processor.py
|
||||
*/
|
||||
|
||||
import { AsyncProcessor, type ProcessorConfig } from "./async-processor.js";
|
||||
import type { Spec } from "../spec/types.js";
|
||||
import type { BackendConsumer } from "../backend/types.js";
|
||||
import { Flow, type FlowDefinition } from "./flow.js";
|
||||
import { topics } from "../schema/topics.js";
|
||||
|
||||
interface ConfigPush {
|
||||
version: number;
|
||||
config: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export abstract class FlowProcessor extends AsyncProcessor {
|
||||
private specifications: Spec[] = [];
|
||||
private flows = new Map<string, Flow>();
|
||||
private configConsumer: BackendConsumer<ConfigPush> | null = null;
|
||||
|
||||
constructor(config: ProcessorConfig) {
|
||||
super(config);
|
||||
this.registerConfigHandler(this.onConfigureFlows.bind(this));
|
||||
}
|
||||
|
||||
registerSpecification(spec: Spec): void {
|
||||
|
|
@ -22,16 +32,38 @@ export abstract class FlowProcessor extends AsyncProcessor {
|
|||
}
|
||||
|
||||
protected async run(): Promise<void> {
|
||||
// The processor sits idle waiting for flow configurations
|
||||
// to arrive via the config push topic. In the meantime,
|
||||
// the consumer loop runs in the background.
|
||||
await new Promise<void>((resolve) => {
|
||||
const check = () => {
|
||||
if (!this.running) resolve();
|
||||
else setTimeout(check, 1000);
|
||||
};
|
||||
check();
|
||||
// Subscribe to config-push topic to receive flow definitions.
|
||||
// Use "earliest" to replay any config pushes that arrived before this service started.
|
||||
this.configConsumer = await this.pubsub.createConsumer<ConfigPush>({
|
||||
topic: topics.configPush,
|
||||
subscription: `${this.config.id}-config-push`,
|
||||
initialPosition: "earliest",
|
||||
});
|
||||
|
||||
console.log(`[${this.config.id}] Listening for config pushes on ${topics.configPush}`);
|
||||
|
||||
while (this.running) {
|
||||
try {
|
||||
const msg = await this.configConsumer.receive(2000);
|
||||
if (!msg) continue;
|
||||
|
||||
const push = msg.value();
|
||||
console.log(`[${this.config.id}] Received config push version=${push.version}`);
|
||||
|
||||
await this.onConfigureFlows(push.config, push.version);
|
||||
|
||||
// Also call any registered config handlers
|
||||
for (const handler of this.configHandlers) {
|
||||
await handler(push.config, push.version);
|
||||
}
|
||||
|
||||
await this.configConsumer.acknowledge(msg);
|
||||
} catch (err) {
|
||||
if (!this.running) break;
|
||||
console.error(`[${this.config.id}] Config consumer error:`, err);
|
||||
await sleep(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async onConfigureFlows(
|
||||
|
|
@ -39,27 +71,43 @@ export abstract class FlowProcessor extends AsyncProcessor {
|
|||
version: number,
|
||||
): Promise<void> {
|
||||
const flowDefs = config.flows as Record<string, FlowDefinition> | undefined;
|
||||
if (!flowDefs) return;
|
||||
if (!flowDefs) {
|
||||
console.log(`[${this.config.id}] No flows in config push, skipping`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop removed flows
|
||||
for (const [name, flow] of this.flows) {
|
||||
if (!(name in flowDefs)) {
|
||||
console.log(`[${this.config.id}] Stopping removed flow: ${name}`);
|
||||
await flow.stop();
|
||||
this.flows.delete(name);
|
||||
}
|
||||
}
|
||||
|
||||
// Start new flows
|
||||
// Start or update flows
|
||||
for (const [name, defn] of Object.entries(flowDefs)) {
|
||||
// Skip invalid definitions (e.g., stringified JSON)
|
||||
if (typeof defn !== "object" || defn === null) {
|
||||
console.warn(`[${this.config.id}] Skipping flow "${name}": definition is not an object`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!this.flows.has(name)) {
|
||||
console.log(`[${this.config.id}] Starting flow "${name}" with topics:`, defn.topics);
|
||||
const flow = new Flow(name, this.config.id, this.pubsub, defn, this.specifications);
|
||||
await flow.start();
|
||||
this.flows.set(name, flow);
|
||||
console.log(`[${this.config.id}] Flow "${name}" started`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override async stop(): Promise<void> {
|
||||
if (this.configConsumer) {
|
||||
await this.configConsumer.close();
|
||||
this.configConsumer = null;
|
||||
}
|
||||
for (const flow of this.flows.values()) {
|
||||
await flow.stop();
|
||||
}
|
||||
|
|
@ -67,3 +115,7 @@ export abstract class FlowProcessor extends AsyncProcessor {
|
|||
await super.stop();
|
||||
}
|
||||
}
|
||||
|
||||
function sleep(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
|
|
|||
357
ts/pnpm-lock.yaml
generated
357
ts/pnpm-lock.yaml
generated
|
|
@ -8,6 +8,9 @@ importers:
|
|||
|
||||
.:
|
||||
devDependencies:
|
||||
tsx:
|
||||
specifier: ^4.21.0
|
||||
version: 4.21.0
|
||||
turbo:
|
||||
specifier: ^2.5.0
|
||||
version: 2.9.4
|
||||
|
|
@ -32,7 +35,7 @@ importers:
|
|||
version: 5.9.3
|
||||
vitest:
|
||||
specifier: ^3.1.0
|
||||
version: 3.2.4(@types/debug@4.1.13)(@types/node@22.19.17)(happy-dom@20.8.9)(jiti@2.6.1)(lightningcss@1.32.0)
|
||||
version: 3.2.4(@types/debug@4.1.13)(@types/node@22.19.17)(happy-dom@20.8.9)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)
|
||||
|
||||
packages/cli:
|
||||
dependencies:
|
||||
|
|
@ -57,7 +60,7 @@ importers:
|
|||
version: 5.9.3
|
||||
vitest:
|
||||
specifier: ^3.1.0
|
||||
version: 3.2.4(@types/debug@4.1.13)(@types/node@25.5.2)(happy-dom@20.8.9)(jiti@2.6.1)(lightningcss@1.32.0)
|
||||
version: 3.2.4(@types/debug@4.1.13)(@types/node@25.5.2)(happy-dom@20.8.9)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)
|
||||
|
||||
packages/client:
|
||||
dependencies:
|
||||
|
|
@ -79,7 +82,7 @@ importers:
|
|||
version: 5.9.3
|
||||
vitest:
|
||||
specifier: ^3.1.0
|
||||
version: 3.2.4(@types/debug@4.1.13)(@types/node@22.19.17)(happy-dom@20.8.9)(jiti@2.6.1)(lightningcss@1.32.0)
|
||||
version: 3.2.4(@types/debug@4.1.13)(@types/node@22.19.17)(happy-dom@20.8.9)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)
|
||||
|
||||
packages/flow:
|
||||
dependencies:
|
||||
|
|
@ -110,7 +113,7 @@ importers:
|
|||
version: 5.9.3
|
||||
vitest:
|
||||
specifier: ^3.1.0
|
||||
version: 3.2.4(@types/debug@4.1.13)(@types/node@25.5.2)(happy-dom@20.8.9)(jiti@2.6.1)(lightningcss@1.32.0)
|
||||
version: 3.2.4(@types/debug@4.1.13)(@types/node@25.5.2)(happy-dom@20.8.9)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)
|
||||
|
||||
packages/mcp:
|
||||
dependencies:
|
||||
|
|
@ -135,7 +138,7 @@ importers:
|
|||
version: 5.9.3
|
||||
vitest:
|
||||
specifier: ^3.1.0
|
||||
version: 3.2.4(@types/debug@4.1.13)(@types/node@22.19.17)(happy-dom@20.8.9)(jiti@2.6.1)(lightningcss@1.32.0)
|
||||
version: 3.2.4(@types/debug@4.1.13)(@types/node@22.19.17)(happy-dom@20.8.9)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)
|
||||
|
||||
packages/workbench:
|
||||
dependencies:
|
||||
|
|
@ -178,7 +181,7 @@ importers:
|
|||
devDependencies:
|
||||
'@tailwindcss/vite':
|
||||
specifier: ^4.1.0
|
||||
version: 4.2.2(vite@6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0))
|
||||
version: 4.2.2(vite@6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0))
|
||||
'@types/react':
|
||||
specifier: ^19.1.0
|
||||
version: 19.2.14
|
||||
|
|
@ -187,7 +190,7 @@ importers:
|
|||
version: 19.2.3(@types/react@19.2.14)
|
||||
'@vitejs/plugin-react':
|
||||
specifier: ^4.5.0
|
||||
version: 4.7.0(vite@6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0))
|
||||
version: 4.7.0(vite@6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0))
|
||||
tailwindcss:
|
||||
specifier: ^4.1.0
|
||||
version: 4.2.2
|
||||
|
|
@ -196,7 +199,7 @@ importers:
|
|||
version: 5.9.3
|
||||
vite:
|
||||
specifier: ^6.3.0
|
||||
version: 6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)
|
||||
version: 6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)
|
||||
|
||||
packages:
|
||||
|
||||
|
|
@ -292,156 +295,312 @@ packages:
|
|||
cpu: [ppc64]
|
||||
os: [aix]
|
||||
|
||||
'@esbuild/aix-ppc64@0.27.7':
|
||||
resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [aix]
|
||||
|
||||
'@esbuild/android-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm@0.25.12':
|
||||
resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm@0.27.7':
|
||||
resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-x64@0.25.12':
|
||||
resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-x64@0.27.7':
|
||||
resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/darwin-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-x64@0.25.12':
|
||||
resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-x64@0.27.7':
|
||||
resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/freebsd-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-x64@0.25.12':
|
||||
resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-x64@0.27.7':
|
||||
resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/linux-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm@0.25.12':
|
||||
resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm@0.27.7':
|
||||
resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ia32@0.25.12':
|
||||
resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ia32@0.27.7':
|
||||
resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-loong64@0.25.12':
|
||||
resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-loong64@0.27.7':
|
||||
resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-mips64el@0.25.12':
|
||||
resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-mips64el@0.27.7':
|
||||
resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ppc64@0.25.12':
|
||||
resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ppc64@0.27.7':
|
||||
resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-riscv64@0.25.12':
|
||||
resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-riscv64@0.27.7':
|
||||
resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-s390x@0.25.12':
|
||||
resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-s390x@0.27.7':
|
||||
resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-x64@0.25.12':
|
||||
resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-x64@0.27.7':
|
||||
resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/netbsd-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/netbsd-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/netbsd-x64@0.25.12':
|
||||
resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/netbsd-x64@0.27.7':
|
||||
resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/openbsd-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-x64@0.25.12':
|
||||
resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-x64@0.27.7':
|
||||
resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openharmony-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@esbuild/openharmony-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@esbuild/sunos-x64@0.25.12':
|
||||
resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
|
||||
'@esbuild/sunos-x64@0.27.7':
|
||||
resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
|
||||
'@esbuild/win32-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-ia32@0.25.12':
|
||||
resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-ia32@0.27.7':
|
||||
resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-x64@0.25.12':
|
||||
resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-x64@0.27.7':
|
||||
resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@falkordb/client@1.6.0':
|
||||
resolution: {integrity: sha512-uZfP3/Ialejan9pLwIKXxqJoQtZaUqWwPVvdUVSFvQU4nQCAHLNxgmKUMHHqI7EckXqRmkY53SzTH2EvSZ50wQ==}
|
||||
engines: {node: '>=14'}
|
||||
|
|
@ -1220,6 +1379,11 @@ packages:
|
|||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
esbuild@0.27.7:
|
||||
resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
escalade@3.2.0:
|
||||
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
|
||||
engines: {node: '>=6'}
|
||||
|
|
@ -1361,6 +1525,9 @@ packages:
|
|||
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
get-tsconfig@4.13.7:
|
||||
resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==}
|
||||
|
||||
gopd@1.2.0:
|
||||
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
|
@ -1922,6 +2089,9 @@ packages:
|
|||
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
resolve-pkg-maps@1.0.0:
|
||||
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
|
||||
|
||||
ret@0.5.0:
|
||||
resolution: {integrity: sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==}
|
||||
engines: {node: '>=10'}
|
||||
|
|
@ -2113,6 +2283,11 @@ packages:
|
|||
trough@2.2.0:
|
||||
resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==}
|
||||
|
||||
tsx@4.21.0:
|
||||
resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
hasBin: true
|
||||
|
||||
turbo@2.9.4:
|
||||
resolution: {integrity: sha512-wZ/kMcZCuK5oEp7sXSSo/5fzKjP9I2EhoiarZjyCm2Ixk0WxFrC/h0gF3686eHHINoFQOOSWgB/pGfvkR8rkgQ==}
|
||||
hasBin: true
|
||||
|
|
@ -2459,81 +2634,159 @@ snapshots:
|
|||
'@esbuild/aix-ppc64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/aix-ppc64@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm64@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-x64@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-arm64@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-x64@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-arm64@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-x64@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm64@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ia32@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ia32@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-loong64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-loong64@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-mips64el@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-mips64el@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ppc64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ppc64@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-riscv64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-riscv64@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-s390x@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-s390x@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-x64@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-arm64@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-x64@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-arm64@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-x64@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openharmony-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openharmony-arm64@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/sunos-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/sunos-x64@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-arm64@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-ia32@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-ia32@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-x64@0.27.7':
|
||||
optional: true
|
||||
|
||||
'@falkordb/client@1.6.0':
|
||||
dependencies:
|
||||
cluster-key-slot: 1.1.2
|
||||
|
|
@ -2771,12 +3024,12 @@ snapshots:
|
|||
'@tailwindcss/oxide-win32-arm64-msvc': 4.2.2
|
||||
'@tailwindcss/oxide-win32-x64-msvc': 4.2.2
|
||||
|
||||
'@tailwindcss/vite@4.2.2(vite@6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0))':
|
||||
'@tailwindcss/vite@4.2.2(vite@6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0))':
|
||||
dependencies:
|
||||
'@tailwindcss/node': 4.2.2
|
||||
'@tailwindcss/oxide': 4.2.2
|
||||
tailwindcss: 4.2.2
|
||||
vite: 6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)
|
||||
vite: 6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)
|
||||
|
||||
'@tanstack/query-core@5.96.2': {}
|
||||
|
||||
|
|
@ -2891,7 +3144,7 @@ snapshots:
|
|||
|
||||
'@ungap/structured-clone@1.3.0': {}
|
||||
|
||||
'@vitejs/plugin-react@4.7.0(vite@6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0))':
|
||||
'@vitejs/plugin-react@4.7.0(vite@6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0))':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0)
|
||||
|
|
@ -2899,7 +3152,7 @@ snapshots:
|
|||
'@rolldown/pluginutils': 1.0.0-beta.27
|
||||
'@types/babel__core': 7.20.5
|
||||
react-refresh: 0.17.0
|
||||
vite: 6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)
|
||||
vite: 6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
|
|
@ -2911,21 +3164,21 @@ snapshots:
|
|||
chai: 5.3.3
|
||||
tinyrainbow: 2.0.0
|
||||
|
||||
'@vitest/mocker@3.2.4(vite@6.4.1(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0))':
|
||||
'@vitest/mocker@3.2.4(vite@6.4.1(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0))':
|
||||
dependencies:
|
||||
'@vitest/spy': 3.2.4
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 0.30.21
|
||||
optionalDependencies:
|
||||
vite: 6.4.1(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0)
|
||||
vite: 6.4.1(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)
|
||||
|
||||
'@vitest/mocker@3.2.4(vite@6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0))':
|
||||
'@vitest/mocker@3.2.4(vite@6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0))':
|
||||
dependencies:
|
||||
'@vitest/spy': 3.2.4
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 0.30.21
|
||||
optionalDependencies:
|
||||
vite: 6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)
|
||||
vite: 6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)
|
||||
|
||||
'@vitest/pretty-format@3.2.4':
|
||||
dependencies:
|
||||
|
|
@ -3278,6 +3531,35 @@ snapshots:
|
|||
'@esbuild/win32-ia32': 0.25.12
|
||||
'@esbuild/win32-x64': 0.25.12
|
||||
|
||||
esbuild@0.27.7:
|
||||
optionalDependencies:
|
||||
'@esbuild/aix-ppc64': 0.27.7
|
||||
'@esbuild/android-arm': 0.27.7
|
||||
'@esbuild/android-arm64': 0.27.7
|
||||
'@esbuild/android-x64': 0.27.7
|
||||
'@esbuild/darwin-arm64': 0.27.7
|
||||
'@esbuild/darwin-x64': 0.27.7
|
||||
'@esbuild/freebsd-arm64': 0.27.7
|
||||
'@esbuild/freebsd-x64': 0.27.7
|
||||
'@esbuild/linux-arm': 0.27.7
|
||||
'@esbuild/linux-arm64': 0.27.7
|
||||
'@esbuild/linux-ia32': 0.27.7
|
||||
'@esbuild/linux-loong64': 0.27.7
|
||||
'@esbuild/linux-mips64el': 0.27.7
|
||||
'@esbuild/linux-ppc64': 0.27.7
|
||||
'@esbuild/linux-riscv64': 0.27.7
|
||||
'@esbuild/linux-s390x': 0.27.7
|
||||
'@esbuild/linux-x64': 0.27.7
|
||||
'@esbuild/netbsd-arm64': 0.27.7
|
||||
'@esbuild/netbsd-x64': 0.27.7
|
||||
'@esbuild/openbsd-arm64': 0.27.7
|
||||
'@esbuild/openbsd-x64': 0.27.7
|
||||
'@esbuild/openharmony-arm64': 0.27.7
|
||||
'@esbuild/sunos-x64': 0.27.7
|
||||
'@esbuild/win32-arm64': 0.27.7
|
||||
'@esbuild/win32-ia32': 0.27.7
|
||||
'@esbuild/win32-x64': 0.27.7
|
||||
|
||||
escalade@3.2.0: {}
|
||||
|
||||
escape-html@1.0.3: {}
|
||||
|
|
@ -3479,6 +3761,10 @@ snapshots:
|
|||
dunder-proto: 1.0.1
|
||||
es-object-atoms: 1.1.1
|
||||
|
||||
get-tsconfig@4.13.7:
|
||||
dependencies:
|
||||
resolve-pkg-maps: 1.0.0
|
||||
|
||||
gopd@1.2.0: {}
|
||||
|
||||
graceful-fs@4.2.11: {}
|
||||
|
|
@ -4141,6 +4427,8 @@ snapshots:
|
|||
|
||||
require-from-string@2.0.2: {}
|
||||
|
||||
resolve-pkg-maps@1.0.0: {}
|
||||
|
||||
ret@0.5.0: {}
|
||||
|
||||
reusify@1.1.0: {}
|
||||
|
|
@ -4351,6 +4639,13 @@ snapshots:
|
|||
|
||||
trough@2.2.0: {}
|
||||
|
||||
tsx@4.21.0:
|
||||
dependencies:
|
||||
esbuild: 0.27.7
|
||||
get-tsconfig: 4.13.7
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
|
||||
turbo@2.9.4:
|
||||
optionalDependencies:
|
||||
'@turbo/darwin-64': 2.9.4
|
||||
|
|
@ -4434,13 +4729,13 @@ snapshots:
|
|||
'@types/unist': 3.0.3
|
||||
vfile-message: 4.0.3
|
||||
|
||||
vite-node@3.2.4(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0):
|
||||
vite-node@3.2.4(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0):
|
||||
dependencies:
|
||||
cac: 6.7.14
|
||||
debug: 4.4.3
|
||||
es-module-lexer: 1.7.0
|
||||
pathe: 2.0.3
|
||||
vite: 6.4.1(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0)
|
||||
vite: 6.4.1(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- jiti
|
||||
|
|
@ -4455,13 +4750,13 @@ snapshots:
|
|||
- tsx
|
||||
- yaml
|
||||
|
||||
vite-node@3.2.4(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0):
|
||||
vite-node@3.2.4(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0):
|
||||
dependencies:
|
||||
cac: 6.7.14
|
||||
debug: 4.4.3
|
||||
es-module-lexer: 1.7.0
|
||||
pathe: 2.0.3
|
||||
vite: 6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)
|
||||
vite: 6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- jiti
|
||||
|
|
@ -4476,7 +4771,7 @@ snapshots:
|
|||
- tsx
|
||||
- yaml
|
||||
|
||||
vite@6.4.1(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0):
|
||||
vite@6.4.1(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0):
|
||||
dependencies:
|
||||
esbuild: 0.25.12
|
||||
fdir: 6.5.0(picomatch@4.0.4)
|
||||
|
|
@ -4489,8 +4784,9 @@ snapshots:
|
|||
fsevents: 2.3.3
|
||||
jiti: 2.6.1
|
||||
lightningcss: 1.32.0
|
||||
tsx: 4.21.0
|
||||
|
||||
vite@6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0):
|
||||
vite@6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0):
|
||||
dependencies:
|
||||
esbuild: 0.25.12
|
||||
fdir: 6.5.0(picomatch@4.0.4)
|
||||
|
|
@ -4503,12 +4799,13 @@ snapshots:
|
|||
fsevents: 2.3.3
|
||||
jiti: 2.6.1
|
||||
lightningcss: 1.32.0
|
||||
tsx: 4.21.0
|
||||
|
||||
vitest@3.2.4(@types/debug@4.1.13)(@types/node@22.19.17)(happy-dom@20.8.9)(jiti@2.6.1)(lightningcss@1.32.0):
|
||||
vitest@3.2.4(@types/debug@4.1.13)(@types/node@22.19.17)(happy-dom@20.8.9)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0):
|
||||
dependencies:
|
||||
'@types/chai': 5.2.3
|
||||
'@vitest/expect': 3.2.4
|
||||
'@vitest/mocker': 3.2.4(vite@6.4.1(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0))
|
||||
'@vitest/mocker': 3.2.4(vite@6.4.1(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0))
|
||||
'@vitest/pretty-format': 3.2.4
|
||||
'@vitest/runner': 3.2.4
|
||||
'@vitest/snapshot': 3.2.4
|
||||
|
|
@ -4526,8 +4823,8 @@ snapshots:
|
|||
tinyglobby: 0.2.15
|
||||
tinypool: 1.1.1
|
||||
tinyrainbow: 2.0.0
|
||||
vite: 6.4.1(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0)
|
||||
vite-node: 3.2.4(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0)
|
||||
vite: 6.4.1(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)
|
||||
vite-node: 3.2.4(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)
|
||||
why-is-node-running: 2.3.0
|
||||
optionalDependencies:
|
||||
'@types/debug': 4.1.13
|
||||
|
|
@ -4547,11 +4844,11 @@ snapshots:
|
|||
- tsx
|
||||
- yaml
|
||||
|
||||
vitest@3.2.4(@types/debug@4.1.13)(@types/node@25.5.2)(happy-dom@20.8.9)(jiti@2.6.1)(lightningcss@1.32.0):
|
||||
vitest@3.2.4(@types/debug@4.1.13)(@types/node@25.5.2)(happy-dom@20.8.9)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0):
|
||||
dependencies:
|
||||
'@types/chai': 5.2.3
|
||||
'@vitest/expect': 3.2.4
|
||||
'@vitest/mocker': 3.2.4(vite@6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0))
|
||||
'@vitest/mocker': 3.2.4(vite@6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0))
|
||||
'@vitest/pretty-format': 3.2.4
|
||||
'@vitest/runner': 3.2.4
|
||||
'@vitest/snapshot': 3.2.4
|
||||
|
|
@ -4569,8 +4866,8 @@ snapshots:
|
|||
tinyglobby: 0.2.15
|
||||
tinypool: 1.1.1
|
||||
tinyrainbow: 2.0.0
|
||||
vite: 6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)
|
||||
vite-node: 3.2.4(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)
|
||||
vite: 6.4.1(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)
|
||||
vite-node: 3.2.4(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)
|
||||
why-is-node-running: 2.3.0
|
||||
optionalDependencies:
|
||||
'@types/debug': 4.1.13
|
||||
|
|
|
|||
19
ts/scripts/reset-nats.ts
Normal file
19
ts/scripts/reset-nats.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import { connect } from "nats";
|
||||
|
||||
async function main() {
|
||||
const nc = await connect({ servers: "nats://localhost:4222" });
|
||||
const jsm = await nc.jetstreamManager();
|
||||
|
||||
try {
|
||||
const info = await jsm.streams.info("tg_flow");
|
||||
console.log("Current stream subjects:", info.config.subjects);
|
||||
await jsm.streams.delete("tg_flow");
|
||||
console.log("Deleted tg_flow stream");
|
||||
} catch (e) {
|
||||
console.log("No stream to delete:", (e as Error).message);
|
||||
}
|
||||
|
||||
await nc.close();
|
||||
}
|
||||
|
||||
main();
|
||||
15
ts/scripts/run-config.ts
Normal file
15
ts/scripts/run-config.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/**
|
||||
* Start the config service.
|
||||
*
|
||||
* Usage: pnpm tsx scripts/run-config.ts
|
||||
*
|
||||
* Env:
|
||||
* NATS_URL (default: nats://localhost:4222)
|
||||
* CONFIG_PERSIST_PATH (optional, e.g., ./data/config.json)
|
||||
*/
|
||||
import { run } from "../packages/flow/src/config/service.js";
|
||||
|
||||
run().catch((err) => {
|
||||
console.error("Config service failed:", err);
|
||||
process.exit(1);
|
||||
});
|
||||
16
ts/scripts/run-gateway.ts
Normal file
16
ts/scripts/run-gateway.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* Start the API gateway.
|
||||
*
|
||||
* Usage: pnpm tsx scripts/run-gateway.ts
|
||||
*
|
||||
* Env:
|
||||
* NATS_URL (default: nats://localhost:4222)
|
||||
* GATEWAY_PORT (default: 8088)
|
||||
* GATEWAY_SECRET (optional)
|
||||
*/
|
||||
import { run } from "../packages/flow/src/gateway/server.js";
|
||||
|
||||
run().catch((err) => {
|
||||
console.error("Gateway failed to start:", err);
|
||||
process.exit(1);
|
||||
});
|
||||
15
ts/scripts/run-llm-claude.ts
Normal file
15
ts/scripts/run-llm-claude.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/**
|
||||
* Start the Claude text-completion service.
|
||||
*
|
||||
* Usage: CLAUDE_KEY=sk-... pnpm tsx scripts/run-llm-claude.ts
|
||||
*
|
||||
* Env:
|
||||
* NATS_URL (default: nats://localhost:4222)
|
||||
* CLAUDE_KEY (required)
|
||||
*/
|
||||
import { run } from "../packages/flow/src/model/text-completion/claude.js";
|
||||
|
||||
run().catch((err) => {
|
||||
console.error("Claude LLM service failed:", err);
|
||||
process.exit(1);
|
||||
});
|
||||
16
ts/scripts/run-llm-openai.ts
Normal file
16
ts/scripts/run-llm-openai.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* Start the OpenAI text-completion service.
|
||||
*
|
||||
* Usage: OPENAI_TOKEN=sk-... pnpm tsx scripts/run-llm-openai.ts
|
||||
*
|
||||
* Env:
|
||||
* NATS_URL (default: nats://localhost:4222)
|
||||
* OPENAI_TOKEN (required)
|
||||
* OPENAI_BASE_URL (optional)
|
||||
*/
|
||||
import { run } from "../packages/flow/src/model/text-completion/openai.js";
|
||||
|
||||
run().catch((err) => {
|
||||
console.error("OpenAI LLM service failed:", err);
|
||||
process.exit(1);
|
||||
});
|
||||
292
ts/scripts/test-pipeline.ts
Normal file
292
ts/scripts/test-pipeline.ts
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
/**
|
||||
* Integration test — exercises the full pipeline:
|
||||
*
|
||||
* 1. Start config service + gateway
|
||||
* 2. Test config CRUD via REST
|
||||
* 3. Push a flow definition (for LLM service)
|
||||
* 4. Optionally test LLM text-completion (if CLAUDE_KEY or OPENAI_TOKEN set)
|
||||
*
|
||||
* Usage: pnpm tsx scripts/test-pipeline.ts
|
||||
*/
|
||||
|
||||
const GATEWAY_URL = process.env.GATEWAY_URL ?? "http://localhost:8088";
|
||||
|
||||
// ─── Helpers ──────────────────────────────────────────────────────────
|
||||
|
||||
async function post(path: string, body: unknown): Promise<unknown> {
|
||||
const res = await fetch(`${GATEWAY_URL}${path}`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
const text = await res.text();
|
||||
try {
|
||||
return JSON.parse(text);
|
||||
} catch {
|
||||
return { status: res.status, body: text };
|
||||
}
|
||||
}
|
||||
|
||||
function log(label: string, data: unknown): void {
|
||||
console.log(`\n[${label}]`, JSON.stringify(data, null, 2));
|
||||
}
|
||||
|
||||
function pass(test: string): void {
|
||||
console.log(` ✓ ${test}`);
|
||||
}
|
||||
|
||||
function fail(test: string, err: unknown): void {
|
||||
console.error(` ✗ ${test}:`, err);
|
||||
}
|
||||
|
||||
// ─── Tests ────────────────────────────────────────────────────────────
|
||||
|
||||
async function testConfigList(): Promise<boolean> {
|
||||
try {
|
||||
const res = await post("/api/v1/config", { operation: "list", keys: [] });
|
||||
log("config/list", res);
|
||||
if (typeof res === "object" && res !== null && "version" in res) {
|
||||
pass("Config list returns version");
|
||||
return true;
|
||||
}
|
||||
fail("Config list", "unexpected response");
|
||||
return false;
|
||||
} catch (err) {
|
||||
fail("Config list", err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function testConfigPut(): Promise<boolean> {
|
||||
try {
|
||||
const res = await post("/api/v1/config", {
|
||||
operation: "put",
|
||||
keys: ["test"],
|
||||
values: { greeting: "hello from trustgraph-ts!" },
|
||||
});
|
||||
log("config/put", res);
|
||||
if (typeof res === "object" && res !== null && "version" in res) {
|
||||
pass("Config put accepted");
|
||||
return true;
|
||||
}
|
||||
fail("Config put", "unexpected response");
|
||||
return false;
|
||||
} catch (err) {
|
||||
fail("Config put", err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function testConfigGet(): Promise<boolean> {
|
||||
try {
|
||||
const res = await post("/api/v1/config", {
|
||||
operation: "get",
|
||||
keys: ["test"],
|
||||
});
|
||||
log("config/get", res);
|
||||
const r = res as Record<string, unknown>;
|
||||
const values = r.values as Record<string, unknown> | undefined;
|
||||
if (values?.greeting === "hello from trustgraph-ts!") {
|
||||
pass("Config get returns stored value");
|
||||
return true;
|
||||
}
|
||||
fail("Config get", "value mismatch");
|
||||
return false;
|
||||
} catch (err) {
|
||||
fail("Config get", err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function testConfigDelete(): Promise<boolean> {
|
||||
try {
|
||||
const res = await post("/api/v1/config", {
|
||||
operation: "delete",
|
||||
keys: ["test"],
|
||||
});
|
||||
log("config/delete", res);
|
||||
|
||||
// Verify it's gone
|
||||
const check = await post("/api/v1/config", {
|
||||
operation: "get",
|
||||
keys: ["test"],
|
||||
}) as Record<string, unknown>;
|
||||
|
||||
const values = check.values as Record<string, unknown> | undefined;
|
||||
if (!values || Object.keys(values).length === 0) {
|
||||
pass("Config delete removes value");
|
||||
return true;
|
||||
}
|
||||
fail("Config delete", "value still present");
|
||||
return false;
|
||||
} catch (err) {
|
||||
fail("Config delete", err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function testPushFlowConfig(): Promise<boolean> {
|
||||
try {
|
||||
// Push a flow definition that LLM services will pick up
|
||||
const res = await post("/api/v1/config", {
|
||||
operation: "put",
|
||||
keys: ["flows"],
|
||||
values: {
|
||||
default: {
|
||||
topics: {
|
||||
request: "tg.flow.text-completion-request",
|
||||
response: "tg.flow.text-completion-response",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
log("config/push-flow", res);
|
||||
if (typeof res === "object" && res !== null && "version" in res) {
|
||||
pass("Flow config pushed");
|
||||
return true;
|
||||
}
|
||||
fail("Flow config push", "unexpected response");
|
||||
return false;
|
||||
} catch (err) {
|
||||
fail("Flow config push", err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function testTextCompletion(): Promise<boolean> {
|
||||
try {
|
||||
console.log("\n Sending text-completion request (may take a few seconds)...");
|
||||
// Use model from env or default to qwen2.5:0.5b (Ollama-compatible)
|
||||
const model = process.env.LLM_MODEL ?? "qwen2.5:0.5b";
|
||||
const res = await post("/api/v1/flow/default/service/text-completion", {
|
||||
system: "You are a helpful assistant. Reply in one sentence.",
|
||||
prompt: "What is 2+2?",
|
||||
model,
|
||||
});
|
||||
log("text-completion", res);
|
||||
const r = res as Record<string, unknown>;
|
||||
if (r.response && typeof r.response === "string") {
|
||||
pass(`Text completion returned: "${(r.response as string).slice(0, 80)}..."`);
|
||||
return true;
|
||||
}
|
||||
if (r.error) {
|
||||
fail("Text completion", r.error);
|
||||
return false;
|
||||
}
|
||||
fail("Text completion", "unexpected response");
|
||||
return false;
|
||||
} catch (err) {
|
||||
fail("Text completion", err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function testWebSocket(): Promise<boolean> {
|
||||
try {
|
||||
// Use the vendored client's WebSocket adapter
|
||||
const { getWebSocketConstructor } = await import(
|
||||
"../packages/client/src/socket/websocket-adapter.js"
|
||||
);
|
||||
const WS = getWebSocketConstructor();
|
||||
|
||||
return new Promise<boolean>((resolve) => {
|
||||
const ws = new WS(`${GATEWAY_URL.replace("http", "ws")}/api/v1/socket`);
|
||||
const timeout = setTimeout(() => {
|
||||
ws.close();
|
||||
fail("WebSocket", "connection timeout");
|
||||
resolve(false);
|
||||
}, 5000);
|
||||
|
||||
ws.onopen = () => {
|
||||
clearTimeout(timeout);
|
||||
// Send a config list request
|
||||
const msg = JSON.stringify({
|
||||
id: "test-ws-1",
|
||||
service: "config",
|
||||
request: { operation: "list", keys: [] },
|
||||
});
|
||||
ws.send(msg);
|
||||
};
|
||||
|
||||
ws.onmessage = (event: { data: unknown }) => {
|
||||
clearTimeout(timeout);
|
||||
const data = JSON.parse(String(event.data));
|
||||
log("websocket/response", data);
|
||||
ws.close();
|
||||
if (data.id === "test-ws-1") {
|
||||
pass("WebSocket round-trip works");
|
||||
resolve(true);
|
||||
} else {
|
||||
fail("WebSocket", "unexpected response id");
|
||||
resolve(false);
|
||||
}
|
||||
};
|
||||
|
||||
ws.onerror = (err: unknown) => {
|
||||
clearTimeout(timeout);
|
||||
fail("WebSocket", err);
|
||||
resolve(false);
|
||||
};
|
||||
});
|
||||
} catch (err) {
|
||||
fail("WebSocket", err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Main ─────────────────────────────────────────────────────────────
|
||||
|
||||
async function main(): Promise<void> {
|
||||
console.log("╔══════════════════════════════════════════════════╗");
|
||||
console.log("║ TrustGraph TypeScript — Integration Test ║");
|
||||
console.log("╚══════════════════════════════════════════════════╝");
|
||||
console.log(`\nGateway: ${GATEWAY_URL}`);
|
||||
|
||||
// Check gateway is reachable
|
||||
try {
|
||||
const res = await fetch(`${GATEWAY_URL}/api/v1/metrics`);
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
pass("Gateway reachable");
|
||||
} catch (err) {
|
||||
fail("Gateway reachable", err);
|
||||
console.error("\n⚠ Gateway not running. Start it first:");
|
||||
console.error(" pnpm tsx scripts/run-gateway.ts");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let passed = 0;
|
||||
let failed = 0;
|
||||
const run = async (name: string, fn: () => Promise<boolean>) => {
|
||||
console.log(`\n── ${name} ──`);
|
||||
if (await fn()) passed++;
|
||||
else failed++;
|
||||
};
|
||||
|
||||
// Config CRUD tests
|
||||
await run("Config List", testConfigList);
|
||||
await run("Config Put", testConfigPut);
|
||||
await run("Config Get", testConfigGet);
|
||||
await run("Config Delete", testConfigDelete);
|
||||
|
||||
// WebSocket test
|
||||
await run("WebSocket Round-Trip", testWebSocket);
|
||||
|
||||
// Flow config push
|
||||
await run("Push Flow Config", testPushFlowConfig);
|
||||
|
||||
// LLM test (only if a running LLM service is available)
|
||||
if (process.env.SKIP_LLM !== "1") {
|
||||
console.log("\n (Testing text-completion — set SKIP_LLM=1 to skip)");
|
||||
await run("Text Completion", testTextCompletion);
|
||||
} else {
|
||||
console.log("\n (SKIP_LLM=1 — skipping LLM test)");
|
||||
}
|
||||
|
||||
console.log("\n══════════════════════════════════════════════════");
|
||||
console.log(` Results: ${passed} passed, ${failed} failed`);
|
||||
console.log("══════════════════════════════════════════════════\n");
|
||||
|
||||
process.exit(failed > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
main();
|
||||
Loading…
Add table
Add a link
Reference in a new issue