From ceb3c5052f029f6bb726943ed5c6a0d5ae4202f9 Mon Sep 17 00:00:00 2001 From: moosebay Date: Sat, 7 Mar 2026 00:45:12 +0300 Subject: [PATCH 1/5] feat: WebSocket flow nodes, Wait node, flow runner overhaul, and dep updates WebSocket Support: - Add WebSocket Connection and Send flow nodes (client + server) - Add WebSocket request page and API - Add drag-and-drop from file tree to flow canvas for WebSocket items - Add WS echo server integration test, migrate to coder/websocket Wait Node: - Add Wait flow node with configurable duration Flow Runner Overhaul: - Extract flow execution into flowexec/flowresult packages (~900 lines) - Wire runner abstractions into strategies with shared helpers - Fix CANCELED status not sent when stopping a flow Bug Fixes: - Fix WS Send node dropdown empty when no selection exists - Fix @lezer/common override for CodeMirror highlight crash - Fix sync insert handler idempotency, node event publisher types - Fix wait node copy/paste, server panic on closed WS channel Dependencies: - Update all npm packages to latest (ESLint pinned to v9, syncpack to v13) - Update Scoop dependencies (7zip, gcc, go, nodejs, etc.) - Fix eslint-plugin-better-tailwindcss v4 config changes - Fix @types/react FormEvent deprecation - Fix matchRoute return type change --- apps/cli/cmd/flow.go | 5 + apps/cli/internal/common/services.go | 37 +- apps/cli/internal/runner/runner.go | 4 +- apps/cli/internal/runner/runner_test.go | 119 + .../yamlflow/integration_yamlflow_test.go | 1 + apps/cli/test/yamlflow/ws_run_example.yaml | 57 + apps/desktop/package.json | 2 +- apps/desktop/src/renderer/main.tsx | 2 +- go.work.sum | 36 +- install.ps1 | 722 + .../client/src/app/router/route-tree.gen.ts | 68 +- .../client/src/features/file-system/index.tsx | 193 +- packages/client/src/pages/flow/add-node.tsx | 61 +- .../client/src/pages/flow/agent-panel.tsx | 6 +- packages/client/src/pages/flow/edge.tsx | 2 +- packages/client/src/pages/flow/edit.tsx | 28 + packages/client/src/pages/flow/handle.tsx | 25 +- packages/client/src/pages/flow/node.tsx | 53 +- packages/client/src/pages/flow/nodes/wait.tsx | 69 + .../src/pages/flow/nodes/ws-connection.tsx | 144 + .../client/src/pages/flow/nodes/ws-send.tsx | 99 + .../client/src/pages/websocket/@x/flow.tsx | 1 + .../src/pages/websocket/@x/workspace.tsx | 3 + packages/client/src/pages/websocket/page.tsx | 47 + .../src/pages/websocket/request/header.tsx | 140 + .../src/pages/websocket/request/index.tsx | 3 + .../src/pages/websocket/request/panel.tsx | 117 + .../src/pages/websocket/request/top-bar.tsx | 78 + .../src/pages/websocket/request/url.tsx | 91 + .../src/pages/websocket/response/index.tsx | 152 + .../websocket/$websocketIdCan/index.tsx | 19 + .../websocket/$websocketIdCan/route.tsx | 11 + packages/client/src/pages/websocket/tab.tsx | 35 + .../src/pages/websocket/use-websocket.ts | 107 + .../$workspaceIdCan/(websocket)/__virtual.ts | 3 + .../src/shared/api/collection.internal.tsx | 6 +- packages/client/src/shared/routes.tsx | 4 + packages/db/pkg/sqlc/gen/db.go | 250 + packages/db/pkg/sqlc/gen/flow.sql.go | 72 + packages/db/pkg/sqlc/gen/models.go | 40 + packages/db/pkg/sqlc/gen/websocket.sql.go | 443 + packages/db/pkg/sqlc/queries/flow.sql | 30 + packages/db/pkg/sqlc/queries/websocket.sql | 134 + packages/db/pkg/sqlc/schema/05_flow.sql | 5 + packages/db/pkg/sqlc/schema/10_websocket.sql | 57 + packages/db/pkg/sqlc/sqlc.yaml | 53 + packages/server/cmd/serverrun/serverrun.go | 58 +- packages/server/go.mod | 5 +- packages/server/go.sum | 2 + .../server/internal/api/rexportv2/export.go | 279 +- .../internal/api/rexportv2/exporter_test.go | 30 +- .../internal/api/rexportv2/rexportv2.go | 70 +- packages/server/internal/api/rfile/rfile.go | 4 + .../internal/api/rflowv2/logging_test.go | 8 +- .../api/rflowv2/node_config_sync_test.go | 4 +- .../server/internal/api/rflowv2/rflowv2.go | 241 +- .../api/rflowv2/rflowv2_copy_paste.go | 148 + .../internal/api/rflowv2/rflowv2_exec.go | 920 +- .../api/rflowv2/rflowv2_exec_publisher.go | 241 + .../internal/api/rflowv2/rflowv2_exec_test.go | 57 +- .../rflowv2/rflowv2_exec_transaction_test.go | 137 +- .../internal/api/rflowv2/rflowv2_flow.go | 82 +- .../rflowv2/rflowv2_node_condition_test.go | 8 +- .../internal/api/rflowv2/rflowv2_node_exec.go | 70 - .../api/rflowv2/rflowv2_node_exec_test.go | 15 +- .../internal/api/rflowv2/rflowv2_node_wait.go | 426 + .../api/rflowv2/rflowv2_node_ws_connection.go | 464 + .../api/rflowv2/rflowv2_node_ws_send.go | 446 + .../rflowv2/rflowv2_sync_zero_value_test.go | 2 +- .../api/rflowv2/rflowv2_testutil_test.go | 8 +- .../api/rflowv2/sync_robustness_test.go | 2 +- .../server/internal/api/rgraphql/rgraphql.go | 5 + .../api/rgraphql/rgraphql_converter.go | 221 + .../api/rgraphql/rgraphql_crud_assert.go | 58 +- .../rgraphql/rgraphql_crud_header_delta.go | 62 +- .../api/rimportv2/integration_test.go | 2 + .../internal/api/rimportv2/integrity.go | 6 + .../internal/api/rimportv2/rimportv2_event.go | 2 +- .../internal/api/rreference/rreference.go | 12 +- .../internal/api/rwebsocket/rwebsocket.go | 790 ++ .../server/internal/converter/converter.go | 6 + .../internal/converter/converter_test.go | 2 + .../migrations/01KJZMR5_add_flow_node_wait.go | 50 + .../01KKFQT8_add_websocket_tables.go | 233 + .../internal/migrations/migrations_test.go | 8 +- .../server/pkg/flow/flowbuilder/builder.go | 123 +- packages/server/pkg/flow/flowexec/session.go | 165 + .../server/pkg/flow/flowexec/session_test.go | 36 + packages/server/pkg/flow/flowexec/snapshot.go | 396 + .../server/pkg/flow/flowexec/snapshot_test.go | 238 + packages/server/pkg/flow/flowresult/drain.go | 212 + packages/server/pkg/flow/flowresult/noop.go | 70 + .../server/pkg/flow/flowresult/processor.go | 152 + .../server/pkg/flow/flowresult/publisher.go | 28 + .../pkg/flow/flowresult/statetracker.go | 247 + packages/server/pkg/flow/node/entry.go | 26 + .../server/pkg/flow/node/nfor/nfor_test.go | 6 +- .../pkg/flow/node/nforeach/nforeach_test.go | 6 +- packages/server/pkg/flow/node/node.go | 37 +- .../server/pkg/flow/node/nstart/nstart.go | 4 + packages/server/pkg/flow/node/nwait/nwait.go | 51 + .../flow/node/nwsconnection/nwsconnection.go | 291 + .../node/nwsconnection/nwsconnection_test.go | 204 + .../server/pkg/flow/node/nwssend/nwssend.go | 111 + .../pkg/flow/node/nwssend/nwssend_test.go | 152 + .../flow/runner/flowlocalrunner/executor.go | 67 + .../runner/flowlocalrunner/flowlocalrunner.go | 1177 +- .../flowlocalrunner_inputdata_test.go | 6 +- .../flowlocalrunner/flowlocalrunner_test.go | 363 +- .../flow/runner/flowlocalrunner/helpers.go | 91 + .../runner/flowlocalrunner/mode_select.go | 72 + .../runner/flowlocalrunner/strategy_multi.go | 281 + .../runner/flowlocalrunner/strategy_single.go | 106 + packages/server/pkg/flow/runner/graph.go | 126 + packages/server/pkg/flow/runner/runner.go | 9 - packages/server/pkg/flow/runner/status.go | 160 + .../server/pkg/flow/simulation/mockflows.go | 18 +- .../pkg/flow/simulation/mockflows_test.go | 14 +- packages/server/pkg/ioworkspace/exporter.go | 62 +- packages/server/pkg/ioworkspace/importer.go | 48 +- .../server/pkg/ioworkspace/importer_flow.go | 98 + packages/server/pkg/ioworkspace/types.go | 19 +- packages/server/pkg/model/mfile/mfile.go | 14 +- packages/server/pkg/model/mflow/edge.go | 1 + packages/server/pkg/model/mflow/node.go | 8 +- packages/server/pkg/model/mflow/node_types.go | 26 +- .../server/pkg/model/mwebsocket/mwebsocket.go | 29 + packages/server/pkg/mutation/delete_file.go | 5 + packages/server/pkg/mutation/event.go | 3 + packages/server/pkg/mutation/insert_flow.go | 337 - packages/server/pkg/mutation/update_flow.go | 383 - .../server/pkg/service/sflow/node_mapper.go | 4 +- .../server/pkg/service/sflow/node_wait.go | 51 + .../pkg/service/sflow/node_wait_mapper.go | 20 + .../pkg/service/sflow/node_wait_reader.go | 34 + .../pkg/service/sflow/node_wait_writer.go | 38 + .../server/pkg/service/sflow/node_writer.go | 20 +- .../pkg/service/sflow/node_ws_connection.go | 49 + .../sflow/node_ws_connection_mapper.go | 24 + .../sflow/node_ws_connection_reader.go | 30 + .../sflow/node_ws_connection_writer.go | 46 + .../server/pkg/service/sflow/node_ws_send.go | 49 + .../pkg/service/sflow/node_ws_send_mapper.go | 22 + .../pkg/service/sflow/node_ws_send_reader.go | 30 + .../pkg/service/sflow/node_ws_send_writer.go | 35 + .../server/pkg/service/sgraphql/header.go | 11 + .../server/pkg/service/swebsocket/header.go | 75 + .../server/pkg/service/swebsocket/mapper.go | 58 + .../pkg/service/swebsocket/swebsocket.go | 72 + .../yamlflowsimplev2/converter_flow.go | 5 + .../yamlflowsimplev2/converter_node.go | 121 + .../translate/yamlflowsimplev2/exporter.go | 80 +- .../pkg/translate/yamlflowsimplev2/types.go | 28 +- .../pkg/translate/yamlflowsimplev2/utils.go | 10 +- .../translate/yamlflowsimplev2/utils_test.go | 5 +- packages/server/test/e2e_har_to_cli_test.go | 10 +- packages/spec/api/export.tsp | 10 + packages/spec/api/file-system.tsp | 1 + packages/spec/api/flow.tsp | 23 + packages/spec/api/main.tsp | 1 + packages/spec/api/websocket.tsp | 23 + packages/spec/package.json | 2 +- pnpm-lock.yaml | 11132 ++++++++-------- pnpm-workspace.yaml | 147 +- scoop.json | 64 +- tools/eslint/config.ts | 2 +- 166 files changed, 18513 insertions(+), 8715 deletions(-) create mode 100644 apps/cli/test/yamlflow/ws_run_example.yaml create mode 100644 install.ps1 create mode 100644 packages/client/src/pages/flow/nodes/wait.tsx create mode 100644 packages/client/src/pages/flow/nodes/ws-connection.tsx create mode 100644 packages/client/src/pages/flow/nodes/ws-send.tsx create mode 100644 packages/client/src/pages/websocket/@x/flow.tsx create mode 100644 packages/client/src/pages/websocket/@x/workspace.tsx create mode 100644 packages/client/src/pages/websocket/page.tsx create mode 100644 packages/client/src/pages/websocket/request/header.tsx create mode 100644 packages/client/src/pages/websocket/request/index.tsx create mode 100644 packages/client/src/pages/websocket/request/panel.tsx create mode 100644 packages/client/src/pages/websocket/request/top-bar.tsx create mode 100644 packages/client/src/pages/websocket/request/url.tsx create mode 100644 packages/client/src/pages/websocket/response/index.tsx create mode 100644 packages/client/src/pages/websocket/routes/websocket/$websocketIdCan/index.tsx create mode 100644 packages/client/src/pages/websocket/routes/websocket/$websocketIdCan/route.tsx create mode 100644 packages/client/src/pages/websocket/tab.tsx create mode 100644 packages/client/src/pages/websocket/use-websocket.ts create mode 100644 packages/client/src/pages/workspace/routes/workspace/$workspaceIdCan/(websocket)/__virtual.ts create mode 100644 packages/db/pkg/sqlc/gen/websocket.sql.go create mode 100644 packages/db/pkg/sqlc/queries/websocket.sql create mode 100644 packages/db/pkg/sqlc/schema/10_websocket.sql create mode 100644 packages/server/internal/api/rflowv2/rflowv2_exec_publisher.go create mode 100644 packages/server/internal/api/rflowv2/rflowv2_node_wait.go create mode 100644 packages/server/internal/api/rflowv2/rflowv2_node_ws_connection.go create mode 100644 packages/server/internal/api/rflowv2/rflowv2_node_ws_send.go create mode 100644 packages/server/internal/api/rwebsocket/rwebsocket.go create mode 100644 packages/server/internal/migrations/01KJZMR5_add_flow_node_wait.go create mode 100644 packages/server/internal/migrations/01KKFQT8_add_websocket_tables.go create mode 100644 packages/server/pkg/flow/flowexec/session.go create mode 100644 packages/server/pkg/flow/flowexec/session_test.go create mode 100644 packages/server/pkg/flow/flowexec/snapshot.go create mode 100644 packages/server/pkg/flow/flowexec/snapshot_test.go create mode 100644 packages/server/pkg/flow/flowresult/drain.go create mode 100644 packages/server/pkg/flow/flowresult/noop.go create mode 100644 packages/server/pkg/flow/flowresult/processor.go create mode 100644 packages/server/pkg/flow/flowresult/publisher.go create mode 100644 packages/server/pkg/flow/flowresult/statetracker.go create mode 100644 packages/server/pkg/flow/node/entry.go create mode 100644 packages/server/pkg/flow/node/nwait/nwait.go create mode 100644 packages/server/pkg/flow/node/nwsconnection/nwsconnection.go create mode 100644 packages/server/pkg/flow/node/nwsconnection/nwsconnection_test.go create mode 100644 packages/server/pkg/flow/node/nwssend/nwssend.go create mode 100644 packages/server/pkg/flow/node/nwssend/nwssend_test.go create mode 100644 packages/server/pkg/flow/runner/flowlocalrunner/executor.go create mode 100644 packages/server/pkg/flow/runner/flowlocalrunner/helpers.go create mode 100644 packages/server/pkg/flow/runner/flowlocalrunner/mode_select.go create mode 100644 packages/server/pkg/flow/runner/flowlocalrunner/strategy_multi.go create mode 100644 packages/server/pkg/flow/runner/flowlocalrunner/strategy_single.go create mode 100644 packages/server/pkg/flow/runner/graph.go create mode 100644 packages/server/pkg/flow/runner/status.go create mode 100644 packages/server/pkg/model/mwebsocket/mwebsocket.go delete mode 100644 packages/server/pkg/mutation/insert_flow.go delete mode 100644 packages/server/pkg/mutation/update_flow.go create mode 100644 packages/server/pkg/service/sflow/node_wait.go create mode 100644 packages/server/pkg/service/sflow/node_wait_mapper.go create mode 100644 packages/server/pkg/service/sflow/node_wait_reader.go create mode 100644 packages/server/pkg/service/sflow/node_wait_writer.go create mode 100644 packages/server/pkg/service/sflow/node_ws_connection.go create mode 100644 packages/server/pkg/service/sflow/node_ws_connection_mapper.go create mode 100644 packages/server/pkg/service/sflow/node_ws_connection_reader.go create mode 100644 packages/server/pkg/service/sflow/node_ws_connection_writer.go create mode 100644 packages/server/pkg/service/sflow/node_ws_send.go create mode 100644 packages/server/pkg/service/sflow/node_ws_send_mapper.go create mode 100644 packages/server/pkg/service/sflow/node_ws_send_reader.go create mode 100644 packages/server/pkg/service/sflow/node_ws_send_writer.go create mode 100644 packages/server/pkg/service/swebsocket/header.go create mode 100644 packages/server/pkg/service/swebsocket/mapper.go create mode 100644 packages/server/pkg/service/swebsocket/swebsocket.go create mode 100644 packages/spec/api/websocket.tsp diff --git a/apps/cli/cmd/flow.go b/apps/cli/cmd/flow.go index 3935bfeea..510547c10 100644 --- a/apps/cli/cmd/flow.go +++ b/apps/cli/cmd/flow.go @@ -184,6 +184,11 @@ var yamlflowRunCmd = &cobra.Command{ &services.NodeAiProvider, &services.NodeMemory, &services.NodeGraphQL, + &services.NodeWsConnection, + &services.NodeWsSend, + &services.NodeWait, + &services.WebSocket, + &services.WebSocketHeader, &services.GraphQL, &services.GraphQLHeader, &services.Workspace, diff --git a/apps/cli/internal/common/services.go b/apps/cli/internal/common/services.go index f2657757c..ee75bfeb1 100644 --- a/apps/cli/internal/common/services.go +++ b/apps/cli/internal/common/services.go @@ -12,6 +12,7 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sflow" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sgraphql" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/shttp" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/swebsocket" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sworkspace" ) @@ -32,16 +33,23 @@ type Services struct { FlowVariable sflow.FlowVariableService // Flow Nodes - Node sflow.NodeService - NodeRequest sflow.NodeRequestService - NodeFor sflow.NodeForService - NodeForEach sflow.NodeForEachService - NodeIf sflow.NodeIfService - NodeJS sflow.NodeJsService - NodeAI sflow.NodeAIService - NodeAiProvider sflow.NodeAiProviderService - NodeMemory sflow.NodeMemoryService - NodeGraphQL sflow.NodeGraphQLService + Node sflow.NodeService + NodeRequest sflow.NodeRequestService + NodeFor sflow.NodeForService + NodeForEach sflow.NodeForEachService + NodeIf sflow.NodeIfService + NodeJS sflow.NodeJsService + NodeAI sflow.NodeAIService + NodeAiProvider sflow.NodeAiProviderService + NodeMemory sflow.NodeMemoryService + NodeGraphQL sflow.NodeGraphQLService + NodeWsConnection sflow.NodeWsConnectionService + NodeWsSend sflow.NodeWsSendService + NodeWait sflow.NodeWaitService + + // WebSocket + WebSocket swebsocket.WebSocketService + WebSocketHeader swebsocket.WebSocketHeaderService // GraphQL GraphQL sgraphql.GraphQLService @@ -94,7 +102,14 @@ func CreateServices(ctx context.Context, db *sql.DB, logger *slog.Logger) (*Serv NodeAI: sflow.NewNodeAIService(queries), NodeAiProvider: sflow.NewNodeAiProviderService(queries), NodeMemory: sflow.NewNodeMemoryService(queries), - NodeGraphQL: sflow.NewNodeGraphQLService(queries), + NodeGraphQL: sflow.NewNodeGraphQLService(queries), + NodeWsConnection: sflow.NewNodeWsConnectionService(queries), + NodeWsSend: sflow.NewNodeWsSendService(queries), + NodeWait: sflow.NewNodeWaitService(queries), + + // WebSocket + WebSocket: swebsocket.New(queries, logger), + WebSocketHeader: swebsocket.NewWebSocketHeaderService(queries), // GraphQL GraphQL: sgraphql.New(queries, logger), diff --git a/apps/cli/internal/runner/runner.go b/apps/cli/internal/runner/runner.go index d4ae4e6b1..325da9dc9 100644 --- a/apps/cli/internal/runner/runner.go +++ b/apps/cli/internal/runner/runner.go @@ -264,7 +264,7 @@ func RunFlow(ctx context.Context, flowPtr *mflow.Flow, services RunnerServices, defer close(gqlRespChan) // Build flow node map using flowbuilder - flowNodeMap, startNodeID, err := services.Builder.BuildNodes( + flowNodeMap, startNodeIDs, err := services.Builder.BuildNodes( ctx, *flowPtr, nodes, @@ -279,7 +279,7 @@ func RunFlow(ctx context.Context, flowPtr *mflow.Flow, services RunnerServices, } // Use the same timeout for the flow runner - runnerInst := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), latestFlowID, startNodeID, flowNodeMap, edgeMap, nodeTimeout, nil) + runnerInst := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), latestFlowID, startNodeIDs, flowNodeMap, edgeMap, nodeTimeout, nil) // Use a large buffer for CLI to avoid blocking flowNodeStatusChan := make(chan runner.FlowNodeStatus, 10000) diff --git a/apps/cli/internal/runner/runner_test.go b/apps/cli/internal/runner/runner_test.go index 67271a7c2..cd11a0105 100644 --- a/apps/cli/internal/runner/runner_test.go +++ b/apps/cli/internal/runner/runner_test.go @@ -26,9 +26,11 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/senv" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sflow" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/shttp" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/swebsocket" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sworkspace" yamlflowsimplev2 "github.com/the-dev-tools/dev-tools/packages/server/pkg/translate/yamlflowsimplev2" "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/private/node_js_executor/v1/node_js_executorv1connect" + "github.com/coder/websocket" ) // flowTestFixture provides a common test environment for flow execution tests @@ -88,6 +90,13 @@ func newFlowTestFixture(t *testing.T) *flowTestFixture { httpBodyRawService := shttp.NewHttpBodyRawService(queries) httpAssertService := shttp.NewHttpAssertService(queries) + // WebSocket services + nodeWsConnectionService := sflow.NewNodeWsConnectionService(queries) + nodeWsSendService := sflow.NewNodeWsSendService(queries) + nodeWaitService := sflow.NewNodeWaitService(queries) + webSocketService := swebsocket.New(queries, logger) + webSocketHeaderService := swebsocket.NewWebSocketHeaderService(queries) + // Additional services for builder varService := senv.NewVariableService(queries, logger) @@ -114,6 +123,11 @@ func newFlowTestFixture(t *testing.T) *flowTestFixture { nil, // NodeAiProviderService - not needed for CLI tests nil, // NodeMemoryService - not needed for CLI tests nil, // NodeGraphQLService - not needed for CLI tests + &nodeWsConnectionService, + &nodeWsSendService, + &nodeWaitService, + &webSocketService, + &webSocketHeaderService, nil, // GraphQLService - not needed for CLI tests nil, // GraphQLHeaderService - not needed for CLI tests &workspaceService, @@ -149,6 +163,11 @@ func newFlowTestFixture(t *testing.T) *flowTestFixture { HTTPBodyUrlEncoded: httpBodyUrlEncodedService, HTTPBodyRaw: httpBodyRawService, HTTPAssert: httpAssertService, + NodeWsConnection: nodeWsConnectionService, + NodeWsSend: nodeWsSendService, + NodeWait: nodeWaitService, + WebSocket: webSocketService, + WebSocketHeader: webSocketHeaderService, Logger: logger, } @@ -763,3 +782,103 @@ flows: t.Error("OrphanRequest should NOT have been executed (it's an orphan node)") } } + +// echoWSServer creates a test WebSocket server that echoes messages back. +func echoWSServer(t *testing.T) *httptest.Server { + t.Helper() + return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + conn, err := websocket.Accept(w, r, nil) + if err != nil { + return + } + defer conn.Close(websocket.StatusNormalClosure, "") //nolint:errcheck // best-effort cleanup + for { + typ, msg, err := conn.Read(r.Context()) + if err != nil { + return + } + if err := conn.Write(r.Context(), typ, msg); err != nil { + return + } + } + })) +} + +func wsURL(s *httptest.Server) string { + return "ws" + strings.TrimPrefix(s.URL, "http") +} + +// TestFlowRun_WebSocket tests a flow with WebSocket connection and send nodes. +func TestFlowRun_WebSocket(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } + + fixture := newFlowTestFixture(t) + + wsSrv := echoWSServer(t) + defer wsSrv.Close() + + yamlContent := fmt.Sprintf(`workspace_name: WS Test +flows: + - name: WSFlow + steps: + - manual_start: + name: Start + - ws_connection: + name: MyWS + depends_on: Start + url: %s + - ws_send: + name: SendHello + depends_on: MyWS + ws_connection_node_name: MyWS + message: '{"hello":"world"}' +`, wsURL(wsSrv)) + + resolved, err := yamlflowsimplev2.ConvertSimplifiedYAML([]byte(yamlContent), yamlflowsimplev2.ConvertOptionsV2{ + WorkspaceID: fixture.workspaceID, + }) + if err != nil { + t.Fatalf("failed to convert YAML: %v", err) + } + + fixture.importWorkspaceBundle(resolved) + + flow := fixture.getFlowByName("WSFlow") + if flow == nil { + t.Fatal("WSFlow not found") + } + + ctx, cancel := context.WithTimeout(fixture.ctx, 10*time.Second) + defer cancel() + + result, err := runner.RunFlow(ctx, flow, fixture.getRunnerServices(nil), nil) + + if err != nil { + t.Errorf("flow execution failed: %v", err) + } + + if result.Status != "success" { + t.Errorf("expected status 'success', got '%s'. Error: %s", result.Status, result.Error) + } + + // Verify both WS nodes were executed + foundConn := false + foundSend := false + for _, node := range result.Nodes { + switch node.Name { + case "MyWS": + foundConn = true + case "SendHello": + foundSend = true + } + } + + if !foundConn { + t.Error("WS connection node 'MyWS' was not executed") + } + if !foundSend { + t.Error("WS send node 'SendHello' was not executed") + } +} diff --git a/apps/cli/test/yamlflow/integration_yamlflow_test.go b/apps/cli/test/yamlflow/integration_yamlflow_test.go index 95d09ed26..a53ee1f17 100644 --- a/apps/cli/test/yamlflow/integration_yamlflow_test.go +++ b/apps/cli/test/yamlflow/integration_yamlflow_test.go @@ -76,3 +76,4 @@ func TestYAMLFlow_TestRunField(t *testing.T) { func TestYAMLFlow_GraphQLRun(t *testing.T) { runCLI(t, "graphql_run_example.yaml") } + diff --git a/apps/cli/test/yamlflow/ws_run_example.yaml b/apps/cli/test/yamlflow/ws_run_example.yaml new file mode 100644 index 000000000..400c8ce6c --- /dev/null +++ b/apps/cli/test/yamlflow/ws_run_example.yaml @@ -0,0 +1,57 @@ +workspace_name: New Workspace +run: + - flow: ws-integration +flows: + - name: ws-integration + steps: + - manual_start: + name: Start + position_x: -182.05 + position_y: -3.7 + - wait: + name: wait_4 + depends_on: Start + position_x: 201 + position_y: -139.77 + duration_ms: '8000' + - ws_connection: + name: ws_connection_5 + depends_on: Start + position_x: 218.43 + position_y: -3.21 + url: http://localhost:8080/ + - for: + name: for_6 + depends_on: ws_connection_5 + position_x: 462.56 + position_y: -146.17 + iter_count: '10' + - wait: + name: wait_7 + depends_on: ws_connection_5 + position_x: 470.57 + position_y: 88.8 + duration_ms: '1000' + - ws_send: + name: ws_send_6 + depends_on: for_6.loop + position_x: 592.26 + position_y: -52.7 + ws_connection_node_name: ws_connection_5 + message: '{"a":"{{ for_6.index }}"}' + - ws_send: + name: ws_send_6_1 + depends_on: wait_7 + position_x: 631.96 + position_y: 99.13 + ws_connection_node_name: ws_connection_5 + message: '{"a":"2"}' + - wait: + name: wait_7 + depends_on: ws_send_6 + position_x: 803.84 + position_y: -54.89 + duration_ms: '1000' +environments: + - name: default + variables: {} diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 5e22dcbe5..d617a2a1c 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -37,7 +37,7 @@ "electron": "catalog:", "electron-builder": "catalog:", "electron-devtools-installer": "catalog:", - "electron-updater": "6.7.3", + "electron-updater": "catalog:", "electron-vite": "catalog:", "eslint": "catalog:", "react": "catalog:", diff --git a/apps/desktop/src/renderer/main.tsx b/apps/desktop/src/renderer/main.tsx index d1fee1941..a79d93a31 100644 --- a/apps/desktop/src/renderer/main.tsx +++ b/apps/desktop/src/renderer/main.tsx @@ -68,7 +68,7 @@ const UpdateAvailable = ({ children }: UpdateAvailableProps) => {
Update available!
- {/* eslint-disable-next-line better-tailwindcss/no-unregistered-classes */} + {/* eslint-disable-next-line better-tailwindcss/no-unknown-classes */}
{children}
diff --git a/go.work.sum b/go.work.sum index f04746243..1b3e66c8e 100644 --- a/go.work.sum +++ b/go.work.sum @@ -25,18 +25,12 @@ cloud.google.com/go v0.112.2/go.mod h1:iEqjp//KquGIJV/m+Pk3xecgKNhV+ry+vVTsy4TbD cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU= cloud.google.com/go v0.118.3/go.mod h1:Lhs3YLnBlwJ4KA6nuObNMZ/fCbOQBPuWKPoE0Wa/9Vc= cloud.google.com/go v0.120.0/go.mod h1:/beW32s8/pGRuj4IILWQNd4uuebeT4dkOhKmkfit64Q= -cloud.google.com/go v0.121.2 h1:v2qQpN6Dx9x2NmwrqlesOt3Ys4ol5/lFZ6Mg1B7OJCg= -cloud.google.com/go v0.121.2/go.mod h1:nRFlrHq39MNVWu+zESP2PosMWA0ryJw8KUBZ2iZpxbw= cloud.google.com/go/accessapproval v1.8.6/go.mod h1:FfmTs7Emex5UvfnnpMkhuNkRCP85URnBFt5ClLxhZaQ= cloud.google.com/go/accessapproval v1.8.8/go.mod h1:RFwPY9JDKseP4gJrX1BlAVsP5O6kI8NdGlTmaeDefmk= cloud.google.com/go/accesscontextmanager v1.9.6/go.mod h1:884XHwy1AQpCX5Cj2VqYse77gfLaq9f8emE2bYriilk= cloud.google.com/go/accesscontextmanager v1.9.7/go.mod h1:i6e0nd5CPcrh7+YwGq4bKvju5YB9sgoAip+mXU73aMM= cloud.google.com/go/ai v0.8.0 h1:rXUEz8Wp2OlrM8r1bfmpF2+VKqc1VJpafE3HgzRnD/w= cloud.google.com/go/ai v0.8.0/go.mod h1:t3Dfk4cM61sytiggo2UyGsDVW3RF1qGZaUKDrZFyqkE= -cloud.google.com/go/ai v0.12.1 h1:m1n/VjUuHS+pEO/2R4/VbuuEIkgk0w67fDQvFaMngM0= -cloud.google.com/go/ai v0.12.1/go.mod h1:5vIPNe1ZQsVZqCliXIPL4QnhObQQY4d9hAGHdVc4iw4= -cloud.google.com/go/aiplatform v1.89.0 h1:niSJYc6ldWWVM9faXPo1Et1MVSQoLvVGriD7fwbJdtE= -cloud.google.com/go/aiplatform v1.89.0/go.mod h1:TzZtegPkinfXTtXVvZZpxx7noINFMVDrLkE7cEWhYEk= cloud.google.com/go/aiplatform v1.109.0/go.mod h1:4rwKOMdubQOND81AlO3EckcskvEFCYSzXKfn42GMm8k= cloud.google.com/go/alloydb v1.14.0/go.mod h1:OTBY1HoL0Z8PsHoMMVhkaUPKyY8oP7hzIAe/Dna6UHk= cloud.google.com/go/alloydbconn v1.13.2/go.mod h1:0wlYQAOr2XuvxYsvNNVckmG2v17WVUKzMD+gmTOibSU= @@ -67,12 +61,8 @@ cloud.google.com/go/auth v0.16.0/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI= cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4= cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA= -cloud.google.com/go/auth v0.16.3 h1:kabzoQ9/bobUmnseYnBO6qQG7q4a/CffFRlJSxv2wCc= -cloud.google.com/go/auth v0.16.3/go.mod h1:NucRGjaXfzP1ltpcQ7On/VTZ0H4kWB5Jy+Y9Dnm76fA= cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= -cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= -cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/automl v1.14.7/go.mod h1:8a4XbIH5pdvrReOU72oB+H3pOw2JBxo9XTk39oljObE= cloud.google.com/go/automl v1.15.0/go.mod h1:U9zOtQb8zVrFNGTuW3BfxeqmLyeleLgT9B12EaXfODg= cloud.google.com/go/baremetalsolution v1.3.6/go.mod h1:7/CS0LzpLccRGO0HL3q2Rofxas2JwjREKut414sE9iM= @@ -115,8 +105,6 @@ cloud.google.com/go/compute v1.49.1/go.mod h1:1uoZvP8Avyfhe3Y4he7sMOR16ZiAm2Q+Rc cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= -cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU= -cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo= cloud.google.com/go/contactcenterinsights v1.17.3/go.mod h1:7Uu2CpxS3f6XxhRdlEzYAkrChpR5P5QfcdGAFEdHOG8= cloud.google.com/go/contactcenterinsights v1.17.4/go.mod h1:kZe6yOnKDfpPz2GphDHynxk/Spx+53UX/pGf+SmWAKM= cloud.google.com/go/container v1.43.0/go.mod h1:ETU9WZ1KM9ikEKLzrhRVao7KHtalDQu6aPqM34zDr/U= @@ -182,8 +170,6 @@ cloud.google.com/go/gkemulticloud v1.5.4/go.mod h1:7l9+6Tp4jySSGj4PStO8CE6RrHFdc cloud.google.com/go/grafeas v0.3.15/go.mod h1:irwcwIQOBlLBotGdMwme8PipnloOPqILfIvMwlmu8Pk= cloud.google.com/go/gsuiteaddons v1.7.7/go.mod h1:zTGmmKG/GEBCONsvMOY2ckDiEsq3FN+lzWGUiXccF9o= cloud.google.com/go/gsuiteaddons v1.7.8/go.mod h1:DBKNHH4YXAdd/rd6zVvtOGAJNGo0ekOh+nIjTUDEJ5U= -cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8= -cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE= cloud.google.com/go/iam v1.5.3/go.mod h1:MR3v9oLkZCTlaqljW6Eb2d3HGDGK5/bDv93jhfISFvU= cloud.google.com/go/iap v1.11.2/go.mod h1:Bh99DMUpP5CitL9lK0BC8MYgjjYO4b3FbyhgW1VHJvg= cloud.google.com/go/iap v1.11.3/go.mod h1:+gXO0ClH62k2LVlfhHzrpiHQNyINlEVmGAE3+DB4ShU= @@ -203,8 +189,6 @@ cloud.google.com/go/longrunning v0.5.6/go.mod h1:vUaDrWYOMKRuhiv6JBnn49YxCPz2Ayn cloud.google.com/go/longrunning v0.5.7 h1:WLbHekDbjK1fVFD3ibpFFVoyizlLRl73I7YKuAKilhU= cloud.google.com/go/longrunning v0.5.7/go.mod h1:8GClkudohy1Fxm3owmBGid8W0pSgodEMwEAztp38Xng= cloud.google.com/go/longrunning v0.6.6/go.mod h1:hyeGJUrPHcx0u2Uu1UFSoYZLn4lkMrccJig0t4FI7yw= -cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE= -cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY= cloud.google.com/go/longrunning v0.7.0/go.mod h1:ySn2yXmjbK9Ba0zsQqunhDkYi0+9rlXIwnoAf+h+TPY= cloud.google.com/go/managedidentities v1.7.6/go.mod h1:pYCWPaI1AvR8Q027Vtp+SFSM/VOVgbjBF4rxp1/z5p4= cloud.google.com/go/managedidentities v1.7.7/go.mod h1:nwNlMxtBo2YJMvsKXRtAD1bL41qiCI9npS7cbqrsJUs= @@ -472,7 +456,6 @@ github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHf github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cristalhq/acmd v0.12.0 h1:RdlKnxjN+txbQosg8p/TRNZ+J1Rdne43MVQZ1zDhGWk= github.com/cristalhq/acmd v0.12.0/go.mod h1:LG5oa43pE/BbxtfMoImHCQN++0Su7dzipdgBjMCBVDQ= github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 h1:iwZdTE0PVqJCos1vaoKsclOGD3ADKpshg3SRtYBbwso= @@ -605,8 +588,6 @@ github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl76 github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/generative-ai-go v0.19.0 h1:R71szggh8wHMCUlEMsW2A/3T+5LdEIkiaHSYgSpUgdg= github.com/google/generative-ai-go v0.19.0/go.mod h1:JYolL13VG7j79kM5BtHz4qwONHkeJQzOCkKXnpqtS/E= -github.com/google/generative-ai-go v0.20.1 h1:6dEIujpgN2V0PgLhr6c/M1ynRdc7ARtiIDPFzj45uNQ= -github.com/google/generative-ai-go v0.20.1/go.mod h1:TjOnZJmZKzarWbjUJgy+r3Ee7HGBRVLhOIgupnwR4Bg= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -646,22 +627,19 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/cloud-bigtable-clients-test v0.0.3/go.mod h1:TWtDzrrAI70C3dNLDY+nZN3gxHtFdZIbpL9rCTFyxE0= github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/enterprise-certificate-proxy v0.3.5/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= -github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4= -github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= github.com/googleapis/gax-go/v2 v2.12.5/go.mod h1:BUDKcWo+RaKq5SC9vVYL0wLADa3VcfswbOMMRmB9H3E= github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0= github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w= -github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo= -github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= github.com/goph/emperror v0.17.2 h1:yLapQcmEsO0ipe9p5TaN22djm3OFV/TfM/fcYP0/J18= github.com/goph/emperror v0.17.2/go.mod h1:+ZbQ+fUNO/6FNiUo0ujtMjhgad9Xa6fQL9KhH4LNHic= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= @@ -735,7 +713,6 @@ github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= @@ -829,7 +806,6 @@ github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2 github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pinecone-io/go-pinecone v0.4.1/go.mod h1:KwWSueZFx9zccC+thBk13+LDiOgii8cff9bliUI4tQs= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= @@ -847,7 +823,6 @@ github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71 h1:CN github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50= github.com/redis/rueidis v1.0.34/go.mod h1:g8nPmgR4C68N3abFiOc/gUOSEKw3Tom6/teYMehg4RE= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= @@ -990,8 +965,6 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.5 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 h1:rgMkmiGfix9vFJDcDi1PK8WEQP4FLQwLDfhp5ZLpFeE= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0/go.mod h1:vy+2G/6NvVMpwGX/NyLqcC41fxepnuKHk16E6IZUcJc= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= @@ -1253,8 +1226,6 @@ golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= -golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= -golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -1346,8 +1317,6 @@ google.golang.org/api v0.235.0/go.mod h1:QpeJkemzkFKe5VCE/PMv7GsUfn9ZF+u+q1Q7w6c google.golang.org/api v0.237.0 h1:MP7XVsGZesOsx3Q8WVa4sUdbrsTvDSOERd3Vh4xj/wc= google.golang.org/api v0.237.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50= google.golang.org/api v0.239.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50= -google.golang.org/api v0.246.0 h1:H0ODDs5PnMZVZAEtdLMn2Ul2eQi7QNjqM2DIFp8TlTM= -google.golang.org/api v0.246.0/go.mod h1:dMVhVcylamkirHdzEBAIQWUCgqY885ivNeZYd7VAVr8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1398,8 +1367,6 @@ google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:sAo5UzpjUwgFBCzupwhcLcxHVDK7vG5IqI30YnwX2eE= google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk= -google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4= -google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s= google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= google.golang.org/genproto/googleapis/api v0.0.0-20240429193739-8cf5692501f6/go.mod h1:10yRODfgim2/T8csjQsMPgZOMvtytXKTDRzH6HRGzRw= google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU= @@ -1528,6 +1495,7 @@ modernc.org/scannertest v1.0.2 h1:JPtfxcVdbRvzmRf2YUvsDibJsQRw8vKA/3jb31y7cy0= modernc.org/scannertest v1.0.2/go.mod h1:RzTm5RwglF/6shsKoEivo8N91nQIoWtcWI7ns+zPyGA= modernc.org/y v1.1.0 h1:JdIvLry+rKeSsVNRCdr6YWYimwwNm0GXtzxid77VfWc= modernc.org/y v1.1.0/go.mod h1:Iz3BmyIS4OwAbwGaUS7cqRrLsSsfp2sFWtpzX+P4CsE= +nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/install.ps1 b/install.ps1 new file mode 100644 index 000000000..c16f16ef1 --- /dev/null +++ b/install.ps1 @@ -0,0 +1,722 @@ +# Issue Tracker: https://github.com/ScoopInstaller/Install/issues +# Unlicense License: +# +# This is free and unencumbered software released into the public domain. +# +# Anyone is free to copy, modify, publish, use, compile, sell, or +# distribute this software, either in source code form or as a compiled +# binary, for any purpose, commercial or non-commercial, and by any +# means. +# +# In jurisdictions that recognize copyright laws, the author or authors +# of this software dedicate any and all copyright interest in the +# software to the public domain. We make this dedication for the benefit +# of the public at large and to the detriment of our heirs and +# successors. We intend this dedication to be an overt act of +# relinquishment in perpetuity of all present and future rights to this +# software under copyright law. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# For more information, please refer to + +<# +.SYNOPSIS + Scoop installer. +.DESCRIPTION + The installer of Scoop. For details please check the website and wiki. +.PARAMETER ScoopDir + Specifies Scoop root path. + If not specified, Scoop will be installed to '$env:USERPROFILE\scoop'. +.PARAMETER ScoopGlobalDir + Specifies directory to store global apps. + If not specified, global apps will be installed to '$env:ProgramData\scoop'. +.PARAMETER ScoopCacheDir + Specifies cache directory. + If not specified, caches will be downloaded to '$ScoopDir\cache'. +.PARAMETER NoProxy + Bypass system proxy during the installation. +.PARAMETER Proxy + Specifies proxy to use during the installation. +.PARAMETER ProxyCredential + Specifies credential for the given proxy. +.PARAMETER ProxyUseDefaultCredentials + Use the credentials of the current user for the proxy server that is specified by the -Proxy parameter. +.PARAMETER RunAsAdmin + Force to run the installer as administrator. +.LINK + https://scoop.sh +.LINK + https://github.com/ScoopInstaller/Scoop/wiki +#> +param( + [String] $ScoopDir, + [String] $ScoopGlobalDir, + [String] $ScoopCacheDir, + [Switch] $NoProxy, + [Uri] $Proxy, + [System.Management.Automation.PSCredential] $ProxyCredential, + [Switch] $ProxyUseDefaultCredentials, + [Switch] $RunAsAdmin +) + +# Disable StrictMode in this script +Set-StrictMode -Off + +function Write-InstallInfo { + param( + [Parameter(Mandatory = $True, Position = 0)] + [String] $String, + [Parameter(Mandatory = $False, Position = 1)] + [System.ConsoleColor] $ForegroundColor = $host.UI.RawUI.ForegroundColor + ) + + $backup = $host.UI.RawUI.ForegroundColor + + if ($ForegroundColor -ne $host.UI.RawUI.ForegroundColor) { + $host.UI.RawUI.ForegroundColor = $ForegroundColor + } + + Write-Output "$String" + + $host.UI.RawUI.ForegroundColor = $backup +} + +function Exit-Install { + param( + [Int] $ErrorCode = 1 + ) + + if ($IS_EXECUTED_FROM_IEX) { + # Don't abort with `exit` that would close the PS session if invoked + # with iex, yet set `LASTEXITCODE` for the caller to check + $Global:LASTEXITCODE = $ErrorCode + break + } else { + exit $ErrorCode + } +} + +function Deny-Install { + param( + [String] $Message, + [Int] $ErrorCode = 1 + ) + + Write-InstallInfo -String $Message -ForegroundColor DarkRed + Write-InstallInfo 'Abort.' + Exit-Install -ErrorCode $ErrorCode +} + +function Test-LanguageMode { + if ($ExecutionContext.SessionState.LanguageMode -ne 'FullLanguage') { + # `Write-InstallInfo` cannot be used here as it depends on FullLanguage mode + Write-Output 'Scoop requires PowerShell FullLanguage mode to run, current PowerShell environment is restricted.' + Write-Output 'Abort.' + Exit-Install + } +} + +function Test-ValidateParameter { + if ($null -eq $Proxy -and ($null -ne $ProxyCredential -or $ProxyUseDefaultCredentials)) { + Deny-Install 'Provide a valid proxy URI for the -Proxy parameter when using the -ProxyCredential or -ProxyUseDefaultCredentials.' + } + + if ($ProxyUseDefaultCredentials -and $null -ne $ProxyCredential) { + Deny-Install "ProxyUseDefaultCredentials is conflict with ProxyCredential. Don't use the -ProxyCredential and -ProxyUseDefaultCredentials together." + } +} + +function Test-IsAdministrator { + return ([Security.Principal.WindowsPrincipal]` + [Security.Principal.WindowsIdentity]::GetCurrent()` + ).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) +} + +function Test-Prerequisite { + # Scoop requires PowerShell 5 at least + if (($PSVersionTable.PSVersion.Major) -lt 5) { + Deny-Install 'PowerShell 5 or later is required to run Scoop. Go to https://microsoft.com/powershell to get the latest version of PowerShell.' + } + + # Scoop requires TLS 1.2 SecurityProtocol, which exists in .NET Framework 4.5+ + if ([System.Enum]::GetNames([System.Net.SecurityProtocolType]) -notcontains 'Tls12') { + Deny-Install 'Scoop requires .NET Framework 4.5+ to work. Go to https://microsoft.com/net/download to get the latest version of .NET Framework.' + } + + # Ensure Robocopy.exe is accessible + if (!(Test-CommandAvailable('robocopy'))) { + Deny-Install "Scoop requires 'C:\Windows\System32\Robocopy.exe' to work. Please make sure 'C:\Windows\System32' is in your PATH." + } + + # Detect if RunAsAdministrator, there is no need to run as administrator when installing Scoop + if (!$RunAsAdmin -and (Test-IsAdministrator)) { + # Exception: Windows Sandbox, GitHub Actions CI + $exception = ($env:USERNAME -eq 'WDAGUtilityAccount') -or ($env:GITHUB_ACTIONS -eq 'true' -and $env:CI -eq 'true') + if (!$exception) { + Deny-Install 'Running the installer as administrator is disabled by default, see https://github.com/ScoopInstaller/Install#for-admin for details.' + } + } + + # Show notification to change execution policy + $allowedExecutionPolicy = @('Unrestricted', 'RemoteSigned', 'ByPass') + if ((Get-ExecutionPolicy).ToString() -notin $allowedExecutionPolicy) { + Deny-Install "PowerShell requires an execution policy in [$($allowedExecutionPolicy -join ', ')] to run Scoop. For example, to set the execution policy to 'RemoteSigned' please run 'Set-ExecutionPolicy RemoteSigned -Scope CurrentUser'." + } + + # Test if scoop is installed, by checking if scoop command exists. + if (Test-CommandAvailable('scoop')) { + Deny-Install "Scoop is already installed. Run 'scoop update' to get the latest version." -ErrorCode 0 + } +} + +function Optimize-SecurityProtocol { + # .NET Framework 4.7+ has a default security protocol called 'SystemDefault', + # which allows the operating system to choose the best protocol to use. + # If SecurityProtocolType contains 'SystemDefault' (means .NET4.7+ detected) + # and the value of SecurityProtocol is 'SystemDefault', just do nothing on SecurityProtocol, + # 'SystemDefault' will use TLS 1.2 if the webrequest requires. + $isNewerNetFramework = ([System.Enum]::GetNames([System.Net.SecurityProtocolType]) -contains 'SystemDefault') + $isSystemDefault = ([System.Net.ServicePointManager]::SecurityProtocol.Equals([System.Net.SecurityProtocolType]::SystemDefault)) + + # If not, change it to support TLS 1.2 + if (!($isNewerNetFramework -and $isSystemDefault)) { + # Set to TLS 1.2 (3072), then TLS 1.1 (768), and TLS 1.0 (192). Ssl3 has been superseded, + # https://docs.microsoft.com/en-us/dotnet/api/system.net.securityprotocoltype?view=netframework-4.5 + [System.Net.ServicePointManager]::SecurityProtocol = 3072 -bor 768 -bor 192 + Write-Verbose 'SecurityProtocol has been updated to support TLS 1.2' + } +} + +function Get-Downloader { + $downloadSession = New-Object System.Net.WebClient + + # Set proxy to null if NoProxy is specified + if ($NoProxy) { + $downloadSession.Proxy = $null + } elseif ($Proxy) { + # Prepend protocol if not provided + if (!$Proxy.IsAbsoluteUri) { + $Proxy = New-Object System.Uri('http://' + $Proxy.OriginalString) + } + + $Proxy = New-Object System.Net.WebProxy($Proxy) + + if ($null -ne $ProxyCredential) { + $Proxy.Credentials = $ProxyCredential.GetNetworkCredential() + } elseif ($ProxyUseDefaultCredentials) { + $Proxy.UseDefaultCredentials = $true + } + + $downloadSession.Proxy = $Proxy + } + + return $downloadSession +} + +function Test-isFileLocked { + param( + [String] $path + ) + + $file = New-Object System.IO.FileInfo $path + + if (!(Test-Path $path)) { + return $false + } + + try { + $stream = $file.Open( + [System.IO.FileMode]::Open, + [System.IO.FileAccess]::ReadWrite, + [System.IO.FileShare]::None + ) + if ($stream) { + $stream.Close() + } + return $false + } catch { + # The file is locked by a process. + return $true + } +} + +function Expand-ZipArchive { + param( + [String] $path, + [String] $to + ) + + if (!(Test-Path $path)) { + Deny-Install "Unzip failed: can't find $path to unzip." + } + + # Check if the zip file is locked, by antivirus software for example + $retries = 0 + while ($retries -le 10) { + if ($retries -eq 10) { + Deny-Install "Unzip failed: can't unzip because a process is locking the file." + } + if (Test-isFileLocked $path) { + Write-InstallInfo "Waiting for $path to be unlocked by another process... ($retries/10)" + $retries++ + Start-Sleep -Seconds 2 + } else { + break + } + } + + # Workaround to suspend Expand-Archive verbose output, + # upstream issue: https://github.com/PowerShell/Microsoft.PowerShell.Archive/issues/98 + $oldVerbosePreference = $VerbosePreference + $global:VerbosePreference = 'SilentlyContinue' + + # Disable progress bar to gain performance + $oldProgressPreference = $ProgressPreference + $global:ProgressPreference = 'SilentlyContinue' + + # PowerShell 5+: use Expand-Archive to extract zip files + Microsoft.PowerShell.Archive\Expand-Archive -Path $path -DestinationPath $to -Force + $global:VerbosePreference = $oldVerbosePreference + $global:ProgressPreference = $oldProgressPreference +} + +function Out-UTF8File { + param( + [Parameter(Mandatory = $True, Position = 0)] + [Alias('Path')] + [String] $FilePath, + [Switch] $Append, + [Switch] $NoNewLine, + [Parameter(ValueFromPipeline = $True)] + [PSObject] $InputObject + ) + process { + if ($Append) { + [System.IO.File]::AppendAllText($FilePath, $InputObject) + } else { + if (!$NoNewLine) { + # Ref: https://stackoverflow.com/questions/5596982 + # Performance Note: `WriteAllLines` throttles memory usage while + # `WriteAllText` needs to keep the complete string in memory. + [System.IO.File]::WriteAllLines($FilePath, $InputObject) + } else { + # However `WriteAllText` does not add ending newline. + [System.IO.File]::WriteAllText($FilePath, $InputObject) + } + } + } +} + +function Import-ScoopShim { + Write-InstallInfo 'Creating shim...' + # The scoop executable + $path = "$SCOOP_APP_DIR\bin\scoop.ps1" + + if (!(Test-Path $SCOOP_SHIMS_DIR)) { + New-Item -Type Directory $SCOOP_SHIMS_DIR | Out-Null + } + + # The scoop shim + $shim = "$SCOOP_SHIMS_DIR\scoop" + + # Convert to relative path + Push-Location $SCOOP_SHIMS_DIR + $relativePath = Resolve-Path -Relative $path + Pop-Location + $absolutePath = Resolve-Path $path + + # if $path points to another drive resolve-path prepends .\ which could break shims + $ps1text = if ($relativePath -match '^(\.\\)?\w:.*$') { + @( + "# $absolutePath", + "`$path = `"$path`"", + "if (`$MyInvocation.ExpectingInput) { `$input | & `$path $arg @args } else { & `$path $arg @args }", + "exit `$LASTEXITCODE" + ) + } else { + @( + "# $absolutePath", + "`$path = Join-Path `$PSScriptRoot `"$relativePath`"", + "if (`$MyInvocation.ExpectingInput) { `$input | & `$path $arg @args } else { & `$path $arg @args }", + "exit `$LASTEXITCODE" + ) + } + $ps1text -join "`r`n" | Out-UTF8File "$shim.ps1" + + # make ps1 accessible from cmd.exe + @( + "@rem $absolutePath", + '@echo off', + 'setlocal enabledelayedexpansion', + 'set args=%*', + ':: replace problem characters in arguments', + "set args=%args:`"='%", + "set args=%args:(=``(%", + "set args=%args:)=``)%", + "set invalid=`"='", + 'if !args! == !invalid! ( set args= )', + 'where /q pwsh.exe', + 'if %errorlevel% equ 0 (', + " pwsh -noprofile -ex unrestricted -file `"$absolutePath`" $arg %args%", + ') else (', + " powershell -noprofile -ex unrestricted -file `"$absolutePath`" $arg %args%", + ')' + ) -join "`r`n" | Out-UTF8File "$shim.cmd" + + @( + '#!/bin/sh', + "# $absolutePath", + 'if command -v pwsh.exe > /dev/null 2>&1; then', + " pwsh.exe -noprofile -ex unrestricted -file `"$absolutePath`" $arg `"$@`"", + 'else', + " powershell.exe -noprofile -ex unrestricted -file `"$absolutePath`" $arg `"$@`"", + 'fi' + ) -join "`n" | Out-UTF8File $shim -NoNewLine +} + +function Get-Env { + param( + [String] $name, + [Switch] $global + ) + + $RegisterKey = if ($global) { + Get-Item -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager' + } else { + Get-Item -Path 'HKCU:' + } + + $EnvRegisterKey = $RegisterKey.OpenSubKey('Environment') + $RegistryValueOption = [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames + $EnvRegisterKey.GetValue($name, $null, $RegistryValueOption) +} + +function Publish-Env { + if (-not ('Win32.NativeMethods' -as [Type])) { + Add-Type -Namespace Win32 -Name NativeMethods -MemberDefinition @' +[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] +public static extern IntPtr SendMessageTimeout( + IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam, + uint fuFlags, uint uTimeout, out UIntPtr lpdwResult); +'@ + } + + $HWND_BROADCAST = [IntPtr] 0xffff + $WM_SETTINGCHANGE = 0x1a + $result = [UIntPtr]::Zero + + [Win32.Nativemethods]::SendMessageTimeout($HWND_BROADCAST, + $WM_SETTINGCHANGE, + [UIntPtr]::Zero, + 'Environment', + 2, + 5000, + [ref] $result + ) | Out-Null +} + +function Write-Env { + param( + [String] $name, + [String] $val, + [Switch] $global + ) + + $RegisterKey = if ($global) { + Get-Item -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager' + } else { + Get-Item -Path 'HKCU:' + } + + $EnvRegisterKey = $RegisterKey.OpenSubKey('Environment', $true) + if ($val -eq $null) { + $EnvRegisterKey.DeleteValue($name) + } else { + $RegistryValueKind = if ($val.Contains('%')) { + [Microsoft.Win32.RegistryValueKind]::ExpandString + } elseif ($EnvRegisterKey.GetValue($name)) { + $EnvRegisterKey.GetValueKind($name) + } else { + [Microsoft.Win32.RegistryValueKind]::String + } + $EnvRegisterKey.SetValue($name, $val, $RegistryValueKind) + } + Publish-Env +} + +function Add-ShimsDirToPath { + # Get $env:PATH of current user + $userEnvPath = Get-Env 'PATH' + + if ($userEnvPath -notmatch [Regex]::Escape($SCOOP_SHIMS_DIR)) { + $h = (Get-PSProvider 'FileSystem').Home + if (!$h.EndsWith('\')) { + $h += '\' + } + + if (!($h -eq '\')) { + $friendlyPath = "$SCOOP_SHIMS_DIR" -replace ([Regex]::Escape($h)), '~\' + Write-InstallInfo "Adding $friendlyPath to your path." + } else { + Write-InstallInfo "Adding $SCOOP_SHIMS_DIR to your path." + } + + # For future sessions + Write-Env 'PATH' "$SCOOP_SHIMS_DIR;$userEnvPath" + # For current session + $env:PATH = "$SCOOP_SHIMS_DIR;$env:PATH" + } +} + +function Use-Config { + if (!(Test-Path $SCOOP_CONFIG_FILE)) { + return $null + } + + try { + return (Get-Content $SCOOP_CONFIG_FILE -Raw | ConvertFrom-Json -ErrorAction Stop) + } catch { + Deny-Install "ERROR loading $SCOOP_CONFIG_FILE`: $($_.Exception.Message)" + } +} + +function Add-Config { + param ( + [Parameter(Mandatory = $True, Position = 0)] + [String] $Name, + [Parameter(Mandatory = $True, Position = 1)] + [String] $Value + ) + + $scoopConfig = Use-Config + + if ($scoopConfig -is [System.Management.Automation.PSObject]) { + if ($Value -eq [bool]::TrueString -or $Value -eq [bool]::FalseString) { + $Value = [System.Convert]::ToBoolean($Value) + } + if ($null -eq $scoopConfig.$Name) { + $scoopConfig | Add-Member -MemberType NoteProperty -Name $Name -Value $Value + } else { + $scoopConfig.$Name = $Value + } + } else { + $baseDir = Split-Path -Path $SCOOP_CONFIG_FILE + if (!(Test-Path $baseDir)) { + New-Item -Type Directory $baseDir | Out-Null + } + + $scoopConfig = New-Object PSObject + $scoopConfig | Add-Member -MemberType NoteProperty -Name $Name -Value $Value + } + + if ($null -eq $Value) { + $scoopConfig.PSObject.Properties.Remove($Name) + } + + ConvertTo-Json $scoopConfig | Set-Content $SCOOP_CONFIG_FILE -Encoding ASCII + return $scoopConfig +} + +function Add-DefaultConfig { + # If user-level SCOOP env not defined, save to root_path + if (!(Get-Env 'SCOOP')) { + if ($SCOOP_DIR -ne "$env:USERPROFILE\scoop") { + Write-Verbose "Adding config root_path: $SCOOP_DIR" + Add-Config -Name 'root_path' -Value $SCOOP_DIR | Out-Null + } + } + + # Use system SCOOP_GLOBAL, or set system SCOOP_GLOBAL + # with $env:SCOOP_GLOBAL if RunAsAdmin, otherwise save to global_path + if (!(Get-Env 'SCOOP_GLOBAL' -global)) { + if ((Test-IsAdministrator) -and $env:SCOOP_GLOBAL) { + Write-Verbose "Setting System Environment Variable SCOOP_GLOBAL: $env:SCOOP_GLOBAL" + [Environment]::SetEnvironmentVariable('SCOOP_GLOBAL', $env:SCOOP_GLOBAL, 'Machine') + } else { + if ($SCOOP_GLOBAL_DIR -ne "$env:ProgramData\scoop") { + Write-Verbose "Adding config global_path: $SCOOP_GLOBAL_DIR" + Add-Config -Name 'global_path' -Value $SCOOP_GLOBAL_DIR | Out-Null + } + } + } + + # Use system SCOOP_CACHE, or set system SCOOP_CACHE + # with $env:SCOOP_CACHE if RunAsAdmin, otherwise save to cache_path + if (!(Get-Env 'SCOOP_CACHE' -global)) { + if ((Test-IsAdministrator) -and $env:SCOOP_CACHE) { + Write-Verbose "Setting System Environment Variable SCOOP_CACHE: $env:SCOOP_CACHE" + [Environment]::SetEnvironmentVariable('SCOOP_CACHE', $env:SCOOP_CACHE, 'Machine') + } else { + if ($SCOOP_CACHE_DIR -ne "$SCOOP_DIR\cache") { + Write-Verbose "Adding config cache_path: $SCOOP_CACHE_DIR" + Add-Config -Name 'cache_path' -Value $SCOOP_CACHE_DIR | Out-Null + } + } + } + + # save current datetime to last_update + Add-Config -Name 'last_update' -Value ([System.DateTime]::Now.ToString('o')) | Out-Null +} + +function Test-CommandAvailable { + param ( + [Parameter(Mandatory = $True, Position = 0)] + [String] $Command + ) + return [Boolean](Get-Command $Command -ErrorAction SilentlyContinue) +} + +function Install-Scoop { + Write-InstallInfo 'Initializing...' + # Validate install parameters + Test-ValidateParameter + # Check prerequisites + Test-Prerequisite + # Enable TLS 1.2 + Optimize-SecurityProtocol + + # Download scoop from GitHub + Write-InstallInfo 'Downloading...' + $downloader = Get-Downloader + [bool]$downloadZipsRequired = $True + + if (Test-CommandAvailable('git')) { + $old_https = $env:HTTPS_PROXY + $old_http = $env:HTTP_PROXY + try { + if ($downloader.Proxy) { + #define env vars for git when behind a proxy + $Env:HTTP_PROXY = $downloader.Proxy.Address + $Env:HTTPS_PROXY = $downloader.Proxy.Address + } + Write-Verbose "Cloning $SCOOP_PACKAGE_GIT_REPO to $SCOOP_APP_DIR" + git clone -q $SCOOP_PACKAGE_GIT_REPO $SCOOP_APP_DIR + if (-not $?) { + throw 'Cloning failed. Falling back to downloading zip files.' + } + Write-Verbose "Cloning $SCOOP_MAIN_BUCKET_GIT_REPO to $SCOOP_MAIN_BUCKET_DIR" + git clone -q $SCOOP_MAIN_BUCKET_GIT_REPO $SCOOP_MAIN_BUCKET_DIR + if (-not $?) { + throw 'Cloning failed. Falling back to downloading zip files.' + } + $downloadZipsRequired = $False + } catch { + Write-Warning "$($_.Exception.Message)" + $Global:LASTEXITCODE = 0 + } finally { + $env:HTTPS_PROXY = $old_https + $env:HTTP_PROXY = $old_http + } + } + + if ($downloadZipsRequired) { + # 1. download scoop + $scoopZipfile = "$SCOOP_APP_DIR\scoop.zip" + if (!(Test-Path $SCOOP_APP_DIR)) { + New-Item -Type Directory $SCOOP_APP_DIR | Out-Null + } + Write-Verbose "Downloading $SCOOP_PACKAGE_REPO to $scoopZipfile" + $downloader.downloadFile($SCOOP_PACKAGE_REPO, $scoopZipfile) + # 2. download scoop main bucket + $scoopMainZipfile = "$SCOOP_MAIN_BUCKET_DIR\scoop-main.zip" + if (!(Test-Path $SCOOP_MAIN_BUCKET_DIR)) { + New-Item -Type Directory $SCOOP_MAIN_BUCKET_DIR | Out-Null + } + Write-Verbose "Downloading $SCOOP_MAIN_BUCKET_REPO to $scoopMainZipfile" + $downloader.downloadFile($SCOOP_MAIN_BUCKET_REPO, $scoopMainZipfile) + + # Extract files from downloaded zip + Write-InstallInfo 'Extracting...' + # 1. extract scoop + $scoopUnzipTempDir = "$SCOOP_APP_DIR\_tmp" + Write-Verbose "Extracting $scoopZipfile to $scoopUnzipTempDir" + Expand-ZipArchive $scoopZipfile $scoopUnzipTempDir + Copy-Item "$scoopUnzipTempDir\scoop-*\*" $SCOOP_APP_DIR -Recurse -Force + # 2. extract scoop main bucket + $scoopMainUnzipTempDir = "$SCOOP_MAIN_BUCKET_DIR\_tmp" + Write-Verbose "Extracting $scoopMainZipfile to $scoopMainUnzipTempDir" + Expand-ZipArchive $scoopMainZipfile $scoopMainUnzipTempDir + Copy-Item "$scoopMainUnzipTempDir\Main-*\*" $SCOOP_MAIN_BUCKET_DIR -Recurse -Force + + # Cleanup + Remove-Item $scoopUnzipTempDir -Recurse -Force + Remove-Item $scoopZipfile + Remove-Item $scoopMainUnzipTempDir -Recurse -Force + Remove-Item $scoopMainZipfile + } + # Create the scoop shim + Import-ScoopShim + # Ensure scoop shims is in the PATH + Add-ShimsDirToPath + # Setup initial configuration of Scoop + Add-DefaultConfig + + Write-InstallInfo 'Scoop was installed successfully!' -ForegroundColor DarkGreen + Write-InstallInfo "Type 'scoop help' for instructions." +} + +function Write-DebugInfo { + param($BoundArgs) + + Write-Verbose '-------- PSBoundParameters --------' + $BoundArgs.GetEnumerator() | ForEach-Object { Write-Verbose $_ } + Write-Verbose '-------- Environment Variables --------' + Write-Verbose "`$env:USERPROFILE: $env:USERPROFILE" + Write-Verbose "`$env:ProgramData: $env:ProgramData" + Write-Verbose "`$env:SCOOP: $env:SCOOP" + Write-Verbose "`$env:SCOOP_CACHE: $SCOOP_CACHE" + Write-Verbose "`$env:SCOOP_GLOBAL: $env:SCOOP_GLOBAL" + Write-Verbose '-------- Selected Variables --------' + Write-Verbose "SCOOP_DIR: $SCOOP_DIR" + Write-Verbose "SCOOP_CACHE_DIR: $SCOOP_CACHE_DIR" + Write-Verbose "SCOOP_GLOBAL_DIR: $SCOOP_GLOBAL_DIR" + Write-Verbose "SCOOP_CONFIG_HOME: $SCOOP_CONFIG_HOME" +} + +# Prepare variables +$IS_EXECUTED_FROM_IEX = ($null -eq $MyInvocation.MyCommand.Path) + +# Abort when the language mode is restricted +Test-LanguageMode + +# Scoop root directory +$SCOOP_DIR = $ScoopDir, $env:SCOOP, "$env:USERPROFILE\scoop" | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -First 1 +# Scoop global apps directory +$SCOOP_GLOBAL_DIR = $ScoopGlobalDir, $env:SCOOP_GLOBAL, "$env:ProgramData\scoop" | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -First 1 +# Scoop cache directory +$SCOOP_CACHE_DIR = $ScoopCacheDir, $env:SCOOP_CACHE, "$SCOOP_DIR\cache" | Where-Object { -not [String]::IsNullOrEmpty($_) } | Select-Object -First 1 +# Scoop shims directory +$SCOOP_SHIMS_DIR = "$SCOOP_DIR\shims" +# Scoop itself directory +$SCOOP_APP_DIR = "$SCOOP_DIR\apps\scoop\current" +# Scoop main bucket directory +$SCOOP_MAIN_BUCKET_DIR = "$SCOOP_DIR\buckets\main" +# Scoop config file location +$SCOOP_CONFIG_HOME = $env:XDG_CONFIG_HOME, "$env:USERPROFILE\.config" | Select-Object -First 1 +$SCOOP_CONFIG_FILE = "$SCOOP_CONFIG_HOME\scoop\config.json" + +# TODO: Use a specific version of Scoop and the main bucket +$SCOOP_PACKAGE_REPO = 'https://github.com/ScoopInstaller/Scoop/archive/master.zip' +$SCOOP_MAIN_BUCKET_REPO = 'https://github.com/ScoopInstaller/Main/archive/master.zip' + +$SCOOP_PACKAGE_GIT_REPO = 'https://github.com/ScoopInstaller/Scoop.git' +$SCOOP_MAIN_BUCKET_GIT_REPO = 'https://github.com/ScoopInstaller/Main.git' + +# Quit if anything goes wrong +$oldErrorActionPreference = $ErrorActionPreference +$ErrorActionPreference = 'Stop' + +# Logging debug info +Write-DebugInfo $PSBoundParameters +# Bootstrap function +Install-Scoop + +# Reset $ErrorActionPreference to original value +$ErrorActionPreference = $oldErrorActionPreference diff --git a/packages/client/src/app/router/route-tree.gen.ts b/packages/client/src/app/router/route-tree.gen.ts index 6cd100d81..5d073f254 100644 --- a/packages/client/src/app/router/route-tree.gen.ts +++ b/packages/client/src/app/router/route-tree.gen.ts @@ -14,9 +14,11 @@ import { Route as dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDot import { Route as dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotUserRoutesSignInRouteImport } from './../../pages/user/routes/signIn' import { Route as dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWorkspaceRoutesWorkspaceWorkspaceIdCanRouteRouteImport } from './../../pages/workspace/routes/workspace/$workspaceIdCan/route' import { Route as dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWorkspaceRoutesWorkspaceWorkspaceIdCanIndexRouteImport } from './../../pages/workspace/routes/workspace/$workspaceIdCan/index' +import { Route as dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanRouteRouteImport } from './../../pages/websocket/routes/websocket/$websocketIdCan/route' import { Route as dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotHttpRoutesHttpHttpIdCanRouteRouteImport } from './../../pages/http/routes/http/$httpIdCan/route' import { Route as dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotGraphqlRoutesGraphqlGraphqlIdCanRouteRouteImport } from './../../pages/graphql/routes/graphql/$graphqlIdCan/route' import { Route as dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotFlowRoutesFlowFlowIdCanRouteRouteImport } from './../../pages/flow/routes/flow/$flowIdCan/route' +import { Route as dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanIndexRouteImport } from './../../pages/websocket/routes/websocket/$websocketIdCan/index' import { Route as dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotHttpRoutesHttpHttpIdCanIndexRouteImport } from './../../pages/http/routes/http/$httpIdCan/index' import { Route as dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotGraphqlRoutesGraphqlGraphqlIdCanIndexRouteImport } from './../../pages/graphql/routes/graphql/$graphqlIdCan/index' import { Route as dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotFlowRoutesFlowFlowIdCanIndexRouteImport } from './../../pages/flow/routes/flow/$flowIdCan/index' @@ -64,6 +66,15 @@ const dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWorkspace dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWorkspaceRoutesWorkspaceWorkspaceIdCanRouteRoute, } as any, ) +const dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanRouteRoute = + dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanRouteRouteImport.update( + { + id: '/(websocket)/websocket/$websocketIdCan', + path: '/websocket/$websocketIdCan', + getParentRoute: () => + dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWorkspaceRoutesWorkspaceWorkspaceIdCanRouteRoute, + } as any, + ) const dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotHttpRoutesHttpHttpIdCanRouteRoute = dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotHttpRoutesHttpHttpIdCanRouteRouteImport.update( { @@ -91,6 +102,15 @@ const dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotFlowRoute dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWorkspaceRoutesWorkspaceWorkspaceIdCanRouteRoute, } as any, ) +const dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanIndexRoute = + dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanIndexRouteImport.update( + { + id: '/', + path: '/', + getParentRoute: () => + dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanRouteRoute, + } as any, + ) const dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotHttpRoutesHttpHttpIdCanIndexRoute = dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotHttpRoutesHttpHttpIdCanIndexRouteImport.update( { @@ -164,11 +184,13 @@ export interface FileRoutesByFullPath { '/workspace/$workspaceIdCan/flow/$flowIdCan': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotFlowRoutesFlowFlowIdCanRouteRouteWithChildren '/workspace/$workspaceIdCan/graphql/$graphqlIdCan': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotGraphqlRoutesGraphqlGraphqlIdCanRouteRouteWithChildren '/workspace/$workspaceIdCan/http/$httpIdCan': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotHttpRoutesHttpHttpIdCanRouteRouteWithChildren + '/workspace/$workspaceIdCan/websocket/$websocketIdCan': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanRouteRouteWithChildren '/workspace/$workspaceIdCan/flow/$flowIdCan/history': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotFlowRoutesFlowFlowIdCanHistoryRoute - '/workspace/$workspaceIdCan/credential/$credentialIdCan': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotCredentialRoutesCredentialCredentialIdCanIndexRoute + '/workspace/$workspaceIdCan/credential/$credentialIdCan/': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotCredentialRoutesCredentialCredentialIdCanIndexRoute '/workspace/$workspaceIdCan/flow/$flowIdCan/': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotFlowRoutesFlowFlowIdCanIndexRoute '/workspace/$workspaceIdCan/graphql/$graphqlIdCan/': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotGraphqlRoutesGraphqlGraphqlIdCanIndexRoute '/workspace/$workspaceIdCan/http/$httpIdCan/': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotHttpRoutesHttpHttpIdCanIndexRoute + '/workspace/$workspaceIdCan/websocket/$websocketIdCan/': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanIndexRoute '/workspace/$workspaceIdCan/graphql/$graphqlIdCan/delta/$deltaGraphqlIdCan': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotGraphqlRoutesGraphqlGraphqlIdCanDeltaDotdeltaGraphqlIdCanRoute '/workspace/$workspaceIdCan/http/$httpIdCan/delta/$deltaHttpIdCan': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotHttpRoutesHttpHttpIdCanDeltaDotdeltaHttpIdCanRoute } @@ -182,6 +204,7 @@ export interface FileRoutesByTo { '/workspace/$workspaceIdCan/flow/$flowIdCan': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotFlowRoutesFlowFlowIdCanIndexRoute '/workspace/$workspaceIdCan/graphql/$graphqlIdCan': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotGraphqlRoutesGraphqlGraphqlIdCanIndexRoute '/workspace/$workspaceIdCan/http/$httpIdCan': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotHttpRoutesHttpHttpIdCanIndexRoute + '/workspace/$workspaceIdCan/websocket/$websocketIdCan': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanIndexRoute '/workspace/$workspaceIdCan/graphql/$graphqlIdCan/delta/$deltaGraphqlIdCan': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotGraphqlRoutesGraphqlGraphqlIdCanDeltaDotdeltaGraphqlIdCanRoute '/workspace/$workspaceIdCan/http/$httpIdCan/delta/$deltaHttpIdCan': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotHttpRoutesHttpHttpIdCanDeltaDotdeltaHttpIdCanRoute } @@ -195,11 +218,13 @@ export interface FileRoutesById { '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(flow)/flow/$flowIdCan': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotFlowRoutesFlowFlowIdCanRouteRouteWithChildren '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(graphql)/graphql/$graphqlIdCan': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotGraphqlRoutesGraphqlGraphqlIdCanRouteRouteWithChildren '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(http)/http/$httpIdCan': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotHttpRoutesHttpHttpIdCanRouteRouteWithChildren + '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(websocket)/websocket/$websocketIdCan': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanRouteRouteWithChildren '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(flow)/flow/$flowIdCan/history': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotFlowRoutesFlowFlowIdCanHistoryRoute '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(credential)/credential/$credentialIdCan/': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotCredentialRoutesCredentialCredentialIdCanIndexRoute '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(flow)/flow/$flowIdCan/': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotFlowRoutesFlowFlowIdCanIndexRoute '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(graphql)/graphql/$graphqlIdCan/': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotGraphqlRoutesGraphqlGraphqlIdCanIndexRoute '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(http)/http/$httpIdCan/': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotHttpRoutesHttpHttpIdCanIndexRoute + '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(websocket)/websocket/$websocketIdCan/': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanIndexRoute '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(graphql)/graphql/$graphqlIdCan/delta/$deltaGraphqlIdCan': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotGraphqlRoutesGraphqlGraphqlIdCanDeltaDotdeltaGraphqlIdCanRoute '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(http)/http/$httpIdCan/delta/$deltaHttpIdCan': typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotHttpRoutesHttpHttpIdCanDeltaDotdeltaHttpIdCanRoute } @@ -214,11 +239,13 @@ export interface FileRouteTypes { | '/workspace/$workspaceIdCan/flow/$flowIdCan' | '/workspace/$workspaceIdCan/graphql/$graphqlIdCan' | '/workspace/$workspaceIdCan/http/$httpIdCan' + | '/workspace/$workspaceIdCan/websocket/$websocketIdCan' | '/workspace/$workspaceIdCan/flow/$flowIdCan/history' - | '/workspace/$workspaceIdCan/credential/$credentialIdCan' + | '/workspace/$workspaceIdCan/credential/$credentialIdCan/' | '/workspace/$workspaceIdCan/flow/$flowIdCan/' | '/workspace/$workspaceIdCan/graphql/$graphqlIdCan/' | '/workspace/$workspaceIdCan/http/$httpIdCan/' + | '/workspace/$workspaceIdCan/websocket/$websocketIdCan/' | '/workspace/$workspaceIdCan/graphql/$graphqlIdCan/delta/$deltaGraphqlIdCan' | '/workspace/$workspaceIdCan/http/$httpIdCan/delta/$deltaHttpIdCan' fileRoutesByTo: FileRoutesByTo @@ -232,6 +259,7 @@ export interface FileRouteTypes { | '/workspace/$workspaceIdCan/flow/$flowIdCan' | '/workspace/$workspaceIdCan/graphql/$graphqlIdCan' | '/workspace/$workspaceIdCan/http/$httpIdCan' + | '/workspace/$workspaceIdCan/websocket/$websocketIdCan' | '/workspace/$workspaceIdCan/graphql/$graphqlIdCan/delta/$deltaGraphqlIdCan' | '/workspace/$workspaceIdCan/http/$httpIdCan/delta/$deltaHttpIdCan' id: @@ -244,11 +272,13 @@ export interface FileRouteTypes { | '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(flow)/flow/$flowIdCan' | '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(graphql)/graphql/$graphqlIdCan' | '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(http)/http/$httpIdCan' + | '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(websocket)/websocket/$websocketIdCan' | '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(flow)/flow/$flowIdCan/history' | '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(credential)/credential/$credentialIdCan/' | '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(flow)/flow/$flowIdCan/' | '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(graphql)/graphql/$graphqlIdCan/' | '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(http)/http/$httpIdCan/' + | '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(websocket)/websocket/$websocketIdCan/' | '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(graphql)/graphql/$graphqlIdCan/delta/$deltaGraphqlIdCan' | '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(http)/http/$httpIdCan/delta/$deltaHttpIdCan' fileRoutesById: FileRoutesById @@ -297,6 +327,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWorkspaceRoutesWorkspaceWorkspaceIdCanIndexRouteImport parentRoute: typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWorkspaceRoutesWorkspaceWorkspaceIdCanRouteRoute } + '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(websocket)/websocket/$websocketIdCan': { + id: '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(websocket)/websocket/$websocketIdCan' + path: '/websocket/$websocketIdCan' + fullPath: '/workspace/$workspaceIdCan/websocket/$websocketIdCan' + preLoaderRoute: typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanRouteRouteImport + parentRoute: typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWorkspaceRoutesWorkspaceWorkspaceIdCanRouteRoute + } '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(http)/http/$httpIdCan': { id: '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(http)/http/$httpIdCan' path: '/http/$httpIdCan' @@ -318,6 +355,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotFlowRoutesFlowFlowIdCanRouteRouteImport parentRoute: typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWorkspaceRoutesWorkspaceWorkspaceIdCanRouteRoute } + '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(websocket)/websocket/$websocketIdCan/': { + id: '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(websocket)/websocket/$websocketIdCan/' + path: '/' + fullPath: '/workspace/$workspaceIdCan/websocket/$websocketIdCan/' + preLoaderRoute: typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanIndexRouteImport + parentRoute: typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanRouteRoute + } '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(http)/http/$httpIdCan/': { id: '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(http)/http/$httpIdCan/' path: '/' @@ -342,7 +386,7 @@ declare module '@tanstack/react-router' { '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(credential)/credential/$credentialIdCan/': { id: '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(credential)/credential/$credentialIdCan/' path: '/credential/$credentialIdCan' - fullPath: '/workspace/$workspaceIdCan/credential/$credentialIdCan' + fullPath: '/workspace/$workspaceIdCan/credential/$credentialIdCan/' preLoaderRoute: typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotCredentialRoutesCredentialCredentialIdCanIndexRouteImport parentRoute: typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWorkspaceRoutesWorkspaceWorkspaceIdCanRouteRoute } @@ -424,11 +468,27 @@ const dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotHttpRoute dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotHttpRoutesHttpHttpIdCanRouteRouteChildren, ) +interface dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanRouteRouteChildren { + dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanIndexRoute: typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanIndexRoute +} + +const dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanRouteRouteChildren: dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanRouteRouteChildren = + { + dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanIndexRoute: + dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanIndexRoute, + } + +const dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanRouteRouteWithChildren = + dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanRouteRoute._addFileChildren( + dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanRouteRouteChildren, + ) + interface dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWorkspaceRoutesWorkspaceWorkspaceIdCanRouteRouteChildren { dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWorkspaceRoutesWorkspaceWorkspaceIdCanIndexRoute: typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWorkspaceRoutesWorkspaceWorkspaceIdCanIndexRoute dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotFlowRoutesFlowFlowIdCanRouteRoute: typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotFlowRoutesFlowFlowIdCanRouteRouteWithChildren dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotGraphqlRoutesGraphqlGraphqlIdCanRouteRoute: typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotGraphqlRoutesGraphqlGraphqlIdCanRouteRouteWithChildren dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotHttpRoutesHttpHttpIdCanRouteRoute: typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotHttpRoutesHttpHttpIdCanRouteRouteWithChildren + dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanRouteRoute: typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanRouteRouteWithChildren dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotCredentialRoutesCredentialCredentialIdCanIndexRoute: typeof dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotCredentialRoutesCredentialCredentialIdCanIndexRoute } @@ -442,6 +502,8 @@ const dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWorkspace dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotGraphqlRoutesGraphqlGraphqlIdCanRouteRouteWithChildren, dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotHttpRoutesHttpHttpIdCanRouteRoute: dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotHttpRoutesHttpHttpIdCanRouteRouteWithChildren, + dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanRouteRoute: + dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotWebsocketRoutesWebsocketWebsocketIdCanRouteRouteWithChildren, dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotCredentialRoutesCredentialCredentialIdCanIndexRoute: dashboardDotDotDotDotDotDotDotDotPagesDashboardRoutesDotDotDotDotCredentialRoutesCredentialCredentialIdCanIndexRoute, } diff --git a/packages/client/src/features/file-system/index.tsx b/packages/client/src/features/file-system/index.tsx index 72bb20001..5cb800586 100644 --- a/packages/client/src/features/file-system/index.tsx +++ b/packages/client/src/features/file-system/index.tsx @@ -15,7 +15,7 @@ import { TreeProps, useDragAndDrop, } from 'react-aria-components'; -import { FiFolder, FiMoreHorizontal, FiX } from 'react-icons/fi'; +import { FiFolder, FiMoreHorizontal, FiWifi, FiX } from 'react-icons/fi'; import { RiAnthropicFill, RiGeminiFill, RiOpenaiFill } from 'react-icons/ri'; import { TbGauge } from 'react-icons/tb'; import { twJoin } from 'tailwind-merge'; @@ -31,6 +31,7 @@ import { import { FlowSchema, FlowService } from '@the-dev-tools/spec/buf/api/flow/v1/flow_pb'; import { GraphQLSchema as GraphQLItemSchema } from '@the-dev-tools/spec/buf/api/graph_q_l/v1/graph_q_l_pb'; import { HttpDeltaSchema, HttpMethod, HttpSchema, HttpService } from '@the-dev-tools/spec/buf/api/http/v1/http_pb'; +import { WebSocketSchema as WebSocketItemSchema } from '@the-dev-tools/spec/buf/api/web_socket/v1/web_socket_pb'; import { CredentialAnthropicCollectionSchema, CredentialCollectionSchema, @@ -41,6 +42,7 @@ import { FileCollectionSchema, FolderCollectionSchema } from '@the-dev-tools/spe import { FlowCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/flow'; import { GraphQLCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/graph_q_l'; import { HttpCollectionSchema, HttpDeltaCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/http'; +import { WebSocketCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/web_socket'; import { Button } from '@the-dev-tools/ui/button'; import { FlowsIcon, FolderOpenedIcon } from '@the-dev-tools/ui/icons'; import { Menu, MenuItem, useContextMenuState } from '@the-dev-tools/ui/menu'; @@ -89,6 +91,7 @@ export const FileCreateMenu = ({ parentFolderId, ...props }: FileCreateMenuProps const graphqlCollection = useApiCollection(GraphQLCollectionSchema); const httpCollection = useApiCollection(HttpCollectionSchema); const flowCollection = useApiCollection(FlowCollectionSchema); + const websocketCollection = useApiCollection(WebSocketCollectionSchema); const insertFile = useInsertFile(parentFolderId); @@ -152,6 +155,16 @@ export const FileCreateMenu = ({ parentFolderId, ...props }: FileCreateMenuProps Flow + { + const websocketUlid = Ulid.generate(); + websocketCollection.utils.insert({ name: 'New WebSocket', url: '', websocketId: websocketUlid.bytes }); + await insertFile({ fileId: websocketUlid.bytes, kind: FileKind.WEB_SOCKET }); + }} + > + WebSocket + + ); @@ -353,6 +366,7 @@ const FileItem = ({ id }: FileItemProps) => { Match.when(FileKind.FLOW, () => ), Match.when(FileKind.GRAPH_Q_L, () => ), Match.when(FileKind.CREDENTIAL, () => ), + Match.when(FileKind.WEB_SOCKET, () => ), Match.orElse(() => null), ); }; @@ -908,6 +922,10 @@ const GraphQLFile = ({ id }: FileItemProps) => { const router = useRouter(); const matchRoute = useMatchRoute(); + const { theme } = useTheme(); + + const { workspaceId } = routes.dashboard.workspace.route.useLoaderData(); + const fileCollection = useApiCollection(FileCollectionSchema); const { fileId: graphqlId } = useMemo(() => fileCollection.utils.parseKeyUnsafe(id), [fileCollection.utils, id]); @@ -924,6 +942,11 @@ const GraphQLFile = ({ id }: FileItemProps) => { [graphqlCollection, graphqlId], ).data ?? create(GraphQLItemSchema); + const modal = useProgrammaticModal(); + + const exportMutation = useConnectMutation(ExportService.method.export); + const exportCurlGraphQLMutation = useConnectMutation(ExportService.method.exportCurlGraphQL); + const { containerRef, navigate: toNavigate = false, showControls } = useContext(FileTreeContext); const { escapeRef, escapeRender } = useEscapePortal(containerRef); @@ -943,6 +966,8 @@ const GraphQLFile = ({ id }: FileItemProps) => { const content = ( <> + {modal.children && } + GQL @@ -968,6 +993,167 @@ const GraphQLFile = ({ id }: FileItemProps) => { void edit()}>Rename + + Export + + + { + const { data, name } = await exportMutation.mutateAsync({ + fileIds: [graphqlId], + workspaceId, + }); + saveFile({ blobParts: [data], name }); + }} + > + YAML (DevTools) + + + { + const { data } = await exportCurlGraphQLMutation.mutateAsync({ + graphqlIds: [graphqlId], + workspaceId, + }); + modal.onOpenChange( + true, + + {({ close }) => ( + <> +
+ + cURL export + + + +
+ + + + )} +
, + ); + }} + > + cURL +
+
+
+ + pipe(fileCollection.utils.parseKeyUnsafe(id), (_) => fileCollection.utils.delete(_))} + variant='danger' + > + Delete + +
+ + )} + + ); + + const props = { + children: content, + className: toNavigate && matchRoute(route) !== false ? tw`bg-neutral` : '', + id, + onContextMenu, + textValue: name, + } satisfies TreeItemProps; + + return toNavigate ? : ; +}; + +const WebSocketFile = ({ id }: FileItemProps) => { + const router = useRouter(); + const matchRoute = useMatchRoute(); + + const { workspaceId } = routes.dashboard.workspace.route.useLoaderData(); + + const fileCollection = useApiCollection(FileCollectionSchema); + + const { fileId: websocketId } = useMemo(() => fileCollection.utils.parseKeyUnsafe(id), [fileCollection.utils, id]); + + const websocketCollection = useApiCollection(WebSocketCollectionSchema); + + const { name } = + useLiveQuery( + (_) => + _.from({ item: websocketCollection }) + .where((_) => eq(_.item.websocketId, websocketId)) + .select((_) => pick(_.item, 'name')) + .findOne(), + [websocketCollection, websocketId], + ).data ?? create(WebSocketItemSchema); + + const exportMutation = useConnectMutation(ExportService.method.export); + + const { containerRef, navigate: toNavigate = false, showControls } = useContext(FileTreeContext); + + const { escapeRef, escapeRender } = useEscapePortal(containerRef); + + const { edit, isEditing, textFieldProps } = useEditableTextState({ + onSuccess: (_) => websocketCollection.utils.update({ name: _, websocketId }), + value: name, + }); + + const { menuProps, menuTriggerProps, onContextMenu } = useContextMenuState(); + + const route = { + from: router.routesById[routes.dashboard.workspace.route.id].fullPath, + params: { websocketIdCan: Ulid.construct(websocketId).toCanonical() }, + to: router.routesById[routes.dashboard.workspace.websocket.route.id].fullPath, + } satisfies ToOptions; + + const content = ( + <> + + + + {name} + + + {isEditing && + escapeRender( + , + )} + + {showControls && ( + + + + + void edit()}>Rename + + + Export + + + { + const { data, name } = await exportMutation.mutateAsync({ + fileIds: [websocketId], + workspaceId, + }); + saveFile({ blobParts: [data], name }); + }} + > + YAML (DevTools) + + + + pipe(fileCollection.utils.parseKeyUnsafe(id), (_) => fileCollection.utils.delete(_))} variant='danger' @@ -1028,6 +1214,8 @@ const CredentialFile = ({ id }: FileItemProps) => { to: router.routesById[routes.dashboard.workspace.credential.id].fullPath, }); + + const content = ( <> {pipe( @@ -1075,7 +1263,8 @@ const CredentialFile = ({ id }: FileItemProps) => { const props = { children: content, - className: toNavigate && matchRoute(route) !== false ? tw`bg-neutral` : '', + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + className: toNavigate && matchRoute(route) ? tw`bg-neutral` : '', id, onContextMenu, textValue: name, diff --git a/packages/client/src/pages/flow/add-node.tsx b/packages/client/src/pages/flow/add-node.tsx index 5a0a644dd..c8dc9f8b7 100644 --- a/packages/client/src/pages/flow/add-node.tsx +++ b/packages/client/src/pages/flow/add-node.tsx @@ -3,7 +3,7 @@ import * as XF from '@xyflow/react'; import { Ulid } from 'id128'; import { ReactNode, use } from 'react'; import * as RAC from 'react-aria-components'; -import { FiArrowLeft, FiBriefcase, FiChevronRight, FiTerminal, FiX } from 'react-icons/fi'; +import { FiArrowLeft, FiBriefcase, FiChevronRight, FiClock, FiSend, FiTerminal, FiWifi, FiX } from 'react-icons/fi'; import { TbRobotFace } from 'react-icons/tb'; import { FileKind } from '@the-dev-tools/spec/buf/api/file_system/v1/file_system_pb'; import { @@ -24,9 +24,13 @@ import { NodeGraphQLCollectionSchema, NodeHttpCollectionSchema, NodeJsCollectionSchema, + NodeWaitCollectionSchema, + NodeWsConnectionCollectionSchema, + NodeWsSendCollectionSchema, } from '@the-dev-tools/spec/tanstack-db/v1/api/flow'; import { GraphQLCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/graph_q_l'; import { HttpCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/http'; +import { WebSocketCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/web_socket'; import { Button } from '@the-dev-tools/ui/button'; import { FlowsIcon, ForIcon, IfIcon, SendRequestIcon } from '@the-dev-tools/ui/icons'; import { ListBoxItem } from '@the-dev-tools/ui/list-box'; @@ -181,6 +185,7 @@ const AddFlowNodeSidebar = ({ handleKind, position, previous, sourceId, targetId const conditionCollection = useApiCollection(NodeConditionCollectionSchema); const forCollection = useApiCollection(NodeForCollectionSchema); const forEachCollection = useApiCollection(NodeForEachCollectionSchema); + const waitCollection = useApiCollection(NodeWaitCollectionSchema); return ( <> @@ -219,6 +224,17 @@ const AddFlowNodeSidebar = ({ handleKind, position, previous, sourceId, targetId }} title='For each loop' /> + + } + onAction={() => { + const nodeId = Ulid.generate().bytes; + waitCollection.utils.insert({ durationMs: 1000n, nodeId }); + insertNode({ handleKind, kind: NodeKind.WAIT, name: 'wait', nodeId, position, sourceId, targetId }); + }} + title='Wait' + /> ); @@ -231,6 +247,9 @@ const AddCoreNodeSidebar = (props: AddNodeSidebarProps) => { const insertNode = useInsertNode(); const jsCollection = useApiCollection(NodeJsCollectionSchema); + const websocketCollection = useApiCollection(WebSocketCollectionSchema); + const wsConnectionCollection = useApiCollection(NodeWsConnectionCollectionSchema); + const wsSendCollection = useApiCollection(NodeWsSendCollectionSchema); return ( <> @@ -261,6 +280,46 @@ const AddCoreNodeSidebar = (props: AddNodeSidebarProps) => { onAction={() => void setSidebar?.((_) => )} title='GraphQL Request' /> + + } + onAction={() => { + const websocketId = Ulid.generate().bytes; + websocketCollection.utils.insert({ name: 'New WebSocket', url: '', websocketId }); + const nodeId = Ulid.generate().bytes; + wsConnectionCollection.utils.insert({ nodeId, websocketId }); + insertNode({ + handleKind, + kind: NodeKind.WS_CONNECTION, + name: 'ws_connection', + nodeId, + position, + sourceId, + targetId, + }); + }} + title='WebSocket Connection' + /> + + } + onAction={() => { + const nodeId = Ulid.generate().bytes; + wsSendCollection.utils.insert({ nodeId }); + insertNode({ + handleKind, + kind: NodeKind.WS_SEND, + name: 'ws_send', + nodeId, + position, + sourceId, + targetId, + }); + }} + title='WebSocket Send' + /> ); diff --git a/packages/client/src/pages/flow/agent-panel.tsx b/packages/client/src/pages/flow/agent-panel.tsx index 71a08e8c3..e658bc065 100644 --- a/packages/client/src/pages/flow/agent-panel.tsx +++ b/packages/client/src/pages/flow/agent-panel.tsx @@ -1,6 +1,6 @@ import { eq, useLiveQuery } from '@tanstack/react-db'; import { Ulid } from 'id128'; -import { FormEvent, KeyboardEvent, use, useEffect, useMemo, useRef, useState } from 'react'; +import { type SyntheticEvent, KeyboardEvent, use, useEffect, useMemo, useRef, useState } from 'react'; import { FiArrowUp, FiChevronUp, FiEdit, FiSettings, FiX } from 'react-icons/fi'; import Markdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; @@ -133,7 +133,7 @@ export const AgentPanel = () => { el.style.height = `${el.scrollHeight}px`; }; - const handleSubmit = (e?: FormEvent) => { + const handleSubmit = (e?: SyntheticEvent) => { e?.preventDefault(); if (!input.trim() || isLoading) return; void sendMessage(input.trim()); @@ -369,7 +369,7 @@ const ApiKeyPrompt = ({ setValue(''); }, [provider]); - const handleSubmit = (e?: FormEvent) => { + const handleSubmit = (e?: SyntheticEvent) => { e?.preventDefault(); if (!value.trim()) return; onSubmit(value); diff --git a/packages/client/src/pages/flow/edge.tsx b/packages/client/src/pages/flow/edge.tsx index 07d726b14..c730d1a5f 100644 --- a/packages/client/src/pages/flow/edge.tsx +++ b/packages/client/src/pages/flow/edge.tsx @@ -147,7 +147,7 @@ const DefaultEdge = ({ id, sourcePosition, sourceX, sourceY, targetPosition, tar
diff --git a/packages/client/src/pages/flow/edit.tsx b/packages/client/src/pages/flow/edit.tsx index fc58004c7..d0bccf96c 100644 --- a/packages/client/src/pages/flow/edit.tsx +++ b/packages/client/src/pages/flow/edit.tsx @@ -35,6 +35,7 @@ import { NodeCollectionSchema, NodeGraphQLCollectionSchema, NodeHttpCollectionSchema, + NodeWsConnectionCollectionSchema, } from '@the-dev-tools/spec/tanstack-db/v1/api/flow'; import { Button, ButtonAsRouteLink } from '@the-dev-tools/ui/button'; import { Checkbox } from '@the-dev-tools/ui/checkbox'; @@ -83,6 +84,9 @@ import { GraphQLNode, GraphQLSettings } from './nodes/graphql'; import { HttpNode, HttpSettings } from './nodes/http'; import { JavaScriptNode, JavaScriptSettings } from './nodes/javascript'; import { ManualStartNode } from './nodes/manual-start'; +import { WaitNode, WaitSettings } from './nodes/wait'; +import { WsConnectionNode, WsConnectionSettings } from './nodes/ws-connection'; +import { WsSendNode, WsSendSettings } from './nodes/ws-send'; import { useFlowSelection } from './selection'; import { useUndoStack } from './undo'; import { useViewport, VIEWPORT_MAX_ZOOM, VIEWPORT_MIN_ZOOM } from './viewport'; @@ -99,6 +103,9 @@ export const nodeTypes: XF.NodeTypes = { [NodeKind.JS]: JavaScriptNode, [NodeKind.MANUAL_START]: ManualStartNode, [NodeKind.UNSPECIFIED]: () => null, + [NodeKind.WAIT]: WaitNode, + [NodeKind.WS_CONNECTION]: WsConnectionNode, + [NodeKind.WS_SEND]: WsSendNode, }; export const FlowEditPage = () => { @@ -153,6 +160,7 @@ export const Flow = ({ children }: PropsWithChildren) => { const nodeCollection = useApiCollection(NodeCollectionSchema); const nodeGraphQLCollection = useApiCollection(NodeGraphQLCollectionSchema); const nodeHttpCollection = useApiCollection(NodeHttpCollectionSchema); + const nodeWsConnectionCollection = useApiCollection(NodeWsConnectionCollectionSchema); const nodeEditDialog = useNodeEditDialog(); @@ -461,6 +469,23 @@ export const Flow = ({ children }: PropsWithChildren) => { position, }); } + + if (file?.kind === FileKind.WEB_SOCKET) { + const nodeId = Ulid.generate().bytes; + + nodeWsConnectionCollection.utils.insert({ + nodeId, + websocketId: file.fileId, + }); + + nodeCollection.utils.insert({ + flowId, + kind: NodeKind.WS_CONNECTION, + name: `ws_connection_${getNodes().length}`, + nodeId, + position, + }); + } }, ref, }); @@ -881,6 +906,9 @@ const useNodeEditDialog = () => { Match.when({ kind: NodeKind.AI }, (_) => ), Match.when({ kind: NodeKind.AI_PROVIDER }, (_) => ), Match.when({ kind: NodeKind.AI_MEMORY }, (_) => ), + Match.when({ kind: NodeKind.WAIT }, () => ), + Match.when({ kind: NodeKind.WS_CONNECTION }, () => ), + Match.when({ kind: NodeKind.WS_SEND }, () => ), Match.orElse(() => null), ); diff --git a/packages/client/src/pages/flow/handle.tsx b/packages/client/src/pages/flow/handle.tsx index e85a4e763..48e47bd36 100644 --- a/packages/client/src/pages/flow/handle.tsx +++ b/packages/client/src/pages/flow/handle.tsx @@ -16,6 +16,7 @@ import { FlowContext } from './context'; interface HandleProps extends Omit { alwaysVisible?: boolean; kind?: HandleKind; + label?: string; nodeId: Uint8Array; nodeOffset?: { x?: number; y?: number }; Sidebar?: (props: AddNodeSidebarProps) => ReactNode; @@ -25,6 +26,7 @@ export const Handle = ({ alwaysVisible, className, kind = HandleKind.UNSPECIFIED, + label: labelOverride, nodeId, nodeOffset, Sidebar = AddNodeSidebar, @@ -38,16 +40,19 @@ export const Handle = ({ const id = kind === HandleKind.UNSPECIFIED ? null : kind.toString(); - const label = pipe( - Match.value(kind), - Match.when(HandleKind.ELSE, () => 'Else'), - Match.when(HandleKind.THEN, () => 'Then'), - Match.when(HandleKind.LOOP, () => 'Loop'), - Match.when(HandleKind.AI_PROVIDER, () => 'Provider'), - Match.when(HandleKind.AI_MEMORY, () => 'Memory'), - Match.when(HandleKind.AI_TOOLS, () => 'Tools'), - Match.orElse(() => null), - ); + const label = + labelOverride ?? + pipe( + Match.value(kind), + Match.when(HandleKind.ELSE, () => 'Else'), + Match.when(HandleKind.THEN, () => 'Then'), + Match.when(HandleKind.LOOP, () => 'Loop'), + Match.when(HandleKind.AI_PROVIDER, () => 'Provider'), + Match.when(HandleKind.AI_MEMORY, () => 'Memory'), + Match.when(HandleKind.AI_TOOLS, () => 'Tools'), + Match.when(HandleKind.WS_MESSAGE, () => 'Message'), + Match.orElse(() => null), + ); const edgeCollection = useApiCollection(EdgeCollectionSchema); diff --git a/packages/client/src/pages/flow/node.tsx b/packages/client/src/pages/flow/node.tsx index 4fb6b6ad8..f431f88ef 100644 --- a/packages/client/src/pages/flow/node.tsx +++ b/packages/client/src/pages/flow/node.tsx @@ -9,7 +9,7 @@ import { usePacedMutations, } from '@tanstack/react-db'; import * as XF from '@xyflow/react'; -import { Array, Match, Option, pipe, Schema } from 'effect'; +import { Array, Match, pipe, Schema } from 'effect'; import { Ulid } from 'id128'; import { ReactNode, useCallback, useContext, useRef, useState } from 'react'; import { Button as AriaButton, Key, Tooltip, TooltipTrigger, Tree } from 'react-aria-components'; @@ -454,46 +454,42 @@ interface NodeSettingsBodyProps { export const NodeSettingsBody = ({ children, input, nodeId, output, settingsHeader, title }: NodeSettingsBodyProps) => { const executionCollection = useApiCollection(NodeExecutionCollectionSchema); - const { data: executions } = useLiveQuery( + const { data: rawExecutions } = useLiveQuery( (_) => { const item = _.from({ item: executionCollection }) .where((_) => eq(_.item.nodeId, nodeId)) .fn.select((_) => ({ ...pick(_.item, 'nodeExecutionId', 'name'), - order: Ulid.construct(_.item.nodeExecutionId).toCanonical(), + key: Ulid.construct(_.item.nodeExecutionId).toCanonical(), })); - return _.from({ item }).orderBy((_) => _.item.order, 'desc'); + return _.from({ item }).orderBy((_) => _.item.key, 'desc'); }, [executionCollection, nodeId], ); - const latestExecutionId = pipe( - Array.head(executions), - Option.map((_) => _.nodeExecutionId), - Option.getOrNull, - ); + // Deduplicate by canonical ULID — reactive queries can transiently emit duplicates during sync + const executions = Array.dedupeWith(rawExecutions, (a, b) => a.key === b.key); - const latestExecutionIdCan = latestExecutionId ? Ulid.construct(latestExecutionId).toCanonical() : null; + const latestKey = executions[0]?.key ?? null; - const [selectedExecKey, setSelectedExecKey] = useState(latestExecutionId ? 'latest' : null); + // Track whether user is "following" the latest execution (auto-advance on new arrivals) + // vs pinned to a specific historical execution. + const [pinnedKey, setPinnedKey] = useState(null); + const selectedKey = pinnedKey ?? latestKey; - const selectedExecutionId = - selectedExecKey === 'latest' - ? latestExecutionId - : typeof selectedExecKey === 'string' - ? Ulid.fromCanonical(selectedExecKey).bytes - : null; + const handleSelectionChange = (key: Key | null) => { + // If user selects the latest execution, clear the pin so we follow new arrivals + setPinnedKey(key === latestKey ? null : typeof key === 'string' ? key : null); + }; - const selectedExecutionIdCan = selectedExecutionId ? Ulid.construct(selectedExecutionId).toCanonical() : null; + const selectedExecutionId = + typeof selectedKey === 'string' ? (executions.find((_) => _.key === selectedKey)?.nodeExecutionId ?? null) : null; - // Fix React Aria over-rendering non-visible components + // React Aria workaround: only render full list when dropdown is open // https://github.com/adobe/react-spectrum/issues/8783#issuecomment-3233350825 - // TODO: move the workaround to an improved select component const [isExecListOpen, setIsExecListOpen] = useState(false); - const execItems = isExecListOpen - ? executions - : executions.filter((_) => Ulid.construct(_.nodeExecutionId).toCanonical() === selectedExecutionIdCan); + const execItems = isExecListOpen ? executions : executions.filter((_) => _.key === selectedKey); const nodeSettingsLayout = useDefaultLayout({ id: 'node-settings' }); @@ -506,16 +502,11 @@ export const NodeSettingsBody = ({ children, input, nodeId, output, settingsHead aria-label='Node execution' isOpen={isExecListOpen} items={execItems} - onChange={setSelectedExecKey} + onChange={handleSelectionChange} onOpenChange={setIsExecListOpen} - value={selectedExecKey} + value={selectedKey} > - {(_) => { - let key = Ulid.construct(_.nodeExecutionId).toCanonical(); - if (key === latestExecutionIdCan) key = 'latest'; - - return {_.name}; - }} + {(_) => {_.name}} ) } diff --git a/packages/client/src/pages/flow/nodes/wait.tsx b/packages/client/src/pages/flow/nodes/wait.tsx new file mode 100644 index 000000000..05619ab0a --- /dev/null +++ b/packages/client/src/pages/flow/nodes/wait.tsx @@ -0,0 +1,69 @@ +import { create } from '@bufbuild/protobuf'; +import { eq, useLiveQuery } from '@tanstack/react-db'; +import * as XF from '@xyflow/react'; +import { Ulid } from 'id128'; +import { use } from 'react'; +import { FiClock } from 'react-icons/fi'; +import { NodeWaitSchema } from '@the-dev-tools/spec/buf/api/flow/v1/flow_pb'; +import { NodeWaitCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/flow'; +import { NumberField } from '@the-dev-tools/ui/number-field'; +import { tw } from '@the-dev-tools/ui/tailwind-literal'; +import { useApiCollection } from '~/shared/api'; +import { pick } from '~/shared/lib'; +import { FlowContext } from '../context'; +import { Handle } from '../handle'; +import { NodeSettingsBody, NodeSettingsProps, NodeTitle, SimpleNode } from '../node'; + +const defaultNodeWait = create(NodeWaitSchema); + +export const WaitNode = ({ id, selected }: XF.NodeProps) => { + const nodeId = Ulid.fromCanonical(id).bytes; + + return ( + + + + + } + icon={} + nodeId={nodeId} + selected={selected} + > + Wait + + ); +}; + +export const WaitSettings = ({ nodeId }: NodeSettingsProps) => { + const collection = useApiCollection(NodeWaitCollectionSchema); + + const data = + useLiveQuery( + (_) => + _.from({ item: collection }) + .where((_) => eq(_.item.nodeId, nodeId)) + .select((_) => pick(_.item, 'durationMs')) + .findOne(), + [collection, nodeId], + ).data ?? defaultNodeWait; + + const { isReadOnly = false } = use(FlowContext); + + return ( + +
+ collection.utils.updatePaced({ durationMs: BigInt(_), nodeId })} + value={Number(data.durationMs)} + /> +
+
+ ); +}; diff --git a/packages/client/src/pages/flow/nodes/ws-connection.tsx b/packages/client/src/pages/flow/nodes/ws-connection.tsx new file mode 100644 index 000000000..89ca512f4 --- /dev/null +++ b/packages/client/src/pages/flow/nodes/ws-connection.tsx @@ -0,0 +1,144 @@ +import { create } from '@bufbuild/protobuf'; +import { eq, useLiveQuery } from '@tanstack/react-db'; +import { useRouter } from '@tanstack/react-router'; +import * as XF from '@xyflow/react'; +import { Ulid } from 'id128'; +import { use } from 'react'; +import { FiExternalLink, FiWifi } from 'react-icons/fi'; +import { HandleKind, NodeWsConnectionSchema } from '@the-dev-tools/spec/buf/api/flow/v1/flow_pb'; +import { NodeWsConnectionCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/flow'; +import { WebSocketCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/web_socket'; +import { ButtonAsLink } from '@the-dev-tools/ui/button'; +import { FieldLabel } from '@the-dev-tools/ui/field'; +import { tw } from '@the-dev-tools/ui/tailwind-literal'; +import { ReferenceContext, ReferenceField } from '~/features/expression'; +import { WebSocketHeaderTable } from '~/pages/websocket/@x/flow'; +import { useApiCollection } from '~/shared/api'; +import { eqStruct, pick } from '~/shared/lib'; +import { routes } from '~/shared/routes'; +import { FlowContext } from '../context'; +import { Handle } from '../handle'; +import { NodeSettingsBody, NodeSettingsProps, SimpleNode } from '../node'; + +const defaultNodeWsConnection = create(NodeWsConnectionSchema); + +export const WsConnectionNode = ({ id, selected }: XF.NodeProps) => { + const nodeId = Ulid.fromCanonical(id).bytes; + + const nodeWsCollection = useApiCollection(NodeWsConnectionCollectionSchema); + const wsCollection = useApiCollection(WebSocketCollectionSchema); + + const { websocketId } = + useLiveQuery( + (_) => + _.from({ item: nodeWsCollection }) + .where((_) => eq(_.item.nodeId, nodeId)) + .select((_) => pick(_.item, 'websocketId')) + .findOne(), + [nodeWsCollection, nodeId], + ).data ?? defaultNodeWsConnection; + + const { url } = + useLiveQuery( + (_) => + _.from({ item: wsCollection }) + .where((_) => (websocketId ? eqStruct({ websocketId })(_) : eq(true, false))) + .select((_) => pick(_.item, 'url')) + .findOne(), + [wsCollection, websocketId], + ).data ?? {}; + + return ( + + + + + + } + icon={} + nodeId={nodeId} + selected={selected} + title='WS Connection' + > +
+ WS +
{url ?? 'No URL'}
+
+
+ ); +}; + +export const WsConnectionSettings = ({ nodeId }: NodeSettingsProps) => { + const router = useRouter(); + + const { isReadOnly = false } = use(FlowContext); + + const { workspaceId } = routes.dashboard.workspace.route.useLoaderData(); + const { workspaceIdCan } = routes.dashboard.workspace.route.useParams(); + + const nodeWsCollection = useApiCollection(NodeWsConnectionCollectionSchema); + const wsCollection = useApiCollection(WebSocketCollectionSchema); + + const { websocketId } = + useLiveQuery( + (_) => + _.from({ item: nodeWsCollection }) + .where((_) => eq(_.item.nodeId, nodeId)) + .select((_) => pick(_.item, 'websocketId')) + .findOne(), + [nodeWsCollection, nodeId], + ).data ?? defaultNodeWsConnection; + + const { url } = + useLiveQuery( + (_) => + _.from({ item: wsCollection }) + .where((_) => (websocketId ? eqStruct({ websocketId })(_) : eq(true, false))) + .select((_) => pick(_.item, 'url')) + .findOne(), + [wsCollection, websocketId], + ).data ?? {}; + + return ( + + + Open WebSocket + + ) + } + title='WebSocket Connection' + > + + URL + websocketId && wsCollection.utils.update({ url: _, websocketId })} + readOnly={isReadOnly || !websocketId} + value={url ?? ''} + /> + + {websocketId && ( + <> + Headers + + + )} + + + ); +}; diff --git a/packages/client/src/pages/flow/nodes/ws-send.tsx b/packages/client/src/pages/flow/nodes/ws-send.tsx new file mode 100644 index 000000000..46bc9f011 --- /dev/null +++ b/packages/client/src/pages/flow/nodes/ws-send.tsx @@ -0,0 +1,99 @@ +import { create } from '@bufbuild/protobuf'; +import { eq, useLiveQuery } from '@tanstack/react-db'; +import * as XF from '@xyflow/react'; +import { Ulid } from 'id128'; +import { use, useState } from 'react'; +import { FiSend } from 'react-icons/fi'; +import { NodeKind, NodeWsSendSchema } from '@the-dev-tools/spec/buf/api/flow/v1/flow_pb'; +import { NodeCollectionSchema, NodeWsSendCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/flow'; +import { FieldLabel } from '@the-dev-tools/ui/field'; +import { Select, SelectItem } from '@the-dev-tools/ui/select'; +import { tw } from '@the-dev-tools/ui/tailwind-literal'; +import { ReferenceField } from '~/features/expression'; +import { useApiCollection } from '~/shared/api'; +import { eqStruct, pick } from '~/shared/lib'; +import { FlowContext } from '../context'; +import { Handle } from '../handle'; +import { NodeSettingsBody, NodeSettingsProps, SimpleNode } from '../node'; + +const defaultNodeWsSend = create(NodeWsSendSchema); + +export const WsSendNode = ({ id, selected }: XF.NodeProps) => { + const nodeId = Ulid.fromCanonical(id).bytes; + + return ( + + + + + } + icon={} + nodeId={nodeId} + selected={selected} + title='WS Send' + /> + ); +}; + +export const WsSendSettings = ({ nodeId }: NodeSettingsProps) => { + const collection = useApiCollection(NodeWsSendCollectionSchema); + const nodeCollection = useApiCollection(NodeCollectionSchema); + + const { flowId, isReadOnly = false } = use(FlowContext); + + const { message, wsConnectionNodeName } = + useLiveQuery( + (_) => + _.from({ item: collection }) + .where((_) => eq(_.item.nodeId, nodeId)) + .select((_) => pick(_.item, 'message', 'wsConnectionNodeName')) + .findOne(), + [collection, nodeId], + ).data ?? defaultNodeWsSend; + + const { data: wsConnectionNodes } = useLiveQuery( + (_) => + _.from({ item: nodeCollection }) + .where(eqStruct({ flowId, kind: NodeKind.WS_CONNECTION })) + .select((_) => pick(_.item, 'name', 'nodeId')), + [flowId, nodeCollection], + ); + + // React Aria workaround: only render full list when dropdown is open + // https://github.com/adobe/react-spectrum/issues/8783#issuecomment-3233350825 + const [isConnListOpen, setIsConnListOpen] = useState(false); + const connItems = + isConnListOpen || !wsConnectionNodeName + ? wsConnectionNodes + : wsConnectionNodes.filter((_) => _.name === wsConnectionNodeName); + + return ( + + Connection + + + Message + collection.utils.updatePaced({ message: _, nodeId })} + readOnly={isReadOnly} + value={message} + /> + + ); +}; diff --git a/packages/client/src/pages/websocket/@x/flow.tsx b/packages/client/src/pages/websocket/@x/flow.tsx new file mode 100644 index 000000000..86595cee3 --- /dev/null +++ b/packages/client/src/pages/websocket/@x/flow.tsx @@ -0,0 +1 @@ +export { WebSocketHeaderTable } from '../request/header'; diff --git a/packages/client/src/pages/websocket/@x/workspace.tsx b/packages/client/src/pages/websocket/@x/workspace.tsx new file mode 100644 index 000000000..13825d610 --- /dev/null +++ b/packages/client/src/pages/websocket/@x/workspace.tsx @@ -0,0 +1,3 @@ +import { resolveRoutesTo } from '../../../shared/lib/router'; + +export const resolveRoutesFrom = resolveRoutesTo(import.meta.dirname, '../routes'); diff --git a/packages/client/src/pages/websocket/page.tsx b/packages/client/src/pages/websocket/page.tsx new file mode 100644 index 000000000..a7c29dd29 --- /dev/null +++ b/packages/client/src/pages/websocket/page.tsx @@ -0,0 +1,47 @@ +import { Panel, Group as PanelGroup, useDefaultLayout } from 'react-resizable-panels'; +import { PanelResizeHandle } from '@the-dev-tools/ui/resizable-panel'; +import { ReferenceContext } from '~/features/expression'; +import { routes } from '~/shared/routes'; + +import { WebSocketRequestPanel, WebSocketTopBar, WebSocketUrlBar } from './request'; +import { WebSocketMessageLog } from './response'; +import { useWebSocket } from './use-websocket'; + +export const WebSocketPage = () => { + const { websocketId } = routes.dashboard.workspace.websocket.route.useRouteContext(); + const { workspaceId } = routes.dashboard.workspace.route.useLoaderData(); + + const ws = useWebSocket(); + + const endpointLayout = useDefaultLayout({ id: 'websocket-endpoint' }); + + return ( + + + + + + + + + + + + + + + + + + ); +}; diff --git a/packages/client/src/pages/websocket/request/header.tsx b/packages/client/src/pages/websocket/request/header.tsx new file mode 100644 index 000000000..958175a49 --- /dev/null +++ b/packages/client/src/pages/websocket/request/header.tsx @@ -0,0 +1,140 @@ +import { Query, useLiveQuery } from '@tanstack/react-db'; +import { Ulid } from 'id128'; +import { useDragAndDrop } from 'react-aria-components'; +import { FiPlus } from 'react-icons/fi'; +import { WebSocketHeaderCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/web_socket'; +import { Button } from '@the-dev-tools/ui/button'; +import { Checkbox } from '@the-dev-tools/ui/checkbox'; +import { DropIndicatorHorizontal } from '@the-dev-tools/ui/reorder'; +import { Table, TableBody, TableCell, TableColumn, TableFooter, TableHeader, TableRow } from '@the-dev-tools/ui/table'; +import { tw } from '@the-dev-tools/ui/tailwind-literal'; +import { TextInputField } from '@the-dev-tools/ui/text-field'; +import { ReferenceField } from '~/features/expression'; +import { ColumnActionDelete } from '~/features/form-table'; +import { useApiCollection } from '~/shared/api'; +import { eqStruct, getNextOrder, handleCollectionReorder, LiveQuery, pickStruct } from '~/shared/lib'; + +export interface WebSocketHeaderTableProps { + websocketId: Uint8Array; +} + +export const WebSocketHeaderTable = ({ websocketId }: WebSocketHeaderTableProps) => { + const collection = useApiCollection(WebSocketHeaderCollectionSchema); + + const { data: items } = useLiveQuery( + (_) => + _.from({ item: collection }) + .where(eqStruct({ websocketId })) + .orderBy((_) => _.item.order) + .select(pickStruct('websocketHeaderId', 'order')), + [collection, websocketId], + ); + + const { dragAndDropHooks } = useDragAndDrop({ + getItems: (keys) => [...keys].map((key) => ({ key: key.toString() })), + onReorder: handleCollectionReorder(collection), + renderDropIndicator: () => , + }); + + return ( + + + + Key + Value + Description + + + + + {({ websocketHeaderId }) => { + const query = new Query().from({ item: collection }).where(eqStruct({ websocketHeaderId })).findOne(); + + return ( + + + query.select(pickStruct('enabled'))}> + {({ data }) => ( + void collection.utils.update({ enabled: _, websocketHeaderId })} + /> + )} + + + + + query.select(pickStruct('key'))}> + {({ data }) => ( + void collection.utils.update({ key: _, websocketHeaderId })} + placeholder='Enter key' + value={data?.key ?? ''} + variant='table-cell' + /> + )} + + + + + query.select(pickStruct('value'))}> + {({ data }) => ( + void collection.utils.update({ value: _, websocketHeaderId })} + placeholder='Enter value' + value={data?.value ?? ''} + variant='table-cell' + /> + )} + + + + + query.select(pickStruct('description'))}> + {({ data }) => ( + void collection.utils.update({ description: _, websocketHeaderId })} + placeholder='Enter description' + value={data?.description ?? ''} + /> + )} + + + + + void collection.utils.delete({ websocketHeaderId })} /> + + + ); + }} + + + + + +
+ ); +}; diff --git a/packages/client/src/pages/websocket/request/index.tsx b/packages/client/src/pages/websocket/request/index.tsx new file mode 100644 index 000000000..c4e213def --- /dev/null +++ b/packages/client/src/pages/websocket/request/index.tsx @@ -0,0 +1,3 @@ +export { WebSocketRequestPanel } from './panel'; +export { WebSocketTopBar } from './top-bar'; +export { WebSocketUrlBar } from './url'; diff --git a/packages/client/src/pages/websocket/request/panel.tsx b/packages/client/src/pages/websocket/request/panel.tsx new file mode 100644 index 000000000..89f0150dc --- /dev/null +++ b/packages/client/src/pages/websocket/request/panel.tsx @@ -0,0 +1,117 @@ +import { count, useLiveQuery } from '@tanstack/react-db'; +import CodeMirror from '@uiw/react-codemirror'; +import { Suspense, useState } from 'react'; +import { Tab, TabList, TabPanel, Tabs } from 'react-aria-components'; +import { twMerge } from 'tailwind-merge'; +import { WebSocketHeaderCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/web_socket'; +import { Button } from '@the-dev-tools/ui/button'; +import { Spinner } from '@the-dev-tools/ui/spinner'; +import { tw } from '@the-dev-tools/ui/tailwind-literal'; +import { useTheme } from '@the-dev-tools/ui/theme'; +import { useCodeMirrorLanguageExtensions } from '~/features/expression'; +import { useApiCollection } from '~/shared/api'; +import { eqStruct } from '~/shared/lib'; + +import { type ConnectionState } from '../use-websocket'; +import { WebSocketHeaderTable } from './header'; + +export interface WebSocketRequestPanelProps { + connectionState: ConnectionState; + onSend: (message: string) => void; + websocketId: Uint8Array; +} + +export const WebSocketRequestPanel = ({ connectionState, onSend, websocketId }: WebSocketRequestPanelProps) => { + const headerCollection = useApiCollection(WebSocketHeaderCollectionSchema); + + const { headerCount = 0 } = + useLiveQuery( + (_) => + _.from({ item: headerCollection }) + .where(eqStruct({ websocketId })) + .select((_) => ({ headerCount: count(_.item.websocketId) })) + .findOne(), + [headerCollection, websocketId], + ).data ?? {}; + + const tabClass = ({ isSelected }: { isSelected: boolean }) => + twMerge( + tw` + -mb-px cursor-pointer border-b-2 border-transparent py-1.5 text-md leading-5 font-medium tracking-tight + text-on-neutral-low transition-colors + `, + isSelected && tw`border-b-accent text-on-neutral`, + ); + + return ( + + + + Message + + + Headers + {headerCount > 0 && ({headerCount})} + + + + + +
+ } + > + + + + + + + + + + ); +}; + +interface MessageComposerProps { + connectionState: ConnectionState; + onSend: (message: string) => void; +} + +const MessageComposer = ({ connectionState, onSend }: MessageComposerProps) => { + const { theme } = useTheme(); + const extensions = useCodeMirrorLanguageExtensions('json'); + const [message, setMessage] = useState(''); + + const isConnected = connectionState === 'connected'; + + return ( + <> +
+ +
+ +
+ +
+ + ); +}; diff --git a/packages/client/src/pages/websocket/request/top-bar.tsx b/packages/client/src/pages/websocket/request/top-bar.tsx new file mode 100644 index 000000000..e3dd89243 --- /dev/null +++ b/packages/client/src/pages/websocket/request/top-bar.tsx @@ -0,0 +1,78 @@ +import { useLiveQuery } from '@tanstack/react-db'; +import { Button as AriaButton, MenuTrigger } from 'react-aria-components'; +import { FiMoreHorizontal } from 'react-icons/fi'; +import { WebSocketCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/web_socket'; +import { Button } from '@the-dev-tools/ui/button'; +import { Menu, MenuItem, useContextMenuState } from '@the-dev-tools/ui/menu'; +import { tw } from '@the-dev-tools/ui/tailwind-literal'; +import { TextInputField, useEditableTextState } from '@the-dev-tools/ui/text-field'; +import { useApiCollection } from '~/shared/api'; +import { eqStruct, pick } from '~/shared/lib'; + +export interface WebSocketTopBarProps { + websocketId: Uint8Array; +} + +export const WebSocketTopBar = ({ websocketId }: WebSocketTopBarProps) => { + const collection = useApiCollection(WebSocketCollectionSchema); + + const name = + useLiveQuery( + (_) => + _.from({ item: collection }) + .where(eqStruct({ websocketId })) + .select((_) => pick(_.item, 'name')) + .findOne(), + [collection, websocketId], + ).data?.name ?? 'WebSocket'; + + const { menuProps, menuTriggerProps, onContextMenu } = useContextMenuState(); + + const { edit, isEditing, textFieldProps } = useEditableTextState({ + onSuccess: (_) => { + if (_ === name) return; + void collection.utils.update({ name: _, websocketId }); + }, + value: name, + }); + + return ( +
+
+ {isEditing ? ( + + ) : ( + void edit()} + > + {name} + + )} +
+ + + + + + void edit()}>Rename + + collection.utils.delete({ websocketId })} variant='danger'> + Delete + + + +
+ ); +}; diff --git a/packages/client/src/pages/websocket/request/url.tsx b/packages/client/src/pages/websocket/request/url.tsx new file mode 100644 index 000000000..1960d0ab3 --- /dev/null +++ b/packages/client/src/pages/websocket/request/url.tsx @@ -0,0 +1,91 @@ +import { useLiveQuery } from '@tanstack/react-db'; +import { useState } from 'react'; +import { WebSocketCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/web_socket'; +import { Button } from '@the-dev-tools/ui/button'; +import { Separator } from '@the-dev-tools/ui/separator'; +import { tw } from '@the-dev-tools/ui/tailwind-literal'; +import { ReferenceField } from '~/features/expression'; +import { useApiCollection } from '~/shared/api'; +import { eqStruct, pick } from '~/shared/lib'; + +import { type ConnectionState } from '../use-websocket'; + +export interface WebSocketUrlBarProps { + connectionState: ConnectionState; + onConnect: (url: string) => void; + onDisconnect: () => void; + websocketId: Uint8Array; +} + +export const WebSocketUrlBar = ({ connectionState, onConnect, onDisconnect, websocketId }: WebSocketUrlBarProps) => { + const collection = useApiCollection(WebSocketCollectionSchema); + + const { data } = useLiveQuery( + (_) => + _.from({ item: collection }) + .where(eqStruct({ websocketId })) + .select((_) => pick(_.item, 'url')) + .findOne(), + [collection, websocketId], + ); + + const url = data?.url ?? ''; + + const [urlState, setUrlState] = useState(); + + const saveUrl = () => { + if (urlState !== undefined && urlState !== url) { + collection.utils.update({ url: urlState, websocketId }); + } + setUrlState(undefined); + }; + + const handleConnect = () => { + const currentUrl = urlState ?? url; + if (urlState !== undefined) { + collection.utils.update({ url: urlState, websocketId }); + setUrlState(undefined); + } + onConnect(currentUrl); + }; + + const isConnected = connectionState === 'connected'; + const isConnecting = connectionState === 'connecting'; + + return ( +
+
+ + WS + + + + + void saveUrl()} + onChange={(_) => void setUrlState(_)} + value={urlState ?? url} + /> +
+ + {isConnected ? ( + + ) : ( + + )} +
+ ); +}; diff --git a/packages/client/src/pages/websocket/response/index.tsx b/packages/client/src/pages/websocket/response/index.tsx new file mode 100644 index 000000000..fc381c809 --- /dev/null +++ b/packages/client/src/pages/websocket/response/index.tsx @@ -0,0 +1,152 @@ +import { useQuery } from '@tanstack/react-query'; +import CodeMirror from '@uiw/react-codemirror'; +import { useEffect, useRef, useState } from 'react'; +import { FiArrowDown, FiArrowUp, FiTrash2 } from 'react-icons/fi'; +import { twJoin } from 'tailwind-merge'; +import { Button } from '@the-dev-tools/ui/button'; +import { tw } from '@the-dev-tools/ui/tailwind-literal'; +import { useTheme } from '@the-dev-tools/ui/theme'; +import { guessLanguage, prettierFormatQueryOptions, useCodeMirrorLanguageExtensions } from '~/features/expression'; + +import { type ConnectionState, type WsMessage } from '../use-websocket'; + +export interface WebSocketMessageLogProps { + clearMessages: () => void; + error: string | undefined; + messages: WsMessage[]; + state: ConnectionState; +} + +const statusConfig = { + connected: { color: tw`bg-success`, label: 'Connected' }, + connecting: { color: tw`bg-info`, label: 'Connecting...' }, + disconnected: { color: tw`bg-neutral-high`, label: 'Disconnected' }, + error: { color: tw`bg-danger`, label: 'Error' }, +} as const; + +const formatTimestamp = (ts: number) => { + const d = new Date(ts); + return `${d.getHours().toString().padStart(2, '0')}:${d.getMinutes().toString().padStart(2, '0')}:${d.getSeconds().toString().padStart(2, '0')}.${d.getMilliseconds().toString().padStart(3, '0')}`; +}; + +export const WebSocketMessageLog = ({ clearMessages, error, messages, state }: WebSocketMessageLogProps) => { + const bottomRef = useRef(null); + + useEffect(() => { + bottomRef.current?.scrollIntoView({ behavior: 'smooth' }); + }, [messages.length]); + + const { color, label } = statusConfig[state]; + + return ( +
+
+
+
+ {label} +
+ + {error && {error}} + +
+ + {messages.length > 0 && {messages.length} messages} + + +
+ +
+ {messages.length === 0 ? ( +
+ No messages yet. Connect to start. +
+ ) : ( +
+ {messages.map((msg) => ( + + ))} +
+
+ )} +
+
+ ); +}; + +interface MessageRowProps { + message: WsMessage; +} + +const MessageRow = ({ message }: MessageRowProps) => { + const [expanded, setExpanded] = useState(false); + const isSent = message.direction === 'sent'; + const isJson = isJsonString(message.data); + + const preview = message.data.length > 120 ? message.data.slice(0, 120) + '...' : message.data; + + return ( +
+ + + {expanded && ( +
+ {isJson ? ( + + ) : ( +
{message.data}
+ )} +
+ )} +
+ ); +}; + +const isJsonString = (str: string): boolean => { + try { + JSON.parse(str); + return true; + } catch { + return false; + } +}; + +interface JsonViewerProps { + data: string; +} + +const JsonViewer = ({ data }: JsonViewerProps) => { + const { theme } = useTheme(); + const language = guessLanguage(data); + const result = useQuery(prettierFormatQueryOptions({ language, text: data })); + const extensions = useCodeMirrorLanguageExtensions(language); + + return ( + + ); +}; diff --git a/packages/client/src/pages/websocket/routes/websocket/$websocketIdCan/index.tsx b/packages/client/src/pages/websocket/routes/websocket/$websocketIdCan/index.tsx new file mode 100644 index 000000000..2e32a210d --- /dev/null +++ b/packages/client/src/pages/websocket/routes/websocket/$websocketIdCan/index.tsx @@ -0,0 +1,19 @@ +import { createFileRoute } from '@tanstack/react-router'; +import { openTab } from '~/widgets/tabs'; +import { WebSocketPage } from '../../../page'; +import { WebSocketTab, websocketTabId } from '../../../tab'; + +export const Route = createFileRoute( + '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(websocket)/websocket/$websocketIdCan/', +)({ + component: WebSocketPage, + onEnter: async (match) => { + const { websocketId } = match.context; + + await openTab({ + id: websocketTabId({ websocketId }), + match, + node: , + }); + }, +}); diff --git a/packages/client/src/pages/websocket/routes/websocket/$websocketIdCan/route.tsx b/packages/client/src/pages/websocket/routes/websocket/$websocketIdCan/route.tsx new file mode 100644 index 000000000..66c867f12 --- /dev/null +++ b/packages/client/src/pages/websocket/routes/websocket/$websocketIdCan/route.tsx @@ -0,0 +1,11 @@ +import { createFileRoute } from '@tanstack/react-router'; +import { Ulid } from 'id128'; + +export const Route = createFileRoute( + '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(websocket)/websocket/$websocketIdCan', +)({ + context: ({ params: { websocketIdCan } }) => { + const websocketId = Ulid.fromCanonical(websocketIdCan).bytes; + return { websocketId }; + }, +}); diff --git a/packages/client/src/pages/websocket/tab.tsx b/packages/client/src/pages/websocket/tab.tsx new file mode 100644 index 000000000..d5fef1ec5 --- /dev/null +++ b/packages/client/src/pages/websocket/tab.tsx @@ -0,0 +1,35 @@ +import { useLiveQuery } from '@tanstack/react-db'; +import { FiWifi } from 'react-icons/fi'; +import { WebSocketCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/web_socket'; +import { tw } from '@the-dev-tools/ui/tailwind-literal'; +import { useApiCollection } from '~/shared/api'; +import { eqStruct } from '~/shared/lib'; +import { routes } from '~/shared/routes'; + +export interface WebSocketTabProps { + websocketId: Uint8Array; +} + +export const websocketTabId = ({ websocketId }: WebSocketTabProps) => + JSON.stringify({ route: routes.dashboard.workspace.websocket.route.id, websocketId }); + +export const WebSocketTab = ({ websocketId }: WebSocketTabProps) => { + const websocketCollection = useApiCollection(WebSocketCollectionSchema); + + const name = + useLiveQuery( + (_) => + _.from({ item: websocketCollection }) + .where(eqStruct({ websocketId })) + .select((_) => ({ name: _.item.name })) + .findOne(), + [websocketCollection, websocketId], + ).data?.name ?? 'WebSocket'; + + return ( + <> + + {name} + + ); +}; diff --git a/packages/client/src/pages/websocket/use-websocket.ts b/packages/client/src/pages/websocket/use-websocket.ts new file mode 100644 index 000000000..c8fe6e14b --- /dev/null +++ b/packages/client/src/pages/websocket/use-websocket.ts @@ -0,0 +1,107 @@ +import { useCallback, useEffect, useRef, useState } from 'react'; + +export type ConnectionState = 'connected' | 'connecting' | 'disconnected' | 'error'; + +export interface WsMessage { + data: string; + direction: 'received' | 'sent'; + id: string; + timestamp: number; +} + +const MAX_MESSAGES = 1000; + +export interface UseWebSocketReturn { + clearMessages: () => void; + connect: (url: string) => void; + disconnect: () => void; + error: string | undefined; + messages: WsMessage[]; + send: (message: string) => void; + state: ConnectionState; +} + +export const useWebSocket = (): UseWebSocketReturn => { + const wsRef = useRef(null); + const [state, setState] = useState('disconnected'); + const [messages, setMessages] = useState([]); + const [error, setError] = useState(); + + const disconnect = useCallback(() => { + if (wsRef.current) { + wsRef.current.close(); + wsRef.current = null; + } + }, []); + + const connect = useCallback( + (url: string) => { + disconnect(); + setError(undefined); + setState('connecting'); + + let wsUrl = url; + if (wsUrl.startsWith('http://')) wsUrl = 'ws://' + wsUrl.slice(7); + else if (wsUrl.startsWith('https://')) wsUrl = 'wss://' + wsUrl.slice(8); + + try { + const ws = new WebSocket(wsUrl); + wsRef.current = ws; + + ws.onopen = () => { + setState('connected'); + }; + + ws.onclose = () => { + setState('disconnected'); + wsRef.current = null; + }; + + ws.onerror = () => { + setError('Connection failed'); + setState('error'); + }; + + ws.onmessage = (event: MessageEvent) => { + const msg: WsMessage = { + data: typeof event.data === 'string' ? event.data : String(event.data), + direction: 'received', + id: crypto.randomUUID(), + timestamp: Date.now(), + }; + setMessages((prev) => (prev.length >= MAX_MESSAGES ? [...prev.slice(1), msg] : [...prev, msg])); + }; + } catch { + setError('Invalid WebSocket URL'); + setState('error'); + } + }, + [disconnect], + ); + + const send = useCallback((message: string) => { + const ws = wsRef.current; + if (ws?.readyState !== WebSocket.OPEN) return; + + ws.send(message); + const msg: WsMessage = { + data: message, + direction: 'sent', + id: crypto.randomUUID(), + timestamp: Date.now(), + }; + setMessages((prev) => (prev.length >= MAX_MESSAGES ? [...prev.slice(1), msg] : [...prev, msg])); + }, []); + + const clearMessages = useCallback(() => { + setMessages([]); + }, []); + + useEffect(() => { + return () => { + wsRef.current?.close(); + }; + }, []); + + return { clearMessages, connect, disconnect, error, messages, send, state }; +}; diff --git a/packages/client/src/pages/workspace/routes/workspace/$workspaceIdCan/(websocket)/__virtual.ts b/packages/client/src/pages/workspace/routes/workspace/$workspaceIdCan/(websocket)/__virtual.ts new file mode 100644 index 000000000..a74b3fae4 --- /dev/null +++ b/packages/client/src/pages/workspace/routes/workspace/$workspaceIdCan/(websocket)/__virtual.ts @@ -0,0 +1,3 @@ +import { resolveRoutesFrom } from '../../../../../websocket/@x/workspace'; + +export default resolveRoutesFrom(import.meta.dirname); diff --git a/packages/client/src/shared/api/collection.internal.tsx b/packages/client/src/shared/api/collection.internal.tsx index 62e60d034..03d896b80 100644 --- a/packages/client/src/shared/api/collection.internal.tsx +++ b/packages/client/src/shared/api/collection.internal.tsx @@ -108,7 +108,11 @@ const createApiCollection = (schema: TSchem Match.value, Match.when( { $typeName: schema.sync.insert.typeName }, - (_: Message) => void write({ type: 'insert', value: createAlike(schema.item, _) as Item }), + (_: Message) => + void write({ + type: collection.has(getKey(_ as Item)) ? 'update' : 'insert', + value: createAlike(schema.item, _) as Item, + }), ), Match.when( { $typeName: schema.sync.upsert.typeName }, diff --git a/packages/client/src/shared/routes.tsx b/packages/client/src/shared/routes.tsx index b7c3990f0..73bc88fe3 100644 --- a/packages/client/src/shared/routes.tsx +++ b/packages/client/src/shared/routes.tsx @@ -34,6 +34,10 @@ export const routes = { '/(dashboard)/(workspace)/workspace/$workspaceIdCan/(http)/http/$httpIdCan/delta/$deltaHttpIdCan', ), }, + websocket: { + route: getRouteApi('/(dashboard)/(workspace)/workspace/$workspaceIdCan/(websocket)/websocket/$websocketIdCan'), + index: getRouteApi('/(dashboard)/(workspace)/workspace/$workspaceIdCan/(websocket)/websocket/$websocketIdCan/'), + }, }, }, }; diff --git a/packages/db/pkg/sqlc/gen/db.go b/packages/db/pkg/sqlc/gen/db.go index d2a8aeb06..604277fa3 100644 --- a/packages/db/pkg/sqlc/gen/db.go +++ b/packages/db/pkg/sqlc/gen/db.go @@ -141,6 +141,9 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) { if q.cleanupOrphanedFlowNodeJsStmt, err = db.PrepareContext(ctx, cleanupOrphanedFlowNodeJs); err != nil { return nil, fmt.Errorf("error preparing query CleanupOrphanedFlowNodeJs: %w", err) } + if q.cleanupOrphanedFlowNodeWaitStmt, err = db.PrepareContext(ctx, cleanupOrphanedFlowNodeWait); err != nil { + return nil, fmt.Errorf("error preparing query CleanupOrphanedFlowNodeWait: %w", err) + } if q.cleanupOrphanedNodeExecutionsStmt, err = db.PrepareContext(ctx, cleanupOrphanedNodeExecutions); err != nil { return nil, fmt.Errorf("error preparing query CleanupOrphanedNodeExecutions: %w", err) } @@ -198,9 +201,18 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) { if q.createFlowNodeMemoryStmt, err = db.PrepareContext(ctx, createFlowNodeMemory); err != nil { return nil, fmt.Errorf("error preparing query CreateFlowNodeMemory: %w", err) } + if q.createFlowNodeWaitStmt, err = db.PrepareContext(ctx, createFlowNodeWait); err != nil { + return nil, fmt.Errorf("error preparing query CreateFlowNodeWait: %w", err) + } if q.createFlowNodeWithStateStmt, err = db.PrepareContext(ctx, createFlowNodeWithState); err != nil { return nil, fmt.Errorf("error preparing query CreateFlowNodeWithState: %w", err) } + if q.createFlowNodeWsConnectionStmt, err = db.PrepareContext(ctx, createFlowNodeWsConnection); err != nil { + return nil, fmt.Errorf("error preparing query CreateFlowNodeWsConnection: %w", err) + } + if q.createFlowNodeWsSendStmt, err = db.PrepareContext(ctx, createFlowNodeWsSend); err != nil { + return nil, fmt.Errorf("error preparing query CreateFlowNodeWsSend: %w", err) + } if q.createFlowNodesBulkStmt, err = db.PrepareContext(ctx, createFlowNodesBulk); err != nil { return nil, fmt.Errorf("error preparing query CreateFlowNodesBulk: %w", err) } @@ -306,6 +318,12 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) { if q.createVariableBulkStmt, err = db.PrepareContext(ctx, createVariableBulk); err != nil { return nil, fmt.Errorf("error preparing query CreateVariableBulk: %w", err) } + if q.createWebSocketStmt, err = db.PrepareContext(ctx, createWebSocket); err != nil { + return nil, fmt.Errorf("error preparing query CreateWebSocket: %w", err) + } + if q.createWebSocketHeaderStmt, err = db.PrepareContext(ctx, createWebSocketHeader); err != nil { + return nil, fmt.Errorf("error preparing query CreateWebSocketHeader: %w", err) + } if q.createWorkspaceStmt, err = db.PrepareContext(ctx, createWorkspace); err != nil { return nil, fmt.Errorf("error preparing query CreateWorkspace: %w", err) } @@ -366,6 +384,15 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) { if q.deleteFlowNodeMemoryStmt, err = db.PrepareContext(ctx, deleteFlowNodeMemory); err != nil { return nil, fmt.Errorf("error preparing query DeleteFlowNodeMemory: %w", err) } + if q.deleteFlowNodeWaitStmt, err = db.PrepareContext(ctx, deleteFlowNodeWait); err != nil { + return nil, fmt.Errorf("error preparing query DeleteFlowNodeWait: %w", err) + } + if q.deleteFlowNodeWsConnectionStmt, err = db.PrepareContext(ctx, deleteFlowNodeWsConnection); err != nil { + return nil, fmt.Errorf("error preparing query DeleteFlowNodeWsConnection: %w", err) + } + if q.deleteFlowNodeWsSendStmt, err = db.PrepareContext(ctx, deleteFlowNodeWsSend); err != nil { + return nil, fmt.Errorf("error preparing query DeleteFlowNodeWsSend: %w", err) + } if q.deleteFlowTagStmt, err = db.PrepareContext(ctx, deleteFlowTag); err != nil { return nil, fmt.Errorf("error preparing query DeleteFlowTag: %w", err) } @@ -435,6 +462,15 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) { if q.deleteVariableStmt, err = db.PrepareContext(ctx, deleteVariable); err != nil { return nil, fmt.Errorf("error preparing query DeleteVariable: %w", err) } + if q.deleteWebSocketStmt, err = db.PrepareContext(ctx, deleteWebSocket); err != nil { + return nil, fmt.Errorf("error preparing query DeleteWebSocket: %w", err) + } + if q.deleteWebSocketHeaderStmt, err = db.PrepareContext(ctx, deleteWebSocketHeader); err != nil { + return nil, fmt.Errorf("error preparing query DeleteWebSocketHeader: %w", err) + } + if q.deleteWebSocketHeadersByWebSocketIDStmt, err = db.PrepareContext(ctx, deleteWebSocketHeadersByWebSocketID); err != nil { + return nil, fmt.Errorf("error preparing query DeleteWebSocketHeadersByWebSocketID: %w", err) + } if q.deleteWorkspaceStmt, err = db.PrepareContext(ctx, deleteWorkspace); err != nil { return nil, fmt.Errorf("error preparing query DeleteWorkspace: %w", err) } @@ -561,6 +597,15 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) { if q.getFlowNodeMemoryStmt, err = db.PrepareContext(ctx, getFlowNodeMemory); err != nil { return nil, fmt.Errorf("error preparing query GetFlowNodeMemory: %w", err) } + if q.getFlowNodeWaitStmt, err = db.PrepareContext(ctx, getFlowNodeWait); err != nil { + return nil, fmt.Errorf("error preparing query GetFlowNodeWait: %w", err) + } + if q.getFlowNodeWsConnectionStmt, err = db.PrepareContext(ctx, getFlowNodeWsConnection); err != nil { + return nil, fmt.Errorf("error preparing query GetFlowNodeWsConnection: %w", err) + } + if q.getFlowNodeWsSendStmt, err = db.PrepareContext(ctx, getFlowNodeWsSend); err != nil { + return nil, fmt.Errorf("error preparing query GetFlowNodeWsSend: %w", err) + } if q.getFlowNodesByFlowIDStmt, err = db.PrepareContext(ctx, getFlowNodesByFlowID); err != nil { return nil, fmt.Errorf("error preparing query GetFlowNodesByFlowID: %w", err) } @@ -870,6 +915,21 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) { if q.getVariablesByEnvironmentIDOrderedStmt, err = db.PrepareContext(ctx, getVariablesByEnvironmentIDOrdered); err != nil { return nil, fmt.Errorf("error preparing query GetVariablesByEnvironmentIDOrdered: %w", err) } + if q.getWebSocketStmt, err = db.PrepareContext(ctx, getWebSocket); err != nil { + return nil, fmt.Errorf("error preparing query GetWebSocket: %w", err) + } + if q.getWebSocketHeaderByIDStmt, err = db.PrepareContext(ctx, getWebSocketHeaderByID); err != nil { + return nil, fmt.Errorf("error preparing query GetWebSocketHeaderByID: %w", err) + } + if q.getWebSocketHeadersStmt, err = db.PrepareContext(ctx, getWebSocketHeaders); err != nil { + return nil, fmt.Errorf("error preparing query GetWebSocketHeaders: %w", err) + } + if q.getWebSocketWorkspaceIDStmt, err = db.PrepareContext(ctx, getWebSocketWorkspaceID); err != nil { + return nil, fmt.Errorf("error preparing query GetWebSocketWorkspaceID: %w", err) + } + if q.getWebSocketsByWorkspaceIDStmt, err = db.PrepareContext(ctx, getWebSocketsByWorkspaceID); err != nil { + return nil, fmt.Errorf("error preparing query GetWebSocketsByWorkspaceID: %w", err) + } if q.getWorkspaceStmt, err = db.PrepareContext(ctx, getWorkspace); err != nil { return nil, fmt.Errorf("error preparing query GetWorkspace: %w", err) } @@ -975,6 +1035,15 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) { if q.updateFlowNodeStateStmt, err = db.PrepareContext(ctx, updateFlowNodeState); err != nil { return nil, fmt.Errorf("error preparing query UpdateFlowNodeState: %w", err) } + if q.updateFlowNodeWaitStmt, err = db.PrepareContext(ctx, updateFlowNodeWait); err != nil { + return nil, fmt.Errorf("error preparing query UpdateFlowNodeWait: %w", err) + } + if q.updateFlowNodeWsConnectionStmt, err = db.PrepareContext(ctx, updateFlowNodeWsConnection); err != nil { + return nil, fmt.Errorf("error preparing query UpdateFlowNodeWsConnection: %w", err) + } + if q.updateFlowNodeWsSendStmt, err = db.PrepareContext(ctx, updateFlowNodeWsSend); err != nil { + return nil, fmt.Errorf("error preparing query UpdateFlowNodeWsSend: %w", err) + } if q.updateFlowVariableStmt, err = db.PrepareContext(ctx, updateFlowVariable); err != nil { return nil, fmt.Errorf("error preparing query UpdateFlowVariable: %w", err) } @@ -1071,6 +1140,12 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) { if q.updateVariableStmt, err = db.PrepareContext(ctx, updateVariable); err != nil { return nil, fmt.Errorf("error preparing query UpdateVariable: %w", err) } + if q.updateWebSocketStmt, err = db.PrepareContext(ctx, updateWebSocket); err != nil { + return nil, fmt.Errorf("error preparing query UpdateWebSocket: %w", err) + } + if q.updateWebSocketHeaderStmt, err = db.PrepareContext(ctx, updateWebSocketHeader); err != nil { + return nil, fmt.Errorf("error preparing query UpdateWebSocketHeader: %w", err) + } if q.updateWorkspaceStmt, err = db.PrepareContext(ctx, updateWorkspace); err != nil { return nil, fmt.Errorf("error preparing query UpdateWorkspace: %w", err) } @@ -1286,6 +1361,11 @@ func (q *Queries) Close() error { err = fmt.Errorf("error closing cleanupOrphanedFlowNodeJsStmt: %w", cerr) } } + if q.cleanupOrphanedFlowNodeWaitStmt != nil { + if cerr := q.cleanupOrphanedFlowNodeWaitStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing cleanupOrphanedFlowNodeWaitStmt: %w", cerr) + } + } if q.cleanupOrphanedNodeExecutionsStmt != nil { if cerr := q.cleanupOrphanedNodeExecutionsStmt.Close(); cerr != nil { err = fmt.Errorf("error closing cleanupOrphanedNodeExecutionsStmt: %w", cerr) @@ -1381,11 +1461,26 @@ func (q *Queries) Close() error { err = fmt.Errorf("error closing createFlowNodeMemoryStmt: %w", cerr) } } + if q.createFlowNodeWaitStmt != nil { + if cerr := q.createFlowNodeWaitStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createFlowNodeWaitStmt: %w", cerr) + } + } if q.createFlowNodeWithStateStmt != nil { if cerr := q.createFlowNodeWithStateStmt.Close(); cerr != nil { err = fmt.Errorf("error closing createFlowNodeWithStateStmt: %w", cerr) } } + if q.createFlowNodeWsConnectionStmt != nil { + if cerr := q.createFlowNodeWsConnectionStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createFlowNodeWsConnectionStmt: %w", cerr) + } + } + if q.createFlowNodeWsSendStmt != nil { + if cerr := q.createFlowNodeWsSendStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createFlowNodeWsSendStmt: %w", cerr) + } + } if q.createFlowNodesBulkStmt != nil { if cerr := q.createFlowNodesBulkStmt.Close(); cerr != nil { err = fmt.Errorf("error closing createFlowNodesBulkStmt: %w", cerr) @@ -1561,6 +1656,16 @@ func (q *Queries) Close() error { err = fmt.Errorf("error closing createVariableBulkStmt: %w", cerr) } } + if q.createWebSocketStmt != nil { + if cerr := q.createWebSocketStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createWebSocketStmt: %w", cerr) + } + } + if q.createWebSocketHeaderStmt != nil { + if cerr := q.createWebSocketHeaderStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createWebSocketHeaderStmt: %w", cerr) + } + } if q.createWorkspaceStmt != nil { if cerr := q.createWorkspaceStmt.Close(); cerr != nil { err = fmt.Errorf("error closing createWorkspaceStmt: %w", cerr) @@ -1661,6 +1766,21 @@ func (q *Queries) Close() error { err = fmt.Errorf("error closing deleteFlowNodeMemoryStmt: %w", cerr) } } + if q.deleteFlowNodeWaitStmt != nil { + if cerr := q.deleteFlowNodeWaitStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing deleteFlowNodeWaitStmt: %w", cerr) + } + } + if q.deleteFlowNodeWsConnectionStmt != nil { + if cerr := q.deleteFlowNodeWsConnectionStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing deleteFlowNodeWsConnectionStmt: %w", cerr) + } + } + if q.deleteFlowNodeWsSendStmt != nil { + if cerr := q.deleteFlowNodeWsSendStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing deleteFlowNodeWsSendStmt: %w", cerr) + } + } if q.deleteFlowTagStmt != nil { if cerr := q.deleteFlowTagStmt.Close(); cerr != nil { err = fmt.Errorf("error closing deleteFlowTagStmt: %w", cerr) @@ -1776,6 +1896,21 @@ func (q *Queries) Close() error { err = fmt.Errorf("error closing deleteVariableStmt: %w", cerr) } } + if q.deleteWebSocketStmt != nil { + if cerr := q.deleteWebSocketStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing deleteWebSocketStmt: %w", cerr) + } + } + if q.deleteWebSocketHeaderStmt != nil { + if cerr := q.deleteWebSocketHeaderStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing deleteWebSocketHeaderStmt: %w", cerr) + } + } + if q.deleteWebSocketHeadersByWebSocketIDStmt != nil { + if cerr := q.deleteWebSocketHeadersByWebSocketIDStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing deleteWebSocketHeadersByWebSocketIDStmt: %w", cerr) + } + } if q.deleteWorkspaceStmt != nil { if cerr := q.deleteWorkspaceStmt.Close(); cerr != nil { err = fmt.Errorf("error closing deleteWorkspaceStmt: %w", cerr) @@ -1986,6 +2121,21 @@ func (q *Queries) Close() error { err = fmt.Errorf("error closing getFlowNodeMemoryStmt: %w", cerr) } } + if q.getFlowNodeWaitStmt != nil { + if cerr := q.getFlowNodeWaitStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getFlowNodeWaitStmt: %w", cerr) + } + } + if q.getFlowNodeWsConnectionStmt != nil { + if cerr := q.getFlowNodeWsConnectionStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getFlowNodeWsConnectionStmt: %w", cerr) + } + } + if q.getFlowNodeWsSendStmt != nil { + if cerr := q.getFlowNodeWsSendStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getFlowNodeWsSendStmt: %w", cerr) + } + } if q.getFlowNodesByFlowIDStmt != nil { if cerr := q.getFlowNodesByFlowIDStmt.Close(); cerr != nil { err = fmt.Errorf("error closing getFlowNodesByFlowIDStmt: %w", cerr) @@ -2501,6 +2651,31 @@ func (q *Queries) Close() error { err = fmt.Errorf("error closing getVariablesByEnvironmentIDOrderedStmt: %w", cerr) } } + if q.getWebSocketStmt != nil { + if cerr := q.getWebSocketStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getWebSocketStmt: %w", cerr) + } + } + if q.getWebSocketHeaderByIDStmt != nil { + if cerr := q.getWebSocketHeaderByIDStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getWebSocketHeaderByIDStmt: %w", cerr) + } + } + if q.getWebSocketHeadersStmt != nil { + if cerr := q.getWebSocketHeadersStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getWebSocketHeadersStmt: %w", cerr) + } + } + if q.getWebSocketWorkspaceIDStmt != nil { + if cerr := q.getWebSocketWorkspaceIDStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getWebSocketWorkspaceIDStmt: %w", cerr) + } + } + if q.getWebSocketsByWorkspaceIDStmt != nil { + if cerr := q.getWebSocketsByWorkspaceIDStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getWebSocketsByWorkspaceIDStmt: %w", cerr) + } + } if q.getWorkspaceStmt != nil { if cerr := q.getWorkspaceStmt.Close(); cerr != nil { err = fmt.Errorf("error closing getWorkspaceStmt: %w", cerr) @@ -2676,6 +2851,21 @@ func (q *Queries) Close() error { err = fmt.Errorf("error closing updateFlowNodeStateStmt: %w", cerr) } } + if q.updateFlowNodeWaitStmt != nil { + if cerr := q.updateFlowNodeWaitStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateFlowNodeWaitStmt: %w", cerr) + } + } + if q.updateFlowNodeWsConnectionStmt != nil { + if cerr := q.updateFlowNodeWsConnectionStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateFlowNodeWsConnectionStmt: %w", cerr) + } + } + if q.updateFlowNodeWsSendStmt != nil { + if cerr := q.updateFlowNodeWsSendStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateFlowNodeWsSendStmt: %w", cerr) + } + } if q.updateFlowVariableStmt != nil { if cerr := q.updateFlowVariableStmt.Close(); cerr != nil { err = fmt.Errorf("error closing updateFlowVariableStmt: %w", cerr) @@ -2836,6 +3026,16 @@ func (q *Queries) Close() error { err = fmt.Errorf("error closing updateVariableStmt: %w", cerr) } } + if q.updateWebSocketStmt != nil { + if cerr := q.updateWebSocketStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateWebSocketStmt: %w", cerr) + } + } + if q.updateWebSocketHeaderStmt != nil { + if cerr := q.updateWebSocketHeaderStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateWebSocketHeaderStmt: %w", cerr) + } + } if q.updateWorkspaceStmt != nil { if cerr := q.updateWorkspaceStmt.Close(); cerr != nil { err = fmt.Errorf("error closing updateWorkspaceStmt: %w", cerr) @@ -2939,6 +3139,7 @@ type Queries struct { cleanupOrphanedFlowNodeGraphQLStmt *sql.Stmt cleanupOrphanedFlowNodeHttpStmt *sql.Stmt cleanupOrphanedFlowNodeJsStmt *sql.Stmt + cleanupOrphanedFlowNodeWaitStmt *sql.Stmt cleanupOrphanedNodeExecutionsStmt *sql.Stmt createCredentialStmt *sql.Stmt createCredentialAnthropicStmt *sql.Stmt @@ -2958,7 +3159,10 @@ type Queries struct { createFlowNodeHTTPStmt *sql.Stmt createFlowNodeJsStmt *sql.Stmt createFlowNodeMemoryStmt *sql.Stmt + createFlowNodeWaitStmt *sql.Stmt createFlowNodeWithStateStmt *sql.Stmt + createFlowNodeWsConnectionStmt *sql.Stmt + createFlowNodeWsSendStmt *sql.Stmt createFlowNodesBulkStmt *sql.Stmt createFlowTagStmt *sql.Stmt createFlowVariableStmt *sql.Stmt @@ -2994,6 +3198,8 @@ type Queries struct { createUserStmt *sql.Stmt createVariableStmt *sql.Stmt createVariableBulkStmt *sql.Stmt + createWebSocketStmt *sql.Stmt + createWebSocketHeaderStmt *sql.Stmt createWorkspaceStmt *sql.Stmt createWorkspaceUserStmt *sql.Stmt deleteCredentialStmt *sql.Stmt @@ -3014,6 +3220,9 @@ type Queries struct { deleteFlowNodeHTTPStmt *sql.Stmt deleteFlowNodeJsStmt *sql.Stmt deleteFlowNodeMemoryStmt *sql.Stmt + deleteFlowNodeWaitStmt *sql.Stmt + deleteFlowNodeWsConnectionStmt *sql.Stmt + deleteFlowNodeWsSendStmt *sql.Stmt deleteFlowTagStmt *sql.Stmt deleteFlowVariableStmt *sql.Stmt deleteGraphQLStmt *sql.Stmt @@ -3037,6 +3246,9 @@ type Queries struct { deleteTagStmt *sql.Stmt deleteUserStmt *sql.Stmt deleteVariableStmt *sql.Stmt + deleteWebSocketStmt *sql.Stmt + deleteWebSocketHeaderStmt *sql.Stmt + deleteWebSocketHeadersByWebSocketIDStmt *sql.Stmt deleteWorkspaceStmt *sql.Stmt deleteWorkspaceUserStmt *sql.Stmt findFileByPathHashStmt *sql.Stmt @@ -3079,6 +3291,9 @@ type Queries struct { getFlowNodeHTTPStmt *sql.Stmt getFlowNodeJsStmt *sql.Stmt getFlowNodeMemoryStmt *sql.Stmt + getFlowNodeWaitStmt *sql.Stmt + getFlowNodeWsConnectionStmt *sql.Stmt + getFlowNodeWsSendStmt *sql.Stmt getFlowNodesByFlowIDStmt *sql.Stmt getFlowNodesByFlowIDsStmt *sql.Stmt getFlowTagStmt *sql.Stmt @@ -3182,6 +3397,11 @@ type Queries struct { getVariableStmt *sql.Stmt getVariablesByEnvironmentIDStmt *sql.Stmt getVariablesByEnvironmentIDOrderedStmt *sql.Stmt + getWebSocketStmt *sql.Stmt + getWebSocketHeaderByIDStmt *sql.Stmt + getWebSocketHeadersStmt *sql.Stmt + getWebSocketWorkspaceIDStmt *sql.Stmt + getWebSocketsByWorkspaceIDStmt *sql.Stmt getWorkspaceStmt *sql.Stmt getWorkspaceByUserIDStmt *sql.Stmt getWorkspaceByUserIDandWorkspaceIDStmt *sql.Stmt @@ -3217,6 +3437,9 @@ type Queries struct { updateFlowNodeJsStmt *sql.Stmt updateFlowNodeMemoryStmt *sql.Stmt updateFlowNodeStateStmt *sql.Stmt + updateFlowNodeWaitStmt *sql.Stmt + updateFlowNodeWsConnectionStmt *sql.Stmt + updateFlowNodeWsSendStmt *sql.Stmt updateFlowVariableStmt *sql.Stmt updateFlowVariableOrderStmt *sql.Stmt updateGraphQLStmt *sql.Stmt @@ -3249,6 +3472,8 @@ type Queries struct { updateTagStmt *sql.Stmt updateUserStmt *sql.Stmt updateVariableStmt *sql.Stmt + updateWebSocketStmt *sql.Stmt + updateWebSocketHeaderStmt *sql.Stmt updateWorkspaceStmt *sql.Stmt updateWorkspaceUpdatedTimeStmt *sql.Stmt updateWorkspaceUserStmt *sql.Stmt @@ -3299,6 +3524,7 @@ func (q *Queries) WithTx(tx *sql.Tx) *Queries { cleanupOrphanedFlowNodeGraphQLStmt: q.cleanupOrphanedFlowNodeGraphQLStmt, cleanupOrphanedFlowNodeHttpStmt: q.cleanupOrphanedFlowNodeHttpStmt, cleanupOrphanedFlowNodeJsStmt: q.cleanupOrphanedFlowNodeJsStmt, + cleanupOrphanedFlowNodeWaitStmt: q.cleanupOrphanedFlowNodeWaitStmt, cleanupOrphanedNodeExecutionsStmt: q.cleanupOrphanedNodeExecutionsStmt, createCredentialStmt: q.createCredentialStmt, createCredentialAnthropicStmt: q.createCredentialAnthropicStmt, @@ -3318,7 +3544,10 @@ func (q *Queries) WithTx(tx *sql.Tx) *Queries { createFlowNodeHTTPStmt: q.createFlowNodeHTTPStmt, createFlowNodeJsStmt: q.createFlowNodeJsStmt, createFlowNodeMemoryStmt: q.createFlowNodeMemoryStmt, + createFlowNodeWaitStmt: q.createFlowNodeWaitStmt, createFlowNodeWithStateStmt: q.createFlowNodeWithStateStmt, + createFlowNodeWsConnectionStmt: q.createFlowNodeWsConnectionStmt, + createFlowNodeWsSendStmt: q.createFlowNodeWsSendStmt, createFlowNodesBulkStmt: q.createFlowNodesBulkStmt, createFlowTagStmt: q.createFlowTagStmt, createFlowVariableStmt: q.createFlowVariableStmt, @@ -3354,6 +3583,8 @@ func (q *Queries) WithTx(tx *sql.Tx) *Queries { createUserStmt: q.createUserStmt, createVariableStmt: q.createVariableStmt, createVariableBulkStmt: q.createVariableBulkStmt, + createWebSocketStmt: q.createWebSocketStmt, + createWebSocketHeaderStmt: q.createWebSocketHeaderStmt, createWorkspaceStmt: q.createWorkspaceStmt, createWorkspaceUserStmt: q.createWorkspaceUserStmt, deleteCredentialStmt: q.deleteCredentialStmt, @@ -3374,6 +3605,9 @@ func (q *Queries) WithTx(tx *sql.Tx) *Queries { deleteFlowNodeHTTPStmt: q.deleteFlowNodeHTTPStmt, deleteFlowNodeJsStmt: q.deleteFlowNodeJsStmt, deleteFlowNodeMemoryStmt: q.deleteFlowNodeMemoryStmt, + deleteFlowNodeWaitStmt: q.deleteFlowNodeWaitStmt, + deleteFlowNodeWsConnectionStmt: q.deleteFlowNodeWsConnectionStmt, + deleteFlowNodeWsSendStmt: q.deleteFlowNodeWsSendStmt, deleteFlowTagStmt: q.deleteFlowTagStmt, deleteFlowVariableStmt: q.deleteFlowVariableStmt, deleteGraphQLStmt: q.deleteGraphQLStmt, @@ -3397,6 +3631,9 @@ func (q *Queries) WithTx(tx *sql.Tx) *Queries { deleteTagStmt: q.deleteTagStmt, deleteUserStmt: q.deleteUserStmt, deleteVariableStmt: q.deleteVariableStmt, + deleteWebSocketStmt: q.deleteWebSocketStmt, + deleteWebSocketHeaderStmt: q.deleteWebSocketHeaderStmt, + deleteWebSocketHeadersByWebSocketIDStmt: q.deleteWebSocketHeadersByWebSocketIDStmt, deleteWorkspaceStmt: q.deleteWorkspaceStmt, deleteWorkspaceUserStmt: q.deleteWorkspaceUserStmt, findFileByPathHashStmt: q.findFileByPathHashStmt, @@ -3439,6 +3676,9 @@ func (q *Queries) WithTx(tx *sql.Tx) *Queries { getFlowNodeHTTPStmt: q.getFlowNodeHTTPStmt, getFlowNodeJsStmt: q.getFlowNodeJsStmt, getFlowNodeMemoryStmt: q.getFlowNodeMemoryStmt, + getFlowNodeWaitStmt: q.getFlowNodeWaitStmt, + getFlowNodeWsConnectionStmt: q.getFlowNodeWsConnectionStmt, + getFlowNodeWsSendStmt: q.getFlowNodeWsSendStmt, getFlowNodesByFlowIDStmt: q.getFlowNodesByFlowIDStmt, getFlowNodesByFlowIDsStmt: q.getFlowNodesByFlowIDsStmt, getFlowTagStmt: q.getFlowTagStmt, @@ -3542,6 +3782,11 @@ func (q *Queries) WithTx(tx *sql.Tx) *Queries { getVariableStmt: q.getVariableStmt, getVariablesByEnvironmentIDStmt: q.getVariablesByEnvironmentIDStmt, getVariablesByEnvironmentIDOrderedStmt: q.getVariablesByEnvironmentIDOrderedStmt, + getWebSocketStmt: q.getWebSocketStmt, + getWebSocketHeaderByIDStmt: q.getWebSocketHeaderByIDStmt, + getWebSocketHeadersStmt: q.getWebSocketHeadersStmt, + getWebSocketWorkspaceIDStmt: q.getWebSocketWorkspaceIDStmt, + getWebSocketsByWorkspaceIDStmt: q.getWebSocketsByWorkspaceIDStmt, getWorkspaceStmt: q.getWorkspaceStmt, getWorkspaceByUserIDStmt: q.getWorkspaceByUserIDStmt, getWorkspaceByUserIDandWorkspaceIDStmt: q.getWorkspaceByUserIDandWorkspaceIDStmt, @@ -3577,6 +3822,9 @@ func (q *Queries) WithTx(tx *sql.Tx) *Queries { updateFlowNodeJsStmt: q.updateFlowNodeJsStmt, updateFlowNodeMemoryStmt: q.updateFlowNodeMemoryStmt, updateFlowNodeStateStmt: q.updateFlowNodeStateStmt, + updateFlowNodeWaitStmt: q.updateFlowNodeWaitStmt, + updateFlowNodeWsConnectionStmt: q.updateFlowNodeWsConnectionStmt, + updateFlowNodeWsSendStmt: q.updateFlowNodeWsSendStmt, updateFlowVariableStmt: q.updateFlowVariableStmt, updateFlowVariableOrderStmt: q.updateFlowVariableOrderStmt, updateGraphQLStmt: q.updateGraphQLStmt, @@ -3609,6 +3857,8 @@ func (q *Queries) WithTx(tx *sql.Tx) *Queries { updateTagStmt: q.updateTagStmt, updateUserStmt: q.updateUserStmt, updateVariableStmt: q.updateVariableStmt, + updateWebSocketStmt: q.updateWebSocketStmt, + updateWebSocketHeaderStmt: q.updateWebSocketHeaderStmt, updateWorkspaceStmt: q.updateWorkspaceStmt, updateWorkspaceUpdatedTimeStmt: q.updateWorkspaceUpdatedTimeStmt, updateWorkspaceUserStmt: q.updateWorkspaceUserStmt, diff --git a/packages/db/pkg/sqlc/gen/flow.sql.go b/packages/db/pkg/sqlc/gen/flow.sql.go index 8398c387c..5b262ffdb 100644 --- a/packages/db/pkg/sqlc/gen/flow.sql.go +++ b/packages/db/pkg/sqlc/gen/flow.sql.go @@ -79,6 +79,15 @@ func (q *Queries) CleanupOrphanedFlowNodeJs(ctx context.Context) error { return err } +const cleanupOrphanedFlowNodeWait = `-- name: CleanupOrphanedFlowNodeWait :exec +DELETE FROM flow_node_wait WHERE flow_node_id NOT IN (SELECT id FROM flow_node) +` + +func (q *Queries) CleanupOrphanedFlowNodeWait(ctx context.Context) error { + _, err := q.exec(ctx, q.cleanupOrphanedFlowNodeWaitStmt, cleanupOrphanedFlowNodeWait) + return err +} + const cleanupOrphanedNodeExecutions = `-- name: CleanupOrphanedNodeExecutions :exec DELETE FROM node_execution WHERE node_id NOT IN (SELECT id FROM flow_node) ` @@ -294,6 +303,23 @@ func (q *Queries) CreateFlowNodeJs(ctx context.Context, arg CreateFlowNodeJsPara return err } +const createFlowNodeWait = `-- name: CreateFlowNodeWait :exec +INSERT INTO + flow_node_wait (flow_node_id, duration_ms) +VALUES + (?, ?) +` + +type CreateFlowNodeWaitParams struct { + FlowNodeID idwrap.IDWrap + DurationMs int64 +} + +func (q *Queries) CreateFlowNodeWait(ctx context.Context, arg CreateFlowNodeWaitParams) error { + _, err := q.exec(ctx, q.createFlowNodeWaitStmt, createFlowNodeWait, arg.FlowNodeID, arg.DurationMs) + return err +} + const createFlowNodeWithState = `-- name: CreateFlowNodeWithState :exec INSERT INTO flow_node (id, flow_id, name, node_kind, position_x, position_y, state) @@ -1070,6 +1096,17 @@ func (q *Queries) DeleteFlowNodeJs(ctx context.Context, flowNodeID idwrap.IDWrap return err } +const deleteFlowNodeWait = `-- name: DeleteFlowNodeWait :exec +DELETE FROM flow_node_wait +WHERE + flow_node_id = ? +` + +func (q *Queries) DeleteFlowNodeWait(ctx context.Context, flowNodeID idwrap.IDWrap) error { + _, err := q.exec(ctx, q.deleteFlowNodeWaitStmt, deleteFlowNodeWait, flowNodeID) + return err +} + const deleteFlowTag = `-- name: DeleteFlowTag :exec DELETE FROM flow_tag WHERE @@ -1592,6 +1629,23 @@ func (q *Queries) GetFlowNodeJs(ctx context.Context, flowNodeID idwrap.IDWrap) ( return i, err } +const getFlowNodeWait = `-- name: GetFlowNodeWait :one +SELECT + flow_node_id, + duration_ms +FROM + flow_node_wait +WHERE + flow_node_id = ? +` + +func (q *Queries) GetFlowNodeWait(ctx context.Context, flowNodeID idwrap.IDWrap) (FlowNodeWait, error) { + row := q.queryRow(ctx, q.getFlowNodeWaitStmt, getFlowNodeWait, flowNodeID) + var i FlowNodeWait + err := row.Scan(&i.FlowNodeID, &i.DurationMs) + return i, err +} + const getFlowNodesByFlowID = `-- name: GetFlowNodesByFlowID :many SELECT id, @@ -2711,6 +2765,24 @@ func (q *Queries) UpdateFlowNodeState(ctx context.Context, arg UpdateFlowNodeSta return err } +const updateFlowNodeWait = `-- name: UpdateFlowNodeWait :exec +UPDATE flow_node_wait +SET + duration_ms = ? +WHERE + flow_node_id = ? +` + +type UpdateFlowNodeWaitParams struct { + DurationMs int64 + FlowNodeID idwrap.IDWrap +} + +func (q *Queries) UpdateFlowNodeWait(ctx context.Context, arg UpdateFlowNodeWaitParams) error { + _, err := q.exec(ctx, q.updateFlowNodeWaitStmt, updateFlowNodeWait, arg.DurationMs, arg.FlowNodeID) + return err +} + const updateFlowVariable = `-- name: UpdateFlowVariable :exec UPDATE flow_variable SET diff --git a/packages/db/pkg/sqlc/gen/models.go b/packages/db/pkg/sqlc/gen/models.go index 0ce8a7244..0f01990c4 100644 --- a/packages/db/pkg/sqlc/gen/models.go +++ b/packages/db/pkg/sqlc/gen/models.go @@ -201,6 +201,22 @@ type FlowNodeMemory struct { WindowSize int32 } +type FlowNodeWait struct { + FlowNodeID idwrap.IDWrap + DurationMs int64 +} + +type FlowNodeWsConnection struct { + FlowNodeID idwrap.IDWrap + WebsocketID *idwrap.IDWrap +} + +type FlowNodeWsSend struct { + FlowNodeID idwrap.IDWrap + WsConnectionNodeName string + Message string +} + type FlowTag struct { ID idwrap.IDWrap FlowID idwrap.IDWrap @@ -529,6 +545,30 @@ type Variable struct { DisplayOrder float64 } +type Websocket struct { + ID idwrap.IDWrap + WorkspaceID idwrap.IDWrap + FolderID *idwrap.IDWrap + Name string + Url string + Description string + LastRunAt interface{} + CreatedAt int64 + UpdatedAt int64 +} + +type WebsocketHeader struct { + ID idwrap.IDWrap + WebsocketID idwrap.IDWrap + HeaderKey string + HeaderValue string + Description string + Enabled bool + DisplayOrder float64 + CreatedAt int64 + UpdatedAt int64 +} + type Workspace struct { ID idwrap.IDWrap Name string diff --git a/packages/db/pkg/sqlc/gen/websocket.sql.go b/packages/db/pkg/sqlc/gen/websocket.sql.go new file mode 100644 index 000000000..2eebf9c71 --- /dev/null +++ b/packages/db/pkg/sqlc/gen/websocket.sql.go @@ -0,0 +1,443 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.30.0 +// source: websocket.sql + +package gen + +import ( + "context" + + idwrap "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" +) + +const createFlowNodeWsConnection = `-- name: CreateFlowNodeWsConnection :exec +INSERT INTO flow_node_ws_connection (flow_node_id, websocket_id) VALUES (?, ?) +` + +type CreateFlowNodeWsConnectionParams struct { + FlowNodeID idwrap.IDWrap + WebsocketID *idwrap.IDWrap +} + +func (q *Queries) CreateFlowNodeWsConnection(ctx context.Context, arg CreateFlowNodeWsConnectionParams) error { + _, err := q.exec(ctx, q.createFlowNodeWsConnectionStmt, createFlowNodeWsConnection, arg.FlowNodeID, arg.WebsocketID) + return err +} + +const createFlowNodeWsSend = `-- name: CreateFlowNodeWsSend :exec +INSERT INTO flow_node_ws_send (flow_node_id, ws_connection_node_name, message) VALUES (?, ?, ?) +` + +type CreateFlowNodeWsSendParams struct { + FlowNodeID idwrap.IDWrap + WsConnectionNodeName string + Message string +} + +func (q *Queries) CreateFlowNodeWsSend(ctx context.Context, arg CreateFlowNodeWsSendParams) error { + _, err := q.exec(ctx, q.createFlowNodeWsSendStmt, createFlowNodeWsSend, arg.FlowNodeID, arg.WsConnectionNodeName, arg.Message) + return err +} + +const createWebSocket = `-- name: CreateWebSocket :exec +INSERT INTO websocket ( + id, workspace_id, folder_id, name, url, + description, last_run_at, created_at, updated_at +) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) +` + +type CreateWebSocketParams struct { + ID idwrap.IDWrap + WorkspaceID idwrap.IDWrap + FolderID *idwrap.IDWrap + Name string + Url string + Description string + LastRunAt interface{} + CreatedAt int64 + UpdatedAt int64 +} + +func (q *Queries) CreateWebSocket(ctx context.Context, arg CreateWebSocketParams) error { + _, err := q.exec(ctx, q.createWebSocketStmt, createWebSocket, + arg.ID, + arg.WorkspaceID, + arg.FolderID, + arg.Name, + arg.Url, + arg.Description, + arg.LastRunAt, + arg.CreatedAt, + arg.UpdatedAt, + ) + return err +} + +const createWebSocketHeader = `-- name: CreateWebSocketHeader :exec +INSERT INTO websocket_header ( + id, websocket_id, header_key, header_value, description, + enabled, display_order, created_at, updated_at +) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) +` + +type CreateWebSocketHeaderParams struct { + ID idwrap.IDWrap + WebsocketID idwrap.IDWrap + HeaderKey string + HeaderValue string + Description string + Enabled bool + DisplayOrder float64 + CreatedAt int64 + UpdatedAt int64 +} + +func (q *Queries) CreateWebSocketHeader(ctx context.Context, arg CreateWebSocketHeaderParams) error { + _, err := q.exec(ctx, q.createWebSocketHeaderStmt, createWebSocketHeader, + arg.ID, + arg.WebsocketID, + arg.HeaderKey, + arg.HeaderValue, + arg.Description, + arg.Enabled, + arg.DisplayOrder, + arg.CreatedAt, + arg.UpdatedAt, + ) + return err +} + +const deleteFlowNodeWsConnection = `-- name: DeleteFlowNodeWsConnection :exec +DELETE FROM flow_node_ws_connection WHERE flow_node_id = ? +` + +func (q *Queries) DeleteFlowNodeWsConnection(ctx context.Context, flowNodeID idwrap.IDWrap) error { + _, err := q.exec(ctx, q.deleteFlowNodeWsConnectionStmt, deleteFlowNodeWsConnection, flowNodeID) + return err +} + +const deleteFlowNodeWsSend = `-- name: DeleteFlowNodeWsSend :exec +DELETE FROM flow_node_ws_send WHERE flow_node_id = ? +` + +func (q *Queries) DeleteFlowNodeWsSend(ctx context.Context, flowNodeID idwrap.IDWrap) error { + _, err := q.exec(ctx, q.deleteFlowNodeWsSendStmt, deleteFlowNodeWsSend, flowNodeID) + return err +} + +const deleteWebSocket = `-- name: DeleteWebSocket :exec +DELETE FROM websocket +WHERE id = ? +` + +func (q *Queries) DeleteWebSocket(ctx context.Context, id idwrap.IDWrap) error { + _, err := q.exec(ctx, q.deleteWebSocketStmt, deleteWebSocket, id) + return err +} + +const deleteWebSocketHeader = `-- name: DeleteWebSocketHeader :exec +DELETE FROM websocket_header +WHERE id = ? +` + +func (q *Queries) DeleteWebSocketHeader(ctx context.Context, id idwrap.IDWrap) error { + _, err := q.exec(ctx, q.deleteWebSocketHeaderStmt, deleteWebSocketHeader, id) + return err +} + +const deleteWebSocketHeadersByWebSocketID = `-- name: DeleteWebSocketHeadersByWebSocketID :exec +DELETE FROM websocket_header +WHERE websocket_id = ? +` + +func (q *Queries) DeleteWebSocketHeadersByWebSocketID(ctx context.Context, websocketID idwrap.IDWrap) error { + _, err := q.exec(ctx, q.deleteWebSocketHeadersByWebSocketIDStmt, deleteWebSocketHeadersByWebSocketID, websocketID) + return err +} + +const getFlowNodeWsConnection = `-- name: GetFlowNodeWsConnection :one + +SELECT + flow_node_id, + websocket_id +FROM flow_node_ws_connection +WHERE flow_node_id = ? +LIMIT 1 +` + +// Flow Node WebSocket Queries +func (q *Queries) GetFlowNodeWsConnection(ctx context.Context, flowNodeID idwrap.IDWrap) (FlowNodeWsConnection, error) { + row := q.queryRow(ctx, q.getFlowNodeWsConnectionStmt, getFlowNodeWsConnection, flowNodeID) + var i FlowNodeWsConnection + err := row.Scan(&i.FlowNodeID, &i.WebsocketID) + return i, err +} + +const getFlowNodeWsSend = `-- name: GetFlowNodeWsSend :one +SELECT + flow_node_id, + ws_connection_node_name, + message +FROM flow_node_ws_send +WHERE flow_node_id = ? +LIMIT 1 +` + +func (q *Queries) GetFlowNodeWsSend(ctx context.Context, flowNodeID idwrap.IDWrap) (FlowNodeWsSend, error) { + row := q.queryRow(ctx, q.getFlowNodeWsSendStmt, getFlowNodeWsSend, flowNodeID) + var i FlowNodeWsSend + err := row.Scan(&i.FlowNodeID, &i.WsConnectionNodeName, &i.Message) + return i, err +} + +const getWebSocket = `-- name: GetWebSocket :one + +SELECT + id, workspace_id, folder_id, name, url, + description, last_run_at, created_at, updated_at +FROM websocket +WHERE id = ? LIMIT 1 +` + +// WebSocket Core Queries +func (q *Queries) GetWebSocket(ctx context.Context, id idwrap.IDWrap) (Websocket, error) { + row := q.queryRow(ctx, q.getWebSocketStmt, getWebSocket, id) + var i Websocket + err := row.Scan( + &i.ID, + &i.WorkspaceID, + &i.FolderID, + &i.Name, + &i.Url, + &i.Description, + &i.LastRunAt, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getWebSocketHeaderByID = `-- name: GetWebSocketHeaderByID :one +SELECT + id, websocket_id, header_key, header_value, description, + enabled, display_order, created_at, updated_at +FROM websocket_header +WHERE id = ? LIMIT 1 +` + +func (q *Queries) GetWebSocketHeaderByID(ctx context.Context, id idwrap.IDWrap) (WebsocketHeader, error) { + row := q.queryRow(ctx, q.getWebSocketHeaderByIDStmt, getWebSocketHeaderByID, id) + var i WebsocketHeader + err := row.Scan( + &i.ID, + &i.WebsocketID, + &i.HeaderKey, + &i.HeaderValue, + &i.Description, + &i.Enabled, + &i.DisplayOrder, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getWebSocketHeaders = `-- name: GetWebSocketHeaders :many + +SELECT + id, websocket_id, header_key, header_value, description, + enabled, display_order, created_at, updated_at +FROM websocket_header +WHERE websocket_id = ? +ORDER BY display_order +` + +// WebSocket Header Queries +func (q *Queries) GetWebSocketHeaders(ctx context.Context, websocketID idwrap.IDWrap) ([]WebsocketHeader, error) { + rows, err := q.query(ctx, q.getWebSocketHeadersStmt, getWebSocketHeaders, websocketID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []WebsocketHeader{} + for rows.Next() { + var i WebsocketHeader + if err := rows.Scan( + &i.ID, + &i.WebsocketID, + &i.HeaderKey, + &i.HeaderValue, + &i.Description, + &i.Enabled, + &i.DisplayOrder, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getWebSocketWorkspaceID = `-- name: GetWebSocketWorkspaceID :one +SELECT workspace_id +FROM websocket +WHERE id = ? +LIMIT 1 +` + +func (q *Queries) GetWebSocketWorkspaceID(ctx context.Context, id idwrap.IDWrap) (idwrap.IDWrap, error) { + row := q.queryRow(ctx, q.getWebSocketWorkspaceIDStmt, getWebSocketWorkspaceID, id) + var workspace_id idwrap.IDWrap + err := row.Scan(&workspace_id) + return workspace_id, err +} + +const getWebSocketsByWorkspaceID = `-- name: GetWebSocketsByWorkspaceID :many +SELECT + id, workspace_id, folder_id, name, url, + description, last_run_at, created_at, updated_at +FROM websocket +WHERE workspace_id = ? +ORDER BY updated_at DESC +` + +func (q *Queries) GetWebSocketsByWorkspaceID(ctx context.Context, workspaceID idwrap.IDWrap) ([]Websocket, error) { + rows, err := q.query(ctx, q.getWebSocketsByWorkspaceIDStmt, getWebSocketsByWorkspaceID, workspaceID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []Websocket{} + for rows.Next() { + var i Websocket + if err := rows.Scan( + &i.ID, + &i.WorkspaceID, + &i.FolderID, + &i.Name, + &i.Url, + &i.Description, + &i.LastRunAt, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateFlowNodeWsConnection = `-- name: UpdateFlowNodeWsConnection :exec +INSERT INTO flow_node_ws_connection (flow_node_id, websocket_id) VALUES (?, ?) +ON CONFLICT(flow_node_id) DO UPDATE SET + websocket_id = excluded.websocket_id +` + +type UpdateFlowNodeWsConnectionParams struct { + FlowNodeID idwrap.IDWrap + WebsocketID *idwrap.IDWrap +} + +func (q *Queries) UpdateFlowNodeWsConnection(ctx context.Context, arg UpdateFlowNodeWsConnectionParams) error { + _, err := q.exec(ctx, q.updateFlowNodeWsConnectionStmt, updateFlowNodeWsConnection, arg.FlowNodeID, arg.WebsocketID) + return err +} + +const updateFlowNodeWsSend = `-- name: UpdateFlowNodeWsSend :exec +INSERT INTO flow_node_ws_send (flow_node_id, ws_connection_node_name, message) VALUES (?, ?, ?) +ON CONFLICT(flow_node_id) DO UPDATE SET + ws_connection_node_name = excluded.ws_connection_node_name, + message = excluded.message +` + +type UpdateFlowNodeWsSendParams struct { + FlowNodeID idwrap.IDWrap + WsConnectionNodeName string + Message string +} + +func (q *Queries) UpdateFlowNodeWsSend(ctx context.Context, arg UpdateFlowNodeWsSendParams) error { + _, err := q.exec(ctx, q.updateFlowNodeWsSendStmt, updateFlowNodeWsSend, arg.FlowNodeID, arg.WsConnectionNodeName, arg.Message) + return err +} + +const updateWebSocket = `-- name: UpdateWebSocket :exec +UPDATE websocket +SET + name = ?, + url = ?, + description = ?, + last_run_at = COALESCE(?, last_run_at), + updated_at = unixepoch() +WHERE id = ? +` + +type UpdateWebSocketParams struct { + Name string + Url string + Description string + LastRunAt interface{} + ID idwrap.IDWrap +} + +func (q *Queries) UpdateWebSocket(ctx context.Context, arg UpdateWebSocketParams) error { + _, err := q.exec(ctx, q.updateWebSocketStmt, updateWebSocket, + arg.Name, + arg.Url, + arg.Description, + arg.LastRunAt, + arg.ID, + ) + return err +} + +const updateWebSocketHeader = `-- name: UpdateWebSocketHeader :exec +UPDATE websocket_header +SET + header_key = ?, + header_value = ?, + description = ?, + enabled = ?, + display_order = ?, + updated_at = unixepoch() +WHERE id = ? +` + +type UpdateWebSocketHeaderParams struct { + HeaderKey string + HeaderValue string + Description string + Enabled bool + DisplayOrder float64 + ID idwrap.IDWrap +} + +func (q *Queries) UpdateWebSocketHeader(ctx context.Context, arg UpdateWebSocketHeaderParams) error { + _, err := q.exec(ctx, q.updateWebSocketHeaderStmt, updateWebSocketHeader, + arg.HeaderKey, + arg.HeaderValue, + arg.Description, + arg.Enabled, + arg.DisplayOrder, + arg.ID, + ) + return err +} diff --git a/packages/db/pkg/sqlc/queries/flow.sql b/packages/db/pkg/sqlc/queries/flow.sql index 43a055cf4..db9763adf 100644 --- a/packages/db/pkg/sqlc/queries/flow.sql +++ b/packages/db/pkg/sqlc/queries/flow.sql @@ -522,6 +522,33 @@ DELETE FROM flow_node_js WHERE flow_node_id = ?; +-- name: GetFlowNodeWait :one +SELECT + flow_node_id, + duration_ms +FROM + flow_node_wait +WHERE + flow_node_id = ?; + +-- name: CreateFlowNodeWait :exec +INSERT INTO + flow_node_wait (flow_node_id, duration_ms) +VALUES + (?, ?); + +-- name: UpdateFlowNodeWait :exec +UPDATE flow_node_wait +SET + duration_ms = ? +WHERE + flow_node_id = ?; + +-- name: DeleteFlowNodeWait :exec +DELETE FROM flow_node_wait +WHERE + flow_node_id = ?; + -- name: GetMigration :one SELECT id, @@ -741,6 +768,9 @@ DELETE FROM flow_node_condition WHERE flow_node_id NOT IN (SELECT id FROM flow_n -- name: CleanupOrphanedFlowNodeJs :exec DELETE FROM flow_node_js WHERE flow_node_id NOT IN (SELECT id FROM flow_node); +-- name: CleanupOrphanedFlowNodeWait :exec +DELETE FROM flow_node_wait WHERE flow_node_id NOT IN (SELECT id FROM flow_node); + -- name: CleanupOrphanedFlowEdges :exec DELETE FROM flow_edge WHERE source_id NOT IN (SELECT id FROM flow_node) OR target_id NOT IN (SELECT id FROM flow_node); diff --git a/packages/db/pkg/sqlc/queries/websocket.sql b/packages/db/pkg/sqlc/queries/websocket.sql new file mode 100644 index 000000000..dd7a70f00 --- /dev/null +++ b/packages/db/pkg/sqlc/queries/websocket.sql @@ -0,0 +1,134 @@ +-- +-- WebSocket Core Queries +-- + +-- name: GetWebSocket :one +SELECT + id, workspace_id, folder_id, name, url, + description, last_run_at, created_at, updated_at +FROM websocket +WHERE id = ? LIMIT 1; + +-- name: GetWebSocketsByWorkspaceID :many +SELECT + id, workspace_id, folder_id, name, url, + description, last_run_at, created_at, updated_at +FROM websocket +WHERE workspace_id = ? +ORDER BY updated_at DESC; + +-- name: GetWebSocketWorkspaceID :one +SELECT workspace_id +FROM websocket +WHERE id = ? +LIMIT 1; + +-- name: CreateWebSocket :exec +INSERT INTO websocket ( + id, workspace_id, folder_id, name, url, + description, last_run_at, created_at, updated_at +) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?); + +-- name: UpdateWebSocket :exec +UPDATE websocket +SET + name = ?, + url = ?, + description = ?, + last_run_at = COALESCE(?, last_run_at), + updated_at = unixepoch() +WHERE id = ?; + +-- name: DeleteWebSocket :exec +DELETE FROM websocket +WHERE id = ?; + +-- +-- WebSocket Header Queries +-- + +-- name: GetWebSocketHeaders :many +SELECT + id, websocket_id, header_key, header_value, description, + enabled, display_order, created_at, updated_at +FROM websocket_header +WHERE websocket_id = ? +ORDER BY display_order; + +-- name: GetWebSocketHeaderByID :one +SELECT + id, websocket_id, header_key, header_value, description, + enabled, display_order, created_at, updated_at +FROM websocket_header +WHERE id = ? LIMIT 1; + +-- name: CreateWebSocketHeader :exec +INSERT INTO websocket_header ( + id, websocket_id, header_key, header_value, description, + enabled, display_order, created_at, updated_at +) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?); + +-- name: UpdateWebSocketHeader :exec +UPDATE websocket_header +SET + header_key = ?, + header_value = ?, + description = ?, + enabled = ?, + display_order = ?, + updated_at = unixepoch() +WHERE id = ?; + +-- name: DeleteWebSocketHeader :exec +DELETE FROM websocket_header +WHERE id = ?; + +-- name: DeleteWebSocketHeadersByWebSocketID :exec +DELETE FROM websocket_header +WHERE websocket_id = ?; + +-- +-- Flow Node WebSocket Queries +-- + +-- name: GetFlowNodeWsConnection :one +SELECT + flow_node_id, + websocket_id +FROM flow_node_ws_connection +WHERE flow_node_id = ? +LIMIT 1; + +-- name: CreateFlowNodeWsConnection :exec +INSERT INTO flow_node_ws_connection (flow_node_id, websocket_id) VALUES (?, ?); + +-- name: UpdateFlowNodeWsConnection :exec +INSERT INTO flow_node_ws_connection (flow_node_id, websocket_id) VALUES (?, ?) +ON CONFLICT(flow_node_id) DO UPDATE SET + websocket_id = excluded.websocket_id; + +-- name: DeleteFlowNodeWsConnection :exec +DELETE FROM flow_node_ws_connection WHERE flow_node_id = ?; + +-- name: GetFlowNodeWsSend :one +SELECT + flow_node_id, + ws_connection_node_name, + message +FROM flow_node_ws_send +WHERE flow_node_id = ? +LIMIT 1; + +-- name: CreateFlowNodeWsSend :exec +INSERT INTO flow_node_ws_send (flow_node_id, ws_connection_node_name, message) VALUES (?, ?, ?); + +-- name: UpdateFlowNodeWsSend :exec +INSERT INTO flow_node_ws_send (flow_node_id, ws_connection_node_name, message) VALUES (?, ?, ?) +ON CONFLICT(flow_node_id) DO UPDATE SET + ws_connection_node_name = excluded.ws_connection_node_name, + message = excluded.message; + +-- name: DeleteFlowNodeWsSend :exec +DELETE FROM flow_node_ws_send WHERE flow_node_id = ?; diff --git a/packages/db/pkg/sqlc/schema/05_flow.sql b/packages/db/pkg/sqlc/schema/05_flow.sql index 6d7729c6c..c80a925c4 100644 --- a/packages/db/pkg/sqlc/schema/05_flow.sql +++ b/packages/db/pkg/sqlc/schema/05_flow.sql @@ -103,6 +103,11 @@ CREATE TABLE flow_node_js ( code_compress_type INT8 NOT NULL ); +CREATE TABLE flow_node_wait ( + flow_node_id BLOB NOT NULL PRIMARY KEY, + duration_ms BIGINT NOT NULL +); + CREATE TABLE flow_variable ( id BLOB NOT NULL PRIMARY KEY, flow_id BLOB NOT NULL, diff --git a/packages/db/pkg/sqlc/schema/10_websocket.sql b/packages/db/pkg/sqlc/schema/10_websocket.sql new file mode 100644 index 000000000..d8be5935d --- /dev/null +++ b/packages/db/pkg/sqlc/schema/10_websocket.sql @@ -0,0 +1,57 @@ +/* + * + * WEBSOCKET SYSTEM + * WebSocket connection support for flows and standalone testing + * + */ + +-- Core WebSocket connection definition +CREATE TABLE websocket ( + id BLOB NOT NULL PRIMARY KEY, + workspace_id BLOB NOT NULL, + folder_id BLOB, + name TEXT NOT NULL, + url TEXT NOT NULL, + description TEXT NOT NULL DEFAULT '', + last_run_at BIGINT NULL, + created_at BIGINT NOT NULL DEFAULT (unixepoch()), + updated_at BIGINT NOT NULL DEFAULT (unixepoch()), + + FOREIGN KEY (workspace_id) REFERENCES workspaces (id) ON DELETE CASCADE, + FOREIGN KEY (folder_id) REFERENCES files (id) ON DELETE SET NULL +); + +CREATE INDEX websocket_workspace_idx ON websocket (workspace_id); +CREATE INDEX websocket_folder_idx ON websocket (folder_id) WHERE folder_id IS NOT NULL; + +-- WebSocket connection headers (sent during handshake) +CREATE TABLE websocket_header ( + id BLOB NOT NULL PRIMARY KEY, + websocket_id BLOB NOT NULL, + header_key TEXT NOT NULL, + header_value TEXT NOT NULL, + description TEXT NOT NULL DEFAULT '', + enabled BOOLEAN NOT NULL DEFAULT TRUE, + display_order REAL NOT NULL DEFAULT 0, + created_at BIGINT NOT NULL DEFAULT (unixepoch()), + updated_at BIGINT NOT NULL DEFAULT (unixepoch()), + + FOREIGN KEY (websocket_id) REFERENCES websocket (id) ON DELETE CASCADE +); + +CREATE INDEX websocket_header_ws_idx ON websocket_header (websocket_id); +CREATE INDEX websocket_header_order_idx ON websocket_header (websocket_id, display_order); + +-- Flow node: WebSocket Connection (entry/listener node) +CREATE TABLE flow_node_ws_connection ( + flow_node_id BLOB NOT NULL PRIMARY KEY, + websocket_id BLOB, + FOREIGN KEY (websocket_id) REFERENCES websocket (id) ON DELETE SET NULL +); + +-- Flow node: WebSocket Send (action node) +CREATE TABLE flow_node_ws_send ( + flow_node_id BLOB NOT NULL PRIMARY KEY, + ws_connection_node_name TEXT NOT NULL DEFAULT '', + message TEXT NOT NULL DEFAULT '' +); diff --git a/packages/db/pkg/sqlc/sqlc.yaml b/packages/db/pkg/sqlc/sqlc.yaml index 2402ae3ae..b8a7e5067 100644 --- a/packages/db/pkg/sqlc/sqlc.yaml +++ b/packages/db/pkg/sqlc/sqlc.yaml @@ -932,3 +932,56 @@ sql: import: 'github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap' package: 'idwrap' type: 'IDWrap' + ## WebSocket system + ### websocket table + - column: 'websocket.id' + go_type: + import: 'github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap' + package: 'idwrap' + type: 'IDWrap' + - column: 'websocket.workspace_id' + go_type: + import: 'github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap' + package: 'idwrap' + type: 'IDWrap' + - column: 'websocket.folder_id' + go_type: + import: 'github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap' + package: 'idwrap' + type: 'IDWrap' + pointer: true + ### websocket_header table + - column: 'websocket_header.id' + go_type: + import: 'github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap' + package: 'idwrap' + type: 'IDWrap' + - column: 'websocket_header.websocket_id' + go_type: + import: 'github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap' + package: 'idwrap' + type: 'IDWrap' + ### flow_node_ws_connection table + - column: 'flow_node_ws_connection.flow_node_id' + go_type: + import: 'github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap' + package: 'idwrap' + type: 'IDWrap' + - column: 'flow_node_ws_connection.websocket_id' + go_type: + import: 'github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap' + package: 'idwrap' + type: 'IDWrap' + pointer: true + ### flow_node_ws_send table + - column: 'flow_node_ws_send.flow_node_id' + go_type: + import: 'github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap' + package: 'idwrap' + type: 'IDWrap' + ### flow_node_wait table + - column: 'flow_node_wait.flow_node_id' + go_type: + import: 'github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap' + package: 'idwrap' + type: 'IDWrap' diff --git a/packages/server/cmd/serverrun/serverrun.go b/packages/server/cmd/serverrun/serverrun.go index ae80bae5f..4e6d5fa85 100644 --- a/packages/server/cmd/serverrun/serverrun.go +++ b/packages/server/cmd/serverrun/serverrun.go @@ -34,6 +34,7 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/internal/api/rimportv2" "github.com/the-dev-tools/dev-tools/packages/server/internal/api/rlog" "github.com/the-dev-tools/dev-tools/packages/server/internal/api/rreference" + "github.com/the-dev-tools/dev-tools/packages/server/internal/api/rwebsocket" "github.com/the-dev-tools/dev-tools/packages/server/internal/api/rworkspace" "github.com/the-dev-tools/dev-tools/packages/server/internal/migrations" "github.com/the-dev-tools/dev-tools/packages/server/pkg/credvault" @@ -52,6 +53,7 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sgraphql" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/shttp" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/suser" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/swebsocket" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sworkspace" "github.com/the-dev-tools/dev-tools/packages/server/pkg/streamregistry" envapiv1 "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/environment/v1" @@ -193,6 +195,13 @@ func Run() error { flowNodeAiProviderService := sflow.NewNodeAiProviderService(queries) flowNodeMemoryService := sflow.NewNodeMemoryService(queries) flowNodeGraphQLService := sflow.NewNodeGraphQLService(queries) + flowNodeWsConnectionService := sflow.NewNodeWsConnectionService(queries) + flowNodeWsSendService := sflow.NewNodeWsSendService(queries) + flowNodeWaitService := sflow.NewNodeWaitService(queries) + + // WebSocket + websocketService := swebsocket.New(queries, logger) + websocketHeaderService := swebsocket.NewWebSocketHeaderService(queries) // GraphQL graphqlService := sgraphql.New(queries, logger) @@ -466,8 +475,13 @@ func Run() error { NodeAI: &flowNodeAIService, NodeAiProvider: &flowNodeAiProviderService, NodeMemory: &flowNodeMemoryService, - NodeGraphQL: &flowNodeGraphQLService, - NodeExecution: &nodeExecutionService, + NodeGraphQL: &flowNodeGraphQLService, + NodeWsConnection: &flowNodeWsConnectionService, + NodeWsSend: &flowNodeWsSendService, + NodeWait: &flowNodeWaitService, + WebSocket: &websocketService, + WebSocketHeader: &websocketHeaderService, + NodeExecution: &nodeExecutionService, FlowVariable: &flowVariableService, Env: &environmentService, Var: &variableService, @@ -497,6 +511,7 @@ func Run() error { Memory: streamers.Memory, NodeGraphQL: streamers.NodeGraphQL, GraphQL: streamers.GraphQL, + WebSocket: streamers.WebSocket, Execution: streamers.Execution, HttpResponse: streamers.HttpResponse, HttpResponseHeader: streamers.HttpResponseHeader, @@ -519,14 +534,19 @@ func Run() error { // ExportV2 Service exportV2Srv := rexportv2.NewExportV2RPC(rexportv2.ExportV2Deps{ - DB: currentDB, - Queries: queries, - Workspace: workspaceService, - User: userService, - Http: &httpService, - Flow: &flowService, - File: fileService, - Logger: logger, + DB: currentDB, + Queries: queries, + Workspace: workspaceService, + User: userService, + Http: &httpService, + Flow: &flowService, + File: fileService, + GraphQL: &graphqlService, + GraphQLHeader: &graphqlHeaderService, + GraphQLAssert: &graphqlAssertService, + WebSocket: &websocketService, + WebSocketHeader: &websocketHeaderService, + Logger: logger, }) newServiceManager.addService(rexportv2.CreateExportV2Service(*exportV2Srv, optionsAll)) @@ -618,6 +638,18 @@ func Run() error { }) newServiceManager.addService(rreference.CreateService(refServiceRPC, optionsAll)) + // WebSocket Service + wsSrv := rwebsocket.New(rwebsocket.Deps{ + DB: currentDB, + WS: websocketService, + WSH: websocketHeaderService, + US: userService, + Workspace: workspaceService, + WSStream: streamers.WebSocket, + WSHStream: streamers.WebSocketHeader, + }) + newServiceManager.addService(rwebsocket.CreateService(wsSrv, optionsAll)) + // Start services go func() { err := api.ListenServices(newServiceManager.getServices(), port) @@ -774,6 +806,8 @@ type streamers struct { CredentialOpenAi eventstream.SyncStreamer[rcredential.CredentialOpenAiTopic, rcredential.CredentialOpenAiEvent] CredentialGemini eventstream.SyncStreamer[rcredential.CredentialGeminiTopic, rcredential.CredentialGeminiEvent] CredentialAnthropic eventstream.SyncStreamer[rcredential.CredentialAnthropicTopic, rcredential.CredentialAnthropicEvent] + WebSocket eventstream.SyncStreamer[rwebsocket.WebSocketTopic, rwebsocket.WebSocketEvent] + WebSocketHeader eventstream.SyncStreamer[rwebsocket.WebSocketHeaderTopic, rwebsocket.WebSocketHeaderEvent] } func newStreamers() *streamers { @@ -819,6 +853,8 @@ func newStreamers() *streamers { CredentialOpenAi: memory.NewInMemorySyncStreamer[rcredential.CredentialOpenAiTopic, rcredential.CredentialOpenAiEvent](), CredentialGemini: memory.NewInMemorySyncStreamer[rcredential.CredentialGeminiTopic, rcredential.CredentialGeminiEvent](), CredentialAnthropic: memory.NewInMemorySyncStreamer[rcredential.CredentialAnthropicTopic, rcredential.CredentialAnthropicEvent](), + WebSocket: memory.NewInMemorySyncStreamer[rwebsocket.WebSocketTopic, rwebsocket.WebSocketEvent](), + WebSocketHeader: memory.NewInMemorySyncStreamer[rwebsocket.WebSocketHeaderTopic, rwebsocket.WebSocketHeaderEvent](), } } @@ -864,6 +900,8 @@ func (s *streamers) shutdown() { s.CredentialOpenAi.Shutdown() s.CredentialGemini.Shutdown() s.CredentialAnthropic.Shutdown() + s.WebSocket.Shutdown() + s.WebSocketHeader.Shutdown() } // registerCascadeHandlers registers all handlers needed for cascade deletion events. diff --git a/packages/server/go.mod b/packages/server/go.mod index 5ab3b3353..b1760b14f 100644 --- a/packages/server/go.mod +++ b/packages/server/go.mod @@ -6,6 +6,7 @@ require ( connectrpc.com/connect v1.19.1 github.com/Microsoft/go-winio v0.6.2 github.com/andybalholm/brotli v1.2.0 + github.com/coder/websocket v1.8.14 github.com/expr-lang/expr v1.17.7 github.com/goccy/go-json v0.10.5 github.com/golang-jwt/jwt/v5 v5.3.0 @@ -21,9 +22,11 @@ require ( github.com/tmc/langchaingo v0.1.14 golang.org/x/crypto v0.46.0 golang.org/x/net v0.48.0 + golang.org/x/sync v0.19.0 golang.org/x/text v0.32.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 + modernc.org/sqlite v1.43.0 ) require ( @@ -65,7 +68,6 @@ require ( go.uber.org/zap v1.27.1 // indirect golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect golang.org/x/oauth2 v0.30.0 // indirect - golang.org/x/sync v0.19.0 // indirect golang.org/x/sys v0.40.0 // indirect golang.org/x/time v0.12.0 // indirect google.golang.org/api v0.246.0 // indirect @@ -77,7 +79,6 @@ require ( modernc.org/libc v1.67.4 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect - modernc.org/sqlite v1.43.0 // indirect ) replace ( diff --git a/packages/server/go.sum b/packages/server/go.sum index c42857ce8..b451ff1d3 100644 --- a/packages/server/go.sum +++ b/packages/server/go.sum @@ -26,6 +26,8 @@ github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= +github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= diff --git a/packages/server/internal/api/rexportv2/export.go b/packages/server/internal/api/rexportv2/export.go index 3221b247c..a65275137 100644 --- a/packages/server/internal/api/rexportv2/export.go +++ b/packages/server/internal/api/rexportv2/export.go @@ -3,6 +3,7 @@ package rexportv2 import ( "context" + "encoding/json" "fmt" "log/slog" "strings" @@ -10,11 +11,17 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/internal/api/middleware/mwauth" "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" "github.com/the-dev-tools/dev-tools/packages/server/pkg/ioworkspace" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mfile" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mgraphql" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sfile" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sflow" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sgraphql" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/shttp" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/suser" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/swebsocket" "github.com/the-dev-tools/dev-tools/packages/server/pkg/translate/yamlflowsimplev2" + + "gopkg.in/yaml.v3" ) // Interfaces @@ -37,20 +44,40 @@ type Validator interface { // SimpleExporter implements the Exporter interface using modern services type SimpleExporter struct { - httpService *shttp.HTTPService - flowService *sflow.FlowService - fileService *sfile.FileService - ioWorkspaceService *ioworkspace.IOWorkspaceService - storage Storage + httpService *shttp.HTTPService + flowService *sflow.FlowService + fileService *sfile.FileService + ioWorkspaceService *ioworkspace.IOWorkspaceService + graphqlService *sgraphql.GraphQLService + graphqlHeaderService *sgraphql.GraphQLHeaderService + graphqlAssertService *sgraphql.GraphQLAssertService + websocketService *swebsocket.WebSocketService + websocketHeaderService *swebsocket.WebSocketHeaderService + storage Storage } // NewExporter creates a new SimpleExporter -func NewExporter(httpService *shttp.HTTPService, flowService *sflow.FlowService, fileService *sfile.FileService, ioWorkspaceService *ioworkspace.IOWorkspaceService) *SimpleExporter { +func NewExporter( + httpService *shttp.HTTPService, + flowService *sflow.FlowService, + fileService *sfile.FileService, + ioWorkspaceService *ioworkspace.IOWorkspaceService, + graphqlService *sgraphql.GraphQLService, + graphqlHeaderService *sgraphql.GraphQLHeaderService, + graphqlAssertService *sgraphql.GraphQLAssertService, + websocketService *swebsocket.WebSocketService, + websocketHeaderService *swebsocket.WebSocketHeaderService, +) *SimpleExporter { return &SimpleExporter{ - httpService: httpService, - flowService: flowService, - fileService: fileService, - ioWorkspaceService: ioWorkspaceService, + httpService: httpService, + flowService: flowService, + fileService: fileService, + ioWorkspaceService: ioWorkspaceService, + graphqlService: graphqlService, + graphqlHeaderService: graphqlHeaderService, + graphqlAssertService: graphqlAssertService, + websocketService: websocketService, + websocketHeaderService: websocketHeaderService, } } @@ -171,6 +198,227 @@ func (e *SimpleExporter) ExportToCurl(ctx context.Context, data *WorkspaceExport return strings.Join(commands, "\n\n"), nil } +// ExportGraphQLToCurl exports GraphQL requests as cURL commands (POST with JSON body) +func (e *SimpleExporter) ExportGraphQLToCurl(ctx context.Context, graphqlIDs []idwrap.IDWrap) (string, error) { + if len(graphqlIDs) == 0 { + return "", nil + } + + var commands []string + for _, gqlID := range graphqlIDs { + gql, err := e.graphqlService.Get(ctx, gqlID) + if err != nil { + continue + } + + headers, err := e.graphqlHeaderService.GetByGraphQLID(ctx, gqlID) + if err != nil { + headers = nil + } + + var cmd strings.Builder + cmd.WriteString(fmt.Sprintf("curl -X POST '%s'", gql.Url)) + cmd.WriteString(" -H \"Content-Type: application/json\"") + + for _, h := range headers { + if h.Enabled { + cmd.WriteString(fmt.Sprintf(" -H \"%s: %s\"", h.Key, h.Value)) + } + } + + // Build JSON body with query and variables + body := buildGraphQLJSONBody(gql.Query, gql.Variables) + cmd.WriteString(fmt.Sprintf(" --data-raw '%s'", strings.ReplaceAll(body, "'", "'\"'\"'"))) + cmd.WriteString(fmt.Sprintf(" # %s", gql.Name)) + commands = append(commands, cmd.String()) + } + + if len(commands) == 0 { + return "", nil + } + return strings.Join(commands, "\n\n"), nil +} + +// buildGraphQLJSONBody builds a JSON string with query and optional variables +func buildGraphQLJSONBody(query, variables string) string { + // Escape the query string for JSON + queryJSON, _ := json.Marshal(query) + + if variables == "" || variables == "{}" { + return fmt.Sprintf(`{"query":%s}`, string(queryJSON)) + } + + // Variables is already a JSON string, use it directly + return fmt.Sprintf(`{"query":%s,"variables":%s}`, string(queryJSON), variables) +} + +// ExportGraphQLToYAML exports GraphQL requests as a focused YAML +func (e *SimpleExporter) ExportGraphQLToYAML(ctx context.Context, graphqlIDs []idwrap.IDWrap) ([]byte, error) { + var gqlDefs []yamlflowsimplev2.YamlGraphQLDefV2 + + for _, gqlID := range graphqlIDs { + gql, err := e.graphqlService.Get(ctx, gqlID) + if err != nil { + continue + } + + headers, err := e.graphqlHeaderService.GetByGraphQLID(ctx, gqlID) + if err != nil { + headers = nil + } + + asserts, err := e.graphqlAssertService.GetByGraphQLID(ctx, gqlID) + if err != nil { + asserts = nil + } + + gqlDef := yamlflowsimplev2.YamlGraphQLDefV2{ + Name: gql.Name, + URL: gql.Url, + Query: gql.Query, + Variables: gql.Variables, + Headers: buildGraphQLHeaderMapOrSliceExport(headers), + Assertions: buildGraphQLAssertionsExport(asserts), + } + gqlDefs = append(gqlDefs, gqlDef) + } + + yamlFormat := yamlflowsimplev2.YamlFlowFormatV2{ + WorkspaceName: "export", + GraphQLRequests: gqlDefs, + } + + return yaml.Marshal(yamlFormat) +} + +// ExportWebSocketToYAML exports WebSocket items as a focused YAML +func (e *SimpleExporter) ExportWebSocketToYAML(ctx context.Context, websocketIDs []idwrap.IDWrap) ([]byte, error) { + // Build a minimal YAML with websocket info + type wsYAMLItem struct { + Name string `yaml:"name"` + URL string `yaml:"url"` + Headers map[string]string `yaml:"headers,omitempty"` + } + + type wsYAMLFormat struct { + WorkspaceName string `yaml:"workspace_name"` + WebSockets []wsYAMLItem `yaml:"websockets"` + } + + var items []wsYAMLItem + for _, wsID := range websocketIDs { + ws, err := e.websocketService.Get(ctx, wsID) + if err != nil { + continue + } + + headers, err := e.websocketHeaderService.GetByWebSocketID(ctx, wsID) + if err != nil { + headers = nil + } + + headerMap := make(map[string]string) + for _, h := range headers { + if h.Enabled { + headerMap[h.Key] = h.Value + } + } + + item := wsYAMLItem{ + Name: ws.Name, + URL: ws.Url, + } + if len(headerMap) > 0 { + item.Headers = headerMap + } + items = append(items, item) + } + + wsFormat := wsYAMLFormat{ + WorkspaceName: "export", + WebSockets: items, + } + + return yaml.Marshal(wsFormat) +} + +// tryPerItemYAMLExport checks if fileIDs refer to GraphQL or WebSocket items +// and exports them as focused YAML. Returns (data, name, handled). +func (e *SimpleExporter) tryPerItemYAMLExport(ctx context.Context, fileIDs []idwrap.IDWrap) ([]byte, string, bool) { + if e.fileService == nil { + return nil, "", false + } + + // Check the first fileID's content type + file, err := e.fileService.GetFile(ctx, fileIDs[0]) + if err != nil { + return nil, "", false + } + + switch file.ContentType { + case mfile.ContentTypeGraphQL: + data, err := e.ExportGraphQLToYAML(ctx, fileIDs) + if err != nil { + return nil, "", false + } + return data, "graphql_export.yaml", true + + case mfile.ContentTypeWebSocket: + data, err := e.ExportWebSocketToYAML(ctx, fileIDs) + if err != nil { + return nil, "", false + } + return data, "websocket_export.yaml", true + + case mfile.ContentTypeHTTP, mfile.ContentTypeHTTPDelta: + // Use FilterByHTTPIDs for per-item HTTP export + exportOpts := ioworkspace.ExportOptions{ + WorkspaceID: file.WorkspaceID, + IncludeHTTP: true, + FilterByHTTPIDs: fileIDs, + } + bundle, err := e.ioWorkspaceService.Export(ctx, exportOpts) + if err != nil { + return nil, "", false + } + yamlData, err := yamlflowsimplev2.MarshalSimplifiedYAML(bundle) + if err != nil { + return nil, "", false + } + return yamlData, "http_export.yaml", true + + default: + return nil, "", false + } +} + +func buildGraphQLHeaderMapOrSliceExport(headers []mgraphql.GraphQLHeader) yamlflowsimplev2.HeaderMapOrSlice { + if len(headers) == 0 { + return nil + } + var result []yamlflowsimplev2.YamlNameValuePairV2 + for _, h := range headers { + result = append(result, yamlflowsimplev2.YamlNameValuePairV2{ + Name: h.Key, + Value: h.Value, + Enabled: h.Enabled, + Description: h.Description, + }) + } + return yamlflowsimplev2.HeaderMapOrSlice(result) +} + +func buildGraphQLAssertionsExport(asserts []mgraphql.GraphQLAssert) yamlflowsimplev2.AssertionsOrSlice { + if len(asserts) == 0 { + return nil + } + var result []yamlflowsimplev2.YamlAssertionV2 + for _, a := range asserts { + result = append(result, yamlflowsimplev2.YamlAssertionV2{Expression: a.Value, Enabled: a.Enabled}) + } + return yamlflowsimplev2.AssertionsOrSlice(result) +} + // Validator Implementation // SimpleValidator implements basic validation @@ -336,6 +584,17 @@ func (s *Service) Export(ctx context.Context, req *ExportRequest) (*ExportRespon switch req.Format { case ExportFormat_YAML: + // Try per-item YAML export for GraphQL and WebSocket items + if simpleExporter, ok := s.exporter.(*SimpleExporter); ok && len(req.FileIDs) > 0 { + itemData, itemName, handled := simpleExporter.tryPerItemYAMLExport(ctx, req.FileIDs) + if handled { + return &ExportResponse{ + Name: itemName, + Data: itemData, + }, nil + } + } + data, err = s.exporter.ExportToYAML(ctx, exportData, req.Simplified, req.FileIDs) if err != nil { return nil, fmt.Errorf("YAML export failed: %w", err) diff --git a/packages/server/internal/api/rexportv2/exporter_test.go b/packages/server/internal/api/rexportv2/exporter_test.go index 28578fd77..1230eefff 100644 --- a/packages/server/internal/api/rexportv2/exporter_test.go +++ b/packages/server/internal/api/rexportv2/exporter_test.go @@ -15,7 +15,9 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/senv" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sfile" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sflow" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sgraphql" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/shttp" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/swebsocket" "github.com/the-dev-tools/dev-tools/packages/server/pkg/testutil" ) @@ -36,7 +38,12 @@ func TestNewExporter(t *testing.T) { // Create IOWorkspaceService ioWorkspaceService := ioworkspace.New(base.Queries, logger) - exporter := NewExporter(&httpService, &flowService, fileService, ioWorkspaceService) + graphqlService := sgraphql.New(base.Queries, logger) + graphqlHeaderService := sgraphql.NewGraphQLHeaderService(base.Queries) + graphqlAssertService := sgraphql.NewGraphQLAssertService(base.Queries) + websocketService := swebsocket.New(base.Queries, logger) + websocketHeaderService := swebsocket.NewWebSocketHeaderService(base.Queries) + exporter := NewExporter(&httpService, &flowService, fileService, ioWorkspaceService, &graphqlService, &graphqlHeaderService, &graphqlAssertService, &websocketService, &websocketHeaderService) storage := NewStorage(&workspaceService, &httpService, &flowService, fileService) exporter.SetStorage(storage) @@ -123,7 +130,12 @@ func TestDefaultExporter_ExportToYAML_WithEnvironments(t *testing.T) { workspaceService := services.WorkspaceService ioWorkspaceService := ioworkspace.New(base.Queries, logger) - exporter := NewExporter(&httpService, &flowService, fileService, ioWorkspaceService) + graphqlService := sgraphql.New(base.Queries, logger) + graphqlHeaderService := sgraphql.NewGraphQLHeaderService(base.Queries) + graphqlAssertService := sgraphql.NewGraphQLAssertService(base.Queries) + websocketService := swebsocket.New(base.Queries, logger) + websocketHeaderService := swebsocket.NewWebSocketHeaderService(base.Queries) + exporter := NewExporter(&httpService, &flowService, fileService, ioWorkspaceService, &graphqlService, &graphqlHeaderService, &graphqlAssertService, &websocketService, &websocketHeaderService) storage := NewStorage(&workspaceService, &httpService, &flowService, fileService) exporter.SetStorage(storage) @@ -524,7 +536,12 @@ func setupExporterWithoutData(t *testing.T, ctx context.Context) *SimpleExporter // Create IOWorkspaceService ioWorkspaceService := ioworkspace.New(base.Queries, logger) - exporter := NewExporter(&httpService, &flowService, fileService, ioWorkspaceService) + graphqlService := sgraphql.New(base.Queries, logger) + graphqlHeaderService := sgraphql.NewGraphQLHeaderService(base.Queries) + graphqlAssertService := sgraphql.NewGraphQLAssertService(base.Queries) + websocketService := swebsocket.New(base.Queries, logger) + websocketHeaderService := swebsocket.NewWebSocketHeaderService(base.Queries) + exporter := NewExporter(&httpService, &flowService, fileService, ioWorkspaceService, &graphqlService, &graphqlHeaderService, &graphqlAssertService, &websocketService, &websocketHeaderService) storage := NewStorage(&workspaceService, &httpService, &flowService, fileService) exporter.SetStorage(storage) @@ -549,7 +566,12 @@ func setupExporterWithTestData(t *testing.T, ctx context.Context) (*SimpleExport // Create IOWorkspaceService ioWorkspaceService := ioworkspace.New(base.Queries, logger) - exporter := NewExporter(&httpService, &flowService, fileService, ioWorkspaceService) + graphqlService := sgraphql.New(base.Queries, logger) + graphqlHeaderService := sgraphql.NewGraphQLHeaderService(base.Queries) + graphqlAssertService := sgraphql.NewGraphQLAssertService(base.Queries) + websocketService := swebsocket.New(base.Queries, logger) + websocketHeaderService := swebsocket.NewWebSocketHeaderService(base.Queries) + exporter := NewExporter(&httpService, &flowService, fileService, ioWorkspaceService, &graphqlService, &graphqlHeaderService, &graphqlAssertService, &websocketService, &websocketHeaderService) storage := NewStorage(&workspaceService, &httpService, &flowService, fileService) exporter.SetStorage(storage) diff --git a/packages/server/internal/api/rexportv2/rexportv2.go b/packages/server/internal/api/rexportv2/rexportv2.go index f8633de31..1d21c103a 100644 --- a/packages/server/internal/api/rexportv2/rexportv2.go +++ b/packages/server/internal/api/rexportv2/rexportv2.go @@ -14,8 +14,10 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/pkg/ioworkspace" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sfile" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sflow" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sgraphql" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/shttp" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/suser" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/swebsocket" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sworkspace" exportv1 "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/export/v1" "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/export/v1/exportv1connect" @@ -158,14 +160,19 @@ type ExportV2RPC struct { } type ExportV2Deps struct { - DB *sql.DB - Queries *gen.Queries - Workspace sworkspace.WorkspaceService - User suser.UserService - Http *shttp.HTTPService - Flow *sflow.FlowService - File *sfile.FileService - Logger *slog.Logger + DB *sql.DB + Queries *gen.Queries + Workspace sworkspace.WorkspaceService + User suser.UserService + Http *shttp.HTTPService + Flow *sflow.FlowService + File *sfile.FileService + GraphQL *sgraphql.GraphQLService + GraphQLHeader *sgraphql.GraphQLHeaderService + GraphQLAssert *sgraphql.GraphQLAssertService + WebSocket *swebsocket.WebSocketService + WebSocketHeader *swebsocket.WebSocketHeaderService + Logger *slog.Logger } func (d *ExportV2Deps) Validate() error { @@ -203,7 +210,9 @@ func NewExportV2RPC(deps ExportV2Deps) *ExportV2RPC { storage := NewStorage(&deps.Workspace, deps.Http, deps.Flow, deps.File) // Create simple exporter with IOWorkspaceService - exporter := NewExporter(deps.Http, deps.Flow, deps.File, ioWorkspaceService) + exporter := NewExporter(deps.Http, deps.Flow, deps.File, ioWorkspaceService, + deps.GraphQL, deps.GraphQLHeader, deps.GraphQLAssert, + deps.WebSocket, deps.WebSocketHeader) // Create simple validator validator := NewValidator(&deps.User) @@ -291,6 +300,49 @@ func (h *ExportV2RPC) ExportCurl(ctx context.Context, req *connect.Request[expor return connect.NewResponse(protoResp), nil } +// ExportCurlGraphQL implements the ExportCurlGraphQL RPC method +func (h *ExportV2RPC) ExportCurlGraphQL(ctx context.Context, req *connect.Request[exportv1.ExportCurlGraphQLRequest]) (*connect.Response[exportv1.ExportCurlGraphQLResponse], error) { + h.logger.Info("Received ExportCurlGraphQL request", + "workspace_id", req.Msg.WorkspaceId, + "graphql_ids_count", len(req.Msg.GraphqlIds)) + + // Parse workspace ID + workspaceID, err := idwrap.NewFromBytes(req.Msg.WorkspaceId) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, NewValidationError("workspaceId", err.Error())) + } + + // Validate workspace access + if err := h.service.validator.ValidateWorkspaceAccess(ctx, workspaceID); err != nil { + return nil, handleServiceError(err) + } + + // Parse GraphQL IDs + graphqlIDs := make([]idwrap.IDWrap, 0, len(req.Msg.GraphqlIds)) + for _, idBytes := range req.Msg.GraphqlIds { + gqlID, err := idwrap.NewFromBytes(idBytes) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, NewValidationError("graphqlIds", err.Error())) + } + graphqlIDs = append(graphqlIDs, gqlID) + } + + // Get the exporter + simpleExporter, ok := h.service.exporter.(*SimpleExporter) + if !ok { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("exporter does not support GraphQL cURL export")) + } + + curlData, err := simpleExporter.ExportGraphQLToCurl(ctx, graphqlIDs) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + return connect.NewResponse(&exportv1.ExportCurlGraphQLResponse{ + Data: curlData, + }), nil +} + // Private conversion functions // convertToExportRequest converts protobuf request to internal request model diff --git a/packages/server/internal/api/rfile/rfile.go b/packages/server/internal/api/rfile/rfile.go index d25c87e2e..6ffb22ad5 100644 --- a/packages/server/internal/api/rfile/rfile.go +++ b/packages/server/internal/api/rfile/rfile.go @@ -142,6 +142,8 @@ func toAPIFileKind(kind mfile.ContentType) apiv1.FileKind { return apiv1.FileKind_FILE_KIND_CREDENTIAL case mfile.ContentTypeGraphQL: return apiv1.FileKind_FILE_KIND_GRAPH_Q_L + case mfile.ContentTypeWebSocket: + return apiv1.FileKind_FILE_KIND_WEB_SOCKET default: return apiv1.FileKind_FILE_KIND_UNSPECIFIED } @@ -162,6 +164,8 @@ func fromAPIFileKind(kind apiv1.FileKind) mfile.ContentType { return mfile.ContentTypeCredential case apiv1.FileKind_FILE_KIND_GRAPH_Q_L: return mfile.ContentTypeGraphQL + case apiv1.FileKind_FILE_KIND_WEB_SOCKET: + return mfile.ContentTypeWebSocket default: return mfile.ContentTypeUnknown } diff --git a/packages/server/internal/api/rflowv2/logging_test.go b/packages/server/internal/api/rflowv2/logging_test.go index 61e7520be..be32c3e7f 100644 --- a/packages/server/internal/api/rflowv2/logging_test.go +++ b/packages/server/internal/api/rflowv2/logging_test.go @@ -18,6 +18,7 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/pkg/dbtime" "github.com/the-dev-tools/dev-tools/packages/server/pkg/eventstream/memory" "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/flowbuilder" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/flowexec" "github.com/the-dev-tools/dev-tools/packages/server/pkg/http/resolver" "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" @@ -81,6 +82,11 @@ func TestFlowRun_Logging(t *testing.T) { nil, // NodeAiProviderService nil, // NodeMemoryService nil, // NodeGraphQLService + nil, // NodeWsConnectionService + nil, // NodeWsSendService + nil, // NodeWaitService + nil, // WebSocketService + nil, // WebSocketHeaderService nil, // GraphQLService nil, // GraphQLHeaderService &wsService, @@ -110,7 +116,7 @@ func TestFlowRun_Logging(t *testing.T) { fvs: &flowVarService, logger: logger, logStream: logStreamer, - builder: builder, + sessionFactory: &flowexec.LocalSessionFactory{Builder: builder}, runningFlows: make(map[string]context.CancelFunc), } diff --git a/packages/server/internal/api/rflowv2/node_config_sync_test.go b/packages/server/internal/api/rflowv2/node_config_sync_test.go index d5de51d17..d7e175a76 100644 --- a/packages/server/internal/api/rflowv2/node_config_sync_test.go +++ b/packages/server/internal/api/rflowv2/node_config_sync_test.go @@ -283,7 +283,7 @@ func TestNodeHttpSync_PublishesEventsOnCRUD(t *testing.T) { events := collectNodeEvents(registry.nodeEvents, 1, 100*time.Millisecond) require.Len(t, events, 1) - assert.Equal(t, nodeEventUpdate, events[0].Type) + assert.Equal(t, nodeEventInsert, events[0].Type) }) t.Run("Update publishes event", func(t *testing.T) { @@ -307,7 +307,7 @@ func TestNodeHttpSync_PublishesEventsOnCRUD(t *testing.T) { events := collectNodeEvents(registry.nodeEvents, 1, 100*time.Millisecond) require.Len(t, events, 1) - assert.Equal(t, nodeEventUpdate, events[0].Type) + assert.Equal(t, nodeEventDelete, events[0].Type) }) } diff --git a/packages/server/internal/api/rflowv2/rflowv2.go b/packages/server/internal/api/rflowv2/rflowv2.go index 6cd086888..7a750f257 100644 --- a/packages/server/internal/api/rflowv2/rflowv2.go +++ b/packages/server/internal/api/rflowv2/rflowv2.go @@ -15,7 +15,9 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/internal/api/rgraphql" "github.com/the-dev-tools/dev-tools/packages/server/internal/api/rhttp" "github.com/the-dev-tools/dev-tools/packages/server/internal/api/rlog" + "github.com/the-dev-tools/dev-tools/packages/server/internal/api/rwebsocket" "github.com/the-dev-tools/dev-tools/packages/server/pkg/eventstream" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/flowexec" "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/flowbuilder" gqlresolver "github.com/the-dev-tools/dev-tools/packages/server/pkg/graphql/resolver" "github.com/the-dev-tools/dev-tools/packages/server/pkg/http/resolver" @@ -28,6 +30,7 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sflow" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sgraphql" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/shttp" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/swebsocket" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sworkspace" flowv1 "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/flow/v1" "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/flow/v1/flowv1connect" @@ -190,6 +193,18 @@ type nodeGraphQLWithFlow struct { baseNode *mflow.Node } +type nodeWsConnectionWithFlow struct { + nodeWsConnection mflow.NodeWsConnection + flowID idwrap.IDWrap + baseNode *mflow.Node +} + +type nodeWsSendWithFlow struct { + nodeWsSend mflow.NodeWsSend + flowID idwrap.IDWrap + baseNode *mflow.Node +} + // Shared event type strings for all entity types. // Using mutation.Operation.String() values for consistency. const ( @@ -278,8 +293,13 @@ type FlowServiceV2Services struct { NodeAI *sflow.NodeAIService NodeAiProvider *sflow.NodeAiProviderService NodeMemory *sflow.NodeMemoryService - NodeGraphQL *sflow.NodeGraphQLService - NodeExecution *sflow.NodeExecutionService + NodeGraphQL *sflow.NodeGraphQLService + NodeWsConnection *sflow.NodeWsConnectionService + NodeWsSend *sflow.NodeWsSendService + NodeWait *sflow.NodeWaitService + WebSocket *swebsocket.WebSocketService + WebSocketHeader *swebsocket.WebSocketHeaderService + NodeExecution *sflow.NodeExecutionService FlowVariable *sflow.FlowVariableService Env *senv.EnvironmentService Var *senv.VariableService @@ -370,6 +390,7 @@ type FlowServiceV2Streamers struct { Memory eventstream.SyncStreamer[MemoryTopic, MemoryEvent] NodeGraphQL eventstream.SyncStreamer[NodeGraphQLTopic, NodeGraphQLEvent] GraphQL eventstream.SyncStreamer[rgraphql.GraphQLTopic, rgraphql.GraphQLEvent] + WebSocket eventstream.SyncStreamer[rwebsocket.WebSocketTopic, rwebsocket.WebSocketEvent] Execution eventstream.SyncStreamer[ExecutionTopic, ExecutionEvent] Http eventstream.SyncStreamer[rhttp.HttpTopic, rhttp.HttpEvent] HttpResponse eventstream.SyncStreamer[rhttp.HttpResponseTopic, rhttp.HttpResponseEvent] @@ -438,8 +459,13 @@ type FlowServiceV2RPC struct { naps *sflow.NodeAiProviderService nmems *sflow.NodeMemoryService ngqs *sflow.NodeGraphQLService - gqls *sgraphql.GraphQLService - gqlhs *sgraphql.GraphQLHeaderService + nwcs *sflow.NodeWsConnectionService + nwss *sflow.NodeWsSendService + nwaits *sflow.NodeWaitService + wsService *swebsocket.WebSocketService + wsHeaderService *swebsocket.WebSocketHeaderService + gqls *sgraphql.GraphQLService + gqlhs *sgraphql.GraphQLHeaderService nes *sflow.NodeExecutionService fvs *sflow.FlowVariableService envs *senv.EnvironmentService @@ -466,6 +492,7 @@ type FlowServiceV2RPC struct { memoryStream eventstream.SyncStreamer[MemoryTopic, MemoryEvent] nodeGraphQLStream eventstream.SyncStreamer[NodeGraphQLTopic, NodeGraphQLEvent] graphqlStream eventstream.SyncStreamer[rgraphql.GraphQLTopic, rgraphql.GraphQLEvent] + wsStream eventstream.SyncStreamer[rwebsocket.WebSocketTopic, rwebsocket.WebSocketEvent] executionStream eventstream.SyncStreamer[ExecutionTopic, ExecutionEvent] httpStream eventstream.SyncStreamer[rhttp.HttpTopic, rhttp.HttpEvent] httpResponseStream eventstream.SyncStreamer[rhttp.HttpResponseTopic, rhttp.HttpResponseEvent] @@ -478,11 +505,11 @@ type FlowServiceV2RPC struct { fileService *sfile.FileService fileStream eventstream.SyncStreamer[rfile.FileTopic, rfile.FileEvent] - // JS executor client for running JS nodes (connects to worker-js) - jsClient node_js_executorv1connect.NodeJsExecutorServiceClient + // Session factory for creating execution sessions (local or distributed) + sessionFactory flowexec.SessionFactory - // Shared builder for flow execution - builder *flowbuilder.Builder + // Snapshot registry for flow version snapshots + snapshotRegistry *flowexec.SnapshotRegistry // Running flows map for cancellation runningFlowsMu sync.Mutex @@ -501,11 +528,42 @@ func New(deps FlowServiceV2Deps) *FlowServiceV2RPC { deps.Services.Node, deps.Services.NodeRequest, deps.Services.NodeFor, deps.Services.NodeForEach, deps.Services.NodeIf, deps.Services.NodeJs, deps.Services.NodeAI, deps.Services.NodeAiProvider, deps.Services.NodeMemory, deps.Services.NodeGraphQL, + deps.Services.NodeWsConnection, deps.Services.NodeWsSend, deps.Services.NodeWait, + deps.Services.WebSocket, deps.Services.WebSocketHeader, deps.Services.GraphQL, deps.Services.GraphQLHeader, deps.Services.Workspace, deps.Services.Var, deps.Services.FlowVariable, deps.Resolver, deps.GraphQLResolver, deps.Logger, llmFactory, ) + // Build snapshot registry for flow version snapshots + registry := flowexec.NewSnapshotRegistry() + registry.Register(&flowexec.RequestSnapshot{Service: deps.Services.NodeRequest}) + registry.Register(&flowexec.ForSnapshot{Service: deps.Services.NodeFor}) + registry.Register(&flowexec.ForEachSnapshot{Service: deps.Services.NodeForEach}) + registry.Register(&flowexec.ConditionSnapshot{Service: deps.Services.NodeIf}) + registry.Register(&flowexec.JSSnapshot{Service: deps.Services.NodeJs}) + if deps.Services.NodeAI != nil { + registry.Register(&flowexec.AISnapshot{Service: deps.Services.NodeAI}) + } + if deps.Services.NodeAiProvider != nil { + registry.Register(&flowexec.AIProviderSnapshot{Service: deps.Services.NodeAiProvider}) + } + if deps.Services.NodeMemory != nil { + registry.Register(&flowexec.MemorySnapshot{Service: deps.Services.NodeMemory}) + } + if deps.Services.NodeGraphQL != nil { + registry.Register(&flowexec.GraphQLSnapshot{Service: deps.Services.NodeGraphQL}) + } + if deps.Services.NodeWsConnection != nil { + registry.Register(&flowexec.WsConnectionSnapshot{Service: deps.Services.NodeWsConnection}) + } + if deps.Services.NodeWsSend != nil { + registry.Register(&flowexec.WsSendSnapshot{Service: deps.Services.NodeWsSend}) + } + if deps.Services.NodeWait != nil { + registry.Register(&flowexec.WaitSnapshot{Service: deps.Services.NodeWait}) + } + return &FlowServiceV2RPC{ DB: deps.DB, wsReader: deps.Readers.Workspace, @@ -527,6 +585,11 @@ func New(deps FlowServiceV2Deps) *FlowServiceV2RPC { naps: deps.Services.NodeAiProvider, nmems: deps.Services.NodeMemory, ngqs: deps.Services.NodeGraphQL, + nwcs: deps.Services.NodeWsConnection, + nwss: deps.Services.NodeWsSend, + nwaits: deps.Services.NodeWait, + wsService: deps.Services.WebSocket, + wsHeaderService: deps.Services.WebSocketHeader, gqls: deps.Services.GraphQL, gqlhs: deps.Services.GraphQLHeader, nes: deps.Services.NodeExecution, @@ -554,6 +617,7 @@ func New(deps FlowServiceV2Deps) *FlowServiceV2RPC { memoryStream: deps.Streamers.Memory, nodeGraphQLStream: deps.Streamers.NodeGraphQL, graphqlStream: deps.Streamers.GraphQL, + wsStream: deps.Streamers.WebSocket, executionStream: deps.Streamers.Execution, httpStream: deps.Streamers.Http, httpResponseStream: deps.Streamers.HttpResponse, @@ -565,8 +629,11 @@ func New(deps FlowServiceV2Deps) *FlowServiceV2RPC { logStream: deps.Streamers.Log, fileService: deps.Services.File, fileStream: deps.Streamers.File, - jsClient: deps.JsClient, - builder: builder, + sessionFactory: &flowexec.LocalSessionFactory{ + Builder: builder, + JsClient: deps.JsClient, + }, + snapshotRegistry: registry, runningFlows: make(map[string]context.CancelFunc), } } @@ -640,6 +707,12 @@ func (p *rflowPublisher) PublishAll(events []mutation.Event) { p.publishNodeMemory(evt) case mutation.EntityFlowNodeGraphQL: p.publishNodeGraphQL(evt) + case mutation.EntityFlowNodeWsConnection: + p.publishNodeWsConnection(evt) + case mutation.EntityFlowNodeWsSend: + p.publishNodeWsSend(evt) + case mutation.EntityFlowNodeWait: + p.publishNodeWait(evt) case mutation.EntityFlowEdge: p.publishEdge(evt) case mutation.EntityFlowVariable: @@ -819,15 +892,24 @@ func (p *rflowPublisher) publishNodeHttp(evt mutation.Event) { var node *flowv1.Node var flowID idwrap.IDWrap + var eventType string - // 1. Publish update to base node stream + // 1. Publish to base node stream switch evt.Op { - case mutation.OpInsert, mutation.OpUpdate: + case mutation.OpInsert: + eventType = nodeEventInsert + if data, ok := evt.Payload.(nodeHttpWithFlow); ok && data.baseNode != nil { + node = serializeNode(*data.baseNode) + flowID = data.flowID + } + case mutation.OpUpdate: + eventType = nodeEventUpdate if data, ok := evt.Payload.(nodeHttpWithFlow); ok && data.baseNode != nil { node = serializeNode(*data.baseNode) flowID = data.flowID } case mutation.OpDelete: + eventType = nodeEventDelete node = &flowv1.Node{ NodeId: evt.ID.Bytes(), FlowId: evt.ParentID.Bytes(), @@ -837,7 +919,7 @@ func (p *rflowPublisher) publishNodeHttp(evt mutation.Event) { if node != nil { p.nodeStream.Publish(NodeTopic{FlowID: flowID}, NodeEvent{ - Type: nodeEventUpdate, + Type: eventType, FlowID: flowID, Node: node, }) @@ -1080,14 +1162,63 @@ func (p *rflowPublisher) publishNodeGraphQL(evt mutation.Event) { var node *flowv1.Node var flowID idwrap.IDWrap + var eventType string switch evt.Op { - case mutation.OpInsert, mutation.OpUpdate: + case mutation.OpInsert: + eventType = nodeEventInsert if data, ok := evt.Payload.(nodeGraphQLWithFlow); ok && data.baseNode != nil { node = serializeNode(*data.baseNode) flowID = data.flowID } + case mutation.OpUpdate: + eventType = nodeEventUpdate + if data, ok := evt.Payload.(nodeGraphQLWithFlow); ok && data.baseNode != nil { + node = serializeNode(*data.baseNode) + flowID = data.flowID + } + case mutation.OpDelete: + eventType = nodeEventDelete + node = &flowv1.Node{ + NodeId: evt.ID.Bytes(), + FlowId: evt.ParentID.Bytes(), + } + flowID = evt.ParentID + } + + if node != nil { + p.nodeStream.Publish(NodeTopic{FlowID: flowID}, NodeEvent{ + Type: eventType, + FlowID: flowID, + Node: node, + }) + } +} + +func (p *rflowPublisher) publishNodeWsConnection(evt mutation.Event) { + if p.nodeStream == nil { + return + } + + var node *flowv1.Node + var flowID idwrap.IDWrap + var eventType string + + switch evt.Op { + case mutation.OpInsert: + eventType = nodeEventInsert + if data, ok := evt.Payload.(nodeWsConnectionWithFlow); ok && data.baseNode != nil { + node = serializeNode(*data.baseNode) + flowID = data.flowID + } + case mutation.OpUpdate: + eventType = nodeEventUpdate + if data, ok := evt.Payload.(nodeWsConnectionWithFlow); ok && data.baseNode != nil { + node = serializeNode(*data.baseNode) + flowID = data.flowID + } case mutation.OpDelete: + eventType = nodeEventDelete node = &flowv1.Node{ NodeId: evt.ID.Bytes(), FlowId: evt.ParentID.Bytes(), @@ -1097,7 +1228,87 @@ func (p *rflowPublisher) publishNodeGraphQL(evt mutation.Event) { if node != nil { p.nodeStream.Publish(NodeTopic{FlowID: flowID}, NodeEvent{ - Type: nodeEventUpdate, + Type: eventType, + FlowID: flowID, + Node: node, + }) + } +} + +func (p *rflowPublisher) publishNodeWsSend(evt mutation.Event) { + if p.nodeStream == nil { + return + } + + var node *flowv1.Node + var flowID idwrap.IDWrap + var eventType string + + switch evt.Op { + case mutation.OpInsert: + eventType = nodeEventInsert + if data, ok := evt.Payload.(nodeWsSendWithFlow); ok && data.baseNode != nil { + node = serializeNode(*data.baseNode) + flowID = data.flowID + } + case mutation.OpUpdate: + eventType = nodeEventUpdate + if data, ok := evt.Payload.(nodeWsSendWithFlow); ok && data.baseNode != nil { + node = serializeNode(*data.baseNode) + flowID = data.flowID + } + case mutation.OpDelete: + eventType = nodeEventDelete + node = &flowv1.Node{ + NodeId: evt.ID.Bytes(), + FlowId: evt.ParentID.Bytes(), + } + flowID = evt.ParentID + } + + if node != nil { + p.nodeStream.Publish(NodeTopic{FlowID: flowID}, NodeEvent{ + Type: eventType, + FlowID: flowID, + Node: node, + }) + } +} + +func (p *rflowPublisher) publishNodeWait(evt mutation.Event) { + if p.nodeStream == nil { + return + } + + var node *flowv1.Node + var flowID idwrap.IDWrap + var eventType string + + switch evt.Op { + case mutation.OpInsert: + eventType = nodeEventInsert + if data, ok := evt.Payload.(nodeWaitWithFlow); ok && data.baseNode != nil { + node = serializeNode(*data.baseNode) + flowID = data.flowID + } + case mutation.OpUpdate: + eventType = nodeEventUpdate + if data, ok := evt.Payload.(nodeWaitWithFlow); ok && data.baseNode != nil { + node = serializeNode(*data.baseNode) + flowID = data.flowID + } + case mutation.OpDelete: + eventType = nodeEventDelete + node = &flowv1.Node{ + NodeId: evt.ID.Bytes(), + FlowId: evt.ParentID.Bytes(), + } + flowID = evt.ParentID + } + + if node != nil { + p.nodeStream.Publish(NodeTopic{FlowID: flowID}, NodeEvent{ + Type: eventType, FlowID: flowID, Node: node, }) diff --git a/packages/server/internal/api/rflowv2/rflowv2_copy_paste.go b/packages/server/internal/api/rflowv2/rflowv2_copy_paste.go index e822e1372..504246be7 100644 --- a/packages/server/internal/api/rflowv2/rflowv2_copy_paste.go +++ b/packages/server/internal/api/rflowv2/rflowv2_copy_paste.go @@ -13,6 +13,7 @@ import ( devtoolsdb "github.com/the-dev-tools/dev-tools/packages/db" "github.com/the-dev-tools/dev-tools/packages/server/internal/api/rgraphql" "github.com/the-dev-tools/dev-tools/packages/server/internal/api/rhttp" + "github.com/the-dev-tools/dev-tools/packages/server/internal/api/rwebsocket" "github.com/the-dev-tools/dev-tools/packages/server/internal/converter" "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" "github.com/the-dev-tools/dev-tools/packages/server/pkg/ioworkspace" @@ -20,11 +21,13 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mgraphql" "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mhttp" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mwebsocket" "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mworkspace" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sflow" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/shttp" "github.com/the-dev-tools/dev-tools/packages/server/pkg/translate/yamlflowsimplev2" flowv1 "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/flow/v1" + wsapiv1 "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/web_socket/v1" ) // FlowNodesCopy serializes selected nodes to YAML for clipboard copy. @@ -98,6 +101,8 @@ func (s *FlowServiceV2RPC) FlowNodesCopy( // Fetch type-specific data switch n.NodeKind { + case mflow.NODE_KIND_MANUAL_START: + // No type-specific data for ManualStart case mflow.NODE_KIND_REQUEST: if d, err := s.nrs.GetNodeRequest(ctx, n.ID); err == nil && d != nil { bundle.FlowRequestNodes = append(bundle.FlowRequestNodes, *d) @@ -168,6 +173,27 @@ func (s *FlowServiceV2RPC) FlowNodesCopy( } } } + case mflow.NODE_KIND_WS_CONNECTION: + if s.nwcs != nil { + if d, err := s.nwcs.GetNodeWsConnection(ctx, n.ID); err == nil { + bundle.FlowWsConnectionNodes = append(bundle.FlowWsConnectionNodes, *d) + if d.WebSocketID != nil { + s.populateWebSocketBundle(ctx, *d.WebSocketID, bundle) + } + } + } + case mflow.NODE_KIND_WS_SEND: + if s.nwss != nil { + if d, err := s.nwss.GetNodeWsSend(ctx, n.ID); err == nil { + bundle.FlowWsSendNodes = append(bundle.FlowWsSendNodes, *d) + } + } + case mflow.NODE_KIND_WAIT: + if s.nwaits != nil { + if d, err := s.nwaits.GetNodeWait(ctx, n.ID); err == nil && d != nil { + bundle.FlowWaitNodes = append(bundle.FlowWaitNodes, *d) + } + } } } @@ -223,6 +249,20 @@ func (s *FlowServiceV2RPC) populateGraphQLBundle(ctx context.Context, graphqlID } } +// populateWebSocketBundle fetches the WebSocket entity and its headers and adds them to the bundle. +func (s *FlowServiceV2RPC) populateWebSocketBundle(ctx context.Context, wsID idwrap.IDWrap, bundle *ioworkspace.WorkspaceBundle) { + if s.wsService != nil { + if ws, err := s.wsService.Get(ctx, wsID); err == nil { + bundle.WebSockets = append(bundle.WebSockets, *ws) + } + } + if s.wsHeaderService != nil { + if headers, err := s.wsHeaderService.GetByWebSocketID(ctx, wsID); err == nil { + bundle.WebSocketHeaders = append(bundle.WebSocketHeaders, headers...) + } + } +} + // FlowNodesPaste parses YAML from clipboard and creates nodes in the target flow. func (s *FlowServiceV2RPC) FlowNodesPaste( ctx context.Context, @@ -390,6 +430,21 @@ func (s *FlowServiceV2RPC) FlowNodesPaste( parsed.FlowGraphQLNodes[i].FlowNodeID = newID } } + for i := range parsed.FlowWsConnectionNodes { + if newID, ok := nodeIDMapping[parsed.FlowWsConnectionNodes[i].FlowNodeID]; ok { + parsed.FlowWsConnectionNodes[i].FlowNodeID = newID + } + } + for i := range parsed.FlowWsSendNodes { + if newID, ok := nodeIDMapping[parsed.FlowWsSendNodes[i].FlowNodeID]; ok { + parsed.FlowWsSendNodes[i].FlowNodeID = newID + } + } + for i := range parsed.FlowWaitNodes { + if newID, ok := nodeIDMapping[parsed.FlowWaitNodes[i].FlowNodeID]; ok { + parsed.FlowWaitNodes[i].FlowNodeID = newID + } + } // Remap variable references in expression fields when node names changed if len(nameMapping) > 0 { @@ -440,6 +495,18 @@ func (s *FlowServiceV2RPC) FlowNodesPaste( for i := range parsed.GraphQLHeaders { parsed.GraphQLHeaders[i].Value = remapVarRefs(parsed.GraphQLHeaders[i].Value, nameMapping) } + for i := range parsed.FlowWsSendNodes { + parsed.FlowWsSendNodes[i].Message = remapVarRefs(parsed.FlowWsSendNodes[i].Message, nameMapping) + if newName, ok := nameMapping[parsed.FlowWsSendNodes[i].WsConnectionNodeName]; ok { + parsed.FlowWsSendNodes[i].WsConnectionNodeName = newName + } + } + for i := range parsed.WebSockets { + parsed.WebSockets[i].Url = remapVarRefs(parsed.WebSockets[i].Url, nameMapping) + } + for i := range parsed.WebSocketHeaders { + parsed.WebSocketHeaders[i].Value = remapVarRefs(parsed.WebSocketHeaders[i].Value, nameMapping) + } } // Remap edges @@ -617,6 +684,34 @@ func (s *FlowServiceV2RPC) FlowNodesPaste( } } + // Handle WebSocket entities — create copies + wsIDMapping := make(map[idwrap.IDWrap]idwrap.IDWrap) + for i := range parsed.WebSockets { + ws := &parsed.WebSockets[i] + oldID := ws.ID + newID := idwrap.NewNow() + wsIDMapping[oldID] = newID + ws.ID = newID + ws.WorkspaceID = targetFlow.WorkspaceID + } + for i := range parsed.FlowWsConnectionNodes { + wcn := &parsed.FlowWsConnectionNodes[i] + if wcn.WebSocketID != nil { + if newID, ok := wsIDMapping[*wcn.WebSocketID]; ok { + wcn.WebSocketID = &newID + } + } + } + var wsHeadersToCreate []mwebsocket.WebSocketHeader + for i := range parsed.WebSocketHeaders { + h := &parsed.WebSocketHeaders[i] + if newID, ok := wsIDMapping[h.WebSocketID]; ok { + h.WebSocketID = newID + h.ID = idwrap.NewNow() + wsHeadersToCreate = append(wsHeadersToCreate, *h) + } + } + // Begin transaction for creating all entities tx, err := s.DB.BeginTx(ctx, nil) if err != nil { @@ -767,6 +862,46 @@ func (s *FlowServiceV2RPC) FlowNodesPaste( } } } + if s.wsService != nil { + for i := range parsed.WebSockets { + wsTx := s.wsService.TX(tx) + if err := wsTx.Create(ctx, &parsed.WebSockets[i]); err != nil { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to create websocket: %w", err)) + } + } + } + if s.wsHeaderService != nil { + for _, h := range wsHeadersToCreate { + wshTx := s.wsHeaderService.TX(tx) + if err := wshTx.Create(ctx, h); err != nil { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to create ws header: %w", err)) + } + } + } + if s.nwcs != nil { + for _, wsn := range parsed.FlowWsConnectionNodes { + nwcsWriter := sflow.NewNodeWsConnectionWriter(tx) + if err := nwcsWriter.CreateNodeWsConnection(ctx, wsn); err != nil { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to create ws connection node: %w", err)) + } + } + } + if s.nwss != nil { + for _, wsn := range parsed.FlowWsSendNodes { + nwssWriter := sflow.NewNodeWsSendWriter(tx) + if err := nwssWriter.CreateNodeWsSend(ctx, wsn); err != nil { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to create ws send node: %w", err)) + } + } + } + if s.nwaits != nil { + for _, wn := range parsed.FlowWaitNodes { + nwaitsWriter := sflow.NewNodeWaitWriter(tx) + if err := nwaitsWriter.CreateNodeWait(ctx, wn); err != nil { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to create wait node: %w", err)) + } + } + } // Create edges for _, e := range validEdges { @@ -815,6 +950,19 @@ func (s *FlowServiceV2RPC) FlowNodesPaste( } } + // Publish WebSocket events for newly created entities + for i := range parsed.WebSockets { + ws := parsed.WebSockets[i] + s.wsStream.Publish(rwebsocket.WebSocketTopic{WorkspaceID: targetFlow.WorkspaceID}, rwebsocket.WebSocketEvent{ + Type: eventTypeInsert, + WebSocket: &wsapiv1.WebSocket{ + WebsocketId: ws.ID.Bytes(), + Name: ws.Name, + Url: ws.Url, + }, + }) + } + return connect.NewResponse(&flowv1.FlowNodesPasteResponse{ NodeIds: createdNodeIDs, }), nil diff --git a/packages/server/internal/api/rflowv2/rflowv2_exec.go b/packages/server/internal/api/rflowv2/rflowv2_exec.go index 0d9cd119c..0fe2fc68e 100644 --- a/packages/server/internal/api/rflowv2/rflowv2_exec.go +++ b/packages/server/internal/api/rflowv2/rflowv2_exec.go @@ -7,27 +7,17 @@ import ( "encoding/json" "errors" "fmt" - "math" - "sync" - "time" "connectrpc.com/connect" emptypb "google.golang.org/protobuf/types/known/emptypb" devtoolsdb "github.com/the-dev-tools/dev-tools/packages/db" - "github.com/the-dev-tools/dev-tools/packages/server/internal/api/rlog" - "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/ngraphql" - "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/nrequest" - "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/runner" - "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/runner/flowlocalrunner" - "github.com/the-dev-tools/dev-tools/packages/server/pkg/httpclient" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/flowexec" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/flowresult" "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" - "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mcondition" "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" - "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mgraphql" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sflow" flowv1 "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/flow/v1" - logv1 "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/log/v1" ) func (s *FlowServiceV2RPC) FlowRun(ctx context.Context, req *connect.Request[flowv1.FlowRunRequest]) (*connect.Response[emptypb.Empty], error) { @@ -134,7 +124,7 @@ func (s *FlowServiceV2RPC) FlowRun(ctx context.Context, req *connect.Request[flo cancel() }() - duration, execErr := s.executeFlow(bgCtx, flow, nodes, edges, flowVars, version.ID, nodeIDMapping) + duration, execErr := s.executeFlow(bgCtx, flow, nodes, edges, flowVars, nodeIDMapping) // Copy final node/edge states from parent to version (best-effort). // Use Background() because bgCtx may be cancelled on FlowStop. @@ -171,161 +161,55 @@ func (s *FlowServiceV2RPC) executeFlow( nodes []mflow.Node, edges []mflow.Edge, flowVars []mflow.FlowVariable, - versionFlowID idwrap.IDWrap, nodeIDMapping map[string]idwrap.IDWrap, ) (int32, error) { - // Build base variables by merging: GlobalEnv -> ActiveEnv -> FlowVars - // Later values override earlier ones - baseVars, err := s.builder.BuildVariables(ctx, flow.WorkspaceID, flowVars) - if err != nil { - return 0, fmt.Errorf("failed to build execution variables: %w", err) + // Filter orphaned edges (source or target node missing) + validEdges := filterValidEdges(nodes, edges) + + // Create result processor + proc := flowresult.NewServerResultProcessor(flowresult.ServerResultProcessorOpts{ + FlowID: flow.ID, + WorkspaceID: flow.WorkspaceID, + Nodes: nodes, + Edges: validEdges, + NodeIDMapping: nodeIDMapping, + HTTPResponseService: s.httpResponseService, + GraphQLResponseService: s.graphqlResponseService, + NodeExecutionService: s.nes, + NodeService: s.ns, + EdgeService: s.es, + Publisher: s.newExecEventPublisher(), + Logger: s.logger, + }) + + // Create and prepare execution session + session := s.sessionFactory.Create(proc) + + if err := session.Prepare(ctx, flowexec.ExecutionParams{ + Flow: flow, + Nodes: nodes, + Edges: validEdges, + FlowVars: flowVars, + }); err != nil { + return 0, err } - requestRespChan := make(chan nrequest.NodeRequestSideResp, len(nodes)*2+1) - // Track when HTTP responses are published so node execution events can wait - // This ensures frontend receives HttpResponse before NodeExecution with ResponseID - responsePublished := make(map[string]chan struct{}) - var responsePublishedMu sync.Mutex - var respDrain sync.WaitGroup - respDrain.Add(1) - go func() { - defer respDrain.Done() - for resp := range requestRespChan { - responseID := resp.Resp.HTTPResponse.ID.String() - - // Register the channel before processing so nodeStateChan can find it - responsePublishedMu.Lock() - publishedChan := make(chan struct{}) - responsePublished[responseID] = publishedChan - responsePublishedMu.Unlock() - - // Save HTTP Response - if err := s.httpResponseService.Create(ctx, resp.Resp.HTTPResponse); err != nil { - s.logger.Error("failed to save http response", "error", err) - } else { - s.publishHttpResponseEvent("insert", resp.Resp.HTTPResponse, flow.WorkspaceID) - } - - // Save Headers - for _, h := range resp.Resp.ResponseHeaders { - if err := s.httpResponseService.CreateHeader(ctx, h); err != nil { - s.logger.Error("failed to save http response header", "error", err) - } else { - s.publishHttpResponseHeaderEvent("insert", h, flow.WorkspaceID) - } - } - - // Save Asserts - for _, a := range resp.Resp.ResponseAsserts { - if err := s.httpResponseService.CreateAssert(ctx, a); err != nil { - s.logger.Error("failed to save http response assert", "error", err) - } else { - s.publishHttpResponseAssertEvent("insert", a, flow.WorkspaceID) - } - } + // Reset node/edge states before execution (batch-publishes UI events) + s.resetNodeStates(ctx, flow.ID, nodes) + s.resetEdgeStates(ctx, flow.ID, edges) - // Signal that response is published - nodeStateChan can now publish execution - close(publishedChan) - - if resp.Done != nil { - close(resp.Done) - } - } - }() - defer func() { - close(requestRespChan) - respDrain.Wait() - }() - - gqlRespChan := make(chan ngraphql.NodeGraphQLSideResp, len(nodes)*2+1) - gqlResponsePublished := make(map[string]chan struct{}) - var gqlResponsePublishedMu sync.Mutex - var gqlRespDrain sync.WaitGroup - gqlRespDrain.Add(1) - go func() { - defer gqlRespDrain.Done() - for resp := range gqlRespChan { - responseID := resp.Response.ID.String() - - gqlResponsePublishedMu.Lock() - publishedChan := make(chan struct{}) - gqlResponsePublished[responseID] = publishedChan - gqlResponsePublishedMu.Unlock() - - // Save all entities first, THEN publish events in batch - // This ensures atomicity and ordering - the client can query for - // child entities (headers/assertions) immediately after receiving - // the response event, preventing race conditions in real-time updates - - // Save GraphQL Response - responseSuccess := false - if err := s.graphqlResponseService.Create(ctx, resp.Response); err != nil { - s.logger.Error("failed to save graphql response", "error", err) - } else { - responseSuccess = true - } - - // Save Response Headers - var successHeaders []mgraphql.GraphQLResponseHeader - for _, h := range resp.RespHeaders { - if err := s.graphqlResponseService.CreateHeader(ctx, h); err != nil { - s.logger.Error("failed to save graphql response header", "error", err) - } else { - successHeaders = append(successHeaders, h) - } - } - - // Save Asserts - var successAsserts []mgraphql.GraphQLResponseAssert - for _, a := range resp.RespAsserts { - if err := s.graphqlResponseService.CreateAssert(ctx, a); err != nil { - s.logger.Error("failed to save graphql response assert", "error", err) - } else { - successAsserts = append(successAsserts, a) - } - } - - // Publish all events atomically AFTER all saves complete - // This guarantees the client receives events in the correct order: - // 1. Response (parent) - // 2. Headers (children) - // 3. Assertions (children) - if responseSuccess { - // Publish response first - s.publishGraphQLResponseEvent("insert", resp.Response, flow.WorkspaceID) - - // Then headers - for _, h := range successHeaders { - s.publishGraphQLResponseHeaderEvent("insert", h, flow.WorkspaceID) - } - - // Then assertions - for _, a := range successAsserts { - s.publishGraphQLResponseAssertEvent("insert", a, flow.WorkspaceID) - } - } - - close(publishedChan) - - if resp.Done != nil { - close(resp.Done) - } - } - }() - defer func() { - close(gqlRespChan) - gqlRespDrain.Wait() - }() - - sharedHTTPClient := httpclient.New() + // Execute flow and wait for result processing + result, err := session.Run(ctx) + return result.Duration, err +} - // Filter out orphaned edges (source or target node missing) to prevent - // runner panics when edges reference deleted nodes. +// filterValidEdges removes edges whose source or target node is missing. +func filterValidEdges(nodes []mflow.Node, edges []mflow.Edge) []mflow.Edge { nodeIDSet := make(map[idwrap.IDWrap]struct{}, len(nodes)) for _, n := range nodes { nodeIDSet[n.ID] = struct{}{} } - validEdges := edges[:0:0] + validEdges := make([]mflow.Edge, 0, len(edges)) for _, e := range edges { if _, srcOK := nodeIDSet[e.SourceID]; !srcOK { continue @@ -335,34 +219,11 @@ func (s *FlowServiceV2RPC) executeFlow( } validEdges = append(validEdges, e) } + return validEdges +} - edgeMap := mflow.NewEdgesMap(validEdges) - // Build edgesBySource map for O(1) edge lookup by source node ID - edgesBySource := make(map[idwrap.IDWrap][]mflow.Edge, len(validEdges)) - for _, edge := range validEdges { - edgesBySource[edge.SourceID] = append(edgesBySource[edge.SourceID], edge) - } - - const defaultNodeTimeout = 60 // seconds - timeoutDuration := time.Duration(defaultNodeTimeout) * time.Second - - flowNodeMap, startNodeID, err := s.builder.BuildNodes( - ctx, - flow, - nodes, - timeoutDuration, - sharedHTTPClient, - requestRespChan, - gqlRespChan, - s.jsClient, - ) - if err != nil { - return 0, err - } - - flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewMonotonic(), flow.ID, startNodeID, flowNodeMap, edgeMap, 0, nil) - - // Reset all node states to UNSPECIFIED before flow execution +// resetNodeStates sets all node states to UNSPECIFIED and batch-publishes events. +func (s *FlowServiceV2RPC) resetNodeStates(ctx context.Context, flowID idwrap.IDWrap, nodes []mflow.Node) { nodeResetEvents := make([]NodeEvent, 0, len(nodes)) for _, node := range nodes { if err := s.ns.UpdateNodeState(ctx, node.ID, mflow.NODE_STATE_UNSPECIFIED); err != nil { @@ -372,17 +233,18 @@ func (s *FlowServiceV2RPC) executeFlow( resetNode.State = mflow.NODE_STATE_UNSPECIFIED nodeResetEvents = append(nodeResetEvents, NodeEvent{ Type: nodeEventUpdate, - FlowID: flow.ID, + FlowID: flowID, Node: serializeNode(resetNode), }) } } - // Bulk publish node reset events for real-time sync if len(nodeResetEvents) > 0 && s.nodeStream != nil { - s.nodeStream.Publish(NodeTopic{FlowID: flow.ID}, nodeResetEvents...) + s.nodeStream.Publish(NodeTopic{FlowID: flowID}, nodeResetEvents...) } +} - // Reset all edge states to UNSPECIFIED before flow execution +// resetEdgeStates sets all edge states to UNSPECIFIED and batch-publishes events. +func (s *FlowServiceV2RPC) resetEdgeStates(ctx context.Context, flowID idwrap.IDWrap, edges []mflow.Edge) { edgeResetEvents := make([]EdgeEvent, 0, len(edges)) for _, edge := range edges { if err := s.es.UpdateEdgeState(ctx, edge.ID, mflow.NODE_STATE_UNSPECIFIED); err != nil { @@ -392,349 +254,14 @@ func (s *FlowServiceV2RPC) executeFlow( resetEdge.State = mflow.NODE_STATE_UNSPECIFIED edgeResetEvents = append(edgeResetEvents, EdgeEvent{ Type: edgeEventUpdate, - FlowID: flow.ID, + FlowID: flowID, Edge: serializeEdge(resetEdge), }) } } - // Bulk publish edge reset events for real-time sync if len(edgeResetEvents) > 0 && s.edgeStream != nil { - s.edgeStream.Publish(EdgeTopic{FlowID: flow.ID}, edgeResetEvents...) + s.edgeStream.Publish(EdgeTopic{FlowID: flowID}, edgeResetEvents...) } - - // Build nodeKindMap for O(1) lookup of node kinds - // Used to skip NodeExecution creation for loop coordinator wrapper statuses - nodeKindMap := make(map[idwrap.IDWrap]mflow.NodeKind, len(nodes)) - for _, node := range nodes { - nodeKindMap[node.ID] = node.NodeKind - } - - nodeStateChan := make(chan runner.FlowNodeStatus, len(nodes)*2+1) - var stateDrain sync.WaitGroup - stateDrain.Add(1) - - // Create inverse mapping to map versioned IDs back to original IDs for live sync - inverseNodeIDMapping := make(map[string]idwrap.IDWrap, len(nodeIDMapping)) - for k, v := range nodeIDMapping { - inverseNodeIDMapping[v.String()] = idwrap.NewTextMust(k) - } - - go func() { - defer stateDrain.Done() - - // Cache execution IDs to ensure stability across multiple events for the same execution - // Key: NodeID + Iteration info - executionCache := make(map[string]idwrap.IDWrap) - - for status := range nodeStateChan { - // Find the original node ID if this is a versioned ID - originalNodeID := status.NodeID - if origID, ok := inverseNodeIDMapping[status.NodeID.String()]; ok { - originalNodeID = origID - } - - // Check if this is a loop coordinator (For/ForEach) wrapper status - // Skip NodeExecution creation for these, but still update node visual state - nodeKind := nodeKindMap[status.NodeID] - isLoopNode := nodeKind == mflow.NODE_KIND_FOR || nodeKind == mflow.NODE_KIND_FOR_EACH - skipExecution := isLoopNode && !status.IterationEvent - - // Persist execution state (skip for loop node wrapper statuses) - if !skipExecution { - execID := status.ExecutionID - isNewExecution := false - - if isZeroID(execID) { - // Construct cache key based on node and iteration context - cacheKey := status.NodeID.String() - if status.IterationContext != nil { - // Use iteration path and index for uniqueness in loops - cacheKey = fmt.Sprintf("%s:%v:%d", cacheKey, status.IterationContext.IterationPath, status.IterationContext.ExecutionIndex) - } else if status.IterationIndex >= 0 { - cacheKey = fmt.Sprintf("%s:%d", cacheKey, status.IterationIndex) - } - - if cachedID, ok := executionCache[cacheKey]; ok { - execID = cachedID - } else { - execID = idwrap.NewMonotonic() - executionCache[cacheKey] = execID - isNewExecution = true - } - } - - // Include timestamp in execution name for easy identification - executionName := fmt.Sprintf("%s - %s", status.Name, time.Now().Format("2006-01-02 15:04")) - - // Debug: Log AuxiliaryID value being set - if status.AuxiliaryID != nil { - s.logger.Debug("Creating execution with AuxiliaryID", - "exec_id", execID.String(), - "node_id", status.NodeID.String(), - "node_name", status.Name, - "state", status.State, - "auxiliary_id", status.AuxiliaryID.String(), - ) - } else { - s.logger.Debug("Creating execution without AuxiliaryID", - "exec_id", execID.String(), - "node_id", status.NodeID.String(), - "node_name", status.Name, - "state", status.State, - ) - } - - model := mflow.NodeExecution{ - ID: execID, - NodeID: status.NodeID, - Name: executionName, - State: status.State, - } - - // Set the appropriate response ID based on node kind - nodeKindForAux := nodeKindMap[status.NodeID] - if status.AuxiliaryID != nil { - if nodeKindForAux == mflow.NODE_KIND_GRAPHQL { - model.GraphQLResponseID = status.AuxiliaryID - } else { - model.ResponseID = status.AuxiliaryID - } - } - - if status.Error != nil { - errStr := status.Error.Error() - model.Error = &errStr - } - - if status.InputData != nil { - if b, err := json.Marshal(status.InputData); err == nil { - _ = model.SetInputJSON(b) - } - } - if status.OutputData != nil { - if b, err := json.Marshal(status.OutputData); err == nil { - _ = model.SetOutputJSON(b) - } - } - - // Set CompletedAt for terminal states - if status.State == mflow.NODE_STATE_SUCCESS || - status.State == mflow.NODE_STATE_FAILURE || - status.State == mflow.NODE_STATE_CANCELED { - now := time.Now().Unix() - model.CompletedAt = &now - } - - eventType := executionEventInsert - // Only use UPDATE if it's NOT a new execution AND the state is terminal. - // If it's a new execution (first time seeing this node run), we MUST send INSERT, - // even if the state is already SUCCESS/FAILURE (instant execution). - if !isNewExecution && (status.State == mflow.NODE_STATE_SUCCESS || - status.State == mflow.NODE_STATE_FAILURE || - status.State == mflow.NODE_STATE_CANCELED) { - eventType = executionEventUpdate - } - - if err := s.nes.UpsertNodeExecution(ctx, model); err != nil { - s.logger.Error("failed to persist node execution", "error", err) - } - - // If this execution has a ResponseID, wait for the response to be published first - // This ensures frontend receives HttpResponse/GraphQLResponse before NodeExecution - if status.AuxiliaryID != nil { - respIDStr := status.AuxiliaryID.String() - - // Check HTTP response published map - responsePublishedMu.Lock() - publishedChan, ok := responsePublished[respIDStr] - responsePublishedMu.Unlock() - if ok { - select { - case <-publishedChan: - case <-ctx.Done(): - } - responsePublishedMu.Lock() - delete(responsePublished, respIDStr) - responsePublishedMu.Unlock() - } - - // Check GraphQL response published map - gqlResponsePublishedMu.Lock() - gqlPublishedChan, gqlOK := gqlResponsePublished[respIDStr] - gqlResponsePublishedMu.Unlock() - if gqlOK { - select { - case <-gqlPublishedChan: - case <-ctx.Done(): - } - gqlResponsePublishedMu.Lock() - delete(gqlResponsePublished, respIDStr) - gqlResponsePublishedMu.Unlock() - } - } - - // Publish execution event - s.publishExecutionEvent(eventType, model, flow.ID) - } - - // Update node state in database (always use versioned ID for state persistence) - if err := s.ns.UpdateNodeState(ctx, status.NodeID, status.State); err != nil { - s.logger.Error("failed to update node state", "node_id", status.NodeID.String(), "error", err) - } - - // Update edge states based on node execution state - if status.State == mflow.NODE_STATE_SUCCESS || status.State == mflow.NODE_STATE_FAILURE { - // Find edges that start from this node using O(1) map lookup - edgesFromNode := edgesBySource[status.NodeID] - edgeState := mflow.NODE_STATE_SUCCESS - if status.State == mflow.NODE_STATE_FAILURE { - edgeState = mflow.NODE_STATE_FAILURE - } - for _, edge := range edgesFromNode { - if err := s.es.UpdateEdgeState(ctx, edge.ID, edgeState); err != nil { - s.logger.Error("failed to update edge state", "edge_id", edge.ID.String(), "error", err) - } else { - // Publish edge state update event for real-time sync - updatedEdge := edge - updatedEdge.State = edgeState - s.publishEdgeEvent(edgeEventUpdate, updatedEdge) - } - } - } - - // Note: Version node executions are no longer created here. - // Executions are moved from parent nodes to version nodes at the start of the next run. - - if s.nodeStream != nil { - var info string - if status.Error != nil { - info = status.Error.Error() - } else { - iterIndex := -1 - if status.IterationEvent { - iterIndex = status.IterationIndex - } else if status.IterationContext != nil { - iterIndex = status.IterationContext.ExecutionIndex - } - - if iterIndex >= 0 { - info = fmt.Sprintf("Iter: %d", iterIndex+1) - } - } - - // Map versioned node ID back to original node ID for live sync on current view - nodePB := &flowv1.Node{ - NodeId: originalNodeID.Bytes(), - FlowId: flow.ID.Bytes(), - State: flowv1.FlowItemState(status.State), - } - if info != "" { - nodePB.Info = &info - } - - s.nodeStream.Publish(NodeTopic{FlowID: flow.ID}, NodeEvent{ - Type: nodeEventUpdate, - FlowID: flow.ID, - Node: nodePB, - }) - } - - if s.logStream != nil && status.State != mflow.NODE_STATE_RUNNING { - idStr := status.NodeID.String() - stateStr := mflow.StringNodeState(status.State) - nodeName := status.Name - if nodeName == "" { - nodeName = idStr - } - msg := fmt.Sprintf("Node %s: %s", nodeName, stateStr) - - var logLevel logv1.LogLevel - switch status.State { - case mflow.NODE_STATE_FAILURE: - logLevel = logv1.LogLevel_LOG_LEVEL_ERROR - case mflow.NODE_STATE_CANCELED: - logLevel = logv1.LogLevel_LOG_LEVEL_WARNING - default: - logLevel = logv1.LogLevel_LOG_LEVEL_UNSPECIFIED - } - - // Create structured value with full node details - logData := map[string]any{ - "node_id": status.NodeID.String(), - "node_name": status.Name, - "state": stateStr, - "flow_id": flow.ID.String(), - "duration_ms": status.RunDuration.Milliseconds(), - } - - // Convert output/input to JSON-safe format via marshal/unmarshal - // This ensures types like []byte are properly converted - // Limit size to avoid very large log entries that could slow down the frontend - const maxLogDataSize = 64 * 1024 // 64KB limit - if status.OutputData != nil { - if jsonBytes, err := json.Marshal(status.OutputData); err == nil { - if len(jsonBytes) <= maxLogDataSize { - var jsonSafe any - if json.Unmarshal(jsonBytes, &jsonSafe) == nil { - logData["output"] = jsonSafe - } - } else { - logData["output"] = "(output too large to display)" - } - } - } - if status.InputData != nil { - if jsonBytes, err := json.Marshal(status.InputData); err == nil { - if len(jsonBytes) <= maxLogDataSize { - var jsonSafe any - if json.Unmarshal(jsonBytes, &jsonSafe) == nil { - logData["input"] = jsonSafe - } - } else { - logData["input"] = "(input too large to display)" - } - } - } - if status.Error != nil { - logData["error"] = status.Error.Error() - } - if status.IterationContext != nil { - logData["iteration_index"] = status.IterationContext.ExecutionIndex - logData["iteration_path"] = status.IterationContext.IterationPath - } - - val, err := rlog.NewLogValue(logData) - if err != nil { - s.logger.Error("failed to create log value", "error", err) - } - - s.logStream.Publish(rlog.LogTopic{}, rlog.LogEvent{ - Type: rlog.EventTypeInsert, - Log: &logv1.Log{ - LogId: idwrap.NewMonotonic().Bytes(), - Name: msg, - Level: logLevel, - Value: val, - }, - }) - } - } - }() - - startTime := time.Now() - runErr := flowRunner.RunWithEvents(ctx, runner.FlowEventChannels{ - NodeStates: nodeStateChan, - }, baseVars) - - duration := time.Since(startTime).Milliseconds() - if duration > math.MaxInt32 { - duration = math.MaxInt32 - } - //nolint:gosec // duration clamped to MaxInt32 - durationInt := int32(duration) - - stateDrain.Wait() - return durationInt, runErr } func (s *FlowServiceV2RPC) FlowStop(ctx context.Context, req *connect.Request[flowv1.FlowStopRequest]) (*connect.Response[emptypb.Empty], error) { @@ -794,100 +321,7 @@ func (s *FlowServiceV2RPC) createFlowVersionSnapshot( ) (mflow.Flow, map[string]idwrap.IDWrap, error) { // === PREPARATION PHASE (BEFORE TRANSACTION) === // Read all sub-node configurations before starting the transaction to minimize transaction duration. - // This follows SQLite best practices of keeping transactions short and doing reads outside when possible. - - type nodeConfig struct { - sourceNode mflow.Node - requestData *mflow.NodeRequest - forData *mflow.NodeFor - forEachData *mflow.NodeForEach - conditionData *mflow.NodeIf - jsData *mflow.NodeJS - aiData *mflow.NodeAI - aiProviderData *mflow.NodeAiProvider - memoryData *mflow.NodeMemory - graphqlData *mflow.NodeGraphQL - } - - nodeConfigs := make([]nodeConfig, 0, len(sourceNodes)) - - for _, sourceNode := range sourceNodes { - config := nodeConfig{sourceNode: sourceNode} - - switch sourceNode.NodeKind { - case mflow.NODE_KIND_REQUEST: - requestData, err := s.nrs.GetNodeRequest(ctx, sourceNode.ID) - if err == nil && requestData != nil { - config.requestData = requestData - } - - case mflow.NODE_KIND_FOR: - forData, err := s.nfs.GetNodeFor(ctx, sourceNode.ID) - if err != nil { - s.logger.Warn("failed to get for node config, using defaults", "node_id", sourceNode.ID.String(), "error", err) - } else if forData != nil { - config.forData = forData - } - - case mflow.NODE_KIND_FOR_EACH: - forEachData, err := s.nfes.GetNodeForEach(ctx, sourceNode.ID) - if err != nil { - s.logger.Warn("failed to get foreach node config, using defaults", "node_id", sourceNode.ID.String(), "error", err) - } else if forEachData != nil { - config.forEachData = forEachData - } - - case mflow.NODE_KIND_CONDITION: - conditionData, err := s.nifs.GetNodeIf(ctx, sourceNode.ID) - if err != nil { - s.logger.Warn("failed to get condition node config, using defaults", "node_id", sourceNode.ID.String(), "error", err) - } else if conditionData != nil { - config.conditionData = conditionData - } - - case mflow.NODE_KIND_JS: - jsData, err := s.njss.GetNodeJS(ctx, sourceNode.ID) - if err != nil { - s.logger.Warn("failed to get js node config, using defaults", "node_id", sourceNode.ID.String(), "error", err) - } else if jsData != nil { - config.jsData = jsData - } - - case mflow.NODE_KIND_AI: - aiData, err := s.nais.GetNodeAI(ctx, sourceNode.ID) - if err != nil { - s.logger.Warn("failed to get ai node config, using defaults", "node_id", sourceNode.ID.String(), "error", err) - } else if aiData != nil { - config.aiData = aiData - } - - case mflow.NODE_KIND_AI_PROVIDER: - aiProviderData, err := s.naps.GetNodeAiProvider(ctx, sourceNode.ID) - if err != nil { - s.logger.Warn("failed to get ai provider node config, using defaults", "node_id", sourceNode.ID.String(), "error", err) - } else if aiProviderData != nil { - config.aiProviderData = aiProviderData - } - - case mflow.NODE_KIND_AI_MEMORY: - memoryData, err := s.nmems.GetNodeMemory(ctx, sourceNode.ID) - if err != nil { - s.logger.Warn("failed to get memory node config, using defaults", "node_id", sourceNode.ID.String(), "error", err) - } else if memoryData != nil { - config.memoryData = memoryData - } - - case mflow.NODE_KIND_GRAPHQL: - graphqlData, err := s.ngqs.GetNodeGraphQL(ctx, sourceNode.ID) - if err != nil { - s.logger.Warn("failed to get graphql node config, using defaults", "node_id", sourceNode.ID.String(), "error", err) - } else if graphqlData != nil { - config.graphqlData = graphqlData - } - } - - nodeConfigs = append(nodeConfigs, config) - } + nodeConfigs := s.snapshotRegistry.ReadAll(ctx, sourceNodes, s.logger) // === BEGIN TRANSACTION === tx, err := s.DB.BeginTx(ctx, nil) @@ -896,34 +330,8 @@ func (s *FlowServiceV2RPC) createFlowVersionSnapshot( } defer devtoolsdb.TxnRollback(tx) - // Get TX-bound service writers flowWriter := s.fs.TX(tx) nodeWriter := s.ns.TX(tx) - nrsWriter := s.nrs.TX(tx) - nfsWriter := s.nfs.TX(tx) - nfesWriter := s.nfes.TX(tx) - nifsWriter := s.nifs.TX(tx) - njssWriter := s.njss.TX(tx) - var naisWriter *sflow.NodeAIService - if s.nais != nil { - txService := s.nais.TX(tx) - naisWriter = &txService - } - var napsWriter *sflow.NodeAiProviderService - if s.naps != nil { - txService := s.naps.TX(tx) - napsWriter = &txService - } - var nmemsWriter *sflow.NodeMemoryService - if s.nmems != nil { - txService := s.nmems.TX(tx) - nmemsWriter = &txService - } - var ngqsWriter *sflow.NodeGraphQLService - if s.ngqs != nil { - txService := s.ngqs.TX(tx) - ngqsWriter = &txService - } edgeWriter := s.es.TX(tx) varWriter := s.fvs.TX(tx) @@ -940,18 +348,12 @@ func (s *FlowServiceV2RPC) createFlowVersionSnapshot( // Events collections for bulk publishing (after commit) nodeEvents := make([]NodeEvent, 0, len(sourceNodes)) - jsEvents := make([]JsEvent, 0) - forEvents := make([]ForEvent, 0) - // Duplicate all nodes and their sub-node data - for _, config := range nodeConfigs { - sourceNode := config.sourceNode + // Duplicate all nodes + for _, sourceNode := range sourceNodes { newNodeID := idwrap.NewMonotonic() nodeIDMapping[sourceNode.ID.String()] = newNodeID - // Create the base node with UNSPECIFIED state. The parent node's state is from - // the previous run and would be misleading — this version's execution hasn't - // happened yet, so its nodes should start clean. newNode := mflow.Node{ ID: newNodeID, FlowID: versionFlowID, @@ -962,195 +364,47 @@ func (s *FlowServiceV2RPC) createFlowVersionSnapshot( State: mflow.NODE_STATE_UNSPECIFIED, } - // Use CreateNodeWithState to set the initial state in the snapshot if err := nodeWriter.CreateNodeWithState(ctx, newNode); err != nil { return mflow.Flow{}, nil, fmt.Errorf("create node %s: %w", sourceNode.Name, err) } - // Duplicate node-type specific data - switch sourceNode.NodeKind { - case mflow.NODE_KIND_REQUEST: - if config.requestData != nil { - // Copy the request node config (referencing same HTTP, not duplicating) - newRequestData := mflow.NodeRequest{ - FlowNodeID: newNodeID, - HttpID: config.requestData.HttpID, - DeltaHttpID: config.requestData.DeltaHttpID, - HasRequestConfig: config.requestData.HasRequestConfig, - } - if err := nrsWriter.CreateNodeRequest(ctx, newRequestData); err != nil { - return mflow.Flow{}, nil, fmt.Errorf("create request node: %w", err) - } - // Request node events are handled through nodeStream subscription - } - - case mflow.NODE_KIND_FOR: - // Always create For node config with defaults - newForData := mflow.NodeFor{ - FlowNodeID: newNodeID, - IterCount: 1, // default - Condition: mcondition.Condition{}, // default empty - ErrorHandling: mflow.ErrorHandling_ERROR_HANDLING_BREAK, // default - } - if config.forData != nil { - // Override with actual values, but keep default of 1 if IterCount is 0 - if config.forData.IterCount > 0 { - newForData.IterCount = config.forData.IterCount - } - newForData.Condition = config.forData.Condition - newForData.ErrorHandling = config.forData.ErrorHandling - } - if err := nfsWriter.CreateNodeFor(ctx, newForData); err != nil { - return mflow.Flow{}, nil, fmt.Errorf("create for node: %w", err) - } - forEvents = append(forEvents, ForEvent{ - Type: forEventInsert, - FlowID: versionFlowID, - Node: serializeNodeFor(newForData), - }) + nodeEvents = append(nodeEvents, NodeEvent{ + Type: nodeEventInsert, + FlowID: versionFlowID, + Node: serializeNode(newNode), + }) + } - case mflow.NODE_KIND_FOR_EACH: - // Always create ForEach node config with defaults - newForEachData := mflow.NodeForEach{ - FlowNodeID: newNodeID, - IterExpression: "", // default empty - Condition: mcondition.Condition{}, // default empty - ErrorHandling: mflow.ErrorHandling_ERROR_HANDLING_BREAK, // default - } - if config.forEachData != nil { - // Override with actual values - newForEachData.IterExpression = config.forEachData.IterExpression - newForEachData.Condition = config.forEachData.Condition - newForEachData.ErrorHandling = config.forEachData.ErrorHandling - } - if err := nfesWriter.CreateNodeForEach(ctx, newForEachData); err != nil { - return mflow.Flow{}, nil, fmt.Errorf("create foreach node: %w", err) - } - // ForEach node events are handled through nodeStream subscription + // Write type-specific node configs via snapshot registry + configResults, err := s.snapshotRegistry.WriteAllTx(ctx, tx, sourceNodes, nodeIDMapping, nodeConfigs) + if err != nil { + return mflow.Flow{}, nil, err + } - case mflow.NODE_KIND_CONDITION: - // Always create Condition node config with defaults - newConditionData := mflow.NodeIf{ - FlowNodeID: newNodeID, - Condition: mcondition.Condition{}, // default empty - } - if config.conditionData != nil { - // Override with actual values - newConditionData.Condition = config.conditionData.Condition - } - if err := nifsWriter.CreateNodeIf(ctx, newConditionData); err != nil { - return mflow.Flow{}, nil, fmt.Errorf("create condition node: %w", err) + // Collect type-specific events for publishing + var jsEvents []JsEvent + var forEvents []ForEvent + for _, result := range configResults { + switch result.NodeKind { + case mflow.NODE_KIND_FOR: + if data, ok := result.Config.(mflow.NodeFor); ok { + forEvents = append(forEvents, ForEvent{ + Type: forEventInsert, + FlowID: versionFlowID, + Node: serializeNodeFor(data), + }) } - // Condition node events are handled through nodeStream subscription - case mflow.NODE_KIND_JS: - // Always create JS node config with defaults - newJsData := mflow.NodeJS{ - FlowNodeID: newNodeID, - Code: nil, // default empty - CodeCompressType: 0, // default none - } - if config.jsData != nil { - // Override with actual values - newJsData.Code = config.jsData.Code - newJsData.CodeCompressType = config.jsData.CodeCompressType - } - if err := njssWriter.CreateNodeJS(ctx, newJsData); err != nil { - return mflow.Flow{}, nil, fmt.Errorf("create js node: %w", err) - } - jsEvents = append(jsEvents, JsEvent{ - Type: jsEventInsert, - FlowID: versionFlowID, - Node: serializeNodeJs(newJsData), - }) - - case mflow.NODE_KIND_AI: - // Skip if AI service is not available - if naisWriter == nil { - s.logger.Warn("NodeAI service not available, skipping AI node config", "node_id", sourceNode.ID.String()) - } else { - // Create AI node config (model/credential now via connected Model node) - newAIData := mflow.NodeAI{ - FlowNodeID: newNodeID, - Prompt: "", - MaxIterations: 5, - } - if config.aiData != nil { - newAIData.Prompt = config.aiData.Prompt - newAIData.MaxIterations = config.aiData.MaxIterations - } - if err := naisWriter.CreateNodeAI(ctx, newAIData); err != nil { - return mflow.Flow{}, nil, fmt.Errorf("create ai node: %w", err) - } - // AI node events are handled through nodeStream subscription - } - - case mflow.NODE_KIND_AI_PROVIDER: - // Skip if AI Provider service is not available - if napsWriter == nil { - s.logger.Warn("NodeAiProvider service not available, skipping AI Provider node config", "node_id", sourceNode.ID.String()) - } else { - // Create AI Provider node config with defaults - newAiProviderData := mflow.NodeAiProvider{ - FlowNodeID: newNodeID, - CredentialID: nil, - Model: mflow.AiModelUnspecified, - Temperature: nil, - MaxTokens: nil, - } - if config.aiProviderData != nil { - newAiProviderData.CredentialID = config.aiProviderData.CredentialID - newAiProviderData.Model = config.aiProviderData.Model - newAiProviderData.Temperature = config.aiProviderData.Temperature - newAiProviderData.MaxTokens = config.aiProviderData.MaxTokens - } - if err := napsWriter.CreateNodeAiProvider(ctx, newAiProviderData); err != nil { - return mflow.Flow{}, nil, fmt.Errorf("create ai provider node: %w", err) - } - // AI Provider node events are handled through nodeStream subscription - } - - case mflow.NODE_KIND_AI_MEMORY: - // Skip if Memory service is not available - if nmemsWriter == nil { - s.logger.Warn("NodeMemory service not available, skipping Memory node config", "node_id", sourceNode.ID.String()) - } else { - // Create Memory node config with defaults - newMemoryData := mflow.NodeMemory{ - FlowNodeID: newNodeID, - MemoryType: mflow.AiMemoryTypeWindowBuffer, - WindowSize: 10, // Default window size - } - if config.memoryData != nil { - newMemoryData.MemoryType = config.memoryData.MemoryType - newMemoryData.WindowSize = config.memoryData.WindowSize - } - if err := nmemsWriter.CreateNodeMemory(ctx, newMemoryData); err != nil { - return mflow.Flow{}, nil, fmt.Errorf("create memory node: %w", err) - } - // Memory node events are handled through nodeStream subscription - } - - case mflow.NODE_KIND_GRAPHQL: - if ngqsWriter == nil { - s.logger.Warn("NodeGraphQL service not available, skipping GraphQL node config", "node_id", sourceNode.ID.String()) - } else if config.graphqlData != nil { - newGraphQLData := mflow.NodeGraphQL{ - FlowNodeID: newNodeID, - GraphQLID: config.graphqlData.GraphQLID, - } - if err := ngqsWriter.CreateNodeGraphQL(ctx, newGraphQLData); err != nil { - return mflow.Flow{}, nil, fmt.Errorf("create graphql node: %w", err) - } + if data, ok := result.Config.(mflow.NodeJS); ok { + jsEvents = append(jsEvents, JsEvent{ + Type: jsEventInsert, + FlowID: versionFlowID, + Node: serializeNodeJs(data), + }) } + default: + // Other node kinds don't need type-specific events } - - // Collect base node event - nodeEvents = append(nodeEvents, NodeEvent{ - Type: nodeEventInsert, - FlowID: versionFlowID, - Node: serializeNode(newNode), - }) } // Duplicate all edges with remapped node IDs diff --git a/packages/server/internal/api/rflowv2/rflowv2_exec_publisher.go b/packages/server/internal/api/rflowv2/rflowv2_exec_publisher.go new file mode 100644 index 000000000..262a7f9ca --- /dev/null +++ b/packages/server/internal/api/rflowv2/rflowv2_exec_publisher.go @@ -0,0 +1,241 @@ +package rflowv2 + +import ( + "encoding/json" + "fmt" + + "github.com/the-dev-tools/dev-tools/packages/server/internal/api/rgraphql" + "github.com/the-dev-tools/dev-tools/packages/server/internal/api/rhttp" + "github.com/the-dev-tools/dev-tools/packages/server/internal/api/rlog" + "github.com/the-dev-tools/dev-tools/packages/server/internal/converter" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/eventstream" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/runner" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mgraphql" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mhttp" + flowv1 "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/flow/v1" + logv1 "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/log/v1" +) + +// execEventPublisher implements flowresult.EventPublisher by delegating +// to the event stream fields on FlowServiceV2RPC. +type execEventPublisher struct { + executionStream eventstream.SyncStreamer[ExecutionTopic, ExecutionEvent] + nodeStream eventstream.SyncStreamer[NodeTopic, NodeEvent] + edgeStream eventstream.SyncStreamer[EdgeTopic, EdgeEvent] + httpResponseStream eventstream.SyncStreamer[rhttp.HttpResponseTopic, rhttp.HttpResponseEvent] + httpResponseHeaderStream eventstream.SyncStreamer[rhttp.HttpResponseHeaderTopic, rhttp.HttpResponseHeaderEvent] + httpResponseAssertStream eventstream.SyncStreamer[rhttp.HttpResponseAssertTopic, rhttp.HttpResponseAssertEvent] + gqlResponseStream eventstream.SyncStreamer[rgraphql.GraphQLResponseTopic, rgraphql.GraphQLResponseEvent] + gqlResponseHeaderStream eventstream.SyncStreamer[rgraphql.GraphQLResponseHeaderTopic, rgraphql.GraphQLResponseHeaderEvent] + gqlResponseAssertStream eventstream.SyncStreamer[rgraphql.GraphQLResponseAssertTopic, rgraphql.GraphQLResponseAssertEvent] + logStream eventstream.SyncStreamer[rlog.LogTopic, rlog.LogEvent] + logger func(msg string, args ...any) +} + +func (s *FlowServiceV2RPC) newExecEventPublisher() *execEventPublisher { + return &execEventPublisher{ + executionStream: s.executionStream, + nodeStream: s.nodeStream, + edgeStream: s.edgeStream, + httpResponseStream: s.httpResponseStream, + httpResponseHeaderStream: s.httpResponseHeaderStream, + httpResponseAssertStream: s.httpResponseAssertStream, + gqlResponseStream: s.graphqlResponseStream, + gqlResponseHeaderStream: s.graphqlResponseHeaderStream, + gqlResponseAssertStream: s.graphqlResponseAssertStream, + logStream: s.logStream, + logger: func(msg string, args ...any) { + s.logger.Error(msg, args...) + }, + } +} + +func (p *execEventPublisher) PublishHTTPResponse(response mhttp.HTTPResponse, workspaceID idwrap.IDWrap) { + if p.httpResponseStream == nil { + return + } + responsePB := converter.ToAPIHttpResponse(response) + p.httpResponseStream.Publish(rhttp.HttpResponseTopic{WorkspaceID: workspaceID}, rhttp.HttpResponseEvent{ + Type: eventTypeInsert, + HttpResponse: responsePB, + }) +} + +func (p *execEventPublisher) PublishHTTPResponseHeader(header mhttp.HTTPResponseHeader, workspaceID idwrap.IDWrap) { + if p.httpResponseHeaderStream == nil { + return + } + headerPB := converter.ToAPIHttpResponseHeader(header) + p.httpResponseHeaderStream.Publish(rhttp.HttpResponseHeaderTopic{WorkspaceID: workspaceID}, rhttp.HttpResponseHeaderEvent{ + Type: eventTypeInsert, + HttpResponseHeader: headerPB, + }) +} + +func (p *execEventPublisher) PublishHTTPResponseAssert(assert mhttp.HTTPResponseAssert, workspaceID idwrap.IDWrap) { + if p.httpResponseAssertStream == nil { + return + } + assertPB := converter.ToAPIHttpResponseAssert(assert) + p.httpResponseAssertStream.Publish(rhttp.HttpResponseAssertTopic{WorkspaceID: workspaceID}, rhttp.HttpResponseAssertEvent{ + Type: eventTypeInsert, + HttpResponseAssert: assertPB, + }) +} + +func (p *execEventPublisher) PublishGraphQLResponse(response mgraphql.GraphQLResponse, workspaceID idwrap.IDWrap) { + if p.gqlResponseStream == nil { + return + } + responsePB := rgraphql.ToAPIGraphQLResponse(response) + p.gqlResponseStream.Publish(rgraphql.GraphQLResponseTopic{WorkspaceID: workspaceID}, rgraphql.GraphQLResponseEvent{ + Type: eventTypeInsert, + GraphQLResponse: responsePB, + }) +} + +func (p *execEventPublisher) PublishGraphQLResponseHeader(header mgraphql.GraphQLResponseHeader, workspaceID idwrap.IDWrap) { + if p.gqlResponseHeaderStream == nil { + return + } + headerPB := rgraphql.ToAPIGraphQLResponseHeader(header) + p.gqlResponseHeaderStream.Publish(rgraphql.GraphQLResponseHeaderTopic{WorkspaceID: workspaceID}, rgraphql.GraphQLResponseHeaderEvent{ + Type: eventTypeInsert, + GraphQLResponseHeader: headerPB, + }) +} + +func (p *execEventPublisher) PublishGraphQLResponseAssert(assert mgraphql.GraphQLResponseAssert, workspaceID idwrap.IDWrap) { + if p.gqlResponseAssertStream == nil { + return + } + assertPB := rgraphql.ToAPIGraphQLResponseAssert(assert) + p.gqlResponseAssertStream.Publish(rgraphql.GraphQLResponseAssertTopic{WorkspaceID: workspaceID}, rgraphql.GraphQLResponseAssertEvent{ + Type: eventTypeInsert, + GraphQLResponseAssert: assertPB, + }) +} + +func (p *execEventPublisher) PublishExecution(eventType string, execution mflow.NodeExecution, flowID idwrap.IDWrap) { + if p.executionStream == nil { + return + } + executionPB := serializeNodeExecution(execution) + p.executionStream.Publish(ExecutionTopic{FlowID: flowID}, ExecutionEvent{ + Type: eventType, + FlowID: flowID, + Execution: executionPB, + }) +} + +func (p *execEventPublisher) PublishNodeState(flowID, originalNodeID idwrap.IDWrap, state mflow.NodeState, info string) { + if p.nodeStream == nil { + return + } + nodePB := &flowv1.Node{ + NodeId: originalNodeID.Bytes(), + FlowId: flowID.Bytes(), + State: flowv1.FlowItemState(state), + } + if info != "" { + nodePB.Info = &info + } + p.nodeStream.Publish(NodeTopic{FlowID: flowID}, NodeEvent{ + Type: nodeEventUpdate, + FlowID: flowID, + Node: nodePB, + }) +} + +func (p *execEventPublisher) PublishEdgeState(edge mflow.Edge) { + if p.edgeStream == nil { + return + } + p.edgeStream.Publish(EdgeTopic{FlowID: edge.FlowID}, EdgeEvent{ + Type: edgeEventUpdate, + FlowID: edge.FlowID, + Edge: serializeEdge(edge), + }) +} + +func (p *execEventPublisher) PublishLog(flowID idwrap.IDWrap, status runner.FlowNodeStatus) { + if p.logStream == nil { + return + } + + idStr := status.NodeID.String() + stateStr := mflow.StringNodeState(status.State) + nodeName := status.Name + if nodeName == "" { + nodeName = idStr + } + msg := fmt.Sprintf("Node %s: %s", nodeName, stateStr) + + var logLevel logv1.LogLevel + switch status.State { + case mflow.NODE_STATE_FAILURE: + logLevel = logv1.LogLevel_LOG_LEVEL_ERROR + case mflow.NODE_STATE_CANCELED: + logLevel = logv1.LogLevel_LOG_LEVEL_WARNING + default: + logLevel = logv1.LogLevel_LOG_LEVEL_UNSPECIFIED + } + + logData := map[string]any{ + "node_id": status.NodeID.String(), + "node_name": status.Name, + "state": stateStr, + "flow_id": flowID.String(), + "duration_ms": status.RunDuration.Milliseconds(), + } + + const maxLogDataSize = 64 * 1024 // 64KB limit + if status.OutputData != nil { + if jsonBytes, err := json.Marshal(status.OutputData); err == nil { + if len(jsonBytes) <= maxLogDataSize { + var jsonSafe any + if json.Unmarshal(jsonBytes, &jsonSafe) == nil { + logData["output"] = jsonSafe + } + } else { + logData["output"] = "(output too large to display)" + } + } + } + if status.InputData != nil { + if jsonBytes, err := json.Marshal(status.InputData); err == nil { + if len(jsonBytes) <= maxLogDataSize { + var jsonSafe any + if json.Unmarshal(jsonBytes, &jsonSafe) == nil { + logData["input"] = jsonSafe + } + } else { + logData["input"] = "(input too large to display)" + } + } + } + if status.Error != nil { + logData["error"] = status.Error.Error() + } + if status.IterationContext != nil { + logData["iteration_index"] = status.IterationContext.ExecutionIndex + logData["iteration_path"] = status.IterationContext.IterationPath + } + + val, err := rlog.NewLogValue(logData) + if err != nil { + p.logger("failed to create log value", "error", err) + } + + p.logStream.Publish(rlog.LogTopic{}, rlog.LogEvent{ + Type: rlog.EventTypeInsert, + Log: &logv1.Log{ + LogId: idwrap.NewMonotonic().Bytes(), + Name: msg, + Level: logLevel, + Value: val, + }, + }) +} diff --git a/packages/server/internal/api/rflowv2/rflowv2_exec_test.go b/packages/server/internal/api/rflowv2/rflowv2_exec_test.go index 9406ae293..2eb1e5a75 100644 --- a/packages/server/internal/api/rflowv2/rflowv2_exec_test.go +++ b/packages/server/internal/api/rflowv2/rflowv2_exec_test.go @@ -20,6 +20,7 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/internal/api/middleware/mwauth" "github.com/the-dev-tools/dev-tools/packages/server/pkg/dbtime" "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/flowbuilder" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/flowexec" "github.com/the-dev-tools/dev-tools/packages/server/pkg/http/resolver" "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" @@ -76,6 +77,11 @@ func setupTestService(t *testing.T) (*FlowServiceV2RPC, *gen.Queries, context.Co &aiProviderService, &memoryService, nil, // NodeGraphQLService + nil, // NodeWsConnectionService + nil, // NodeWsSendService + nil, // NodeWaitService + nil, // WebSocketService + nil, // WebSocketHeaderService nil, // GraphQLService nil, // GraphQLHeaderService &wsService, @@ -87,27 +93,38 @@ func setupTestService(t *testing.T) (*FlowServiceV2RPC, *gen.Queries, context.Co nil, // LLMProviderFactory ) + // Build snapshot registry for version snapshots + registry := flowexec.NewSnapshotRegistry() + registry.Register(&flowexec.RequestSnapshot{Service: &reqService}) + registry.Register(&flowexec.ForSnapshot{Service: &forService}) + registry.Register(&flowexec.ForEachSnapshot{Service: &forEachService}) + registry.Register(&flowexec.ConditionSnapshot{Service: ifService}) + registry.Register(&flowexec.JSSnapshot{Service: &jsService}) + registry.Register(&flowexec.AIProviderSnapshot{Service: &aiProviderService}) + registry.Register(&flowexec.MemorySnapshot{Service: &memoryService}) + svc := &FlowServiceV2RPC{ - DB: db, - wsReader: wsReader, - fsReader: fsReader, - nsReader: nsReader, - ws: &wsService, - fs: &flowService, - ns: &nodeService, - nes: &nodeExecService, - es: &edgeService, - fvs: &flowVarService, - nrs: &reqService, // Added missing services to struct - nfs: &forService, - nfes: &forEachService, - nifs: ifService, - njss: &jsService, - naps: &aiProviderService, - nmems: &memoryService, - logger: logger, - builder: builder, - runningFlows: make(map[string]context.CancelFunc), + DB: db, + wsReader: wsReader, + fsReader: fsReader, + nsReader: nsReader, + ws: &wsService, + fs: &flowService, + ns: &nodeService, + nes: &nodeExecService, + es: &edgeService, + fvs: &flowVarService, + nrs: &reqService, + nfs: &forService, + nfes: &forEachService, + nifs: ifService, + njss: &jsService, + naps: &aiProviderService, + nmems: &memoryService, + logger: logger, + sessionFactory: &flowexec.LocalSessionFactory{Builder: builder}, + snapshotRegistry: registry, + runningFlows: make(map[string]context.CancelFunc), } // Setup User & Workspace diff --git a/packages/server/internal/api/rflowv2/rflowv2_exec_transaction_test.go b/packages/server/internal/api/rflowv2/rflowv2_exec_transaction_test.go index f82a93202..5171998b4 100644 --- a/packages/server/internal/api/rflowv2/rflowv2_exec_transaction_test.go +++ b/packages/server/internal/api/rflowv2/rflowv2_exec_transaction_test.go @@ -16,6 +16,7 @@ import ( gen "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" "github.com/the-dev-tools/dev-tools/packages/server/internal/api/middleware/mwauth" "github.com/the-dev-tools/dev-tools/packages/server/pkg/dbtime" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/flowexec" "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mcondition" "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" @@ -25,6 +26,16 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/pkg/testutil" ) +func newTestSnapshotRegistry(nrs *sflow.NodeRequestService, nfs *sflow.NodeForService, nfes *sflow.NodeForEachService, nifs *sflow.NodeIfService, njss *sflow.NodeJsService) *flowexec.SnapshotRegistry { + registry := flowexec.NewSnapshotRegistry() + registry.Register(&flowexec.RequestSnapshot{Service: nrs}) + registry.Register(&flowexec.ForSnapshot{Service: nfs}) + registry.Register(&flowexec.ForEachSnapshot{Service: nfes}) + registry.Register(&flowexec.ConditionSnapshot{Service: nifs}) + registry.Register(&flowexec.JSSnapshot{Service: njss}) + return registry +} + // TestFlowVersionSnapshot_TransactionAtomicity verifies that createFlowVersionSnapshot // uses a single transaction and either creates ALL entities or NONE. // This test ensures the critical data corruption bug is fixed where partial flow @@ -53,18 +64,19 @@ func TestFlowVersionSnapshot_TransactionAtomicity(t *testing.T) { logger := slog.New(slog.NewTextHandler(os.Stdout, nil)) svc := &FlowServiceV2RPC{ - DB: db, - ws: &wsService, - fs: &flowService, - ns: &nodeService, - es: &edgeService, - nrs: &nrsService, - nfs: &nfsService, - nfes: &nfesService, - nifs: nifsService, - njss: &njssService, - fvs: &varService, - logger: logger, + DB: db, + ws: &wsService, + fs: &flowService, + ns: &nodeService, + es: &edgeService, + nrs: &nrsService, + nfs: &nfsService, + nfes: &nfesService, + nifs: nifsService, + njss: &njssService, + fvs: &varService, + logger: logger, + snapshotRegistry: newTestSnapshotRegistry(&nrsService, &nfsService, &nfesService, nifsService, &njssService), } // Create test data @@ -284,6 +296,7 @@ func TestFlowVersionSnapshot_TransactionAtomicity(t *testing.T) { ifData, err := nifsService.GetNodeIf(ctx, node.ID) require.NoError(t, err) require.NotNil(t, ifData, "Condition config should exist") + default: } } @@ -329,18 +342,19 @@ func TestFlowVersionSnapshot_EmptyFlow(t *testing.T) { logger := slog.New(slog.NewTextHandler(os.Stdout, nil)) svc := &FlowServiceV2RPC{ - DB: db, - ws: &wsService, - fs: &flowService, - ns: &nodeService, - es: &edgeService, - nrs: &nrsService, - nfs: &nfsService, - nfes: &nfesService, - nifs: nifsService, - njss: &njssService, - fvs: &varService, - logger: logger, + DB: db, + ws: &wsService, + fs: &flowService, + ns: &nodeService, + es: &edgeService, + nrs: &nrsService, + nfs: &nfsService, + nfes: &nfesService, + nifs: nifsService, + njss: &njssService, + fvs: &varService, + logger: logger, + snapshotRegistry: newTestSnapshotRegistry(&nrsService, &nfsService, &nfesService, nifsService, &njssService), } userID := idwrap.NewNow() @@ -439,18 +453,19 @@ func TestFlowVersionSnapshot_Concurrency_Simple(t *testing.T) { logger := slog.New(slog.NewTextHandler(os.Stdout, nil)) svc := &FlowServiceV2RPC{ - DB: db, - ws: &wsService, - fs: &flowService, - ns: &nodeService, - es: &edgeService, - nrs: &nrsService, - nfs: &nfsService, - nfes: &nfesService, - nifs: nifsService, - njss: &njssService, - fvs: &varService, - logger: logger, + DB: db, + ws: &wsService, + fs: &flowService, + ns: &nodeService, + es: &edgeService, + nrs: &nrsService, + nfs: &nfsService, + nfes: &nfesService, + nifs: nifsService, + njss: &njssService, + fvs: &varService, + logger: logger, + snapshotRegistry: newTestSnapshotRegistry(&nrsService, &nfsService, &nfesService, nifsService, &njssService), } userID := idwrap.NewNow() @@ -548,18 +563,19 @@ func TestFlowVersionSnapshot_Concurrency_WithNodes(t *testing.T) { logger := slog.New(slog.NewTextHandler(os.Stdout, nil)) svc := &FlowServiceV2RPC{ - DB: db, - ws: &wsService, - fs: &flowService, - ns: &nodeService, - es: &edgeService, - nrs: &nrsService, - nfs: &nfsService, - nfes: &nfesService, - nifs: nifsService, - njss: &njssService, - fvs: &varService, - logger: logger, + DB: db, + ws: &wsService, + fs: &flowService, + ns: &nodeService, + es: &edgeService, + nrs: &nrsService, + nfs: &nfsService, + nfes: &nfesService, + nifs: nifsService, + njss: &njssService, + fvs: &varService, + logger: logger, + snapshotRegistry: newTestSnapshotRegistry(&nrsService, &nfsService, &nfesService, nifsService, &njssService), } userID := idwrap.NewNow() @@ -676,18 +692,19 @@ func TestFlowVersionSnapshot_Concurrency_Complex(t *testing.T) { logger := slog.New(slog.NewTextHandler(os.Stdout, nil)) svc := &FlowServiceV2RPC{ - DB: db, - ws: &wsService, - fs: &flowService, - ns: &nodeService, - es: &edgeService, - nrs: &nrsService, - nfs: &nfsService, - nfes: &nfesService, - nifs: nifsService, - njss: &njssService, - fvs: &varService, - logger: logger, + DB: db, + ws: &wsService, + fs: &flowService, + ns: &nodeService, + es: &edgeService, + nrs: &nrsService, + nfs: &nfsService, + nfes: &nfesService, + nifs: nifsService, + njss: &njssService, + fvs: &varService, + logger: logger, + snapshotRegistry: newTestSnapshotRegistry(&nrsService, &nfsService, &nfesService, nifsService, &njssService), } userID := idwrap.NewNow() diff --git a/packages/server/internal/api/rflowv2/rflowv2_flow.go b/packages/server/internal/api/rflowv2/rflowv2_flow.go index 34631224c..7d464c54d 100644 --- a/packages/server/internal/api/rflowv2/rflowv2_flow.go +++ b/packages/server/internal/api/rflowv2/rflowv2_flow.go @@ -533,21 +533,27 @@ func (s *FlowServiceV2RPC) FlowDuplicate(ctx context.Context, req *connect.Reque // Collect node details outside TX type nodeDetail struct { - node mflow.Node - request *mflow.NodeRequest - http *mhttp.HTTP - forNode *mflow.NodeFor - forEach *mflow.NodeForEach - ifNode *mflow.NodeIf - jsNode *mflow.NodeJS - aiNode *mflow.NodeAI - aiProvider *mflow.NodeAiProvider - memoryNode *mflow.NodeMemory + node mflow.Node + request *mflow.NodeRequest + http *mhttp.HTTP + forNode *mflow.NodeFor + forEach *mflow.NodeForEach + ifNode *mflow.NodeIf + jsNode *mflow.NodeJS + aiNode *mflow.NodeAI + aiProvider *mflow.NodeAiProvider + memoryNode *mflow.NodeMemory + graphqlNode *mflow.NodeGraphQL + wsConnectionNode *mflow.NodeWsConnection + wsSendNode *mflow.NodeWsSend + waitNode *mflow.NodeWait } details := make([]nodeDetail, 0, len(sourceNodes)) for _, n := range sourceNodes { detail := nodeDetail{node: n} switch n.NodeKind { + case mflow.NODE_KIND_MANUAL_START: + // No type-specific data for ManualStart case mflow.NODE_KIND_REQUEST: if d, err := s.nrs.GetNodeRequest(ctx, n.ID); err == nil && d != nil { detail.request = d @@ -591,6 +597,30 @@ func (s *FlowServiceV2RPC) FlowDuplicate(ctx context.Context, req *connect.Reque detail.memoryNode = d } } + case mflow.NODE_KIND_GRAPHQL: + if s.ngqs != nil { + if d, err := s.ngqs.GetNodeGraphQL(ctx, n.ID); err == nil { + detail.graphqlNode = d + } + } + case mflow.NODE_KIND_WS_CONNECTION: + if s.nwcs != nil { + if d, err := s.nwcs.GetNodeWsConnection(ctx, n.ID); err == nil { + detail.wsConnectionNode = d + } + } + case mflow.NODE_KIND_WS_SEND: + if s.nwss != nil { + if d, err := s.nwss.GetNodeWsSend(ctx, n.ID); err == nil { + detail.wsSendNode = d + } + } + case mflow.NODE_KIND_WAIT: + if s.nwaits != nil { + if d, err := s.nwaits.GetNodeWait(ctx, n.ID); err == nil && d != nil { + detail.waitNode = d + } + } } details = append(details, detail) } @@ -723,6 +753,38 @@ func (s *FlowServiceV2RPC) FlowDuplicate(ctx context.Context, req *connect.Reque return nil, connect.NewError(connect.CodeInternal, err) } } + if d.graphqlNode != nil && s.ngqs != nil { + node := *d.graphqlNode + node.FlowNodeID = newNodeID + ngqsWriter := s.ngqs.TX(tx) + if err := ngqsWriter.CreateNodeGraphQL(ctx, node); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + } + if d.wsConnectionNode != nil && s.nwcs != nil { + node := *d.wsConnectionNode + node.FlowNodeID = newNodeID + nwcsWriter := s.nwcs.TX(tx) + if err := nwcsWriter.CreateNodeWsConnection(ctx, node); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + } + if d.wsSendNode != nil && s.nwss != nil { + node := *d.wsSendNode + node.FlowNodeID = newNodeID + nwssWriter := s.nwss.TX(tx) + if err := nwssWriter.CreateNodeWsSend(ctx, node); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + } + if d.waitNode != nil && s.nwaits != nil { + node := *d.waitNode + node.FlowNodeID = newNodeID + nwaitsWriter := s.nwaits.TX(tx) + if err := nwaitsWriter.CreateNodeWait(ctx, node); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + } } // Track created edges for event publishing diff --git a/packages/server/internal/api/rflowv2/rflowv2_node_condition_test.go b/packages/server/internal/api/rflowv2/rflowv2_node_condition_test.go index 9af57a738..f1a523190 100644 --- a/packages/server/internal/api/rflowv2/rflowv2_node_condition_test.go +++ b/packages/server/internal/api/rflowv2/rflowv2_node_condition_test.go @@ -17,6 +17,7 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/internal/api/middleware/mwauth" "github.com/the-dev-tools/dev-tools/packages/server/pkg/dbtime" "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/flowbuilder" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/flowexec" "github.com/the-dev-tools/dev-tools/packages/server/pkg/http/resolver" "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" @@ -72,6 +73,11 @@ func TestNodeCondition_CRUD(t *testing.T) { nil, // NodeAiProviderService nil, // NodeMemoryService nil, // NodeGraphQLService + nil, // NodeWsConnectionService + nil, // NodeWsSendService + nil, // NodeWaitService + nil, // WebSocketService + nil, // WebSocketHeaderService nil, // GraphQLService nil, // GraphQLHeaderService &wsService, @@ -96,7 +102,7 @@ func TestNodeCondition_CRUD(t *testing.T) { es: &edgeService, fvs: &flowVarService, logger: logger, - builder: builder, + sessionFactory: &flowexec.LocalSessionFactory{Builder: builder}, } // Setup Data diff --git a/packages/server/internal/api/rflowv2/rflowv2_node_exec.go b/packages/server/internal/api/rflowv2/rflowv2_node_exec.go index 834659791..db49ae7df 100644 --- a/packages/server/internal/api/rflowv2/rflowv2_node_exec.go +++ b/packages/server/internal/api/rflowv2/rflowv2_node_exec.go @@ -10,14 +10,9 @@ import ( "connectrpc.com/connect" emptypb "google.golang.org/protobuf/types/known/emptypb" - "github.com/the-dev-tools/dev-tools/packages/server/internal/api/rgraphql" - "github.com/the-dev-tools/dev-tools/packages/server/internal/api/rhttp" - "github.com/the-dev-tools/dev-tools/packages/server/internal/converter" "github.com/the-dev-tools/dev-tools/packages/server/pkg/eventstream" "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" - "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mgraphql" - "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mhttp" flowv1 "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/flow/v1" ) @@ -161,71 +156,6 @@ func (s *FlowServiceV2RPC) publishExecutionEvent(eventType string, execution mfl }) } -func (s *FlowServiceV2RPC) publishHttpResponseEvent(eventType string, response mhttp.HTTPResponse, workspaceID idwrap.IDWrap) { - if s.httpResponseStream == nil { - return - } - responsePB := converter.ToAPIHttpResponse(response) - s.httpResponseStream.Publish(rhttp.HttpResponseTopic{WorkspaceID: workspaceID}, rhttp.HttpResponseEvent{ - Type: eventType, - HttpResponse: responsePB, - }) -} - -func (s *FlowServiceV2RPC) publishHttpResponseHeaderEvent(eventType string, header mhttp.HTTPResponseHeader, workspaceID idwrap.IDWrap) { - if s.httpResponseHeaderStream == nil { - return - } - headerPB := converter.ToAPIHttpResponseHeader(header) - s.httpResponseHeaderStream.Publish(rhttp.HttpResponseHeaderTopic{WorkspaceID: workspaceID}, rhttp.HttpResponseHeaderEvent{ - Type: eventType, - HttpResponseHeader: headerPB, - }) -} - -func (s *FlowServiceV2RPC) publishHttpResponseAssertEvent(eventType string, assert mhttp.HTTPResponseAssert, workspaceID idwrap.IDWrap) { - if s.httpResponseAssertStream == nil { - return - } - assertPB := converter.ToAPIHttpResponseAssert(assert) - s.httpResponseAssertStream.Publish(rhttp.HttpResponseAssertTopic{WorkspaceID: workspaceID}, rhttp.HttpResponseAssertEvent{ - Type: eventType, - HttpResponseAssert: assertPB, - }) -} - -func (s *FlowServiceV2RPC) publishGraphQLResponseEvent(eventType string, response mgraphql.GraphQLResponse, workspaceID idwrap.IDWrap) { - if s.graphqlResponseStream == nil { - return - } - responsePB := rgraphql.ToAPIGraphQLResponse(response) - s.graphqlResponseStream.Publish(rgraphql.GraphQLResponseTopic{WorkspaceID: workspaceID}, rgraphql.GraphQLResponseEvent{ - Type: eventType, - GraphQLResponse: responsePB, - }) -} - -func (s *FlowServiceV2RPC) publishGraphQLResponseHeaderEvent(eventType string, header mgraphql.GraphQLResponseHeader, workspaceID idwrap.IDWrap) { - if s.graphqlResponseHeaderStream == nil { - return - } - headerPB := rgraphql.ToAPIGraphQLResponseHeader(header) - s.graphqlResponseHeaderStream.Publish(rgraphql.GraphQLResponseHeaderTopic{WorkspaceID: workspaceID}, rgraphql.GraphQLResponseHeaderEvent{ - Type: eventType, - GraphQLResponseHeader: headerPB, - }) -} - -func (s *FlowServiceV2RPC) publishGraphQLResponseAssertEvent(eventType string, assert mgraphql.GraphQLResponseAssert, workspaceID idwrap.IDWrap) { - if s.graphqlResponseAssertStream == nil { - return - } - assertPB := rgraphql.ToAPIGraphQLResponseAssert(assert) - s.graphqlResponseAssertStream.Publish(rgraphql.GraphQLResponseAssertTopic{WorkspaceID: workspaceID}, rgraphql.GraphQLResponseAssertEvent{ - Type: eventType, - GraphQLResponseAssert: assertPB, - }) -} func (s *FlowServiceV2RPC) executionEventToSyncResponse( ctx context.Context, diff --git a/packages/server/internal/api/rflowv2/rflowv2_node_exec_test.go b/packages/server/internal/api/rflowv2/rflowv2_node_exec_test.go index d75541308..297edd26b 100644 --- a/packages/server/internal/api/rflowv2/rflowv2_node_exec_test.go +++ b/packages/server/internal/api/rflowv2/rflowv2_node_exec_test.go @@ -17,6 +17,7 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/internal/api/middleware/mwauth" "github.com/the-dev-tools/dev-tools/packages/server/pkg/dbtime" "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/flowbuilder" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/flowexec" "github.com/the-dev-tools/dev-tools/packages/server/pkg/http/resolver" "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" @@ -72,6 +73,11 @@ func TestNodeExecution_Collection(t *testing.T) { nil, // NodeAiProviderService nil, // NodeMemoryService nil, // NodeGraphQLService + nil, // NodeWsConnectionService + nil, // NodeWsSendService + nil, // NodeWaitService + nil, // WebSocketService + nil, // WebSocketHeaderService nil, // GraphQLService nil, // GraphQLHeaderService &wsService, @@ -96,7 +102,7 @@ func TestNodeExecution_Collection(t *testing.T) { es: &edgeService, fvs: &flowVarService, logger: logger, - builder: builder, + sessionFactory: &flowexec.LocalSessionFactory{Builder: builder}, } // Setup Data @@ -223,6 +229,11 @@ func TestNodeExecution_Collection_VersionFlow(t *testing.T) { nil, // NodeAiProviderService nil, // NodeMemoryService nil, // NodeGraphQLService + nil, // NodeWsConnectionService + nil, // NodeWsSendService + nil, // NodeWaitService + nil, // WebSocketService + nil, // WebSocketHeaderService nil, // GraphQLService nil, // GraphQLHeaderService &wsService, @@ -247,7 +258,7 @@ func TestNodeExecution_Collection_VersionFlow(t *testing.T) { es: &edgeService, fvs: &flowVarService, logger: logger, - builder: builder, + sessionFactory: &flowexec.LocalSessionFactory{Builder: builder}, } // Setup Data diff --git a/packages/server/internal/api/rflowv2/rflowv2_node_wait.go b/packages/server/internal/api/rflowv2/rflowv2_node_wait.go new file mode 100644 index 000000000..8197beb84 --- /dev/null +++ b/packages/server/internal/api/rflowv2/rflowv2_node_wait.go @@ -0,0 +1,426 @@ +//nolint:revive // exported +package rflowv2 + +import ( + "context" + "database/sql" + "errors" + "fmt" + "sync" + + "connectrpc.com/connect" + emptypb "google.golang.org/protobuf/types/known/emptypb" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/mutation" + flowv1 "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/flow/v1" +) + +type nodeWaitWithFlow struct { + nodeWait mflow.NodeWait + flowID idwrap.IDWrap + baseNode *mflow.Node +} + +func (s *FlowServiceV2RPC) NodeWaitCollection( + ctx context.Context, + _ *connect.Request[emptypb.Empty], +) (*connect.Response[flowv1.NodeWaitCollectionResponse], error) { + flows, err := s.listAccessibleFlows(ctx) + if err != nil { + return nil, err + } + + var items []*flowv1.NodeWait + for _, flow := range flows { + nodes, err := s.nsReader.GetNodesByFlowID(ctx, flow.ID) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return nil, connect.NewError(connect.CodeInternal, err) + } + for _, node := range nodes { + if node.NodeKind != mflow.NODE_KIND_WAIT { + continue + } + nodeWait, err := s.nwaits.GetNodeWait(ctx, node.ID) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + continue + } + return nil, connect.NewError(connect.CodeInternal, err) + } + if nodeWait == nil { + continue + } + items = append(items, serializeNodeWait(*nodeWait)) + } + } + + return connect.NewResponse(&flowv1.NodeWaitCollectionResponse{Items: items}), nil +} + +func (s *FlowServiceV2RPC) NodeWaitInsert( + ctx context.Context, + req *connect.Request[flowv1.NodeWaitInsertRequest], +) (*connect.Response[emptypb.Empty], error) { + type insertData struct { + nodeID idwrap.IDWrap + durationMs int64 + baseNode *mflow.Node + flowID idwrap.IDWrap + workspaceID idwrap.IDWrap + } + var validatedItems []insertData + + for _, item := range req.Msg.GetItems() { + nodeID, err := idwrap.NewFromBytes(item.GetNodeId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid node id: %w", err)) + } + + baseNode, _ := s.ns.GetNode(ctx, nodeID) + + var flowID idwrap.IDWrap + var workspaceID idwrap.IDWrap + if baseNode != nil { + flowID = baseNode.FlowID + flow, err := s.fsReader.GetFlow(ctx, flowID) + if err == nil { + workspaceID = flow.WorkspaceID + } + } + + validatedItems = append(validatedItems, insertData{ + nodeID: nodeID, + durationMs: item.GetDurationMs(), + baseNode: baseNode, + flowID: flowID, + workspaceID: workspaceID, + }) + } + + if len(validatedItems) == 0 { + return connect.NewResponse(&emptypb.Empty{}), nil + } + + mut := mutation.New(s.DB, mutation.WithPublisher(s.mutationPublisher())) + if err := mut.Begin(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer mut.Rollback() + + nwaitsWriter := s.nwaits.TX(mut.TX()) + + for _, data := range validatedItems { + nodeWait := mflow.NodeWait{ + FlowNodeID: data.nodeID, + DurationMs: data.durationMs, + } + + if err := nwaitsWriter.CreateNodeWait(ctx, nodeWait); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + if data.baseNode != nil { + mut.Track(mutation.Event{ + Entity: mutation.EntityFlowNodeWait, + Op: mutation.OpInsert, + ID: data.nodeID, + WorkspaceID: data.workspaceID, + ParentID: data.flowID, + Payload: nodeWaitWithFlow{ + nodeWait: nodeWait, + flowID: data.flowID, + baseNode: data.baseNode, + }, + }) + } + } + + if err := mut.Commit(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func (s *FlowServiceV2RPC) NodeWaitUpdate( + ctx context.Context, + req *connect.Request[flowv1.NodeWaitUpdateRequest], +) (*connect.Response[emptypb.Empty], error) { + type updateData struct { + nodeID idwrap.IDWrap + durationMs int64 + baseNode *mflow.Node + workspaceID idwrap.IDWrap + } + var validatedItems []updateData + + for _, item := range req.Msg.GetItems() { + nodeID, err := idwrap.NewFromBytes(item.GetNodeId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid node id: %w", err)) + } + + nodeModel, err := s.ensureNodeAccess(ctx, nodeID) + if err != nil { + return nil, err + } + + flow, err := s.fsReader.GetFlow(ctx, nodeModel.FlowID) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + existing, err := s.nwaits.GetNodeWait(ctx, nodeID) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + durationMs := existing.DurationMs + if item.DurationMs != nil { + durationMs = *item.DurationMs + } + + validatedItems = append(validatedItems, updateData{ + nodeID: nodeID, + durationMs: durationMs, + baseNode: nodeModel, + workspaceID: flow.WorkspaceID, + }) + } + + if len(validatedItems) == 0 { + return connect.NewResponse(&emptypb.Empty{}), nil + } + + mut := mutation.New(s.DB, mutation.WithPublisher(s.mutationPublisher())) + if err := mut.Begin(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer mut.Rollback() + + nwaitsWriter := s.nwaits.TX(mut.TX()) + + for _, data := range validatedItems { + nodeWait := mflow.NodeWait{ + FlowNodeID: data.nodeID, + DurationMs: data.durationMs, + } + + if err := nwaitsWriter.UpdateNodeWait(ctx, nodeWait); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + mut.Track(mutation.Event{ + Entity: mutation.EntityFlowNodeWait, + Op: mutation.OpUpdate, + ID: data.nodeID, + WorkspaceID: data.workspaceID, + ParentID: data.baseNode.FlowID, + Payload: nodeWaitWithFlow{ + nodeWait: nodeWait, + flowID: data.baseNode.FlowID, + baseNode: data.baseNode, + }, + }) + } + + if err := mut.Commit(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func (s *FlowServiceV2RPC) NodeWaitDelete( + ctx context.Context, + req *connect.Request[flowv1.NodeWaitDeleteRequest], +) (*connect.Response[emptypb.Empty], error) { + type deleteData struct { + nodeID idwrap.IDWrap + flowID idwrap.IDWrap + } + var validatedItems []deleteData + + for _, item := range req.Msg.GetItems() { + nodeID, err := idwrap.NewFromBytes(item.GetNodeId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid node id: %w", err)) + } + + nodeModel, err := s.ensureNodeAccess(ctx, nodeID) + if err != nil { + return nil, err + } + + validatedItems = append(validatedItems, deleteData{ + nodeID: nodeID, + flowID: nodeModel.FlowID, + }) + } + + if len(validatedItems) == 0 { + return connect.NewResponse(&emptypb.Empty{}), nil + } + + mut := mutation.New(s.DB, mutation.WithPublisher(s.mutationPublisher())) + if err := mut.Begin(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer mut.Rollback() + + for _, data := range validatedItems { + mut.Track(mutation.Event{ + Entity: mutation.EntityFlowNodeWait, + Op: mutation.OpDelete, + ID: data.nodeID, + ParentID: data.flowID, + }) + if err := mut.Queries().DeleteFlowNodeWait(ctx, data.nodeID); err != nil && !errors.Is(err, sql.ErrNoRows) { + return nil, connect.NewError(connect.CodeInternal, err) + } + } + + if err := mut.Commit(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func (s *FlowServiceV2RPC) NodeWaitSync( + ctx context.Context, + _ *connect.Request[emptypb.Empty], + stream *connect.ServerStream[flowv1.NodeWaitSyncResponse], +) error { + if stream == nil { + return connect.NewError(connect.CodeInternal, errors.New("stream is required")) + } + return s.streamNodeWaitSync(ctx, func(resp *flowv1.NodeWaitSyncResponse) error { + return stream.Send(resp) + }) +} + +func (s *FlowServiceV2RPC) streamNodeWaitSync( + ctx context.Context, + send func(*flowv1.NodeWaitSyncResponse) error, +) error { + if s.nodeStream == nil { + return connect.NewError(connect.CodeUnavailable, errors.New("node stream not configured")) + } + + var flowSet sync.Map + + filter := func(topic NodeTopic) bool { + if _, ok := flowSet.Load(topic.FlowID.String()); ok { + return true + } + if err := s.ensureFlowAccess(ctx, topic.FlowID); err != nil { + return false + } + flowSet.Store(topic.FlowID.String(), struct{}{}) + return true + } + + events, err := s.nodeStream.Subscribe(ctx, filter) + if err != nil { + return connect.NewError(connect.CodeInternal, err) + } + + for { + select { + case evt, ok := <-events: + if !ok { + return nil + } + resp, err := s.nodeWaitEventToSyncResponse(ctx, evt.Payload) + if err != nil { + return connect.NewError(connect.CodeInternal, fmt.Errorf("failed to convert wait node event: %w", err)) + } + if resp == nil { + continue + } + if err := send(resp); err != nil { + return err + } + case <-ctx.Done(): + return ctx.Err() + } + } +} + +func (s *FlowServiceV2RPC) nodeWaitEventToSyncResponse( + ctx context.Context, + evt NodeEvent, +) (*flowv1.NodeWaitSyncResponse, error) { + if evt.Node == nil { + return nil, nil + } + + if evt.Node.GetKind() != flowv1.NodeKind_NODE_KIND_WAIT { + return nil, nil + } + + nodeID, err := idwrap.NewFromBytes(evt.Node.GetNodeId()) + if err != nil { + return nil, fmt.Errorf("invalid node id: %w", err) + } + + nodeWait, err := s.nwaits.GetNodeWait(ctx, nodeID) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return nil, err + } + + var syncEvent *flowv1.NodeWaitSync + switch evt.Type { + case nodeEventInsert: + if nodeWait == nil { + return nil, nil + } + syncEvent = &flowv1.NodeWaitSync{ + Value: &flowv1.NodeWaitSync_ValueUnion{ + Kind: flowv1.NodeWaitSync_ValueUnion_KIND_INSERT, + Insert: &flowv1.NodeWaitSyncInsert{ + NodeId: nodeID.Bytes(), + DurationMs: nodeWait.DurationMs, + }, + }, + } + case nodeEventUpdate: + if nodeWait == nil { + return nil, nil + } + syncEvent = &flowv1.NodeWaitSync{ + Value: &flowv1.NodeWaitSync_ValueUnion{ + Kind: flowv1.NodeWaitSync_ValueUnion_KIND_UPDATE, + Update: &flowv1.NodeWaitSyncUpdate{ + NodeId: nodeID.Bytes(), + DurationMs: &nodeWait.DurationMs, + }, + }, + } + case nodeEventDelete: + syncEvent = &flowv1.NodeWaitSync{ + Value: &flowv1.NodeWaitSync_ValueUnion{ + Kind: flowv1.NodeWaitSync_ValueUnion_KIND_DELETE, + Delete: &flowv1.NodeWaitSyncDelete{ + NodeId: nodeID.Bytes(), + }, + }, + } + default: + return nil, nil + } + + return &flowv1.NodeWaitSyncResponse{ + Items: []*flowv1.NodeWaitSync{syncEvent}, + }, nil +} + +func serializeNodeWait(n mflow.NodeWait) *flowv1.NodeWait { + return &flowv1.NodeWait{ + NodeId: n.FlowNodeID.Bytes(), + DurationMs: n.DurationMs, + } +} diff --git a/packages/server/internal/api/rflowv2/rflowv2_node_ws_connection.go b/packages/server/internal/api/rflowv2/rflowv2_node_ws_connection.go new file mode 100644 index 000000000..9869370ec --- /dev/null +++ b/packages/server/internal/api/rflowv2/rflowv2_node_ws_connection.go @@ -0,0 +1,464 @@ +//nolint:revive // exported +package rflowv2 + +import ( + "context" + "database/sql" + "errors" + "fmt" + "sync" + + "connectrpc.com/connect" + emptypb "google.golang.org/protobuf/types/known/emptypb" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/mutation" + flowv1 "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/flow/v1" +) + +// NodeWsConnectionTopic identifies the flow whose WS Connection nodes are being published. +type NodeWsConnectionTopic struct { + FlowID idwrap.IDWrap +} + +// NodeWsConnectionEvent describes a WS Connection node change for sync streaming. +type NodeWsConnectionEvent struct { + Type string + FlowID idwrap.IDWrap + Node *flowv1.NodeWsConnection +} + +func (s *FlowServiceV2RPC) NodeWsConnectionCollection( + ctx context.Context, + _ *connect.Request[emptypb.Empty], +) (*connect.Response[flowv1.NodeWsConnectionCollectionResponse], error) { + flows, err := s.listAccessibleFlows(ctx) + if err != nil { + return nil, err + } + + var items []*flowv1.NodeWsConnection + for _, flow := range flows { + nodes, err := s.nsReader.GetNodesByFlowID(ctx, flow.ID) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return nil, connect.NewError(connect.CodeInternal, err) + } + for _, node := range nodes { + if node.NodeKind != mflow.NODE_KIND_WS_CONNECTION { + continue + } + nodeWsConn, err := s.nwcs.GetNodeWsConnection(ctx, node.ID) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + continue + } + return nil, connect.NewError(connect.CodeInternal, err) + } + if nodeWsConn == nil { + continue + } + items = append(items, serializeNodeWsConnection(*nodeWsConn)) + } + } + + return connect.NewResponse(&flowv1.NodeWsConnectionCollectionResponse{Items: items}), nil +} + +func (s *FlowServiceV2RPC) NodeWsConnectionInsert( + ctx context.Context, + req *connect.Request[flowv1.NodeWsConnectionInsertRequest], +) (*connect.Response[emptypb.Empty], error) { + type insertData struct { + nodeID idwrap.IDWrap + wsID *idwrap.IDWrap + baseNode *mflow.Node + flowID idwrap.IDWrap + workspaceID idwrap.IDWrap + } + var validatedItems []insertData + + for _, item := range req.Msg.GetItems() { + nodeID, err := idwrap.NewFromBytes(item.GetNodeId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid node id: %w", err)) + } + + var wsID *idwrap.IDWrap + if len(item.GetWebsocketId()) > 0 { + parsedID, err := idwrap.NewFromBytes(item.GetWebsocketId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid websocket id: %w", err)) + } + if !isZeroID(parsedID) { + wsID = &parsedID + } + } + + baseNode, _ := s.ns.GetNode(ctx, nodeID) + + var flowID idwrap.IDWrap + var workspaceID idwrap.IDWrap + if baseNode != nil { + flowID = baseNode.FlowID + flow, err := s.fsReader.GetFlow(ctx, flowID) + if err == nil { + workspaceID = flow.WorkspaceID + } + } + + validatedItems = append(validatedItems, insertData{ + nodeID: nodeID, + wsID: wsID, + baseNode: baseNode, + flowID: flowID, + workspaceID: workspaceID, + }) + } + + if len(validatedItems) == 0 { + return connect.NewResponse(&emptypb.Empty{}), nil + } + + mut := mutation.New(s.DB, mutation.WithPublisher(s.mutationPublisher())) + if err := mut.Begin(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer mut.Rollback() + + nwcsWriter := s.nwcs.TX(mut.TX()) + + for _, data := range validatedItems { + nodeWsConn := mflow.NodeWsConnection{ + FlowNodeID: data.nodeID, + WebSocketID: data.wsID, + } + + if err := nwcsWriter.CreateNodeWsConnection(ctx, nodeWsConn); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + if data.baseNode != nil { + mut.Track(mutation.Event{ + Entity: mutation.EntityFlowNodeWsConnection, + Op: mutation.OpInsert, + ID: data.nodeID, + WorkspaceID: data.workspaceID, + ParentID: data.flowID, + Payload: nodeWsConnectionWithFlow{ + nodeWsConnection: nodeWsConn, + flowID: data.flowID, + baseNode: data.baseNode, + }, + }) + } + } + + if err := mut.Commit(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func (s *FlowServiceV2RPC) NodeWsConnectionUpdate( + ctx context.Context, + req *connect.Request[flowv1.NodeWsConnectionUpdateRequest], +) (*connect.Response[emptypb.Empty], error) { + type updateData struct { + nodeID idwrap.IDWrap + wsID *idwrap.IDWrap + baseNode *mflow.Node + workspaceID idwrap.IDWrap + } + var validatedItems []updateData + + for _, item := range req.Msg.GetItems() { + nodeID, err := idwrap.NewFromBytes(item.GetNodeId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid node id: %w", err)) + } + + nodeModel, err := s.ensureNodeAccess(ctx, nodeID) + if err != nil { + return nil, err + } + + flow, err := s.fsReader.GetFlow(ctx, nodeModel.FlowID) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + var wsID *idwrap.IDWrap + if wsUnion := item.GetWebsocketId(); wsUnion != nil { + if wsUnion.GetKind() == flowv1.NodeWsConnectionUpdate_WebsocketIdUnion_KIND_VALUE { + if len(wsUnion.GetValue()) > 0 { + parsedID, err := idwrap.NewFromBytes(wsUnion.GetValue()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid websocket id: %w", err)) + } + if !isZeroID(parsedID) { + wsID = &parsedID + } + } + } + // KIND_UNSET leaves wsID as nil (clears it) + } else { + // No update to websocket_id — preserve existing + existing, err := s.nwcs.GetNodeWsConnection(ctx, nodeID) + if err == nil { + wsID = existing.WebSocketID + } + } + + validatedItems = append(validatedItems, updateData{ + nodeID: nodeID, + wsID: wsID, + baseNode: nodeModel, + workspaceID: flow.WorkspaceID, + }) + } + + if len(validatedItems) == 0 { + return connect.NewResponse(&emptypb.Empty{}), nil + } + + mut := mutation.New(s.DB, mutation.WithPublisher(s.mutationPublisher())) + if err := mut.Begin(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer mut.Rollback() + + nwcsWriter := s.nwcs.TX(mut.TX()) + + for _, data := range validatedItems { + nodeWsConn := mflow.NodeWsConnection{ + FlowNodeID: data.nodeID, + WebSocketID: data.wsID, + } + + if err := nwcsWriter.UpdateNodeWsConnection(ctx, nodeWsConn); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + mut.Track(mutation.Event{ + Entity: mutation.EntityFlowNodeWsConnection, + Op: mutation.OpUpdate, + ID: data.nodeID, + WorkspaceID: data.workspaceID, + ParentID: data.baseNode.FlowID, + Payload: nodeWsConnectionWithFlow{ + nodeWsConnection: nodeWsConn, + flowID: data.baseNode.FlowID, + baseNode: data.baseNode, + }, + }) + } + + if err := mut.Commit(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func (s *FlowServiceV2RPC) NodeWsConnectionDelete( + ctx context.Context, + req *connect.Request[flowv1.NodeWsConnectionDeleteRequest], +) (*connect.Response[emptypb.Empty], error) { + type deleteData struct { + nodeID idwrap.IDWrap + flowID idwrap.IDWrap + } + var validatedItems []deleteData + + for _, item := range req.Msg.GetItems() { + nodeID, err := idwrap.NewFromBytes(item.GetNodeId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid node id: %w", err)) + } + + nodeModel, err := s.ensureNodeAccess(ctx, nodeID) + if err != nil { + return nil, err + } + + validatedItems = append(validatedItems, deleteData{ + nodeID: nodeID, + flowID: nodeModel.FlowID, + }) + } + + if len(validatedItems) == 0 { + return connect.NewResponse(&emptypb.Empty{}), nil + } + + mut := mutation.New(s.DB, mutation.WithPublisher(s.mutationPublisher())) + if err := mut.Begin(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer mut.Rollback() + + for _, data := range validatedItems { + mut.Track(mutation.Event{ + Entity: mutation.EntityFlowNodeWsConnection, + Op: mutation.OpDelete, + ID: data.nodeID, + ParentID: data.flowID, + }) + if err := mut.Queries().DeleteFlowNodeWsConnection(ctx, data.nodeID); err != nil && !errors.Is(err, sql.ErrNoRows) { + return nil, connect.NewError(connect.CodeInternal, err) + } + } + + if err := mut.Commit(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func (s *FlowServiceV2RPC) NodeWsConnectionSync( + ctx context.Context, + _ *connect.Request[emptypb.Empty], + stream *connect.ServerStream[flowv1.NodeWsConnectionSyncResponse], +) error { + if stream == nil { + return connect.NewError(connect.CodeInternal, errors.New("stream is required")) + } + return s.streamNodeWsConnectionSync(ctx, func(resp *flowv1.NodeWsConnectionSyncResponse) error { + return stream.Send(resp) + }) +} + +func (s *FlowServiceV2RPC) streamNodeWsConnectionSync( + ctx context.Context, + send func(*flowv1.NodeWsConnectionSyncResponse) error, +) error { + if s.nodeStream == nil { + return connect.NewError(connect.CodeUnavailable, errors.New("node stream not configured")) + } + + var flowSet sync.Map + + filter := func(topic NodeTopic) bool { + if _, ok := flowSet.Load(topic.FlowID.String()); ok { + return true + } + if err := s.ensureFlowAccess(ctx, topic.FlowID); err != nil { + return false + } + flowSet.Store(topic.FlowID.String(), struct{}{}) + return true + } + + events, err := s.nodeStream.Subscribe(ctx, filter) + if err != nil { + return connect.NewError(connect.CodeInternal, err) + } + + for { + select { + case evt, ok := <-events: + if !ok { + return nil + } + resp, err := s.nodeWsConnectionEventToSyncResponse(ctx, evt.Payload) + if err != nil { + return connect.NewError(connect.CodeInternal, fmt.Errorf("failed to convert WS connection node event: %w", err)) + } + if resp == nil { + continue + } + if err := send(resp); err != nil { + return err + } + case <-ctx.Done(): + return ctx.Err() + } + } +} + +func (s *FlowServiceV2RPC) nodeWsConnectionEventToSyncResponse( + ctx context.Context, + evt NodeEvent, +) (*flowv1.NodeWsConnectionSyncResponse, error) { + if evt.Node == nil { + return nil, nil + } + + if evt.Node.GetKind() != flowv1.NodeKind_NODE_KIND_WS_CONNECTION { + return nil, nil + } + + nodeID, err := idwrap.NewFromBytes(evt.Node.GetNodeId()) + if err != nil { + return nil, fmt.Errorf("invalid node id: %w", err) + } + + nodeWsConn, err := s.nwcs.GetNodeWsConnection(ctx, nodeID) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, nil // Skip — version nodes don't have WsConnection records + } + return nil, err + } + + var syncEvent *flowv1.NodeWsConnectionSync + switch evt.Type { + case nodeEventInsert: + insert := &flowv1.NodeWsConnectionSyncInsert{ + NodeId: nodeID.Bytes(), + } + if nodeWsConn != nil && nodeWsConn.WebSocketID != nil && !isZeroID(*nodeWsConn.WebSocketID) { + insert.WebsocketId = nodeWsConn.WebSocketID.Bytes() + } + syncEvent = &flowv1.NodeWsConnectionSync{ + Value: &flowv1.NodeWsConnectionSync_ValueUnion{ + Kind: flowv1.NodeWsConnectionSync_ValueUnion_KIND_INSERT, + Insert: insert, + }, + } + case nodeEventUpdate: + update := &flowv1.NodeWsConnectionSyncUpdate{ + NodeId: nodeID.Bytes(), + } + if nodeWsConn != nil && nodeWsConn.WebSocketID != nil && !isZeroID(*nodeWsConn.WebSocketID) { + update.WebsocketId = &flowv1.NodeWsConnectionSyncUpdate_WebsocketIdUnion{ + Kind: flowv1.NodeWsConnectionSyncUpdate_WebsocketIdUnion_KIND_VALUE, + Value: nodeWsConn.WebSocketID.Bytes(), + } + } + syncEvent = &flowv1.NodeWsConnectionSync{ + Value: &flowv1.NodeWsConnectionSync_ValueUnion{ + Kind: flowv1.NodeWsConnectionSync_ValueUnion_KIND_UPDATE, + Update: update, + }, + } + case nodeEventDelete: + syncEvent = &flowv1.NodeWsConnectionSync{ + Value: &flowv1.NodeWsConnectionSync_ValueUnion{ + Kind: flowv1.NodeWsConnectionSync_ValueUnion_KIND_DELETE, + Delete: &flowv1.NodeWsConnectionSyncDelete{ + NodeId: nodeID.Bytes(), + }, + }, + } + default: + return nil, nil + } + + return &flowv1.NodeWsConnectionSyncResponse{ + Items: []*flowv1.NodeWsConnectionSync{syncEvent}, + }, nil +} + +func serializeNodeWsConnection(n mflow.NodeWsConnection) *flowv1.NodeWsConnection { + msg := &flowv1.NodeWsConnection{ + NodeId: n.FlowNodeID.Bytes(), + } + if n.WebSocketID != nil && !isZeroID(*n.WebSocketID) { + msg.WebsocketId = n.WebSocketID.Bytes() + } + return msg +} diff --git a/packages/server/internal/api/rflowv2/rflowv2_node_ws_send.go b/packages/server/internal/api/rflowv2/rflowv2_node_ws_send.go new file mode 100644 index 000000000..8da1796a8 --- /dev/null +++ b/packages/server/internal/api/rflowv2/rflowv2_node_ws_send.go @@ -0,0 +1,446 @@ +//nolint:revive // exported +package rflowv2 + +import ( + "context" + "database/sql" + "errors" + "fmt" + "sync" + + "connectrpc.com/connect" + emptypb "google.golang.org/protobuf/types/known/emptypb" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/mutation" + flowv1 "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/flow/v1" +) + +// NodeWsSendTopic identifies the flow whose WS Send nodes are being published. +type NodeWsSendTopic struct { + FlowID idwrap.IDWrap +} + +// NodeWsSendEvent describes a WS Send node change for sync streaming. +type NodeWsSendEvent struct { + Type string + FlowID idwrap.IDWrap + Node *flowv1.NodeWsSend +} + +func (s *FlowServiceV2RPC) NodeWsSendCollection( + ctx context.Context, + _ *connect.Request[emptypb.Empty], +) (*connect.Response[flowv1.NodeWsSendCollectionResponse], error) { + flows, err := s.listAccessibleFlows(ctx) + if err != nil { + return nil, err + } + + var items []*flowv1.NodeWsSend + for _, flow := range flows { + nodes, err := s.nsReader.GetNodesByFlowID(ctx, flow.ID) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return nil, connect.NewError(connect.CodeInternal, err) + } + for _, node := range nodes { + if node.NodeKind != mflow.NODE_KIND_WS_SEND { + continue + } + nodeWsSend, err := s.nwss.GetNodeWsSend(ctx, node.ID) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + continue + } + return nil, connect.NewError(connect.CodeInternal, err) + } + if nodeWsSend == nil { + continue + } + items = append(items, serializeNodeWsSend(*nodeWsSend)) + } + } + + return connect.NewResponse(&flowv1.NodeWsSendCollectionResponse{Items: items}), nil +} + +func (s *FlowServiceV2RPC) NodeWsSendInsert( + ctx context.Context, + req *connect.Request[flowv1.NodeWsSendInsertRequest], +) (*connect.Response[emptypb.Empty], error) { + type insertData struct { + nodeID idwrap.IDWrap + wsConnectionNodeName string + message string + baseNode *mflow.Node + flowID idwrap.IDWrap + workspaceID idwrap.IDWrap + } + var validatedItems []insertData + + for _, item := range req.Msg.GetItems() { + nodeID, err := idwrap.NewFromBytes(item.GetNodeId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid node id: %w", err)) + } + + baseNode, _ := s.ns.GetNode(ctx, nodeID) + + var flowID idwrap.IDWrap + var workspaceID idwrap.IDWrap + if baseNode != nil { + flowID = baseNode.FlowID + flow, err := s.fsReader.GetFlow(ctx, flowID) + if err == nil { + workspaceID = flow.WorkspaceID + } + } + + validatedItems = append(validatedItems, insertData{ + nodeID: nodeID, + wsConnectionNodeName: item.GetWsConnectionNodeName(), + message: item.GetMessage(), + baseNode: baseNode, + flowID: flowID, + workspaceID: workspaceID, + }) + } + + if len(validatedItems) == 0 { + return connect.NewResponse(&emptypb.Empty{}), nil + } + + mut := mutation.New(s.DB, mutation.WithPublisher(s.mutationPublisher())) + if err := mut.Begin(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer mut.Rollback() + + nwssWriter := s.nwss.TX(mut.TX()) + + for _, data := range validatedItems { + nodeWsSend := mflow.NodeWsSend{ + FlowNodeID: data.nodeID, + WsConnectionNodeName: data.wsConnectionNodeName, + Message: data.message, + } + + if err := nwssWriter.CreateNodeWsSend(ctx, nodeWsSend); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + if data.baseNode != nil { + mut.Track(mutation.Event{ + Entity: mutation.EntityFlowNodeWsSend, + Op: mutation.OpInsert, + ID: data.nodeID, + WorkspaceID: data.workspaceID, + ParentID: data.flowID, + Payload: nodeWsSendWithFlow{ + nodeWsSend: nodeWsSend, + flowID: data.flowID, + baseNode: data.baseNode, + }, + }) + } + } + + if err := mut.Commit(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func (s *FlowServiceV2RPC) NodeWsSendUpdate( + ctx context.Context, + req *connect.Request[flowv1.NodeWsSendUpdateRequest], +) (*connect.Response[emptypb.Empty], error) { + type updateData struct { + nodeID idwrap.IDWrap + wsConnectionNodeName string + message string + baseNode *mflow.Node + workspaceID idwrap.IDWrap + } + var validatedItems []updateData + + for _, item := range req.Msg.GetItems() { + nodeID, err := idwrap.NewFromBytes(item.GetNodeId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid node id: %w", err)) + } + + nodeModel, err := s.ensureNodeAccess(ctx, nodeID) + if err != nil { + return nil, err + } + + flow, err := s.fsReader.GetFlow(ctx, nodeModel.FlowID) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + // Get existing values to merge partial updates + existing, err := s.nwss.GetNodeWsSend(ctx, nodeID) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + wsConnName := existing.WsConnectionNodeName + if item.WsConnectionNodeName != nil { + wsConnName = *item.WsConnectionNodeName + } + msg := existing.Message + if item.Message != nil { + msg = *item.Message + } + + validatedItems = append(validatedItems, updateData{ + nodeID: nodeID, + wsConnectionNodeName: wsConnName, + message: msg, + baseNode: nodeModel, + workspaceID: flow.WorkspaceID, + }) + } + + if len(validatedItems) == 0 { + return connect.NewResponse(&emptypb.Empty{}), nil + } + + mut := mutation.New(s.DB, mutation.WithPublisher(s.mutationPublisher())) + if err := mut.Begin(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer mut.Rollback() + + nwssWriter := s.nwss.TX(mut.TX()) + + for _, data := range validatedItems { + nodeWsSend := mflow.NodeWsSend{ + FlowNodeID: data.nodeID, + WsConnectionNodeName: data.wsConnectionNodeName, + Message: data.message, + } + + if err := nwssWriter.UpdateNodeWsSend(ctx, nodeWsSend); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + mut.Track(mutation.Event{ + Entity: mutation.EntityFlowNodeWsSend, + Op: mutation.OpUpdate, + ID: data.nodeID, + WorkspaceID: data.workspaceID, + ParentID: data.baseNode.FlowID, + Payload: nodeWsSendWithFlow{ + nodeWsSend: nodeWsSend, + flowID: data.baseNode.FlowID, + baseNode: data.baseNode, + }, + }) + } + + if err := mut.Commit(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func (s *FlowServiceV2RPC) NodeWsSendDelete( + ctx context.Context, + req *connect.Request[flowv1.NodeWsSendDeleteRequest], +) (*connect.Response[emptypb.Empty], error) { + type deleteData struct { + nodeID idwrap.IDWrap + flowID idwrap.IDWrap + } + var validatedItems []deleteData + + for _, item := range req.Msg.GetItems() { + nodeID, err := idwrap.NewFromBytes(item.GetNodeId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid node id: %w", err)) + } + + nodeModel, err := s.ensureNodeAccess(ctx, nodeID) + if err != nil { + return nil, err + } + + validatedItems = append(validatedItems, deleteData{ + nodeID: nodeID, + flowID: nodeModel.FlowID, + }) + } + + if len(validatedItems) == 0 { + return connect.NewResponse(&emptypb.Empty{}), nil + } + + mut := mutation.New(s.DB, mutation.WithPublisher(s.mutationPublisher())) + if err := mut.Begin(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer mut.Rollback() + + for _, data := range validatedItems { + mut.Track(mutation.Event{ + Entity: mutation.EntityFlowNodeWsSend, + Op: mutation.OpDelete, + ID: data.nodeID, + ParentID: data.flowID, + }) + if err := mut.Queries().DeleteFlowNodeWsSend(ctx, data.nodeID); err != nil && !errors.Is(err, sql.ErrNoRows) { + return nil, connect.NewError(connect.CodeInternal, err) + } + } + + if err := mut.Commit(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func (s *FlowServiceV2RPC) NodeWsSendSync( + ctx context.Context, + _ *connect.Request[emptypb.Empty], + stream *connect.ServerStream[flowv1.NodeWsSendSyncResponse], +) error { + if stream == nil { + return connect.NewError(connect.CodeInternal, errors.New("stream is required")) + } + return s.streamNodeWsSendSync(ctx, func(resp *flowv1.NodeWsSendSyncResponse) error { + return stream.Send(resp) + }) +} + +func (s *FlowServiceV2RPC) streamNodeWsSendSync( + ctx context.Context, + send func(*flowv1.NodeWsSendSyncResponse) error, +) error { + if s.nodeStream == nil { + return connect.NewError(connect.CodeUnavailable, errors.New("node stream not configured")) + } + + var flowSet sync.Map + + filter := func(topic NodeTopic) bool { + if _, ok := flowSet.Load(topic.FlowID.String()); ok { + return true + } + if err := s.ensureFlowAccess(ctx, topic.FlowID); err != nil { + return false + } + flowSet.Store(topic.FlowID.String(), struct{}{}) + return true + } + + events, err := s.nodeStream.Subscribe(ctx, filter) + if err != nil { + return connect.NewError(connect.CodeInternal, err) + } + + for { + select { + case evt, ok := <-events: + if !ok { + return nil + } + resp, err := s.nodeWsSendEventToSyncResponse(ctx, evt.Payload) + if err != nil { + return connect.NewError(connect.CodeInternal, fmt.Errorf("failed to convert WS send node event: %w", err)) + } + if resp == nil { + continue + } + if err := send(resp); err != nil { + return err + } + case <-ctx.Done(): + return ctx.Err() + } + } +} + +func (s *FlowServiceV2RPC) nodeWsSendEventToSyncResponse( + ctx context.Context, + evt NodeEvent, +) (*flowv1.NodeWsSendSyncResponse, error) { + if evt.Node == nil { + return nil, nil + } + + if evt.Node.GetKind() != flowv1.NodeKind_NODE_KIND_WS_SEND { + return nil, nil + } + + nodeID, err := idwrap.NewFromBytes(evt.Node.GetNodeId()) + if err != nil { + return nil, fmt.Errorf("invalid node id: %w", err) + } + + nodeWsSend, err := s.nwss.GetNodeWsSend(ctx, nodeID) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return nil, err + } + + var syncEvent *flowv1.NodeWsSendSync + switch evt.Type { + case nodeEventInsert: + insert := &flowv1.NodeWsSendSyncInsert{ + NodeId: nodeID.Bytes(), + } + if nodeWsSend != nil { + insert.WsConnectionNodeName = nodeWsSend.WsConnectionNodeName + insert.Message = nodeWsSend.Message + } + syncEvent = &flowv1.NodeWsSendSync{ + Value: &flowv1.NodeWsSendSync_ValueUnion{ + Kind: flowv1.NodeWsSendSync_ValueUnion_KIND_INSERT, + Insert: insert, + }, + } + case nodeEventUpdate: + update := &flowv1.NodeWsSendSyncUpdate{ + NodeId: nodeID.Bytes(), + } + if nodeWsSend != nil { + update.WsConnectionNodeName = &nodeWsSend.WsConnectionNodeName + update.Message = &nodeWsSend.Message + } + syncEvent = &flowv1.NodeWsSendSync{ + Value: &flowv1.NodeWsSendSync_ValueUnion{ + Kind: flowv1.NodeWsSendSync_ValueUnion_KIND_UPDATE, + Update: update, + }, + } + case nodeEventDelete: + syncEvent = &flowv1.NodeWsSendSync{ + Value: &flowv1.NodeWsSendSync_ValueUnion{ + Kind: flowv1.NodeWsSendSync_ValueUnion_KIND_DELETE, + Delete: &flowv1.NodeWsSendSyncDelete{ + NodeId: nodeID.Bytes(), + }, + }, + } + default: + return nil, nil + } + + return &flowv1.NodeWsSendSyncResponse{ + Items: []*flowv1.NodeWsSendSync{syncEvent}, + }, nil +} + +func serializeNodeWsSend(n mflow.NodeWsSend) *flowv1.NodeWsSend { + return &flowv1.NodeWsSend{ + NodeId: n.FlowNodeID.Bytes(), + WsConnectionNodeName: n.WsConnectionNodeName, + Message: n.Message, + } +} diff --git a/packages/server/internal/api/rflowv2/rflowv2_sync_zero_value_test.go b/packages/server/internal/api/rflowv2/rflowv2_sync_zero_value_test.go index 4e0efb777..e113ec1f9 100644 --- a/packages/server/internal/api/rflowv2/rflowv2_sync_zero_value_test.go +++ b/packages/server/internal/api/rflowv2/rflowv2_sync_zero_value_test.go @@ -654,6 +654,6 @@ func TestNodeHttp_DeleteConfig(t *testing.T) { // Wait for sync event evt, ok := waitForEvent(t, eventChan, 2*time.Second) require.True(t, ok, "Should receive sync event for NodeHttp delete") - assert.Equal(t, nodeEventUpdate, evt.Type) + assert.Equal(t, nodeEventDelete, evt.Type) }) } diff --git a/packages/server/internal/api/rflowv2/rflowv2_testutil_test.go b/packages/server/internal/api/rflowv2/rflowv2_testutil_test.go index a644cb5f9..8ad0571fc 100644 --- a/packages/server/internal/api/rflowv2/rflowv2_testutil_test.go +++ b/packages/server/internal/api/rflowv2/rflowv2_testutil_test.go @@ -14,6 +14,7 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/internal/api/middleware/mwauth" "github.com/the-dev-tools/dev-tools/packages/server/pkg/dbtime" "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/flowbuilder" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/flowexec" "github.com/the-dev-tools/dev-tools/packages/server/pkg/http/resolver" "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" @@ -92,6 +93,11 @@ func NewRFlowTestContext(t *testing.T) *RFlowTestContext { nil, // NodeAiProviderService - not needed for non-AI tests nil, // NodeMemoryService - not needed for non-AI tests nil, // NodeGraphQLService - not needed for non-GraphQL tests + nil, // NodeWsConnectionService - not needed for non-WS tests + nil, // NodeWsSendService - not needed for non-WS tests + nil, // NodeWaitService - not needed for non-wait tests + nil, // WebSocketService - not needed for non-WS tests + nil, // WebSocketHeaderService - not needed for non-WS tests nil, // GraphQLService - not needed for non-GraphQL tests nil, // GraphQLHeaderService - not needed for non-GraphQL tests &wsService, @@ -121,7 +127,7 @@ func NewRFlowTestContext(t *testing.T) *RFlowTestContext { nifs: nifsService, njss: &njssService, logger: logger, - builder: builder, + sessionFactory: &flowexec.LocalSessionFactory{Builder: builder}, } // Create User diff --git a/packages/server/internal/api/rflowv2/sync_robustness_test.go b/packages/server/internal/api/rflowv2/sync_robustness_test.go index 6d34bb671..5a43cda66 100644 --- a/packages/server/internal/api/rflowv2/sync_robustness_test.go +++ b/packages/server/internal/api/rflowv2/sync_robustness_test.go @@ -51,7 +51,7 @@ func TestSync_DeleteRobustness(t *testing.T) { // Should still receive an event because we publish it to trigger re-fetch events := collectNodeEvents(registry.nodeEvents, 1, 100*time.Millisecond) require.Len(t, events, 1) - assert.Equal(t, nodeEventUpdate, events[0].Type) + assert.Equal(t, nodeEventDelete, events[0].Type) }) t.Run("NodeJs Delete robustness", func(t *testing.T) { diff --git a/packages/server/internal/api/rgraphql/rgraphql.go b/packages/server/internal/api/rgraphql/rgraphql.go index 4de3ef65c..184e9288b 100644 --- a/packages/server/internal/api/rgraphql/rgraphql.go +++ b/packages/server/internal/api/rgraphql/rgraphql.go @@ -53,6 +53,7 @@ type GraphQLHeaderTopic struct { type GraphQLHeaderEvent struct { Type string GraphQLHeader *graphqlv1.GraphQLHeader + IsDelta bool } type GraphQLResponseTopic struct { @@ -333,6 +334,7 @@ func (p *rgraphqlPublisher) publishGraphQLHeader(evt mutation.Event) { } var model *graphqlv1.GraphQLHeader var eventType string + isDelta := false switch evt.Op { case mutation.OpInsert, mutation.OpUpdate: @@ -343,8 +345,10 @@ func (p *rgraphqlPublisher) publishGraphQLHeader(evt mutation.Event) { } if h, ok := evt.Payload.(mgraphql.GraphQLHeader); ok { model = ToAPIGraphQLHeader(h) + isDelta = h.IsDelta } else if hp, ok := evt.Payload.(*mgraphql.GraphQLHeader); ok { model = ToAPIGraphQLHeader(*hp) + isDelta = hp.IsDelta } case mutation.OpDelete: eventType = eventTypeDelete @@ -355,6 +359,7 @@ func (p *rgraphqlPublisher) publishGraphQLHeader(evt mutation.Event) { p.streamers.GraphQLHeader.Publish(GraphQLHeaderTopic{WorkspaceID: evt.WorkspaceID}, GraphQLHeaderEvent{ Type: eventType, GraphQLHeader: model, + IsDelta: isDelta, }) } } diff --git a/packages/server/internal/api/rgraphql/rgraphql_converter.go b/packages/server/internal/api/rgraphql/rgraphql_converter.go index f28287e0f..226d1a55f 100644 --- a/packages/server/internal/api/rgraphql/rgraphql_converter.go +++ b/packages/server/internal/api/rgraphql/rgraphql_converter.go @@ -8,6 +8,7 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mgraphql" graphqlv1 "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/graph_q_l/v1" + globalv1 "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/global/v1" ) // Model -> Proto @@ -288,6 +289,226 @@ func graphqlDeltaSyncResponseFrom(event GraphQLEvent) *graphqlv1.GraphQLDeltaSyn return nil } +func graphqlHeaderDeltaSyncResponseFrom(event GraphQLHeaderEvent, header mgraphql.GraphQLHeader) *graphqlv1.GraphQLHeaderDeltaSyncResponse { + var value *graphqlv1.GraphQLHeaderDeltaSync_ValueUnion + + switch event.Type { + case eventTypeInsert: + delta := &graphqlv1.GraphQLHeaderDeltaSyncInsert{ + DeltaGraphqlHeaderId: header.ID.Bytes(), + GraphqlId: header.GraphQLID.Bytes(), + } + if header.ParentGraphQLHeaderID != nil { + delta.GraphqlHeaderId = header.ParentGraphQLHeaderID.Bytes() + } + if header.DeltaKey != nil { + delta.Key = header.DeltaKey + } + if header.DeltaValue != nil { + delta.Value = header.DeltaValue + } + if header.DeltaEnabled != nil { + delta.Enabled = header.DeltaEnabled + } + if header.DeltaDescription != nil { + delta.Description = header.DeltaDescription + } + if header.DeltaDisplayOrder != nil { + delta.Order = header.DeltaDisplayOrder + } + value = &graphqlv1.GraphQLHeaderDeltaSync_ValueUnion{ + Kind: graphqlv1.GraphQLHeaderDeltaSync_ValueUnion_KIND_INSERT, + Insert: delta, + } + case eventTypeUpdate: + delta := &graphqlv1.GraphQLHeaderDeltaSyncUpdate{ + DeltaGraphqlHeaderId: header.ID.Bytes(), + GraphqlId: header.GraphQLID.Bytes(), + } + if header.ParentGraphQLHeaderID != nil { + delta.GraphqlHeaderId = header.ParentGraphQLHeaderID.Bytes() + } + if header.DeltaKey != nil { + keyStr := *header.DeltaKey + delta.Key = &graphqlv1.GraphQLHeaderDeltaSyncUpdate_KeyUnion{ + Kind: graphqlv1.GraphQLHeaderDeltaSyncUpdate_KeyUnion_KIND_VALUE, + Value: &keyStr, + } + } else { + delta.Key = &graphqlv1.GraphQLHeaderDeltaSyncUpdate_KeyUnion{ + Kind: graphqlv1.GraphQLHeaderDeltaSyncUpdate_KeyUnion_KIND_UNSET, + Unset: globalv1.Unset_UNSET.Enum(), + } + } + if header.DeltaValue != nil { + valueStr := *header.DeltaValue + delta.Value = &graphqlv1.GraphQLHeaderDeltaSyncUpdate_ValueUnion{ + Kind: graphqlv1.GraphQLHeaderDeltaSyncUpdate_ValueUnion_KIND_VALUE, + Value: &valueStr, + } + } else { + delta.Value = &graphqlv1.GraphQLHeaderDeltaSyncUpdate_ValueUnion{ + Kind: graphqlv1.GraphQLHeaderDeltaSyncUpdate_ValueUnion_KIND_UNSET, + Unset: globalv1.Unset_UNSET.Enum(), + } + } + if header.DeltaEnabled != nil { + enabledBool := *header.DeltaEnabled + delta.Enabled = &graphqlv1.GraphQLHeaderDeltaSyncUpdate_EnabledUnion{ + Kind: graphqlv1.GraphQLHeaderDeltaSyncUpdate_EnabledUnion_KIND_VALUE, + Value: &enabledBool, + } + } else { + delta.Enabled = &graphqlv1.GraphQLHeaderDeltaSyncUpdate_EnabledUnion{ + Kind: graphqlv1.GraphQLHeaderDeltaSyncUpdate_EnabledUnion_KIND_UNSET, + Unset: globalv1.Unset_UNSET.Enum(), + } + } + if header.DeltaDescription != nil { + descStr := *header.DeltaDescription + delta.Description = &graphqlv1.GraphQLHeaderDeltaSyncUpdate_DescriptionUnion{ + Kind: graphqlv1.GraphQLHeaderDeltaSyncUpdate_DescriptionUnion_KIND_VALUE, + Value: &descStr, + } + } else { + delta.Description = &graphqlv1.GraphQLHeaderDeltaSyncUpdate_DescriptionUnion{ + Kind: graphqlv1.GraphQLHeaderDeltaSyncUpdate_DescriptionUnion_KIND_UNSET, + Unset: globalv1.Unset_UNSET.Enum(), + } + } + if header.DeltaDisplayOrder != nil { + orderFloat := *header.DeltaDisplayOrder + delta.Order = &graphqlv1.GraphQLHeaderDeltaSyncUpdate_OrderUnion{ + Kind: graphqlv1.GraphQLHeaderDeltaSyncUpdate_OrderUnion_KIND_VALUE, + Value: &orderFloat, + } + } else { + delta.Order = &graphqlv1.GraphQLHeaderDeltaSyncUpdate_OrderUnion{ + Kind: graphqlv1.GraphQLHeaderDeltaSyncUpdate_OrderUnion_KIND_UNSET, + Unset: globalv1.Unset_UNSET.Enum(), + } + } + value = &graphqlv1.GraphQLHeaderDeltaSync_ValueUnion{ + Kind: graphqlv1.GraphQLHeaderDeltaSync_ValueUnion_KIND_UPDATE, + Update: delta, + } + case eventTypeDelete: + value = &graphqlv1.GraphQLHeaderDeltaSync_ValueUnion{ + Kind: graphqlv1.GraphQLHeaderDeltaSync_ValueUnion_KIND_DELETE, + Delete: &graphqlv1.GraphQLHeaderDeltaSyncDelete{ + DeltaGraphqlHeaderId: header.ID.Bytes(), + }, + } + } + + if value == nil { + return nil + } + + return &graphqlv1.GraphQLHeaderDeltaSyncResponse{ + Items: []*graphqlv1.GraphQLHeaderDeltaSync{ + { + Value: value, + }, + }, + } +} + +func graphqlAssertDeltaSyncResponseFrom(event GraphQLAssertEvent, assert mgraphql.GraphQLAssert) *graphqlv1.GraphQLAssertDeltaSyncResponse { + var value *graphqlv1.GraphQLAssertDeltaSync_ValueUnion + + switch event.Type { + case eventTypeInsert: + delta := &graphqlv1.GraphQLAssertDeltaSyncInsert{ + DeltaGraphqlAssertId: assert.ID.Bytes(), + GraphqlId: assert.GraphQLID.Bytes(), + } + if assert.ParentGraphQLAssertID != nil { + delta.GraphqlAssertId = assert.ParentGraphQLAssertID.Bytes() + } + if assert.DeltaValue != nil { + delta.Value = assert.DeltaValue + } + if assert.DeltaEnabled != nil { + delta.Enabled = assert.DeltaEnabled + } + if assert.DeltaDisplayOrder != nil { + delta.Order = assert.DeltaDisplayOrder + } + value = &graphqlv1.GraphQLAssertDeltaSync_ValueUnion{ + Kind: graphqlv1.GraphQLAssertDeltaSync_ValueUnion_KIND_INSERT, + Insert: delta, + } + case eventTypeUpdate: + delta := &graphqlv1.GraphQLAssertDeltaSyncUpdate{ + DeltaGraphqlAssertId: assert.ID.Bytes(), + GraphqlId: assert.GraphQLID.Bytes(), + } + if assert.ParentGraphQLAssertID != nil { + delta.GraphqlAssertId = assert.ParentGraphQLAssertID.Bytes() + } + if assert.DeltaValue != nil { + valueStr := *assert.DeltaValue + delta.Value = &graphqlv1.GraphQLAssertDeltaSyncUpdate_ValueUnion{ + Kind: graphqlv1.GraphQLAssertDeltaSyncUpdate_ValueUnion_KIND_VALUE, + Value: &valueStr, + } + } else { + delta.Value = &graphqlv1.GraphQLAssertDeltaSyncUpdate_ValueUnion{ + Kind: graphqlv1.GraphQLAssertDeltaSyncUpdate_ValueUnion_KIND_UNSET, + Unset: globalv1.Unset_UNSET.Enum(), + } + } + if assert.DeltaEnabled != nil { + enabledBool := *assert.DeltaEnabled + delta.Enabled = &graphqlv1.GraphQLAssertDeltaSyncUpdate_EnabledUnion{ + Kind: graphqlv1.GraphQLAssertDeltaSyncUpdate_EnabledUnion_KIND_VALUE, + Value: &enabledBool, + } + } else { + delta.Enabled = &graphqlv1.GraphQLAssertDeltaSyncUpdate_EnabledUnion{ + Kind: graphqlv1.GraphQLAssertDeltaSyncUpdate_EnabledUnion_KIND_UNSET, + Unset: globalv1.Unset_UNSET.Enum(), + } + } + if assert.DeltaDisplayOrder != nil { + orderFloat := *assert.DeltaDisplayOrder + delta.Order = &graphqlv1.GraphQLAssertDeltaSyncUpdate_OrderUnion{ + Kind: graphqlv1.GraphQLAssertDeltaSyncUpdate_OrderUnion_KIND_VALUE, + Value: &orderFloat, + } + } else { + delta.Order = &graphqlv1.GraphQLAssertDeltaSyncUpdate_OrderUnion{ + Kind: graphqlv1.GraphQLAssertDeltaSyncUpdate_OrderUnion_KIND_UNSET, + Unset: globalv1.Unset_UNSET.Enum(), + } + } + value = &graphqlv1.GraphQLAssertDeltaSync_ValueUnion{ + Kind: graphqlv1.GraphQLAssertDeltaSync_ValueUnion_KIND_UPDATE, + Update: delta, + } + case eventTypeDelete: + value = &graphqlv1.GraphQLAssertDeltaSync_ValueUnion{ + Kind: graphqlv1.GraphQLAssertDeltaSync_ValueUnion_KIND_DELETE, + Delete: &graphqlv1.GraphQLAssertDeltaSyncDelete{ + DeltaGraphqlAssertId: assert.ID.Bytes(), + }, + } + } + + if value == nil { + return nil + } + + return &graphqlv1.GraphQLAssertDeltaSyncResponse{ + Items: []*graphqlv1.GraphQLAssertDeltaSync{ + { + Value: value, + }, + }, + } +} + // graphqlAssertSyncResponseFrom converts GraphQLAssertEvent to GraphQLAssertSync response func graphqlAssertSyncResponseFrom(event GraphQLAssertEvent) *graphqlv1.GraphQLAssertSyncResponse { var value *graphqlv1.GraphQLAssertSync_ValueUnion diff --git a/packages/server/internal/api/rgraphql/rgraphql_crud_assert.go b/packages/server/internal/api/rgraphql/rgraphql_crud_assert.go index 746bf4097..118fc452b 100644 --- a/packages/server/internal/api/rgraphql/rgraphql_crud_assert.go +++ b/packages/server/internal/api/rgraphql/rgraphql_crud_assert.go @@ -830,8 +830,62 @@ func (s *GraphQLServiceRPC) GraphQLAssertDeltaDelete(ctx context.Context, req *c } func (s *GraphQLServiceRPC) GraphQLAssertDeltaSync(ctx context.Context, req *connect.Request[emptypb.Empty], stream *connect.ServerStream[graphqlv1.GraphQLAssertDeltaSyncResponse]) error { - // TODO: Implement streaming delta sync - return nil + userID, err := mwauth.GetContextUserID(ctx) + if err != nil { + return connect.NewError(connect.CodeUnauthenticated, err) + } + + return s.streamGraphQLAssertDeltaSync(ctx, userID, stream.Send) +} + +func (s *GraphQLServiceRPC) streamGraphQLAssertDeltaSync(ctx context.Context, userID idwrap.IDWrap, send func(*graphqlv1.GraphQLAssertDeltaSyncResponse) error) error { + var workspaceSet sync.Map + + filter := func(topic GraphQLAssertTopic) bool { + if _, ok := workspaceSet.Load(topic.WorkspaceID.String()); ok { + return true + } + belongs, err := s.us.CheckUserBelongsToWorkspace(ctx, userID, topic.WorkspaceID) + if err != nil || !belongs { + return false + } + workspaceSet.Store(topic.WorkspaceID.String(), struct{}{}) + return true + } + + events, err := s.streamers.GraphQLAssert.Subscribe(ctx, filter) + if err != nil { + return connect.NewError(connect.CodeInternal, err) + } + + for { + select { + case evt, ok := <-events: + if !ok { + return nil + } + if !evt.Payload.IsDelta { + continue + } + assertID, err := idwrap.NewFromBytes(evt.Payload.GraphQLAssert.GetGraphqlAssertId()) + if err != nil { + continue + } + assertRecord, err := s.graphqlAssertService.GetByID(ctx, assertID) + if err != nil { + continue + } + resp := graphqlAssertDeltaSyncResponseFrom(evt.Payload, *assertRecord) + if resp == nil { + continue + } + if err := send(resp); err != nil { + return err + } + case <-ctx.Done(): + return ctx.Err() + } + } } // Helper functions for null conversions diff --git a/packages/server/internal/api/rgraphql/rgraphql_crud_header_delta.go b/packages/server/internal/api/rgraphql/rgraphql_crud_header_delta.go index 5789f81c3..2271dbf53 100644 --- a/packages/server/internal/api/rgraphql/rgraphql_crud_header_delta.go +++ b/packages/server/internal/api/rgraphql/rgraphql_crud_header_delta.go @@ -4,6 +4,7 @@ package rgraphql import ( "context" "errors" + "sync" "connectrpc.com/connect" "google.golang.org/protobuf/types/known/emptypb" @@ -335,9 +336,60 @@ func (s *GraphQLServiceRPC) GraphQLHeaderDeltaDelete(ctx context.Context, req *c // GraphQLHeaderDeltaSync streams delta header changes to the client func (s *GraphQLServiceRPC) GraphQLHeaderDeltaSync(ctx context.Context, req *connect.Request[emptypb.Empty], stream *connect.ServerStream[graphqlv1.GraphQLHeaderDeltaSyncResponse]) error { - // TODO: Implement streaming delta sync with proper event filtering - // Similar to GraphQLDeltaSync, this requires a delta-specific event stream - // that only publishes delta-related changes to prevent flooding clients - // with non-delta header updates. - return nil + userID, err := mwauth.GetContextUserID(ctx) + if err != nil { + return connect.NewError(connect.CodeUnauthenticated, err) + } + + return s.streamGraphQLHeaderDeltaSync(ctx, userID, stream.Send) +} + +func (s *GraphQLServiceRPC) streamGraphQLHeaderDeltaSync(ctx context.Context, userID idwrap.IDWrap, send func(*graphqlv1.GraphQLHeaderDeltaSyncResponse) error) error { + var workspaceSet sync.Map + + filter := func(topic GraphQLHeaderTopic) bool { + if _, ok := workspaceSet.Load(topic.WorkspaceID.String()); ok { + return true + } + belongs, err := s.us.CheckUserBelongsToWorkspace(ctx, userID, topic.WorkspaceID) + if err != nil || !belongs { + return false + } + workspaceSet.Store(topic.WorkspaceID.String(), struct{}{}) + return true + } + + events, err := s.streamers.GraphQLHeader.Subscribe(ctx, filter) + if err != nil { + return connect.NewError(connect.CodeInternal, err) + } + + for { + select { + case evt, ok := <-events: + if !ok { + return nil + } + headerID, err := idwrap.NewFromBytes(evt.Payload.GraphQLHeader.GetGraphqlHeaderId()) + if err != nil { + continue + } + headerRecord, err := s.headerService.GetByID(ctx, headerID) + if err != nil { + continue + } + if !headerRecord.IsDelta { + continue + } + resp := graphqlHeaderDeltaSyncResponseFrom(evt.Payload, *headerRecord) + if resp == nil { + continue + } + if err := send(resp); err != nil { + return err + } + case <-ctx.Done(): + return ctx.Err() + } + } } diff --git a/packages/server/internal/api/rimportv2/integration_test.go b/packages/server/internal/api/rimportv2/integration_test.go index 0d6dd678f..461ad2133 100644 --- a/packages/server/internal/api/rimportv2/integration_test.go +++ b/packages/server/internal/api/rimportv2/integration_test.go @@ -1788,6 +1788,7 @@ flows: require.NotEmpty(t, forEachNode.IterExpression, "ForEach node should have items expression for node %s", node.Name) t.Logf(" ForEach Node: Items=%q", forEachNode.IterExpression) forEachNodesFound++ + default: } } @@ -1976,6 +1977,7 @@ flows: if fe != nil { gotForEach++ } + default: } } diff --git a/packages/server/internal/api/rimportv2/integrity.go b/packages/server/internal/api/rimportv2/integrity.go index c8eb60224..4b39052af 100644 --- a/packages/server/internal/api/rimportv2/integrity.go +++ b/packages/server/internal/api/rimportv2/integrity.go @@ -108,6 +108,9 @@ func ValidateImportIntegrity( case mfile.ContentTypeGraphQL: // GraphQL files reference GraphQL IDs - validation not yet implemented continue + case mfile.ContentTypeWebSocket: + // WebSocket files reference WebSocket IDs - validation not yet implemented + continue case mfile.ContentTypeFlow, mfile.ContentTypeFolder, mfile.ContentTypeCredential: // Flow files reference flow IDs - we could validate these too // Folders don't have ContentID @@ -178,6 +181,9 @@ func ValidateTranslationResult(result *TranslationResult) *IntegrityReport { case mfile.ContentTypeGraphQL: // GraphQL files reference GraphQL IDs - validation not yet implemented continue + case mfile.ContentTypeWebSocket: + // WebSocket files reference WebSocket IDs - validation not yet implemented + continue case mfile.ContentTypeFlow, mfile.ContentTypeFolder, mfile.ContentTypeCredential: continue } diff --git a/packages/server/internal/api/rimportv2/rimportv2_event.go b/packages/server/internal/api/rimportv2/rimportv2_event.go index ced5dbc86..9b6ca468a 100644 --- a/packages/server/internal/api/rimportv2/rimportv2_event.go +++ b/packages/server/internal/api/rimportv2/rimportv2_event.go @@ -74,7 +74,7 @@ func (h *ImportV2RPC) publishEvents(ctx context.Context, results *ImportResults) kind = eventsync.KindFlowFile case mfile.ContentTypeFolder: kind = eventsync.KindFolder - case mfile.ContentTypeHTTP, mfile.ContentTypeHTTPDelta, mfile.ContentTypeCredential, mfile.ContentTypeGraphQL: + case mfile.ContentTypeHTTP, mfile.ContentTypeHTTPDelta, mfile.ContentTypeCredential, mfile.ContentTypeGraphQL, mfile.ContentTypeWebSocket: // Keep default KindHTTPFile } diff --git a/packages/server/internal/api/rreference/rreference.go b/packages/server/internal/api/rreference/rreference.go index 4f0ad9fe0..08ec536d1 100644 --- a/packages/server/internal/api/rreference/rreference.go +++ b/packages/server/internal/api/rreference/rreference.go @@ -563,8 +563,9 @@ func (c *ReferenceServiceRPC) HandleNode(ctx context.Context, nodeID idwrap.IDWr if err := appendNodeRef(nodeVarRef, fmt.Sprintf("node %q request schema", node.Name)); err != nil { return nil, connect.NewError(connect.CodeInternal, err) } + default: + // Other node types (JS, CONDITION, etc.) don't have default schemas } - // Other node types (JS, CONDITION, etc.) don't have default schemas } return nodeRefs, nil @@ -860,6 +861,8 @@ func (c *ReferenceServiceRPC) ReferenceCompletion(ctx context.Context, req *conn "metrics": map[string]interface{}{}, } creator.AddWithKey(node.Name, nodeVarsMap) + default: + // Other node types don't have default schemas for completion } } @@ -1014,6 +1017,8 @@ func (c *ReferenceServiceRPC) ReferenceCompletion(ctx context.Context, req *conn "duration": 0, }) } + default: + // Other node types don't have self-reference schemas } } } @@ -1297,8 +1302,9 @@ func (c *ReferenceServiceRPC) ReferenceValue(ctx context.Context, req *connect.R }, } lookup.AddWithKey(node.Name, nodeVarsMap) + default: + // Other node types (JS, CONDITION, etc.) don't have default schemas } - // Other node types (JS, CONDITION, etc.) don't have default schemas } // Add self-reference for REQUEST, FOR, and FOREACH nodes so they can reference their own variables @@ -1412,6 +1418,8 @@ func (c *ReferenceServiceRPC) ReferenceValue(ctx context.Context, req *connect.R "duration": 0, }) } + default: + // Other node types don't have self-reference schemas } } } diff --git a/packages/server/internal/api/rwebsocket/rwebsocket.go b/packages/server/internal/api/rwebsocket/rwebsocket.go new file mode 100644 index 000000000..7c8eae00f --- /dev/null +++ b/packages/server/internal/api/rwebsocket/rwebsocket.go @@ -0,0 +1,790 @@ +package rwebsocket + +import ( + "context" + "database/sql" + "errors" + "sync" + "time" + + "connectrpc.com/connect" + "google.golang.org/protobuf/types/known/emptypb" + + devtoolsdb "github.com/the-dev-tools/dev-tools/packages/db" + "github.com/the-dev-tools/dev-tools/packages/server/internal/api" + "github.com/the-dev-tools/dev-tools/packages/server/internal/api/middleware/mwauth" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/eventstream" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mwebsocket" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/permcheck" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/suser" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/swebsocket" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sworkspace" + apiv1 "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/web_socket/v1" + "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/web_socket/v1/web_socketv1connect" +) + +const ( + eventTypeInsert = "insert" + eventTypeUpdate = "update" + eventTypeDelete = "delete" +) + +type WebSocketTopic struct { + WorkspaceID idwrap.IDWrap +} + +type WebSocketEvent struct { + Type string + WebSocket *apiv1.WebSocket +} + +type WebSocketHeaderTopic struct { + WorkspaceID idwrap.IDWrap +} + +type WebSocketHeaderEvent struct { + Type string + WebSocketHeader *apiv1.WebSocketHeader +} + +// WebSocketRPC handles WebSocket CRUD operations and real-time sync. +type WebSocketRPC struct { + web_socketv1connect.UnimplementedWebSocketServiceHandler + + DB *sql.DB + ws swebsocket.WebSocketService + wsh swebsocket.WebSocketHeaderService + us suser.UserService + wk sworkspace.WorkspaceService + wsStream eventstream.SyncStreamer[WebSocketTopic, WebSocketEvent] + wshStream eventstream.SyncStreamer[WebSocketHeaderTopic, WebSocketHeaderEvent] +} + +type Deps struct { + DB *sql.DB + WS swebsocket.WebSocketService + WSH swebsocket.WebSocketHeaderService + US suser.UserService + Workspace sworkspace.WorkspaceService + WSStream eventstream.SyncStreamer[WebSocketTopic, WebSocketEvent] + WSHStream eventstream.SyncStreamer[WebSocketHeaderTopic, WebSocketHeaderEvent] +} + +func New(deps Deps) WebSocketRPC { + return WebSocketRPC{ + DB: deps.DB, + ws: deps.WS, + wsh: deps.WSH, + us: deps.US, + wk: deps.Workspace, + wsStream: deps.WSStream, + wshStream: deps.WSHStream, + } +} + +func CreateService(srv WebSocketRPC, options []connect.HandlerOption) (*api.Service, error) { + path, handler := web_socketv1connect.NewWebSocketServiceHandler(&srv, options...) + return &api.Service{Path: path, Handler: handler}, nil +} + +func (s *WebSocketRPC) WebSocketCollection(ctx context.Context, _ *connect.Request[emptypb.Empty]) (*connect.Response[apiv1.WebSocketCollectionResponse], error) { + userID, err := mwauth.GetContextUserID(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeUnauthenticated, err) + } + + workspaces, err := s.wk.GetWorkspacesByUserIDOrdered(ctx, userID) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + var items []*apiv1.WebSocket + for _, workspace := range workspaces { + wsList, err := s.ws.GetByWorkspaceID(ctx, workspace.ID) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + for _, ws := range wsList { + items = append(items, &apiv1.WebSocket{ + WebsocketId: ws.ID.Bytes(), + Name: ws.Name, + Url: ws.Url, + }) + } + } + + return connect.NewResponse(&apiv1.WebSocketCollectionResponse{Items: items}), nil +} + +func (s *WebSocketRPC) WebSocketSync(ctx context.Context, _ *connect.Request[emptypb.Empty], stream *connect.ServerStream[apiv1.WebSocketSyncResponse]) error { + userID, err := mwauth.GetContextUserID(ctx) + if err != nil { + return connect.NewError(connect.CodeUnauthenticated, err) + } + + var workspaceSet sync.Map + filter := func(topic WebSocketTopic) bool { + if _, ok := workspaceSet.Load(topic.WorkspaceID.String()); ok { + return true + } + belongs, err := s.us.CheckUserBelongsToWorkspace(ctx, userID, topic.WorkspaceID) + if err != nil || !belongs { + return false + } + workspaceSet.Store(topic.WorkspaceID.String(), struct{}{}) + return true + } + + events, err := s.wsStream.Subscribe(ctx, filter) + if err != nil { + return connect.NewError(connect.CodeInternal, err) + } + + for { + select { + case evt, ok := <-events: + if !ok { + return nil + } + resp := webSocketSyncResponseFrom(evt.Payload) + if resp == nil { + continue + } + if err := stream.Send(resp); err != nil { + return err + } + case <-ctx.Done(): + return ctx.Err() + } + } +} + +func (s *WebSocketRPC) WebSocketHeaderCollection(ctx context.Context, _ *connect.Request[emptypb.Empty]) (*connect.Response[apiv1.WebSocketHeaderCollectionResponse], error) { + userID, err := mwauth.GetContextUserID(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeUnauthenticated, err) + } + + workspaces, err := s.wk.GetWorkspacesByUserIDOrdered(ctx, userID) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + var items []*apiv1.WebSocketHeader + for _, workspace := range workspaces { + wsList, err := s.ws.GetByWorkspaceID(ctx, workspace.ID) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + for _, ws := range wsList { + headers, err := s.wsh.GetByWebSocketID(ctx, ws.ID) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + for _, h := range headers { + items = append(items, toAPIWebSocketHeader(h)) + } + } + } + + return connect.NewResponse(&apiv1.WebSocketHeaderCollectionResponse{Items: items}), nil +} + +func (s *WebSocketRPC) WebSocketHeaderSync(ctx context.Context, _ *connect.Request[emptypb.Empty], stream *connect.ServerStream[apiv1.WebSocketHeaderSyncResponse]) error { + userID, err := mwauth.GetContextUserID(ctx) + if err != nil { + return connect.NewError(connect.CodeUnauthenticated, err) + } + + var workspaceSet sync.Map + filter := func(topic WebSocketHeaderTopic) bool { + if _, ok := workspaceSet.Load(topic.WorkspaceID.String()); ok { + return true + } + belongs, err := s.us.CheckUserBelongsToWorkspace(ctx, userID, topic.WorkspaceID) + if err != nil || !belongs { + return false + } + workspaceSet.Store(topic.WorkspaceID.String(), struct{}{}) + return true + } + + events, err := s.wshStream.Subscribe(ctx, filter) + if err != nil { + return connect.NewError(connect.CodeInternal, err) + } + + for { + select { + case evt, ok := <-events: + if !ok { + return nil + } + resp := webSocketHeaderSyncResponseFrom(evt.Payload) + if resp == nil { + continue + } + if err := stream.Send(resp); err != nil { + return err + } + case <-ctx.Done(): + return ctx.Err() + } + } +} + +func (s *WebSocketRPC) WebSocketInsert(ctx context.Context, req *connect.Request[apiv1.WebSocketInsertRequest]) (*connect.Response[emptypb.Empty], error) { + if len(req.Msg.GetItems()) == 0 { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("at least one item must be provided")) + } + + // FETCH + userID, err := mwauth.GetContextUserID(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeUnauthenticated, err) + } + + workspaces, err := s.wk.GetWorkspacesByUserIDOrdered(ctx, userID) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + if len(workspaces) == 0 { + return nil, connect.NewError(connect.CodeNotFound, errors.New("user has no workspaces")) + } + defaultWorkspaceID := workspaces[0].ID + + // CHECK + rpcErr := permcheck.CheckPerm(mwauth.CheckOwnerWorkspace(ctx, s.us, defaultWorkspaceID)) + if rpcErr != nil { + return nil, rpcErr + } + + // Parse items + now := time.Now().Unix() + items := make([]mwebsocket.WebSocket, 0, len(req.Msg.Items)) + for _, item := range req.Msg.Items { + if len(item.GetWebsocketId()) == 0 { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("websocket_id is required")) + } + wsID, err := idwrap.NewFromBytes(item.GetWebsocketId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + items = append(items, mwebsocket.WebSocket{ + ID: wsID, + WorkspaceID: defaultWorkspaceID, + Name: item.GetName(), + Url: item.GetUrl(), + CreatedAt: now, + UpdatedAt: now, + }) + } + + // ACT + tx, err := s.DB.BeginTx(ctx, nil) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer devtoolsdb.TxnRollback(tx) + + wsTx := s.ws.TX(tx) + for i := range items { + if err := wsTx.Create(ctx, &items[i]); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + } + + if err := tx.Commit(); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + for _, item := range items { + s.wsStream.Publish(WebSocketTopic{WorkspaceID: item.WorkspaceID}, WebSocketEvent{ + Type: eventTypeInsert, + WebSocket: &apiv1.WebSocket{ + WebsocketId: item.ID.Bytes(), + Name: item.Name, + Url: item.Url, + }, + }) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func (s *WebSocketRPC) WebSocketUpdate(ctx context.Context, req *connect.Request[apiv1.WebSocketUpdateRequest]) (*connect.Response[emptypb.Empty], error) { + if len(req.Msg.GetItems()) == 0 { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("at least one item must be provided")) + } + + // FETCH + CHECK + updates := make([]mwebsocket.WebSocket, 0, len(req.Msg.Items)) + for _, item := range req.Msg.Items { + if len(item.GetWebsocketId()) == 0 { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("websocket_id is required")) + } + wsID, err := idwrap.NewFromBytes(item.GetWebsocketId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + existing, err := s.ws.Get(ctx, wsID) + if err != nil { + if errors.Is(err, swebsocket.ErrNoWebSocketFound) { + return nil, connect.NewError(connect.CodeNotFound, err) + } + return nil, connect.NewError(connect.CodeInternal, err) + } + + rpcErr := permcheck.CheckPerm(mwauth.CheckOwnerWorkspace(ctx, s.us, existing.WorkspaceID)) + if rpcErr != nil { + return nil, rpcErr + } + + // Apply partial updates + if item.Name != nil { + existing.Name = *item.Name + } + if item.Url != nil { + existing.Url = *item.Url + } + existing.UpdatedAt = time.Now().Unix() + + updates = append(updates, *existing) + } + + // ACT + tx, err := s.DB.BeginTx(ctx, nil) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer devtoolsdb.TxnRollback(tx) + + wsTx := s.ws.TX(tx) + for i := range updates { + if err := wsTx.Update(ctx, &updates[i]); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + } + + if err := tx.Commit(); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + for _, item := range updates { + s.wsStream.Publish(WebSocketTopic{WorkspaceID: item.WorkspaceID}, WebSocketEvent{ + Type: eventTypeUpdate, + WebSocket: &apiv1.WebSocket{ + WebsocketId: item.ID.Bytes(), + Name: item.Name, + Url: item.Url, + }, + }) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func (s *WebSocketRPC) WebSocketDelete(ctx context.Context, req *connect.Request[apiv1.WebSocketDeleteRequest]) (*connect.Response[emptypb.Empty], error) { + if len(req.Msg.GetItems()) == 0 { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("at least one item must be provided")) + } + + // FETCH + CHECK + type deleteItem struct { + ID idwrap.IDWrap + WorkspaceID idwrap.IDWrap + } + deleteItems := make([]deleteItem, 0, len(req.Msg.Items)) + for _, item := range req.Msg.Items { + if len(item.GetWebsocketId()) == 0 { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("websocket_id is required")) + } + wsID, err := idwrap.NewFromBytes(item.GetWebsocketId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + workspaceID, err := s.ws.GetWorkspaceID(ctx, wsID) + if err != nil { + if errors.Is(err, swebsocket.ErrNoWebSocketFound) { + return nil, connect.NewError(connect.CodeNotFound, err) + } + return nil, connect.NewError(connect.CodeInternal, err) + } + + rpcErr := permcheck.CheckPerm(mwauth.CheckOwnerWorkspace(ctx, s.us, workspaceID)) + if rpcErr != nil { + return nil, rpcErr + } + + deleteItems = append(deleteItems, deleteItem{ID: wsID, WorkspaceID: workspaceID}) + } + + // ACT + tx, err := s.DB.BeginTx(ctx, nil) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer devtoolsdb.TxnRollback(tx) + + wsTx := s.ws.TX(tx) + for _, item := range deleteItems { + if err := wsTx.Delete(ctx, item.ID); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + } + + if err := tx.Commit(); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + for _, item := range deleteItems { + s.wsStream.Publish(WebSocketTopic{WorkspaceID: item.WorkspaceID}, WebSocketEvent{ + Type: eventTypeDelete, + WebSocket: &apiv1.WebSocket{ + WebsocketId: item.ID.Bytes(), + }, + }) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func (s *WebSocketRPC) WebSocketHeaderInsert(ctx context.Context, req *connect.Request[apiv1.WebSocketHeaderInsertRequest]) (*connect.Response[emptypb.Empty], error) { + if len(req.Msg.GetItems()) == 0 { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("at least one item must be provided")) + } + + // FETCH + CHECK + items := make([]mwebsocket.WebSocketHeader, 0, len(req.Msg.Items)) + workspaceIDs := make([]idwrap.IDWrap, 0, len(req.Msg.Items)) + now := time.Now().Unix() + for _, item := range req.Msg.Items { + if len(item.GetWebsocketHeaderId()) == 0 { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("websocket_header_id is required")) + } + headerID, err := idwrap.NewFromBytes(item.GetWebsocketHeaderId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + if len(item.GetWebsocketId()) == 0 { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("websocket_id is required")) + } + wsID, err := idwrap.NewFromBytes(item.GetWebsocketId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + workspaceID, err := s.ws.GetWorkspaceID(ctx, wsID) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + rpcErr := permcheck.CheckPerm(mwauth.CheckOwnerWorkspace(ctx, s.us, workspaceID)) + if rpcErr != nil { + return nil, rpcErr + } + + items = append(items, mwebsocket.WebSocketHeader{ + ID: headerID, + WebSocketID: wsID, + Key: item.GetKey(), + Value: item.GetValue(), + Enabled: item.GetEnabled(), + Description: item.GetDescription(), + DisplayOrder: item.GetOrder(), + CreatedAt: now, + UpdatedAt: now, + }) + workspaceIDs = append(workspaceIDs, workspaceID) + } + + // ACT + tx, err := s.DB.BeginTx(ctx, nil) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer devtoolsdb.TxnRollback(tx) + + wshTx := s.wsh.TX(tx) + for _, h := range items { + if err := wshTx.Create(ctx, h); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + } + + if err := tx.Commit(); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + for i, h := range items { + s.wshStream.Publish(WebSocketHeaderTopic{WorkspaceID: workspaceIDs[i]}, WebSocketHeaderEvent{ + Type: eventTypeInsert, + WebSocketHeader: toAPIWebSocketHeader(h), + }) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func (s *WebSocketRPC) WebSocketHeaderUpdate(ctx context.Context, req *connect.Request[apiv1.WebSocketHeaderUpdateRequest]) (*connect.Response[emptypb.Empty], error) { + if len(req.Msg.GetItems()) == 0 { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("at least one item must be provided")) + } + + // FETCH + CHECK + updates := make([]mwebsocket.WebSocketHeader, 0, len(req.Msg.Items)) + updateWorkspaceIDs := make([]idwrap.IDWrap, 0, len(req.Msg.Items)) + for _, item := range req.Msg.Items { + if len(item.GetWebsocketHeaderId()) == 0 { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("websocket_header_id is required")) + } + headerID, err := idwrap.NewFromBytes(item.GetWebsocketHeaderId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + existing, err := s.wsh.GetByID(ctx, headerID) + if err != nil { + return nil, connect.NewError(connect.CodeNotFound, err) + } + + workspaceID, err := s.ws.GetWorkspaceID(ctx, existing.WebSocketID) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + rpcErr := permcheck.CheckPerm(mwauth.CheckOwnerWorkspace(ctx, s.us, workspaceID)) + if rpcErr != nil { + return nil, rpcErr + } + + if item.Key != nil { + existing.Key = *item.Key + } + if item.Value != nil { + existing.Value = *item.Value + } + if item.Enabled != nil { + existing.Enabled = *item.Enabled + } + if item.Description != nil { + existing.Description = *item.Description + } + if item.Order != nil { + existing.DisplayOrder = *item.Order + } + existing.UpdatedAt = time.Now().Unix() + + updates = append(updates, existing) + updateWorkspaceIDs = append(updateWorkspaceIDs, workspaceID) + } + + // ACT + tx, err := s.DB.BeginTx(ctx, nil) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer devtoolsdb.TxnRollback(tx) + + wshTx := s.wsh.TX(tx) + for _, h := range updates { + if err := wshTx.Update(ctx, h); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + } + + if err := tx.Commit(); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + for i, h := range updates { + s.wshStream.Publish(WebSocketHeaderTopic{WorkspaceID: updateWorkspaceIDs[i]}, WebSocketHeaderEvent{ + Type: eventTypeUpdate, + WebSocketHeader: toAPIWebSocketHeader(h), + }) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func (s *WebSocketRPC) WebSocketHeaderDelete(ctx context.Context, req *connect.Request[apiv1.WebSocketHeaderDeleteRequest]) (*connect.Response[emptypb.Empty], error) { + if len(req.Msg.GetItems()) == 0 { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("at least one item must be provided")) + } + + // FETCH + CHECK + type headerDeleteItem struct { + ID idwrap.IDWrap + WorkspaceID idwrap.IDWrap + } + headerDeleteItems := make([]headerDeleteItem, 0, len(req.Msg.Items)) + for _, item := range req.Msg.Items { + if len(item.GetWebsocketHeaderId()) == 0 { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("websocket_header_id is required")) + } + headerID, err := idwrap.NewFromBytes(item.GetWebsocketHeaderId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + existing, err := s.wsh.GetByID(ctx, headerID) + if err != nil { + return nil, connect.NewError(connect.CodeNotFound, err) + } + + workspaceID, err := s.ws.GetWorkspaceID(ctx, existing.WebSocketID) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + rpcErr := permcheck.CheckPerm(mwauth.CheckOwnerWorkspace(ctx, s.us, workspaceID)) + if rpcErr != nil { + return nil, rpcErr + } + + headerDeleteItems = append(headerDeleteItems, headerDeleteItem{ID: headerID, WorkspaceID: workspaceID}) + } + + // ACT + tx, err := s.DB.BeginTx(ctx, nil) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer devtoolsdb.TxnRollback(tx) + + wshTx := s.wsh.TX(tx) + for _, item := range headerDeleteItems { + if err := wshTx.Delete(ctx, item.ID); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + } + + if err := tx.Commit(); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + for _, item := range headerDeleteItems { + s.wshStream.Publish(WebSocketHeaderTopic{WorkspaceID: item.WorkspaceID}, WebSocketHeaderEvent{ + Type: eventTypeDelete, + WebSocketHeader: &apiv1.WebSocketHeader{ + WebsocketHeaderId: item.ID.Bytes(), + }, + }) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func toAPIWebSocketHeader(h mwebsocket.WebSocketHeader) *apiv1.WebSocketHeader { + return &apiv1.WebSocketHeader{ + WebsocketHeaderId: h.ID.Bytes(), + WebsocketId: h.WebSocketID.Bytes(), + Key: h.Key, + Value: h.Value, + Enabled: h.Enabled, + Description: h.Description, + Order: h.DisplayOrder, + } +} + +func stringPtr(s string) *string { return &s } +func boolPtr(b bool) *bool { return &b } +func float32Ptr(f float32) *float32 { return &f } + +func webSocketSyncResponseFrom(evt WebSocketEvent) *apiv1.WebSocketSyncResponse { + if evt.WebSocket == nil { + return nil + } + + switch evt.Type { + case eventTypeInsert: + msg := &apiv1.WebSocketSync{ + Value: &apiv1.WebSocketSync_ValueUnion{ + Kind: apiv1.WebSocketSync_ValueUnion_KIND_INSERT, + Insert: &apiv1.WebSocketSyncInsert{ + WebsocketId: evt.WebSocket.WebsocketId, + Name: evt.WebSocket.Name, + Url: evt.WebSocket.Url, + }, + }, + } + return &apiv1.WebSocketSyncResponse{Items: []*apiv1.WebSocketSync{msg}} + case eventTypeUpdate: + msg := &apiv1.WebSocketSync{ + Value: &apiv1.WebSocketSync_ValueUnion{ + Kind: apiv1.WebSocketSync_ValueUnion_KIND_UPDATE, + Update: &apiv1.WebSocketSyncUpdate{ + WebsocketId: evt.WebSocket.WebsocketId, + Name: stringPtr(evt.WebSocket.Name), + Url: stringPtr(evt.WebSocket.Url), + }, + }, + } + return &apiv1.WebSocketSyncResponse{Items: []*apiv1.WebSocketSync{msg}} + case eventTypeDelete: + msg := &apiv1.WebSocketSync{ + Value: &apiv1.WebSocketSync_ValueUnion{ + Kind: apiv1.WebSocketSync_ValueUnion_KIND_DELETE, + Delete: &apiv1.WebSocketSyncDelete{ + WebsocketId: evt.WebSocket.WebsocketId, + }, + }, + } + return &apiv1.WebSocketSyncResponse{Items: []*apiv1.WebSocketSync{msg}} + default: + return nil + } +} + +func webSocketHeaderSyncResponseFrom(evt WebSocketHeaderEvent) *apiv1.WebSocketHeaderSyncResponse { + if evt.WebSocketHeader == nil { + return nil + } + + switch evt.Type { + case eventTypeInsert: + msg := &apiv1.WebSocketHeaderSync{ + Value: &apiv1.WebSocketHeaderSync_ValueUnion{ + Kind: apiv1.WebSocketHeaderSync_ValueUnion_KIND_INSERT, + Insert: &apiv1.WebSocketHeaderSyncInsert{ + WebsocketHeaderId: evt.WebSocketHeader.WebsocketHeaderId, + WebsocketId: evt.WebSocketHeader.WebsocketId, + Key: evt.WebSocketHeader.Key, + Value: evt.WebSocketHeader.Value, + Enabled: evt.WebSocketHeader.Enabled, + Description: evt.WebSocketHeader.Description, + Order: evt.WebSocketHeader.Order, + }, + }, + } + return &apiv1.WebSocketHeaderSyncResponse{Items: []*apiv1.WebSocketHeaderSync{msg}} + case eventTypeUpdate: + msg := &apiv1.WebSocketHeaderSync{ + Value: &apiv1.WebSocketHeaderSync_ValueUnion{ + Kind: apiv1.WebSocketHeaderSync_ValueUnion_KIND_UPDATE, + Update: &apiv1.WebSocketHeaderSyncUpdate{ + WebsocketHeaderId: evt.WebSocketHeader.WebsocketHeaderId, + WebsocketId: evt.WebSocketHeader.WebsocketId, + Key: stringPtr(evt.WebSocketHeader.Key), + Value: stringPtr(evt.WebSocketHeader.Value), + Enabled: boolPtr(evt.WebSocketHeader.Enabled), + Description: stringPtr(evt.WebSocketHeader.Description), + Order: float32Ptr(evt.WebSocketHeader.Order), + }, + }, + } + return &apiv1.WebSocketHeaderSyncResponse{Items: []*apiv1.WebSocketHeaderSync{msg}} + case eventTypeDelete: + msg := &apiv1.WebSocketHeaderSync{ + Value: &apiv1.WebSocketHeaderSync_ValueUnion{ + Kind: apiv1.WebSocketHeaderSync_ValueUnion_KIND_DELETE, + Delete: &apiv1.WebSocketHeaderSyncDelete{ + WebsocketHeaderId: evt.WebSocketHeader.WebsocketHeaderId, + }, + }, + } + return &apiv1.WebSocketHeaderSyncResponse{Items: []*apiv1.WebSocketHeaderSync{msg}} + default: + return nil + } +} diff --git a/packages/server/internal/converter/converter.go b/packages/server/internal/converter/converter.go index 1bb61310a..2f33f94f1 100644 --- a/packages/server/internal/converter/converter.go +++ b/packages/server/internal/converter/converter.go @@ -379,6 +379,12 @@ func ToAPINodeKind(kind mflow.NodeKind) flowv1.NodeKind { return flowv1.NodeKind_NODE_KIND_AI_MEMORY case mflow.NODE_KIND_GRAPHQL: return flowv1.NodeKind_NODE_KIND_GRAPH_Q_L + case mflow.NODE_KIND_WS_CONNECTION: + return flowv1.NodeKind_NODE_KIND_WS_CONNECTION + case mflow.NODE_KIND_WS_SEND: + return flowv1.NodeKind_NODE_KIND_WS_SEND + case mflow.NODE_KIND_WAIT: + return flowv1.NodeKind_NODE_KIND_WAIT default: return flowv1.NodeKind_NODE_KIND_UNSPECIFIED } diff --git a/packages/server/internal/converter/converter_test.go b/packages/server/internal/converter/converter_test.go index 690f864cd..f67b5ee60 100644 --- a/packages/server/internal/converter/converter_test.go +++ b/packages/server/internal/converter/converter_test.go @@ -626,6 +626,8 @@ func TestToAPINodeKind(t *testing.T) { {mflow.NODE_KIND_FOR, flowv1.NodeKind_NODE_KIND_FOR}, {mflow.NODE_KIND_FOR_EACH, flowv1.NodeKind_NODE_KIND_FOR_EACH}, {mflow.NODE_KIND_JS, flowv1.NodeKind_NODE_KIND_JS}, + {mflow.NODE_KIND_WS_CONNECTION, flowv1.NodeKind_NODE_KIND_WS_CONNECTION}, + {mflow.NODE_KIND_WS_SEND, flowv1.NodeKind_NODE_KIND_WS_SEND}, {mflow.NodeKind(-1), flowv1.NodeKind_NODE_KIND_UNSPECIFIED}, } diff --git a/packages/server/internal/migrations/01KJZMR5_add_flow_node_wait.go b/packages/server/internal/migrations/01KJZMR5_add_flow_node_wait.go new file mode 100644 index 000000000..cfde105fa --- /dev/null +++ b/packages/server/internal/migrations/01KJZMR5_add_flow_node_wait.go @@ -0,0 +1,50 @@ +package migrations + +import ( + "context" + "database/sql" + "fmt" + + "github.com/the-dev-tools/dev-tools/packages/server/internal/migrate" +) + +const MigrationAddFlowNodeWaitID = "01KJZMR5232X0983HYB7GS2WZ7" + +const MigrationAddFlowNodeWaitChecksum = "sha256:add-flow-node-wait-v1" + +func init() { + if err := migrate.Register(migrate.Migration{ + ID: MigrationAddFlowNodeWaitID, + Checksum: MigrationAddFlowNodeWaitChecksum, + Description: "Add flow_node_wait table for wait/delay nodes", + Apply: applyFlowNodeWait, + Validate: validateFlowNodeWait, + RequiresBackup: false, + }); err != nil { + panic("failed to register flow_node_wait migration: " + err.Error()) + } +} + +func applyFlowNodeWait(ctx context.Context, tx *sql.Tx) error { + if _, err := tx.ExecContext(ctx, ` + CREATE TABLE IF NOT EXISTS flow_node_wait ( + flow_node_id BLOB NOT NULL PRIMARY KEY, + duration_ms BIGINT NOT NULL + ) + `); err != nil { + return fmt.Errorf("create flow_node_wait table: %w", err) + } + return nil +} + +func validateFlowNodeWait(ctx context.Context, db *sql.DB) error { + var name string + err := db.QueryRowContext(ctx, ` + SELECT name FROM sqlite_master + WHERE type='table' AND name='flow_node_wait' + `).Scan(&name) + if err != nil { + return fmt.Errorf("flow_node_wait table not found: %w", err) + } + return nil +} diff --git a/packages/server/internal/migrations/01KKFQT8_add_websocket_tables.go b/packages/server/internal/migrations/01KKFQT8_add_websocket_tables.go new file mode 100644 index 000000000..362a7b66e --- /dev/null +++ b/packages/server/internal/migrations/01KKFQT8_add_websocket_tables.go @@ -0,0 +1,233 @@ +package migrations + +import ( + "context" + "database/sql" + "fmt" + "strings" + + "github.com/the-dev-tools/dev-tools/packages/server/internal/migrate" +) + +// MigrationAddWebSocketTablesID is the ULID for the WebSocket tables migration. +const MigrationAddWebSocketTablesID = "01KKFQT81KV5MX8H9MNTPCWDV9" + +// MigrationAddWebSocketTablesChecksum is a stable hash of this migration. +const MigrationAddWebSocketTablesChecksum = "sha256:add-websocket-tables-v1" + +func init() { + if err := migrate.Register(migrate.Migration{ + ID: MigrationAddWebSocketTablesID, + Checksum: MigrationAddWebSocketTablesChecksum, + Description: "Add WebSocket tables for connections, headers, and flow nodes", + Apply: applyWebSocketTables, + Validate: validateWebSocketTables, + RequiresBackup: true, + }); err != nil { + panic("failed to register WebSocket tables migration: " + err.Error()) + } +} + +func applyWebSocketTables(ctx context.Context, tx *sql.Tx) error { + // 1. Create websocket table + if _, err := tx.ExecContext(ctx, ` + CREATE TABLE IF NOT EXISTS websocket ( + id BLOB NOT NULL PRIMARY KEY, + workspace_id BLOB NOT NULL, + folder_id BLOB, + name TEXT NOT NULL, + url TEXT NOT NULL, + description TEXT NOT NULL DEFAULT '', + last_run_at BIGINT NULL, + created_at BIGINT NOT NULL DEFAULT (unixepoch()), + updated_at BIGINT NOT NULL DEFAULT (unixepoch()), + + FOREIGN KEY (workspace_id) REFERENCES workspaces (id) ON DELETE CASCADE, + FOREIGN KEY (folder_id) REFERENCES files (id) ON DELETE SET NULL + ) + `); err != nil { + return err + } + + wsIndexes := []string{ + `CREATE INDEX IF NOT EXISTS websocket_workspace_idx ON websocket (workspace_id)`, + `CREATE INDEX IF NOT EXISTS websocket_folder_idx ON websocket (folder_id) WHERE folder_id IS NOT NULL`, + } + for _, idx := range wsIndexes { + if _, err := tx.ExecContext(ctx, idx); err != nil { + return fmt.Errorf("create websocket index: %w", err) + } + } + + // 2. Create websocket_header table + if _, err := tx.ExecContext(ctx, ` + CREATE TABLE IF NOT EXISTS websocket_header ( + id BLOB NOT NULL PRIMARY KEY, + websocket_id BLOB NOT NULL, + header_key TEXT NOT NULL, + header_value TEXT NOT NULL, + description TEXT NOT NULL DEFAULT '', + enabled BOOLEAN NOT NULL DEFAULT TRUE, + display_order REAL NOT NULL DEFAULT 0, + created_at BIGINT NOT NULL DEFAULT (unixepoch()), + updated_at BIGINT NOT NULL DEFAULT (unixepoch()), + + FOREIGN KEY (websocket_id) REFERENCES websocket (id) ON DELETE CASCADE + ) + `); err != nil { + return err + } + + headerIndexes := []string{ + `CREATE INDEX IF NOT EXISTS websocket_header_ws_idx ON websocket_header (websocket_id)`, + `CREATE INDEX IF NOT EXISTS websocket_header_order_idx ON websocket_header (websocket_id, display_order)`, + } + for _, idx := range headerIndexes { + if _, err := tx.ExecContext(ctx, idx); err != nil { + return fmt.Errorf("create websocket_header index: %w", err) + } + } + + // 3. Create flow_node_ws_connection table + if _, err := tx.ExecContext(ctx, ` + CREATE TABLE IF NOT EXISTS flow_node_ws_connection ( + flow_node_id BLOB NOT NULL PRIMARY KEY, + websocket_id BLOB, + FOREIGN KEY (websocket_id) REFERENCES websocket (id) ON DELETE SET NULL + ) + `); err != nil { + return err + } + + // 4. Create flow_node_ws_send table + if _, err := tx.ExecContext(ctx, ` + CREATE TABLE IF NOT EXISTS flow_node_ws_send ( + flow_node_id BLOB NOT NULL PRIMARY KEY, + ws_connection_node_name TEXT NOT NULL DEFAULT '', + message TEXT NOT NULL DEFAULT '' + ) + `); err != nil { + return err + } + + // 5. Update files table CHECK constraint to allow content_kind = 6 (websocket) + if err := updateFilesCheckConstraintWebSocket(ctx, tx); err != nil { + return fmt.Errorf("update files check constraint: %w", err) + } + + return nil +} + +// updateFilesCheckConstraintWebSocket recreates the files table with WebSocket content_kind support. +func updateFilesCheckConstraintWebSocket(ctx context.Context, tx *sql.Tx) error { + var tableSql string + err := tx.QueryRowContext(ctx, ` + SELECT sql FROM sqlite_master WHERE type='table' AND name='files' + `).Scan(&tableSql) + if err != nil { + return fmt.Errorf("read files table schema: %w", err) + } + if strings.Contains(tableSql, "5, 6)") { + return nil + } + + if _, err := tx.ExecContext(ctx, ` + CREATE TABLE files_new ( + id BLOB NOT NULL PRIMARY KEY, + workspace_id BLOB NOT NULL, + parent_id BLOB, + content_id BLOB, + content_kind INT8 NOT NULL DEFAULT 0, + name TEXT NOT NULL, + display_order REAL NOT NULL DEFAULT 0, + path_hash TEXT, + updated_at BIGINT NOT NULL DEFAULT (unixepoch()), + CHECK (length (id) == 16), + CHECK (content_kind IN (0, 1, 2, 3, 4, 5, 6)), + CHECK ( + (content_kind = 0 AND content_id IS NOT NULL) OR + (content_kind = 1 AND content_id IS NOT NULL) OR + (content_kind = 2 AND content_id IS NOT NULL) OR + (content_kind = 3 AND content_id IS NOT NULL) OR + (content_kind = 4 AND content_id IS NOT NULL) OR + (content_kind = 5 AND content_id IS NOT NULL) OR + (content_kind = 6 AND content_id IS NOT NULL) OR + (content_id IS NULL) + ), + FOREIGN KEY (workspace_id) REFERENCES workspaces (id) ON DELETE CASCADE, + FOREIGN KEY (parent_id) REFERENCES files (id) ON DELETE SET NULL + ) + `); err != nil { + return fmt.Errorf("create files_new: %w", err) + } + + if _, err := tx.ExecContext(ctx, `INSERT INTO files_new SELECT * FROM files`); err != nil { + return fmt.Errorf("copy files data: %w", err) + } + + if _, err := tx.ExecContext(ctx, `DROP TABLE files`); err != nil { + return fmt.Errorf("drop old files: %w", err) + } + + if _, err := tx.ExecContext(ctx, `ALTER TABLE files_new RENAME TO files`); err != nil { + return fmt.Errorf("rename files_new: %w", err) + } + + indexes := []string{ + `CREATE INDEX files_workspace_idx ON files (workspace_id)`, + `CREATE UNIQUE INDEX files_path_hash_idx ON files (workspace_id, path_hash) WHERE path_hash IS NOT NULL`, + `CREATE INDEX files_hierarchy_idx ON files (workspace_id, parent_id, display_order)`, + `CREATE INDEX files_content_lookup_idx ON files (content_kind, content_id) WHERE content_id IS NOT NULL`, + `CREATE INDEX files_parent_lookup_idx ON files (parent_id, display_order) WHERE parent_id IS NOT NULL`, + `CREATE INDEX files_name_search_idx ON files (workspace_id, name)`, + `CREATE INDEX files_kind_filter_idx ON files (workspace_id, content_kind)`, + `CREATE INDEX files_workspace_hierarchy_idx ON files (workspace_id, parent_id, content_kind, display_order)`, + } + for _, idx := range indexes { + if _, err := tx.ExecContext(ctx, idx); err != nil { + return fmt.Errorf("recreate index: %w", err) + } + } + + return nil +} + +func validateWebSocketTables(ctx context.Context, db *sql.DB) error { + tables := []string{ + "websocket", + "websocket_header", + "flow_node_ws_connection", + "flow_node_ws_send", + } + + for _, table := range tables { + var name string + err := db.QueryRowContext(ctx, ` + SELECT name FROM sqlite_master + WHERE type='table' AND name=? + `, table).Scan(&name) + if err != nil { + return fmt.Errorf("table %s not found: %w", table, err) + } + } + + indexes := []string{ + "websocket_workspace_idx", + "websocket_folder_idx", + "websocket_header_ws_idx", + "websocket_header_order_idx", + } + + for _, idx := range indexes { + var name string + err := db.QueryRowContext(ctx, ` + SELECT name FROM sqlite_master + WHERE type='index' AND name=? + `, idx).Scan(&name) + if err != nil { + return fmt.Errorf("index %s not found: %w", idx, err) + } + } + + return nil +} diff --git a/packages/server/internal/migrations/migrations_test.go b/packages/server/internal/migrations/migrations_test.go index 00932679b..4f506acad 100644 --- a/packages/server/internal/migrations/migrations_test.go +++ b/packages/server/internal/migrations/migrations_test.go @@ -210,7 +210,7 @@ func TestFilesTableConstraintUpdated(t *testing.T) { t.Fatalf("failed to run migrations: %v", err) } - // Verify files table supports content_kind=5 (graphql) + // Verify files table supports content_kind=6 (websocket) var tableDef string err = db.QueryRowContext(ctx, ` SELECT sql FROM sqlite_master @@ -220,9 +220,9 @@ func TestFilesTableConstraintUpdated(t *testing.T) { t.Fatalf("failed to get files table definition: %v", err) } - // Check that the constraint includes content_kind=5 - if !contains(tableDef, "content_kind IN (0, 1, 2, 3, 4, 5)") { - t.Errorf("files table CHECK constraint doesn't include content_kind=5: %s", tableDef) + // Check that the constraint includes content_kind=6 + if !contains(tableDef, "content_kind IN (0, 1, 2, 3, 4, 5, 6)") { + t.Errorf("files table CHECK constraint doesn't include content_kind=6: %s", tableDef) } } diff --git a/packages/server/pkg/flow/flowbuilder/builder.go b/packages/server/pkg/flow/flowbuilder/builder.go index 018b4e809..3248fdedd 100644 --- a/packages/server/pkg/flow/flowbuilder/builder.go +++ b/packages/server/pkg/flow/flowbuilder/builder.go @@ -20,6 +20,9 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/naiprovider" "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/nrequest" "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/nstart" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/nwait" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/nwsconnection" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/nwssend" gqlresolver "github.com/the-dev-tools/dev-tools/packages/server/pkg/graphql/resolver" "github.com/the-dev-tools/dev-tools/packages/server/pkg/http/resolver" "github.com/the-dev-tools/dev-tools/packages/server/pkg/httpclient" @@ -30,6 +33,7 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/senv" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sflow" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sgraphql" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/swebsocket" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sworkspace" "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/private/node_js_executor/v1/node_js_executorv1connect" ) @@ -44,9 +48,14 @@ type Builder struct { NodeAI *sflow.NodeAIService NodeAiProvider *sflow.NodeAiProviderService NodeMemory *sflow.NodeMemoryService - NodeGraphQL *sflow.NodeGraphQLService - GraphQL *sgraphql.GraphQLService - GraphQLHeader *sgraphql.GraphQLHeaderService + NodeGraphQL *sflow.NodeGraphQLService + NodeWsConnection *sflow.NodeWsConnectionService + NodeWsSend *sflow.NodeWsSendService + NodeWait *sflow.NodeWaitService + WebSocket *swebsocket.WebSocketService + WebSocketHeader *swebsocket.WebSocketHeaderService + GraphQL *sgraphql.GraphQLService + GraphQLHeader *sgraphql.GraphQLHeaderService Workspace *sworkspace.WorkspaceService Variable *senv.VariableService @@ -69,6 +78,11 @@ func New( naps *sflow.NodeAiProviderService, nmems *sflow.NodeMemoryService, ngqs *sflow.NodeGraphQLService, + nwcs *sflow.NodeWsConnectionService, + nwss *sflow.NodeWsSendService, + nwaits *sflow.NodeWaitService, + wsSvc *swebsocket.WebSocketService, + wsHeaderSvc *swebsocket.WebSocketHeaderService, gqls *sgraphql.GraphQLService, gqlhs *sgraphql.GraphQLHeaderService, ws *sworkspace.WorkspaceService, @@ -90,6 +104,11 @@ func New( NodeAiProvider: naps, NodeMemory: nmems, NodeGraphQL: ngqs, + NodeWsConnection: nwcs, + NodeWsSend: nwss, + NodeWait: nwaits, + WebSocket: wsSvc, + WebSocketHeader: wsHeaderSvc, GraphQL: gqls, GraphQLHeader: gqlhs, Workspace: ws, @@ -111,27 +130,27 @@ func (b *Builder) BuildNodes( respChan chan nrequest.NodeRequestSideResp, gqlRespChan chan ngraphql.NodeGraphQLSideResp, jsClient node_js_executorv1connect.NodeJsExecutorServiceClient, -) (map[idwrap.IDWrap]node.FlowNode, idwrap.IDWrap, error) { +) (map[idwrap.IDWrap]node.FlowNode, []idwrap.IDWrap, error) { flowNodeMap := make(map[idwrap.IDWrap]node.FlowNode, len(nodes)) - var startNodeID idwrap.IDWrap + var startNodeIDs []idwrap.IDWrap for _, nodeModel := range nodes { switch nodeModel.NodeKind { case mflow.NODE_KIND_MANUAL_START: flowNodeMap[nodeModel.ID] = nstart.New(nodeModel.ID, nodeModel.Name) - startNodeID = nodeModel.ID + startNodeIDs = append(startNodeIDs, nodeModel.ID) case mflow.NODE_KIND_REQUEST: requestCfg, err := b.NodeRequest.GetNodeRequest(ctx, nodeModel.ID) if err != nil { - return nil, idwrap.IDWrap{}, err + return nil, nil, err } if requestCfg == nil || requestCfg.HttpID == nil || isZeroID(*requestCfg.HttpID) { - return nil, idwrap.IDWrap{}, fmt.Errorf("request node %s missing http configuration", nodeModel.ID.String()) + return nil, nil, fmt.Errorf("request node %s missing http configuration", nodeModel.ID.String()) } resolved, err := b.Resolver.Resolve(ctx, *requestCfg.HttpID, requestCfg.DeltaHttpID) if err != nil { - return nil, idwrap.IDWrap{}, fmt.Errorf("resolve http %s: %w", requestCfg.HttpID.String(), err) + return nil, nil, fmt.Errorf("resolve http %s: %w", requestCfg.HttpID.String(), err) } requestNode := nrequest.New( @@ -153,7 +172,7 @@ func (b *Builder) BuildNodes( case mflow.NODE_KIND_FOR: forCfg, err := b.NodeFor.GetNodeFor(ctx, nodeModel.ID) if err != nil { - return nil, idwrap.IDWrap{}, err + return nil, nil, err } if forCfg == nil { // Default configuration if missing @@ -173,7 +192,7 @@ func (b *Builder) BuildNodes( case mflow.NODE_KIND_FOR_EACH: forEachCfg, err := b.NodeForEach.GetNodeForEach(ctx, nodeModel.ID) if err != nil { - return nil, idwrap.IDWrap{}, err + return nil, nil, err } if forEachCfg == nil { // Default configuration if missing @@ -184,7 +203,7 @@ func (b *Builder) BuildNodes( case mflow.NODE_KIND_CONDITION: condCfg, err := b.NodeIf.GetNodeIf(ctx, nodeModel.ID) if err != nil { - return nil, idwrap.IDWrap{}, err + return nil, nil, err } if condCfg == nil { // Default to "true" or "false"? Usually better to default to something safe or empty. @@ -196,7 +215,7 @@ func (b *Builder) BuildNodes( case mflow.NODE_KIND_JS: jsCfg, err := b.NodeJS.GetNodeJS(ctx, nodeModel.ID) if err != nil { - return nil, idwrap.IDWrap{}, err + return nil, nil, err } if jsCfg == nil { // Default empty JS @@ -206,7 +225,7 @@ func (b *Builder) BuildNodes( if jsCfg.CodeCompressType != compress.CompressTypeNone { codeBytes, err = compress.Decompress(jsCfg.Code, jsCfg.CodeCompressType) if err != nil { - return nil, idwrap.IDWrap{}, fmt.Errorf("decompress js code: %w", err) + return nil, nil, fmt.Errorf("decompress js code: %w", err) } } flowNodeMap[nodeModel.ID] = njs.New(nodeModel.ID, nodeModel.Name, string(codeBytes), jsClient) @@ -214,7 +233,7 @@ func (b *Builder) BuildNodes( case mflow.NODE_KIND_AI: aiCfg, err := b.NodeAI.GetNodeAI(ctx, nodeModel.ID) if err != nil { - return nil, idwrap.IDWrap{}, err + return nil, nil, err } if aiCfg == nil { // Default AI node with empty prompt @@ -237,7 +256,7 @@ func (b *Builder) BuildNodes( case mflow.NODE_KIND_AI_PROVIDER: providerCfg, err := b.NodeAiProvider.GetNodeAiProvider(ctx, nodeModel.ID) if err != nil && !errors.Is(err, sflow.ErrNoNodeAiProviderFound) { - return nil, idwrap.IDWrap{}, err + return nil, nil, err } if providerCfg == nil { // Default AI Provider node (no credential set) @@ -262,7 +281,7 @@ func (b *Builder) BuildNodes( case mflow.NODE_KIND_AI_MEMORY: memoryCfg, err := b.NodeMemory.GetNodeMemory(ctx, nodeModel.ID) if err != nil && !errors.Is(err, sflow.ErrNoNodeMemoryFound) { - return nil, idwrap.IDWrap{}, err + return nil, nil, err } if memoryCfg == nil { // Default Memory node with window buffer of 10 messages @@ -283,16 +302,16 @@ func (b *Builder) BuildNodes( case mflow.NODE_KIND_GRAPHQL: gqlCfg, err := b.NodeGraphQL.GetNodeGraphQL(ctx, nodeModel.ID) if err != nil { - return nil, idwrap.IDWrap{}, err + return nil, nil, err } if gqlCfg == nil || gqlCfg.GraphQLID == nil || isZeroID(*gqlCfg.GraphQLID) { - return nil, idwrap.IDWrap{}, fmt.Errorf("graphql node %s missing graphql configuration", nodeModel.ID.String()) + return nil, nil, fmt.Errorf("graphql node %s missing graphql configuration", nodeModel.ID.String()) } // Resolve GraphQL entity with delta resolved, err := b.GraphQLResolver.Resolve(ctx, *gqlCfg.GraphQLID, gqlCfg.DeltaGraphQLID) if err != nil { - return nil, idwrap.IDWrap{}, fmt.Errorf("resolve graphql %s: %w", gqlCfg.GraphQLID.String(), err) + return nil, nil, fmt.Errorf("resolve graphql %s: %w", gqlCfg.GraphQLID.String(), err) } flowNodeMap[nodeModel.ID] = ngraphql.New( @@ -305,16 +324,72 @@ func (b *Builder) BuildNodes( gqlRespChan, b.Logger, ) + case mflow.NODE_KIND_WS_CONNECTION: + var url string + var headers map[string]string + if b.NodeWsConnection != nil { + wsCfg, err := b.NodeWsConnection.GetNodeWsConnection(ctx, nodeModel.ID) + if err != nil { + return nil, nil, fmt.Errorf("get ws connection config: %w", err) + } + if wsCfg != nil && wsCfg.WebSocketID != nil && !isZeroID(*wsCfg.WebSocketID) && b.WebSocket != nil { + wsEntity, err := b.WebSocket.Get(ctx, *wsCfg.WebSocketID) + if err != nil { + return nil, nil, fmt.Errorf("resolve websocket %s: %w", wsCfg.WebSocketID.String(), err) + } + url = wsEntity.Url + if b.WebSocketHeader != nil { + wsHeaders, err := b.WebSocketHeader.GetByWebSocketID(ctx, *wsCfg.WebSocketID) + if err != nil { + return nil, nil, fmt.Errorf("resolve websocket headers %s: %w", wsCfg.WebSocketID.String(), err) + } + headers = make(map[string]string, len(wsHeaders)) + for _, h := range wsHeaders { + if h.Enabled { + headers[h.Key] = h.Value + } + } + } + } + } + wsNode := nwsconnection.New(nodeModel.ID, nodeModel.Name, url, headers) + flowNodeMap[nodeModel.ID] = wsNode + case mflow.NODE_KIND_WS_SEND: + var wsConnName string + var message string + if b.NodeWsSend != nil { + wsCfg, err := b.NodeWsSend.GetNodeWsSend(ctx, nodeModel.ID) + if err != nil { + return nil, nil, fmt.Errorf("get ws send config: %w", err) + } + if wsCfg != nil { + wsConnName = wsCfg.WsConnectionNodeName + message = wsCfg.Message + } + } + flowNodeMap[nodeModel.ID] = nwssend.New(nodeModel.ID, nodeModel.Name, wsConnName, message) + case mflow.NODE_KIND_WAIT: + var durationMs int64 = 1000 // default 1 second + if b.NodeWait != nil { + waitCfg, err := b.NodeWait.GetNodeWait(ctx, nodeModel.ID) + if err != nil { + return nil, nil, fmt.Errorf("get wait config: %w", err) + } + if waitCfg != nil { + durationMs = waitCfg.DurationMs + } + } + flowNodeMap[nodeModel.ID] = nwait.New(nodeModel.ID, nodeModel.Name, durationMs) default: - return nil, idwrap.IDWrap{}, fmt.Errorf("node kind %d not supported", nodeModel.NodeKind) + return nil, nil, fmt.Errorf("node kind %d not supported", nodeModel.NodeKind) } } - if startNodeID == (idwrap.IDWrap{}) { - return nil, idwrap.IDWrap{}, errors.New("flow missing start node") + if len(startNodeIDs) == 0 { + return nil, nil, errors.New("flow missing start node") } - return flowNodeMap, startNodeID, nil + return flowNodeMap, startNodeIDs, nil } func (b *Builder) BuildVariables( diff --git a/packages/server/pkg/flow/flowexec/session.go b/packages/server/pkg/flow/flowexec/session.go new file mode 100644 index 000000000..d406ab34a --- /dev/null +++ b/packages/server/pkg/flow/flowexec/session.go @@ -0,0 +1,165 @@ +// Package flowexec manages flow execution sessions. +// It orchestrates the flow lifecycle: variable resolution, node construction, +// runner creation, and result processing. +// +// The ExecutionSession interface supports both local execution (ServerSession) +// and future distributed execution across regions. +package flowexec + +import ( + "context" + "fmt" + "math" + "time" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/flowbuilder" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/flowresult" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/runner" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/runner/flowlocalrunner" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/httpclient" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" + "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/private/node_js_executor/v1/node_js_executorv1connect" +) + +// ExecutionSession manages a single flow execution lifecycle. +// Implementations may run the flow locally (ServerSession) or dispatch +// to remote workers for distributed execution. +type ExecutionSession interface { + // Prepare builds the execution graph from flow data. + // Must be called before Run. + Prepare(ctx context.Context, params ExecutionParams) error + + // Run executes the prepared flow and returns the result. + // The processor lifecycle (Start/Wait) is managed internally. + Run(ctx context.Context) (ExecutionResult, error) +} + +// ExecutionParams contains the flow data needed for execution. +type ExecutionParams struct { + Flow mflow.Flow + Nodes []mflow.Node + Edges []mflow.Edge // Only valid edges (no orphaned source/target references) + FlowVars []mflow.FlowVariable +} + +// ExecutionResult contains the outcome of a flow execution. +type ExecutionResult struct { + Duration int32 +} + +// SessionFactory creates ExecutionSession instances. +// Implementations control where the flow runs: locally (LocalSessionFactory) +// or on remote workers for distributed execution. +type SessionFactory interface { + Create(processor flowresult.ResultProcessor) ExecutionSession +} + +// LocalSessionFactory creates ServerSession instances for local execution. +type LocalSessionFactory struct { + Builder *flowbuilder.Builder + JsClient node_js_executorv1connect.NodeJsExecutorServiceClient +} + +var _ SessionFactory = (*LocalSessionFactory)(nil) + +func (f *LocalSessionFactory) Create(processor flowresult.ResultProcessor) ExecutionSession { + return NewServerSession(ServerSessionOpts{ + Builder: f.Builder, + JsClient: f.JsClient, + Processor: processor, + }) +} + +// ServerSessionOpts configures a ServerSession. +type ServerSessionOpts struct { + Builder *flowbuilder.Builder + JsClient node_js_executorv1connect.NodeJsExecutorServiceClient + Processor flowresult.ResultProcessor +} + +// ServerSession implements ExecutionSession for local server execution. +// It builds the execution graph, runs the flow via FlowLocalRunner, +// and delegates result processing to a ResultProcessor. +type ServerSession struct { + builder *flowbuilder.Builder + jsClient node_js_executorv1connect.NodeJsExecutorServiceClient + processor flowresult.ResultProcessor + + // Prepared state (set by Prepare, consumed by Run) + flowRunner runner.FlowRunner + baseVars map[string]any +} + +var _ ExecutionSession = (*ServerSession)(nil) + +// NewServerSession creates a new ServerSession for local flow execution. +func NewServerSession(opts ServerSessionOpts) *ServerSession { + return &ServerSession{ + builder: opts.Builder, + jsClient: opts.JsClient, + processor: opts.Processor, + } +} + +// Prepare builds execution variables, constructs flow nodes, and creates the runner. +func (s *ServerSession) Prepare(ctx context.Context, params ExecutionParams) error { + baseVars, err := s.builder.BuildVariables(ctx, params.Flow.WorkspaceID, params.FlowVars) + if err != nil { + return fmt.Errorf("failed to build execution variables: %w", err) + } + s.baseVars = baseVars + + edgeMap := mflow.NewEdgesMap(params.Edges) + sharedHTTPClient := httpclient.New() + + const defaultNodeTimeout = 60 // seconds + timeoutDuration := time.Duration(defaultNodeTimeout) * time.Second + + flowNodeMap, startNodeIDs, err := s.builder.BuildNodes( + ctx, + params.Flow, + params.Nodes, + timeoutDuration, + sharedHTTPClient, + s.processor.HTTPResponseChan(), + s.processor.GraphQLResponseChan(), + s.jsClient, + ) + if err != nil { + return err + } + + s.flowRunner = flowlocalrunner.CreateFlowRunner( + idwrap.NewMonotonic(), + params.Flow.ID, + startNodeIDs, + flowNodeMap, + edgeMap, + 0, + nil, + ) + + return nil +} + +// Run starts the result processor, executes the flow, waits for all result +// processing to complete, and returns the execution duration. +func (s *ServerSession) Run(ctx context.Context) (ExecutionResult, error) { + s.processor.Start() + + startTime := time.Now() + runErr := s.flowRunner.RunWithEvents(ctx, runner.FlowEventChannels{ + NodeStates: s.processor.NodeStateChan(), + }, s.baseVars) + + duration := time.Since(startTime).Milliseconds() + if duration > math.MaxInt32 { + duration = math.MaxInt32 + } + + s.processor.Wait() + + //nolint:gosec // duration clamped to MaxInt32 + return ExecutionResult{Duration: int32(duration)}, runErr +} diff --git a/packages/server/pkg/flow/flowexec/session_test.go b/packages/server/pkg/flow/flowexec/session_test.go new file mode 100644 index 000000000..46d151c9d --- /dev/null +++ b/packages/server/pkg/flow/flowexec/session_test.go @@ -0,0 +1,36 @@ +package flowexec + +import ( + "log/slog" + "os" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/flowresult" +) + +func TestLocalSessionFactory_Create(t *testing.T) { + t.Parallel() + + factory := &LocalSessionFactory{ + Builder: nil, // Not used until Prepare + } + + proc := flowresult.NewNoopResultProcessor(0) + session := factory.Create(proc) + + assert.NotNil(t, session) + _, ok := session.(*ServerSession) + assert.True(t, ok, "factory should create ServerSession") +} + +func TestLocalSessionFactory_Interface(t *testing.T) { + t.Parallel() + + // Verify LocalSessionFactory satisfies SessionFactory at compile time + var _ SessionFactory = (*LocalSessionFactory)(nil) + + logger := slog.New(slog.NewTextHandler(os.Stdout, nil)) + _ = logger +} diff --git a/packages/server/pkg/flow/flowexec/snapshot.go b/packages/server/pkg/flow/flowexec/snapshot.go new file mode 100644 index 000000000..03c4b2ae6 --- /dev/null +++ b/packages/server/pkg/flow/flowexec/snapshot.go @@ -0,0 +1,396 @@ +package flowexec + +import ( + "context" + "database/sql" + "fmt" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mcondition" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sflow" +) + +// NodeConfigSnapshot reads and writes a single node kind's type-specific +// configuration during flow version snapshots. +type NodeConfigSnapshot interface { + Kind() mflow.NodeKind + // Read fetches the type-specific config for a node. Returns (nil, nil) if none exists. + Read(ctx context.Context, nodeID idwrap.IDWrap) (any, error) + // WriteTx creates a copy of the config with the new node ID inside the given transaction. + // Returns the created model (for event publishing) or (nil, nil) if skipped. + WriteTx(ctx context.Context, tx *sql.Tx, newNodeID idwrap.IDWrap, config any) (any, error) +} + +// SnapshotRegistry maps node kinds to their snapshot handlers. +type SnapshotRegistry struct { + handlers map[mflow.NodeKind]NodeConfigSnapshot +} + +// NewSnapshotRegistry creates an empty registry. +func NewSnapshotRegistry() *SnapshotRegistry { + return &SnapshotRegistry{handlers: make(map[mflow.NodeKind]NodeConfigSnapshot)} +} + +// Register adds a snapshot handler for a node kind. +func (r *SnapshotRegistry) Register(s NodeConfigSnapshot) { + r.handlers[s.Kind()] = s +} + +// Get returns the snapshot handler for a node kind, if registered. +// Returns (nil, false) if the registry is nil or the kind is not registered. +func (r *SnapshotRegistry) Get(kind mflow.NodeKind) (NodeConfigSnapshot, bool) { + if r == nil { + return nil, false + } + s, ok := r.handlers[kind] + return s, ok +} + +// ReadAll reads type-specific configurations for all nodes that have registered handlers. +// Returns a map from node ID to the config value. Errors are logged and the node is +// skipped (resulting in default config when written). +func (r *SnapshotRegistry) ReadAll(ctx context.Context, nodes []mflow.Node, logger interface{ Warn(msg string, args ...any) }) map[idwrap.IDWrap]any { + configs := make(map[idwrap.IDWrap]any, len(nodes)) + for _, node := range nodes { + handler, ok := r.Get(node.NodeKind) + if !ok { + continue + } + config, err := handler.Read(ctx, node.ID) + if err != nil { + logger.Warn("failed to read node config, using defaults", + "node_id", node.ID.String(), "kind", node.NodeKind, "error", err) + continue + } + configs[node.ID] = config + } + return configs +} + +// NodeConfigResult holds the result of writing a single node's type-specific config. +type NodeConfigResult struct { + NodeKind mflow.NodeKind + Config any // The created model (e.g., mflow.NodeFor, mflow.NodeJS) +} + +// WriteAllTx writes type-specific configurations for all nodes within a transaction. +// Uses configs from ReadAll. Returns the created configs for event publishing. +func (r *SnapshotRegistry) WriteAllTx( + ctx context.Context, + tx *sql.Tx, + sourceNodes []mflow.Node, + nodeIDMapping map[string]idwrap.IDWrap, + configs map[idwrap.IDWrap]any, +) ([]NodeConfigResult, error) { + var results []NodeConfigResult + for _, sourceNode := range sourceNodes { + handler, ok := r.Get(sourceNode.NodeKind) + if !ok { + continue + } + newNodeID, ok := nodeIDMapping[sourceNode.ID.String()] + if !ok { + continue + } + config := configs[sourceNode.ID] + created, err := handler.WriteTx(ctx, tx, newNodeID, config) + if err != nil { + return nil, fmt.Errorf("create %s node config: %w", sourceNode.Name, err) + } + if created != nil { + results = append(results, NodeConfigResult{ + NodeKind: sourceNode.NodeKind, + Config: created, + }) + } + } + return results, nil +} + +// --- Request --- + +type RequestSnapshot struct{ Service *sflow.NodeRequestService } + +func (s *RequestSnapshot) Kind() mflow.NodeKind { return mflow.NODE_KIND_REQUEST } + +func (s *RequestSnapshot) Read(ctx context.Context, nodeID idwrap.IDWrap) (any, error) { + return s.Service.GetNodeRequest(ctx, nodeID) +} + +func (s *RequestSnapshot) WriteTx(ctx context.Context, tx *sql.Tx, newNodeID idwrap.IDWrap, config any) (any, error) { + src, _ := config.(*mflow.NodeRequest) + if src == nil { + return nil, nil + } + newData := mflow.NodeRequest{ + FlowNodeID: newNodeID, + HttpID: src.HttpID, + DeltaHttpID: src.DeltaHttpID, + HasRequestConfig: src.HasRequestConfig, + } + writer := s.Service.TX(tx) + return newData, writer.CreateNodeRequest(ctx, newData) +} + +// --- For --- + +type ForSnapshot struct{ Service *sflow.NodeForService } + +func (s *ForSnapshot) Kind() mflow.NodeKind { return mflow.NODE_KIND_FOR } + +func (s *ForSnapshot) Read(ctx context.Context, nodeID idwrap.IDWrap) (any, error) { + return s.Service.GetNodeFor(ctx, nodeID) +} + +func (s *ForSnapshot) WriteTx(ctx context.Context, tx *sql.Tx, newNodeID idwrap.IDWrap, config any) (any, error) { + newData := mflow.NodeFor{ + FlowNodeID: newNodeID, + IterCount: 1, + Condition: mcondition.Condition{}, + ErrorHandling: mflow.ErrorHandling_ERROR_HANDLING_BREAK, + } + if src, ok := config.(*mflow.NodeFor); ok && src != nil { + if src.IterCount > 0 { + newData.IterCount = src.IterCount + } + newData.Condition = src.Condition + newData.ErrorHandling = src.ErrorHandling + } + writer := s.Service.TX(tx) + return newData, writer.CreateNodeFor(ctx, newData) +} + +// --- ForEach --- + +type ForEachSnapshot struct{ Service *sflow.NodeForEachService } + +func (s *ForEachSnapshot) Kind() mflow.NodeKind { return mflow.NODE_KIND_FOR_EACH } + +func (s *ForEachSnapshot) Read(ctx context.Context, nodeID idwrap.IDWrap) (any, error) { + return s.Service.GetNodeForEach(ctx, nodeID) +} + +func (s *ForEachSnapshot) WriteTx(ctx context.Context, tx *sql.Tx, newNodeID idwrap.IDWrap, config any) (any, error) { + newData := mflow.NodeForEach{ + FlowNodeID: newNodeID, + IterExpression: "", + Condition: mcondition.Condition{}, + ErrorHandling: mflow.ErrorHandling_ERROR_HANDLING_BREAK, + } + if src, ok := config.(*mflow.NodeForEach); ok && src != nil { + newData.IterExpression = src.IterExpression + newData.Condition = src.Condition + newData.ErrorHandling = src.ErrorHandling + } + writer := s.Service.TX(tx) + return newData, writer.CreateNodeForEach(ctx, newData) +} + +// --- Condition (If) --- + +type ConditionSnapshot struct{ Service *sflow.NodeIfService } + +func (s *ConditionSnapshot) Kind() mflow.NodeKind { return mflow.NODE_KIND_CONDITION } + +func (s *ConditionSnapshot) Read(ctx context.Context, nodeID idwrap.IDWrap) (any, error) { + return s.Service.GetNodeIf(ctx, nodeID) +} + +func (s *ConditionSnapshot) WriteTx(ctx context.Context, tx *sql.Tx, newNodeID idwrap.IDWrap, config any) (any, error) { + newData := mflow.NodeIf{ + FlowNodeID: newNodeID, + Condition: mcondition.Condition{}, + } + if src, ok := config.(*mflow.NodeIf); ok && src != nil { + newData.Condition = src.Condition + } + writer := s.Service.TX(tx) + return newData, writer.CreateNodeIf(ctx, newData) +} + +// --- JS --- + +type JSSnapshot struct{ Service *sflow.NodeJsService } + +func (s *JSSnapshot) Kind() mflow.NodeKind { return mflow.NODE_KIND_JS } + +func (s *JSSnapshot) Read(ctx context.Context, nodeID idwrap.IDWrap) (any, error) { + return s.Service.GetNodeJS(ctx, nodeID) +} + +func (s *JSSnapshot) WriteTx(ctx context.Context, tx *sql.Tx, newNodeID idwrap.IDWrap, config any) (any, error) { + newData := mflow.NodeJS{ + FlowNodeID: newNodeID, + Code: nil, + CodeCompressType: 0, + } + if src, ok := config.(*mflow.NodeJS); ok && src != nil { + newData.Code = src.Code + newData.CodeCompressType = src.CodeCompressType + } + writer := s.Service.TX(tx) + return newData, writer.CreateNodeJS(ctx, newData) +} + +// --- AI --- + +type AISnapshot struct{ Service *sflow.NodeAIService } + +func (s *AISnapshot) Kind() mflow.NodeKind { return mflow.NODE_KIND_AI } + +func (s *AISnapshot) Read(ctx context.Context, nodeID idwrap.IDWrap) (any, error) { + return s.Service.GetNodeAI(ctx, nodeID) +} + +func (s *AISnapshot) WriteTx(ctx context.Context, tx *sql.Tx, newNodeID idwrap.IDWrap, config any) (any, error) { + newData := mflow.NodeAI{ + FlowNodeID: newNodeID, + Prompt: "", + MaxIterations: 5, + } + if src, ok := config.(*mflow.NodeAI); ok && src != nil { + newData.Prompt = src.Prompt + newData.MaxIterations = src.MaxIterations + } + writer := s.Service.TX(tx) + return newData, writer.CreateNodeAI(ctx, newData) +} + +// --- AI Provider --- + +type AIProviderSnapshot struct{ Service *sflow.NodeAiProviderService } + +func (s *AIProviderSnapshot) Kind() mflow.NodeKind { return mflow.NODE_KIND_AI_PROVIDER } + +func (s *AIProviderSnapshot) Read(ctx context.Context, nodeID idwrap.IDWrap) (any, error) { + return s.Service.GetNodeAiProvider(ctx, nodeID) +} + +func (s *AIProviderSnapshot) WriteTx(ctx context.Context, tx *sql.Tx, newNodeID idwrap.IDWrap, config any) (any, error) { + newData := mflow.NodeAiProvider{ + FlowNodeID: newNodeID, + CredentialID: nil, + Model: mflow.AiModelUnspecified, + Temperature: nil, + MaxTokens: nil, + } + if src, ok := config.(*mflow.NodeAiProvider); ok && src != nil { + newData.CredentialID = src.CredentialID + newData.Model = src.Model + newData.Temperature = src.Temperature + newData.MaxTokens = src.MaxTokens + } + writer := s.Service.TX(tx) + return newData, writer.CreateNodeAiProvider(ctx, newData) +} + +// --- Memory --- + +type MemorySnapshot struct{ Service *sflow.NodeMemoryService } + +func (s *MemorySnapshot) Kind() mflow.NodeKind { return mflow.NODE_KIND_AI_MEMORY } + +func (s *MemorySnapshot) Read(ctx context.Context, nodeID idwrap.IDWrap) (any, error) { + return s.Service.GetNodeMemory(ctx, nodeID) +} + +func (s *MemorySnapshot) WriteTx(ctx context.Context, tx *sql.Tx, newNodeID idwrap.IDWrap, config any) (any, error) { + newData := mflow.NodeMemory{ + FlowNodeID: newNodeID, + MemoryType: mflow.AiMemoryTypeWindowBuffer, + WindowSize: 10, + } + if src, ok := config.(*mflow.NodeMemory); ok && src != nil { + newData.MemoryType = src.MemoryType + newData.WindowSize = src.WindowSize + } + writer := s.Service.TX(tx) + return newData, writer.CreateNodeMemory(ctx, newData) +} + +// --- GraphQL --- + +type GraphQLSnapshot struct{ Service *sflow.NodeGraphQLService } + +func (s *GraphQLSnapshot) Kind() mflow.NodeKind { return mflow.NODE_KIND_GRAPHQL } + +func (s *GraphQLSnapshot) Read(ctx context.Context, nodeID idwrap.IDWrap) (any, error) { + return s.Service.GetNodeGraphQL(ctx, nodeID) +} + +func (s *GraphQLSnapshot) WriteTx(ctx context.Context, tx *sql.Tx, newNodeID idwrap.IDWrap, config any) (any, error) { + src, _ := config.(*mflow.NodeGraphQL) + if src == nil { + return nil, nil + } + newData := mflow.NodeGraphQL{ + FlowNodeID: newNodeID, + GraphQLID: src.GraphQLID, + } + writer := s.Service.TX(tx) + return newData, writer.CreateNodeGraphQL(ctx, newData) +} + +// --- WebSocket Connection --- + +type WsConnectionSnapshot struct{ Service *sflow.NodeWsConnectionService } + +func (s *WsConnectionSnapshot) Kind() mflow.NodeKind { return mflow.NODE_KIND_WS_CONNECTION } + +func (s *WsConnectionSnapshot) Read(ctx context.Context, nodeID idwrap.IDWrap) (any, error) { + return s.Service.GetNodeWsConnection(ctx, nodeID) +} + +func (s *WsConnectionSnapshot) WriteTx(ctx context.Context, tx *sql.Tx, newNodeID idwrap.IDWrap, config any) (any, error) { + src, _ := config.(*mflow.NodeWsConnection) + if src == nil { + return nil, nil + } + newData := *src + newData.FlowNodeID = newNodeID + writer := s.Service.TX(tx) + return newData, writer.CreateNodeWsConnection(ctx, newData) +} + +// --- WebSocket Send --- + +type WsSendSnapshot struct{ Service *sflow.NodeWsSendService } + +func (s *WsSendSnapshot) Kind() mflow.NodeKind { return mflow.NODE_KIND_WS_SEND } + +func (s *WsSendSnapshot) Read(ctx context.Context, nodeID idwrap.IDWrap) (any, error) { + return s.Service.GetNodeWsSend(ctx, nodeID) +} + +func (s *WsSendSnapshot) WriteTx(ctx context.Context, tx *sql.Tx, newNodeID idwrap.IDWrap, config any) (any, error) { + src, _ := config.(*mflow.NodeWsSend) + if src == nil { + return nil, nil + } + newData := *src + newData.FlowNodeID = newNodeID + writer := s.Service.TX(tx) + return newData, writer.CreateNodeWsSend(ctx, newData) +} + +// --- Wait --- + +type WaitSnapshot struct{ Service *sflow.NodeWaitService } + +func (s *WaitSnapshot) Kind() mflow.NodeKind { return mflow.NODE_KIND_WAIT } + +func (s *WaitSnapshot) Read(ctx context.Context, nodeID idwrap.IDWrap) (any, error) { + return s.Service.GetNodeWait(ctx, nodeID) +} + +func (s *WaitSnapshot) WriteTx(ctx context.Context, tx *sql.Tx, newNodeID idwrap.IDWrap, config any) (any, error) { + src, _ := config.(*mflow.NodeWait) + if src == nil { + return nil, nil + } + newData := *src + newData.FlowNodeID = newNodeID + writer := s.Service.TX(tx) + return newData, writer.CreateNodeWait(ctx, newData) +} diff --git a/packages/server/pkg/flow/flowexec/snapshot_test.go b/packages/server/pkg/flow/flowexec/snapshot_test.go new file mode 100644 index 000000000..46f69f90e --- /dev/null +++ b/packages/server/pkg/flow/flowexec/snapshot_test.go @@ -0,0 +1,238 @@ +package flowexec + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/dbtest" + gen "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sflow" +) + +func TestSnapshotRegistry_NilSafe(t *testing.T) { + t.Parallel() + + var r *SnapshotRegistry + handler, ok := r.Get(mflow.NODE_KIND_REQUEST) + assert.False(t, ok) + assert.Nil(t, handler) +} + +func TestSnapshotRegistry_GetUnregistered(t *testing.T) { + t.Parallel() + + r := NewSnapshotRegistry() + handler, ok := r.Get(mflow.NODE_KIND_REQUEST) + assert.False(t, ok) + assert.Nil(t, handler) +} + +func TestSnapshotRegistry_RegisterAndGet(t *testing.T) { + t.Parallel() + + ctx := context.Background() + db, err := dbtest.GetTestDB(ctx) + require.NoError(t, err) + defer db.Close() + + queries := gen.New(db) + forService := sflow.NewNodeForService(queries) + + r := NewSnapshotRegistry() + r.Register(&ForSnapshot{Service: &forService}) + + handler, ok := r.Get(mflow.NODE_KIND_FOR) + assert.True(t, ok) + assert.Equal(t, mflow.NODE_KIND_FOR, handler.Kind()) + + // Unregistered kind still returns false + _, ok = r.Get(mflow.NODE_KIND_REQUEST) + assert.False(t, ok) +} + +// TestWriteTx_TypedNilConfig verifies that WriteTx handles Go's typed nil +// interface gotcha: (*T)(nil) wrapped in any is NOT == nil. +func TestWriteTx_TypedNilConfig(t *testing.T) { + t.Parallel() + + ctx := context.Background() + db, err := dbtest.GetTestDB(ctx) + require.NoError(t, err) + defer db.Close() + + queries := gen.New(db) + newNodeID := idwrap.NewNow() + + nrsService := sflow.NewNodeRequestService(queries) + ngqsService := sflow.NewNodeGraphQLService(queries) + nwcsService := sflow.NewNodeWsConnectionService(queries) + nwssService := sflow.NewNodeWsSendService(queries) + nwaitsService := sflow.NewNodeWaitService(queries) + + tests := []struct { + name string + handler NodeConfigSnapshot + config any // typed nil pointer + }{ + { + name: "Request typed nil", + handler: &RequestSnapshot{Service: &nrsService}, + config: (*mflow.NodeRequest)(nil), + }, + { + name: "GraphQL typed nil", + handler: &GraphQLSnapshot{Service: &ngqsService}, + config: (*mflow.NodeGraphQL)(nil), + }, + { + name: "WsConnection typed nil", + handler: &WsConnectionSnapshot{Service: &nwcsService}, + config: (*mflow.NodeWsConnection)(nil), + }, + { + name: "WsSend typed nil", + handler: &WsSendSnapshot{Service: &nwssService}, + config: (*mflow.NodeWsSend)(nil), + }, + { + name: "Wait typed nil", + handler: &WaitSnapshot{Service: &nwaitsService}, + config: (*mflow.NodeWait)(nil), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Should NOT panic — must handle typed nil gracefully + result, err := tt.handler.WriteTx(ctx, nil, newNodeID, tt.config) + assert.NoError(t, err) + assert.Nil(t, result) + }) + } +} + +// TestWriteTx_DefaultsWithTypedNil verifies that "always create with defaults" +// snapshot types create valid records even with typed nil config. +func TestWriteTx_DefaultsWithTypedNil(t *testing.T) { + t.Parallel() + + ctx := context.Background() + db, err := dbtest.GetTestDB(ctx) + require.NoError(t, err) + defer db.Close() + + queries := gen.New(db) + + // Create required parent records + flowID := idwrap.NewNow() + err = queries.CreateFlow(ctx, gen.CreateFlowParams{ + ID: flowID, + WorkspaceID: idwrap.NewNow(), + Name: "test", + }) + require.NoError(t, err) + + nfsService := sflow.NewNodeForService(queries) + naisService := sflow.NewNodeAIService(queries) + nmemsService := sflow.NewNodeMemoryService(queries) + + tests := []struct { + name string + handler NodeConfigSnapshot + config any + checkDefaults func(t *testing.T, result any) + }{ + { + name: "For with typed nil uses defaults", + handler: &ForSnapshot{Service: &nfsService}, + config: (*mflow.NodeFor)(nil), + checkDefaults: func(t *testing.T, result any) { + data := result.(mflow.NodeFor) + assert.Equal(t, int64(1), data.IterCount, "default IterCount") + assert.Equal(t, mflow.ErrorHandling_ERROR_HANDLING_BREAK, data.ErrorHandling, "default ErrorHandling") + }, + }, + { + name: "For with config copies values", + handler: &ForSnapshot{Service: &nfsService}, + config: &mflow.NodeFor{ + IterCount: 10, + ErrorHandling: mflow.ErrorHandling_ERROR_HANDLING_IGNORE, + }, + checkDefaults: func(t *testing.T, result any) { + data := result.(mflow.NodeFor) + assert.Equal(t, int64(10), data.IterCount, "copied IterCount") + assert.Equal(t, mflow.ErrorHandling_ERROR_HANDLING_IGNORE, data.ErrorHandling, "copied ErrorHandling") + }, + }, + { + name: "AI with typed nil uses defaults", + handler: &AISnapshot{Service: &naisService}, + config: (*mflow.NodeAI)(nil), + checkDefaults: func(t *testing.T, result any) { + data := result.(mflow.NodeAI) + assert.Equal(t, "", data.Prompt, "default Prompt") + assert.Equal(t, int32(5), data.MaxIterations, "default MaxIterations") + }, + }, + { + name: "Memory with typed nil uses defaults", + handler: &MemorySnapshot{Service: &nmemsService}, + config: (*mflow.NodeMemory)(nil), + checkDefaults: func(t *testing.T, result any) { + data := result.(mflow.NodeMemory) + assert.Equal(t, mflow.AiMemoryTypeWindowBuffer, data.MemoryType) + assert.Equal(t, int32(10), data.WindowSize) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + nodeID := idwrap.NewNow() + err := queries.CreateFlowNode(ctx, gen.CreateFlowNodeParams{ + ID: nodeID, + FlowID: flowID, + Name: tt.name, + NodeKind: int32(tt.handler.Kind()), + }) + require.NoError(t, err) + + tx, err := db.BeginTx(ctx, nil) + require.NoError(t, err) + defer tx.Rollback() //nolint:errcheck + + result, err := tt.handler.WriteTx(ctx, tx, nodeID, tt.config) + require.NoError(t, err) + require.NotNil(t, result) + + tt.checkDefaults(t, result) + + err = tx.Commit() + require.NoError(t, err) + }) + } +} + +// TestWriteTx_UntypedNil verifies that pure nil (not typed nil) is also handled. +func TestWriteTx_UntypedNil(t *testing.T) { + t.Parallel() + + ctx := context.Background() + db, err := dbtest.GetTestDB(ctx) + require.NoError(t, err) + defer db.Close() + + queries := gen.New(db) + nrsService := sflow.NewNodeRequestService(queries) + + handler := &RequestSnapshot{Service: &nrsService} + result, err := handler.WriteTx(ctx, nil, idwrap.NewNow(), nil) + assert.NoError(t, err) + assert.Nil(t, result) +} diff --git a/packages/server/pkg/flow/flowresult/drain.go b/packages/server/pkg/flow/flowresult/drain.go new file mode 100644 index 000000000..d15b9952a --- /dev/null +++ b/packages/server/pkg/flow/flowresult/drain.go @@ -0,0 +1,212 @@ +package flowresult + +import ( + "context" + "log/slog" + "sync" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/ngraphql" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/nrequest" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mgraphql" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sgraphql" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/shttp" +) + +// ResponseDrain persists HTTP and GraphQL responses produced during flow execution. +// It runs two goroutines (one per protocol) that consume from channels, persist +// to the database, publish events, and signal completion via per-response channels. +// +// The signal mechanism allows the ExecutionStateTracker to wait for a response +// to be published before publishing the execution event that references it, +// ensuring correct event ordering for frontends. +type ResponseDrain struct { + workspaceID idwrap.IDWrap + + httpChan chan nrequest.NodeRequestSideResp + gqlChan chan ngraphql.NodeGraphQLSideResp + + // Per-response signal: closed when the response has been persisted and published. + httpSignals map[string]chan struct{} + httpSignalsMu sync.Mutex + gqlSignals map[string]chan struct{} + gqlSignalsMu sync.Mutex + + httpSvc shttp.HttpResponseService + gqlSvc sgraphql.GraphQLResponseService + + publisher EventPublisher + logger *slog.Logger + + httpWg sync.WaitGroup + gqlWg sync.WaitGroup +} + +// ResponseDrainOpts configures a ResponseDrain. +type ResponseDrainOpts struct { + WorkspaceID idwrap.IDWrap + BufSize int + + HTTPResponseService shttp.HttpResponseService + GraphQLResponseService sgraphql.GraphQLResponseService + + Publisher EventPublisher + Logger *slog.Logger +} + +func newResponseDrain(opts ResponseDrainOpts) *ResponseDrain { + return &ResponseDrain{ + workspaceID: opts.WorkspaceID, + httpChan: make(chan nrequest.NodeRequestSideResp, opts.BufSize), + gqlChan: make(chan ngraphql.NodeGraphQLSideResp, opts.BufSize), + httpSignals: make(map[string]chan struct{}), + gqlSignals: make(map[string]chan struct{}), + httpSvc: opts.HTTPResponseService, + gqlSvc: opts.GraphQLResponseService, + publisher: opts.Publisher, + logger: opts.Logger, + } +} + +func (d *ResponseDrain) start(ctx context.Context) { + d.httpWg.Add(1) + go d.runHTTP(ctx) + + d.gqlWg.Add(1) + go d.runGraphQL(ctx) +} + +// closeAndWait closes both channels and waits for goroutines to finish. +func (d *ResponseDrain) closeAndWait() { + close(d.httpChan) + d.httpWg.Wait() + + close(d.gqlChan) + d.gqlWg.Wait() +} + +// WaitForResponse blocks until the response with the given ID has been +// persisted and its event published. Call this before publishing an +// execution event that references the response. +func (d *ResponseDrain) WaitForResponse(respID string) { + // Check HTTP signals + d.httpSignalsMu.Lock() + ch, ok := d.httpSignals[respID] + d.httpSignalsMu.Unlock() + if ok { + <-ch + d.httpSignalsMu.Lock() + delete(d.httpSignals, respID) + d.httpSignalsMu.Unlock() + } + + // Check GraphQL signals + d.gqlSignalsMu.Lock() + ch, ok = d.gqlSignals[respID] + d.gqlSignalsMu.Unlock() + if ok { + <-ch + d.gqlSignalsMu.Lock() + delete(d.gqlSignals, respID) + d.gqlSignalsMu.Unlock() + } +} + +func (d *ResponseDrain) runHTTP(ctx context.Context) { + defer d.httpWg.Done() + for resp := range d.httpChan { + responseID := resp.Resp.HTTPResponse.ID.String() + + // Register signal before processing so state tracker can find it + d.httpSignalsMu.Lock() + signal := make(chan struct{}) + d.httpSignals[responseID] = signal + d.httpSignalsMu.Unlock() + + // Save HTTP Response + if err := d.httpSvc.Create(ctx, resp.Resp.HTTPResponse); err != nil { + d.logger.Error("failed to save http response", "error", err) + } else { + d.publisher.PublishHTTPResponse(resp.Resp.HTTPResponse, d.workspaceID) + } + + // Save Headers + for _, h := range resp.Resp.ResponseHeaders { + if err := d.httpSvc.CreateHeader(ctx, h); err != nil { + d.logger.Error("failed to save http response header", "error", err) + } else { + d.publisher.PublishHTTPResponseHeader(h, d.workspaceID) + } + } + + // Save Asserts + for _, a := range resp.Resp.ResponseAsserts { + if err := d.httpSvc.CreateAssert(ctx, a); err != nil { + d.logger.Error("failed to save http response assert", "error", err) + } else { + d.publisher.PublishHTTPResponseAssert(a, d.workspaceID) + } + } + + close(signal) + + if resp.Done != nil { + close(resp.Done) + } + } +} + +func (d *ResponseDrain) runGraphQL(ctx context.Context) { + defer d.gqlWg.Done() + for resp := range d.gqlChan { + responseID := resp.Response.ID.String() + + d.gqlSignalsMu.Lock() + signal := make(chan struct{}) + d.gqlSignals[responseID] = signal + d.gqlSignalsMu.Unlock() + + // Save all entities first, THEN publish events + responseSuccess := false + if err := d.gqlSvc.Create(ctx, resp.Response); err != nil { + d.logger.Error("failed to save graphql response", "error", err) + } else { + responseSuccess = true + } + + var successHeaders []mgraphql.GraphQLResponseHeader + for _, h := range resp.RespHeaders { + if err := d.gqlSvc.CreateHeader(ctx, h); err != nil { + d.logger.Error("failed to save graphql response header", "error", err) + } else { + successHeaders = append(successHeaders, h) + } + } + + var successAsserts []mgraphql.GraphQLResponseAssert + for _, a := range resp.RespAsserts { + if err := d.gqlSvc.CreateAssert(ctx, a); err != nil { + d.logger.Error("failed to save graphql response assert", "error", err) + } else { + successAsserts = append(successAsserts, a) + } + } + + // Publish events atomically after saves + if responseSuccess { + d.publisher.PublishGraphQLResponse(resp.Response, d.workspaceID) + for _, h := range successHeaders { + d.publisher.PublishGraphQLResponseHeader(h, d.workspaceID) + } + for _, a := range successAsserts { + d.publisher.PublishGraphQLResponseAssert(a, d.workspaceID) + } + } + + close(signal) + + if resp.Done != nil { + close(resp.Done) + } + } +} diff --git a/packages/server/pkg/flow/flowresult/noop.go b/packages/server/pkg/flow/flowresult/noop.go new file mode 100644 index 000000000..509e2927e --- /dev/null +++ b/packages/server/pkg/flow/flowresult/noop.go @@ -0,0 +1,70 @@ +package flowresult + +import ( + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/ngraphql" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/nrequest" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/runner" +) + +// NoopResultProcessor discards all execution results. +// Used for testing and CLI where persistence/events are not needed. +type NoopResultProcessor struct { + httpChan chan nrequest.NodeRequestSideResp + gqlChan chan ngraphql.NodeGraphQLSideResp + stateChan chan runner.FlowNodeStatus +} + +var _ ResultProcessor = (*NoopResultProcessor)(nil) + +func NewNoopResultProcessor(nodeCount int) *NoopResultProcessor { + bufSize := nodeCount*2 + 1 + return &NoopResultProcessor{ + httpChan: make(chan nrequest.NodeRequestSideResp, bufSize), + gqlChan: make(chan ngraphql.NodeGraphQLSideResp, bufSize), + stateChan: make(chan runner.FlowNodeStatus, bufSize), + } +} + +func (n *NoopResultProcessor) HTTPResponseChan() chan nrequest.NodeRequestSideResp { + return n.httpChan +} + +func (n *NoopResultProcessor) GraphQLResponseChan() chan ngraphql.NodeGraphQLSideResp { + return n.gqlChan +} + +func (n *NoopResultProcessor) NodeStateChan() chan runner.FlowNodeStatus { + return n.stateChan +} + +func (n *NoopResultProcessor) Start() { + // Drain HTTP responses + go func() { + for resp := range n.httpChan { + if resp.Done != nil { + close(resp.Done) + } + } + }() + + // Drain GraphQL responses + go func() { + for resp := range n.gqlChan { + if resp.Done != nil { + close(resp.Done) + } + } + }() + + // Drain node statuses + go func() { + //nolint:revive // intentional empty drain + for range n.stateChan { + } + }() +} + +func (n *NoopResultProcessor) Wait() { + // Channels are closed by their producers (runner closes stateChan). + // Response channels should be closed by the caller after the runner completes. +} diff --git a/packages/server/pkg/flow/flowresult/processor.go b/packages/server/pkg/flow/flowresult/processor.go new file mode 100644 index 000000000..6471e8cf6 --- /dev/null +++ b/packages/server/pkg/flow/flowresult/processor.go @@ -0,0 +1,152 @@ +package flowresult + +import ( + "context" + "log/slog" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/ngraphql" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/nrequest" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/runner" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sflow" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sgraphql" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/shttp" +) + +// ResultProcessor handles the side effects of flow execution: +// response persistence, execution state tracking, and event publishing. +// +// Channel accessors are exposed because local execution requires wiring +// channels between the node builder (producer) and the processor (consumer). +// In a distributed scenario, remote workers would use their own channels +// locally and send results back via RPC to a different ResultProcessor +// implementation that doesn't need these channels. +type ResultProcessor interface { + // HTTPResponseChan returns the channel for HTTP response side-effects. + // Pass this to the node builder so request nodes can send responses. + HTTPResponseChan() chan nrequest.NodeRequestSideResp + + // GraphQLResponseChan returns the channel for GraphQL response side-effects. + // Pass this to the node builder so GraphQL nodes can send responses. + GraphQLResponseChan() chan ngraphql.NodeGraphQLSideResp + + // NodeStateChan returns the channel for node execution status events. + // Pass this to the FlowRunner via FlowEventChannels.NodeStates. + NodeStateChan() chan runner.FlowNodeStatus + + // Start begins the drain goroutines that process responses and status events. + // Must be called before the flow runner starts. + Start() + + // Wait blocks until all processing is complete. + // The runner must have finished (closing NodeStateChan) before Wait returns. + // Wait also closes the response channels and waits for their drains. + Wait() +} + +// ServerResultProcessorOpts configures a ServerResultProcessor. +type ServerResultProcessorOpts struct { + FlowID idwrap.IDWrap + WorkspaceID idwrap.IDWrap + + // Flow data — maps are built internally from these + Nodes []mflow.Node + Edges []mflow.Edge + NodeIDMapping map[string]idwrap.IDWrap // original → versioned node ID mapping + + // Services for persistence + HTTPResponseService shttp.HttpResponseService + GraphQLResponseService sgraphql.GraphQLResponseService + NodeExecutionService *sflow.NodeExecutionService + NodeService *sflow.NodeService + EdgeService *sflow.EdgeService + + // Event publishing + Publisher EventPublisher + Logger *slog.Logger +} + +// ServerResultProcessor coordinates response persistence (ResponseDrain) +// and execution state tracking (ExecutionStateTracker) during flow execution. +type ServerResultProcessor struct { + drain *ResponseDrain + tracker *ExecutionStateTracker +} + +var _ ResultProcessor = (*ServerResultProcessor)(nil) + +// NewServerResultProcessor creates a processor that persists execution results +// and publishes real-time events for connected clients. +func NewServerResultProcessor(opts ServerResultProcessorOpts) *ServerResultProcessor { + bufSize := len(opts.Nodes)*2 + 1 + + // Build lookup maps from raw flow data + nodeKindMap := make(map[idwrap.IDWrap]mflow.NodeKind, len(opts.Nodes)) + for _, node := range opts.Nodes { + nodeKindMap[node.ID] = node.NodeKind + } + edgesBySource := make(map[idwrap.IDWrap][]mflow.Edge, len(opts.Edges)) + for _, edge := range opts.Edges { + edgesBySource[edge.SourceID] = append(edgesBySource[edge.SourceID], edge) + } + inverseNodeIDMap := make(map[string]idwrap.IDWrap, len(opts.NodeIDMapping)) + for k, v := range opts.NodeIDMapping { + inverseNodeIDMap[v.String()] = idwrap.NewTextMust(k) + } + + drain := newResponseDrain(ResponseDrainOpts{ + WorkspaceID: opts.WorkspaceID, + BufSize: bufSize, + HTTPResponseService: opts.HTTPResponseService, + GraphQLResponseService: opts.GraphQLResponseService, + Publisher: opts.Publisher, + Logger: opts.Logger, + }) + + tracker := newExecutionStateTracker(ExecutionStateTrackerOpts{ + FlowID: opts.FlowID, + BufSize: bufSize, + NodeKindMap: nodeKindMap, + EdgesBySource: edgesBySource, + InverseNodeIDMap: inverseNodeIDMap, + Drain: drain, + NodeExecutionService: opts.NodeExecutionService, + NodeService: opts.NodeService, + EdgeService: opts.EdgeService, + Publisher: opts.Publisher, + Logger: opts.Logger, + }) + + return &ServerResultProcessor{ + drain: drain, + tracker: tracker, + } +} + +func (p *ServerResultProcessor) HTTPResponseChan() chan nrequest.NodeRequestSideResp { + return p.drain.httpChan +} + +func (p *ServerResultProcessor) GraphQLResponseChan() chan ngraphql.NodeGraphQLSideResp { + return p.drain.gqlChan +} + +func (p *ServerResultProcessor) NodeStateChan() chan runner.FlowNodeStatus { + return p.tracker.stateChan +} + +func (p *ServerResultProcessor) Start() { + // Background context: persistence must outlive flow cancellation + ctx := context.Background() + p.drain.start(ctx) + p.tracker.start(ctx) +} + +// Wait blocks until all processing completes. +// Order: state tracker finishes (nodeStateChan closed by runner) → +// close response channels → response drains finish. +func (p *ServerResultProcessor) Wait() { + p.tracker.wait() + p.drain.closeAndWait() +} diff --git a/packages/server/pkg/flow/flowresult/publisher.go b/packages/server/pkg/flow/flowresult/publisher.go new file mode 100644 index 000000000..f0009867f --- /dev/null +++ b/packages/server/pkg/flow/flowresult/publisher.go @@ -0,0 +1,28 @@ +// Package flowresult handles the side effects of flow execution: +// response persistence, execution state tracking, and event publishing. +package flowresult + +import ( + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/runner" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mgraphql" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mhttp" +) + +// EventPublisher abstracts the event stream publishing that happens during flow execution. +// The rflowv2 package provides the concrete implementation backed by eventstream.SyncStreamer. +type EventPublisher interface { + PublishHTTPResponse(response mhttp.HTTPResponse, workspaceID idwrap.IDWrap) + PublishHTTPResponseHeader(header mhttp.HTTPResponseHeader, workspaceID idwrap.IDWrap) + PublishHTTPResponseAssert(assert mhttp.HTTPResponseAssert, workspaceID idwrap.IDWrap) + + PublishGraphQLResponse(response mgraphql.GraphQLResponse, workspaceID idwrap.IDWrap) + PublishGraphQLResponseHeader(header mgraphql.GraphQLResponseHeader, workspaceID idwrap.IDWrap) + PublishGraphQLResponseAssert(assert mgraphql.GraphQLResponseAssert, workspaceID idwrap.IDWrap) + + PublishExecution(eventType string, execution mflow.NodeExecution, flowID idwrap.IDWrap) + PublishNodeState(flowID, originalNodeID idwrap.IDWrap, state mflow.NodeState, info string) + PublishEdgeState(edge mflow.Edge) + PublishLog(flowID idwrap.IDWrap, status runner.FlowNodeStatus) +} diff --git a/packages/server/pkg/flow/flowresult/statetracker.go b/packages/server/pkg/flow/flowresult/statetracker.go new file mode 100644 index 000000000..1550ccb3b --- /dev/null +++ b/packages/server/pkg/flow/flowresult/statetracker.go @@ -0,0 +1,247 @@ +package flowresult + +import ( + "context" + "encoding/json" + "fmt" + "log/slog" + "sync" + "time" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/runner" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sflow" +) + +// ExecutionStateTracker handles node execution lifecycle events: +// - Persists NodeExecution records (with dedup via execution cache) +// - Updates node and edge states in the database +// - Waits for response signals from ResponseDrain before publishing execution events +// - Publishes node state, edge state, and log events +type ExecutionStateTracker struct { + flowID idwrap.IDWrap + + nodeKindMap map[idwrap.IDWrap]mflow.NodeKind + edgesBySource map[idwrap.IDWrap][]mflow.Edge + inverseNodeIDMap map[string]idwrap.IDWrap + + stateChan chan runner.FlowNodeStatus + + drain *ResponseDrain + + nodeExecSvc *sflow.NodeExecutionService + nodeSvc *sflow.NodeService + edgeSvc *sflow.EdgeService + + publisher EventPublisher + logger *slog.Logger + + wg sync.WaitGroup +} + +// ExecutionStateTrackerOpts configures an ExecutionStateTracker. +type ExecutionStateTrackerOpts struct { + FlowID idwrap.IDWrap + BufSize int + + NodeKindMap map[idwrap.IDWrap]mflow.NodeKind + EdgesBySource map[idwrap.IDWrap][]mflow.Edge + InverseNodeIDMap map[string]idwrap.IDWrap + + Drain *ResponseDrain + + NodeExecutionService *sflow.NodeExecutionService + NodeService *sflow.NodeService + EdgeService *sflow.EdgeService + + Publisher EventPublisher + Logger *slog.Logger +} + +func newExecutionStateTracker(opts ExecutionStateTrackerOpts) *ExecutionStateTracker { + return &ExecutionStateTracker{ + flowID: opts.FlowID, + nodeKindMap: opts.NodeKindMap, + edgesBySource: opts.EdgesBySource, + inverseNodeIDMap: opts.InverseNodeIDMap, + stateChan: make(chan runner.FlowNodeStatus, opts.BufSize), + drain: opts.Drain, + nodeExecSvc: opts.NodeExecutionService, + nodeSvc: opts.NodeService, + edgeSvc: opts.EdgeService, + publisher: opts.Publisher, + logger: opts.Logger, + } +} + +func (t *ExecutionStateTracker) start(ctx context.Context) { + t.wg.Add(1) + go t.run(ctx) +} + +func (t *ExecutionStateTracker) wait() { + t.wg.Wait() +} + +func (t *ExecutionStateTracker) run(ctx context.Context) { + defer t.wg.Done() + + // Execution cache: prevents duplicate NodeExecution creation for same iteration + executionCache := make(map[string]idwrap.IDWrap) + + for status := range t.stateChan { + t.processStatus(ctx, status, executionCache) + } +} + +func (t *ExecutionStateTracker) processStatus(ctx context.Context, status runner.FlowNodeStatus, executionCache map[string]idwrap.IDWrap) { + // Find the original node ID if this is a versioned ID + originalNodeID := status.NodeID + if origID, ok := t.inverseNodeIDMap[status.NodeID.String()]; ok { + originalNodeID = origID + } + + // Check if this is a loop coordinator wrapper status + nodeKind := t.nodeKindMap[status.NodeID] + isLoopNode := nodeKind == mflow.NODE_KIND_FOR || nodeKind == mflow.NODE_KIND_FOR_EACH || nodeKind == mflow.NODE_KIND_WS_CONNECTION + skipExecution := isLoopNode && !status.IterationEvent + + // Persist execution state (skip for loop node wrapper statuses) + if !skipExecution { + t.persistExecution(ctx, status, executionCache) + } + + // Update node state in database + if err := t.nodeSvc.UpdateNodeState(ctx, status.NodeID, status.State); err != nil { + t.logger.Error("failed to update node state", "node_id", status.NodeID.String(), "error", err) + } + + // Update edge states based on node execution state + if status.State == mflow.NODE_STATE_SUCCESS || status.State == mflow.NODE_STATE_FAILURE { + edgesFromNode := t.edgesBySource[status.NodeID] + edgeState := mflow.NODE_STATE_SUCCESS + if status.State == mflow.NODE_STATE_FAILURE { + edgeState = mflow.NODE_STATE_FAILURE + } + for _, edge := range edgesFromNode { + if err := t.edgeSvc.UpdateEdgeState(ctx, edge.ID, edgeState); err != nil { + t.logger.Error("failed to update edge state", "edge_id", edge.ID.String(), "error", err) + } else { + updatedEdge := edge + updatedEdge.State = edgeState + t.publisher.PublishEdgeState(updatedEdge) + } + } + } + + // Publish node state event (map versioned ID back to original for live sync) + var info string + if status.Error != nil { + info = status.Error.Error() + } else { + iterIndex := -1 + if status.IterationEvent { + iterIndex = status.IterationIndex + } else if status.IterationContext != nil { + iterIndex = status.IterationContext.ExecutionIndex + } + if iterIndex >= 0 { + info = fmt.Sprintf("Iter: %d", iterIndex+1) + } + } + t.publisher.PublishNodeState(t.flowID, originalNodeID, status.State, info) + + // Publish log event for terminal states + if status.State != mflow.NODE_STATE_RUNNING { + t.publisher.PublishLog(t.flowID, status) + } +} + +func (t *ExecutionStateTracker) persistExecution(ctx context.Context, status runner.FlowNodeStatus, executionCache map[string]idwrap.IDWrap) { + execID := status.ExecutionID + isNewExecution := false + + if isZeroID(execID) { + // Construct cache key based on node and iteration context + cacheKey := status.NodeID.String() + if status.IterationContext != nil { + cacheKey = fmt.Sprintf("%s:%v:%d", cacheKey, status.IterationContext.IterationPath, status.IterationContext.ExecutionIndex) + } else if status.IterationIndex >= 0 { + cacheKey = fmt.Sprintf("%s:%d", cacheKey, status.IterationIndex) + } + + if cachedID, ok := executionCache[cacheKey]; ok { + execID = cachedID + } else { + execID = idwrap.NewMonotonic() + executionCache[cacheKey] = execID + isNewExecution = true + } + } + + executionName := fmt.Sprintf("%s - %s", status.Name, time.Now().Format("2006-01-02 15:04")) + + model := mflow.NodeExecution{ + ID: execID, + NodeID: status.NodeID, + Name: executionName, + State: status.State, + } + + // Set the appropriate response ID based on node kind + nodeKindForAux := t.nodeKindMap[status.NodeID] + if status.AuxiliaryID != nil { + if nodeKindForAux == mflow.NODE_KIND_GRAPHQL { + model.GraphQLResponseID = status.AuxiliaryID + } else { + model.ResponseID = status.AuxiliaryID + } + } + + if status.Error != nil { + errStr := status.Error.Error() + model.Error = &errStr + } + + if status.InputData != nil { + if b, err := json.Marshal(status.InputData); err == nil { + _ = model.SetInputJSON(b) + } + } + if status.OutputData != nil { + if b, err := json.Marshal(status.OutputData); err == nil { + _ = model.SetOutputJSON(b) + } + } + + // Set CompletedAt for terminal states + if status.State == mflow.NODE_STATE_SUCCESS || + status.State == mflow.NODE_STATE_FAILURE || + status.State == mflow.NODE_STATE_CANCELED { + now := time.Now().Unix() + model.CompletedAt = &now + } + + eventType := "insert" + if !isNewExecution && (status.State == mflow.NODE_STATE_SUCCESS || + status.State == mflow.NODE_STATE_FAILURE || + status.State == mflow.NODE_STATE_CANCELED) { + eventType = "update" + } + + if err := t.nodeExecSvc.UpsertNodeExecution(ctx, model); err != nil { + t.logger.Error("failed to persist node execution", "error", err) + } + + // Wait for response to be published before publishing execution event + if status.AuxiliaryID != nil { + t.drain.WaitForResponse(status.AuxiliaryID.String()) + } + + t.publisher.PublishExecution(eventType, model, t.flowID) +} + +func isZeroID(id idwrap.IDWrap) bool { + return id == idwrap.IDWrap{} +} diff --git a/packages/server/pkg/flow/node/entry.go b/packages/server/pkg/flow/node/entry.go new file mode 100644 index 000000000..7cf1e625e --- /dev/null +++ b/packages/server/pkg/flow/node/entry.go @@ -0,0 +1,26 @@ +//nolint:revive // exported +package node + +// EntryNode marks a node as a valid flow entry point (no incoming edges expected). +// The runner collects all EntryNodes and starts them concurrently. +type EntryNode interface { + FlowNode + IsEntryNode() bool +} + +// ListenerEntry is an entry node that runs for the flow's lifetime, +// receiving events in a loop (e.g., WebSocket Connection). +// It implements LoopCoordinator so the runner doesn't apply per-node timeout. +type ListenerEntry interface { + EntryNode + LoopCoordinator +} + +// TriggerEntry is an entry node whose external event initiates the flow run. +// Examples: Webhook (HTTP request triggers flow), Queue (message triggers flow). +// The trigger payload is written to VarMap before downstream nodes execute. +type TriggerEntry interface { + EntryNode + // TriggerType returns a string identifier for the trigger kind (e.g., "webhook", "queue"). + TriggerType() string +} diff --git a/packages/server/pkg/flow/node/nfor/nfor_test.go b/packages/server/pkg/flow/node/nfor/nfor_test.go index e8e2cc7e0..813411261 100644 --- a/packages/server/pkg/flow/node/nfor/nfor_test.go +++ b/packages/server/pkg/flow/node/nfor/nfor_test.go @@ -98,7 +98,7 @@ func TestNodeForDefaultErrorDoesNotLogLoopFailure(t *testing.T) { }, } - flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), loopID, map[idwrap.IDWrap]node.FlowNode{ + flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), []idwrap.IDWrap{loopID}, map[idwrap.IDWrap]node.FlowNode{ loopID: loop, childID: child, }, edgeMap, 0, nil) @@ -165,7 +165,7 @@ func TestNodeForSetsIterationEventFlag(t *testing.T) { }, } - flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), loopID, map[idwrap.IDWrap]node.FlowNode{ + flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), []idwrap.IDWrap{loopID}, map[idwrap.IDWrap]node.FlowNode{ loopID: loop, }, edgeMap, 0, nil) @@ -225,7 +225,7 @@ func TestNodeForSkipsDuplicateLoopEntryTargets(t *testing.T) { flowRunner := flowlocalrunner.CreateFlowRunner( idwrap.NewNow(), idwrap.NewNow(), - loopID, + []idwrap.IDWrap{loopID}, map[idwrap.IDWrap]node.FlowNode{ loopID: loop, nodeAID: nodeA, diff --git a/packages/server/pkg/flow/node/nforeach/nforeach_test.go b/packages/server/pkg/flow/node/nforeach/nforeach_test.go index a2f744921..f8d71c471 100644 --- a/packages/server/pkg/flow/node/nforeach/nforeach_test.go +++ b/packages/server/pkg/flow/node/nforeach/nforeach_test.go @@ -101,7 +101,7 @@ func TestNodeForEachDefaultErrorDoesNotLogLoopFailure(t *testing.T) { }, } - flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), loopID, map[idwrap.IDWrap]node.FlowNode{ + flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), []idwrap.IDWrap{loopID}, map[idwrap.IDWrap]node.FlowNode{ loopID: loop, childID: child, }, edgeMap, 0, nil) @@ -167,7 +167,7 @@ func TestNodeForEachSetsIterationEventFlag(t *testing.T) { }, } - flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), loopID, map[idwrap.IDWrap]node.FlowNode{ + flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), []idwrap.IDWrap{loopID}, map[idwrap.IDWrap]node.FlowNode{ loopID: loop, }, edgeMap, 0, nil) @@ -228,7 +228,7 @@ func TestNodeForEachSkipsDuplicateLoopEntryTargets(t *testing.T) { flowRunner := flowlocalrunner.CreateFlowRunner( idwrap.NewNow(), idwrap.NewNow(), - loopID, + []idwrap.IDWrap{loopID}, map[idwrap.IDWrap]node.FlowNode{ loopID: loop, nodeAID: nodeA, diff --git a/packages/server/pkg/flow/node/node.go b/packages/server/pkg/flow/node/node.go index 7435e8295..c7dc06894 100644 --- a/packages/server/pkg/flow/node/node.go +++ b/packages/server/pkg/flow/node/node.go @@ -56,6 +56,7 @@ type FlowNodeRequest struct { Timeout time.Duration LogPushFunc LogPushFunc PendingAtmoicMap map[idwrap.IDWrap]uint32 + PendingMapMu *sync.Mutex // Thread-safe pending map across concurrent entry chains VariableTracker *tracking.VariableTracker // Optional tracking for input/output data IterationContext *runner.IterationContext // For hierarchical execution naming in loops ExecutionID idwrap.IDWrap // Unique ID for this specific execution of the node @@ -239,36 +240,44 @@ func FilterLoopEntryNodes(edgeMap mflow.EdgesMap, loopTargets []idwrap.IDWrap) [ // When the requested targets already match the existing loop edges, the // original map is returned to avoid unnecessary allocations. func BuildLoopExecutionEdgeMap(edgeMap mflow.EdgesMap, loopNodeID idwrap.IDWrap, loopTargets []idwrap.IDWrap) mflow.EdgesMap { - if len(loopTargets) == 0 { + return BuildHandleExecutionEdgeMap(edgeMap, loopNodeID, mflow.HandleLoop, loopTargets) +} + +// BuildHandleExecutionEdgeMap returns an edge map suitable for executing a +// sub-chain connected via the given handle. It rewrites the handle on nodeID +// to include only the provided targets so duplicate edges to downstream nodes +// do not participate in scheduling decisions. +func BuildHandleExecutionEdgeMap(edgeMap mflow.EdgesMap, nodeID idwrap.IDWrap, handle mflow.EdgeHandle, targets []idwrap.IDWrap) mflow.EdgesMap { + if len(targets) == 0 { return edgeMap } - loopHandles, ok := edgeMap[loopNodeID] + handles, ok := edgeMap[nodeID] if ok { - if current, ok := loopHandles[mflow.HandleLoop]; ok && equalIDSlice(current, loopTargets) { + if current, ok := handles[handle]; ok && equalIDSlice(current, targets) { return edgeMap } } cloned := make(mflow.EdgesMap, len(edgeMap)) - for sourceID, handles := range edgeMap { - handleMap := make(map[mflow.EdgeHandle][]idwrap.IDWrap, len(handles)) - for handle, targets := range handles { - if sourceID == loopNodeID && handle == mflow.HandleLoop { - handleMap[handle] = append([]idwrap.IDWrap(nil), loopTargets...) + for sourceID, srcHandles := range edgeMap { + handleMap := make(map[mflow.EdgeHandle][]idwrap.IDWrap, len(srcHandles)) + for h, t := range srcHandles { + if sourceID == nodeID && h == handle { + handleMap[h] = append([]idwrap.IDWrap(nil), targets...) continue } - handleMap[handle] = append([]idwrap.IDWrap(nil), targets...) + handleMap[h] = append([]idwrap.IDWrap(nil), t...) } cloned[sourceID] = handleMap } - if _, exists := cloned[loopNodeID]; !exists { - cloned[loopNodeID] = map[mflow.EdgeHandle][]idwrap.IDWrap{ - mflow.HandleLoop: append([]idwrap.IDWrap(nil), loopTargets...), + if _, exists := cloned[nodeID]; !exists { + cloned[nodeID] = map[mflow.EdgeHandle][]idwrap.IDWrap{ + handle: append([]idwrap.IDWrap(nil), targets...), } - } else if _, ok := cloned[loopNodeID][mflow.HandleLoop]; !ok { - cloned[loopNodeID][mflow.HandleLoop] = append([]idwrap.IDWrap(nil), loopTargets...) + } else if _, ok := cloned[nodeID][handle]; !ok { + cloned[nodeID][handle] = append([]idwrap.IDWrap(nil), targets...) } return cloned diff --git a/packages/server/pkg/flow/node/nstart/nstart.go b/packages/server/pkg/flow/node/nstart/nstart.go index 66aa616bc..5763090ba 100644 --- a/packages/server/pkg/flow/node/nstart/nstart.go +++ b/packages/server/pkg/flow/node/nstart/nstart.go @@ -41,6 +41,10 @@ func (nr *NodeStart) RunSync(ctx context.Context, req *node.FlowNodeRequest) nod } } +func (nr *NodeStart) IsEntryNode() bool { + return true +} + func (nr *NodeStart) RunAsync(ctx context.Context, req *node.FlowNodeRequest, resultChan chan node.FlowNodeResult) { nextID := mflow.GetNextNodeID(req.EdgeSourceMap, nr.FlowNodeID, mflow.HandleUnspecified) diff --git a/packages/server/pkg/flow/node/nwait/nwait.go b/packages/server/pkg/flow/node/nwait/nwait.go new file mode 100644 index 000000000..4cdf44f4a --- /dev/null +++ b/packages/server/pkg/flow/node/nwait/nwait.go @@ -0,0 +1,51 @@ +//nolint:revive // exported +package nwait + +import ( + "context" + "time" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +type NodeWait struct { + FlowNodeID idwrap.IDWrap + Name string + DurationMs int64 +} + +func New(id idwrap.IDWrap, name string, durationMs int64) *NodeWait { + return &NodeWait{ + FlowNodeID: id, + Name: name, + DurationMs: durationMs, + } +} + +func (n *NodeWait) GetID() idwrap.IDWrap { + return n.FlowNodeID +} + +func (n *NodeWait) GetName() string { + return n.Name +} + +func (n *NodeWait) RunSync(ctx context.Context, req *node.FlowNodeRequest) node.FlowNodeResult { + timer := time.NewTimer(time.Duration(n.DurationMs) * time.Millisecond) + defer timer.Stop() + + select { + case <-ctx.Done(): + return node.FlowNodeResult{Err: ctx.Err()} + case <-timer.C: + } + + nextID := mflow.GetNextNodeID(req.EdgeSourceMap, n.FlowNodeID, mflow.HandleUnspecified) + return node.FlowNodeResult{NextNodeID: nextID} +} + +func (n *NodeWait) RunAsync(ctx context.Context, req *node.FlowNodeRequest, resultChan chan node.FlowNodeResult) { + resultChan <- n.RunSync(ctx, req) +} diff --git a/packages/server/pkg/flow/node/nwsconnection/nwsconnection.go b/packages/server/pkg/flow/node/nwsconnection/nwsconnection.go new file mode 100644 index 000000000..9aa6ba0fc --- /dev/null +++ b/packages/server/pkg/flow/node/nwsconnection/nwsconnection.go @@ -0,0 +1,291 @@ +//nolint:revive // exported +package nwsconnection + +import ( + "context" + "fmt" + "net/http" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/expression" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/runner" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/runner/flowlocalrunner" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" + "github.com/coder/websocket" +) + +// Compile-time check that NodeWsConnection implements VariableIntrospector. +var _ node.VariableIntrospector = (*NodeWsConnection)(nil) + +// NodeWsConnection is a listener entry node that connects to a WebSocket +// and dispatches HandleWsMessage chains for each incoming message. +type NodeWsConnection struct { + FlowNodeID idwrap.IDWrap + Name string + URL string + Headers map[string]string +} + +func New(id idwrap.IDWrap, name string, url string, headers map[string]string) *NodeWsConnection { + return &NodeWsConnection{ + FlowNodeID: id, + Name: name, + URL: url, + Headers: headers, + } +} + +func (n *NodeWsConnection) GetID() idwrap.IDWrap { + return n.FlowNodeID +} + +func (n *NodeWsConnection) SetID(id idwrap.IDWrap) { + n.FlowNodeID = id +} + +func (n *NodeWsConnection) GetName() string { + return n.Name +} + +// IsEntryNode marks this as a valid flow entry point (no incoming edges). +func (n *NodeWsConnection) IsEntryNode() bool { + return true +} + +// IsLoopCoordinator prevents the runner from applying per-node timeout. +func (n *NodeWsConnection) IsLoopCoordinator() bool { + return true +} + +// GetRequiredVariables implements node.VariableIntrospector. +func (n *NodeWsConnection) GetRequiredVariables() []string { + sources := []string{n.URL} + for _, v := range n.Headers { + sources = append(sources, v) + } + return expression.ExtractVarKeysFromMultiple(sources...) +} + +// GetOutputVariables implements node.VariableIntrospector. +func (n *NodeWsConnection) GetOutputVariables() []string { + return []string{ + "url", + "connected", + "lastMessage", + } +} + +func (n *NodeWsConnection) RunSync(ctx context.Context, req *node.FlowNodeRequest) node.FlowNodeResult { + // Interpolate URL with variables + varMapCopy := node.DeepCopyVarMap(req) + env := newExprEnv(varMapCopy) + url, err := env.InterpolateCtx(ctx, n.URL) + if err != nil { + return node.FlowNodeResult{Err: fmt.Errorf("interpolate url: %w", err)} + } + + // Build HTTP headers + httpHeaders := http.Header{} + for k, v := range n.Headers { + interpolatedVal, err := env.InterpolateCtx(ctx, v) + if err != nil { + return node.FlowNodeResult{Err: fmt.Errorf("interpolate header %s: %w", k, err)} + } + httpHeaders.Set(k, interpolatedVal) + } + + // Dial WebSocket + conn, resp, err := websocket.Dial(ctx, url, &websocket.DialOptions{ + HTTPHeader: httpHeaders, + }) + if resp != nil && resp.Body != nil { + _ = resp.Body.Close() + } + if err != nil { + return node.FlowNodeResult{Err: fmt.Errorf("websocket dial %s: %w", url, err)} + } + + closeConn := func() { + _ = conn.Close(websocket.StatusNormalClosure, "") + } + + // Store connection in VarMap so WsSend nodes can use it + writeVar := func(key string, v any) error { + if req.VariableTracker != nil { + return node.WriteNodeVarWithTracking(req, n.Name, key, v, req.VariableTracker) + } + return node.WriteNodeVar(req, n.Name, key, v) + } + if err := writeVar("url", url); err != nil { + closeConn() + return node.FlowNodeResult{Err: fmt.Errorf("write url var: %w", err)} + } + if err := writeVar("connected", true); err != nil { + closeConn() + return node.FlowNodeResult{Err: fmt.Errorf("write connected var: %w", err)} + } + // Store the actual connection object (internal, not tracked) + if err := node.WriteNodeVar(req, n.Name, "_conn", conn); err != nil { + closeConn() + return node.FlowNodeResult{Err: fmt.Errorf("write conn var: %w", err)} + } + nextID := mflow.GetNextNodeID(req.EdgeSourceMap, n.FlowNodeID, mflow.HandleUnspecified) + + // Check for HandleWsMessage targets — if present, read messages and dispatch child chains + msgTargets := mflow.GetNextNodeID(req.EdgeSourceMap, n.FlowNodeID, mflow.HandleWsMessage) + + // No HandleWsMessage targets — just read and log messages passively + if msgTargets == nil { + go func() { + defer conn.Close(websocket.StatusNormalClosure, "done") //nolint:errcheck // best-effort cleanup + var msgIndex int + for { + select { + case <-ctx.Done(): + return + default: + } + _, msg, err := conn.Read(ctx) + if err != nil { + return + } + msgStr := string(msg) + _ = node.WriteNodeVar(req, n.Name, "lastMessage", msgStr) + + if req.LogPushFunc != nil { + executionID := idwrap.NewMonotonic() + req.LogPushFunc(runner.FlowNodeStatus{ + ExecutionID: executionID, + NodeID: n.FlowNodeID, + Name: fmt.Sprintf("%s Message %d", n.Name, msgIndex+1), + State: mflow.NODE_STATE_SUCCESS, + OutputData: map[string]any{"type": "received", "index": msgIndex, "message": msgStr}, + IterationEvent: true, + IterationIndex: msgIndex, + LoopNodeID: n.FlowNodeID, + }) + } + msgIndex++ + } + }() + return node.FlowNodeResult{NextNodeID: nextID} + } + + msgTargets = node.FilterLoopEntryNodes(req.EdgeSourceMap, msgTargets) + msgEdgeMap := node.BuildHandleExecutionEdgeMap(req.EdgeSourceMap, n.FlowNodeID, mflow.HandleWsMessage, msgTargets) + predecessorMap := flowlocalrunner.BuildPredecessorMap(msgEdgeMap) + pendingTemplate := node.BuildPendingMap(predecessorMap) + + // Read messages in a loop until context cancellation, executing the message handler chain per message + go func() { + defer conn.Close(websocket.StatusNormalClosure, "done") //nolint:errcheck // best-effort cleanup + var msgIndex int + for { + select { + case <-ctx.Done(): + return + default: + } + _, msg, err := conn.Read(ctx) + if err != nil { + return + } + + msgStr := string(msg) + _ = node.WriteNodeVar(req, n.Name, "lastMessage", msgStr) + + executionID := idwrap.NewMonotonic() + + // Build iteration context for this message + var parentPath []int + var parentNodes []idwrap.IDWrap + var parentLabels []runner.IterationLabel + if req.IterationContext != nil { + parentPath = req.IterationContext.IterationPath + parentNodes = req.IterationContext.ParentNodes + parentLabels = node.CloneIterationLabels(req.IterationContext.Labels) + } + labels := make([]runner.IterationLabel, len(parentLabels), len(parentLabels)+1) + copy(labels, parentLabels) + labels = append(labels, runner.IterationLabel{ + NodeID: n.FlowNodeID, + Name: n.Name, + Iteration: msgIndex + 1, + }) + iterContext := &runner.IterationContext{ + IterationPath: append(parentPath, msgIndex), + ParentNodes: append(parentNodes, n.FlowNodeID), + Labels: labels, + } + + executionName := fmt.Sprintf("%s Message %d", n.Name, msgIndex+1) + if req.LogPushFunc != nil { + req.LogPushFunc(runner.FlowNodeStatus{ + ExecutionID: executionID, + NodeID: n.FlowNodeID, + Name: executionName, + State: mflow.NODE_STATE_RUNNING, + OutputData: map[string]any{"type": "received", "index": msgIndex, "message": msgStr}, + IterationEvent: true, + IterationIndex: msgIndex, + LoopNodeID: n.FlowNodeID, + IterationContext: iterContext, + }) + } + + // Execute message handler chain + var iterErr error + for _, targetID := range msgTargets { + childIterCtx := &runner.IterationContext{ + IterationPath: append([]int(nil), iterContext.IterationPath...), + ExecutionIndex: msgIndex, + ParentNodes: append([]idwrap.IDWrap(nil), iterContext.ParentNodes...), + Labels: node.CloneIterationLabels(iterContext.Labels), + } + + childReq := *req + childReq.EdgeSourceMap = msgEdgeMap + childReq.PendingAtmoicMap = node.ClonePendingMap(pendingTemplate) + childReq.IterationContext = childIterCtx + childReq.ExecutionID = idwrap.NewMonotonic() + + if err := flowlocalrunner.RunNodeSync(ctx, targetID, &childReq, req.LogPushFunc, predecessorMap); err != nil { + iterErr = err + break + } + } + + if req.LogPushFunc != nil { + state := mflow.NODE_STATE_SUCCESS + if iterErr != nil { + state = mflow.NODE_STATE_FAILURE + } + req.LogPushFunc(runner.FlowNodeStatus{ + ExecutionID: executionID, + NodeID: n.FlowNodeID, + Name: executionName, + State: state, + Error: iterErr, + OutputData: map[string]any{"type": "received", "index": msgIndex, "message": msgStr}, + IterationEvent: true, + IterationIndex: msgIndex, + LoopNodeID: n.FlowNodeID, + IterationContext: iterContext, + }) + } + + msgIndex++ + } + }() + + return node.FlowNodeResult{NextNodeID: nextID} +} + +func (n *NodeWsConnection) RunAsync(ctx context.Context, req *node.FlowNodeRequest, resultChan chan node.FlowNodeResult) { + resultChan <- n.RunSync(ctx, req) +} + +func newExprEnv(varMap map[string]any) *expression.UnifiedEnv { + return expression.NewUnifiedEnv(varMap) +} diff --git a/packages/server/pkg/flow/node/nwsconnection/nwsconnection_test.go b/packages/server/pkg/flow/node/nwsconnection/nwsconnection_test.go new file mode 100644 index 000000000..3c4aa6290 --- /dev/null +++ b/packages/server/pkg/flow/node/nwsconnection/nwsconnection_test.go @@ -0,0 +1,204 @@ +package nwsconnection + +import ( + "context" + "net/http" + "net/http/httptest" + "strings" + "sync" + "testing" + "time" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/runner" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" + "github.com/coder/websocket" +) + +// echoServer creates a test WS server that echoes messages back. +func echoServer(t *testing.T) *httptest.Server { + t.Helper() + return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + conn, err := websocket.Accept(w, r, nil) + if err != nil { + t.Logf("accept error: %v", err) + return + } + defer conn.Close(websocket.StatusNormalClosure, "") + for { + typ, msg, err := conn.Read(r.Context()) + if err != nil { + return + } + if err := conn.Write(r.Context(), typ, msg); err != nil { + return + } + } + })) +} + +// wsURL converts an httptest server URL to a ws:// URL. +func wsURL(s *httptest.Server) string { + return "ws" + strings.TrimPrefix(s.URL, "http") +} + +func newReq(edgeMap mflow.EdgesMap, nodeMap map[idwrap.IDWrap]node.FlowNode) *node.FlowNodeRequest { + return &node.FlowNodeRequest{ + VarMap: make(map[string]any), + ReadWriteLock: &sync.RWMutex{}, + NodeMap: nodeMap, + EdgeSourceMap: edgeMap, + Timeout: 10 * time.Second, + PendingAtmoicMap: make(map[idwrap.IDWrap]uint32), + PendingMapMu: &sync.Mutex{}, + } +} + +func TestNodeWsConnection_Connect(t *testing.T) { + srv := echoServer(t) + defer srv.Close() + + nodeID := idwrap.NewNow() + n := New(nodeID, "MyWS", wsURL(srv), nil) + + req := newReq(mflow.EdgesMap{}, nil) + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + result := n.RunSync(ctx, req) + if result.Err != nil { + t.Fatalf("RunSync error: %v", result.Err) + } + + // Verify url variable + urlVal, err := node.ReadNodeVar(req, "MyWS", "url") + if err != nil { + t.Fatalf("read url var: %v", err) + } + if urlVal != wsURL(srv) { + t.Errorf("url = %v, want %v", urlVal, wsURL(srv)) + } + + // Verify connected variable + connectedVal, err := node.ReadNodeVar(req, "MyWS", "connected") + if err != nil { + t.Fatalf("read connected var: %v", err) + } + if connectedVal != true { + t.Errorf("connected = %v, want true", connectedVal) + } + + // Verify _conn is a *websocket.Conn + connVal, err := node.ReadNodeVar(req, "MyWS", "_conn") + if err != nil { + t.Fatalf("read _conn var: %v", err) + } + if _, ok := connVal.(*websocket.Conn); !ok { + t.Errorf("_conn type = %T, want *websocket.Conn", connVal) + } + + cancel() // Clean up WS connection +} + +func TestNodeWsConnection_PassiveMessageLogging(t *testing.T) { + srv := echoServer(t) + defer srv.Close() + + nodeID := idwrap.NewNow() + n := New(nodeID, "MyWS", wsURL(srv), nil) + + var statuses []runner.FlowNodeStatus + var mu sync.Mutex + logFunc := node.LogPushFunc(func(s runner.FlowNodeStatus) { + mu.Lock() + defer mu.Unlock() + statuses = append(statuses, s) + }) + + req := newReq(mflow.EdgesMap{}, nil) + req.LogPushFunc = logFunc + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + result := n.RunSync(ctx, req) + if result.Err != nil { + t.Fatalf("RunSync error: %v", result.Err) + } + + // Get the connection and send a message to trigger the passive listener + connVal, _ := node.ReadNodeVar(req, "MyWS", "_conn") + conn := connVal.(*websocket.Conn) + + if err := conn.Write(ctx, websocket.MessageText, []byte("hello")); err != nil { + t.Fatalf("write: %v", err) + } + + // Wait for the echo to be read and logged + time.Sleep(200 * time.Millisecond) + + // Verify lastMessage was set + lastMsg, err := node.ReadNodeVar(req, "MyWS", "lastMessage") + if err != nil { + t.Fatalf("read lastMessage: %v", err) + } + if lastMsg != "hello" { + t.Errorf("lastMessage = %v, want hello", lastMsg) + } + + // Verify a status was emitted + mu.Lock() + count := len(statuses) + mu.Unlock() + if count == 0 { + t.Error("expected at least one status event for the echoed message") + } + + cancel() +} + +func TestNodeWsConnection_DialError(t *testing.T) { + nodeID := idwrap.NewNow() + n := New(nodeID, "MyWS", "ws://127.0.0.1:1", nil) // nothing listening + + req := newReq(mflow.EdgesMap{}, nil) + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + + result := n.RunSync(ctx, req) + if result.Err == nil { + t.Fatal("expected error for bad dial") + } +} + +func TestNodeWsConnection_URLInterpolation(t *testing.T) { + srv := echoServer(t) + defer srv.Close() + + nodeID := idwrap.NewNow() + n := New(nodeID, "MyWS", "{{ baseUrl }}", nil) + + req := newReq(mflow.EdgesMap{}, nil) + req.VarMap["baseUrl"] = wsURL(srv) + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + result := n.RunSync(ctx, req) + if result.Err != nil { + t.Fatalf("RunSync error: %v", result.Err) + } + + urlVal, err := node.ReadNodeVar(req, "MyWS", "url") + if err != nil { + t.Fatalf("read url var: %v", err) + } + if urlVal != wsURL(srv) { + t.Errorf("url = %v, want %v", urlVal, wsURL(srv)) + } + + cancel() +} diff --git a/packages/server/pkg/flow/node/nwssend/nwssend.go b/packages/server/pkg/flow/node/nwssend/nwssend.go new file mode 100644 index 000000000..70c5c91c7 --- /dev/null +++ b/packages/server/pkg/flow/node/nwssend/nwssend.go @@ -0,0 +1,111 @@ +//nolint:revive // exported +package nwssend + +import ( + "context" + "fmt" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/expression" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" + "github.com/coder/websocket" +) + +// Compile-time check that NodeWsSend implements VariableIntrospector. +var _ node.VariableIntrospector = (*NodeWsSend)(nil) + +// NodeWsSend sends a message to a WebSocket connection established by a WsConnection node. +type NodeWsSend struct { + FlowNodeID idwrap.IDWrap + Name string + WsConnectionNodeName string + Message string +} + +func New(id idwrap.IDWrap, name string, wsConnectionNodeName string, message string) *NodeWsSend { + return &NodeWsSend{ + FlowNodeID: id, + Name: name, + WsConnectionNodeName: wsConnectionNodeName, + Message: message, + } +} + +func (n *NodeWsSend) GetID() idwrap.IDWrap { + return n.FlowNodeID +} + +func (n *NodeWsSend) SetID(id idwrap.IDWrap) { + n.FlowNodeID = id +} + +func (n *NodeWsSend) GetName() string { + return n.Name +} + +// GetRequiredVariables implements node.VariableIntrospector. +func (n *NodeWsSend) GetRequiredVariables() []string { + return expression.ExtractVarKeysFromMultiple(n.Message, n.WsConnectionNodeName) +} + +// GetOutputVariables implements node.VariableIntrospector. +func (n *NodeWsSend) GetOutputVariables() []string { + return []string{ + "type", + "message", + "connectionNode", + } +} + +func (n *NodeWsSend) RunSync(ctx context.Context, req *node.FlowNodeRequest) node.FlowNodeResult { + // Interpolate the message template + varMapCopy := node.DeepCopyVarMap(req) + env := expression.NewUnifiedEnv(varMapCopy) + interpolated, err := env.InterpolateCtx(ctx, n.Message) + if err != nil { + return node.FlowNodeResult{Err: fmt.Errorf("interpolate message: %w", err)} + } + + // Read the WebSocket connection from the WsConnection node's VarMap + connRaw, err := node.ReadNodeVar(req, n.WsConnectionNodeName, "_conn") + if err != nil { + return node.FlowNodeResult{Err: fmt.Errorf("read ws connection from node %q: %w", n.WsConnectionNodeName, err)} + } + + conn, ok := connRaw.(*websocket.Conn) + if !ok { + return node.FlowNodeResult{Err: fmt.Errorf("ws connection from node %q is not a valid WebSocket connection", n.WsConnectionNodeName)} + } + + // Send the message + if err := conn.Write(ctx, websocket.MessageText, []byte(interpolated)); err != nil { + return node.FlowNodeResult{Err: fmt.Errorf("websocket write: %w", err)} + } + + // Write the sent message to output vars + writeVar := func(key string, v any) error { + if req.VariableTracker != nil { + return node.WriteNodeVarWithTracking(req, n.Name, key, v, req.VariableTracker) + } + return node.WriteNodeVar(req, n.Name, key, v) + } + if err := writeVar("type", "sent"); err != nil { + return node.FlowNodeResult{Err: fmt.Errorf("write type var: %w", err)} + } + if err := writeVar("message", interpolated); err != nil { + return node.FlowNodeResult{Err: fmt.Errorf("write message var: %w", err)} + } + if err := writeVar("connectionNode", n.WsConnectionNodeName); err != nil { + return node.FlowNodeResult{Err: fmt.Errorf("write connectionNode var: %w", err)} + } + + nextID := mflow.GetNextNodeID(req.EdgeSourceMap, n.FlowNodeID, mflow.HandleUnspecified) + return node.FlowNodeResult{ + NextNodeID: nextID, + } +} + +func (n *NodeWsSend) RunAsync(ctx context.Context, req *node.FlowNodeRequest, resultChan chan node.FlowNodeResult) { + resultChan <- n.RunSync(ctx, req) +} diff --git a/packages/server/pkg/flow/node/nwssend/nwssend_test.go b/packages/server/pkg/flow/node/nwssend/nwssend_test.go new file mode 100644 index 000000000..c724e8461 --- /dev/null +++ b/packages/server/pkg/flow/node/nwssend/nwssend_test.go @@ -0,0 +1,152 @@ +package nwssend + +import ( + "context" + "net/http" + "net/http/httptest" + "strings" + "sync" + "testing" + "time" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" + "github.com/coder/websocket" +) + +// echoServer creates a test WS server that echoes messages back. +func echoServer(t *testing.T) *httptest.Server { + t.Helper() + return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + conn, err := websocket.Accept(w, r, nil) + if err != nil { + return + } + defer conn.Close(websocket.StatusNormalClosure, "") + for { + typ, msg, err := conn.Read(r.Context()) + if err != nil { + return + } + if err := conn.Write(r.Context(), typ, msg); err != nil { + return + } + } + })) +} + +func wsURL(s *httptest.Server) string { + return "ws" + strings.TrimPrefix(s.URL, "http") +} + +func newReq(edgeMap mflow.EdgesMap) *node.FlowNodeRequest { + return &node.FlowNodeRequest{ + VarMap: make(map[string]any), + ReadWriteLock: &sync.RWMutex{}, + EdgeSourceMap: edgeMap, + Timeout: 10 * time.Second, + PendingAtmoicMap: make(map[idwrap.IDWrap]uint32), + PendingMapMu: &sync.Mutex{}, + } +} + +func TestNodeWsSend_Success(t *testing.T) { + srv := echoServer(t) + defer srv.Close() + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + // Establish a real WebSocket connection + conn, _, err := websocket.Dial(ctx, wsURL(srv), nil) + if err != nil { + t.Fatalf("dial: %v", err) + } + defer conn.Close(websocket.StatusNormalClosure, "") + + // Set up the WsSend node + nodeID := idwrap.NewNow() + n := New(nodeID, "SendMsg", "MyWS", "hello world") + + req := newReq(mflow.EdgesMap{}) + // Simulate WsConnection node having stored the connection + _ = node.WriteNodeVar(req, "MyWS", "_conn", conn) + + result := n.RunSync(ctx, req) + if result.Err != nil { + t.Fatalf("RunSync error: %v", result.Err) + } + + // Verify output variables + sentMsg, err := node.ReadNodeVar(req, "SendMsg", "message") + if err != nil { + t.Fatalf("read message: %v", err) + } + if sentMsg != "hello world" { + t.Errorf("message = %v, want hello world", sentMsg) + } + + connNode, err := node.ReadNodeVar(req, "SendMsg", "connectionNode") + if err != nil { + t.Fatalf("read connectionNode: %v", err) + } + if connNode != "MyWS" { + t.Errorf("connectionNode = %v, want MyWS", connNode) + } + + // Read the echo back to confirm message was actually sent + _, msg, err := conn.Read(ctx) + if err != nil { + t.Fatalf("read echo: %v", err) + } + if string(msg) != "hello world" { + t.Errorf("echoed = %v, want hello world", string(msg)) + } +} + +func TestNodeWsSend_Interpolation(t *testing.T) { + srv := echoServer(t) + defer srv.Close() + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + conn, _, err := websocket.Dial(ctx, wsURL(srv), nil) + if err != nil { + t.Fatalf("dial: %v", err) + } + defer conn.Close(websocket.StatusNormalClosure, "") + + nodeID := idwrap.NewNow() + n := New(nodeID, "SendMsg", "MyWS", "hello {{ name }}") + + req := newReq(mflow.EdgesMap{}) + _ = node.WriteNodeVar(req, "MyWS", "_conn", conn) + req.VarMap["name"] = "world" + + result := n.RunSync(ctx, req) + if result.Err != nil { + t.Fatalf("RunSync error: %v", result.Err) + } + + sentMsg, _ := node.ReadNodeVar(req, "SendMsg", "message") + if sentMsg != "hello world" { + t.Errorf("message = %v, want hello world", sentMsg) + } +} + +func TestNodeWsSend_MissingConnection(t *testing.T) { + nodeID := idwrap.NewNow() + n := New(nodeID, "SendMsg", "NonExistent", "hello") + + req := newReq(mflow.EdgesMap{}) + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + + result := n.RunSync(ctx, req) + if result.Err == nil { + t.Fatal("expected error for missing connection node") + } +} diff --git a/packages/server/pkg/flow/runner/flowlocalrunner/executor.go b/packages/server/pkg/flow/runner/flowlocalrunner/executor.go new file mode 100644 index 000000000..ccd34527f --- /dev/null +++ b/packages/server/pkg/flow/runner/flowlocalrunner/executor.go @@ -0,0 +1,67 @@ +package flowlocalrunner + +import ( + "context" + "sync" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/tracking" +) + +// ExecutionOutcome is the raw result from executing a single node, +// including optional tracked variable data. +type ExecutionOutcome struct { + Result node.FlowNodeResult + TrackedInput map[string]any + TrackedOutput map[string]any +} + +// LocalExecutor runs nodes in the current process with optional variable tracking. +// It owns the tracker pool, replacing the previous global variable. +// +// For a remote runner, a RemoteExecutor would serialize the request and dispatch +// to a worker instead of calling RunSync directly. +type LocalExecutor struct { + trackerPool *sync.Pool + trackData bool +} + +// NewLocalExecutor creates an executor with the given data tracking setting. +func NewLocalExecutor(trackData bool) *LocalExecutor { + return &LocalExecutor{ + trackerPool: &sync.Pool{New: func() any { return tracking.NewVariableTracker() }}, + trackData: trackData, + } +} + +// Execute runs a node with optional variable tracking, returning the result +// and any tracked input/output data. +func (e *LocalExecutor) Execute(ctx context.Context, n node.FlowNode, req *node.FlowNodeRequest) ExecutionOutcome { + var tracker *tracking.VariableTracker + if e.trackData { + tracker = e.trackerPool.Get().(*tracking.VariableTracker) + tracker.Reset() + req.VariableTracker = tracker + } else { + req.VariableTracker = nil + } + + result := n.RunSync(ctx, req) + + var trackedInput, trackedOutput map[string]any + if tracker != nil { + trackedOutput = tracker.GetWrittenVarsAsTree() + reads := tracker.GetReadVarsAsTree() + if len(reads) > 0 { + trackedInput = reads + } + tracker.Reset() + e.trackerPool.Put(tracker) + } + + return ExecutionOutcome{ + Result: result, + TrackedInput: trackedInput, + TrackedOutput: trackedOutput, + } +} diff --git a/packages/server/pkg/flow/runner/flowlocalrunner/flowlocalrunner.go b/packages/server/pkg/flow/runner/flowlocalrunner/flowlocalrunner.go index ad658f934..8fae92f62 100644 --- a/packages/server/pkg/flow/runner/flowlocalrunner/flowlocalrunner.go +++ b/packages/server/pkg/flow/runner/flowlocalrunner/flowlocalrunner.go @@ -3,17 +3,17 @@ package flowlocalrunner import ( "context" - "errors" - "fmt" - "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node" - "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/runner" - "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/tracking" - "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" - "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" "log/slog" "runtime" "sync" "time" + + "golang.org/x/sync/errgroup" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/runner" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" ) // ExecutionMode controls how FlowLocalRunner schedules nodes. @@ -25,33 +25,42 @@ const ( ExecutionModeMulti ) -type FlowLocalRunner struct { - ID idwrap.IDWrap - FlowID idwrap.IDWrap - FlowNodeMap map[idwrap.IDWrap]node.FlowNode - PendingAtmoicMap map[idwrap.IDWrap]uint32 +// RunConfig bundles the parameters that both strategies need, reducing the +// parameter count of runNodes and the strategy functions. +type RunConfig struct { + Timeout time.Duration + TrackData bool + MaxConcurrency int + Emitter *runner.StatusEmitter + StatusLogFunc node.LogPushFunc + PredecessorMap map[idwrap.IDWrap][]idwrap.IDWrap +} - EdgesMap mflow.EdgesMap - StartNodeID idwrap.IDWrap +type FlowLocalRunner struct { + ID idwrap.IDWrap + FlowID idwrap.IDWrap + FlowNodeMap map[idwrap.IDWrap]node.FlowNode Timeout time.Duration - mode ExecutionMode - selectedMode ExecutionMode + graph *runner.FlowGraph + maxConcurrency int + mode ExecutionMode + selectedMode ExecutionMode + enableDataTracking bool logger *slog.Logger } var _ runner.FlowRunner = (*FlowLocalRunner)(nil) -func CreateFlowRunner(id, flowID, startNodeID idwrap.IDWrap, flowNodeMap map[idwrap.IDWrap]node.FlowNode, edgesMap mflow.EdgesMap, timeout time.Duration, logger *slog.Logger) *FlowLocalRunner { +func CreateFlowRunner(id, flowID idwrap.IDWrap, startNodeIDs []idwrap.IDWrap, flowNodeMap map[idwrap.IDWrap]node.FlowNode, edgesMap mflow.EdgesMap, timeout time.Duration, logger *slog.Logger) *FlowLocalRunner { return &FlowLocalRunner{ ID: id, FlowID: flowID, - StartNodeID: startNodeID, FlowNodeMap: flowNodeMap, - PendingAtmoicMap: make(map[idwrap.IDWrap]uint32), - EdgesMap: edgesMap, Timeout: timeout, + graph: runner.NewFlowGraph(edgesMap, startNodeIDs), + maxConcurrency: goroutineCount, mode: ExecutionModeAuto, selectedMode: ExecutionModeMulti, enableDataTracking: true, @@ -59,51 +68,6 @@ func CreateFlowRunner(id, flowID, startNodeID idwrap.IDWrap, flowNodeMap map[idw } } -type nodeStatusEmitter struct { - channels runner.FlowEventChannels -} - -func newNodeStatusEmitter(channels runner.FlowEventChannels) *nodeStatusEmitter { - return &nodeStatusEmitter{channels: channels} -} - -func (e *nodeStatusEmitter) emit(status runner.FlowNodeStatus) { - targets := runner.FlowNodeEventTargetState - if status.State != mflow.NODE_STATE_RUNNING { - targets |= runner.FlowNodeEventTargetLog - } - e.emitWithTargets(status, targets) -} - -func (e *nodeStatusEmitter) emitWithTargets(status runner.FlowNodeStatus, targets runner.FlowNodeEventTarget) { - if e == nil { - return - } - event := runner.FlowNodeEvent{ - Status: status, - Targets: targets, - } - if event.ShouldSend(runner.FlowNodeEventTargetState) && e.channels.NodeStates != nil { - e.channels.NodeStates <- event.Status - } - if event.ShouldSend(runner.FlowNodeEventTargetLog) && e.channels.NodeLogs != nil { - payload := runner.FlowNodeLogPayload{ - ExecutionID: status.ExecutionID, - NodeID: status.NodeID, - Name: status.Name, - State: status.State, - Error: status.Error, - OutputData: status.OutputData, - RunDuration: status.RunDuration, - IterationContext: status.IterationContext, - IterationEvent: status.IterationEvent, - IterationIndex: status.IterationIndex, - LoopNodeID: status.LoopNodeID, - } - e.channels.NodeLogs <- payload - } -} - // SetExecutionMode overrides the default Auto mode for the next run. func (r *FlowLocalRunner) SetExecutionMode(mode ExecutionMode) { if mode < ExecutionModeAuto || mode > ExecutionModeMulti { @@ -122,326 +86,50 @@ func (r *FlowLocalRunner) SetDataTrackingEnabled(enabled bool) { r.enableDataTracking = enabled } -func selectExecutionMode(nodeMap map[idwrap.IDWrap]node.FlowNode, edgesMap mflow.EdgesMap) ExecutionMode { - nodeCount := len(nodeMap) - if nodeCount == 0 { - return ExecutionModeSingle - } - - const smallFlowThreshold = 6 - - simpleStructure := true - incomingNonLoop := make(map[idwrap.IDWrap]int) - - for sourceID, handles := range edgesMap { - nonLoopTargets := 0 - for handle, targetIDs := range handles { - if len(targetIDs) == 0 { - continue - } - if handle == mflow.HandleLoop { - if len(targetIDs) > 1 { - simpleStructure = false - } - continue - } - - nonLoopTargets += len(targetIDs) - if len(targetIDs) > 1 { - simpleStructure = false - } - for _, targetID := range targetIDs { - incomingNonLoop[targetID]++ - } - } - if nonLoopTargets > 1 { - simpleStructure = false - } - if _, ok := handles[mflow.HandleLoop]; ok && nonLoopTargets > 0 { - // Loop node with additional branch work beyond the loop/then path - if nonLoopTargets > 1 { - simpleStructure = false - } - } - - if _, exists := nodeMap[sourceID]; !exists { - // Node present in edges but missing from map; treat as complex and bail out - simpleStructure = false - } - } - - for targetID, count := range incomingNonLoop { - if count > 1 { - simpleStructure = false - break - } - if _, exists := nodeMap[targetID]; !exists { - simpleStructure = false - } - } - - if nodeCount <= smallFlowThreshold && simpleStructure { - return ExecutionModeSingle - } - - return ExecutionModeMulti -} - func runNodes(ctx context.Context, startNodeID idwrap.IDWrap, req *node.FlowNodeRequest, - statusLogFunc node.LogPushFunc, predecessorMap map[idwrap.IDWrap][]idwrap.IDWrap, - mode ExecutionMode, timeout time.Duration, trackData bool, + mode ExecutionMode, cfg RunConfig, ) error { + executor := NewLocalExecutor(cfg.TrackData) + tracker := runner.NewConvergenceTrackerFromPending(req.PendingAtmoicMap) + switch mode { case ExecutionModeSingle: - return runNodesSingle(ctx, startNodeID, req, statusLogFunc, predecessorMap, timeout, trackData) - case ExecutionModeMulti: - if timeout == 0 { - return runNodesMultiNoTimeout(ctx, startNodeID, req, statusLogFunc, predecessorMap, trackData) - } - return runNodesMultiWithTimeout(ctx, startNodeID, req, statusLogFunc, predecessorMap, timeout, trackData) + return runNodesSingle(ctx, startNodeID, req, cfg, executor, tracker) default: - if timeout == 0 { - return runNodesMultiNoTimeout(ctx, startNodeID, req, statusLogFunc, predecessorMap, trackData) - } - return runNodesMultiWithTimeout(ctx, startNodeID, req, statusLogFunc, predecessorMap, timeout, trackData) - } -} - -func gatherSingleModeInputData(req *node.FlowNodeRequest, predecessorIDs []idwrap.IDWrap) map[string]any { - if len(predecessorIDs) == 0 { - return nil - } - - inputs := make(map[string]any, len(predecessorIDs)) - for _, predID := range predecessorIDs { - predNode, ok := req.NodeMap[predID] - if !ok { - continue - } - predName := predNode.GetName() - if predName == "" { - continue - } - if data, err := node.ReadVarRaw(req, predName); err == nil { - inputs[predName] = node.DeepCopyValue(data) - } - } - - if len(inputs) == 0 { - return nil - } - return inputs -} - -func collectSingleModeOutput(req *node.FlowNodeRequest, nodeName string) any { - if nodeName == "" { - return nil - } - if data, err := node.ReadVarRaw(req, nodeName); err == nil { - return node.DeepCopyValue(data) - } - return nil -} - -func flattenNodeOutput(nodeName string, output any) any { - if nodeName == "" || output == nil { - return output - } - m, ok := output.(map[string]any) - if !ok { - return output - } - nested, ok := m[nodeName] - if !ok { - return output - } - nestedMap, ok := nested.(map[string]any) - if !ok { - return output - } - delete(m, nodeName) - for k, v := range nestedMap { - if _, exists := m[k]; !exists { - m[k] = v - } - } - return m -} - -func sendQueuedCancellationStatuses(queue []idwrap.IDWrap, req *node.FlowNodeRequest, statusLogFunc node.LogPushFunc, cancelErr error) { - for _, nodeID := range queue { - if nodeRef, ok := req.NodeMap[nodeID]; ok { - statusLogFunc(runner.FlowNodeStatus{ - ExecutionID: idwrap.NewMonotonic(), - NodeID: nodeID, - Name: nodeRef.GetName(), - State: mflow.NODE_STATE_CANCELED, - Error: cancelErr, - IterationContext: req.IterationContext, - }) - } + return runNodesMultiEventDriven(ctx, startNodeID, req, cfg, executor, tracker) } } -func runNodesSingle(ctx context.Context, startNodeID idwrap.IDWrap, req *node.FlowNodeRequest, - statusLogFunc node.LogPushFunc, predecessorMap map[idwrap.IDWrap][]idwrap.IDWrap, - timeout time.Duration, trackData bool, -) error { - queue := []idwrap.IDWrap{startNodeID} - - for len(queue) > 0 { - if ctx.Err() != nil { - sendQueuedCancellationStatuses(queue, req, statusLogFunc, ctx.Err()) - return ctx.Err() - } - - nodeID := queue[0] - queue = queue[1:] - - currentNode, ok := req.NodeMap[nodeID] - if !ok { - return fmt.Errorf("node not found: %v", nodeID) - } - - var inputData map[string]any - if trackData { - inputData = gatherSingleModeInputData(req, predecessorMap[nodeID]) - } - - executionID := idwrap.NewMonotonic() - runningStatus := runner.FlowNodeStatus{ - ExecutionID: executionID, - NodeID: nodeID, - Name: currentNode.GetName(), - State: mflow.NODE_STATE_RUNNING, - IterationContext: req.IterationContext, - } - statusLogFunc(runningStatus) - - nodeReq := *req - nodeReq.ExecutionID = executionID - var tracker *tracking.VariableTracker - if trackData { - tracker = trackerPool.Get().(*tracking.VariableTracker) - tracker.Reset() - nodeReq.VariableTracker = tracker - } else { - nodeReq.VariableTracker = nil - } - - nodeCtx := ctx - cancelNodeCtx := func() {} - if timeout > 0 { - nodeCtx, cancelNodeCtx = context.WithTimeout(ctx, timeout) - } - startTime := time.Now() - - result := processNode(nodeCtx, currentNode, &nodeReq) - - var ( - trackedOutput map[string]any - trackedInput map[string]any - ) - if tracker != nil { - trackedOutput = tracker.GetWrittenVarsAsTree() - reads := tracker.GetReadVarsAsTree() - if len(reads) > 0 { - trackedInput = reads - } - tracker.Reset() - trackerPool.Put(tracker) - } - nodeCtxErr := nodeCtx.Err() - cancelNodeCtx() - - status := runner.FlowNodeStatus{ - ExecutionID: executionID, - NodeID: nodeID, - Name: currentNode.GetName(), - IterationContext: req.IterationContext, - RunDuration: time.Since(startTime), - AuxiliaryID: result.AuxiliaryID, - } - - if trackData { - if len(trackedInput) > 0 { - status.InputData = node.DeepCopyValue(trackedInput) - } else if len(inputData) > 0 { - status.InputData = node.DeepCopyValue(inputData) - } - } - - if result.Err != nil { - if runner.IsCancellationError(result.Err) { - status.State = mflow.NODE_STATE_CANCELED - } else { - status.State = mflow.NODE_STATE_FAILURE - } - status.Error = result.Err - if trackData { - if len(trackedOutput) > 0 { - status.OutputData = node.DeepCopyValue(trackedOutput) - } else { - status.OutputData = collectSingleModeOutput(&nodeReq, currentNode.GetName()) - } - } - status.OutputData = flattenNodeOutput(status.Name, status.OutputData) - statusLogFunc(status) - return result.Err - } - - if nodeCtxErr != nil { - status.State = mflow.NODE_STATE_CANCELED - status.Error = nodeCtxErr - if trackData { - if len(trackedOutput) > 0 { - status.OutputData = node.DeepCopyValue(trackedOutput) - } else { - status.OutputData = collectSingleModeOutput(&nodeReq, currentNode.GetName()) - } - } - status.OutputData = flattenNodeOutput(status.Name, status.OutputData) - statusLogFunc(status) - return nodeCtxErr - } - - if !result.SkipFinalStatus { - status.State = mflow.NODE_STATE_SUCCESS - if trackData { - if len(trackedOutput) > 0 { - status.OutputData = node.DeepCopyValue(trackedOutput) - } else { - status.OutputData = collectSingleModeOutput(&nodeReq, currentNode.GetName()) - } - } - status.OutputData = flattenNodeOutput(status.Name, status.OutputData) - statusLogFunc(status) - } - - for _, nextID := range result.NextNodeID { - if remaining, ok := req.PendingAtmoicMap[nextID]; ok && remaining > 1 { - req.PendingAtmoicMap[nextID] = remaining - 1 - continue - } - queue = append(queue, nextID) - } - } - - return nil -} - // RunNodeSync retains the legacy behaviour for packages that directly invoke the runner. func RunNodeSync(ctx context.Context, startNodeID idwrap.IDWrap, req *node.FlowNodeRequest, statusLogFunc node.LogPushFunc, predecessorMap map[idwrap.IDWrap][]idwrap.IDWrap, ) error { - return runNodes(ctx, startNodeID, req, statusLogFunc, predecessorMap, ExecutionModeMulti, 0, true) + emitter := runner.NewStatusEmitter(func(s runner.FlowNodeStatus) { statusLogFunc(s) }) + cfg := RunConfig{ + Timeout: 0, + TrackData: true, + MaxConcurrency: goroutineCount, + Emitter: emitter, + StatusLogFunc: statusLogFunc, + PredecessorMap: predecessorMap, + } + return runNodes(ctx, startNodeID, req, ExecutionModeMulti, cfg) } // RunNodeASync retains the legacy behaviour for packages that directly invoke the runner with timeouts. func RunNodeASync(ctx context.Context, startNodeID idwrap.IDWrap, req *node.FlowNodeRequest, statusLogFunc node.LogPushFunc, predecessorMap map[idwrap.IDWrap][]idwrap.IDWrap, ) error { - return runNodes(ctx, startNodeID, req, statusLogFunc, predecessorMap, ExecutionModeMulti, req.Timeout, true) + emitter := runner.NewStatusEmitter(func(s runner.FlowNodeStatus) { statusLogFunc(s) }) + cfg := RunConfig{ + Timeout: req.Timeout, + TrackData: true, + MaxConcurrency: goroutineCount, + Emitter: emitter, + StatusLogFunc: statusLogFunc, + PredecessorMap: predecessorMap, + } + return runNodes(ctx, startNodeID, req, ExecutionModeMulti, cfg) } func (r *FlowLocalRunner) Run(ctx context.Context, flowNodeStatusChan chan runner.FlowNodeStatus, flowStatusChan chan runner.FlowStatus, baseVars map[string]any) error { @@ -449,6 +137,10 @@ func (r *FlowLocalRunner) Run(ctx context.Context, flowNodeStatusChan chan runne } func (r *FlowLocalRunner) RunWithEvents(ctx context.Context, channels runner.FlowEventChannels, baseVars map[string]any) error { + // Cancel context before closing channels (LIFO order) so background + // goroutines (e.g., WebSocket readers) get the stop signal first. + ctx, cancel := context.WithCancel(ctx) + defer cancel() if channels.NodeStates != nil { defer close(channels.NodeStates) } @@ -459,53 +151,43 @@ func (r *FlowLocalRunner) RunWithEvents(ctx context.Context, channels runner.Flo defer close(channels.FlowStatus) } - nextNodeID := &r.StartNodeID - - flowEdgeDepCounter := make(map[idwrap.IDWrap]uint32) - for _, v := range r.EdgesMap { - for _, targetIDs := range v { - for _, targetID := range targetIDs { - current, ok := flowEdgeDepCounter[targetID] - if !ok { - flowEdgeDepCounter[targetID] = 0 - } - flowEdgeDepCounter[targetID] = current + 1 - } - } - } - - pendingAtmoicMap := make(map[idwrap.IDWrap]uint32) - for k, v := range flowEdgeDepCounter { - if v > 1 { - pendingAtmoicMap[k] = v - } + // Clone convergence counts for per-execution mutable pending map + pendingAtmoicMap := make(map[idwrap.IDWrap]uint32, len(r.graph.ConvergeCounts)) + for k, v := range r.graph.ConvergeCounts { + pendingAtmoicMap[k] = v } if baseVars == nil { baseVars = make(map[string]any) } - statusEmitter := newNodeStatusEmitter(channels) - statusFunc := node.LogPushFunc(func(runner.FlowNodeStatus) {}) + var emitFn func(runner.FlowNodeStatus) if channels.NodeStates != nil || channels.NodeLogs != nil { - statusFunc = node.LogPushFunc(statusEmitter.emit) + emitFn = runner.NewChannelEmitFunc(channels) + } else { + emitFn = func(runner.FlowNodeStatus) {} } + emitter := runner.NewStatusEmitter(emitFn) + statusFunc := node.LogPushFunc(emitFn) + + // Shared mutex for PendingAtmoicMap across concurrent entry chains + pendingMu := &sync.Mutex{} req := &node.FlowNodeRequest{ VarMap: baseVars, ReadWriteLock: &sync.RWMutex{}, NodeMap: r.FlowNodeMap, - EdgeSourceMap: r.EdgesMap, + EdgeSourceMap: r.graph.Edges, LogPushFunc: statusFunc, Timeout: r.Timeout, PendingAtmoicMap: pendingAtmoicMap, + PendingMapMu: pendingMu, Logger: r.logger, } - predecessorMap := BuildPredecessorMap(r.EdgesMap) mode := r.mode if mode == ExecutionModeAuto { - mode = selectExecutionMode(r.FlowNodeMap, r.EdgesMap) + mode = selectExecutionMode(r.FlowNodeMap, r.graph.Edges) } r.selectedMode = mode @@ -513,7 +195,29 @@ func (r *FlowLocalRunner) RunWithEvents(ctx context.Context, channels runner.Flo channels.FlowStatus <- runner.FlowStatusStarting } - err := runNodes(ctx, *nextNodeID, req, statusFunc, predecessorMap, mode, r.Timeout, r.enableDataTracking) + cfg := RunConfig{ + Timeout: r.Timeout, + TrackData: r.enableDataTracking, + MaxConcurrency: r.maxConcurrency, + Emitter: emitter, + StatusLogFunc: statusFunc, + PredecessorMap: r.graph.Predecessors, + } + + var err error + if len(r.graph.StartNodeIDs) == 1 { + // Single entry — fast path, no errgroup overhead + err = runNodes(ctx, r.graph.StartNodeIDs[0], req, mode, cfg) + } else { + // Multiple entries — run each chain concurrently + eg, egCtx := errgroup.WithContext(ctx) + for _, startID := range r.graph.StartNodeIDs { + eg.Go(func() error { + return runNodes(egCtx, startID, req, mode, cfg) + }) + } + err = eg.Wait() + } if channels.FlowStatus != nil { if err != nil { @@ -525,60 +229,6 @@ func (r *FlowLocalRunner) RunWithEvents(ctx context.Context, channels runner.Flo return err } -type processResult struct { - originalID idwrap.IDWrap - executionID idwrap.IDWrap - nextNodes []idwrap.IDWrap - err error - inputData map[string]any - outputData map[string]any // NEW: From tracker.GetWrittenVars() - skipFinalStatus bool // From FlowNodeResult.SkipFinalStatus - AuxiliaryID *idwrap.IDWrap -} - -func processNode(ctx context.Context, n node.FlowNode, req *node.FlowNodeRequest, -) node.FlowNodeResult { - return n.RunSync(ctx, req) -} - -type FlowNodeStatusLocal struct { - StartTime time.Time -} - -type nodeSignal struct { - once sync.Once - ch chan struct{} -} - -func acquireNodeSignal(signals *sync.Map, id idwrap.IDWrap) *nodeSignal { - val, _ := signals.LoadOrStore(id, &nodeSignal{ch: make(chan struct{})}) - return val.(*nodeSignal) -} - -func waitForPredecessors(ctx context.Context, signals, seen *sync.Map, predecessors []idwrap.IDWrap) error { - for _, predID := range predecessors { - if seen != nil { - if _, ok := seen.Load(predID); !ok { - continue - } - } - sig := acquireNodeSignal(signals, predID) - select { - case <-sig.ch: - case <-ctx.Done(): - return ctx.Err() - } - } - return nil -} - -func signalNodeComplete(signals *sync.Map, id idwrap.IDWrap) { - sig := acquireNodeSignal(signals, id) - sig.once.Do(func() { - close(sig.ch) - }) -} - func MaxParallelism() int { maxProcs := runtime.GOMAXPROCS(0) numCPU := runtime.NumCPU() @@ -588,627 +238,18 @@ func MaxParallelism() int { return numCPU } -var ( - goroutineCount int = MaxParallelism() - trackerPool = sync.Pool{New: func() any { return tracking.NewVariableTracker() }} -) +var goroutineCount = MaxParallelism() -func BuildPredecessorMap(edgesMap mflow.EdgesMap) map[idwrap.IDWrap][]idwrap.IDWrap { - predecessors := make(map[idwrap.IDWrap][]idwrap.IDWrap, len(edgesMap)) - for sourceID, edges := range edgesMap { - for _, targets := range edges { - for _, targetID := range targets { - predecessors[targetID] = append(predecessors[targetID], sourceID) - } - } - } - return predecessors +// SetGoroutineCountForTesting overrides the goroutine count for testing. +// Returns a cleanup function that restores the original value. +func SetGoroutineCountForTesting(n int) func() { + old := goroutineCount + goroutineCount = n + return func() { goroutineCount = old } } -func runNodesMultiNoTimeout(ctx context.Context, startNodeID idwrap.IDWrap, req *node.FlowNodeRequest, - statusLogFunc node.LogPushFunc, - predecessorMap map[idwrap.IDWrap][]idwrap.IDWrap, - trackData bool, -) error { - queue := []idwrap.IDWrap{startNodeID} - - var status runner.FlowNodeStatus - var processCount int - // Mutex to protect PendingAtmoicMap from concurrent access - var pendingMapMutex sync.Mutex - // Track nodes that have been sent RUNNING status but haven't completed - // Map from executionID to the full status for proper state transitions - runningNodes := make(map[idwrap.IDWrap]runner.FlowNodeStatus) - runningNodesMutex := sync.Mutex{} - // Track start times for duration calculation - nodeStartTimes := make(map[idwrap.IDWrap]time.Time) - - // Cleanup function to send CANCELED status for all running/queued nodes - sendCanceledStatuses := func(cancelErr error) { - // Send CANCELED status for any nodes still in RUNNING state - runningNodesMutex.Lock() - for execID, runningStatus := range runningNodes { - // Calculate actual duration if we have a start time - duration := time.Duration(0) - if startTime, ok := nodeStartTimes[execID]; ok { - duration = time.Since(startTime) - } - - canceledStatus := runner.FlowNodeStatus{ - ExecutionID: execID, - NodeID: runningStatus.NodeID, - Name: runningStatus.Name, - State: mflow.NODE_STATE_CANCELED, - Error: cancelErr, - IterationContext: runningStatus.IterationContext, - RunDuration: duration, - } - statusLogFunc(canceledStatus) - } - // Clear the maps after sending all canceled statuses - runningNodes = make(map[idwrap.IDWrap]runner.FlowNodeStatus) - nodeStartTimes = make(map[idwrap.IDWrap]time.Time) - runningNodesMutex.Unlock() - - // Send CANCELED status for any nodes still in the queue - for _, nodeID := range queue { - if node, ok := req.NodeMap[nodeID]; ok { - canceledStatus := runner.FlowNodeStatus{ - ExecutionID: idwrap.NewMonotonic(), - NodeID: nodeID, - Name: node.GetName(), - State: mflow.NODE_STATE_CANCELED, - Error: cancelErr, - IterationContext: req.IterationContext, - } - statusLogFunc(canceledStatus) - } - } - } - - // Ensure we send canceled statuses on any return path - defer func() { - if ctx.Err() != nil { - sendCanceledStatuses(ctx.Err()) - } - }() - - nodeSignals := &sync.Map{} - seenNodes := &sync.Map{} - seenNodes.Store(startNodeID, struct{}{}) - - for queueLen := len(queue); queueLen != 0; queueLen = len(queue) { - // Check if context was cancelled before processing next batch - if ctx.Err() != nil { - return ctx.Err() - } - - processCount = min(goroutineCount, queueLen) - - var wg sync.WaitGroup - resultChan := make(chan processResult, processCount) - - nodeStateMap := make(map[idwrap.IDWrap]FlowNodeStatusLocal, processCount) - - subqueue := queue[:processCount] - - FlowNodeCancelCtx, FlowNodeCancelCtxCancel := context.WithCancel(ctx) - defer FlowNodeCancelCtxCancel() - var batchErr error - for _, flowNodeID := range subqueue { - currentNode, ok := req.NodeMap[flowNodeID] - if !ok { - batchErr = fmt.Errorf("node not found: %v", flowNodeID) - FlowNodeCancelCtxCancel() - break - } - nodeStateMap[flowNodeID] = FlowNodeStatusLocal{StartTime: time.Now()} - seenNodes.Store(flowNodeID, struct{}{}) - wg.Add(1) - go func(nodeID idwrap.IDWrap) { - defer wg.Done() - - if predecessors := predecessorMap[nodeID]; len(predecessors) > 0 { - if err := waitForPredecessors(FlowNodeCancelCtx, nodeSignals, seenNodes, predecessors); err != nil { - resultChan <- processResult{ - originalID: currentNode.GetID(), - executionID: idwrap.IDWrap{}, - err: err, - } - return - } - } - - // Generate execution ID right before processing - executionID := idwrap.NewMonotonic() - - // Log RUNNING status with execution ID - runningStatus := runner.FlowNodeStatus{ - ExecutionID: executionID, - NodeID: nodeID, - Name: currentNode.GetName(), - State: mflow.NODE_STATE_RUNNING, - Error: nil, - IterationContext: req.IterationContext, - } - statusLogFunc(runningStatus) - - // Track this node as running with its start time - runningNodesMutex.Lock() - runningNodes[executionID] = runningStatus - nodeStartTimes[executionID] = time.Now() - runningNodesMutex.Unlock() - - // Create a copy of the request for this execution to avoid race conditions - // This ensures each goroutine has its own tracker and execution ID - nodeReq := *req // Shallow copy of the request struct - - var tracker *tracking.VariableTracker - if trackData { - tracker = trackerPool.Get().(*tracking.VariableTracker) - tracker.Reset() - nodeReq.VariableTracker = tracker - } - - // Set the execution ID in the copied request - nodeReq.ExecutionID = executionID - - result := processNode(FlowNodeCancelCtx, currentNode, &nodeReq) - - // Capture tracked data as tree structures when enabled - var ( - outputData map[string]any - inputData map[string]any - ) - if tracker != nil { - outputData = tracker.GetWrittenVarsAsTree() - trackedReads := tracker.GetReadVarsAsTree() - if len(trackedReads) > 0 { - inputData = trackedReads - } - tracker.Reset() - trackerPool.Put(tracker) - } - - resultChan <- processResult{ - originalID: currentNode.GetID(), - executionID: executionID, - nextNodes: result.NextNodeID, - err: result.Err, - inputData: inputData, - outputData: outputData, - skipFinalStatus: result.SkipFinalStatus, - AuxiliaryID: result.AuxiliaryID, - } - }(flowNodeID) - } - - wg.Wait() - - close(resultChan) - - if batchErr != nil { - // Drain any results from goroutines that ran before the error - for range resultChan { - } - return batchErr - } - - var lastNodeError error - for result := range resultChan { - status.NodeID = result.originalID - status.ExecutionID = result.executionID - currentNode := req.NodeMap[result.originalID] - status.Name = currentNode.GetName() - status.IterationContext = req.IterationContext - nodeState := nodeStateMap[status.NodeID] - status.RunDuration = time.Since(nodeState.StartTime) - status.InputData = nil - status.OutputData = nil - status.AuxiliaryID = result.AuxiliaryID - signalNodeComplete(nodeSignals, result.originalID) - - // Remove from running nodes since we're processing its completion - runningNodesMutex.Lock() - delete(runningNodes, result.executionID) - delete(nodeStartTimes, result.executionID) - runningNodesMutex.Unlock() - - // Prefer node-specific result error over global cancellation status. - // If the node returned an error, report it first; only mark as canceled - // due to global context cancellation when there is no node error. - if result.err != nil { - if runner.IsCancellationError(result.err) { - status.State = mflow.NODE_STATE_CANCELED - } else { - status.State = mflow.NODE_STATE_FAILURE - } - status.Error = result.err - if trackData { - if result.outputData != nil { - status.OutputData = node.DeepCopyValue(result.outputData) - } else { - status.OutputData = collectSingleModeOutput(req, status.Name) - } - if result.inputData != nil { - status.InputData = node.DeepCopyValue(result.inputData) - } - } - status.OutputData = flattenNodeOutput(status.Name, status.OutputData) - statusLogFunc(status) - lastNodeError = result.err - // Trigger cancellation for remaining nodes after reporting this failure - FlowNodeCancelCtxCancel() - continue - } - - if FlowNodeCancelCtx.Err() != nil { - status.State = mflow.NODE_STATE_CANCELED - status.Error = FlowNodeCancelCtx.Err() - if trackData { - // Capture tracked input/output data even for canceled nodes - // This ensures we show what data was read/written before cancellation - if result.inputData != nil { - status.InputData = node.DeepCopyValue(result.inputData) - } - if result.outputData != nil { - status.OutputData = node.DeepCopyValue(result.outputData) - } - } - status.OutputData = flattenNodeOutput(status.Name, status.OutputData) - statusLogFunc(status) - // Remove from running nodes since we've sent the CANCELED status - runningNodesMutex.Lock() - delete(runningNodes, result.executionID) - delete(nodeStartTimes, result.executionID) - runningNodesMutex.Unlock() - continue - } - - // All nodes should report SUCCESS when they complete successfully - // Loop nodes handle their own iteration tracking internally - // FOR/FOREACH nodes set skipFinalStatus to avoid creating empty main execution - if !result.skipFinalStatus { - status.State = mflow.NODE_STATE_SUCCESS - status.Error = nil - if trackData { - // Use the tracked output data which has the proper tree structure - if result.outputData != nil { - status.OutputData = node.DeepCopyValue(result.outputData) - } - // Deep copy input data as well - if result.inputData != nil { - status.InputData = node.DeepCopyValue(result.inputData) - } - } - status.OutputData = flattenNodeOutput(status.Name, status.OutputData) - statusLogFunc(status) - } - - for _, id := range result.nextNodes { - pendingMapMutex.Lock() - i, ok := req.PendingAtmoicMap[id] - if !ok || i == 1 { - pendingMapMutex.Unlock() - queue = append(queue, id) - seenNodes.Store(id, struct{}{}) - } else { - req.PendingAtmoicMap[id] = i - 1 - pendingMapMutex.Unlock() - } - } - } - - if lastNodeError != nil { - return lastNodeError - } - - // Check if flow was canceled - the defer will handle sending CANCELED statuses - if FlowNodeCancelCtx.Err() != nil { - return FlowNodeCancelCtx.Err() - } - - // remove from queue - queue = queue[processCount:] - } - - return nil -} - -// RunNodeASync runs nodes with timeout handling -func runNodesMultiWithTimeout(ctx context.Context, startNodeID idwrap.IDWrap, req *node.FlowNodeRequest, - statusLogFunc node.LogPushFunc, - predecessorMap map[idwrap.IDWrap][]idwrap.IDWrap, - timeout time.Duration, - trackData bool, -) error { - if timeout <= 0 { - return runNodesMultiNoTimeout(ctx, startNodeID, req, statusLogFunc, predecessorMap, trackData) - } - - queue := []idwrap.IDWrap{startNodeID} - - var status runner.FlowNodeStatus - var processCount int - var pendingMapMutex sync.Mutex - runningNodes := make(map[idwrap.IDWrap]runner.FlowNodeStatus) - runningNodesMutex := sync.Mutex{} - nodeStartTimes := make(map[idwrap.IDWrap]time.Time) - - sendCanceledStatuses := func(cancelErr error) { - runningNodesMutex.Lock() - for execID, runningStatus := range runningNodes { - duration := time.Duration(0) - if startTime, ok := nodeStartTimes[execID]; ok { - duration = time.Since(startTime) - } - statusLogFunc(runner.FlowNodeStatus{ - ExecutionID: execID, - NodeID: runningStatus.NodeID, - Name: runningStatus.Name, - State: mflow.NODE_STATE_CANCELED, - Error: cancelErr, - IterationContext: runningStatus.IterationContext, - RunDuration: duration, - }) - } - runningNodes = make(map[idwrap.IDWrap]runner.FlowNodeStatus) - nodeStartTimes = make(map[idwrap.IDWrap]time.Time) - runningNodesMutex.Unlock() - - for _, nodeID := range queue { - if nodeRef, ok := req.NodeMap[nodeID]; ok { - statusLogFunc(runner.FlowNodeStatus{ - ExecutionID: idwrap.NewMonotonic(), - NodeID: nodeID, - Name: nodeRef.GetName(), - State: mflow.NODE_STATE_CANCELED, - Error: cancelErr, - IterationContext: req.IterationContext, - }) - } - } - } - - defer func() { - if ctx.Err() != nil { - sendCanceledStatuses(ctx.Err()) - } - }() - - nodeSignals := &sync.Map{} - seenNodes := &sync.Map{} - seenNodes.Store(startNodeID, struct{}{}) - - for queueLen := len(queue); queueLen != 0; queueLen = len(queue) { - if ctx.Err() != nil { - return ctx.Err() - } - - processCount = min(goroutineCount, queueLen) - - var wg sync.WaitGroup - resultChan := make(chan processResult, processCount) - timeStart := make(map[idwrap.IDWrap]time.Time, processCount) - - batch := queue[:processCount] - flowCtx, flowCancel := context.WithCancel(ctx) - defer flowCancel() - - var batchErr error - for _, nodeID := range batch { - currentNode, ok := req.NodeMap[nodeID] - if !ok { - batchErr = fmt.Errorf("node not found: %v", nodeID) - flowCancel() - break - } - - timeStart[nodeID] = time.Now() - seenNodes.Store(nodeID, struct{}{}) - - wg.Add(1) - go func(nodeID idwrap.IDWrap, flowNode node.FlowNode) { - defer wg.Done() - - if predecessors := predecessorMap[nodeID]; len(predecessors) > 0 { - if err := waitForPredecessors(flowCtx, nodeSignals, seenNodes, predecessors); err != nil { - resultChan <- processResult{originalID: flowNode.GetID(), err: err} - return - } - } - - executionID := idwrap.NewMonotonic() - - runningStatus := runner.FlowNodeStatus{ - ExecutionID: executionID, - NodeID: nodeID, - Name: flowNode.GetName(), - State: mflow.NODE_STATE_RUNNING, - Error: nil, - IterationContext: req.IterationContext, - } - statusLogFunc(runningStatus) - - runningNodesMutex.Lock() - runningNodes[executionID] = runningStatus - nodeStartTimes[executionID] = time.Now() - runningNodesMutex.Unlock() - - nodeReq := *req - - var tracker *tracking.VariableTracker - if trackData { - tracker = trackerPool.Get().(*tracking.VariableTracker) - tracker.Reset() - nodeReq.VariableTracker = tracker - } - - nodeReq.ExecutionID = executionID - - nodeCtx := flowCtx - var cancelNode context.CancelFunc - if timeout > 0 { - if _, isLoop := flowNode.(node.LoopCoordinator); !isLoop { - nodeCtx, cancelNode = context.WithTimeout(flowCtx, timeout) - } - } - if cancelNode != nil { - defer cancelNode() - } - - result := processNode(nodeCtx, flowNode, &nodeReq) - - var ( - outputData map[string]any - inputData map[string]any - ) - if tracker != nil { - outputData = tracker.GetWrittenVarsAsTree() - trackedReads := tracker.GetReadVarsAsTree() - if len(trackedReads) > 0 { - inputData = trackedReads - } - tracker.Reset() - trackerPool.Put(tracker) - } - - if result.Err == nil && errors.Is(nodeCtx.Err(), context.DeadlineExceeded) { - result.Err = nodeCtx.Err() - } - - resultChan <- processResult{ - originalID: flowNode.GetID(), - executionID: executionID, - nextNodes: result.NextNodeID, - err: result.Err, - inputData: inputData, - outputData: outputData, - skipFinalStatus: result.SkipFinalStatus, - AuxiliaryID: result.AuxiliaryID, - } - }(nodeID, currentNode) - } - - wg.Wait() - close(resultChan) - - if batchErr != nil { - for range resultChan { - } - return batchErr - } - - queue = queue[processCount:] - - var lastNodeError error - timedOut := false - - for result := range resultChan { - status.NodeID = result.originalID - status.ExecutionID = result.executionID - currentNode := req.NodeMap[result.originalID] - status.Name = currentNode.GetName() - status.IterationContext = req.IterationContext - status.RunDuration = time.Since(timeStart[status.NodeID]) - status.InputData = nil - status.OutputData = nil - status.AuxiliaryID = result.AuxiliaryID - _, isLoop := currentNode.(node.LoopCoordinator) - - signalNodeComplete(nodeSignals, result.originalID) - - runningNodesMutex.Lock() - delete(runningNodes, result.executionID) - delete(nodeStartTimes, result.executionID) - runningNodesMutex.Unlock() - - if result.err != nil { - if errors.Is(result.err, context.DeadlineExceeded) { - timedOut = true - } - if runner.IsCancellationError(result.err) { - status.State = mflow.NODE_STATE_CANCELED - } else { - status.State = mflow.NODE_STATE_FAILURE - } - status.Error = result.err - if trackData { - if result.outputData != nil { - status.OutputData = node.DeepCopyValue(result.outputData) - } else { - status.OutputData = collectSingleModeOutput(req, status.Name) - } - if result.inputData != nil { - status.InputData = node.DeepCopyValue(result.inputData) - } - } - status.OutputData = flattenNodeOutput(status.Name, status.OutputData) - statusLogFunc(status) - lastNodeError = result.err - continue - } - - if flowCtx.Err() != nil && !isLoop { - status.State = mflow.NODE_STATE_CANCELED - status.Error = flowCtx.Err() - if trackData { - if result.inputData != nil { - status.InputData = node.DeepCopyValue(result.inputData) - } - if result.outputData != nil { - status.OutputData = node.DeepCopyValue(result.outputData) - } - } - status.OutputData = flattenNodeOutput(status.Name, status.OutputData) - statusLogFunc(status) - timedOut = true - continue - } - - if !result.skipFinalStatus { - status.State = mflow.NODE_STATE_SUCCESS - status.Error = nil - if trackData { - if result.outputData != nil { - status.OutputData = node.DeepCopyValue(result.outputData) - } - if result.inputData != nil { - status.InputData = node.DeepCopyValue(result.inputData) - } - } - status.OutputData = flattenNodeOutput(status.Name, status.OutputData) - statusLogFunc(status) - } - - for _, id := range result.nextNodes { - pendingMapMutex.Lock() - i, ok := req.PendingAtmoicMap[id] - if !ok || i == 1 { - pendingMapMutex.Unlock() - queue = append(queue, id) - seenNodes.Store(id, struct{}{}) - } else { - req.PendingAtmoicMap[id] = i - 1 - pendingMapMutex.Unlock() - } - } - } - - if lastNodeError != nil { - return lastNodeError - } - - if cancelErr := flowCtx.Err(); cancelErr != nil { - if !timedOut { - return cancelErr - } - } - - if timedOut { - return context.DeadlineExceeded - } - } - - return nil +// BuildPredecessorMap forwards to runner.BuildPredecessorMap. +// Kept for backward compatibility with node packages (nfor, nforeach, nwsconnection, nai). +func BuildPredecessorMap(edgesMap mflow.EdgesMap) map[idwrap.IDWrap][]idwrap.IDWrap { + return runner.BuildPredecessorMap(edgesMap) } diff --git a/packages/server/pkg/flow/runner/flowlocalrunner/flowlocalrunner_inputdata_test.go b/packages/server/pkg/flow/runner/flowlocalrunner/flowlocalrunner_inputdata_test.go index a3e6f7f4e..6a93ed48e 100644 --- a/packages/server/pkg/flow/runner/flowlocalrunner/flowlocalrunner_inputdata_test.go +++ b/packages/server/pkg/flow/runner/flowlocalrunner/flowlocalrunner_inputdata_test.go @@ -88,7 +88,7 @@ func TestFlowLocalRunnerEmitsInputDataForTrackedReads(t *testing.T) { runnerID := idwrap.NewNow() flowID := idwrap.NewNow() - fr := CreateFlowRunner(runnerID, flowID, startID, nodeMap, edgesMap, 0, nil) + fr := CreateFlowRunner(runnerID, flowID, []idwrap.IDWrap{startID}, nodeMap, edgesMap, 0, nil) nodeStates := make(chan runner.FlowNodeStatus, 10) flowStatus := make(chan runner.FlowStatus, 2) @@ -225,7 +225,7 @@ func TestFlowLocalRunnerRequestNodeEmitsInputData(t *testing.T) { runnerID := idwrap.NewNow() flowID := idwrap.NewNow() - fr := CreateFlowRunner(runnerID, flowID, startID, nodeMap, edgesMap, 0, nil) + fr := CreateFlowRunner(runnerID, flowID, []idwrap.IDWrap{startID}, nodeMap, edgesMap, 0, nil) nodeStates := make(chan runner.FlowNodeStatus, 10) flowStatus := make(chan runner.FlowStatus, 2) @@ -372,7 +372,7 @@ func TestFlowLocalRunnerRequestNodeEmitsInputDataForBodyOnlyVariables(t *testing runnerID := idwrap.NewNow() flowID := idwrap.NewNow() - fr := CreateFlowRunner(runnerID, flowID, startID, nodeMap, edgesMap, 0, nil) + fr := CreateFlowRunner(runnerID, flowID, []idwrap.IDWrap{startID}, nodeMap, edgesMap, 0, nil) nodeStates := make(chan runner.FlowNodeStatus, 10) flowStatus := make(chan runner.FlowStatus, 2) diff --git a/packages/server/pkg/flow/runner/flowlocalrunner/flowlocalrunner_test.go b/packages/server/pkg/flow/runner/flowlocalrunner/flowlocalrunner_test.go index 77fe05a58..14017c74c 100644 --- a/packages/server/pkg/flow/runner/flowlocalrunner/flowlocalrunner_test.go +++ b/packages/server/pkg/flow/runner/flowlocalrunner/flowlocalrunner_test.go @@ -275,7 +275,7 @@ func TestFlowLocalRunnerEmitsLogEvents(t *testing.T) { }, } - flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), startID, nodeMap, edgesMap, 0, nil) + flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), []idwrap.IDWrap{startID}, nodeMap, edgesMap, 0, nil) stateChan := make(chan runner.FlowNodeStatus, 8) logChan := make(chan runner.FlowNodeLogPayload, 8) @@ -343,7 +343,7 @@ func TestFlowLocalRunnerMultiFailureIncludesOutputData(t *testing.T) { }, } - flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), startID, nodeMap, edgesMap, 0, nil) + flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), []idwrap.IDWrap{startID}, nodeMap, edgesMap, 0, nil) flowRunner.SetExecutionMode(flowlocalrunner.ExecutionModeMulti) stateChan := make(chan runner.FlowNodeStatus, 8) @@ -539,7 +539,7 @@ func TestLoopNodeEmitsFinalSuccessStatus(t *testing.T) { nodeID: loopNode, } edgesMap := make(mflow.EdgesMap) - flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), nodeID, nodeMap, edgesMap, 0, nil) + flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), []idwrap.IDWrap{nodeID}, nodeMap, edgesMap, 0, nil) statusChan := make(chan runner.FlowNodeStatus, 8) flowStatusChan := make(chan runner.FlowStatus, 2) @@ -590,7 +590,7 @@ func BenchmarkFlowRunnerForLoopWithMockRequest(b *testing.B) { }, } - flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), loopID, nodeMap, edgesMap, 0, nil) + flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), []idwrap.IDWrap{loopID}, nodeMap, edgesMap, 0, nil) b.ResetTimer() for i := 0; i < b.N; i++ { @@ -615,7 +615,7 @@ func TestFlowLocalRunnerSingleModeSequential(t *testing.T) { } runnerID := idwrap.NewNow() - flowRunner := flowlocalrunner.CreateFlowRunner(runnerID, idwrap.NewNow(), startID, nodeMap, edgesMap, 0, nil) + flowRunner := flowlocalrunner.CreateFlowRunner(runnerID, idwrap.NewNow(), []idwrap.IDWrap{startID}, nodeMap, edgesMap, 0, nil) flowRunner.SetExecutionMode(flowlocalrunner.ExecutionModeSingle) statusChan := make(chan runner.FlowNodeStatus, 16) @@ -690,7 +690,7 @@ func TestFlowLocalRunnerMultiModeConcurrentExecution(t *testing.T) { rightNode.GetID(): map[mflow.EdgeHandle][]idwrap.IDWrap{}, } - flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), startID, nodeMap, edgesMap, 0, nil) + flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), []idwrap.IDWrap{startID}, nodeMap, edgesMap, 0, nil) flowRunner.SetExecutionMode(flowlocalrunner.ExecutionModeMulti) statusChan := make(chan runner.FlowNodeStatus, 16) @@ -738,7 +738,7 @@ func TestFlowLocalRunnerMultiModeConcurrentExecution(t *testing.T) { func TestFlowLocalRunnerAutoModeSelection(t *testing.T) { linearStart, linearNodeMap, linearEdges, _ := buildLinearStubFlow(3, false) - linearRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), linearStart, linearNodeMap, linearEdges, 0, nil) + linearRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), []idwrap.IDWrap{linearStart}, linearNodeMap, linearEdges, 0, nil) statusChan := make(chan runner.FlowNodeStatus, 8) flowStatusChan := make(chan runner.FlowStatus, 4) @@ -755,7 +755,7 @@ func TestFlowLocalRunnerAutoModeSelection(t *testing.T) { } branchStart, branchNodes, branchEdges := buildBranchingStubFlow() - branchRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), branchStart, branchNodes, branchEdges, 0, nil) + branchRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), []idwrap.IDWrap{branchStart}, branchNodes, branchEdges, 0, nil) statusChan = make(chan runner.FlowNodeStatus, 8) flowStatusChan = make(chan runner.FlowStatus, 4) @@ -786,7 +786,7 @@ func TestFlowLocalRunnerAutoModeSelection(t *testing.T) { bodyID: map[mflow.EdgeHandle][]idwrap.IDWrap{}, } - loopRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), loopID, loopNodes, loopEdges, 0, nil) + loopRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), []idwrap.IDWrap{loopID}, loopNodes, loopEdges, 0, nil) statusChan = make(chan runner.FlowNodeStatus, 8) flowStatusChan = make(chan runner.FlowStatus, 4) if err := loopRunner.Run(context.Background(), statusChan, flowStatusChan, nil); err != nil { @@ -823,7 +823,7 @@ func TestFlowLocalRunnerAutoModeSelection(t *testing.T) { bodyBID: map[mflow.EdgeHandle][]idwrap.IDWrap{}, } - complexRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), loopID2, complexNodes, complexEdges, 0, nil) + complexRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), []idwrap.IDWrap{loopID2}, complexNodes, complexEdges, 0, nil) statusChan = make(chan runner.FlowNodeStatus, 8) flowStatusChan = make(chan runner.FlowStatus, 4) if err := complexRunner.Run(context.Background(), statusChan, flowStatusChan, nil); err != nil { @@ -841,7 +841,7 @@ func TestFlowLocalRunnerAutoModeSelection(t *testing.T) { func TestFlowLocalRunnerModeOverride(t *testing.T) { startID, nodeMap, edgesMap, _ := buildLinearStubFlow(2, false) - flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), startID, nodeMap, edgesMap, 0, nil) + flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), []idwrap.IDWrap{startID}, nodeMap, edgesMap, 0, nil) flowRunner.SetExecutionMode(flowlocalrunner.ExecutionModeMulti) statusChan := make(chan runner.FlowNodeStatus, 8) @@ -880,7 +880,7 @@ func TestLoopCoordinatorPerNodeTimeout(t *testing.T) { bodyID: map[mflow.EdgeHandle][]idwrap.IDWrap{}, } - flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), loopID, nodeMap, edgesMap, perNodeTimeout, nil) + flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), []idwrap.IDWrap{loopID}, nodeMap, edgesMap, perNodeTimeout, nil) flowRunner.SetExecutionMode(flowlocalrunner.ExecutionModeMulti) stateChan := make(chan runner.FlowNodeStatus, 64) @@ -933,7 +933,7 @@ func benchmarkBlockingFlow(b *testing.B, mode flowlocalrunner.ExecutionMode, wid edgesMap[startID][mflow.HandleUnspecified] = append([]idwrap.IDWrap(nil), branchIDs...) startNode.next = append([]idwrap.IDWrap(nil), branchIDs...) - flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), startID, nodeMap, edgesMap, 0, nil) + flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), []idwrap.IDWrap{startID}, nodeMap, edgesMap, 0, nil) flowRunner.SetExecutionMode(mode) statusChan := make(chan runner.FlowNodeStatus, width*4) @@ -978,7 +978,7 @@ func runExecutionModeBenchmark(b *testing.B, startID idwrap.IDWrap, nodeMap map[ b.ResetTimer() for i := 0; i < b.N; i++ { - flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), startID, nodeMap, edgesMap, 0, nil) + flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), []idwrap.IDWrap{startID}, nodeMap, edgesMap, 0, nil) flowRunner.SetExecutionMode(mode) statusChan := make(chan runner.FlowNodeStatus, len(nodeMap)*4) @@ -1041,3 +1041,338 @@ func BenchmarkFlowLocalRunnerLoopFlow(b *testing.B) { runExecutionModeBenchmark(b, startID, nodeMap, edgesMap, flowlocalrunner.ExecutionModeAuto) }) } + +// TestEventDrivenIndependentBranches verifies that independent branches don't +// block each other. When START → [FAST, SLOW] and FAST → FAST_CHILD, FAST_CHILD +// should start executing while SLOW is still running. +func TestEventDrivenIndependentBranches(t *testing.T) { + slowRelease := make(chan struct{}) + slowNode := newBlockingNode("slow", slowRelease) + + fastID := idwrap.NewNow() + fastChildID := idwrap.NewNow() + fastChild := newBlockingNode("fast_child", nil) // completes immediately + + startID := idwrap.NewNow() + startNode := &stubNode{ + id: startID, + name: "start", + next: []idwrap.IDWrap{fastID, slowNode.GetID()}, + } + fastNode := &stubNode{ + id: fastID, + name: "fast", + next: []idwrap.IDWrap{fastChildID}, + } + + nodeMap := map[idwrap.IDWrap]node.FlowNode{ + startID: startNode, + fastID: fastNode, + slowNode.GetID(): slowNode, + fastChildID: fastChild, + } + edgesMap := mflow.EdgesMap{ + startID: {mflow.HandleUnspecified: []idwrap.IDWrap{fastID, slowNode.GetID()}}, + fastID: {mflow.HandleUnspecified: []idwrap.IDWrap{fastChildID}}, + slowNode.GetID(): {}, + fastChildID: {}, + } + + flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), []idwrap.IDWrap{startID}, nodeMap, edgesMap, 0, nil) + flowRunner.SetExecutionMode(flowlocalrunner.ExecutionModeMulti) + + statusChan := make(chan runner.FlowNodeStatus, 32) + flowStatusChan := make(chan runner.FlowStatus, 4) + errCh := make(chan error, 1) + + go func() { + errCh <- flowRunner.Run(context.Background(), statusChan, flowStatusChan, nil) + }() + + // Wait for fast_child to start — this proves it didn't wait for slow + waitForStart(t, fastChild.started, "fast_child") + + // At this point, slow should still be running (it's blocked) + waitForStart(t, slowNode.started, "slow") + + // Release slow so the flow can complete + close(slowRelease) + + if err := <-errCh; err != nil { + t.Fatalf("flow runner returned error: %v", err) + } + + for range statusChan { + } + for range flowStatusChan { + } +} + +// blockingStubNode combines blocking behavior with next-node return. +type blockingStubNode struct { + id idwrap.IDWrap + name string + release <-chan struct{} + started chan struct{} + once sync.Once + next []idwrap.IDWrap +} + +func newBlockingStubNode(name string, release <-chan struct{}, next []idwrap.IDWrap) *blockingStubNode { + return &blockingStubNode{ + id: idwrap.NewNow(), + name: name, + release: release, + started: make(chan struct{}), + next: next, + } +} + +func (b *blockingStubNode) GetID() idwrap.IDWrap { return b.id } +func (b *blockingStubNode) GetName() string { return b.name } + +func (b *blockingStubNode) RunSync(ctx context.Context, _ *node.FlowNodeRequest) node.FlowNodeResult { + b.once.Do(func() { close(b.started) }) + if b.release != nil { + select { + case <-b.release: + case <-ctx.Done(): + return node.FlowNodeResult{Err: ctx.Err()} + } + } + return node.FlowNodeResult{NextNodeID: append([]idwrap.IDWrap(nil), b.next...)} +} + +func (b *blockingStubNode) RunAsync(ctx context.Context, req *node.FlowNodeRequest, resultChan chan node.FlowNodeResult) { + resultChan <- b.RunSync(ctx, req) +} + +// TestEventDrivenDiamondConvergence verifies that converge points still wait for +// all predecessors. In START → [A, B] → JOIN, JOIN only executes after both +// A and B complete. +func TestEventDrivenDiamondConvergence(t *testing.T) { + joinID := idwrap.NewNow() + + releaseA := make(chan struct{}) + releaseB := make(chan struct{}) + nodeA := newBlockingStubNode("a", releaseA, []idwrap.IDWrap{joinID}) + nodeB := newBlockingStubNode("b", releaseB, []idwrap.IDWrap{joinID}) + + joinNode := newBlockingStubNode("join", nil, nil) + // Override the auto-generated ID to use our pre-declared joinID + joinNode.id = joinID + + startID := idwrap.NewNow() + startNode := &stubNode{ + id: startID, + name: "start", + next: []idwrap.IDWrap{nodeA.GetID(), nodeB.GetID()}, + } + + nodeMap := map[idwrap.IDWrap]node.FlowNode{ + startID: startNode, + nodeA.GetID(): nodeA, + nodeB.GetID(): nodeB, + joinID: joinNode, + } + edgesMap := mflow.EdgesMap{ + startID: {mflow.HandleUnspecified: []idwrap.IDWrap{nodeA.GetID(), nodeB.GetID()}}, + nodeA.GetID(): {mflow.HandleUnspecified: []idwrap.IDWrap{joinID}}, + nodeB.GetID(): {mflow.HandleUnspecified: []idwrap.IDWrap{joinID}}, + joinID: {}, + } + + flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), []idwrap.IDWrap{startID}, nodeMap, edgesMap, 0, nil) + flowRunner.SetExecutionMode(flowlocalrunner.ExecutionModeMulti) + + statusChan := make(chan runner.FlowNodeStatus, 32) + flowStatusChan := make(chan runner.FlowStatus, 4) + errCh := make(chan error, 1) + + go func() { + errCh <- flowRunner.Run(context.Background(), statusChan, flowStatusChan, nil) + }() + + // Wait for A and B to start + waitForStart(t, nodeA.started, "a") + waitForStart(t, nodeB.started, "b") + + // Release B first — JOIN should NOT start yet (A is still blocked) + close(releaseB) + time.Sleep(50 * time.Millisecond) + + select { + case <-joinNode.started: + t.Fatal("join started before all predecessors completed") + default: + // Good — join hasn't started yet + } + + // Release A — NOW join should start + close(releaseA) + waitForStart(t, joinNode.started, "join") + + if err := <-errCh; err != nil { + t.Fatalf("flow runner returned error: %v", err) + } + + for range statusChan { + } + for range flowStatusChan { + } +} + +// TestEventDrivenErrorCancelsOtherBranches verifies that when one branch fails, +// other in-flight branches are canceled. +func TestEventDrivenErrorCancelsOtherBranches(t *testing.T) { + slowRelease := make(chan struct{}) + slowNode := newBlockingNode("slow", slowRelease) + defer close(slowRelease) + + failID := idwrap.NewNow() + failNode := newFailingNode(failID, "fail", nil, errors.New("boom")) + + startID := idwrap.NewNow() + startNode := &stubNode{ + id: startID, + name: "start", + next: []idwrap.IDWrap{failID, slowNode.GetID()}, + } + + nodeMap := map[idwrap.IDWrap]node.FlowNode{ + startID: startNode, + failID: failNode, + slowNode.GetID(): slowNode, + } + edgesMap := mflow.EdgesMap{ + startID: {mflow.HandleUnspecified: []idwrap.IDWrap{failID, slowNode.GetID()}}, + failID: {}, + slowNode.GetID(): {}, + } + + flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), []idwrap.IDWrap{startID}, nodeMap, edgesMap, 0, nil) + flowRunner.SetExecutionMode(flowlocalrunner.ExecutionModeMulti) + + statusChan := make(chan runner.FlowNodeStatus, 32) + flowStatusChan := make(chan runner.FlowStatus, 4) + + err := flowRunner.Run(context.Background(), statusChan, flowStatusChan, nil) + require.Error(t, err) + + statuses := drainStates(statusChan) + _ = drainFlowStatus(flowStatusChan) + + // Verify the failing node reported FAILURE + foundFailure := false + foundCanceled := false + for _, s := range statuses { + if s.NodeID == failID && s.State == mflow.NODE_STATE_FAILURE { + foundFailure = true + } + if s.NodeID == slowNode.GetID() && s.State == mflow.NODE_STATE_CANCELED { + foundCanceled = true + } + } + + require.True(t, foundFailure, "expected FAILURE status for fail node, statuses: %+v", statuses) + require.True(t, foundCanceled, "expected CANCELED status for slow node, statuses: %+v", statuses) +} + +// concurrencyTrackingNode is a FlowNode that tracks concurrent execution. +type concurrencyTrackingNode struct { + id idwrap.IDWrap + nodeName string + mu *sync.Mutex + activeConcur *int + maxConcur *int +} + +func (n *concurrencyTrackingNode) GetID() idwrap.IDWrap { return n.id } +func (n *concurrencyTrackingNode) GetName() string { return n.nodeName } + +func (n *concurrencyTrackingNode) RunSync(_ context.Context, _ *node.FlowNodeRequest) node.FlowNodeResult { + n.mu.Lock() + *n.activeConcur++ + if *n.activeConcur > *n.maxConcur { + *n.maxConcur = *n.activeConcur + } + n.mu.Unlock() + + // Small delay to increase the window for concurrent overlap + time.Sleep(5 * time.Millisecond) + + n.mu.Lock() + *n.activeConcur-- + n.mu.Unlock() + + return node.FlowNodeResult{} +} + +func (n *concurrencyTrackingNode) RunAsync(ctx context.Context, req *node.FlowNodeRequest, resultChan chan node.FlowNodeResult) { + resultChan <- n.RunSync(ctx, req) +} + +// TestEventDrivenSemaphoreBoundsConcurrency verifies that the semaphore limits +// how many nodes are actively processing at any time. +func TestEventDrivenSemaphoreBoundsConcurrency(t *testing.T) { + cleanup := flowlocalrunner.SetGoroutineCountForTesting(1) + defer cleanup() + + var mu sync.Mutex + maxConcurrent := 0 + activeConcurrent := 0 + + newTrackingNode := func(name string) *concurrencyTrackingNode { + return &concurrencyTrackingNode{ + id: idwrap.NewNow(), + nodeName: name, + mu: &mu, + activeConcur: &activeConcurrent, + maxConcur: &maxConcurrent, + } + } + + tn1 := newTrackingNode("worker-0") + tn2 := newTrackingNode("worker-1") + tn3 := newTrackingNode("worker-2") + + startID := idwrap.NewNow() + startNode := &stubNode{ + id: startID, + name: "start", + next: []idwrap.IDWrap{tn1.id, tn2.id, tn3.id}, + } + + nodeMap := map[idwrap.IDWrap]node.FlowNode{ + startID: startNode, + tn1.id: tn1, + tn2.id: tn2, + tn3.id: tn3, + } + edgesMap := mflow.EdgesMap{ + startID: {mflow.HandleUnspecified: []idwrap.IDWrap{tn1.id, tn2.id, tn3.id}}, + tn1.id: {}, + tn2.id: {}, + tn3.id: {}, + } + + flowRunner := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), idwrap.NewNow(), []idwrap.IDWrap{startID}, nodeMap, edgesMap, 0, nil) + flowRunner.SetExecutionMode(flowlocalrunner.ExecutionModeMulti) + + statusChan := make(chan runner.FlowNodeStatus, 32) + flowStatusChan := make(chan runner.FlowStatus, 4) + + err := flowRunner.Run(context.Background(), statusChan, flowStatusChan, nil) + require.Nil(t, err) + + for range statusChan { + } + for range flowStatusChan { + } + + mu.Lock() + finalMax := maxConcurrent + mu.Unlock() + + require.LessOrEqual(t, finalMax, 1, "expected max concurrent processing to be 1 (semaphore bound), got %d", finalMax) +} diff --git a/packages/server/pkg/flow/runner/flowlocalrunner/helpers.go b/packages/server/pkg/flow/runner/flowlocalrunner/helpers.go new file mode 100644 index 000000000..9f9c3275f --- /dev/null +++ b/packages/server/pkg/flow/runner/flowlocalrunner/helpers.go @@ -0,0 +1,91 @@ +package flowlocalrunner + +import ( + "context" + "errors" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/runner" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +// buildTerminalStatus consolidates state classification, data attachment, and +// output flattening into a single function. Both strategies call this instead +// of duplicating ~50 lines each. +// +// base must have ExecutionID, NodeID, Name, IterationContext, RunDuration, +// and AuxiliaryID pre-filled. This function fills State, Error, InputData, +// and OutputData. +func buildTerminalStatus( + base runner.FlowNodeStatus, + nodeErr error, + timedOut bool, + trackedInput, trackedOutput map[string]any, + req *node.FlowNodeRequest, + trackData bool, +) runner.FlowNodeStatus { + status := base + + if nodeErr != nil { + switch { + case timedOut || errors.Is(nodeErr, context.DeadlineExceeded): + status.State = mflow.NODE_STATE_FAILURE + case runner.IsCancellationError(nodeErr): + status.State = mflow.NODE_STATE_CANCELED + default: + status.State = mflow.NODE_STATE_FAILURE + } + status.Error = nodeErr + } else { + status.State = mflow.NODE_STATE_SUCCESS + } + + if trackData { + if len(trackedOutput) > 0 { + status.OutputData = node.DeepCopyValue(trackedOutput) + } else { + status.OutputData = collectSingleModeOutput(req, status.Name) + } + if len(trackedInput) > 0 { + status.InputData = node.DeepCopyValue(trackedInput) + } + } + status.OutputData = flattenNodeOutput(status.Name, status.OutputData) + + return status +} + +func collectSingleModeOutput(req *node.FlowNodeRequest, nodeName string) any { + if nodeName == "" { + return nil + } + if data, err := node.ReadVarRaw(req, nodeName); err == nil { + return node.DeepCopyValue(data) + } + return nil +} + +func flattenNodeOutput(nodeName string, output any) any { + if nodeName == "" || output == nil { + return output + } + m, ok := output.(map[string]any) + if !ok { + return output + } + nested, ok := m[nodeName] + if !ok { + return output + } + nestedMap, ok := nested.(map[string]any) + if !ok { + return output + } + delete(m, nodeName) + for k, v := range nestedMap { + if _, exists := m[k]; !exists { + m[k] = v + } + } + return m +} diff --git a/packages/server/pkg/flow/runner/flowlocalrunner/mode_select.go b/packages/server/pkg/flow/runner/flowlocalrunner/mode_select.go new file mode 100644 index 000000000..874be0498 --- /dev/null +++ b/packages/server/pkg/flow/runner/flowlocalrunner/mode_select.go @@ -0,0 +1,72 @@ +package flowlocalrunner + +import ( + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +func selectExecutionMode(nodeMap map[idwrap.IDWrap]node.FlowNode, edgesMap mflow.EdgesMap) ExecutionMode { + nodeCount := len(nodeMap) + if nodeCount == 0 { + return ExecutionModeSingle + } + + const smallFlowThreshold = 6 + + simpleStructure := true + incomingNonLoop := make(map[idwrap.IDWrap]int) + + for sourceID, handles := range edgesMap { + nonLoopTargets := 0 + for handle, targetIDs := range handles { + if len(targetIDs) == 0 { + continue + } + if handle == mflow.HandleLoop { + if len(targetIDs) > 1 { + simpleStructure = false + } + continue + } + + nonLoopTargets += len(targetIDs) + if len(targetIDs) > 1 { + simpleStructure = false + } + for _, targetID := range targetIDs { + incomingNonLoop[targetID]++ + } + } + if nonLoopTargets > 1 { + simpleStructure = false + } + if _, ok := handles[mflow.HandleLoop]; ok && nonLoopTargets > 0 { + // Loop node with additional branch work beyond the loop/then path + if nonLoopTargets > 1 { + simpleStructure = false + } + } + + if _, exists := nodeMap[sourceID]; !exists { + // Node present in edges but missing from map; treat as complex and bail out + simpleStructure = false + } + } + + for targetID, count := range incomingNonLoop { + if count > 1 { + simpleStructure = false + break + } + if _, exists := nodeMap[targetID]; !exists { + simpleStructure = false + } + } + + if nodeCount <= smallFlowThreshold && simpleStructure { + return ExecutionModeSingle + } + + return ExecutionModeMulti +} diff --git a/packages/server/pkg/flow/runner/flowlocalrunner/strategy_multi.go b/packages/server/pkg/flow/runner/flowlocalrunner/strategy_multi.go new file mode 100644 index 000000000..4997eec0e --- /dev/null +++ b/packages/server/pkg/flow/runner/flowlocalrunner/strategy_multi.go @@ -0,0 +1,281 @@ +package flowlocalrunner + +import ( + "context" + "errors" + "fmt" + "sync" + "sync/atomic" + "time" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/runner" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" +) + +type processResult struct { + originalID idwrap.IDWrap + executionID idwrap.IDWrap + nextNodes []idwrap.IDWrap + err error + inputData map[string]any + outputData map[string]any + skipFinalStatus bool // From FlowNodeResult.SkipFinalStatus + AuxiliaryID *idwrap.IDWrap + startTime time.Time // When the node started executing + timedOut bool // Whether the node hit a per-node deadline +} + +type nodeSignal struct { + once sync.Once + ch chan struct{} +} + +func acquireNodeSignal(signals *sync.Map, id idwrap.IDWrap) *nodeSignal { + val, _ := signals.LoadOrStore(id, &nodeSignal{ch: make(chan struct{})}) + return val.(*nodeSignal) +} + +func waitForPredecessors(ctx context.Context, signals, seen *sync.Map, predecessors []idwrap.IDWrap) error { + for _, predID := range predecessors { + if seen != nil { + if _, ok := seen.Load(predID); !ok { + continue + } + } + sig := acquireNodeSignal(signals, predID) + select { + case <-sig.ch: + case <-ctx.Done(): + return ctx.Err() + } + } + return nil +} + +func signalNodeComplete(signals *sync.Map, id idwrap.IDWrap) { + sig := acquireNodeSignal(signals, id) + sig.once.Do(func() { + close(sig.ch) + }) +} + +// runNodesMultiEventDriven executes nodes concurrently using an event-driven model. +// Unlike the previous batch model that waited for all nodes in a batch to complete, +// this dispatches successors immediately when a node finishes. Only converge points +// (nodes with multiple incoming edges) wait for all predecessors. +func runNodesMultiEventDriven(ctx context.Context, startNodeID idwrap.IDWrap, req *node.FlowNodeRequest, + cfg RunConfig, executor *LocalExecutor, tracker *runner.ConvergenceTracker, +) error { + nodeSignals := &sync.Map{} + seenNodes := &sync.Map{} + + // Semaphore for bounded processing concurrency + sem := make(chan struct{}, cfg.MaxConcurrency) + resultChan := make(chan processResult, cfg.MaxConcurrency) + + // Cancellation context for the entire execution + flowCtx, flowCancel := context.WithCancel(ctx) + defer flowCancel() + + var outstanding int64 + + // launchNode spawns a goroutine to execute a node. It never blocks the caller. + launchNode := func(nodeID idwrap.IDWrap) { + currentNode, ok := req.NodeMap[nodeID] + if !ok { + atomic.AddInt64(&outstanding, 1) + go func() { + resultChan <- processResult{ + originalID: nodeID, + err: fmt.Errorf("node not found: %v", nodeID), + } + }() + return + } + + seenNodes.Store(nodeID, struct{}{}) + atomic.AddInt64(&outstanding, 1) + + go func() { + // Phase 1: Wait for predecessors OUTSIDE the semaphore. + // This prevents deadlocks where goroutines hold semaphore slots + // while waiting for predecessors that need slots to finish. + if predecessors := cfg.PredecessorMap[nodeID]; len(predecessors) > 0 { + if err := waitForPredecessors(flowCtx, nodeSignals, seenNodes, predecessors); err != nil { + resultChan <- processResult{ + originalID: currentNode.GetID(), + err: err, + } + return + } + } + + // Phase 2: Acquire semaphore to bound active processing concurrency. + select { + case sem <- struct{}{}: + case <-flowCtx.Done(): + resultChan <- processResult{ + originalID: currentNode.GetID(), + err: flowCtx.Err(), + } + return + } + defer func() { <-sem }() + + // Generate execution ID right before processing + executionID := idwrap.NewMonotonic() + startTime := time.Now() + + // Atomically register + emit RUNNING (fixes race with cancellation) + cfg.Emitter.EmitRunning(runner.NodeExecution{ + ExecutionID: executionID, + NodeID: nodeID, + Name: currentNode.GetName(), + StartTime: startTime, + IterCtx: req.IterationContext, + }) + + // Create per-node request copy + nodeReq := *req + nodeReq.ExecutionID = executionID + + // Per-node timeout (skip for LoopCoordinator nodes) + nodeCtx := flowCtx + var cancelNode context.CancelFunc + if cfg.Timeout > 0 { + if _, isLoop := currentNode.(node.LoopCoordinator); !isLoop { + nodeCtx, cancelNode = context.WithTimeout(flowCtx, cfg.Timeout) + } + } + if cancelNode != nil { + defer cancelNode() + } + + // Execute the node with variable tracking + outcome := executor.Execute(nodeCtx, currentNode, &nodeReq) + inputData := outcome.TrackedInput + outputData := outcome.TrackedOutput + result := outcome.Result + + // Check for node-level timeout + nodeTimedOut := false + if result.Err == nil && nodeCtx.Err() != nil && errors.Is(nodeCtx.Err(), context.DeadlineExceeded) { + result.Err = nodeCtx.Err() + nodeTimedOut = true + } + + resultChan <- processResult{ + originalID: currentNode.GetID(), + executionID: executionID, + nextNodes: result.NextNodeID, + err: result.Err, + inputData: inputData, + outputData: outputData, + skipFinalStatus: result.SkipFinalStatus, + AuxiliaryID: result.AuxiliaryID, + startTime: startTime, + timedOut: nodeTimedOut, + } + }() + } + + defer func() { + if ctx.Err() != nil { + cfg.Emitter.CancelAllRunning(ctx.Err()) + } + }() + + // Launch start node + launchNode(startNodeID) + + // Main event loop: process results as they arrive + var firstErr error + + for atomic.LoadInt64(&outstanding) > 0 { + select { + case result := <-resultChan: + atomic.AddInt64(&outstanding, -1) + + currentNode := req.NodeMap[result.originalID] + nodeName := "" + if currentNode != nil { + nodeName = currentNode.GetName() + } + + // Signal that this node completed (unblocks nodes waiting for it) + signalNodeComplete(nodeSignals, result.originalID) + + // Build base status (shared across all terminal paths) + base := runner.FlowNodeStatus{ + NodeID: result.originalID, + ExecutionID: result.executionID, + Name: nodeName, + IterationContext: req.IterationContext, + RunDuration: time.Since(result.startTime), + AuxiliaryID: result.AuxiliaryID, + } + + // ERROR PATH + if result.err != nil { + status := buildTerminalStatus(base, result.err, result.timedOut, result.inputData, result.outputData, req, cfg.TrackData) + cfg.Emitter.EmitTerminal(result.executionID, status, false) + + if firstErr == nil { + firstErr = result.err + } + // Cancel all other in-flight work + flowCancel() + continue + } + + // Check if flow was already canceled (by another node's failure) + if flowCtx.Err() != nil { + isLoop := false + if currentNode != nil { + _, isLoop = currentNode.(node.LoopCoordinator) + } + if !isLoop { + status := buildTerminalStatus(base, flowCtx.Err(), false, result.inputData, result.outputData, req, cfg.TrackData) + cfg.Emitter.EmitTerminal(result.executionID, status, false) + continue + } + // LoopCoordinator exemption: fall through to success path. + // EmitTerminal handles deregistration — calling Deregister here + // would clear wasRunning and suppress the success emission. + } + + // SUCCESS PATH + status := buildTerminalStatus(base, nil, false, result.inputData, result.outputData, req, cfg.TrackData) + cfg.Emitter.EmitTerminal(result.executionID, status, result.skipFinalStatus) + + // Dispatch ready successors immediately + if firstErr == nil { + for _, nextID := range result.nextNodes { + if !tracker.Arrive(nextID) { + continue + } + launchNode(nextID) + } + } + + case <-ctx.Done(): + flowCancel() + // Send CANCELED status for all currently running nodes + // BEFORE draining, since drain removes goroutines from tracking. + cfg.Emitter.CancelAllRunning(ctx.Err()) + // Drain remaining results so goroutines can exit + for atomic.LoadInt64(&outstanding) > 0 { + result := <-resultChan + atomic.AddInt64(&outstanding, -1) + signalNodeComplete(nodeSignals, result.originalID) + } + if firstErr != nil { + return firstErr + } + return ctx.Err() + } + } + + return firstErr +} diff --git a/packages/server/pkg/flow/runner/flowlocalrunner/strategy_single.go b/packages/server/pkg/flow/runner/flowlocalrunner/strategy_single.go new file mode 100644 index 000000000..acd830b69 --- /dev/null +++ b/packages/server/pkg/flow/runner/flowlocalrunner/strategy_single.go @@ -0,0 +1,106 @@ +package flowlocalrunner + +import ( + "context" + "fmt" + "time" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/runner" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +func sendQueuedCancellationStatuses(queue []idwrap.IDWrap, req *node.FlowNodeRequest, statusLogFunc node.LogPushFunc, cancelErr error) { + for _, nodeID := range queue { + if nodeRef, ok := req.NodeMap[nodeID]; ok { + statusLogFunc(runner.FlowNodeStatus{ + ExecutionID: idwrap.NewMonotonic(), + NodeID: nodeID, + Name: nodeRef.GetName(), + State: mflow.NODE_STATE_CANCELED, + Error: cancelErr, + IterationContext: req.IterationContext, + }) + } + } +} + +func runNodesSingle(ctx context.Context, startNodeID idwrap.IDWrap, req *node.FlowNodeRequest, + cfg RunConfig, executor *LocalExecutor, tracker *runner.ConvergenceTracker, +) error { + queue := []idwrap.IDWrap{startNodeID} + + for len(queue) > 0 { + if ctx.Err() != nil { + sendQueuedCancellationStatuses(queue, req, cfg.StatusLogFunc, ctx.Err()) + return ctx.Err() + } + + nodeID := queue[0] + queue = queue[1:] + + currentNode, ok := req.NodeMap[nodeID] + if !ok { + return fmt.Errorf("node not found: %v", nodeID) + } + + executionID := idwrap.NewMonotonic() + cfg.StatusLogFunc(runner.FlowNodeStatus{ + ExecutionID: executionID, + NodeID: nodeID, + Name: currentNode.GetName(), + State: mflow.NODE_STATE_RUNNING, + IterationContext: req.IterationContext, + }) + + nodeReq := *req + nodeReq.ExecutionID = executionID + + nodeCtx := ctx + cancelNodeCtx := func() {} + if cfg.Timeout > 0 { + nodeCtx, cancelNodeCtx = context.WithTimeout(ctx, cfg.Timeout) + } + startTime := time.Now() + + outcome := executor.Execute(nodeCtx, currentNode, &nodeReq) + nodeCtxErr := nodeCtx.Err() + cancelNodeCtx() + + // Merge node error with context timeout + nodeErr := outcome.Result.Err + if nodeErr == nil && nodeCtxErr != nil { + nodeErr = nodeCtxErr + } + + base := runner.FlowNodeStatus{ + ExecutionID: executionID, + NodeID: nodeID, + Name: currentNode.GetName(), + IterationContext: req.IterationContext, + RunDuration: time.Since(startTime), + AuxiliaryID: outcome.Result.AuxiliaryID, + } + + if nodeErr != nil { + status := buildTerminalStatus(base, nodeErr, false, outcome.TrackedInput, outcome.TrackedOutput, req, cfg.TrackData) + cfg.StatusLogFunc(status) + return nodeErr + } + + if !outcome.Result.SkipFinalStatus { + status := buildTerminalStatus(base, nil, false, outcome.TrackedInput, outcome.TrackedOutput, req, cfg.TrackData) + cfg.StatusLogFunc(status) + } + + for _, nextID := range outcome.Result.NextNodeID { + if !tracker.Arrive(nextID) { + continue + } + queue = append(queue, nextID) + } + } + + return nil +} diff --git a/packages/server/pkg/flow/runner/graph.go b/packages/server/pkg/flow/runner/graph.go new file mode 100644 index 000000000..f49798346 --- /dev/null +++ b/packages/server/pkg/flow/runner/graph.go @@ -0,0 +1,126 @@ +package runner + +import ( + "sync" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +// FlowGraph is an immutable representation of a flow's DAG topology. +// Constructed once before execution begins, then shared across all components. +// It holds no node implementations (no node.FlowNode) to avoid import cycles. +type FlowGraph struct { + Edges mflow.EdgesMap + StartNodeIDs []idwrap.IDWrap + Predecessors map[idwrap.IDWrap][]idwrap.IDWrap + ConvergeCounts map[idwrap.IDWrap]uint32 +} + +// NewFlowGraph constructs an immutable graph from edges and start nodes. +// It precomputes predecessor maps and convergence counts. +func NewFlowGraph(edges mflow.EdgesMap, startNodeIDs []idwrap.IDWrap) *FlowGraph { + predecessors := BuildPredecessorMap(edges) + convergeCounts := make(map[idwrap.IDWrap]uint32) + for nodeID, preds := range predecessors { + if count := uint32(len(preds)); count > 1 { //nolint:gosec // G115 + convergeCounts[nodeID] = count + } + } + return &FlowGraph{ + Edges: edges, + StartNodeIDs: startNodeIDs, + Predecessors: predecessors, + ConvergeCounts: convergeCounts, + } +} + +// NewFlowGraphFromPredecessors constructs a FlowGraph when the predecessor map +// is already computed (e.g., inside RunNodeSync where loop nodes pre-build it). +func NewFlowGraphFromPredecessors( + edges mflow.EdgesMap, + startNodeID idwrap.IDWrap, + predecessors map[idwrap.IDWrap][]idwrap.IDWrap, +) *FlowGraph { + convergeCounts := make(map[idwrap.IDWrap]uint32) + for nodeID, preds := range predecessors { + if count := uint32(len(preds)); count > 1 { //nolint:gosec // G115 + convergeCounts[nodeID] = count + } + } + return &FlowGraph{ + Edges: edges, + StartNodeIDs: []idwrap.IDWrap{startNodeID}, + Predecessors: predecessors, + ConvergeCounts: convergeCounts, + } +} + +// NewConvergenceTracker creates a fresh mutable tracker for one execution. +func (g *FlowGraph) NewConvergenceTracker() *ConvergenceTracker { + pending := make(map[idwrap.IDWrap]uint32, len(g.ConvergeCounts)) + for nodeID, count := range g.ConvergeCounts { + pending[nodeID] = count + } + return &ConvergenceTracker{pending: pending} +} + +// NewConvergenceTrackerFromPending creates a tracker from a pre-built pending +// map (e.g. from FlowNodeRequest.PendingAtmoicMap). It copies the map to avoid +// aliasing the original. +func NewConvergenceTrackerFromPending(pending map[idwrap.IDWrap]uint32) *ConvergenceTracker { + clone := make(map[idwrap.IDWrap]uint32, len(pending)) + for k, v := range pending { + clone[k] = v + } + return &ConvergenceTracker{pending: clone} +} + +// BuildPredecessorMap computes which nodes precede each node in the graph. +func BuildPredecessorMap(edges mflow.EdgesMap) map[idwrap.IDWrap][]idwrap.IDWrap { + predecessors := make(map[idwrap.IDWrap][]idwrap.IDWrap, len(edges)) + for sourceID, handles := range edges { + for _, targets := range handles { + for _, targetID := range targets { + predecessors[targetID] = append(predecessors[targetID], sourceID) + } + } + } + return predecessors +} + +// ConvergenceTracker tracks how many predecessors have completed for +// convergence (join) nodes. It is the mutable counterpart to FlowGraph's +// immutable ConvergeCounts. +type ConvergenceTracker struct { + mu sync.Mutex + pending map[idwrap.IDWrap]uint32 +} + +// Arrive records that one predecessor of nodeID has completed. +// Returns true when all predecessors have arrived (the node is ready). +func (ct *ConvergenceTracker) Arrive(nodeID idwrap.IDWrap) bool { + ct.mu.Lock() + defer ct.mu.Unlock() + remaining, ok := ct.pending[nodeID] + if !ok { + return true // not a convergence point + } + if remaining <= 1 { + delete(ct.pending, nodeID) + return true + } + ct.pending[nodeID] = remaining - 1 + return false +} + +// Clone creates an independent copy for loop iteration isolation. +func (ct *ConvergenceTracker) Clone() *ConvergenceTracker { + ct.mu.Lock() + defer ct.mu.Unlock() + clone := make(map[idwrap.IDWrap]uint32, len(ct.pending)) + for k, v := range ct.pending { + clone[k] = v + } + return &ConvergenceTracker{pending: clone} +} diff --git a/packages/server/pkg/flow/runner/runner.go b/packages/server/pkg/flow/runner/runner.go index e1e946eaf..a947cd23a 100644 --- a/packages/server/pkg/flow/runner/runner.go +++ b/packages/server/pkg/flow/runner/runner.go @@ -70,15 +70,6 @@ type FlowNodeStatus struct { AuxiliaryID *idwrap.IDWrap } -func NewFlowNodeStatus(nodeID idwrap.IDWrap, status mflow.NodeState, output []byte) FlowNodeStatus { - return FlowNodeStatus{ - NodeID: nodeID, - State: status, - OutputData: output, - Error: nil, - } -} - type FlowNodeEventTarget uint8 const ( diff --git a/packages/server/pkg/flow/runner/status.go b/packages/server/pkg/flow/runner/status.go new file mode 100644 index 000000000..9d12b2516 --- /dev/null +++ b/packages/server/pkg/flow/runner/status.go @@ -0,0 +1,160 @@ +package runner + +import ( + "sync" + "time" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +// NodeExecution identifies a single node execution for status tracking. +type NodeExecution struct { + ExecutionID idwrap.IDWrap + NodeID idwrap.IDWrap + Name string + StartTime time.Time + IterCtx *IterationContext +} + +// StatusEmitter tracks running nodes and emits status events. +// It delegates the actual event delivery to an emit function, making it +// usable with both channel-based delivery (RunWithEvents) and callback-based +// delivery (RunNodeSync from loop nodes). +// +// For a remote runner, the same StatusEmitter works — only the emitFn changes. +type StatusEmitter struct { + emitFn func(FlowNodeStatus) + + mu sync.Mutex + running map[idwrap.IDWrap]runningEntry +} + +type runningEntry struct { + nodeID idwrap.IDWrap + name string + startTime time.Time + iterCtx *IterationContext +} + +// NewStatusEmitter creates an emitter that delegates to the given function. +func NewStatusEmitter(emitFn func(FlowNodeStatus)) *StatusEmitter { + return &StatusEmitter{ + emitFn: emitFn, + running: make(map[idwrap.IDWrap]runningEntry), + } +} + +// Emit sends a status event. This is used as the LogPushFunc callback for nodes. +func (se *StatusEmitter) Emit(status FlowNodeStatus) { + se.emitFn(status) +} + +// EmitRunning atomically registers a node as running and emits RUNNING status. +// This eliminates the race where cancellation could miss a node between +// status emission and registration. +func (se *StatusEmitter) EmitRunning(exec NodeExecution) { + se.mu.Lock() + se.running[exec.ExecutionID] = runningEntry{ + nodeID: exec.NodeID, + name: exec.Name, + startTime: exec.StartTime, + iterCtx: exec.IterCtx, + } + se.mu.Unlock() + + se.emitFn(FlowNodeStatus{ + ExecutionID: exec.ExecutionID, + NodeID: exec.NodeID, + Name: exec.Name, + State: mflow.NODE_STATE_RUNNING, + IterationContext: exec.IterCtx, + }) +} + +// EmitTerminal deregisters the node and emits a pre-built terminal status. +// The wasRunning guard prevents double emission: if CancelAllRunning already +// processed this node (cleared from running map), emission is skipped. +func (se *StatusEmitter) EmitTerminal(executionID idwrap.IDWrap, status FlowNodeStatus, skip bool) { + se.mu.Lock() + _, wasRunning := se.running[executionID] + delete(se.running, executionID) + se.mu.Unlock() + + if skip || !wasRunning { + return + } + se.emitFn(status) +} + +// Deregister removes a node from running tracking without emitting a status. +// Used when the caller handles status emission itself (e.g., with custom state +// logic for errors, timeouts, or loop coordinators). +func (se *StatusEmitter) Deregister(executionID idwrap.IDWrap) { + se.mu.Lock() + delete(se.running, executionID) + se.mu.Unlock() +} + +// CancelAllRunning emits CANCELED for every node currently tracked as RUNNING. +// Called during context cancellation cleanup. +func (se *StatusEmitter) CancelAllRunning(cancelErr error) { + se.mu.Lock() + entries := make(map[idwrap.IDWrap]runningEntry, len(se.running)) + for k, v := range se.running { + entries[k] = v + } + se.running = make(map[idwrap.IDWrap]runningEntry) + se.mu.Unlock() + + for execID, entry := range entries { + se.emitFn(FlowNodeStatus{ + ExecutionID: execID, + NodeID: entry.nodeID, + Name: entry.name, + State: mflow.NODE_STATE_CANCELED, + Error: cancelErr, + RunDuration: time.Since(entry.startTime), + IterationContext: entry.iterCtx, + }) + } +} + +// NewChannelEmitFunc creates an emit function that routes status events to +// FlowEventChannels. RUNNING events go to NodeStates only; terminal events +// go to both NodeStates and NodeLogs. +// Safe to call after channels are closed (recovers from send-on-closed-channel). +func NewChannelEmitFunc(channels FlowEventChannels) func(FlowNodeStatus) { + return func(status FlowNodeStatus) { + // Background goroutines (e.g., WebSocket message readers) may try to emit + // after RunWithEvents closes channels. Recover rather than crashing. + defer func() { recover() }() //nolint:errcheck // intentional panic recovery + + targets := FlowNodeEventTargetState + if status.State != mflow.NODE_STATE_RUNNING { + targets |= FlowNodeEventTargetLog + } + event := FlowNodeEvent{ + Status: status, + Targets: targets, + } + if event.ShouldSend(FlowNodeEventTargetState) && channels.NodeStates != nil { + channels.NodeStates <- event.Status + } + if event.ShouldSend(FlowNodeEventTargetLog) && channels.NodeLogs != nil { + channels.NodeLogs <- FlowNodeLogPayload{ + ExecutionID: status.ExecutionID, + NodeID: status.NodeID, + Name: status.Name, + State: status.State, + Error: status.Error, + OutputData: status.OutputData, + RunDuration: status.RunDuration, + IterationContext: status.IterationContext, + IterationEvent: status.IterationEvent, + IterationIndex: status.IterationIndex, + LoopNodeID: status.LoopNodeID, + } + } + } +} diff --git a/packages/server/pkg/flow/simulation/mockflows.go b/packages/server/pkg/flow/simulation/mockflows.go index e04d8b840..383c9632f 100644 --- a/packages/server/pkg/flow/simulation/mockflows.go +++ b/packages/server/pkg/flow/simulation/mockflows.go @@ -19,10 +19,11 @@ type MockFlowParams struct { // MockFlowResult contains the three data structures FlowLocalRunner needs type MockFlowResult struct { - Nodes map[idwrap.IDWrap]node.FlowNode - Edges []mflow.Edge - EdgesMap mflow.EdgesMap - StartNodeID idwrap.IDWrap + Nodes map[idwrap.IDWrap]node.FlowNode + Edges []mflow.Edge + EdgesMap mflow.EdgesMap + StartNodeID idwrap.IDWrap + StartNodeIDs []idwrap.IDWrap } // CreateMockFlow creates a simple linear mock flow for testing @@ -109,9 +110,10 @@ func CreateMockFlow(params MockFlowParams) MockFlowResult { edgesMap := mflow.NewEdgesMap(edges) return MockFlowResult{ - Nodes: nodes, - Edges: edges, - EdgesMap: edgesMap, - StartNodeID: startNodeID, + Nodes: nodes, + Edges: edges, + EdgesMap: edgesMap, + StartNodeID: startNodeID, + StartNodeIDs: []idwrap.IDWrap{startNodeID}, } } diff --git a/packages/server/pkg/flow/simulation/mockflows_test.go b/packages/server/pkg/flow/simulation/mockflows_test.go index 4ed2215ca..c145d1fda 100644 --- a/packages/server/pkg/flow/simulation/mockflows_test.go +++ b/packages/server/pkg/flow/simulation/mockflows_test.go @@ -246,7 +246,7 @@ func TestCreateMockFlow_IntegrationWithFlowLocalRunner(t *testing.T) { flowRunner := flowlocalrunner.CreateFlowRunner( idwrap.NewNow(), flowID, - result.StartNodeID, + result.StartNodeIDs, result.Nodes, result.EdgesMap, 5*time.Second, // 5 second timeout @@ -334,7 +334,7 @@ func TestCreateMockFlow_Performance_BasicLoad(t *testing.T) { flowRunner := flowlocalrunner.CreateFlowRunner( idwrap.NewNow(), flowID, - result.StartNodeID, + result.StartNodeIDs, result.Nodes, result.EdgesMap, 10*time.Second, // Generous timeout @@ -455,7 +455,7 @@ func TestCreateMockFlow_ExecutionModeSelection(t *testing.T) { flowRunner := flowlocalrunner.CreateFlowRunner( idwrap.NewNow(), flowID, - result.StartNodeID, + result.StartNodeIDs, result.Nodes, result.EdgesMap, 5*time.Second, @@ -521,7 +521,7 @@ func TestCreateMockFlow_TimeoutBehavior(t *testing.T) { flowRunner := flowlocalrunner.CreateFlowRunner( idwrap.NewNow(), flowID, - result.StartNodeID, + result.StartNodeIDs, result.Nodes, result.EdgesMap, timeout, @@ -676,7 +676,7 @@ func BenchmarkFlowExecution_Small(b *testing.B) { flowRunner := flowlocalrunner.CreateFlowRunner( idwrap.NewNow(), flowID, - result.StartNodeID, + result.StartNodeIDs, result.Nodes, result.EdgesMap, 5*time.Second, @@ -713,7 +713,7 @@ func BenchmarkFlowExecution_Medium(b *testing.B) { flowRunner := flowlocalrunner.CreateFlowRunner( idwrap.NewNow(), flowID, - result.StartNodeID, + result.StartNodeIDs, result.Nodes, result.EdgesMap, 10*time.Second, @@ -750,7 +750,7 @@ func BenchmarkFlowExecution_Large(b *testing.B) { flowRunner := flowlocalrunner.CreateFlowRunner( idwrap.NewNow(), flowID, - result.StartNodeID, + result.StartNodeIDs, result.Nodes, result.EdgesMap, 30*time.Second, diff --git a/packages/server/pkg/ioworkspace/exporter.go b/packages/server/pkg/ioworkspace/exporter.go index 014ac5fa5..bc8fb2bb4 100644 --- a/packages/server/pkg/ioworkspace/exporter.go +++ b/packages/server/pkg/ioworkspace/exporter.go @@ -15,6 +15,7 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sflow" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sgraphql" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/shttp" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/swebsocket" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sworkspace" ) @@ -228,6 +229,11 @@ func (s *IOWorkspaceService) exportFlows(ctx context.Context, opts ExportOptions nodeAIProviderService := sflow.NewNodeAiProviderService(s.queries) nodeMemoryService := sflow.NewNodeMemoryService(s.queries) nodeGraphQLService := sflow.NewNodeGraphQLService(s.queries) + nodeWsConnectionService := sflow.NewNodeWsConnectionService(s.queries) + nodeWsSendService := sflow.NewNodeWsSendService(s.queries) + nodeWaitService := sflow.NewNodeWaitService(s.queries) + websocketService := swebsocket.New(s.queries, s.logger) + websocketHeaderService := swebsocket.NewWebSocketHeaderService(s.queries) var flowIDs []idwrap.IDWrap @@ -281,7 +287,7 @@ func (s *IOWorkspaceService) exportFlows(ctx context.Context, opts ExportOptions // Export node implementations based on node types for _, node := range nodes { - if err := s.exportNodeImplementation(ctx, node, bundle, nodeRequestService, nodeIfService, nodeForService, nodeForEachService, nodeJSService, nodeAIService, nodeAIProviderService, nodeMemoryService, nodeGraphQLService); err != nil { + if err := s.exportNodeImplementation(ctx, node, bundle, nodeRequestService, nodeIfService, nodeForService, nodeForEachService, nodeJSService, nodeAIService, nodeAIProviderService, nodeMemoryService, nodeGraphQLService, nodeWsConnectionService, nodeWsSendService, nodeWaitService, websocketService, websocketHeaderService); err != nil { return fmt.Errorf("failed to export node implementation for node %s: %w", node.ID.String(), err) } } @@ -299,7 +305,10 @@ func (s *IOWorkspaceService) exportFlows(ctx context.Context, opts ExportOptions "ai_nodes", len(bundle.FlowAINodes), "ai_provider_nodes", len(bundle.FlowAIProviderNodes), "ai_memory_nodes", len(bundle.FlowAIMemoryNodes), - "graphql_nodes", len(bundle.FlowGraphQLNodes)) + "graphql_nodes", len(bundle.FlowGraphQLNodes), + "ws_connection_nodes", len(bundle.FlowWsConnectionNodes), + "ws_send_nodes", len(bundle.FlowWsSendNodes), + "wait_nodes", len(bundle.FlowWaitNodes)) return nil } @@ -352,8 +361,15 @@ func (s *IOWorkspaceService) exportNodeImplementation( nodeAIProviderService sflow.NodeAiProviderService, nodeMemoryService sflow.NodeMemoryService, nodeGraphQLService sflow.NodeGraphQLService, + nodeWsConnectionService sflow.NodeWsConnectionService, + nodeWsSendService sflow.NodeWsSendService, + nodeWaitService sflow.NodeWaitService, + websocketService swebsocket.WebSocketService, + websocketHeaderService swebsocket.WebSocketHeaderService, ) error { switch node.NodeKind { + case mflow.NODE_KIND_MANUAL_START: + // No type-specific data for ManualStart case mflow.NODE_KIND_REQUEST: nodeRequest, err := nodeRequestService.GetNodeRequest(ctx, node.ID) if err != nil { @@ -434,6 +450,48 @@ func (s *IOWorkspaceService) exportNodeImplementation( if nodeGraphQL != nil { bundle.FlowGraphQLNodes = append(bundle.FlowGraphQLNodes, *nodeGraphQL) } + + case mflow.NODE_KIND_WS_CONNECTION: + nodeWsConn, err := nodeWsConnectionService.GetNodeWsConnection(ctx, node.ID) + if err != nil { + return fmt.Errorf("failed to get ws connection node: %w", err) + } + if nodeWsConn != nil { + bundle.FlowWsConnectionNodes = append(bundle.FlowWsConnectionNodes, *nodeWsConn) + // Also fetch and store the WebSocket entity and headers + if nodeWsConn.WebSocketID != nil { + wsEntity, err := websocketService.Get(ctx, *nodeWsConn.WebSocketID) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return fmt.Errorf("failed to get websocket entity: %w", err) + } + if wsEntity != nil { + bundle.WebSockets = append(bundle.WebSockets, *wsEntity) + } + wsHeaders, err := websocketHeaderService.GetByWebSocketID(ctx, *nodeWsConn.WebSocketID) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return fmt.Errorf("failed to get websocket headers: %w", err) + } + bundle.WebSocketHeaders = append(bundle.WebSocketHeaders, wsHeaders...) + } + } + + case mflow.NODE_KIND_WS_SEND: + nodeWsSend, err := nodeWsSendService.GetNodeWsSend(ctx, node.ID) + if err != nil { + return fmt.Errorf("failed to get ws send node: %w", err) + } + if nodeWsSend != nil { + bundle.FlowWsSendNodes = append(bundle.FlowWsSendNodes, *nodeWsSend) + } + + case mflow.NODE_KIND_WAIT: + nodeWait, err := nodeWaitService.GetNodeWait(ctx, node.ID) + if err != nil { + return fmt.Errorf("failed to get wait node: %w", err) + } + if nodeWait != nil { + bundle.FlowWaitNodes = append(bundle.FlowWaitNodes, *nodeWait) + } } return nil diff --git a/packages/server/pkg/ioworkspace/importer.go b/packages/server/pkg/ioworkspace/importer.go index e64d3360e..a34135cf5 100644 --- a/packages/server/pkg/ioworkspace/importer.go +++ b/packages/server/pkg/ioworkspace/importer.go @@ -11,6 +11,7 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sflow" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sgraphql" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/shttp" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/swebsocket" ) // ImportResult contains statistics and mappings from the import operation. @@ -36,8 +37,13 @@ type ImportResult struct { FlowAINodesCreated int FlowAIProviderNodesCreated int FlowAIMemoryNodesCreated int - FlowGraphQLNodesCreated int - GraphQLRequestsCreated int + FlowGraphQLNodesCreated int + FlowWsConnectionNodesCreated int + FlowWsSendNodesCreated int + FlowWaitNodesCreated int + WebSocketsCreated int + WebSocketHeadersCreated int + GraphQLRequestsCreated int GraphQLHeadersCreated int GraphQLAssertsCreated int EnvironmentsCreated int @@ -49,6 +55,7 @@ type ImportResult struct { NodeIDMap map[idwrap.IDWrap]idwrap.IDWrap FileIDMap map[idwrap.IDWrap]idwrap.IDWrap EnvironmentIDMap map[idwrap.IDWrap]idwrap.IDWrap + WebSocketIDMap map[idwrap.IDWrap]idwrap.IDWrap } // Import imports a WorkspaceBundle into the database using the provided options. @@ -66,6 +73,7 @@ func (s *IOWorkspaceService) Import(ctx context.Context, tx *sql.Tx, bundle *Wor NodeIDMap: make(map[idwrap.IDWrap]idwrap.IDWrap), FileIDMap: make(map[idwrap.IDWrap]idwrap.IDWrap), EnvironmentIDMap: make(map[idwrap.IDWrap]idwrap.IDWrap), + WebSocketIDMap: make(map[idwrap.IDWrap]idwrap.IDWrap), } // Create service instances with transaction support @@ -91,11 +99,17 @@ func (s *IOWorkspaceService) Import(ctx context.Context, tx *sql.Tx, bundle *Wor nodeAIProviderService := sflow.NewNodeAiProviderService(s.queries).TX(tx) nodeMemoryService := sflow.NewNodeMemoryService(s.queries).TX(tx) nodeGraphQLService := sflow.NewNodeGraphQLService(s.queries).TX(tx) + nodeWsConnectionService := sflow.NewNodeWsConnectionService(s.queries).TX(tx) + nodeWsSendService := sflow.NewNodeWsSendService(s.queries).TX(tx) + nodeWaitService := sflow.NewNodeWaitService(s.queries).TX(tx) graphqlService := sgraphql.New(s.queries, nil).TX(tx) graphqlHeaderService := sgraphql.NewGraphQLHeaderService(s.queries).TX(tx) graphqlAssertService := sgraphql.NewGraphQLAssertService(s.queries).TX(tx) + websocketService := swebsocket.New(s.queries, nil).TX(tx) + websocketHeaderService := swebsocket.NewWebSocketHeaderService(s.queries).TX(tx) + fileService := sfile.New(s.queries, nil).TX(tx) envService := senv.NewEnvironmentService(s.queries, nil).TX(tx) varService := senv.NewVariableService(s.queries, nil).TX(tx) @@ -120,6 +134,12 @@ func (s *IOWorkspaceService) Import(ctx context.Context, tx *sql.Tx, bundle *Wor } } + if opts.ImportHTTP && len(bundle.WebSockets) > 0 { + if err := s.importWebSockets(ctx, websocketService, bundle, opts, result); err != nil { + return nil, fmt.Errorf("failed to import WebSocket requests: %w", err) + } + } + if opts.CreateFiles && len(bundle.Files) > 0 { if err := s.importFiles(ctx, fileService, bundle, opts, result); err != nil { return nil, fmt.Errorf("failed to import files: %w", err) @@ -159,6 +179,12 @@ func (s *IOWorkspaceService) Import(ctx context.Context, tx *sql.Tx, bundle *Wor } } + if opts.ImportHTTP && len(bundle.WebSocketHeaders) > 0 { + if err := s.importWebSocketHeaders(ctx, websocketHeaderService, bundle, opts, result); err != nil { + return nil, fmt.Errorf("failed to import WebSocket headers: %w", err) + } + } + if opts.ImportHTTP { if len(bundle.HTTPHeaders) > 0 { if err := s.importHTTPHeaders(ctx, httpHeaderService, bundle, opts, result); err != nil { @@ -265,6 +291,24 @@ func (s *IOWorkspaceService) Import(ctx context.Context, tx *sql.Tx, bundle *Wor return nil, fmt.Errorf("failed to import flow GraphQL nodes: %w", err) } } + + if len(bundle.FlowWsConnectionNodes) > 0 { + if err := s.importFlowWsConnectionNodes(ctx, nodeWsConnectionService, bundle, opts, result); err != nil { + return nil, fmt.Errorf("failed to import flow WS connection nodes: %w", err) + } + } + + if len(bundle.FlowWsSendNodes) > 0 { + if err := s.importFlowWsSendNodes(ctx, nodeWsSendService, bundle, opts, result); err != nil { + return nil, fmt.Errorf("failed to import flow WS send nodes: %w", err) + } + } + + if len(bundle.FlowWaitNodes) > 0 { + if err := s.importFlowWaitNodes(ctx, nodeWaitService, bundle, opts, result); err != nil { + return nil, fmt.Errorf("failed to import flow wait nodes: %w", err) + } + } } return result, nil diff --git a/packages/server/pkg/ioworkspace/importer_flow.go b/packages/server/pkg/ioworkspace/importer_flow.go index c8602a7a7..4840ff801 100644 --- a/packages/server/pkg/ioworkspace/importer_flow.go +++ b/packages/server/pkg/ioworkspace/importer_flow.go @@ -8,6 +8,7 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sflow" "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sgraphql" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/swebsocket" ) // importFlows imports flows from the bundle. @@ -355,3 +356,100 @@ func (s *IOWorkspaceService) importFlowGraphQLNodes(ctx context.Context, nodeGra } return nil } + +// importFlowWsConnectionNodes imports flow WS connection nodes from the bundle. +func (s *IOWorkspaceService) importFlowWsConnectionNodes(ctx context.Context, nodeWsConnectionService sflow.NodeWsConnectionService, bundle *WorkspaceBundle, _ ImportOptions, result *ImportResult) error { + for _, wsNode := range bundle.FlowWsConnectionNodes { + if newNodeID, ok := result.NodeIDMap[wsNode.FlowNodeID]; ok { + wsNode.FlowNodeID = newNodeID + } + + // Remap WebSocket ID + if wsNode.WebSocketID != nil { + if newWSID, ok := result.WebSocketIDMap[*wsNode.WebSocketID]; ok { + wsNode.WebSocketID = &newWSID + } + } + + if err := nodeWsConnectionService.CreateNodeWsConnection(ctx, wsNode); err != nil { + return fmt.Errorf("failed to create flow WS connection node: %w", err) + } + + result.FlowWsConnectionNodesCreated++ + } + return nil +} + +// importFlowWsSendNodes imports flow WS send nodes from the bundle. +func (s *IOWorkspaceService) importFlowWsSendNodes(ctx context.Context, nodeWsSendService sflow.NodeWsSendService, bundle *WorkspaceBundle, _ ImportOptions, result *ImportResult) error { + for _, wsNode := range bundle.FlowWsSendNodes { + if newNodeID, ok := result.NodeIDMap[wsNode.FlowNodeID]; ok { + wsNode.FlowNodeID = newNodeID + } + + if err := nodeWsSendService.CreateNodeWsSend(ctx, wsNode); err != nil { + return fmt.Errorf("failed to create flow WS send node: %w", err) + } + + result.FlowWsSendNodesCreated++ + } + return nil +} + +// importFlowWaitNodes imports flow wait nodes from the bundle. +func (s *IOWorkspaceService) importFlowWaitNodes(ctx context.Context, nodeWaitService sflow.NodeWaitService, bundle *WorkspaceBundle, _ ImportOptions, result *ImportResult) error { + for _, waitNode := range bundle.FlowWaitNodes { + if newNodeID, ok := result.NodeIDMap[waitNode.FlowNodeID]; ok { + waitNode.FlowNodeID = newNodeID + } + + if err := nodeWaitService.CreateNodeWait(ctx, waitNode); err != nil { + return fmt.Errorf("failed to create flow wait node: %w", err) + } + + result.FlowWaitNodesCreated++ + } + return nil +} + +// importWebSockets imports WebSocket entities from the bundle. +func (s *IOWorkspaceService) importWebSockets(ctx context.Context, wsService swebsocket.WebSocketService, bundle *WorkspaceBundle, opts ImportOptions, result *ImportResult) error { + for _, ws := range bundle.WebSockets { + oldID := ws.ID + + if !opts.PreserveIDs { + ws.ID = idwrap.NewNow() + } + ws.WorkspaceID = opts.WorkspaceID + + if err := wsService.Create(ctx, &ws); err != nil { + return fmt.Errorf("failed to create WebSocket %s: %w", ws.Name, err) + } + + result.WebSocketIDMap[oldID] = ws.ID + result.WebSocketsCreated++ + } + return nil +} + +// importWebSocketHeaders imports WebSocket headers from the bundle. +func (s *IOWorkspaceService) importWebSocketHeaders(ctx context.Context, wsHeaderService swebsocket.WebSocketHeaderService, bundle *WorkspaceBundle, opts ImportOptions, result *ImportResult) error { + for _, h := range bundle.WebSocketHeaders { + // Generate new ID if not preserving + if !opts.PreserveIDs { + h.ID = idwrap.NewNow() + } + + // Remap parent WebSocket ID + if newWSID, ok := result.WebSocketIDMap[h.WebSocketID]; ok { + h.WebSocketID = newWSID + } + + if err := wsHeaderService.Create(ctx, h); err != nil { + return fmt.Errorf("failed to create WebSocket header: %w", err) + } + + result.WebSocketHeadersCreated++ + } + return nil +} diff --git a/packages/server/pkg/ioworkspace/types.go b/packages/server/pkg/ioworkspace/types.go index b8eb6747f..ff2328af1 100644 --- a/packages/server/pkg/ioworkspace/types.go +++ b/packages/server/pkg/ioworkspace/types.go @@ -8,6 +8,7 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mgraphql" "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mhttp" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mwebsocket" "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mworkspace" ) @@ -32,6 +33,10 @@ type WorkspaceBundle struct { GraphQLHeaders []mgraphql.GraphQLHeader GraphQLAsserts []mgraphql.GraphQLAssert + // WebSocket requests and associated data + WebSockets []mwebsocket.WebSocket + WebSocketHeaders []mwebsocket.WebSocketHeader + // File organization Files []mfile.File @@ -50,7 +55,10 @@ type WorkspaceBundle struct { FlowAINodes []mflow.NodeAI FlowAIProviderNodes []mflow.NodeAiProvider FlowAIMemoryNodes []mflow.NodeMemory - FlowGraphQLNodes []mflow.NodeGraphQL + FlowGraphQLNodes []mflow.NodeGraphQL + FlowWsConnectionNodes []mflow.NodeWsConnection + FlowWsSendNodes []mflow.NodeWsSend + FlowWaitNodes []mflow.NodeWait // Environments and variables Environments []menv.Env @@ -73,6 +81,8 @@ func (wb *WorkspaceBundle) CountEntities() map[string]int { "http_asserts": len(wb.HTTPAsserts), "graphql_requests": len(wb.GraphQLRequests), "graphql_headers": len(wb.GraphQLHeaders), + "websockets": len(wb.WebSockets), + "websocket_headers": len(wb.WebSocketHeaders), "files": len(wb.Files), "flows": len(wb.Flows), "flow_variables": len(wb.FlowVariables), @@ -86,8 +96,11 @@ func (wb *WorkspaceBundle) CountEntities() map[string]int { "flow_ai_nodes": len(wb.FlowAINodes), "flow_ai_provider_nodes": len(wb.FlowAIProviderNodes), "flow_ai_memory_nodes": len(wb.FlowAIMemoryNodes), - "flow_graphql_nodes": len(wb.FlowGraphQLNodes), - "environments": len(wb.Environments), + "flow_graphql_nodes": len(wb.FlowGraphQLNodes), + "flow_ws_connection_nodes": len(wb.FlowWsConnectionNodes), + "flow_ws_send_nodes": len(wb.FlowWsSendNodes), + "flow_wait_nodes": len(wb.FlowWaitNodes), + "environments": len(wb.Environments), "environment_vars": len(wb.EnvironmentVars), "credentials": len(wb.Credentials), } diff --git a/packages/server/pkg/model/mfile/mfile.go b/packages/server/pkg/model/mfile/mfile.go index 5d0920615..dbd15f66e 100644 --- a/packages/server/pkg/model/mfile/mfile.go +++ b/packages/server/pkg/model/mfile/mfile.go @@ -18,7 +18,8 @@ const ( ContentTypeHTTPDelta ContentType = 2 // http delta (draft/overlay) ContentTypeFlow ContentType = 3 // flow ContentTypeCredential ContentType = 4 // credential - ContentTypeGraphQL ContentType = 5 // graphql + ContentTypeGraphQL ContentType = 5 // graphql + ContentTypeWebSocket ContentType = 6 // websocket ) // String returns the string representation of ContentType @@ -36,6 +37,8 @@ func (ct ContentType) String() string { return "credential" case ContentTypeGraphQL: return "graphql" + case ContentTypeWebSocket: + return "websocket" default: return "unknown" } @@ -95,6 +98,11 @@ func (f File) IsGraphQL() bool { return f.ContentType == ContentTypeGraphQL } +// IsWebSocket returns true if the file contains a WebSocket connection +func (f File) IsWebSocket() bool { + return f.ContentType == ContentTypeWebSocket +} + // IsRoot returns true if the file has no parent folder func (f File) IsRoot() bool { return f.ParentID == nil @@ -140,6 +148,8 @@ func ContentTypeFromString(s string) ContentType { return ContentTypeCredential case "graphql": return ContentTypeGraphQL + case "websocket": + return ContentTypeWebSocket default: return ContentTypeUnknown } @@ -147,7 +157,7 @@ func ContentTypeFromString(s string) ContentType { // IsValidContentType checks if the content type is valid func IsValidContentType(kind ContentType) bool { - return kind == ContentTypeFolder || kind == ContentTypeFlow || kind == ContentTypeHTTP || kind == ContentTypeHTTPDelta || kind == ContentTypeCredential || kind == ContentTypeGraphQL + return kind == ContentTypeFolder || kind == ContentTypeFlow || kind == ContentTypeHTTP || kind == ContentTypeHTTPDelta || kind == ContentTypeCredential || kind == ContentTypeGraphQL || kind == ContentTypeWebSocket } // IDEquals checks if two IDWrap values are equal diff --git a/packages/server/pkg/model/mflow/edge.go b/packages/server/pkg/model/mflow/edge.go index 37b68d5e4..2cb2efd26 100644 --- a/packages/server/pkg/model/mflow/edge.go +++ b/packages/server/pkg/model/mflow/edge.go @@ -23,6 +23,7 @@ const ( HandleAiProvider HandleAiMemory HandleAiTools + HandleWsMessage HandleLength ) diff --git a/packages/server/pkg/model/mflow/node.go b/packages/server/pkg/model/mflow/node.go index 8218e74ae..35ed7dd76 100644 --- a/packages/server/pkg/model/mflow/node.go +++ b/packages/server/pkg/model/mflow/node.go @@ -5,7 +5,7 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" ) -type NodeKind = int32 +type NodeKind int32 const ( NODE_KIND_UNSPECIFIED NodeKind = 0 @@ -18,7 +18,11 @@ const ( NODE_KIND_AI NodeKind = 7 NODE_KIND_AI_PROVIDER NodeKind = 8 NODE_KIND_AI_MEMORY NodeKind = 9 - NODE_KIND_GRAPHQL NodeKind = 10 + NODE_KIND_GRAPHQL NodeKind = 10 + NODE_KIND_WS_CONNECTION NodeKind = 11 + NODE_KIND_WS_SEND NodeKind = 12 + NODE_KIND_WAIT NodeKind = 13 + // NODE_KIND_WEBHOOK NodeKind = 14 // reserved for future trigger entry ) type NodeState = int8 diff --git a/packages/server/pkg/model/mflow/node_types.go b/packages/server/pkg/model/mflow/node_types.go index 747306b76..7dfb3f7bc 100644 --- a/packages/server/pkg/model/mflow/node_types.go +++ b/packages/server/pkg/model/mflow/node_types.go @@ -256,7 +256,27 @@ type NodeMemory struct { // --- GraphQL Node --- type NodeGraphQL struct { - FlowNodeID idwrap.IDWrap - GraphQLID *idwrap.IDWrap - DeltaGraphQLID *idwrap.IDWrap + FlowNodeID idwrap.IDWrap + GraphQLID *idwrap.IDWrap + DeltaGraphQLID *idwrap.IDWrap +} + +// --- WebSocket Nodes --- + +type NodeWsConnection struct { + FlowNodeID idwrap.IDWrap + WebSocketID *idwrap.IDWrap +} + +type NodeWsSend struct { + FlowNodeID idwrap.IDWrap + WsConnectionNodeName string + Message string +} + +// --- Wait Node --- + +type NodeWait struct { + FlowNodeID idwrap.IDWrap + DurationMs int64 } diff --git a/packages/server/pkg/model/mwebsocket/mwebsocket.go b/packages/server/pkg/model/mwebsocket/mwebsocket.go new file mode 100644 index 000000000..990f1b622 --- /dev/null +++ b/packages/server/pkg/model/mwebsocket/mwebsocket.go @@ -0,0 +1,29 @@ +package mwebsocket + +import ( + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" +) + +type WebSocket struct { + ID idwrap.IDWrap `json:"id"` + WorkspaceID idwrap.IDWrap `json:"workspace_id"` + FolderID *idwrap.IDWrap `json:"folder_id,omitempty"` + Name string `json:"name"` + Url string `json:"url"` + Description string `json:"description"` + LastRunAt *int64 `json:"last_run_at,omitempty"` + CreatedAt int64 `json:"created_at"` + UpdatedAt int64 `json:"updated_at"` +} + +type WebSocketHeader struct { + ID idwrap.IDWrap `json:"id"` + WebSocketID idwrap.IDWrap `json:"websocket_id"` + Key string `json:"key"` + Value string `json:"value"` + Enabled bool `json:"enabled"` + Description string `json:"description"` + DisplayOrder float32 `json:"order"` + CreatedAt int64 `json:"created_at"` + UpdatedAt int64 `json:"updated_at"` +} diff --git a/packages/server/pkg/mutation/delete_file.go b/packages/server/pkg/mutation/delete_file.go index 7d5c7819b..2ae8b8ca5 100644 --- a/packages/server/pkg/mutation/delete_file.go +++ b/packages/server/pkg/mutation/delete_file.go @@ -59,6 +59,11 @@ func (c *Context) DeleteFile(ctx context.Context, file FileDeleteItem) error { }); err != nil { return err } + case mfile.ContentTypeWebSocket: + // WebSocket - cascade via FK ON DELETE CASCADE in DB + if err := c.q.DeleteWebSocket(ctx, *file.ContentID); err != nil { + return err + } case mfile.ContentTypeFolder: // Content deletion handled by recursion above (folders don't have separate content tables) } diff --git a/packages/server/pkg/mutation/event.go b/packages/server/pkg/mutation/event.go index a89acfe1c..6e69e7377 100644 --- a/packages/server/pkg/mutation/event.go +++ b/packages/server/pkg/mutation/event.go @@ -39,6 +39,9 @@ const ( EntityFlowNodeAiProvider EntityFlowNodeMemory EntityFlowNodeGraphQL + EntityFlowNodeWsConnection + EntityFlowNodeWsSend + EntityFlowNodeWait EntityFlowEdge EntityFlowVariable EntityFlowTag diff --git a/packages/server/pkg/mutation/insert_flow.go b/packages/server/pkg/mutation/insert_flow.go deleted file mode 100644 index 65828ab66..000000000 --- a/packages/server/pkg/mutation/insert_flow.go +++ /dev/null @@ -1,337 +0,0 @@ -package mutation - -import ( - "context" - - "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" - "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" -) - -// FlowNodeInsertItem represents a flow node to insert. -type FlowNodeInsertItem struct { - ID idwrap.IDWrap - FlowID idwrap.IDWrap - WorkspaceID idwrap.IDWrap - Name string - NodeKind int32 - PositionX float64 - PositionY float64 -} - -// InsertFlowNode inserts a flow node and tracks the event. -func (c *Context) InsertFlowNode(ctx context.Context, item FlowNodeInsertItem) error { - err := c.q.CreateFlowNode(ctx, gen.CreateFlowNodeParams{ - ID: item.ID, - FlowID: item.FlowID, - Name: item.Name, - NodeKind: item.NodeKind, - PositionX: item.PositionX, - PositionY: item.PositionY, - }) - if err != nil { - return err - } - c.track(Event{ - Entity: EntityFlowNode, - Op: OpInsert, - ID: item.ID, - WorkspaceID: item.WorkspaceID, - ParentID: item.FlowID, - }) - return nil -} - -// InsertFlowNodeBatch inserts multiple flow nodes. -func (c *Context) InsertFlowNodeBatch(ctx context.Context, items []FlowNodeInsertItem) error { - for _, item := range items { - if err := c.InsertFlowNode(ctx, item); err != nil { - return err - } - } - return nil -} - -// FlowEdgeInsertItem represents a flow edge to insert. -type FlowEdgeInsertItem struct { - ID idwrap.IDWrap - FlowID idwrap.IDWrap - WorkspaceID idwrap.IDWrap - SourceID idwrap.IDWrap - TargetID idwrap.IDWrap - SourceHandle int32 -} - -// InsertFlowEdge inserts a flow edge and tracks the event. -func (c *Context) InsertFlowEdge(ctx context.Context, item FlowEdgeInsertItem) error { - err := c.q.CreateFlowEdge(ctx, gen.CreateFlowEdgeParams{ - ID: item.ID, - FlowID: item.FlowID, - SourceID: item.SourceID, - TargetID: item.TargetID, - SourceHandle: item.SourceHandle, - }) - if err != nil { - return err - } - c.track(Event{ - Entity: EntityFlowEdge, - Op: OpInsert, - ID: item.ID, - WorkspaceID: item.WorkspaceID, - ParentID: item.FlowID, - }) - return nil -} - -// InsertFlowEdgeBatch inserts multiple flow edges. -func (c *Context) InsertFlowEdgeBatch(ctx context.Context, items []FlowEdgeInsertItem) error { - for _, item := range items { - if err := c.InsertFlowEdge(ctx, item); err != nil { - return err - } - } - return nil -} - -// FlowVariableInsertItem represents a flow variable to insert. -type FlowVariableInsertItem struct { - ID idwrap.IDWrap - FlowID idwrap.IDWrap - WorkspaceID idwrap.IDWrap - Key string - Value string - Enabled bool - Description string - DisplayOrder float64 -} - -// InsertFlowVariable inserts a flow variable and tracks the event. -func (c *Context) InsertFlowVariable(ctx context.Context, item FlowVariableInsertItem) error { - err := c.q.CreateFlowVariable(ctx, gen.CreateFlowVariableParams{ - ID: item.ID, - FlowID: item.FlowID, - Key: item.Key, - Value: item.Value, - Enabled: item.Enabled, - Description: item.Description, - DisplayOrder: item.DisplayOrder, - }) - if err != nil { - return err - } - c.track(Event{ - Entity: EntityFlowVariable, - Op: OpInsert, - ID: item.ID, - WorkspaceID: item.WorkspaceID, - ParentID: item.FlowID, - }) - return nil -} - -// InsertFlowVariableBatch inserts multiple flow variables. -func (c *Context) InsertFlowVariableBatch(ctx context.Context, items []FlowVariableInsertItem) error { - for _, item := range items { - if err := c.InsertFlowVariable(ctx, item); err != nil { - return err - } - } - return nil -} - -// FlowNodeJSInsertItem represents a flow node JS to insert. -type FlowNodeJSInsertItem struct { - FlowNodeID idwrap.IDWrap - FlowID idwrap.IDWrap - WorkspaceID idwrap.IDWrap - Code []byte - CodeCompressType int8 -} - -// InsertFlowNodeJS inserts a flow node JS and tracks the event. -func (c *Context) InsertFlowNodeJS(ctx context.Context, item FlowNodeJSInsertItem) error { - err := c.q.CreateFlowNodeJs(ctx, gen.CreateFlowNodeJsParams{ - FlowNodeID: item.FlowNodeID, - Code: item.Code, - CodeCompressType: item.CodeCompressType, - }) - if err != nil { - return err - } - c.track(Event{ - Entity: EntityFlowNodeJS, - Op: OpInsert, - ID: item.FlowNodeID, - WorkspaceID: item.WorkspaceID, - ParentID: item.FlowID, - }) - return nil -} - -// InsertFlowNodeJSBatch inserts multiple flow node JS records. -func (c *Context) InsertFlowNodeJSBatch(ctx context.Context, items []FlowNodeJSInsertItem) error { - for _, item := range items { - if err := c.InsertFlowNodeJS(ctx, item); err != nil { - return err - } - } - return nil -} - -// FlowNodeHTTPInsertItem represents a flow node HTTP to insert. -type FlowNodeHTTPInsertItem struct { - FlowNodeID idwrap.IDWrap - FlowID idwrap.IDWrap - WorkspaceID idwrap.IDWrap - HttpID idwrap.IDWrap - DeltaHttpID []byte -} - -// InsertFlowNodeHTTP inserts a flow node HTTP and tracks the event. -func (c *Context) InsertFlowNodeHTTP(ctx context.Context, item FlowNodeHTTPInsertItem) error { - err := c.q.CreateFlowNodeHTTP(ctx, gen.CreateFlowNodeHTTPParams{ - FlowNodeID: item.FlowNodeID, - HttpID: item.HttpID, - DeltaHttpID: item.DeltaHttpID, - }) - if err != nil { - return err - } - c.track(Event{ - Entity: EntityFlowNodeHTTP, - Op: OpInsert, - ID: item.FlowNodeID, - WorkspaceID: item.WorkspaceID, - ParentID: item.FlowID, - }) - return nil -} - -// InsertFlowNodeHTTPBatch inserts multiple flow node HTTP records. -func (c *Context) InsertFlowNodeHTTPBatch(ctx context.Context, items []FlowNodeHTTPInsertItem) error { - for _, item := range items { - if err := c.InsertFlowNodeHTTP(ctx, item); err != nil { - return err - } - } - return nil -} - -// FlowNodeForInsertItem represents a flow node for-loop to insert. -type FlowNodeForInsertItem struct { - FlowNodeID idwrap.IDWrap - FlowID idwrap.IDWrap - WorkspaceID idwrap.IDWrap - IterCount int64 - ErrorHandling int8 - Expression string -} - -// InsertFlowNodeFor inserts a flow node for-loop and tracks the event. -func (c *Context) InsertFlowNodeFor(ctx context.Context, item FlowNodeForInsertItem) error { - err := c.q.CreateFlowNodeFor(ctx, gen.CreateFlowNodeForParams{ - FlowNodeID: item.FlowNodeID, - IterCount: item.IterCount, - ErrorHandling: item.ErrorHandling, - Expression: item.Expression, - }) - if err != nil { - return err - } - c.track(Event{ - Entity: EntityFlowNodeFor, - Op: OpInsert, - ID: item.FlowNodeID, - WorkspaceID: item.WorkspaceID, - ParentID: item.FlowID, - }) - return nil -} - -// InsertFlowNodeForBatch inserts multiple flow node for-loop records. -func (c *Context) InsertFlowNodeForBatch(ctx context.Context, items []FlowNodeForInsertItem) error { - for _, item := range items { - if err := c.InsertFlowNodeFor(ctx, item); err != nil { - return err - } - } - return nil -} - -// FlowNodeForEachInsertItem represents a flow node for-each to insert. -type FlowNodeForEachInsertItem struct { - FlowNodeID idwrap.IDWrap - FlowID idwrap.IDWrap - WorkspaceID idwrap.IDWrap - IterExpression string - ErrorHandling int8 - Expression string -} - -// InsertFlowNodeForEach inserts a flow node for-each and tracks the event. -func (c *Context) InsertFlowNodeForEach(ctx context.Context, item FlowNodeForEachInsertItem) error { - err := c.q.CreateFlowNodeForEach(ctx, gen.CreateFlowNodeForEachParams{ - FlowNodeID: item.FlowNodeID, - IterExpression: item.IterExpression, - ErrorHandling: item.ErrorHandling, - Expression: item.Expression, - }) - if err != nil { - return err - } - c.track(Event{ - Entity: EntityFlowNodeForEach, - Op: OpInsert, - ID: item.FlowNodeID, - WorkspaceID: item.WorkspaceID, - ParentID: item.FlowID, - }) - return nil -} - -// InsertFlowNodeForEachBatch inserts multiple flow node for-each records. -func (c *Context) InsertFlowNodeForEachBatch(ctx context.Context, items []FlowNodeForEachInsertItem) error { - for _, item := range items { - if err := c.InsertFlowNodeForEach(ctx, item); err != nil { - return err - } - } - return nil -} - -// FlowNodeConditionInsertItem represents a flow node condition to insert. -type FlowNodeConditionInsertItem struct { - FlowNodeID idwrap.IDWrap - FlowID idwrap.IDWrap - WorkspaceID idwrap.IDWrap - Expression string -} - -// InsertFlowNodeCondition inserts a flow node condition and tracks the event. -func (c *Context) InsertFlowNodeCondition(ctx context.Context, item FlowNodeConditionInsertItem) error { - err := c.q.CreateFlowNodeCondition(ctx, gen.CreateFlowNodeConditionParams{ - FlowNodeID: item.FlowNodeID, - Expression: item.Expression, - }) - if err != nil { - return err - } - c.track(Event{ - Entity: EntityFlowNodeCondition, - Op: OpInsert, - ID: item.FlowNodeID, - WorkspaceID: item.WorkspaceID, - ParentID: item.FlowID, - }) - return nil -} - -// InsertFlowNodeConditionBatch inserts multiple flow node condition records. -func (c *Context) InsertFlowNodeConditionBatch(ctx context.Context, items []FlowNodeConditionInsertItem) error { - for _, item := range items { - if err := c.InsertFlowNodeCondition(ctx, item); err != nil { - return err - } - } - return nil -} diff --git a/packages/server/pkg/mutation/update_flow.go b/packages/server/pkg/mutation/update_flow.go deleted file mode 100644 index e028a68b8..000000000 --- a/packages/server/pkg/mutation/update_flow.go +++ /dev/null @@ -1,383 +0,0 @@ -package mutation - -import ( - "context" - - "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" - "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" -) - -// FlowNodeUpdateItem represents a flow node to update. -type FlowNodeUpdateItem struct { - ID idwrap.IDWrap - FlowID idwrap.IDWrap - WorkspaceID idwrap.IDWrap - Name string - PositionX float64 - PositionY float64 -} - -// FlowNodePatch represents optional fields for partial update. -type FlowNodePatch struct { - Name *string - PositionX *float64 - PositionY *float64 -} - -// UpdateFlowNode updates a flow node and tracks the event. -func (c *Context) UpdateFlowNode(ctx context.Context, item FlowNodeUpdateItem) error { - err := c.q.UpdateFlowNode(ctx, gen.UpdateFlowNodeParams{ - ID: item.ID, - Name: item.Name, - PositionX: item.PositionX, - PositionY: item.PositionY, - }) - if err != nil { - return err - } - c.track(Event{ - Entity: EntityFlowNode, - Op: OpUpdate, - ID: item.ID, - WorkspaceID: item.WorkspaceID, - ParentID: item.FlowID, - }) - return nil -} - -// UpdateFlowNodeBatch updates multiple flow nodes. -func (c *Context) UpdateFlowNodeBatch(ctx context.Context, items []FlowNodeUpdateItem) error { - for _, item := range items { - if err := c.UpdateFlowNode(ctx, item); err != nil { - return err - } - } - return nil -} - -// FlowEdgeUpdateItem represents a flow edge to update. -type FlowEdgeUpdateItem struct { - ID idwrap.IDWrap - FlowID idwrap.IDWrap - WorkspaceID idwrap.IDWrap - SourceID idwrap.IDWrap - TargetID idwrap.IDWrap - SourceHandle int32 -} - -// FlowEdgePatch represents optional fields for partial update. -type FlowEdgePatch struct { - SourceID *idwrap.IDWrap - TargetID *idwrap.IDWrap - SourceHandle *int32 -} - -// UpdateFlowEdge updates a flow edge and tracks the event. -func (c *Context) UpdateFlowEdge(ctx context.Context, item FlowEdgeUpdateItem) error { - err := c.q.UpdateFlowEdge(ctx, gen.UpdateFlowEdgeParams{ - ID: item.ID, - SourceID: item.SourceID, - TargetID: item.TargetID, - SourceHandle: item.SourceHandle, - }) - if err != nil { - return err - } - c.track(Event{ - Entity: EntityFlowEdge, - Op: OpUpdate, - ID: item.ID, - WorkspaceID: item.WorkspaceID, - ParentID: item.FlowID, - }) - return nil -} - -// UpdateFlowEdgeBatch updates multiple flow edges. -func (c *Context) UpdateFlowEdgeBatch(ctx context.Context, items []FlowEdgeUpdateItem) error { - for _, item := range items { - if err := c.UpdateFlowEdge(ctx, item); err != nil { - return err - } - } - return nil -} - -// FlowVariableUpdateItem represents a flow variable to update. -type FlowVariableUpdateItem struct { - ID idwrap.IDWrap - FlowID idwrap.IDWrap - WorkspaceID idwrap.IDWrap - Key string - Value string - Enabled bool - Description string -} - -// FlowVariablePatch represents optional fields for partial update. -type FlowVariablePatch struct { - Key *string - Value *string - Enabled *bool - Description *string -} - -// UpdateFlowVariable updates a flow variable and tracks the event. -func (c *Context) UpdateFlowVariable(ctx context.Context, item FlowVariableUpdateItem) error { - err := c.q.UpdateFlowVariable(ctx, gen.UpdateFlowVariableParams{ - ID: item.ID, - Key: item.Key, - Value: item.Value, - Enabled: item.Enabled, - Description: item.Description, - }) - if err != nil { - return err - } - c.track(Event{ - Entity: EntityFlowVariable, - Op: OpUpdate, - ID: item.ID, - WorkspaceID: item.WorkspaceID, - ParentID: item.FlowID, - }) - return nil -} - -// UpdateFlowVariableBatch updates multiple flow variables. -func (c *Context) UpdateFlowVariableBatch(ctx context.Context, items []FlowVariableUpdateItem) error { - for _, item := range items { - if err := c.UpdateFlowVariable(ctx, item); err != nil { - return err - } - } - return nil -} - -// FlowNodeJSUpdateItem represents a flow node JS to update. -type FlowNodeJSUpdateItem struct { - FlowNodeID idwrap.IDWrap - FlowID idwrap.IDWrap - WorkspaceID idwrap.IDWrap - Code []byte - CodeCompressType int8 -} - -// FlowNodeJSPatch represents optional fields for partial update. -type FlowNodeJSPatch struct { - Code []byte - CodeCompressType *int8 -} - -// UpdateFlowNodeJS updates a flow node JS and tracks the event. -func (c *Context) UpdateFlowNodeJS(ctx context.Context, item FlowNodeJSUpdateItem) error { - err := c.q.UpdateFlowNodeJs(ctx, gen.UpdateFlowNodeJsParams{ - FlowNodeID: item.FlowNodeID, - Code: item.Code, - CodeCompressType: item.CodeCompressType, - }) - if err != nil { - return err - } - c.track(Event{ - Entity: EntityFlowNodeJS, - Op: OpUpdate, - ID: item.FlowNodeID, - WorkspaceID: item.WorkspaceID, - ParentID: item.FlowID, - }) - return nil -} - -// UpdateFlowNodeJSBatch updates multiple flow node JS records. -func (c *Context) UpdateFlowNodeJSBatch(ctx context.Context, items []FlowNodeJSUpdateItem) error { - for _, item := range items { - if err := c.UpdateFlowNodeJS(ctx, item); err != nil { - return err - } - } - return nil -} - -// FlowNodeHTTPUpdateItem represents a flow node HTTP to update. -type FlowNodeHTTPUpdateItem struct { - FlowNodeID idwrap.IDWrap - FlowID idwrap.IDWrap - WorkspaceID idwrap.IDWrap - HttpID idwrap.IDWrap - DeltaHttpID []byte -} - -// FlowNodeHTTPPatch represents optional fields for partial update. -type FlowNodeHTTPPatch struct { - HttpID *idwrap.IDWrap - DeltaHttpID []byte -} - -// UpdateFlowNodeHTTP updates a flow node HTTP and tracks the event. -func (c *Context) UpdateFlowNodeHTTP(ctx context.Context, item FlowNodeHTTPUpdateItem) error { - err := c.q.UpdateFlowNodeHTTP(ctx, gen.UpdateFlowNodeHTTPParams{ - FlowNodeID: item.FlowNodeID, - HttpID: item.HttpID, - DeltaHttpID: item.DeltaHttpID, - }) - if err != nil { - return err - } - c.track(Event{ - Entity: EntityFlowNodeHTTP, - Op: OpUpdate, - ID: item.FlowNodeID, - WorkspaceID: item.WorkspaceID, - ParentID: item.FlowID, - }) - return nil -} - -// UpdateFlowNodeHTTPBatch updates multiple flow node HTTP records. -func (c *Context) UpdateFlowNodeHTTPBatch(ctx context.Context, items []FlowNodeHTTPUpdateItem) error { - for _, item := range items { - if err := c.UpdateFlowNodeHTTP(ctx, item); err != nil { - return err - } - } - return nil -} - -// FlowNodeForUpdateItem represents a flow node for-loop to update. -type FlowNodeForUpdateItem struct { - FlowNodeID idwrap.IDWrap - FlowID idwrap.IDWrap - WorkspaceID idwrap.IDWrap - IterCount int64 - ErrorHandling int8 - Expression string -} - -// FlowNodeForPatch represents optional fields for partial update. -type FlowNodeForPatch struct { - IterCount *int64 - ErrorHandling *int8 - Expression *string -} - -// UpdateFlowNodeFor updates a flow node for-loop and tracks the event. -func (c *Context) UpdateFlowNodeFor(ctx context.Context, item FlowNodeForUpdateItem) error { - err := c.q.UpdateFlowNodeFor(ctx, gen.UpdateFlowNodeForParams{ - FlowNodeID: item.FlowNodeID, - IterCount: item.IterCount, - ErrorHandling: item.ErrorHandling, - Expression: item.Expression, - }) - if err != nil { - return err - } - c.track(Event{ - Entity: EntityFlowNodeFor, - Op: OpUpdate, - ID: item.FlowNodeID, - WorkspaceID: item.WorkspaceID, - ParentID: item.FlowID, - }) - return nil -} - -// UpdateFlowNodeForBatch updates multiple flow node for-loop records. -func (c *Context) UpdateFlowNodeForBatch(ctx context.Context, items []FlowNodeForUpdateItem) error { - for _, item := range items { - if err := c.UpdateFlowNodeFor(ctx, item); err != nil { - return err - } - } - return nil -} - -// FlowNodeForEachUpdateItem represents a flow node for-each to update. -type FlowNodeForEachUpdateItem struct { - FlowNodeID idwrap.IDWrap - FlowID idwrap.IDWrap - WorkspaceID idwrap.IDWrap - IterExpression string - ErrorHandling int8 - Expression string -} - -// FlowNodeForEachPatch represents optional fields for partial update. -type FlowNodeForEachPatch struct { - IterExpression *string - ErrorHandling *int8 - Expression *string -} - -// UpdateFlowNodeForEach updates a flow node for-each and tracks the event. -func (c *Context) UpdateFlowNodeForEach(ctx context.Context, item FlowNodeForEachUpdateItem) error { - err := c.q.UpdateFlowNodeForEach(ctx, gen.UpdateFlowNodeForEachParams{ - FlowNodeID: item.FlowNodeID, - IterExpression: item.IterExpression, - ErrorHandling: item.ErrorHandling, - Expression: item.Expression, - }) - if err != nil { - return err - } - c.track(Event{ - Entity: EntityFlowNodeForEach, - Op: OpUpdate, - ID: item.FlowNodeID, - WorkspaceID: item.WorkspaceID, - ParentID: item.FlowID, - }) - return nil -} - -// UpdateFlowNodeForEachBatch updates multiple flow node for-each records. -func (c *Context) UpdateFlowNodeForEachBatch(ctx context.Context, items []FlowNodeForEachUpdateItem) error { - for _, item := range items { - if err := c.UpdateFlowNodeForEach(ctx, item); err != nil { - return err - } - } - return nil -} - -// FlowNodeConditionUpdateItem represents a flow node condition to update. -type FlowNodeConditionUpdateItem struct { - FlowNodeID idwrap.IDWrap - FlowID idwrap.IDWrap - WorkspaceID idwrap.IDWrap - Expression string -} - -// FlowNodeConditionPatch represents optional fields for partial update. -type FlowNodeConditionPatch struct { - Expression *string -} - -// UpdateFlowNodeCondition updates a flow node condition and tracks the event. -func (c *Context) UpdateFlowNodeCondition(ctx context.Context, item FlowNodeConditionUpdateItem) error { - err := c.q.UpdateFlowNodeCondition(ctx, gen.UpdateFlowNodeConditionParams{ - FlowNodeID: item.FlowNodeID, - Expression: item.Expression, - }) - if err != nil { - return err - } - c.track(Event{ - Entity: EntityFlowNodeCondition, - Op: OpUpdate, - ID: item.FlowNodeID, - WorkspaceID: item.WorkspaceID, - ParentID: item.FlowID, - }) - return nil -} - -// UpdateFlowNodeConditionBatch updates multiple flow node condition records. -func (c *Context) UpdateFlowNodeConditionBatch(ctx context.Context, items []FlowNodeConditionUpdateItem) error { - for _, item := range items { - if err := c.UpdateFlowNodeCondition(ctx, item); err != nil { - return err - } - } - return nil -} diff --git a/packages/server/pkg/service/sflow/node_mapper.go b/packages/server/pkg/service/sflow/node_mapper.go index 84c09203f..d792c2124 100644 --- a/packages/server/pkg/service/sflow/node_mapper.go +++ b/packages/server/pkg/service/sflow/node_mapper.go @@ -10,7 +10,7 @@ func ConvertNodeToDB(n mflow.Node) *gen.FlowNode { ID: n.ID, FlowID: n.FlowID, Name: n.Name, - NodeKind: n.NodeKind, + NodeKind: int32(n.NodeKind), PositionX: n.PositionX, PositionY: n.PositionY, State: n.State, @@ -22,7 +22,7 @@ func ConvertNodeToModel(n gen.FlowNode) *mflow.Node { ID: n.ID, FlowID: n.FlowID, Name: n.Name, - NodeKind: n.NodeKind, + NodeKind: mflow.NodeKind(n.NodeKind), PositionX: n.PositionX, PositionY: n.PositionY, State: n.State, diff --git a/packages/server/pkg/service/sflow/node_wait.go b/packages/server/pkg/service/sflow/node_wait.go new file mode 100644 index 000000000..7932e6b9a --- /dev/null +++ b/packages/server/pkg/service/sflow/node_wait.go @@ -0,0 +1,51 @@ +//nolint:revive // exported +package sflow + +import ( + "context" + "database/sql" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +var ErrNoNodeWaitFound = sql.ErrNoRows + +type NodeWaitService struct { + reader *NodeWaitReader + queries *gen.Queries +} + +func NewNodeWaitService(queries *gen.Queries) NodeWaitService { + return NodeWaitService{ + reader: NewNodeWaitReaderFromQueries(queries), + queries: queries, + } +} + +func (s NodeWaitService) TX(tx *sql.Tx) NodeWaitService { + newQueries := s.queries.WithTx(tx) + return NodeWaitService{ + reader: NewNodeWaitReaderFromQueries(newQueries), + queries: newQueries, + } +} + +func (s NodeWaitService) GetNodeWait(ctx context.Context, id idwrap.IDWrap) (*mflow.NodeWait, error) { + return s.reader.GetNodeWait(ctx, id) +} + +func (s NodeWaitService) CreateNodeWait(ctx context.Context, mn mflow.NodeWait) error { + return NewNodeWaitWriterFromQueries(s.queries).CreateNodeWait(ctx, mn) +} + +func (s NodeWaitService) UpdateNodeWait(ctx context.Context, mn mflow.NodeWait) error { + return NewNodeWaitWriterFromQueries(s.queries).UpdateNodeWait(ctx, mn) +} + +func (s NodeWaitService) DeleteNodeWait(ctx context.Context, id idwrap.IDWrap) error { + return NewNodeWaitWriterFromQueries(s.queries).DeleteNodeWait(ctx, id) +} + +func (s NodeWaitService) Reader() *NodeWaitReader { return s.reader } diff --git a/packages/server/pkg/service/sflow/node_wait_mapper.go b/packages/server/pkg/service/sflow/node_wait_mapper.go new file mode 100644 index 000000000..e88201b1e --- /dev/null +++ b/packages/server/pkg/service/sflow/node_wait_mapper.go @@ -0,0 +1,20 @@ +package sflow + +import ( + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +func ConvertDBToNodeWait(nw gen.FlowNodeWait) *mflow.NodeWait { + return &mflow.NodeWait{ + FlowNodeID: nw.FlowNodeID, + DurationMs: nw.DurationMs, + } +} + +func ConvertNodeWaitToDB(mn mflow.NodeWait) gen.FlowNodeWait { + return gen.FlowNodeWait{ + FlowNodeID: mn.FlowNodeID, + DurationMs: mn.DurationMs, + } +} diff --git a/packages/server/pkg/service/sflow/node_wait_reader.go b/packages/server/pkg/service/sflow/node_wait_reader.go new file mode 100644 index 000000000..b28462fa6 --- /dev/null +++ b/packages/server/pkg/service/sflow/node_wait_reader.go @@ -0,0 +1,34 @@ +package sflow + +import ( + "context" + "database/sql" + "errors" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +type NodeWaitReader struct { + queries *gen.Queries +} + +func NewNodeWaitReader(db *sql.DB) *NodeWaitReader { + return &NodeWaitReader{queries: gen.New(db)} +} + +func NewNodeWaitReaderFromQueries(queries *gen.Queries) *NodeWaitReader { + return &NodeWaitReader{queries: queries} +} + +func (r *NodeWaitReader) GetNodeWait(ctx context.Context, id idwrap.IDWrap) (*mflow.NodeWait, error) { + nodeWait, err := r.queries.GetFlowNodeWait(ctx, id) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, nil + } + return nil, err + } + return ConvertDBToNodeWait(nodeWait), nil +} diff --git a/packages/server/pkg/service/sflow/node_wait_writer.go b/packages/server/pkg/service/sflow/node_wait_writer.go new file mode 100644 index 000000000..304dd9bcc --- /dev/null +++ b/packages/server/pkg/service/sflow/node_wait_writer.go @@ -0,0 +1,38 @@ +package sflow + +import ( + "context" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +type NodeWaitWriter struct { + queries *gen.Queries +} + +func NewNodeWaitWriter(tx gen.DBTX) *NodeWaitWriter { + return &NodeWaitWriter{queries: gen.New(tx)} +} + +func NewNodeWaitWriterFromQueries(queries *gen.Queries) *NodeWaitWriter { + return &NodeWaitWriter{queries: queries} +} + +func (w *NodeWaitWriter) CreateNodeWait(ctx context.Context, mn mflow.NodeWait) error { + nodeWait := ConvertNodeWaitToDB(mn) + return w.queries.CreateFlowNodeWait(ctx, gen.CreateFlowNodeWaitParams(nodeWait)) +} + +func (w *NodeWaitWriter) UpdateNodeWait(ctx context.Context, mn mflow.NodeWait) error { + nodeWait := ConvertNodeWaitToDB(mn) + return w.queries.UpdateFlowNodeWait(ctx, gen.UpdateFlowNodeWaitParams{ + DurationMs: nodeWait.DurationMs, + FlowNodeID: nodeWait.FlowNodeID, + }) +} + +func (w *NodeWaitWriter) DeleteNodeWait(ctx context.Context, id idwrap.IDWrap) error { + return w.queries.DeleteFlowNodeWait(ctx, id) +} diff --git a/packages/server/pkg/service/sflow/node_writer.go b/packages/server/pkg/service/sflow/node_writer.go index e4ab597cf..96adaff4f 100644 --- a/packages/server/pkg/service/sflow/node_writer.go +++ b/packages/server/pkg/service/sflow/node_writer.go @@ -62,61 +62,61 @@ func (w *NodeWriter) CreateNodeBulk(ctx context.Context, nodes []mflow.Node) err ID: batch[0].ID, FlowID: batch[0].FlowID, Name: batch[0].Name, - NodeKind: batch[0].NodeKind, + NodeKind: int32(batch[0].NodeKind), PositionX: batch[0].PositionX, PositionY: batch[0].PositionY, ID_2: batch[1].ID, FlowID_2: batch[1].FlowID, Name_2: batch[1].Name, - NodeKind_2: batch[1].NodeKind, + NodeKind_2: int32(batch[1].NodeKind), PositionX_2: batch[1].PositionX, PositionY_2: batch[1].PositionY, ID_3: batch[2].ID, FlowID_3: batch[2].FlowID, Name_3: batch[2].Name, - NodeKind_3: batch[2].NodeKind, + NodeKind_3: int32(batch[2].NodeKind), PositionX_3: batch[2].PositionX, PositionY_3: batch[2].PositionY, ID_4: batch[3].ID, FlowID_4: batch[3].FlowID, Name_4: batch[3].Name, - NodeKind_4: batch[3].NodeKind, + NodeKind_4: int32(batch[3].NodeKind), PositionX_4: batch[3].PositionX, PositionY_4: batch[3].PositionY, ID_5: batch[4].ID, FlowID_5: batch[4].FlowID, Name_5: batch[4].Name, - NodeKind_5: batch[4].NodeKind, + NodeKind_5: int32(batch[4].NodeKind), PositionX_5: batch[4].PositionX, PositionY_5: batch[4].PositionY, ID_6: batch[5].ID, FlowID_6: batch[5].FlowID, Name_6: batch[5].Name, - NodeKind_6: batch[5].NodeKind, + NodeKind_6: int32(batch[5].NodeKind), PositionX_6: batch[5].PositionX, PositionY_6: batch[5].PositionY, ID_7: batch[6].ID, FlowID_7: batch[6].FlowID, Name_7: batch[6].Name, - NodeKind_7: batch[6].NodeKind, + NodeKind_7: int32(batch[6].NodeKind), PositionX_7: batch[6].PositionX, PositionY_7: batch[6].PositionY, ID_8: batch[7].ID, FlowID_8: batch[7].FlowID, Name_8: batch[7].Name, - NodeKind_8: batch[7].NodeKind, + NodeKind_8: int32(batch[7].NodeKind), PositionX_8: batch[7].PositionX, PositionY_8: batch[7].PositionY, ID_9: batch[8].ID, FlowID_9: batch[8].FlowID, Name_9: batch[8].Name, - NodeKind_9: batch[8].NodeKind, + NodeKind_9: int32(batch[8].NodeKind), PositionX_9: batch[8].PositionX, PositionY_9: batch[8].PositionY, ID_10: batch[9].ID, FlowID_10: batch[9].FlowID, Name_10: batch[9].Name, - NodeKind_10: batch[9].NodeKind, + NodeKind_10: int32(batch[9].NodeKind), PositionX_10: batch[9].PositionX, PositionY_10: batch[9].PositionY, } diff --git a/packages/server/pkg/service/sflow/node_ws_connection.go b/packages/server/pkg/service/sflow/node_ws_connection.go new file mode 100644 index 000000000..63caeae3f --- /dev/null +++ b/packages/server/pkg/service/sflow/node_ws_connection.go @@ -0,0 +1,49 @@ +//nolint:revive // exported +package sflow + +import ( + "context" + "database/sql" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +type NodeWsConnectionService struct { + reader *NodeWsConnectionReader + queries *gen.Queries +} + +func NewNodeWsConnectionService(queries *gen.Queries) NodeWsConnectionService { + return NodeWsConnectionService{ + reader: NewNodeWsConnectionReaderFromQueries(queries), + queries: queries, + } +} + +func (s NodeWsConnectionService) TX(tx *sql.Tx) NodeWsConnectionService { + newQueries := s.queries.WithTx(tx) + return NodeWsConnectionService{ + reader: NewNodeWsConnectionReaderFromQueries(newQueries), + queries: newQueries, + } +} + +func (s NodeWsConnectionService) GetNodeWsConnection(ctx context.Context, id idwrap.IDWrap) (*mflow.NodeWsConnection, error) { + return s.reader.GetNodeWsConnection(ctx, id) +} + +func (s NodeWsConnectionService) CreateNodeWsConnection(ctx context.Context, n mflow.NodeWsConnection) error { + return NewNodeWsConnectionWriterFromQueries(s.queries).CreateNodeWsConnection(ctx, n) +} + +func (s NodeWsConnectionService) UpdateNodeWsConnection(ctx context.Context, n mflow.NodeWsConnection) error { + return NewNodeWsConnectionWriterFromQueries(s.queries).UpdateNodeWsConnection(ctx, n) +} + +func (s NodeWsConnectionService) DeleteNodeWsConnection(ctx context.Context, id idwrap.IDWrap) error { + return NewNodeWsConnectionWriterFromQueries(s.queries).DeleteNodeWsConnection(ctx, id) +} + +func (s NodeWsConnectionService) Reader() *NodeWsConnectionReader { return s.reader } diff --git a/packages/server/pkg/service/sflow/node_ws_connection_mapper.go b/packages/server/pkg/service/sflow/node_ws_connection_mapper.go new file mode 100644 index 000000000..c3104731d --- /dev/null +++ b/packages/server/pkg/service/sflow/node_ws_connection_mapper.go @@ -0,0 +1,24 @@ +package sflow + +import ( + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +func ConvertToDBNodeWsConnection(n mflow.NodeWsConnection) (gen.FlowNodeWsConnection, bool) { + if n.WebSocketID == nil || isZeroID(*n.WebSocketID) { + return gen.FlowNodeWsConnection{}, false + } + + return gen.FlowNodeWsConnection{ + FlowNodeID: n.FlowNodeID, + WebsocketID: n.WebSocketID, + }, true +} + +func ConvertToModelNodeWsConnection(n gen.FlowNodeWsConnection) *mflow.NodeWsConnection { + return &mflow.NodeWsConnection{ + FlowNodeID: n.FlowNodeID, + WebSocketID: n.WebsocketID, + } +} diff --git a/packages/server/pkg/service/sflow/node_ws_connection_reader.go b/packages/server/pkg/service/sflow/node_ws_connection_reader.go new file mode 100644 index 000000000..374b71881 --- /dev/null +++ b/packages/server/pkg/service/sflow/node_ws_connection_reader.go @@ -0,0 +1,30 @@ +package sflow + +import ( + "context" + "database/sql" + "errors" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +type NodeWsConnectionReader struct { + queries *gen.Queries +} + +func NewNodeWsConnectionReaderFromQueries(queries *gen.Queries) *NodeWsConnectionReader { + return &NodeWsConnectionReader{queries: queries} +} + +func (r *NodeWsConnectionReader) GetNodeWsConnection(ctx context.Context, id idwrap.IDWrap) (*mflow.NodeWsConnection, error) { + nodeWsConn, err := r.queries.GetFlowNodeWsConnection(ctx, id) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, nil + } + return nil, err + } + return ConvertToModelNodeWsConnection(nodeWsConn), nil +} diff --git a/packages/server/pkg/service/sflow/node_ws_connection_writer.go b/packages/server/pkg/service/sflow/node_ws_connection_writer.go new file mode 100644 index 000000000..fb8b629e4 --- /dev/null +++ b/packages/server/pkg/service/sflow/node_ws_connection_writer.go @@ -0,0 +1,46 @@ +package sflow + +import ( + "context" + "database/sql" + "errors" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +type NodeWsConnectionWriter struct { + queries *gen.Queries +} + +func NewNodeWsConnectionWriter(tx gen.DBTX) *NodeWsConnectionWriter { + return &NodeWsConnectionWriter{queries: gen.New(tx)} +} + +func NewNodeWsConnectionWriterFromQueries(queries *gen.Queries) *NodeWsConnectionWriter { + return &NodeWsConnectionWriter{queries: queries} +} + +func (w *NodeWsConnectionWriter) CreateNodeWsConnection(ctx context.Context, n mflow.NodeWsConnection) error { + dbModel, ok := ConvertToDBNodeWsConnection(n) + if !ok { + return nil + } + return w.queries.CreateFlowNodeWsConnection(ctx, gen.CreateFlowNodeWsConnectionParams(dbModel)) +} + +func (w *NodeWsConnectionWriter) UpdateNodeWsConnection(ctx context.Context, n mflow.NodeWsConnection) error { + dbModel, ok := ConvertToDBNodeWsConnection(n) + if !ok { + if err := w.queries.DeleteFlowNodeWsConnection(ctx, n.FlowNodeID); err != nil && !errors.Is(err, sql.ErrNoRows) { + return err + } + return nil + } + return w.queries.UpdateFlowNodeWsConnection(ctx, gen.UpdateFlowNodeWsConnectionParams(dbModel)) +} + +func (w *NodeWsConnectionWriter) DeleteNodeWsConnection(ctx context.Context, id idwrap.IDWrap) error { + return w.queries.DeleteFlowNodeWsConnection(ctx, id) +} diff --git a/packages/server/pkg/service/sflow/node_ws_send.go b/packages/server/pkg/service/sflow/node_ws_send.go new file mode 100644 index 000000000..f68c318c5 --- /dev/null +++ b/packages/server/pkg/service/sflow/node_ws_send.go @@ -0,0 +1,49 @@ +//nolint:revive // exported +package sflow + +import ( + "context" + "database/sql" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +type NodeWsSendService struct { + reader *NodeWsSendReader + queries *gen.Queries +} + +func NewNodeWsSendService(queries *gen.Queries) NodeWsSendService { + return NodeWsSendService{ + reader: NewNodeWsSendReaderFromQueries(queries), + queries: queries, + } +} + +func (s NodeWsSendService) TX(tx *sql.Tx) NodeWsSendService { + newQueries := s.queries.WithTx(tx) + return NodeWsSendService{ + reader: NewNodeWsSendReaderFromQueries(newQueries), + queries: newQueries, + } +} + +func (s NodeWsSendService) GetNodeWsSend(ctx context.Context, id idwrap.IDWrap) (*mflow.NodeWsSend, error) { + return s.reader.GetNodeWsSend(ctx, id) +} + +func (s NodeWsSendService) CreateNodeWsSend(ctx context.Context, n mflow.NodeWsSend) error { + return NewNodeWsSendWriterFromQueries(s.queries).CreateNodeWsSend(ctx, n) +} + +func (s NodeWsSendService) UpdateNodeWsSend(ctx context.Context, n mflow.NodeWsSend) error { + return NewNodeWsSendWriterFromQueries(s.queries).UpdateNodeWsSend(ctx, n) +} + +func (s NodeWsSendService) DeleteNodeWsSend(ctx context.Context, id idwrap.IDWrap) error { + return NewNodeWsSendWriterFromQueries(s.queries).DeleteNodeWsSend(ctx, id) +} + +func (s NodeWsSendService) Reader() *NodeWsSendReader { return s.reader } diff --git a/packages/server/pkg/service/sflow/node_ws_send_mapper.go b/packages/server/pkg/service/sflow/node_ws_send_mapper.go new file mode 100644 index 000000000..2be4a8f75 --- /dev/null +++ b/packages/server/pkg/service/sflow/node_ws_send_mapper.go @@ -0,0 +1,22 @@ +package sflow + +import ( + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +func ConvertToDBNodeWsSend(n mflow.NodeWsSend) gen.FlowNodeWsSend { + return gen.FlowNodeWsSend{ + FlowNodeID: n.FlowNodeID, + WsConnectionNodeName: n.WsConnectionNodeName, + Message: n.Message, + } +} + +func ConvertToModelNodeWsSend(n gen.FlowNodeWsSend) *mflow.NodeWsSend { + return &mflow.NodeWsSend{ + FlowNodeID: n.FlowNodeID, + WsConnectionNodeName: n.WsConnectionNodeName, + Message: n.Message, + } +} diff --git a/packages/server/pkg/service/sflow/node_ws_send_reader.go b/packages/server/pkg/service/sflow/node_ws_send_reader.go new file mode 100644 index 000000000..d519855b7 --- /dev/null +++ b/packages/server/pkg/service/sflow/node_ws_send_reader.go @@ -0,0 +1,30 @@ +package sflow + +import ( + "context" + "database/sql" + "errors" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +type NodeWsSendReader struct { + queries *gen.Queries +} + +func NewNodeWsSendReaderFromQueries(queries *gen.Queries) *NodeWsSendReader { + return &NodeWsSendReader{queries: queries} +} + +func (r *NodeWsSendReader) GetNodeWsSend(ctx context.Context, id idwrap.IDWrap) (*mflow.NodeWsSend, error) { + nodeWsSend, err := r.queries.GetFlowNodeWsSend(ctx, id) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, nil + } + return nil, err + } + return ConvertToModelNodeWsSend(nodeWsSend), nil +} diff --git a/packages/server/pkg/service/sflow/node_ws_send_writer.go b/packages/server/pkg/service/sflow/node_ws_send_writer.go new file mode 100644 index 000000000..a52319344 --- /dev/null +++ b/packages/server/pkg/service/sflow/node_ws_send_writer.go @@ -0,0 +1,35 @@ +package sflow + +import ( + "context" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +type NodeWsSendWriter struct { + queries *gen.Queries +} + +func NewNodeWsSendWriter(tx gen.DBTX) *NodeWsSendWriter { + return &NodeWsSendWriter{queries: gen.New(tx)} +} + +func NewNodeWsSendWriterFromQueries(queries *gen.Queries) *NodeWsSendWriter { + return &NodeWsSendWriter{queries: queries} +} + +func (w *NodeWsSendWriter) CreateNodeWsSend(ctx context.Context, n mflow.NodeWsSend) error { + dbModel := ConvertToDBNodeWsSend(n) + return w.queries.CreateFlowNodeWsSend(ctx, gen.CreateFlowNodeWsSendParams(dbModel)) +} + +func (w *NodeWsSendWriter) UpdateNodeWsSend(ctx context.Context, n mflow.NodeWsSend) error { + dbModel := ConvertToDBNodeWsSend(n) + return w.queries.UpdateFlowNodeWsSend(ctx, gen.UpdateFlowNodeWsSendParams(dbModel)) +} + +func (w *NodeWsSendWriter) DeleteNodeWsSend(ctx context.Context, id idwrap.IDWrap) error { + return w.queries.DeleteFlowNodeWsSend(ctx, id) +} diff --git a/packages/server/pkg/service/sgraphql/header.go b/packages/server/pkg/service/sgraphql/header.go index 04798fc78..08bbe988f 100644 --- a/packages/server/pkg/service/sgraphql/header.go +++ b/packages/server/pkg/service/sgraphql/header.go @@ -25,6 +25,17 @@ func (s GraphQLHeaderService) TX(tx *sql.Tx) GraphQLHeaderService { return GraphQLHeaderService{queries: s.queries.WithTx(tx)} } +func (s GraphQLHeaderService) GetByID(ctx context.Context, id idwrap.IDWrap) (*mgraphql.GraphQLHeader, error) { + headers, err := s.GetByIDs(ctx, []idwrap.IDWrap{id}) + if err != nil { + return nil, err + } + if len(headers) == 0 { + return nil, ErrNoGraphQLHeaderFound + } + return &headers[0], nil +} + func (s GraphQLHeaderService) GetByGraphQLID(ctx context.Context, graphqlID idwrap.IDWrap) ([]mgraphql.GraphQLHeader, error) { headers, err := s.queries.GetGraphQLHeaders(ctx, graphqlID) if err != nil { diff --git a/packages/server/pkg/service/swebsocket/header.go b/packages/server/pkg/service/swebsocket/header.go new file mode 100644 index 000000000..3904db10e --- /dev/null +++ b/packages/server/pkg/service/swebsocket/header.go @@ -0,0 +1,75 @@ +package swebsocket + +import ( + "context" + "database/sql" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mwebsocket" +) + +type WebSocketHeaderService struct { + queries *gen.Queries +} + +func NewWebSocketHeaderService(queries *gen.Queries) WebSocketHeaderService { + return WebSocketHeaderService{queries: queries} +} + +func (s WebSocketHeaderService) TX(tx *sql.Tx) WebSocketHeaderService { + return WebSocketHeaderService{queries: s.queries.WithTx(tx)} +} + +func (s WebSocketHeaderService) GetByID(ctx context.Context, id idwrap.IDWrap) (mwebsocket.WebSocketHeader, error) { + h, err := s.queries.GetWebSocketHeaderByID(ctx, id) + if err != nil { + return mwebsocket.WebSocketHeader{}, err + } + return convertToModelHeader(h), nil +} + +func (s WebSocketHeaderService) GetByWebSocketID(ctx context.Context, wsID idwrap.IDWrap) ([]mwebsocket.WebSocketHeader, error) { + headers, err := s.queries.GetWebSocketHeaders(ctx, wsID) + if err != nil { + return nil, err + } + result := make([]mwebsocket.WebSocketHeader, len(headers)) + for i, h := range headers { + result[i] = convertToModelHeader(h) + } + return result, nil +} + +func (s WebSocketHeaderService) Create(ctx context.Context, h mwebsocket.WebSocketHeader) error { + return s.queries.CreateWebSocketHeader(ctx, gen.CreateWebSocketHeaderParams{ + ID: h.ID, + WebsocketID: h.WebSocketID, + HeaderKey: h.Key, + HeaderValue: h.Value, + Description: h.Description, + Enabled: h.Enabled, + DisplayOrder: float64(h.DisplayOrder), + CreatedAt: h.CreatedAt, + UpdatedAt: h.UpdatedAt, + }) +} + +func (s WebSocketHeaderService) Update(ctx context.Context, h mwebsocket.WebSocketHeader) error { + return s.queries.UpdateWebSocketHeader(ctx, gen.UpdateWebSocketHeaderParams{ + ID: h.ID, + HeaderKey: h.Key, + HeaderValue: h.Value, + Description: h.Description, + Enabled: h.Enabled, + DisplayOrder: float64(h.DisplayOrder), + }) +} + +func (s WebSocketHeaderService) Delete(ctx context.Context, id idwrap.IDWrap) error { + return s.queries.DeleteWebSocketHeader(ctx, id) +} + +func (s WebSocketHeaderService) DeleteByWebSocketID(ctx context.Context, wsID idwrap.IDWrap) error { + return s.queries.DeleteWebSocketHeadersByWebSocketID(ctx, wsID) +} diff --git a/packages/server/pkg/service/swebsocket/mapper.go b/packages/server/pkg/service/swebsocket/mapper.go new file mode 100644 index 000000000..ccf76f415 --- /dev/null +++ b/packages/server/pkg/service/swebsocket/mapper.go @@ -0,0 +1,58 @@ +package swebsocket + +import ( + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mwebsocket" +) + +func convertToModelWebSocket(db gen.Websocket) *mwebsocket.WebSocket { + ws := &mwebsocket.WebSocket{ + ID: db.ID, + WorkspaceID: db.WorkspaceID, + FolderID: db.FolderID, + Name: db.Name, + Url: db.Url, + Description: db.Description, + CreatedAt: db.CreatedAt, + UpdatedAt: db.UpdatedAt, + } + + if db.LastRunAt != nil { + if v, ok := db.LastRunAt.(int64); ok { + ws.LastRunAt = &v + } + } + + return ws +} + +func convertToDBCreateWebSocket(ws mwebsocket.WebSocket) gen.CreateWebSocketParams { + p := gen.CreateWebSocketParams{ + ID: ws.ID, + WorkspaceID: ws.WorkspaceID, + FolderID: ws.FolderID, + Name: ws.Name, + Url: ws.Url, + Description: ws.Description, + CreatedAt: ws.CreatedAt, + UpdatedAt: ws.UpdatedAt, + } + if ws.LastRunAt != nil { + p.LastRunAt = *ws.LastRunAt + } + return p +} + +func convertToModelHeader(db gen.WebsocketHeader) mwebsocket.WebSocketHeader { + return mwebsocket.WebSocketHeader{ + ID: db.ID, + WebSocketID: db.WebsocketID, + Key: db.HeaderKey, + Value: db.HeaderValue, + Enabled: db.Enabled, + Description: db.Description, + DisplayOrder: float32(db.DisplayOrder), + CreatedAt: db.CreatedAt, + UpdatedAt: db.UpdatedAt, + } +} diff --git a/packages/server/pkg/service/swebsocket/swebsocket.go b/packages/server/pkg/service/swebsocket/swebsocket.go new file mode 100644 index 000000000..a87d9d23a --- /dev/null +++ b/packages/server/pkg/service/swebsocket/swebsocket.go @@ -0,0 +1,72 @@ +package swebsocket + +import ( + "context" + "database/sql" + "log/slog" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mwebsocket" +) + +var ErrNoWebSocketFound = sql.ErrNoRows + +type WebSocketService struct { + queries *gen.Queries + logger *slog.Logger +} + +func New(queries *gen.Queries, logger *slog.Logger) WebSocketService { + return WebSocketService{queries: queries, logger: logger} +} + +func (s WebSocketService) TX(tx *sql.Tx) WebSocketService { + return WebSocketService{queries: s.queries.WithTx(tx), logger: s.logger} +} + +func (s WebSocketService) Get(ctx context.Context, id idwrap.IDWrap) (*mwebsocket.WebSocket, error) { + ws, err := s.queries.GetWebSocket(ctx, id) + if err != nil { + return nil, err + } + return convertToModelWebSocket(ws), nil +} + +func (s WebSocketService) GetByWorkspaceID(ctx context.Context, workspaceID idwrap.IDWrap) ([]mwebsocket.WebSocket, error) { + wsList, err := s.queries.GetWebSocketsByWorkspaceID(ctx, workspaceID) + if err != nil { + return nil, err + } + result := make([]mwebsocket.WebSocket, len(wsList)) + for i, ws := range wsList { + result[i] = *convertToModelWebSocket(ws) + } + return result, nil +} + +func (s WebSocketService) GetWorkspaceID(ctx context.Context, id idwrap.IDWrap) (idwrap.IDWrap, error) { + return s.queries.GetWebSocketWorkspaceID(ctx, id) +} + +func (s WebSocketService) Create(ctx context.Context, ws *mwebsocket.WebSocket) error { + return s.queries.CreateWebSocket(ctx, convertToDBCreateWebSocket(*ws)) +} + +func (s WebSocketService) Update(ctx context.Context, ws *mwebsocket.WebSocket) error { + var lastRunAt interface{} + if ws.LastRunAt != nil { + lastRunAt = *ws.LastRunAt + } + return s.queries.UpdateWebSocket(ctx, gen.UpdateWebSocketParams{ + ID: ws.ID, + Name: ws.Name, + Url: ws.Url, + Description: ws.Description, + LastRunAt: lastRunAt, + }) +} + +func (s WebSocketService) Delete(ctx context.Context, id idwrap.IDWrap) error { + return s.queries.DeleteWebSocket(ctx, id) +} diff --git a/packages/server/pkg/translate/yamlflowsimplev2/converter_flow.go b/packages/server/pkg/translate/yamlflowsimplev2/converter_flow.go index a50d19e3a..8781465eb 100644 --- a/packages/server/pkg/translate/yamlflowsimplev2/converter_flow.go +++ b/packages/server/pkg/translate/yamlflowsimplev2/converter_flow.go @@ -275,6 +275,11 @@ func mergeFlowData(result *ioworkspace.WorkspaceBundle, flowData *ioworkspace.Wo result.GraphQLHeaders = append(result.GraphQLHeaders, flowData.GraphQLHeaders...) result.GraphQLAsserts = append(result.GraphQLAsserts, flowData.GraphQLAsserts...) result.FlowGraphQLNodes = append(result.FlowGraphQLNodes, flowData.FlowGraphQLNodes...) + result.FlowWsConnectionNodes = append(result.FlowWsConnectionNodes, flowData.FlowWsConnectionNodes...) + result.FlowWsSendNodes = append(result.FlowWsSendNodes, flowData.FlowWsSendNodes...) + result.FlowWaitNodes = append(result.FlowWaitNodes, flowData.FlowWaitNodes...) + result.WebSockets = append(result.WebSockets, flowData.WebSockets...) + result.WebSocketHeaders = append(result.WebSocketHeaders, flowData.WebSocketHeaders...) } func mergeAssociatedData(result *ioworkspace.WorkspaceBundle, assoc *HTTPAssociatedData) { diff --git a/packages/server/pkg/translate/yamlflowsimplev2/converter_node.go b/packages/server/pkg/translate/yamlflowsimplev2/converter_node.go index 2089851d9..0c5195427 100644 --- a/packages/server/pkg/translate/yamlflowsimplev2/converter_node.go +++ b/packages/server/pkg/translate/yamlflowsimplev2/converter_node.go @@ -13,6 +13,7 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mgraphql" "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mhttp" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mwebsocket" "github.com/the-dev-tools/dev-tools/packages/server/pkg/varsystem" ) @@ -37,6 +38,12 @@ func getStepCommon(sw YamlStepWrapper) *YamlStepCommon { return &sw.AIMemory.YamlStepCommon case sw.GraphQL != nil: return &sw.GraphQL.YamlStepCommon + case sw.WsConnection != nil: + return &sw.WsConnection.YamlStepCommon + case sw.WsSend != nil: + return &sw.WsSend.YamlStepCommon + case sw.Wait != nil: + return &sw.Wait.YamlStepCommon case sw.ManualStart != nil: return sw.ManualStart default: @@ -96,6 +103,15 @@ func processSteps(flowEntry YamlFlowFlowV2, templates map[string]YamlRequestDefV case stepWrapper.AIMemory != nil: nodeName = stepWrapper.AIMemory.Name dependsOn = stepWrapper.AIMemory.DependsOn + case stepWrapper.WsConnection != nil: + nodeName = stepWrapper.WsConnection.Name + dependsOn = stepWrapper.WsConnection.DependsOn + case stepWrapper.WsSend != nil: + nodeName = stepWrapper.WsSend.Name + dependsOn = stepWrapper.WsSend.DependsOn + case stepWrapper.Wait != nil: + nodeName = stepWrapper.Wait.Name + dependsOn = stepWrapper.Wait.DependsOn case stepWrapper.ManualStart != nil: nodeName = stepWrapper.ManualStart.Name dependsOn = stepWrapper.ManualStart.DependsOn @@ -181,6 +197,18 @@ func processSteps(flowEntry YamlFlowFlowV2, templates map[string]YamlRequestDefV if err := processAIMemoryStructStep(stepWrapper.AIMemory, nodeID, flowID, result); err != nil { return nil, err } + case stepWrapper.WsConnection != nil: + if err := processWsConnectionStructStep(stepWrapper.WsConnection, nodeID, flowID, opts, result); err != nil { + return nil, err + } + case stepWrapper.WsSend != nil: + if err := processWsSendStructStep(stepWrapper.WsSend, nodeID, flowID, result); err != nil { + return nil, err + } + case stepWrapper.Wait != nil: + if err := processWaitStructStep(stepWrapper.Wait, nodeID, flowID, result); err != nil { + return nil, err + } case stepWrapper.ManualStart != nil: info.id = startNodeID createStartNodeWithID(startNodeID, flowID, result) @@ -603,3 +631,96 @@ func processGraphQLStructStep(step *YamlStepGraphQL, nodeID, flowID idwrap.IDWra return nil } + +func processWsConnectionStructStep(step *YamlStepWsConnection, nodeID, flowID idwrap.IDWrap, opts ConvertOptionsV2, result *ioworkspace.WorkspaceBundle) error { + if step.URL == "" { + return NewYamlFlowErrorV2(fmt.Sprintf("ws_connection step '%s' missing required url", step.Name), "url", nil) + } + + flowNode := mflow.Node{ + ID: nodeID, + FlowID: flowID, + Name: step.Name, + NodeKind: mflow.NODE_KIND_WS_CONNECTION, + } + result.FlowNodes = append(result.FlowNodes, flowNode) + + // Create WebSocket entity (like GraphQL pattern) + wsID := idwrap.NewNow() + now := time.Now().UnixMilli() + ws := mwebsocket.WebSocket{ + ID: wsID, + WorkspaceID: opts.WorkspaceID, + Name: step.Name, + Url: step.URL, + CreatedAt: now, + UpdatedAt: now, + } + result.WebSockets = append(result.WebSockets, ws) + + // Create headers + for i, h := range step.Headers { + header := mwebsocket.WebSocketHeader{ + ID: idwrap.NewNow(), + WebSocketID: wsID, + Key: h.Name, + Value: h.Value, + Enabled: h.Enabled, + DisplayOrder: float32(i), + CreatedAt: now, + UpdatedAt: now, + } + result.WebSocketHeaders = append(result.WebSocketHeaders, header) + } + + wsConnNode := mflow.NodeWsConnection{ + FlowNodeID: nodeID, + WebSocketID: &wsID, + } + result.FlowWsConnectionNodes = append(result.FlowWsConnectionNodes, wsConnNode) + return nil +} + +func processWsSendStructStep(step *YamlStepWsSend, nodeID, flowID idwrap.IDWrap, result *ioworkspace.WorkspaceBundle) error { + flowNode := mflow.Node{ + ID: nodeID, + FlowID: flowID, + Name: step.Name, + NodeKind: mflow.NODE_KIND_WS_SEND, + } + result.FlowNodes = append(result.FlowNodes, flowNode) + + wsSendNode := mflow.NodeWsSend{ + FlowNodeID: nodeID, + WsConnectionNodeName: step.WsConnectionNodeName, + Message: step.Message, + } + result.FlowWsSendNodes = append(result.FlowWsSendNodes, wsSendNode) + return nil +} + +func processWaitStructStep(step *YamlStepWait, nodeID, flowID idwrap.IDWrap, result *ioworkspace.WorkspaceBundle) error { + flowNode := mflow.Node{ + ID: nodeID, + FlowID: flowID, + Name: step.Name, + NodeKind: mflow.NODE_KIND_WAIT, + } + result.FlowNodes = append(result.FlowNodes, flowNode) + + var durationMs int64 + if step.DurationMs != "" { + d, err := strconv.ParseInt(step.DurationMs, 10, 64) + if err != nil { + return NewYamlFlowErrorV2(fmt.Sprintf("invalid duration_ms value '%s': %v", step.DurationMs, err), "duration_ms", step.DurationMs) + } + durationMs = d + } + + waitNode := mflow.NodeWait{ + FlowNodeID: nodeID, + DurationMs: durationMs, + } + result.FlowWaitNodes = append(result.FlowWaitNodes, waitNode) + return nil +} diff --git a/packages/server/pkg/translate/yamlflowsimplev2/exporter.go b/packages/server/pkg/translate/yamlflowsimplev2/exporter.go index 6ea9184ed..1e2c08609 100644 --- a/packages/server/pkg/translate/yamlflowsimplev2/exporter.go +++ b/packages/server/pkg/translate/yamlflowsimplev2/exporter.go @@ -5,6 +5,7 @@ import ( "fmt" "math" "sort" + "strconv" "github.com/the-dev-tools/dev-tools/packages/server/pkg/flowgraph" "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" @@ -13,6 +14,7 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mgraphql" "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mhttp" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mwebsocket" "gopkg.in/yaml.v3" ) @@ -123,6 +125,31 @@ func MarshalSimplifiedYAML(data *ioworkspace.WorkspaceBundle) ([]byte, error) { graphqlNodeMap[n.FlowNodeID] = n } + wsConnectionNodeMap := make(map[idwrap.IDWrap]mflow.NodeWsConnection) + for _, n := range data.FlowWsConnectionNodes { + wsConnectionNodeMap[n.FlowNodeID] = n + } + + wsSendNodeMap := make(map[idwrap.IDWrap]mflow.NodeWsSend) + for _, n := range data.FlowWsSendNodes { + wsSendNodeMap[n.FlowNodeID] = n + } + + waitNodeMap := make(map[idwrap.IDWrap]mflow.NodeWait) + for _, n := range data.FlowWaitNodes { + waitNodeMap[n.FlowNodeID] = n + } + + wsEntityMap := make(map[idwrap.IDWrap]mwebsocket.WebSocket) + for _, ws := range data.WebSockets { + wsEntityMap[ws.ID] = ws + } + + wsHeaderMap := make(map[idwrap.IDWrap][]mwebsocket.WebSocketHeader) + for _, h := range data.WebSocketHeaders { + wsHeaderMap[h.WebSocketID] = append(wsHeaderMap[h.WebSocketID], h) + } + graphqlMap := make(map[idwrap.IDWrap]mgraphql.GraphQL) for _, g := range data.GraphQLRequests { graphqlMap[g.ID] = g @@ -372,6 +399,8 @@ func MarshalSimplifiedYAML(data *ioworkspace.WorkspaceBundle) ([]byte, error) { depStr += DependsSuffixElse case mflow.HandleLoop: depStr += DependsSuffixLoop + case mflow.HandleWsMessage: + depStr += DependsSuffixWsMessage case mflow.HandleUnspecified: // Do nothing, just the name default: @@ -562,6 +591,54 @@ func MarshalSimplifiedYAML(data *ioworkspace.WorkspaceBundle) ([]byte, error) { } stepWrapper.GraphQL = gqlStep + case mflow.NODE_KIND_WS_CONNECTION: + wsConnNode, ok := wsConnectionNodeMap[node.ID] + if !ok { + continue + } + wsStep := &YamlStepWsConnection{ + YamlStepCommon: common, + } + if wsConnNode.WebSocketID != nil { + if wsEntity, ok := wsEntityMap[*wsConnNode.WebSocketID]; ok { + wsStep.URL = wsEntity.Url + } + if headers, ok := wsHeaderMap[*wsConnNode.WebSocketID]; ok { + for _, h := range headers { + if h.Enabled { + wsStep.Headers = append(wsStep.Headers, YamlNameValuePairV2{ + Name: h.Key, + Value: h.Value, + Enabled: true, + }) + } + } + } + } + stepWrapper.WsConnection = wsStep + + case mflow.NODE_KIND_WS_SEND: + wsSendNode, ok := wsSendNodeMap[node.ID] + if !ok { + continue + } + wsStep := &YamlStepWsSend{ + YamlStepCommon: common, + WsConnectionNodeName: wsSendNode.WsConnectionNodeName, + Message: wsSendNode.Message, + } + stepWrapper.WsSend = wsStep + + case mflow.NODE_KIND_WAIT: + waitNode, ok := waitNodeMap[node.ID] + if !ok { + continue + } + stepWrapper.Wait = &YamlStepWait{ + YamlStepCommon: common, + DurationMs: strconv.FormatInt(waitNode.DurationMs, 10), + } + case mflow.NODE_KIND_MANUAL_START: if node.ID == startNodeID { stepWrapper.ManualStart = &common @@ -575,7 +652,8 @@ func MarshalSimplifiedYAML(data *ioworkspace.WorkspaceBundle) ([]byte, error) { // Checking if any field is set (simplified check, assume one set if we got here) isValid := stepWrapper.Request != nil || stepWrapper.GraphQL != nil || stepWrapper.If != nil || stepWrapper.For != nil || stepWrapper.ForEach != nil || stepWrapper.JS != nil || stepWrapper.AI != nil || - stepWrapper.AIProvider != nil || stepWrapper.AIMemory != nil || stepWrapper.ManualStart != nil + stepWrapper.AIProvider != nil || stepWrapper.AIMemory != nil || stepWrapper.WsConnection != nil || + stepWrapper.WsSend != nil || stepWrapper.Wait != nil || stepWrapper.ManualStart != nil if isValid { flowYaml.Steps = append(flowYaml.Steps, stepWrapper) } diff --git a/packages/server/pkg/translate/yamlflowsimplev2/types.go b/packages/server/pkg/translate/yamlflowsimplev2/types.go index 8aa6f2322..fb38536eb 100644 --- a/packages/server/pkg/translate/yamlflowsimplev2/types.go +++ b/packages/server/pkg/translate/yamlflowsimplev2/types.go @@ -83,8 +83,11 @@ type YamlStepWrapper struct { JS *YamlStepJS `yaml:"js,omitempty"` AI *YamlStepAI `yaml:"ai,omitempty"` AIProvider *YamlStepAIProvider `yaml:"ai_provider,omitempty"` - AIMemory *YamlStepAIMemory `yaml:"ai_memory,omitempty"` - ManualStart *YamlStepCommon `yaml:"manual_start,omitempty"` + AIMemory *YamlStepAIMemory `yaml:"ai_memory,omitempty"` + WsConnection *YamlStepWsConnection `yaml:"ws_connection,omitempty"` + WsSend *YamlStepWsSend `yaml:"ws_send,omitempty"` + Wait *YamlStepWait `yaml:"wait,omitempty"` + ManualStart *YamlStepCommon `yaml:"manual_start,omitempty"` } // Common fields for all step types @@ -166,6 +169,23 @@ type YamlStepAIMemory struct { WindowSize int `yaml:"window_size,omitempty"` // Number of messages to keep (default 10) } +type YamlStepWsConnection struct { + YamlStepCommon `yaml:",inline"` + URL string `yaml:"url,omitempty"` + Headers HeaderMapOrSlice `yaml:"headers,omitempty"` +} + +type YamlStepWsSend struct { + YamlStepCommon `yaml:",inline"` + WsConnectionNodeName string `yaml:"ws_connection_node_name"` + Message string `yaml:"message,omitempty"` +} + +type YamlStepWait struct { + YamlStepCommon `yaml:",inline"` + DurationMs string `yaml:"duration_ms"` +} + // YamlFlowVariableV2 represents a flow variable type YamlFlowVariableV2 struct { Name string `yaml:"name"` @@ -418,7 +438,9 @@ type YamlFlowDataV2 struct { AINodes []mflow.NodeAI AIProviderNodes []mflow.NodeAiProvider AIMemoryNodes []mflow.NodeMemory - GraphQLNodes []mflow.NodeGraphQL + GraphQLNodes []mflow.NodeGraphQL + WsConnectionNodes []mflow.NodeWsConnection + WsSendNodes []mflow.NodeWsSend } // YamlVariableV2 represents a variable during parsing diff --git a/packages/server/pkg/translate/yamlflowsimplev2/utils.go b/packages/server/pkg/translate/yamlflowsimplev2/utils.go index f9dcaec30..4f4b30859 100644 --- a/packages/server/pkg/translate/yamlflowsimplev2/utils.go +++ b/packages/server/pkg/translate/yamlflowsimplev2/utils.go @@ -4,6 +4,7 @@ import ( "fmt" "net/url" "regexp" + "strconv" "strings" "time" @@ -39,9 +40,10 @@ const ( DefaultCollectionName = "Imported Collection" // Dependency handler suffixes (used in depends_on field) - DependsSuffixThen = ".then" - DependsSuffixElse = ".else" - DependsSuffixLoop = ".loop" + DependsSuffixThen = ".then" + DependsSuffixElse = ".else" + DependsSuffixLoop = ".loop" + DependsSuffixWsMessage = ".ws_message" // Environment variable template patterns (used in credential export) EnvVarTemplateToken = "{{ #env:%s_TOKEN }}" //nolint:gosec // G101: template pattern, not a credential @@ -486,7 +488,7 @@ func GenerateStats(data *ioworkspace.WorkspaceBundle) map[string]interface{} { // Flow node breakdown nodeTypes := make(map[string]int) for _, node := range data.FlowNodes { - nodeTypes[string(node.NodeKind)]++ + nodeTypes[strconv.FormatInt(int64(node.NodeKind), 10)]++ } stats["flow_node_types"] = nodeTypes diff --git a/packages/server/pkg/translate/yamlflowsimplev2/utils_test.go b/packages/server/pkg/translate/yamlflowsimplev2/utils_test.go index b17a089e0..8deffd9f6 100644 --- a/packages/server/pkg/translate/yamlflowsimplev2/utils_test.go +++ b/packages/server/pkg/translate/yamlflowsimplev2/utils_test.go @@ -1,6 +1,7 @@ package yamlflowsimplev2 import ( + "strconv" "strings" "testing" @@ -359,8 +360,8 @@ func TestGenerateStats(t *testing.T) { // Check node type breakdown nodeTypes := stats["flow_node_types"].(map[string]int) - require.Equal(t, 2, nodeTypes[string(mflow.NODE_KIND_REQUEST)]) - require.Equal(t, 1, nodeTypes[string(mflow.NODE_KIND_CONDITION)]) + require.Equal(t, 2, nodeTypes[strconv.FormatInt(int64(mflow.NODE_KIND_REQUEST), 10)]) + require.Equal(t, 1, nodeTypes[strconv.FormatInt(int64(mflow.NODE_KIND_CONDITION), 10)]) // Check averages require.Equal(t, 1.5, stats["avg_nodes_per_flow"].(float64)) diff --git a/packages/server/test/e2e_har_to_cli_test.go b/packages/server/test/e2e_har_to_cli_test.go index c1120ae74..003c1366c 100644 --- a/packages/server/test/e2e_har_to_cli_test.go +++ b/packages/server/test/e2e_har_to_cli_test.go @@ -273,6 +273,11 @@ func TestE2E_HAR_To_CLI_Chain(t *testing.T) { nil, // NodeAiProviderService nil, // NodeMemoryService nil, // NodeGraphQLService + nil, // NodeWsConnectionService + nil, // NodeWsSendService + nil, // NodeWaitService + nil, // WebSocketService + nil, // WebSocketHeaderService nil, // GraphQLService nil, // GraphQLHeaderService cli.Workspace, @@ -449,7 +454,6 @@ func executeFlow(ctx context.Context, flowPtr *mflow.Flow, c *cliServices, build if err != nil { return err } - fmt.Printf("DEBUG: Found %d edges for flow %s\n", len(edges), latestFlowID) edgeMap := mflow.NewEdgesMap(edges) flowVars, err := c.FlowVariable.GetFlowVariablesByFlowID(ctx, latestFlowID) @@ -491,7 +495,7 @@ func executeFlow(ctx context.Context, flowPtr *mflow.Flow, c *cliServices, build defer close(gqlRespChan) // Build flow node map - flowNodeMap, startNodeID, err := builder.BuildNodes( + flowNodeMap, startNodeIDs, err := builder.BuildNodes( ctx, *flowPtr, nodes, @@ -506,7 +510,7 @@ func executeFlow(ctx context.Context, flowPtr *mflow.Flow, c *cliServices, build } // Create runner - runnerInst := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), latestFlowID, startNodeID, flowNodeMap, edgeMap, nodeTimeout, nil) + runnerInst := flowlocalrunner.CreateFlowRunner(idwrap.NewNow(), latestFlowID, startNodeIDs, flowNodeMap, edgeMap, nodeTimeout, nil) flowNodeStatusChan := make(chan runner.FlowNodeStatus, 1000) flowStatusChan := make(chan runner.FlowStatus, 10) diff --git a/packages/spec/api/export.tsp b/packages/spec/api/export.tsp index a327d0aa2..cb14e5706 100644 --- a/packages/spec/api/export.tsp +++ b/packages/spec/api/export.tsp @@ -21,3 +21,13 @@ model ExportCurlResponse { data: string; } op ExportCurl(...ExportCurlRequest): ExportCurlResponse; + +model ExportCurlGraphQLRequest { + workspaceId: Id; + graphqlIds?: Id[]; +} + +model ExportCurlGraphQLResponse { + data: string; +} +op ExportCurlGraphQL(...ExportCurlGraphQLRequest): ExportCurlGraphQLResponse; diff --git a/packages/spec/api/file-system.tsp b/packages/spec/api/file-system.tsp index 88fcdb0b7..ceefccf54 100644 --- a/packages/spec/api/file-system.tsp +++ b/packages/spec/api/file-system.tsp @@ -9,6 +9,7 @@ enum FileKind { Flow, Credential, GraphQL, + WebSocket, } @TanStackDB.collection diff --git a/packages/spec/api/flow.tsp b/packages/spec/api/flow.tsp index 27c23414b..d4e91f4ab 100644 --- a/packages/spec/api/flow.tsp +++ b/packages/spec/api/flow.tsp @@ -67,6 +67,7 @@ enum HandleKind { AiProvider, AiMemory, AiTools, + WsMessage, } @AITools.mutationTool(#{ @@ -96,6 +97,9 @@ enum NodeKind { AiProvider, AiMemory, GraphQL, + WsConnection, + WsSend, + Wait, } enum AiMemoryType { @@ -293,6 +297,25 @@ model NodeAiMemory { windowSize: int32; } +@TanStackDB.collection +model NodeWsConnection { + @primaryKey nodeId: Id; + @foreignKey websocketId?: Id; +} + +@TanStackDB.collection +model NodeWsSend { + @primaryKey nodeId: Id; + wsConnectionNodeName: string; + message: string; +} + +@TanStackDB.collection +model NodeWait { + @primaryKey nodeId: Id; + durationMs: int64; +} + // Copy/Paste operations enum ReferenceMode { CreateCopy, diff --git a/packages/spec/api/main.tsp b/packages/spec/api/main.tsp index ae71a6e20..9fcb49703 100644 --- a/packages/spec/api/main.tsp +++ b/packages/spec/api/main.tsp @@ -17,6 +17,7 @@ import "./private/node-js-executor.tsp"; import "./log.tsp"; import "./reference.tsp"; // import "./user.tsp"; +import "./websocket.tsp"; import "./workspace.tsp"; using DevTools; diff --git a/packages/spec/api/websocket.tsp b/packages/spec/api/websocket.tsp new file mode 100644 index 000000000..cd1e3405e --- /dev/null +++ b/packages/spec/api/websocket.tsp @@ -0,0 +1,23 @@ +using DevTools; + +namespace Api.WebSocket; + +@TanStackDB.collection +model WebSocket { + @primaryKey websocketId: Id; + name: string; + url: string; + lastRunAt?: Protobuf.WellKnown.Timestamp; +} + +@TanStackDB.collection +model WebSocketHeader { + @primaryKey websocketHeaderId: Id; + ...CommonTableFields; +} + +model WebSocketRunRequest { + websocketId: Id; +} + +op WebSocketRun(...WebSocketRunRequest): {}; diff --git a/packages/spec/package.json b/packages/spec/package.json index 1407f9752..01acd4b73 100755 --- a/packages/spec/package.json +++ b/packages/spec/package.json @@ -25,7 +25,7 @@ "@the-dev-tools/eslint-config": "workspace:^", "@types/node": "catalog:", "prettier": "catalog:", - "tsx": "^4.19.0", + "tsx": "catalog:", "typescript": "catalog:" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b2b16a50a..d58464f08 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,8 +7,8 @@ settings: catalogs: default: '@aikidosec/safe-chain': - specifier: 1.4.0 - version: 1.4.0 + specifier: 1.4.4 + version: 1.4.4 '@alloy-js/cli': specifier: 0.22.0 version: 0.22.0 @@ -19,26 +19,26 @@ catalogs: specifier: 0.22.0 version: 0.22.0 '@better-auth/cli': - specifier: 1.4.18 - version: 1.4.18 + specifier: 1.4.21 + version: 1.4.21 '@bufbuild/buf': - specifier: 1.63.0 - version: 1.63.0 + specifier: 1.66.0 + version: 1.66.0 '@bufbuild/protobuf': - specifier: 2.10.2 - version: 2.10.2 + specifier: 2.11.0 + version: 2.11.0 '@bufbuild/protoc-gen-es': - specifier: 2.10.2 - version: 2.10.2 + specifier: 2.11.0 + version: 2.11.0 '@bufbuild/protovalidate': - specifier: 1.1.0 - version: 1.1.0 + specifier: 1.1.1 + version: 1.1.1 '@codemirror/lang-html': specifier: 6.4.11 version: 6.4.11 '@codemirror/lang-javascript': - specifier: 6.2.4 - version: 6.2.4 + specifier: 6.2.5 + version: 6.2.5 '@codemirror/lang-json': specifier: 6.0.2 version: 6.0.2 @@ -58,29 +58,29 @@ catalogs: specifier: 2.1.1 version: 2.1.1 '@effect-atom/atom-react': - specifier: 0.4.4 - version: 0.4.4 + specifier: 0.5.0 + version: 0.5.0 '@effect/cli': - specifier: 0.73.0 - version: 0.73.0 + specifier: 0.73.2 + version: 0.73.2 '@effect/platform': - specifier: 0.94.1 - version: 0.94.1 + specifier: 0.94.5 + version: 0.94.5 '@effect/platform-browser': specifier: 0.74.0 version: 0.74.0 '@effect/platform-node': - specifier: 0.104.0 - version: 0.104.0 + specifier: 0.104.1 + version: 0.104.1 '@eslint/compat': - specifier: 2.0.0 - version: 2.0.0 + specifier: 2.0.2 + version: 2.0.2 '@eslint/js': specifier: 9.39.2 version: 9.39.2 '@faker-js/faker': - specifier: 10.2.0 - version: 10.2.0 + specifier: 10.3.0 + version: 10.3.0 '@fontsource-variable/dm-sans': specifier: 5.2.8 version: 5.2.8 @@ -100,26 +100,26 @@ catalogs: specifier: 1.2.3 version: 1.2.3 '@lezer/lr': - specifier: 1.4.7 - version: 1.4.7 + specifier: 1.4.8 + version: 1.4.8 '@nx/eslint': - specifier: 22.3.3 - version: 22.3.3 + specifier: 22.5.4 + version: 22.5.4 '@nx/js': - specifier: 22.3.3 - version: 22.3.3 + specifier: 22.5.4 + version: 22.5.4 '@nx/react': - specifier: 22.3.3 - version: 22.3.3 + specifier: 22.5.4 + version: 22.5.4 '@nx/storybook': - specifier: 22.3.3 - version: 22.3.3 + specifier: 22.5.4 + version: 22.5.4 '@nx/vite': - specifier: 22.3.3 - version: 22.3.3 + specifier: 22.5.4 + version: 22.5.4 '@nx/web': - specifier: 22.3.3 - version: 22.3.3 + specifier: 22.5.4 + version: 22.5.4 '@octokit/auth-action': specifier: 6.0.2 version: 6.0.2 @@ -130,50 +130,50 @@ catalogs: specifier: 3.4.2 version: 3.4.2 '@react-aria/collections': - specifier: 3.0.1 - version: 3.0.1 + specifier: 3.0.3 + version: 3.0.3 '@standard-schema/spec': specifier: 1.1.0 version: 1.1.0 '@storybook/addon-docs': - specifier: 10.1.11 - version: 10.1.11 + specifier: 10.2.16 + version: 10.2.16 '@storybook/react': - specifier: 10.1.11 - version: 10.1.11 + specifier: 10.2.16 + version: 10.2.16 '@storybook/react-vite': - specifier: 10.1.11 - version: 10.1.11 + specifier: 10.2.16 + version: 10.2.16 '@tailwindcss/typography': specifier: 0.5.19 version: 0.5.19 '@tailwindcss/vite': - specifier: 4.1.18 - version: 4.1.18 + specifier: 4.2.1 + version: 4.2.1 '@tanstack/eslint-plugin-router': - specifier: 1.141.0 - version: 1.141.0 + specifier: 1.161.4 + version: 1.161.4 '@tanstack/react-db': - specifier: 0.1.60 - version: 0.1.60 + specifier: 0.1.74 + version: 0.1.74 '@tanstack/react-query': - specifier: 5.90.16 - version: 5.90.16 + specifier: 5.90.21 + version: 5.90.21 '@tanstack/react-query-devtools': - specifier: 5.91.2 - version: 5.91.2 + specifier: 5.91.3 + version: 5.91.3 '@tanstack/react-router': - specifier: 1.145.7 - version: 1.145.7 + specifier: 1.166.2 + version: 1.166.2 '@tanstack/react-router-devtools': - specifier: 1.145.7 - version: 1.145.7 + specifier: 1.166.2 + version: 1.166.2 '@tanstack/router-plugin': - specifier: 1.145.10 - version: 1.145.10 + specifier: 1.166.2 + version: 1.166.2 '@tanstack/virtual-file-routes': - specifier: 1.145.4 - version: 1.145.4 + specifier: 1.161.4 + version: 1.161.4 '@tsconfig/strictest': specifier: 2.0.8 version: 2.0.8 @@ -181,11 +181,11 @@ catalogs: specifier: 6.10.1 version: 6.10.1 '@types/node': - specifier: 25.0.3 - version: 25.0.3 + specifier: 25.3.5 + version: 25.3.5 '@types/react': - specifier: 19.2.7 - version: 19.2.7 + specifier: 19.2.14 + version: 19.2.14 '@types/react-dom': specifier: 19.2.3 version: 19.2.3 @@ -193,23 +193,23 @@ catalogs: specifier: 8.0.0 version: 8.0.0 '@typescript-eslint/parser': - specifier: 8.52.0 - version: 8.52.0 + specifier: 8.56.1 + version: 8.56.1 '@typespec/compiler': - specifier: 1.7.1 - version: 1.7.1 + specifier: 1.9.0 + version: 1.9.0 '@typespec/emitter-framework': - specifier: 0.14.0 - version: 0.14.0 + specifier: 0.16.0 + version: 0.16.0 '@typespec/prettier-plugin-typespec': - specifier: 1.7.0 - version: 1.7.0 + specifier: 1.9.0 + version: 1.9.0 '@uiw/react-codemirror': - specifier: 4.25.4 - version: 4.25.4 + specifier: 4.25.7 + version: 4.25.7 '@vitejs/plugin-react': - specifier: 5.1.2 - version: 5.1.2 + specifier: 5.1.4 + version: 5.1.4 '@xyflow/react': specifier: 12.10.1 version: 12.10.1 @@ -217,23 +217,26 @@ catalogs: specifier: 19.1.0-rc.3 version: 19.1.0-rc.3 better-auth: - specifier: 1.4.18 - version: 1.4.18 + specifier: 1.5.4 + version: 1.5.4 builder-util-runtime: specifier: 9.5.1 version: 9.5.1 effect: - specifier: 3.19.14 - version: 3.19.14 + specifier: 3.19.19 + version: 3.19.19 electron: - specifier: 39.2.7 - version: 39.2.7 + specifier: 40.8.0 + version: 40.8.0 electron-builder: - specifier: 26.3.1 - version: 26.3.1 + specifier: 26.8.1 + version: 26.8.1 electron-devtools-installer: specifier: 4.0.0 version: 4.0.0 + electron-updater: + specifier: 6.8.3 + version: 6.8.3 electron-vite: specifier: 5.0.0 version: 5.0.0 @@ -247,8 +250,8 @@ catalogs: specifier: 4.4.4 version: 4.4.4 eslint-plugin-better-tailwindcss: - specifier: 3.8.0 - version: 3.8.0 + specifier: 4.3.2 + version: 4.3.2 eslint-plugin-import-x: specifier: 4.16.1 version: 4.16.1 @@ -256,8 +259,8 @@ catalogs: specifier: 6.10.2 version: 6.10.2 eslint-plugin-perfectionist: - specifier: 5.3.0 - version: 5.3.0 + specifier: 5.6.0 + version: 5.6.0 eslint-plugin-react: specifier: 7.37.5 version: 7.37.5 @@ -265,8 +268,8 @@ catalogs: specifier: 7.0.1 version: 7.0.1 globals: - specifier: 17.0.0 - version: 17.0.0 + specifier: 17.4.0 + version: 17.4.0 id128: specifier: 1.6.6 version: 1.6.6 @@ -274,44 +277,44 @@ catalogs: specifier: 2.6.1 version: 2.6.1 nx: - specifier: 22.3.3 - version: 22.3.3 + specifier: 22.5.4 + version: 22.5.4 openai: - specifier: 4.77.0 - version: 4.77.0 + specifier: 6.27.0 + version: 6.27.0 prettier: - specifier: 3.7.4 - version: 3.7.4 + specifier: 3.8.1 + version: 3.8.1 react: - specifier: 19.2.3 - version: 19.2.3 + specifier: 19.2.4 + version: 19.2.4 react-aria: - specifier: 3.45.0 - version: 3.45.0 + specifier: 3.47.0 + version: 3.47.0 react-aria-components: - specifier: 1.14.0 - version: 1.14.0 + specifier: 1.16.0 + version: 1.16.0 react-dom: - specifier: 19.2.3 - version: 19.2.3 + specifier: 19.2.4 + version: 19.2.4 react-error-boundary: - specifier: 6.0.2 - version: 6.0.2 + specifier: 6.1.1 + version: 6.1.1 react-icons: - specifier: 5.5.0 - version: 5.5.0 + specifier: 5.6.0 + version: 5.6.0 react-markdown: specifier: 10.1.0 version: 10.1.0 react-resizable-panels: - specifier: 4.3.0 - version: 4.3.0 + specifier: 4.7.1 + version: 4.7.1 react-scan: - specifier: 0.4.3 - version: 0.4.3 + specifier: 0.5.3 + version: 0.5.3 react-stately: - specifier: 3.43.0 - version: 3.43.0 + specifier: 3.45.0 + version: 3.45.0 react-timeago: specifier: 8.3.0 version: 8.3.0 @@ -319,8 +322,8 @@ catalogs: specifier: 4.0.1 version: 4.0.1 storybook: - specifier: 10.1.11 - version: 10.1.11 + specifier: 10.2.16 + version: 10.2.16 swc-node: specifier: 1.0.0 version: 1.0.0 @@ -328,14 +331,14 @@ catalogs: specifier: 13.0.4 version: 13.0.4 tailwind-merge: - specifier: 3.4.0 - version: 3.4.0 + specifier: 3.5.0 + version: 3.5.0 tailwind-variants: specifier: 3.2.2 version: 3.2.2 tailwindcss: - specifier: 4.1.18 - version: 4.1.18 + specifier: 4.2.1 + version: 4.2.1 tailwindcss-react-aria-components: specifier: 2.0.1 version: 2.0.1 @@ -345,6 +348,9 @@ catalogs: tsup: specifier: 8.5.1 version: 8.5.1 + tsx: + specifier: ^4.21.0 + version: 4.21.0 tw-animate-css: specifier: 1.4.0 version: 1.4.0 @@ -352,20 +358,20 @@ catalogs: specifier: 5.9.3 version: 5.9.3 typescript-eslint: - specifier: 8.52.0 - version: 8.52.0 + specifier: 8.56.1 + version: 8.56.1 undici: - specifier: 7.18.2 - version: 7.18.2 + specifier: 7.22.0 + version: 7.22.0 use-debounce: - specifier: 10.0.6 - version: 10.0.6 + specifier: 10.1.0 + version: 10.1.0 vite: specifier: 7.3.1 version: 7.3.1 vite-tsconfig-paths: - specifier: 6.0.3 - version: 6.0.3 + specifier: 6.1.1 + version: 6.1.1 vitest: specifier: 4.0.18 version: 4.0.18 @@ -379,6 +385,7 @@ overrides: '@codemirror/language': 6.12.1 '@codemirror/state': 6.5.3 '@codemirror/view': 6.39.9 + '@lezer/common': 1.5.1 '@types/eslint': '-' patchedDependencies: @@ -402,25 +409,25 @@ importers: devDependencies: '@aikidosec/safe-chain': specifier: 'catalog:' - version: 1.4.0 + version: 1.4.4 '@nx/eslint': specifier: 'catalog:' - version: 22.3.3(patch_hash=45d7a0a2e2d55c4ffd4beb467a0e02fac3f27bc1857270f522acafd5365d2c6b)(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(@zkochan/js-yaml@0.0.7)(eslint@9.39.2(jiti@2.6.1))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) + version: 22.5.4(patch_hash=45d7a0a2e2d55c4ffd4beb467a0e02fac3f27bc1857270f522acafd5365d2c6b)(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(@zkochan/js-yaml@0.0.7)(eslint@9.39.2(jiti@2.6.1))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) '@nx/js': specifier: 'catalog:' - version: 22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) + version: 22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) '@nx/react': specifier: 'catalog:' - version: 22.3.3(@babel/core@7.28.5)(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/helpers@0.5.18)(@types/babel__core@7.20.5)(@zkochan/js-yaml@0.0.7)(eslint@9.39.2(jiti@2.6.1))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3))(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.18(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))) + version: 22.5.4(@babel/core@7.29.0)(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/helpers@0.5.19)(@types/babel__core@7.20.5)(@zkochan/js-yaml@0.0.7)(eslint@9.39.2(jiti@2.6.1))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) '@nx/storybook': specifier: 'catalog:' - version: 22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(@zkochan/js-yaml@0.0.7)(eslint@9.39.2(jiti@2.6.1))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)))(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3) + version: 22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(@zkochan/js-yaml@0.0.7)(eslint@9.39.2(jiti@2.6.1))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)))(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) '@nx/vite': specifier: 'catalog:' - version: 22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)))(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.18(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)))(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) '@nx/web': specifier: 'catalog:' - version: 22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) + version: 22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) '@the-dev-tools/eslint-config': specifier: workspace:^ version: link:tools/eslint @@ -429,10 +436,10 @@ importers: version: 2.0.8 '@typespec/compiler': specifier: 'catalog:' - version: 1.7.1(@types/node@25.0.3) + version: 1.9.0(@types/node@25.3.5) '@typespec/prettier-plugin-typespec': specifier: 'catalog:' - version: 1.7.0 + version: 1.9.0 eslint: specifier: 'catalog:' version: 9.39.2(jiti@2.6.1) @@ -441,31 +448,31 @@ importers: version: 2.6.1 nx: specifier: 'catalog:' - version: 22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)) + version: 22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)) prettier: specifier: 'catalog:' - version: 3.7.4 + version: 3.8.1 react: specifier: 'catalog:' - version: 19.2.3 + version: 19.2.4 swc-node: specifier: 'catalog:' - version: 1.0.0(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3) + version: 1.0.0(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3) syncpack: specifier: 'catalog:' version: 13.0.4(typescript@5.9.3) tailwindcss: specifier: 'catalog:' - version: 4.1.18 + version: 4.2.1 ts-node: specifier: 'catalog:' - version: 10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3) + version: 10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.19))(@types/node@25.3.5)(typescript@5.9.3) typescript: specifier: 'catalog:' version: 5.9.3 typescript-eslint: specifier: 'catalog:' - version: 8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + version: 8.56.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) apps/cli: dependencies: @@ -487,34 +494,34 @@ importers: devDependencies: '@bufbuild/protobuf': specifier: 'catalog:' - version: 2.10.2 + version: 2.11.0 '@connectrpc/connect': specifier: 'catalog:' - version: 2.1.1(@bufbuild/protobuf@2.10.2) + version: 2.1.1(@bufbuild/protobuf@2.11.0) '@connectrpc/connect-node': specifier: 'catalog:' - version: 2.1.1(@bufbuild/protobuf@2.10.2)(@connectrpc/connect@2.1.1(@bufbuild/protobuf@2.10.2)) + version: 2.1.1(@bufbuild/protobuf@2.11.0)(@connectrpc/connect@2.1.1(@bufbuild/protobuf@2.11.0)) '@effect-atom/atom-react': specifier: 'catalog:' - version: 0.4.4(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14)(react@19.2.3)(scheduler@0.27.0) + version: 0.5.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19)(react@19.2.4)(scheduler@0.27.0) '@effect/platform': specifier: 'catalog:' - version: 0.94.1(effect@3.19.14) + version: 0.94.5(effect@3.19.19) '@effect/platform-browser': specifier: 'catalog:' - version: 0.74.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14) + version: 0.74.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19) '@effect/platform-node': specifier: 'catalog:' - version: 0.104.0(@effect/cluster@0.56.1(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/workflow@0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14) + version: 0.104.1(@effect/cluster@0.56.1(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/workflow@0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19) '@lezer/generator': specifier: 'catalog:' version: 1.8.0 '@tailwindcss/typography': specifier: 'catalog:' - version: 0.5.19(tailwindcss@4.1.18) + version: 0.5.19(tailwindcss@4.2.1) '@tailwindcss/vite': specifier: 'catalog:' - version: 4.1.18(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.2.1(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) '@the-dev-tools/client': specifier: workspace:^ version: link:../../packages/client @@ -526,13 +533,13 @@ importers: version: link:../../packages/ui '@types/react': specifier: 'catalog:' - version: 19.2.7 + version: 19.2.14 '@types/react-dom': specifier: 'catalog:' - version: 19.2.3(@types/react@19.2.7) + version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: 'catalog:' - version: 5.1.2(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 5.1.4(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) babel-plugin-react-compiler: specifier: 'catalog:' version: 19.1.0-rc.3 @@ -541,49 +548,49 @@ importers: version: 9.5.1 effect: specifier: 'catalog:' - version: 3.19.14 + version: 3.19.19 electron: specifier: 'catalog:' - version: 39.2.7 + version: 40.8.0 electron-builder: specifier: 'catalog:' - version: 26.3.1(electron-builder-squirrel-windows@26.4.0) + version: 26.8.1(electron-builder-squirrel-windows@26.4.0) electron-devtools-installer: specifier: 'catalog:' version: 4.0.0 electron-updater: - specifier: 6.7.3 - version: 6.7.3 + specifier: 'catalog:' + version: 6.8.3 electron-vite: specifier: 'catalog:' - version: 5.0.0(@swc/core@1.15.8(@swc/helpers@0.5.18))(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 5.0.0(@swc/core@1.15.8(@swc/helpers@0.5.19))(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) eslint: specifier: 'catalog:' version: 9.39.2(jiti@2.6.1) react: specifier: 'catalog:' - version: 19.2.3 + version: 19.2.4 react-dom: specifier: 'catalog:' - version: 19.2.3(react@19.2.3) + version: 19.2.4(react@19.2.4) react-markdown: specifier: 'catalog:' - version: 10.1.0(@types/react@19.2.7)(react@19.2.3) + version: 10.1.0(@types/react@19.2.14)(react@19.2.4) tailwindcss: specifier: 'catalog:' - version: 4.1.18 + version: 4.2.1 typescript: specifier: 'catalog:' version: 5.9.3 undici: specifier: 'catalog:' - version: 7.18.2 + version: 7.22.0 vite: specifier: 'catalog:' - version: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) vite-tsconfig-paths: specifier: 'catalog:' - version: 6.0.3(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 6.1.1(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) yaml: specifier: 'catalog:' version: 2.8.2 @@ -592,35 +599,35 @@ importers: dependencies: '@bufbuild/protobuf': specifier: 'catalog:' - version: 2.10.2 + version: 2.11.0 '@connectrpc/connect': specifier: 'catalog:' - version: 2.1.1(@bufbuild/protobuf@2.10.2) + version: 2.1.1(@bufbuild/protobuf@2.11.0) '@connectrpc/connect-node': specifier: 'catalog:' - version: 2.1.1(@bufbuild/protobuf@2.10.2)(@connectrpc/connect@2.1.1(@bufbuild/protobuf@2.10.2)) + version: 2.1.1(@bufbuild/protobuf@2.11.0)(@connectrpc/connect@2.1.1(@bufbuild/protobuf@2.11.0)) '@effect/platform': specifier: 'catalog:' - version: 0.94.1(effect@3.19.14) + version: 0.94.5(effect@3.19.19) '@effect/platform-node': specifier: 'catalog:' - version: 0.104.0(@effect/cluster@0.56.1(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/workflow@0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14) + version: 0.104.1(@effect/cluster@0.56.1(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/workflow@0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19) '@the-dev-tools/spec': specifier: workspace:^ version: link:../spec better-auth: specifier: 'catalog:' - version: 1.4.18(@prisma/client@5.22.0)(better-sqlite3@12.6.2)(drizzle-orm@0.41.0(@libsql/client@0.14.0)(@prisma/client@5.22.0)(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(pg@8.18.0))(pg@8.18.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)(vitest@4.0.18(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 1.5.4(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(better-sqlite3@12.6.2)(drizzle-orm@0.41.0(@electric-sql/pglite@0.3.15)(@libsql/client@0.14.0)(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(@types/pg@8.18.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.1.0(socks@2.8.7))(mysql2@3.15.3)(pg@8.20.0)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.10)(vitest@4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) effect: specifier: 'catalog:' - version: 3.19.14 + version: 3.19.19 id128: specifier: 'catalog:' version: 1.6.6 devDependencies: '@better-auth/cli': specifier: 'catalog:' - version: 1.4.18(@better-fetch/fetch@1.1.21)(@libsql/client@0.14.0)(better-call@1.1.8(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)(vitest@4.0.18(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 1.4.21(@better-fetch/fetch@1.1.21)(@electric-sql/pglite@0.3.15)(@libsql/client@0.14.0)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(mongodb@7.1.0(socks@2.8.7))(mysql2@3.15.3)(nanostores@1.1.1)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.10)(vitest@4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) '@the-dev-tools/eslint-config': specifier: workspace:^ version: link:../../tools/eslint @@ -629,7 +636,7 @@ importers: version: link:../server '@types/node': specifier: 'catalog:' - version: 25.0.3 + version: 25.3.5 eslint: specifier: 'catalog:' version: 9.39.2(jiti@2.6.1) @@ -638,16 +645,16 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.0.18(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) packages/client: dependencies: '@bufbuild/protobuf': specifier: 'catalog:' - version: 2.10.2 + version: 2.11.0 '@bufbuild/protovalidate': specifier: 'catalog:' - version: 1.1.0(@bufbuild/protobuf@2.10.2) + version: 1.1.1(@bufbuild/protobuf@2.11.0) '@codemirror/autocomplete': specifier: 6.20.0 version: 6.20.0 @@ -659,7 +666,7 @@ importers: version: 6.4.11 '@codemirror/lang-javascript': specifier: 'catalog:' - version: 6.2.4 + version: 6.2.5 '@codemirror/lang-json': specifier: 'catalog:' version: 6.0.2 @@ -677,55 +684,55 @@ importers: version: 6.39.9 '@connectrpc/connect': specifier: 'catalog:' - version: 2.1.1(@bufbuild/protobuf@2.10.2) + version: 2.1.1(@bufbuild/protobuf@2.11.0) '@connectrpc/connect-query': specifier: 'catalog:' - version: 2.2.0(@bufbuild/protobuf@2.10.2)(@connectrpc/connect@2.1.1(@bufbuild/protobuf@2.10.2))(@tanstack/query-core@5.90.16)(@tanstack/react-query@5.90.16(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 2.2.0(@bufbuild/protobuf@2.11.0)(@connectrpc/connect@2.1.1(@bufbuild/protobuf@2.11.0))(@tanstack/query-core@5.90.20)(@tanstack/react-query@5.90.21(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@connectrpc/connect-web': specifier: 'catalog:' - version: 2.1.1(@bufbuild/protobuf@2.10.2)(@connectrpc/connect@2.1.1(@bufbuild/protobuf@2.10.2)) + version: 2.1.1(@bufbuild/protobuf@2.11.0)(@connectrpc/connect@2.1.1(@bufbuild/protobuf@2.11.0)) '@effect-atom/atom-react': specifier: 'catalog:' - version: 0.4.4(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14)(react@19.2.3)(scheduler@0.27.0) + version: 0.5.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19)(react@19.2.4)(scheduler@0.27.0) '@effect/platform': specifier: 'catalog:' - version: 0.94.1(effect@3.19.14) + version: 0.94.5(effect@3.19.19) '@effect/platform-browser': specifier: 'catalog:' - version: 0.74.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14) + version: 0.74.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19) '@faker-js/faker': specifier: 'catalog:' - version: 10.2.0 + version: 10.3.0 '@hookform/resolvers': specifier: 'catalog:' - version: 5.2.2(react-hook-form@7.70.0(react@19.2.3)) + version: 5.2.2(react-hook-form@7.70.0(react@19.2.4)) '@lezer/highlight': specifier: 'catalog:' version: 1.2.3 '@lezer/lr': specifier: 'catalog:' - version: 1.4.7 + version: 1.4.8 '@prettier/plugin-xml': specifier: 'catalog:' - version: 3.4.2(prettier@3.7.4) + version: 3.4.2(prettier@3.8.1) '@react-aria/collections': specifier: 'catalog:' - version: 3.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 3.0.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@standard-schema/spec': specifier: 'catalog:' version: 1.1.0 '@tanstack/react-db': specifier: 'catalog:' - version: 0.1.60(react@19.2.3)(typescript@5.9.3) + version: 0.1.74(react@19.2.4)(typescript@5.9.3) '@tanstack/react-query': specifier: 'catalog:' - version: 5.90.16(react@19.2.3) + version: 5.90.21(react@19.2.4) '@tanstack/react-router': specifier: 'catalog:' - version: 1.145.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 1.166.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/virtual-file-routes': specifier: 'catalog:' - version: 1.145.4 + version: 1.161.4 '@the-dev-tools/spec': specifier: workspace:^ version: link:../spec @@ -737,89 +744,89 @@ importers: version: link:../ui '@uiw/react-codemirror': specifier: 'catalog:' - version: 4.25.4(@babel/runtime@7.28.4)(@codemirror/autocomplete@6.20.0)(@codemirror/language@6.12.1)(@codemirror/lint@6.9.2)(@codemirror/search@6.5.11)(@codemirror/state@6.5.3)(@codemirror/theme-one-dark@6.1.3)(@codemirror/view@6.39.9)(codemirror@6.0.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 4.25.7(@babel/runtime@7.28.6)(@codemirror/autocomplete@6.20.0)(@codemirror/language@6.12.1)(@codemirror/lint@6.9.5)(@codemirror/search@6.5.11)(@codemirror/state@6.5.3)(@codemirror/theme-one-dark@6.1.3)(@codemirror/view@6.39.9)(codemirror@6.0.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@xyflow/react': specifier: 'catalog:' - version: 12.10.1(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 12.10.1(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) effect: specifier: 'catalog:' - version: 3.19.14 + version: 3.19.19 id128: specifier: 'catalog:' version: 1.6.6 openai: specifier: 'catalog:' - version: 4.77.0(encoding@0.1.13)(zod@3.25.76) + version: 6.27.0(ws@8.19.0)(zod@4.3.6) prettier: specifier: 'catalog:' - version: 3.7.4 + version: 3.8.1 react: specifier: 'catalog:' - version: 19.2.3 + version: 19.2.4 react-aria: specifier: 'catalog:' - version: 3.45.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 3.47.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react-aria-components: specifier: 'catalog:' - version: 1.14.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 1.16.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react-dom: specifier: 'catalog:' - version: 19.2.3(react@19.2.3) + version: 19.2.4(react@19.2.4) react-error-boundary: specifier: 'catalog:' - version: 6.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 6.1.1(react@19.2.4) react-icons: specifier: 'catalog:' - version: 5.5.0(react@19.2.3) + version: 5.6.0(react@19.2.4) react-markdown: specifier: 'catalog:' - version: 10.1.0(@types/react@19.2.7)(react@19.2.3) + version: 10.1.0(@types/react@19.2.14)(react@19.2.4) react-resizable-panels: specifier: 'catalog:' - version: 4.3.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 4.7.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react-scan: specifier: 'catalog:' - version: 0.4.3(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rollup@4.55.1) + version: 0.5.3(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0) react-stately: specifier: 'catalog:' - version: 3.43.0(react@19.2.3) + version: 3.45.0(react@19.2.4) react-timeago: specifier: 'catalog:' - version: 8.3.0(react@19.2.3) + version: 8.3.0(react@19.2.4) remark-gfm: specifier: 'catalog:' version: 4.0.1 tailwind-merge: specifier: 'catalog:' - version: 3.4.0 + version: 3.5.0 tailwind-variants: specifier: 'catalog:' - version: 3.2.2(tailwind-merge@3.4.0)(tailwindcss@4.1.18) + version: 3.2.2(tailwind-merge@3.5.0)(tailwindcss@4.2.1) use-debounce: specifier: 'catalog:' - version: 10.0.6(react@19.2.3) + version: 10.1.0(react@19.2.4) devDependencies: '@hookform/devtools': specifier: 'catalog:' - version: 4.4.0(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 4.4.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@lezer/generator': specifier: 'catalog:' version: 1.8.0 '@storybook/react-vite': specifier: 'catalog:' - version: 10.1.11(esbuild@0.27.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rollup@4.55.1)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2)) + version: 10.2.16(esbuild@0.27.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))(esbuild@0.27.3)) '@tailwindcss/vite': specifier: 'catalog:' - version: 4.1.18(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.2.1(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) '@tanstack/react-query-devtools': specifier: 'catalog:' - version: 5.91.2(@tanstack/react-query@5.90.16(react@19.2.3))(react@19.2.3) + version: 5.91.3(@tanstack/react-query@5.90.21(react@19.2.4))(react@19.2.4) '@tanstack/react-router-devtools': specifier: 'catalog:' - version: 1.145.7(@tanstack/react-router@1.145.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.145.7)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10) + version: 1.166.2(@tanstack/react-router@1.166.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.166.2)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/router-plugin': specifier: 'catalog:' - version: 1.145.10(@tanstack/react-router@1.145.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2)) + version: 1.166.2(@tanstack/react-router@1.166.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))(esbuild@0.27.3)) '@the-dev-tools/auth': specifier: workspace:^ version: link:../auth @@ -828,40 +835,40 @@ importers: version: link:../../tools/eslint '@types/react': specifier: 'catalog:' - version: 19.2.7 + version: 19.2.14 '@types/react-dom': specifier: 'catalog:' - version: 19.2.3(@types/react@19.2.7) + version: 19.2.3(@types/react@19.2.14) '@types/react-timeago': specifier: 'catalog:' - version: 8.0.0(react@19.2.3) + version: 8.0.0(react@19.2.4) '@vitejs/plugin-react': specifier: 'catalog:' - version: 5.1.2(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 5.1.4(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) babel-plugin-react-compiler: specifier: 'catalog:' version: 19.1.0-rc.3 electron: specifier: 'catalog:' - version: 39.2.7 + version: 40.8.0 eslint: specifier: 'catalog:' version: 9.39.2(jiti@2.6.1) globals: specifier: 'catalog:' - version: 17.0.0 + version: 17.4.0 storybook: specifier: 'catalog:' - version: 10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) typescript: specifier: 'catalog:' version: 5.9.3 vite: specifier: 'catalog:' - version: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) vite-tsconfig-paths: specifier: 'catalog:' - version: 6.0.3(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 6.1.1(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) packages/server: dependencies: @@ -876,28 +883,28 @@ importers: version: link:../../tools/spec-lib effect: specifier: 'catalog:' - version: 3.19.14 + version: 3.19.19 devDependencies: '@bufbuild/buf': specifier: 'catalog:' - version: 1.63.0 + version: 1.66.0 '@bufbuild/protobuf': specifier: 'catalog:' - version: 2.10.2 + version: 2.11.0 '@bufbuild/protoc-gen-es': specifier: 'catalog:' - version: 2.10.2(@bufbuild/protobuf@2.10.2) + version: 2.11.0(@bufbuild/protobuf@2.11.0) '@the-dev-tools/eslint-config': specifier: workspace:^ version: link:../../tools/eslint '@types/node': specifier: 'catalog:' - version: 25.0.3 + version: 25.3.5 prettier: specifier: 'catalog:' - version: 3.7.4 + version: 3.8.1 tsx: - specifier: ^4.19.0 + specifier: 'catalog:' version: 4.21.0 typescript: specifier: 'catalog:' @@ -907,7 +914,7 @@ importers: dependencies: '@bufbuild/protobuf': specifier: 'catalog:' - version: 2.10.2 + version: 2.11.0 '@fontsource-variable/dm-sans': specifier: 'catalog:' version: 5.2.8 @@ -916,77 +923,77 @@ importers: version: 5.2.7 '@react-aria/collections': specifier: 'catalog:' - version: 3.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 3.0.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/react-router': specifier: 'catalog:' - version: 1.145.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 1.166.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) effect: specifier: 'catalog:' - version: 3.19.14 + version: 3.19.19 react: specifier: 'catalog:' - version: 19.2.3 + version: 19.2.4 react-aria: specifier: 'catalog:' - version: 3.45.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 3.47.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react-aria-components: specifier: 'catalog:' - version: 1.14.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 1.16.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react-dom: specifier: 'catalog:' - version: 19.2.3(react@19.2.3) + version: 19.2.4(react@19.2.4) react-icons: specifier: 'catalog:' - version: 5.5.0(react@19.2.3) + version: 5.6.0(react@19.2.4) react-resizable-panels: specifier: 'catalog:' - version: 4.3.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 4.7.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) tailwind-merge: specifier: 'catalog:' - version: 3.4.0 + version: 3.5.0 tailwind-variants: specifier: 'catalog:' - version: 3.2.2(tailwind-merge@3.4.0)(tailwindcss@4.1.18) + version: 3.2.2(tailwind-merge@3.5.0)(tailwindcss@4.2.1) devDependencies: '@storybook/addon-docs': specifier: 'catalog:' - version: 10.1.11(@types/react@19.2.7)(esbuild@0.27.2)(rollup@4.55.1)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2)) + version: 10.2.16(@types/react@19.2.14)(esbuild@0.27.3)(rollup@4.59.0)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))(esbuild@0.27.3)) '@storybook/react': specifier: 'catalog:' - version: 10.1.11(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3) + version: 10.2.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) '@storybook/react-vite': specifier: 'catalog:' - version: 10.1.11(esbuild@0.27.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rollup@4.55.1)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2)) + version: 10.2.16(esbuild@0.27.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))(esbuild@0.27.3)) '@tailwindcss/vite': specifier: 'catalog:' - version: 4.1.18(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.2.1(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) '@the-dev-tools/eslint-config': specifier: workspace:^ version: link:../../tools/eslint '@types/node': specifier: 'catalog:' - version: 25.0.3 + version: 25.3.5 '@types/react': specifier: 'catalog:' - version: 19.2.7 + version: 19.2.14 '@types/react-dom': specifier: 'catalog:' - version: 19.2.3(@types/react@19.2.7) + version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: 'catalog:' - version: 5.1.2(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 5.1.4(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) babel-plugin-react-compiler: specifier: 'catalog:' version: 19.1.0-rc.3 storybook: specifier: 'catalog:' - version: 10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) tailwindcss: specifier: 'catalog:' - version: 4.1.18 + version: 4.2.1 tailwindcss-react-aria-components: specifier: 'catalog:' - version: 2.0.1(tailwindcss@4.1.18) + version: 2.0.1(tailwindcss@4.2.1) tw-animate-css: specifier: 'catalog:' version: 1.4.0 @@ -995,22 +1002,22 @@ importers: version: 5.9.3 vite: specifier: 'catalog:' - version: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) packages/worker-js: devDependencies: '@bufbuild/protobuf': specifier: 'catalog:' - version: 2.10.2 + version: 2.11.0 '@connectrpc/connect': specifier: 'catalog:' - version: 2.1.1(@bufbuild/protobuf@2.10.2) + version: 2.1.1(@bufbuild/protobuf@2.11.0) '@effect/platform': specifier: 'catalog:' - version: 0.94.1(effect@3.19.14) + version: 0.94.5(effect@3.19.19) '@effect/platform-node': specifier: 'catalog:' - version: 0.104.0(@effect/cluster@0.56.1(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/workflow@0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14) + version: 0.104.1(@effect/cluster@0.56.1(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/workflow@0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19) '@the-dev-tools/eslint-config': specifier: workspace:^ version: link:../../tools/eslint @@ -1019,16 +1026,16 @@ importers: version: link:../spec '@types/node': specifier: 'catalog:' - version: 25.0.3 + version: 25.3.5 effect: specifier: 'catalog:' - version: 3.19.14 + version: 3.19.19 eslint: specifier: 'catalog:' version: 9.39.2(jiti@2.6.1) tsup: specifier: 'catalog:' - version: 8.5.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) + version: 8.5.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) typescript: specifier: 'catalog:' version: 5.9.3 @@ -1037,25 +1044,25 @@ importers: devDependencies: '@eslint/compat': specifier: 'catalog:' - version: 2.0.0(eslint@9.39.2(jiti@2.6.1)) + version: 2.0.2(eslint@9.39.2(jiti@2.6.1)) '@eslint/js': specifier: 'catalog:' version: 9.39.2 '@tanstack/eslint-plugin-router': specifier: 'catalog:' - version: 1.141.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + version: 1.161.4(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@types/eslint-plugin-jsx-a11y': specifier: 'catalog:' version: 6.10.1(jiti@2.6.1) '@types/node': specifier: 'catalog:' - version: 25.0.3 + version: 25.3.5 '@typescript-eslint/parser': specifier: 'catalog:' - version: 8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + version: 8.56.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) effect: specifier: 'catalog:' - version: 3.19.14 + version: 3.19.19 eslint: specifier: 'catalog:' version: 9.39.2(jiti@2.6.1) @@ -1064,19 +1071,19 @@ importers: version: 10.1.8(eslint@9.39.2(jiti@2.6.1)) eslint-import-resolver-typescript: specifier: 'catalog:' - version: 4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)) + version: 4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.56.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-better-tailwindcss: specifier: 'catalog:' - version: 3.8.0(eslint@9.39.2(jiti@2.6.1))(tailwindcss@4.1.18) + version: 4.3.2(eslint@9.39.2(jiti@2.6.1))(tailwindcss@4.2.1)(typescript@5.9.3) eslint-plugin-import-x: specifier: 'catalog:' - version: 4.16.1(@typescript-eslint/utils@8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)) + version: 4.16.1(@typescript-eslint/utils@8.56.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-jsx-a11y: specifier: 'catalog:' version: 6.10.2(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-perfectionist: specifier: 'catalog:' - version: 5.3.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + version: 5.6.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint-plugin-react: specifier: 'catalog:' version: 7.37.5(eslint@9.39.2(jiti@2.6.1)) @@ -1085,25 +1092,25 @@ importers: version: 7.0.1(eslint@9.39.2(jiti@2.6.1)) globals: specifier: 'catalog:' - version: 17.0.0 + version: 17.4.0 typescript: specifier: 'catalog:' version: 5.9.3 typescript-eslint: specifier: 'catalog:' - version: 8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + version: 8.56.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) tools/gha-scripts: devDependencies: '@effect/cli': specifier: 'catalog:' - version: 0.73.0(@effect/platform@0.94.1(effect@3.19.14))(@effect/printer-ansi@0.47.0(@effect/typeclass@0.38.0(effect@3.19.14))(effect@3.19.14))(@effect/printer@0.47.0(@effect/typeclass@0.38.0(effect@3.19.14))(effect@3.19.14))(effect@3.19.14) + version: 0.73.2(@effect/platform@0.94.5(effect@3.19.19))(@effect/printer-ansi@0.47.0(@effect/typeclass@0.38.0(effect@3.19.19))(effect@3.19.19))(@effect/printer@0.47.0(@effect/typeclass@0.38.0(effect@3.19.19))(effect@3.19.19))(effect@3.19.19) '@effect/platform': specifier: 'catalog:' - version: 0.94.1(effect@3.19.14) + version: 0.94.5(effect@3.19.19) '@effect/platform-node': specifier: 'catalog:' - version: 0.104.0(@effect/cluster@0.56.1(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/workflow@0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14) + version: 0.104.1(@effect/cluster@0.56.1(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/workflow@0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19) '@octokit/auth-action': specifier: 'catalog:' version: 6.0.2 @@ -1115,13 +1122,13 @@ importers: version: link:../eslint '@types/node': specifier: 'catalog:' - version: 25.0.3 + version: 25.3.5 effect: specifier: 'catalog:' - version: 3.19.14 + version: 3.19.19 nx: specifier: 'catalog:' - version: 22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)) + version: 22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)) typescript: specifier: 'catalog:' version: 5.9.3 @@ -1130,7 +1137,7 @@ importers: dependencies: effect: specifier: 'catalog:' - version: 3.19.14 + version: 3.19.19 devDependencies: '@alloy-js/cli': specifier: 'catalog:' @@ -1143,19 +1150,19 @@ importers: version: 0.22.0 '@bufbuild/protobuf': specifier: 'catalog:' - version: 2.10.2 + version: 2.11.0 '@the-dev-tools/eslint-config': specifier: workspace:^ version: link:../eslint '@types/node': specifier: 'catalog:' - version: 25.0.3 + version: 25.3.5 '@typespec/emitter-framework': specifier: 'catalog:' - version: 0.14.0(@alloy-js/core@0.22.0)(@alloy-js/csharp@0.21.0)(@alloy-js/typescript@0.22.0)(@typespec/compiler@1.7.1(@types/node@25.0.3)) + version: 0.16.0(@alloy-js/core@0.22.0)(@alloy-js/csharp@0.21.0)(@alloy-js/python@0.3.0)(@alloy-js/typescript@0.22.0)(@typespec/compiler@1.9.0(@types/node@25.3.5)) prettier: specifier: 'catalog:' - version: 3.7.4 + version: 3.8.1 typescript: specifier: 'catalog:' version: 5.9.3 @@ -1164,56 +1171,56 @@ importers: dependencies: effect: specifier: 'catalog:' - version: 3.19.14 + version: 3.19.19 react: specifier: 'catalog:' - version: 19.2.3 + version: 19.2.4 react-dom: specifier: 'catalog:' - version: 19.2.3(react@19.2.3) + version: 19.2.4(react@19.2.4) devDependencies: '@storybook/addon-docs': specifier: 'catalog:' - version: 10.1.11(@types/react@19.2.7)(esbuild@0.27.2)(rollup@4.55.1)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2)) + version: 10.2.16(@types/react@19.2.14)(esbuild@0.27.3)(rollup@4.59.0)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))(esbuild@0.27.3)) '@storybook/react': specifier: 'catalog:' - version: 10.1.11(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3) + version: 10.2.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) '@storybook/react-vite': specifier: 'catalog:' - version: 10.1.11(esbuild@0.27.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rollup@4.55.1)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2)) + version: 10.2.16(esbuild@0.27.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))(esbuild@0.27.3)) '@tailwindcss/vite': specifier: 'catalog:' - version: 4.1.18(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.2.1(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) '@the-dev-tools/eslint-config': specifier: workspace:^ version: link:../eslint '@types/node': specifier: 'catalog:' - version: 25.0.3 + version: 25.3.5 '@types/react': specifier: 'catalog:' - version: 19.2.7 + version: 19.2.14 '@types/react-dom': specifier: 'catalog:' - version: 19.2.3(@types/react@19.2.7) + version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: 'catalog:' - version: 5.1.2(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 5.1.4(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) babel-plugin-react-compiler: specifier: 'catalog:' version: 19.1.0-rc.3 storybook: specifier: 'catalog:' - version: 10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) tailwindcss: specifier: 'catalog:' - version: 4.1.18 + version: 4.2.1 typescript: specifier: 'catalog:' version: 5.9.3 vite: specifier: 'catalog:' - version: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) packages: @@ -1223,8 +1230,8 @@ packages: '@adobe/css-tools@4.4.4': resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} - '@aikidosec/safe-chain@1.4.0': - resolution: {integrity: sha512-me+R8atYLE8zWdgmR6QDAbnYvm/zYtXvgITWDC5Oxd4n/U/FTBkOVR5dLRchyybA8g+DphsZqs4SZzn09+ff+g==} + '@aikidosec/safe-chain@1.4.4': + resolution: {integrity: sha512-yxsjN1fXQ3Iuk0J8DxpAR0D6dHuuqlf5XYUYlXbzrcZwKN6Lf1V6NyTUypct2sYNKIJRipiN/iTVIxb5y3dKlw==} hasBin: true '@alloy-js/babel-plugin-jsx-dom-expressions@0.39.1': @@ -1257,39 +1264,42 @@ packages: '@alloy-js/msbuild@0.21.0': resolution: {integrity: sha512-QmMwF7eoYMdR5mX+8cIKb5F3Mgi3uQlFYrGYq92ht6BOc/XKyBXIwCXq6zqPMAT7nd2BHDD2hvgbL6nLS4QcGg==} + '@alloy-js/python@0.3.0': + resolution: {integrity: sha512-VujQyh6aGC5oAXvmtKcDGYg3rRgU01IvN5uOu6u5m/kXR7rUTsndrv960r0bBniIL+EvRF3CMu7E6EEcbb3Pyg==} + '@alloy-js/typescript@0.22.0': resolution: {integrity: sha512-jARBNxAA5aEhysleFFd7cGfjckkEXLCH9kDaJSH5xBOu4cU0v7q5TvAqgPlEIkhfOh2983XLX0nVtZu01p0UjQ==} - '@babel/code-frame@7.27.1': - resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + '@babel/code-frame@7.28.6': + resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==} engines: {node: '>=6.9.0'} '@babel/code-frame@7.29.0': resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.28.5': - resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} engines: {node: '>=6.9.0'} - '@babel/core@7.28.5': - resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} engines: {node: '>=6.9.0'} - '@babel/generator@7.28.5': - resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} engines: {node: '>=6.9.0'} '@babel/helper-annotate-as-pure@7.27.3': resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.27.2': - resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} engines: {node: '>=6.9.0'} - '@babel/helper-create-class-features-plugin@7.28.5': - resolution: {integrity: sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==} + '@babel/helper-create-class-features-plugin@7.28.6': + resolution: {integrity: sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1300,8 +1310,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-define-polyfill-provider@0.6.5': - resolution: {integrity: sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==} + '@babel/helper-define-polyfill-provider@0.6.6': + resolution: {integrity: sha512-mOAsxeeKkUKayvZR3HeTYD/fICpCPLJrU5ZjelT/PA6WHtNDBOE436YiaEUvHN454bRM3CebhDsIpieCc4texA==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 @@ -1317,8 +1327,12 @@ packages: resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.28.3': - resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1327,8 +1341,8 @@ packages: resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} engines: {node: '>=6.9.0'} - '@babel/helper-plugin-utils@7.27.1': - resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} engines: {node: '>=6.9.0'} '@babel/helper-remap-async-to-generator@7.27.1': @@ -1337,8 +1351,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-replace-supers@7.27.1': - resolution: {integrity: sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==} + '@babel/helper-replace-supers@7.28.6': + resolution: {integrity: sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1359,16 +1373,16 @@ packages: resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - '@babel/helper-wrap-function@7.28.3': - resolution: {integrity: sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==} + '@babel/helper-wrap-function@7.28.6': + resolution: {integrity: sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.28.4': - resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} + '@babel/helpers@7.28.6': + resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} engines: {node: '>=6.9.0'} - '@babel/parser@7.28.5': - resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + '@babel/parser@7.29.0': + resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} engines: {node: '>=6.0.0'} hasBin: true @@ -1396,14 +1410,14 @@ packages: peerDependencies: '@babel/core': ^7.13.0 - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3': - resolution: {integrity: sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==} + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.6': + resolution: {integrity: sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-proposal-decorators@7.28.0': - resolution: {integrity: sha512-zOiZqvANjWDUaUS9xMxbMcK/Zccztbe/6ikvUXaG9nsPH3w6qh5UaPGAnirI/WhIbZ8m3OHU0ReyPrknG+ZKeg==} + '@babel/plugin-proposal-decorators@7.29.0': + resolution: {integrity: sha512-CVBVv3VY/XRMxRYq5dwr2DS7/MvqPm23cOCjbwNnVrfOqcWlnefua1uUs0sjdKOGjvPUG633o07uWzJq4oI6dA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1414,32 +1428,32 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-decorators@7.27.1': - resolution: {integrity: sha512-YMq8Z87Lhl8EGkmb0MwYkt36QnxC+fzCgrl66ereamPlYToRpIk5nUjKUY3QKLWq8mwUB1BgbeXcTJhZOCDg5A==} + '@babel/plugin-syntax-decorators@7.28.6': + resolution: {integrity: sha512-71EYI0ONURHJBL4rSFXnITXqXrrY8q4P0q006DPfN+Rk+ASM+++IBXem/ruokgBZR8YNEWZ8R6B+rCb8VcUTqA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-assertions@7.27.1': - resolution: {integrity: sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==} + '@babel/plugin-syntax-import-assertions@7.28.6': + resolution: {integrity: sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-attributes@7.27.1': - resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==} + '@babel/plugin-syntax-import-attributes@7.28.6': + resolution: {integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-jsx@7.27.1': - resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} + '@babel/plugin-syntax-jsx@7.28.6': + resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-typescript@7.27.1': - resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} + '@babel/plugin-syntax-typescript@7.28.6': + resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1456,14 +1470,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-async-generator-functions@7.28.0': - resolution: {integrity: sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==} + '@babel/plugin-transform-async-generator-functions@7.29.0': + resolution: {integrity: sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-async-to-generator@7.27.1': - resolution: {integrity: sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==} + '@babel/plugin-transform-async-to-generator@7.28.6': + resolution: {integrity: sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1474,32 +1488,32 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoping@7.28.5': - resolution: {integrity: sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==} + '@babel/plugin-transform-block-scoping@7.28.6': + resolution: {integrity: sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-class-properties@7.27.1': - resolution: {integrity: sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==} + '@babel/plugin-transform-class-properties@7.28.6': + resolution: {integrity: sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-class-static-block@7.28.3': - resolution: {integrity: sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==} + '@babel/plugin-transform-class-static-block@7.28.6': + resolution: {integrity: sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.12.0 - '@babel/plugin-transform-classes@7.28.4': - resolution: {integrity: sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==} + '@babel/plugin-transform-classes@7.28.6': + resolution: {integrity: sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-computed-properties@7.27.1': - resolution: {integrity: sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==} + '@babel/plugin-transform-computed-properties@7.28.6': + resolution: {integrity: sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1510,8 +1524,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-dotall-regex@7.27.1': - resolution: {integrity: sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==} + '@babel/plugin-transform-dotall-regex@7.28.6': + resolution: {integrity: sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1522,8 +1536,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1': - resolution: {integrity: sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==} + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.0': + resolution: {integrity: sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1534,14 +1548,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-explicit-resource-management@7.28.0': - resolution: {integrity: sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==} + '@babel/plugin-transform-explicit-resource-management@7.28.6': + resolution: {integrity: sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-exponentiation-operator@7.28.5': - resolution: {integrity: sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==} + '@babel/plugin-transform-exponentiation-operator@7.28.6': + resolution: {integrity: sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1564,8 +1578,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-json-strings@7.27.1': - resolution: {integrity: sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==} + '@babel/plugin-transform-json-strings@7.28.6': + resolution: {integrity: sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1576,8 +1590,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-logical-assignment-operators@7.28.5': - resolution: {integrity: sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==} + '@babel/plugin-transform-logical-assignment-operators@7.28.6': + resolution: {integrity: sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1594,14 +1608,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-commonjs@7.27.1': - resolution: {integrity: sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==} + '@babel/plugin-transform-modules-commonjs@7.28.6': + resolution: {integrity: sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-systemjs@7.28.5': - resolution: {integrity: sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==} + '@babel/plugin-transform-modules-systemjs@7.29.0': + resolution: {integrity: sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1612,8 +1626,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-named-capturing-groups-regex@7.27.1': - resolution: {integrity: sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==} + '@babel/plugin-transform-named-capturing-groups-regex@7.29.0': + resolution: {integrity: sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1624,20 +1638,20 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-nullish-coalescing-operator@7.27.1': - resolution: {integrity: sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==} + '@babel/plugin-transform-nullish-coalescing-operator@7.28.6': + resolution: {integrity: sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-numeric-separator@7.27.1': - resolution: {integrity: sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==} + '@babel/plugin-transform-numeric-separator@7.28.6': + resolution: {integrity: sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-object-rest-spread@7.28.4': - resolution: {integrity: sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==} + '@babel/plugin-transform-object-rest-spread@7.28.6': + resolution: {integrity: sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1648,14 +1662,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-optional-catch-binding@7.27.1': - resolution: {integrity: sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==} + '@babel/plugin-transform-optional-catch-binding@7.28.6': + resolution: {integrity: sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-optional-chaining@7.28.5': - resolution: {integrity: sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==} + '@babel/plugin-transform-optional-chaining@7.28.6': + resolution: {integrity: sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1666,14 +1680,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-private-methods@7.27.1': - resolution: {integrity: sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==} + '@babel/plugin-transform-private-methods@7.28.6': + resolution: {integrity: sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-private-property-in-object@7.27.1': - resolution: {integrity: sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==} + '@babel/plugin-transform-private-property-in-object@7.28.6': + resolution: {integrity: sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1714,8 +1728,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx@7.27.1': - resolution: {integrity: sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==} + '@babel/plugin-transform-react-jsx@7.28.6': + resolution: {integrity: sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1726,14 +1740,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-regenerator@7.28.4': - resolution: {integrity: sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==} + '@babel/plugin-transform-regenerator@7.29.0': + resolution: {integrity: sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-regexp-modifiers@7.27.1': - resolution: {integrity: sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==} + '@babel/plugin-transform-regexp-modifiers@7.28.6': + resolution: {integrity: sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1744,8 +1758,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-runtime@7.28.5': - resolution: {integrity: sha512-20NUVgOrinudkIBzQ2bNxP08YpKprUkRTiRSd2/Z5GOdPImJGkoN4Z7IQe1T5AdyKI1i5L6RBmluqdSzvaq9/w==} + '@babel/plugin-transform-runtime@7.29.0': + resolution: {integrity: sha512-jlaRT5dJtMaMCV6fAuLbsQMSwz/QkvaHOHOSXRitGGwSpR1blCY4KUKoyP2tYO8vJcqYe8cEj96cqSztv3uF9w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1756,8 +1770,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-spread@7.27.1': - resolution: {integrity: sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==} + '@babel/plugin-transform-spread@7.28.6': + resolution: {integrity: sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1780,8 +1794,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-typescript@7.28.5': - resolution: {integrity: sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA==} + '@babel/plugin-transform-typescript@7.28.6': + resolution: {integrity: sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1792,8 +1806,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-property-regex@7.27.1': - resolution: {integrity: sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==} + '@babel/plugin-transform-unicode-property-regex@7.28.6': + resolution: {integrity: sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1804,14 +1818,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-sets-regex@7.27.1': - resolution: {integrity: sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==} + '@babel/plugin-transform-unicode-sets-regex@7.28.6': + resolution: {integrity: sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/preset-env@7.28.5': - resolution: {integrity: sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==} + '@babel/preset-env@7.29.0': + resolution: {integrity: sha512-fNEdfc0yi16lt6IZo2Qxk3knHVdfMYX33czNb4v8yWhemoBhibCpQK/uYHtSKIiO+p/zd3+8fYVXhQdOVV608w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1833,28 +1847,28 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/runtime@7.28.4': - resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + '@babel/runtime@7.28.6': + resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} engines: {node: '>=6.9.0'} - '@babel/template@7.27.2': - resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.28.5': - resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} engines: {node: '>=6.9.0'} - '@babel/types@7.28.5': - resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} - '@better-auth/cli@1.4.18': - resolution: {integrity: sha512-T7koP/fNpP0+hZ3INNj+A2bx2B/6783XPE8xKjldndmdhG3orJZFkzKWzlXPJYh1jX56tFOfcvDMNErzE40LjQ==} + '@better-auth/cli@1.4.21': + resolution: {integrity: sha512-bKEa8BupnZxNjLk9ZDntvgQGm5jogeE2wHdMbYifhet3GTyxgDi6pXoOK8+aqHYQGg1C3OALi9hVVWnrv7JJWQ==} hasBin: true - '@better-auth/core@1.4.18': - resolution: {integrity: sha512-q+awYgC7nkLEBdx2sW0iJjkzgSHlIxGnOpsN1r/O1+a4m7osJNHtfK2mKJSL1I+GfNyIlxJF8WvD/NLuYMpmcg==} + '@better-auth/core@1.4.21': + resolution: {integrity: sha512-R4s7pwShkqB21fZ599QASbXxqFcoxanLyz7DHSX6SJPNYV748wBLsm3xM9VrjfvWMpS+cQUErOCt9yWT1hMn6w==} peerDependencies: '@better-auth/utils': 0.3.0 '@better-fetch/fetch': 1.1.21 @@ -1863,92 +1877,149 @@ packages: kysely: ^0.28.5 nanostores: ^1.0.1 - '@better-auth/telemetry@1.4.18': - resolution: {integrity: sha512-e5rDF8S4j3Um/0LIVATL2in9dL4lfO2fr2v1Wio4qTMRbfxqnUDTa+6SZtwdeJrbc4O+a3c+IyIpjG9Q/6GpfQ==} + '@better-auth/core@1.5.4': + resolution: {integrity: sha512-k5AdwPRQETZn0vdB60EB9CDxxfllpJXKqVxTjyXIUSRz7delNGlU0cR/iRP3VfVJwvYR1NbekphBDNo+KGoEzQ==} + peerDependencies: + '@better-auth/utils': 0.3.1 + '@better-fetch/fetch': 1.1.21 + '@cloudflare/workers-types': '>=4' + better-call: 1.3.2 + jose: ^6.1.0 + kysely: ^0.28.5 + nanostores: ^1.0.1 + peerDependenciesMeta: + '@cloudflare/workers-types': + optional: true + + '@better-auth/drizzle-adapter@1.5.4': + resolution: {integrity: sha512-4M4nMAWrDd3TmpV6dONkJjybBVKRZghe5Oj0NNyDEoXubxastQdO7Sb5B54I1rTx5yoMgsqaB+kbJnu/9UgjQg==} peerDependencies: - '@better-auth/core': 1.4.18 + '@better-auth/core': 1.5.4 + '@better-auth/utils': ^0.3.0 + drizzle-orm: '>=0.41.0' + + '@better-auth/kysely-adapter@1.5.4': + resolution: {integrity: sha512-DPww7rIfz6Ed7dZlJSW9xMQ42VKaJLB5Cs+pPqd+UHKRyighKjf3VgvMIcAdFPc4olQ0qRHo3+ZJhFlBCxRhxA==} + peerDependencies: + '@better-auth/core': 1.5.4 + '@better-auth/utils': ^0.3.0 + kysely: ^0.27.0 || ^0.28.0 + + '@better-auth/memory-adapter@1.5.4': + resolution: {integrity: sha512-iiWYut9rbQqiAsgRBtj6+nxanwjapxRgpIJbiS2o81h7b9iclE0AiDA0Foes590gdFQvskNauZcCpuF8ytxthg==} + peerDependencies: + '@better-auth/core': 1.5.4 + '@better-auth/utils': ^0.3.0 + + '@better-auth/mongo-adapter@1.5.4': + resolution: {integrity: sha512-ArzJN5Obk6i6+vLK1HpPzLIcsjxZYXPPUvxVU8eyU5HyoUT2MlswWfPQ8UJAKPn0iq/T4PVp/wZcQMhWk1tuNA==} + peerDependencies: + '@better-auth/core': 1.5.4 + '@better-auth/utils': ^0.3.0 + mongodb: ^6.0.0 || ^7.0.0 + + '@better-auth/prisma-adapter@1.5.4': + resolution: {integrity: sha512-ZQTbcBopw/ezjjbNFsfR3CRp0QciC4tJCarAnB5G9fZtUYbDjfY0vZOxIRmU4kI3x755CXQpGqTrkwmXaMRa3w==} + peerDependencies: + '@better-auth/core': 1.5.4 + '@better-auth/utils': ^0.3.0 + '@prisma/client': ^5.0.0 || ^6.0.0 || ^7.0.0 + prisma: ^5.0.0 || ^6.0.0 || ^7.0.0 + + '@better-auth/telemetry@1.4.21': + resolution: {integrity: sha512-LX+FGMZnhR2KQZ0idHH1+UwlXvkOl6P8w3Gne4TtjvUCt3QjG9FKIuP9JD3MAmEEkwGt0SoAPHPJEGTjUl3ydg==} + peerDependencies: + '@better-auth/core': 1.4.21 + + '@better-auth/telemetry@1.5.4': + resolution: {integrity: sha512-mGXTY7Ecxo7uvlMr6TFCBUvlH0NUMOeE9LKgPhG4HyhBN6VfCEg/DD9PG0Z2IatmMWQbckkt7ox5A0eBpG9m5w==} + peerDependencies: + '@better-auth/core': 1.5.4 '@better-auth/utils@0.3.0': resolution: {integrity: sha512-W+Adw6ZA6mgvnSnhOki270rwJ42t4XzSK6YWGF//BbVXL6SwCLWfyzBc1lN2m/4RM28KubdBKQ4X5VMoLRNPQw==} + '@better-auth/utils@0.3.1': + resolution: {integrity: sha512-+CGp4UmZSUrHHnpHhLPYu6cV+wSUSvVbZbNykxhUDocpVNTo9uFFxw/NqJlh1iC4wQ9HKKWGCKuZ5wUgS0v6Kg==} + '@better-fetch/fetch@1.1.21': resolution: {integrity: sha512-/ImESw0sskqlVR94jB+5+Pxjf+xBwDZF/N5+y2/q4EqD7IARUTSpPfIo8uf39SYpCxyOCtbyYpUrZ3F/k0zT4A==} - '@bufbuild/buf-darwin-arm64@1.63.0': - resolution: {integrity: sha512-Jpbz2mnNO+23E3TmDgLdbYuF+ozqsKu/ASvD37RjDgp9HtqQT+ciJMYOzqd/HdrGiM9tWYN1vhjl/gP/Y23lIw==} + '@bufbuild/buf-darwin-arm64@1.66.0': + resolution: {integrity: sha512-C9orXX4SSVYKEumWFEO2T6xKrXsrvij0uS8kR20sHt9MYuFke14y6DfnAvXINPZrNpDiyOTldG7BPQtR40poRw==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] - '@bufbuild/buf-darwin-x64@1.63.0': - resolution: {integrity: sha512-HkVMm2cOBnTtT+AZFAQAUyrwcXtnvaBtVCW0ltBi5PzLp6CNgmkH97OAROKWiNPWrXJh5thdhdZBNjGPyTfX3w==} + '@bufbuild/buf-darwin-x64@1.66.0': + resolution: {integrity: sha512-5I33S9UbimoBNCpOdMsmJHcW9NfxzKW5PsVrSyajpo+LL22Lfyha2ZO3JNhT/k3ZlGVvtpDAS9pRS0ouNKmGgA==} engines: {node: '>=12'} cpu: [x64] os: [darwin] - '@bufbuild/buf-linux-aarch64@1.63.0': - resolution: {integrity: sha512-vFeFKzC+PZSngct0bP3ASGCus7qhBPFxSfz6Hi+3a2zAajn857iJC3iPiX0tRlRIUTOHuj5NmOYxg9dhev0vDw==} + '@bufbuild/buf-linux-aarch64@1.66.0': + resolution: {integrity: sha512-KFz9HukP3ACKfSe0fo+XbxndQR0kKCVLVfUkoc6qPUTrKn9lACnah6HlUtBlwanK95vg+MIMvy0DWoLYUX9cuA==} engines: {node: '>=12'} cpu: [arm64] os: [linux] - '@bufbuild/buf-linux-armv7@1.63.0': - resolution: {integrity: sha512-XbrRiOfeY3d/GmR+WNnkcDo480V+cz/ecfj/Ay/JO/ZLe7quEQqHmJ6dMcIQN8QNFPZBKv0IVyhhljh8+0/gkA==} + '@bufbuild/buf-linux-armv7@1.66.0': + resolution: {integrity: sha512-W56iEZtnqB4ww9JCyhIipPrwZVe/zQ5I0pmWrJF8Daw67qvRYtvP3NSxtF5f0yAoB0tQAXDoqIiB/Ypl1UOz0g==} engines: {node: '>=12'} cpu: [arm] os: [linux] - '@bufbuild/buf-linux-x64@1.63.0': - resolution: {integrity: sha512-78TsMWxQ7Rn4FJPN4QZZDM3NTS1U5ZCcwLYJmwOLJbHyfYnFiC1e91yL6sVfYrWXF1Pt9xJZU50yhmJZ+9AtmA==} + '@bufbuild/buf-linux-x64@1.66.0': + resolution: {integrity: sha512-6AYYyc2O32jnDjjHbyW9Oqcehd+PMw+34qVo+wGfaEgGwC+fyoL2oxcEmzsPyEvhY4mkYJRXaCb8p90Ndzd2vQ==} engines: {node: '>=12'} cpu: [x64] os: [linux] - '@bufbuild/buf-win32-arm64@1.63.0': - resolution: {integrity: sha512-sMZ63kK+MuxZVBFAh95Woly9QmeApohgQoWvO9ZppTzNXya7Kznz5lqa0B7f3zfDxgy2/DmOXILOMn3n8GoAww==} + '@bufbuild/buf-win32-arm64@1.66.0': + resolution: {integrity: sha512-S+CD5NZ6q0HCI0g0PTVypjSQ63LsLm1Svd7yG1MjKz9mQ83Vl6rYXuzmYYVi2cww7w5tDew8sYASZETewvEuxg==} engines: {node: '>=12'} cpu: [arm64] os: [win32] - '@bufbuild/buf-win32-x64@1.63.0': - resolution: {integrity: sha512-ooY4o3XPpvJ6BEOWB18pc52beeB9NdRRHMINuZ1oef3HNsFqtbv7DrPX9vm/mmOkzbTQDa8m7M8bjWjBO9ynkg==} + '@bufbuild/buf-win32-x64@1.66.0': + resolution: {integrity: sha512-uSPoWRaX8Qd5pHZt6zzRuZXr4Sdbqe4Pm1PmMax/SGUPacVpH1v9AGX1/BTgx+g+b4vLS5T4SGxTl9ngkQaY3Q==} engines: {node: '>=12'} cpu: [x64] os: [win32] - '@bufbuild/buf@1.63.0': - resolution: {integrity: sha512-SvYWiCs9J8tX8qIh1haNJEwM0MmyauSFDDksHL4wtPjeXcEj+SMvWudIn8KdWoiFbNDY98phn4sqZQ4F6uViPQ==} + '@bufbuild/buf@1.66.0': + resolution: {integrity: sha512-JSZT6OT8uKG2frScYNOS3Y4E+7wg1KSPQMKfLlbZZFnBoXwMqDdsxQF7O5ucameU+3DKRs+yQFI8tNQjFJ5T2g==} engines: {node: '>=12'} hasBin: true - '@bufbuild/cel-spec@0.3.0': - resolution: {integrity: sha512-mN669LGlXkYNco6NzSTpFoW52UwGb0h5UJNct43nkOjk9YrgUtzcBn9PfjrwbyAe3OlUtasvXAFf1Tjs3NQLOg==} + '@bufbuild/cel-spec@0.4.0': + resolution: {integrity: sha512-dUS6f2fNt6KEumsYGE7YFxERZE5ZuyME1hQmGjtO8tkZhR6ow6/ne3v4Gik9cfdb9lSLK3AJ+vDxCdGWmDbWvA==} peerDependencies: '@bufbuild/protobuf': ^2.6.2 - '@bufbuild/cel@0.3.0': - resolution: {integrity: sha512-vIdcn0Ot6XDKakcDqEQvvlCtMlYwLlxc++SrVjjCmYIiZRH+tlr1GRYpe5R9kguSiTS3BLh7C+I7ZoektVPICQ==} + '@bufbuild/cel@0.4.0': + resolution: {integrity: sha512-CdW/JgiTJCYXqnwuaJRo7NcoYhR37AaF58MMiog0/t8nudn86ZyLXYaA1f2yGhm2U17h8pKGZNksTHVSTcpmAw==} peerDependencies: '@bufbuild/protobuf': ^2.6.2 - '@bufbuild/protobuf@2.10.2': - resolution: {integrity: sha512-uFsRXwIGyu+r6AMdz+XijIIZJYpoWeYzILt5yZ2d3mCjQrWUTVpVD9WL/jZAbvp+Ed04rOhrsk7FiTcEDseB5A==} + '@bufbuild/protobuf@2.11.0': + resolution: {integrity: sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==} - '@bufbuild/protoc-gen-es@2.10.2': - resolution: {integrity: sha512-vbjPsuofbtZwZXuOP7Y16CQsxrwCjuRONffmJSBEhoC7PQu/Cabp0+Fu/poLPm9CNM0tDCQA0xvgobgudaEYxQ==} + '@bufbuild/protoc-gen-es@2.11.0': + resolution: {integrity: sha512-VzQuwEQDXipbZ1soWUuAWm1Z0C3B/IDWGeysnbX6ogJ6As91C2mdvAND/ekQ4YIWgen4d5nqLfIBOWLqCCjYUA==} engines: {node: '>=20'} hasBin: true peerDependencies: - '@bufbuild/protobuf': 2.10.2 + '@bufbuild/protobuf': 2.11.0 peerDependenciesMeta: '@bufbuild/protobuf': optional: true - '@bufbuild/protoplugin@2.10.2': - resolution: {integrity: sha512-RAWVs9tCzRqSS3tUtaFhOcauOAazCrm7tlGh0WHFq/44n5Fj6YgefdlZEPIaAK6VAA+FdOoFgtOJK2Ji5U24pw==} + '@bufbuild/protoplugin@2.11.0': + resolution: {integrity: sha512-lyZVNFUHArIOt4W0+dwYBe5GBwbKzbOy8ObaloEqsw9Mmiwv2O48TwddDoHN4itylC+BaEGqFdI1W8WQt2vWJQ==} - '@bufbuild/protovalidate@1.1.0': - resolution: {integrity: sha512-oC1sYAr9eQucZsLb0M7cIk3TftZ/cOBbKT1XBIL9Aypm5e0IcC8/HlfN+NrwPVhw9JI4bOQM1Ar1E6x7L71nbA==} + '@bufbuild/protovalidate@1.1.1': + resolution: {integrity: sha512-sE6CojU25nfeb1w88Sm+jRnmk4GvQTeEZvLDHHDPvIHbj2NsDJWFAUJdJr+RcuMnjdWmbur+rAS38VuEK/XviQ==} peerDependencies: '@bufbuild/protobuf': ^2.8.0 @@ -1964,18 +2035,12 @@ packages: '@chevrotain/utils@10.5.0': resolution: {integrity: sha512-hBzuU5+JjB2cqNZyszkDHZgOSrUUT8V3dhgRl8Q9Gp6dAj/H5+KILGjbhDpc3Iy9qmqlm/akuOI2ut9VUtzJxQ==} - '@clack/core@0.3.5': - resolution: {integrity: sha512-5cfhQNH+1VQ2xLQlmzXMqUoiaH0lRBq9/CLW9lTyMbuKLC3+xEK01tHVvyut++mLOn5urSHmkm6I0Lg9MaJSTQ==} - '@clack/core@0.5.0': resolution: {integrity: sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==} '@clack/prompts@0.11.0': resolution: {integrity: sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==} - '@clack/prompts@0.8.2': - resolution: {integrity: sha512-6b9Ab2UiZwJYA9iMyboYyW9yJvAO9V753ZhS+DHKEjZRKAxPPOb7MXXu84lsPFG+vZt6FRFniZ8rXi+zCIw4yQ==} - '@codemirror/autocomplete@6.20.0': resolution: {integrity: sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==} @@ -1988,8 +2053,8 @@ packages: '@codemirror/lang-html@6.4.11': resolution: {integrity: sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==} - '@codemirror/lang-javascript@6.2.4': - resolution: {integrity: sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==} + '@codemirror/lang-javascript@6.2.5': + resolution: {integrity: sha512-zD4e5mS+50htS7F+TYjBPsiIFGanfVqg4HyUz6WNFikgOPf2BgKlx+TQedI1w6n/IqRBVBbBWmGFdLB/7uxO4A==} '@codemirror/lang-json@6.0.2': resolution: {integrity: sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==} @@ -2000,8 +2065,8 @@ packages: '@codemirror/language@6.12.1': resolution: {integrity: sha512-Fa6xkSiuGKc8XC8Cn96T+TQHYj4ZZ7RdFmXA3i9xe/3hLHfwPZdM+dqfX0Cp0zQklBKhVD8Yzc8LS45rkqcwpQ==} - '@codemirror/lint@6.9.2': - resolution: {integrity: sha512-sv3DylBiIyi+xKwRCJAAsBZZZWo82shJ/RTMymLabAdtbkV5cSKwWDeCgtUq3v8flTaXS2y1kKkICuRYtUswyQ==} + '@codemirror/lint@6.9.5': + resolution: {integrity: sha512-GElsbU9G7QT9xXhpUg1zWGmftA/7jamh+7+ydKRuT0ORpWS3wOSP0yT1FOlIZa7mIJjpVPipErsyvVqB9cfTFA==} '@codemirror/search@6.5.11': resolution: {integrity: sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==} @@ -2061,28 +2126,28 @@ packages: resolution: {integrity: sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==} engines: {node: '>= 8.9.0'} - '@effect-atom/atom-react@0.4.4': - resolution: {integrity: sha512-EWT9WpB67GNCecxQXJdAZNVMhuk3VxpdDfojxg1wOgWmR5TPaGiXA74Jqa2Y9AEjSB0hMMAk7RNve2CoIikg2w==} + '@effect-atom/atom-react@0.5.0': + resolution: {integrity: sha512-aFfjWi4rEJCqfM12Oi36/EKaDm/W6n4/N6yM5vL0t/QozKhJhK05rQL/GY4XMxlH2eqkQ4ih8jBQa3Yyp0Fiqw==} peerDependencies: effect: ^3.19 react: '>=18 <20' scheduler: '*' - '@effect-atom/atom@0.4.11': - resolution: {integrity: sha512-bahWNw2xQ349HXkqshpls/t4wUu5fbMfjT6/7FhDj1uPjP9BArUAwL1Js5b7EG0ZPonS+G1O9LftpxVWAxr86g==} + '@effect-atom/atom@0.5.3': + resolution: {integrity: sha512-TRZv/i+YT3TtnN0oFORJqXdxSs1fc7lrJlH+1xZvDFyjC9hgoVnrcKbeZsDFmr6r0wYRqVo7U3IftxiQNjpNZA==} peerDependencies: - '@effect/experimental': ^0.57.0 - '@effect/platform': ^0.93.0 - '@effect/rpc': ^0.72.1 - effect: ^3.19.0 + '@effect/experimental': ^0.58.0 + '@effect/platform': ^0.94.2 + '@effect/rpc': ^0.73.0 + effect: ^3.19.15 - '@effect/cli@0.73.0': - resolution: {integrity: sha512-KkRtFjfyG52kQ6Z3ZEjwytfKZQACsLzn/RI2jKKxMJDebY9BQganOiE3VGCT4slU3Zisur6SP//ghM0vCLQs4g==} + '@effect/cli@0.73.2': + resolution: {integrity: sha512-K8IJo81+qa1LU8dhxcDU4QO/bIjL/dPd3zUOSCpLiuUNz8Y3/T+WNs3GqIXEhMfCFMSlRZERN0YgmtRlEZUREA==} peerDependencies: - '@effect/platform': ^0.94.0 + '@effect/platform': ^0.94.3 '@effect/printer': ^0.47.0 '@effect/printer-ansi': ^0.47.0 - effect: ^3.19.13 + effect: ^3.19.16 '@effect/cluster@0.56.1': resolution: {integrity: sha512-gnrsH6kfrUjn+82j/bw1IR4yFqJqV8tc7xZvrbJPRgzANycc6K1hu3LMg548uYbUkTzD8YYyqrSatMO1mkQpzw==} @@ -2112,28 +2177,28 @@ packages: '@effect/platform': ^0.94.0 effect: ^3.19.13 - '@effect/platform-node-shared@0.57.0': - resolution: {integrity: sha512-QXuvmLNlABCQLcTl+lN1YPhKosR6KqArPYjC2reU0fb5lroCo3YRb/aGpXIgLthHzQL8cLU5XMGA3Cu5hKY2Tw==} + '@effect/platform-node-shared@0.57.1': + resolution: {integrity: sha512-oX/bApMdoKsyrDiNdJxo7U9Rz1RXsjRv+ecfAPp1qGlSdGIo32wVRvJ2XCHqYj0sqaYJS0pU0/GCulRfVGuJag==} peerDependencies: - '@effect/cluster': ^0.56.0 - '@effect/platform': ^0.94.0 + '@effect/cluster': ^0.56.1 + '@effect/platform': ^0.94.2 '@effect/rpc': ^0.73.0 '@effect/sql': ^0.49.0 - effect: ^3.19.13 + effect: ^3.19.15 - '@effect/platform-node@0.104.0': - resolution: {integrity: sha512-2ZkUDDTxLD95ARdYIKBx4tdIIgqA3cwb3jlnVVBxmHUf0Pg5N2HdMuD0Q+CXQ7Q94FDwnLW3ZvaSfxDh6FvrNw==} + '@effect/platform-node@0.104.1': + resolution: {integrity: sha512-jT1a/z98niK6fnEU8pWHPPCdJMVDRCIdB65lolcOjse5rsTwVbczMjvKkhVQpF63mNWoOnol7OTRNkw5L54llg==} peerDependencies: - '@effect/cluster': ^0.56.0 - '@effect/platform': ^0.94.0 + '@effect/cluster': ^0.56.1 + '@effect/platform': ^0.94.2 '@effect/rpc': ^0.73.0 '@effect/sql': ^0.49.0 - effect: ^3.19.13 + effect: ^3.19.15 - '@effect/platform@0.94.1': - resolution: {integrity: sha512-SlL8OMTogHmMNnFLnPAHHo3ua1yrB1LNQOVQMiZsqYu9g3216xjr0gn5WoDgCxUyOdZcseegMjWJ7dhm/2vnfg==} + '@effect/platform@0.94.5': + resolution: {integrity: sha512-z05APUiDDPbodhTkH/RJqOLoCU11bU2IZLfcwLFrld03+ob1VeqRnELQlmueLIYm6NZifHAtjl32V+GRt34y4A==} peerDependencies: - effect: ^3.19.14 + effect: ^3.19.17 '@effect/printer-ansi@0.47.0': resolution: {integrity: sha512-tDEQ9XJpXDNYoWMQJHFRMxKGmEOu6z32x3Kb8YLOV5nkauEKnKmWNs7NBp8iio/pqoJbaSwqDwUg9jXVquxfWQ==} @@ -2173,6 +2238,20 @@ packages: '@effect/rpc': ^0.73.0 effect: ^3.19.13 + '@electric-sql/pglite-socket@0.0.20': + resolution: {integrity: sha512-J5nLGsicnD9wJHnno9r+DGxfcZWh+YJMCe0q/aCgtG6XOm9Z7fKeite8IZSNXgZeGltSigM9U/vAWZQWdgcSFg==} + hasBin: true + peerDependencies: + '@electric-sql/pglite': 0.3.15 + + '@electric-sql/pglite-tools@0.2.20': + resolution: {integrity: sha512-BK50ZnYa3IG7ztXhtgYf0Q7zijV32Iw1cYS8C+ThdQlwx12V5VZ9KRJ42y82Hyb4PkTxZQklVQA9JHyUlex33A==} + peerDependencies: + '@electric-sql/pglite': 0.3.15 + + '@electric-sql/pglite@0.3.15': + resolution: {integrity: sha512-Cj++n1Mekf9ETfdc16TlDi+cDDQF0W7EcbyRHYOAeZdsAe8M/FJg18itDTSwyHfar2WIezawM9o0EKaRGVKygQ==} + '@electron/asar@3.4.1': resolution: {integrity: sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==} engines: {node: '>=10.12.0'} @@ -2186,6 +2265,10 @@ packages: resolution: {integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==} engines: {node: '>=12'} + '@electron/get@3.1.0': + resolution: {integrity: sha512-F+nKc0xW+kVbBRhFzaMgPy3KwmuNTYX1fx6+FxxoSnNgwYX6LD7AKBTWkU0MQ6IBoe7dz069CNkR673sPAgkCQ==} + engines: {node: '>=14'} + '@electron/notarize@2.5.0': resolution: {integrity: sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==} engines: {node: '>= 10.0.0'} @@ -2200,6 +2283,11 @@ packages: engines: {node: '>=22.12.0'} hasBin: true + '@electron/rebuild@4.0.3': + resolution: {integrity: sha512-u9vpTHRMkOYCs/1FLiSVAFZ7FbjsXK+bQuzviJZa+lG7BHZl1nz52/IcGvwa3sk80/fc3llutBkbCq10Vh8WQA==} + engines: {node: '>=22.12.0'} + hasBin: true + '@electron/universal@2.0.3': resolution: {integrity: sha512-Wn9sPYIVFRFl5HmwMJkARCCf7rqK/EurkfQ/rJZ14mHP3iYTjZSIOSVonEAnhWeAXwtw7zOekGRlc6yTtZ0t+g==} engines: {node: '>=16.4'} @@ -2278,8 +2366,8 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.27.2': - resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} + '@esbuild/aix-ppc64@0.27.3': + resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] @@ -2290,8 +2378,8 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.27.2': - resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} + '@esbuild/android-arm64@0.27.3': + resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} engines: {node: '>=18'} cpu: [arm64] os: [android] @@ -2302,8 +2390,8 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.27.2': - resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} + '@esbuild/android-arm@0.27.3': + resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} engines: {node: '>=18'} cpu: [arm] os: [android] @@ -2314,8 +2402,8 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.27.2': - resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} + '@esbuild/android-x64@0.27.3': + resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} engines: {node: '>=18'} cpu: [x64] os: [android] @@ -2326,8 +2414,8 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.27.2': - resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} + '@esbuild/darwin-arm64@0.27.3': + resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] @@ -2338,8 +2426,8 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.27.2': - resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} + '@esbuild/darwin-x64@0.27.3': + resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} engines: {node: '>=18'} cpu: [x64] os: [darwin] @@ -2350,8 +2438,8 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.27.2': - resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} + '@esbuild/freebsd-arm64@0.27.3': + resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] @@ -2362,8 +2450,8 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.2': - resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} + '@esbuild/freebsd-x64@0.27.3': + resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] @@ -2374,8 +2462,8 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.27.2': - resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} + '@esbuild/linux-arm64@0.27.3': + resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} engines: {node: '>=18'} cpu: [arm64] os: [linux] @@ -2386,8 +2474,8 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.27.2': - resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} + '@esbuild/linux-arm@0.27.3': + resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} engines: {node: '>=18'} cpu: [arm] os: [linux] @@ -2398,8 +2486,8 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.27.2': - resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} + '@esbuild/linux-ia32@0.27.3': + resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] @@ -2410,8 +2498,8 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.27.2': - resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} + '@esbuild/linux-loong64@0.27.3': + resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} engines: {node: '>=18'} cpu: [loong64] os: [linux] @@ -2422,8 +2510,8 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.27.2': - resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} + '@esbuild/linux-mips64el@0.27.3': + resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] @@ -2434,8 +2522,8 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.27.2': - resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} + '@esbuild/linux-ppc64@0.27.3': + resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] @@ -2446,8 +2534,8 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.27.2': - resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} + '@esbuild/linux-riscv64@0.27.3': + resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] @@ -2458,8 +2546,8 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.27.2': - resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} + '@esbuild/linux-s390x@0.27.3': + resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] @@ -2470,8 +2558,8 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.27.2': - resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} + '@esbuild/linux-x64@0.27.3': + resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} engines: {node: '>=18'} cpu: [x64] os: [linux] @@ -2482,8 +2570,8 @@ packages: cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-arm64@0.27.2': - resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} + '@esbuild/netbsd-arm64@0.27.3': + resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] @@ -2494,8 +2582,8 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.27.2': - resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} + '@esbuild/netbsd-x64@0.27.3': + resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] @@ -2506,8 +2594,8 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-arm64@0.27.2': - resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} + '@esbuild/openbsd-arm64@0.27.3': + resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] @@ -2518,8 +2606,8 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.2': - resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} + '@esbuild/openbsd-x64@0.27.3': + resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] @@ -2530,8 +2618,8 @@ packages: cpu: [arm64] os: [openharmony] - '@esbuild/openharmony-arm64@0.27.2': - resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==} + '@esbuild/openharmony-arm64@0.27.3': + resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] @@ -2542,8 +2630,8 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.27.2': - resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} + '@esbuild/sunos-x64@0.27.3': + resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] @@ -2554,8 +2642,8 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.27.2': - resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} + '@esbuild/win32-arm64@0.27.3': + resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] @@ -2566,8 +2654,8 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.27.2': - resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} + '@esbuild/win32-ia32@0.27.3': + resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} engines: {node: '>=18'} cpu: [ia32] os: [win32] @@ -2578,8 +2666,8 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.27.2': - resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} + '@esbuild/win32-x64@0.27.3': + resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -2594,11 +2682,11 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/compat@2.0.0': - resolution: {integrity: sha512-T9AfE1G1uv4wwq94ozgTGio5EUQBqAVe1X9qsQtSNVEYW6j3hvtZVm8Smr4qL1qDPFg+lOB2cL5RxTRMzq4CTA==} + '@eslint/compat@2.0.2': + resolution: {integrity: sha512-pR1DoD0h3HfF675QZx0xsyrsU8q70Z/plx7880NOhS02NuWLgBCOMDL787nUeQ7EWLkxv3bPQJaarjcPQb2Dwg==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} peerDependencies: - eslint: ^8.40 || 9 + eslint: ^8.40 || 9 || 10 peerDependenciesMeta: eslint: optional: true @@ -2615,16 +2703,16 @@ packages: resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@1.0.0': - resolution: {integrity: sha512-PRfWP+8FOldvbApr6xL7mNCw4cJcSTq4GA7tYbgq15mRb0kWKO/wEB2jr+uwjFH3sZvEZneZyCUGTxsv4Sahyw==} + '@eslint/core@1.1.0': + resolution: {integrity: sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/css-tree@3.6.8': - resolution: {integrity: sha512-s0f40zY7dlMp8i0Jf0u6l/aSswS0WRAgkhgETgiCJRcxIWb4S/Sp9uScKHWbkM3BnoFLbJbmOYk5AZUDFVxaLA==} + '@eslint/css-tree@3.6.9': + resolution: {integrity: sha512-3D5/OHibNEGk+wKwNwMbz63NMf367EoR4mVNNpxddCHKEb2Nez7z62J2U6YjtErSsZDoY0CsccmoUpdEbkogNA==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} - '@eslint/eslintrc@3.3.3': - resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} + '@eslint/eslintrc@3.3.4': + resolution: {integrity: sha512-4h4MVF8pmBsncB60r0wSJiIeUKTSD4m7FmTFThG8RHlsg9ajqckLm9OraguFGZE4vVdpiI1Q4+hFnisopmG6gQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/js@9.39.2': @@ -2639,8 +2727,8 @@ packages: resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@faker-js/faker@10.2.0': - resolution: {integrity: sha512-rTXwAsIxpCqzUnZvrxVh3L0QA0NzToqWBLAhV+zDV3MIIwiQhAZHMdPCIaj5n/yADu/tyk12wIPgL6YHGXJP+g==} + '@faker-js/faker@10.3.0': + resolution: {integrity: sha512-It0Sne6P3szg7JIi6CgKbvTZoMjxBZhcv91ZrqrNuaZQfB5WoqYYbzCUOq89YR+VY8juY9M1vDWmDDa2TzfXCw==} engines: {node: ^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0, npm: '>=10'} '@fontsource-variable/dm-sans@5.2.8': @@ -2664,6 +2752,12 @@ packages: '@formatjs/intl-localematcher@0.6.2': resolution: {integrity: sha512-XOMO2Hupl0wdd172Y06h6kLpBz6Dv+J4okPLl4LPtzbr8f66WbIoy4ev98EBuZ6ZK4h5ydTN6XneT4QVpD7cdA==} + '@hono/node-server@1.19.9': + resolution: {integrity: sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@hookform/devtools@4.4.0': resolution: {integrity: sha512-Mtlic+uigoYBPXlfvPBfiYYUZuyMrD3pTjDpVIhL6eCZTvQkHsKBSKeZCvXWUZr8fqrkzDg27N+ZuazLKq6Vmg==} peerDependencies: @@ -2691,12 +2785,12 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@inquirer/ansi@2.0.2': - resolution: {integrity: sha512-SYLX05PwJVnW+WVegZt1T4Ip1qba1ik+pNJPDiqvk6zS5Y/i8PhRzLpGEtVd7sW0G8cMtkD8t4AZYhQwm8vnww==} + '@inquirer/ansi@2.0.3': + resolution: {integrity: sha512-g44zhR3NIKVs0zUesa4iMzExmZpLUdTLRMCStqX3GE5NT6VkPcxQGJ+uC8tDgBUC/vB1rUhUd55cOf++4NZcmw==} engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} - '@inquirer/checkbox@5.0.3': - resolution: {integrity: sha512-xtQP2eXMFlOcAhZ4ReKP2KZvDIBb1AnCfZ81wWXG3DXLVH0f0g4obE0XDPH+ukAEMRcZT0kdX2AS1jrWGXbpxw==} + '@inquirer/checkbox@5.1.0': + resolution: {integrity: sha512-/HjF1LN0a1h4/OFsbGKHNDtWICFU/dqXCdym719HFTyJo9IG7Otr+ziGWc9S0iQuohRZllh+WprSgd5UW5Fw0g==} engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' @@ -2704,8 +2798,8 @@ packages: '@types/node': optional: true - '@inquirer/confirm@6.0.3': - resolution: {integrity: sha512-lyEvibDFL+NA5R4xl8FUmNhmu81B+LDL9L/MpKkZlQDJZXzG8InxiqYxiAlQYa9cqLLhYqKLQwZqXmSTqCLjyw==} + '@inquirer/confirm@6.0.8': + resolution: {integrity: sha512-Di6dgmiZ9xCSUxWUReWTqDtbhXCuG2MQm2xmgSAIruzQzBqNf49b8E07/vbCYY506kDe8BiwJbegXweG8M1klw==} engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' @@ -2713,8 +2807,8 @@ packages: '@types/node': optional: true - '@inquirer/core@11.1.0': - resolution: {integrity: sha512-+jD/34T1pK8M5QmZD/ENhOfXdl9Zr+BrQAUc5h2anWgi7gggRq15ZbiBeLoObj0TLbdgW7TAIQRU2boMc9uOKQ==} + '@inquirer/core@11.1.5': + resolution: {integrity: sha512-QQPAX+lka8GyLcZ7u7Nb1h6q72iZ/oy0blilC3IB2nSt1Qqxp7akt94Jqhi/DzARuN3Eo9QwJRvtl4tmVe4T5A==} engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' @@ -2722,8 +2816,8 @@ packages: '@types/node': optional: true - '@inquirer/editor@5.0.3': - resolution: {integrity: sha512-wYyQo96TsAqIciP/r5D3cFeV8h4WqKQ/YOvTg5yOfP2sqEbVVpbxPpfV3LM5D0EP4zUI3EZVHyIUIllnoIa8OQ==} + '@inquirer/editor@5.0.8': + resolution: {integrity: sha512-sLcpbb9B3XqUEGrj1N66KwhDhEckzZ4nI/W6SvLXyBX8Wic3LDLENlWRvkOGpCPoserabe+MxQkpiMoI8irvyA==} engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' @@ -2731,8 +2825,8 @@ packages: '@types/node': optional: true - '@inquirer/expand@5.0.3': - resolution: {integrity: sha512-2oINvuL27ujjxd95f6K2K909uZOU2x1WiAl7Wb1X/xOtL8CgQ1kSxzykIr7u4xTkXkXOAkCuF45T588/YKee7w==} + '@inquirer/expand@5.0.8': + resolution: {integrity: sha512-QieW3F1prNw3j+hxO7/NKkG1pk3oz7pOB6+5Upwu3OIwADfPX0oZVppsqlL+Vl/uBHHDSOBY0BirLctLnXwGGg==} engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' @@ -2740,8 +2834,8 @@ packages: '@types/node': optional: true - '@inquirer/external-editor@2.0.2': - resolution: {integrity: sha512-X/fMXK7vXomRWEex1j8mnj7s1mpnTeP4CO/h2gysJhHLT2WjBnLv4ZQEGpm/kcYI8QfLZ2fgW+9kTKD+jeopLg==} + '@inquirer/external-editor@2.0.3': + resolution: {integrity: sha512-LgyI7Agbda74/cL5MvA88iDpvdXI2KuMBCGRkbCl2Dg1vzHeOgs+s0SDcXV7b+WZJrv2+ERpWSM65Fpi9VfY3w==} engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' @@ -2749,12 +2843,12 @@ packages: '@types/node': optional: true - '@inquirer/figures@2.0.2': - resolution: {integrity: sha512-qXm6EVvQx/FmnSrCWCIGtMHwqeLgxABP8XgcaAoywsL0NFga9gD5kfG0gXiv80GjK9Hsoz4pgGwF/+CjygyV9A==} + '@inquirer/figures@2.0.3': + resolution: {integrity: sha512-y09iGt3JKoOCBQ3w4YrSJdokcD8ciSlMIWsD+auPu+OZpfxLuyz+gICAQ6GCBOmJJt4KEQGHuZSVff2jiNOy7g==} engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} - '@inquirer/input@5.0.3': - resolution: {integrity: sha512-4R0TdWl53dtp79Vs6Df2OHAtA2FVNqya1hND1f5wjHWxZJxwDMSNB1X5ADZJSsQKYAJ5JHCTO+GpJZ42mK0Otw==} + '@inquirer/input@5.0.8': + resolution: {integrity: sha512-p0IJslw0AmedLEkOU+yrEX3Aj2RTpQq7ZOf8nc1DIhjzaxRWrrgeuE5Kyh39fVRgtcACaMXx/9WNo8+GjgBOfw==} engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' @@ -2762,8 +2856,8 @@ packages: '@types/node': optional: true - '@inquirer/number@4.0.3': - resolution: {integrity: sha512-TjQLe93GGo5snRlu83JxE38ZPqj5ZVggL+QqqAF2oBA5JOJoxx25GG3EGH/XN/Os5WOmKfO8iLVdCXQxXRZIMQ==} + '@inquirer/number@4.0.8': + resolution: {integrity: sha512-uGLiQah9A0F9UIvJBX52m0CnqtLaym0WpT9V4YZrjZ+YRDKZdwwoEPz06N6w8ChE2lrnsdyhY9sL+Y690Kh9gQ==} engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' @@ -2771,8 +2865,8 @@ packages: '@types/node': optional: true - '@inquirer/password@5.0.3': - resolution: {integrity: sha512-rCozGbUMAHedTeYWEN8sgZH4lRCdgG/WinFkit6ZPsp8JaNg2T0g3QslPBS5XbpORyKP/I+xyBO81kFEvhBmjA==} + '@inquirer/password@5.0.8': + resolution: {integrity: sha512-zt1sF4lYLdvPqvmvHdmjOzuUUjuCQ897pdUCO8RbXMUDKXJTTyOQgtn23le+jwcb+MpHl3VAFvzIdxRAf6aPlA==} engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' @@ -2780,8 +2874,8 @@ packages: '@types/node': optional: true - '@inquirer/prompts@8.1.0': - resolution: {integrity: sha512-LsZMdKcmRNF5LyTRuZE5nWeOjganzmN3zwbtNfcs6GPh3I2TsTtF1UYZlbxVfhxd+EuUqLGs/Lm3Xt4v6Az1wA==} + '@inquirer/prompts@8.3.0': + resolution: {integrity: sha512-JAj66kjdH/F1+B7LCigjARbwstt3SNUOSzMdjpsvwJmzunK88gJeXmcm95L9nw1KynvFVuY4SzXh/3Y0lvtgSg==} engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' @@ -2789,8 +2883,8 @@ packages: '@types/node': optional: true - '@inquirer/rawlist@5.1.0': - resolution: {integrity: sha512-yUCuVh0jW026Gr2tZlG3kHignxcrLKDR3KBp+eUgNz+BAdSeZk0e18yt2gyBr+giYhj/WSIHCmPDOgp1mT2niQ==} + '@inquirer/rawlist@5.2.4': + resolution: {integrity: sha512-fTuJ5Cq9W286isLxwj6GGyfTjx1Zdk4qppVEPexFuA6yioCCXS4V1zfKroQqw7QdbDPN73xs2DiIAlo55+kBqg==} engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' @@ -2798,8 +2892,8 @@ packages: '@types/node': optional: true - '@inquirer/search@4.0.3': - resolution: {integrity: sha512-lzqVw0YwuKYetk5VwJ81Ba+dyVlhseHPx9YnRKQgwXdFS0kEavCz2gngnNhnMIxg8+j1N/rUl1t5s1npwa7bqg==} + '@inquirer/search@4.1.4': + resolution: {integrity: sha512-9yPTxq7LPmYjrGn3DRuaPuPbmC6u3fiWcsE9ggfLcdgO/ICHYgxq7mEy1yJ39brVvgXhtOtvDVjDh9slJxE4LQ==} engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' @@ -2807,8 +2901,8 @@ packages: '@types/node': optional: true - '@inquirer/select@5.0.3': - resolution: {integrity: sha512-M+ynbwS0ecQFDYMFrQrybA0qL8DV0snpc4kKevCCNaTpfghsRowRY7SlQBeIYNzHqXtiiz4RG9vTOeb/udew7w==} + '@inquirer/select@5.1.0': + resolution: {integrity: sha512-OyYbKnchS1u+zRe14LpYrN8S0wH1vD0p2yKISvSsJdH2TpI87fh4eZdWnpdbrGauCRWDph3NwxRmM4Pcm/hx1Q==} engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' @@ -2816,8 +2910,8 @@ packages: '@types/node': optional: true - '@inquirer/type@4.0.2': - resolution: {integrity: sha512-cae7mzluplsjSdgFA6ACLygb5jC8alO0UUnFPyu0E7tNRPrL+q/f8VcSXp+cjZQ7l5CMpDpi2G1+IQvkOiL1Lw==} + '@inquirer/type@4.0.3': + resolution: {integrity: sha512-cKZN7qcXOpj1h+1eTTcGDVLaBIHNMT1Rz9JqJP5MnEJ0JhgVWllx7H/tahUp5YEK1qaByH2Itb8wLG/iScD5kw==} engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' @@ -2825,8 +2919,8 @@ packages: '@types/node': optional: true - '@internationalized/date@3.10.1': - resolution: {integrity: sha512-oJrXtQiAXLvT9clCf1K4kxp3eKsQhIaZqxEyowkBcsvZDdZkbWrVmnGknxs5flTD0VGsxrxKgBCZty1EzoiMzA==} + '@internationalized/date@3.12.0': + resolution: {integrity: sha512-/PyIMzK29jtXaGU23qTvNZxvBXRtKbNnGDFD+PY6CZw/Y8Ex8pFUzkuCJCG9aOqmShjqhS9mPqP6Dk5onQY8rQ==} '@internationalized/message@3.1.8': resolution: {integrity: sha512-Rwk3j/TlYZhn3HQ6PyXUV0XP9Uv42jqZGNegt0BXlxjE6G3+LwHjbQZAGHhCnCPdaA6Tvd3ma/7QzLlLkJxAWA==} @@ -2837,22 +2931,10 @@ packages: '@internationalized/string@3.2.7': resolution: {integrity: sha512-D4OHBjrinH+PFZPvfCXvG28n2LSykWcJ7GIioQL+ok0LON15SdfoUssoHzzOUmVZLbRoREsQXVzA6r8JKsbP6A==} - '@isaacs/balanced-match@4.0.1': - resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} - engines: {node: 20 || >=22} - - '@isaacs/brace-expansion@5.0.0': - resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} - engines: {node: 20 || >=22} - '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} - '@isaacs/cliui@9.0.0': - resolution: {integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==} - engines: {node: '>=18'} - '@isaacs/fs-minipass@4.0.1': resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} engines: {node: '>=18.0.0'} @@ -2869,8 +2951,8 @@ packages: resolution: {integrity: sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@joshwooding/vite-plugin-react-docgen-typescript@0.6.3': - resolution: {integrity: sha512-9TGZuAX+liGkNKkwuo3FYJu7gHWT0vkBcf7GkOe7s7fmC19XwH/4u5u7sDIFrMooe558ORcmuBvBz7Ur5PlbHw==} + '@joshwooding/vite-plugin-react-docgen-typescript@0.6.4': + resolution: {integrity: sha512-6PyZBYKnnVNqOSB0YFly+62R7dmov8segT27A+RVTBVd4iAE6kbW9QBJGlyR2yG4D4ohzhZSTIu7BK1UTtmFFA==} peerDependencies: typescript: '>= 4.3.x' vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 @@ -2900,14 +2982,11 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - '@lezer/common@1.5.0': - resolution: {integrity: sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA==} - '@lezer/common@1.5.1': resolution: {integrity: sha512-6YRVG9vBkaY7p1IVxL4s44n5nUnaNnGM2/AckNgYOnxTG2kWh1vR8BMxPseWPjRNpb5VtXnMpeYAEAADoRV1Iw==} - '@lezer/css@1.3.0': - resolution: {integrity: sha512-pBL7hup88KbI7hXnZV3PQsn43DHy6TWyzuyk2AO9UyoXcDltvIdqWKE1dLL/45JVZ+YZkHe1WVHqO6wugZZWcw==} + '@lezer/css@1.3.1': + resolution: {integrity: sha512-PYAKeUVBo3HFThruRyp/iK91SwiZJnzXh8QzkQlwijB5y+N5iB28+iLk78o2zmKqqV0uolNhCwFqB8LA7b0Svg==} '@lezer/generator@1.8.0': resolution: {integrity: sha512-/SF4EDWowPqV1jOgoGSGTIFsE7Ezdr7ZYxyihl5eMKVO5tlnpIhFcDavgm1hHY5GEonoOAEnJ0CU0x+tvuAuUg==} @@ -2925,8 +3004,8 @@ packages: '@lezer/json@1.0.3': resolution: {integrity: sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==} - '@lezer/lr@1.4.7': - resolution: {integrity: sha512-wNIFWdSUfX9Jc6ePMzxSPVgTVB4EOfDIwLQLWASyiUdHKaMsiilj9bYiGkGQCKVodd0x6bgQCV207PILGFCF9Q==} + '@lezer/lr@1.4.8': + resolution: {integrity: sha512-bPWa0Pgx69ylNlMlPvBPryqeLYQjyJjqPx+Aupm5zydLIF3NE+6MMLT8Yi23Bd9cif9VS00aUebn+6fDIGBcDA==} '@lezer/xml@1.0.6': resolution: {integrity: sha512-CdDwirL0OEaStFue/66ZmFSeppuL6Dwjlk8qk153mSQwiSH/Dlri4GNymrNWnUmPl2Um7QfV1FO9KFUyX3Twww==} @@ -3002,16 +3081,16 @@ packages: '@module-federation/bridge-react-webpack-plugin@0.21.6': resolution: {integrity: sha512-lJMmdhD4VKVkeg8RHb+Jwe6Ou9zKVgjtb1inEURDG/sSS2ksdZA8pVKLYbRPRbdmjr193Y8gJfqFbI2dqoyc/g==} - '@module-federation/bridge-react-webpack-plugin@0.22.0': - resolution: {integrity: sha512-OzMBBbUhOMbDVX/wkVDxaOshgyUdxv+kRQDtxl1/ipV5GXTjs1tpS4NHtDwiJi0qKeG0AvnvGCrPu7bjMOcAVw==} + '@module-federation/bridge-react-webpack-plugin@2.1.0': + resolution: {integrity: sha512-c/iiwLwxHDG5i227v2GQ84JRPWHU+d2uhxhZhbxIAQ5uRe6kbtj8O4uPUfEq+iabiqqtUwTLbcpUFFy1bLllYA==} '@module-federation/cli@0.21.6': resolution: {integrity: sha512-qNojnlc8pTyKtK7ww3i/ujLrgWwgXqnD5DcDPsjADVIpu7STaoaVQ0G5GJ7WWS/ajXw6EyIAAGW/AMFh4XUxsQ==} engines: {node: '>=16.0.0'} hasBin: true - '@module-federation/cli@0.22.0': - resolution: {integrity: sha512-kdeDg6HuOqJYKtPeoupWQg6wLZT7B+AwMDwMjwhcKHxKEmKFPImbJLymBWEgmKTktZKh1ERtEOplwFt9u5iEBA==} + '@module-federation/cli@2.1.0': + resolution: {integrity: sha512-VbMJMEfP1vp/693HbQTMYqMu73Qbv23aJEW9/NhmVkRXkfjBtNfP+mROSFjJVQsWhYyU5vy8kBX7DQS/mvZGBg==} engines: {node: '>=16.0.0'} hasBin: true @@ -3021,11 +3100,16 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' - '@module-federation/data-prefetch@0.22.0': - resolution: {integrity: sha512-NESR/5Wcn9unPY18oQSSXlbXTnMbUFwqqvSZnpJt5vBb/8QlcJEiPnxERZqKhKrIS6GTD8KneHPRCOQsP6Xcqw==} + '@module-federation/data-prefetch@2.1.0': + resolution: {integrity: sha512-/rHwtZEknzujpCoXChZcy29vD7zNY2b/XfAcOpCkMVfWyQiNhppKxeyjA6FnPEp64NAOLzj2XxaadceXa1eFeA==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true '@module-federation/dts-plugin@0.21.6': resolution: {integrity: sha512-YIsDk8/7QZIWn0I1TAYULniMsbyi2LgKTi9OInzVmZkwMC6644x/ratTWBOUDbdY1Co+feNkoYeot1qIWv2L7w==} @@ -3036,8 +3120,8 @@ packages: vue-tsc: optional: true - '@module-federation/dts-plugin@0.22.0': - resolution: {integrity: sha512-lj5YtUZz0moaT1XziM0OyizE0mIhMa8W65RUiX/+UZ4iNK/KMs4e/CGpfhEt2Lj9+j6KYSzI2+676d+73j/kag==} + '@module-federation/dts-plugin@2.1.0': + resolution: {integrity: sha512-2ubWFjF72i3Z5TM2G8hg6SOS6dB0v7PRLXPUMNoVMBxHGxiFG/F0xryZ2UYFwLA2hcNmf60LNP30F1tJhsH4wg==} peerDependencies: typescript: ^4.9.0 || ^5.0.0 vue-tsc: '>=1.0.24' @@ -3060,8 +3144,8 @@ packages: webpack: optional: true - '@module-federation/enhanced@0.22.0': - resolution: {integrity: sha512-OysyO6xbhpP+CeOEDp2v6HyFcVT5wWAdQrfga3jhlFUAdIR7nZZ2albysnF2CGn/xyU050Ss74ttgy7GiKi5fQ==} + '@module-federation/enhanced@2.1.0': + resolution: {integrity: sha512-nWCe31vzYLGsT3DYf2cKtxSjUDLWVgErZeDEB8cddtuA3c4npSdKeG8P/bI9GtRph5ybIUFbyAMtuKPPhMahOw==} hasBin: true peerDependencies: typescript: ^4.9.0 || ^5.0.0 @@ -3078,44 +3162,37 @@ packages: '@module-federation/error-codes@0.21.6': resolution: {integrity: sha512-MLJUCQ05KnoVl8xd6xs9a5g2/8U+eWmVxg7xiBMeR0+7OjdWUbHwcwgVFatRIwSZvFgKHfWEiI7wsU1q1XbTRQ==} - '@module-federation/error-codes@0.22.0': - resolution: {integrity: sha512-xF9SjnEy7vTdx+xekjPCV5cIHOGCkdn3pIxo9vU7gEZMIw0SvAEdsy6Uh17xaCpm8V0FWvR0SZoK9Ik6jGOaug==} + '@module-federation/error-codes@2.1.0': + resolution: {integrity: sha512-W+uCmPsFuV+15E1S7JUB1AeUDBFqKjJ2hImXdBNYx7T1CGM6awS/veooXqNoP7iM/kwKjtpTQPIeccWLrq76Mg==} '@module-federation/inject-external-runtime-core-plugin@0.21.6': resolution: {integrity: sha512-DJQne7NQ988AVi3QB8byn12FkNb+C2lBeU1NRf8/WbL0gmHsr6kW8hiEJCm8LYaURwtsQqtsEV7i+8+51qjSmQ==} peerDependencies: '@module-federation/runtime-tools': 0.21.6 - '@module-federation/inject-external-runtime-core-plugin@0.22.0': - resolution: {integrity: sha512-zeN6XiLV9l0tAsZzQxHLEQM28sWiijmIBp9CiIDc4iqk2f/kgCSqiBWTiNcS4sZODzupPkktaWsC5+5eWk0ENQ==} + '@module-federation/inject-external-runtime-core-plugin@2.1.0': + resolution: {integrity: sha512-okAVRH/9rROh1fBSKF7Li/Ia8bQhgz38AfVvUSzVu32/HCvdjpfddQtPFFxvmi2oayPgUDY4Qy8RXT1pUlBqpA==} peerDependencies: - '@module-federation/runtime-tools': 0.22.0 + '@module-federation/runtime-tools': 2.1.0 '@module-federation/managers@0.21.6': resolution: {integrity: sha512-BeV6m2/7kF5MDVz9JJI5T8h8lMosnXkH2bOxxFewcra7ZjvDOgQu7WIio0mgk5l1zjNPvnEVKhnhrenEdcCiWg==} - '@module-federation/managers@0.22.0': - resolution: {integrity: sha512-Ptv8gEUihPBeoQEpsKq3GZUEB4y/hqG83mKw5NrKpXMIfcoF6SZjcknXz5LuN7NF3xMi1XHYU74z/nKzr+izew==} + '@module-federation/managers@2.1.0': + resolution: {integrity: sha512-8HX721e3uuDSURtnOpj6Zy/+Qc4IM5no9hMPODYdGjrYe2YUmXY4/5JScSVnFeYm+zBPw6y9QoufeG9g2jrWBg==} '@module-federation/manifest@0.21.6': resolution: {integrity: sha512-yg93+I1qjRs5B5hOSvjbjmIoI2z3th8/yst9sfwvx4UDOG1acsE3HHMyPN0GdoIGwplC/KAnU5NmUz4tREUTGQ==} - '@module-federation/manifest@0.22.0': - resolution: {integrity: sha512-Exv+frMkRGKDs3KKXeBBKcHvL7nNTk5Yt2ftEvxCUIRPC16Ebvy6RcQvFFvbvmOhuM/If6j6E/aZu5Z9oau6xw==} + '@module-federation/manifest@2.1.0': + resolution: {integrity: sha512-icIUhMG4FwaFZyBmVjadkdqscNb98iXrITTVeMeAxJcrnZltSBBSEHepfpfeW+tHW+wMmr+lWFnAbSCepV73+A==} - '@module-federation/node@2.7.26': - resolution: {integrity: sha512-C7aIABSxbZKOvVDMIivmV9Q/aOVh9xpUv+y+nwSWuQr9v2pgmMzVK3rxWoeusmkpaENia8h5AWNpYjcrMi+O9g==} + '@module-federation/node@2.7.33': + resolution: {integrity: sha512-ATR5zu7qUb8wasOyIYrbVfoPb00c7wC9F66g/GeSJwV1O9SvhR5r4rsfCSQ3uB8/Y7VCeHz0w8DZSqMRkuoHYQ==} peerDependencies: - next: '*' - react: ^16||^17||^18||^19 - react-dom: ^16||^17||^18||^19 webpack: ^5.40.0 peerDependenciesMeta: - next: - optional: true - react: - optional: true - react-dom: + webpack: optional: true '@module-federation/rspack@0.21.6': @@ -3130,10 +3207,10 @@ packages: vue-tsc: optional: true - '@module-federation/rspack@0.22.0': - resolution: {integrity: sha512-PvDlFxzCbufArZvt6wSLsJNm20hdDsz/4X04YAxAZfp/dTECZghZsebLcR7nHOzOwR2gCX8vv+gB3r+5MheobA==} + '@module-federation/rspack@2.1.0': + resolution: {integrity: sha512-bojG6yIoWsta7CDdKZ3nrTn1IKT98algUGG5/uyR6nhyOxsu7CJpf17kcLUqTKdBwN9S8qZOjycXGDeEX//N3w==} peerDependencies: - '@rspack/core': '>=0.7' + '@rspack/core': ^0.7.0 || ^1.0.0 || ^2.0.0-0 typescript: ^4.9.0 || ^5.0.0 vue-tsc: '>=1.0.24' peerDependenciesMeta: @@ -3145,38 +3222,41 @@ packages: '@module-federation/runtime-core@0.21.6': resolution: {integrity: sha512-5Hd1Y5qp5lU/aTiK66lidMlM/4ji2gr3EXAtJdreJzkY+bKcI5+21GRcliZ4RAkICmvdxQU5PHPL71XmNc7Lsw==} - '@module-federation/runtime-core@0.22.0': - resolution: {integrity: sha512-GR1TcD6/s7zqItfhC87zAp30PqzvceoeDGYTgF3Vx2TXvsfDrhP6Qw9T4vudDQL3uJRne6t7CzdT29YyVxlgIA==} + '@module-federation/runtime-core@2.1.0': + resolution: {integrity: sha512-9W+wV5s7PTMnSFCmyNvItnOf3VRYSxAPMZQ91bOT4GdwHTO23dfmC57o0SiqXw+ri/XOQVA8gd/p8TDwDDYx6A==} '@module-federation/runtime-tools@0.21.6': resolution: {integrity: sha512-fnP+ZOZTFeBGiTAnxve+axGmiYn2D60h86nUISXjXClK3LUY1krUfPgf6MaD4YDJ4i51OGXZWPekeMe16pkd8Q==} - '@module-federation/runtime-tools@0.22.0': - resolution: {integrity: sha512-4ScUJ/aUfEernb+4PbLdhM/c60VHl698Gn1gY21m9vyC1Ucn69fPCA1y2EwcCB7IItseRMoNhdcWQnzt/OPCNA==} + '@module-federation/runtime-tools@2.1.0': + resolution: {integrity: sha512-2pOyGOiWIGG0+fE0jBY6pRYVH4+G/gFiP9KnyVDp6zj3leFRdePtlIZDa4O0X1dQcMOMmOORrx+TLRZeygbCnw==} '@module-federation/runtime@0.21.6': resolution: {integrity: sha512-+caXwaQqwTNh+CQqyb4mZmXq7iEemRDrTZQGD+zyeH454JAYnJ3s/3oDFizdH6245pk+NiqDyOOkHzzFQorKhQ==} - '@module-federation/runtime@0.22.0': - resolution: {integrity: sha512-38g5iPju2tPC3KHMPxRKmy4k4onNp6ypFPS1eKGsNLUkXgHsPMBFqAjDw96iEcjri91BrahG4XcdyKi97xZzlA==} + '@module-federation/runtime@2.1.0': + resolution: {integrity: sha512-Cs6H6vAQrLeD7tWW3nI7Z9EdvhcFcbqQdYWJ2SaN1X/eX2YvgHJe8sRxa7K7zlVRV5QZEPKgQCbrUfef+d5xqQ==} '@module-federation/sdk@0.21.6': resolution: {integrity: sha512-x6hARETb8iqHVhEsQBysuWpznNZViUh84qV2yE7AD+g7uIzHKiYdoWqj10posbo5XKf/147qgWDzKZoKoEP2dw==} - '@module-federation/sdk@0.22.0': - resolution: {integrity: sha512-x4aFNBKn2KVQRuNVC5A7SnrSCSqyfIWmm1DvubjbO9iKFe7ith5niw8dqSFBekYBg2Fwy+eMg4sEFNVvCAdo6g==} + '@module-federation/sdk@2.1.0': + resolution: {integrity: sha512-HhiSo1X+t2+r5lxU+JBVsJdE2IJZOaD1e0linw+4bLlEy8uIgXhGttF9+9rAnRKWlhn6R8E23ionwBCuSLVeXQ==} '@module-federation/third-party-dts-extractor@0.21.6': resolution: {integrity: sha512-Il6x4hLsvCgZNk1DFwuMBNeoxD1BsZ5AW2BI/nUgu0k5FiAvfcz1OFawRFEHtaM/kVrCsymMOW7pCao90DaX3A==} - '@module-federation/third-party-dts-extractor@0.22.0': - resolution: {integrity: sha512-3y2DZdeEjArNKDqA1Ds32Q6A5RATcsmywCXyQaWcfaScprpmzfEWiDkeD/nzoA/0+4ePY8OEinJ4hLtoMNLbLQ==} + '@module-federation/third-party-dts-extractor@2.1.0': + resolution: {integrity: sha512-w/hn0J+gw+lEfsXTR3DsbtcxpAndMZJ2PHnQTFn2s5BujNL18FcStaoz0tDpcJAVxi2iQZATJ3bGrlO2t2aDjQ==} '@module-federation/webpack-bundler-runtime@0.21.6': resolution: {integrity: sha512-7zIp3LrcWbhGuFDTUMLJ2FJvcwjlddqhWGxi/MW3ur1a+HaO8v5tF2nl+vElKmbG1DFLU/52l3PElVcWf/YcsQ==} - '@module-federation/webpack-bundler-runtime@0.22.0': - resolution: {integrity: sha512-aM8gCqXu+/4wBmJtVeMeeMN5guw3chf+2i6HajKtQv7SJfxV/f4IyNQJUeUQu9HfiAZHjqtMV5Lvq/Lvh8LdyA==} + '@module-federation/webpack-bundler-runtime@2.1.0': + resolution: {integrity: sha512-yThI7cPanvH5eobaeFUsQ51sjllA3nyN/8OxfSdlbeTogLF4K8tkCr6H7QW+alE9lXxOzI2BTCxMV6NJBKWmTQ==} + + '@mongodb-js/saslprep@1.4.6': + resolution: {integrity: sha512-y+x3H1xBZd38n10NZF/rEBlvDOOMQ6LKUTHqr8R9VkJ+mmQOYtJFxIlkkK8fZrtOiL6VixbOBWMbZGBdal3Z1g==} '@mrleebo/prisma-ast@0.13.1': resolution: {integrity: sha512-XyroGQXcHrZdvmrGJvsA9KNeOOgGMg1Vg9OlheUsBOSKznLMDl+YChxbkboRHvtFYJEMRYmlV3uoo/njCw05iw==} @@ -3267,108 +3347,108 @@ packages: resolution: {integrity: sha512-gOBg5YHMfZy+TfHArfVogwgfBeQnKbbGo3pSUyK/gSI0AVu+pEiDVcKlQb0D8Mg1LNRZILZ6XG8I5dJ4KuAd9Q==} engines: {node: ^20.17.0 || >=22.9.0} - '@nx/cypress@22.3.3': - resolution: {integrity: sha512-HWy05q0GSnbxljq1fBVfXPGw8quG9zvu4UaLErNqPHh46oWmUoWuR2TkDkpWEZn9JvYxx+m4QhsGpXzHXioeXg==} + '@nx/cypress@22.5.4': + resolution: {integrity: sha512-mKh8BOLDKGRSCRCd5PtRwdio9djpX7Nu5fvWmXNnbMXq37MFlh/L3xlFP2cxLMmugSibJbz19GYBkkjmjf8ZDw==} peerDependencies: cypress: '>= 13 < 16' peerDependenciesMeta: cypress: optional: true - '@nx/devkit@22.3.3': - resolution: {integrity: sha512-/hxcdhE+QDalsWEbJurHtZh9aY27taHeImbCVJnogwv85H3RbAE+0YuKXGInutfLszAs7phwzli71yq+d2P45Q==} + '@nx/devkit@22.5.4': + resolution: {integrity: sha512-+QCmpQZQmEGvi8IurC6bOgUTk+Q0dQo7wkp6V04lskXBztSyasBS0BGy5ic90kY05UlQUd++zRA1VY0jc+Yz5Q==} peerDependencies: nx: '>= 21 <= 23 || ^22.0.0-0' - '@nx/eslint@22.3.3': - resolution: {integrity: sha512-iG/LvrYf2CFAm2A0kfmRU4VeCTAN5PjUw8xc6oD1zfQ/KTmE/gFG2P1aJBo2mTIyzk9k8ZI0dqIhPLdl/AAtxg==} + '@nx/eslint@22.5.4': + resolution: {integrity: sha512-LMFpyep6N5Se7v5Ck2icZPBa3krWcuGYpubzjEuG35dQm2f/Fr+vLNfQWvfHiF+gP3eSYuJJPI/E38ifTZ/J5A==} peerDependencies: '@zkochan/js-yaml': 0.0.7 - eslint: ^8.0.0 || ^9.0.0 + eslint: ^8.0.0 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: '@zkochan/js-yaml': optional: true - '@nx/js@22.3.3': - resolution: {integrity: sha512-L3MOb8cLc2TIg2R3hGC9FLlcuVqlqST/fztmOihw9wS3lo52E4v2gP/BpYGfRh/u9r6Ekm6LF03Or+VwYzPuzA==} + '@nx/js@22.5.4': + resolution: {integrity: sha512-RPGDQjPm68ml5vKOk2RhRgNUM51qyMfIkRsKSxTWy0EpMOa7ud0I2bPQyNDMkqP04w8I5GZPD8O8opesDrdmtg==} peerDependencies: verdaccio: ^6.0.5 peerDependenciesMeta: verdaccio: optional: true - '@nx/module-federation@22.3.3': - resolution: {integrity: sha512-bo0qsW0hDhuyS/WnHQ1nndHcd7VeuMS3bxCwPJkPm8+qsVhWT88GO9WoYnlvdpx/LfTT/N6k1AOVOKAygRuUNQ==} + '@nx/module-federation@22.5.4': + resolution: {integrity: sha512-rjYSxbKMrrRHQOh+25GlNI91cads+PyHe1LVNn3/S1NTZH20PObtt+KRuppj6L2Mjg3/gK0WfQoMrvFNRiV48A==} - '@nx/nx-darwin-arm64@22.3.3': - resolution: {integrity: sha512-zBAGFGLal09CxhQkdMpOVwcwa9Y01aFm88jTTn35s/DdIWsfngmPzz0t4mG7u2D05q7TJfGQ31pIf5GkNUjo6g==} + '@nx/nx-darwin-arm64@22.5.4': + resolution: {integrity: sha512-Ib9znwSLQZSZ/9hhg5ODplpNhE/RhGVXzdfRj6YonTuWSj/kH3dLMio+4JEkjRdTQVm06cDW0KdwSgnwovqMGg==} cpu: [arm64] os: [darwin] - '@nx/nx-darwin-x64@22.3.3': - resolution: {integrity: sha512-6ZQ6rMqH8NY4Jz+Gc89D5bIH2NxZb5S/vaA4yJ9RrqAfl4QWchNFD5na+aRivSd+UdsYLPKKl6qohet5SE6vOg==} + '@nx/nx-darwin-x64@22.5.4': + resolution: {integrity: sha512-DjyXuQMc93MPU2XdRsJYjzbv1tgCzMi+zm7O0gc4x3h+ECFjKkjzQBg67pqGdhE3TV27MAlVRKrgHStyK9iigg==} cpu: [x64] os: [darwin] - '@nx/nx-freebsd-x64@22.3.3': - resolution: {integrity: sha512-J/PP5pIOQtR7ZzrFwP6d6h0yfY7r9EravG2m940GsgzGbtZGYIDqnh5Wdt+4uBWPH8VpdNOwFqH0afELtJA3MA==} + '@nx/nx-freebsd-x64@22.5.4': + resolution: {integrity: sha512-DhxdP8AhIfN0yCtFhZQcbp32MVN3L7UiTotYqqnOgwW922NRGSd5e+KEAWiJVrIO6TdgnI7prxpg1hfQQK0WDw==} cpu: [x64] os: [freebsd] - '@nx/nx-linux-arm-gnueabihf@22.3.3': - resolution: {integrity: sha512-/zn0altzM15S7qAgXMaB41vHkEn18HyTVUvRrjmmwaVqk9WfmDmqOQlGWoJ6XCbpvKQ8bh14RyhR9LGw1JJkNA==} + '@nx/nx-linux-arm-gnueabihf@22.5.4': + resolution: {integrity: sha512-pv1x1afTaLAOxPxVhQneLeXgjclp11f9ORxR7jA4E86bSgc9OL92dLSCkXtLQzqPNOej6SZ2fO+PPHVMZwtaPQ==} cpu: [arm] os: [linux] - '@nx/nx-linux-arm64-gnu@22.3.3': - resolution: {integrity: sha512-NmPeCexWIZHW9RM3lDdFENN9C3WtlQ5L4RSNFESIjreS921rgePhulsszYdGnHdcnKPYlBBJnX/NxVsfioBbnQ==} + '@nx/nx-linux-arm64-gnu@22.5.4': + resolution: {integrity: sha512-mPji9PzleWPvXpmFDKaXpTymRgZkk/hW8JHGhvEZpKHHXMYgTGWC+BqOEM2A4dYC4bu4fi9RrteL7aouRRWJoQ==} cpu: [arm64] os: [linux] - '@nx/nx-linux-arm64-musl@22.3.3': - resolution: {integrity: sha512-K02U88Q0dpvCfmSXXvY7KbYQSa1m+mkYeqDBRHp11yHk1GoIqaHp8oEWda7FV4gsriNExPSS5tX1/QGVoLZrCw==} + '@nx/nx-linux-arm64-musl@22.5.4': + resolution: {integrity: sha512-hF/HvEhbCjcFpTgY7RbP1tUTbp0M1adZq4ckyW8mwhDWQ/MDsc8FnOHwCO3Bzy9ZeJM0zQUES6/m0Onz8geaEA==} cpu: [arm64] os: [linux] - '@nx/nx-linux-x64-gnu@22.3.3': - resolution: {integrity: sha512-04TEbvgwRaB9ifr39YwJmWh3RuXb4Ry4m84SOJyjNXAfPrepcWgfIQn1VL2ul1Ybq+P023dLO9ME8uqFh6j1YQ==} + '@nx/nx-linux-x64-gnu@22.5.4': + resolution: {integrity: sha512-1+vicSYEOtc7CNMoRCjo59no4gFe8w2nGIT127wk1yeW3EJzRVNlOA7Deu10NUUbzLeOvHc8EFOaU7clT+F7XQ==} cpu: [x64] os: [linux] - '@nx/nx-linux-x64-musl@22.3.3': - resolution: {integrity: sha512-uxBXx5q+S5OGatbYDxnamsKXRKlYn+Eq1nrCAHaf8rIfRoHlDiRV2PqtWuF+O2pxR5FWKpvr+/sZtt9rAf7KMw==} + '@nx/nx-linux-x64-musl@22.5.4': + resolution: {integrity: sha512-/KjndxVB14yU0SJOhqADHOWoTy4Y45h5RjW3cxcXlPSJZz7ar1FnlLne1rWMMMUttepc8ku+3T//SGKi2eu+Nw==} cpu: [x64] os: [linux] - '@nx/nx-win32-arm64-msvc@22.3.3': - resolution: {integrity: sha512-aOwlfD6ZA1K6hjZtbhBSp7s1yi3sHbMpLCa4stXzfhCCpKUv46HU/EdiWdE1N8AsyNFemPZFq81k1VTowcACdg==} + '@nx/nx-win32-arm64-msvc@22.5.4': + resolution: {integrity: sha512-CrYt9FwhjOI6ZNy/G6YHLJmZuXCFJ24BCxugPXiZ7knDx7eGrr7owGgfht4SSiK3KCX40CvWCBJfqR4ZSgaSUA==} cpu: [arm64] os: [win32] - '@nx/nx-win32-x64-msvc@22.3.3': - resolution: {integrity: sha512-EDR8BtqeDvVNQ+kPwnfeSfmerYetitU3tDkxOMIybjKJDh69U2JwTB8n9ARwNaZQbNk7sCGNRUSZFTbAAUKvuQ==} + '@nx/nx-win32-x64-msvc@22.5.4': + resolution: {integrity: sha512-g5YByv4XsYwsYZvFe24A9bvfhZA+mwtIQt6qZtEVduZTT1hfhIsq0LXGHhkGoFLYwRMXSracWOqkalY0KT4IQw==} cpu: [x64] os: [win32] - '@nx/react@22.3.3': - resolution: {integrity: sha512-rbnI34j2UwvS8K5I6KS1IkndYI5psRV+jV7+NfVhfBpDLzEW4NU7WB1IVuK7t1grrLKFfTs7GKw5cTSX33hnNg==} + '@nx/react@22.5.4': + resolution: {integrity: sha512-QWQF4rZMtSABWTRdksjK4YQaCKZW+PRfYOskebwb8OtaoRFeEZwPeN0RvQFRGInhZJfDQRJhKMKy5YHdVvuTaw==} - '@nx/rollup@22.3.3': - resolution: {integrity: sha512-BJdOHx0CcZ6YMvn7quKTfh9C/X7X9s1e2XAZv+LC2vxiRdxN80w4cq04yZE8i5PPpQNC6SG3OWIG6eDlkJhw5A==} + '@nx/rollup@22.5.4': + resolution: {integrity: sha512-SM4oe2qChid6gy5YynaXavHI0J5Ugfr/Su2TLFxaXNTCB6Wb0wONGhbhGFl90rma1xhAp4SMGQYxtQaReWMi9A==} - '@nx/storybook@22.3.3': - resolution: {integrity: sha512-l4f6nOjcJm2w/rH82aBaKtJyBYOD5gXkvizQQShKro0Pykjs6eTp3rpUkttwm/iT/f2torSU54ys10YFRU5Ysg==} + '@nx/storybook@22.5.4': + resolution: {integrity: sha512-ygzcYyy7XlNM9piKM12Micx95SEz5aBuJSBosSz8Xtn0ZOyLkq5aeSOG10lqWf1keTTNsXZ7j2ZFGeQHRse5cg==} peerDependencies: storybook: '>=7.0.0 <11.0.0' - '@nx/vite@22.3.3': - resolution: {integrity: sha512-JYtQeKJVID6Am65M1gDxCBLyO7pA6p/dBxnQyWEHsbJ5VLiOyCxr+W+YOE4p4roVlQxjAaCMqvtGH3cWnNQWxg==} + '@nx/vite@22.5.4': + resolution: {integrity: sha512-9HPaDp4SHzGFg1ABQQIsPjVFKPqLYrbIC8CLrsb4cLkK3BGMB+GSn4rTtP82rMmley0I2nHFkIzdXmbJvKcsPg==} peerDependencies: vite: ^5.0.0 || ^6.0.0 || ^7.0.0 vitest: ^1.3.1 || ^2.0.0 || ^3.0.0 || ^4.0.0 - '@nx/vitest@22.3.3': - resolution: {integrity: sha512-9BNwWadIfT5EAnEPXLM0n/ucuJ7IQyn+QRMUkUBt6wmms9f0OKMtLpiFxHIMrnQDf0eEk845jo21j7Og2cCZyA==} + '@nx/vitest@22.5.4': + resolution: {integrity: sha512-ppXeq3akwrwv0ftqeFK3VX2s9E70px5H335e81wnFtUmD/LZLB7CyGVM9cDJMTgXdQFcYq90C8fbsPgDSnoc/w==} peerDependencies: vite: ^5.0.0 || ^6.0.0 || ^7.0.0 vitest: ^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0 @@ -3378,11 +3458,11 @@ packages: vitest: optional: true - '@nx/web@22.3.3': - resolution: {integrity: sha512-0iuAxXCljxCAfQ5N4SffMuf0CuUFGJoO5nzOTqnZ60pRy+JIWZ+DXfh7bfHxTEcE3JQ6nT/hbZVLPMVNleoy7Q==} + '@nx/web@22.5.4': + resolution: {integrity: sha512-GH4+TLdFiw4RSUgPwn0KWcu6yHfMu23umidrgVgq9Dmj0fn3i/yfxvfdhMQ6aDiZr831b4tIbTQ7JLNd92ilIQ==} - '@nx/workspace@22.3.3': - resolution: {integrity: sha512-A7Qd1Yi/hp/VPvig6tV+JmlYVSA4WhckNkP1giYZoESpGLxRlpwINpd5ii3oafOlglUdEZ8AiS3X+RUg9QmCAQ==} + '@nx/workspace@22.5.4': + resolution: {integrity: sha512-TZeuCDy+VN/5zqMYxHw15HKe2Ppcb9WBOebz4bmXE206c8Aop3S9QeLfys00Uobt9ZaYh9QUeN0iFsZm7TNv0w==} '@octokit/auth-action@6.0.2': resolution: {integrity: sha512-gEBsz0QioHOMoEU7u2VMr2FfOvfJCrGc42K9rliS7LnlZJLcEMFccIiCiPpPNH+yXs7YYNKQ7lOX67ZTWn6Ysg==} @@ -3396,8 +3476,8 @@ packages: resolution: {integrity: sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==} engines: {node: '>= 20'} - '@octokit/endpoint@11.0.2': - resolution: {integrity: sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ==} + '@octokit/endpoint@11.0.3': + resolution: {integrity: sha512-FWFlNxghg4HrXkD3ifYbS/IdL/mDHjh9QcsNyhQjN8dplUoZbejsdpmuqdA76nxj2xoWPs7p8uX2SNr9rYu0Ag==} engines: {node: '>= 20'} '@octokit/graphql@9.0.3': @@ -3429,8 +3509,8 @@ packages: resolution: {integrity: sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==} engines: {node: '>= 20'} - '@octokit/request@10.0.7': - resolution: {integrity: sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA==} + '@octokit/request@10.0.8': + resolution: {integrity: sha512-SJZNwY9pur9Agf7l87ywFi14W+Hd9Jg6Ifivsd33+/bGUQIjNujdFiXII2/qSlN2ybqUHfp5xpekMEjIBTjlSw==} engines: {node: '>= 20'} '@octokit/rest@22.0.1': @@ -3440,199 +3520,193 @@ packages: '@octokit/types@16.0.0': resolution: {integrity: sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==} - '@oxc-resolver/binding-android-arm-eabi@11.16.2': - resolution: {integrity: sha512-lVJbvydLQIDZHKUb6Zs9Rq80QVTQ9xdCQE30eC9/cjg4wsMoEOg65QZPymUAIVJotpUAWJD0XYcwE7ugfxx5kQ==} + '@oxc-resolver/binding-android-arm-eabi@11.19.1': + resolution: {integrity: sha512-aUs47y+xyXHUKlbhqHUjBABjvycq6YSD7bpxSW7vplUmdzAlJ93yXY6ZR0c1o1x5A/QKbENCvs3+NlY8IpIVzg==} cpu: [arm] os: [android] - '@oxc-resolver/binding-android-arm64@11.16.2': - resolution: {integrity: sha512-fEk+g/g2rJ6LnBVPqeLcx+/alWZ/Db1UlXG+ZVivip0NdrnOzRL48PAmnxTMGOrLwsH1UDJkwY3wOjrrQltCqg==} + '@oxc-resolver/binding-android-arm64@11.19.1': + resolution: {integrity: sha512-oolbkRX+m7Pq2LNjr/kKgYeC7bRDMVTWPgxBGMjSpZi/+UskVo4jsMU3MLheZV55jL6c3rNelPl4oD60ggYmqA==} cpu: [arm64] os: [android] - '@oxc-resolver/binding-darwin-arm64@11.16.2': - resolution: {integrity: sha512-Pkbp1qi7kdUX6k3Fk1PvAg6p7ruwaWKg1AhOlDgrg2vLXjtv9ZHo7IAQN6kLj0W771dPJZWqNxoqTPacp2oYWA==} + '@oxc-resolver/binding-darwin-arm64@11.19.1': + resolution: {integrity: sha512-nUC6d2i3R5B12sUW4O646qD5cnMXf2oBGPLIIeaRfU9doJRORAbE2SGv4eW6rMqhD+G7nf2Y8TTJTLiiO3Q/dQ==} cpu: [arm64] os: [darwin] - '@oxc-resolver/binding-darwin-x64@11.16.2': - resolution: {integrity: sha512-FYCGcU1iSoPkADGLfQbuj0HWzS+0ItjDCt9PKtu2Hzy6T0dxO4Y1enKeCOxCweOlmLEkSxUlW5UPT4wvT3LnAg==} + '@oxc-resolver/binding-darwin-x64@11.19.1': + resolution: {integrity: sha512-cV50vE5+uAgNcFa3QY1JOeKDSkM/9ReIcc/9wn4TavhW/itkDGrXhw9jaKnkQnGbjJ198Yh5nbX/Gr2mr4Z5jQ==} cpu: [x64] os: [darwin] - '@oxc-resolver/binding-freebsd-x64@11.16.2': - resolution: {integrity: sha512-1zHCoK6fMcBjE54P2EG/z70rTjcRxvyKfvk4E/QVrWLxNahuGDFZIxoEoo4kGnnEcmPj41F0c2PkrQbqlpja5g==} + '@oxc-resolver/binding-freebsd-x64@11.19.1': + resolution: {integrity: sha512-xZOQiYGFxtk48PBKff+Zwoym7ScPAIVp4c14lfLxizO2LTTTJe5sx9vQNGrBymrf/vatSPNMD4FgsaaRigPkqw==} cpu: [x64] os: [freebsd] - '@oxc-resolver/binding-linux-arm-gnueabihf@11.16.2': - resolution: {integrity: sha512-+ucLYz8EO5FDp6kZ4o1uDmhoP+M98ysqiUW4hI3NmfiOJQWLrAzQjqaTdPfIOzlCXBU9IHp5Cgxu6wPjVb8dbA==} + '@oxc-resolver/binding-linux-arm-gnueabihf@11.19.1': + resolution: {integrity: sha512-lXZYWAC6kaGe/ky2su94e9jN9t6M0/6c+GrSlCqL//XO1cxi5lpAhnJYdyrKfm0ZEr/c7RNyAx3P7FSBcBd5+A==} cpu: [arm] os: [linux] - '@oxc-resolver/binding-linux-arm-musleabihf@11.16.2': - resolution: {integrity: sha512-qq+TpNXyw1odDgoONRpMLzH4hzhwnEw55398dL8rhKGvvYbio71WrJ00jE+hGlEi7H1Gkl11KoPJRaPlRAVGPw==} + '@oxc-resolver/binding-linux-arm-musleabihf@11.19.1': + resolution: {integrity: sha512-veG1kKsuK5+t2IsO9q0DErYVSw2azvCVvWHnfTOS73WE0STdLLB7Q1bB9WR+yHPQM76ASkFyRbogWo1GR1+WbQ==} cpu: [arm] os: [linux] - '@oxc-resolver/binding-linux-arm64-gnu@11.16.2': - resolution: {integrity: sha512-xlMh4gNtplNQEwuF5icm69udC7un0WyzT5ywOeHrPMEsghKnLjXok2wZgAA7ocTm9+JsI+nVXIQa5XO1x+HPQg==} + '@oxc-resolver/binding-linux-arm64-gnu@11.19.1': + resolution: {integrity: sha512-heV2+jmXyYnUrpUXSPugqWDRpnsQcDm2AX4wzTuvgdlZfoNYO0O3W2AVpJYaDn9AG4JdM6Kxom8+foE7/BcSig==} cpu: [arm64] os: [linux] - '@oxc-resolver/binding-linux-arm64-musl@11.16.2': - resolution: {integrity: sha512-OZs33QTMi0xmHv/4P0+RAKXJTBk7UcMH5tpTaCytWRXls/DGaJ48jOHmriQGK2YwUqXl+oneuNyPOUO0obJ+Hg==} + '@oxc-resolver/binding-linux-arm64-musl@11.19.1': + resolution: {integrity: sha512-jvo2Pjs1c9KPxMuMPIeQsgu0mOJF9rEb3y3TdpsrqwxRM+AN6/nDDwv45n5ZrUnQMsdBy5gIabioMKnQfWo9ew==} cpu: [arm64] os: [linux] - '@oxc-resolver/binding-linux-ppc64-gnu@11.16.2': - resolution: {integrity: sha512-UVyuhaV32dJGtF6fDofOcBstg9JwB2Jfnjfb8jGlu3xcG+TsubHRhuTwQ6JZ1sColNT1nMxBiu7zdKUEZi1kwg==} + '@oxc-resolver/binding-linux-ppc64-gnu@11.19.1': + resolution: {integrity: sha512-vLmdNxWCdN7Uo5suays6A/+ywBby2PWBBPXctWPg5V0+eVuzsJxgAn6MMB4mPlshskYbppjpN2Zg83ArHze9gQ==} cpu: [ppc64] os: [linux] - '@oxc-resolver/binding-linux-riscv64-gnu@11.16.2': - resolution: {integrity: sha512-YZZS0yv2q5nE1uL/Fk4Y7m9018DSEmDNSG8oJzy1TJjA1jx5HL52hEPxi98XhU6OYhSO/vC1jdkJeE8TIHugug==} + '@oxc-resolver/binding-linux-riscv64-gnu@11.19.1': + resolution: {integrity: sha512-/b+WgR+VTSBxzgOhDO7TlMXC1ufPIMR6Vj1zN+/x+MnyXGW7prTLzU9eW85Aj7Th7CCEG9ArCbTeqxCzFWdg2w==} cpu: [riscv64] os: [linux] - '@oxc-resolver/binding-linux-riscv64-musl@11.16.2': - resolution: {integrity: sha512-9VYuypwtx4kt1lUcwJAH4dPmgJySh4/KxtAPdRoX2BTaZxVm/yEXHq0mnl/8SEarjzMvXKbf7Cm6UBgptm3DZw==} + '@oxc-resolver/binding-linux-riscv64-musl@11.19.1': + resolution: {integrity: sha512-YlRdeWb9j42p29ROh+h4eg/OQ3dTJlpHSa+84pUM9+p6i3djtPz1q55yLJhgW9XfDch7FN1pQ/Vd6YP+xfRIuw==} cpu: [riscv64] os: [linux] - '@oxc-resolver/binding-linux-s390x-gnu@11.16.2': - resolution: {integrity: sha512-3gbwQ+xlL5gpyzgSDdC8B4qIM4mZaPDLaFOi3c/GV7CqIdVJc5EZXW4V3T6xwtPBOpXPXfqQLbhTnUD4SqwJtA==} + '@oxc-resolver/binding-linux-s390x-gnu@11.19.1': + resolution: {integrity: sha512-EDpafVOQWF8/MJynsjOGFThcqhRHy417sRyLfQmeiamJ8qVhSKAn2Dn2VVKUGCjVB9C46VGjhNo7nOPUi1x6uA==} cpu: [s390x] os: [linux] - '@oxc-resolver/binding-linux-x64-gnu@11.16.2': - resolution: {integrity: sha512-m0WcK0j54tSwWa+hQaJMScZdWneqE7xixp/vpFqlkbhuKW9dRHykPAFvSYg1YJ3MJgu9ZzVNpYHhPKJiEQq57Q==} + '@oxc-resolver/binding-linux-x64-gnu@11.19.1': + resolution: {integrity: sha512-NxjZe+rqWhr+RT8/Ik+5ptA3oz7tUw361Wa5RWQXKnfqwSSHdHyrw6IdcTfYuml9dM856AlKWZIUXDmA9kkiBQ==} cpu: [x64] os: [linux] - '@oxc-resolver/binding-linux-x64-musl@11.16.2': - resolution: {integrity: sha512-ZjUm3w96P2t47nWywGwj1A2mAVBI/8IoS7XHhcogWCfXnEI3M6NPIRQPYAZW4s5/u3u6w1uPtgOwffj2XIOb/g==} + '@oxc-resolver/binding-linux-x64-musl@11.19.1': + resolution: {integrity: sha512-cM/hQwsO3ReJg5kR+SpI69DMfvNCp+A/eVR4b4YClE5bVZwz8rh2Nh05InhwI5HR/9cArbEkzMjcKgTHS6UaNw==} cpu: [x64] os: [linux] - '@oxc-resolver/binding-openharmony-arm64@11.16.2': - resolution: {integrity: sha512-OFVQ2x3VenTp13nIl6HcQ/7dmhFmM9dg2EjKfHcOtYfrVLQdNR6THFU7GkMdmc8DdY1zLUeilHwBIsyxv5hkwQ==} + '@oxc-resolver/binding-openharmony-arm64@11.19.1': + resolution: {integrity: sha512-QF080IowFB0+9Rh6RcD19bdgh49BpQHUW5TajG1qvWHvmrQznTZZjYlgE2ltLXyKY+qs4F/v5xuX1XS7Is+3qA==} cpu: [arm64] os: [openharmony] - '@oxc-resolver/binding-wasm32-wasi@11.16.2': - resolution: {integrity: sha512-+O1sY3RrGyA2AqDnd3yaDCsqZqCblSTEpY7TbbaOaw0X7iIbGjjRLdrQk9StG3QSiZuBy9FdFwotIiSXtwvbAQ==} + '@oxc-resolver/binding-wasm32-wasi@11.19.1': + resolution: {integrity: sha512-w8UCKhX826cP/ZLokXDS6+milN8y4X7zidsAttEdWlVoamTNf6lhBJldaWr3ukTDiye7s4HRcuPEPOXNC432Vg==} engines: {node: '>=14.0.0'} cpu: [wasm32] - '@oxc-resolver/binding-win32-arm64-msvc@11.16.2': - resolution: {integrity: sha512-jMrMJL+fkx6xoSMFPOeyQ1ctTFjavWPOSZEKUY5PebDwQmC9cqEr4LhdTnGsOtFrWYLXlEU4xWeMdBoc/XKkOA==} + '@oxc-resolver/binding-win32-arm64-msvc@11.19.1': + resolution: {integrity: sha512-nJ4AsUVZrVKwnU/QRdzPCCrO0TrabBqgJ8pJhXITdZGYOV28TIYystV1VFLbQ7DtAcaBHpocT5/ZJnF78YJPtQ==} cpu: [arm64] os: [win32] - '@oxc-resolver/binding-win32-ia32-msvc@11.16.2': - resolution: {integrity: sha512-tl0xDA5dcQplG2yg2ZhgVT578dhRFafaCfyqMEAXq8KNpor85nJ53C3PLpfxD2NKzPioFgWEexNsjqRi+kW2Mg==} + '@oxc-resolver/binding-win32-ia32-msvc@11.19.1': + resolution: {integrity: sha512-EW+ND5q2Tl+a3pH81l1QbfgbF3HmqgwLfDfVithRFheac8OTcnbXt/JxqD2GbDkb7xYEqy1zNaVFRr3oeG8npA==} cpu: [ia32] os: [win32] - '@oxc-resolver/binding-win32-x64-msvc@11.16.2': - resolution: {integrity: sha512-M7z0xjYQq1HdJk2DxTSLMvRMyBSI4wn4FXGcVQBsbAihgXevAReqwMdb593nmCK/OiFwSNcOaGIzUvzyzQ+95w==} + '@oxc-resolver/binding-win32-x64-msvc@11.19.1': + resolution: {integrity: sha512-6hIU3RQu45B+VNTY4Ru8ppFwjVS/S5qwYyGhBotmjxfEKk41I2DlGtRfGJndZ5+6lneE2pwloqunlOyZuX/XAw==} cpu: [x64] os: [win32] - '@parcel/watcher-android-arm64@2.5.1': - resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} + '@parcel/watcher-android-arm64@2.5.6': + resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [android] - '@parcel/watcher-darwin-arm64@2.5.1': - resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} + '@parcel/watcher-darwin-arm64@2.5.6': + resolution: {integrity: sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [darwin] - '@parcel/watcher-darwin-x64@2.5.1': - resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} + '@parcel/watcher-darwin-x64@2.5.6': + resolution: {integrity: sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [darwin] - '@parcel/watcher-freebsd-x64@2.5.1': - resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} + '@parcel/watcher-freebsd-x64@2.5.6': + resolution: {integrity: sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [freebsd] - '@parcel/watcher-linux-arm-glibc@2.5.1': - resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} + '@parcel/watcher-linux-arm-glibc@2.5.6': + resolution: {integrity: sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - '@parcel/watcher-linux-arm-musl@2.5.1': - resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} + '@parcel/watcher-linux-arm-musl@2.5.6': + resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - '@parcel/watcher-linux-arm64-glibc@2.5.1': - resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} + '@parcel/watcher-linux-arm64-glibc@2.5.6': + resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - '@parcel/watcher-linux-arm64-musl@2.5.1': - resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} + '@parcel/watcher-linux-arm64-musl@2.5.6': + resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - '@parcel/watcher-linux-x64-glibc@2.5.1': - resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} + '@parcel/watcher-linux-x64-glibc@2.5.6': + resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - '@parcel/watcher-linux-x64-musl@2.5.1': - resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} + '@parcel/watcher-linux-x64-musl@2.5.6': + resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - '@parcel/watcher-win32-arm64@2.5.1': - resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} + '@parcel/watcher-win32-arm64@2.5.6': + resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [win32] - '@parcel/watcher-win32-ia32@2.5.1': - resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} + '@parcel/watcher-win32-ia32@2.5.6': + resolution: {integrity: sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==} engines: {node: '>= 10.0.0'} cpu: [ia32] os: [win32] - '@parcel/watcher-win32-x64@2.5.1': - resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} + '@parcel/watcher-win32-x64@2.5.6': + resolution: {integrity: sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [win32] - '@parcel/watcher@2.5.1': - resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} + '@parcel/watcher@2.5.6': + resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==} engines: {node: '>= 10.0.0'} - '@phenomnomnominal/tsquery@5.0.1': - resolution: {integrity: sha512-3nVv+e2FQwsW8Aw6qTU6f+1rfcJ3hrcnvH/mu9i8YhxO+9sqbOfpL8m6PbET5+xKOlz/VSbp0RoYWYCtIsnmuA==} + '@phenomnomnominal/tsquery@6.1.4': + resolution: {integrity: sha512-3tHlGy/fxjJCHqIV8nelAzbRTNkCUY+k7lqBGKNuQz99H2OKGRt6oU+U2SZs6LYrbOe8mxMFl6kq6gzHapFRkw==} peerDependencies: typescript: ^3 || ^4 || ^5 - '@pivanov/utils@0.0.2': - resolution: {integrity: sha512-q9CN0bFWxWgMY5hVVYyBgez1jGiLBa6I+LkG37ycylPhFvEGOOeaADGtUSu46CaZasPnlY8fCdVJZmrgKb1EPA==} - peerDependencies: - react: '>=18' - react-dom: '>=18' - '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -3641,11 +3715,11 @@ packages: resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@preact/signals-core@1.12.1': - resolution: {integrity: sha512-BwbTXpj+9QutoZLQvbttRg5x3l5468qaV2kufh+51yha1c53ep5dY4kTuZR35+3pAZxpfQerGJiQqg34ZNZ6uA==} + '@preact/signals-core@1.13.0': + resolution: {integrity: sha512-slT6XeTCAbdql61GVLlGU4x7XHI7kCZV5Um5uhE4zLX4ApgiiXc0UYFvVOKq06xcovzp7p+61l68oPi563ARKg==} - '@preact/signals@1.3.2': - resolution: {integrity: sha512-naxcJgUJ6BTOROJ7C3QML7KvwKwCXQJYTc5L/b0eEsdYgPB6SxwoQ1vDGcS0Q7GVjAenVq/tXrybVdFShHYZWg==} + '@preact/signals@1.3.4': + resolution: {integrity: sha512-TPMkStdT0QpSc8FpB63aOwXoSiZyIrPsP9Uj347KopdS6olZdAYeeird/5FZv/M1Yc1ge5qstub2o8VDbvkT4g==} peerDependencies: preact: 10.x @@ -3663,134 +3737,171 @@ packages: prisma: optional: true - '@react-aria/autocomplete@3.0.0-rc.4': - resolution: {integrity: sha512-4bMMVNaCuYDZX9HM4ZNSAImZMcL/orwhLLe818+lyzmSrvGmW9h433PZxTolb0d+FnJVfn1MDY0zEWLiyI86GA==} + '@prisma/config@7.4.2': + resolution: {integrity: sha512-CftBjWxav99lzY1Z4oDgomdb1gh9BJFAOmWF6P2v1xRfXqQb56DfBub+QKcERRdNoAzCb3HXy3Zii8Vb4AsXhg==} + + '@prisma/debug@7.2.0': + resolution: {integrity: sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw==} + + '@prisma/debug@7.4.2': + resolution: {integrity: sha512-aP7qzu+g/JnbF6U69LMwHoUkELiserKmWsE2shYuEpNUJ4GrtxBCvZwCyCBHFSH2kLTF2l1goBlBh4wuvRq62w==} + + '@prisma/dev@0.20.0': + resolution: {integrity: sha512-ovlBYwWor0OzG+yH4J3Ot+AneD818BttLA+Ii7wjbcLHUrnC4tbUPVGyNd3c/+71KETPKZfjhkTSpdS15dmXNQ==} + + '@prisma/engines-version@7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919': + resolution: {integrity: sha512-5FIKY3KoYQlBuZC2yc16EXfVRQ8HY+fLqgxkYfWCtKhRb3ajCRzP/rPeoSx11+NueJDANdh4hjY36mdmrTcGSg==} + + '@prisma/engines@7.4.2': + resolution: {integrity: sha512-B+ZZhI4rXlzjVqRw/93AothEKOU5/x4oVyJFGo9RpHPnBwaPwk4Pi0Q4iGXipKxeXPs/dqljgNBjK0m8nocOJA==} + + '@prisma/fetch-engine@7.4.2': + resolution: {integrity: sha512-f/c/MwYpdJO7taLETU8rahEstLeXfYgQGlz5fycG7Fbmva3iPdzGmjiSWHeSWIgNnlXnelUdCJqyZnFocurZuA==} + + '@prisma/get-platform@7.2.0': + resolution: {integrity: sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA==} + + '@prisma/get-platform@7.4.2': + resolution: {integrity: sha512-UTnChXRwiauzl/8wT4hhe7Xmixja9WE28oCnGpBtRejaHhvekx5kudr3R4Y9mLSA0kqGnAMeyTiKwDVMjaEVsw==} + + '@prisma/query-plan-executor@7.2.0': + resolution: {integrity: sha512-EOZmNzcV8uJ0mae3DhTsiHgoNCuu1J9mULQpGCh62zN3PxPTd+qI9tJvk5jOst8WHKQNwJWR3b39t0XvfBB0WQ==} + + '@prisma/studio-core@0.13.1': + resolution: {integrity: sha512-agdqaPEePRHcQ7CexEfkX1RvSH9uWDb6pXrZnhCRykhDFAV0/0P3d07WtfiY8hZWb7oRU4v+NkT4cGFHkQJIPg==} + peerDependencies: + '@types/react': ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + + '@react-aria/autocomplete@3.0.0-rc.6': + resolution: {integrity: sha512-uymUNJ8NW+dX7lmgkHE+SklAbxwktycAJcI5lBBw6KPZyc0EdMHC+/Fc5CUz3enIAhNwd2oxxogcSHknquMzQA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/breadcrumbs@3.5.30': - resolution: {integrity: sha512-DZymglA70SwvDJA7GB147sUexvdDy6vWcriGrlEHhMMzBLhGB30I5J96R4pPzURLxXISrWFH56KC5rRgIqsqqg==} + '@react-aria/breadcrumbs@3.5.32': + resolution: {integrity: sha512-S61vh5DJ2PXiXUwD7gk+pvS/b4VPrc3ZJOUZ0yVRLHkVESr5LhIZH+SAVgZkm1lzKyMRG+BH+fiRH/DZRSs7SA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/button@3.14.3': - resolution: {integrity: sha512-iJTuEECs9im7TwrCRZ0dvuwp8Gao0+I1IuYs1LQvJQgKLpgRH2/6jAiqb2bdAcoAjdbaMs7Xe0xUwURpVNkEyA==} + '@react-aria/button@3.14.5': + resolution: {integrity: sha512-ZuLx+wQj9VQhH9BYe7t0JowmKnns2XrFHFNvIVBb5RwxL+CIycIOL7brhWKg2rGdxvlOom7jhVbcjSmtAaSyaQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/calendar@3.9.3': - resolution: {integrity: sha512-F12UQ4zd8GIxpJxs9GAHzDD9Lby2hESHm0LF5tjsYBIOBJc5K7ICeeE5UqLMBPzgnEP5nfh1CKS8KhCB0mS7PA==} + '@react-aria/calendar@3.9.5': + resolution: {integrity: sha512-k0kvceYdZZu+DoeqephtlmIvh1CxqdFyoN52iqVzTz9O0pe5Xfhq7zxPGbeCp4pC61xzp8Lu/6uFA/YNfQQNag==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/checkbox@3.16.3': - resolution: {integrity: sha512-2p1haCUtERo5XavBAWNaX//dryNVnOOWfSKyzLs4UiCZR/NL0ttN+Nu/i445q0ipjLqZ6bBJtx0g0NNrubbU7Q==} + '@react-aria/checkbox@3.16.5': + resolution: {integrity: sha512-ZhUT7ELuD52hb+Zpzw0ElLQiVOd5sKYahrh+PK3vq13Wk5TedBscALpjuXetI4pwFfdmAM1Lhgcsrd8+6AmyvA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/collections@3.0.1': - resolution: {integrity: sha512-C8KBQGXzVefR4I+hQmkb10t09Jt1Ivl12qgQKshmT0hV2yBESXEYWMZUxV4ggOgWDreAgCtr+Ho3X+7MzBQT8Q==} + '@react-aria/collections@3.0.3': + resolution: {integrity: sha512-lbC5DEbHeVFvVr4ke9y8D9Nynnr8G8UjVEBoFGRylpAaScU7SX1TN84QI+EjMbsdZ0/5P2H7gUTS+MYd+6U3Rg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/color@3.1.3': - resolution: {integrity: sha512-EHzsFbqzFrO1/3irEa8E8wawlQg7hRd4/Jscvl9zhplAcrWFd6L5TWl8463Z6h0J6zN1eH9T2QDEn6rivDLkkg==} + '@react-aria/color@3.1.5': + resolution: {integrity: sha512-eysWdBRzE8WDhBzh1nfjyUgzseMokXGHjIoJo880T7IPJ8tTavfQni49pU1B2qWrNOWPyrwx4Bd9pzHyboxJSA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/combobox@3.14.1': - resolution: {integrity: sha512-wuP/4UQrGsYXLw1Gk8G/FcnUlHuoViA9G6w3LhtUgu5Q3E5DvASJalxej3NtyYU+4w4epD1gJidzosAL0rf8Ug==} + '@react-aria/combobox@3.15.0': + resolution: {integrity: sha512-qSjQTFwKl3x1jCP2NRSJ6doZqAp6c2GTfoiFwWjaWg1IewwLsglaW6NnzqRDFiqFbDGgXPn4MqtC1VYEJ3NEjA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/datepicker@3.15.3': - resolution: {integrity: sha512-0KkLYeLs+IubHXb879n8dzzKU/NWcxC9DXtv7M/ofL7vAvMSTmaceYJcMW+2gGYhJVpyYz8B6bk0W7kTxgB3jg==} + '@react-aria/datepicker@3.16.1': + resolution: {integrity: sha512-6BltCVWt09yefTkGjb2gViGCwoddx9HKJiZbY9u6Es/Q+VhwNJQRtczbnZ3K32p262hIknukNf/5nZaCOI1AKA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/dialog@3.5.32': - resolution: {integrity: sha512-2puMjsJS2FtB8LiFuQDAdBSU4dt3lqdJn4FWt/8GL6l91RZBqp2Dnm5Obuee6rV2duNJZcSAUWsQZ/S1iW8Y2g==} + '@react-aria/dialog@3.5.34': + resolution: {integrity: sha512-/x53Q5ynpW5Kv9637WYu7SrDfj3woSp6jJRj8l6teGnWW/iNZWYJETgzHfbxx+HPKYATCZesRoIeO2LnYIXyEA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/disclosure@3.1.1': - resolution: {integrity: sha512-4k8Y3CZEl+Qhou0fH7Sj7BbzvwAfi1JDL+hG7U20ZL5+MJ/VbDYuYX2gYK2KqdlbeuuzGcov3ZFQbyIVHMY+/A==} + '@react-aria/disclosure@3.1.3': + resolution: {integrity: sha512-S3k7Wqrj+x0sWcP88Z1stSr5TIZmKEmx2rU7RB1O1/jPpbw5mgKnjtiriOlTh+kwdK11FkeqgxyHzAcBAR+FMQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/dnd@3.11.4': - resolution: {integrity: sha512-dBrnM33Kmk76F+Pknh2WfSLIX4dsYwFzWJUIABJCPmPc80hTG0so7mfqH45ba759/6ERMfXXoodZPLtypOjYPg==} + '@react-aria/dnd@3.11.6': + resolution: {integrity: sha512-4YLHUeYJleF+moAYaYt8UZqujudPvpoaHR+QMkWIFzhfridVUhCr6ZjGWrzpSZY3r68k46TG7YCsi4IEiNnysw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/focus@3.21.3': - resolution: {integrity: sha512-FsquWvjSCwC2/sBk4b+OqJyONETUIXQ2vM0YdPAuC+QFQh2DT6TIBo6dOZVSezlhudDla69xFBd6JvCFq1AbUw==} + '@react-aria/focus@3.21.5': + resolution: {integrity: sha512-V18fwCyf8zqgJdpLQeDU5ZRNd9TeOfBbhLgmX77Zr5ae9XwaoJ1R3SFJG1wCJX60t34AW+aLZSEEK+saQElf3Q==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/form@3.1.3': - resolution: {integrity: sha512-HAKnPjMiqTxoGLVbfZyGYcZQ1uu6aSeCi9ODmtZuKM5DWZZnTUjDmM1i2L6IXvF+d1kjyApyJC7VTbKZ8AI77g==} + '@react-aria/form@3.1.5': + resolution: {integrity: sha512-BWlONgHn8hmaMkcS6AgMSLQeNqVBwqPNLhdqjDO/PCfzvV7O8NZw/dFeIzJwfG4aBfSpbHHRdXGdfrk3d8dylQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/grid@3.14.6': - resolution: {integrity: sha512-xagBKHNPu4Ovt/I5He7T/oIEq82MDMSrRi5Sw3oxSCwwtZpv+7eyKRSrFz9vrNUzNgWCcx5VHLE660bLdeVNDQ==} + '@react-aria/grid@3.14.8': + resolution: {integrity: sha512-X6rRFKDu/Kh6Sv8FBap3vjcb+z4jXkSOwkYnexIJp5kMTo5/Dqo55cCBio5B70Tanfv32Ev/6SpzYG7ryxnM9w==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/gridlist@3.14.2': - resolution: {integrity: sha512-c51ip0bc/lKppfrPNFHbWu1n/r0NHd9Xl114904cDxuRcElJ3H/V/3e3U9HyDy+4xioiXZIdZ75CNxtEoTmrxw==} + '@react-aria/gridlist@3.14.4': + resolution: {integrity: sha512-C/SbwC0qagZatoBrCjx8iZUex9apaJ8o8iRJ9eVHz0cpj7mXg6HuuotYGmDy9q67A2hve4I693RM1Cuwqwm+PQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/i18n@3.12.14': - resolution: {integrity: sha512-zYvs1FlLamFD49uneX3i5mPHrAsB3OjVpSWApTcPw8ydxOaphQDp/Q1aqrbcxlrQCcxZdXWHuvLlbkNR4+8jzw==} + '@react-aria/i18n@3.12.16': + resolution: {integrity: sha512-Km2CAz6MFQOUEaattaW+2jBdWOHUF8WX7VQoNbjlqElCP58nSaqi9yxTWUDRhAcn8/xFUnkFh4MFweNgtrHuEA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/interactions@3.26.0': - resolution: {integrity: sha512-AAEcHiltjfbmP1i9iaVw34Mb7kbkiHpYdqieWufldh4aplWgsF11YQZOfaCJW4QoR2ML4Zzoa9nfFwLXA52R7Q==} + '@react-aria/interactions@3.27.1': + resolution: {integrity: sha512-M3wLpTTmDflI0QGNK0PJNUaBXXfeBXue8ZxLMngfc1piHNiH4G5lUvWd9W14XVbqrSCVY8i8DfGrNYpyyZu0tw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/label@3.7.23': - resolution: {integrity: sha512-dRkuCJfsyBHPTq3WOJVHNRvNyQL4cRRLELmjYfUX9/jQKIsUW2l71YnUHZTRCSn2ZjhdAcdwq96fNcQo0hncBQ==} + '@react-aria/label@3.7.25': + resolution: {integrity: sha512-oNK3Pqj4LDPwEbQaoM/uCip4QvQmmwGOh08VeW+vzSi6TAwf+KoWTyH/tiAeB0CHWNDK0k3e1iTygTAt4wzBmg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/landmark@3.0.8': - resolution: {integrity: sha512-xuY8kYxCrF9C0h0Pj2lZHoxCidNfQ/SrkYWXuiN+LuBTJGCmPVif93gt7TklQ0rKJ+pKJsUgh8AC0pgwI3QP7A==} + '@react-aria/landmark@3.0.10': + resolution: {integrity: sha512-GpNjJaI8/a6WxYDZgzTCLYSzPM6xp2pxCIQ4udiGbTCtxx13Trmm0cPABvPtzELidgolCf05em9Phr+3G0eE8A==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/link@3.8.7': - resolution: {integrity: sha512-TOC6Hf/x3N0P8SLR1KD/dGiJ9PmwAq8H57RiwbFbdINnG/HIvIQr5MxGTjwBvOOWcJu9brgWL5HkQaZK7Q/4Yw==} + '@react-aria/link@3.8.9': + resolution: {integrity: sha512-UaAFBfs84/Qq6TxlMWkREqqNY6SFLukot+z2Aa1kC+VyStv1kWG6sE5QLjm4SBn1Q3CGRsefhB/5+taaIbB4Pw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/listbox@3.15.1': - resolution: {integrity: sha512-81iDLFhmPXvLOtkI0SKzgrngfzwfR2o9oFDAYRfpYCOxgT7jjh8SaB4wCteJXRiMwymRGmgyTvD4yxWTluEeXA==} + '@react-aria/listbox@3.15.3': + resolution: {integrity: sha512-C6YgiyrHS5sbS5UBdxGMhEs+EKJYotJgGVtl9l0ySXpBUXERiHJWLOyV7a8PwkUOmepbB4FaLD7Y9EUzGkrGlw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 @@ -3798,74 +3909,74 @@ packages: '@react-aria/live-announcer@3.4.4': resolution: {integrity: sha512-PTTBIjNRnrdJOIRTDGNifY2d//kA7GUAwRFJNOEwSNG4FW+Bq9awqLiflw0JkpyB0VNIwou6lqKPHZVLsGWOXA==} - '@react-aria/menu@3.19.4': - resolution: {integrity: sha512-0A0DUEkEvZynmaD3zktHavM+EmgZSR/ht+g1ExS2jXe73CegA+dbSRfPl9eIKcHxaRrWOV96qMj2pTf0yWTBDg==} + '@react-aria/menu@3.21.0': + resolution: {integrity: sha512-CKTVZ4izSE1eKIti6TbTtzJAUo+WT8O4JC0XZCYDBpa0f++lD19Kz9aY+iY1buv5xGI20gAfpO474E9oEd4aQA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/meter@3.4.28': - resolution: {integrity: sha512-elACITUBOf4Dp+BQ2aIgHIe58fjWYjspxhVcE5BMiqePktOfRkpb9ESj8nWcNXO8eqCYwrFJpElHvXkjYLWemw==} + '@react-aria/meter@3.4.30': + resolution: {integrity: sha512-ZmANKW7s/Z4QGylHi46nhwtQ47T1bfMsU9MysBu7ViXXNJ03F4b6JXCJlKL5o2goQ3NbfZ68GeWamIT0BWSgtw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/numberfield@3.12.3': - resolution: {integrity: sha512-70LRXWPEuj2X8mbQXUx6l6We+RGs49Kb+2eUiSSLArHK4RvTWJWEfSjHL5IHHJ+j2AkbORdryD7SR3gcXSX+5w==} + '@react-aria/numberfield@3.12.5': + resolution: {integrity: sha512-Fi41IUWXEHLFIeJ/LHuZ9Azs8J/P563fZi37GSBkIq5P1pNt1rPgJJng5CNn4KsHxwqadTRUlbbZwbZraWDtRg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/overlays@3.31.0': - resolution: {integrity: sha512-Vq41X1s8XheGIhGbbuqRJslJEX08qmMVX//dwuBaFX9T18mMR04tumKOMxp8Lz+vqwdGLvjNUYDMcgolL+AMjw==} + '@react-aria/overlays@3.31.2': + resolution: {integrity: sha512-78HYI08r6LvcfD34gyv19ArRIjy1qxOKuXl/jYnjLDyQzD4pVb634IQWcm0zt10RdKgyuH6HTqvuDOgZTLet7Q==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/progress@3.4.28': - resolution: {integrity: sha512-3NUUAu+rwf1M7pau9WFkrxe/PlBPiqCl/1maGU7iufVveHnz+SVVqXdNkjYx+WkPE0ViwG86Zx6OU4AYJ1pjNw==} + '@react-aria/progress@3.4.30': + resolution: {integrity: sha512-S6OWVGgluSWYSd/A6O8CVjz83eeMUfkuWSra0ewAV9bmxZ7TP9pUmD3bGdqHZEl97nt5vHGjZ3eq/x8eCmzKhA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/radio@3.12.3': - resolution: {integrity: sha512-noucVX++9J3VYWg7dB+r09NVX8UZSR1TWUMCbT/MffzhltOsmiLJVvgJ0uEeeVRuu3+ZM63jOshrzG89anX4TQ==} + '@react-aria/radio@3.12.5': + resolution: {integrity: sha512-8CCJKJzfozEiWBPO9QAATG1rBGJEJ+xoqvHf9LKU2sPFGsA2/SRnLs6LB9fCG5R3spvaK1xz0any1fjWPl7x8A==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/searchfield@3.8.10': - resolution: {integrity: sha512-1wMoSjXoekcETC4ZP5AUcWoaK96FssVuF9MgqQNqE5VnauQDjZBpPCfz6GSZwRHTGwoqb7CI4iEi7433kd50xg==} + '@react-aria/searchfield@3.8.12': + resolution: {integrity: sha512-kYlUHD/+mWzNroHoR8ojUxYBoMviRZn134WaKPFjfNUGZDOEuh4XzOoj+cjdJfe6N3mwTaYu6rJQtunSHIAfhA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/select@3.17.1': - resolution: {integrity: sha512-jPMuaSp+4SbdE9G5UrrTer2CPbbUnUSLd8I2wgRgGcyk3wFw9DtnUNfms+UBA/2SrVnAEJ6KCQAI0oiMK2m+tQ==} + '@react-aria/select@3.17.3': + resolution: {integrity: sha512-u0UFWw0S7q9oiSbjetDpRoLLIcC+L89uYlm+YfCrdT8ntbQgABNiJRxdVvxnhR0fR6MC9ASTTvuQnNHNn52+1A==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/selection@3.27.0': - resolution: {integrity: sha512-4zgreuCu4QM4t2U7aF3mbMvIKCEkTEo6h6nGJvbyZALZ/eFtLTvUiV8/5CGDJRLGvgMvi3XxUeF9PZbpk5nMJg==} + '@react-aria/selection@3.27.2': + resolution: {integrity: sha512-GbUSSLX/ciXix95KW1g+SLM9np7iXpIZrFDSXkC6oNx1uhy18eAcuTkeZE25+SY5USVUmEzjI3m/3JoSUcebbg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/separator@3.4.14': - resolution: {integrity: sha512-a32OB5HMAmXEdExyDvsadsnlmNcVxxpx3tt+Jxxl6H9CHsLO+Ak077KGFJteGVg4bTfhWGAgczOsnvIioR88xw==} + '@react-aria/separator@3.4.16': + resolution: {integrity: sha512-RCUtQhDGnPxKzyG8KM79yOB0fSiEf8r/rxShidOVnGLiBW2KFmBa22/Gfc4jnqg/keN3dxvkSGoqmeXgctyp6g==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/slider@3.8.3': - resolution: {integrity: sha512-tOZVH+wLt3ik0C3wyuXqHL9fvnQ5S+/tHMYB7z8aZV5cEe36Gt4efBILphlA7ChkL/RvpHGK2AGpEGxvuEQIuQ==} + '@react-aria/slider@3.8.5': + resolution: {integrity: sha512-gqkJxznk141mE0JamXF5CXml9PDbPkBz8dyKlihtWHWX4yhEbVYdC9J0otE7iCR3zx69Bm7WHoTGL0BsdpKzVA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/spinbutton@3.7.0': - resolution: {integrity: sha512-FOyH94BZp+jNhUJuZqXSubQZDNQEJyW/J19/gwCxQvQvxAP79dhDFshh1UtrL4EjbjIflmaOes+sH/XEHUnJVA==} + '@react-aria/spinbutton@3.7.2': + resolution: {integrity: sha512-adjE1wNCWlugvAtVXlXWPtIG9JWurEgYVn1Eeyh19x038+oXGvOsOAoKCXM+SnGleTWQ9J7pEZITFoEI3cVfAw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 @@ -3876,80 +3987,80 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/switch@3.7.9': - resolution: {integrity: sha512-RZtuFRXews0PBx8Fc2R/kqaIARD5YIM5uYtmwnWfY7y5bEsBGONxp0d+m2vDyY7yk+VNpVFBdwewY9GbZmH1CA==} + '@react-aria/switch@3.7.11': + resolution: {integrity: sha512-dYVX71HiepBsKyeMaQgHbhqI+MQ3MVoTd5EnTbUjefIBnmQZavYj1/e4NUiUI4Ix+/C0HxL8ibDAv4NlSW3eLQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/table@3.17.9': - resolution: {integrity: sha512-Jby561E1YfzoRgtp+RQuhDz4vnxlcqol9RTgQQ7FWXC2IcN9Pny1COU34LkA1cL9VeB9LJ0+qfMhGw4aAwaUmw==} + '@react-aria/table@3.17.11': + resolution: {integrity: sha512-GkYmWPiW3OM+FUZxdS33teHXHXde7TjHuYgDDaG9phvg6cQTQjGilJozrzA3OfftTOq5VB8XcKTIQW3c0tpYsQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/tabs@3.10.9': - resolution: {integrity: sha512-2+FNd7Ohr3hrEgYrKdZW0FWbgybzTVZft6tw95oQ2+9PnjdDVdtzHliI+8HY8jzb4hTf4bU7O8n+s/HBlCBSIw==} + '@react-aria/tabs@3.11.1': + resolution: {integrity: sha512-3Ppz7yaEDW9L7p9PE9yNOl5caLwNnnLQqI+MX/dwbWlw9HluHS7uIjb21oswNl6UbSxAWyENOka45+KN4Fkh7A==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/tag@3.7.3': - resolution: {integrity: sha512-fonqGFxhpnlIDOz3u38y4+MG5wyAef9+oDybsCKaJ57K+D4BTvSmpGBemN/mcaxdabnYfyhasCm0H91Q9XRcCA==} + '@react-aria/tag@3.8.1': + resolution: {integrity: sha512-VonpO++F8afXGDWc9VUxAc2wefyJpp1n9OGpbnB7zmqWiuPwO/RixjUdcH7iJkiC4vADwx9uLnhyD6kcwGV2ig==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/textfield@3.18.3': - resolution: {integrity: sha512-ehiSHOKuKCwPdxFe7wGE0QJlSeeJR4iJuH+OdsYVlZzYbl9J/uAdGbpsj/zPhNtBo1g/Td76U8TtTlYRZ8lUZw==} + '@react-aria/textfield@3.18.5': + resolution: {integrity: sha512-ttwVSuwoV3RPaG2k2QzEXKeQNQ3mbdl/2yy6I4Tjrn1ZNkYHfVyJJ26AjenfSmj1kkTQoSAfZ8p+7rZp4n0xoQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/toast@3.0.9': - resolution: {integrity: sha512-2sRitczXl5VEwyq97o8TVvq3bIqLA7EfA7dhDPkYlHGa4T1vzKkhNqgkskKd9+Tw7gqeFRFjnokh+es9jkM11g==} + '@react-aria/toast@3.0.11': + resolution: {integrity: sha512-2DjZjBAvm8/CWbnZ6s7LjkYCkULKtjMve6GvhPTq98AthuEDLEiBvM1wa3xdecCRhZyRT1g6DXqVca0EfZ9fJA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/toggle@3.12.3': - resolution: {integrity: sha512-mciUbeVP99fRObnH5qLFrkKXX+5VKeV6BhFJlmz1eo3ltR/0xZKnUcycA2CGzmqtB70w09CAhr8NMEnpNH8dwQ==} + '@react-aria/toggle@3.12.5': + resolution: {integrity: sha512-XXVFLzcV8fr9mz7y/wfxEAhWvaBZ9jSfhCMuxH2bsivO7nTcMJ1jb4g2xJNwZgne17bMWNc7mKvW5dbsdlI6BA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/toolbar@3.0.0-beta.22': - resolution: {integrity: sha512-Q1gOj6N4vzvpGrIoNAxpUudEQP82UgQACENH/bcH8FnEMbSP7DHvVfDhj7GTU6ldMXO2cjqLhiidoUK53gkCiA==} + '@react-aria/toolbar@3.0.0-beta.24': + resolution: {integrity: sha512-B2Rmpko7Ghi2RbNfsGdbR7I+RQBDhPGVE4bU3/EwHz+P/vNe5LyGPTeSwqaOMsQTF9lKNCkY8424dVTCr6RUMg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/tooltip@3.9.0': - resolution: {integrity: sha512-2O1DXEV8/+DeUq9dIlAfaNa7lSG+7FCZDuF+sNiPYnZM6tgFOrsId26uMF5EuwpVfOvXSSGnq0+6Ma2On7mZPg==} + '@react-aria/tooltip@3.9.2': + resolution: {integrity: sha512-VrgkPwHiEnAnBhoQ4W7kfry/RfVuRWrUPaJSp0+wKM6u0gg2tmn7OFRDXTxBAm/omQUguIdIjRWg7sf3zHH82A==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/tree@3.1.5': - resolution: {integrity: sha512-FAq7pAhRVrWU0U/8QbQIJfBqHuoCD+F9rR9ruoM3oL0vVIZxVN57ak/dhyge3EGlraTl9vzFi6IRceXiMuk5kg==} + '@react-aria/tree@3.1.7': + resolution: {integrity: sha512-C54yH5NmsOFa2Q+cg6B1BPr5KUlU9vLIoBnVrgrH237FRSXQPIbcM4VpmITAHq1VR7w6ayyS1hgTwFxo67ykWQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/utils@3.32.0': - resolution: {integrity: sha512-/7Rud06+HVBIlTwmwmJa2W8xVtgxgzm0+kLbuFooZRzKDON6hhozS1dOMR/YLMxyJOaYOTpImcP4vRR9gL1hEg==} + '@react-aria/utils@3.33.1': + resolution: {integrity: sha512-kIx1Sj6bbAT0pdqCegHuPanR9zrLn5zMRiM7LN12rgRf55S19ptd9g3ncahArifYTRkfEU9VIn+q0HjfMqS9/w==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/virtualizer@4.1.11': - resolution: {integrity: sha512-eYL//bX11Aox4Eh1BSZFX4I/4EdyVVWLjmpW+Y5qy4WajNrowjiuJJM7Fp1rQBlOAVuz0KbaDmFhiU3Z3rWjsw==} + '@react-aria/virtualizer@4.1.13': + resolution: {integrity: sha512-d5KS+p8GXGNRbGPRE/N6jtth3et3KssQIz52h2+CAoAh7C3vvR64kkTaGdeywClvM+fSo8FxJuBrdfQvqC2ktQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/visually-hidden@3.8.29': - resolution: {integrity: sha512-1joCP+MHBLd+YA6Gb08nMFfDBhOF0Kh1gR1SA8zoxEB5RMfQEEkufIB8k0GGwvHGSCK3gFyO8UAVsD0+rRYEyg==} + '@react-aria/visually-hidden@3.8.31': + resolution: {integrity: sha512-RTOHHa4n56a9A3criThqFHBifvZoV71+MCkSuNP2cKO662SUWjqKkd0tJt/mBRMEJPkys8K7Eirp6T8Wt5FFRA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 @@ -3959,142 +4070,142 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/calendar@3.9.1': - resolution: {integrity: sha512-q0Q8fivpQa1rcLg5daUVxwVj1smCp1VnpX9A5Q5PkI9lH9x+xdS0Y6eOqb8Ih3TKBDkx9/oEZonOX7RYNIzSig==} + '@react-stately/calendar@3.9.3': + resolution: {integrity: sha512-uw7fCZXoypSBBUsVkbNvJMQWTihZReRbyLIGG3o/ZM630N3OCZhb/h4Uxke4pNu7n527H0V1bAnZgAldIzOYqg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/checkbox@3.7.3': - resolution: {integrity: sha512-ve2K+uWT+NRM1JMn+tkWJDP2iBAaWvbZ0TbSXs371IUcTWaNW61HygZ+UFOB/frAZGloazEKGqAsX5XjFpgB9w==} + '@react-stately/checkbox@3.7.5': + resolution: {integrity: sha512-K5R5ted7AxLB3sDkuVAazUdyRMraFT1imVqij2GuAiOUFvsZvbuocnDuFkBVKojyV3GpqLBvViV8IaCMc4hNIw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/collections@3.12.8': - resolution: {integrity: sha512-AceJYLLXt1Y2XIcOPi6LEJSs4G/ubeYW3LqOCQbhfIgMaNqKfQMIfagDnPeJX9FVmPFSlgoCBxb1pTJW2vjCAQ==} + '@react-stately/collections@3.12.10': + resolution: {integrity: sha512-wmF9VxJDyBujBuQ76vXj2g/+bnnj8fx5DdXgRmyfkkYhPB46+g2qnjbVGEvipo7bJuGxDftCUC4SN7l7xqUWfg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/color@3.9.3': - resolution: {integrity: sha512-H5lQgl07upsI7+cxTwYo639ziDDG1DFgOtq5pmC4Nxi8uNl8sR/8YeLaYuxyJiVkj2VLHBYRQ3+JcxrdduFvPQ==} + '@react-stately/color@3.9.5': + resolution: {integrity: sha512-8pZxzXWDRuglzDwyTG7mLw2LQMCHIVNbVc9YmbsxbOjAL+lOqszo60KzyaFKVxeDQczSvrNTHcQZqlbNIC0eyQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/combobox@3.12.1': - resolution: {integrity: sha512-RwfTTYgKJ9raIY+7grZ5DbfVRSO5pDjo/ur2VN/28LZzM0eOQrLFQ00vpBmY7/R64sHRpcXLDxpz5cqpKCdvTw==} + '@react-stately/combobox@3.13.0': + resolution: {integrity: sha512-dX9g/cK1hjLRjcbWVF6keHxTQDGhKGB2QAgPhWcBmOK3qJv+2dQqsJ6YCGWn/Y2N2acoEseLrAA7+Qe4HWV9cg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/data@3.15.0': - resolution: {integrity: sha512-ocP39NQQkrbtHVCPsqltNncpEHaONyYX/8s2UK9xeLRc+55NtDI2RZDKTUf/mi6H2SHxzEwLMQH8hWtEwC55mQ==} + '@react-stately/data@3.15.2': + resolution: {integrity: sha512-BsmeeGgFwOGwo0g9Waprdyt+846n3KhKggZfpEnp5+sC4dE4uW1VIYpdyupMfr3bQcmX123q6TegfNP3eszrUA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/datepicker@3.15.3': - resolution: {integrity: sha512-RDYoz1R/EkCyxHYewb58T7DngU3gl6CnQL7xiWiDlayPnstGaanoQ3yCZGJaIQwR8PrKdNbQwXF9NlSmj8iCOw==} + '@react-stately/datepicker@3.16.1': + resolution: {integrity: sha512-BtAMDvxd1OZxkxjqq5tN5TYmp6Hm8+o3+IDA4qmem2/pfQfVbOZeWS2WitcPBImj4n4T+W1A5+PI7mT/6DUBVg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/disclosure@3.0.9': - resolution: {integrity: sha512-M3HKsXqdzYKQf1TpnQRLZ6+/b8E3Nba3oOuY0OW5NnM5dZWSnXuj8foBQJT118FdLgMjpfBdPIkUvnaGiDCs5w==} + '@react-stately/disclosure@3.0.11': + resolution: {integrity: sha512-/KjB/0HkxGWbhFAPztCP411LUKZCx9k8cKukrlGqrUWyvrcXlmza90j0g/CuxACBoV+DJP9V+4q+8ide0x750A==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/dnd@3.7.2': - resolution: {integrity: sha512-tr5nNgrLMn5GV308K1f010XUZ2j8CApqHrrcjg5fa2AnpO2gECcOf+UEnAvoFNUsvknje4iPX8y0/0No2ZHsgA==} + '@react-stately/dnd@3.7.4': + resolution: {integrity: sha512-YD0TVR5JkvTqskc1ouBpVKs6t/QS4RYCIyu8Ug8RgO122iIizuf2pfKnRLjYMdu5lXzBXGaIgd49dvnLzEXHIw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 '@react-stately/flags@3.1.2': resolution: {integrity: sha512-2HjFcZx1MyQXoPqcBGALwWWmgFVUk2TuKVIQxCbRq7fPyWXIl6VHcakCLurdtYC2Iks7zizvz0Idv48MQ38DWg==} - '@react-stately/form@3.2.2': - resolution: {integrity: sha512-soAheOd7oaTO6eNs6LXnfn0tTqvOoe3zN9FvtIhhrErKz9XPc5sUmh3QWwR45+zKbitOi1HOjfA/gifKhZcfWw==} + '@react-stately/form@3.2.4': + resolution: {integrity: sha512-qNBzun8SbLdgahryhKLqL1eqP+MXY6as82sVXYOOvUYLzgU5uuN8mObxYlxJgMI5akSdQJQV3RzyfVobPRE7Kw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/grid@3.11.7': - resolution: {integrity: sha512-SqzBSxUTFZKLZicfXDK+M0A3gh07AYK1pmU/otcq2cjZ0nSC4CceKijQ2GBZnl+YGcGHI1RgkhpLP6ZioMYctQ==} + '@react-stately/grid@3.11.9': + resolution: {integrity: sha512-qQY6F+27iZRn30dt0ZOrSetUmbmNJ0pLe9Weuqw3+XDVSuWT+2O/rO1UUYeK+mO0Acjzdv+IWiYbu9RKf2wS9w==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/layout@4.5.2': - resolution: {integrity: sha512-quAzYkshApkv1vChz2NXBaLTC7ihJUmv3ijqJBHCkZSY6qq+1qnc4aGespDF1f3mPhmpGswTFGXFImFTAYfi5g==} + '@react-stately/layout@4.6.0': + resolution: {integrity: sha512-kBenEsP03nh5rKgfqlVMPcoKTJv0v92CTvrAb5gYY8t9g8LOwzdL89Yannq7f5xv8LFck/MmRQlotpMt2InETg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/list@3.13.2': - resolution: {integrity: sha512-dGFALuQWNNOkv7W12qSsXLF4mJHLeWeK2hVvdyj4SI8Vxku+BOfaVKuW3sn3mNiixI1dM/7FY2ip4kK+kv27vw==} + '@react-stately/list@3.13.4': + resolution: {integrity: sha512-HHYSjA9VG7FPSAtpXAjQyM/V7qFHWGg88WmMrDt5QDlTBexwPuH0oFLnW0qaVZpAIxuWIsutZfxRAnme/NhhAA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/menu@3.9.9': - resolution: {integrity: sha512-moW5JANxMxPilfR0SygpCWCZe7Ef09oadgzTZthRymNRv0PXVS9ad4wd1EkwuMvPH/n0uZLZE2s8hNyFDgyqPA==} + '@react-stately/menu@3.9.11': + resolution: {integrity: sha512-vYkpO9uV2OUecsIkrOc+Urdl/s1xw/ibNH/UXsp4PtjMnS6mK9q2kXZTM3WvMAKoh12iveUO+YkYCZQshmFLHQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/numberfield@3.10.3': - resolution: {integrity: sha512-40g/oyVcWoEaLqkr61KuHZzQVLLXFi3oa2K8XLnb6o+859SM4TX3XPNqL6eNQjXSKoJO5Hlgpqhee9j+VDbGog==} + '@react-stately/numberfield@3.11.0': + resolution: {integrity: sha512-rxfC047vL0LP4tanjinfjKAriAvdVL57Um5RUL5nHML8IOWCB3TBxegQkJ6to6goScC/oZhd0/Y2LSaiRuKbNw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/overlays@3.6.21': - resolution: {integrity: sha512-7f25H1PS2g+SNvuWPEW30pSGqYNHxesCP4w+1RcV/XV1oQI7oP5Ji2WfI0QsJEFc9wP/ZO1pyjHNKpfLI3O88g==} + '@react-stately/overlays@3.6.23': + resolution: {integrity: sha512-RzWxots9A6gAzQMP4s8hOAHV7SbJRTFSlQbb6ly1nkWQXacOSZSFNGsKOaS0eIatfNPlNnW4NIkgtGws5UYzfw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/radio@3.11.3': - resolution: {integrity: sha512-8+Cy0azV1aBWKcBfGHi3nBa285lAS6XhmVw2LfEwxq8DeVKTbJAaCHHwvDoclxDiOAnqzE0pio0QMD8rYISt9g==} + '@react-stately/radio@3.11.5': + resolution: {integrity: sha512-QxA779S4ea5icQ0ja7CeiNzY1cj7c9G9TN0m7maAIGiTSinZl2Ia8naZJ0XcbRRp+LBll7RFEdekne15TjvS/w==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/searchfield@3.5.17': - resolution: {integrity: sha512-/KExpJt6EGyuLxy/PRQJlETQxJGw8tRxVws6qF1lankN49Os2UhFEWi7ogbMCOWN67gIgevhZRdzmJnuov6BEQ==} + '@react-stately/searchfield@3.5.19': + resolution: {integrity: sha512-URllgjbtTQEaOCfddbHpJSPKOzG3pE3ajQHJ7Df8qCoHTjKfL6hnm/vp7X5sxPaZaN7VLZ5kAQxTE8hpo6s0+A==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/select@3.9.0': - resolution: {integrity: sha512-eNE33zVYpVdCPKRPGYyViN3LnEq82e1wjBIrs9T7Vo4EBnJeT57pqMZpalTPk7qsA+861t14Qrj7GnUd+YbEXw==} + '@react-stately/select@3.9.2': + resolution: {integrity: sha512-oWn0bijuusp8YI7FRM/wgtPVqiIrgU/ZUfLKe/qJUmT8D+JFaMAJnyrAzKpx98TrgamgtXynF78ccpopPhgrKQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/selection@3.20.7': - resolution: {integrity: sha512-NkiRsNCfORBIHNF1bCavh4Vvj+Yd5NffE10iXtaFuhF249NlxLynJZmkcVCqNP9taC2pBIHX00+9tcBgxhG+mA==} + '@react-stately/selection@3.20.9': + resolution: {integrity: sha512-RhxRR5Wovg9EVi3pq7gBPK2BoKmP59tOXDMh2r1PbnGevg/7TNdR67DCEblcmXwHuBNS46ELfKdd0XGHqmS8nQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/slider@3.7.3': - resolution: {integrity: sha512-9QGnQNXFAH52BzxtU7weyOV/VV7/so6uIvE8VOHfc6QR3GMBM/kJvqBCTWZfQ0pxDIsRagBQDD/tjB09ixTOzg==} + '@react-stately/slider@3.7.5': + resolution: {integrity: sha512-OrQMNR5xamLYH52TXtvTgyw3EMwv+JI+1istQgEj1CHBjC9eZZqn5iNCN20tzm+uDPTH0EIGULFjjPIumqYUQg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/table@3.15.2': - resolution: {integrity: sha512-vgEArBN5ocqsQdeORBj6xk8acu5iFnd/CyXEQKl0R5RyuYuw0ms8UmFHvs8Fv1HONehPYg+XR4QPliDFPX8R9A==} + '@react-stately/table@3.15.4': + resolution: {integrity: sha512-fGaNyw3wv7JgRCNzgyDzpaaTFuSy5f4Qekch4UheMXDJX7dOeaMhUXeOfvnXCVg+BGM4ey/D82RvDOGvPy1Nww==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/tabs@3.8.7': - resolution: {integrity: sha512-ETZEzg7s9F2SCvisZ2cCpLx6XBHqdvVgDGU5l3C3s9zBKBr6lgyLFt61IdGW8XXZRUvw4mMGT6tGQbXeGvR0Wg==} + '@react-stately/tabs@3.8.9': + resolution: {integrity: sha512-AQ4Xrn6YzIolaVShCV9cnwOjBKPAOGP/PTp7wpSEtQbQ0HZzUDG2RG/M4baMeUB2jZ33b7ifXyPcK78o0uOftg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/toast@3.1.2': - resolution: {integrity: sha512-HiInm7bck32khFBHZThTQaAF6e6/qm57F4mYRWdTq8IVeGDzpkbUYibnLxRhk0UZ5ybc6me+nqqPkG/lVmM42Q==} + '@react-stately/toast@3.1.3': + resolution: {integrity: sha512-mT9QJKmD523lqFpOp0VWZ6QHZENFK7HrodnNJDVc7g616s5GNmemdlkITV43fSY3tHeThCVvPu+Uzh7RvQ9mpQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/toggle@3.9.3': - resolution: {integrity: sha512-G6aA/aTnid/6dQ9dxNEd7/JqzRmVkVYYpOAP+l02hepiuSmFwLu4nE98i4YFBQqFZ5b4l01gMrS90JGL7HrNmw==} + '@react-stately/toggle@3.9.5': + resolution: {integrity: sha512-PVzXc788q3jH98Kvw1LYDL+wpVC14dCEKjOku8cSaqhEof6AJGaLR9yq+EF1yYSL2dxI6z8ghc0OozY8WrcFcA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/tooltip@3.5.9': - resolution: {integrity: sha512-YwqtxFqQFfJtbeh+axHVGAfz9XHf73UaBndHxSbVM/T5c1PfI2yOB39T2FOU5fskZ2VMO3qTDhiXmFgGbGYSfQ==} + '@react-stately/tooltip@3.5.11': + resolution: {integrity: sha512-o8PnFXbvDCuVZ4Ht9ahfS6KHwIZjXopvoQ2vUPxv920irdgWEeC+4omgDOnJ/xFvcpmmJAmSsrQsTQrTguDUQA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/tree@3.9.4': - resolution: {integrity: sha512-Re1fdEiR0hHPcEda+7ecw+52lgGfFW0MAEDzFg9I6J/t8STQSP+1YC0VVVkv2xRrkLbKLPqggNKgmD8nggecnw==} + '@react-stately/tree@3.9.6': + resolution: {integrity: sha512-JCuhGyX2A+PAMsx2pRSwArfqNFZJ9JSPkDaOQJS8MFPAsBe5HemvXsdmv9aBIMzlbCYcVq6EsrFnzbVVTBt/6w==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 @@ -4103,154 +4214,154 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/virtualizer@4.4.4': - resolution: {integrity: sha512-ri8giqXSZOrznZDCCOE4U36wSkOhy+hrFK7yo/YVcpxTqqp3d3eisfKMqbDsgqBW+XTHycTU/xeAf0u9NqrfpQ==} + '@react-stately/virtualizer@4.4.6': + resolution: {integrity: sha512-9SfXgLFB61/8SXNLfg5ARx9jAK4m03Aw6/Cg8mdZN24SYarL4TKNRpfw8K/HHVU/bi6WHSJypk6Z/z19o/ztrg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/autocomplete@3.0.0-alpha.36': - resolution: {integrity: sha512-J/wYkXom9zmEX/xuGjKrqMco9sf5AcByNXOgGAx82LMlk0jFcViggVjIYo/Qzr0TmDeTWyy++r1N59POI6179g==} + '@react-types/autocomplete@3.0.0-alpha.38': + resolution: {integrity: sha512-0XrlVC8drzcrCNzybbkZdLcTofXEzBsHuaFevt5awW1J0xBJ+SMLIQMDeUYrvKjjwXUBlCtjJJpOvitGt4Z+KA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/breadcrumbs@3.7.17': - resolution: {integrity: sha512-IhvVTcfli5o/UDlGACXxjlor2afGlMQA8pNR3faH0bBUay1Fmm3IWktVw9Xwmk+KraV2RTAg9e+E6p8DOQZfiw==} + '@react-types/breadcrumbs@3.7.19': + resolution: {integrity: sha512-AnkyYYmzaM2QFi/N0P/kQLM8tHOyFi7p397B/jEMucXDfwMw5Ny1ObCXeIEqbh8KrIa2Xp8SxmQlCV+8FPs4LA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/button@3.14.1': - resolution: {integrity: sha512-D8C4IEwKB7zEtiWYVJ3WE/5HDcWlze9mLWQ5hfsBfpePyWCgO3bT/+wjb/7pJvcAocrkXo90QrMm85LcpBtrpg==} + '@react-types/button@3.15.1': + resolution: {integrity: sha512-M1HtsKreJkigCnqceuIT22hDJBSStbPimnpmQmsl7SNyqCFY3+DHS7y/Sl3GvqCkzxF7j9UTL0dG38lGQ3K4xQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/calendar@3.8.1': - resolution: {integrity: sha512-B0UuitMP7YkArBAQldwSZSNL2WwazNGCG+lp6yEDj831NrH9e36/jcjv1rObQ9ZMS6uDX9LXu5C8V5RFwGQabA==} + '@react-types/calendar@3.8.3': + resolution: {integrity: sha512-fpH6WNXotzH0TlKHXXxtjeLZ7ko0sbyHmwDAwmDFyP7T0Iwn1YQZ+lhceLifvynlxuOgX6oBItyUKmkHQ0FouQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/checkbox@3.10.2': - resolution: {integrity: sha512-ktPkl6ZfIdGS1tIaGSU/2S5Agf2NvXI9qAgtdMDNva0oLyAZ4RLQb6WecPvofw1J7YKXu0VA5Mu7nlX+FM2weQ==} + '@react-types/checkbox@3.10.4': + resolution: {integrity: sha512-tYCG0Pd1usEz5hjvBEYcqcA0youx930Rss1QBIse9TgMekA1c2WmPDNupYV8phpO8Zuej3DL1WfBeXcgavK8aw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/color@3.1.2': - resolution: {integrity: sha512-NP0TAY3j4tlMztOp/bBfMlPwC9AQKTjSiTFmc2oQNkx5M4sl3QpPqFPosdt7jZ8M4nItvfCWZrlZGjST4SB83A==} + '@react-types/color@3.1.4': + resolution: {integrity: sha512-s+Xj4pvNBlJPpQ1Gr7bO1j4/tuwMUfdS9xIVFuiW5RvDsSybKTUJ/gqPzTxms94VDCRhLFocVn2STNdD2Erf6A==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/combobox@3.13.10': - resolution: {integrity: sha512-Wo4iix++ID6JzoH9eD7ddGUlirQiGpN/VQc3iFjnaTXiJ/cj3v+1oGsDGCZZTklTVeUMU7SRBfMhMgxHHIYLXA==} + '@react-types/combobox@3.14.0': + resolution: {integrity: sha512-zmSSS7BcCOD8rGT8eGbVy7UlL5qq1vm88fFn4WgFe+lfK33ne+E7yTzTxcPY2TCGSo5fY6xMj3OG79FfVNGbSg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/datepicker@3.13.3': - resolution: {integrity: sha512-OTRa3banGxcUQKRTLUzr0zTVUMUL+Az1BWARCYQ+8Z/dlkYXYUW0fnS5I0pUEqihgai15KxiY13U0gAqbNSfcA==} + '@react-types/datepicker@3.13.5': + resolution: {integrity: sha512-j28Vz+xvbb4bj7+9Xbpc4WTvSitlBvt7YEaEGM/8ZQ5g4Jr85H2KwkmDwjzmMN2r6VMQMMYq9JEcemq5wWpfUQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/dialog@3.5.22': - resolution: {integrity: sha512-smSvzOcqKE196rWk0oqJDnz+ox5JM5+OT0PmmJXiUD4q7P5g32O6W5Bg7hMIFUI9clBtngo8kLaX2iMg+GqAzg==} + '@react-types/dialog@3.5.24': + resolution: {integrity: sha512-NFurEP/zV0dA/41422lV1t+0oh6f/13n+VmLHZG8R13m1J3ql/kAXZ49zBSqkqANBO1ojyugWebk99IiR4pYOw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/form@3.7.16': - resolution: {integrity: sha512-Sb7KJoWEaQ/e4XIY+xRbjKvbP1luome98ZXevpD+zVSyGjEcfIroebizP6K1yMHCWP/043xH6GUkgEqWPoVGjg==} + '@react-types/form@3.7.18': + resolution: {integrity: sha512-0sBJW0+I9nJcF4SmKrYFEWAlehiebSTy7xqriqAXtqfTEdvzAYLGaAK2/7gx+wlNZeDTdW43CDRJ4XAhyhBqnw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/grid@3.3.6': - resolution: {integrity: sha512-vIZJlYTii2n1We9nAugXwM2wpcpsC6JigJFBd6vGhStRdRWRoU4yv1Gc98Usbx0FQ/J7GLVIgeG8+1VMTKBdxw==} + '@react-types/grid@3.3.8': + resolution: {integrity: sha512-zJvXH8gc1e1VH2H3LRnHH/W2HIkLkZMH3Cu5pLcj0vDuLBSWpcr3Ikh3jZ+VUOZF0G1Jt1lO8pKIaqFzDLNmLQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/link@3.6.5': - resolution: {integrity: sha512-+I2s3XWBEvLrzts0GnNeA84mUkwo+a7kLUWoaJkW0TOBDG7my95HFYxF9WnqKye7NgpOkCqz4s3oW96xPdIniQ==} + '@react-types/link@3.6.7': + resolution: {integrity: sha512-1apXCFJgMC1uydc2KNENrps1qR642FqDpwlNWe254UTpRZn/hEZhA6ImVr8WhomfLJu672WyWA0rUOv4HT+/pQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/listbox@3.7.4': - resolution: {integrity: sha512-p4YEpTl/VQGrqVE8GIfqTS5LkT5jtjDTbVeZgrkPnX/fiPhsfbTPiZ6g0FNap4+aOGJFGEEZUv2q4vx+rCORww==} + '@react-types/listbox@3.7.6': + resolution: {integrity: sha512-335NYElKEByXMalAmeRPyulKIDd2cjOCQhLwvv2BtxO5zaJfZnBbhZs+XPd9zwU6YomyOxODKSHrwbNDx+Jf3w==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/menu@3.10.5': - resolution: {integrity: sha512-HBTrKll2hm0VKJNM4ubIv1L9MNo8JuOnm2G3M+wXvb6EYIyDNxxJkhjsqsGpUXJdAOSkacHBDcNh2HsZABNX4A==} + '@react-types/menu@3.10.7': + resolution: {integrity: sha512-+p7ixZdvPDJZhisqdtWiiuJ9pteNfK5i19NB6wzAw5XkljbEzodNhwLv6rI96DY5XpbFso2kcjw7IWi+rAAGGQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/meter@3.4.13': - resolution: {integrity: sha512-EiarfbpHcvmeyXvXcr6XLaHkNHuGc4g7fBVEiDPwssFJKKfbUzqnnknDxPjyspqUVRcXC08CokS98J1jYobqDg==} + '@react-types/meter@3.4.15': + resolution: {integrity: sha512-9WjNphhLLM+TA4Ev1y2MkpugJ5JjTXseHh7ZWWx2veq5DrXMZYclkRpfUrUdLVKvaBIPQCgpQIj0TcQi+quR9A==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/numberfield@3.8.16': - resolution: {integrity: sha512-945F0GsD7K2T293YXhap+2Runl3tZWbnhadXVHFWLbqIKKONZFSZTfLKxQcbFr+bQXr2uh1bVJhYcOiS1l5M+A==} + '@react-types/numberfield@3.8.18': + resolution: {integrity: sha512-nLzk7YAG9yAUtSv+9R8LgCHsu8hJq8/A+m1KsKxvc8WmNJjIujSFgWvT21MWBiUgPBzJKGzAqpMDDa087mltJQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/overlays@3.9.2': - resolution: {integrity: sha512-Q0cRPcBGzNGmC8dBuHyoPR7N3057KTS5g+vZfQ53k8WwmilXBtemFJPLsogJbspuewQ/QJ3o2HYsp2pne7/iNw==} + '@react-types/overlays@3.9.4': + resolution: {integrity: sha512-7Z9HaebMFyYBqtv3XVNHEmVkm7AiYviV7gv0c98elEN2Co+eQcKFGvwBM9Gy/lV57zlTqFX1EX/SAqkMEbCLOA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/progress@3.5.16': - resolution: {integrity: sha512-I9tSdCFfvQ7gHJtm90VAKgwdTWXQgVNvLRStEc0z9h+bXBxdvZb+QuiRPERChwFQ9VkK4p4rDqaFo69nDqWkpw==} + '@react-types/progress@3.5.18': + resolution: {integrity: sha512-mKeQn+KrHr1y0/k7KtrbeDGDaERH6i4f6yBwj/ZtYDCTNKMO3tPHJY6nzF0w/KKZLplIO+BjUbHXc2RVm8ovwQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/radio@3.9.2': - resolution: {integrity: sha512-3UcJXu37JrTkRyP4GJPDBU7NmDTInrEdOe+bVzA1j4EegzdkJmLBkLg5cLDAbpiEHB+xIsvbJdx6dxeMuc+H3g==} + '@react-types/radio@3.9.4': + resolution: {integrity: sha512-TkMRY3sA1PcFZhhclu4IUzUTIir6MzNJj8h6WT8vO6Nug2kXJ72qigugVFBWJSE472mltduOErEAo0rtAYWbQA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/searchfield@3.6.6': - resolution: {integrity: sha512-cl3itr/fk7wbIQc2Gz5Ie8aVeUmPjVX/mRGS5/EXlmzycAKNYTvqf2mlxwObLndtLISmt7IgNjRRhbUUDI8Ang==} + '@react-types/searchfield@3.6.8': + resolution: {integrity: sha512-M2p7OVdMTMDmlBcHd4N2uCBwg3uJSNM4lmEyf09YD44N5wDAI0yogk52QBwsnhpe+i2s65UwCYgunB+QltRX8A==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/select@3.12.0': - resolution: {integrity: sha512-tM3mEbQNotvCJs1gYRFyIeXmXrIBSBLGw7feCIaYSO45IyjCGv8NZwpQWjoKPaWo3GpbHfHMNlWlq3v5QQPIXw==} + '@react-types/select@3.12.2': + resolution: {integrity: sha512-AseOjfr3qM1W1qIWcbAe6NFpwZluVeQX/dmu9BYxjcnVvtoBLPMbE5zX/BPbv+N5eFYjoMyj7Ug9dqnI+LrlGw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/shared@3.32.1': - resolution: {integrity: sha512-famxyD5emrGGpFuUlgOP6fVW2h/ZaF405G5KDi3zPHzyjAWys/8W6NAVJtNbkCkhedmvL0xOhvt8feGXyXaw5w==} + '@react-types/shared@3.33.1': + resolution: {integrity: sha512-oJHtjvLG43VjwemQDadlR5g/8VepK56B/xKO2XORPHt9zlW6IZs3tZrYlvH29BMvoqC7RtE7E5UjgbnbFtDGag==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/slider@3.8.2': - resolution: {integrity: sha512-MQYZP76OEOYe7/yA2To+Dl0LNb0cKKnvh5JtvNvDnAvEprn1RuLiay8Oi/rTtXmc2KmBa4VdTcsXsmkbbkeN2Q==} + '@react-types/slider@3.8.4': + resolution: {integrity: sha512-C+xFVvfKREai9S/ekBDCVaGPOQYkNUAsQhjQnNsUAATaox4I6IYLmcIgLmljpMQWqAe+gZiWsIwacRYMez2Tew==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/switch@3.5.15': - resolution: {integrity: sha512-r/ouGWQmIeHyYSP1e5luET+oiR7N7cLrAlWsrAfYRWHxqXOSNQloQnZJ3PLHrKFT02fsrQhx2rHaK2LfKeyN3A==} + '@react-types/switch@3.5.17': + resolution: {integrity: sha512-2GTPJvBCYI8YZ3oerHtXg+qikabIXCMJ6C2wcIJ5Xn0k9XOovowghfJi10OPB2GGyOiLBU74CczP5nx8adG90Q==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/table@3.13.4': - resolution: {integrity: sha512-I/DYiZQl6aNbMmjk90J9SOhkzVDZvyA3Vn3wMWCiajkMNjvubFhTfda5DDf2SgFP5l0Yh6TGGH5XumRv9LqL5Q==} + '@react-types/table@3.13.6': + resolution: {integrity: sha512-eluL+iFfnVmFm7OSZrrFG9AUjw+tcv898zbv+NsZACa8oXG1v9AimhZfd+Mo8q/5+sX/9hguWNXFkSvmTjuVPQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/tabs@3.3.20': - resolution: {integrity: sha512-Kjq4PypapdMOVPAQgaFIKH65Kr3YnRvaxBGd6RYizTsqYImQhXoGj6B4lBpjYy4KhfRd4dYS82frHqTGKmBYiA==} + '@react-types/tabs@3.3.22': + resolution: {integrity: sha512-HGwLD9dA3k3AGfRKGFBhNgxU9/LyRmxN0kxVj1ghA4L9S/qTOzS6GhrGNkGzsGxyVLV4JN8MLxjWN2o9QHnLEg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/textfield@3.12.6': - resolution: {integrity: sha512-hpEVKE+M3uUkTjw2WrX1NrH/B3rqDJFUa+ViNK2eVranLY4ZwFqbqaYXSzHupOF3ecSjJJv2C103JrwFvx6TPQ==} + '@react-types/textfield@3.12.8': + resolution: {integrity: sha512-wt6FcuE5AyntxsnPika/h3nf/DPmeAVbI018L9o6h+B/IL4sMWWdx663wx2KOOeHH8ejKGZQNPLhUKs4s1mVQA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/tooltip@3.5.0': - resolution: {integrity: sha512-o/m1wlKlOD2sLb9vZLWdVkD5LFLHBMLGeeK/bhyUtp0IEdUeKy0ZRTS7pa/A50trov9RvdbzLK79xG8nKNxHew==} + '@react-types/tooltip@3.5.2': + resolution: {integrity: sha512-FvSuZ2WP08NEWefrpCdBYpEEZh/5TvqvGjq0wqGzWg2OPwpc14HjD8aE7I3MOuylXkD4MSlMjl7J4DlvlcCs3Q==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@rolldown/pluginutils@1.0.0-beta.53': - resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==} + '@rolldown/pluginutils@1.0.0-rc.3': + resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} '@rollup/plugin-babel@6.1.0': resolution: {integrity: sha512-dFZNuFD2YRcoomP4oYf+DvQNSUA9ih+A3vUqopQx5EdtPGo3WBnQcI/S8pwpz91UsGfL0HsMSOlaMld8HrbubA==} @@ -4327,128 +4438,128 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.55.1': - resolution: {integrity: sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==} + '@rollup/rollup-android-arm-eabi@4.59.0': + resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.55.1': - resolution: {integrity: sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==} + '@rollup/rollup-android-arm64@4.59.0': + resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.55.1': - resolution: {integrity: sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==} + '@rollup/rollup-darwin-arm64@4.59.0': + resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.55.1': - resolution: {integrity: sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==} + '@rollup/rollup-darwin-x64@4.59.0': + resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.55.1': - resolution: {integrity: sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==} + '@rollup/rollup-freebsd-arm64@4.59.0': + resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.55.1': - resolution: {integrity: sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==} + '@rollup/rollup-freebsd-x64@4.59.0': + resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.55.1': - resolution: {integrity: sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==} + '@rollup/rollup-linux-arm-gnueabihf@4.59.0': + resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.55.1': - resolution: {integrity: sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==} + '@rollup/rollup-linux-arm-musleabihf@4.59.0': + resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.55.1': - resolution: {integrity: sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==} + '@rollup/rollup-linux-arm64-gnu@4.59.0': + resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.55.1': - resolution: {integrity: sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==} + '@rollup/rollup-linux-arm64-musl@4.59.0': + resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loong64-gnu@4.55.1': - resolution: {integrity: sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==} + '@rollup/rollup-linux-loong64-gnu@4.59.0': + resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-loong64-musl@4.55.1': - resolution: {integrity: sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==} + '@rollup/rollup-linux-loong64-musl@4.59.0': + resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.55.1': - resolution: {integrity: sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==} + '@rollup/rollup-linux-ppc64-gnu@4.59.0': + resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-ppc64-musl@4.55.1': - resolution: {integrity: sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==} + '@rollup/rollup-linux-ppc64-musl@4.59.0': + resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.55.1': - resolution: {integrity: sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==} + '@rollup/rollup-linux-riscv64-gnu@4.59.0': + resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.55.1': - resolution: {integrity: sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==} + '@rollup/rollup-linux-riscv64-musl@4.59.0': + resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.55.1': - resolution: {integrity: sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==} + '@rollup/rollup-linux-s390x-gnu@4.59.0': + resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.55.1': - resolution: {integrity: sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==} + '@rollup/rollup-linux-x64-gnu@4.59.0': + resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.55.1': - resolution: {integrity: sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==} + '@rollup/rollup-linux-x64-musl@4.59.0': + resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} cpu: [x64] os: [linux] - '@rollup/rollup-openbsd-x64@4.55.1': - resolution: {integrity: sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==} + '@rollup/rollup-openbsd-x64@4.59.0': + resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.55.1': - resolution: {integrity: sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==} + '@rollup/rollup-openharmony-arm64@4.59.0': + resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.55.1': - resolution: {integrity: sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==} + '@rollup/rollup-win32-arm64-msvc@4.59.0': + resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.55.1': - resolution: {integrity: sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==} + '@rollup/rollup-win32-ia32-msvc@4.59.0': + resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.55.1': - resolution: {integrity: sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==} + '@rollup/rollup-win32-x64-gnu@4.59.0': + resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.55.1': - resolution: {integrity: sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==} + '@rollup/rollup-win32-x64-msvc@4.59.0': + resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==} cpu: [x64] os: [win32] @@ -4516,8 +4627,8 @@ packages: '@rspack/lite-tapable@1.1.0': resolution: {integrity: sha512-E2B0JhYFmVAwdDiG14+DW0Di4Ze4Jg10Pc4/lILUrd5DRCaklduz2OvJ5HYQ6G+hd+WTzqQb3QnDNfK4yvAFYw==} - '@sinclair/typebox@0.34.47': - resolution: {integrity: sha512-ZGIBQ+XDvO5JQku9wmwtabcVTHJsgSWAHYtVuM9pBNNR5E88v6Jcj/llpmsjivig5X8A8HHOb4/mbEKPS5EvAw==} + '@sinclair/typebox@0.34.48': + resolution: {integrity: sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==} '@sindresorhus/is@4.6.0': resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} @@ -4537,23 +4648,23 @@ packages: '@standard-schema/utils@0.3.0': resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} - '@storybook/addon-docs@10.1.11': - resolution: {integrity: sha512-Jwm291Fhim2eVcZIVlkG1B2skb0ZI9oru6nqMbJxceQZlvZmcIa4oxvS1oaMTKw2DJnCv97gLm57P/YvRZ8eUg==} + '@storybook/addon-docs@10.2.16': + resolution: {integrity: sha512-tdndvqYqUybCFb3co+IfpInfD37mMWtsC9OBBRLEHhHODH/6c16n6iSdzEEOIJhc4rfjxvwNYsTq7jddplAT4g==} peerDependencies: - storybook: ^10.1.11 + storybook: ^10.2.16 - '@storybook/builder-vite@10.1.11': - resolution: {integrity: sha512-MMD09Ap7FyzDfWG961pkIMv/w684XXe1bBEi+wCEpHxvrgAd3j3A9w/Rqp9Am2uRDPCEdi1QgSzS3SGW3aGThQ==} + '@storybook/builder-vite@10.2.16': + resolution: {integrity: sha512-fP+fjvHC2oh2mJue3594AscGKY01wnM80+1s5EVQcSJ8hOk69qPKwN+97SUC5XfoZXg4ZMP0eglzY7TT3i2erA==} peerDependencies: - storybook: ^10.1.11 + storybook: ^10.2.16 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 - '@storybook/csf-plugin@10.1.11': - resolution: {integrity: sha512-Ant0NhgqHKzQsseeVTSetZCuDHHs0W2HRkHt51Kg/sUl0T/sDtfVA+fWZT8nGzGZqYSFkxqYPWjauPmIhPtaRw==} + '@storybook/csf-plugin@10.2.16': + resolution: {integrity: sha512-4p4ZFloO70BQwwLYXSH7N1FdZEXISVxJW16941MLSBDtHBqZxVLL+507424hCATi7d65yPKFL2460WVNodTXig==} peerDependencies: esbuild: '*' rollup: '*' - storybook: ^10.1.11 + storybook: ^10.2.16 vite: '*' webpack: '*' peerDependenciesMeta: @@ -4575,27 +4686,27 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@storybook/react-dom-shim@10.1.11': - resolution: {integrity: sha512-o8WPhRlZbORUWG9lAgDgJP0pi905VHJUFJr1Kp8980gHqtlemtnzjPxKy5vFwj6glNhAlK8SS8OOYzWP7hloTQ==} + '@storybook/react-dom-shim@10.2.16': + resolution: {integrity: sha512-waDfcEx8OW78qH8COQLKD2nDtDEXzw1zwXm47VPrRKiyhdea5z8OwO/SIk3y1lcoFMCT1RVJKBdYUPeVAoIB6w==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.1.11 + storybook: ^10.2.16 - '@storybook/react-vite@10.1.11': - resolution: {integrity: sha512-qh1BCD25nIoiDfqwha+qBkl7pcG4WuzM+c8tsE63YEm8AFIbNKg5K8lVUoclF+4CpFz7IwBpWe61YUTDfp+91w==} + '@storybook/react-vite@10.2.16': + resolution: {integrity: sha512-4HZnBn/XJlbXk/heaV3Gr/zt+NFWn+8ph8ewfMFLWe/oi1PXeXQKBSujreqGz4C8SvBGgrzQ4ORdmycsaESWMg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.1.11 + storybook: ^10.2.16 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 - '@storybook/react@10.1.11': - resolution: {integrity: sha512-rmMGmEwBaM2YpB8oDk2moM0MNjNMqtwyoPPZxjyruY9WVhYca8EDPGKEdRzUlb4qZJsTgLi7VU4eqg6LD/mL3Q==} + '@storybook/react@10.2.16': + resolution: {integrity: sha512-0MQJaeHvjBHnDGpsyxujjvvcgPlXeoF4bTtOhB1vYrdxO5Rozjf7hs9K/gY9hx9v95lTttNsU4Qib5L+K6XK+Q==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.1.11 + storybook: ^10.2.16 typescript: '>= 4.9.x' peerDependenciesMeta: typescript: @@ -4767,8 +4878,8 @@ packages: '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} - '@swc/helpers@0.5.18': - resolution: {integrity: sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==} + '@swc/helpers@0.5.19': + resolution: {integrity: sha512-QamiFeIK3txNjgUTNppE6MiG3p7TdninpZu0E0PbqVh1a9FNLT2FRhisaa4NcaX52XVhA5l7Pk58Ft7Sqi/2sA==} '@swc/types@0.1.25': resolution: {integrity: sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==} @@ -4777,65 +4888,65 @@ packages: resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} engines: {node: '>=10'} - '@tailwindcss/node@4.1.18': - resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==} + '@tailwindcss/node@4.2.1': + resolution: {integrity: sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==} - '@tailwindcss/oxide-android-arm64@4.1.18': - resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-android-arm64@4.2.1': + resolution: {integrity: sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==} + engines: {node: '>= 20'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.1.18': - resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-darwin-arm64@4.2.1': + resolution: {integrity: sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==} + engines: {node: '>= 20'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.1.18': - resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-darwin-x64@4.2.1': + resolution: {integrity: sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==} + engines: {node: '>= 20'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.1.18': - resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-freebsd-x64@4.2.1': + resolution: {integrity: sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==} + engines: {node: '>= 20'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': - resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1': + resolution: {integrity: sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==} + engines: {node: '>= 20'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': - resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-arm64-gnu@4.2.1': + resolution: {integrity: sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==} + engines: {node: '>= 20'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-arm64-musl@4.1.18': - resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-arm64-musl@4.2.1': + resolution: {integrity: sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==} + engines: {node: '>= 20'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-x64-gnu@4.1.18': - resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-x64-gnu@4.2.1': + resolution: {integrity: sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==} + engines: {node: '>= 20'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-linux-x64-musl@4.1.18': - resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-x64-musl@4.2.1': + resolution: {integrity: sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==} + engines: {node: '>= 20'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-wasm32-wasi@4.1.18': - resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} + '@tailwindcss/oxide-wasm32-wasi@4.2.1': + resolution: {integrity: sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==} engines: {node: '>=14.0.0'} cpu: [wasm32] bundledDependencies: @@ -4846,127 +4957,126 @@ packages: - '@emnapi/wasi-threads' - tslib - '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': - resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-win32-arm64-msvc@4.2.1': + resolution: {integrity: sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==} + engines: {node: '>= 20'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.1.18': - resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-win32-x64-msvc@4.2.1': + resolution: {integrity: sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==} + engines: {node: '>= 20'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.1.18': - resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==} - engines: {node: '>= 10'} + '@tailwindcss/oxide@4.2.1': + resolution: {integrity: sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==} + engines: {node: '>= 20'} '@tailwindcss/typography@0.5.19': resolution: {integrity: sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==} peerDependencies: tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1' - '@tailwindcss/vite@4.1.18': - resolution: {integrity: sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==} + '@tailwindcss/vite@4.2.1': + resolution: {integrity: sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w==} peerDependencies: vite: ^5.2.0 || ^6 || ^7 - '@tanstack/db-ivm@0.1.14': - resolution: {integrity: sha512-GluhFsd/Z1E/MZTf60l9dZpKNpmdxtV4izPRnj1RK6TYrhC9LMndN+ywk1VDFBrjtBq/CTShz4CilECLwVlTGg==} + '@tanstack/db-ivm@0.1.17': + resolution: {integrity: sha512-DK7vm56CDxNuRAdsbiPs+gITJ+16tUtYgZg3BRTLYKGIDsy8sdIO7sQFq5zl7Y+aIKAPmMAbVp9UjJ75FTtwgQ==} peerDependencies: typescript: '>=4.7' - '@tanstack/db@0.5.16': - resolution: {integrity: sha512-V4oCsGlighwgKGWldw1umaXaVYiDR0sK/1fCWictrx2lqxqmBMUEfmNtWnt0CFJXEbyRA/LF8TyFn1ooXtyZ3w==} + '@tanstack/db@0.5.30': + resolution: {integrity: sha512-kgBbmGrWSrDdKPzl465OEGy2Epyc6HsoI2U/jUrMSHuGgUEtgowpnBCTyPJCGBrHL8+bYgASFV4ULsFn4L6pLg==} peerDependencies: typescript: '>=4.7' - '@tanstack/eslint-plugin-router@1.141.0': - resolution: {integrity: sha512-E5QSLvoS8By2UajtUE64CNp22LVyzdqNyR/ponVV+yxONWHC3IzDUUHKBnPxW1yVwRT88qQoJYV0RJL6noW25A==} + '@tanstack/eslint-plugin-router@1.161.4': + resolution: {integrity: sha512-Cw6naM1QII0DEpjQvs1VDCa8f0hNhCQ0DehdAeVqHfovwUSWw+5F7WhgSlUrZAQN2RodzehWkRm6K/BqtQYnyA==} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - '@tanstack/history@1.145.7': - resolution: {integrity: sha512-gMo/ReTUp0a3IOcZoI3hH6PLDC2R/5ELQ7P2yu9F6aEkA0wSQh+Q4qzMrtcKvF2ut0oE+16xWCGDo/TdYd6cEQ==} - engines: {node: '>=12'} + '@tanstack/history@1.161.4': + resolution: {integrity: sha512-Kp/WSt411ZWYvgXy6uiv5RmhHrz9cAml05AQPrtdAp7eUqvIDbMGPnML25OKbzR3RJ1q4wgENxDTvlGPa9+Mww==} + engines: {node: '>=20.19'} - '@tanstack/pacer-lite@0.1.1': - resolution: {integrity: sha512-y/xtNPNt/YeyoVxE/JCx+T7yjEzpezmbb+toK8DDD1P4m7Kzs5YR956+7OKexG3f8aXgC3rLZl7b1V+yNUSy5w==} + '@tanstack/pacer-lite@0.2.1': + resolution: {integrity: sha512-3PouiFjR4B6x1c969/Pl4ZIJleof1M0n6fNX8NRiC9Sqv1g06CVDlEaXUR4212ycGFyfq4q+t8Gi37Xy+z34iQ==} engines: {node: '>=18'} - '@tanstack/query-core@5.90.16': - resolution: {integrity: sha512-MvtWckSVufs/ja463/K4PyJeqT+HMlJWtw6PrCpywznd2NSgO3m4KwO9RqbFqGg6iDE8vVMFWMeQI4Io3eEYww==} + '@tanstack/query-core@5.90.20': + resolution: {integrity: sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg==} - '@tanstack/query-devtools@5.92.0': - resolution: {integrity: sha512-N8D27KH1vEpVacvZgJL27xC6yPFUy0Zkezn5gnB3L3gRCxlDeSuiya7fKge8Y91uMTnC8aSxBQhcK6ocY7alpQ==} + '@tanstack/query-devtools@5.93.0': + resolution: {integrity: sha512-+kpsx1NQnOFTZsw6HAFCW3HkKg0+2cepGtAWXjiiSOJJ1CtQpt72EE2nyZb+AjAbLRPoeRmPJ8MtQd8r8gsPdg==} - '@tanstack/react-db@0.1.60': - resolution: {integrity: sha512-Pz3pwH4vgRxlS/L3+BszINjNlIUXahJ6EqSEsYBMBT19G36GzTzyd5Qq98JaOXuu8V0dkiFWEoyEoTv3BiHcrg==} + '@tanstack/react-db@0.1.74': + resolution: {integrity: sha512-5c5sIVLWsqDnufK4fTnO6VQWUjuIQXB5LEY7zBSqhfJgTMomHtFVxb899O97z2oqF+UzIzmW/lXqUq9Xm8l1Pg==} peerDependencies: react: '>=16.8.0' - '@tanstack/react-query-devtools@5.91.2': - resolution: {integrity: sha512-ZJ1503ay5fFeEYFUdo7LMNFzZryi6B0Cacrgr2h1JRkvikK1khgIq6Nq2EcblqEdIlgB/r7XDW8f8DQ89RuUgg==} + '@tanstack/react-query-devtools@5.91.3': + resolution: {integrity: sha512-nlahjMtd/J1h7IzOOfqeyDh5LNfG0eULwlltPEonYy0QL+nqrBB+nyzJfULV+moL7sZyxc2sHdNJki+vLA9BSA==} peerDependencies: - '@tanstack/react-query': ^5.90.14 + '@tanstack/react-query': ^5.90.20 react: ^18 || ^19 - '@tanstack/react-query@5.90.16': - resolution: {integrity: sha512-bpMGOmV4OPmif7TNMteU/Ehf/hoC0Kf98PDc0F4BZkFrEapRMEqI/V6YS0lyzwSV6PQpY1y4xxArUIfBW5LVxQ==} + '@tanstack/react-query@5.90.21': + resolution: {integrity: sha512-0Lu6y5t+tvlTJMTO7oh5NSpJfpg/5D41LlThfepTixPYkJ0sE2Jj0m0f6yYqujBwIXlId87e234+MxG3D3g7kg==} peerDependencies: react: ^18 || ^19 - '@tanstack/react-router-devtools@1.145.7': - resolution: {integrity: sha512-crzHSQ/rcGX7RfuYsmm1XG5quurNMDTIApU7jfwDx5J9HnUxCOSJrbFX0L3w0o0VRCw5xhrL2EdCnW78Ic86hg==} - engines: {node: '>=12'} + '@tanstack/react-router-devtools@1.166.2': + resolution: {integrity: sha512-EQhFQRArwxS0OjIWWGD5wfNboJq7rIYCbioHvepgbxgblKtNLWnRr3LFj34QhXTP1aQsPYb9t8+VTi3VbFuAfA==} + engines: {node: '>=20.19'} peerDependencies: - '@tanstack/react-router': ^1.145.7 - '@tanstack/router-core': ^1.145.7 + '@tanstack/react-router': ^1.166.2 + '@tanstack/router-core': ^1.166.2 react: '>=18.0.0 || >=19.0.0' react-dom: '>=18.0.0 || >=19.0.0' peerDependenciesMeta: '@tanstack/router-core': optional: true - '@tanstack/react-router@1.145.7': - resolution: {integrity: sha512-0O+a4TjJSPXd2BsvDPwDPBKRQKYqNIBg5TAg9NzCteqJ0NXRxwohyqCksHqCEEtJe/uItwqmHoqkK4q5MDhEsA==} - engines: {node: '>=12'} + '@tanstack/react-router@1.166.2': + resolution: {integrity: sha512-pKhUtrvVLlhjWhsHkJSuIzh1J4LcP+8ErbIqRLORX9Js8dUFMKoT0+8oFpi+P8QRpuhm/7rzjYiWfcyTsqQZtA==} + engines: {node: '>=20.19'} peerDependencies: react: '>=18.0.0 || >=19.0.0' react-dom: '>=18.0.0 || >=19.0.0' - '@tanstack/react-store@0.8.0': - resolution: {integrity: sha512-1vG9beLIuB7q69skxK9r5xiLN3ztzIPfSQSs0GfeqWGO2tGIyInZx0x1COhpx97RKaONSoAb8C3dxacWksm1ow==} + '@tanstack/react-store@0.9.1': + resolution: {integrity: sha512-YzJLnRvy5lIEFTLWBAZmcOjK3+2AepnBv/sr6NZmiqJvq7zTQggyK99Gw8fqYdMdHPQWXjz0epFKJXC+9V2xDA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tanstack/router-core@1.145.7': - resolution: {integrity: sha512-v6jx6JqVUBM0/FcBq1tX22xiPq8Ufc0PDEP582/4deYoq2/RYd+bZstANp3mGSsqdxE/luhoLYuuSQiwi/j1wA==} - engines: {node: '>=12'} + '@tanstack/router-core@1.166.2': + resolution: {integrity: sha512-zn3NhENOAX9ToQiX077UV2OH3aJKOvV2ZMNZZxZ3gDG3i3WqL8NfWfEgetEAfMN37/Mnt90PpotYgf7IyuoKqQ==} + engines: {node: '>=20.19'} - '@tanstack/router-devtools-core@1.145.7': - resolution: {integrity: sha512-oKeq/6QvN49THCh++FJyPv1X65i20qGS4aJHQTNsl4cu1piW1zWUhab2L3DZVr3G8C40FW3xb6hVw92N/fzZbQ==} - engines: {node: '>=12'} + '@tanstack/router-devtools-core@1.166.2': + resolution: {integrity: sha512-Ke8HquuwMhLYpo/6nxNgrzi9Ns2lsK9uwDba6WKA8I0K7fyYZoAUu+7AD6gdEcVU4NF6LjtMPfUCHmVtYYRTDw==} + engines: {node: '>=20.19'} peerDependencies: - '@tanstack/router-core': ^1.145.7 + '@tanstack/router-core': ^1.166.2 csstype: ^3.0.10 - solid-js: '>=1.9.5' peerDependenciesMeta: csstype: optional: true - '@tanstack/router-generator@1.145.7': - resolution: {integrity: sha512-xg71c1WTku0ro0rgpJWh3Dt+ognV9qWe2KJHAPzrqfOYdUYu9sGq7Ri4jo8Rk0luXWZrWsrFdBP+9Jx6JH6zWA==} - engines: {node: '>=12'} + '@tanstack/router-generator@1.166.2': + resolution: {integrity: sha512-wbvdyP1PKKQKk4aVlGeK9S5uDy8zodTr3tEZ2gRKNavJLusXbEWqtoo42JxHFFNB6dtguehFMt8PyZPAtkgWwQ==} + engines: {node: '>=20.19'} - '@tanstack/router-plugin@1.145.10': - resolution: {integrity: sha512-2001Qu/aUdEXVjyKa21/8HXXmgyDwTEtvgNoWaB9H6KmpqUUnlNuh+hlfa1tjGSnlFevkjbLb3NfveSy/Bvynw==} - engines: {node: '>=12'} + '@tanstack/router-plugin@1.166.2': + resolution: {integrity: sha512-TnyV/7//Vp5fR49mmNbOWHGz9IJTm1lqVxzPdtpzg7D5PjkW2HFmLFLtWwpJgz2R7AJJWR4Ge5kIPmC+fVZ6eQ==} + engines: {node: '>=20.19'} peerDependencies: '@rsbuild/core': '>=1.0.2' - '@tanstack/react-router': ^1.145.7 + '@tanstack/react-router': ^1.166.2 vite: '>=5.0.0 || >=6.0.0 || >=7.0.0' vite-plugin-solid: ^2.11.10 webpack: '>=5.92.0' @@ -4982,16 +5092,16 @@ packages: webpack: optional: true - '@tanstack/router-utils@1.143.11': - resolution: {integrity: sha512-N24G4LpfyK8dOlnP8BvNdkuxg1xQljkyl6PcrdiPSA301pOjatRT1y8wuCCJZKVVD8gkd0MpCZ0VEjRMGILOtA==} - engines: {node: '>=12'} + '@tanstack/router-utils@1.161.4': + resolution: {integrity: sha512-r8TpjyIZoqrXXaf2DDyjd44gjGBoyE+/oEaaH68yLI9ySPO1gUWmQENZ1MZnmBnpUGN24NOZxdjDLc8npK0SAw==} + engines: {node: '>=20.19'} - '@tanstack/store@0.8.0': - resolution: {integrity: sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ==} + '@tanstack/store@0.9.1': + resolution: {integrity: sha512-+qcNkOy0N1qSGsP7omVCW0SDrXtaDcycPqBDE726yryiA5eTDFpjBReaYjghVJwNf1pcPMyzIwTGlYjCSQR0Fg==} - '@tanstack/virtual-file-routes@1.145.4': - resolution: {integrity: sha512-CI75JrfqSluhdGwLssgVeQBaCphgfkMQpi8MCY3UJX1hoGzXa8kHYJcUuIFMOLs1q7zqHy++EVVtMK03osR5wQ==} - engines: {node: '>=12'} + '@tanstack/virtual-file-routes@1.161.4': + resolution: {integrity: sha512-42WoRePf8v690qG8yGRe/YOh+oHni9vUaUUfoqlS91U2scd3a5rkLtVsc6b7z60w3RogH0I00vdrC5AaeiZ18w==} + engines: {node: '>=20.19'} '@testing-library/dom@10.4.1': resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} @@ -5007,10 +5117,6 @@ packages: peerDependencies: '@testing-library/dom': '>=7.21.4' - '@trysound/sax@0.2.0': - resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} - engines: {node: '>=10.13.0'} - '@tsconfig/node10@1.0.12': resolution: {integrity: sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==} @@ -5086,6 +5192,9 @@ packages: '@types/eslint-scope@3.7.7': resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} + '@types/esquery@1.5.4': + resolution: {integrity: sha512-yYO4Q8H+KJHKW1rEeSzHxcZi90durqYgWVfnh5K6ZADVBjBv2e1NEveYX5yT2bffgN7RqzH3k9930m+i2yBoMA==} + '@types/estree-jsx@1.0.5': resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} @@ -5098,8 +5207,8 @@ packages: '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} - '@types/http-cache-semantics@4.0.4': - resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + '@types/http-cache-semantics@4.2.0': + resolution: {integrity: sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==} '@types/http-proxy@1.17.17': resolution: {integrity: sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==} @@ -5110,8 +5219,8 @@ packages: '@types/keyv@3.1.4': resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} - '@types/lodash@4.17.21': - resolution: {integrity: sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==} + '@types/lodash@4.17.24': + resolution: {integrity: sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==} '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} @@ -5122,26 +5231,20 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node-fetch@2.6.13': - resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} + '@types/node@20.19.37': + resolution: {integrity: sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==} - '@types/node@18.19.130': - resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==} + '@types/node@24.12.0': + resolution: {integrity: sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==} - '@types/node@20.19.27': - resolution: {integrity: sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==} - - '@types/node@22.19.3': - resolution: {integrity: sha512-1N9SBnWYOJTrNZCdh/yJE+t910Y128BoyY+zBLWhL3r0TYzlTmFdXrPwHL9DyFZmlEXNQQolTZh3KHV31QDhyA==} - - '@types/node@25.0.3': - resolution: {integrity: sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==} + '@types/node@25.3.5': + resolution: {integrity: sha512-oX8xrhvpiyRCQkG1MFchB09f+cXftgIXb3a7UUa4Y3wpmZPw5tyZGTLWhlESOLq1Rq6oDlc8npVU2/9xiCuXMA==} '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} - '@types/pg@8.16.0': - resolution: {integrity: sha512-RmhMd/wD+CF8Dfo+cVIy3RR5cl8CyfXQ0tGgW6XBL8L4LM/UTEbNXYRbLwU6w+CgrKBNbrQWt4FUtTfaU5jSYQ==} + '@types/pg@8.18.0': + resolution: {integrity: sha512-gT+oueVQkqnj6ajGJXblFR4iavIXWsGAFCk3dP4Kki5+a9R4NMt0JARdk6s8cUKcfUoqP5dAtDSLU8xYUTFV+Q==} '@types/plist@3.0.5': resolution: {integrity: sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==} @@ -5160,8 +5263,8 @@ packages: resolution: {integrity: sha512-omC9GxqKOdEiHLlqWU6NrDUF+qD7DHIZ9K5Wxw/XPrm22rfP/jgZrW8c27u23ON5LMWM/nIlUf0FUh+/DlftlQ==} deprecated: This is a stub types definition. react-timeago provides its own type definitions, so you do not need this installed. - '@types/react@19.2.7': - resolution: {integrity: sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==} + '@types/react@19.2.14': + resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} @@ -5184,94 +5287,101 @@ packages: '@types/verror@1.10.11': resolution: {integrity: sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==} + '@types/webidl-conversions@7.0.3': + resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==} + + '@types/whatwg-url@13.0.0': + resolution: {integrity: sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q==} + '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} '@types/yauzl@2.10.3': resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - '@typescript-eslint/eslint-plugin@8.52.0': - resolution: {integrity: sha512-okqtOgqu2qmZJ5iN4TWlgfF171dZmx2FzdOv2K/ixL2LZWDStL8+JgQerI2sa8eAEfoydG9+0V96m7V+P8yE1Q==} + '@typescript-eslint/eslint-plugin@8.56.1': + resolution: {integrity: sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.52.0 - eslint: ^8.57.0 || ^9.0.0 + '@typescript-eslint/parser': ^8.56.1 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.52.0': - resolution: {integrity: sha512-iIACsx8pxRnguSYhHiMn2PvhvfpopO9FXHyn1mG5txZIsAaB6F0KwbFnUQN3KCiG3Jcuad/Cao2FAs1Wp7vAyg==} + '@typescript-eslint/parser@8.56.1': + resolution: {integrity: sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.52.0': - resolution: {integrity: sha512-xD0MfdSdEmeFa3OmVqonHi+Cciab96ls1UhIF/qX/O/gPu5KXD0bY9lu33jj04fjzrXHcuvjBcBC+D3SNSadaw==} + '@typescript-eslint/project-service@8.56.1': + resolution: {integrity: sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.52.0': - resolution: {integrity: sha512-ixxqmmCcc1Nf8S0mS0TkJ/3LKcC8mruYJPOU6Ia2F/zUUR4pApW7LzrpU3JmtePbRUTes9bEqRc1Gg4iyRnDzA==} + '@typescript-eslint/scope-manager@8.56.1': + resolution: {integrity: sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.52.0': - resolution: {integrity: sha512-jl+8fzr/SdzdxWJznq5nvoI7qn2tNYV/ZBAEcaFMVXf+K6jmXvAFrgo/+5rxgnL152f//pDEAYAhhBAZGrVfwg==} + '@typescript-eslint/tsconfig-utils@8.56.1': + resolution: {integrity: sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.52.0': - resolution: {integrity: sha512-JD3wKBRWglYRQkAtsyGz1AewDu3mTc7NtRjR/ceTyGoPqmdS5oCdx/oZMWD5Zuqmo6/MpsYs0wp6axNt88/2EQ==} + '@typescript-eslint/type-utils@8.56.1': + resolution: {integrity: sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.52.0': - resolution: {integrity: sha512-LWQV1V4q9V4cT4H5JCIx3481iIFxH1UkVk+ZkGGAV1ZGcjGI9IoFOfg3O6ywz8QqCDEp7Inlg6kovMofsNRaGg==} + '@typescript-eslint/types@8.56.1': + resolution: {integrity: sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.52.0': - resolution: {integrity: sha512-XP3LClsCc0FsTK5/frGjolyADTh3QmsLp6nKd476xNI9CsSsLnmn4f0jrzNoAulmxlmNIpeXuHYeEQv61Q6qeQ==} + '@typescript-eslint/typescript-estree@8.56.1': + resolution: {integrity: sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.52.0': - resolution: {integrity: sha512-wYndVMWkweqHpEpwPhwqE2lnD2DxC6WVLupU/DOt/0/v+/+iQbbzO3jOHjmBMnhu0DgLULvOaU4h4pwHYi2oRQ==} + '@typescript-eslint/utils@8.56.1': + resolution: {integrity: sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.52.0': - resolution: {integrity: sha512-ink3/Zofus34nmBsPjow63FP5M7IGff0RKAgqR6+CFpdk22M7aLwC9gOcLGYqr7MczLPzZVERW9hRog3O4n1sQ==} + '@typescript-eslint/visitor-keys@8.56.1': + resolution: {integrity: sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript/vfs@1.6.2': - resolution: {integrity: sha512-hoBwJwcbKHmvd2QVebiytN1aELvpk9B74B4L1mFm/XT1Q/VOYAWl2vQ9AWRFtQq8zmz6enTpfTV8WRc4ATjW/g==} + '@typescript/vfs@1.6.4': + resolution: {integrity: sha512-PJFXFS4ZJKiJ9Qiuix6Dz/OwEIqHD7Dme1UwZhTK11vR+5dqW2ACbdndWQexBzCx+CPuMe5WBYQWCsFyGlQLlQ==} peerDependencies: typescript: '*' - '@typespec/compiler@1.7.1': - resolution: {integrity: sha512-sb3MEsKjFlAx8ZG484exs5Ec+JwmYf2anJqLjMusrV3rRMUhv3fbEulk9MD+l4eOkBS46VMNGqRu0wTn8suVVA==} + '@typespec/compiler@1.9.0': + resolution: {integrity: sha512-Rz9fFWQSTJSnhBfZvtA/bDIuO82fknYdtyMsL9lZNJE82rquC6JByHPFsnbGH1VXA0HhMj9L7Oqyp3f0m/BTOA==} engines: {node: '>=20.0.0'} hasBin: true - '@typespec/emitter-framework@0.14.0': - resolution: {integrity: sha512-35C9XlLOFk2hQ85Hf6YT19gWOz4SfVgOCoBMs4rgx/KrJj7qM/AbdXjuSO+QLp76a928NWAAHQhbq5NbOpKztw==} + '@typespec/emitter-framework@0.16.0': + resolution: {integrity: sha512-9Sug3Jt4y7acDVqrP9fD+YBSGqXqnAvUpGcTfTIH6d6QE1+Jxn4qEl7AjyKtyVd7Fyxwp4kqooUocL+QHLzXVw==} peerDependencies: - '@alloy-js/core': ^0.21.0 - '@alloy-js/csharp': ^0.21.0 - '@alloy-js/typescript': ^0.21.0 - '@typespec/compiler': ^1.7.0 + '@alloy-js/core': ^0.22.0 + '@alloy-js/csharp': ^0.22.0 + '@alloy-js/python': ^0.3.0 + '@alloy-js/typescript': ^0.22.0 + '@typespec/compiler': ^1.9.0 - '@typespec/prettier-plugin-typespec@1.7.0': - resolution: {integrity: sha512-QxCCjWOHqlf43ZMIqma4JU9dnsuknqlUO8yfYUXdxXIBxadevY6Pk3HbTR+ecNgeZlxuvd8ms2v1rhcojw3pTA==} + '@typespec/prettier-plugin-typespec@1.9.0': + resolution: {integrity: sha512-39Nc1uRM/kwDLrFfuMh+aS9P8fUpKi8IOBVF/3s45vFnITt2Pa1Pud3+xcU+/JWoc/q6bkzXM6PmfJ4/60Z+mw==} - '@uiw/codemirror-extensions-basic-setup@4.25.4': - resolution: {integrity: sha512-YzNwkm0AbPv1EXhCHYR5v0nqfemG2jEB0Z3Att4rBYqKrlG7AA9Rhjc3IyBaOzsBu18wtrp9/+uhTyu7TXSRng==} + '@uiw/codemirror-extensions-basic-setup@4.25.7': + resolution: {integrity: sha512-tPV/AGjF4yM22D5mnyH7EuYBkWO05wF5Y4x3lmQJo6LuHmhjh0RQsVDjqeIgNOkXT3UO9OdkL4dzxw465/JZVg==} peerDependencies: '@codemirror/autocomplete': 6.20.0 '@codemirror/commands': 6.10.1 @@ -5281,8 +5391,8 @@ packages: '@codemirror/state': 6.5.3 '@codemirror/view': 6.39.9 - '@uiw/react-codemirror@4.25.4': - resolution: {integrity: sha512-ipO067oyfUw+DVaXhQCxkB0ZD9b7RnY+ByrprSYSKCHaULvJ3sqWYC/Zen6zVQ8/XC4o5EPBfatGiX20kC7XGA==} + '@uiw/react-codemirror@4.25.7': + resolution: {integrity: sha512-s/EbEe0dFANWEgfLbfdIrrOGv0R7M1XhkKG3ShroBeH6uP9pVNQy81YHOLRCSVcytTp9zAWRNfXR/+XxZTvV7w==} peerDependencies: '@babel/runtime': '>=7.11.0' '@codemirror/state': 6.5.3 @@ -5390,8 +5500,13 @@ packages: cpu: [x64] os: [win32] - '@vitejs/plugin-react@5.1.2': - resolution: {integrity: sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ==} + '@valibot/to-json-schema@1.5.0': + resolution: {integrity: sha512-GE7DmSr1C2UCWPiV0upRH6mv0cCPsqYGs819fb6srCS1tWhyXrkGGe+zxUiwzn/L1BOfADH4sNjY/YHCuP8phQ==} + peerDependencies: + valibot: ^1.2.0 + + '@vitejs/plugin-react@5.1.4': + resolution: {integrity: sha512-VIcFLdRi/VYRU8OL/puL7QXMYafHmqOnwTZY50U1JPlCNj30PxCMx65c494b1K9be9hX83KVt0+gTEwTWLqToA==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 @@ -5402,17 +5517,6 @@ packages: '@vitest/expect@4.0.18': resolution: {integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==} - '@vitest/mocker@3.2.4': - resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} - peerDependencies: - msw: ^2.4.9 - vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 - peerDependenciesMeta: - msw: - optional: true - vite: - optional: true - '@vitest/mocker@4.0.18': resolution: {integrity: sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==} peerDependencies: @@ -5448,17 +5552,11 @@ packages: '@vitest/utils@4.0.18': resolution: {integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==} - '@vue/reactivity@3.5.26': - resolution: {integrity: sha512-9EnYB1/DIiUYYnzlnUBgwU32NNvLp/nhxLXeWRhHUEeWNTn1ECxX8aGO7RTXeX6PPcxe3LLuNBFoJbV4QZ+CFQ==} - - '@vue/reactivity@3.5.28': - resolution: {integrity: sha512-gr5hEsxvn+RNyu9/9o1WtdYdwDjg5FgjUSBEkZWqgTKlo/fvwZ2+8W6AfKsc9YN2k/+iHYdS9vZYAhpi10kNaw==} - - '@vue/shared@3.5.26': - resolution: {integrity: sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A==} + '@vue/reactivity@3.5.29': + resolution: {integrity: sha512-zcrANcrRdcLtmGZETBxWqIkoQei8HaFpZWx/GHKxx79JZsiZ8j1du0VUJtu4eJjgFvU/iKL5lRXFXksVmI+5DA==} - '@vue/shared@3.5.28': - resolution: {integrity: sha512-cfWa1fCGBxrvaHRhvV3Is0MgmrbSCxYTXCSCau2I0a1Xw1N1pHAvkWCiXPRAqjvToILvguNyEwjevUqAuBQWvQ==} + '@vue/shared@3.5.29': + resolution: {integrity: sha512-w7SR0A5zyRByL9XUkCfdLs7t9XOHUyJ67qPGQjOou3p6GvBeBW+AVjUUmlxtZ4PIYaRvE+1LmK44O4uajlZwcg==} '@webassemblyjs/ast@1.14.1': resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} @@ -5561,12 +5659,12 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn-walk@8.3.4: - resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + acorn-walk@8.3.5: + resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==} engines: {node: '>=0.4.0'} - acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} hasBin: true @@ -5582,10 +5680,6 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} - agentkeepalive@4.6.0: - resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} - engines: {node: '>= 8.0.0'} - ajv-formats@2.1.1: resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependencies: @@ -5604,12 +5698,15 @@ packages: peerDependencies: ajv: ^8.8.2 - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@6.14.0: + resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} @@ -5648,13 +5745,6 @@ packages: app-builder-bin@5.0.0-alpha.12: resolution: {integrity: sha512-j87o0j6LqPL3QRr8yid6c+Tt5gC7xNfYo6uQIQkorAC6MpeayVMZrEDzKmJJ/Hlv7EnOQpaRm53k6ktDYZyB6w==} - app-builder-lib@26.3.1: - resolution: {integrity: sha512-TA6SCnyfZkUVv+QUwNlF75bq9Fq9/zHRm3l1dNa5RZx2a/mtOI71In82O2aglu3uHhmqUwmjkgPxxmkp4pvDmw==} - engines: {node: '>=14.0.0'} - peerDependencies: - dmg-builder: 26.3.1 - electron-builder-squirrel-windows: 26.3.1 - app-builder-lib@26.4.0: resolution: {integrity: sha512-Uas6hNe99KzP3xPWxh5LGlH8kWIVjZixzmMJHNB9+6hPyDpjc7NQMkVgi16rQDdpCFy22ZU5sp8ow7tvjeMgYQ==} engines: {node: '>=14.0.0'} @@ -5662,6 +5752,21 @@ packages: dmg-builder: 26.4.0 electron-builder-squirrel-windows: 26.4.0 + app-builder-lib@26.8.1: + resolution: {integrity: sha512-p0Im/Dx5C4tmz8QEE1Yn4MkuPC8PrnlRneMhWJj7BBXQfNTJUshM/bp3lusdEsDbvvfJZpXWnYesgSLvwtM2Zw==} + engines: {node: '>=14.0.0'} + peerDependencies: + dmg-builder: 26.8.1 + electron-builder-squirrel-windows: 26.8.1 + + archiver-utils@5.0.2: + resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==} + engines: {node: '>= 14'} + + archiver@7.0.1: + resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==} + engines: {node: '>= 14'} + arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -5746,8 +5851,8 @@ packages: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} - autoprefixer@10.4.23: - resolution: {integrity: sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==} + autoprefixer@10.4.27: + resolution: {integrity: sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==} engines: {node: ^10 || ^12 || >=14} hasBin: true peerDependencies: @@ -5757,19 +5862,31 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + aws-ssl-profiles@1.1.2: + resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} + engines: {node: '>= 6.0.0'} + axe-core@4.11.1: resolution: {integrity: sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==} engines: {node: '>=4'} - axios@1.13.2: - resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} + axios@1.13.6: + resolution: {integrity: sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==} axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} - babel-dead-code-elimination@1.0.11: - resolution: {integrity: sha512-mwq3W3e/pKSI6TG8lXMiDWvEi1VXYlSBlJlB3l+I0bAb5u1RNUl88udos85eOPNK3m5EXK9uO7d2g08pesTySQ==} + b4a@1.8.0: + resolution: {integrity: sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==} + peerDependencies: + react-native-b4a: '*' + peerDependenciesMeta: + react-native-b4a: + optional: true + + babel-dead-code-elimination@1.0.12: + resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==} babel-plugin-const-enum@1.2.0: resolution: {integrity: sha512-o1m/6iyyFnp9MRsK1dHF3bneqyf3AlM2q3A/YbgQr2pCat6B6XJVDv2TXqzfY2RYUi4mak6WAksSBPlyYGx9dg==} @@ -5780,8 +5897,8 @@ packages: resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} engines: {node: '>=10', npm: '>=6'} - babel-plugin-polyfill-corejs2@0.4.14: - resolution: {integrity: sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==} + babel-plugin-polyfill-corejs2@0.4.15: + resolution: {integrity: sha512-hR3GwrRwHUfYwGfrisXPIDP3JcYfBrW7wKE7+Au6wDYl7fm/ka1NEII6kORzxNU556JjfidZeBsO10kYvtV1aw==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 @@ -5790,8 +5907,13 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - babel-plugin-polyfill-regenerator@0.6.5: - resolution: {integrity: sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==} + babel-plugin-polyfill-corejs3@0.14.0: + resolution: {integrity: sha512-AvDcMxJ34W4Wgy4KBIIePQTAOP1Ie2WFwkQp3dB7FQ/f0lI5+nM96zUnYEOE1P9sEg0es5VCP0HxiWu5fUHZAQ==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-regenerator@0.6.6: + resolution: {integrity: sha512-hYm+XLYRMvupxiQzrvXUj7YyvFFVfv5gI0R71AJzudg1g2AI2vyCPPIFEBjk162/wFzti3inBHo7isWFuEVS/A==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 @@ -5813,15 +5935,54 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - balanced-match@4.0.2: - resolution: {integrity: sha512-x0K50QvKQ97fdEz2kPehIerj+YTeptKF9hyYkKf6egnwmMWAkADiO0QCzSp0R5xN8FTZgYaBfSaue46Ej62nMg==} - engines: {node: 20 || >=22} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + bare-events@2.8.2: + resolution: {integrity: sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==} + peerDependencies: + bare-abort-controller: '*' + peerDependenciesMeta: + bare-abort-controller: + optional: true + + bare-fs@4.5.5: + resolution: {integrity: sha512-XvwYM6VZqKoqDll8BmSww5luA5eflDzY0uEFfBJtFKe4PAAtxBjU3YIxzIBzhyaEQBy1VXEQBto4cpN5RZJw+w==} + engines: {bare: '>=1.16.0'} + peerDependencies: + bare-buffer: '*' + peerDependenciesMeta: + bare-buffer: + optional: true + + bare-os@3.7.1: + resolution: {integrity: sha512-ebvMaS5BgZKmJlvuWh14dg9rbUI84QeV3WlWn6Ph6lFI8jJoh7ADtVTyD2c93euwbe+zgi0DVrl4YmqXeM9aIA==} + engines: {bare: '>=1.14.0'} + + bare-path@3.0.0: + resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==} + + bare-stream@2.8.0: + resolution: {integrity: sha512-reUN0M2sHRqCdG4lUK3Fw8w98eeUIZHL5c3H7Mbhk2yVBL+oofgaIp0ieLfD5QXwPCypBpmEEKU2WZKzbAk8GA==} + peerDependencies: + bare-buffer: '*' + bare-events: '*' + peerDependenciesMeta: + bare-buffer: + optional: true + bare-events: + optional: true + + bare-url@2.3.2: + resolution: {integrity: sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==} base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.9.11: - resolution: {integrity: sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==} + baseline-browser-mapping@2.10.0: + resolution: {integrity: sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==} + engines: {node: '>=6.0.0'} hasBin: true basic-auth@2.0.1: @@ -5831,8 +5992,8 @@ packages: before-after-hook@4.0.0: resolution: {integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==} - better-auth@1.4.18: - resolution: {integrity: sha512-bnyifLWBPcYVltH3RhS7CM62MoelEqC6Q+GnZwfiDWNfepXoQZBjEvn4urcERC7NTKgKq5zNBM8rvPvRBa6xcg==} + better-auth@1.4.21: + resolution: {integrity: sha512-qdrIZS7xnGF2HPBV5wYNPWTkPojhauOOjz1+MhLvwFy+zXpgLofQmWsI5I9DY+ef845NKt93XcgpyAc4RPPT9A==} peerDependencies: '@lynx-js/react': '*' '@prisma/client': ^5.0.0 || ^6.0.0 || ^7.0.0 @@ -5893,43 +6054,110 @@ packages: vue: optional: true - better-call@1.1.8: - resolution: {integrity: sha512-XMQ2rs6FNXasGNfMjzbyroSwKwYbZ/T3IxruSS6U2MJRsSYh3wYtG3o6H00ZlKZ/C/UPOAD97tqgQJNsxyeTXw==} + better-auth@1.5.4: + resolution: {integrity: sha512-ReykcEKx6Kp9560jG1wtlDBnftA7L7xb3ZZdDWm5yGXKKe2pUf+oBjH0fqekrkRII0m4XBVQbQ0mOrFv+3FdYg==} peerDependencies: - zod: ^4.0.0 + '@lynx-js/react': '*' + '@prisma/client': ^5.0.0 || ^6.0.0 || ^7.0.0 + '@sveltejs/kit': ^2.0.0 + '@tanstack/react-start': ^1.0.0 + '@tanstack/solid-start': ^1.0.0 + better-sqlite3: ^12.0.0 + drizzle-kit: '>=0.31.4' + drizzle-orm: '>=0.41.0' + mongodb: ^6.0.0 || ^7.0.0 + mysql2: ^3.0.0 + next: ^14.0.0 || ^15.0.0 || ^16.0.0 + pg: ^8.0.0 + prisma: ^5.0.0 || ^6.0.0 || ^7.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + solid-js: ^1.0.0 + svelte: ^4.0.0 || ^5.0.0 + vitest: ^2.0.0 || ^3.0.0 || ^4.0.0 + vue: ^3.0.0 peerDependenciesMeta: - zod: + '@lynx-js/react': optional: true + '@prisma/client': + optional: true + '@sveltejs/kit': + optional: true + '@tanstack/react-start': + optional: true + '@tanstack/solid-start': + optional: true + better-sqlite3: + optional: true + drizzle-kit: + optional: true + drizzle-orm: + optional: true + mongodb: + optional: true + mysql2: + optional: true + next: + optional: true + pg: + optional: true + prisma: + optional: true + react: + optional: true + react-dom: + optional: true + solid-js: + optional: true + svelte: + optional: true + vitest: + optional: true + vue: + optional: true + + better-call@1.1.8: + resolution: {integrity: sha512-XMQ2rs6FNXasGNfMjzbyroSwKwYbZ/T3IxruSS6U2MJRsSYh3wYtG3o6H00ZlKZ/C/UPOAD97tqgQJNsxyeTXw==} + peerDependencies: + zod: ^4.0.0 + peerDependenciesMeta: + zod: + optional: true + + better-call@1.3.2: + resolution: {integrity: sha512-4cZIfrerDsNTn3cm+MhLbUePN0gdwkhSXEuG7r/zuQ8c/H7iU0/jSK5TD3FW7U0MgKHce/8jGpPYNO4Ve+4NBw==} + peerDependencies: + zod: ^4.0.0 + peerDependenciesMeta: + zod: + optional: true + + better-sqlite3@12.6.2: + resolution: {integrity: sha512-8VYKM3MjCa9WcaSAI3hzwhmyHVlH8tiGFwf0RlTsZPWJ1I5MkzjiudCo4KC4DxOaL/53A5B1sI/IbldNFDbsKA==} + engines: {node: 20.x || 22.x || 23.x || 24.x || 25.x} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + + bippy@0.5.30: + resolution: {integrity: sha512-8CFmJAHD3gmTLDOCDHuWhjm1nxHSFZdlGoWtak9r53Uxn36ynOjxBLyxXHh/7h/XiKLyPvfdXa0gXWcD9o9lLQ==} + peerDependencies: + react: '>=17.0.1' + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + + body-parser@1.20.4: + resolution: {integrity: sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - better-sqlite3@12.6.2: - resolution: {integrity: sha512-8VYKM3MjCa9WcaSAI3hzwhmyHVlH8tiGFwf0RlTsZPWJ1I5MkzjiudCo4KC4DxOaL/53A5B1sI/IbldNFDbsKA==} - engines: {node: 20.x || 22.x || 23.x || 24.x || 25.x} - - big.js@5.2.2: - resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} - - binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} - - bindings@1.5.0: - resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} - - bippy@0.3.34: - resolution: {integrity: sha512-vmptmU/20UdIWHHhq7qCSHhHzK7Ro3YJ1utU0fBG7ujUc58LEfTtilKxcF0IOgSjT5XLcm7CBzDjbv4lcKApGQ==} - peerDependencies: - react: '>=17.0.1' - - bl@4.1.0: - resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - - body-parser@1.20.4: - resolution: {integrity: sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - - boolbase@1.0.0: - resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - boolean@3.2.0: resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. @@ -5940,9 +6168,9 @@ packages: brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} - brace-expansion@5.0.2: - resolution: {integrity: sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==} - engines: {node: 20 || >=22} + brace-expansion@5.0.4: + resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==} + engines: {node: 18 || 20 || >=22} braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} @@ -5953,6 +6181,10 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + bson@7.2.0: + resolution: {integrity: sha512-YCEo7KjMlbNlyHhz7zAZNDpIpQbd+wOEHJYezv0nMYTn4x31eIUM2yomNNubclAt63dObUzKHWsBLJ9QcZNSnQ==} + engines: {node: '>=20.19.0'} + btoa@1.2.1: resolution: {integrity: sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==} engines: {node: '>= 0.4.0'} @@ -5961,22 +6193,29 @@ packages: buffer-crc32@0.2.13: resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + buffer-crc32@1.0.0: + resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} + engines: {node: '>=8.0.0'} + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + builder-util-runtime@9.5.1: resolution: {integrity: sha512-qt41tMfgHTllhResqM5DcnHyDIWNgzHvuY2jDcYP9iaGpkWxTUzV6GQjDeLnlR1/DtdlcsWQbA7sByMpmJFTLQ==} engines: {node: '>=12.0.0'} - builder-util@26.3.1: - resolution: {integrity: sha512-pplZEYBx1g15qvIOshpR1WTwjAwQM4ukhGgSNdYPnbuM6wLePq3+njy1sGfekCrJmUP+2xfuwuT9zEoUWfX5zQ==} - builder-util@26.3.4: resolution: {integrity: sha512-aRn88mYMktHxzdqDMF6Ayj0rKoX+ZogJ75Ck7RrIqbY/ad0HBvnS2xA4uHfzrGr5D2aLL3vU6OBEH4p0KMV2XQ==} + builder-util@26.8.1: + resolution: {integrity: sha512-pm1lTYbGyc90DHgCDO7eo8Rl4EqKLciayNbZqGziqnH9jrlKe8ZANGdityLZU+pJh16dfzjAx2xQq9McuIPEtw==} + bundle-name@4.1.0: resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} engines: {node: '>=18'} @@ -5991,6 +6230,14 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} + c12@3.1.0: + resolution: {integrity: sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==} + peerDependencies: + magicast: ^0.3.5 + peerDependenciesMeta: + magicast: + optional: true + c12@3.3.3: resolution: {integrity: sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q==} peerDependencies: @@ -6039,11 +6286,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-api@3.0.0: - resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} - - caniuse-lite@1.0.30001762: - resolution: {integrity: sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw==} + caniuse-lite@1.0.30001777: + resolution: {integrity: sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -6142,6 +6386,10 @@ packages: resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} engines: {node: '>=8'} + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} + engines: {node: '>=8'} + citty@0.1.6: resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} @@ -6211,9 +6459,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - colord@2.9.3: - resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} - colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -6240,6 +6485,10 @@ packages: resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} engines: {node: '>=18'} + commander@14.0.3: + resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} + engines: {node: '>=20'} + commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} @@ -6259,8 +6508,8 @@ packages: resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} engines: {node: ^12.20.0 || >=14} - comment-parser@1.4.1: - resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} + comment-parser@1.4.5: + resolution: {integrity: sha512-aRDkn3uyIlCFfk5NUA+VdwMmMsh8JGhc4hapfV4yxymHGQ3BVskMQfoXGpCo5IoBuQ9tS5iiVKhCpTcB4pW4qw==} engines: {node: '>= 12.0.0'} commondir@1.0.1: @@ -6270,6 +6519,10 @@ packages: resolution: {integrity: sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==} engines: {node: '>=0.10.0'} + compress-commons@6.0.2: + resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==} + engines: {node: '>= 14'} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -6314,8 +6567,8 @@ packages: resolution: {integrity: sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==} engines: {node: '>= 0.8'} - core-js-compat@3.47.0: - resolution: {integrity: sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==} + core-js-compat@3.48.0: + resolution: {integrity: sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q==} core-util-is@1.0.2: resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} @@ -6340,8 +6593,8 @@ packages: typescript: optional: true - cosmiconfig@9.0.0: - resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} + cosmiconfig@9.0.1: + resolution: {integrity: sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==} engines: {node: '>=14'} peerDependencies: typescript: '>=4.9.5' @@ -6349,6 +6602,15 @@ packages: typescript: optional: true + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + + crc32-stream@6.0.0: + resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==} + engines: {node: '>= 14'} + crc@3.8.0: resolution: {integrity: sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==} @@ -6369,22 +6631,9 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - css-declaration-sorter@6.4.1: - resolution: {integrity: sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==} - engines: {node: ^10 || ^12 || >=14} - peerDependencies: - postcss: ^8.0.9 - - css-select@4.3.0: - resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} - css-select@5.2.2: resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} - css-tree@1.1.3: - resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==} - engines: {node: '>=8.0.0'} - css-tree@2.2.1: resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} @@ -6405,28 +6654,6 @@ packages: engines: {node: '>=4'} hasBin: true - cssnano-preset-default@5.2.14: - resolution: {integrity: sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - cssnano-utils@3.1.0: - resolution: {integrity: sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - cssnano@5.1.15: - resolution: {integrity: sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - csso@4.2.0: - resolution: {integrity: sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==} - engines: {node: '>=8.0.0'} - csso@5.0.5: resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} @@ -6536,6 +6763,10 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + deepmerge-ts@7.1.5: + resolution: {integrity: sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==} + engines: {node: '>=16.0.0'} + deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} @@ -6544,8 +6775,8 @@ packages: resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} engines: {node: '>=18'} - default-browser@5.4.0: - resolution: {integrity: sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg==} + default-browser@5.5.0: + resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==} engines: {node: '>=18'} defaults@1.0.4: @@ -6581,6 +6812,10 @@ packages: delegates@1.0.0: resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} + denque@2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} + depd@1.1.2: resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} engines: {node: '>= 0.6'} @@ -6600,11 +6835,6 @@ packages: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - detect-libc@1.0.3: - resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} - engines: {node: '>=0.10'} - hasBin: true - detect-libc@2.0.2: resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} engines: {node: '>=8'} @@ -6624,19 +6854,19 @@ packages: devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} - diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + diff@4.0.4: + resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} engines: {node: '>=0.3.1'} - diff@8.0.2: - resolution: {integrity: sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==} + diff@8.0.3: + resolution: {integrity: sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==} engines: {node: '>=0.3.1'} dir-compare@4.2.0: resolution: {integrity: sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==} - dmg-builder@26.3.1: - resolution: {integrity: sha512-hYOlXCqmBxFXz8TZrAGm/Ym5ji+/Am5sgQaT+yZ/VULb9O+E7Lr1Z0HFnKk8GaaYfULV8PDVCYO4/bpQyb+BSg==} + dmg-builder@26.8.1: + resolution: {integrity: sha512-glMJgnTreo8CFINujtAhCgN96QAqApDMZ8Vl1r8f0QT8QprvC1UCltV4CcWj20YoIyLZx6IUskaJZ0NV8fokcg==} dmg-license@1.0.11: resolution: {integrity: sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==} @@ -6658,26 +6888,16 @@ packages: dom-accessibility-api@0.6.3: resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} - dom-serializer@1.4.1: - resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} - dom-serializer@2.0.0: resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} domelementtype@2.3.0: resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} - domhandler@4.3.1: - resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} - engines: {node: '>= 4'} - domhandler@5.0.3: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} - domutils@2.8.0: - resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} - domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} @@ -6799,8 +7019,11 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - effect@3.19.14: - resolution: {integrity: sha512-3vwdq0zlvQOxXzXNKRIPKTqZNMyGCdaFUBfMPqpsyzZDre67kgC1EEHDV4EoQTovJ4w5fmJW756f86kkuz7WFA==} + effect@3.18.4: + resolution: {integrity: sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==} + + effect@3.19.19: + resolution: {integrity: sha512-Yc8U/SVXo2dHnaP7zNBlAo83h/nzSJpi7vph6Hzyl4ulgMBIgPmz3UzOjb9sBgpFE00gC0iETR244sfXDNLHRg==} ejs@3.1.10: resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} @@ -6810,25 +7033,25 @@ packages: electron-builder-squirrel-windows@26.4.0: resolution: {integrity: sha512-7dvalY38xBzWNaoOJ4sqy2aGIEpl2S1gLPkkB0MHu1Hu5xKQ82il1mKSFlXs6fLpXUso/NmyjdHGlSHDRoG8/w==} - electron-builder@26.3.1: - resolution: {integrity: sha512-e8utkPlf+VF94KX1M6/qZqCXsQMLKEASg+DNO5JWLtPZeKkvXS9Oyac8hb6HelvlGzEP02N7IDX6UFGjmvV66g==} + electron-builder@26.8.1: + resolution: {integrity: sha512-uWhx1r74NGpCagG0ULs/P9Nqv2nsoo+7eo4fLUOB8L8MdWltq9odW/uuLXMFCDGnPafknYLZgjNX0ZIFRzOQAw==} engines: {node: '>=14.0.0'} hasBin: true electron-devtools-installer@4.0.0: resolution: {integrity: sha512-9Tntu/jtfSn0n6N/ZI6IdvRqXpDyLQiDuuIbsBI+dL+1Ef7C8J2JwByw58P3TJiNeuqyV3ZkphpNWuZK5iSY2w==} - electron-publish@26.3.1: - resolution: {integrity: sha512-XYGYL/fpQULLW9slTVPelaUOGlKfOTmV2Uda3K+qzFzvNnkGJCj7L0nLVvMuj5cgxpAX+3BhO5HOUb4rv6jikA==} - electron-publish@26.3.4: resolution: {integrity: sha512-5/ouDPb73SkKuay2EXisPG60LTFTMNHWo2WLrK5GDphnWK9UC+yzYrzVeydj078Yk4WUXi0+TaaZsNd6Zt5k/A==} - electron-to-chromium@1.5.267: - resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} + electron-publish@26.8.1: + resolution: {integrity: sha512-q+jrSTIh/Cv4eGZa7oVR+grEJo/FoLMYBAnSL5GCtqwUpr1T+VgKB/dn1pnzxIxqD8S/jP1yilT9VrwCqINR4w==} - electron-updater@6.7.3: - resolution: {integrity: sha512-EgkT8Z9noqXKbwc3u5FkJA+r48jwZ5DTUiOkJMOTEEH//n5Am6wfQGz7nvSFEA2oIAMv9jRzn5JKTyWeSKOPgg==} + electron-to-chromium@1.5.307: + resolution: {integrity: sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==} + + electron-updater@6.8.3: + resolution: {integrity: sha512-Z6sgw3jgbikWKXei1ENdqFOxBP0WlXg3TtKfz0rgw2vIZFJUyI4pD7ZN7jrkm7EoMK+tcm/qTnPUdqfZukBlBQ==} electron-vite@5.0.0: resolution: {integrity: sha512-OHp/vjdlubNlhNkPkL/+3JD34ii5ov7M0GpuXEVdQeqdQ3ulvVR7Dg/rNBLfS5XPIFwgoBLDf9sjjrL+CuDyRQ==} @@ -6845,8 +7068,8 @@ packages: resolution: {integrity: sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==} engines: {node: '>=8.0.0'} - electron@39.2.7: - resolution: {integrity: sha512-KU0uFS6LSTh4aOIC3miolcbizOFP7N1M46VTYVfqIgFiuA2ilfNaOHLDS9tCMvwwHRowAsvqBrh9NgMXcTOHCQ==} + electron@40.8.0: + resolution: {integrity: sha512-WoPq0Nr9Yx3g7T6VnJXdwa/rr2+VRyH3a+K+ezfMKBlf6WjxE/LmhMQabKbb6yjm9RbZhJBRcYyoLph421O2mQ==} engines: {node: '>= 12.20.55'} hasBin: true @@ -6859,10 +7082,6 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - emojis-list@3.0.0: - resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} - engines: {node: '>= 4'} - empathic@2.0.0: resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} engines: {node: '>=14'} @@ -6877,8 +7096,8 @@ packages: end-of-stream@1.4.5: resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} - enhanced-resolve@5.18.4: - resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==} + enhanced-resolve@5.20.0: + resolution: {integrity: sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==} engines: {node: '>=10.13.0'} enquirer@2.3.6: @@ -6889,9 +7108,6 @@ packages: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} - entities@2.2.0: - resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} - entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} @@ -6956,8 +7172,8 @@ packages: engines: {node: '>=18'} hasBin: true - esbuild@0.27.2: - resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} + esbuild@0.27.3: + resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} engines: {node: '>=18'} hasBin: true @@ -7008,12 +7224,18 @@ packages: eslint-plugin-import-x: optional: true - eslint-plugin-better-tailwindcss@3.8.0: - resolution: {integrity: sha512-bRJVOb47d3ONK4Qb6Zt58ra37E8rMCexWy7RuNgLQZS/Ch92oLRFBupa/s+FB1O9XRdph9ZMCXBiEFKc4gAGTQ==} - engines: {node: ^20.11.0 || >=21.2.0} + eslint-plugin-better-tailwindcss@4.3.2: + resolution: {integrity: sha512-1DLX2QmHmOj3u667f8vEI0zKoRc0Y1qJt33tfIeIkpTyzWaz9b2GzWBLD4bR+WJ/kxzC0Skcbx7cMerRWQ6OYg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23.0.0} peerDependencies: - eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - tailwindcss: ^3.3.0 || ^4.1.6 + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 + oxlint: ^1.35.0 + tailwindcss: ^3.3.0 || ^4.1.17 + peerDependenciesMeta: + eslint: + optional: true + oxlint: + optional: true eslint-plugin-import-x@4.16.1: resolution: {integrity: sha512-vPZZsiOKaBAIATpFE2uMI4w5IRwdv/FpQ+qZZMR4E+PeOcM4OeoEbqxRMnywdxP19TyB/3h6QBB0EWon7letSQ==} @@ -7034,11 +7256,11 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 - eslint-plugin-perfectionist@5.3.0: - resolution: {integrity: sha512-Y3qYps6MpFrwyR+6DGd479GrgEA2PmCNWJ10Q6LnnfQfJTTtb0DNaKOjF5TAQc4wz/9mHwA8lx9ruR5EdFcylA==} + eslint-plugin-perfectionist@5.6.0: + resolution: {integrity: sha512-pxrLrfRp5wl1Vol1fAEa/G5yTXxefTPJjz07qC7a8iWFXcOZNuWBItMQ2OtTzfQIvMq6bMyYcrzc3Wz++na55Q==} engines: {node: ^20.0.0 || >=22.0.0} peerDependencies: - eslint: '>=8.45.0' + eslint: ^8.45.0 || ^9.0.0 || ^10.0.0 eslint-plugin-react-hooks@7.0.1: resolution: {integrity: sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==} @@ -7068,6 +7290,10 @@ packages: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + eslint@9.39.2: resolution: {integrity: sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -7106,9 +7332,6 @@ packages: estree-util-is-identifier-name@3.0.0: resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} - estree-walker@0.6.1: - resolution: {integrity: sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==} - estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} @@ -7130,6 +7353,9 @@ packages: eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + events-universal@1.0.1: + resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==} + events@3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} @@ -7178,6 +7404,9 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + fast-glob@3.3.3: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} @@ -7188,9 +7417,18 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-string-truncated-width@3.0.3: + resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} + + fast-string-width@3.0.2: + resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} + fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fast-wrap-ansi@0.2.0: + resolution: {integrity: sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w==} + fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} @@ -7218,17 +7456,11 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} - file-loader@6.2.0: - resolution: {integrity: sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==} - engines: {node: '>= 10.13.0'} - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 - file-uri-to-path@1.0.0: resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - filelist@1.0.4: - resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + filelist@1.0.6: + resolution: {integrity: sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==} fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} @@ -7275,8 +7507,8 @@ packages: resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} hasBin: true - flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + flatted@3.3.4: + resolution: {integrity: sha512-3+mMldrTAPdta5kjX2G2J7iX4zxtnwpdA8Tr2ZSjkyPSanvbZAcy6flmtnXbEybHrDcU9641lxrMfFuUxVz9vA==} follow-redirects@1.15.11: resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} @@ -7295,17 +7527,10 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} - form-data-encoder@1.7.2: - resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==} - form-data@4.0.5: resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} engines: {node: '>= 6'} - formdata-node@4.4.1: - resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} - engines: {node: '>= 12.20'} - formdata-polyfill@4.0.10: resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} engines: {node: '>=12.20.0'} @@ -7335,8 +7560,8 @@ packages: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} - fs-extra@11.3.3: - resolution: {integrity: sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==} + fs-extra@11.3.4: + resolution: {integrity: sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==} engines: {node: '>=14.14'} fs-extra@7.0.1: @@ -7362,11 +7587,6 @@ packages: fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -7382,6 +7602,9 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + generate-function@2.3.1: + resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} + generator-function@2.0.1: resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} engines: {node: '>= 0.4'} @@ -7397,14 +7620,17 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - get-east-asian-width@1.4.0: - resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} + get-east-asian-width@1.5.0: + resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} engines: {node: '>=18'} get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} + get-port-please@3.2.0: + resolution: {integrity: sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==} + get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} @@ -7417,8 +7643,8 @@ packages: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} - get-tsconfig@4.13.0: - resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + get-tsconfig@4.13.6: + resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==} giget@2.0.0: resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} @@ -7443,15 +7669,9 @@ packages: deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true - glob@11.1.0: - resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==} - engines: {node: 20 || >=22} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - hasBin: true - - glob@13.0.0: - resolution: {integrity: sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==} - engines: {node: 20 || >=22} + glob@13.0.6: + resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} + engines: {node: 18 || 20 || >=22} glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} @@ -7478,8 +7698,8 @@ packages: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} - globals@17.0.0: - resolution: {integrity: sha512-gv5BeD2EssA793rlFWVPMMCqefTlpusw6/2TbAVMy0FzcG8wKJn4O+NqJ4+XWmmwrayJgw5TzrmWjFgmz1XPqw==} + globals@17.4.0: + resolution: {integrity: sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw==} engines: {node: '>=18'} globalthis@1.0.4: @@ -7490,8 +7710,8 @@ packages: resolution: {integrity: sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==} engines: {node: '>=18'} - globby@16.0.0: - resolution: {integrity: sha512-ejy4TJFga99yW6Q0uhM3pFawKWZmtZzZD/v/GwI5+9bCV5Ew+D2pSND6W7fUes5UykqSsJkUfxFVdRh7Q1+P3Q==} + globby@16.1.1: + resolution: {integrity: sha512-dW7vl+yiAJSp6aCekaVnVJxurRv7DCOLyXqEG3RYMYUg7AuJ2jCqPkZTA8ooqC2vtnkaMcV5WfFBMuEnTu1OQg==} engines: {node: '>=20'} globrex@0.1.2: @@ -7513,6 +7733,12 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + grammex@3.1.12: + resolution: {integrity: sha512-6ufJOsSA7LcQehIJNCO7HIBykfM7DXQual0Ny780/DEcJIpBlHRvcqEBWGPYd7hrXL2GJ3oJI1MIhaXjWmLQOQ==} + + graphmatch@1.1.1: + resolution: {integrity: sha512-5ykVn/EXM1hF0XCaWh05VbYvEiOL2lY1kBxZtaYsyvjp7cmWOU1XsAdfQBwClraEofXDT197lFbXOEVMHpvQOg==} + has-bigints@1.1.0: resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} engines: {node: '>= 0.4'} @@ -7563,6 +7789,10 @@ packages: resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} engines: {node: '>=0.10.0'} + hono@4.11.4: + resolution: {integrity: sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA==} + engines: {node: '>=16.9.0'} + hosted-git-info@4.1.0: resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} engines: {node: '>=10'} @@ -7617,6 +7847,9 @@ packages: engines: {node: '>=12'} hasBin: true + http-status-codes@2.3.0: + resolution: {integrity: sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==} + http2-wrapper@1.0.3: resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} engines: {node: '>=10.19.0'} @@ -7625,9 +7858,6 @@ packages: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} - humanize-ms@1.2.1: - resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} - iconv-corefoundation@1.1.7: resolution: {integrity: sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==} engines: {node: ^8.11.2 || >=10} @@ -7641,13 +7871,10 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} - iconv-lite@0.7.1: - resolution: {integrity: sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==} + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} engines: {node: '>=0.10.0'} - icss-replace-symbols@1.1.0: - resolution: {integrity: sha512-chIaY3Vh2mh2Q3RGXttaDIzeiPvaVXJ+C4DAh/w3c37SKZ/U6PGMmuicR2EQQp9bKG8zLMCl7I+PtIoOOPp8Gg==} - icss-utils@5.1.0: resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} engines: {node: ^10 || ^12 || >= 14} @@ -7672,18 +7899,10 @@ packages: immediate@3.0.6: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} - import-cwd@3.0.0: - resolution: {integrity: sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==} - engines: {node: '>=8'} - import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} - import-from@3.0.0: - resolution: {integrity: sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==} - engines: {node: '>=8'} - imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -7856,6 +8075,9 @@ packages: resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} engines: {node: '>=0.10.0'} + is-property@1.0.2: + resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} + is-reference@1.2.1: resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} @@ -7871,6 +8093,10 @@ packages: resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} engines: {node: '>= 0.4'} + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + is-string@1.1.1: resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} engines: {node: '>= 0.4'} @@ -7915,8 +8141,8 @@ packages: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} - is-wsl@3.1.0: - resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} engines: {node: '>=16'} isarray@1.0.0: @@ -7933,16 +8159,16 @@ packages: resolution: {integrity: sha512-gnWD14Jh3FzS3CPhF0AxNOJ8CxqeblPTADzI38r0wt8ZyQl5edpy75myt08EG2oKvpyiqSqsx+Wkz9vtkbTqYQ==} engines: {node: '>= 18.0.0'} - isbot@5.1.32: - resolution: {integrity: sha512-VNfjM73zz2IBZmdShMfAUg10prm6t7HFUQmNAEOAVS4YH92ZrZcvkMcGX6cIgBJAzWDzPent/EeAtYEHNPNPBQ==} + isbot@5.1.35: + resolution: {integrity: sha512-waFfC72ZNfwLLuJ2iLaoVaqcNo+CAaLR7xCpAn0Y5WfGzkNHv7ZN39Vbi1y+kb+Zs46XHOX3tZNExroFUPX+Kg==} engines: {node: '>=18'} isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - isexe@3.1.1: - resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==} - engines: {node: '>=16'} + isexe@3.1.5: + resolution: {integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==} + engines: {node: '>=18'} isomorphic-ws@5.0.0: resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==} @@ -7956,14 +8182,6 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - jackspeak@4.1.1: - resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} - engines: {node: 20 || >=22} - - jackspeak@4.2.3: - resolution: {integrity: sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==} - engines: {node: 20 || >=22} - jake@10.9.4: resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==} engines: {node: '>=10'} @@ -7985,8 +8203,8 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true - jose@6.1.3: - resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} + jose@6.2.0: + resolution: {integrity: sha512-xsfE1TcSCbUdo6U07tR0mvhg0flGxU8tPLbF03mirl2ukGQENhUg4ubGYQnhVH0b5stLlPM+WOqDkEl1R1y5sQ==} joycon@3.1.1: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} @@ -8029,6 +8247,9 @@ packages: json-stringify-safe@5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + json-with-bigint@3.5.7: + resolution: {integrity: sha512-7ei3MdAI5+fJPVnKlW77TKNKwQ5ppSzWvhPuSuINT/GYW9ZOC1eRKOuhV9yHG5aEsUPj9BBx5JIekkmoLHxZOw==} + json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} @@ -8068,10 +8289,6 @@ packages: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} - kleur@4.1.5: - resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} - engines: {node: '>=6'} - koa-compose@4.1.0: resolution: {integrity: sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==} @@ -8096,6 +8313,10 @@ packages: lazy-val@1.0.5: resolution: {integrity: sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==} + lazystream@1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -8108,74 +8329,74 @@ packages: lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} - lightningcss-android-arm64@1.30.2: - resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + lightningcss-android-arm64@1.31.1: + resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [android] - lightningcss-darwin-arm64@1.30.2: - resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} + lightningcss-darwin-arm64@1.31.1: + resolution: {integrity: sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.30.2: - resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} + lightningcss-darwin-x64@1.31.1: + resolution: {integrity: sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.30.2: - resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} + lightningcss-freebsd-x64@1.31.1: + resolution: {integrity: sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.30.2: - resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} + lightningcss-linux-arm-gnueabihf@1.31.1: + resolution: {integrity: sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.30.2: - resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} + lightningcss-linux-arm64-gnu@1.31.1: + resolution: {integrity: sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - lightningcss-linux-arm64-musl@1.30.2: - resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} + lightningcss-linux-arm64-musl@1.31.1: + resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - lightningcss-linux-x64-gnu@1.30.2: - resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} + lightningcss-linux-x64-gnu@1.31.1: + resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - lightningcss-linux-x64-musl@1.30.2: - resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} + lightningcss-linux-x64-musl@1.31.1: + resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - lightningcss-win32-arm64-msvc@1.30.2: - resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} + lightningcss-win32-arm64-msvc@1.31.1: + resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] - lightningcss-win32-x64-msvc@1.30.2: - resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} + lightningcss-win32-x64-msvc@1.31.1: + resolution: {integrity: sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss@1.30.2: - resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} + lightningcss@1.31.1: + resolution: {integrity: sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==} engines: {node: '>= 12.0.0'} lilconfig@2.1.0: @@ -8206,10 +8427,6 @@ packages: resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} engines: {node: '>=6.11.5'} - loader-utils@2.0.4: - resolution: {integrity: sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==} - engines: {node: '>=8.9.0'} - loader-utils@3.3.1: resolution: {integrity: sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==} engines: {node: '>= 12.13.0'} @@ -8238,15 +8455,9 @@ packages: resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead. - lodash.memoize@4.1.2: - resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} - lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - lodash.uniq@4.5.0: - resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} - lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -8268,6 +8479,9 @@ packages: long-timeout@0.1.1: resolution: {integrity: sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w==} + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} @@ -8288,8 +8502,8 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.2.4: - resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==} + lru-cache@11.2.6: + resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==} engines: {node: 20 || >=22} lru-cache@5.1.1: @@ -8299,6 +8513,10 @@ packages: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} + lru.min@1.1.4: + resolution: {integrity: sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==} + engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} + luxon@3.7.2: resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==} engines: {node: '>=12'} @@ -8344,8 +8562,8 @@ packages: mdast-util-find-and-replace@3.0.2: resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} - mdast-util-from-markdown@2.0.2: - resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + mdast-util-from-markdown@2.0.3: + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} mdast-util-gfm-autolink-literal@2.0.1: resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} @@ -8386,9 +8604,6 @@ packages: mdast-util-to-string@4.0.0: resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} - mdn-data@2.0.14: - resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==} - mdn-data@2.0.28: resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} @@ -8406,6 +8621,9 @@ packages: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} + memory-pager@1.5.0: + resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==} + merge-descriptors@1.0.3: resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} @@ -8563,29 +8781,25 @@ packages: resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==} hasBin: true - minimatch@10.1.1: - resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} - engines: {node: 20 || >=22} - - minimatch@10.2.1: - resolution: {integrity: sha512-MClCe8IL5nRRmawL6ib/eT4oLyeKMGCghibcDWK+J0hh0Q8kqSdia6BvbRMVk6mPa6WqUa5uR2oxt6C5jd533A==} - engines: {node: 20 || >=22} + minimatch@10.2.4: + resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} + engines: {node: 18 || 20 || >=22} - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} engines: {node: '>=10'} - minimatch@9.0.3: - resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} - engines: {node: '>=16 || 14 >=14.17'} - minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} + engines: {node: '>=16 || 14 >=14.17'} + minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -8597,8 +8811,8 @@ packages: resolution: {integrity: sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ==} engines: {node: ^18.17.0 || >=20.5.0} - minipass-fetch@5.0.0: - resolution: {integrity: sha512-fiCdUALipqgPWrOVTz9fw0XhcazULXOSU6ie40DDbX1F49p1dBrSRBuswndTx1x3vEb/g0FT7vC4c4C2u/mh3A==} + minipass-fetch@5.0.2: + resolution: {integrity: sha512-2d0q2a8eCi2IRg/IGubCNRJoYbA1+YPXAzQVRFmB45gdGZafyivnZ5YSEfo3JikbjGxOdntGFvBQGqaSMXlAFQ==} engines: {node: ^20.17.0 || >=22.9.0} minipass-flush@1.0.5: @@ -8613,6 +8827,10 @@ packages: resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} engines: {node: '>=8'} + minipass-sized@2.0.0: + resolution: {integrity: sha512-zSsHhto5BcUVM2m1LurnXY6M//cGhVaegT71OfOXoprxT6o780GZd792ea6FfrQkuU4usHZIUczAQMRUE2plzA==} + engines: {node: '>=8'} + minipass@3.3.6: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} engines: {node: '>=8'} @@ -8621,8 +8839,8 @@ packages: resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} engines: {node: '>=8'} - minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} minizlib@2.1.2: @@ -8645,12 +8863,39 @@ packages: engines: {node: '>=10'} hasBin: true - mlly@1.8.0: - resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} + mlly@1.8.1: + resolution: {integrity: sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ==} - mri@1.2.0: - resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} - engines: {node: '>=4'} + mongodb-connection-string-url@7.0.1: + resolution: {integrity: sha512-h0AZ9A7IDVwwHyMxmdMXKy+9oNlF0zFoahHiX3vQ8e3KFcSP3VmsmfvtRSuLPxmyv2vjIDxqty8smTgie/SNRQ==} + engines: {node: '>=20.19.0'} + + mongodb@7.1.0: + resolution: {integrity: sha512-kMfnKunbolQYwCIyrkxNJFB4Ypy91pYqua5NargS/f8ODNSJxT03ZU3n1JqL4mCzbSih8tvmMEMLpKTT7x5gCg==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@aws-sdk/credential-providers': ^3.806.0 + '@mongodb-js/zstd': ^7.0.0 + gcp-metadata: ^7.0.1 + kerberos: ^7.0.0 + mongodb-client-encryption: '>=7.0.0 <7.1.0' + snappy: ^7.3.2 + socks: ^2.8.6 + peerDependenciesMeta: + '@aws-sdk/credential-providers': + optional: true + '@mongodb-js/zstd': + optional: true + gcp-metadata: + optional: true + kerberos: + optional: true + mongodb-client-encryption: + optional: true + snappy: + optional: true + socks: + optional: true ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} @@ -8676,16 +8921,24 @@ packages: resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==} engines: {node: ^20.17.0 || >=22.9.0} + mysql2@3.15.3: + resolution: {integrity: sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==} + engines: {node: '>= 8.0'} + mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + named-placeholders@1.1.6: + resolution: {integrity: sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==} + engines: {node: '>=8.0.0'} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - nanostores@1.1.0: - resolution: {integrity: sha512-yJBmDJr18xy47dbNVlHcgdPrulSn1nhSE6Ns9vTG+Nx9VPT6iV1MD6aQFp/t52zpf82FhLLTXAXr30NuCnxvwA==} + nanostores@1.1.1: + resolution: {integrity: sha512-EYJqS25r2iBeTtGQCHidXl1VfZ1jXM7Q04zXJOrMlxVVmD0ptxJaNux92n1mJ7c5lN3zTq12MhH/8x59nP+qmg==} engines: {node: ^20.0.0 || >=22.0.0} napi-build-utils@2.0.0: @@ -8721,8 +8974,8 @@ packages: resolution: {integrity: sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ==} engines: {node: '>=10'} - node-abi@4.24.0: - resolution: {integrity: sha512-u2EC1CeNe25uVtX3EZbdQ275c74zdZmmpzrHEQh2aIYqoVjlglfUpOX9YY85x1nlBydEKDVaSmMNhR7N82Qj8A==} + node-abi@4.26.0: + resolution: {integrity: sha512-8QwIZqikRvDIkXS2S93LjzhsSPJuIbfaMETWH+Bx8oOT9Sa9UsUtBFQlc3gBNd1+QINjaTloitXr1W3dQLi9Iw==} engines: {node: '>=22.12.0'} node-addon-api@1.7.2: @@ -8739,6 +8992,10 @@ packages: engines: {node: '>=10.5.0'} deprecated: Use your platform's native DOMException instead + node-exports-info@1.6.0: + resolution: {integrity: sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==} + engines: {node: '>= 0.4'} + node-fetch-native@1.6.7: resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} @@ -8771,8 +9028,8 @@ packages: node-machine-id@1.1.12: resolution: {integrity: sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==} - node-releases@2.0.27: - resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + node-releases@2.0.36: + resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} node-schedule@2.1.1: resolution: {integrity: sha512-OXdegQq03OmXEjt2hZP33W2YPs/E5BcFQks46+G2gAxs4gHOIVD1u7EqlYLYSKsaIpyKCK9Gbk0ta1/gjRSMRQ==} @@ -8810,12 +9067,12 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - nx@22.3.3: - resolution: {integrity: sha512-pOxtKWUfvf0oD8Geqs8D89Q2xpstRTaSY+F6Ut/Wd0GnEjUjO32SS1ymAM6WggGPHDZN4qpNrd5cfIxQmAbRLg==} + nx@22.5.4: + resolution: {integrity: sha512-L8wL7uCjnmpyvq4r2mN9s+oriUE4lY+mX9VgOpjj0ucRd5nzaEaBQppVs0zQGkbKC0BnHS8PGtnAglspd5Gh1Q==} hasBin: true peerDependencies: - '@swc-node/register': ^1.8.0 - '@swc/core': ^1.3.85 + '@swc-node/register': ^1.11.1 + '@swc/core': ^1.15.8 peerDependenciesMeta: '@swc-node/register': optional: true @@ -8884,12 +9141,15 @@ packages: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} - openai@4.77.0: - resolution: {integrity: sha512-WWacavtns/7pCUkOWvQIjyOfcdr9X+9n9Vvb0zFeKVDAqwCMDHB+iSr24SVaBAhplvSG6JrRXFpcNM9gWhOGIw==} + openai@6.27.0: + resolution: {integrity: sha512-osTKySlrdYrLYTt0zjhY8yp0JUBmWDCN+Q+QxsV4xMQnnoVFpylgKGgxwN8sSdTNw0G4y+WUXs4eCMWpyDNWZQ==} hasBin: true peerDependencies: - zod: ^3.23.8 + ws: ^8.18.0 + zod: ^3.25 || ^4.0 peerDependenciesMeta: + ws: + optional: true zod: optional: true @@ -8917,17 +9177,13 @@ packages: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} - oxc-resolver@11.16.2: - resolution: {integrity: sha512-Uy76u47vwhhF7VAmVY61Srn+ouiOobf45MU9vGct9GD2ARy6hKoqEElyHDB0L+4JOM6VLuZ431KiLwyjI/A21g==} + oxc-resolver@11.19.1: + resolution: {integrity: sha512-qE/CIg/spwrTBFt5aKmwe3ifeDdLfA2NESN30E42X/lII5ClF8V7Wt6WIJhcGZjp0/Q+nQ+9vgxGk//xZNX2hg==} p-cancelable@2.1.1: resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} engines: {node: '>=8'} - p-finally@1.0.0: - resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} - engines: {node: '>=4'} - p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -8948,14 +9204,6 @@ packages: resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==} engines: {node: '>=18'} - p-queue@6.6.2: - resolution: {integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==} - engines: {node: '>=8'} - - p-timeout@3.2.0: - resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==} - engines: {node: '>=8'} - p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} @@ -9004,9 +9252,9 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} - path-scurry@2.0.1: - resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==} - engines: {node: 20 || >=22} + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} path-to-regexp@0.1.12: resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} @@ -9033,33 +9281,36 @@ packages: pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + perfect-debounce@2.1.0: resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} pg-cloudflare@1.3.0: resolution: {integrity: sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==} - pg-connection-string@2.11.0: - resolution: {integrity: sha512-kecgoJwhOpxYU21rZjULrmrBJ698U2RxXofKVzOn5UDj61BPj/qMb7diYUR1nLScCDbrztQFl1TaQZT0t1EtzQ==} + pg-connection-string@2.12.0: + resolution: {integrity: sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==} pg-int8@1.0.1: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} engines: {node: '>=4.0.0'} - pg-pool@3.11.0: - resolution: {integrity: sha512-MJYfvHwtGp870aeusDh+hg9apvOe2zmpZJpyt+BMtzUWlVqbhFmMK6bOBXLBUPd7iRtIF9fZplDc7KrPN3PN7w==} + pg-pool@3.13.0: + resolution: {integrity: sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==} peerDependencies: pg: '>=8.0' - pg-protocol@1.11.0: - resolution: {integrity: sha512-pfsxk2M9M3BuGgDOfuy37VNRRX3jmKgMjcvAcWqNDpZSf4cUmv8HSOl5ViRQFsfARFn0KuUQTgLxVMbNq5NW3g==} + pg-protocol@1.13.0: + resolution: {integrity: sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==} pg-types@2.2.0: resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} engines: {node: '>=4'} - pg@8.18.0: - resolution: {integrity: sha512-xqrUDL1b9MbkydY/s+VZ6v+xiMUmOUk7SS9d/1kpyQxoJ6U9AO1oIJyUWVZojbfe5Cc/oluutcgFG4L9RDP1iQ==} + pg@8.20.0: + resolution: {integrity: sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==} engines: {node: '>= 16.0.0'} peerDependencies: pg-native: '>=3.0.1' @@ -9085,14 +9336,6 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} - pify@2.3.0: - resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} - engines: {node: '>=0.10.0'} - - pify@5.0.0: - resolution: {integrity: sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==} - engines: {node: '>=10'} - pirates@4.0.7: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} @@ -9107,16 +9350,6 @@ packages: pkg-types@2.3.0: resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} - playwright-core@1.57.0: - resolution: {integrity: sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==} - engines: {node: '>=18'} - hasBin: true - - playwright@1.57.0: - resolution: {integrity: sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==} - engines: {node: '>=18'} - hasBin: true - plist@3.1.0: resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} engines: {node: '>=10.4.0'} @@ -9129,130 +9362,35 @@ packages: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} - postcss-calc@8.2.4: - resolution: {integrity: sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==} + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} peerDependencies: - postcss: ^8.2.2 + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true - postcss-colormin@5.3.1: - resolution: {integrity: sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==} - engines: {node: ^10 || ^12 || >=14.0} + postcss-modules-extract-imports@3.1.0: + resolution: {integrity: sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==} + engines: {node: ^10 || ^12 || >= 14} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.1.0 - postcss-convert-values@5.1.3: - resolution: {integrity: sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==} - engines: {node: ^10 || ^12 || >=14.0} + postcss-modules-local-by-default@4.2.0: + resolution: {integrity: sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==} + engines: {node: ^10 || ^12 || >= 14} peerDependencies: - postcss: ^8.2.15 - - postcss-discard-comments@5.1.2: - resolution: {integrity: sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - postcss-discard-duplicates@5.1.0: - resolution: {integrity: sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - postcss-discard-empty@5.1.1: - resolution: {integrity: sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - postcss-discard-overridden@5.1.0: - resolution: {integrity: sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - postcss-import@16.1.1: - resolution: {integrity: sha512-2xVS1NCZAfjtVdvXiyegxzJ447GyqCeEI5V7ApgQVOWnros1p5lGNovJNapwPpMombyFBfqDwt7AD3n2l0KOfQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - postcss: ^8.0.0 - - postcss-load-config@3.1.4: - resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} - engines: {node: '>= 10'} - peerDependencies: - postcss: '>=8.0.9' - ts-node: '>=9.0.0' - peerDependenciesMeta: - postcss: - optional: true - ts-node: - optional: true - - postcss-load-config@6.0.1: - resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} - engines: {node: '>= 18'} - peerDependencies: - jiti: '>=1.21.0' - postcss: '>=8.0.9' - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - jiti: - optional: true - postcss: - optional: true - tsx: - optional: true - yaml: - optional: true - - postcss-merge-longhand@5.1.7: - resolution: {integrity: sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - postcss-merge-rules@5.1.4: - resolution: {integrity: sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - postcss-minify-font-values@5.1.0: - resolution: {integrity: sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - postcss-minify-gradients@5.1.1: - resolution: {integrity: sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - postcss-minify-params@5.1.4: - resolution: {integrity: sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - postcss-minify-selectors@5.2.1: - resolution: {integrity: sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - postcss-modules-extract-imports@3.1.0: - resolution: {integrity: sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==} - engines: {node: ^10 || ^12 || >= 14} - peerDependencies: - postcss: ^8.1.0 - - postcss-modules-local-by-default@4.2.0: - resolution: {integrity: sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==} - engines: {node: ^10 || ^12 || >= 14} - peerDependencies: - postcss: ^8.1.0 + postcss: ^8.1.0 postcss-modules-scope@3.2.1: resolution: {integrity: sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==} @@ -9266,83 +9404,11 @@ packages: peerDependencies: postcss: ^8.1.0 - postcss-modules@4.3.1: - resolution: {integrity: sha512-ItUhSUxBBdNamkT3KzIZwYNNRFKmkJrofvC2nWab3CPKhYBQ1f27XXh1PAPE27Psx58jeelPsxWB/+og+KEH0Q==} + postcss-modules@6.0.1: + resolution: {integrity: sha512-zyo2sAkVvuZFFy0gc2+4O+xar5dYlaVy/ebO24KT0ftk/iJevSNyPyQellsBLlnccwh7f6V6Y4GvuKRYToNgpQ==} peerDependencies: postcss: ^8.0.0 - postcss-normalize-charset@5.1.0: - resolution: {integrity: sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - postcss-normalize-display-values@5.1.0: - resolution: {integrity: sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - postcss-normalize-positions@5.1.1: - resolution: {integrity: sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - postcss-normalize-repeat-style@5.1.1: - resolution: {integrity: sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - postcss-normalize-string@5.1.0: - resolution: {integrity: sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - postcss-normalize-timing-functions@5.1.0: - resolution: {integrity: sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - postcss-normalize-unicode@5.1.1: - resolution: {integrity: sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - postcss-normalize-url@5.1.0: - resolution: {integrity: sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - postcss-normalize-whitespace@5.1.1: - resolution: {integrity: sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - postcss-ordered-values@5.1.3: - resolution: {integrity: sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - postcss-reduce-initial@5.1.2: - resolution: {integrity: sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - postcss-reduce-transforms@5.1.0: - resolution: {integrity: sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - postcss-selector-parser@6.0.10: resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} engines: {node: '>=4'} @@ -9351,23 +9417,11 @@ packages: resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} engines: {node: '>=4'} - postcss-svgo@5.1.0: - resolution: {integrity: sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - - postcss-unique-selectors@5.1.1: - resolution: {integrity: sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + postcss@8.5.8: + resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} engines: {node: ^10 || ^12 || >=14} postgres-array@2.0.0: @@ -9386,13 +9440,17 @@ packages: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} engines: {node: '>=0.10.0'} + postgres@3.4.7: + resolution: {integrity: sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==} + engines: {node: '>=12'} + postject@1.0.0-alpha.6: resolution: {integrity: sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==} engines: {node: '>=14.0.0'} hasBin: true - preact@10.28.2: - resolution: {integrity: sha512-lbteaWGzGHdlIuiJ0l2Jq454m6kcpI1zNje6d8MlGAFlYvP2GO4ibnat7P74Esfz4sPTdM6UxtTwh/d3pwM9JA==} + preact@10.28.4: + resolution: {integrity: sha512-uKFfOHWuSNpRFVTnljsCluEFq57OKT+0QdOiQo8XWnQ/pSvg7OpX5eNOejELXJMWy+BwM2nobz0FkvzmnpCNsQ==} prebuild-install@7.1.3: resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} @@ -9404,16 +9462,6 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@3.6.2: - resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} - engines: {node: '>=14'} - hasBin: true - - prettier@3.7.4: - resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==} - engines: {node: '>=14'} - hasBin: true - prettier@3.8.1: resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} engines: {node: '>=14'} @@ -9427,6 +9475,19 @@ packages: resolution: {integrity: sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + prisma@7.4.2: + resolution: {integrity: sha512-2bP8Ruww3Q95Z2eH4Yqh4KAENRsj/SxbdknIVBfd6DmjPwmpsC4OVFMLOeHt6tM3Amh8ebjvstrUz3V/hOe1dA==} + engines: {node: ^20.19 || ^22.12 || >=24.0} + hasBin: true + peerDependencies: + better-sqlite3: '>=9.0.0' + typescript: '>=5.4.0' + peerDependenciesMeta: + better-sqlite3: + optional: true + typescript: + optional: true + proc-log@5.0.0: resolution: {integrity: sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==} engines: {node: ^18.17.0 || >=20.5.0} @@ -9438,6 +9499,10 @@ packages: process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + progress@2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} @@ -9449,10 +9514,6 @@ packages: resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} engines: {node: '>=10'} - promise.series@0.2.0: - resolution: {integrity: sha512-VWQJyU2bcDTgZw8kpfBpB/ejZASlCrzwz5f2hjb/zlujOEB4oeiAhHygAWq8ubsX2GVkD4kCU5V2dwOTaCY5EQ==} - engines: {node: '>=0.12'} - prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} @@ -9460,6 +9521,9 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + proper-lockfile@4.1.2: + resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} + property-information@7.1.0: resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} @@ -9470,8 +9534,8 @@ packages: proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - pump@3.0.3: - resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} @@ -9480,8 +9544,12 @@ packages: pure-rand@6.1.0: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} - qs@6.14.1: - resolution: {integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==} + qs@6.14.2: + resolution: {integrity: sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==} + engines: {node: '>=0.6'} + + qs@6.15.0: + resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} engines: {node: '>=0.6'} queue-microtask@1.2.3: @@ -9494,9 +9562,6 @@ packages: rambda@9.4.2: resolution: {integrity: sha512-++euMfxnl7OgaEKwXh9QqThOjMeta2HH001N1v4mYQzBjJBnmXBh2BCK6dZAbICFVXOFUVD3xFG0R3ZPU0mxXw==} - randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - range-parser@1.2.1: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} @@ -9512,14 +9577,14 @@ packages: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true - react-aria-components@1.14.0: - resolution: {integrity: sha512-u21N/yS6Ozk9P9oO8wxMNZSFiPk6F3aAE9w6aN7pseGPApkjXqDyPNCnTsTTvMtVL3QRBkVbf7fJ5yi2hksVEg==} + react-aria-components@1.16.0: + resolution: {integrity: sha512-MjHbTLpMFzzD2Tv5KbeXoZwPczuUWZcRavVvQQlNHRtXHH38D+sToMEYpNeir7Wh3K/XWtzeX3EujfJW6QNkrw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - react-aria@3.45.0: - resolution: {integrity: sha512-QsdWIhhm3+IAiW3SU9tEm7pmeIcveEPAO6riZ1IUF78ZCvH/47nU4zVztcdtYmwYWSL4168QxLncWKtlMva3BA==} + react-aria@3.47.0: + resolution: {integrity: sha512-nvahimIqdByl/PXk/xPkG30LPRzcin+/Uk0uFfwbbKRRFC9aa22a6BRULZLqVHwa9GaNyKe6CDUxO1Dde4v0kA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 @@ -9533,16 +9598,15 @@ packages: resolution: {integrity: sha512-+NRMYs2DyTP4/tqWz371Oo50JqmWltR1h2gcdgUMAWZJIAvrd0/SqlCfx7tpzpl/s36rzw6qH2MjoNrxtRNYhA==} engines: {node: ^20.9.0 || >=22} - react-dom@19.2.3: - resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==} + react-dom@19.2.4: + resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} peerDependencies: - react: ^19.2.3 + react: ^19.2.4 - react-error-boundary@6.0.2: - resolution: {integrity: sha512-yvWErn55ag/ywZEFqYpXYX9rxIDPIabXIX25F184KY3F5Szk2x/cVieOflw5R47ltN3KzWOw82Lmlb4vNjyn9A==} + react-error-boundary@6.1.1: + resolution: {integrity: sha512-BrYwPOdXi5mqkk5lw+Uvt0ThHx32rCt3BkukS4X23A2AIWDPSGX6iaWTc0y9TU/mHDA/6qOSGel+B2ERkOvD1w==} peerDependencies: react: ^18.0.0 || ^19.0.0 - react-dom: ^18.0.0 || ^19.0.0 react-hook-form@7.70.0: resolution: {integrity: sha512-COOMajS4FI3Wuwrs3GPpi/Jeef/5W1DRR84Yl5/ShlT3dKVFUfoGiEZ/QE6Uw8P4T2/CLJdcTVYKvWBMQTEpvw==} @@ -9550,8 +9614,8 @@ packages: peerDependencies: react: ^16.8.0 || ^17 || ^18 || ^19 - react-icons@5.5.0: - resolution: {integrity: sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==} + react-icons@5.6.0: + resolution: {integrity: sha512-RH93p5ki6LfOiIt0UtDyNg/cee+HLVR6cHHtW3wALfo+eOHTp8RnU2kRkI6E+H19zMIs03DyxUG/GfZMOGvmiA==} peerDependencies: react: '*' @@ -9574,39 +9638,26 @@ packages: resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} engines: {node: '>=0.10.0'} - react-resizable-panels@4.3.0: - resolution: {integrity: sha512-F8LGxzK3tq5N4m1oSvTZSDTH+QUhr5qPLuFhPyxVrOPqCFGZ1j2KOSx2K96aiKC4UI4kGR3/NKHczCumTgxVxA==} + react-resizable-panels@4.7.1: + resolution: {integrity: sha512-RYBRgvdZhnUds5jJWYr1up0hYFofgN1dqSwhxfBl9Savoxms0gyGF0AfaXskhxTYkXrlwc+TlQPe5UkoV+1neg==} peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - react-scan@0.4.3: - resolution: {integrity: sha512-jhAQuQ1nja6HUYrSpbmNFHqZPsRCXk8Yqu0lHoRIw9eb8N96uTfXCpVyQhTTnJ/nWqnwuvxbpKVG/oWZT8+iTQ==} + react-scan@0.5.3: + resolution: {integrity: sha512-qde9PupmUf0L3MU1H6bjmoukZNbCXdMyTEwP4Gh8RQ4rZPd2GGNBgEKWszwLm96E8k+sGtMpc0B9P0KyFDP6Bw==} hasBin: true peerDependencies: - '@remix-run/react': '>=1.0.0' - next: '>=13.0.0' react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-router: ^5.0.0 || ^6.0.0 || ^7.0.0 - react-router-dom: ^5.0.0 || ^6.0.0 || ^7.0.0 - peerDependenciesMeta: - '@remix-run/react': - optional: true - next: - optional: true - react-router: - optional: true - react-router-dom: - optional: true react-simple-animate@3.5.3: resolution: {integrity: sha512-Ob+SmB5J1tXDEZyOe2Hf950K4M8VaWBBmQ3cS2BUnTORqHjhK0iKG8fB+bo47ZL15t8d3g/Y0roiqH05UBjG7A==} peerDependencies: react-dom: ^16.8.0 || ^17 || ^18 || ^19 - react-stately@3.43.0: - resolution: {integrity: sha512-dScb9fTL1tRtFODPnk/2rP0a9kp1C+7+40RArS0C7j0auAUmnrO/wDILojwQUso7/kkys4fP707fTwGJDeJ7vg==} + react-stately@3.45.0: + resolution: {integrity: sha512-G3bYr0BIiookpt4H05VeZUuVS/FslQAj2TeT8vDfCiL314Y+LtPXIPe/a3eamCA0wljy7z1EDYKV50Qbz7pcJg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 @@ -9615,17 +9666,14 @@ packages: peerDependencies: react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react@19.2.3: - resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} + react@19.2.4: + resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} engines: {node: '>=0.10.0'} read-binary-file-arch@1.0.6: resolution: {integrity: sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==} hasBin: true - read-cache@1.0.0: - resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} - read-yaml-file@2.1.0: resolution: {integrity: sha512-UkRNRIwnhG+y7hpqnycCL/xbTk7+ia9VuVTC0S+zVbwd65DI9eUpRMfsWIGrCWxTU/mi+JW8cHQCrv+zfCbEPQ==} engines: {node: '>=10.13'} @@ -9637,6 +9685,13 @@ packages: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} + readable-stream@4.7.0: + resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -9698,6 +9753,9 @@ packages: remark-stringify@11.0.0: resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + remeda@2.33.4: + resolution: {integrity: sha512-ygHswjlc/opg2VrtiYvUOPLjxjtdKvjGz1/plDhkG66hjNjFr1xmfrs2ClNFo/E6TyUFiwYNh53bKV26oBoMGQ==} + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -9744,8 +9802,9 @@ packages: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true - resolve@2.0.0-next.5: - resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + resolve@2.0.0-next.6: + resolution: {integrity: sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==} + engines: {node: '>= 0.4'} hasBin: true responselike@2.0.1: @@ -9779,23 +9838,14 @@ packages: resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==} engines: {node: '>=8.0'} - rollup-plugin-postcss@4.0.2: - resolution: {integrity: sha512-05EaY6zvZdmvPUDi3uCcAQoESDcYnv8ogJJQRp6V5kZ6J6P7uAVJlrTZcaaA20wTH527YTnKfkAoPxWI/jPp4w==} - engines: {node: '>=10'} - peerDependencies: - postcss: 8.x - rollup-plugin-typescript2@0.36.0: resolution: {integrity: sha512-NB2CSQDxSe9+Oe2ahZbf+B4bh7pHwjV5L+RSYpCu7Q5ROuN94F9b6ioWwKfz3ueL3KTtmX4o2MUH2cgHDIEUsw==} peerDependencies: rollup: '>=1.26.3' typescript: '>=2.4.0' - rollup-pluginutils@2.8.2: - resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} - - rollup@4.55.1: - resolution: {integrity: sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==} + rollup@4.59.0: + resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -9819,9 +9869,6 @@ packages: safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - safe-identifier@0.4.2: - resolution: {integrity: sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==} - safe-push-apply@1.0.0: resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} engines: {node: '>= 0.4'} @@ -9836,16 +9883,13 @@ packages: sanitize-filename@1.6.3: resolution: {integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==} - sax@1.4.3: - resolution: {integrity: sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==} + sax@1.5.0: + resolution: {integrity: sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==} + engines: {node: '>=11.0.0'} scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - schema-utils@3.3.0: - resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} - engines: {node: '>= 10.13.0'} - schema-utils@4.3.3: resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} engines: {node: '>= 10.13.0'} @@ -9874,11 +9918,6 @@ packages: engines: {node: '>=10'} hasBin: true - semver@7.7.3: - resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} - engines: {node: '>=10'} - hasBin: true - semver@7.7.4: resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} engines: {node: '>=10'} @@ -9888,21 +9927,21 @@ packages: resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} engines: {node: '>= 0.8.0'} + seq-queue@0.0.5: + resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} + serialize-error@7.0.1: resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} engines: {node: '>=10'} - serialize-javascript@6.0.2: - resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} - seroval-plugins@1.3.3: resolution: {integrity: sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w==} engines: {node: '>=10'} peerDependencies: seroval: ^1.0 - seroval-plugins@1.4.2: - resolution: {integrity: sha512-X7p4MEDTi+60o2sXZ4bnDBhgsUYDSkQEvzYZuJyFqWg9jcoPsHts5nrg5O956py2wyt28lUrBxk0M0/wU8URpA==} + seroval-plugins@1.5.0: + resolution: {integrity: sha512-EAHqADIQondwRZIdeW2I636zgsODzoBDwb3PT/+7TLDWyw1Dy/Xv7iGUIEXXav7usHDE9HVhOU61irI3EnyyHA==} engines: {node: '>=10'} peerDependencies: seroval: ^1.0 @@ -9911,8 +9950,8 @@ packages: resolution: {integrity: sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==} engines: {node: '>=10'} - seroval@1.4.2: - resolution: {integrity: sha512-N3HEHRCZYn3cQbsC4B5ldj9j+tHdf4JZoYPlcI4rRYu0Xy4qN8MQf1Z08EibzB0WpgRG5BGK08FTrmM66eSzKQ==} + seroval@1.5.0: + resolution: {integrity: sha512-OE4cvmJ1uSPrKorFIH9/w/Qwuvi/IMcGbv5RKgcJ/zjA/IohDLU6SVaxFN9FwajbP7nsX0dQqMDes1whk3y+yw==} engines: {node: '>=10'} serve-static@1.16.3: @@ -9922,6 +9961,9 @@ packages: set-cookie-parser@2.7.2: resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + set-cookie-parser@3.0.1: + resolution: {integrity: sha512-n7Z7dXZhJbwuAHhNzkTti6Aw9QDDjZtm3JTpTGATIdNzdQz5GuFs22w90BcvF4INfnrL5xrX3oGsuqO5Dx3A1Q==} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -10044,6 +10086,9 @@ packages: space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + sparse-bitfield@3.0.3: + resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==} + split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} @@ -10054,22 +10099,22 @@ packages: sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + sqlstring@2.3.3: + resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} + engines: {node: '>= 0.6'} + ssri@12.0.0: resolution: {integrity: sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==} engines: {node: ^18.17.0 || >=20.5.0} - ssri@13.0.0: - resolution: {integrity: sha512-yizwGBpbCn4YomB2lzhZqrHLJoqFGXihNbib3ozhqF/cIp5ue+xSmOQrjNasEE62hFxsCcg/V/z23t4n8jMEng==} + ssri@13.0.1: + resolution: {integrity: sha512-QUiRf1+u9wPTL/76GTYlKttDEBWV1ga9ZXW8BG6kfdeyyM8LGPix9gROyg9V2+P0xNyF3X2Go526xKFdMZrHSQ==} engines: {node: ^20.17.0 || >=22.9.0} stable-hash-x@0.2.0: resolution: {integrity: sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==} engines: {node: '>=12.0.0'} - stable@0.1.8: - resolution: {integrity: sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==} - deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility' - stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -10096,8 +10141,8 @@ packages: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} - storybook@10.1.11: - resolution: {integrity: sha512-pKP5jXJYM4OjvNklGuHKO53wOCAwfx79KvZyOWHoi9zXUH5WVMFUe/ZfWyxXG/GTcj0maRgHGUjq/0I43r0dDQ==} + storybook@10.2.16: + resolution: {integrity: sha512-Az1Qro0XjCBttsuO55H2aIGPYqGx00T8O3o29rLQswOyZhgAVY9H2EnJiVsfmSG1Kwt8qYTVv7VxzLlqDxropA==} hasBin: true peerDependencies: prettier: ^2 || ^3 @@ -10109,6 +10154,9 @@ packages: resolution: {integrity: sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==} engines: {node: '>=8.0'} + streamx@2.23.0: + resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==} + string-hash@1.1.3: resolution: {integrity: sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==} @@ -10160,8 +10208,8 @@ packages: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} - strip-ansi@7.1.2: - resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} engines: {node: '>=12'} strip-bom@3.0.0: @@ -10188,9 +10236,6 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - style-inject@0.3.0: - resolution: {integrity: sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==} - style-mod@4.1.3: resolution: {integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==} @@ -10200,12 +10245,6 @@ packages: style-to-object@1.0.14: resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} - stylehacks@5.1.1: - resolution: {integrity: sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - stylis@4.2.0: resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} @@ -10233,13 +10272,8 @@ packages: svg-parser@2.0.4: resolution: {integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==} - svgo@2.8.0: - resolution: {integrity: sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==} - engines: {node: '>=10.13.0'} - hasBin: true - - svgo@3.3.2: - resolution: {integrity: sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==} + svgo@3.3.3: + resolution: {integrity: sha512-+wn7I4p7YgJhHs38k2TNjy1vCfPIfLIJWR5MnCStsN8WuuTcBnRKcMHQLMM2ijxGZmDoZwNv8ipl5aTTen62ng==} engines: {node: '>=14.0.0'} hasBin: true @@ -10247,8 +10281,8 @@ packages: resolution: {integrity: sha512-4+kibROq06E7Yj3kEcCRN1Ki2C/5i+5P1B7An9iS9PO1BQY5VzWFuLhV7y7xNxkZjc8FEaLCh97NGzs/XBfOMQ==} hasBin: true - synckit@0.11.11: - resolution: {integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==} + synckit@0.11.12: + resolution: {integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==} engines: {node: ^14.18.0 || >=16.0.0} syncpack@13.0.4: @@ -10260,8 +10294,8 @@ packages: resolution: {integrity: sha512-FzD187HuFIZEyeR7Xy6sJbJll2d4SybS90satC8SKIuaNRC05CxMvdzN7BUsfDQffcnabckRM5OIcfArjsZ0mg==} engines: {node: '>=18.18'} - tailwind-merge@3.4.0: - resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} + tailwind-merge@3.5.0: + resolution: {integrity: sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==} tailwind-variants@3.2.2: resolution: {integrity: sha512-Mi4kHeMTLvKlM98XPnK+7HoBPmf4gygdFmqQPaDivc3DpYS6aIY6KiG/PgThrGvii5YZJqRsPz0aPyhoFzmZgg==} @@ -10278,8 +10312,8 @@ packages: peerDependencies: tailwindcss: ^4.0.0 - tailwindcss@4.1.18: - resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==} + tailwindcss@4.2.1: + resolution: {integrity: sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==} tapable@2.3.0: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} @@ -10292,15 +10326,20 @@ packages: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} engines: {node: '>=6'} + tar-stream@3.1.8: + resolution: {integrity: sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ==} + tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - tar@7.5.2: - resolution: {integrity: sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==} + tar@7.5.10: + resolution: {integrity: sha512-8mOPs1//5q/rlkNSPcCegA6hiHJYDmSLEI8aMH/CdSQJNWztHC9WHNam5zdQlfpTwB9Xp7IBEsHfV5LKMJGVAw==} engines: {node: '>=18'} - deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + + teex@1.0.1: + resolution: {integrity: sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==} temp-file@3.4.0: resolution: {integrity: sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==} @@ -10315,8 +10354,8 @@ packages: temporal-spec@0.3.0: resolution: {integrity: sha512-n+noVpIqz4hYgFSMOSiINNOUOMFtV5cZQNCmmszA6GiVFVRt3G7AqVyhXjhCSmowvQn+NsGn+jMDMKJYHd3bSQ==} - terser-webpack-plugin@5.3.16: - resolution: {integrity: sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==} + terser-webpack-plugin@5.3.17: + resolution: {integrity: sha512-YR7PtUp6GMU91BgSJmlaX/rS2lGDbAF7D+Wtq7hRO+MiljNmodYvqslzCFiYVAgW+Qoaaia/QUIP4lGXufjdZw==} engines: {node: '>= 10.13.0'} peerDependencies: '@swc/core': '*' @@ -10331,11 +10370,14 @@ packages: uglify-js: optional: true - terser@5.44.1: - resolution: {integrity: sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==} + terser@5.46.0: + resolution: {integrity: sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==} engines: {node: '>=10'} hasBin: true + text-decoder@1.2.7: + resolution: {integrity: sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==} + thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} @@ -10406,6 +10448,10 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + tr46@5.1.1: + resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} + engines: {node: '>=18'} + tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -10536,11 +10582,11 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} - typescript-eslint@8.52.0: - resolution: {integrity: sha512-atlQQJ2YkO4pfTVQmQ+wvYQwexPDOIgo+RaVcD7gHgzy/IQA+XTyuxNM9M9TVXvttkF7koBHmcwisKdOAf2EcA==} + typescript-eslint@8.56.1: + resolution: {integrity: sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' typescript@5.4.5: @@ -10553,24 +10599,24 @@ packages: engines: {node: '>=14.17'} hasBin: true - ufo@1.6.2: - resolution: {integrity: sha512-heMioaxBcG9+Znsda5Q8sQbWnLJSl98AFDXTO80wELWEzX3hordXsTdxrIfMQoO9IY1MEnoGoPjpoKpMj+Yx0Q==} + ufo@1.6.3: + resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} - undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - undici@7.18.2: - resolution: {integrity: sha512-y+8YjDFzWdQlSE9N5nzKMT3g4a5UBX1HKowfdXh0uvAnTaqqwqB92Jt4UXBAeKekDs5IaDKyJFR4X1gYVCgXcw==} + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + + undici@7.22.0: + resolution: {integrity: sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==} engines: {node: '>=20.18.1'} unicode-canonical-property-names-ecmascript@2.0.1: @@ -10680,8 +10726,8 @@ packages: url-join@4.0.1: resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} - use-debounce@10.0.6: - resolution: {integrity: sha512-C5OtPyhAZgVoteO9heXMTdW7v/IbFI+8bSVKYCJrSmiWWCLsbUxiBSp4t9v0hNBTGY97bT72ydDIDyGSFWfwXg==} + use-debounce@10.1.0: + resolution: {integrity: sha512-lu87Za35V3n/MyMoEpD5zJv0k7hCn0p+V/fK2kWD+3k2u3kOCwO593UArbczg1fhfs2rqPEnHpULJ3KmGdDzvg==} engines: {node: '>= 16.0.0'} peerDependencies: react: '*' @@ -10718,6 +10764,14 @@ packages: v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + valibot@1.2.0: + resolution: {integrity: sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==} + peerDependencies: + typescript: '>=5' + peerDependenciesMeta: + typescript: + optional: true + validate-html-nesting@1.2.4: resolution: {integrity: sha512-doQi7e8EJ2OWneSG1aZpJluS6A49aZM0+EICXWKm1i6WvqTLmq0tpUcImc4KTWG50mORO0C4YDBtOCSYvElftw==} @@ -10743,13 +10797,10 @@ packages: vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - vite-tsconfig-paths@6.0.3: - resolution: {integrity: sha512-7bL7FPX/DSviaZGYUKowWF1AiDVWjMjxNbE8lyaVGDezkedWqfGhlnQ4BZXre0ZN5P4kAgIJfAlgFDVyjrCIyg==} + vite-tsconfig-paths@6.1.1: + resolution: {integrity: sha512-2cihq7zliibCCZ8P9cKJrQBkfgdvcFkOOc3Y02o3GWUDLgqjWsZudaoiuOwO/gzTzy17cS5F7ZPo4bsnS4DGkg==} peerDependencies: vite: '*' - peerDependenciesMeta: - vite: - optional: true vite@7.3.1: resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} @@ -10845,8 +10896,8 @@ packages: w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} - watchpack@2.5.0: - resolution: {integrity: sha512-e6vZvY6xboSwLz2GD36c16+O/2Z6fKvIf4pOXptw2rY9MVwE/TXc6RGqxD3I3x0a28lwBY7DE+76uTPSsBrrCA==} + watchpack@2.5.1: + resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} engines: {node: '>=10.13.0'} wcwidth@1.0.1: @@ -10856,22 +10907,22 @@ packages: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} - web-streams-polyfill@4.0.0-beta.3: - resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==} - engines: {node: '>= 14'} - webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - webpack-sources@3.3.3: - resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==} + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + webpack-sources@3.3.4: + resolution: {integrity: sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==} engines: {node: '>=10.13.0'} webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - webpack@5.104.1: - resolution: {integrity: sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==} + webpack@5.105.4: + resolution: {integrity: sha512-jTywjboN9aHxFlToqb0K0Zs9SbBoW4zRUlGzI2tYNxVYcEi/IPpn+Xi4ye5jTLvX2YeLuic/IvxNot+Q1jMoOw==} engines: {node: '>=10.13.0'} hasBin: true peerDependencies: @@ -10885,6 +10936,10 @@ packages: engines: {node: '>=12'} deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation + whatwg-url@14.2.0: + resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} + engines: {node: '>=18'} + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -10900,8 +10955,8 @@ packages: resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} engines: {node: '>= 0.4'} - which-typed-array@1.1.19: - resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} + which-typed-array@1.1.20: + resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} engines: {node: '>= 0.4'} which@1.3.1: @@ -11039,6 +11094,13 @@ packages: resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} engines: {node: '>=18'} + zeptomatch@2.1.0: + resolution: {integrity: sha512-KiGErG2J0G82LSpniV0CtIzjlJ10E04j02VOudJsPyPwNZgGnRKQy7I1R7GMyg/QswnE4l7ohSGrQbQbjXPPDA==} + + zip-stream@6.0.1: + resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} + engines: {node: '>= 14'} + zod-validation-error@4.0.2: resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} engines: {node: '>=18.0.0'} @@ -11048,9 +11110,6 @@ packages: zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - zod@4.3.5: - resolution: {integrity: sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==} - zod@4.3.6: resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} @@ -11078,8 +11137,9 @@ snapshots: '@adobe/css-tools@4.4.4': {} - '@aikidosec/safe-chain@1.4.0': + '@aikidosec/safe-chain@1.4.4': dependencies: + archiver: 7.0.1 certifi: 14.5.15 chalk: 5.4.1 https-proxy-agent: 7.0.6 @@ -11089,42 +11149,45 @@ snapshots: npm-registry-fetch: 19.1.1 semver: 7.7.2 transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a - supports-color - '@alloy-js/babel-plugin-jsx-dom-expressions@0.39.1(@babel/core@7.28.5)': + '@alloy-js/babel-plugin-jsx-dom-expressions@0.39.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 '@babel/helper-module-imports': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) - '@babel/types': 7.28.5 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/types': 7.29.0 html-entities: 2.6.0 validate-html-nesting: 1.2.4 transitivePeerDependencies: - supports-color - '@alloy-js/babel-plugin@0.2.1(@babel/core@7.28.5)': + '@alloy-js/babel-plugin@0.2.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/generator': 7.28.5 + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 '@babel/helper-module-imports': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) - '@babel/types': 7.28.5 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@alloy-js/babel-preset@0.2.1(@babel/core@7.28.5)': + '@alloy-js/babel-preset@0.2.1(@babel/core@7.29.0)': dependencies: - '@alloy-js/babel-plugin': 0.2.1(@babel/core@7.28.5) - '@alloy-js/babel-plugin-jsx-dom-expressions': 0.39.1(@babel/core@7.28.5) + '@alloy-js/babel-plugin': 0.2.1(@babel/core@7.29.0) + '@alloy-js/babel-plugin-jsx-dom-expressions': 0.39.1(@babel/core@7.29.0) transitivePeerDependencies: - '@babel/core' - supports-color '@alloy-js/cli@0.22.0': dependencies: - '@alloy-js/babel-preset': 0.2.1(@babel/core@7.28.5) - '@babel/core': 7.28.5 - '@babel/preset-typescript': 7.28.5(@babel/core@7.28.5) + '@alloy-js/babel-preset': 0.2.1(@babel/core@7.29.0) + '@babel/core': 7.29.0 + '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) pathe: 2.0.3 picocolors: 1.1.1 transitivePeerDependencies: @@ -11132,7 +11195,7 @@ snapshots: '@alloy-js/core@0.21.0': dependencies: - '@vue/reactivity': 3.5.28 + '@vue/reactivity': 3.5.29 cli-table3: 0.6.5 pathe: 2.0.3 picocolors: 1.1.1 @@ -11140,11 +11203,11 @@ snapshots: '@alloy-js/core@0.22.0': dependencies: - '@vue/reactivity': 3.5.26 + '@vue/reactivity': 3.5.29 cli-table3: 0.6.5 pathe: 2.0.3 picocolors: 1.1.1 - prettier: 3.7.4 + prettier: 3.8.1 '@alloy-js/csharp@0.21.0': dependencies: @@ -11161,13 +11224,19 @@ snapshots: marked: 16.4.2 pathe: 2.0.3 + '@alloy-js/python@0.3.0': + dependencies: + '@alloy-js/core': 0.22.0 + change-case: 5.4.4 + pathe: 2.0.3 + '@alloy-js/typescript@0.22.0': dependencies: '@alloy-js/core': 0.22.0 change-case: 5.4.4 pathe: 2.0.3 - '@babel/code-frame@7.27.1': + '@babel/code-frame@7.28.6': dependencies: '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 @@ -11179,19 +11248,19 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.28.5': {} + '@babel/compat-data@7.29.0': {} - '@babel/core@7.28.5': + '@babel/core@7.29.0': dependencies: '@babel/code-frame': 7.29.0 - '@babel/generator': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3 @@ -11201,51 +11270,51 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.28.5': + '@babel/generator@7.29.1': dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 '@babel/helper-annotate-as-pure@7.27.3': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.0 - '@babel/helper-compilation-targets@7.27.2': + '@babel/helper-compilation-targets@7.28.6': dependencies: - '@babel/compat-data': 7.28.5 + '@babel/compat-data': 7.29.0 '@babel/helper-validator-option': 7.27.1 browserslist: 4.28.1 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.28.5(@babel/core@7.28.5)': + '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-member-expression-to-functions': 7.28.5 '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.28.5 + '@babel/traverse': 7.29.0 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.28.5)': + '@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.27.3 regexpu-core: 6.4.0 semver: 6.3.1 - '@babel/helper-define-polyfill-provider@0.6.5(@babel/core@7.28.5)': + '@babel/helper-define-polyfill-provider@0.6.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 debug: 4.4.3 lodash.debounce: 4.0.8 resolve: 1.22.11 @@ -11256,55 +11325,62 @@ snapshots: '@babel/helper-member-expression-to-functions@7.28.5': dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color '@babel/helper-module-imports@7.27.1': dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': + '@babel/helper-module-imports@7.28.6': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.5 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color '@babel/helper-optimise-call-expression@7.27.1': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.0 - '@babel/helper-plugin-utils@7.27.1': {} + '@babel/helper-plugin-utils@7.28.6': {} - '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.28.5)': + '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-wrap-function': 7.28.3 - '@babel/traverse': 7.28.5 + '@babel/helper-wrap-function': 7.28.6 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helper-replace-supers@7.27.1(@babel/core@7.28.5)': + '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 '@babel/helper-member-expression-to-functions': 7.28.5 '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.28.5 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color '@babel/helper-skip-transparent-expression-wrappers@7.27.1': dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color @@ -11314,654 +11390,654 @@ snapshots: '@babel/helper-validator-option@7.27.1': {} - '@babel/helper-wrap-function@7.28.3': + '@babel/helper-wrap-function@7.28.6': dependencies: - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helpers@7.28.4': + '@babel/helpers@7.28.6': dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 - '@babel/parser@7.28.5': + '@babel/parser@7.29.0': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.0 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.5) + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0) transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3(@babel/core@7.28.5)': + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/plugin-proposal-decorators@7.28.0(@babel/core@7.28.5)': + '@babel/plugin-proposal-decorators@7.29.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-decorators': 7.27.1(@babel/core@7.28.5) + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-decorators': 7.28.6(@babel/core@7.29.0) transitivePeerDependencies: - supports-color - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.5)': + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 - '@babel/plugin-syntax-decorators@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-decorators@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-import-assertions@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-import-assertions@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.28.5)': + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-async-generator-functions@7.28.0(@babel/core@7.28.5)': + '@babel/plugin-transform-async-generator-functions@7.29.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.5) - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.29.0) + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-async-to-generator@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-async-to-generator@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.5) + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.29.0) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-block-scoping@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-block-scoping@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-class-properties@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-class-properties@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-class-static-block@7.28.3(@babel/core@7.28.5)': + '@babel/plugin-transform-class-static-block@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-classes@7.28.4(@babel/core@7.28.5)': + '@babel/plugin-transform-classes@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-compilation-targets': 7.28.6 '@babel/helper-globals': 7.28.0 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) - '@babel/traverse': 7.28.5 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-computed-properties@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-computed-properties@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/template': 7.27.2 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/template': 7.28.6 - '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-dotall-regex@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-dotall-regex@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-explicit-resource-management@7.28.0(@babel/core@7.28.5)': + '@babel/plugin-transform-explicit-resource-management@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-exponentiation-operator@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-exponentiation-operator@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-json-strings@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-json-strings@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-literals@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-literals@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-logical-assignment-operators@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-logical-assignment-operators@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-systemjs@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-modules-systemjs@7.29.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.5 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-named-capturing-groups-regex@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-named-capturing-groups-regex@7.29.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-nullish-coalescing-operator@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-nullish-coalescing-operator@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-numeric-separator@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-numeric-separator@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-object-rest-spread@7.28.4(@babel/core@7.28.5)': + '@babel/plugin-transform-object-rest-spread@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.5) - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.29.0) + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-optional-catch-binding@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-optional-catch-binding@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-optional-chaining@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-optional-chaining@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.28.5)': + '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-private-methods@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-private-methods@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-private-property-in-object@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-private-property-in-object@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-react-constant-elements@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-react-constant-elements@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-react-display-name@7.28.0(@babel/core@7.28.5)': + '@babel/plugin-transform-react-display-name@7.28.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-react-jsx-development@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-react-jsx-development@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.5) + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-react-jsx@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-react-jsx@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) - '@babel/types': 7.28.5 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-react-pure-annotations@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-react-pure-annotations@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-regenerator@7.28.4(@babel/core@7.28.5)': + '@babel/plugin-transform-regenerator@7.29.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-regexp-modifiers@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-regexp-modifiers@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-runtime@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-runtime@7.29.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.5) - babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.5) - babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.5) + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + babel-plugin-polyfill-corejs2: 0.4.15(@babel/core@7.29.0) + babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.29.0) + babel-plugin-polyfill-regenerator: 0.6.6(@babel/core@7.29.0) semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-spread@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-spread@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-typescript@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-unicode-property-regex@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-unicode-property-regex@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-unicode-sets-regex@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-unicode-sets-regex@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 - '@babel/preset-env@7.28.5(@babel/core@7.28.5)': + '@babel/preset-env@7.29.0(@babel/core@7.29.0)': dependencies: - '@babel/compat-data': 7.28.5 - '@babel/core': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/compat-data': 7.29.0 + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.3(@babel/core@7.28.5) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.5) - '@babel/plugin-syntax-import-assertions': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.28.5) - '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-async-generator-functions': 7.28.0(@babel/core@7.28.5) - '@babel/plugin-transform-async-to-generator': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-block-scoping': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-class-static-block': 7.28.3(@babel/core@7.28.5) - '@babel/plugin-transform-classes': 7.28.4(@babel/core@7.28.5) - '@babel/plugin-transform-computed-properties': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-dotall-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-explicit-resource-management': 7.28.0(@babel/core@7.28.5) - '@babel/plugin-transform-exponentiation-operator': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-json-strings': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-logical-assignment-operators': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-modules-systemjs': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-nullish-coalescing-operator': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-numeric-separator': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-object-rest-spread': 7.28.4(@babel/core@7.28.5) - '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-optional-catch-binding': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.5) - '@babel/plugin-transform-private-methods': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-private-property-in-object': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-regenerator': 7.28.4(@babel/core@7.28.5) - '@babel/plugin-transform-regexp-modifiers': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-spread': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-unicode-property-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-unicode-sets-regex': 7.27.1(@babel/core@7.28.5) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.28.5) - babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.5) - babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.5) - babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.5) - core-js-compat: 3.47.0 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.29.0) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.0) + '@babel/plugin-syntax-import-assertions': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.29.0) + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-async-generator-functions': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-async-to-generator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-block-scoping': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-class-static-block': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-classes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-computed-properties': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) + '@babel/plugin-transform-dotall-regex': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-explicit-resource-management': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-exponentiation-operator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-json-strings': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-logical-assignment-operators': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-modules-systemjs': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-named-capturing-groups-regex': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-nullish-coalescing-operator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-numeric-separator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-object-rest-spread': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-optional-catch-binding': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.29.0) + '@babel/plugin-transform-private-methods': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-private-property-in-object': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-regenerator': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-regexp-modifiers': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-spread': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-property-regex': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-sets-regex': 7.28.6(@babel/core@7.29.0) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.29.0) + babel-plugin-polyfill-corejs2: 0.4.15(@babel/core@7.29.0) + babel-plugin-polyfill-corejs3: 0.14.0(@babel/core@7.29.0) + babel-plugin-polyfill-regenerator: 0.6.6(@babel/core@7.29.0) + core-js-compat: 3.48.0 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.28.5)': + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/types': 7.28.5 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/types': 7.29.0 esutils: 2.0.3 - '@babel/preset-react@7.28.5(@babel/core@7.28.5)': + '@babel/preset-react@7.28.5(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-transform-react-display-name': 7.28.0(@babel/core@7.28.5) - '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-react-pure-annotations': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-react-display-name': 7.28.0(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-pure-annotations': 7.27.1(@babel/core@7.29.0) transitivePeerDependencies: - supports-color - '@babel/preset-typescript@7.28.5(@babel/core@7.28.5)': + '@babel/preset-typescript@7.28.5(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5) + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) transitivePeerDependencies: - supports-color - '@babel/runtime@7.28.4': {} + '@babel/runtime@7.28.6': {} - '@babel/template@7.27.2': + '@babel/template@7.28.6': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 - '@babel/traverse@7.28.5': + '@babel/traverse@7.29.0': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 debug: 4.4.3 transitivePeerDependencies: - supports-color - '@babel/types@7.28.5': + '@babel/types@7.29.0': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 - '@better-auth/cli@1.4.18(@better-fetch/fetch@1.1.21)(@libsql/client@0.14.0)(better-call@1.1.8(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)(vitest@4.0.18(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@better-auth/cli@1.4.21(@better-fetch/fetch@1.1.21)(@electric-sql/pglite@0.3.15)(@libsql/client@0.14.0)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(mongodb@7.1.0(socks@2.8.7))(mysql2@3.15.3)(nanostores@1.1.1)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.10)(vitest@4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/preset-react': 7.28.5(@babel/core@7.28.5) - '@babel/preset-typescript': 7.28.5(@babel/core@7.28.5) - '@better-auth/core': 1.4.18(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.0) - '@better-auth/telemetry': 1.4.18(@better-auth/core@1.4.18(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.0)) + '@babel/core': 7.29.0 + '@babel/preset-react': 7.28.5(@babel/core@7.29.0) + '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) + '@better-auth/core': 1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1) + '@better-auth/telemetry': 1.4.21(@better-auth/core@1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1)) '@better-auth/utils': 0.3.0 '@clack/prompts': 0.11.0 '@mrleebo/prisma-ast': 0.13.1 - '@prisma/client': 5.22.0 - '@types/pg': 8.16.0 - better-auth: 1.4.18(@prisma/client@5.22.0)(better-sqlite3@12.6.2)(drizzle-orm@0.41.0(@libsql/client@0.14.0)(@prisma/client@5.22.0)(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(pg@8.18.0))(pg@8.18.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)(vitest@4.0.18(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@prisma/client': 5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)) + '@types/pg': 8.18.0 + better-auth: 1.4.21(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(better-sqlite3@12.6.2)(drizzle-orm@0.41.0(@electric-sql/pglite@0.3.15)(@libsql/client@0.14.0)(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(@types/pg@8.18.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.1.0(socks@2.8.7))(mysql2@3.15.3)(pg@8.20.0)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.10)(vitest@4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) better-sqlite3: 12.6.2 c12: 3.3.3 chalk: 5.6.2 commander: 12.1.0 dotenv: 17.3.1 - drizzle-orm: 0.41.0(@libsql/client@0.14.0)(@prisma/client@5.22.0)(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(pg@8.18.0) + drizzle-orm: 0.41.0(@electric-sql/pglite@0.3.15)(@libsql/client@0.14.0)(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(@types/pg@8.18.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)) open: 10.2.0 - pg: 8.18.0 + pg: 8.20.0 prettier: 3.8.1 prompts: 2.4.2 semver: 7.7.4 @@ -12013,89 +12089,149 @@ snapshots: - vitest - vue - '@better-auth/core@1.4.18(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.0)': + '@better-auth/core@1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1)': dependencies: '@better-auth/utils': 0.3.0 '@better-fetch/fetch': 1.1.21 '@standard-schema/spec': 1.1.0 better-call: 1.1.8(zod@4.3.6) - jose: 6.1.3 + jose: 6.2.0 + kysely: 0.28.11 + nanostores: 1.1.1 + zod: 4.3.6 + + '@better-auth/core@1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1)': + dependencies: + '@better-auth/utils': 0.3.0 + '@better-fetch/fetch': 1.1.21 + '@standard-schema/spec': 1.1.0 + better-call: 1.3.2(zod@4.3.6) + jose: 6.2.0 + kysely: 0.28.11 + nanostores: 1.1.1 + zod: 4.3.6 + + '@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1)': + dependencies: + '@better-auth/utils': 0.3.1 + '@better-fetch/fetch': 1.1.21 + '@standard-schema/spec': 1.1.0 + better-call: 1.3.2(zod@4.3.6) + jose: 6.2.0 kysely: 0.28.11 - nanostores: 1.1.0 + nanostores: 1.1.1 zod: 4.3.6 - '@better-auth/telemetry@1.4.18(@better-auth/core@1.4.18(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.0))': + '@better-auth/drizzle-adapter@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(drizzle-orm@0.41.0(@electric-sql/pglite@0.3.15)(@libsql/client@0.14.0)(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(@types/pg@8.18.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))': + dependencies: + '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1) + '@better-auth/utils': 0.3.1 + drizzle-orm: 0.41.0(@electric-sql/pglite@0.3.15)(@libsql/client@0.14.0)(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(@types/pg@8.18.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)) + + '@better-auth/kysely-adapter@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(kysely@0.28.11)': + dependencies: + '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1) + '@better-auth/utils': 0.3.1 + kysely: 0.28.11 + + '@better-auth/memory-adapter@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)': + dependencies: + '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1) + '@better-auth/utils': 0.3.1 + + '@better-auth/mongo-adapter@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(mongodb@7.1.0(socks@2.8.7))': + dependencies: + '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1) + '@better-auth/utils': 0.3.1 + mongodb: 7.1.0(socks@2.8.7) + + '@better-auth/prisma-adapter@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))': dependencies: - '@better-auth/core': 1.4.18(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.0) + '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1) + '@better-auth/utils': 0.3.1 + '@prisma/client': 5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)) + prisma: 7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + + '@better-auth/telemetry@1.4.21(@better-auth/core@1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))': + dependencies: + '@better-auth/core': 1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1) '@better-auth/utils': 0.3.0 '@better-fetch/fetch': 1.1.21 + '@better-auth/telemetry@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))': + dependencies: + '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1) + '@better-auth/utils': 0.3.1 + '@better-fetch/fetch': 1.1.21 + '@better-auth/utils@0.3.0': {} + '@better-auth/utils@0.3.1': {} + '@better-fetch/fetch@1.1.21': {} - '@bufbuild/buf-darwin-arm64@1.63.0': + '@bufbuild/buf-darwin-arm64@1.66.0': optional: true - '@bufbuild/buf-darwin-x64@1.63.0': + '@bufbuild/buf-darwin-x64@1.66.0': optional: true - '@bufbuild/buf-linux-aarch64@1.63.0': + '@bufbuild/buf-linux-aarch64@1.66.0': optional: true - '@bufbuild/buf-linux-armv7@1.63.0': + '@bufbuild/buf-linux-armv7@1.66.0': optional: true - '@bufbuild/buf-linux-x64@1.63.0': + '@bufbuild/buf-linux-x64@1.66.0': optional: true - '@bufbuild/buf-win32-arm64@1.63.0': + '@bufbuild/buf-win32-arm64@1.66.0': optional: true - '@bufbuild/buf-win32-x64@1.63.0': + '@bufbuild/buf-win32-x64@1.66.0': optional: true - '@bufbuild/buf@1.63.0': + '@bufbuild/buf@1.66.0': optionalDependencies: - '@bufbuild/buf-darwin-arm64': 1.63.0 - '@bufbuild/buf-darwin-x64': 1.63.0 - '@bufbuild/buf-linux-aarch64': 1.63.0 - '@bufbuild/buf-linux-armv7': 1.63.0 - '@bufbuild/buf-linux-x64': 1.63.0 - '@bufbuild/buf-win32-arm64': 1.63.0 - '@bufbuild/buf-win32-x64': 1.63.0 + '@bufbuild/buf-darwin-arm64': 1.66.0 + '@bufbuild/buf-darwin-x64': 1.66.0 + '@bufbuild/buf-linux-aarch64': 1.66.0 + '@bufbuild/buf-linux-armv7': 1.66.0 + '@bufbuild/buf-linux-x64': 1.66.0 + '@bufbuild/buf-win32-arm64': 1.66.0 + '@bufbuild/buf-win32-x64': 1.66.0 - '@bufbuild/cel-spec@0.3.0(@bufbuild/protobuf@2.10.2)': + '@bufbuild/cel-spec@0.4.0(@bufbuild/protobuf@2.11.0)': dependencies: - '@bufbuild/protobuf': 2.10.2 + '@bufbuild/protobuf': 2.11.0 - '@bufbuild/cel@0.3.0(@bufbuild/protobuf@2.10.2)': + '@bufbuild/cel@0.4.0(@bufbuild/protobuf@2.11.0)': dependencies: - '@bufbuild/cel-spec': 0.3.0(@bufbuild/protobuf@2.10.2) - '@bufbuild/protobuf': 2.10.2 + '@bufbuild/cel-spec': 0.4.0(@bufbuild/protobuf@2.11.0) + '@bufbuild/protobuf': 2.11.0 - '@bufbuild/protobuf@2.10.2': {} + '@bufbuild/protobuf@2.11.0': {} - '@bufbuild/protoc-gen-es@2.10.2(@bufbuild/protobuf@2.10.2)': + '@bufbuild/protoc-gen-es@2.11.0(@bufbuild/protobuf@2.11.0)': dependencies: - '@bufbuild/protoplugin': 2.10.2 + '@bufbuild/protoplugin': 2.11.0 optionalDependencies: - '@bufbuild/protobuf': 2.10.2 + '@bufbuild/protobuf': 2.11.0 transitivePeerDependencies: - supports-color - '@bufbuild/protoplugin@2.10.2': + '@bufbuild/protoplugin@2.11.0': dependencies: - '@bufbuild/protobuf': 2.10.2 - '@typescript/vfs': 1.6.2(typescript@5.4.5) + '@bufbuild/protobuf': 2.11.0 + '@typescript/vfs': 1.6.4(typescript@5.4.5) typescript: 5.4.5 transitivePeerDependencies: - supports-color - '@bufbuild/protovalidate@1.1.0(@bufbuild/protobuf@2.10.2)': + '@bufbuild/protovalidate@1.1.1(@bufbuild/protobuf@2.11.0)': dependencies: - '@bufbuild/cel': 0.3.0(@bufbuild/protobuf@2.10.2) - '@bufbuild/protobuf': 2.10.2 + '@bufbuild/cel': 0.4.0(@bufbuild/protobuf@2.11.0) + '@bufbuild/protobuf': 2.11.0 '@chevrotain/cst-dts-gen@10.5.0': dependencies: @@ -12112,11 +12248,6 @@ snapshots: '@chevrotain/utils@10.5.0': {} - '@clack/core@0.3.5': - dependencies: - picocolors: 1.1.1 - sisteransi: 1.0.5 - '@clack/core@0.5.0': dependencies: picocolors: 1.1.1 @@ -12128,12 +12259,6 @@ snapshots: picocolors: 1.1.1 sisteransi: 1.0.5 - '@clack/prompts@0.8.2': - dependencies: - '@clack/core': 0.3.5 - picocolors: 1.1.1 - sisteransi: 1.0.5 - '@codemirror/autocomplete@6.20.0': dependencies: '@codemirror/language': 6.12.1 @@ -12153,29 +12278,29 @@ snapshots: '@codemirror/autocomplete': 6.20.0 '@codemirror/language': 6.12.1 '@codemirror/state': 6.5.3 - '@lezer/common': 1.5.0 - '@lezer/css': 1.3.0 + '@lezer/common': 1.5.1 + '@lezer/css': 1.3.1 '@codemirror/lang-html@6.4.11': dependencies: '@codemirror/autocomplete': 6.20.0 '@codemirror/lang-css': 6.3.1 - '@codemirror/lang-javascript': 6.2.4 + '@codemirror/lang-javascript': 6.2.5 '@codemirror/language': 6.12.1 '@codemirror/state': 6.5.3 '@codemirror/view': 6.39.9 - '@lezer/common': 1.5.0 - '@lezer/css': 1.3.0 + '@lezer/common': 1.5.1 + '@lezer/css': 1.3.1 '@lezer/html': 1.3.13 - '@codemirror/lang-javascript@6.2.4': + '@codemirror/lang-javascript@6.2.5': dependencies: '@codemirror/autocomplete': 6.20.0 '@codemirror/language': 6.12.1 - '@codemirror/lint': 6.9.2 + '@codemirror/lint': 6.9.5 '@codemirror/state': 6.5.3 '@codemirror/view': 6.39.9 - '@lezer/common': 1.5.0 + '@lezer/common': 1.5.1 '@lezer/javascript': 1.5.4 '@codemirror/lang-json@6.0.2': @@ -12189,7 +12314,7 @@ snapshots: '@codemirror/language': 6.12.1 '@codemirror/state': 6.5.3 '@codemirror/view': 6.39.9 - '@lezer/common': 1.5.0 + '@lezer/common': 1.5.1 '@lezer/xml': 1.0.6 '@codemirror/language@6.12.1': @@ -12198,10 +12323,10 @@ snapshots: '@codemirror/view': 6.39.9 '@lezer/common': 1.5.1 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.7 + '@lezer/lr': 1.4.8 style-mod: 4.1.3 - '@codemirror/lint@6.9.2': + '@codemirror/lint@6.9.5': dependencies: '@codemirror/state': 6.5.3 '@codemirror/view': 6.39.9 @@ -12234,36 +12359,36 @@ snapshots: '@colors/colors@1.5.0': optional: true - '@connectrpc/connect-node@2.1.1(@bufbuild/protobuf@2.10.2)(@connectrpc/connect@2.1.1(@bufbuild/protobuf@2.10.2))': + '@connectrpc/connect-node@2.1.1(@bufbuild/protobuf@2.11.0)(@connectrpc/connect@2.1.1(@bufbuild/protobuf@2.11.0))': dependencies: - '@bufbuild/protobuf': 2.10.2 - '@connectrpc/connect': 2.1.1(@bufbuild/protobuf@2.10.2) + '@bufbuild/protobuf': 2.11.0 + '@connectrpc/connect': 2.1.1(@bufbuild/protobuf@2.11.0) - '@connectrpc/connect-query-core@2.2.0(@bufbuild/protobuf@2.10.2)(@connectrpc/connect@2.1.1(@bufbuild/protobuf@2.10.2))(@tanstack/query-core@5.90.16)': + '@connectrpc/connect-query-core@2.2.0(@bufbuild/protobuf@2.11.0)(@connectrpc/connect@2.1.1(@bufbuild/protobuf@2.11.0))(@tanstack/query-core@5.90.20)': dependencies: - '@bufbuild/protobuf': 2.10.2 - '@connectrpc/connect': 2.1.1(@bufbuild/protobuf@2.10.2) - '@tanstack/query-core': 5.90.16 + '@bufbuild/protobuf': 2.11.0 + '@connectrpc/connect': 2.1.1(@bufbuild/protobuf@2.11.0) + '@tanstack/query-core': 5.90.20 - '@connectrpc/connect-query@2.2.0(@bufbuild/protobuf@2.10.2)(@connectrpc/connect@2.1.1(@bufbuild/protobuf@2.10.2))(@tanstack/query-core@5.90.16)(@tanstack/react-query@5.90.16(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@connectrpc/connect-query@2.2.0(@bufbuild/protobuf@2.11.0)(@connectrpc/connect@2.1.1(@bufbuild/protobuf@2.11.0))(@tanstack/query-core@5.90.20)(@tanstack/react-query@5.90.21(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@bufbuild/protobuf': 2.10.2 - '@connectrpc/connect': 2.1.1(@bufbuild/protobuf@2.10.2) - '@connectrpc/connect-query-core': 2.2.0(@bufbuild/protobuf@2.10.2)(@connectrpc/connect@2.1.1(@bufbuild/protobuf@2.10.2))(@tanstack/query-core@5.90.16) - '@tanstack/react-query': 5.90.16(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + '@bufbuild/protobuf': 2.11.0 + '@connectrpc/connect': 2.1.1(@bufbuild/protobuf@2.11.0) + '@connectrpc/connect-query-core': 2.2.0(@bufbuild/protobuf@2.11.0)(@connectrpc/connect@2.1.1(@bufbuild/protobuf@2.11.0))(@tanstack/query-core@5.90.20) + '@tanstack/react-query': 5.90.21(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - '@tanstack/query-core' - '@connectrpc/connect-web@2.1.1(@bufbuild/protobuf@2.10.2)(@connectrpc/connect@2.1.1(@bufbuild/protobuf@2.10.2))': + '@connectrpc/connect-web@2.1.1(@bufbuild/protobuf@2.11.0)(@connectrpc/connect@2.1.1(@bufbuild/protobuf@2.11.0))': dependencies: - '@bufbuild/protobuf': 2.10.2 - '@connectrpc/connect': 2.1.1(@bufbuild/protobuf@2.10.2) + '@bufbuild/protobuf': 2.11.0 + '@connectrpc/connect': 2.1.1(@bufbuild/protobuf@2.11.0) - '@connectrpc/connect@2.1.1(@bufbuild/protobuf@2.10.2)': + '@connectrpc/connect@2.1.1(@bufbuild/protobuf@2.11.0)': dependencies: - '@bufbuild/protobuf': 2.10.2 + '@bufbuild/protobuf': 2.11.0 '@cspotcode/source-map-support@0.8.1': dependencies: @@ -12271,134 +12396,144 @@ snapshots: '@develar/schema-utils@2.6.5': dependencies: - ajv: 6.12.6 - ajv-keywords: 3.5.2(ajv@6.12.6) + ajv: 6.14.0 + ajv-keywords: 3.5.2(ajv@6.14.0) - '@effect-atom/atom-react@0.4.4(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14)(react@19.2.3)(scheduler@0.27.0)': + '@effect-atom/atom-react@0.5.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19)(react@19.2.4)(scheduler@0.27.0)': dependencies: - '@effect-atom/atom': 0.4.11(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14) - effect: 3.19.14 - react: 19.2.3 + '@effect-atom/atom': 0.5.3(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19) + effect: 3.19.19 + react: 19.2.4 scheduler: 0.27.0 transitivePeerDependencies: - '@effect/experimental' - '@effect/platform' - '@effect/rpc' - '@effect-atom/atom@0.4.11(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14)': + '@effect-atom/atom@0.5.3(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19)': dependencies: - '@effect/experimental': 0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14) - '@effect/platform': 0.94.1(effect@3.19.14) - '@effect/rpc': 0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14) - effect: 3.19.14 + '@effect/experimental': 0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19) + '@effect/platform': 0.94.5(effect@3.19.19) + '@effect/rpc': 0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19) + effect: 3.19.19 - '@effect/cli@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(@effect/printer-ansi@0.47.0(@effect/typeclass@0.38.0(effect@3.19.14))(effect@3.19.14))(@effect/printer@0.47.0(@effect/typeclass@0.38.0(effect@3.19.14))(effect@3.19.14))(effect@3.19.14)': + '@effect/cli@0.73.2(@effect/platform@0.94.5(effect@3.19.19))(@effect/printer-ansi@0.47.0(@effect/typeclass@0.38.0(effect@3.19.19))(effect@3.19.19))(@effect/printer@0.47.0(@effect/typeclass@0.38.0(effect@3.19.19))(effect@3.19.19))(effect@3.19.19)': dependencies: - '@effect/platform': 0.94.1(effect@3.19.14) - '@effect/printer': 0.47.0(@effect/typeclass@0.38.0(effect@3.19.14))(effect@3.19.14) - '@effect/printer-ansi': 0.47.0(@effect/typeclass@0.38.0(effect@3.19.14))(effect@3.19.14) - effect: 3.19.14 + '@effect/platform': 0.94.5(effect@3.19.19) + '@effect/printer': 0.47.0(@effect/typeclass@0.38.0(effect@3.19.19))(effect@3.19.19) + '@effect/printer-ansi': 0.47.0(@effect/typeclass@0.38.0(effect@3.19.19))(effect@3.19.19) + effect: 3.19.19 ini: 4.1.3 toml: 3.0.0 yaml: 2.8.2 - '@effect/cluster@0.56.1(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/workflow@0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14))(effect@3.19.14)': + '@effect/cluster@0.56.1(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/workflow@0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19))(effect@3.19.19)': dependencies: - '@effect/platform': 0.94.1(effect@3.19.14) - '@effect/rpc': 0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14) - '@effect/sql': 0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14) - '@effect/workflow': 0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14) - effect: 3.19.14 + '@effect/platform': 0.94.5(effect@3.19.19) + '@effect/rpc': 0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19) + '@effect/sql': 0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19) + '@effect/workflow': 0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19) + effect: 3.19.19 kubernetes-types: 1.30.0 - '@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14)': + '@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19)': dependencies: - '@effect/platform': 0.94.1(effect@3.19.14) - effect: 3.19.14 + '@effect/platform': 0.94.5(effect@3.19.19) + effect: 3.19.19 uuid: 11.1.0 - '@effect/platform-browser@0.74.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14)': + '@effect/platform-browser@0.74.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19)': dependencies: - '@effect/platform': 0.94.1(effect@3.19.14) - effect: 3.19.14 + '@effect/platform': 0.94.5(effect@3.19.19) + effect: 3.19.19 multipasta: 0.2.7 - '@effect/platform-node-shared@0.57.0(patch_hash=0f57ae91978b8a7454da3f1d774942d9b9a6292e28f875c6b487454e91676fbf)(@effect/cluster@0.56.1(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/workflow@0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14)': + '@effect/platform-node-shared@0.57.1(patch_hash=0f57ae91978b8a7454da3f1d774942d9b9a6292e28f875c6b487454e91676fbf)(@effect/cluster@0.56.1(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/workflow@0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19)': dependencies: - '@effect/cluster': 0.56.1(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/workflow@0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14))(effect@3.19.14) - '@effect/platform': 0.94.1(effect@3.19.14) - '@effect/rpc': 0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14) - '@effect/sql': 0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14) - '@parcel/watcher': 2.5.1 - effect: 3.19.14 + '@effect/cluster': 0.56.1(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/workflow@0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19))(effect@3.19.19) + '@effect/platform': 0.94.5(effect@3.19.19) + '@effect/rpc': 0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19) + '@effect/sql': 0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19) + '@parcel/watcher': 2.5.6 + effect: 3.19.19 multipasta: 0.2.7 ws: 8.19.0 transitivePeerDependencies: - bufferutil - utf-8-validate - '@effect/platform-node@0.104.0(@effect/cluster@0.56.1(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/workflow@0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14)': + '@effect/platform-node@0.104.1(@effect/cluster@0.56.1(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/workflow@0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19)': dependencies: - '@effect/cluster': 0.56.1(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/workflow@0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14))(effect@3.19.14) - '@effect/platform': 0.94.1(effect@3.19.14) - '@effect/platform-node-shared': 0.57.0(patch_hash=0f57ae91978b8a7454da3f1d774942d9b9a6292e28f875c6b487454e91676fbf)(@effect/cluster@0.56.1(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/workflow@0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14) - '@effect/rpc': 0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14) - '@effect/sql': 0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14) - effect: 3.19.14 + '@effect/cluster': 0.56.1(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/workflow@0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19))(effect@3.19.19) + '@effect/platform': 0.94.5(effect@3.19.19) + '@effect/platform-node-shared': 0.57.1(patch_hash=0f57ae91978b8a7454da3f1d774942d9b9a6292e28f875c6b487454e91676fbf)(@effect/cluster@0.56.1(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/workflow@0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19) + '@effect/rpc': 0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19) + '@effect/sql': 0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19) + effect: 3.19.19 mime: 3.0.0 - undici: 7.18.2 + undici: 7.22.0 ws: 8.19.0 transitivePeerDependencies: - bufferutil - utf-8-validate - '@effect/platform@0.94.1(effect@3.19.14)': + '@effect/platform@0.94.5(effect@3.19.19)': dependencies: - effect: 3.19.14 + effect: 3.19.19 find-my-way-ts: 0.1.6 msgpackr: 1.11.8 multipasta: 0.2.7 - '@effect/printer-ansi@0.47.0(@effect/typeclass@0.38.0(effect@3.19.14))(effect@3.19.14)': + '@effect/printer-ansi@0.47.0(@effect/typeclass@0.38.0(effect@3.19.19))(effect@3.19.19)': dependencies: - '@effect/printer': 0.47.0(@effect/typeclass@0.38.0(effect@3.19.14))(effect@3.19.14) - '@effect/typeclass': 0.38.0(effect@3.19.14) - effect: 3.19.14 + '@effect/printer': 0.47.0(@effect/typeclass@0.38.0(effect@3.19.19))(effect@3.19.19) + '@effect/typeclass': 0.38.0(effect@3.19.19) + effect: 3.19.19 - '@effect/printer@0.47.0(@effect/typeclass@0.38.0(effect@3.19.14))(effect@3.19.14)': + '@effect/printer@0.47.0(@effect/typeclass@0.38.0(effect@3.19.19))(effect@3.19.19)': dependencies: - '@effect/typeclass': 0.38.0(effect@3.19.14) - effect: 3.19.14 + '@effect/typeclass': 0.38.0(effect@3.19.19) + effect: 3.19.19 - '@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14)': + '@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19)': dependencies: - '@effect/platform': 0.94.1(effect@3.19.14) - effect: 3.19.14 + '@effect/platform': 0.94.5(effect@3.19.19) + effect: 3.19.19 msgpackr: 1.11.8 - '@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14)': + '@effect/sql@0.49.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19)': dependencies: - '@effect/experimental': 0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14) - '@effect/platform': 0.94.1(effect@3.19.14) - effect: 3.19.14 + '@effect/experimental': 0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19) + '@effect/platform': 0.94.5(effect@3.19.19) + effect: 3.19.19 uuid: 11.1.0 - '@effect/typeclass@0.38.0(effect@3.19.14)': + '@effect/typeclass@0.38.0(effect@3.19.19)': + dependencies: + effect: 3.19.19 + + '@effect/workflow@0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(@effect/platform@0.94.5(effect@3.19.19))(@effect/rpc@0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19))(effect@3.19.19)': dependencies: - effect: 3.19.14 + '@effect/experimental': 0.57.11(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19) + '@effect/platform': 0.94.5(effect@3.19.19) + '@effect/rpc': 0.73.0(@effect/platform@0.94.5(effect@3.19.19))(effect@3.19.19) + effect: 3.19.19 - '@effect/workflow@0.16.0(@effect/experimental@0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(@effect/platform@0.94.1(effect@3.19.14))(@effect/rpc@0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14))(effect@3.19.14)': + '@electric-sql/pglite-socket@0.0.20(@electric-sql/pglite@0.3.15)': dependencies: - '@effect/experimental': 0.57.11(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14) - '@effect/platform': 0.94.1(effect@3.19.14) - '@effect/rpc': 0.73.0(@effect/platform@0.94.1(effect@3.19.14))(effect@3.19.14) - effect: 3.19.14 + '@electric-sql/pglite': 0.3.15 + + '@electric-sql/pglite-tools@0.2.20(@electric-sql/pglite@0.3.15)': + dependencies: + '@electric-sql/pglite': 0.3.15 + + '@electric-sql/pglite@0.3.15': {} '@electron/asar@3.4.1': dependencies: commander: 5.1.0 glob: 7.2.3 - minimatch: 3.1.2 + minimatch: 3.1.5 '@electron/fuses@1.8.0': dependencies: @@ -12420,6 +12555,20 @@ snapshots: transitivePeerDependencies: - supports-color + '@electron/get@3.1.0': + dependencies: + debug: 4.4.3 + env-paths: 2.2.1 + fs-extra: 8.1.0 + got: 11.8.6 + progress: 2.0.3 + semver: 6.3.1 + sumchecker: 3.0.1 + optionalDependencies: + global-agent: 3.0.0 + transitivePeerDependencies: + - supports-color + '@electron/notarize@2.5.0': dependencies: debug: 4.4.3 @@ -12447,25 +12596,43 @@ snapshots: detect-libc: 2.1.2 got: 11.8.6 graceful-fs: 4.2.11 - node-abi: 4.24.0 + node-abi: 4.26.0 node-api-version: 0.2.1 node-gyp: 11.5.0 ora: 5.4.1 read-binary-file-arch: 1.0.6 - semver: 7.7.3 + semver: 7.7.4 tar: 6.2.1 yargs: 17.7.2 transitivePeerDependencies: - supports-color - '@electron/universal@2.0.3': + '@electron/rebuild@4.0.3': dependencies: - '@electron/asar': 3.4.1 '@malept/cross-spawn-promise': 2.0.0 debug: 4.4.3 - dir-compare: 4.2.0 - fs-extra: 11.3.3 - minimatch: 9.0.5 + detect-libc: 2.1.2 + got: 11.8.6 + graceful-fs: 4.2.11 + node-abi: 4.26.0 + node-api-version: 0.2.1 + node-gyp: 11.5.0 + ora: 5.4.1 + read-binary-file-arch: 1.0.6 + semver: 7.7.4 + tar: 7.5.10 + yargs: 17.7.2 + transitivePeerDependencies: + - supports-color + + '@electron/universal@2.0.3': + dependencies: + '@electron/asar': 3.4.1 + '@malept/cross-spawn-promise': 2.0.0 + debug: 4.4.3 + dir-compare: 4.2.0 + fs-extra: 11.3.4 + minimatch: 9.0.9 plist: 3.1.0 transitivePeerDependencies: - supports-color @@ -12474,7 +12641,7 @@ snapshots: dependencies: cross-dirname: 0.1.0 debug: 4.4.3 - fs-extra: 11.3.3 + fs-extra: 11.3.4 minimist: 1.2.8 postject: 1.0.0-alpha.6 transitivePeerDependencies: @@ -12496,8 +12663,8 @@ snapshots: '@emotion/babel-plugin@11.13.5': dependencies: - '@babel/helper-module-imports': 7.27.1 - '@babel/runtime': 7.28.4 + '@babel/helper-module-imports': 7.28.6 + '@babel/runtime': 7.28.6 '@emotion/hash': 0.9.2 '@emotion/memoize': 0.9.0 '@emotion/serialize': 1.3.3 @@ -12526,19 +12693,19 @@ snapshots: '@emotion/memoize@0.9.0': {} - '@emotion/react@11.14.0(@types/react@19.2.7)(react@19.2.3)': + '@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4)': dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.28.6 '@emotion/babel-plugin': 11.13.5 '@emotion/cache': 11.14.0 '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.3) + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.4) '@emotion/utils': 1.4.2 '@emotion/weak-memoize': 0.4.0 hoist-non-react-statics: 3.3.2 - react: 19.2.3 + react: 19.2.4 optionalDependencies: - '@types/react': 19.2.7 + '@types/react': 19.2.14 transitivePeerDependencies: - supports-color @@ -12552,26 +12719,26 @@ snapshots: '@emotion/sheet@1.4.0': {} - '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.7)(react@19.2.3))(@types/react@19.2.7)(react@19.2.3)': + '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)': dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.28.6 '@emotion/babel-plugin': 11.13.5 '@emotion/is-prop-valid': 1.4.0 - '@emotion/react': 11.14.0(@types/react@19.2.7)(react@19.2.3) + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.3) + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.4) '@emotion/utils': 1.4.2 - react: 19.2.3 + react: 19.2.4 optionalDependencies: - '@types/react': 19.2.7 + '@types/react': 19.2.14 transitivePeerDependencies: - supports-color '@emotion/unitless@0.10.0': {} - '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.3)': + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.4)': dependencies: - react: 19.2.3 + react: 19.2.4 '@emotion/utils@1.4.2': {} @@ -12580,157 +12747,157 @@ snapshots: '@esbuild/aix-ppc64@0.25.12': optional: true - '@esbuild/aix-ppc64@0.27.2': + '@esbuild/aix-ppc64@0.27.3': optional: true '@esbuild/android-arm64@0.25.12': optional: true - '@esbuild/android-arm64@0.27.2': + '@esbuild/android-arm64@0.27.3': optional: true '@esbuild/android-arm@0.25.12': optional: true - '@esbuild/android-arm@0.27.2': + '@esbuild/android-arm@0.27.3': optional: true '@esbuild/android-x64@0.25.12': optional: true - '@esbuild/android-x64@0.27.2': + '@esbuild/android-x64@0.27.3': optional: true '@esbuild/darwin-arm64@0.25.12': optional: true - '@esbuild/darwin-arm64@0.27.2': + '@esbuild/darwin-arm64@0.27.3': optional: true '@esbuild/darwin-x64@0.25.12': optional: true - '@esbuild/darwin-x64@0.27.2': + '@esbuild/darwin-x64@0.27.3': optional: true '@esbuild/freebsd-arm64@0.25.12': optional: true - '@esbuild/freebsd-arm64@0.27.2': + '@esbuild/freebsd-arm64@0.27.3': optional: true '@esbuild/freebsd-x64@0.25.12': optional: true - '@esbuild/freebsd-x64@0.27.2': + '@esbuild/freebsd-x64@0.27.3': optional: true '@esbuild/linux-arm64@0.25.12': optional: true - '@esbuild/linux-arm64@0.27.2': + '@esbuild/linux-arm64@0.27.3': optional: true '@esbuild/linux-arm@0.25.12': optional: true - '@esbuild/linux-arm@0.27.2': + '@esbuild/linux-arm@0.27.3': optional: true '@esbuild/linux-ia32@0.25.12': optional: true - '@esbuild/linux-ia32@0.27.2': + '@esbuild/linux-ia32@0.27.3': optional: true '@esbuild/linux-loong64@0.25.12': optional: true - '@esbuild/linux-loong64@0.27.2': + '@esbuild/linux-loong64@0.27.3': optional: true '@esbuild/linux-mips64el@0.25.12': optional: true - '@esbuild/linux-mips64el@0.27.2': + '@esbuild/linux-mips64el@0.27.3': optional: true '@esbuild/linux-ppc64@0.25.12': optional: true - '@esbuild/linux-ppc64@0.27.2': + '@esbuild/linux-ppc64@0.27.3': optional: true '@esbuild/linux-riscv64@0.25.12': optional: true - '@esbuild/linux-riscv64@0.27.2': + '@esbuild/linux-riscv64@0.27.3': optional: true '@esbuild/linux-s390x@0.25.12': optional: true - '@esbuild/linux-s390x@0.27.2': + '@esbuild/linux-s390x@0.27.3': optional: true '@esbuild/linux-x64@0.25.12': optional: true - '@esbuild/linux-x64@0.27.2': + '@esbuild/linux-x64@0.27.3': optional: true '@esbuild/netbsd-arm64@0.25.12': optional: true - '@esbuild/netbsd-arm64@0.27.2': + '@esbuild/netbsd-arm64@0.27.3': optional: true '@esbuild/netbsd-x64@0.25.12': optional: true - '@esbuild/netbsd-x64@0.27.2': + '@esbuild/netbsd-x64@0.27.3': optional: true '@esbuild/openbsd-arm64@0.25.12': optional: true - '@esbuild/openbsd-arm64@0.27.2': + '@esbuild/openbsd-arm64@0.27.3': optional: true '@esbuild/openbsd-x64@0.25.12': optional: true - '@esbuild/openbsd-x64@0.27.2': + '@esbuild/openbsd-x64@0.27.3': optional: true '@esbuild/openharmony-arm64@0.25.12': optional: true - '@esbuild/openharmony-arm64@0.27.2': + '@esbuild/openharmony-arm64@0.27.3': optional: true '@esbuild/sunos-x64@0.25.12': optional: true - '@esbuild/sunos-x64@0.27.2': + '@esbuild/sunos-x64@0.27.3': optional: true '@esbuild/win32-arm64@0.25.12': optional: true - '@esbuild/win32-arm64@0.27.2': + '@esbuild/win32-arm64@0.27.3': optional: true '@esbuild/win32-ia32@0.25.12': optional: true - '@esbuild/win32-ia32@0.27.2': + '@esbuild/win32-ia32@0.27.3': optional: true '@esbuild/win32-x64@0.25.12': optional: true - '@esbuild/win32-x64@0.27.2': + '@esbuild/win32-x64@0.27.3': optional: true '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))': @@ -12740,9 +12907,9 @@ snapshots: '@eslint-community/regexpp@4.12.2': {} - '@eslint/compat@2.0.0(eslint@9.39.2(jiti@2.6.1))': + '@eslint/compat@2.0.2(eslint@9.39.2(jiti@2.6.1))': dependencies: - '@eslint/core': 1.0.0 + '@eslint/core': 1.1.0 optionalDependencies: eslint: 9.39.2(jiti@2.6.1) @@ -12750,7 +12917,7 @@ snapshots: dependencies: '@eslint/object-schema': 2.1.7 debug: 4.4.3 - minimatch: 3.1.2 + minimatch: 3.1.5 transitivePeerDependencies: - supports-color @@ -12762,25 +12929,25 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/core@1.0.0': + '@eslint/core@1.1.0': dependencies: '@types/json-schema': 7.0.15 - '@eslint/css-tree@3.6.8': + '@eslint/css-tree@3.6.9': dependencies: mdn-data: 2.23.0 source-map-js: 1.2.1 - '@eslint/eslintrc@3.3.3': + '@eslint/eslintrc@3.3.4': dependencies: - ajv: 6.12.6 + ajv: 6.14.0 debug: 4.4.3 espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.1 js-yaml: 4.1.1 - minimatch: 3.1.2 + minimatch: 3.1.5 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color @@ -12794,7 +12961,7 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 - '@faker-js/faker@10.2.0': {} + '@faker-js/faker@10.3.0': {} '@fontsource-variable/dm-sans@5.2.8': {} @@ -12826,26 +12993,30 @@ snapshots: dependencies: tslib: 2.8.1 - '@hookform/devtools@4.4.0(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@hono/node-server@1.19.9(hono@4.11.4)': dependencies: - '@emotion/react': 11.14.0(@types/react@19.2.7)(react@19.2.3) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.7)(react@19.2.3))(@types/react@19.2.7)(react@19.2.3) - '@types/lodash': 4.17.21 - little-state-machine: 4.8.1(react@19.2.3) - lodash: 4.17.21 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - react-simple-animate: 3.5.3(react-dom@19.2.3(react@19.2.3)) - use-deep-compare-effect: 1.8.1(react@19.2.3) + hono: 4.11.4 + + '@hookform/devtools@4.4.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) + '@types/lodash': 4.17.24 + little-state-machine: 4.8.1(react@19.2.4) + lodash: 4.17.23 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-simple-animate: 3.5.3(react-dom@19.2.4(react@19.2.4)) + use-deep-compare-effect: 1.8.1(react@19.2.4) uuid: 8.3.2 transitivePeerDependencies: - '@types/react' - supports-color - '@hookform/resolvers@5.2.2(react-hook-form@7.70.0(react@19.2.3))': + '@hookform/resolvers@5.2.2(react-hook-form@7.70.0(react@19.2.4))': dependencies: '@standard-schema/utils': 0.3.0 - react-hook-form: 7.70.0(react@19.2.3) + react-hook-form: 7.70.0(react@19.2.4) '@humanfs/core@0.19.1': {} @@ -12858,162 +13029,154 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@inquirer/ansi@2.0.2': {} + '@inquirer/ansi@2.0.3': {} - '@inquirer/checkbox@5.0.3(@types/node@25.0.3)': + '@inquirer/checkbox@5.1.0(@types/node@25.3.5)': dependencies: - '@inquirer/ansi': 2.0.2 - '@inquirer/core': 11.1.0(@types/node@25.0.3) - '@inquirer/figures': 2.0.2 - '@inquirer/type': 4.0.2(@types/node@25.0.3) + '@inquirer/ansi': 2.0.3 + '@inquirer/core': 11.1.5(@types/node@25.3.5) + '@inquirer/figures': 2.0.3 + '@inquirer/type': 4.0.3(@types/node@25.3.5) optionalDependencies: - '@types/node': 25.0.3 + '@types/node': 25.3.5 - '@inquirer/confirm@6.0.3(@types/node@25.0.3)': + '@inquirer/confirm@6.0.8(@types/node@25.3.5)': dependencies: - '@inquirer/core': 11.1.0(@types/node@25.0.3) - '@inquirer/type': 4.0.2(@types/node@25.0.3) + '@inquirer/core': 11.1.5(@types/node@25.3.5) + '@inquirer/type': 4.0.3(@types/node@25.3.5) optionalDependencies: - '@types/node': 25.0.3 + '@types/node': 25.3.5 - '@inquirer/core@11.1.0(@types/node@25.0.3)': + '@inquirer/core@11.1.5(@types/node@25.3.5)': dependencies: - '@inquirer/ansi': 2.0.2 - '@inquirer/figures': 2.0.2 - '@inquirer/type': 4.0.2(@types/node@25.0.3) + '@inquirer/ansi': 2.0.3 + '@inquirer/figures': 2.0.3 + '@inquirer/type': 4.0.3(@types/node@25.3.5) cli-width: 4.1.0 + fast-wrap-ansi: 0.2.0 mute-stream: 3.0.0 signal-exit: 4.1.0 - wrap-ansi: 9.0.2 optionalDependencies: - '@types/node': 25.0.3 + '@types/node': 25.3.5 - '@inquirer/editor@5.0.3(@types/node@25.0.3)': + '@inquirer/editor@5.0.8(@types/node@25.3.5)': dependencies: - '@inquirer/core': 11.1.0(@types/node@25.0.3) - '@inquirer/external-editor': 2.0.2(@types/node@25.0.3) - '@inquirer/type': 4.0.2(@types/node@25.0.3) + '@inquirer/core': 11.1.5(@types/node@25.3.5) + '@inquirer/external-editor': 2.0.3(@types/node@25.3.5) + '@inquirer/type': 4.0.3(@types/node@25.3.5) optionalDependencies: - '@types/node': 25.0.3 + '@types/node': 25.3.5 - '@inquirer/expand@5.0.3(@types/node@25.0.3)': + '@inquirer/expand@5.0.8(@types/node@25.3.5)': dependencies: - '@inquirer/core': 11.1.0(@types/node@25.0.3) - '@inquirer/type': 4.0.2(@types/node@25.0.3) + '@inquirer/core': 11.1.5(@types/node@25.3.5) + '@inquirer/type': 4.0.3(@types/node@25.3.5) optionalDependencies: - '@types/node': 25.0.3 + '@types/node': 25.3.5 - '@inquirer/external-editor@2.0.2(@types/node@25.0.3)': + '@inquirer/external-editor@2.0.3(@types/node@25.3.5)': dependencies: chardet: 2.1.1 - iconv-lite: 0.7.1 + iconv-lite: 0.7.2 optionalDependencies: - '@types/node': 25.0.3 + '@types/node': 25.3.5 - '@inquirer/figures@2.0.2': {} + '@inquirer/figures@2.0.3': {} - '@inquirer/input@5.0.3(@types/node@25.0.3)': + '@inquirer/input@5.0.8(@types/node@25.3.5)': dependencies: - '@inquirer/core': 11.1.0(@types/node@25.0.3) - '@inquirer/type': 4.0.2(@types/node@25.0.3) + '@inquirer/core': 11.1.5(@types/node@25.3.5) + '@inquirer/type': 4.0.3(@types/node@25.3.5) optionalDependencies: - '@types/node': 25.0.3 + '@types/node': 25.3.5 - '@inquirer/number@4.0.3(@types/node@25.0.3)': + '@inquirer/number@4.0.8(@types/node@25.3.5)': dependencies: - '@inquirer/core': 11.1.0(@types/node@25.0.3) - '@inquirer/type': 4.0.2(@types/node@25.0.3) + '@inquirer/core': 11.1.5(@types/node@25.3.5) + '@inquirer/type': 4.0.3(@types/node@25.3.5) optionalDependencies: - '@types/node': 25.0.3 + '@types/node': 25.3.5 - '@inquirer/password@5.0.3(@types/node@25.0.3)': + '@inquirer/password@5.0.8(@types/node@25.3.5)': dependencies: - '@inquirer/ansi': 2.0.2 - '@inquirer/core': 11.1.0(@types/node@25.0.3) - '@inquirer/type': 4.0.2(@types/node@25.0.3) + '@inquirer/ansi': 2.0.3 + '@inquirer/core': 11.1.5(@types/node@25.3.5) + '@inquirer/type': 4.0.3(@types/node@25.3.5) optionalDependencies: - '@types/node': 25.0.3 - - '@inquirer/prompts@8.1.0(@types/node@25.0.3)': - dependencies: - '@inquirer/checkbox': 5.0.3(@types/node@25.0.3) - '@inquirer/confirm': 6.0.3(@types/node@25.0.3) - '@inquirer/editor': 5.0.3(@types/node@25.0.3) - '@inquirer/expand': 5.0.3(@types/node@25.0.3) - '@inquirer/input': 5.0.3(@types/node@25.0.3) - '@inquirer/number': 4.0.3(@types/node@25.0.3) - '@inquirer/password': 5.0.3(@types/node@25.0.3) - '@inquirer/rawlist': 5.1.0(@types/node@25.0.3) - '@inquirer/search': 4.0.3(@types/node@25.0.3) - '@inquirer/select': 5.0.3(@types/node@25.0.3) + '@types/node': 25.3.5 + + '@inquirer/prompts@8.3.0(@types/node@25.3.5)': + dependencies: + '@inquirer/checkbox': 5.1.0(@types/node@25.3.5) + '@inquirer/confirm': 6.0.8(@types/node@25.3.5) + '@inquirer/editor': 5.0.8(@types/node@25.3.5) + '@inquirer/expand': 5.0.8(@types/node@25.3.5) + '@inquirer/input': 5.0.8(@types/node@25.3.5) + '@inquirer/number': 4.0.8(@types/node@25.3.5) + '@inquirer/password': 5.0.8(@types/node@25.3.5) + '@inquirer/rawlist': 5.2.4(@types/node@25.3.5) + '@inquirer/search': 4.1.4(@types/node@25.3.5) + '@inquirer/select': 5.1.0(@types/node@25.3.5) optionalDependencies: - '@types/node': 25.0.3 + '@types/node': 25.3.5 - '@inquirer/rawlist@5.1.0(@types/node@25.0.3)': + '@inquirer/rawlist@5.2.4(@types/node@25.3.5)': dependencies: - '@inquirer/core': 11.1.0(@types/node@25.0.3) - '@inquirer/type': 4.0.2(@types/node@25.0.3) + '@inquirer/core': 11.1.5(@types/node@25.3.5) + '@inquirer/type': 4.0.3(@types/node@25.3.5) optionalDependencies: - '@types/node': 25.0.3 + '@types/node': 25.3.5 - '@inquirer/search@4.0.3(@types/node@25.0.3)': + '@inquirer/search@4.1.4(@types/node@25.3.5)': dependencies: - '@inquirer/core': 11.1.0(@types/node@25.0.3) - '@inquirer/figures': 2.0.2 - '@inquirer/type': 4.0.2(@types/node@25.0.3) + '@inquirer/core': 11.1.5(@types/node@25.3.5) + '@inquirer/figures': 2.0.3 + '@inquirer/type': 4.0.3(@types/node@25.3.5) optionalDependencies: - '@types/node': 25.0.3 + '@types/node': 25.3.5 - '@inquirer/select@5.0.3(@types/node@25.0.3)': + '@inquirer/select@5.1.0(@types/node@25.3.5)': dependencies: - '@inquirer/ansi': 2.0.2 - '@inquirer/core': 11.1.0(@types/node@25.0.3) - '@inquirer/figures': 2.0.2 - '@inquirer/type': 4.0.2(@types/node@25.0.3) + '@inquirer/ansi': 2.0.3 + '@inquirer/core': 11.1.5(@types/node@25.3.5) + '@inquirer/figures': 2.0.3 + '@inquirer/type': 4.0.3(@types/node@25.3.5) optionalDependencies: - '@types/node': 25.0.3 + '@types/node': 25.3.5 - '@inquirer/type@4.0.2(@types/node@25.0.3)': + '@inquirer/type@4.0.3(@types/node@25.3.5)': optionalDependencies: - '@types/node': 25.0.3 + '@types/node': 25.3.5 - '@internationalized/date@3.10.1': + '@internationalized/date@3.12.0': dependencies: - '@swc/helpers': 0.5.18 + '@swc/helpers': 0.5.19 '@internationalized/message@3.1.8': dependencies: - '@swc/helpers': 0.5.18 + '@swc/helpers': 0.5.19 intl-messageformat: 10.7.18 '@internationalized/number@3.6.5': dependencies: - '@swc/helpers': 0.5.18 + '@swc/helpers': 0.5.19 '@internationalized/string@3.2.7': dependencies: - '@swc/helpers': 0.5.18 - - '@isaacs/balanced-match@4.0.1': {} - - '@isaacs/brace-expansion@5.0.0': - dependencies: - '@isaacs/balanced-match': 4.0.1 + '@swc/helpers': 0.5.19 '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 string-width-cjs: string-width@4.2.3 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 strip-ansi-cjs: strip-ansi@6.0.1 wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 - '@isaacs/cliui@9.0.0': {} - '@isaacs/fs-minipass@4.0.1': dependencies: - minipass: 7.1.2 + minipass: 7.1.3 '@jest/diff-sequences@30.0.1': {} @@ -13021,13 +13184,13 @@ snapshots: '@jest/schemas@30.0.5': dependencies: - '@sinclair/typebox': 0.34.47 + '@sinclair/typebox': 0.34.48 - '@joshwooding/vite-plugin-react-docgen-typescript@0.6.3(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@joshwooding/vite-plugin-react-docgen-typescript@0.6.4(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': dependencies: - glob: 11.1.0 + glob: 13.0.6 react-docgen-typescript: 2.4.0(typescript@5.9.3) - vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) optionalDependencies: typescript: 5.9.3 @@ -13060,52 +13223,50 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@lezer/common@1.5.0': {} - '@lezer/common@1.5.1': {} - '@lezer/css@1.3.0': + '@lezer/css@1.3.1': dependencies: - '@lezer/common': 1.5.0 + '@lezer/common': 1.5.1 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.7 + '@lezer/lr': 1.4.8 '@lezer/generator@1.8.0': dependencies: - '@lezer/common': 1.5.0 - '@lezer/lr': 1.4.7 + '@lezer/common': 1.5.1 + '@lezer/lr': 1.4.8 '@lezer/highlight@1.2.3': dependencies: - '@lezer/common': 1.5.0 + '@lezer/common': 1.5.1 '@lezer/html@1.3.13': dependencies: - '@lezer/common': 1.5.0 + '@lezer/common': 1.5.1 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.7 + '@lezer/lr': 1.4.8 '@lezer/javascript@1.5.4': dependencies: - '@lezer/common': 1.5.0 + '@lezer/common': 1.5.1 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.7 + '@lezer/lr': 1.4.8 '@lezer/json@1.0.3': dependencies: - '@lezer/common': 1.5.0 + '@lezer/common': 1.5.1 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.7 + '@lezer/lr': 1.4.8 - '@lezer/lr@1.4.7': + '@lezer/lr@1.4.8': dependencies: - '@lezer/common': 1.5.0 + '@lezer/common': 1.5.1 '@lezer/xml@1.0.6': dependencies: - '@lezer/common': 1.5.0 + '@lezer/common': 1.5.1 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.7 + '@lezer/lr': 1.4.8 '@libsql/client@0.14.0': dependencies: @@ -13176,18 +13337,18 @@ snapshots: dependencies: debug: 4.4.3 fs-extra: 9.1.0 - lodash: 4.17.21 + lodash: 4.17.23 tmp-promise: 3.0.3 transitivePeerDependencies: - supports-color '@marijn/find-cluster-break@1.0.2': {} - '@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3)': + '@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4)': dependencies: '@types/mdx': 2.0.13 - '@types/react': 19.2.7 - react: 19.2.3 + '@types/react': 19.2.14 + react: 19.2.4 '@module-federation/bridge-react-webpack-plugin@0.21.6': dependencies: @@ -13195,9 +13356,9 @@ snapshots: '@types/semver': 7.5.8 semver: 7.6.3 - '@module-federation/bridge-react-webpack-plugin@0.22.0': + '@module-federation/bridge-react-webpack-plugin@2.1.0': dependencies: - '@module-federation/sdk': 0.22.0 + '@module-federation/sdk': 2.1.0 '@types/semver': 7.5.8 semver: 7.6.3 @@ -13216,10 +13377,10 @@ snapshots: - utf-8-validate - vue-tsc - '@module-federation/cli@0.22.0(typescript@5.9.3)': + '@module-federation/cli@2.1.0(typescript@5.9.3)': dependencies: - '@module-federation/dts-plugin': 0.22.0(typescript@5.9.3) - '@module-federation/sdk': 0.22.0 + '@module-federation/dts-plugin': 2.1.0(typescript@5.9.3) + '@module-federation/sdk': 2.1.0 chalk: 3.0.0 commander: 11.1.0 jiti: 2.4.2 @@ -13231,21 +13392,22 @@ snapshots: - utf-8-validate - vue-tsc - '@module-federation/data-prefetch@0.21.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@module-federation/data-prefetch@0.21.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@module-federation/runtime': 0.21.6 '@module-federation/sdk': 0.21.6 fs-extra: 9.1.0 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) - '@module-federation/data-prefetch@0.22.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@module-federation/data-prefetch@2.1.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@module-federation/runtime': 0.22.0 - '@module-federation/sdk': 0.22.0 + '@module-federation/runtime': 2.1.0 + '@module-federation/sdk': 2.1.0 fs-extra: 9.1.0 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) '@module-federation/dts-plugin@0.21.6(typescript@5.9.3)': dependencies: @@ -13255,7 +13417,7 @@ snapshots: '@module-federation/third-party-dts-extractor': 0.21.6 adm-zip: 0.5.16 ansi-colors: 4.1.3 - axios: 1.13.2 + axios: 1.13.6 chalk: 3.0.0 fs-extra: 9.1.0 isomorphic-ws: 5.0.0(ws@8.18.0) @@ -13272,19 +13434,18 @@ snapshots: - supports-color - utf-8-validate - '@module-federation/dts-plugin@0.22.0(typescript@5.9.3)': + '@module-federation/dts-plugin@2.1.0(typescript@5.9.3)': dependencies: - '@module-federation/error-codes': 0.22.0 - '@module-federation/managers': 0.22.0 - '@module-federation/sdk': 0.22.0 - '@module-federation/third-party-dts-extractor': 0.22.0 + '@module-federation/error-codes': 2.1.0 + '@module-federation/managers': 2.1.0 + '@module-federation/sdk': 2.1.0 + '@module-federation/third-party-dts-extractor': 2.1.0 adm-zip: 0.5.16 ansi-colors: 4.1.3 - axios: 1.13.2 + axios: 1.13.6 chalk: 3.0.0 fs-extra: 9.1.0 isomorphic-ws: 5.0.0(ws@8.18.0) - koa: 3.0.3 lodash.clonedeepwith: 4.5.0 log4js: 6.9.1 node-schedule: 2.1.1 @@ -13297,17 +13458,17 @@ snapshots: - supports-color - utf-8-validate - '@module-federation/enhanced@0.21.6(@rspack/core@1.6.8(@swc/helpers@0.5.18))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18)))': + '@module-federation/enhanced@0.21.6(@rspack/core@1.6.8(@swc/helpers@0.5.19))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19)))': dependencies: '@module-federation/bridge-react-webpack-plugin': 0.21.6 '@module-federation/cli': 0.21.6(typescript@5.9.3) - '@module-federation/data-prefetch': 0.21.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@module-federation/data-prefetch': 0.21.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@module-federation/dts-plugin': 0.21.6(typescript@5.9.3) '@module-federation/error-codes': 0.21.6 '@module-federation/inject-external-runtime-core-plugin': 0.21.6(@module-federation/runtime-tools@0.21.6) '@module-federation/managers': 0.21.6 '@module-federation/manifest': 0.21.6(typescript@5.9.3) - '@module-federation/rspack': 0.21.6(@rspack/core@1.6.8(@swc/helpers@0.5.18))(typescript@5.9.3) + '@module-federation/rspack': 0.21.6(@rspack/core@1.6.8(@swc/helpers@0.5.19))(typescript@5.9.3) '@module-federation/runtime-tools': 0.21.6 '@module-federation/sdk': 0.21.6 btoa: 1.2.1 @@ -13315,7 +13476,7 @@ snapshots: upath: 2.0.1 optionalDependencies: typescript: 5.9.3 - webpack: 5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18)) + webpack: 5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19)) transitivePeerDependencies: - '@rspack/core' - bufferutil @@ -13325,25 +13486,25 @@ snapshots: - supports-color - utf-8-validate - '@module-federation/enhanced@0.22.0(@rspack/core@1.6.8(@swc/helpers@0.5.18))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18)))': - dependencies: - '@module-federation/bridge-react-webpack-plugin': 0.22.0 - '@module-federation/cli': 0.22.0(typescript@5.9.3) - '@module-federation/data-prefetch': 0.22.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@module-federation/dts-plugin': 0.22.0(typescript@5.9.3) - '@module-federation/error-codes': 0.22.0 - '@module-federation/inject-external-runtime-core-plugin': 0.22.0(@module-federation/runtime-tools@0.22.0) - '@module-federation/managers': 0.22.0 - '@module-federation/manifest': 0.22.0(typescript@5.9.3) - '@module-federation/rspack': 0.22.0(@rspack/core@1.6.8(@swc/helpers@0.5.18))(typescript@5.9.3) - '@module-federation/runtime-tools': 0.22.0 - '@module-federation/sdk': 0.22.0 + '@module-federation/enhanced@2.1.0(@rspack/core@1.6.8(@swc/helpers@0.5.19))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19)))': + dependencies: + '@module-federation/bridge-react-webpack-plugin': 2.1.0 + '@module-federation/cli': 2.1.0(typescript@5.9.3) + '@module-federation/data-prefetch': 2.1.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@module-federation/dts-plugin': 2.1.0(typescript@5.9.3) + '@module-federation/error-codes': 2.1.0 + '@module-federation/inject-external-runtime-core-plugin': 2.1.0(@module-federation/runtime-tools@2.1.0) + '@module-federation/managers': 2.1.0 + '@module-federation/manifest': 2.1.0(typescript@5.9.3) + '@module-federation/rspack': 2.1.0(@rspack/core@1.6.8(@swc/helpers@0.5.19))(typescript@5.9.3) + '@module-federation/runtime-tools': 2.1.0 + '@module-federation/sdk': 2.1.0 btoa: 1.2.1 schema-utils: 4.3.3 upath: 2.0.1 optionalDependencies: typescript: 5.9.3 - webpack: 5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18)) + webpack: 5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19)) transitivePeerDependencies: - '@rspack/core' - bufferutil @@ -13355,15 +13516,15 @@ snapshots: '@module-federation/error-codes@0.21.6': {} - '@module-federation/error-codes@0.22.0': {} + '@module-federation/error-codes@2.1.0': {} '@module-federation/inject-external-runtime-core-plugin@0.21.6(@module-federation/runtime-tools@0.21.6)': dependencies: '@module-federation/runtime-tools': 0.21.6 - '@module-federation/inject-external-runtime-core-plugin@0.22.0(@module-federation/runtime-tools@0.22.0)': + '@module-federation/inject-external-runtime-core-plugin@2.1.0(@module-federation/runtime-tools@2.1.0)': dependencies: - '@module-federation/runtime-tools': 0.22.0 + '@module-federation/runtime-tools': 2.1.0 '@module-federation/managers@0.21.6': dependencies: @@ -13371,9 +13532,9 @@ snapshots: find-pkg: 2.0.0 fs-extra: 9.1.0 - '@module-federation/managers@0.22.0': + '@module-federation/managers@2.1.0': dependencies: - '@module-federation/sdk': 0.22.0 + '@module-federation/sdk': 2.1.0 find-pkg: 2.0.0 fs-extra: 9.1.0 @@ -13392,11 +13553,11 @@ snapshots: - utf-8-validate - vue-tsc - '@module-federation/manifest@0.22.0(typescript@5.9.3)': + '@module-federation/manifest@2.1.0(typescript@5.9.3)': dependencies: - '@module-federation/dts-plugin': 0.22.0(typescript@5.9.3) - '@module-federation/managers': 0.22.0 - '@module-federation/sdk': 0.22.0 + '@module-federation/dts-plugin': 2.1.0(typescript@5.9.3) + '@module-federation/managers': 2.1.0 + '@module-federation/sdk': 2.1.0 chalk: 3.0.0 find-pkg: 2.0.0 transitivePeerDependencies: @@ -13407,28 +13568,28 @@ snapshots: - utf-8-validate - vue-tsc - '@module-federation/node@2.7.26(@rspack/core@1.6.8(@swc/helpers@0.5.18))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18)))': + '@module-federation/node@2.7.33(@rspack/core@1.6.8(@swc/helpers@0.5.19))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19)))': dependencies: - '@module-federation/enhanced': 0.22.0(@rspack/core@1.6.8(@swc/helpers@0.5.18))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@module-federation/runtime': 0.22.0 - '@module-federation/sdk': 0.22.0 + '@module-federation/enhanced': 2.1.0(@rspack/core@1.6.8(@swc/helpers@0.5.19))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@module-federation/runtime': 2.1.0 + '@module-federation/sdk': 2.1.0 btoa: 1.2.1 encoding: 0.1.13 node-fetch: 2.7.0(encoding@0.1.13) - webpack: 5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18)) optionalDependencies: - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + webpack: 5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19)) transitivePeerDependencies: - '@rspack/core' - bufferutil - debug + - react + - react-dom - supports-color - typescript - utf-8-validate - vue-tsc - '@module-federation/rspack@0.21.6(@rspack/core@1.6.8(@swc/helpers@0.5.18))(typescript@5.9.3)': + '@module-federation/rspack@0.21.6(@rspack/core@1.6.8(@swc/helpers@0.5.19))(typescript@5.9.3)': dependencies: '@module-federation/bridge-react-webpack-plugin': 0.21.6 '@module-federation/dts-plugin': 0.21.6(typescript@5.9.3) @@ -13437,7 +13598,7 @@ snapshots: '@module-federation/manifest': 0.21.6(typescript@5.9.3) '@module-federation/runtime-tools': 0.21.6 '@module-federation/sdk': 0.21.6 - '@rspack/core': 1.6.8(@swc/helpers@0.5.18) + '@rspack/core': 1.6.8(@swc/helpers@0.5.19) btoa: 1.2.1 optionalDependencies: typescript: 5.9.3 @@ -13447,16 +13608,16 @@ snapshots: - supports-color - utf-8-validate - '@module-federation/rspack@0.22.0(@rspack/core@1.6.8(@swc/helpers@0.5.18))(typescript@5.9.3)': + '@module-federation/rspack@2.1.0(@rspack/core@1.6.8(@swc/helpers@0.5.19))(typescript@5.9.3)': dependencies: - '@module-federation/bridge-react-webpack-plugin': 0.22.0 - '@module-federation/dts-plugin': 0.22.0(typescript@5.9.3) - '@module-federation/inject-external-runtime-core-plugin': 0.22.0(@module-federation/runtime-tools@0.22.0) - '@module-federation/managers': 0.22.0 - '@module-federation/manifest': 0.22.0(typescript@5.9.3) - '@module-federation/runtime-tools': 0.22.0 - '@module-federation/sdk': 0.22.0 - '@rspack/core': 1.6.8(@swc/helpers@0.5.18) + '@module-federation/bridge-react-webpack-plugin': 2.1.0 + '@module-federation/dts-plugin': 2.1.0(typescript@5.9.3) + '@module-federation/inject-external-runtime-core-plugin': 2.1.0(@module-federation/runtime-tools@2.1.0) + '@module-federation/managers': 2.1.0 + '@module-federation/manifest': 2.1.0(typescript@5.9.3) + '@module-federation/runtime-tools': 2.1.0 + '@module-federation/sdk': 2.1.0 + '@rspack/core': 1.6.8(@swc/helpers@0.5.19) btoa: 1.2.1 optionalDependencies: typescript: 5.9.3 @@ -13471,20 +13632,20 @@ snapshots: '@module-federation/error-codes': 0.21.6 '@module-federation/sdk': 0.21.6 - '@module-federation/runtime-core@0.22.0': + '@module-federation/runtime-core@2.1.0': dependencies: - '@module-federation/error-codes': 0.22.0 - '@module-federation/sdk': 0.22.0 + '@module-federation/error-codes': 2.1.0 + '@module-federation/sdk': 2.1.0 '@module-federation/runtime-tools@0.21.6': dependencies: '@module-federation/runtime': 0.21.6 '@module-federation/webpack-bundler-runtime': 0.21.6 - '@module-federation/runtime-tools@0.22.0': + '@module-federation/runtime-tools@2.1.0': dependencies: - '@module-federation/runtime': 0.22.0 - '@module-federation/webpack-bundler-runtime': 0.22.0 + '@module-federation/runtime': 2.1.0 + '@module-federation/webpack-bundler-runtime': 2.1.0 '@module-federation/runtime@0.21.6': dependencies: @@ -13492,15 +13653,15 @@ snapshots: '@module-federation/runtime-core': 0.21.6 '@module-federation/sdk': 0.21.6 - '@module-federation/runtime@0.22.0': + '@module-federation/runtime@2.1.0': dependencies: - '@module-federation/error-codes': 0.22.0 - '@module-federation/runtime-core': 0.22.0 - '@module-federation/sdk': 0.22.0 + '@module-federation/error-codes': 2.1.0 + '@module-federation/runtime-core': 2.1.0 + '@module-federation/sdk': 2.1.0 '@module-federation/sdk@0.21.6': {} - '@module-federation/sdk@0.22.0': {} + '@module-federation/sdk@2.1.0': {} '@module-federation/third-party-dts-extractor@0.21.6': dependencies: @@ -13508,7 +13669,7 @@ snapshots: fs-extra: 9.1.0 resolve: 1.22.8 - '@module-federation/third-party-dts-extractor@0.22.0': + '@module-federation/third-party-dts-extractor@2.1.0': dependencies: find-pkg: 2.0.0 fs-extra: 9.1.0 @@ -13519,10 +13680,14 @@ snapshots: '@module-federation/runtime': 0.21.6 '@module-federation/sdk': 0.21.6 - '@module-federation/webpack-bundler-runtime@0.22.0': + '@module-federation/webpack-bundler-runtime@2.1.0': dependencies: - '@module-federation/runtime': 0.22.0 - '@module-federation/sdk': 0.22.0 + '@module-federation/runtime': 2.1.0 + '@module-federation/sdk': 2.1.0 + + '@mongodb-js/saslprep@1.4.6': + dependencies: + sparse-bitfield: 3.0.3 '@mrleebo/prisma-ast@0.13.1': dependencies: @@ -13608,27 +13773,27 @@ snapshots: agent-base: 7.1.4 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 - lru-cache: 11.2.4 + lru-cache: 11.2.6 socks-proxy-agent: 8.0.5 transitivePeerDependencies: - supports-color '@npmcli/fs@4.0.0': dependencies: - semver: 7.7.3 + semver: 7.7.4 '@npmcli/fs@5.0.0': dependencies: - semver: 7.7.3 + semver: 7.7.2 '@npmcli/redact@4.0.0': {} - '@nx/cypress@22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(@zkochan/js-yaml@0.0.7)(eslint@9.39.2(jiti@2.6.1))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)))(typescript@5.9.3)': + '@nx/cypress@22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(@zkochan/js-yaml@0.0.7)(eslint@9.39.2(jiti@2.6.1))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)))(typescript@5.9.3)': dependencies: - '@nx/devkit': 22.3.3(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@nx/eslint': 22.3.3(patch_hash=45d7a0a2e2d55c4ffd4beb467a0e02fac3f27bc1857270f522acafd5365d2c6b)(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(@zkochan/js-yaml@0.0.7)(eslint@9.39.2(jiti@2.6.1))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@nx/js': 22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@phenomnomnominal/tsquery': 5.0.1(typescript@5.9.3) + '@nx/devkit': 22.5.4(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@nx/eslint': 22.5.4(patch_hash=45d7a0a2e2d55c4ffd4beb467a0e02fac3f27bc1857270f522acafd5365d2c6b)(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(@zkochan/js-yaml@0.0.7)(eslint@9.39.2(jiti@2.6.1))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@nx/js': 22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@phenomnomnominal/tsquery': 6.1.4(typescript@5.9.3) detect-port: 1.6.1 semver: 7.7.4 tree-kill: 1.2.2 @@ -13645,21 +13810,21 @@ snapshots: - typescript - verdaccio - '@nx/devkit@22.3.3(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)))': + '@nx/devkit@22.5.4(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)))': dependencies: '@zkochan/js-yaml': 0.0.7 ejs: 3.1.10 enquirer: 2.3.6 - minimatch: 9.0.3 - nx: 22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)) + minimatch: 10.2.4 + nx: 22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)) semver: 7.7.4 tslib: 2.8.1 yargs-parser: 21.1.1 - '@nx/eslint@22.3.3(patch_hash=45d7a0a2e2d55c4ffd4beb467a0e02fac3f27bc1857270f522acafd5365d2c6b)(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(@zkochan/js-yaml@0.0.7)(eslint@9.39.2(jiti@2.6.1))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)))': + '@nx/eslint@22.5.4(patch_hash=45d7a0a2e2d55c4ffd4beb467a0e02fac3f27bc1857270f522acafd5365d2c6b)(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(@zkochan/js-yaml@0.0.7)(eslint@9.39.2(jiti@2.6.1))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)))': dependencies: - '@nx/devkit': 22.3.3(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@nx/js': 22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) + '@nx/devkit': 22.5.4(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@nx/js': 22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) eslint: 9.39.2(jiti@2.6.1) semver: 7.7.4 tslib: 2.8.1 @@ -13675,21 +13840,21 @@ snapshots: - supports-color - verdaccio - '@nx/js@22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)))': - dependencies: - '@babel/core': 7.28.5 - '@babel/plugin-proposal-decorators': 7.28.0(@babel/core@7.28.5) - '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-runtime': 7.28.5(@babel/core@7.28.5) - '@babel/preset-env': 7.28.5(@babel/core@7.28.5) - '@babel/preset-typescript': 7.28.5(@babel/core@7.28.5) - '@babel/runtime': 7.28.4 - '@nx/devkit': 22.3.3(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@nx/workspace': 22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)) + '@nx/js@22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)))': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-runtime': 7.29.0(@babel/core@7.29.0) + '@babel/preset-env': 7.29.0(@babel/core@7.29.0) + '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) + '@babel/runtime': 7.28.6 + '@nx/devkit': 22.5.4(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@nx/workspace': 22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)) '@zkochan/js-yaml': 0.0.7 - babel-plugin-const-enum: 1.2.0(@babel/core@7.28.5) + babel-plugin-const-enum: 1.2.0(@babel/core@7.29.0) babel-plugin-macros: 3.1.0 - babel-plugin-transform-typescript-metadata: 0.3.2(@babel/core@7.28.5)(@babel/traverse@7.28.5) + babel-plugin-transform-typescript-metadata: 0.3.2(@babel/core@7.29.0)(@babel/traverse@7.29.0) chalk: 4.1.2 columnify: 1.6.0 detect-port: 1.6.1 @@ -13711,20 +13876,20 @@ snapshots: - nx - supports-color - '@nx/module-federation@22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/helpers@0.5.18)(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@nx/module-federation@22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/helpers@0.5.19)(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)': dependencies: - '@module-federation/enhanced': 0.21.6(@rspack/core@1.6.8(@swc/helpers@0.5.18))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@module-federation/node': 2.7.26(@rspack/core@1.6.8(@swc/helpers@0.5.18))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))) + '@module-federation/enhanced': 0.21.6(@rspack/core@1.6.8(@swc/helpers@0.5.19))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@module-federation/node': 2.7.33(@rspack/core@1.6.8(@swc/helpers@0.5.19))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))) '@module-federation/sdk': 0.21.6 - '@nx/devkit': 22.3.3(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@nx/js': 22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@nx/web': 22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@rspack/core': 1.6.8(@swc/helpers@0.5.18) + '@nx/devkit': 22.5.4(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@nx/js': 22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@nx/web': 22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@rspack/core': 1.6.8(@swc/helpers@0.5.19) express: 4.22.1 http-proxy-middleware: 3.0.5 picocolors: 1.1.1 tslib: 2.8.1 - webpack: 5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18)) + webpack: 5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19)) transitivePeerDependencies: - '@babel/traverse' - '@swc-node/register' @@ -13733,7 +13898,6 @@ snapshots: - bufferutil - debug - esbuild - - next - nx - react - react-dom @@ -13745,55 +13909,54 @@ snapshots: - vue-tsc - webpack-cli - '@nx/nx-darwin-arm64@22.3.3': + '@nx/nx-darwin-arm64@22.5.4': optional: true - '@nx/nx-darwin-x64@22.3.3': + '@nx/nx-darwin-x64@22.5.4': optional: true - '@nx/nx-freebsd-x64@22.3.3': + '@nx/nx-freebsd-x64@22.5.4': optional: true - '@nx/nx-linux-arm-gnueabihf@22.3.3': + '@nx/nx-linux-arm-gnueabihf@22.5.4': optional: true - '@nx/nx-linux-arm64-gnu@22.3.3': + '@nx/nx-linux-arm64-gnu@22.5.4': optional: true - '@nx/nx-linux-arm64-musl@22.3.3': + '@nx/nx-linux-arm64-musl@22.5.4': optional: true - '@nx/nx-linux-x64-gnu@22.3.3': + '@nx/nx-linux-x64-gnu@22.5.4': optional: true - '@nx/nx-linux-x64-musl@22.3.3': + '@nx/nx-linux-x64-musl@22.5.4': optional: true - '@nx/nx-win32-arm64-msvc@22.3.3': + '@nx/nx-win32-arm64-msvc@22.5.4': optional: true - '@nx/nx-win32-x64-msvc@22.3.3': + '@nx/nx-win32-x64-msvc@22.5.4': optional: true - '@nx/react@22.3.3(@babel/core@7.28.5)(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/helpers@0.5.18)(@types/babel__core@7.20.5)(@zkochan/js-yaml@0.0.7)(eslint@9.39.2(jiti@2.6.1))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3))(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.18(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18)))': + '@nx/react@22.5.4(@babel/core@7.29.0)(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/helpers@0.5.19)(@types/babel__core@7.20.5)(@zkochan/js-yaml@0.0.7)(eslint@9.39.2(jiti@2.6.1))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': dependencies: - '@nx/devkit': 22.3.3(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@nx/eslint': 22.3.3(patch_hash=45d7a0a2e2d55c4ffd4beb467a0e02fac3f27bc1857270f522acafd5365d2c6b)(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(@zkochan/js-yaml@0.0.7)(eslint@9.39.2(jiti@2.6.1))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@nx/js': 22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@nx/module-federation': 22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/helpers@0.5.18)(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@nx/rollup': 22.3.3(@babel/core@7.28.5)(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/babel__core@7.20.5)(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)))(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3))(typescript@5.9.3) - '@nx/web': 22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@phenomnomnominal/tsquery': 5.0.1(typescript@5.9.3) + '@nx/devkit': 22.5.4(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@nx/eslint': 22.5.4(patch_hash=45d7a0a2e2d55c4ffd4beb467a0e02fac3f27bc1857270f522acafd5365d2c6b)(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(@zkochan/js-yaml@0.0.7)(eslint@9.39.2(jiti@2.6.1))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@nx/js': 22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@nx/module-federation': 22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/helpers@0.5.19)(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@nx/rollup': 22.5.4(@babel/core@7.29.0)(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(@types/babel__core@7.20.5)(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)))(typescript@5.9.3) + '@nx/web': 22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@phenomnomnominal/tsquery': 6.1.4(typescript@5.9.3) '@svgr/webpack': 8.1.0(typescript@5.9.3) express: 4.22.1 - file-loader: 6.2.0(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))) http-proxy-middleware: 3.0.5 - minimatch: 9.0.3 + minimatch: 10.2.4 picocolors: 1.1.1 semver: 7.7.4 tslib: 2.8.1 optionalDependencies: - '@nx/vite': 22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)))(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.18(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@nx/vite': 22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)))(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) transitivePeerDependencies: - '@babel/core' - '@babel/traverse' @@ -13806,12 +13969,10 @@ snapshots: - debug - esbuild - eslint - - next - nx - react - react-dom - supports-color - - ts-node - typescript - uglify-js - utf-8-validate @@ -13819,26 +13980,26 @@ snapshots: - vite - vitest - vue-tsc - - webpack - webpack-cli - '@nx/rollup@22.3.3(@babel/core@7.28.5)(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/babel__core@7.20.5)(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)))(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3))(typescript@5.9.3)': - dependencies: - '@nx/devkit': 22.3.3(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@nx/js': 22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@rollup/plugin-babel': 6.1.0(@babel/core@7.28.5)(@types/babel__core@7.20.5)(rollup@4.55.1) - '@rollup/plugin-commonjs': 25.0.8(rollup@4.55.1) - '@rollup/plugin-image': 3.0.3(rollup@4.55.1) - '@rollup/plugin-json': 6.1.0(rollup@4.55.1) - '@rollup/plugin-node-resolve': 15.3.1(rollup@4.55.1) - '@rollup/plugin-typescript': 12.3.0(rollup@4.55.1)(tslib@2.8.1)(typescript@5.9.3) - autoprefixer: 10.4.23(postcss@8.5.6) + '@nx/rollup@22.5.4(@babel/core@7.29.0)(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(@types/babel__core@7.20.5)(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)))(typescript@5.9.3)': + dependencies: + '@nx/devkit': 22.5.4(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@nx/js': 22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@rollup/plugin-babel': 6.1.0(@babel/core@7.29.0)(@types/babel__core@7.20.5)(rollup@4.59.0) + '@rollup/plugin-commonjs': 25.0.8(rollup@4.59.0) + '@rollup/plugin-image': 3.0.3(rollup@4.59.0) + '@rollup/plugin-json': 6.1.0(rollup@4.59.0) + '@rollup/plugin-node-resolve': 15.3.1(rollup@4.59.0) + '@rollup/plugin-typescript': 12.3.0(rollup@4.59.0)(tslib@2.8.1)(typescript@5.9.3) + autoprefixer: 10.4.27(postcss@8.5.8) + concat-with-sourcemaps: 1.1.0 picocolors: 1.1.1 picomatch: 4.0.2 - postcss: 8.5.6 - rollup: 4.55.1 - rollup-plugin-postcss: 4.0.2(postcss@8.5.6)(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)) - rollup-plugin-typescript2: 0.36.0(rollup@4.55.1)(typescript@5.9.3) + postcss: 8.5.8 + postcss-modules: 6.0.1(postcss@8.5.8) + rollup: 4.59.0 + rollup-plugin-typescript2: 0.36.0(rollup@4.59.0)(typescript@5.9.3) tslib: 2.8.1 transitivePeerDependencies: - '@babel/core' @@ -13849,19 +14010,18 @@ snapshots: - debug - nx - supports-color - - ts-node - typescript - verdaccio - '@nx/storybook@22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(@zkochan/js-yaml@0.0.7)(eslint@9.39.2(jiti@2.6.1))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)))(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)': + '@nx/storybook@22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(@zkochan/js-yaml@0.0.7)(eslint@9.39.2(jiti@2.6.1))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)))(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)': dependencies: - '@nx/cypress': 22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(@zkochan/js-yaml@0.0.7)(eslint@9.39.2(jiti@2.6.1))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)))(typescript@5.9.3) - '@nx/devkit': 22.3.3(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@nx/eslint': 22.3.3(patch_hash=45d7a0a2e2d55c4ffd4beb467a0e02fac3f27bc1857270f522acafd5365d2c6b)(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(@zkochan/js-yaml@0.0.7)(eslint@9.39.2(jiti@2.6.1))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@nx/js': 22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@phenomnomnominal/tsquery': 5.0.1(typescript@5.9.3) + '@nx/cypress': 22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(@zkochan/js-yaml@0.0.7)(eslint@9.39.2(jiti@2.6.1))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)))(typescript@5.9.3) + '@nx/devkit': 22.5.4(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@nx/eslint': 22.5.4(patch_hash=45d7a0a2e2d55c4ffd4beb467a0e02fac3f27bc1857270f522acafd5365d2c6b)(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(@zkochan/js-yaml@0.0.7)(eslint@9.39.2(jiti@2.6.1))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@nx/js': 22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@phenomnomnominal/tsquery': 6.1.4(typescript@5.9.3) semver: 7.7.4 - storybook: 10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + storybook: 10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) tslib: 2.8.1 transitivePeerDependencies: - '@babel/traverse' @@ -13876,20 +14036,20 @@ snapshots: - typescript - verdaccio - '@nx/vite@22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)))(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.18(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@nx/vite@22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)))(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': dependencies: - '@nx/devkit': 22.3.3(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@nx/js': 22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@nx/vitest': 22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)))(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.18(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) - '@phenomnomnominal/tsquery': 5.0.1(typescript@5.9.3) - ajv: 8.17.1 + '@nx/devkit': 22.5.4(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@nx/js': 22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@nx/vitest': 22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)))(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + '@phenomnomnominal/tsquery': 6.1.4(typescript@5.9.3) + ajv: 8.18.0 enquirer: 2.3.6 picomatch: 4.0.2 semver: 7.7.4 tsconfig-paths: 4.2.0 tslib: 2.8.1 - vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - vitest: 4.0.18(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vitest: 4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - '@babel/traverse' - '@swc-node/register' @@ -13900,16 +14060,16 @@ snapshots: - typescript - verdaccio - '@nx/vitest@22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)))(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.18(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@nx/vitest@22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)))(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': dependencies: - '@nx/devkit': 22.3.3(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@nx/js': 22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@phenomnomnominal/tsquery': 5.0.1(typescript@5.9.3) + '@nx/devkit': 22.5.4(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@nx/js': 22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@phenomnomnominal/tsquery': 6.1.4(typescript@5.9.3) semver: 7.7.4 tslib: 2.8.1 optionalDependencies: - vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - vitest: 4.0.18(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vitest: 4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - '@babel/traverse' - '@swc-node/register' @@ -13920,10 +14080,10 @@ snapshots: - typescript - verdaccio - '@nx/web@22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)))': + '@nx/web@22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)))': dependencies: - '@nx/devkit': 22.3.3(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) - '@nx/js': 22.3.3(@babel/traverse@7.28.5)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) + '@nx/devkit': 22.5.4(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) + '@nx/js': 22.5.4(@babel/traverse@7.29.0)(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) detect-port: 1.6.1 http-server: 14.1.1 picocolors: 1.1.1 @@ -13937,13 +14097,13 @@ snapshots: - supports-color - verdaccio - '@nx/workspace@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))': + '@nx/workspace@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))': dependencies: - '@nx/devkit': 22.3.3(nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18))) + '@nx/devkit': 22.5.4(nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19))) '@zkochan/js-yaml': 0.0.7 chalk: 4.1.2 enquirer: 2.3.6 - nx: 22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)) + nx: 22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)) picomatch: 4.0.2 semver: 7.7.4 tslib: 2.8.1 @@ -13964,20 +14124,20 @@ snapshots: dependencies: '@octokit/auth-token': 6.0.0 '@octokit/graphql': 9.0.3 - '@octokit/request': 10.0.7 + '@octokit/request': 10.0.8 '@octokit/request-error': 7.1.0 '@octokit/types': 16.0.0 before-after-hook: 4.0.0 universal-user-agent: 7.0.3 - '@octokit/endpoint@11.0.2': + '@octokit/endpoint@11.0.3': dependencies: '@octokit/types': 16.0.0 universal-user-agent: 7.0.3 '@octokit/graphql@9.0.3': dependencies: - '@octokit/request': 10.0.7 + '@octokit/request': 10.0.8 '@octokit/types': 16.0.0 universal-user-agent: 7.0.3 @@ -14001,12 +14161,13 @@ snapshots: dependencies: '@octokit/types': 16.0.0 - '@octokit/request@10.0.7': + '@octokit/request@10.0.8': dependencies: - '@octokit/endpoint': 11.0.2 + '@octokit/endpoint': 11.0.3 '@octokit/request-error': 7.1.0 '@octokit/types': 16.0.0 fast-content-type-parse: 3.0.0 + json-with-bigint: 3.5.7 universal-user-agent: 7.0.3 '@octokit/rest@22.0.1': @@ -14020,1252 +14181,1320 @@ snapshots: dependencies: '@octokit/openapi-types': 27.0.0 - '@oxc-resolver/binding-android-arm-eabi@11.16.2': + '@oxc-resolver/binding-android-arm-eabi@11.19.1': optional: true - '@oxc-resolver/binding-android-arm64@11.16.2': + '@oxc-resolver/binding-android-arm64@11.19.1': optional: true - '@oxc-resolver/binding-darwin-arm64@11.16.2': + '@oxc-resolver/binding-darwin-arm64@11.19.1': optional: true - '@oxc-resolver/binding-darwin-x64@11.16.2': + '@oxc-resolver/binding-darwin-x64@11.19.1': optional: true - '@oxc-resolver/binding-freebsd-x64@11.16.2': + '@oxc-resolver/binding-freebsd-x64@11.19.1': optional: true - '@oxc-resolver/binding-linux-arm-gnueabihf@11.16.2': + '@oxc-resolver/binding-linux-arm-gnueabihf@11.19.1': optional: true - '@oxc-resolver/binding-linux-arm-musleabihf@11.16.2': + '@oxc-resolver/binding-linux-arm-musleabihf@11.19.1': optional: true - '@oxc-resolver/binding-linux-arm64-gnu@11.16.2': + '@oxc-resolver/binding-linux-arm64-gnu@11.19.1': optional: true - '@oxc-resolver/binding-linux-arm64-musl@11.16.2': + '@oxc-resolver/binding-linux-arm64-musl@11.19.1': optional: true - '@oxc-resolver/binding-linux-ppc64-gnu@11.16.2': + '@oxc-resolver/binding-linux-ppc64-gnu@11.19.1': optional: true - '@oxc-resolver/binding-linux-riscv64-gnu@11.16.2': + '@oxc-resolver/binding-linux-riscv64-gnu@11.19.1': optional: true - '@oxc-resolver/binding-linux-riscv64-musl@11.16.2': + '@oxc-resolver/binding-linux-riscv64-musl@11.19.1': optional: true - '@oxc-resolver/binding-linux-s390x-gnu@11.16.2': + '@oxc-resolver/binding-linux-s390x-gnu@11.19.1': optional: true - '@oxc-resolver/binding-linux-x64-gnu@11.16.2': + '@oxc-resolver/binding-linux-x64-gnu@11.19.1': optional: true - '@oxc-resolver/binding-linux-x64-musl@11.16.2': + '@oxc-resolver/binding-linux-x64-musl@11.19.1': optional: true - '@oxc-resolver/binding-openharmony-arm64@11.16.2': + '@oxc-resolver/binding-openharmony-arm64@11.19.1': optional: true - '@oxc-resolver/binding-wasm32-wasi@11.16.2': + '@oxc-resolver/binding-wasm32-wasi@11.19.1': dependencies: '@napi-rs/wasm-runtime': 1.1.1 optional: true - '@oxc-resolver/binding-win32-arm64-msvc@11.16.2': + '@oxc-resolver/binding-win32-arm64-msvc@11.19.1': optional: true - '@oxc-resolver/binding-win32-ia32-msvc@11.16.2': + '@oxc-resolver/binding-win32-ia32-msvc@11.19.1': optional: true - '@oxc-resolver/binding-win32-x64-msvc@11.16.2': + '@oxc-resolver/binding-win32-x64-msvc@11.19.1': optional: true - '@parcel/watcher-android-arm64@2.5.1': + '@parcel/watcher-android-arm64@2.5.6': optional: true - '@parcel/watcher-darwin-arm64@2.5.1': + '@parcel/watcher-darwin-arm64@2.5.6': optional: true - '@parcel/watcher-darwin-x64@2.5.1': + '@parcel/watcher-darwin-x64@2.5.6': optional: true - '@parcel/watcher-freebsd-x64@2.5.1': + '@parcel/watcher-freebsd-x64@2.5.6': optional: true - '@parcel/watcher-linux-arm-glibc@2.5.1': + '@parcel/watcher-linux-arm-glibc@2.5.6': optional: true - '@parcel/watcher-linux-arm-musl@2.5.1': + '@parcel/watcher-linux-arm-musl@2.5.6': optional: true - '@parcel/watcher-linux-arm64-glibc@2.5.1': + '@parcel/watcher-linux-arm64-glibc@2.5.6': optional: true - '@parcel/watcher-linux-arm64-musl@2.5.1': + '@parcel/watcher-linux-arm64-musl@2.5.6': optional: true - '@parcel/watcher-linux-x64-glibc@2.5.1': + '@parcel/watcher-linux-x64-glibc@2.5.6': optional: true - '@parcel/watcher-linux-x64-musl@2.5.1': + '@parcel/watcher-linux-x64-musl@2.5.6': optional: true - '@parcel/watcher-win32-arm64@2.5.1': + '@parcel/watcher-win32-arm64@2.5.6': optional: true - '@parcel/watcher-win32-ia32@2.5.1': + '@parcel/watcher-win32-ia32@2.5.6': optional: true - '@parcel/watcher-win32-x64@2.5.1': + '@parcel/watcher-win32-x64@2.5.6': optional: true - '@parcel/watcher@2.5.1': + '@parcel/watcher@2.5.6': dependencies: - detect-libc: 1.0.3 + detect-libc: 2.1.2 is-glob: 4.0.3 - micromatch: 4.0.8 node-addon-api: 7.1.1 + picomatch: 4.0.3 optionalDependencies: - '@parcel/watcher-android-arm64': 2.5.1 - '@parcel/watcher-darwin-arm64': 2.5.1 - '@parcel/watcher-darwin-x64': 2.5.1 - '@parcel/watcher-freebsd-x64': 2.5.1 - '@parcel/watcher-linux-arm-glibc': 2.5.1 - '@parcel/watcher-linux-arm-musl': 2.5.1 - '@parcel/watcher-linux-arm64-glibc': 2.5.1 - '@parcel/watcher-linux-arm64-musl': 2.5.1 - '@parcel/watcher-linux-x64-glibc': 2.5.1 - '@parcel/watcher-linux-x64-musl': 2.5.1 - '@parcel/watcher-win32-arm64': 2.5.1 - '@parcel/watcher-win32-ia32': 2.5.1 - '@parcel/watcher-win32-x64': 2.5.1 - - '@phenomnomnominal/tsquery@5.0.1(typescript@5.9.3)': - dependencies: + '@parcel/watcher-android-arm64': 2.5.6 + '@parcel/watcher-darwin-arm64': 2.5.6 + '@parcel/watcher-darwin-x64': 2.5.6 + '@parcel/watcher-freebsd-x64': 2.5.6 + '@parcel/watcher-linux-arm-glibc': 2.5.6 + '@parcel/watcher-linux-arm-musl': 2.5.6 + '@parcel/watcher-linux-arm64-glibc': 2.5.6 + '@parcel/watcher-linux-arm64-musl': 2.5.6 + '@parcel/watcher-linux-x64-glibc': 2.5.6 + '@parcel/watcher-linux-x64-musl': 2.5.6 + '@parcel/watcher-win32-arm64': 2.5.6 + '@parcel/watcher-win32-ia32': 2.5.6 + '@parcel/watcher-win32-x64': 2.5.6 + + '@phenomnomnominal/tsquery@6.1.4(typescript@5.9.3)': + dependencies: + '@types/esquery': 1.5.4 esquery: 1.7.0 typescript: 5.9.3 - '@pivanov/utils@0.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - '@pkgjs/parseargs@0.11.0': optional: true '@pkgr/core@0.2.9': {} - '@preact/signals-core@1.12.1': {} + '@preact/signals-core@1.13.0': {} - '@preact/signals@1.3.2(preact@10.28.2)': + '@preact/signals@1.3.4(preact@10.28.4)': dependencies: - '@preact/signals-core': 1.12.1 - preact: 10.28.2 + '@preact/signals-core': 1.13.0 + preact: 10.28.4 - '@prettier/plugin-xml@3.4.2(prettier@3.7.4)': + '@prettier/plugin-xml@3.4.2(prettier@3.8.1)': dependencies: '@xml-tools/parser': 1.0.11 - prettier: 3.7.4 - - '@prisma/client@5.22.0': {} - - '@react-aria/autocomplete@3.0.0-rc.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/combobox': 3.14.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/focus': 3.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/listbox': 3.15.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/searchfield': 3.8.10(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/textfield': 3.18.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/autocomplete': 3.0.0-beta.4(react@19.2.3) - '@react-stately/combobox': 3.12.1(react@19.2.3) - '@react-types/autocomplete': 3.0.0-alpha.36(react@19.2.3) - '@react-types/button': 3.14.1(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/breadcrumbs@3.5.30(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/link': 3.8.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-types/breadcrumbs': 3.7.17(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/button@3.14.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/toolbar': 3.0.0-beta.22(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/toggle': 3.9.3(react@19.2.3) - '@react-types/button': 3.14.1(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/calendar@3.9.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@internationalized/date': 3.10.1 - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + prettier: 3.8.1 + + '@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))': + optionalDependencies: + prisma: 7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + + '@prisma/config@7.4.2': + dependencies: + c12: 3.1.0 + deepmerge-ts: 7.1.5 + effect: 3.18.4 + empathic: 2.0.0 + transitivePeerDependencies: + - magicast + + '@prisma/debug@7.2.0': {} + + '@prisma/debug@7.4.2': {} + + '@prisma/dev@0.20.0(typescript@5.9.3)': + dependencies: + '@electric-sql/pglite': 0.3.15 + '@electric-sql/pglite-socket': 0.0.20(@electric-sql/pglite@0.3.15) + '@electric-sql/pglite-tools': 0.2.20(@electric-sql/pglite@0.3.15) + '@hono/node-server': 1.19.9(hono@4.11.4) + '@mrleebo/prisma-ast': 0.13.1 + '@prisma/get-platform': 7.2.0 + '@prisma/query-plan-executor': 7.2.0 + foreground-child: 3.3.1 + get-port-please: 3.2.0 + hono: 4.11.4 + http-status-codes: 2.3.0 + pathe: 2.0.3 + proper-lockfile: 4.1.2 + remeda: 2.33.4 + std-env: 3.10.0 + valibot: 1.2.0(typescript@5.9.3) + zeptomatch: 2.1.0 + transitivePeerDependencies: + - typescript + + '@prisma/engines-version@7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919': {} + + '@prisma/engines@7.4.2': + dependencies: + '@prisma/debug': 7.4.2 + '@prisma/engines-version': 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 + '@prisma/fetch-engine': 7.4.2 + '@prisma/get-platform': 7.4.2 + + '@prisma/fetch-engine@7.4.2': + dependencies: + '@prisma/debug': 7.4.2 + '@prisma/engines-version': 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 + '@prisma/get-platform': 7.4.2 + + '@prisma/get-platform@7.2.0': + dependencies: + '@prisma/debug': 7.2.0 + + '@prisma/get-platform@7.4.2': + dependencies: + '@prisma/debug': 7.4.2 + + '@prisma/query-plan-executor@7.2.0': {} + + '@prisma/studio-core@0.13.1(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@types/react': 19.2.14 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/autocomplete@3.0.0-rc.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/combobox': 3.15.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/focus': 3.21.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/listbox': 3.15.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/searchfield': 3.8.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/textfield': 3.18.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/autocomplete': 3.0.0-beta.4(react@19.2.4) + '@react-stately/combobox': 3.13.0(react@19.2.4) + '@react-types/autocomplete': 3.0.0-alpha.38(react@19.2.4) + '@react-types/button': 3.15.1(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/breadcrumbs@3.5.32(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/link': 3.8.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-types/breadcrumbs': 3.7.19(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/button@3.14.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/toolbar': 3.0.0-beta.24(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/toggle': 3.9.5(react@19.2.4) + '@react-types/button': 3.15.1(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/calendar@3.9.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@internationalized/date': 3.12.0 + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/live-announcer': 3.4.4 - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/calendar': 3.9.1(react@19.2.3) - '@react-types/button': 3.14.1(react@19.2.3) - '@react-types/calendar': 3.8.1(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/checkbox@3.16.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/form': 3.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/label': 3.7.23(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/toggle': 3.12.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/checkbox': 3.7.3(react@19.2.3) - '@react-stately/form': 3.2.2(react@19.2.3) - '@react-stately/toggle': 3.9.3(react@19.2.3) - '@react-types/checkbox': 3.10.2(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/collections@3.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/ssr': 3.9.10(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - use-sync-external-store: 1.6.0(react@19.2.3) - - '@react-aria/color@3.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/numberfield': 3.12.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/slider': 3.8.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/spinbutton': 3.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/textfield': 3.18.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/visually-hidden': 3.8.29(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/color': 3.9.3(react@19.2.3) - '@react-stately/form': 3.2.2(react@19.2.3) - '@react-types/color': 3.1.2(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/combobox@3.14.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/focus': 3.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/listbox': 3.15.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/calendar': 3.9.3(react@19.2.4) + '@react-types/button': 3.15.1(react@19.2.4) + '@react-types/calendar': 3.8.3(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/checkbox@3.16.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/form': 3.1.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/label': 3.7.25(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/toggle': 3.12.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/checkbox': 3.7.5(react@19.2.4) + '@react-stately/form': 3.2.4(react@19.2.4) + '@react-stately/toggle': 3.9.5(react@19.2.4) + '@react-types/checkbox': 3.10.4(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/collections@3.0.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/ssr': 3.9.10(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + use-sync-external-store: 1.6.0(react@19.2.4) + + '@react-aria/color@3.1.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/numberfield': 3.12.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/slider': 3.8.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/spinbutton': 3.7.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/textfield': 3.18.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/visually-hidden': 3.8.31(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/color': 3.9.5(react@19.2.4) + '@react-stately/form': 3.2.4(react@19.2.4) + '@react-types/color': 3.1.4(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/combobox@3.15.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/focus': 3.21.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/listbox': 3.15.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/live-announcer': 3.4.4 - '@react-aria/menu': 3.19.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/overlays': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/selection': 3.27.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/textfield': 3.18.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/collections': 3.12.8(react@19.2.3) - '@react-stately/combobox': 3.12.1(react@19.2.3) - '@react-stately/form': 3.2.2(react@19.2.3) - '@react-types/button': 3.14.1(react@19.2.3) - '@react-types/combobox': 3.13.10(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/datepicker@3.15.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@internationalized/date': 3.10.1 + '@react-aria/menu': 3.21.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/overlays': 3.31.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/selection': 3.27.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/textfield': 3.18.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/collections': 3.12.10(react@19.2.4) + '@react-stately/combobox': 3.13.0(react@19.2.4) + '@react-stately/form': 3.2.4(react@19.2.4) + '@react-types/button': 3.15.1(react@19.2.4) + '@react-types/combobox': 3.14.0(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/datepicker@3.16.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@internationalized/date': 3.12.0 '@internationalized/number': 3.6.5 '@internationalized/string': 3.2.7 - '@react-aria/focus': 3.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/form': 3.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/label': 3.7.23(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/spinbutton': 3.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/datepicker': 3.15.3(react@19.2.3) - '@react-stately/form': 3.2.2(react@19.2.3) - '@react-types/button': 3.14.1(react@19.2.3) - '@react-types/calendar': 3.8.1(react@19.2.3) - '@react-types/datepicker': 3.13.3(react@19.2.3) - '@react-types/dialog': 3.5.22(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/dialog@3.5.32(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/overlays': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-types/dialog': 3.5.22(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/disclosure@3.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/ssr': 3.9.10(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/disclosure': 3.0.9(react@19.2.3) - '@react-types/button': 3.14.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/dnd@3.11.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@react-aria/focus': 3.21.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/form': 3.1.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/label': 3.7.25(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/spinbutton': 3.7.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/datepicker': 3.16.1(react@19.2.4) + '@react-stately/form': 3.2.4(react@19.2.4) + '@react-types/button': 3.15.1(react@19.2.4) + '@react-types/calendar': 3.8.3(react@19.2.4) + '@react-types/datepicker': 3.13.5(react@19.2.4) + '@react-types/dialog': 3.5.24(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/dialog@3.5.34(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/overlays': 3.31.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-types/dialog': 3.5.24(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/disclosure@3.1.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/ssr': 3.9.10(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/disclosure': 3.0.11(react@19.2.4) + '@react-types/button': 3.15.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/dnd@3.11.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@internationalized/string': 3.2.7 - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/live-announcer': 3.4.4 - '@react-aria/overlays': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/collections': 3.12.8(react@19.2.3) - '@react-stately/dnd': 3.7.2(react@19.2.3) - '@react-types/button': 3.14.1(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/focus@3.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 + '@react-aria/overlays': 3.31.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/collections': 3.12.10(react@19.2.4) + '@react-stately/dnd': 3.7.4(react@19.2.4) + '@react-types/button': 3.15.1(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/focus@3.21.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 clsx: 2.1.1 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) - '@react-aria/form@3.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@react-aria/form@3.1.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/form': 3.2.2(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/form': 3.2.4(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) - '@react-aria/grid@3.14.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@react-aria/grid@3.14.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@react-aria/focus': 3.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/focus': 3.21.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/live-announcer': 3.4.4 - '@react-aria/selection': 3.27.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/collections': 3.12.8(react@19.2.3) - '@react-stately/grid': 3.11.7(react@19.2.3) - '@react-stately/selection': 3.20.7(react@19.2.3) - '@react-types/checkbox': 3.10.2(react@19.2.3) - '@react-types/grid': 3.3.6(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/gridlist@3.14.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/focus': 3.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/grid': 3.14.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/selection': 3.27.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/list': 3.13.2(react@19.2.3) - '@react-stately/tree': 3.9.4(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/i18n@3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@internationalized/date': 3.10.1 + '@react-aria/selection': 3.27.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/collections': 3.12.10(react@19.2.4) + '@react-stately/grid': 3.11.9(react@19.2.4) + '@react-stately/selection': 3.20.9(react@19.2.4) + '@react-types/checkbox': 3.10.4(react@19.2.4) + '@react-types/grid': 3.3.8(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/gridlist@3.14.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/focus': 3.21.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/grid': 3.14.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/selection': 3.27.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/list': 3.13.4(react@19.2.4) + '@react-stately/tree': 3.9.6(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/i18n@3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@internationalized/date': 3.12.0 '@internationalized/message': 3.1.8 '@internationalized/number': 3.6.5 '@internationalized/string': 3.2.7 - '@react-aria/ssr': 3.9.10(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + '@react-aria/ssr': 3.9.10(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) - '@react-aria/interactions@3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@react-aria/interactions@3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@react-aria/ssr': 3.9.10(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/ssr': 3.9.10(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-stately/flags': 3.1.2 - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/label@3.7.23(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/landmark@3.0.8(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - use-sync-external-store: 1.6.0(react@19.2.3) - - '@react-aria/link@3.8.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-types/link': 3.6.5(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/listbox@3.15.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/label': 3.7.23(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/selection': 3.27.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/collections': 3.12.8(react@19.2.3) - '@react-stately/list': 3.13.2(react@19.2.3) - '@react-types/listbox': 3.7.4(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/label@3.7.25(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/landmark@3.0.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + use-sync-external-store: 1.6.0(react@19.2.4) + + '@react-aria/link@3.8.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-types/link': 3.6.7(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/listbox@3.15.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/label': 3.7.25(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/selection': 3.27.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/collections': 3.12.10(react@19.2.4) + '@react-stately/list': 3.13.4(react@19.2.4) + '@react-types/listbox': 3.7.6(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) '@react-aria/live-announcer@3.4.4': dependencies: - '@swc/helpers': 0.5.18 - - '@react-aria/menu@3.19.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/focus': 3.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/overlays': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/selection': 3.27.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/collections': 3.12.8(react@19.2.3) - '@react-stately/menu': 3.9.9(react@19.2.3) - '@react-stately/selection': 3.20.7(react@19.2.3) - '@react-stately/tree': 3.9.4(react@19.2.3) - '@react-types/button': 3.14.1(react@19.2.3) - '@react-types/menu': 3.10.5(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/meter@3.4.28(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/progress': 3.4.28(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-types/meter': 3.4.13(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/numberfield@3.12.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/spinbutton': 3.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/textfield': 3.18.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/form': 3.2.2(react@19.2.3) - '@react-stately/numberfield': 3.10.3(react@19.2.3) - '@react-types/button': 3.14.1(react@19.2.3) - '@react-types/numberfield': 3.8.16(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/overlays@3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/focus': 3.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/ssr': 3.9.10(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/visually-hidden': 3.8.29(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/overlays': 3.6.21(react@19.2.3) - '@react-types/button': 3.14.1(react@19.2.3) - '@react-types/overlays': 3.9.2(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/progress@3.4.28(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/label': 3.7.23(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-types/progress': 3.5.16(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/radio@3.12.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/focus': 3.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/form': 3.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/label': 3.7.23(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/radio': 3.11.3(react@19.2.3) - '@react-types/radio': 3.9.2(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/searchfield@3.8.10(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/textfield': 3.18.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/searchfield': 3.5.17(react@19.2.3) - '@react-types/button': 3.14.1(react@19.2.3) - '@react-types/searchfield': 3.6.6(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/select@3.17.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/form': 3.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/label': 3.7.23(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/listbox': 3.15.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/menu': 3.19.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/selection': 3.27.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/visually-hidden': 3.8.29(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/select': 3.9.0(react@19.2.3) - '@react-types/button': 3.14.1(react@19.2.3) - '@react-types/select': 3.12.0(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/selection@3.27.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/focus': 3.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/selection': 3.20.7(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/separator@3.4.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/slider@3.8.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/label': 3.7.23(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/slider': 3.7.3(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@react-types/slider': 3.8.2(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/spinbutton@3.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@swc/helpers': 0.5.19 + + '@react-aria/menu@3.21.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/focus': 3.21.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/overlays': 3.31.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/selection': 3.27.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/collections': 3.12.10(react@19.2.4) + '@react-stately/menu': 3.9.11(react@19.2.4) + '@react-stately/selection': 3.20.9(react@19.2.4) + '@react-stately/tree': 3.9.6(react@19.2.4) + '@react-types/button': 3.15.1(react@19.2.4) + '@react-types/menu': 3.10.7(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/meter@3.4.30(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/progress': 3.4.30(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-types/meter': 3.4.15(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/numberfield@3.12.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/live-announcer': 3.4.4 + '@react-aria/spinbutton': 3.7.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/textfield': 3.18.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/form': 3.2.4(react@19.2.4) + '@react-stately/numberfield': 3.11.0(react@19.2.4) + '@react-types/button': 3.15.1(react@19.2.4) + '@react-types/numberfield': 3.8.18(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/overlays@3.31.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/focus': 3.21.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/ssr': 3.9.10(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/visually-hidden': 3.8.31(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/flags': 3.1.2 + '@react-stately/overlays': 3.6.23(react@19.2.4) + '@react-types/button': 3.15.1(react@19.2.4) + '@react-types/overlays': 3.9.4(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/progress@3.4.30(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/label': 3.7.25(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-types/progress': 3.5.18(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/radio@3.12.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/focus': 3.21.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/form': 3.1.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/label': 3.7.25(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/radio': 3.11.5(react@19.2.4) + '@react-types/radio': 3.9.4(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/searchfield@3.8.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/textfield': 3.18.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/searchfield': 3.5.19(react@19.2.4) + '@react-types/button': 3.15.1(react@19.2.4) + '@react-types/searchfield': 3.6.8(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/select@3.17.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/form': 3.1.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/label': 3.7.25(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/listbox': 3.15.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/menu': 3.21.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/selection': 3.27.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/visually-hidden': 3.8.31(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/select': 3.9.2(react@19.2.4) + '@react-types/button': 3.15.1(react@19.2.4) + '@react-types/select': 3.12.2(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/selection@3.27.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/focus': 3.21.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/selection': 3.20.9(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/separator@3.4.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/slider@3.8.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/label': 3.7.25(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/slider': 3.7.5(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@react-types/slider': 3.8.4(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/spinbutton@3.7.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/live-announcer': 3.4.4 - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-types/button': 3.14.1(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/ssr@3.9.10(react@19.2.3)': - dependencies: - '@swc/helpers': 0.5.18 - react: 19.2.3 - - '@react-aria/switch@3.7.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/toggle': 3.12.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/toggle': 3.9.3(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@react-types/switch': 3.5.15(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/table@3.17.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/focus': 3.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/grid': 3.14.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-types/button': 3.15.1(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/ssr@3.9.10(react@19.2.4)': + dependencies: + '@swc/helpers': 0.5.19 + react: 19.2.4 + + '@react-aria/switch@3.7.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/toggle': 3.12.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/toggle': 3.9.5(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@react-types/switch': 3.5.17(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/table@3.17.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/focus': 3.21.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/grid': 3.14.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/live-announcer': 3.4.4 - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/visually-hidden': 3.8.29(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/collections': 3.12.8(react@19.2.3) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/visually-hidden': 3.8.31(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/collections': 3.12.10(react@19.2.4) '@react-stately/flags': 3.1.2 - '@react-stately/table': 3.15.2(patch_hash=5ac384399a7b8e18c4e19f25e434b2f2f27fbd45e7a91cdeb30408330b7243b4)(react@19.2.3) - '@react-types/checkbox': 3.10.2(react@19.2.3) - '@react-types/grid': 3.3.6(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@react-types/table': 3.13.4(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/tabs@3.10.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/focus': 3.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/selection': 3.27.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/tabs': 3.8.7(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@react-types/tabs': 3.3.20(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/tag@3.7.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/gridlist': 3.14.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/label': 3.7.23(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/selection': 3.27.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/list': 3.13.2(react@19.2.3) - '@react-types/button': 3.14.1(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/textfield@3.18.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/form': 3.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/label': 3.7.23(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/form': 3.2.2(react@19.2.3) - '@react-stately/utils': 3.11.0(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@react-types/textfield': 3.12.6(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/toast@3.0.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/landmark': 3.0.8(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/toast': 3.1.2(react@19.2.3) - '@react-types/button': 3.14.1(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/toggle@3.12.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/toggle': 3.9.3(react@19.2.3) - '@react-types/checkbox': 3.10.2(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/toolbar@3.0.0-beta.22(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/focus': 3.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/tooltip@3.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/tooltip': 3.5.9(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@react-types/tooltip': 3.5.0(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/tree@3.1.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/gridlist': 3.14.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/selection': 3.27.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/tree': 3.9.4(react@19.2.3) - '@react-types/button': 3.14.1(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@react-aria/utils@3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@react-aria/ssr': 3.9.10(react@19.2.3) + '@react-stately/table': 3.15.4(patch_hash=5ac384399a7b8e18c4e19f25e434b2f2f27fbd45e7a91cdeb30408330b7243b4)(react@19.2.4) + '@react-types/checkbox': 3.10.4(react@19.2.4) + '@react-types/grid': 3.3.8(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@react-types/table': 3.13.6(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/tabs@3.11.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/focus': 3.21.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/selection': 3.27.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/tabs': 3.8.9(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@react-types/tabs': 3.3.22(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/tag@3.8.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/gridlist': 3.14.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/label': 3.7.25(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/selection': 3.27.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/list': 3.13.4(react@19.2.4) + '@react-types/button': 3.15.1(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/textfield@3.18.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/form': 3.1.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/label': 3.7.25(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/form': 3.2.4(react@19.2.4) + '@react-stately/utils': 3.11.0(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@react-types/textfield': 3.12.8(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/toast@3.0.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/landmark': 3.0.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/toast': 3.1.3(react@19.2.4) + '@react-types/button': 3.15.1(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/toggle@3.12.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/toggle': 3.9.5(react@19.2.4) + '@react-types/checkbox': 3.10.4(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/toolbar@3.0.0-beta.24(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/focus': 3.21.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/tooltip@3.9.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/tooltip': 3.5.11(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@react-types/tooltip': 3.5.2(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/tree@3.1.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/gridlist': 3.14.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/selection': 3.27.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/tree': 3.9.6(react@19.2.4) + '@react-types/button': 3.15.1(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@react-aria/utils@3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-aria/ssr': 3.9.10(react@19.2.4) '@react-stately/flags': 3.1.2 - '@react-stately/utils': 3.11.0(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 + '@react-stately/utils': 3.11.0(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 clsx: 2.1.1 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) - '@react-aria/virtualizer@4.1.11(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@react-aria/virtualizer@4.1.13(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/virtualizer': 4.4.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/virtualizer': 4.4.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) - '@react-aria/visually-hidden@3.8.29(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@react-aria/visually-hidden@3.8.31(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) - '@react-stately/autocomplete@3.0.0-beta.4(react@19.2.3)': + '@react-stately/autocomplete@3.0.0-beta.4(react@19.2.4)': dependencies: - '@react-stately/utils': 3.11.0(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@react-stately/utils': 3.11.0(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 - '@react-stately/calendar@3.9.1(react@19.2.3)': + '@react-stately/calendar@3.9.3(react@19.2.4)': dependencies: - '@internationalized/date': 3.10.1 - '@react-stately/utils': 3.11.0(react@19.2.3) - '@react-types/calendar': 3.8.1(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@internationalized/date': 3.12.0 + '@react-stately/utils': 3.11.0(react@19.2.4) + '@react-types/calendar': 3.8.3(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 - '@react-stately/checkbox@3.7.3(react@19.2.3)': + '@react-stately/checkbox@3.7.5(react@19.2.4)': dependencies: - '@react-stately/form': 3.2.2(react@19.2.3) - '@react-stately/utils': 3.11.0(react@19.2.3) - '@react-types/checkbox': 3.10.2(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@react-stately/form': 3.2.4(react@19.2.4) + '@react-stately/utils': 3.11.0(react@19.2.4) + '@react-types/checkbox': 3.10.4(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 - '@react-stately/collections@3.12.8(react@19.2.3)': + '@react-stately/collections@3.12.10(react@19.2.4)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 - '@react-stately/color@3.9.3(react@19.2.3)': + '@react-stately/color@3.9.5(react@19.2.4)': dependencies: '@internationalized/number': 3.6.5 '@internationalized/string': 3.2.7 - '@react-stately/form': 3.2.2(react@19.2.3) - '@react-stately/numberfield': 3.10.3(react@19.2.3) - '@react-stately/slider': 3.7.3(react@19.2.3) - '@react-stately/utils': 3.11.0(react@19.2.3) - '@react-types/color': 3.1.2(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - - '@react-stately/combobox@3.12.1(react@19.2.3)': - dependencies: - '@react-stately/collections': 3.12.8(react@19.2.3) - '@react-stately/form': 3.2.2(react@19.2.3) - '@react-stately/list': 3.13.2(react@19.2.3) - '@react-stately/overlays': 3.6.21(react@19.2.3) - '@react-stately/utils': 3.11.0(react@19.2.3) - '@react-types/combobox': 3.13.10(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - - '@react-stately/data@3.15.0(react@19.2.3)': - dependencies: - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - - '@react-stately/datepicker@3.15.3(react@19.2.3)': - dependencies: - '@internationalized/date': 3.10.1 + '@react-stately/form': 3.2.4(react@19.2.4) + '@react-stately/numberfield': 3.11.0(react@19.2.4) + '@react-stately/slider': 3.7.5(react@19.2.4) + '@react-stately/utils': 3.11.0(react@19.2.4) + '@react-types/color': 3.1.4(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + + '@react-stately/combobox@3.13.0(react@19.2.4)': + dependencies: + '@react-stately/collections': 3.12.10(react@19.2.4) + '@react-stately/form': 3.2.4(react@19.2.4) + '@react-stately/list': 3.13.4(react@19.2.4) + '@react-stately/overlays': 3.6.23(react@19.2.4) + '@react-stately/utils': 3.11.0(react@19.2.4) + '@react-types/combobox': 3.14.0(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + + '@react-stately/data@3.15.2(react@19.2.4)': + dependencies: + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + + '@react-stately/datepicker@3.16.1(react@19.2.4)': + dependencies: + '@internationalized/date': 3.12.0 + '@internationalized/number': 3.6.5 '@internationalized/string': 3.2.7 - '@react-stately/form': 3.2.2(react@19.2.3) - '@react-stately/overlays': 3.6.21(react@19.2.3) - '@react-stately/utils': 3.11.0(react@19.2.3) - '@react-types/datepicker': 3.13.3(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@react-stately/form': 3.2.4(react@19.2.4) + '@react-stately/overlays': 3.6.23(react@19.2.4) + '@react-stately/utils': 3.11.0(react@19.2.4) + '@react-types/datepicker': 3.13.5(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 - '@react-stately/disclosure@3.0.9(react@19.2.3)': + '@react-stately/disclosure@3.0.11(react@19.2.4)': dependencies: - '@react-stately/utils': 3.11.0(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@react-stately/utils': 3.11.0(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 - '@react-stately/dnd@3.7.2(react@19.2.3)': + '@react-stately/dnd@3.7.4(react@19.2.4)': dependencies: - '@react-stately/selection': 3.20.7(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@react-stately/selection': 3.20.9(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 '@react-stately/flags@3.1.2': dependencies: - '@swc/helpers': 0.5.18 + '@swc/helpers': 0.5.19 - '@react-stately/form@3.2.2(react@19.2.3)': + '@react-stately/form@3.2.4(react@19.2.4)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 - '@react-stately/grid@3.11.7(react@19.2.3)': + '@react-stately/grid@3.11.9(react@19.2.4)': dependencies: - '@react-stately/collections': 3.12.8(react@19.2.3) - '@react-stately/selection': 3.20.7(react@19.2.3) - '@react-types/grid': 3.3.6(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@react-stately/collections': 3.12.10(react@19.2.4) + '@react-stately/selection': 3.20.9(react@19.2.4) + '@react-types/grid': 3.3.8(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 - '@react-stately/layout@4.5.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@react-stately/layout@4.6.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@react-stately/collections': 3.12.8(react@19.2.3) - '@react-stately/table': 3.15.2(patch_hash=5ac384399a7b8e18c4e19f25e434b2f2f27fbd45e7a91cdeb30408330b7243b4)(react@19.2.3) - '@react-stately/virtualizer': 4.4.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-types/grid': 3.3.6(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@react-types/table': 3.13.4(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + '@react-stately/collections': 3.12.10(react@19.2.4) + '@react-stately/table': 3.15.4(patch_hash=5ac384399a7b8e18c4e19f25e434b2f2f27fbd45e7a91cdeb30408330b7243b4)(react@19.2.4) + '@react-stately/virtualizer': 4.4.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-types/grid': 3.3.8(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@react-types/table': 3.13.6(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) - '@react-stately/list@3.13.2(react@19.2.3)': + '@react-stately/list@3.13.4(react@19.2.4)': dependencies: - '@react-stately/collections': 3.12.8(react@19.2.3) - '@react-stately/selection': 3.20.7(react@19.2.3) - '@react-stately/utils': 3.11.0(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@react-stately/collections': 3.12.10(react@19.2.4) + '@react-stately/selection': 3.20.9(react@19.2.4) + '@react-stately/utils': 3.11.0(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 - '@react-stately/menu@3.9.9(react@19.2.3)': + '@react-stately/menu@3.9.11(react@19.2.4)': dependencies: - '@react-stately/overlays': 3.6.21(react@19.2.3) - '@react-types/menu': 3.10.5(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@react-stately/overlays': 3.6.23(react@19.2.4) + '@react-types/menu': 3.10.7(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 - '@react-stately/numberfield@3.10.3(react@19.2.3)': + '@react-stately/numberfield@3.11.0(react@19.2.4)': dependencies: '@internationalized/number': 3.6.5 - '@react-stately/form': 3.2.2(react@19.2.3) - '@react-stately/utils': 3.11.0(react@19.2.3) - '@react-types/numberfield': 3.8.16(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@react-stately/form': 3.2.4(react@19.2.4) + '@react-stately/utils': 3.11.0(react@19.2.4) + '@react-types/numberfield': 3.8.18(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 - '@react-stately/overlays@3.6.21(react@19.2.3)': + '@react-stately/overlays@3.6.23(react@19.2.4)': dependencies: - '@react-stately/utils': 3.11.0(react@19.2.3) - '@react-types/overlays': 3.9.2(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@react-stately/utils': 3.11.0(react@19.2.4) + '@react-types/overlays': 3.9.4(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 - '@react-stately/radio@3.11.3(react@19.2.3)': + '@react-stately/radio@3.11.5(react@19.2.4)': dependencies: - '@react-stately/form': 3.2.2(react@19.2.3) - '@react-stately/utils': 3.11.0(react@19.2.3) - '@react-types/radio': 3.9.2(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@react-stately/form': 3.2.4(react@19.2.4) + '@react-stately/utils': 3.11.0(react@19.2.4) + '@react-types/radio': 3.9.4(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 - '@react-stately/searchfield@3.5.17(react@19.2.3)': + '@react-stately/searchfield@3.5.19(react@19.2.4)': dependencies: - '@react-stately/utils': 3.11.0(react@19.2.3) - '@react-types/searchfield': 3.6.6(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@react-stately/utils': 3.11.0(react@19.2.4) + '@react-types/searchfield': 3.6.8(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 - '@react-stately/select@3.9.0(react@19.2.3)': + '@react-stately/select@3.9.2(react@19.2.4)': dependencies: - '@react-stately/form': 3.2.2(react@19.2.3) - '@react-stately/list': 3.13.2(react@19.2.3) - '@react-stately/overlays': 3.6.21(react@19.2.3) - '@react-stately/utils': 3.11.0(react@19.2.3) - '@react-types/select': 3.12.0(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@react-stately/form': 3.2.4(react@19.2.4) + '@react-stately/list': 3.13.4(react@19.2.4) + '@react-stately/overlays': 3.6.23(react@19.2.4) + '@react-stately/utils': 3.11.0(react@19.2.4) + '@react-types/select': 3.12.2(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 - '@react-stately/selection@3.20.7(react@19.2.3)': + '@react-stately/selection@3.20.9(react@19.2.4)': dependencies: - '@react-stately/collections': 3.12.8(react@19.2.3) - '@react-stately/utils': 3.11.0(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@react-stately/collections': 3.12.10(react@19.2.4) + '@react-stately/utils': 3.11.0(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 - '@react-stately/slider@3.7.3(react@19.2.3)': + '@react-stately/slider@3.7.5(react@19.2.4)': dependencies: - '@react-stately/utils': 3.11.0(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@react-types/slider': 3.8.2(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@react-stately/utils': 3.11.0(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@react-types/slider': 3.8.4(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 - '@react-stately/table@3.15.2(patch_hash=5ac384399a7b8e18c4e19f25e434b2f2f27fbd45e7a91cdeb30408330b7243b4)(react@19.2.3)': + '@react-stately/table@3.15.4(patch_hash=5ac384399a7b8e18c4e19f25e434b2f2f27fbd45e7a91cdeb30408330b7243b4)(react@19.2.4)': dependencies: - '@react-stately/collections': 3.12.8(react@19.2.3) + '@react-stately/collections': 3.12.10(react@19.2.4) '@react-stately/flags': 3.1.2 - '@react-stately/grid': 3.11.7(react@19.2.3) - '@react-stately/selection': 3.20.7(react@19.2.3) - '@react-stately/utils': 3.11.0(react@19.2.3) - '@react-types/grid': 3.3.6(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@react-types/table': 3.13.4(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@react-stately/grid': 3.11.9(react@19.2.4) + '@react-stately/selection': 3.20.9(react@19.2.4) + '@react-stately/utils': 3.11.0(react@19.2.4) + '@react-types/grid': 3.3.8(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@react-types/table': 3.13.6(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 - '@react-stately/tabs@3.8.7(react@19.2.3)': + '@react-stately/tabs@3.8.9(react@19.2.4)': dependencies: - '@react-stately/list': 3.13.2(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@react-types/tabs': 3.3.20(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@react-stately/list': 3.13.4(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@react-types/tabs': 3.3.22(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 - '@react-stately/toast@3.1.2(react@19.2.3)': + '@react-stately/toast@3.1.3(react@19.2.4)': dependencies: - '@swc/helpers': 0.5.18 - react: 19.2.3 - use-sync-external-store: 1.6.0(react@19.2.3) + '@swc/helpers': 0.5.19 + react: 19.2.4 + use-sync-external-store: 1.6.0(react@19.2.4) - '@react-stately/toggle@3.9.3(react@19.2.3)': + '@react-stately/toggle@3.9.5(react@19.2.4)': dependencies: - '@react-stately/utils': 3.11.0(react@19.2.3) - '@react-types/checkbox': 3.10.2(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@react-stately/utils': 3.11.0(react@19.2.4) + '@react-types/checkbox': 3.10.4(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 - '@react-stately/tooltip@3.5.9(react@19.2.3)': + '@react-stately/tooltip@3.5.11(react@19.2.4)': dependencies: - '@react-stately/overlays': 3.6.21(react@19.2.3) - '@react-types/tooltip': 3.5.0(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@react-stately/overlays': 3.6.23(react@19.2.4) + '@react-types/tooltip': 3.5.2(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 - '@react-stately/tree@3.9.4(react@19.2.3)': + '@react-stately/tree@3.9.6(react@19.2.4)': dependencies: - '@react-stately/collections': 3.12.8(react@19.2.3) - '@react-stately/selection': 3.20.7(react@19.2.3) - '@react-stately/utils': 3.11.0(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@react-stately/collections': 3.12.10(react@19.2.4) + '@react-stately/selection': 3.20.9(react@19.2.4) + '@react-stately/utils': 3.11.0(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 - '@react-stately/utils@3.11.0(react@19.2.3)': + '@react-stately/utils@3.11.0(react@19.2.4)': dependencies: - '@swc/helpers': 0.5.18 - react: 19.2.3 + '@swc/helpers': 0.5.19 + react: 19.2.4 - '@react-stately/virtualizer@4.4.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@react-stately/virtualizer@4.4.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.3) - '@swc/helpers': 0.5.18 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + '@react-types/shared': 3.33.1(react@19.2.4) + '@swc/helpers': 0.5.19 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) - '@react-types/autocomplete@3.0.0-alpha.36(react@19.2.3)': + '@react-types/autocomplete@3.0.0-alpha.38(react@19.2.4)': dependencies: - '@react-types/combobox': 3.13.10(react@19.2.3) - '@react-types/searchfield': 3.6.6(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@react-types/combobox': 3.14.0(react@19.2.4) + '@react-types/searchfield': 3.6.8(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@react-types/breadcrumbs@3.7.17(react@19.2.3)': + '@react-types/breadcrumbs@3.7.19(react@19.2.4)': dependencies: - '@react-types/link': 3.6.5(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@react-types/link': 3.6.7(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@react-types/button@3.14.1(react@19.2.3)': + '@react-types/button@3.15.1(react@19.2.4)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@react-types/calendar@3.8.1(react@19.2.3)': + '@react-types/calendar@3.8.3(react@19.2.4)': dependencies: - '@internationalized/date': 3.10.1 - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@internationalized/date': 3.12.0 + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@react-types/checkbox@3.10.2(react@19.2.3)': + '@react-types/checkbox@3.10.4(react@19.2.4)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@react-types/color@3.1.2(react@19.2.3)': + '@react-types/color@3.1.4(react@19.2.4)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.3) - '@react-types/slider': 3.8.2(react@19.2.3) - react: 19.2.3 + '@react-types/shared': 3.33.1(react@19.2.4) + '@react-types/slider': 3.8.4(react@19.2.4) + react: 19.2.4 - '@react-types/combobox@3.13.10(react@19.2.3)': + '@react-types/combobox@3.14.0(react@19.2.4)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@react-types/datepicker@3.13.3(react@19.2.3)': + '@react-types/datepicker@3.13.5(react@19.2.4)': dependencies: - '@internationalized/date': 3.10.1 - '@react-types/calendar': 3.8.1(react@19.2.3) - '@react-types/overlays': 3.9.2(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@internationalized/date': 3.12.0 + '@react-types/calendar': 3.8.3(react@19.2.4) + '@react-types/overlays': 3.9.4(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@react-types/dialog@3.5.22(react@19.2.3)': + '@react-types/dialog@3.5.24(react@19.2.4)': dependencies: - '@react-types/overlays': 3.9.2(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@react-types/overlays': 3.9.4(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@react-types/form@3.7.16(react@19.2.3)': + '@react-types/form@3.7.18(react@19.2.4)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@react-types/grid@3.3.6(react@19.2.3)': + '@react-types/grid@3.3.8(react@19.2.4)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@react-types/link@3.6.5(react@19.2.3)': + '@react-types/link@3.6.7(react@19.2.4)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@react-types/listbox@3.7.4(react@19.2.3)': + '@react-types/listbox@3.7.6(react@19.2.4)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@react-types/menu@3.10.5(react@19.2.3)': + '@react-types/menu@3.10.7(react@19.2.4)': dependencies: - '@react-types/overlays': 3.9.2(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@react-types/overlays': 3.9.4(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@react-types/meter@3.4.13(react@19.2.3)': + '@react-types/meter@3.4.15(react@19.2.4)': dependencies: - '@react-types/progress': 3.5.16(react@19.2.3) - react: 19.2.3 + '@react-types/progress': 3.5.18(react@19.2.4) + react: 19.2.4 - '@react-types/numberfield@3.8.16(react@19.2.3)': + '@react-types/numberfield@3.8.18(react@19.2.4)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@react-types/overlays@3.9.2(react@19.2.3)': + '@react-types/overlays@3.9.4(react@19.2.4)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@react-types/progress@3.5.16(react@19.2.3)': + '@react-types/progress@3.5.18(react@19.2.4)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@react-types/radio@3.9.2(react@19.2.3)': + '@react-types/radio@3.9.4(react@19.2.4)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@react-types/searchfield@3.6.6(react@19.2.3)': + '@react-types/searchfield@3.6.8(react@19.2.4)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.3) - '@react-types/textfield': 3.12.6(react@19.2.3) - react: 19.2.3 + '@react-types/shared': 3.33.1(react@19.2.4) + '@react-types/textfield': 3.12.8(react@19.2.4) + react: 19.2.4 - '@react-types/select@3.12.0(react@19.2.3)': + '@react-types/select@3.12.2(react@19.2.4)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@react-types/shared@3.32.1(react@19.2.3)': + '@react-types/shared@3.33.1(react@19.2.4)': dependencies: - react: 19.2.3 + react: 19.2.4 - '@react-types/slider@3.8.2(react@19.2.3)': + '@react-types/slider@3.8.4(react@19.2.4)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@react-types/switch@3.5.15(react@19.2.3)': + '@react-types/switch@3.5.17(react@19.2.4)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@react-types/table@3.13.4(react@19.2.3)': + '@react-types/table@3.13.6(react@19.2.4)': dependencies: - '@react-types/grid': 3.3.6(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@react-types/grid': 3.3.8(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@react-types/tabs@3.3.20(react@19.2.3)': + '@react-types/tabs@3.3.22(react@19.2.4)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@react-types/textfield@3.12.6(react@19.2.3)': + '@react-types/textfield@3.12.8(react@19.2.4)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@react-types/tooltip@3.5.0(react@19.2.3)': + '@react-types/tooltip@3.5.2(react@19.2.4)': dependencies: - '@react-types/overlays': 3.9.2(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 + '@react-types/overlays': 3.9.4(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 - '@rolldown/pluginutils@1.0.0-beta.53': {} + '@rolldown/pluginutils@1.0.0-rc.3': {} - '@rollup/plugin-babel@6.1.0(@babel/core@7.28.5)(@types/babel__core@7.20.5)(rollup@4.55.1)': + '@rollup/plugin-babel@6.1.0(@babel/core@7.29.0)(@types/babel__core@7.20.5)(rollup@4.59.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@rollup/pluginutils': 5.3.0(rollup@4.55.1) + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) optionalDependencies: '@types/babel__core': 7.20.5 - rollup: 4.55.1 + rollup: 4.59.0 transitivePeerDependencies: - supports-color - '@rollup/plugin-commonjs@25.0.8(rollup@4.55.1)': + '@rollup/plugin-commonjs@25.0.8(rollup@4.59.0)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.55.1) + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) commondir: 1.0.1 estree-walker: 2.0.2 glob: 8.1.0 is-reference: 1.2.1 magic-string: 0.30.21 optionalDependencies: - rollup: 4.55.1 + rollup: 4.59.0 - '@rollup/plugin-image@3.0.3(rollup@4.55.1)': + '@rollup/plugin-image@3.0.3(rollup@4.59.0)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.55.1) + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) mini-svg-data-uri: 1.4.4 optionalDependencies: - rollup: 4.55.1 + rollup: 4.59.0 - '@rollup/plugin-json@6.1.0(rollup@4.55.1)': + '@rollup/plugin-json@6.1.0(rollup@4.59.0)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.55.1) + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) optionalDependencies: - rollup: 4.55.1 + rollup: 4.59.0 - '@rollup/plugin-node-resolve@15.3.1(rollup@4.55.1)': + '@rollup/plugin-node-resolve@15.3.1(rollup@4.59.0)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.55.1) + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 resolve: 1.22.11 optionalDependencies: - rollup: 4.55.1 + rollup: 4.59.0 - '@rollup/plugin-typescript@12.3.0(rollup@4.55.1)(tslib@2.8.1)(typescript@5.9.3)': + '@rollup/plugin-typescript@12.3.0(rollup@4.59.0)(tslib@2.8.1)(typescript@5.9.3)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.55.1) + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) resolve: 1.22.11 typescript: 5.9.3 optionalDependencies: - rollup: 4.55.1 + rollup: 4.59.0 tslib: 2.8.1 '@rollup/pluginutils@4.2.1': @@ -15273,87 +15502,87 @@ snapshots: estree-walker: 2.0.2 picomatch: 2.3.1 - '@rollup/pluginutils@5.3.0(rollup@4.55.1)': + '@rollup/pluginutils@5.3.0(rollup@4.59.0)': dependencies: '@types/estree': 1.0.8 estree-walker: 2.0.2 picomatch: 4.0.3 optionalDependencies: - rollup: 4.55.1 + rollup: 4.59.0 - '@rollup/rollup-android-arm-eabi@4.55.1': + '@rollup/rollup-android-arm-eabi@4.59.0': optional: true - '@rollup/rollup-android-arm64@4.55.1': + '@rollup/rollup-android-arm64@4.59.0': optional: true - '@rollup/rollup-darwin-arm64@4.55.1': + '@rollup/rollup-darwin-arm64@4.59.0': optional: true - '@rollup/rollup-darwin-x64@4.55.1': + '@rollup/rollup-darwin-x64@4.59.0': optional: true - '@rollup/rollup-freebsd-arm64@4.55.1': + '@rollup/rollup-freebsd-arm64@4.59.0': optional: true - '@rollup/rollup-freebsd-x64@4.55.1': + '@rollup/rollup-freebsd-x64@4.59.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.55.1': + '@rollup/rollup-linux-arm-gnueabihf@4.59.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.55.1': + '@rollup/rollup-linux-arm-musleabihf@4.59.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.55.1': + '@rollup/rollup-linux-arm64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.55.1': + '@rollup/rollup-linux-arm64-musl@4.59.0': optional: true - '@rollup/rollup-linux-loong64-gnu@4.55.1': + '@rollup/rollup-linux-loong64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-loong64-musl@4.55.1': + '@rollup/rollup-linux-loong64-musl@4.59.0': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.55.1': + '@rollup/rollup-linux-ppc64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-ppc64-musl@4.55.1': + '@rollup/rollup-linux-ppc64-musl@4.59.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.55.1': + '@rollup/rollup-linux-riscv64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-riscv64-musl@4.55.1': + '@rollup/rollup-linux-riscv64-musl@4.59.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.55.1': + '@rollup/rollup-linux-s390x-gnu@4.59.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.55.1': + '@rollup/rollup-linux-x64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-x64-musl@4.55.1': + '@rollup/rollup-linux-x64-musl@4.59.0': optional: true - '@rollup/rollup-openbsd-x64@4.55.1': + '@rollup/rollup-openbsd-x64@4.59.0': optional: true - '@rollup/rollup-openharmony-arm64@4.55.1': + '@rollup/rollup-openharmony-arm64@4.59.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.55.1': + '@rollup/rollup-win32-arm64-msvc@4.59.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.55.1': + '@rollup/rollup-win32-ia32-msvc@4.59.0': optional: true - '@rollup/rollup-win32-x64-gnu@4.55.1': + '@rollup/rollup-win32-x64-gnu@4.59.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.55.1': + '@rollup/rollup-win32-x64-msvc@4.59.0': optional: true '@rspack/binding-darwin-arm64@1.6.8': @@ -15401,17 +15630,17 @@ snapshots: '@rspack/binding-win32-ia32-msvc': 1.6.8 '@rspack/binding-win32-x64-msvc': 1.6.8 - '@rspack/core@1.6.8(@swc/helpers@0.5.18)': + '@rspack/core@1.6.8(@swc/helpers@0.5.19)': dependencies: '@module-federation/runtime-tools': 0.21.6 '@rspack/binding': 1.6.8 '@rspack/lite-tapable': 1.1.0 optionalDependencies: - '@swc/helpers': 0.5.18 + '@swc/helpers': 0.5.19 '@rspack/lite-tapable@1.1.0': {} - '@sinclair/typebox@0.34.47': {} + '@sinclair/typebox@0.34.48': {} '@sindresorhus/is@4.6.0': {} @@ -15423,15 +15652,15 @@ snapshots: '@standard-schema/utils@0.3.0': {} - '@storybook/addon-docs@10.1.11(@types/react@19.2.7)(esbuild@0.27.2)(rollup@4.55.1)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2))': + '@storybook/addon-docs@10.2.16(@types/react@19.2.14)(esbuild@0.27.3)(rollup@4.59.0)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))(esbuild@0.27.3))': dependencies: - '@mdx-js/react': 3.1.1(@types/react@19.2.7)(react@19.2.3) - '@storybook/csf-plugin': 10.1.11(esbuild@0.27.2)(rollup@4.55.1)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2)) - '@storybook/icons': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@storybook/react-dom-shim': 10.1.11(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - storybook: 10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@mdx-js/react': 3.1.1(@types/react@19.2.14)(react@19.2.4) + '@storybook/csf-plugin': 10.2.16(esbuild@0.27.3)(rollup@4.59.0)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))(esbuild@0.27.3)) + '@storybook/icons': 2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@storybook/react-dom-shim': 10.2.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + storybook: 10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' @@ -15440,191 +15669,123 @@ snapshots: - vite - webpack - '@storybook/builder-vite@10.1.11(esbuild@0.27.2)(rollup@4.55.1)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2))': - dependencies: - '@storybook/csf-plugin': 10.1.11(esbuild@0.27.2)(rollup@4.55.1)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2)) - '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) - storybook: 10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - ts-dedent: 2.2.0 - vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - transitivePeerDependencies: - - esbuild - - msw - - rollup - - webpack - - '@storybook/builder-vite@10.1.11(esbuild@0.27.2)(rollup@4.55.1)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2))': + '@storybook/builder-vite@10.2.16(esbuild@0.27.3)(rollup@4.59.0)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))(esbuild@0.27.3))': dependencies: - '@storybook/csf-plugin': 10.1.11(esbuild@0.27.2)(rollup@4.55.1)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2)) - '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) - storybook: 10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@storybook/csf-plugin': 10.2.16(esbuild@0.27.3)(rollup@4.59.0)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))(esbuild@0.27.3)) + storybook: 10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) ts-dedent: 2.2.0 - vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - esbuild - - msw - rollup - webpack - '@storybook/csf-plugin@10.1.11(esbuild@0.27.2)(rollup@4.55.1)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2))': - dependencies: - storybook: 10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - unplugin: 2.3.11 - optionalDependencies: - esbuild: 0.27.2 - rollup: 4.55.1 - vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - webpack: 5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2) - - '@storybook/csf-plugin@10.1.11(esbuild@0.27.2)(rollup@4.55.1)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2))': + '@storybook/csf-plugin@10.2.16(esbuild@0.27.3)(rollup@4.59.0)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))(esbuild@0.27.3))': dependencies: - storybook: 10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + storybook: 10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) unplugin: 2.3.11 optionalDependencies: - esbuild: 0.27.2 - rollup: 4.55.1 - vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - webpack: 5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2) + esbuild: 0.27.3 + rollup: 4.59.0 + vite: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + webpack: 5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))(esbuild@0.27.3) '@storybook/global@5.0.0': {} - '@storybook/icons@2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@storybook/react-dom-shim@10.1.11(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))': + '@storybook/icons@2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - storybook: 10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) - '@storybook/react-dom-shim@10.1.11(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))': + '@storybook/react-dom-shim@10.2.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': dependencies: - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - storybook: 10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - - '@storybook/react-vite@10.1.11(esbuild@0.27.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rollup@4.55.1)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2))': - dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.3(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) - '@rollup/pluginutils': 5.3.0(rollup@4.55.1) - '@storybook/builder-vite': 10.1.11(esbuild@0.27.2)(rollup@4.55.1)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2)) - '@storybook/react': 10.1.11(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3) - empathic: 2.0.0 - magic-string: 0.30.21 - react: 19.2.3 - react-docgen: 8.0.2 - react-dom: 19.2.3(react@19.2.3) - resolve: 1.22.11 - storybook: 10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - tsconfig-paths: 4.2.0 - vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - transitivePeerDependencies: - - esbuild - - msw - - rollup - - supports-color - - typescript - - webpack + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + storybook: 10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@storybook/react-vite@10.1.11(esbuild@0.27.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rollup@4.55.1)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2))': + '@storybook/react-vite@10.2.16(esbuild@0.27.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))(esbuild@0.27.3))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.3(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) - '@rollup/pluginutils': 5.3.0(rollup@4.55.1) - '@storybook/builder-vite': 10.1.11(esbuild@0.27.2)(rollup@4.55.1)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2)) - '@storybook/react': 10.1.11(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.4(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + '@storybook/builder-vite': 10.2.16(esbuild@0.27.3)(rollup@4.59.0)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))(esbuild@0.27.3)) + '@storybook/react': 10.2.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) empathic: 2.0.0 magic-string: 0.30.21 - react: 19.2.3 + react: 19.2.4 react-docgen: 8.0.2 - react-dom: 19.2.3(react@19.2.3) + react-dom: 19.2.4(react@19.2.4) resolve: 1.22.11 - storybook: 10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + storybook: 10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) tsconfig-paths: 4.2.0 - vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - esbuild - - msw - rollup - supports-color - typescript - webpack - '@storybook/react@10.1.11(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)': - dependencies: - '@storybook/global': 5.0.0 - '@storybook/react-dom-shim': 10.1.11(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)) - react: 19.2.3 - react-docgen: 8.0.2 - react-dom: 19.2.3(react@19.2.3) - storybook: 10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@storybook/react@10.1.11(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)': + '@storybook/react@10.2.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)': dependencies: '@storybook/global': 5.0.0 - '@storybook/react-dom-shim': 10.1.11(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)) - react: 19.2.3 + '@storybook/react-dom-shim': 10.2.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + react: 19.2.4 react-docgen: 8.0.2 - react-dom: 19.2.3(react@19.2.3) - storybook: 10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react-dom: 19.2.4(react@19.2.4) + storybook: 10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.28.5)': + '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 - '@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.28.5)': + '@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 - '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.28.5)': + '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 - '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.28.5)': + '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 - '@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.28.5)': + '@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 - '@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.28.5)': + '@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 - '@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.28.5)': + '@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 - '@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.28.5)': + '@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 - '@svgr/babel-preset@8.1.0(@babel/core@7.28.5)': + '@svgr/babel-preset@8.1.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.28.5) - '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.28.5) - '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.28.5) - '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.28.5) - '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.28.5) - '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.28.5) - '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.28.5) - '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.28.5) + '@babel/core': 7.29.0 + '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.29.0) + '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.29.0) '@svgr/core@8.1.0(typescript@5.9.3)': dependencies: - '@babel/core': 7.28.5 - '@svgr/babel-preset': 8.1.0(@babel/core@7.28.5) + '@babel/core': 7.29.0 + '@svgr/babel-preset': 8.1.0(@babel/core@7.29.0) camelcase: 6.3.0 cosmiconfig: 8.3.6(typescript@5.9.3) snake-case: 3.0.4 @@ -15634,13 +15795,13 @@ snapshots: '@svgr/hast-util-to-babel-ast@8.0.0': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.0 entities: 4.5.0 '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.9.3))': dependencies: - '@babel/core': 7.28.5 - '@svgr/babel-preset': 8.1.0(@babel/core@7.28.5) + '@babel/core': 7.29.0 + '@svgr/babel-preset': 8.1.0(@babel/core@7.29.0) '@svgr/core': 8.1.0(typescript@5.9.3) '@svgr/hast-util-to-babel-ast': 8.0.0 svg-parser: 2.0.4 @@ -15652,17 +15813,17 @@ snapshots: '@svgr/core': 8.1.0(typescript@5.9.3) cosmiconfig: 8.3.6(typescript@5.9.3) deepmerge: 4.3.1 - svgo: 3.3.2 + svgo: 3.3.3 transitivePeerDependencies: - typescript '@svgr/webpack@8.1.0(typescript@5.9.3)': dependencies: - '@babel/core': 7.28.5 - '@babel/plugin-transform-react-constant-elements': 7.27.1(@babel/core@7.28.5) - '@babel/preset-env': 7.28.5(@babel/core@7.28.5) - '@babel/preset-react': 7.28.5(@babel/core@7.28.5) - '@babel/preset-typescript': 7.28.5(@babel/core@7.28.5) + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-constant-elements': 7.27.1(@babel/core@7.29.0) + '@babel/preset-env': 7.29.0(@babel/core@7.29.0) + '@babel/preset-react': 7.28.5(@babel/core@7.29.0) + '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) '@svgr/core': 8.1.0(typescript@5.9.3) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3)) '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3))(typescript@5.9.3) @@ -15670,19 +15831,19 @@ snapshots: - supports-color - typescript - '@swc-node/core@1.14.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)': + '@swc-node/core@1.14.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)': dependencies: - '@swc/core': 1.15.8(@swc/helpers@0.5.18) + '@swc/core': 1.15.8(@swc/helpers@0.5.19) '@swc/types': 0.1.25 - '@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3)': + '@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3)': dependencies: - '@swc-node/core': 1.14.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25) + '@swc-node/core': 1.14.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25) '@swc-node/sourcemap-support': 0.6.1 - '@swc/core': 1.15.8(@swc/helpers@0.5.18) + '@swc/core': 1.15.8(@swc/helpers@0.5.19) colorette: 2.0.20 debug: 4.4.3 - oxc-resolver: 11.16.2 + oxc-resolver: 11.19.1 pirates: 4.0.7 tslib: 2.8.1 typescript: 5.9.3 @@ -15725,7 +15886,7 @@ snapshots: '@swc/core-win32-x64-msvc@1.15.8': optional: true - '@swc/core@1.15.8(@swc/helpers@0.5.18)': + '@swc/core@1.15.8(@swc/helpers@0.5.19)': dependencies: '@swc/counter': 0.1.3 '@swc/types': 0.1.25 @@ -15740,11 +15901,11 @@ snapshots: '@swc/core-win32-arm64-msvc': 1.15.8 '@swc/core-win32-ia32-msvc': 1.15.8 '@swc/core-win32-x64-msvc': 1.15.8 - '@swc/helpers': 0.5.18 + '@swc/helpers': 0.5.19 '@swc/counter@0.1.3': {} - '@swc/helpers@0.5.18': + '@swc/helpers@0.5.19': dependencies: tslib: 2.8.1 @@ -15756,183 +15917,181 @@ snapshots: dependencies: defer-to-connect: 2.0.1 - '@tailwindcss/node@4.1.18': + '@tailwindcss/node@4.2.1': dependencies: '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.18.4 + enhanced-resolve: 5.20.0 jiti: 2.6.1 - lightningcss: 1.30.2 + lightningcss: 1.31.1 magic-string: 0.30.21 source-map-js: 1.2.1 - tailwindcss: 4.1.18 + tailwindcss: 4.2.1 - '@tailwindcss/oxide-android-arm64@4.1.18': + '@tailwindcss/oxide-android-arm64@4.2.1': optional: true - '@tailwindcss/oxide-darwin-arm64@4.1.18': + '@tailwindcss/oxide-darwin-arm64@4.2.1': optional: true - '@tailwindcss/oxide-darwin-x64@4.1.18': + '@tailwindcss/oxide-darwin-x64@4.2.1': optional: true - '@tailwindcss/oxide-freebsd-x64@4.1.18': + '@tailwindcss/oxide-freebsd-x64@4.2.1': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': + '@tailwindcss/oxide-linux-arm64-gnu@4.2.1': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.1.18': + '@tailwindcss/oxide-linux-arm64-musl@4.2.1': optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.1.18': + '@tailwindcss/oxide-linux-x64-gnu@4.2.1': optional: true - '@tailwindcss/oxide-linux-x64-musl@4.1.18': + '@tailwindcss/oxide-linux-x64-musl@4.2.1': optional: true - '@tailwindcss/oxide-wasm32-wasi@4.1.18': + '@tailwindcss/oxide-wasm32-wasi@4.2.1': optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': + '@tailwindcss/oxide-win32-arm64-msvc@4.2.1': optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.1.18': + '@tailwindcss/oxide-win32-x64-msvc@4.2.1': optional: true - '@tailwindcss/oxide@4.1.18': + '@tailwindcss/oxide@4.2.1': optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.1.18 - '@tailwindcss/oxide-darwin-arm64': 4.1.18 - '@tailwindcss/oxide-darwin-x64': 4.1.18 - '@tailwindcss/oxide-freebsd-x64': 4.1.18 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.18 - '@tailwindcss/oxide-linux-arm64-gnu': 4.1.18 - '@tailwindcss/oxide-linux-arm64-musl': 4.1.18 - '@tailwindcss/oxide-linux-x64-gnu': 4.1.18 - '@tailwindcss/oxide-linux-x64-musl': 4.1.18 - '@tailwindcss/oxide-wasm32-wasi': 4.1.18 - '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18 - '@tailwindcss/oxide-win32-x64-msvc': 4.1.18 - - '@tailwindcss/typography@0.5.19(tailwindcss@4.1.18)': + '@tailwindcss/oxide-android-arm64': 4.2.1 + '@tailwindcss/oxide-darwin-arm64': 4.2.1 + '@tailwindcss/oxide-darwin-x64': 4.2.1 + '@tailwindcss/oxide-freebsd-x64': 4.2.1 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.1 + '@tailwindcss/oxide-linux-arm64-gnu': 4.2.1 + '@tailwindcss/oxide-linux-arm64-musl': 4.2.1 + '@tailwindcss/oxide-linux-x64-gnu': 4.2.1 + '@tailwindcss/oxide-linux-x64-musl': 4.2.1 + '@tailwindcss/oxide-wasm32-wasi': 4.2.1 + '@tailwindcss/oxide-win32-arm64-msvc': 4.2.1 + '@tailwindcss/oxide-win32-x64-msvc': 4.2.1 + + '@tailwindcss/typography@0.5.19(tailwindcss@4.2.1)': dependencies: postcss-selector-parser: 6.0.10 - tailwindcss: 4.1.18 + tailwindcss: 4.2.1 - '@tailwindcss/vite@4.1.18(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@tailwindcss/vite@4.2.1(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': dependencies: - '@tailwindcss/node': 4.1.18 - '@tailwindcss/oxide': 4.1.18 - tailwindcss: 4.1.18 - vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + '@tailwindcss/node': 4.2.1 + '@tailwindcss/oxide': 4.2.1 + tailwindcss: 4.2.1 + vite: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) - '@tanstack/db-ivm@0.1.14(typescript@5.9.3)': + '@tanstack/db-ivm@0.1.17(typescript@5.9.3)': dependencies: fractional-indexing: 3.2.0 sorted-btree: 1.8.1 typescript: 5.9.3 - '@tanstack/db@0.5.16(typescript@5.9.3)': + '@tanstack/db@0.5.30(typescript@5.9.3)': dependencies: '@standard-schema/spec': 1.1.0 - '@tanstack/db-ivm': 0.1.14(typescript@5.9.3) - '@tanstack/pacer-lite': 0.1.1 + '@tanstack/db-ivm': 0.1.17(typescript@5.9.3) + '@tanstack/pacer-lite': 0.2.1 typescript: 5.9.3 - '@tanstack/eslint-plugin-router@1.141.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@tanstack/eslint-plugin-router@1.161.4(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/utils': 8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.56.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) transitivePeerDependencies: - supports-color - typescript - '@tanstack/history@1.145.7': {} + '@tanstack/history@1.161.4': {} - '@tanstack/pacer-lite@0.1.1': {} + '@tanstack/pacer-lite@0.2.1': {} - '@tanstack/query-core@5.90.16': {} + '@tanstack/query-core@5.90.20': {} - '@tanstack/query-devtools@5.92.0': {} + '@tanstack/query-devtools@5.93.0': {} - '@tanstack/react-db@0.1.60(react@19.2.3)(typescript@5.9.3)': + '@tanstack/react-db@0.1.74(react@19.2.4)(typescript@5.9.3)': dependencies: - '@tanstack/db': 0.5.16(typescript@5.9.3) - react: 19.2.3 - use-sync-external-store: 1.6.0(react@19.2.3) + '@tanstack/db': 0.5.30(typescript@5.9.3) + react: 19.2.4 + use-sync-external-store: 1.6.0(react@19.2.4) transitivePeerDependencies: - typescript - '@tanstack/react-query-devtools@5.91.2(@tanstack/react-query@5.90.16(react@19.2.3))(react@19.2.3)': + '@tanstack/react-query-devtools@5.91.3(@tanstack/react-query@5.90.21(react@19.2.4))(react@19.2.4)': dependencies: - '@tanstack/query-devtools': 5.92.0 - '@tanstack/react-query': 5.90.16(react@19.2.3) - react: 19.2.3 + '@tanstack/query-devtools': 5.93.0 + '@tanstack/react-query': 5.90.21(react@19.2.4) + react: 19.2.4 - '@tanstack/react-query@5.90.16(react@19.2.3)': + '@tanstack/react-query@5.90.21(react@19.2.4)': dependencies: - '@tanstack/query-core': 5.90.16 - react: 19.2.3 + '@tanstack/query-core': 5.90.20 + react: 19.2.4 - '@tanstack/react-router-devtools@1.145.7(@tanstack/react-router@1.145.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.145.7)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)': + '@tanstack/react-router-devtools@1.166.2(@tanstack/react-router@1.166.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.166.2)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@tanstack/react-router': 1.145.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@tanstack/router-devtools-core': 1.145.7(@tanstack/router-core@1.145.7)(csstype@3.2.3)(solid-js@1.9.10) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + '@tanstack/react-router': 1.166.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-devtools-core': 1.166.2(@tanstack/router-core@1.166.2)(csstype@3.2.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) optionalDependencies: - '@tanstack/router-core': 1.145.7 + '@tanstack/router-core': 1.166.2 transitivePeerDependencies: - csstype - - solid-js - '@tanstack/react-router@1.145.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@tanstack/react-router@1.166.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@tanstack/history': 1.145.7 - '@tanstack/react-store': 0.8.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@tanstack/router-core': 1.145.7 - isbot: 5.1.32 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + '@tanstack/history': 1.161.4 + '@tanstack/react-store': 0.9.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-core': 1.166.2 + isbot: 5.1.35 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) tiny-invariant: 1.3.3 tiny-warning: 1.0.3 - '@tanstack/react-store@0.8.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@tanstack/react-store@0.9.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@tanstack/store': 0.8.0 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - use-sync-external-store: 1.6.0(react@19.2.3) + '@tanstack/store': 0.9.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + use-sync-external-store: 1.6.0(react@19.2.4) - '@tanstack/router-core@1.145.7': + '@tanstack/router-core@1.166.2': dependencies: - '@tanstack/history': 1.145.7 - '@tanstack/store': 0.8.0 + '@tanstack/history': 1.161.4 + '@tanstack/store': 0.9.1 cookie-es: 2.0.0 - seroval: 1.4.2 - seroval-plugins: 1.4.2(seroval@1.4.2) + seroval: 1.5.0 + seroval-plugins: 1.5.0(seroval@1.5.0) tiny-invariant: 1.3.3 tiny-warning: 1.0.3 - '@tanstack/router-devtools-core@1.145.7(@tanstack/router-core@1.145.7)(csstype@3.2.3)(solid-js@1.9.10)': + '@tanstack/router-devtools-core@1.166.2(@tanstack/router-core@1.166.2)(csstype@3.2.3)': dependencies: - '@tanstack/router-core': 1.145.7 + '@tanstack/router-core': 1.166.2 clsx: 2.1.1 goober: 2.1.18(csstype@3.2.3) - solid-js: 1.9.10 tiny-invariant: 1.3.3 optionalDependencies: csstype: 3.2.3 - '@tanstack/router-generator@1.145.7': + '@tanstack/router-generator@1.166.2': dependencies: - '@tanstack/router-core': 1.145.7 - '@tanstack/router-utils': 1.143.11 - '@tanstack/virtual-file-routes': 1.145.4 - prettier: 3.7.4 + '@tanstack/router-core': 1.166.2 + '@tanstack/router-utils': 1.161.4 + '@tanstack/virtual-file-routes': 1.161.4 + prettier: 3.8.1 recast: 0.23.11 source-map: 0.7.6 tsx: 4.21.0 @@ -15940,49 +16099,50 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/router-plugin@1.145.10(@tanstack/react-router@1.145.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2))': - dependencies: - '@babel/core': 7.28.5 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - '@tanstack/router-core': 1.145.7 - '@tanstack/router-generator': 1.145.7 - '@tanstack/router-utils': 1.143.11 - '@tanstack/virtual-file-routes': 1.145.4 - babel-dead-code-elimination: 1.0.11 + '@tanstack/router-plugin@1.166.2(@tanstack/react-router@1.166.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))(esbuild@0.27.3))': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@tanstack/router-core': 1.166.2 + '@tanstack/router-generator': 1.166.2 + '@tanstack/router-utils': 1.161.4 + '@tanstack/virtual-file-routes': 1.161.4 chokidar: 3.6.0 unplugin: 2.3.11 zod: 3.25.76 optionalDependencies: - '@tanstack/react-router': 1.145.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - webpack: 5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2) + '@tanstack/react-router': 1.166.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + vite: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + webpack: 5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))(esbuild@0.27.3) transitivePeerDependencies: - supports-color - '@tanstack/router-utils@1.143.11': + '@tanstack/router-utils@1.161.4': dependencies: - '@babel/core': 7.28.5 - '@babel/generator': 7.28.5 - '@babel/parser': 7.28.5 + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 ansis: 4.2.0 - diff: 8.0.2 + babel-dead-code-elimination: 1.0.12 + diff: 8.0.3 pathe: 2.0.3 tinyglobby: 0.2.15 transitivePeerDependencies: - supports-color - '@tanstack/store@0.8.0': {} + '@tanstack/store@0.9.1': {} - '@tanstack/virtual-file-routes@1.145.4': {} + '@tanstack/virtual-file-routes@1.161.4': {} '@testing-library/dom@10.4.1': dependencies: '@babel/code-frame': 7.29.0 - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.28.6 '@types/aria-query': 5.0.4 aria-query: 5.3.0 dom-accessibility-api: 0.5.16 @@ -16003,8 +16163,6 @@ snapshots: dependencies: '@testing-library/dom': 10.4.1 - '@trysound/sax@0.2.0': {} - '@tsconfig/node10@1.0.12': {} '@tsconfig/node12@1.0.11': {} @@ -16028,30 +16186,30 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.28.0 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.0 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.0 '@types/cacheable-request@6.0.3': dependencies: - '@types/http-cache-semantics': 4.0.4 + '@types/http-cache-semantics': 4.2.0 '@types/keyv': 3.1.4 - '@types/node': 25.0.3 + '@types/node': 24.12.0 '@types/responselike': 1.0.3 '@types/chai@5.2.3': @@ -16099,6 +16257,10 @@ snapshots: dependencies: '@types/estree': 1.0.8 + '@types/esquery@1.5.4': + dependencies: + '@types/estree': 1.0.8 + '@types/estree-jsx@1.0.5': dependencies: '@types/estree': 1.0.8 @@ -16107,25 +16269,25 @@ snapshots: '@types/fs-extra@9.0.13': dependencies: - '@types/node': 25.0.3 + '@types/node': 25.3.5 '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.3 - '@types/http-cache-semantics@4.0.4': {} + '@types/http-cache-semantics@4.2.0': {} '@types/http-proxy@1.17.17': dependencies: - '@types/node': 25.0.3 + '@types/node': 25.3.5 '@types/json-schema@7.0.15': {} '@types/keyv@3.1.4': dependencies: - '@types/node': 25.0.3 + '@types/node': 24.12.0 - '@types/lodash@4.17.21': {} + '@types/lodash@4.17.24': {} '@types/mdast@4.0.4': dependencies: @@ -16135,56 +16297,47 @@ snapshots: '@types/ms@2.1.0': {} - '@types/node-fetch@2.6.13': - dependencies: - '@types/node': 25.0.3 - form-data: 4.0.5 - - '@types/node@18.19.130': - dependencies: - undici-types: 5.26.5 - - '@types/node@20.19.27': + '@types/node@20.19.37': dependencies: undici-types: 6.21.0 - '@types/node@22.19.3': + '@types/node@24.12.0': dependencies: - undici-types: 6.21.0 + undici-types: 7.16.0 - '@types/node@25.0.3': + '@types/node@25.3.5': dependencies: - undici-types: 7.16.0 + undici-types: 7.18.2 '@types/parse-json@4.0.2': {} - '@types/pg@8.16.0': + '@types/pg@8.18.0': dependencies: - '@types/node': 25.0.3 - pg-protocol: 1.11.0 + '@types/node': 25.3.5 + pg-protocol: 1.13.0 pg-types: 2.2.0 '@types/plist@3.0.5': dependencies: - '@types/node': 25.0.3 + '@types/node': 25.3.5 xmlbuilder: 15.1.1 optional: true - '@types/react-dom@19.2.3(@types/react@19.2.7)': + '@types/react-dom@19.2.3(@types/react@19.2.14)': dependencies: - '@types/react': 19.2.7 + '@types/react': 19.2.14 - '@types/react-reconciler@0.28.9(@types/react@19.2.7)': + '@types/react-reconciler@0.28.9(@types/react@19.2.14)': dependencies: - '@types/react': 19.2.7 + '@types/react': 19.2.14 - '@types/react-timeago@8.0.0(react@19.2.3)': + '@types/react-timeago@8.0.0(react@19.2.4)': dependencies: - react-timeago: 8.3.0(react@19.2.3) + react-timeago: 8.3.0(react@19.2.4) transitivePeerDependencies: - react - '@types/react@19.2.7': + '@types/react@19.2.14': dependencies: csstype: 3.2.3 @@ -16194,7 +16347,7 @@ snapshots: '@types/responselike@1.0.3': dependencies: - '@types/node': 25.0.3 + '@types/node': 24.12.0 '@types/semver@7.5.8': {} @@ -16205,24 +16358,30 @@ snapshots: '@types/verror@1.10.11': optional: true + '@types/webidl-conversions@7.0.3': {} + + '@types/whatwg-url@13.0.0': + dependencies: + '@types/webidl-conversions': 7.0.3 + '@types/ws@8.18.1': dependencies: - '@types/node': 25.0.3 + '@types/node': 25.3.5 optional: true '@types/yauzl@2.10.3': dependencies: - '@types/node': 25.0.3 + '@types/node': 24.12.0 optional: true - '@typescript-eslint/eslint-plugin@8.52.0(@typescript-eslint/parser@8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.52.0 - '@typescript-eslint/type-utils': 8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.52.0 + '@typescript-eslint/parser': 8.56.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.56.1 + '@typescript-eslint/type-utils': 8.56.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.56.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.56.1 eslint: 9.39.2(jiti@2.6.1) ignore: 7.0.5 natural-compare: 1.4.0 @@ -16231,41 +16390,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.56.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.52.0 - '@typescript-eslint/types': 8.52.0 - '@typescript-eslint/typescript-estree': 8.52.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.52.0 + '@typescript-eslint/scope-manager': 8.56.1 + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.56.1 debug: 4.4.3 eslint: 9.39.2(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.52.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.56.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.52.0(typescript@5.9.3) - '@typescript-eslint/types': 8.52.0 + '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.9.3) + '@typescript-eslint/types': 8.56.1 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.52.0': + '@typescript-eslint/scope-manager@8.56.1': dependencies: - '@typescript-eslint/types': 8.52.0 - '@typescript-eslint/visitor-keys': 8.52.0 + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/visitor-keys': 8.56.1 - '@typescript-eslint/tsconfig-utils@8.52.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.56.1(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.56.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.52.0 - '@typescript-eslint/typescript-estree': 8.52.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.56.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) debug: 4.4.3 eslint: 9.39.2(jiti@2.6.1) ts-api-utils: 2.4.0(typescript@5.9.3) @@ -16273,60 +16432,60 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.52.0': {} + '@typescript-eslint/types@8.56.1': {} - '@typescript-eslint/typescript-estree@8.52.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.56.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.52.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.52.0(typescript@5.9.3) - '@typescript-eslint/types': 8.52.0 - '@typescript-eslint/visitor-keys': 8.52.0 + '@typescript-eslint/project-service': 8.56.1(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.9.3) + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/visitor-keys': 8.56.1 debug: 4.4.3 - minimatch: 9.0.5 - semver: 7.7.3 + minimatch: 10.2.4 + semver: 7.7.4 tinyglobby: 0.2.15 ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.56.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.52.0 - '@typescript-eslint/types': 8.52.0 - '@typescript-eslint/typescript-estree': 8.52.0(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.56.1 + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.52.0': + '@typescript-eslint/visitor-keys@8.56.1': dependencies: - '@typescript-eslint/types': 8.52.0 - eslint-visitor-keys: 4.2.1 + '@typescript-eslint/types': 8.56.1 + eslint-visitor-keys: 5.0.1 - '@typescript/vfs@1.6.2(typescript@5.4.5)': + '@typescript/vfs@1.6.4(typescript@5.4.5)': dependencies: debug: 4.4.3 typescript: 5.4.5 transitivePeerDependencies: - supports-color - '@typespec/compiler@1.7.1(@types/node@25.0.3)': + '@typespec/compiler@1.9.0(@types/node@25.3.5)': dependencies: - '@babel/code-frame': 7.27.1 - '@inquirer/prompts': 8.1.0(@types/node@25.0.3) + '@babel/code-frame': 7.28.6 + '@inquirer/prompts': 8.3.0(@types/node@25.3.5) ajv: 8.17.1 change-case: 5.4.4 env-paths: 3.0.0 - globby: 16.0.0 + globby: 16.1.1 is-unicode-supported: 2.1.0 mustache: 4.2.0 picocolors: 1.1.1 - prettier: 3.6.2 - semver: 7.7.3 - tar: 7.5.2 + prettier: 3.8.1 + semver: 7.7.4 + tar: 7.5.10 temporal-polyfill: 0.3.0 vscode-languageserver: 9.0.1 vscode-languageserver-textdocument: 1.0.12 @@ -16335,38 +16494,39 @@ snapshots: transitivePeerDependencies: - '@types/node' - '@typespec/emitter-framework@0.14.0(@alloy-js/core@0.22.0)(@alloy-js/csharp@0.21.0)(@alloy-js/typescript@0.22.0)(@typespec/compiler@1.7.1(@types/node@25.0.3))': + '@typespec/emitter-framework@0.16.0(@alloy-js/core@0.22.0)(@alloy-js/csharp@0.21.0)(@alloy-js/python@0.3.0)(@alloy-js/typescript@0.22.0)(@typespec/compiler@1.9.0(@types/node@25.3.5))': dependencies: '@alloy-js/core': 0.22.0 '@alloy-js/csharp': 0.21.0 + '@alloy-js/python': 0.3.0 '@alloy-js/typescript': 0.22.0 - '@typespec/compiler': 1.7.1(@types/node@25.0.3) + '@typespec/compiler': 1.9.0(@types/node@25.3.5) - '@typespec/prettier-plugin-typespec@1.7.0': + '@typespec/prettier-plugin-typespec@1.9.0': dependencies: - prettier: 3.6.2 + prettier: 3.8.1 - '@uiw/codemirror-extensions-basic-setup@4.25.4(@codemirror/autocomplete@6.20.0)(@codemirror/commands@6.10.1)(@codemirror/language@6.12.1)(@codemirror/lint@6.9.2)(@codemirror/search@6.5.11)(@codemirror/state@6.5.3)(@codemirror/view@6.39.9)': + '@uiw/codemirror-extensions-basic-setup@4.25.7(@codemirror/autocomplete@6.20.0)(@codemirror/commands@6.10.1)(@codemirror/language@6.12.1)(@codemirror/lint@6.9.5)(@codemirror/search@6.5.11)(@codemirror/state@6.5.3)(@codemirror/view@6.39.9)': dependencies: '@codemirror/autocomplete': 6.20.0 '@codemirror/commands': 6.10.1 '@codemirror/language': 6.12.1 - '@codemirror/lint': 6.9.2 + '@codemirror/lint': 6.9.5 '@codemirror/search': 6.5.11 '@codemirror/state': 6.5.3 '@codemirror/view': 6.39.9 - '@uiw/react-codemirror@4.25.4(@babel/runtime@7.28.4)(@codemirror/autocomplete@6.20.0)(@codemirror/language@6.12.1)(@codemirror/lint@6.9.2)(@codemirror/search@6.5.11)(@codemirror/state@6.5.3)(@codemirror/theme-one-dark@6.1.3)(@codemirror/view@6.39.9)(codemirror@6.0.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@uiw/react-codemirror@4.25.7(@babel/runtime@7.28.6)(@codemirror/autocomplete@6.20.0)(@codemirror/language@6.12.1)(@codemirror/lint@6.9.5)(@codemirror/search@6.5.11)(@codemirror/state@6.5.3)(@codemirror/theme-one-dark@6.1.3)(@codemirror/view@6.39.9)(codemirror@6.0.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.28.6 '@codemirror/commands': 6.10.1 '@codemirror/state': 6.5.3 '@codemirror/theme-one-dark': 6.1.3 '@codemirror/view': 6.39.9 - '@uiw/codemirror-extensions-basic-setup': 4.25.4(@codemirror/autocomplete@6.20.0)(@codemirror/commands@6.10.1)(@codemirror/language@6.12.1)(@codemirror/lint@6.9.2)(@codemirror/search@6.5.11)(@codemirror/state@6.5.3)(@codemirror/view@6.39.9) + '@uiw/codemirror-extensions-basic-setup': 4.25.7(@codemirror/autocomplete@6.20.0)(@codemirror/commands@6.10.1)(@codemirror/language@6.12.1)(@codemirror/lint@6.9.5)(@codemirror/search@6.5.11)(@codemirror/state@6.5.3)(@codemirror/view@6.39.9) codemirror: 6.0.2 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - '@codemirror/autocomplete' - '@codemirror/language' @@ -16434,15 +16594,19 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vitejs/plugin-react@5.1.2(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@valibot/to-json-schema@1.5.0(valibot@1.2.0(typescript@5.9.3))': + dependencies: + valibot: 1.2.0(typescript@5.9.3) + + '@vitejs/plugin-react@5.1.4(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.5) - '@rolldown/pluginutils': 1.0.0-beta.53 + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) + '@rolldown/pluginutils': 1.0.0-rc.3 '@types/babel__core': 7.20.5 react-refresh: 0.18.0 - vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - supports-color @@ -16463,21 +16627,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': - dependencies: - '@vitest/spy': 3.2.4 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - - '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 4.0.18 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) '@vitest/pretty-format@3.2.4': dependencies: @@ -16515,17 +16671,11 @@ snapshots: '@vitest/pretty-format': 4.0.18 tinyrainbow: 3.0.3 - '@vue/reactivity@3.5.26': - dependencies: - '@vue/shared': 3.5.26 - - '@vue/reactivity@3.5.28': + '@vue/reactivity@3.5.29': dependencies: - '@vue/shared': 3.5.28 - - '@vue/shared@3.5.26': {} + '@vue/shared': 3.5.29 - '@vue/shared@3.5.28': {} + '@vue/shared@3.5.29': {} '@webassemblyjs/ast@1.14.1': dependencies: @@ -16613,13 +16763,13 @@ snapshots: '@xtuc/long@4.2.2': {} - '@xyflow/react@12.10.1(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@xyflow/react@12.10.1(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@xyflow/system': 0.0.75 classcat: 5.0.5 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - zustand: 4.5.7(@types/react@19.2.7)(react@19.2.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + zustand: 4.5.7(@types/react@19.2.14)(react@19.2.4) transitivePeerDependencies: - '@types/react' - immer @@ -16658,19 +16808,19 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 - acorn-import-phases@1.0.4(acorn@8.15.0): + acorn-import-phases@1.0.4(acorn@8.16.0): dependencies: - acorn: 8.15.0 + acorn: 8.16.0 - acorn-jsx@5.3.2(acorn@8.15.0): + acorn-jsx@5.3.2(acorn@8.16.0): dependencies: - acorn: 8.15.0 + acorn: 8.16.0 - acorn-walk@8.3.4: + acorn-walk@8.3.5: dependencies: - acorn: 8.15.0 + acorn: 8.16.0 - acorn@8.15.0: {} + acorn@8.16.0: {} address@1.2.2: {} @@ -16678,24 +16828,20 @@ snapshots: agent-base@7.1.4: {} - agentkeepalive@4.6.0: - dependencies: - humanize-ms: 1.2.1 - - ajv-formats@2.1.1(ajv@8.17.1): + ajv-formats@2.1.1(ajv@8.18.0): optionalDependencies: - ajv: 8.17.1 + ajv: 8.18.0 - ajv-keywords@3.5.2(ajv@6.12.6): + ajv-keywords@3.5.2(ajv@6.14.0): dependencies: - ajv: 6.12.6 + ajv: 6.14.0 - ajv-keywords@5.1.0(ajv@8.17.1): + ajv-keywords@5.1.0(ajv@8.18.0): dependencies: - ajv: 8.17.1 + ajv: 8.18.0 fast-deep-equal: 3.1.3 - ajv@6.12.6: + ajv@6.14.0: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 @@ -16709,6 +16855,13 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + ajv@8.18.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + ansi-colors@4.1.3: {} ansi-regex@5.0.1: {} @@ -16734,7 +16887,7 @@ snapshots: app-builder-bin@5.0.0-alpha.12: {} - app-builder-lib@26.3.1(dmg-builder@26.3.1)(electron-builder-squirrel-windows@26.4.0): + app-builder-lib@26.4.0(dmg-builder@26.8.1)(electron-builder-squirrel-windows@26.4.0): dependencies: '@develar/schema-utils': 2.6.5 '@electron/asar': 3.4.1 @@ -16746,17 +16899,17 @@ snapshots: '@malept/flatpak-bundler': 0.4.0 '@types/fs-extra': 9.0.13 async-exit-hook: 2.0.1 - builder-util: 26.3.1 + builder-util: 26.3.4 builder-util-runtime: 9.5.1 chromium-pickle-js: 0.2.0 ci-info: 4.3.1 debug: 4.4.3 - dmg-builder: 26.3.1(electron-builder-squirrel-windows@26.4.0) + dmg-builder: 26.8.1(electron-builder-squirrel-windows@26.4.0) dotenv: 16.6.1 dotenv-expand: 11.0.7 ejs: 3.1.10 - electron-builder-squirrel-windows: 26.4.0(dmg-builder@26.3.1) - electron-publish: 26.3.1 + electron-builder-squirrel-windows: 26.4.0(dmg-builder@26.8.1) + electron-publish: 26.3.4 fs-extra: 10.1.0 hosted-git-info: 4.1.0 isbinaryfile: 5.0.7 @@ -16764,10 +16917,10 @@ snapshots: js-yaml: 4.1.1 json5: 2.2.3 lazy-val: 1.0.5 - minimatch: 10.1.1 + minimatch: 10.2.4 plist: 3.1.0 resedit: 1.7.2 - semver: 7.7.2 + semver: 7.7.4 tar: 6.2.1 temp-file: 3.4.0 tiny-async-pool: 1.3.0 @@ -16775,29 +16928,30 @@ snapshots: transitivePeerDependencies: - supports-color - app-builder-lib@26.4.0(dmg-builder@26.3.1)(electron-builder-squirrel-windows@26.4.0): + app-builder-lib@26.8.1(dmg-builder@26.8.1)(electron-builder-squirrel-windows@26.4.0): dependencies: '@develar/schema-utils': 2.6.5 '@electron/asar': 3.4.1 '@electron/fuses': 1.8.0 + '@electron/get': 3.1.0 '@electron/notarize': 2.5.0 '@electron/osx-sign': 1.3.3 - '@electron/rebuild': 4.0.1 + '@electron/rebuild': 4.0.3 '@electron/universal': 2.0.3 '@malept/flatpak-bundler': 0.4.0 '@types/fs-extra': 9.0.13 async-exit-hook: 2.0.1 - builder-util: 26.3.4 + builder-util: 26.8.1 builder-util-runtime: 9.5.1 chromium-pickle-js: 0.2.0 ci-info: 4.3.1 debug: 4.4.3 - dmg-builder: 26.3.1(electron-builder-squirrel-windows@26.4.0) + dmg-builder: 26.8.1(electron-builder-squirrel-windows@26.4.0) dotenv: 16.6.1 dotenv-expand: 11.0.7 ejs: 3.1.10 - electron-builder-squirrel-windows: 26.4.0(dmg-builder@26.3.1) - electron-publish: 26.3.4 + electron-builder-squirrel-windows: 26.4.0(dmg-builder@26.8.1) + electron-publish: 26.8.1 fs-extra: 10.1.0 hosted-git-info: 4.1.0 isbinaryfile: 5.0.7 @@ -16805,17 +16959,42 @@ snapshots: js-yaml: 4.1.1 json5: 2.2.3 lazy-val: 1.0.5 - minimatch: 10.2.1 + minimatch: 10.2.4 plist: 3.1.0 + proper-lockfile: 4.1.2 resedit: 1.7.2 semver: 7.7.4 - tar: 6.2.1 + tar: 7.5.10 temp-file: 3.4.0 tiny-async-pool: 1.3.0 which: 5.0.0 transitivePeerDependencies: - supports-color + archiver-utils@5.0.2: + dependencies: + glob: 10.5.0 + graceful-fs: 4.2.11 + is-stream: 2.0.1 + lazystream: 1.0.1 + lodash: 4.17.23 + normalize-path: 3.0.0 + readable-stream: 4.7.0 + + archiver@7.0.1: + dependencies: + archiver-utils: 5.0.2 + async: 3.2.6 + buffer-crc32: 1.0.0 + readable-stream: 4.7.0 + readdir-glob: 1.1.3 + tar-stream: 3.1.8 + zip-stream: 6.0.1 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a + arg@4.1.3: {} argparse@1.0.10: @@ -16913,22 +17092,24 @@ snapshots: at-least-node@1.0.0: {} - autoprefixer@10.4.23(postcss@8.5.6): + autoprefixer@10.4.27(postcss@8.5.8): dependencies: browserslist: 4.28.1 - caniuse-lite: 1.0.30001762 + caniuse-lite: 1.0.30001777 fraction.js: 5.3.4 picocolors: 1.1.1 - postcss: 8.5.6 + postcss: 8.5.8 postcss-value-parser: 4.2.0 available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.1.0 + aws-ssl-profiles@1.1.2: {} + axe-core@4.11.1: {} - axios@1.13.2: + axios@1.13.6: dependencies: follow-redirects: 1.15.11(debug@4.4.3) form-data: 4.0.5 @@ -16938,76 +17119,117 @@ snapshots: axobject-query@4.1.0: {} - babel-dead-code-elimination@1.0.11: + b4a@1.8.0: {} + + babel-dead-code-elimination@1.0.12: dependencies: - '@babel/core': 7.28.5 - '@babel/parser': 7.28.5 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/core': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - babel-plugin-const-enum@1.2.0(@babel/core@7.28.5): + babel-plugin-const-enum@1.2.0(@babel/core@7.29.0): dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color babel-plugin-macros@3.1.0: dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.28.6 cosmiconfig: 7.1.0 resolve: 1.22.11 - babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.5): + babel-plugin-polyfill-corejs2@0.4.15(@babel/core@7.29.0): dependencies: - '@babel/compat-data': 7.28.5 - '@babel/core': 7.28.5 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5) + '@babel/compat-data': 7.29.0 + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.6.6(@babel/core@7.29.0) semver: 6.3.1 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.28.5): + babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.6.6(@babel/core@7.29.0) + core-js-compat: 3.48.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-corejs3@0.14.0(@babel/core@7.29.0): dependencies: - '@babel/core': 7.28.5 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5) - core-js-compat: 3.47.0 + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.6.6(@babel/core@7.29.0) + core-js-compat: 3.48.0 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-regenerator@0.6.5(@babel/core@7.28.5): + babel-plugin-polyfill-regenerator@0.6.6(@babel/core@7.29.0): dependencies: - '@babel/core': 7.28.5 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5) + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.6.6(@babel/core@7.29.0) transitivePeerDependencies: - supports-color babel-plugin-react-compiler@19.1.0-rc.3: dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.0 - babel-plugin-transform-typescript-metadata@0.3.2(@babel/core@7.28.5)(@babel/traverse@7.28.5): + babel-plugin-transform-typescript-metadata@0.3.2(@babel/core@7.29.0)(@babel/traverse@7.29.0): dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 optionalDependencies: - '@babel/traverse': 7.28.5 + '@babel/traverse': 7.29.0 bail@2.0.2: {} balanced-match@1.0.2: {} - balanced-match@4.0.2: + balanced-match@4.0.4: {} + + bare-events@2.8.2: {} + + bare-fs@4.5.5: + dependencies: + bare-events: 2.8.2 + bare-path: 3.0.0 + bare-stream: 2.8.0(bare-events@2.8.2) + bare-url: 2.3.2 + fast-fifo: 1.3.2 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + bare-os@3.7.1: {} + + bare-path@3.0.0: + dependencies: + bare-os: 3.7.1 + + bare-stream@2.8.0(bare-events@2.8.2): dependencies: - jackspeak: 4.2.3 + streamx: 2.23.0 + teex: 1.0.1 + optionalDependencies: + bare-events: 2.8.2 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + bare-url@2.3.2: + dependencies: + bare-path: 3.0.0 base64-js@1.5.1: {} - baseline-browser-mapping@2.9.11: {} + baseline-browser-mapping@2.10.0: {} basic-auth@2.0.1: dependencies: @@ -17015,29 +17237,66 @@ snapshots: before-after-hook@4.0.0: {} - better-auth@1.4.18(@prisma/client@5.22.0)(better-sqlite3@12.6.2)(drizzle-orm@0.41.0(@libsql/client@0.14.0)(@prisma/client@5.22.0)(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(pg@8.18.0))(pg@8.18.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)(vitest@4.0.18(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): + better-auth@1.4.21(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(better-sqlite3@12.6.2)(drizzle-orm@0.41.0(@electric-sql/pglite@0.3.15)(@libsql/client@0.14.0)(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(@types/pg@8.18.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.1.0(socks@2.8.7))(mysql2@3.15.3)(pg@8.20.0)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.10)(vitest@4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): dependencies: - '@better-auth/core': 1.4.18(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.0) - '@better-auth/telemetry': 1.4.18(@better-auth/core@1.4.18(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.0)) + '@better-auth/core': 1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1) + '@better-auth/telemetry': 1.4.21(@better-auth/core@1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1)) '@better-auth/utils': 0.3.0 '@better-fetch/fetch': 1.1.21 '@noble/ciphers': 2.1.1 '@noble/hashes': 2.0.1 better-call: 1.1.8(zod@4.3.6) defu: 6.1.4 - jose: 6.1.3 + jose: 6.2.0 + kysely: 0.28.11 + nanostores: 1.1.1 + zod: 4.3.6 + optionalDependencies: + '@prisma/client': 5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)) + better-sqlite3: 12.6.2 + drizzle-orm: 0.41.0(@electric-sql/pglite@0.3.15)(@libsql/client@0.14.0)(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(@types/pg@8.18.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)) + mongodb: 7.1.0(socks@2.8.7) + mysql2: 3.15.3 + pg: 8.20.0 + prisma: 7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + solid-js: 1.9.10 + vitest: 4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + + better-auth@1.5.4(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(better-sqlite3@12.6.2)(drizzle-orm@0.41.0(@electric-sql/pglite@0.3.15)(@libsql/client@0.14.0)(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(@types/pg@8.18.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.1.0(socks@2.8.7))(mysql2@3.15.3)(pg@8.20.0)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.10)(vitest@4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): + dependencies: + '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1) + '@better-auth/drizzle-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(drizzle-orm@0.41.0(@electric-sql/pglite@0.3.15)(@libsql/client@0.14.0)(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(@types/pg@8.18.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))) + '@better-auth/kysely-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(kysely@0.28.11) + '@better-auth/memory-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1) + '@better-auth/mongo-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(mongodb@7.1.0(socks@2.8.7)) + '@better-auth/prisma-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)) + '@better-auth/telemetry': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1)) + '@better-auth/utils': 0.3.1 + '@better-fetch/fetch': 1.1.21 + '@noble/ciphers': 2.1.1 + '@noble/hashes': 2.0.1 + better-call: 1.3.2(zod@4.3.6) + defu: 6.1.4 + jose: 6.2.0 kysely: 0.28.11 - nanostores: 1.1.0 + nanostores: 1.1.1 zod: 4.3.6 optionalDependencies: - '@prisma/client': 5.22.0 + '@prisma/client': 5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)) better-sqlite3: 12.6.2 - drizzle-orm: 0.41.0(@libsql/client@0.14.0)(@prisma/client@5.22.0)(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(pg@8.18.0) - pg: 8.18.0 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + drizzle-orm: 0.41.0(@electric-sql/pglite@0.3.15)(@libsql/client@0.14.0)(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(@types/pg@8.18.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)) + mongodb: 7.1.0(socks@2.8.7) + mysql2: 3.15.3 + pg: 8.20.0 + prisma: 7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) solid-js: 1.9.10 - vitest: 4.0.18(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vitest: 4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + transitivePeerDependencies: + - '@cloudflare/workers-types' better-call@1.1.8(zod@4.3.6): dependencies: @@ -17048,23 +17307,30 @@ snapshots: optionalDependencies: zod: 4.3.6 + better-call@1.3.2(zod@4.3.6): + dependencies: + '@better-auth/utils': 0.3.1 + '@better-fetch/fetch': 1.1.21 + rou3: 0.7.12 + set-cookie-parser: 3.0.1 + optionalDependencies: + zod: 4.3.6 + better-sqlite3@12.6.2: dependencies: bindings: 1.5.0 prebuild-install: 7.1.3 - big.js@5.2.2: {} - binary-extensions@2.3.0: {} bindings@1.5.0: dependencies: file-uri-to-path: 1.0.0 - bippy@0.3.34(@types/react@19.2.7)(react@19.2.3): + bippy@0.5.30(@types/react@19.2.14)(react@19.2.4): dependencies: - '@types/react-reconciler': 0.28.9(@types/react@19.2.7) - react: 19.2.3 + '@types/react-reconciler': 0.28.9(@types/react@19.2.14) + react: 19.2.4 transitivePeerDependencies: - '@types/react' @@ -17084,7 +17350,7 @@ snapshots: http-errors: 2.0.1 iconv-lite: 0.4.24 on-finished: 2.4.1 - qs: 6.14.1 + qs: 6.14.2 raw-body: 2.5.3 type-is: 1.6.18 unpipe: 1.0.0 @@ -17105,9 +17371,9 @@ snapshots: dependencies: balanced-match: 1.0.2 - brace-expansion@5.0.2: + brace-expansion@5.0.4: dependencies: - balanced-match: 4.0.2 + balanced-match: 4.0.4 braces@3.0.3: dependencies: @@ -17115,16 +17381,20 @@ snapshots: browserslist@4.28.1: dependencies: - baseline-browser-mapping: 2.9.11 - caniuse-lite: 1.0.30001762 - electron-to-chromium: 1.5.267 - node-releases: 2.0.27 + baseline-browser-mapping: 2.10.0 + caniuse-lite: 1.0.30001777 + electron-to-chromium: 1.5.307 + node-releases: 2.0.36 update-browserslist-db: 1.2.3(browserslist@4.28.1) + bson@7.2.0: {} + btoa@1.2.1: {} buffer-crc32@0.2.13: {} + buffer-crc32@1.0.0: {} + buffer-from@1.1.2: {} buffer@5.7.1: @@ -17132,21 +17402,25 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + builder-util-runtime@9.5.1: dependencies: debug: 4.4.3 - sax: 1.4.3 + sax: 1.5.0 transitivePeerDependencies: - supports-color - builder-util@26.3.1: + builder-util@26.3.4: dependencies: 7zip-bin: 5.2.0 '@types/debug': 4.1.12 app-builder-bin: 5.0.0-alpha.12 builder-util-runtime: 9.5.1 chalk: 4.1.2 - ci-info: 4.3.1 cross-spawn: 7.0.6 debug: 4.4.3 fs-extra: 10.1.0 @@ -17161,7 +17435,7 @@ snapshots: transitivePeerDependencies: - supports-color - builder-util@26.3.4: + builder-util@26.8.1: dependencies: 7zip-bin: 5.2.0 '@types/debug': 4.1.12 @@ -17186,57 +17460,72 @@ snapshots: dependencies: run-applescript: 7.1.0 - bundle-require@5.1.0(esbuild@0.27.2): + bundle-require@5.1.0(esbuild@0.27.3): dependencies: - esbuild: 0.27.2 + esbuild: 0.27.3 load-tsconfig: 0.2.5 bytes@3.1.2: {} - c12@3.3.3: + c12@3.1.0: dependencies: - chokidar: 5.0.0 + chokidar: 4.0.3 confbox: 0.2.4 defu: 6.1.4 - dotenv: 17.3.1 + dotenv: 16.6.1 exsolve: 1.0.8 giget: 2.0.0 jiti: 2.6.1 ohash: 2.0.11 pathe: 2.0.3 - perfect-debounce: 2.1.0 + perfect-debounce: 1.0.0 pkg-types: 2.3.0 rc9: 2.1.2 - cac@6.7.14: {} - - cacache@19.0.1: + c12@3.3.3: + dependencies: + chokidar: 5.0.0 + confbox: 0.2.4 + defu: 6.1.4 + dotenv: 17.3.1 + exsolve: 1.0.8 + giget: 2.0.0 + jiti: 2.6.1 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 2.1.0 + pkg-types: 2.3.0 + rc9: 2.1.2 + + cac@6.7.14: {} + + cacache@19.0.1: dependencies: '@npmcli/fs': 4.0.0 fs-minipass: 3.0.3 glob: 10.5.0 lru-cache: 10.4.3 - minipass: 7.1.2 + minipass: 7.1.3 minipass-collect: 2.0.1 minipass-flush: 1.0.5 minipass-pipeline: 1.2.4 p-map: 7.0.4 ssri: 12.0.0 - tar: 7.5.2 + tar: 7.5.10 unique-filename: 4.0.0 cacache@20.0.3: dependencies: '@npmcli/fs': 5.0.0 fs-minipass: 3.0.3 - glob: 13.0.0 - lru-cache: 11.2.4 - minipass: 7.1.2 + glob: 13.0.6 + lru-cache: 11.2.6 + minipass: 7.1.3 minipass-collect: 2.0.1 minipass-flush: 1.0.5 minipass-pipeline: 1.2.4 p-map: 7.0.4 - ssri: 13.0.0 + ssri: 13.0.1 unique-filename: 5.0.0 cacheable-lookup@5.0.4: {} @@ -17272,14 +17561,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-api@3.0.0: - dependencies: - browserslist: 4.28.1 - caniuse-lite: 1.0.30001762 - lodash.memoize: 4.1.2 - lodash.uniq: 4.5.0 - - caniuse-lite@1.0.30001762: {} + caniuse-lite@1.0.30001777: {} ccount@2.0.1: {} @@ -17372,6 +17654,8 @@ snapshots: ci-info@4.3.1: {} + ci-info@4.4.0: {} + citty@0.1.6: dependencies: consola: 3.4.2 @@ -17417,7 +17701,7 @@ snapshots: cliui@9.0.1: dependencies: string-width: 7.2.0 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 wrap-ansi: 9.0.2 clone-response@1.0.3: @@ -17433,7 +17717,7 @@ snapshots: '@codemirror/autocomplete': 6.20.0 '@codemirror/commands': 6.10.1 '@codemirror/language': 6.12.1 - '@codemirror/lint': 6.9.2 + '@codemirror/lint': 6.9.5 '@codemirror/search': 6.5.11 '@codemirror/state': 6.5.3 '@codemirror/view': 6.39.9 @@ -17444,8 +17728,6 @@ snapshots: color-name@1.1.4: {} - colord@2.9.3: {} - colorette@2.0.20: {} columnify@1.6.0: @@ -17465,6 +17747,8 @@ snapshots: commander@13.1.0: {} + commander@14.0.3: {} + commander@2.20.3: {} commander@4.1.1: {} @@ -17476,12 +17760,20 @@ snapshots: commander@9.5.0: optional: true - comment-parser@1.4.1: {} + comment-parser@1.4.5: {} commondir@1.0.1: {} compare-version@0.1.2: {} + compress-commons@6.0.2: + dependencies: + crc-32: 1.2.2 + crc32-stream: 6.0.0 + is-stream: 2.0.1 + normalize-path: 3.0.0 + readable-stream: 4.7.0 + concat-map@0.0.1: {} concat-with-sourcemaps@1.1.0: @@ -17515,7 +17807,7 @@ snapshots: depd: 2.0.0 keygrip: 1.1.0 - core-js-compat@3.47.0: + core-js-compat@3.48.0: dependencies: browserslist: 4.28.1 @@ -17543,7 +17835,7 @@ snapshots: optionalDependencies: typescript: 5.9.3 - cosmiconfig@9.0.0(typescript@5.9.3): + cosmiconfig@9.0.1(typescript@5.9.3): dependencies: env-paths: 2.2.1 import-fresh: 3.3.1 @@ -17552,6 +17844,13 @@ snapshots: optionalDependencies: typescript: 5.9.3 + crc-32@1.2.2: {} + + crc32-stream@6.0.0: + dependencies: + crc-32: 1.2.2 + readable-stream: 4.7.0 + crc@3.8.0: dependencies: buffer: 5.7.1 @@ -17574,18 +17873,6 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - css-declaration-sorter@6.4.1(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - - css-select@4.3.0: - dependencies: - boolbase: 1.0.0 - css-what: 6.2.2 - domhandler: 4.3.1 - domutils: 2.8.0 - nth-check: 2.1.1 - css-select@5.2.2: dependencies: boolbase: 1.0.0 @@ -17594,11 +17881,6 @@ snapshots: domutils: 3.2.2 nth-check: 2.1.1 - css-tree@1.1.3: - dependencies: - mdn-data: 2.0.14 - source-map: 0.6.1 - css-tree@2.2.1: dependencies: mdn-data: 2.0.28 @@ -17615,54 +17897,6 @@ snapshots: cssesc@3.0.0: {} - cssnano-preset-default@5.2.14(postcss@8.5.6): - dependencies: - css-declaration-sorter: 6.4.1(postcss@8.5.6) - cssnano-utils: 3.1.0(postcss@8.5.6) - postcss: 8.5.6 - postcss-calc: 8.2.4(postcss@8.5.6) - postcss-colormin: 5.3.1(postcss@8.5.6) - postcss-convert-values: 5.1.3(postcss@8.5.6) - postcss-discard-comments: 5.1.2(postcss@8.5.6) - postcss-discard-duplicates: 5.1.0(postcss@8.5.6) - postcss-discard-empty: 5.1.1(postcss@8.5.6) - postcss-discard-overridden: 5.1.0(postcss@8.5.6) - postcss-merge-longhand: 5.1.7(postcss@8.5.6) - postcss-merge-rules: 5.1.4(postcss@8.5.6) - postcss-minify-font-values: 5.1.0(postcss@8.5.6) - postcss-minify-gradients: 5.1.1(postcss@8.5.6) - postcss-minify-params: 5.1.4(postcss@8.5.6) - postcss-minify-selectors: 5.2.1(postcss@8.5.6) - postcss-normalize-charset: 5.1.0(postcss@8.5.6) - postcss-normalize-display-values: 5.1.0(postcss@8.5.6) - postcss-normalize-positions: 5.1.1(postcss@8.5.6) - postcss-normalize-repeat-style: 5.1.1(postcss@8.5.6) - postcss-normalize-string: 5.1.0(postcss@8.5.6) - postcss-normalize-timing-functions: 5.1.0(postcss@8.5.6) - postcss-normalize-unicode: 5.1.1(postcss@8.5.6) - postcss-normalize-url: 5.1.0(postcss@8.5.6) - postcss-normalize-whitespace: 5.1.1(postcss@8.5.6) - postcss-ordered-values: 5.1.3(postcss@8.5.6) - postcss-reduce-initial: 5.1.2(postcss@8.5.6) - postcss-reduce-transforms: 5.1.0(postcss@8.5.6) - postcss-svgo: 5.1.0(postcss@8.5.6) - postcss-unique-selectors: 5.1.1(postcss@8.5.6) - - cssnano-utils@3.1.0(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - - cssnano@5.1.15(postcss@8.5.6): - dependencies: - cssnano-preset-default: 5.2.14(postcss@8.5.6) - lilconfig: 2.1.0 - postcss: 8.5.6 - yaml: 1.10.2 - - csso@4.2.0: - dependencies: - css-tree: 1.1.3 - csso@5.0.5: dependencies: css-tree: 2.2.1 @@ -17756,11 +17990,13 @@ snapshots: deep-is@0.1.4: {} + deepmerge-ts@7.1.5: {} + deepmerge@4.3.1: {} default-browser-id@5.0.1: {} - default-browser@5.4.0: + default-browser@5.5.0: dependencies: bundle-name: 4.1.0 default-browser-id: 5.0.1 @@ -17793,6 +18029,8 @@ snapshots: delegates@1.0.0: {} + denque@2.1.0: {} + depd@1.1.2: {} depd@2.0.0: {} @@ -17803,8 +18041,6 @@ snapshots: destroy@1.2.0: {} - detect-libc@1.0.3: {} - detect-libc@2.0.2: optional: true @@ -17824,19 +18060,19 @@ snapshots: dependencies: dequal: 2.0.3 - diff@4.0.2: {} + diff@4.0.4: {} - diff@8.0.2: {} + diff@8.0.3: {} dir-compare@4.2.0: dependencies: - minimatch: 3.1.2 + minimatch: 3.1.5 p-limit: 3.1.0 - dmg-builder@26.3.1(electron-builder-squirrel-windows@26.4.0): + dmg-builder@26.8.1(electron-builder-squirrel-windows@26.4.0): dependencies: - app-builder-lib: 26.3.1(dmg-builder@26.3.1)(electron-builder-squirrel-windows@26.4.0) - builder-util: 26.3.1 + app-builder-lib: 26.8.1(dmg-builder@26.8.1)(electron-builder-squirrel-windows@26.4.0) + builder-util: 26.8.1 fs-extra: 10.1.0 iconv-lite: 0.6.3 js-yaml: 4.1.1 @@ -17850,7 +18086,7 @@ snapshots: dependencies: '@types/plist': 3.0.5 '@types/verror': 1.10.11 - ajv: 6.12.6 + ajv: 6.14.0 crc: 3.8.0 iconv-corefoundation: 1.1.7 plist: 3.1.0 @@ -17870,12 +18106,6 @@ snapshots: dom-accessibility-api@0.6.3: {} - dom-serializer@1.4.1: - dependencies: - domelementtype: 2.3.0 - domhandler: 4.3.1 - entities: 2.2.0 - dom-serializer@2.0.0: dependencies: domelementtype: 2.3.0 @@ -17884,20 +18114,10 @@ snapshots: domelementtype@2.3.0: {} - domhandler@4.3.1: - dependencies: - domelementtype: 2.3.0 - domhandler@5.0.3: dependencies: domelementtype: 2.3.0 - domutils@2.8.0: - dependencies: - dom-serializer: 1.4.1 - domelementtype: 2.3.0 - domhandler: 4.3.1 - domutils@3.2.2: dependencies: dom-serializer: 2.0.0 @@ -17919,14 +18139,18 @@ snapshots: dotenv@17.3.1: {} - drizzle-orm@0.41.0(@libsql/client@0.14.0)(@prisma/client@5.22.0)(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(pg@8.18.0): + drizzle-orm@0.41.0(@electric-sql/pglite@0.3.15)(@libsql/client@0.14.0)(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(@types/pg@8.18.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)): optionalDependencies: + '@electric-sql/pglite': 0.3.15 '@libsql/client': 0.14.0 - '@prisma/client': 5.22.0 - '@types/pg': 8.16.0 + '@prisma/client': 5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)) + '@types/pg': 8.18.0 better-sqlite3: 12.6.2 kysely: 0.28.11 - pg: 8.18.0 + mysql2: 3.15.3 + pg: 8.20.0 + postgres: 3.4.7 + prisma: 7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) dunder-proto@1.0.1: dependencies: @@ -17938,7 +18162,12 @@ snapshots: ee-first@1.1.1: {} - effect@3.19.14: + effect@3.18.4: + dependencies: + '@standard-schema/spec': 1.1.0 + fast-check: 3.23.2 + + effect@3.19.19: dependencies: '@standard-schema/spec': 1.1.0 fast-check: 3.23.2 @@ -17947,23 +18176,23 @@ snapshots: dependencies: jake: 10.9.4 - electron-builder-squirrel-windows@26.4.0(dmg-builder@26.3.1): + electron-builder-squirrel-windows@26.4.0(dmg-builder@26.8.1): dependencies: - app-builder-lib: 26.4.0(dmg-builder@26.3.1)(electron-builder-squirrel-windows@26.4.0) + app-builder-lib: 26.4.0(dmg-builder@26.8.1)(electron-builder-squirrel-windows@26.4.0) builder-util: 26.3.4 electron-winstaller: 5.4.0 transitivePeerDependencies: - dmg-builder - supports-color - electron-builder@26.3.1(electron-builder-squirrel-windows@26.4.0): + electron-builder@26.8.1(electron-builder-squirrel-windows@26.4.0): dependencies: - app-builder-lib: 26.3.1(dmg-builder@26.3.1)(electron-builder-squirrel-windows@26.4.0) - builder-util: 26.3.1 + app-builder-lib: 26.8.1(dmg-builder@26.8.1)(electron-builder-squirrel-windows@26.4.0) + builder-util: 26.8.1 builder-util-runtime: 9.5.1 chalk: 4.1.2 - ci-info: 4.3.1 - dmg-builder: 26.3.1(electron-builder-squirrel-windows@26.4.0) + ci-info: 4.4.0 + dmg-builder: 26.8.1(electron-builder-squirrel-windows@26.4.0) fs-extra: 10.1.0 lazy-val: 1.0.5 simple-update-notifier: 2.0.0 @@ -17976,10 +18205,10 @@ snapshots: dependencies: unzip-crx-3: 0.2.0 - electron-publish@26.3.1: + electron-publish@26.3.4: dependencies: '@types/fs-extra': 9.0.13 - builder-util: 26.3.1 + builder-util: 26.3.4 builder-util-runtime: 9.5.1 chalk: 4.1.2 form-data: 4.0.5 @@ -17989,10 +18218,10 @@ snapshots: transitivePeerDependencies: - supports-color - electron-publish@26.3.4: + electron-publish@26.8.1: dependencies: '@types/fs-extra': 9.0.13 - builder-util: 26.3.4 + builder-util: 26.8.1 builder-util-runtime: 9.5.1 chalk: 4.1.2 form-data: 4.0.5 @@ -18002,9 +18231,9 @@ snapshots: transitivePeerDependencies: - supports-color - electron-to-chromium@1.5.267: {} + electron-to-chromium@1.5.307: {} - electron-updater@6.7.3: + electron-updater@6.8.3: dependencies: builder-util-runtime: 9.5.1 fs-extra: 10.1.0 @@ -18012,22 +18241,22 @@ snapshots: lazy-val: 1.0.5 lodash.escaperegexp: 4.1.2 lodash.isequal: 4.5.0 - semver: 7.7.3 + semver: 7.7.4 tiny-typed-emitter: 2.1.0 transitivePeerDependencies: - supports-color - electron-vite@5.0.0(@swc/core@1.15.8(@swc/helpers@0.5.18))(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): + electron-vite@5.0.0(@swc/core@1.15.8(@swc/helpers@0.5.19))(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): dependencies: - '@babel/core': 7.28.5 - '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.5) + '@babel/core': 7.29.0 + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.29.0) cac: 6.7.14 esbuild: 0.25.12 magic-string: 0.30.21 picocolors: 1.1.1 - vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) optionalDependencies: - '@swc/core': 1.15.8(@swc/helpers@0.5.18) + '@swc/core': 1.15.8(@swc/helpers@0.5.19) transitivePeerDependencies: - supports-color @@ -18043,10 +18272,10 @@ snapshots: transitivePeerDependencies: - supports-color - electron@39.2.7: + electron@40.8.0: dependencies: '@electron/get': 2.0.3 - '@types/node': 22.19.3 + '@types/node': 24.12.0 extract-zip: 2.0.1 transitivePeerDependencies: - supports-color @@ -18057,8 +18286,6 @@ snapshots: emoji-regex@9.2.2: {} - emojis-list@3.0.0: {} - empathic@2.0.0: {} encodeurl@2.0.0: {} @@ -18071,7 +18298,7 @@ snapshots: dependencies: once: 1.4.0 - enhanced-resolve@5.18.4: + enhanced-resolve@5.20.0: dependencies: graceful-fs: 4.2.11 tapable: 2.3.0 @@ -18085,8 +18312,6 @@ snapshots: ansi-colors: 4.1.3 strip-ansi: 6.0.1 - entities@2.2.0: {} - entities@4.5.0: {} env-paths@2.2.1: {} @@ -18154,7 +18379,7 @@ snapshots: typed-array-byte-offset: 1.0.4 typed-array-length: 1.0.7 unbox-primitive: 1.1.0 - which-typed-array: 1.1.19 + which-typed-array: 1.1.20 es-define-property@1.0.1: {} @@ -18236,34 +18461,34 @@ snapshots: '@esbuild/win32-ia32': 0.25.12 '@esbuild/win32-x64': 0.25.12 - esbuild@0.27.2: + esbuild@0.27.3: optionalDependencies: - '@esbuild/aix-ppc64': 0.27.2 - '@esbuild/android-arm': 0.27.2 - '@esbuild/android-arm64': 0.27.2 - '@esbuild/android-x64': 0.27.2 - '@esbuild/darwin-arm64': 0.27.2 - '@esbuild/darwin-x64': 0.27.2 - '@esbuild/freebsd-arm64': 0.27.2 - '@esbuild/freebsd-x64': 0.27.2 - '@esbuild/linux-arm': 0.27.2 - '@esbuild/linux-arm64': 0.27.2 - '@esbuild/linux-ia32': 0.27.2 - '@esbuild/linux-loong64': 0.27.2 - '@esbuild/linux-mips64el': 0.27.2 - '@esbuild/linux-ppc64': 0.27.2 - '@esbuild/linux-riscv64': 0.27.2 - '@esbuild/linux-s390x': 0.27.2 - '@esbuild/linux-x64': 0.27.2 - '@esbuild/netbsd-arm64': 0.27.2 - '@esbuild/netbsd-x64': 0.27.2 - '@esbuild/openbsd-arm64': 0.27.2 - '@esbuild/openbsd-x64': 0.27.2 - '@esbuild/openharmony-arm64': 0.27.2 - '@esbuild/sunos-x64': 0.27.2 - '@esbuild/win32-arm64': 0.27.2 - '@esbuild/win32-ia32': 0.27.2 - '@esbuild/win32-x64': 0.27.2 + '@esbuild/aix-ppc64': 0.27.3 + '@esbuild/android-arm': 0.27.3 + '@esbuild/android-arm64': 0.27.3 + '@esbuild/android-x64': 0.27.3 + '@esbuild/darwin-arm64': 0.27.3 + '@esbuild/darwin-x64': 0.27.3 + '@esbuild/freebsd-arm64': 0.27.3 + '@esbuild/freebsd-x64': 0.27.3 + '@esbuild/linux-arm': 0.27.3 + '@esbuild/linux-arm64': 0.27.3 + '@esbuild/linux-ia32': 0.27.3 + '@esbuild/linux-loong64': 0.27.3 + '@esbuild/linux-mips64el': 0.27.3 + '@esbuild/linux-ppc64': 0.27.3 + '@esbuild/linux-riscv64': 0.27.3 + '@esbuild/linux-s390x': 0.27.3 + '@esbuild/linux-x64': 0.27.3 + '@esbuild/netbsd-arm64': 0.27.3 + '@esbuild/netbsd-x64': 0.27.3 + '@esbuild/openbsd-arm64': 0.27.3 + '@esbuild/openbsd-x64': 0.27.3 + '@esbuild/openharmony-arm64': 0.27.3 + '@esbuild/sunos-x64': 0.27.3 + '@esbuild/win32-arm64': 0.27.3 + '@esbuild/win32-ia32': 0.27.3 + '@esbuild/win32-x64': 0.27.3 escalade@3.2.0: {} @@ -18281,53 +18506,56 @@ snapshots: eslint-import-context@0.1.9(unrs-resolver@1.11.1): dependencies: - get-tsconfig: 4.13.0 + get-tsconfig: 4.13.6 stable-hash-x: 0.2.0 optionalDependencies: unrs-resolver: 1.11.1 - eslint-import-resolver-typescript@4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)): + eslint-import-resolver-typescript@4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.56.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)): dependencies: debug: 4.4.3 eslint: 9.39.2(jiti@2.6.1) eslint-import-context: 0.1.9(unrs-resolver@1.11.1) - get-tsconfig: 4.13.0 + get-tsconfig: 4.13.6 is-bun-module: 2.0.0 stable-hash-x: 0.2.0 tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.56.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)) transitivePeerDependencies: - supports-color - eslint-plugin-better-tailwindcss@3.8.0(eslint@9.39.2(jiti@2.6.1))(tailwindcss@4.1.18): + eslint-plugin-better-tailwindcss@4.3.2(eslint@9.39.2(jiti@2.6.1))(tailwindcss@4.2.1)(typescript@5.9.3): dependencies: - '@eslint/css-tree': 3.6.8 - enhanced-resolve: 5.18.4 - eslint: 9.39.2(jiti@2.6.1) + '@eslint/css-tree': 3.6.9 + '@valibot/to-json-schema': 1.5.0(valibot@1.2.0(typescript@5.9.3)) + enhanced-resolve: 5.20.0 jiti: 2.6.1 - postcss: 8.5.6 - postcss-import: 16.1.1(postcss@8.5.6) - synckit: 0.11.11 + synckit: 0.11.12 tailwind-csstree: 0.1.4 - tailwindcss: 4.1.18 + tailwindcss: 4.2.1 tsconfig-paths-webpack-plugin: 4.2.0 + valibot: 1.2.0(typescript@5.9.3) + optionalDependencies: + eslint: 9.39.2(jiti@2.6.1) + transitivePeerDependencies: + - typescript - eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.56.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)): dependencies: - '@typescript-eslint/types': 8.52.0 - comment-parser: 1.4.1 + '@typescript-eslint/types': 8.56.1 + comment-parser: 1.4.5 debug: 4.4.3 eslint: 9.39.2(jiti@2.6.1) eslint-import-context: 0.1.9(unrs-resolver@1.11.1) is-glob: 4.0.3 - minimatch: 10.1.1 - semver: 7.7.3 + minimatch: 10.2.4 + semver: 7.7.4 stable-hash-x: 0.2.0 unrs-resolver: 1.11.1 optionalDependencies: - '@typescript-eslint/utils': 8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.56.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) transitivePeerDependencies: - supports-color @@ -18345,14 +18573,14 @@ snapshots: hasown: 2.0.2 jsx-ast-utils: 3.3.5 language-tags: 1.0.9 - minimatch: 3.1.2 + minimatch: 3.1.5 object.fromentries: 2.0.8 safe-regex-test: 1.1.0 string.prototype.includes: 2.0.1 - eslint-plugin-perfectionist@5.3.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + eslint-plugin-perfectionist@5.6.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@typescript-eslint/utils': 8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.56.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) natural-orderby: 5.0.0 transitivePeerDependencies: @@ -18361,12 +18589,12 @@ snapshots: eslint-plugin-react-hooks@7.0.1(eslint@9.39.2(jiti@2.6.1)): dependencies: - '@babel/core': 7.28.5 - '@babel/parser': 7.28.5 + '@babel/core': 7.29.0 + '@babel/parser': 7.29.0 eslint: 9.39.2(jiti@2.6.1) hermes-parser: 0.25.1 - zod: 4.3.5 - zod-validation-error: 4.0.2(zod@4.3.5) + zod: 4.3.6 + zod-validation-error: 4.0.2(zod@4.3.6) transitivePeerDependencies: - supports-color @@ -18382,12 +18610,12 @@ snapshots: estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 - minimatch: 3.1.2 + minimatch: 3.1.5 object.entries: 1.1.9 object.fromentries: 2.0.8 object.values: 1.2.1 prop-types: 15.8.1 - resolve: 2.0.0-next.5 + resolve: 2.0.0-next.6 semver: 6.3.1 string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 @@ -18406,6 +18634,8 @@ snapshots: eslint-visitor-keys@4.2.1: {} + eslint-visitor-keys@5.0.1: {} + eslint@9.39.2(jiti@2.6.1): dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) @@ -18413,14 +18643,14 @@ snapshots: '@eslint/config-array': 0.21.1 '@eslint/config-helpers': 0.4.2 '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.3 + '@eslint/eslintrc': 3.3.4 '@eslint/js': 9.39.2 '@eslint/plugin-kit': 0.4.1 '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 '@types/estree': 1.0.8 - ajv: 6.12.6 + ajv: 6.14.0 chalk: 4.1.2 cross-spawn: 7.0.6 debug: 4.4.3 @@ -18439,7 +18669,7 @@ snapshots: is-glob: 4.0.3 json-stable-stringify-without-jsonify: 1.0.1 lodash.merge: 4.6.2 - minimatch: 3.1.2 + minimatch: 3.1.5 natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: @@ -18449,8 +18679,8 @@ snapshots: espree@10.4.0: dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) eslint-visitor-keys: 4.2.1 esprima@4.0.1: {} @@ -18469,8 +18699,6 @@ snapshots: estree-util-is-identifier-name@3.0.0: {} - estree-walker@0.6.1: {} - estree-walker@2.0.2: {} estree-walker@3.0.3: @@ -18485,6 +18713,12 @@ snapshots: eventemitter3@4.0.7: {} + events-universal@1.0.1: + dependencies: + bare-events: 2.8.2 + transitivePeerDependencies: + - bare-abort-controller + events@3.3.0: {} expand-template@2.0.3: {} @@ -18520,7 +18754,7 @@ snapshots: parseurl: 1.3.3 path-to-regexp: 0.1.12 proxy-addr: 2.0.7 - qs: 6.14.1 + qs: 6.14.2 range-parser: 1.2.1 safe-buffer: 5.2.1 send: 0.19.2 @@ -18558,6 +18792,8 @@ snapshots: fast-deep-equal@3.1.3: {} + fast-fifo@1.3.2: {} + fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -18570,8 +18806,18 @@ snapshots: fast-levenshtein@2.0.6: {} + fast-string-truncated-width@3.0.3: {} + + fast-string-width@3.0.2: + dependencies: + fast-string-truncated-width: 3.0.3 + fast-uri@3.1.0: {} + fast-wrap-ansi@0.2.0: + dependencies: + fast-string-width: 3.0.2 + fastq@1.20.1: dependencies: reusify: 1.1.0 @@ -18598,17 +18844,11 @@ snapshots: dependencies: flat-cache: 4.0.1 - file-loader@6.2.0(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))): - dependencies: - loader-utils: 2.0.4 - schema-utils: 3.3.0 - webpack: 5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18)) - file-uri-to-path@1.0.0: {} - filelist@1.0.4: + filelist@1.0.6: dependencies: - minimatch: 5.1.6 + minimatch: 5.1.9 fill-range@7.1.1: dependencies: @@ -18657,17 +18897,17 @@ snapshots: fix-dts-default-cjs-exports@1.0.1: dependencies: magic-string: 0.30.21 - mlly: 1.8.0 - rollup: 4.55.1 + mlly: 1.8.1 + rollup: 4.59.0 flat-cache@4.0.1: dependencies: - flatted: 3.3.3 + flatted: 3.3.4 keyv: 4.5.4 flat@5.0.2: {} - flatted@3.3.3: {} + flatted@3.3.4: {} follow-redirects@1.15.11(debug@4.4.3): optionalDependencies: @@ -18682,8 +18922,6 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - form-data-encoder@1.7.2: {} - form-data@4.0.5: dependencies: asynckit: 0.4.0 @@ -18692,11 +18930,6 @@ snapshots: hasown: 2.0.2 mime-types: 2.1.35 - formdata-node@4.4.1: - dependencies: - node-domexception: 1.0.0 - web-streams-polyfill: 4.0.0-beta.3 - formdata-polyfill@4.0.10: dependencies: fetch-blob: 3.2.0 @@ -18722,7 +18955,7 @@ snapshots: jsonfile: 6.2.0 universalify: 2.0.1 - fs-extra@11.3.3: + fs-extra@11.3.4: dependencies: graceful-fs: 4.2.11 jsonfile: 6.2.0 @@ -18753,13 +18986,10 @@ snapshots: fs-minipass@3.0.3: dependencies: - minipass: 7.1.2 + minipass: 7.1.3 fs.realpath@1.0.0: {} - fsevents@2.3.2: - optional: true - fsevents@2.3.3: optional: true @@ -18776,6 +19006,10 @@ snapshots: functions-have-names@1.2.3: {} + generate-function@2.3.1: + dependencies: + is-property: 1.0.2 + generator-function@2.0.1: {} generic-names@4.0.0: @@ -18786,7 +19020,7 @@ snapshots: get-caller-file@2.0.5: {} - get-east-asian-width@1.4.0: {} + get-east-asian-width@1.5.0: {} get-intrinsic@1.3.0: dependencies: @@ -18801,6 +19035,8 @@ snapshots: hasown: 2.0.2 math-intrinsics: 1.1.0 + get-port-please@3.2.0: {} + get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 @@ -18808,7 +19044,7 @@ snapshots: get-stream@5.2.0: dependencies: - pump: 3.0.3 + pump: 3.0.4 get-symbol-description@1.1.0: dependencies: @@ -18816,7 +19052,7 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 - get-tsconfig@4.13.0: + get-tsconfig@4.13.6: dependencies: resolve-pkg-maps: 1.0.0 @@ -18845,32 +19081,23 @@ snapshots: dependencies: foreground-child: 3.3.1 jackspeak: 3.4.3 - minimatch: 9.0.5 - minipass: 7.1.2 + minimatch: 9.0.9 + minipass: 7.1.3 package-json-from-dist: 1.0.1 path-scurry: 1.11.1 - glob@11.1.0: - dependencies: - foreground-child: 3.3.1 - jackspeak: 4.1.1 - minimatch: 10.1.1 - minipass: 7.1.2 - package-json-from-dist: 1.0.1 - path-scurry: 2.0.1 - - glob@13.0.0: + glob@13.0.6: dependencies: - minimatch: 10.1.1 - minipass: 7.1.2 - path-scurry: 2.0.1 + minimatch: 10.2.4 + minipass: 7.1.3 + path-scurry: 2.0.2 glob@7.2.3: dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 3.1.2 + minimatch: 3.1.5 once: 1.4.0 path-is-absolute: 1.0.1 @@ -18879,7 +19106,7 @@ snapshots: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 5.1.6 + minimatch: 5.1.9 once: 1.4.0 global-agent@3.0.0: @@ -18908,7 +19135,7 @@ snapshots: globals@14.0.0: {} - globals@17.0.0: {} + globals@17.4.0: {} globalthis@1.0.4: dependencies: @@ -18924,7 +19151,7 @@ snapshots: slash: 5.1.0 unicorn-magic: 0.3.0 - globby@16.0.0: + globby@16.1.1: dependencies: '@sindresorhus/merge-streams': 4.0.0 fast-glob: 3.3.3 @@ -18957,6 +19184,10 @@ snapshots: graceful-fs@4.2.11: {} + grammex@3.1.12: {} + + graphmatch@1.1.1: {} + has-bigints@1.1.0: {} has-flag@4.0.0: {} @@ -19019,6 +19250,8 @@ snapshots: dependencies: parse-passwd: 1.0.0 + hono@4.11.4: {} + hosted-git-info@4.1.0: dependencies: lru-cache: 6.0.0 @@ -19029,7 +19262,7 @@ snapshots: hosted-git-info@9.0.2: dependencies: - lru-cache: 11.2.4 + lru-cache: 11.2.6 html-encoding-sniffer@3.0.0: dependencies: @@ -19107,6 +19340,8 @@ snapshots: - debug - supports-color + http-status-codes@2.3.0: {} + http2-wrapper@1.0.3: dependencies: quick-lru: 5.1.1 @@ -19119,10 +19354,6 @@ snapshots: transitivePeerDependencies: - supports-color - humanize-ms@1.2.1: - dependencies: - ms: 2.1.3 - iconv-corefoundation@1.1.7: dependencies: cli-truncate: 2.1.0 @@ -19137,15 +19368,13 @@ snapshots: dependencies: safer-buffer: 2.1.2 - iconv-lite@0.7.1: + iconv-lite@0.7.2: dependencies: safer-buffer: 2.1.2 - icss-replace-symbols@1.1.0: {} - - icss-utils@5.1.0(postcss@8.5.6): + icss-utils@5.1.0(postcss@8.5.8): dependencies: - postcss: 8.5.6 + postcss: 8.5.8 id128@1.6.6: {} @@ -19157,19 +19386,11 @@ snapshots: immediate@3.0.6: {} - import-cwd@3.0.0: - dependencies: - import-from: 3.0.0 - import-fresh@3.3.1: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 - import-from@3.0.0: - dependencies: - resolve-from: 5.0.0 - imurmurhash@0.1.4: {} indent-string@4.0.0: {} @@ -19244,7 +19465,7 @@ snapshots: is-bun-module@2.0.0: dependencies: - semver: 7.7.3 + semver: 7.7.4 is-callable@1.2.7: {} @@ -19318,6 +19539,8 @@ snapshots: is-plain-object@5.0.0: {} + is-property@1.0.2: {} + is-reference@1.2.1: dependencies: '@types/estree': 1.0.8 @@ -19335,6 +19558,8 @@ snapshots: dependencies: call-bound: 1.0.4 + is-stream@2.0.1: {} + is-string@1.1.1: dependencies: call-bound: 1.0.4 @@ -19348,7 +19573,7 @@ snapshots: is-typed-array@1.1.15: dependencies: - which-typed-array: 1.1.19 + which-typed-array: 1.1.20 is-unicode-supported@0.1.0: {} @@ -19373,7 +19598,7 @@ snapshots: dependencies: is-docker: 2.2.1 - is-wsl@3.1.0: + is-wsl@3.1.1: dependencies: is-inside-container: 1.0.0 @@ -19385,11 +19610,11 @@ snapshots: isbinaryfile@5.0.7: {} - isbot@5.1.32: {} + isbot@5.1.35: {} isexe@2.0.0: {} - isexe@3.1.1: {} + isexe@3.1.5: {} isomorphic-ws@5.0.0(ws@8.18.0): dependencies: @@ -19410,18 +19635,10 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 - jackspeak@4.1.1: - dependencies: - '@isaacs/cliui': 8.0.2 - - jackspeak@4.2.3: - dependencies: - '@isaacs/cliui': 9.0.0 - jake@10.9.4: dependencies: async: 3.2.6 - filelist: 1.0.4 + filelist: 1.0.6 picocolors: 1.1.1 jest-diff@30.2.0: @@ -19433,7 +19650,7 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 25.0.3 + '@types/node': 25.3.5 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -19441,7 +19658,7 @@ snapshots: jiti@2.6.1: {} - jose@6.1.3: {} + jose@6.2.0: {} joycon@3.1.1: {} @@ -19474,6 +19691,8 @@ snapshots: json-stringify-safe@5.0.1: optional: true + json-with-bigint@3.5.7: {} + json5@2.2.3: {} jsonc-parser@3.2.0: {} @@ -19516,8 +19735,6 @@ snapshots: kleur@3.0.3: {} - kleur@4.1.5: {} - koa-compose@4.1.0: {} koa@3.0.3: @@ -19553,6 +19770,10 @@ snapshots: lazy-val@1.0.5: {} + lazystream@1.0.1: + dependencies: + readable-stream: 2.3.8 + levn@0.4.1: dependencies: prelude-ls: 1.2.1 @@ -19576,54 +19797,54 @@ snapshots: dependencies: immediate: 3.0.6 - lightningcss-android-arm64@1.30.2: + lightningcss-android-arm64@1.31.1: optional: true - lightningcss-darwin-arm64@1.30.2: + lightningcss-darwin-arm64@1.31.1: optional: true - lightningcss-darwin-x64@1.30.2: + lightningcss-darwin-x64@1.31.1: optional: true - lightningcss-freebsd-x64@1.30.2: + lightningcss-freebsd-x64@1.31.1: optional: true - lightningcss-linux-arm-gnueabihf@1.30.2: + lightningcss-linux-arm-gnueabihf@1.31.1: optional: true - lightningcss-linux-arm64-gnu@1.30.2: + lightningcss-linux-arm64-gnu@1.31.1: optional: true - lightningcss-linux-arm64-musl@1.30.2: + lightningcss-linux-arm64-musl@1.31.1: optional: true - lightningcss-linux-x64-gnu@1.30.2: + lightningcss-linux-x64-gnu@1.31.1: optional: true - lightningcss-linux-x64-musl@1.30.2: + lightningcss-linux-x64-musl@1.31.1: optional: true - lightningcss-win32-arm64-msvc@1.30.2: + lightningcss-win32-arm64-msvc@1.31.1: optional: true - lightningcss-win32-x64-msvc@1.30.2: + lightningcss-win32-x64-msvc@1.31.1: optional: true - lightningcss@1.30.2: + lightningcss@1.31.1: dependencies: detect-libc: 2.1.2 optionalDependencies: - lightningcss-android-arm64: 1.30.2 - lightningcss-darwin-arm64: 1.30.2 - lightningcss-darwin-x64: 1.30.2 - lightningcss-freebsd-x64: 1.30.2 - lightningcss-linux-arm-gnueabihf: 1.30.2 - lightningcss-linux-arm64-gnu: 1.30.2 - lightningcss-linux-arm64-musl: 1.30.2 - lightningcss-linux-x64-gnu: 1.30.2 - lightningcss-linux-x64-musl: 1.30.2 - lightningcss-win32-arm64-msvc: 1.30.2 - lightningcss-win32-x64-msvc: 1.30.2 + lightningcss-android-arm64: 1.31.1 + lightningcss-darwin-arm64: 1.31.1 + lightningcss-darwin-x64: 1.31.1 + lightningcss-freebsd-x64: 1.31.1 + lightningcss-linux-arm-gnueabihf: 1.31.1 + lightningcss-linux-arm64-gnu: 1.31.1 + lightningcss-linux-arm64-musl: 1.31.1 + lightningcss-linux-x64-gnu: 1.31.1 + lightningcss-linux-x64-musl: 1.31.1 + lightningcss-win32-arm64-msvc: 1.31.1 + lightningcss-win32-x64-msvc: 1.31.1 lilconfig@2.1.0: {} @@ -19633,20 +19854,14 @@ snapshots: lines-and-columns@2.0.3: {} - little-state-machine@4.8.1(react@19.2.3): + little-state-machine@4.8.1(react@19.2.4): dependencies: - react: 19.2.3 + react: 19.2.4 load-tsconfig@0.2.5: {} loader-runner@4.3.1: {} - loader-utils@2.0.4: - dependencies: - big.js: 5.2.2 - emojis-list: 3.0.0 - json5: 2.2.3 - loader-utils@3.3.1: {} locate-path@5.0.0: @@ -19667,12 +19882,8 @@ snapshots: lodash.isequal@4.5.0: {} - lodash.memoize@4.1.2: {} - lodash.merge@4.6.2: {} - lodash.uniq@4.5.0: {} - lodash@4.17.21: {} lodash@4.17.23: {} @@ -19691,7 +19902,7 @@ snapshots: dependencies: date-format: 4.0.14 debug: 4.4.3 - flatted: 3.3.3 + flatted: 3.3.4 rfdc: 1.4.1 streamroller: 3.1.5 transitivePeerDependencies: @@ -19699,6 +19910,8 @@ snapshots: long-timeout@0.1.1: {} + long@5.3.2: {} + longest-streak@3.1.0: {} loose-envify@1.4.0: @@ -19715,7 +19928,7 @@ snapshots: lru-cache@10.4.3: {} - lru-cache@11.2.4: {} + lru-cache@11.2.6: {} lru-cache@5.1.1: dependencies: @@ -19725,6 +19938,8 @@ snapshots: dependencies: yallist: 4.0.0 + lru.min@1.1.4: {} + luxon@3.7.2: {} lz-string@1.5.0: {} @@ -19744,7 +19959,7 @@ snapshots: '@npmcli/agent': 3.0.0 cacache: 19.0.1 http-cache-semantics: 4.2.0 - minipass: 7.1.2 + minipass: 7.1.3 minipass-fetch: 4.0.1 minipass-flush: 1.0.5 minipass-pipeline: 1.2.4 @@ -19760,14 +19975,14 @@ snapshots: '@npmcli/agent': 4.0.0 cacache: 20.0.3 http-cache-semantics: 4.2.0 - minipass: 7.1.2 - minipass-fetch: 5.0.0 + minipass: 7.1.3 + minipass-fetch: 5.0.2 minipass-flush: 1.0.5 minipass-pipeline: 1.2.4 negotiator: 1.0.0 proc-log: 6.1.0 promise-retry: 2.0.1 - ssri: 13.0.0 + ssri: 13.0.1 transitivePeerDependencies: - supports-color @@ -19789,7 +20004,7 @@ snapshots: unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 - mdast-util-from-markdown@2.0.2: + mdast-util-from-markdown@2.0.3: dependencies: '@types/mdast': 4.0.4 '@types/unist': 3.0.3 @@ -19818,7 +20033,7 @@ snapshots: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 micromark-util-normalize-identifier: 2.0.1 transitivePeerDependencies: @@ -19827,7 +20042,7 @@ snapshots: mdast-util-gfm-strikethrough@2.0.0: dependencies: '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -19837,7 +20052,7 @@ snapshots: '@types/mdast': 4.0.4 devlop: 1.1.0 markdown-table: 3.0.4 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -19846,14 +20061,14 @@ snapshots: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color mdast-util-gfm@3.1.0: dependencies: - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-gfm-autolink-literal: 2.0.1 mdast-util-gfm-footnote: 2.1.0 mdast-util-gfm-strikethrough: 2.0.0 @@ -19869,7 +20084,7 @@ snapshots: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -19882,7 +20097,7 @@ snapshots: '@types/unist': 3.0.3 ccount: 2.0.1 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 parse-entities: 4.0.2 stringify-entities: 4.0.4 @@ -19897,7 +20112,7 @@ snapshots: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -19935,8 +20150,6 @@ snapshots: dependencies: '@types/mdast': 4.0.4 - mdn-data@2.0.14: {} - mdn-data@2.0.28: {} mdn-data@2.0.30: {} @@ -19947,6 +20160,8 @@ snapshots: media-typer@1.1.0: {} + memory-pager@1.5.0: {} + merge-descriptors@1.0.3: {} merge-stream@2.0.0: {} @@ -20181,27 +20396,23 @@ snapshots: mini-svg-data-uri@1.4.4: {} - minimatch@10.1.1: - dependencies: - '@isaacs/brace-expansion': 5.0.0 - - minimatch@10.2.1: + minimatch@10.2.4: dependencies: - brace-expansion: 5.0.2 + brace-expansion: 5.0.4 - minimatch@3.1.2: + minimatch@3.1.5: dependencies: brace-expansion: 1.1.12 - minimatch@5.1.6: + minimatch@5.1.9: dependencies: brace-expansion: 2.0.2 - minimatch@9.0.3: + minimatch@9.0.5: dependencies: brace-expansion: 2.0.2 - minimatch@9.0.5: + minimatch@9.0.9: dependencies: brace-expansion: 2.0.2 @@ -20209,23 +20420,23 @@ snapshots: minipass-collect@2.0.1: dependencies: - minipass: 7.1.2 + minipass: 7.1.3 minipass-fetch@4.0.1: dependencies: - minipass: 7.1.2 + minipass: 7.1.3 minipass-sized: 1.0.3 minizlib: 3.1.0 optionalDependencies: encoding: 0.1.13 - minipass-fetch@5.0.0: + minipass-fetch@5.0.2: dependencies: - minipass: 7.1.2 - minipass-sized: 1.0.3 + minipass: 7.1.3 + minipass-sized: 2.0.0 minizlib: 3.1.0 optionalDependencies: - encoding: 0.1.13 + iconv-lite: 0.7.2 minipass-flush@1.0.5: dependencies: @@ -20239,13 +20450,17 @@ snapshots: dependencies: minipass: 3.3.6 + minipass-sized@2.0.0: + dependencies: + minipass: 7.1.3 + minipass@3.3.6: dependencies: yallist: 4.0.0 minipass@5.0.0: {} - minipass@7.1.2: {} + minipass@7.1.3: {} minizlib@2.1.2: dependencies: @@ -20254,7 +20469,7 @@ snapshots: minizlib@3.1.0: dependencies: - minipass: 7.1.2 + minipass: 7.1.3 mkdirp-classic@0.5.3: {} @@ -20264,14 +20479,25 @@ snapshots: mkdirp@1.0.4: {} - mlly@1.8.0: + mlly@1.8.1: dependencies: - acorn: 8.15.0 + acorn: 8.16.0 pathe: 2.0.3 pkg-types: 1.3.1 - ufo: 1.6.2 + ufo: 1.6.3 - mri@1.2.0: {} + mongodb-connection-string-url@7.0.1: + dependencies: + '@types/whatwg-url': 13.0.0 + whatwg-url: 14.2.0 + + mongodb@7.1.0(socks@2.8.7): + dependencies: + '@mongodb-js/saslprep': 1.4.6 + bson: 7.2.0 + mongodb-connection-string-url: 7.0.1 + optionalDependencies: + socks: 2.8.7 ms@2.0.0: {} @@ -20299,15 +20525,31 @@ snapshots: mute-stream@3.0.0: {} + mysql2@3.15.3: + dependencies: + aws-ssl-profiles: 1.1.2 + denque: 2.1.0 + generate-function: 2.3.1 + iconv-lite: 0.7.2 + long: 5.3.2 + lru.min: 1.1.4 + named-placeholders: 1.1.6 + seq-queue: 0.0.5 + sqlstring: 2.3.3 + mz@2.7.0: dependencies: any-promise: 1.3.0 object-assign: 4.1.1 thenify-all: 1.6.0 + named-placeholders@1.1.6: + dependencies: + lru.min: 1.1.4 + nanoid@3.3.11: {} - nanostores@1.1.0: {} + nanostores@1.1.1: {} napi-build-utils@2.0.0: {} @@ -20332,9 +20574,9 @@ snapshots: dependencies: semver: 7.7.4 - node-abi@4.24.0: + node-abi@4.26.0: dependencies: - semver: 7.7.3 + semver: 7.7.4 node-addon-api@1.7.2: optional: true @@ -20343,9 +20585,17 @@ snapshots: node-api-version@0.2.1: dependencies: - semver: 7.7.3 + semver: 7.7.4 - node-domexception@1.0.0: {} + node-domexception@1.0.0: + optional: true + + node-exports-info@1.6.0: + dependencies: + array.prototype.flatmap: 1.3.3 + es-errors: 1.3.0 + object.entries: 1.1.9 + semver: 6.3.1 node-fetch-native@1.6.7: {} @@ -20377,8 +20627,8 @@ snapshots: make-fetch-happen: 14.0.3 nopt: 8.1.0 proc-log: 5.0.0 - semver: 7.7.3 - tar: 7.5.2 + semver: 7.7.4 + tar: 7.5.10 tinyglobby: 0.2.15 which: 5.0.0 transitivePeerDependencies: @@ -20386,7 +20636,7 @@ snapshots: node-machine-id@1.1.12: {} - node-releases@2.0.27: {} + node-releases@2.0.36: {} node-schedule@2.1.1: dependencies: @@ -20406,7 +20656,7 @@ snapshots: dependencies: hosted-git-info: 8.1.0 proc-log: 5.0.0 - semver: 7.7.3 + semver: 7.7.4 validate-npm-package-name: 6.0.2 npm-package-arg@13.0.2: @@ -20421,8 +20671,8 @@ snapshots: '@npmcli/redact': 4.0.0 jsonparse: 1.3.1 make-fetch-happen: 15.0.3 - minipass: 7.1.2 - minipass-fetch: 5.0.0 + minipass: 7.1.3 + minipass-fetch: 5.0.2 minizlib: 3.1.0 npm-package-arg: 13.0.2 proc-log: 6.1.0 @@ -20437,19 +20687,19 @@ snapshots: dependencies: boolbase: 1.0.0 - nx@22.3.3(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.18)): + nx@22.5.4(@swc-node/register@1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3))(@swc/core@1.15.8(@swc/helpers@0.5.19)): dependencies: '@napi-rs/wasm-runtime': 0.2.4 '@yarnpkg/lockfile': 1.1.0 '@yarnpkg/parsers': 3.0.2 '@zkochan/js-yaml': 0.0.7 - axios: 1.13.2 - chalk: 4.1.2 + axios: 1.13.6 cli-cursor: 3.1.0 cli-spinners: 2.6.1 cliui: 8.0.1 dotenv: 16.4.7 dotenv-expand: 11.0.7 + ejs: 3.1.10 enquirer: 2.3.6 figures: 3.2.0 flat: 5.0.2 @@ -20458,11 +20708,12 @@ snapshots: jest-diff: 30.2.0 jsonc-parser: 3.2.0 lines-and-columns: 2.0.3 - minimatch: 9.0.3 + minimatch: 10.2.4 node-machine-id: 1.1.12 npm-run-path: 4.0.1 open: 8.4.2 ora: 5.3.0 + picocolors: 1.1.1 resolve.exports: 2.0.3 semver: 7.7.4 string-width: 4.2.3 @@ -20475,18 +20726,18 @@ snapshots: yargs: 17.7.2 yargs-parser: 21.1.1 optionalDependencies: - '@nx/nx-darwin-arm64': 22.3.3 - '@nx/nx-darwin-x64': 22.3.3 - '@nx/nx-freebsd-x64': 22.3.3 - '@nx/nx-linux-arm-gnueabihf': 22.3.3 - '@nx/nx-linux-arm64-gnu': 22.3.3 - '@nx/nx-linux-arm64-musl': 22.3.3 - '@nx/nx-linux-x64-gnu': 22.3.3 - '@nx/nx-linux-x64-musl': 22.3.3 - '@nx/nx-win32-arm64-msvc': 22.3.3 - '@nx/nx-win32-x64-msvc': 22.3.3 - '@swc-node/register': 1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3) - '@swc/core': 1.15.8(@swc/helpers@0.5.18) + '@nx/nx-darwin-arm64': 22.5.4 + '@nx/nx-darwin-x64': 22.5.4 + '@nx/nx-freebsd-x64': 22.5.4 + '@nx/nx-linux-arm-gnueabihf': 22.5.4 + '@nx/nx-linux-arm64-gnu': 22.5.4 + '@nx/nx-linux-arm64-musl': 22.5.4 + '@nx/nx-linux-x64-gnu': 22.5.4 + '@nx/nx-linux-x64-musl': 22.5.4 + '@nx/nx-win32-arm64-msvc': 22.5.4 + '@nx/nx-win32-x64-msvc': 22.5.4 + '@swc-node/register': 1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3) + '@swc/core': 1.15.8(@swc/helpers@0.5.19) transitivePeerDependencies: - debug @@ -20554,7 +20805,7 @@ snapshots: open@10.2.0: dependencies: - default-browser: 5.4.0 + default-browser: 5.5.0 define-lazy-prop: 3.0.0 is-inside-container: 1.0.0 wsl-utils: 0.1.0 @@ -20565,19 +20816,10 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 - openai@4.77.0(encoding@0.1.13)(zod@3.25.76): - dependencies: - '@types/node': 18.19.130 - '@types/node-fetch': 2.6.13 - abort-controller: 3.0.0 - agentkeepalive: 4.6.0 - form-data-encoder: 1.7.2 - formdata-node: 4.4.1 - node-fetch: 2.7.0(encoding@0.1.13) + openai@6.27.0(ws@8.19.0)(zod@4.3.6): optionalDependencies: - zod: 3.25.76 - transitivePeerDependencies: - - encoding + ws: 8.19.0 + zod: 4.3.6 opener@1.5.2: {} @@ -20595,7 +20837,7 @@ snapshots: bl: 4.1.0 chalk: 4.1.2 cli-cursor: 3.1.0 - cli-spinners: 2.9.2 + cli-spinners: 2.6.1 is-interactive: 1.0.0 log-symbols: 4.1.0 strip-ansi: 6.0.1 @@ -20623,7 +20865,7 @@ snapshots: log-symbols: 6.0.0 stdin-discarder: 0.2.2 string-width: 7.2.0 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 own-keys@1.0.1: dependencies: @@ -20631,33 +20873,31 @@ snapshots: object-keys: 1.1.1 safe-push-apply: 1.0.0 - oxc-resolver@11.16.2: + oxc-resolver@11.19.1: optionalDependencies: - '@oxc-resolver/binding-android-arm-eabi': 11.16.2 - '@oxc-resolver/binding-android-arm64': 11.16.2 - '@oxc-resolver/binding-darwin-arm64': 11.16.2 - '@oxc-resolver/binding-darwin-x64': 11.16.2 - '@oxc-resolver/binding-freebsd-x64': 11.16.2 - '@oxc-resolver/binding-linux-arm-gnueabihf': 11.16.2 - '@oxc-resolver/binding-linux-arm-musleabihf': 11.16.2 - '@oxc-resolver/binding-linux-arm64-gnu': 11.16.2 - '@oxc-resolver/binding-linux-arm64-musl': 11.16.2 - '@oxc-resolver/binding-linux-ppc64-gnu': 11.16.2 - '@oxc-resolver/binding-linux-riscv64-gnu': 11.16.2 - '@oxc-resolver/binding-linux-riscv64-musl': 11.16.2 - '@oxc-resolver/binding-linux-s390x-gnu': 11.16.2 - '@oxc-resolver/binding-linux-x64-gnu': 11.16.2 - '@oxc-resolver/binding-linux-x64-musl': 11.16.2 - '@oxc-resolver/binding-openharmony-arm64': 11.16.2 - '@oxc-resolver/binding-wasm32-wasi': 11.16.2 - '@oxc-resolver/binding-win32-arm64-msvc': 11.16.2 - '@oxc-resolver/binding-win32-ia32-msvc': 11.16.2 - '@oxc-resolver/binding-win32-x64-msvc': 11.16.2 + '@oxc-resolver/binding-android-arm-eabi': 11.19.1 + '@oxc-resolver/binding-android-arm64': 11.19.1 + '@oxc-resolver/binding-darwin-arm64': 11.19.1 + '@oxc-resolver/binding-darwin-x64': 11.19.1 + '@oxc-resolver/binding-freebsd-x64': 11.19.1 + '@oxc-resolver/binding-linux-arm-gnueabihf': 11.19.1 + '@oxc-resolver/binding-linux-arm-musleabihf': 11.19.1 + '@oxc-resolver/binding-linux-arm64-gnu': 11.19.1 + '@oxc-resolver/binding-linux-arm64-musl': 11.19.1 + '@oxc-resolver/binding-linux-ppc64-gnu': 11.19.1 + '@oxc-resolver/binding-linux-riscv64-gnu': 11.19.1 + '@oxc-resolver/binding-linux-riscv64-musl': 11.19.1 + '@oxc-resolver/binding-linux-s390x-gnu': 11.19.1 + '@oxc-resolver/binding-linux-x64-gnu': 11.19.1 + '@oxc-resolver/binding-linux-x64-musl': 11.19.1 + '@oxc-resolver/binding-openharmony-arm64': 11.19.1 + '@oxc-resolver/binding-wasm32-wasi': 11.19.1 + '@oxc-resolver/binding-win32-arm64-msvc': 11.19.1 + '@oxc-resolver/binding-win32-ia32-msvc': 11.19.1 + '@oxc-resolver/binding-win32-x64-msvc': 11.19.1 p-cancelable@2.1.1: {} - p-finally@1.0.0: {} - p-limit@2.3.0: dependencies: p-try: 2.2.0 @@ -20676,15 +20916,6 @@ snapshots: p-map@7.0.4: {} - p-queue@6.6.2: - dependencies: - eventemitter3: 4.0.7 - p-timeout: 3.2.0 - - p-timeout@3.2.0: - dependencies: - p-finally: 1.0.0 - p-try@2.2.0: {} package-json-from-dist@1.0.1: {} @@ -20707,7 +20938,7 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.27.1 + '@babel/code-frame': 7.29.0 error-ex: 1.3.4 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -20727,12 +20958,12 @@ snapshots: path-scurry@1.11.1: dependencies: lru-cache: 10.4.3 - minipass: 7.1.2 + minipass: 7.1.3 - path-scurry@2.0.1: + path-scurry@2.0.2: dependencies: - lru-cache: 11.2.4 - minipass: 7.1.2 + lru-cache: 11.2.6 + minipass: 7.1.3 path-to-regexp@0.1.12: {} @@ -20748,20 +20979,22 @@ snapshots: pend@1.2.0: {} + perfect-debounce@1.0.0: {} + perfect-debounce@2.1.0: {} pg-cloudflare@1.3.0: optional: true - pg-connection-string@2.11.0: {} + pg-connection-string@2.12.0: {} pg-int8@1.0.1: {} - pg-pool@3.11.0(pg@8.18.0): + pg-pool@3.13.0(pg@8.20.0): dependencies: - pg: 8.18.0 + pg: 8.20.0 - pg-protocol@1.11.0: {} + pg-protocol@1.13.0: {} pg-types@2.2.0: dependencies: @@ -20771,11 +21004,11 @@ snapshots: postgres-date: 1.0.7 postgres-interval: 1.2.0 - pg@8.18.0: + pg@8.20.0: dependencies: - pg-connection-string: 2.11.0 - pg-pool: 3.11.0(pg@8.18.0) - pg-protocol: 1.11.0 + pg-connection-string: 2.12.0 + pg-pool: 3.13.0(pg@8.20.0) + pg-protocol: 1.13.0 pg-types: 2.2.0 pgpass: 1.0.5 optionalDependencies: @@ -20793,10 +21026,6 @@ snapshots: picomatch@4.0.3: {} - pify@2.3.0: {} - - pify@5.0.0: {} - pirates@4.0.7: {} pkg-dir@4.2.0: @@ -20806,7 +21035,7 @@ snapshots: pkg-types@1.3.1: dependencies: confbox: 0.1.8 - mlly: 1.8.0 + mlly: 1.8.1 pathe: 2.0.3 pkg-types@2.3.0: @@ -20815,14 +21044,6 @@ snapshots: exsolve: 1.0.8 pathe: 2.0.3 - playwright-core@1.57.0: {} - - playwright@1.57.0: - dependencies: - playwright-core: 1.57.0 - optionalDependencies: - fsevents: 2.3.2 - plist@3.1.0: dependencies: '@xmldom/xmldom': 0.8.11 @@ -20838,200 +21059,48 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss-calc@8.2.4(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-selector-parser: 6.0.10 - postcss-value-parser: 4.2.0 - - postcss-colormin@5.3.1(postcss@8.5.6): - dependencies: - browserslist: 4.28.1 - caniuse-api: 3.0.0 - colord: 2.9.3 - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - - postcss-convert-values@5.1.3(postcss@8.5.6): - dependencies: - browserslist: 4.28.1 - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - - postcss-discard-comments@5.1.2(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - - postcss-discard-duplicates@5.1.0(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - - postcss-discard-empty@5.1.1(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - - postcss-discard-overridden@5.1.0(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - - postcss-import@16.1.1(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - read-cache: 1.0.0 - resolve: 1.22.11 - - postcss-load-config@3.1.4(postcss@8.5.6)(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)): - dependencies: - lilconfig: 2.1.0 - yaml: 1.10.2 - optionalDependencies: - postcss: 8.5.6 - ts-node: 10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3) - - postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.2): + postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(yaml@2.8.2): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 2.6.1 - postcss: 8.5.6 + postcss: 8.5.8 tsx: 4.21.0 yaml: 2.8.2 - postcss-merge-longhand@5.1.7(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - stylehacks: 5.1.1(postcss@8.5.6) - - postcss-merge-rules@5.1.4(postcss@8.5.6): - dependencies: - browserslist: 4.28.1 - caniuse-api: 3.0.0 - cssnano-utils: 3.1.0(postcss@8.5.6) - postcss: 8.5.6 - postcss-selector-parser: 6.0.10 - - postcss-minify-font-values@5.1.0(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - - postcss-minify-gradients@5.1.1(postcss@8.5.6): + postcss-modules-extract-imports@3.1.0(postcss@8.5.8): dependencies: - colord: 2.9.3 - cssnano-utils: 3.1.0(postcss@8.5.6) - postcss: 8.5.6 - postcss-value-parser: 4.2.0 + postcss: 8.5.8 - postcss-minify-params@5.1.4(postcss@8.5.6): + postcss-modules-local-by-default@4.2.0(postcss@8.5.8): dependencies: - browserslist: 4.28.1 - cssnano-utils: 3.1.0(postcss@8.5.6) - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - - postcss-minify-selectors@5.2.1(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-selector-parser: 6.0.10 - - postcss-modules-extract-imports@3.1.0(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - - postcss-modules-local-by-default@4.2.0(postcss@8.5.6): - dependencies: - icss-utils: 5.1.0(postcss@8.5.6) - postcss: 8.5.6 + icss-utils: 5.1.0(postcss@8.5.8) + postcss: 8.5.8 postcss-selector-parser: 7.1.1 postcss-value-parser: 4.2.0 - postcss-modules-scope@3.2.1(postcss@8.5.6): + postcss-modules-scope@3.2.1(postcss@8.5.8): dependencies: - postcss: 8.5.6 + postcss: 8.5.8 postcss-selector-parser: 7.1.1 - postcss-modules-values@4.0.0(postcss@8.5.6): + postcss-modules-values@4.0.0(postcss@8.5.8): dependencies: - icss-utils: 5.1.0(postcss@8.5.6) - postcss: 8.5.6 + icss-utils: 5.1.0(postcss@8.5.8) + postcss: 8.5.8 - postcss-modules@4.3.1(postcss@8.5.6): + postcss-modules@6.0.1(postcss@8.5.8): dependencies: generic-names: 4.0.0 - icss-replace-symbols: 1.1.0 + icss-utils: 5.1.0(postcss@8.5.8) lodash.camelcase: 4.3.0 - postcss: 8.5.6 - postcss-modules-extract-imports: 3.1.0(postcss@8.5.6) - postcss-modules-local-by-default: 4.2.0(postcss@8.5.6) - postcss-modules-scope: 3.2.1(postcss@8.5.6) - postcss-modules-values: 4.0.0(postcss@8.5.6) + postcss: 8.5.8 + postcss-modules-extract-imports: 3.1.0(postcss@8.5.8) + postcss-modules-local-by-default: 4.2.0(postcss@8.5.8) + postcss-modules-scope: 3.2.1(postcss@8.5.8) + postcss-modules-values: 4.0.0(postcss@8.5.8) string-hash: 1.1.3 - postcss-normalize-charset@5.1.0(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - - postcss-normalize-display-values@5.1.0(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - - postcss-normalize-positions@5.1.1(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - - postcss-normalize-repeat-style@5.1.1(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - - postcss-normalize-string@5.1.0(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - - postcss-normalize-timing-functions@5.1.0(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - - postcss-normalize-unicode@5.1.1(postcss@8.5.6): - dependencies: - browserslist: 4.28.1 - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - - postcss-normalize-url@5.1.0(postcss@8.5.6): - dependencies: - normalize-url: 6.1.0 - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - - postcss-normalize-whitespace@5.1.1(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - - postcss-ordered-values@5.1.3(postcss@8.5.6): - dependencies: - cssnano-utils: 3.1.0(postcss@8.5.6) - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - - postcss-reduce-initial@5.1.2(postcss@8.5.6): - dependencies: - browserslist: 4.28.1 - caniuse-api: 3.0.0 - postcss: 8.5.6 - - postcss-reduce-transforms@5.1.0(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - postcss-selector-parser@6.0.10: dependencies: cssesc: 3.0.0 @@ -21042,20 +21111,9 @@ snapshots: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-svgo@5.1.0(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - svgo: 2.8.0 - - postcss-unique-selectors@5.1.1(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-selector-parser: 6.0.10 - postcss-value-parser@4.2.0: {} - postcss@8.5.6: + postcss@8.5.8: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 @@ -21071,12 +21129,14 @@ snapshots: dependencies: xtend: 4.0.2 + postgres@3.4.7: {} + postject@1.0.0-alpha.6: dependencies: commander: 9.5.0 optional: true - preact@10.28.2: {} + preact@10.28.4: {} prebuild-install@7.1.3: dependencies: @@ -21087,7 +21147,7 @@ snapshots: mkdirp-classic: 0.5.3 napi-build-utils: 2.0.0 node-abi: 3.87.0 - pump: 3.0.3 + pump: 3.0.4 rc: 1.2.8 simple-get: 4.0.1 tar-fs: 2.1.4 @@ -21095,10 +21155,6 @@ snapshots: prelude-ls@1.2.1: {} - prettier@3.6.2: {} - - prettier@3.7.4: {} - prettier@3.8.1: {} pretty-format@27.5.1: @@ -21113,12 +21169,31 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 + prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3): + dependencies: + '@prisma/config': 7.4.2 + '@prisma/dev': 0.20.0(typescript@5.9.3) + '@prisma/engines': 7.4.2 + '@prisma/studio-core': 0.13.1(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + mysql2: 3.15.3 + postgres: 3.4.7 + optionalDependencies: + better-sqlite3: 12.6.2 + typescript: 5.9.3 + transitivePeerDependencies: + - '@types/react' + - magicast + - react + - react-dom + proc-log@5.0.0: {} proc-log@6.1.0: {} process-nextick-args@2.0.1: {} + process@0.11.10: {} + progress@2.0.3: {} promise-limit@2.7.0: @@ -21129,8 +21204,6 @@ snapshots: err-code: 2.0.3 retry: 0.12.0 - promise.series@0.2.0: {} - prompts@2.4.2: dependencies: kleur: 3.0.3 @@ -21142,6 +21215,12 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 + proper-lockfile@4.1.2: + dependencies: + graceful-fs: 4.2.11 + retry: 0.12.0 + signal-exit: 3.0.7 + property-information@7.1.0: {} proxy-addr@2.0.7: @@ -21151,7 +21230,7 @@ snapshots: proxy-from-env@1.1.0: {} - pump@3.0.3: + pump@3.0.4: dependencies: end-of-stream: 1.4.5 once: 1.4.0 @@ -21160,7 +21239,11 @@ snapshots: pure-rand@6.1.0: {} - qs@6.14.1: + qs@6.14.2: + dependencies: + side-channel: 1.1.0 + + qs@6.15.0: dependencies: side-channel: 1.1.0 @@ -21170,10 +21253,6 @@ snapshots: rambda@9.4.2: {} - randombytes@2.1.0: - dependencies: - safe-buffer: 5.2.1 - range-parser@1.2.1: {} raw-body@2.5.3: @@ -21195,86 +21274,86 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-aria-components@1.14.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + react-aria-components@1.16.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: - '@internationalized/date': 3.10.1 + '@internationalized/date': 3.12.0 '@internationalized/string': 3.2.7 - '@react-aria/autocomplete': 3.0.0-rc.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/collections': 3.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/dnd': 3.11.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/focus': 3.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/autocomplete': 3.0.0-rc.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/collections': 3.0.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/dnd': 3.11.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/focus': 3.21.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@react-aria/live-announcer': 3.4.4 - '@react-aria/overlays': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/ssr': 3.9.10(react@19.2.3) - '@react-aria/textfield': 3.18.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/toolbar': 3.0.0-beta.22(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/virtualizer': 4.1.11(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/autocomplete': 3.0.0-beta.4(react@19.2.3) - '@react-stately/layout': 4.5.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-stately/selection': 3.20.7(react@19.2.3) - '@react-stately/table': 3.15.2(patch_hash=5ac384399a7b8e18c4e19f25e434b2f2f27fbd45e7a91cdeb30408330b7243b4)(react@19.2.3) - '@react-stately/utils': 3.11.0(react@19.2.3) - '@react-stately/virtualizer': 4.4.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-types/form': 3.7.16(react@19.2.3) - '@react-types/grid': 3.3.6(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - '@react-types/table': 3.13.4(react@19.2.3) - '@swc/helpers': 0.5.18 + '@react-aria/overlays': 3.31.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/ssr': 3.9.10(react@19.2.4) + '@react-aria/textfield': 3.18.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/toolbar': 3.0.0-beta.24(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/virtualizer': 4.1.13(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/autocomplete': 3.0.0-beta.4(react@19.2.4) + '@react-stately/layout': 4.6.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-stately/selection': 3.20.9(react@19.2.4) + '@react-stately/table': 3.15.4(patch_hash=5ac384399a7b8e18c4e19f25e434b2f2f27fbd45e7a91cdeb30408330b7243b4)(react@19.2.4) + '@react-stately/utils': 3.11.0(react@19.2.4) + '@react-stately/virtualizer': 4.4.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-types/form': 3.7.18(react@19.2.4) + '@react-types/grid': 3.3.8(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + '@react-types/table': 3.13.6(react@19.2.4) + '@swc/helpers': 0.5.19 client-only: 0.0.1 - react: 19.2.3 - react-aria: 3.45.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react-dom: 19.2.3(react@19.2.3) - react-stately: 3.43.0(react@19.2.3) - use-sync-external-store: 1.6.0(react@19.2.3) + react: 19.2.4 + react-aria: 3.47.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react-dom: 19.2.4(react@19.2.4) + react-stately: 3.45.0(react@19.2.4) + use-sync-external-store: 1.6.0(react@19.2.4) - react-aria@3.45.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + react-aria@3.47.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: '@internationalized/string': 3.2.7 - '@react-aria/breadcrumbs': 3.5.30(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/button': 3.14.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/calendar': 3.9.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/checkbox': 3.16.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/color': 3.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/combobox': 3.14.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/datepicker': 3.15.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/dialog': 3.5.32(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/disclosure': 3.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/dnd': 3.11.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/focus': 3.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/gridlist': 3.14.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/i18n': 3.12.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/label': 3.7.23(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/landmark': 3.0.8(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/link': 3.8.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/listbox': 3.15.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/menu': 3.19.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/meter': 3.4.28(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/numberfield': 3.12.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/overlays': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/progress': 3.4.28(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/radio': 3.12.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/searchfield': 3.8.10(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/select': 3.17.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/selection': 3.27.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/separator': 3.4.14(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/slider': 3.8.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/ssr': 3.9.10(react@19.2.3) - '@react-aria/switch': 3.7.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/table': 3.17.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/tabs': 3.10.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/tag': 3.7.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/textfield': 3.18.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/toast': 3.0.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/tooltip': 3.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/tree': 3.1.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-aria/visually-hidden': 3.8.29(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + '@react-aria/breadcrumbs': 3.5.32(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/button': 3.14.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/calendar': 3.9.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/checkbox': 3.16.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/color': 3.1.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/combobox': 3.15.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/datepicker': 3.16.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/dialog': 3.5.34(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/disclosure': 3.1.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/dnd': 3.11.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/focus': 3.21.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/gridlist': 3.14.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/i18n': 3.12.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/interactions': 3.27.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/label': 3.7.25(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/landmark': 3.0.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/link': 3.8.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/listbox': 3.15.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/menu': 3.21.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/meter': 3.4.30(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/numberfield': 3.12.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/overlays': 3.31.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/progress': 3.4.30(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/radio': 3.12.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/searchfield': 3.8.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/select': 3.17.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/selection': 3.27.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/separator': 3.4.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/slider': 3.8.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/ssr': 3.9.10(react@19.2.4) + '@react-aria/switch': 3.7.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/table': 3.17.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/tabs': 3.11.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/tag': 3.8.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/textfield': 3.18.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/toast': 3.0.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/tooltip': 3.9.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/tree': 3.1.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/utils': 3.33.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-aria/visually-hidden': 3.8.31(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) react-docgen-typescript@2.4.0(typescript@5.9.3): dependencies: @@ -21282,9 +21361,9 @@ snapshots: react-docgen@8.0.2: dependencies: - '@babel/core': 7.28.5 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/core': 7.29.0 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.28.0 '@types/doctrine': 0.0.9 @@ -21295,23 +21374,22 @@ snapshots: transitivePeerDependencies: - supports-color - react-dom@19.2.3(react@19.2.3): + react-dom@19.2.4(react@19.2.4): dependencies: - react: 19.2.3 + react: 19.2.4 scheduler: 0.27.0 - react-error-boundary@6.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + react-error-boundary@6.1.1(react@19.2.4): dependencies: - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + react: 19.2.4 - react-hook-form@7.70.0(react@19.2.3): + react-hook-form@7.70.0(react@19.2.4): dependencies: - react: 19.2.3 + react: 19.2.4 - react-icons@5.5.0(react@19.2.3): + react-icons@5.6.0(react@19.2.4): dependencies: - react: 19.2.3 + react: 19.2.4 react-is@16.13.1: {} @@ -21319,16 +21397,16 @@ snapshots: react-is@18.3.1: {} - react-markdown@10.1.0(@types/react@19.2.7)(react@19.2.3): + react-markdown@10.1.0(@types/react@19.2.14)(react@19.2.4): dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 - '@types/react': 19.2.7 + '@types/react': 19.2.14 devlop: 1.1.0 hast-util-to-jsx-runtime: 2.3.6 html-url-attributes: 3.0.1 mdast-util-to-hast: 13.2.1 - react: 19.2.3 + react: 19.2.4 remark-parse: 11.0.0 remark-rehype: 11.1.2 unified: 11.0.5 @@ -21339,32 +21417,28 @@ snapshots: react-refresh@0.18.0: {} - react-resizable-panels@4.3.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + react-resizable-panels@4.7.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) - react-scan@0.4.3(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rollup@4.55.1): + react-scan@0.5.3(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0): dependencies: - '@babel/core': 7.28.5 - '@babel/generator': 7.28.5 - '@babel/types': 7.28.5 - '@clack/core': 0.3.5 - '@clack/prompts': 0.8.2 - '@pivanov/utils': 0.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@preact/signals': 1.3.2(preact@10.28.2) - '@rollup/pluginutils': 5.3.0(rollup@4.55.1) - '@types/node': 20.19.27 - bippy: 0.3.34(@types/react@19.2.7)(react@19.2.3) + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/types': 7.29.0 + '@preact/signals': 1.3.4(preact@10.28.4) + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + '@types/node': 20.19.37 + bippy: 0.5.30(@types/react@19.2.14)(react@19.2.4) + commander: 14.0.3 esbuild: 0.25.12 estree-walker: 3.0.3 - kleur: 4.1.5 - mri: 1.2.0 - playwright: 1.57.0 - preact: 10.28.2 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - tsx: 4.21.0 + picocolors: 1.1.1 + preact: 10.28.4 + prompts: 2.4.2 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) optionalDependencies: unplugin: 2.1.0 transitivePeerDependencies: @@ -21372,45 +21446,45 @@ snapshots: - rollup - supports-color - react-simple-animate@3.5.3(react-dom@19.2.3(react@19.2.3)): - dependencies: - react-dom: 19.2.3(react@19.2.3) - - react-stately@3.43.0(react@19.2.3): - dependencies: - '@react-stately/calendar': 3.9.1(react@19.2.3) - '@react-stately/checkbox': 3.7.3(react@19.2.3) - '@react-stately/collections': 3.12.8(react@19.2.3) - '@react-stately/color': 3.9.3(react@19.2.3) - '@react-stately/combobox': 3.12.1(react@19.2.3) - '@react-stately/data': 3.15.0(react@19.2.3) - '@react-stately/datepicker': 3.15.3(react@19.2.3) - '@react-stately/disclosure': 3.0.9(react@19.2.3) - '@react-stately/dnd': 3.7.2(react@19.2.3) - '@react-stately/form': 3.2.2(react@19.2.3) - '@react-stately/list': 3.13.2(react@19.2.3) - '@react-stately/menu': 3.9.9(react@19.2.3) - '@react-stately/numberfield': 3.10.3(react@19.2.3) - '@react-stately/overlays': 3.6.21(react@19.2.3) - '@react-stately/radio': 3.11.3(react@19.2.3) - '@react-stately/searchfield': 3.5.17(react@19.2.3) - '@react-stately/select': 3.9.0(react@19.2.3) - '@react-stately/selection': 3.20.7(react@19.2.3) - '@react-stately/slider': 3.7.3(react@19.2.3) - '@react-stately/table': 3.15.2(patch_hash=5ac384399a7b8e18c4e19f25e434b2f2f27fbd45e7a91cdeb30408330b7243b4)(react@19.2.3) - '@react-stately/tabs': 3.8.7(react@19.2.3) - '@react-stately/toast': 3.1.2(react@19.2.3) - '@react-stately/toggle': 3.9.3(react@19.2.3) - '@react-stately/tooltip': 3.5.9(react@19.2.3) - '@react-stately/tree': 3.9.4(react@19.2.3) - '@react-types/shared': 3.32.1(react@19.2.3) - react: 19.2.3 - - react-timeago@8.3.0(react@19.2.3): - dependencies: - react: 19.2.3 - - react@19.2.3: {} + react-simple-animate@3.5.3(react-dom@19.2.4(react@19.2.4)): + dependencies: + react-dom: 19.2.4(react@19.2.4) + + react-stately@3.45.0(react@19.2.4): + dependencies: + '@react-stately/calendar': 3.9.3(react@19.2.4) + '@react-stately/checkbox': 3.7.5(react@19.2.4) + '@react-stately/collections': 3.12.10(react@19.2.4) + '@react-stately/color': 3.9.5(react@19.2.4) + '@react-stately/combobox': 3.13.0(react@19.2.4) + '@react-stately/data': 3.15.2(react@19.2.4) + '@react-stately/datepicker': 3.16.1(react@19.2.4) + '@react-stately/disclosure': 3.0.11(react@19.2.4) + '@react-stately/dnd': 3.7.4(react@19.2.4) + '@react-stately/form': 3.2.4(react@19.2.4) + '@react-stately/list': 3.13.4(react@19.2.4) + '@react-stately/menu': 3.9.11(react@19.2.4) + '@react-stately/numberfield': 3.11.0(react@19.2.4) + '@react-stately/overlays': 3.6.23(react@19.2.4) + '@react-stately/radio': 3.11.5(react@19.2.4) + '@react-stately/searchfield': 3.5.19(react@19.2.4) + '@react-stately/select': 3.9.2(react@19.2.4) + '@react-stately/selection': 3.20.9(react@19.2.4) + '@react-stately/slider': 3.7.5(react@19.2.4) + '@react-stately/table': 3.15.4(patch_hash=5ac384399a7b8e18c4e19f25e434b2f2f27fbd45e7a91cdeb30408330b7243b4)(react@19.2.4) + '@react-stately/tabs': 3.8.9(react@19.2.4) + '@react-stately/toast': 3.1.3(react@19.2.4) + '@react-stately/toggle': 3.9.5(react@19.2.4) + '@react-stately/tooltip': 3.5.11(react@19.2.4) + '@react-stately/tree': 3.9.6(react@19.2.4) + '@react-types/shared': 3.33.1(react@19.2.4) + react: 19.2.4 + + react-timeago@8.3.0(react@19.2.4): + dependencies: + react: 19.2.4 + + react@19.2.4: {} read-binary-file-arch@1.0.6: dependencies: @@ -21418,10 +21492,6 @@ snapshots: transitivePeerDependencies: - supports-color - read-cache@1.0.0: - dependencies: - pify: 2.3.0 - read-yaml-file@2.1.0: dependencies: js-yaml: 4.1.1 @@ -21443,6 +21513,18 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 + readable-stream@4.7.0: + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + + readdir-glob@1.1.3: + dependencies: + minimatch: 5.1.9 + readdirp@3.6.0: dependencies: picomatch: 2.3.1 @@ -21521,7 +21603,7 @@ snapshots: remark-parse@11.0.0: dependencies: '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 micromark-util-types: 2.0.2 unified: 11.0.5 transitivePeerDependencies: @@ -21541,6 +21623,8 @@ snapshots: mdast-util-to-markdown: 2.1.2 unified: 11.0.5 + remeda@2.33.4: {} + require-directory@2.1.1: {} require-from-string@2.0.2: {} @@ -21578,9 +21662,12 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - resolve@2.0.0-next.5: + resolve@2.0.0-next.6: dependencies: + es-errors: 1.3.0 is-core-module: 2.16.1 + node-exports-info: 1.6.0 + object-keys: 1.1.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 @@ -21618,68 +21705,45 @@ snapshots: sprintf-js: 1.1.3 optional: true - rollup-plugin-postcss@4.0.2(postcss@8.5.6)(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)): - dependencies: - chalk: 4.1.2 - concat-with-sourcemaps: 1.1.0 - cssnano: 5.1.15(postcss@8.5.6) - import-cwd: 3.0.0 - p-queue: 6.6.2 - pify: 5.0.0 - postcss: 8.5.6 - postcss-load-config: 3.1.4(postcss@8.5.6)(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)) - postcss-modules: 4.3.1(postcss@8.5.6) - promise.series: 0.2.0 - resolve: 1.22.11 - rollup-pluginutils: 2.8.2 - safe-identifier: 0.4.2 - style-inject: 0.3.0 - transitivePeerDependencies: - - ts-node - - rollup-plugin-typescript2@0.36.0(rollup@4.55.1)(typescript@5.9.3): + rollup-plugin-typescript2@0.36.0(rollup@4.59.0)(typescript@5.9.3): dependencies: '@rollup/pluginutils': 4.2.1 find-cache-dir: 3.3.2 fs-extra: 10.1.0 - rollup: 4.55.1 + rollup: 4.59.0 semver: 7.7.4 tslib: 2.8.1 typescript: 5.9.3 - rollup-pluginutils@2.8.2: - dependencies: - estree-walker: 0.6.1 - - rollup@4.55.1: + rollup@4.59.0: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.55.1 - '@rollup/rollup-android-arm64': 4.55.1 - '@rollup/rollup-darwin-arm64': 4.55.1 - '@rollup/rollup-darwin-x64': 4.55.1 - '@rollup/rollup-freebsd-arm64': 4.55.1 - '@rollup/rollup-freebsd-x64': 4.55.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.55.1 - '@rollup/rollup-linux-arm-musleabihf': 4.55.1 - '@rollup/rollup-linux-arm64-gnu': 4.55.1 - '@rollup/rollup-linux-arm64-musl': 4.55.1 - '@rollup/rollup-linux-loong64-gnu': 4.55.1 - '@rollup/rollup-linux-loong64-musl': 4.55.1 - '@rollup/rollup-linux-ppc64-gnu': 4.55.1 - '@rollup/rollup-linux-ppc64-musl': 4.55.1 - '@rollup/rollup-linux-riscv64-gnu': 4.55.1 - '@rollup/rollup-linux-riscv64-musl': 4.55.1 - '@rollup/rollup-linux-s390x-gnu': 4.55.1 - '@rollup/rollup-linux-x64-gnu': 4.55.1 - '@rollup/rollup-linux-x64-musl': 4.55.1 - '@rollup/rollup-openbsd-x64': 4.55.1 - '@rollup/rollup-openharmony-arm64': 4.55.1 - '@rollup/rollup-win32-arm64-msvc': 4.55.1 - '@rollup/rollup-win32-ia32-msvc': 4.55.1 - '@rollup/rollup-win32-x64-gnu': 4.55.1 - '@rollup/rollup-win32-x64-msvc': 4.55.1 + '@rollup/rollup-android-arm-eabi': 4.59.0 + '@rollup/rollup-android-arm64': 4.59.0 + '@rollup/rollup-darwin-arm64': 4.59.0 + '@rollup/rollup-darwin-x64': 4.59.0 + '@rollup/rollup-freebsd-arm64': 4.59.0 + '@rollup/rollup-freebsd-x64': 4.59.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.59.0 + '@rollup/rollup-linux-arm-musleabihf': 4.59.0 + '@rollup/rollup-linux-arm64-gnu': 4.59.0 + '@rollup/rollup-linux-arm64-musl': 4.59.0 + '@rollup/rollup-linux-loong64-gnu': 4.59.0 + '@rollup/rollup-linux-loong64-musl': 4.59.0 + '@rollup/rollup-linux-ppc64-gnu': 4.59.0 + '@rollup/rollup-linux-ppc64-musl': 4.59.0 + '@rollup/rollup-linux-riscv64-gnu': 4.59.0 + '@rollup/rollup-linux-riscv64-musl': 4.59.0 + '@rollup/rollup-linux-s390x-gnu': 4.59.0 + '@rollup/rollup-linux-x64-gnu': 4.59.0 + '@rollup/rollup-linux-x64-musl': 4.59.0 + '@rollup/rollup-openbsd-x64': 4.59.0 + '@rollup/rollup-openharmony-arm64': 4.59.0 + '@rollup/rollup-win32-arm64-msvc': 4.59.0 + '@rollup/rollup-win32-ia32-msvc': 4.59.0 + '@rollup/rollup-win32-x64-gnu': 4.59.0 + '@rollup/rollup-win32-x64-msvc': 4.59.0 fsevents: 2.3.3 rou3@0.7.12: {} @@ -21702,8 +21766,6 @@ snapshots: safe-buffer@5.2.1: {} - safe-identifier@0.4.2: {} - safe-push-apply@1.0.0: dependencies: es-errors: 1.3.0 @@ -21721,22 +21783,16 @@ snapshots: dependencies: truncate-utf8-bytes: 1.0.2 - sax@1.4.3: {} + sax@1.5.0: {} scheduler@0.27.0: {} - schema-utils@3.3.0: - dependencies: - '@types/json-schema': 7.0.15 - ajv: 6.12.6 - ajv-keywords: 3.5.2(ajv@6.12.6) - schema-utils@4.3.3: dependencies: '@types/json-schema': 7.0.15 - ajv: 8.17.1 - ajv-formats: 2.1.1(ajv@8.17.1) - ajv-keywords: 5.1.0(ajv@8.17.1) + ajv: 8.18.0 + ajv-formats: 2.1.1(ajv@8.18.0) + ajv-keywords: 5.1.0(ajv@8.18.0) secure-compare@3.0.1: {} @@ -21751,8 +21807,6 @@ snapshots: semver@7.7.2: {} - semver@7.7.3: {} - semver@7.7.4: {} send@0.19.2: @@ -21773,26 +21827,26 @@ snapshots: transitivePeerDependencies: - supports-color + seq-queue@0.0.5: {} + serialize-error@7.0.1: dependencies: type-fest: 0.13.1 optional: true - serialize-javascript@6.0.2: - dependencies: - randombytes: 2.1.0 - seroval-plugins@1.3.3(seroval@1.3.2): dependencies: seroval: 1.3.2 + optional: true - seroval-plugins@1.4.2(seroval@1.4.2): + seroval-plugins@1.5.0(seroval@1.5.0): dependencies: - seroval: 1.4.2 + seroval: 1.5.0 - seroval@1.3.2: {} + seroval@1.3.2: + optional: true - seroval@1.4.2: {} + seroval@1.5.0: {} serve-static@1.16.3: dependencies: @@ -21805,6 +21859,8 @@ snapshots: set-cookie-parser@2.7.2: {} + set-cookie-parser@3.0.1: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -21881,7 +21937,7 @@ snapshots: simple-update-notifier@2.0.0: dependencies: - semver: 7.7.3 + semver: 7.7.4 sisteransi@1.0.5: {} @@ -21919,6 +21975,7 @@ snapshots: csstype: 3.2.3 seroval: 1.3.2 seroval-plugins: 1.3.3(seroval@1.3.2) + optional: true sorted-array-functions@1.3.0: {} @@ -21944,6 +22001,10 @@ snapshots: space-separated-tokens@2.0.2: {} + sparse-bitfield@3.0.3: + dependencies: + memory-pager: 1.5.0 + split2@4.2.0: {} sprintf-js@1.0.3: {} @@ -21951,18 +22012,18 @@ snapshots: sprintf-js@1.1.3: optional: true + sqlstring@2.3.3: {} + ssri@12.0.0: dependencies: - minipass: 7.1.2 + minipass: 7.1.3 - ssri@13.0.0: + ssri@13.0.1: dependencies: - minipass: 7.1.2 + minipass: 7.1.3 stable-hash-x@0.2.0: {} - stable@0.1.8: {} - stackback@0.0.2: {} stat-mode@1.0.0: {} @@ -21980,42 +22041,19 @@ snapshots: es-errors: 1.3.0 internal-slot: 1.1.0 - storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: '@storybook/global': 5.0.0 - '@storybook/icons': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@storybook/icons': 2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@testing-library/jest-dom': 6.9.1 '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.1) '@vitest/expect': 3.2.4 '@vitest/spy': 3.2.4 - esbuild: 0.27.2 + esbuild: 0.27.3 open: 10.2.0 recast: 0.23.11 - semver: 7.7.3 - use-sync-external-store: 1.6.0(react@19.2.3) - ws: 8.19.0 - optionalDependencies: - prettier: 3.7.4 - transitivePeerDependencies: - - '@testing-library/dom' - - bufferutil - - react - - react-dom - - utf-8-validate - - storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): - dependencies: - '@storybook/global': 5.0.0 - '@storybook/icons': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@testing-library/jest-dom': 6.9.1 - '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.1) - '@vitest/expect': 3.2.4 - '@vitest/spy': 3.2.4 - esbuild: 0.27.2 - open: 10.2.0 - recast: 0.23.11 - semver: 7.7.3 - use-sync-external-store: 1.6.0(react@19.2.3) + semver: 7.7.4 + use-sync-external-store: 1.6.0(react@19.2.4) ws: 8.19.0 optionalDependencies: prettier: 3.8.1 @@ -22034,6 +22072,15 @@ snapshots: transitivePeerDependencies: - supports-color + streamx@2.23.0: + dependencies: + events-universal: 1.0.1 + fast-fifo: 1.3.2 + text-decoder: 1.2.7 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + string-hash@1.1.3: {} string-width@4.2.3: @@ -22046,13 +22093,13 @@ snapshots: dependencies: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 string-width@7.2.0: dependencies: emoji-regex: 10.6.0 - get-east-asian-width: 1.4.0 - strip-ansi: 7.1.2 + get-east-asian-width: 1.5.0 + strip-ansi: 7.2.0 string.prototype.includes@2.0.1: dependencies: @@ -22121,7 +22168,7 @@ snapshots: dependencies: ansi-regex: 5.0.1 - strip-ansi@7.1.2: + strip-ansi@7.2.0: dependencies: ansi-regex: 6.2.2 @@ -22139,8 +22186,6 @@ snapshots: strip-json-comments@3.1.1: {} - style-inject@0.3.0: {} - style-mod@4.1.3: {} style-to-js@1.1.21: @@ -22151,12 +22196,6 @@ snapshots: dependencies: inline-style-parser: 0.2.7 - stylehacks@5.1.1(postcss@8.5.6): - dependencies: - browserslist: 4.28.1 - postcss: 8.5.6 - postcss-selector-parser: 6.0.10 - stylis@4.2.0: {} sucrase@3.35.1: @@ -22187,36 +22226,26 @@ snapshots: svg-parser@2.0.4: {} - svgo@2.8.0: + svgo@3.3.3: dependencies: - '@trysound/sax': 0.2.0 - commander: 7.2.0 - css-select: 4.3.0 - css-tree: 1.1.3 - csso: 4.2.0 - picocolors: 1.1.1 - stable: 0.1.8 - - svgo@3.3.2: - dependencies: - '@trysound/sax': 0.2.0 commander: 7.2.0 css-select: 5.2.2 css-tree: 2.3.1 css-what: 6.2.2 csso: 5.0.5 picocolors: 1.1.1 + sax: 1.5.0 - swc-node@1.0.0(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3): + swc-node@1.0.0(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3): dependencies: - '@swc-node/register': 1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(@swc/types@0.1.25)(typescript@5.9.3) + '@swc-node/register': 1.11.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(@swc/types@0.1.25)(typescript@5.9.3) transitivePeerDependencies: - '@swc/core' - '@swc/types' - supports-color - typescript - synckit@0.11.11: + synckit@0.11.12: dependencies: '@pkgr/core': 0.2.9 @@ -22225,8 +22254,8 @@ snapshots: chalk: 5.6.2 chalk-template: 1.1.2 commander: 13.1.0 - cosmiconfig: 9.0.0(typescript@5.9.3) - effect: 3.19.14 + cosmiconfig: 9.0.1(typescript@5.9.3) + effect: 3.19.19 enquirer: 2.4.1 fast-check: 3.23.2 globby: 14.1.0 @@ -22236,7 +22265,7 @@ snapshots: ora: 8.2.0 prompts: 2.4.2 read-yaml-file: 2.1.0 - semver: 7.7.3 + semver: 7.7.4 tightrope: 0.2.0 ts-toolbelt: 9.6.0 transitivePeerDependencies: @@ -22244,19 +22273,19 @@ snapshots: tailwind-csstree@0.1.4: {} - tailwind-merge@3.4.0: {} + tailwind-merge@3.5.0: {} - tailwind-variants@3.2.2(tailwind-merge@3.4.0)(tailwindcss@4.1.18): + tailwind-variants@3.2.2(tailwind-merge@3.5.0)(tailwindcss@4.2.1): dependencies: - tailwindcss: 4.1.18 + tailwindcss: 4.2.1 optionalDependencies: - tailwind-merge: 3.4.0 + tailwind-merge: 3.5.0 - tailwindcss-react-aria-components@2.0.1(tailwindcss@4.1.18): + tailwindcss-react-aria-components@2.0.1(tailwindcss@4.2.1): dependencies: - tailwindcss: 4.1.18 + tailwindcss: 4.2.1 - tailwindcss@4.1.18: {} + tailwindcss@4.2.1: {} tapable@2.3.0: {} @@ -22264,7 +22293,7 @@ snapshots: dependencies: chownr: 1.1.4 mkdirp-classic: 0.5.3 - pump: 3.0.3 + pump: 3.0.4 tar-stream: 2.2.0 tar-stream@2.2.0: @@ -22275,6 +22304,17 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 + tar-stream@3.1.8: + dependencies: + b4a: 1.8.0 + bare-fs: 4.5.5 + fast-fifo: 1.3.2 + streamx: 2.23.0 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a + tar@6.2.1: dependencies: chownr: 2.0.0 @@ -22284,14 +22324,21 @@ snapshots: mkdirp: 1.0.4 yallist: 4.0.0 - tar@7.5.2: + tar@7.5.10: dependencies: '@isaacs/fs-minipass': 4.0.1 chownr: 3.0.0 - minipass: 7.1.2 + minipass: 7.1.3 minizlib: 3.1.0 yallist: 5.0.0 + teex@1.0.1: + dependencies: + streamx: 2.23.0 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + temp-file@3.4.0: dependencies: async-exit-hook: 2.0.1 @@ -22308,37 +22355,41 @@ snapshots: temporal-spec@0.3.0: {} - terser-webpack-plugin@5.3.16(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2)(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2)): + terser-webpack-plugin@5.3.17(@swc/core@1.15.8(@swc/helpers@0.5.19))(esbuild@0.27.3)(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))(esbuild@0.27.3)): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 - serialize-javascript: 6.0.2 - terser: 5.44.1 - webpack: 5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2) + terser: 5.46.0 + webpack: 5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))(esbuild@0.27.3) optionalDependencies: - '@swc/core': 1.15.8(@swc/helpers@0.5.18) - esbuild: 0.27.2 + '@swc/core': 1.15.8(@swc/helpers@0.5.19) + esbuild: 0.27.3 optional: true - terser-webpack-plugin@5.3.16(@swc/core@1.15.8(@swc/helpers@0.5.18))(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))): + terser-webpack-plugin@5.3.17(@swc/core@1.15.8(@swc/helpers@0.5.19))(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 - serialize-javascript: 6.0.2 - terser: 5.44.1 - webpack: 5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18)) + terser: 5.46.0 + webpack: 5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19)) optionalDependencies: - '@swc/core': 1.15.8(@swc/helpers@0.5.18) + '@swc/core': 1.15.8(@swc/helpers@0.5.19) - terser@5.44.1: + terser@5.46.0: dependencies: '@jridgewell/source-map': 0.3.11 - acorn: 8.15.0 + acorn: 8.16.0 commander: 2.20.3 source-map-support: 0.5.21 + text-decoder@1.2.7: + dependencies: + b4a: 1.8.0 + transitivePeerDependencies: + - react-native-b4a + thenify-all@1.6.0: dependencies: thenify: 3.3.1 @@ -22392,6 +22443,10 @@ snapshots: tr46@0.0.3: {} + tr46@5.1.1: + dependencies: + punycode: 2.3.1 + tree-kill@1.2.2: {} trim-lines@3.0.1: {} @@ -22410,25 +22465,25 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3): + ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.19))(@types/node@25.3.5)(typescript@5.9.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.12 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 25.0.3 - acorn: 8.15.0 - acorn-walk: 8.3.4 + '@types/node': 25.3.5 + acorn: 8.16.0 + acorn-walk: 8.3.5 arg: 4.1.3 create-require: 1.1.1 - diff: 4.0.2 + diff: 4.0.4 make-error: 1.3.6 typescript: 5.9.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: - '@swc/core': 1.15.8(@swc/helpers@0.5.18) + '@swc/core': 1.15.8(@swc/helpers@0.5.19) ts-toolbelt@9.6.0: {} @@ -22439,7 +22494,7 @@ snapshots: tsconfig-paths-webpack-plugin@4.2.0: dependencies: chalk: 4.1.2 - enhanced-resolve: 5.18.4 + enhanced-resolve: 5.20.0 tapable: 2.3.0 tsconfig-paths: 4.2.0 @@ -22453,28 +22508,28 @@ snapshots: tsscmp@1.0.6: {} - tsup@8.5.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2): + tsup@8.5.1(@swc/core@1.15.8(@swc/helpers@0.5.19))(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2): dependencies: - bundle-require: 5.1.0(esbuild@0.27.2) + bundle-require: 5.1.0(esbuild@0.27.3) cac: 6.7.14 chokidar: 4.0.3 consola: 3.4.2 debug: 4.4.3 - esbuild: 0.27.2 + esbuild: 0.27.3 fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.2) + postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(yaml@2.8.2) resolve-from: 5.0.0 - rollup: 4.55.1 + rollup: 4.59.0 source-map: 0.7.6 sucrase: 3.35.1 tinyexec: 0.3.2 tinyglobby: 0.2.15 tree-kill: 1.2.2 optionalDependencies: - '@swc/core': 1.15.8(@swc/helpers@0.5.18) - postcss: 8.5.6 + '@swc/core': 1.15.8(@swc/helpers@0.5.19) + postcss: 8.5.8 typescript: 5.9.3 transitivePeerDependencies: - jiti @@ -22484,8 +22539,8 @@ snapshots: tsx@4.21.0: dependencies: - esbuild: 0.27.2 - get-tsconfig: 4.13.0 + esbuild: 0.27.3 + get-tsconfig: 4.13.6 optionalDependencies: fsevents: 2.3.3 @@ -22546,12 +22601,12 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typescript-eslint@8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + typescript-eslint@8.56.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.52.0(@typescript-eslint/parser@8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.52.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.56.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.56.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: @@ -22561,7 +22616,7 @@ snapshots: typescript@5.9.3: {} - ufo@1.6.2: {} + ufo@1.6.3: {} unbox-primitive@1.1.0: dependencies: @@ -22570,13 +22625,13 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 - undici-types@5.26.5: {} - undici-types@6.21.0: {} undici-types@7.16.0: {} - undici@7.18.2: {} + undici-types@7.18.2: {} + + undici@7.22.0: {} unicode-canonical-property-names-ecmascript@2.0.1: {} @@ -22605,7 +22660,7 @@ snapshots: union@0.5.0: dependencies: - qs: 6.14.1 + qs: 6.15.0 unique-filename@4.0.0: dependencies: @@ -22656,14 +22711,14 @@ snapshots: unplugin@2.1.0: dependencies: - acorn: 8.15.0 + acorn: 8.16.0 webpack-virtual-modules: 0.6.2 optional: true unplugin@2.3.11: dependencies: '@jridgewell/remapping': 2.3.5 - acorn: 8.15.0 + acorn: 8.16.0 picomatch: 4.0.3 webpack-virtual-modules: 0.6.2 @@ -22711,19 +22766,19 @@ snapshots: url-join@4.0.1: {} - use-debounce@10.0.6(react@19.2.3): + use-debounce@10.1.0(react@19.2.4): dependencies: - react: 19.2.3 + react: 19.2.4 - use-deep-compare-effect@1.8.1(react@19.2.3): + use-deep-compare-effect@1.8.1(react@19.2.4): dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.28.6 dequal: 2.0.3 - react: 19.2.3 + react: 19.2.4 - use-sync-external-store@1.6.0(react@19.2.3): + use-sync-external-store@1.6.0(react@19.2.4): dependencies: - react: 19.2.3 + react: 19.2.4 utf8-byte-length@1.0.5: {} @@ -22737,6 +22792,10 @@ snapshots: v8-compile-cache-lib@3.0.1: {} + valibot@1.2.0(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + validate-html-nesting@1.2.4: {} validate-npm-package-name@6.0.2: {} @@ -22762,38 +22821,37 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite-tsconfig-paths@6.0.3(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): + vite-tsconfig-paths@6.1.1(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): dependencies: debug: 4.4.3 globrex: 0.1.2 tsconfck: 3.1.6(typescript@5.9.3) - optionalDependencies: - vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - supports-color - typescript - vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): + vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): dependencies: - esbuild: 0.27.2 + esbuild: 0.27.3 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.55.1 + postcss: 8.5.8 + rollup: 4.59.0 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 25.0.3 + '@types/node': 25.3.5 fsevents: 2.3.3 jiti: 2.6.1 - lightningcss: 1.30.2 - terser: 5.44.1 + lightningcss: 1.31.1 + terser: 5.46.0 tsx: 4.21.0 yaml: 2.8.2 - vitest@4.0.18(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): + vitest@4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): dependencies: '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/pretty-format': 4.0.18 '@vitest/runner': 4.0.18 '@vitest/snapshot': 4.0.18 @@ -22810,10 +22868,10 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 25.0.3 + '@types/node': 25.3.5 transitivePeerDependencies: - jiti - less @@ -22844,7 +22902,7 @@ snapshots: w3c-keyname@2.2.8: {} - watchpack@2.5.0: + watchpack@2.5.1: dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 @@ -22856,15 +22914,15 @@ snapshots: web-streams-polyfill@3.3.3: optional: true - web-streams-polyfill@4.0.0-beta.3: {} - webidl-conversions@3.0.1: {} - webpack-sources@3.3.3: {} + webidl-conversions@7.0.0: {} + + webpack-sources@3.3.4: {} webpack-virtual-modules@0.6.2: {} - webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18)): + webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19)): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -22872,11 +22930,11 @@ snapshots: '@webassemblyjs/ast': 1.14.1 '@webassemblyjs/wasm-edit': 1.14.1 '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.15.0 - acorn-import-phases: 1.0.4(acorn@8.15.0) + acorn: 8.16.0 + acorn-import-phases: 1.0.4(acorn@8.16.0) browserslist: 4.28.1 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.18.4 + enhanced-resolve: 5.20.0 es-module-lexer: 2.0.0 eslint-scope: 5.1.1 events: 3.3.0 @@ -22888,15 +22946,15 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.3.16(@swc/core@1.15.8(@swc/helpers@0.5.18))(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))) - watchpack: 2.5.0 - webpack-sources: 3.3.3 + terser-webpack-plugin: 5.3.17(@swc/core@1.15.8(@swc/helpers@0.5.19))(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))) + watchpack: 2.5.1 + webpack-sources: 3.3.4 transitivePeerDependencies: - '@swc/core' - esbuild - uglify-js - webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2): + webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))(esbuild@0.27.3): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -22904,11 +22962,11 @@ snapshots: '@webassemblyjs/ast': 1.14.1 '@webassemblyjs/wasm-edit': 1.14.1 '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.15.0 - acorn-import-phases: 1.0.4(acorn@8.15.0) + acorn: 8.16.0 + acorn-import-phases: 1.0.4(acorn@8.16.0) browserslist: 4.28.1 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.18.4 + enhanced-resolve: 5.20.0 es-module-lexer: 2.0.0 eslint-scope: 5.1.1 events: 3.3.0 @@ -22920,9 +22978,9 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.3.16(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2)(webpack@5.104.1(@swc/core@1.15.8(@swc/helpers@0.5.18))(esbuild@0.27.2)) - watchpack: 2.5.0 - webpack-sources: 3.3.3 + terser-webpack-plugin: 5.3.17(@swc/core@1.15.8(@swc/helpers@0.5.19))(esbuild@0.27.3)(webpack@5.105.4(@swc/core@1.15.8(@swc/helpers@0.5.19))(esbuild@0.27.3)) + watchpack: 2.5.1 + webpack-sources: 3.3.4 transitivePeerDependencies: - '@swc/core' - esbuild @@ -22933,6 +22991,11 @@ snapshots: dependencies: iconv-lite: 0.6.3 + whatwg-url@14.2.0: + dependencies: + tr46: 5.1.1 + webidl-conversions: 7.0.0 + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -22960,7 +23023,7 @@ snapshots: isarray: 2.0.5 which-boxed-primitive: 1.1.1 which-collection: 1.0.2 - which-typed-array: 1.1.19 + which-typed-array: 1.1.20 which-collection@1.0.2: dependencies: @@ -22969,7 +23032,7 @@ snapshots: is-weakmap: 2.0.2 is-weakset: 2.0.4 - which-typed-array@1.1.19: + which-typed-array@1.1.20: dependencies: available-typed-arrays: 1.0.7 call-bind: 1.0.8 @@ -22989,7 +23052,7 @@ snapshots: which@5.0.0: dependencies: - isexe: 3.1.1 + isexe: 3.1.5 why-is-node-running@2.3.0: dependencies: @@ -23008,13 +23071,13 @@ snapshots: dependencies: ansi-styles: 6.2.3 string-width: 5.1.2 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 wrap-ansi@9.0.2: dependencies: ansi-styles: 6.2.3 string-width: 7.2.0 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 wrappy@1.0.2: {} @@ -23024,7 +23087,7 @@ snapshots: wsl-utils@0.1.0: dependencies: - is-wsl: 3.1.0 + is-wsl: 3.1.1 xmlbuilder@15.1.1: {} @@ -23082,21 +23145,30 @@ snapshots: yoctocolors@2.1.2: {} - zod-validation-error@4.0.2(zod@4.3.5): + zeptomatch@2.1.0: dependencies: - zod: 4.3.5 + grammex: 3.1.12 + graphmatch: 1.1.1 - zod@3.25.76: {} + zip-stream@6.0.1: + dependencies: + archiver-utils: 5.0.2 + compress-commons: 6.0.2 + readable-stream: 4.7.0 + + zod-validation-error@4.0.2(zod@4.3.6): + dependencies: + zod: 4.3.6 - zod@4.3.5: {} + zod@3.25.76: {} zod@4.3.6: {} - zustand@4.5.7(@types/react@19.2.7)(react@19.2.3): + zustand@4.5.7(@types/react@19.2.14)(react@19.2.4): dependencies: - use-sync-external-store: 1.6.0(react@19.2.3) + use-sync-external-store: 1.6.0(react@19.2.4) optionalDependencies: - '@types/react': 19.2.7 - react: 19.2.3 + '@types/react': 19.2.14 + react: 19.2.4 zwitch@2.0.4: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index cb3a6875f..fcaab6fcd 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -4,131 +4,133 @@ packages: - packages/* catalog: - '@aikidosec/safe-chain': 1.4.0 + '@aikidosec/safe-chain': 1.4.4 '@alloy-js/cli': 0.22.0 '@alloy-js/core': 0.22.0 '@alloy-js/typescript': 0.22.0 - '@better-auth/cli': 1.4.18 - '@bufbuild/buf': 1.63.0 - '@bufbuild/protobuf': 2.10.2 - '@bufbuild/protoc-gen-es': 2.10.2 - '@bufbuild/protovalidate': 1.1.0 - '@codemirror/autocomplete': 6.20.0 - '@codemirror/commands': 6.10.1 + '@better-auth/cli': 1.4.21 + '@bufbuild/buf': 1.66.0 + '@bufbuild/protobuf': 2.11.0 + '@bufbuild/protoc-gen-es': 2.11.0 + '@bufbuild/protovalidate': 1.1.1 + '@codemirror/autocomplete': 6.20.1 + '@codemirror/commands': 6.10.2 '@codemirror/lang-html': 6.4.11 - '@codemirror/lang-javascript': 6.2.4 + '@codemirror/lang-javascript': 6.2.5 '@codemirror/lang-json': 6.0.2 '@codemirror/lang-xml': 6.1.0 - '@codemirror/language': 6.12.1 - '@codemirror/state': 6.5.3 - '@codemirror/view': 6.39.9 + '@codemirror/language': 6.12.2 + '@codemirror/state': 6.5.4 + '@codemirror/view': 6.39.16 '@connectrpc/connect': 2.1.1 '@connectrpc/connect-node': 2.1.1 '@connectrpc/connect-query': 2.2.0 '@connectrpc/connect-web': 2.1.1 - '@effect-atom/atom-react': 0.4.4 - '@effect/cli': 0.73.0 - '@effect/platform': 0.94.1 + '@effect-atom/atom-react': 0.5.0 + '@effect/cli': 0.73.2 + '@effect/platform': 0.94.5 '@effect/platform-browser': 0.74.0 - '@effect/platform-node': 0.104.0 - '@eslint/compat': 2.0.0 + '@effect/platform-node': 0.104.1 + '@eslint/compat': 2.0.2 '@eslint/js': 9.39.2 - '@faker-js/faker': 10.2.0 + '@faker-js/faker': 10.3.0 '@fontsource-variable/dm-sans': 5.2.8 '@fontsource/dm-mono': 5.2.7 '@hookform/devtools': 4.4.0 '@hookform/resolvers': 5.2.2 '@lezer/generator': 1.8.0 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.7 - '@nx/eslint': 22.3.3 - '@nx/js': 22.3.3 - '@nx/react': 22.3.3 - '@nx/storybook': 22.3.3 - '@nx/vite': 22.3.3 - '@nx/web': 22.3.3 + '@lezer/lr': 1.4.8 + '@nx/eslint': 22.5.4 + '@nx/js': 22.5.4 + '@nx/react': 22.5.4 + '@nx/storybook': 22.5.4 + '@nx/vite': 22.5.4 + '@nx/web': 22.5.4 '@octokit/auth-action': 6.0.2 '@octokit/rest': 22.0.1 '@prettier/plugin-xml': 3.4.2 - '@react-aria/collections': 3.0.1 + '@react-aria/collections': 3.0.3 '@standard-schema/spec': 1.1.0 - '@storybook/addon-docs': 10.1.11 - '@storybook/react': 10.1.11 - '@storybook/react-vite': 10.1.11 + '@storybook/addon-docs': 10.2.16 + '@storybook/react': 10.2.16 + '@storybook/react-vite': 10.2.16 '@tailwindcss/typography': 0.5.19 - '@tailwindcss/vite': 4.1.18 - '@tanstack/eslint-plugin-router': 1.141.0 - '@tanstack/react-db': 0.1.60 - '@tanstack/react-query': 5.90.16 - '@tanstack/react-query-devtools': 5.91.2 - '@tanstack/react-router': 1.145.7 - '@tanstack/react-router-devtools': 1.145.7 - '@tanstack/router-plugin': 1.145.10 - '@tanstack/virtual-file-routes': 1.145.4 + '@tailwindcss/vite': 4.2.1 + '@tanstack/eslint-plugin-router': 1.161.4 + '@tanstack/react-db': 0.1.74 + '@tanstack/react-query': 5.90.21 + '@tanstack/react-query-devtools': 5.91.3 + '@tanstack/react-router': 1.166.2 + '@tanstack/react-router-devtools': 1.166.2 + '@tanstack/router-plugin': 1.166.2 + '@tanstack/virtual-file-routes': 1.161.4 '@tsconfig/strictest': 2.0.8 '@types/eslint-plugin-jsx-a11y': 6.10.1 - '@types/node': 25.0.3 - '@types/react': 19.2.7 + '@types/node': 25.3.5 + '@types/react': 19.2.14 '@types/react-dom': 19.2.3 '@types/react-timeago': 8.0.0 - '@typescript-eslint/parser': 8.52.0 - '@typespec/compiler': 1.7.1 - '@typespec/emitter-framework': 0.14.0 - '@typespec/prettier-plugin-typespec': 1.7.0 - '@uiw/react-codemirror': 4.25.4 - '@vitejs/plugin-react': 5.1.2 + '@typescript-eslint/parser': 8.56.1 + '@typespec/compiler': 1.9.0 + '@typespec/emitter-framework': 0.16.0 + '@typespec/prettier-plugin-typespec': 1.9.0 + '@uiw/react-codemirror': 4.25.7 + '@vitejs/plugin-react': 5.1.4 '@xyflow/react': 12.10.1 babel-plugin-react-compiler: 19.1.0-rc.3 - better-auth: 1.4.18 + better-auth: 1.5.4 builder-util-runtime: 9.5.1 - effect: 3.19.14 - electron: 39.2.7 - electron-builder: 26.3.1 + effect: 3.19.19 + electron: 40.8.0 + electron-builder: 26.8.1 electron-devtools-installer: 4.0.0 + electron-updater: 6.8.3 electron-vite: 5.0.0 eslint: 9.39.2 eslint-config-prettier: 10.1.8 eslint-import-resolver-typescript: 4.4.4 - eslint-plugin-better-tailwindcss: 3.8.0 + eslint-plugin-better-tailwindcss: 4.3.2 eslint-plugin-import-x: 4.16.1 eslint-plugin-jsx-a11y: 6.10.2 - eslint-plugin-perfectionist: 5.3.0 + eslint-plugin-perfectionist: 5.6.0 eslint-plugin-react: 7.37.5 eslint-plugin-react-hooks: 7.0.1 - globals: 17.0.0 + globals: 17.4.0 id128: 1.6.6 jiti: 2.6.1 - nx: 22.3.3 - openai: 4.77.0 - prettier: 3.7.4 - react: 19.2.3 - react-aria: 3.45.0 - react-aria-components: 1.14.0 - react-dom: 19.2.3 - react-error-boundary: 6.0.2 - react-icons: 5.5.0 + nx: 22.5.4 + openai: 6.27.0 + prettier: 3.8.1 + react: 19.2.4 + react-aria: 3.47.0 + react-aria-components: 1.16.0 + react-dom: 19.2.4 + react-error-boundary: 6.1.1 + react-icons: 5.6.0 react-markdown: 10.1.0 - react-resizable-panels: 4.3.0 - react-scan: 0.4.3 - react-stately: 3.43.0 + react-resizable-panels: 4.7.1 + react-scan: 0.5.3 + react-stately: 3.45.0 react-timeago: 8.3.0 remark-gfm: 4.0.1 - storybook: 10.1.11 + storybook: 10.2.16 swc-node: 1.0.0 syncpack: 13.0.4 - tailwind-merge: 3.4.0 + tailwind-merge: 3.5.0 tailwind-variants: 3.2.2 - tailwindcss: 4.1.18 + tailwindcss: 4.2.1 tailwindcss-react-aria-components: 2.0.1 ts-node: 10.9.2 tsup: 8.5.1 + tsx: ^4.21.0 tw-animate-css: 1.4.0 typescript: 5.9.3 - typescript-eslint: 8.52.0 - undici: 7.18.2 - use-debounce: 10.0.6 + typescript-eslint: 8.56.1 + undici: 7.22.0 + use-debounce: 10.1.0 vite: 7.3.1 - vite-tsconfig-paths: 6.0.3 + vite-tsconfig-paths: 6.1.1 vitest: 4.0.18 yaml: 2.8.2 @@ -162,6 +164,7 @@ overrides: '@codemirror/language': 6.12.1 '@codemirror/state': 6.5.3 '@codemirror/view': 6.39.9 + '@lezer/common': 1.5.1 '@types/eslint': '-' patchedDependencies: diff --git a/scoop.json b/scoop.json index 10eb1754e..c4bb80e07 100644 --- a/scoop.json +++ b/scoop.json @@ -1,68 +1,68 @@ { + "buckets": [ + { + "Name": "main", + "Source": "https://github.com/ScoopInstaller/Main.git", + "Updated": "2026-03-01T20:30:21+00:00", + "Manifests": 1449 + } + ], "apps": [ { "Info": "", - "Updated": "2025-11-24T00:09:42.6740987+00:00", "Name": "7zip", - "Version": "25.01", - "Source": "main" + "Updated": "2026-03-02T00:11:42.5461877+00:00", + "Source": "main", + "Version": "26.00" }, { "Info": "", - "Updated": "2025-11-24T00:09:52.0812649+00:00", "Name": "gcc", - "Version": "13.2.0", - "Source": "main" + "Updated": "2026-03-02T00:11:55.5410061+00:00", + "Source": "main", + "Version": "15.2.0" }, { "Info": "", - "Updated": "2025-12-29T00:12:40.2282169+00:00", "Name": "go", - "Version": "1.25.5", - "Source": "main" + "Updated": "2026-03-02T00:12:48.7592051+00:00", + "Source": "main", + "Version": "1.26.0" }, { "Info": "", - "Updated": "2025-11-24T00:10:40.0177047+00:00", "Name": "jq", - "Version": "1.8.1", - "Source": "main" + "Updated": "2026-03-02T00:12:49.0700649+00:00", + "Source": "main", + "Version": "1.8.1" }, { "Info": "", - "Updated": "2025-11-24T00:11:28.9374828+00:00", "Name": "mingw", - "Version": "15.2.0-rt_v13-rev0", - "Source": "main" + "Updated": "2026-03-02T00:13:39.1655567+00:00", + "Source": "main", + "Version": "15.2.0-rt_v13-rev1" }, { "Info": "", - "Updated": "2025-11-24T00:11:38.5272031+00:00", "Name": "nodejs", - "Version": "25.2.1", - "Source": "main" + "Updated": "2026-03-02T00:13:47.8899354+00:00", + "Source": "main", + "Version": "25.7.0" }, { "Info": "", - "Updated": "2025-12-29T00:12:41.4945252+00:00", "Name": "pnpm", - "Version": "10.26.2", - "Source": "main" + "Updated": "2026-03-02T00:13:48.5868567+00:00", + "Source": "main", + "Version": "10.30.3" }, { "Info": "", - "Updated": "2025-12-29T00:12:42.3442632+00:00", "Name": "task", - "Version": "3.46.4", - "Source": "main" - } - ], - "buckets": [ - { - "Name": "main", - "Source": "https://github.com/ScoopInstaller/Main.git", - "Updated": "2025-12-28T20:29:45+00:00", - "Manifests": 1412 + "Updated": "2026-03-02T00:13:49.2456734+00:00", + "Source": "main", + "Version": "3.48.0" } ] } diff --git a/tools/eslint/config.ts b/tools/eslint/config.ts index 6b985fae0..7030b7aed 100644 --- a/tools/eslint/config.ts +++ b/tools/eslint/config.ts @@ -137,7 +137,7 @@ const rules = defineConfig({ 'warn', { group: 'emptyLine', preferSingleLine: true, printWidth: 120 }, ], - 'better-tailwindcss/enforce-consistent-variable-syntax': ['warn', { syntax: 'parentheses' }], + 'better-tailwindcss/enforce-consistent-variable-syntax': ['warn', { syntax: 'variable' }], }, }); From 3d58fae34446ae1fe8f102f52c6acf5eb4834e98 Mon Sep 17 00:00:00 2001 From: moosebay Date: Sat, 7 Mar 2026 05:57:00 +0300 Subject: [PATCH 2/5] feat: GraphQL delta UI, tab fixes, header delta service fixes, and flow node docs - Add DeltaResetButton to GraphQL top-bar (name), query editor, and variables editor - Replace inline URL with delta-aware GraphQLUrl component in top-bar - Wire delta-aware delete and send in GraphQL top-bar - Add onStay hooks to all route files (HTTP, GraphQL, WS, Flow, Credential) for tab creation - Fix tab active state: use exact route matching to prevent parent highlighting on delta pages - Add GraphQL delta to file system sidebar (FileKind enum, model, converters, migration, UI) - Fix GraphQL header delta service: Create now passes delta fields, add UpdateDelta method - Fix header delta RPC handler to call UpdateDelta instead of Update - Add UpdateGraphQLHeaderDelta sqlc query - Fix converter.go missing GraphQL/WebSocket/GraphQLDelta cases in ToAPIFileKind - Add NEW_FLOW_NODE.md comprehensive checklist for adding new flow node types --- .../client/src/features/file-system/index.tsx | 218 +++- .../credential/$credentialIdCan/index.tsx | 11 + .../flow/routes/flow/$flowIdCan/route.tsx | 11 + .../pages/graphql/request/query-editor.tsx | 30 +- .../src/pages/graphql/request/top-bar.tsx | 61 +- .../graphql/request/variables-editor.tsx | 32 +- .../delta.$deltaGraphqlIdCan.tsx | 9 + .../routes/graphql/$graphqlIdCan/index.tsx | 9 + .../http/$httpIdCan/delta.$deltaHttpIdCan.tsx | 9 + .../http/routes/http/$httpIdCan/index.tsx | 9 + .../websocket/$websocketIdCan/index.tsx | 9 + packages/client/src/widgets/tabs/index.tsx | 1 + packages/db/pkg/sqlc/gen/db.go | 10 + packages/db/pkg/sqlc/gen/graphql.sql.go | 37 +- packages/db/pkg/sqlc/queries/graphql.sql | 13 +- packages/db/pkg/sqlc/schema/03_files.sql | 4 +- packages/server/cmd/serverrun/serverrun.go | 1 + packages/server/docs/specs/NEW_FLOW_NODE.md | 959 ++++++++++++++++++ packages/server/internal/api/rfile/rfile.go | 4 + .../server/internal/api/rflowv2/rflowv2.go | 3 + .../api/rflowv2/rflowv2_copy_paste.go | 33 +- .../api/rgraphql/rgraphql_crud_assert.go | 10 + .../rgraphql/rgraphql_crud_header_delta.go | 2 +- .../internal/api/rgraphql/rgraphql_exec.go | 21 +- .../api/rgraphql/rgraphql_exec_assert.go | 37 +- .../internal/api/rreference/rreference.go | 219 ++++ .../server/internal/converter/converter.go | 6 + .../01KK31SQ_add_graphql_delta_file_kind.go | 122 +++ packages/server/pkg/ioworkspace/types.go | 1 + packages/server/pkg/model/mfile/mfile.go | 14 +- .../server/pkg/service/sgraphql/header.go | 38 +- packages/spec/api/file-system.tsp | 1 + 32 files changed, 1846 insertions(+), 98 deletions(-) create mode 100644 packages/server/docs/specs/NEW_FLOW_NODE.md create mode 100644 packages/server/internal/migrations/01KK31SQ_add_graphql_delta_file_kind.go diff --git a/packages/client/src/features/file-system/index.tsx b/packages/client/src/features/file-system/index.tsx index 5cb800586..0b900f915 100644 --- a/packages/client/src/features/file-system/index.tsx +++ b/packages/client/src/features/file-system/index.tsx @@ -29,7 +29,10 @@ import { FolderSchema, } from '@the-dev-tools/spec/buf/api/file_system/v1/file_system_pb'; import { FlowSchema, FlowService } from '@the-dev-tools/spec/buf/api/flow/v1/flow_pb'; -import { GraphQLSchema as GraphQLItemSchema } from '@the-dev-tools/spec/buf/api/graph_q_l/v1/graph_q_l_pb'; +import { + GraphQLDeltaSchema, + GraphQLSchema as GraphQLItemSchema, +} from '@the-dev-tools/spec/buf/api/graph_q_l/v1/graph_q_l_pb'; import { HttpDeltaSchema, HttpMethod, HttpSchema, HttpService } from '@the-dev-tools/spec/buf/api/http/v1/http_pb'; import { WebSocketSchema as WebSocketItemSchema } from '@the-dev-tools/spec/buf/api/web_socket/v1/web_socket_pb'; import { @@ -40,7 +43,7 @@ import { } from '@the-dev-tools/spec/tanstack-db/v1/api/credential'; import { FileCollectionSchema, FolderCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/file_system'; import { FlowCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/flow'; -import { GraphQLCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/graph_q_l'; +import { GraphQLCollectionSchema, GraphQLDeltaCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/graph_q_l'; import { HttpCollectionSchema, HttpDeltaCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/http'; import { WebSocketCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/web_socket'; import { Button } from '@the-dev-tools/ui/button'; @@ -290,7 +293,9 @@ export const FileTree = ({ onAction, onSelectionChange, selectedKeys, selectionM if (dropPosition !== 'on') return false; const sourceCanMove = - !sourceKinds.has(`kind_${FileKind.UNSPECIFIED}`) && !sourceKinds.has(`kind_${FileKind.HTTP_DELTA}`); + !sourceKinds.has(`kind_${FileKind.UNSPECIFIED}`) && + !sourceKinds.has(`kind_${FileKind.HTTP_DELTA}`) && + !sourceKinds.has(`kind_${FileKind.GRAPH_Q_L_DELTA}`); const targetCanAccept = fileCollection.get(key.toString())?.kind === FileKind.FOLDER; return sourceCanMove && targetCanAccept; @@ -365,6 +370,7 @@ const FileItem = ({ id }: FileItemProps) => { Match.when(FileKind.HTTP_DELTA, () => ), Match.when(FileKind.FLOW, () => ), Match.when(FileKind.GRAPH_Q_L, () => ), + Match.when(FileKind.GRAPH_Q_L_DELTA, () => ), Match.when(FileKind.CREDENTIAL, () => ), Match.when(FileKind.WEB_SOCKET, () => ), Match.orElse(() => null), @@ -919,8 +925,9 @@ const FlowFile = ({ id }: FileItemProps) => { }; const GraphQLFile = ({ id }: FileItemProps) => { - const router = useRouter(); const matchRoute = useMatchRoute(); + const router = useRouter(); + const navigate = useNavigate(); const { theme } = useTheme(); @@ -942,6 +949,17 @@ const GraphQLFile = ({ id }: FileItemProps) => { [graphqlCollection, graphqlId], ).data ?? create(GraphQLItemSchema); + const deltaCollection = useApiCollection(GraphQLDeltaCollectionSchema); + + const { data: files } = useLiveQuery( + (_) => + _.from({ file: fileCollection }) + .where((_) => eq(_.file.parentId, graphqlId)) + .orderBy((_) => _.file.order) + .select((_) => pick(_.file, 'fileId', 'order')), + [fileCollection, graphqlId], + ); + const modal = useProgrammaticModal(); const exportMutation = useConnectMutation(ExportService.method.export); @@ -991,6 +1009,31 @@ const GraphQLFile = ({ id }: FileItemProps) => { + { + const deltaGraphqlId = Ulid.generate().bytes; + deltaCollection.utils.insert({ deltaGraphqlId, graphqlId }); + fileCollection.utils.insert({ + fileId: deltaGraphqlId, + kind: FileKind.GRAPH_Q_L_DELTA, + order: await getNextOrder(fileCollection), + parentId: graphqlId, + workspaceId, + }); + if (toNavigate) + await navigate({ + from: router.routesById[routes.dashboard.workspace.route.id].fullPath, + params: { + deltaGraphqlIdCan: Ulid.construct(deltaGraphqlId).toCanonical(), + graphqlIdCan: Ulid.construct(graphqlId).toCanonical(), + }, + to: router.routesById[routes.dashboard.workspace.graphql.delta.id].fullPath, + }); + }} + > + New delta + + void edit()}>Rename @@ -1061,8 +1104,175 @@ const GraphQLFile = ({ id }: FileItemProps) => { children: content, className: toNavigate && matchRoute(route) !== false ? tw`bg-neutral` : '', id, + item: (_) => , + items: files, onContextMenu, textValue: name, + } satisfies TreeItemProps<(typeof files)[number]>; + + return toNavigate ? : ; +}; + +const GraphQLDeltaFile = ({ id }: FileItemProps) => { + const router = useRouter(); + const matchRoute = useMatchRoute(); + + const { theme } = useTheme(); + + const { workspaceId } = routes.dashboard.workspace.route.useLoaderData(); + + const fileCollection = useApiCollection(FileCollectionSchema); + + const { fileId: deltaGraphqlId } = useMemo( + () => fileCollection.utils.parseKeyUnsafe(id), + [fileCollection.utils, id], + ); + + const deltaCollection = useApiCollection(GraphQLDeltaCollectionSchema); + + const { graphqlId } = + useLiveQuery( + (_) => + _.from({ item: deltaCollection }) + .where((_) => eq(_.item.deltaGraphqlId, deltaGraphqlId)) + .select((_) => pick(_.item, 'graphqlId')) + .findOne(), + [deltaCollection, deltaGraphqlId], + ).data ?? create(GraphQLDeltaSchema); + + const deltaOptions = { + deltaId: deltaGraphqlId, + deltaSchema: GraphQLDeltaCollectionSchema, + originId: graphqlId, + originSchema: GraphQLCollectionSchema, + } as const; + + const [name, setName] = useDeltaState({ ...deltaOptions, valueKey: 'name' }); + + const modal = useProgrammaticModal(); + + const exportMutation = useConnectMutation(ExportService.method.export); + const exportCurlGraphQLMutation = useConnectMutation(ExportService.method.exportCurlGraphQL); + + const { containerRef, navigate: toNavigate = false, showControls } = useContext(FileTreeContext); + + const { escapeRef, escapeRender } = useEscapePortal(containerRef); + + const { edit, isEditing, textFieldProps } = useEditableTextState({ + onSuccess: (_) => { + if (_ === name) return; + setName(_); + }, + value: name ?? '', + }); + + const { menuProps, menuTriggerProps, onContextMenu } = useContextMenuState(); + + const route = { + from: router.routesById[routes.dashboard.workspace.route.id].fullPath, + params: { + deltaGraphqlIdCan: Ulid.construct(deltaGraphqlId).toCanonical(), + graphqlIdCan: Ulid.construct(graphqlId).toCanonical(), + }, + to: router.routesById[routes.dashboard.workspace.graphql.delta.id].fullPath, + } satisfies ToOptions; + + const content = ( + <> + {modal.children && } + + GQL + + + {name} + + + {isEditing && + escapeRender( + , + )} + + {showControls && ( + + + + + void edit()}>Rename + + + Export + + + { + const { data, name } = await exportMutation.mutateAsync({ + fileIds: [deltaGraphqlId], + workspaceId, + }); + saveFile({ blobParts: [data], name }); + }} + > + YAML (DevTools) + + + { + const { data } = await exportCurlGraphQLMutation.mutateAsync({ + graphqlIds: [deltaGraphqlId], + workspaceId, + }); + modal.onOpenChange( + true, + + {({ close }) => ( + <> +
+ + cURL export + + + +
+ + + + )} +
, + ); + }} + > + cURL +
+
+
+ + void fileCollection.utils.delete({ fileId: deltaGraphqlId })} variant='danger'> + Delete + +
+
+ )} + + ); + + const props = { + children: content, + className: toNavigate && matchRoute(route) !== false ? tw`bg-neutral` : '', + id, + onContextMenu, + textValue: name ?? '', } satisfies TreeItemProps; return toNavigate ? : ; diff --git a/packages/client/src/pages/credential/routes/credential/$credentialIdCan/index.tsx b/packages/client/src/pages/credential/routes/credential/$credentialIdCan/index.tsx index b8d62475e..6c6cb6645 100644 --- a/packages/client/src/pages/credential/routes/credential/$credentialIdCan/index.tsx +++ b/packages/client/src/pages/credential/routes/credential/$credentialIdCan/index.tsx @@ -41,6 +41,17 @@ export const Route = createFileRoute( const { credentialId } = match.loaderData; + await openTab({ + id: credentialTabId(credentialId), + match, + node: , + }); + }, + onStay: async (match) => { + if (!match.loaderData) return; + + const { credentialId } = match.loaderData; + await openTab({ id: credentialTabId(credentialId), match, diff --git a/packages/client/src/pages/flow/routes/flow/$flowIdCan/route.tsx b/packages/client/src/pages/flow/routes/flow/$flowIdCan/route.tsx index 17652e69c..7416145ff 100644 --- a/packages/client/src/pages/flow/routes/flow/$flowIdCan/route.tsx +++ b/packages/client/src/pages/flow/routes/flow/$flowIdCan/route.tsx @@ -17,6 +17,17 @@ export const Route = createFileRoute('/(dashboard)/(workspace)/workspace/$worksp const { flowId } = match.loaderData; + await openTab({ + id: flowTabId(flowId), + match, + node: , + }); + }, + onStay: async (match) => { + if (!match.loaderData) return; + + const { flowId } = match.loaderData; + await openTab({ id: flowTabId(flowId), match, diff --git a/packages/client/src/pages/graphql/request/query-editor.tsx b/packages/client/src/pages/graphql/request/query-editor.tsx index 7ee41cf67..762702c1e 100644 --- a/packages/client/src/pages/graphql/request/query-editor.tsx +++ b/packages/client/src/pages/graphql/request/query-editor.tsx @@ -5,7 +5,7 @@ import { } from '@the-dev-tools/spec/tanstack-db/v1/api/graph_q_l'; import { tw } from '@the-dev-tools/ui/tailwind-literal'; import { useTheme } from '@the-dev-tools/ui/theme'; -import { useDeltaState } from '~/features/delta'; +import { DeltaResetButton, useDeltaState } from '~/features/delta'; export interface GraphQLQueryEditorProps { deltaGraphqlId?: Uint8Array | undefined; @@ -28,15 +28,23 @@ export const GraphQLQueryEditor = ({ deltaGraphqlId, graphqlId, isReadOnly = fal const [value, setValue] = useDeltaState(deltaOptions); return ( - void setValue(_)} - placeholder='Enter your GraphQL query...' - readOnly={isReadOnly} - theme={theme} - value={value ?? ''} - /> +
+ {!isReadOnly && ( +
+ +
+ )} + + void setValue(_)} + placeholder='Enter your GraphQL query...' + readOnly={isReadOnly} + theme={theme} + value={value ?? ''} + /> +
); }; diff --git a/packages/client/src/pages/graphql/request/top-bar.tsx b/packages/client/src/pages/graphql/request/top-bar.tsx index 19229b958..eb1cef64c 100644 --- a/packages/client/src/pages/graphql/request/top-bar.tsx +++ b/packages/client/src/pages/graphql/request/top-bar.tsx @@ -1,17 +1,21 @@ import { Array, pipe } from 'effect'; -import { useState, useTransition } from 'react'; +import { useTransition } from 'react'; import { Button as AriaButton, DialogTrigger, MenuTrigger } from 'react-aria-components'; import { FiClock, FiMoreHorizontal } from 'react-icons/fi'; import { GraphQLService } from '@the-dev-tools/spec/buf/api/graph_q_l/v1/graph_q_l_pb'; -import { GraphQLCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/graph_q_l'; +import { + GraphQLCollectionSchema, + GraphQLDeltaCollectionSchema, +} from '@the-dev-tools/spec/tanstack-db/v1/api/graph_q_l'; import { Button } from '@the-dev-tools/ui/button'; import { Menu, MenuItem, useContextMenuState } from '@the-dev-tools/ui/menu'; import { tw } from '@the-dev-tools/ui/tailwind-literal'; import { TextInputField, useEditableTextState } from '@the-dev-tools/ui/text-field'; -import { ReferenceField } from '~/features/expression'; +import { DeltaResetButton, useDeltaState } from '~/features/delta'; import { request, useApiCollection } from '~/shared/api'; import { routes } from '~/shared/routes'; import { HistoryModal } from '../history'; +import { GraphQLUrl } from './url'; export interface GraphQLTopBarProps { deltaGraphqlId?: Uint8Array | undefined; @@ -22,23 +26,30 @@ export const GraphQLTopBar = ({ deltaGraphqlId, graphqlId }: GraphQLTopBarProps) const { transport } = routes.root.useRouteContext(); const collection = useApiCollection(GraphQLCollectionSchema); + const deltaCollection = useApiCollection(GraphQLDeltaCollectionSchema); - const item = collection.get(collection.utils.getKey({ graphqlId })); + const deltaOptions = { + deltaId: deltaGraphqlId, + deltaSchema: GraphQLDeltaCollectionSchema, + isDelta: deltaGraphqlId !== undefined, + originId: graphqlId, + originSchema: GraphQLCollectionSchema, + }; + + const [name, setName] = useDeltaState({ ...deltaOptions, valueKey: 'name' }); const { menuProps, menuTriggerProps, onContextMenu } = useContextMenuState(); const { edit, isEditing, textFieldProps } = useEditableTextState({ onSuccess: (_) => { - if (_ === item?.name) return; - collection.utils.update({ graphqlId, name: _ }); + if (_ === name) return; + setName(_); }, - value: item?.name ?? '', + value: name ?? '', }); const [isSending, startTransition] = useTransition(); - const [urlState, setUrlState] = useState(); - return ( <>
@@ -59,9 +70,11 @@ export const GraphQLTopBar = ({ deltaGraphqlId, graphqlId }: GraphQLTopBarProps) onContextMenu={onContextMenu} onPress={() => void edit()} > - {item?.name} + {name} )} + +
@@ -80,7 +93,13 @@ export const GraphQLTopBar = ({ deltaGraphqlId, graphqlId }: GraphQLTopBarProps) void edit()}>Rename - collection.utils.delete({ graphqlId })} variant='danger'> + { + if (deltaGraphqlId) deltaCollection.utils.delete({ deltaGraphqlId }); + else collection.utils.delete({ graphqlId }); + }} + variant='danger' + > Delete @@ -88,34 +107,24 @@ export const GraphQLTopBar = ({ deltaGraphqlId, graphqlId }: GraphQLTopBarProps)
- { - if (urlState !== undefined) { - collection.utils.update({ graphqlId, url: urlState }); - } - }} - onChange={(_) => void setUrlState(_)} - value={urlState ?? item?.url ?? ''} - /> + + )} +
+ ))} + + + {!isReadOnly && ( + + )} + + + + + ); +}; diff --git a/packages/client/src/pages/flow/nodes/sub-flow-return.tsx b/packages/client/src/pages/flow/nodes/sub-flow-return.tsx new file mode 100644 index 000000000..a3ad78708 --- /dev/null +++ b/packages/client/src/pages/flow/nodes/sub-flow-return.tsx @@ -0,0 +1,123 @@ +import { create } from '@bufbuild/protobuf'; +import { eq, useLiveQuery } from '@tanstack/react-db'; +import * as XF from '@xyflow/react'; +import { Ulid } from 'id128'; +import { use } from 'react'; +import { FiCornerDownLeft, FiPlus, FiX } from 'react-icons/fi'; +import { NodeSubFlowReturnSchema } from '@the-dev-tools/spec/buf/api/flow/v1/flow_pb'; +import { NodeSubFlowReturnCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/flow'; +import { Button } from '@the-dev-tools/ui/button'; +import { FieldLabel } from '@the-dev-tools/ui/field'; +import { tw } from '@the-dev-tools/ui/tailwind-literal'; +import { TextInputField } from '@the-dev-tools/ui/text-field'; +import { ReferenceField } from '~/features/expression'; +import { useApiCollection } from '~/shared/api'; +import { pick } from '~/shared/lib'; +import { FlowContext } from '../context'; +import { Handle } from '../handle'; +import { NodeSettingsBody, NodeSettingsProps, SimpleNode } from '../node'; + +const defaultNodeSubFlowReturn = create(NodeSubFlowReturnSchema); + +export const SubFlowReturnNode = ({ id, selected }: XF.NodeProps) => { + const nodeId = Ulid.fromCanonical(id).bytes; + + return ( + } + icon={} + nodeId={nodeId} + selected={selected} + title='Sub-Flow Return' + /> + ); +}; + +export const SubFlowReturnSettings = ({ nodeId }: NodeSettingsProps) => { + const collection = useApiCollection(NodeSubFlowReturnCollectionSchema); + + const data = + useLiveQuery( + (_) => + _.from({ item: collection }) + .where((_) => eq(_.item.nodeId, nodeId)) + .select((_) => pick(_.item, 'outputs')) + .findOne(), + [collection, nodeId], + ).data ?? defaultNodeSubFlowReturn; + + const { isReadOnly = false } = use(FlowContext); + + return ( + +
+ Output Mappings +
+ Define values to return to the calling flow. Expressions are evaluated against this flow's variables. +
+ +
+ {data.outputs.map((output, index) => ( +
+
+ { + const outputs = [...data.outputs]; + outputs[index] = { ...outputs[index]!, name }; + collection.utils.updatePaced({ nodeId, outputs }); + }} + placeholder='Output name' + value={output.name} + /> + + { + const outputs = [...data.outputs]; + outputs[index] = { ...outputs[index]!, expression }; + collection.utils.updatePaced({ nodeId, outputs }); + }} + placeholder='Expression' + readOnly={isReadOnly} + value={output.expression} + /> +
+ + {!isReadOnly && ( + + )} +
+ ))} +
+ + {!isReadOnly && ( + + )} +
+
+ ); +}; diff --git a/packages/client/src/pages/flow/nodes/sub-flow-trigger.tsx b/packages/client/src/pages/flow/nodes/sub-flow-trigger.tsx new file mode 100644 index 000000000..b75f77c37 --- /dev/null +++ b/packages/client/src/pages/flow/nodes/sub-flow-trigger.tsx @@ -0,0 +1,210 @@ +import { create } from '@bufbuild/protobuf'; +import { json } from '@codemirror/lang-json'; +import { eq, useLiveQuery } from '@tanstack/react-db'; +import CodeMirror from '@uiw/react-codemirror'; +import * as XF from '@xyflow/react'; +import { Ulid } from 'id128'; +import { use, useMemo } from 'react'; +import { FiPlus, FiX, FiZap } from 'react-icons/fi'; +import { NodeSubFlowTriggerSchema } from '@the-dev-tools/spec/buf/api/flow/v1/flow_pb'; +import { NodeSubFlowTriggerCollectionSchema } from '@the-dev-tools/spec/tanstack-db/v1/api/flow'; +import { Button } from '@the-dev-tools/ui/button'; +import { FieldLabel } from '@the-dev-tools/ui/field'; +import { PlayIcon } from '@the-dev-tools/ui/icons'; +import { Select, SelectItem } from '@the-dev-tools/ui/select'; +import { tw } from '@the-dev-tools/ui/tailwind-literal'; +import { TextInputField } from '@the-dev-tools/ui/text-field'; +import { useTheme } from '@the-dev-tools/ui/theme'; +import { useApiCollection } from '~/shared/api'; +import { pick } from '~/shared/lib'; +import { FlowContext } from '../context'; +import { Handle } from '../handle'; +import { NodeSettingsBody, NodeSettingsProps, SimpleNode } from '../node'; + +const defaultNodeSubFlowTrigger = create(NodeSubFlowTriggerSchema); + +const paramTypes = ['string', 'number', 'boolean', 'json'] as const; + +const placeholderByType: Record = { + boolean: 'true or false', + json: '{"key": "value"} or [1, 2, 3]', + number: '0', + string: 'Default value', +}; + +export const SubFlowTriggerNode = ({ id, selected }: XF.NodeProps) => { + const nodeId = Ulid.fromCanonical(id).bytes; + + return ( + +
+ +
+ + + + } + icon={} + nodeId={nodeId} + selected={selected} + title='Sub-Flow Trigger' + /> + ); +}; + +export const SubFlowTriggerSettings = ({ nodeId }: NodeSettingsProps) => { + const collection = useApiCollection(NodeSubFlowTriggerCollectionSchema); + + const data = + useLiveQuery( + (_) => + _.from({ item: collection }) + .where((_) => eq(_.item.nodeId, nodeId)) + .select((_) => pick(_.item, 'params')) + .findOne(), + [collection, nodeId], + ).data ?? defaultNodeSubFlowTrigger; + + const { isReadOnly = false } = use(FlowContext); + + return ( + +
+ Input Parameters +
+ Define parameters that callers must provide when invoking this sub-flow. +
+ +
+ {data.params.map((param, index) => ( + + ))} +
+ + {!isReadOnly && ( + + )} +
+
+ ); +}; + +interface ParamRowProps { + collection: ReturnType>; + index: number; + isReadOnly: boolean; + nodeId: Uint8Array; + param: (typeof defaultNodeSubFlowTrigger.params)[number]; + params: typeof defaultNodeSubFlowTrigger.params; +} + +const ParamRow = ({ collection, index, isReadOnly, nodeId, param, params }: ParamRowProps) => { + const { theme } = useTheme(); + const jsonExtensions = useMemo(() => [json()], []); + + const updateParam = (patch: Partial) => { + const next = [...params]; + next[index] = { ...next[index]!, ...patch }; + collection.utils.updatePaced({ nodeId, params: next }); + }; + + // Normalize legacy 'any' type to 'string' for display + const displayType = param.type === 'any' || param.type === '' ? 'string' : param.type; + + return ( +
+
+ void updateParam({ name })} + placeholder='Parameter name' + value={param.name} + /> + +
+ + + {displayType === 'json' ? ( +
+ void updateParam({ defaultValue })} + placeholder={placeholderByType.json} + readOnly={isReadOnly} + theme={theme} + value={param.defaultValue} + /> +
+ ) : ( + void updateParam({ defaultValue })} + placeholder={placeholderByType[displayType] ?? 'Default value'} + value={param.defaultValue} + /> + )} + + +
+
+ + {!isReadOnly && ( + + )} +
+ ); +}; diff --git a/packages/client/src/pages/flow/nodes/ws-connection.tsx b/packages/client/src/pages/flow/nodes/ws-connection.tsx index 89ca512f4..4899b77e8 100644 --- a/packages/client/src/pages/flow/nodes/ws-connection.tsx +++ b/packages/client/src/pages/flow/nodes/ws-connection.tsx @@ -123,7 +123,7 @@ export const WsConnectionSettings = ({ nodeId }: NodeSettingsProps) => { } title='WebSocket Connection' > - + URL { }; export const WsSendSettings = ({ nodeId }: NodeSettingsProps) => { + const { workspaceId } = routes.dashboard.workspace.route.useLoaderData(); + const collection = useApiCollection(NodeWsSendCollectionSchema); const nodeCollection = useApiCollection(NodeCollectionSchema); @@ -72,28 +75,30 @@ export const WsSendSettings = ({ nodeId }: NodeSettingsProps) => { return ( - Connection - + + Connection + - Message - collection.utils.updatePaced({ message: _, nodeId })} - readOnly={isReadOnly} - value={message} - /> + Message + collection.utils.updatePaced({ message: _, nodeId })} + readOnly={isReadOnly} + value={message} + /> + ); }; diff --git a/packages/client/src/shared/api/collection.internal.tsx b/packages/client/src/shared/api/collection.internal.tsx index 03d896b80..9e161b78c 100644 --- a/packages/client/src/shared/api/collection.internal.tsx +++ b/packages/client/src/shared/api/collection.internal.tsx @@ -284,24 +284,26 @@ const createApiCollection = (schema: TSchem await waitForSync(mutationTime); }, onMutate: (input) => { + const itemSchema = update.input.field['items']!.message!; pipe( Array.ensure(input), - (_) => create(update.input, { items: _ }) as Message & { items: Item[] }, - (_) => - Array.map(_.items, (delta) => { - params.collection.update(getKey(delta), (draft: Item) => { - draftDelta(draft, delta, UnsetSchema); - }); - }), + Array.map((_) => createDelta(itemSchema, _ as Record)), + Array.map((delta) => { + params.collection.update(getKey(delta as Item), (draft: Item) => { + draftDelta(draft, delta, UnsetSchema); + }); + }), ); }, }); + const updateItemSchema = update.input.field['items']!.message!; + (operations as { updatePaced: Operation<'update'> }).updatePaced = createPacedMutations({ mutationFn: async ({ transaction }) => { const mutationTime = Date.now(); const items = transaction.mutations.map((_) => - createDelta(update.input.field['items']!.message!, { + createDelta(updateItemSchema, { ...parseKeyUnsafe(_.key as string), ..._.changes, }), @@ -312,13 +314,12 @@ const createApiCollection = (schema: TSchem onMutate: (input) => { pipe( Array.ensure(input), - (_) => create(update.input, { items: _ }) as Message & { items: Item[] }, - (_) => - Array.map(_.items, (delta) => { - params.collection.update(getKey(delta), (draft: Item) => { - draftDelta(draft, delta, UnsetSchema); - }); - }), + Array.map((_) => createDelta(updateItemSchema, _ as Record)), + Array.map((delta) => { + params.collection.update(getKey(delta as Item), (draft: Item) => { + draftDelta(draft, delta, UnsetSchema); + }); + }), ); }, strategy: debounceStrategy({ wait: 200 }), diff --git a/packages/client/src/shared/api/protobuf.tsx b/packages/client/src/shared/api/protobuf.tsx index 233d8cbbc..2aec7761f 100644 --- a/packages/client/src/shared/api/protobuf.tsx +++ b/packages/client/src/shared/api/protobuf.tsx @@ -139,7 +139,7 @@ export const createDelta = (schema: T, value: Record { if (!isUnionDesc(schema.field[key]?.message)) return value; // TODO: deduplicate spec union kind enums and un-hardcode numeric value - if (!value) return { kind: 183079996 /* UNSET */, unset: 0 }; + if (value == null) return { kind: 183079996 /* UNSET */, unset: 0 }; return { kind: 165745230 /* VALUE */, value }; }); diff --git a/packages/db/pkg/sqlc/gen/db.go b/packages/db/pkg/sqlc/gen/db.go index 865a998f7..b755345b9 100644 --- a/packages/db/pkg/sqlc/gen/db.go +++ b/packages/db/pkg/sqlc/gen/db.go @@ -141,6 +141,15 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) { if q.cleanupOrphanedFlowNodeJsStmt, err = db.PrepareContext(ctx, cleanupOrphanedFlowNodeJs); err != nil { return nil, fmt.Errorf("error preparing query CleanupOrphanedFlowNodeJs: %w", err) } + if q.cleanupOrphanedFlowNodeRunSubFlowStmt, err = db.PrepareContext(ctx, cleanupOrphanedFlowNodeRunSubFlow); err != nil { + return nil, fmt.Errorf("error preparing query CleanupOrphanedFlowNodeRunSubFlow: %w", err) + } + if q.cleanupOrphanedFlowNodeSubFlowReturnStmt, err = db.PrepareContext(ctx, cleanupOrphanedFlowNodeSubFlowReturn); err != nil { + return nil, fmt.Errorf("error preparing query CleanupOrphanedFlowNodeSubFlowReturn: %w", err) + } + if q.cleanupOrphanedFlowNodeSubFlowTriggerStmt, err = db.PrepareContext(ctx, cleanupOrphanedFlowNodeSubFlowTrigger); err != nil { + return nil, fmt.Errorf("error preparing query CleanupOrphanedFlowNodeSubFlowTrigger: %w", err) + } if q.cleanupOrphanedFlowNodeWaitStmt, err = db.PrepareContext(ctx, cleanupOrphanedFlowNodeWait); err != nil { return nil, fmt.Errorf("error preparing query CleanupOrphanedFlowNodeWait: %w", err) } @@ -201,6 +210,15 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) { if q.createFlowNodeMemoryStmt, err = db.PrepareContext(ctx, createFlowNodeMemory); err != nil { return nil, fmt.Errorf("error preparing query CreateFlowNodeMemory: %w", err) } + if q.createFlowNodeRunSubFlowStmt, err = db.PrepareContext(ctx, createFlowNodeRunSubFlow); err != nil { + return nil, fmt.Errorf("error preparing query CreateFlowNodeRunSubFlow: %w", err) + } + if q.createFlowNodeSubFlowReturnStmt, err = db.PrepareContext(ctx, createFlowNodeSubFlowReturn); err != nil { + return nil, fmt.Errorf("error preparing query CreateFlowNodeSubFlowReturn: %w", err) + } + if q.createFlowNodeSubFlowTriggerStmt, err = db.PrepareContext(ctx, createFlowNodeSubFlowTrigger); err != nil { + return nil, fmt.Errorf("error preparing query CreateFlowNodeSubFlowTrigger: %w", err) + } if q.createFlowNodeWaitStmt, err = db.PrepareContext(ctx, createFlowNodeWait); err != nil { return nil, fmt.Errorf("error preparing query CreateFlowNodeWait: %w", err) } @@ -384,6 +402,15 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) { if q.deleteFlowNodeMemoryStmt, err = db.PrepareContext(ctx, deleteFlowNodeMemory); err != nil { return nil, fmt.Errorf("error preparing query DeleteFlowNodeMemory: %w", err) } + if q.deleteFlowNodeRunSubFlowStmt, err = db.PrepareContext(ctx, deleteFlowNodeRunSubFlow); err != nil { + return nil, fmt.Errorf("error preparing query DeleteFlowNodeRunSubFlow: %w", err) + } + if q.deleteFlowNodeSubFlowReturnStmt, err = db.PrepareContext(ctx, deleteFlowNodeSubFlowReturn); err != nil { + return nil, fmt.Errorf("error preparing query DeleteFlowNodeSubFlowReturn: %w", err) + } + if q.deleteFlowNodeSubFlowTriggerStmt, err = db.PrepareContext(ctx, deleteFlowNodeSubFlowTrigger); err != nil { + return nil, fmt.Errorf("error preparing query DeleteFlowNodeSubFlowTrigger: %w", err) + } if q.deleteFlowNodeWaitStmt, err = db.PrepareContext(ctx, deleteFlowNodeWait); err != nil { return nil, fmt.Errorf("error preparing query DeleteFlowNodeWait: %w", err) } @@ -597,6 +624,15 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) { if q.getFlowNodeMemoryStmt, err = db.PrepareContext(ctx, getFlowNodeMemory); err != nil { return nil, fmt.Errorf("error preparing query GetFlowNodeMemory: %w", err) } + if q.getFlowNodeRunSubFlowStmt, err = db.PrepareContext(ctx, getFlowNodeRunSubFlow); err != nil { + return nil, fmt.Errorf("error preparing query GetFlowNodeRunSubFlow: %w", err) + } + if q.getFlowNodeSubFlowReturnStmt, err = db.PrepareContext(ctx, getFlowNodeSubFlowReturn); err != nil { + return nil, fmt.Errorf("error preparing query GetFlowNodeSubFlowReturn: %w", err) + } + if q.getFlowNodeSubFlowTriggerStmt, err = db.PrepareContext(ctx, getFlowNodeSubFlowTrigger); err != nil { + return nil, fmt.Errorf("error preparing query GetFlowNodeSubFlowTrigger: %w", err) + } if q.getFlowNodeWaitStmt, err = db.PrepareContext(ctx, getFlowNodeWait); err != nil { return nil, fmt.Errorf("error preparing query GetFlowNodeWait: %w", err) } @@ -1032,9 +1068,18 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) { if q.updateFlowNodeMemoryStmt, err = db.PrepareContext(ctx, updateFlowNodeMemory); err != nil { return nil, fmt.Errorf("error preparing query UpdateFlowNodeMemory: %w", err) } + if q.updateFlowNodeRunSubFlowStmt, err = db.PrepareContext(ctx, updateFlowNodeRunSubFlow); err != nil { + return nil, fmt.Errorf("error preparing query UpdateFlowNodeRunSubFlow: %w", err) + } if q.updateFlowNodeStateStmt, err = db.PrepareContext(ctx, updateFlowNodeState); err != nil { return nil, fmt.Errorf("error preparing query UpdateFlowNodeState: %w", err) } + if q.updateFlowNodeSubFlowReturnStmt, err = db.PrepareContext(ctx, updateFlowNodeSubFlowReturn); err != nil { + return nil, fmt.Errorf("error preparing query UpdateFlowNodeSubFlowReturn: %w", err) + } + if q.updateFlowNodeSubFlowTriggerStmt, err = db.PrepareContext(ctx, updateFlowNodeSubFlowTrigger); err != nil { + return nil, fmt.Errorf("error preparing query UpdateFlowNodeSubFlowTrigger: %w", err) + } if q.updateFlowNodeWaitStmt, err = db.PrepareContext(ctx, updateFlowNodeWait); err != nil { return nil, fmt.Errorf("error preparing query UpdateFlowNodeWait: %w", err) } @@ -1364,6 +1409,21 @@ func (q *Queries) Close() error { err = fmt.Errorf("error closing cleanupOrphanedFlowNodeJsStmt: %w", cerr) } } + if q.cleanupOrphanedFlowNodeRunSubFlowStmt != nil { + if cerr := q.cleanupOrphanedFlowNodeRunSubFlowStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing cleanupOrphanedFlowNodeRunSubFlowStmt: %w", cerr) + } + } + if q.cleanupOrphanedFlowNodeSubFlowReturnStmt != nil { + if cerr := q.cleanupOrphanedFlowNodeSubFlowReturnStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing cleanupOrphanedFlowNodeSubFlowReturnStmt: %w", cerr) + } + } + if q.cleanupOrphanedFlowNodeSubFlowTriggerStmt != nil { + if cerr := q.cleanupOrphanedFlowNodeSubFlowTriggerStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing cleanupOrphanedFlowNodeSubFlowTriggerStmt: %w", cerr) + } + } if q.cleanupOrphanedFlowNodeWaitStmt != nil { if cerr := q.cleanupOrphanedFlowNodeWaitStmt.Close(); cerr != nil { err = fmt.Errorf("error closing cleanupOrphanedFlowNodeWaitStmt: %w", cerr) @@ -1464,6 +1524,21 @@ func (q *Queries) Close() error { err = fmt.Errorf("error closing createFlowNodeMemoryStmt: %w", cerr) } } + if q.createFlowNodeRunSubFlowStmt != nil { + if cerr := q.createFlowNodeRunSubFlowStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createFlowNodeRunSubFlowStmt: %w", cerr) + } + } + if q.createFlowNodeSubFlowReturnStmt != nil { + if cerr := q.createFlowNodeSubFlowReturnStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createFlowNodeSubFlowReturnStmt: %w", cerr) + } + } + if q.createFlowNodeSubFlowTriggerStmt != nil { + if cerr := q.createFlowNodeSubFlowTriggerStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createFlowNodeSubFlowTriggerStmt: %w", cerr) + } + } if q.createFlowNodeWaitStmt != nil { if cerr := q.createFlowNodeWaitStmt.Close(); cerr != nil { err = fmt.Errorf("error closing createFlowNodeWaitStmt: %w", cerr) @@ -1769,6 +1844,21 @@ func (q *Queries) Close() error { err = fmt.Errorf("error closing deleteFlowNodeMemoryStmt: %w", cerr) } } + if q.deleteFlowNodeRunSubFlowStmt != nil { + if cerr := q.deleteFlowNodeRunSubFlowStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing deleteFlowNodeRunSubFlowStmt: %w", cerr) + } + } + if q.deleteFlowNodeSubFlowReturnStmt != nil { + if cerr := q.deleteFlowNodeSubFlowReturnStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing deleteFlowNodeSubFlowReturnStmt: %w", cerr) + } + } + if q.deleteFlowNodeSubFlowTriggerStmt != nil { + if cerr := q.deleteFlowNodeSubFlowTriggerStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing deleteFlowNodeSubFlowTriggerStmt: %w", cerr) + } + } if q.deleteFlowNodeWaitStmt != nil { if cerr := q.deleteFlowNodeWaitStmt.Close(); cerr != nil { err = fmt.Errorf("error closing deleteFlowNodeWaitStmt: %w", cerr) @@ -2124,6 +2214,21 @@ func (q *Queries) Close() error { err = fmt.Errorf("error closing getFlowNodeMemoryStmt: %w", cerr) } } + if q.getFlowNodeRunSubFlowStmt != nil { + if cerr := q.getFlowNodeRunSubFlowStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getFlowNodeRunSubFlowStmt: %w", cerr) + } + } + if q.getFlowNodeSubFlowReturnStmt != nil { + if cerr := q.getFlowNodeSubFlowReturnStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getFlowNodeSubFlowReturnStmt: %w", cerr) + } + } + if q.getFlowNodeSubFlowTriggerStmt != nil { + if cerr := q.getFlowNodeSubFlowTriggerStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getFlowNodeSubFlowTriggerStmt: %w", cerr) + } + } if q.getFlowNodeWaitStmt != nil { if cerr := q.getFlowNodeWaitStmt.Close(); cerr != nil { err = fmt.Errorf("error closing getFlowNodeWaitStmt: %w", cerr) @@ -2849,11 +2954,26 @@ func (q *Queries) Close() error { err = fmt.Errorf("error closing updateFlowNodeMemoryStmt: %w", cerr) } } + if q.updateFlowNodeRunSubFlowStmt != nil { + if cerr := q.updateFlowNodeRunSubFlowStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateFlowNodeRunSubFlowStmt: %w", cerr) + } + } if q.updateFlowNodeStateStmt != nil { if cerr := q.updateFlowNodeStateStmt.Close(); cerr != nil { err = fmt.Errorf("error closing updateFlowNodeStateStmt: %w", cerr) } } + if q.updateFlowNodeSubFlowReturnStmt != nil { + if cerr := q.updateFlowNodeSubFlowReturnStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateFlowNodeSubFlowReturnStmt: %w", cerr) + } + } + if q.updateFlowNodeSubFlowTriggerStmt != nil { + if cerr := q.updateFlowNodeSubFlowTriggerStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateFlowNodeSubFlowTriggerStmt: %w", cerr) + } + } if q.updateFlowNodeWaitStmt != nil { if cerr := q.updateFlowNodeWaitStmt.Close(); cerr != nil { err = fmt.Errorf("error closing updateFlowNodeWaitStmt: %w", cerr) @@ -3147,6 +3267,9 @@ type Queries struct { cleanupOrphanedFlowNodeGraphQLStmt *sql.Stmt cleanupOrphanedFlowNodeHttpStmt *sql.Stmt cleanupOrphanedFlowNodeJsStmt *sql.Stmt + cleanupOrphanedFlowNodeRunSubFlowStmt *sql.Stmt + cleanupOrphanedFlowNodeSubFlowReturnStmt *sql.Stmt + cleanupOrphanedFlowNodeSubFlowTriggerStmt *sql.Stmt cleanupOrphanedFlowNodeWaitStmt *sql.Stmt cleanupOrphanedNodeExecutionsStmt *sql.Stmt createCredentialStmt *sql.Stmt @@ -3167,6 +3290,9 @@ type Queries struct { createFlowNodeHTTPStmt *sql.Stmt createFlowNodeJsStmt *sql.Stmt createFlowNodeMemoryStmt *sql.Stmt + createFlowNodeRunSubFlowStmt *sql.Stmt + createFlowNodeSubFlowReturnStmt *sql.Stmt + createFlowNodeSubFlowTriggerStmt *sql.Stmt createFlowNodeWaitStmt *sql.Stmt createFlowNodeWithStateStmt *sql.Stmt createFlowNodeWsConnectionStmt *sql.Stmt @@ -3228,6 +3354,9 @@ type Queries struct { deleteFlowNodeHTTPStmt *sql.Stmt deleteFlowNodeJsStmt *sql.Stmt deleteFlowNodeMemoryStmt *sql.Stmt + deleteFlowNodeRunSubFlowStmt *sql.Stmt + deleteFlowNodeSubFlowReturnStmt *sql.Stmt + deleteFlowNodeSubFlowTriggerStmt *sql.Stmt deleteFlowNodeWaitStmt *sql.Stmt deleteFlowNodeWsConnectionStmt *sql.Stmt deleteFlowNodeWsSendStmt *sql.Stmt @@ -3299,6 +3428,9 @@ type Queries struct { getFlowNodeHTTPStmt *sql.Stmt getFlowNodeJsStmt *sql.Stmt getFlowNodeMemoryStmt *sql.Stmt + getFlowNodeRunSubFlowStmt *sql.Stmt + getFlowNodeSubFlowReturnStmt *sql.Stmt + getFlowNodeSubFlowTriggerStmt *sql.Stmt getFlowNodeWaitStmt *sql.Stmt getFlowNodeWsConnectionStmt *sql.Stmt getFlowNodeWsSendStmt *sql.Stmt @@ -3444,7 +3576,10 @@ type Queries struct { updateFlowNodeIDMappingStmt *sql.Stmt updateFlowNodeJsStmt *sql.Stmt updateFlowNodeMemoryStmt *sql.Stmt + updateFlowNodeRunSubFlowStmt *sql.Stmt updateFlowNodeStateStmt *sql.Stmt + updateFlowNodeSubFlowReturnStmt *sql.Stmt + updateFlowNodeSubFlowTriggerStmt *sql.Stmt updateFlowNodeWaitStmt *sql.Stmt updateFlowNodeWsConnectionStmt *sql.Stmt updateFlowNodeWsSendStmt *sql.Stmt @@ -3533,6 +3668,9 @@ func (q *Queries) WithTx(tx *sql.Tx) *Queries { cleanupOrphanedFlowNodeGraphQLStmt: q.cleanupOrphanedFlowNodeGraphQLStmt, cleanupOrphanedFlowNodeHttpStmt: q.cleanupOrphanedFlowNodeHttpStmt, cleanupOrphanedFlowNodeJsStmt: q.cleanupOrphanedFlowNodeJsStmt, + cleanupOrphanedFlowNodeRunSubFlowStmt: q.cleanupOrphanedFlowNodeRunSubFlowStmt, + cleanupOrphanedFlowNodeSubFlowReturnStmt: q.cleanupOrphanedFlowNodeSubFlowReturnStmt, + cleanupOrphanedFlowNodeSubFlowTriggerStmt: q.cleanupOrphanedFlowNodeSubFlowTriggerStmt, cleanupOrphanedFlowNodeWaitStmt: q.cleanupOrphanedFlowNodeWaitStmt, cleanupOrphanedNodeExecutionsStmt: q.cleanupOrphanedNodeExecutionsStmt, createCredentialStmt: q.createCredentialStmt, @@ -3553,6 +3691,9 @@ func (q *Queries) WithTx(tx *sql.Tx) *Queries { createFlowNodeHTTPStmt: q.createFlowNodeHTTPStmt, createFlowNodeJsStmt: q.createFlowNodeJsStmt, createFlowNodeMemoryStmt: q.createFlowNodeMemoryStmt, + createFlowNodeRunSubFlowStmt: q.createFlowNodeRunSubFlowStmt, + createFlowNodeSubFlowReturnStmt: q.createFlowNodeSubFlowReturnStmt, + createFlowNodeSubFlowTriggerStmt: q.createFlowNodeSubFlowTriggerStmt, createFlowNodeWaitStmt: q.createFlowNodeWaitStmt, createFlowNodeWithStateStmt: q.createFlowNodeWithStateStmt, createFlowNodeWsConnectionStmt: q.createFlowNodeWsConnectionStmt, @@ -3614,6 +3755,9 @@ func (q *Queries) WithTx(tx *sql.Tx) *Queries { deleteFlowNodeHTTPStmt: q.deleteFlowNodeHTTPStmt, deleteFlowNodeJsStmt: q.deleteFlowNodeJsStmt, deleteFlowNodeMemoryStmt: q.deleteFlowNodeMemoryStmt, + deleteFlowNodeRunSubFlowStmt: q.deleteFlowNodeRunSubFlowStmt, + deleteFlowNodeSubFlowReturnStmt: q.deleteFlowNodeSubFlowReturnStmt, + deleteFlowNodeSubFlowTriggerStmt: q.deleteFlowNodeSubFlowTriggerStmt, deleteFlowNodeWaitStmt: q.deleteFlowNodeWaitStmt, deleteFlowNodeWsConnectionStmt: q.deleteFlowNodeWsConnectionStmt, deleteFlowNodeWsSendStmt: q.deleteFlowNodeWsSendStmt, @@ -3685,6 +3829,9 @@ func (q *Queries) WithTx(tx *sql.Tx) *Queries { getFlowNodeHTTPStmt: q.getFlowNodeHTTPStmt, getFlowNodeJsStmt: q.getFlowNodeJsStmt, getFlowNodeMemoryStmt: q.getFlowNodeMemoryStmt, + getFlowNodeRunSubFlowStmt: q.getFlowNodeRunSubFlowStmt, + getFlowNodeSubFlowReturnStmt: q.getFlowNodeSubFlowReturnStmt, + getFlowNodeSubFlowTriggerStmt: q.getFlowNodeSubFlowTriggerStmt, getFlowNodeWaitStmt: q.getFlowNodeWaitStmt, getFlowNodeWsConnectionStmt: q.getFlowNodeWsConnectionStmt, getFlowNodeWsSendStmt: q.getFlowNodeWsSendStmt, @@ -3830,7 +3977,10 @@ func (q *Queries) WithTx(tx *sql.Tx) *Queries { updateFlowNodeIDMappingStmt: q.updateFlowNodeIDMappingStmt, updateFlowNodeJsStmt: q.updateFlowNodeJsStmt, updateFlowNodeMemoryStmt: q.updateFlowNodeMemoryStmt, + updateFlowNodeRunSubFlowStmt: q.updateFlowNodeRunSubFlowStmt, updateFlowNodeStateStmt: q.updateFlowNodeStateStmt, + updateFlowNodeSubFlowReturnStmt: q.updateFlowNodeSubFlowReturnStmt, + updateFlowNodeSubFlowTriggerStmt: q.updateFlowNodeSubFlowTriggerStmt, updateFlowNodeWaitStmt: q.updateFlowNodeWaitStmt, updateFlowNodeWsConnectionStmt: q.updateFlowNodeWsConnectionStmt, updateFlowNodeWsSendStmt: q.updateFlowNodeWsSendStmt, diff --git a/packages/db/pkg/sqlc/gen/flow.sql.go b/packages/db/pkg/sqlc/gen/flow.sql.go index 5b262ffdb..b0faa1dd7 100644 --- a/packages/db/pkg/sqlc/gen/flow.sql.go +++ b/packages/db/pkg/sqlc/gen/flow.sql.go @@ -79,6 +79,33 @@ func (q *Queries) CleanupOrphanedFlowNodeJs(ctx context.Context) error { return err } +const cleanupOrphanedFlowNodeRunSubFlow = `-- name: CleanupOrphanedFlowNodeRunSubFlow :exec +DELETE FROM flow_node_run_sub_flow WHERE flow_node_id NOT IN (SELECT id FROM flow_node) +` + +func (q *Queries) CleanupOrphanedFlowNodeRunSubFlow(ctx context.Context) error { + _, err := q.exec(ctx, q.cleanupOrphanedFlowNodeRunSubFlowStmt, cleanupOrphanedFlowNodeRunSubFlow) + return err +} + +const cleanupOrphanedFlowNodeSubFlowReturn = `-- name: CleanupOrphanedFlowNodeSubFlowReturn :exec +DELETE FROM flow_node_sub_flow_return WHERE flow_node_id NOT IN (SELECT id FROM flow_node) +` + +func (q *Queries) CleanupOrphanedFlowNodeSubFlowReturn(ctx context.Context) error { + _, err := q.exec(ctx, q.cleanupOrphanedFlowNodeSubFlowReturnStmt, cleanupOrphanedFlowNodeSubFlowReturn) + return err +} + +const cleanupOrphanedFlowNodeSubFlowTrigger = `-- name: CleanupOrphanedFlowNodeSubFlowTrigger :exec +DELETE FROM flow_node_sub_flow_trigger WHERE flow_node_id NOT IN (SELECT id FROM flow_node) +` + +func (q *Queries) CleanupOrphanedFlowNodeSubFlowTrigger(ctx context.Context) error { + _, err := q.exec(ctx, q.cleanupOrphanedFlowNodeSubFlowTriggerStmt, cleanupOrphanedFlowNodeSubFlowTrigger) + return err +} + const cleanupOrphanedFlowNodeWait = `-- name: CleanupOrphanedFlowNodeWait :exec DELETE FROM flow_node_wait WHERE flow_node_id NOT IN (SELECT id FROM flow_node) ` @@ -303,6 +330,58 @@ func (q *Queries) CreateFlowNodeJs(ctx context.Context, arg CreateFlowNodeJsPara return err } +const createFlowNodeRunSubFlow = `-- name: CreateFlowNodeRunSubFlow :exec +INSERT INTO flow_node_run_sub_flow (flow_node_id, target_flow_id, target_flow_name, inputs) +VALUES (?, ?, ?, ?) +` + +type CreateFlowNodeRunSubFlowParams struct { + FlowNodeID idwrap.IDWrap + TargetFlowID *idwrap.IDWrap + TargetFlowName string + Inputs []byte +} + +func (q *Queries) CreateFlowNodeRunSubFlow(ctx context.Context, arg CreateFlowNodeRunSubFlowParams) error { + _, err := q.exec(ctx, q.createFlowNodeRunSubFlowStmt, createFlowNodeRunSubFlow, + arg.FlowNodeID, + arg.TargetFlowID, + arg.TargetFlowName, + arg.Inputs, + ) + return err +} + +const createFlowNodeSubFlowReturn = `-- name: CreateFlowNodeSubFlowReturn :exec +INSERT INTO flow_node_sub_flow_return (flow_node_id, outputs) +VALUES (?, ?) +` + +type CreateFlowNodeSubFlowReturnParams struct { + FlowNodeID idwrap.IDWrap + Outputs []byte +} + +func (q *Queries) CreateFlowNodeSubFlowReturn(ctx context.Context, arg CreateFlowNodeSubFlowReturnParams) error { + _, err := q.exec(ctx, q.createFlowNodeSubFlowReturnStmt, createFlowNodeSubFlowReturn, arg.FlowNodeID, arg.Outputs) + return err +} + +const createFlowNodeSubFlowTrigger = `-- name: CreateFlowNodeSubFlowTrigger :exec +INSERT INTO flow_node_sub_flow_trigger (flow_node_id, params) +VALUES (?, ?) +` + +type CreateFlowNodeSubFlowTriggerParams struct { + FlowNodeID idwrap.IDWrap + Params []byte +} + +func (q *Queries) CreateFlowNodeSubFlowTrigger(ctx context.Context, arg CreateFlowNodeSubFlowTriggerParams) error { + _, err := q.exec(ctx, q.createFlowNodeSubFlowTriggerStmt, createFlowNodeSubFlowTrigger, arg.FlowNodeID, arg.Params) + return err +} + const createFlowNodeWait = `-- name: CreateFlowNodeWait :exec INSERT INTO flow_node_wait (flow_node_id, duration_ms) @@ -1096,6 +1175,36 @@ func (q *Queries) DeleteFlowNodeJs(ctx context.Context, flowNodeID idwrap.IDWrap return err } +const deleteFlowNodeRunSubFlow = `-- name: DeleteFlowNodeRunSubFlow :exec +DELETE FROM flow_node_run_sub_flow +WHERE flow_node_id = ? +` + +func (q *Queries) DeleteFlowNodeRunSubFlow(ctx context.Context, flowNodeID idwrap.IDWrap) error { + _, err := q.exec(ctx, q.deleteFlowNodeRunSubFlowStmt, deleteFlowNodeRunSubFlow, flowNodeID) + return err +} + +const deleteFlowNodeSubFlowReturn = `-- name: DeleteFlowNodeSubFlowReturn :exec +DELETE FROM flow_node_sub_flow_return +WHERE flow_node_id = ? +` + +func (q *Queries) DeleteFlowNodeSubFlowReturn(ctx context.Context, flowNodeID idwrap.IDWrap) error { + _, err := q.exec(ctx, q.deleteFlowNodeSubFlowReturnStmt, deleteFlowNodeSubFlowReturn, flowNodeID) + return err +} + +const deleteFlowNodeSubFlowTrigger = `-- name: DeleteFlowNodeSubFlowTrigger :exec +DELETE FROM flow_node_sub_flow_trigger +WHERE flow_node_id = ? +` + +func (q *Queries) DeleteFlowNodeSubFlowTrigger(ctx context.Context, flowNodeID idwrap.IDWrap) error { + _, err := q.exec(ctx, q.deleteFlowNodeSubFlowTriggerStmt, deleteFlowNodeSubFlowTrigger, flowNodeID) + return err +} + const deleteFlowNodeWait = `-- name: DeleteFlowNodeWait :exec DELETE FROM flow_node_wait WHERE @@ -1629,6 +1738,56 @@ func (q *Queries) GetFlowNodeJs(ctx context.Context, flowNodeID idwrap.IDWrap) ( return i, err } +const getFlowNodeRunSubFlow = `-- name: GetFlowNodeRunSubFlow :one +SELECT flow_node_id, target_flow_id, target_flow_name, inputs +FROM flow_node_run_sub_flow +WHERE flow_node_id = ? +LIMIT 1 +` + +// Run Sub-Flow +func (q *Queries) GetFlowNodeRunSubFlow(ctx context.Context, flowNodeID idwrap.IDWrap) (FlowNodeRunSubFlow, error) { + row := q.queryRow(ctx, q.getFlowNodeRunSubFlowStmt, getFlowNodeRunSubFlow, flowNodeID) + var i FlowNodeRunSubFlow + err := row.Scan( + &i.FlowNodeID, + &i.TargetFlowID, + &i.TargetFlowName, + &i.Inputs, + ) + return i, err +} + +const getFlowNodeSubFlowReturn = `-- name: GetFlowNodeSubFlowReturn :one +SELECT flow_node_id, outputs +FROM flow_node_sub_flow_return +WHERE flow_node_id = ? +LIMIT 1 +` + +// Sub-Flow Return +func (q *Queries) GetFlowNodeSubFlowReturn(ctx context.Context, flowNodeID idwrap.IDWrap) (FlowNodeSubFlowReturn, error) { + row := q.queryRow(ctx, q.getFlowNodeSubFlowReturnStmt, getFlowNodeSubFlowReturn, flowNodeID) + var i FlowNodeSubFlowReturn + err := row.Scan(&i.FlowNodeID, &i.Outputs) + return i, err +} + +const getFlowNodeSubFlowTrigger = `-- name: GetFlowNodeSubFlowTrigger :one +SELECT flow_node_id, params +FROM flow_node_sub_flow_trigger +WHERE flow_node_id = ? +LIMIT 1 +` + +// Sub-Flow Trigger +func (q *Queries) GetFlowNodeSubFlowTrigger(ctx context.Context, flowNodeID idwrap.IDWrap) (FlowNodeSubFlowTrigger, error) { + row := q.queryRow(ctx, q.getFlowNodeSubFlowTriggerStmt, getFlowNodeSubFlowTrigger, flowNodeID) + var i FlowNodeSubFlowTrigger + err := row.Scan(&i.FlowNodeID, &i.Params) + return i, err +} + const getFlowNodeWait = `-- name: GetFlowNodeWait :one SELECT flow_node_id, @@ -2747,6 +2906,29 @@ func (q *Queries) UpdateFlowNodeJs(ctx context.Context, arg UpdateFlowNodeJsPara return err } +const updateFlowNodeRunSubFlow = `-- name: UpdateFlowNodeRunSubFlow :exec +UPDATE flow_node_run_sub_flow +SET target_flow_id = ?, target_flow_name = ?, inputs = ? +WHERE flow_node_id = ? +` + +type UpdateFlowNodeRunSubFlowParams struct { + TargetFlowID *idwrap.IDWrap + TargetFlowName string + Inputs []byte + FlowNodeID idwrap.IDWrap +} + +func (q *Queries) UpdateFlowNodeRunSubFlow(ctx context.Context, arg UpdateFlowNodeRunSubFlowParams) error { + _, err := q.exec(ctx, q.updateFlowNodeRunSubFlowStmt, updateFlowNodeRunSubFlow, + arg.TargetFlowID, + arg.TargetFlowName, + arg.Inputs, + arg.FlowNodeID, + ) + return err +} + const updateFlowNodeState = `-- name: UpdateFlowNodeState :exec UPDATE flow_node SET @@ -2765,6 +2947,38 @@ func (q *Queries) UpdateFlowNodeState(ctx context.Context, arg UpdateFlowNodeSta return err } +const updateFlowNodeSubFlowReturn = `-- name: UpdateFlowNodeSubFlowReturn :exec +UPDATE flow_node_sub_flow_return +SET outputs = ? +WHERE flow_node_id = ? +` + +type UpdateFlowNodeSubFlowReturnParams struct { + Outputs []byte + FlowNodeID idwrap.IDWrap +} + +func (q *Queries) UpdateFlowNodeSubFlowReturn(ctx context.Context, arg UpdateFlowNodeSubFlowReturnParams) error { + _, err := q.exec(ctx, q.updateFlowNodeSubFlowReturnStmt, updateFlowNodeSubFlowReturn, arg.Outputs, arg.FlowNodeID) + return err +} + +const updateFlowNodeSubFlowTrigger = `-- name: UpdateFlowNodeSubFlowTrigger :exec +UPDATE flow_node_sub_flow_trigger +SET params = ? +WHERE flow_node_id = ? +` + +type UpdateFlowNodeSubFlowTriggerParams struct { + Params []byte + FlowNodeID idwrap.IDWrap +} + +func (q *Queries) UpdateFlowNodeSubFlowTrigger(ctx context.Context, arg UpdateFlowNodeSubFlowTriggerParams) error { + _, err := q.exec(ctx, q.updateFlowNodeSubFlowTriggerStmt, updateFlowNodeSubFlowTrigger, arg.Params, arg.FlowNodeID) + return err +} + const updateFlowNodeWait = `-- name: UpdateFlowNodeWait :exec UPDATE flow_node_wait SET diff --git a/packages/db/pkg/sqlc/gen/models.go b/packages/db/pkg/sqlc/gen/models.go index 0f01990c4..7ec47cc5b 100644 --- a/packages/db/pkg/sqlc/gen/models.go +++ b/packages/db/pkg/sqlc/gen/models.go @@ -201,6 +201,23 @@ type FlowNodeMemory struct { WindowSize int32 } +type FlowNodeRunSubFlow struct { + FlowNodeID idwrap.IDWrap + TargetFlowID *idwrap.IDWrap + TargetFlowName string + Inputs []byte +} + +type FlowNodeSubFlowReturn struct { + FlowNodeID idwrap.IDWrap + Outputs []byte +} + +type FlowNodeSubFlowTrigger struct { + FlowNodeID idwrap.IDWrap + Params []byte +} + type FlowNodeWait struct { FlowNodeID idwrap.IDWrap DurationMs int64 diff --git a/packages/db/pkg/sqlc/queries/flow.sql b/packages/db/pkg/sqlc/queries/flow.sql index db9763adf..53434776c 100644 --- a/packages/db/pkg/sqlc/queries/flow.sql +++ b/packages/db/pkg/sqlc/queries/flow.sql @@ -771,6 +771,75 @@ DELETE FROM flow_node_js WHERE flow_node_id NOT IN (SELECT id FROM flow_node); -- name: CleanupOrphanedFlowNodeWait :exec DELETE FROM flow_node_wait WHERE flow_node_id NOT IN (SELECT id FROM flow_node); +-- Sub-Flow Trigger +-- name: GetFlowNodeSubFlowTrigger :one +SELECT flow_node_id, params +FROM flow_node_sub_flow_trigger +WHERE flow_node_id = ? +LIMIT 1; + +-- name: CreateFlowNodeSubFlowTrigger :exec +INSERT INTO flow_node_sub_flow_trigger (flow_node_id, params) +VALUES (?, ?); + +-- name: UpdateFlowNodeSubFlowTrigger :exec +UPDATE flow_node_sub_flow_trigger +SET params = ? +WHERE flow_node_id = ?; + +-- name: DeleteFlowNodeSubFlowTrigger :exec +DELETE FROM flow_node_sub_flow_trigger +WHERE flow_node_id = ?; + +-- name: CleanupOrphanedFlowNodeSubFlowTrigger :exec +DELETE FROM flow_node_sub_flow_trigger WHERE flow_node_id NOT IN (SELECT id FROM flow_node); + +-- Sub-Flow Return +-- name: GetFlowNodeSubFlowReturn :one +SELECT flow_node_id, outputs +FROM flow_node_sub_flow_return +WHERE flow_node_id = ? +LIMIT 1; + +-- name: CreateFlowNodeSubFlowReturn :exec +INSERT INTO flow_node_sub_flow_return (flow_node_id, outputs) +VALUES (?, ?); + +-- name: UpdateFlowNodeSubFlowReturn :exec +UPDATE flow_node_sub_flow_return +SET outputs = ? +WHERE flow_node_id = ?; + +-- name: DeleteFlowNodeSubFlowReturn :exec +DELETE FROM flow_node_sub_flow_return +WHERE flow_node_id = ?; + +-- name: CleanupOrphanedFlowNodeSubFlowReturn :exec +DELETE FROM flow_node_sub_flow_return WHERE flow_node_id NOT IN (SELECT id FROM flow_node); + +-- Run Sub-Flow +-- name: GetFlowNodeRunSubFlow :one +SELECT flow_node_id, target_flow_id, target_flow_name, inputs +FROM flow_node_run_sub_flow +WHERE flow_node_id = ? +LIMIT 1; + +-- name: CreateFlowNodeRunSubFlow :exec +INSERT INTO flow_node_run_sub_flow (flow_node_id, target_flow_id, target_flow_name, inputs) +VALUES (?, ?, ?, ?); + +-- name: UpdateFlowNodeRunSubFlow :exec +UPDATE flow_node_run_sub_flow +SET target_flow_id = ?, target_flow_name = ?, inputs = ? +WHERE flow_node_id = ?; + +-- name: DeleteFlowNodeRunSubFlow :exec +DELETE FROM flow_node_run_sub_flow +WHERE flow_node_id = ?; + +-- name: CleanupOrphanedFlowNodeRunSubFlow :exec +DELETE FROM flow_node_run_sub_flow WHERE flow_node_id NOT IN (SELECT id FROM flow_node); + -- name: CleanupOrphanedFlowEdges :exec DELETE FROM flow_edge WHERE source_id NOT IN (SELECT id FROM flow_node) OR target_id NOT IN (SELECT id FROM flow_node); diff --git a/packages/db/pkg/sqlc/schema/05_flow.sql b/packages/db/pkg/sqlc/schema/05_flow.sql index c80a925c4..e7dd8dcb3 100644 --- a/packages/db/pkg/sqlc/schema/05_flow.sql +++ b/packages/db/pkg/sqlc/schema/05_flow.sql @@ -108,6 +108,24 @@ CREATE TABLE flow_node_wait ( duration_ms BIGINT NOT NULL ); +CREATE TABLE flow_node_sub_flow_trigger ( + flow_node_id BLOB NOT NULL PRIMARY KEY, + params BLOB NOT NULL DEFAULT '[]' +); + +CREATE TABLE flow_node_sub_flow_return ( + flow_node_id BLOB NOT NULL PRIMARY KEY, + outputs BLOB NOT NULL DEFAULT '[]' +); + +CREATE TABLE flow_node_run_sub_flow ( + flow_node_id BLOB NOT NULL PRIMARY KEY, + target_flow_id BLOB, + target_flow_name TEXT NOT NULL DEFAULT '', + inputs BLOB NOT NULL DEFAULT '[]', + FOREIGN KEY (target_flow_id) REFERENCES flow (id) ON DELETE SET NULL +); + CREATE TABLE flow_variable ( id BLOB NOT NULL PRIMARY KEY, flow_id BLOB NOT NULL, diff --git a/packages/db/pkg/sqlc/sqlc.yaml b/packages/db/pkg/sqlc/sqlc.yaml index b8a7e5067..2a5aa0a14 100644 --- a/packages/db/pkg/sqlc/sqlc.yaml +++ b/packages/db/pkg/sqlc/sqlc.yaml @@ -985,3 +985,27 @@ sql: import: 'github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap' package: 'idwrap' type: 'IDWrap' + ### flow_node_sub_flow_trigger table + - column: 'flow_node_sub_flow_trigger.flow_node_id' + go_type: + import: 'github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap' + package: 'idwrap' + type: 'IDWrap' + ### flow_node_sub_flow_return table + - column: 'flow_node_sub_flow_return.flow_node_id' + go_type: + import: 'github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap' + package: 'idwrap' + type: 'IDWrap' + ### flow_node_run_sub_flow table + - column: 'flow_node_run_sub_flow.flow_node_id' + go_type: + import: 'github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap' + package: 'idwrap' + type: 'IDWrap' + - column: 'flow_node_run_sub_flow.target_flow_id' + go_type: + import: 'github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap' + package: 'idwrap' + type: 'IDWrap' + pointer: true diff --git a/packages/server/cmd/serverrun/serverrun.go b/packages/server/cmd/serverrun/serverrun.go index 518f655fd..e2a7d3481 100644 --- a/packages/server/cmd/serverrun/serverrun.go +++ b/packages/server/cmd/serverrun/serverrun.go @@ -198,6 +198,9 @@ func Run() error { flowNodeWsConnectionService := sflow.NewNodeWsConnectionService(queries) flowNodeWsSendService := sflow.NewNodeWsSendService(queries) flowNodeWaitService := sflow.NewNodeWaitService(queries) + flowNodeSubFlowTriggerService := sflow.NewNodeSubFlowTriggerService(queries) + flowNodeSubFlowReturnService := sflow.NewNodeSubFlowReturnService(queries) + flowNodeRunSubFlowService := sflow.NewNodeRunSubFlowService(queries) // WebSocket websocketService := swebsocket.New(queries, logger) @@ -478,7 +481,10 @@ func Run() error { NodeGraphQL: &flowNodeGraphQLService, NodeWsConnection: &flowNodeWsConnectionService, NodeWsSend: &flowNodeWsSendService, - NodeWait: &flowNodeWaitService, + NodeWait: &flowNodeWaitService, + NodeSubFlowTrigger: &flowNodeSubFlowTriggerService, + NodeSubFlowReturn: &flowNodeSubFlowReturnService, + NodeRunSubFlow: &flowNodeRunSubFlowService, WebSocket: &websocketService, WebSocketHeader: &websocketHeaderService, NodeExecution: &nodeExecutionService, @@ -634,7 +640,8 @@ func Run() error { FlowEdge: flowEdgeReader, NodeExecution: nodeExecutionReader, HttpResponse: httpResponseReader, - GraphQLResponse: &graphqlResponseService, + GraphQLResponse: &graphqlResponseService, + NodeSubFlowTrigger: &flowNodeSubFlowTriggerService, }, }) newServiceManager.addService(rreference.CreateService(refServiceRPC, optionsAll)) diff --git a/packages/server/docs/specs/NEW_FLOW_NODE.md b/packages/server/docs/specs/NEW_FLOW_NODE.md index e5c18ba1a..00c183123 100644 --- a/packages/server/docs/specs/NEW_FLOW_NODE.md +++ b/packages/server/docs/specs/NEW_FLOW_NODE.md @@ -189,6 +189,17 @@ type struct { These bridge between API types (protobuf) and DB types (sqlc gen). Keep them pure Go — no dependencies on protobuf or sqlc packages. +### Node Kind Converter + +**File:** `packages/server/internal/converter/converter.go` + +Add a case for the new `NODE_KIND_` in `ToAPINodeKind()`. This function converts model `mflow.NodeKind` to API `flowv1.NodeKind` and is called by `serializeNode()` for every sync response. **If the case is missing, the kind falls through to `NODE_KIND_UNSPECIFIED` and the client renders the node as invisible.** + +```go +case mflow.NODE_KIND_: + return flowv1.NodeKind_NODE_KIND_ +``` + --- ## 4. Server Service Layer @@ -312,6 +323,8 @@ func (n *Node) RunSync(ctx context.Context, req *node.FlowNodeRequest) nod } ``` +**Expression evaluation:** If the node evaluates user-provided expressions that come from the client's `ReferenceField` UI, use `env.EvalInterpolated()` — NOT `env.Eval()`. The `ReferenceField` stores expressions in `{{ }}` template format (e.g., `{{ http_0.response.body.id }}`). `EvalInterpolated()` handles both `{{ }}` wrapped expressions and raw expressions, while `Eval()` only handles raw expr-lang syntax and will fail on the `{{ }}` format with a cryptic compile error. + **Existing executor packages** (for reference): - `nrequest` — HTTP requests - `ngraphql` — GraphQL queries @@ -775,6 +788,15 @@ Assertions validate response data after execution: Add the new node type to the reference service so variables like `{{ NodeName.response.body }}` resolve correctly across flow nodes. Only nodes that write output variables (via `WriteNodeVarBulk`) need a reference service entry. Passive nodes (e.g., Memory) that don't produce output should be skipped — the `default` case handles them correctly. +The reference service has **three switch statements** that all need the new node kind case: +1. **`ReferenceSchema`** (~line 640) — returns the variable schema (type structure) for the node +2. **`ReferenceCompletion`** (~line 989) — returns autocomplete suggestions when typing `{{ nodeName.` }} +3. **`ReferenceValue`** (~line 1531) — returns the actual runtime values for variable preview + +**Parameter-based nodes** (e.g., SubFlowTrigger): Some nodes have user-configured parameters that define their output variables, rather than producing output from execution results. For these, inject the node's type-specific service into `ReferenceServiceRPC` and `ReferenceServiceRPCReaders`, then build a variable map from the node's parameter definitions. Example: SubFlowTrigger injects `NodeSubFlowTriggerService` and builds a map from `trigger.Params`. + +**Wiring:** After adding the service to the `ReferenceServiceRPC` struct, also wire it in `serverrun.go` where `ReferenceServiceRPCReaders` is constructed. + ### 12f. Migration **File:** `packages/server/internal/migrations/01XXXXX_add__.go` @@ -785,6 +807,9 @@ Create a migration that adds the new tables. Follow the existing pattern — reg ## Common Pitfalls +### Missing `ToAPINodeKind` Case — Invisible Nodes +If `ToAPINodeKind()` in `converter.go` doesn't have a case for the new `NODE_KIND_`, every sync response serializes the node with `kind = UNSPECIFIED`. The client maps `UNSPECIFIED` to `() => null`, so the node appears briefly (optimistic insert with correct kind) then becomes invisible when the sync response overwrites it with `UNSPECIFIED`. No errors are logged anywhere — completely silent. + ### Sync Events Silently Dropped The most insidious bug. If a CRUD handler calls `mut.Insert()` or `mut.Update()` without a separate `mut.Track(Event{Payload: model})`, the sync event has no payload. The publisher silently drops it (model is nil). The client never receives the update. Data persists in DB but UI doesn't reflect changes until page refresh. Always verify sync works end-to-end. @@ -815,6 +840,12 @@ Three common gaps when adding delta support to sub-entities (headers, assertions 2. **No `UpdateDelta` method** — The service only has a base `Update` that writes base columns. Delta field updates silently do nothing because the `Update` SQL doesn't touch `delta_*` columns. Fix: add an `UpdateDelta` query in sqlc and a corresponding service method. 3. **Handler calls `Update` instead of `UpdateDelta`** — The delta update RPC handler modifies the model's `Delta*` fields in memory, then calls `Update()` which only persists base fields. The delta changes are discarded. Returns 400 if `is_delta` is checked (since the DB row has `is_delta = false` from gap #1). Fix: call `UpdateDelta` in the handler. +### Expression Evaluation — `Eval()` vs `EvalInterpolated()` +If the node evaluates expressions that come from the client's `ReferenceField` UI component, you MUST use `env.EvalInterpolated()`, not `env.Eval()`. The `ReferenceField` stores expressions in `{{ }}` template format (e.g., `{{ http_0.response.body }}`). `Eval()` only handles raw expr-lang syntax and fails on `{{ }}` with an error like `expression "{{ foo.bar }}" failed during compile: a map key must be a quoted string`. `EvalInterpolated()` handles both formats. This affects any node that uses `expression.NewUnifiedEnv()` to evaluate user-provided input/output mappings. + +### Reference Service — Missing Switch Cases or Service Wiring +The reference service (`rreference.go`) has **three** switch statements on `NodeKind`: `ReferenceSchema`, `ReferenceCompletion`, and `ReferenceValue`. If ANY of the three is missing a case for the new node kind, autocomplete won't work for that node's variables. The symptoms are subtle — no error, just empty completion suggestions when pressing Ctrl+Space. For parameter-based nodes (like SubFlowTrigger), the service also needs the type-specific node service injected into both `ReferenceServiceRPC` and `ReferenceServiceRPCReaders` (wired in `serverrun.go`). + ### Tab Active State — Parent Route Highlighting on Delta Pages TanStack Router's link `activeOptions` defaults to `{ exact: false }`. When viewing a delta page (e.g., `/graphql/$id/delta/$deltaId`), the parent route (`/graphql/$id`) also matches as "active". This causes both the original request tab and the delta tab to highlight simultaneously. Fix: add `activeOptions={{ exact: true }}` to tab link components. @@ -908,6 +939,7 @@ This means: - [ ] Model structs created (`pkg/model/m/`) - [ ] Flow node model added to `pkg/model/mflow/node_types.go` - [ ] Node kind constant added to `pkg/model/mflow/node.go` +- [ ] `ToAPINodeKind()` case added in `internal/converter/converter.go` - [ ] Service reader/writer created (`pkg/service/s/`) - [ ] Flow node service created (`pkg/service/sflow/node_*.go` — service, reader, writer, mapper) - [ ] Node kind mapping added to `pkg/service/sflow/node_mapper.go` @@ -921,6 +953,7 @@ This means: - [ ] Executor package created (`pkg/flow/node/n/`) - [ ] Implements `FlowNode` interface (`GetID`, `GetName`, `RunSync`, `RunAsync`) - [ ] Implements `VariableIntrospector` (optional, for AI integration) +- [ ] Uses `EvalInterpolated()` (not `Eval()`) for expressions from ReferenceField UI ### RPC & Wiring - [ ] RPC handlers created (`internal/api/r/`) @@ -953,6 +986,11 @@ This means: - [ ] CodeMirror editors (query, variables, raw body) have `DeltaResetButton` - [ ] Tab links use `activeOptions={{ exact: true }}` to prevent parent route highlighting +### Reference Service +- [ ] All three switch statements updated (`ReferenceSchema`, `ReferenceCompletion`, `ReferenceValue`) +- [ ] Type-specific service injected if node has user-configured parameters +- [ ] Service wired in `serverrun.go` `ReferenceServiceRPCReaders` + ### Verification - [ ] CRUD handlers have `mut.Track()` with Payload for sync - [ ] All tests pass (`task test`) diff --git a/packages/server/internal/api/rflowv2/logging_test.go b/packages/server/internal/api/rflowv2/logging_test.go index be32c3e7f..0c7b1afe4 100644 --- a/packages/server/internal/api/rflowv2/logging_test.go +++ b/packages/server/internal/api/rflowv2/logging_test.go @@ -85,6 +85,9 @@ func TestFlowRun_Logging(t *testing.T) { nil, // NodeWsConnectionService nil, // NodeWsSendService nil, // NodeWaitService + nil, // NodeSubFlowTriggerService + nil, // NodeSubFlowReturnService + nil, // NodeRunSubFlowService nil, // WebSocketService nil, // WebSocketHeaderService nil, // GraphQLService diff --git a/packages/server/internal/api/rflowv2/rflowv2.go b/packages/server/internal/api/rflowv2/rflowv2.go index 8c79ce31b..144c7bea7 100644 --- a/packages/server/internal/api/rflowv2/rflowv2.go +++ b/packages/server/internal/api/rflowv2/rflowv2.go @@ -296,7 +296,10 @@ type FlowServiceV2Services struct { NodeGraphQL *sflow.NodeGraphQLService NodeWsConnection *sflow.NodeWsConnectionService NodeWsSend *sflow.NodeWsSendService - NodeWait *sflow.NodeWaitService + NodeWait *sflow.NodeWaitService + NodeSubFlowTrigger *sflow.NodeSubFlowTriggerService + NodeSubFlowReturn *sflow.NodeSubFlowReturnService + NodeRunSubFlow *sflow.NodeRunSubFlowService WebSocket *swebsocket.WebSocketService WebSocketHeader *swebsocket.WebSocketHeaderService NodeExecution *sflow.NodeExecutionService @@ -463,6 +466,9 @@ type FlowServiceV2RPC struct { nwcs *sflow.NodeWsConnectionService nwss *sflow.NodeWsSendService nwaits *sflow.NodeWaitService + nsfts *sflow.NodeSubFlowTriggerService + nsfrs *sflow.NodeSubFlowReturnService + nrsfs *sflow.NodeRunSubFlowService wsService *swebsocket.WebSocketService wsHeaderService *swebsocket.WebSocketHeaderService gqls *sgraphql.GraphQLService @@ -531,12 +537,18 @@ func New(deps FlowServiceV2Deps) *FlowServiceV2RPC { deps.Services.NodeIf, deps.Services.NodeJs, deps.Services.NodeAI, deps.Services.NodeAiProvider, deps.Services.NodeMemory, deps.Services.NodeGraphQL, deps.Services.NodeWsConnection, deps.Services.NodeWsSend, deps.Services.NodeWait, + deps.Services.NodeSubFlowTrigger, deps.Services.NodeSubFlowReturn, deps.Services.NodeRunSubFlow, deps.Services.WebSocket, deps.Services.WebSocketHeader, deps.Services.GraphQL, deps.Services.GraphQLHeader, deps.Services.Workspace, deps.Services.Var, deps.Services.FlowVariable, deps.Resolver, deps.GraphQLResolver, deps.Logger, llmFactory, ) + // Wire sub-flow executor so RunSubFlow nodes can invoke other flows + builder.SubFlowExecutor = flowbuilder.NewSubFlowExecutor( + builder, deps.Services.Flow, deps.Services.Edge, deps.JsClient, deps.Logger, + ) + // Build snapshot registry for flow version snapshots registry := flowexec.NewSnapshotRegistry() registry.Register(&flowexec.RequestSnapshot{Service: deps.Services.NodeRequest}) @@ -565,6 +577,15 @@ func New(deps FlowServiceV2Deps) *FlowServiceV2RPC { if deps.Services.NodeWait != nil { registry.Register(&flowexec.WaitSnapshot{Service: deps.Services.NodeWait}) } + if deps.Services.NodeSubFlowTrigger != nil { + registry.Register(&flowexec.SubFlowTriggerSnapshot{Service: deps.Services.NodeSubFlowTrigger}) + } + if deps.Services.NodeSubFlowReturn != nil { + registry.Register(&flowexec.SubFlowReturnSnapshot{Service: deps.Services.NodeSubFlowReturn}) + } + if deps.Services.NodeRunSubFlow != nil { + registry.Register(&flowexec.RunSubFlowSnapshot{Service: deps.Services.NodeRunSubFlow}) + } return &FlowServiceV2RPC{ DB: deps.DB, @@ -590,6 +611,9 @@ func New(deps FlowServiceV2Deps) *FlowServiceV2RPC { nwcs: deps.Services.NodeWsConnection, nwss: deps.Services.NodeWsSend, nwaits: deps.Services.NodeWait, + nsfts: deps.Services.NodeSubFlowTrigger, + nsfrs: deps.Services.NodeSubFlowReturn, + nrsfs: deps.Services.NodeRunSubFlow, wsService: deps.Services.WebSocket, wsHeaderService: deps.Services.WebSocketHeader, gqls: deps.Services.GraphQL, @@ -716,6 +740,12 @@ func (p *rflowPublisher) PublishAll(events []mutation.Event) { p.publishNodeWsSend(evt) case mutation.EntityFlowNodeWait: p.publishNodeWait(evt) + case mutation.EntityFlowNodeSubFlowTrigger: + p.publishNodeSubFlowTrigger(evt) + case mutation.EntityFlowNodeSubFlowReturn: + p.publishNodeSubFlowReturn(evt) + case mutation.EntityFlowNodeRunSubFlow: + p.publishNodeRunSubFlow(evt) case mutation.EntityFlowEdge: p.publishEdge(evt) case mutation.EntityFlowVariable: @@ -1317,3 +1347,123 @@ func (p *rflowPublisher) publishNodeWait(evt mutation.Event) { }) } } + +func (p *rflowPublisher) publishNodeSubFlowTrigger(evt mutation.Event) { + if p.nodeStream == nil { + return + } + + var node *flowv1.Node + var flowID idwrap.IDWrap + var eventType string + + switch evt.Op { + case mutation.OpInsert: + eventType = nodeEventInsert + if data, ok := evt.Payload.(nodeSubFlowTriggerWithFlow); ok && data.baseNode != nil { + node = serializeNode(*data.baseNode) + flowID = data.flowID + } + case mutation.OpUpdate: + eventType = nodeEventUpdate + if data, ok := evt.Payload.(nodeSubFlowTriggerWithFlow); ok && data.baseNode != nil { + node = serializeNode(*data.baseNode) + flowID = data.flowID + } + case mutation.OpDelete: + eventType = nodeEventDelete + node = &flowv1.Node{ + NodeId: evt.ID.Bytes(), + FlowId: evt.ParentID.Bytes(), + } + flowID = evt.ParentID + } + + if node != nil { + p.nodeStream.Publish(NodeTopic{FlowID: flowID}, NodeEvent{ + Type: eventType, + FlowID: flowID, + Node: node, + }) + } +} + +func (p *rflowPublisher) publishNodeSubFlowReturn(evt mutation.Event) { + if p.nodeStream == nil { + return + } + + var node *flowv1.Node + var flowID idwrap.IDWrap + var eventType string + + switch evt.Op { + case mutation.OpInsert: + eventType = nodeEventInsert + if data, ok := evt.Payload.(nodeSubFlowReturnWithFlow); ok && data.baseNode != nil { + node = serializeNode(*data.baseNode) + flowID = data.flowID + } + case mutation.OpUpdate: + eventType = nodeEventUpdate + if data, ok := evt.Payload.(nodeSubFlowReturnWithFlow); ok && data.baseNode != nil { + node = serializeNode(*data.baseNode) + flowID = data.flowID + } + case mutation.OpDelete: + eventType = nodeEventDelete + node = &flowv1.Node{ + NodeId: evt.ID.Bytes(), + FlowId: evt.ParentID.Bytes(), + } + flowID = evt.ParentID + } + + if node != nil { + p.nodeStream.Publish(NodeTopic{FlowID: flowID}, NodeEvent{ + Type: eventType, + FlowID: flowID, + Node: node, + }) + } +} + +func (p *rflowPublisher) publishNodeRunSubFlow(evt mutation.Event) { + if p.nodeStream == nil { + return + } + + var node *flowv1.Node + var flowID idwrap.IDWrap + var eventType string + + switch evt.Op { + case mutation.OpInsert: + eventType = nodeEventInsert + if data, ok := evt.Payload.(nodeRunSubFlowWithFlow); ok && data.baseNode != nil { + node = serializeNode(*data.baseNode) + flowID = data.flowID + } + case mutation.OpUpdate: + eventType = nodeEventUpdate + if data, ok := evt.Payload.(nodeRunSubFlowWithFlow); ok && data.baseNode != nil { + node = serializeNode(*data.baseNode) + flowID = data.flowID + } + case mutation.OpDelete: + eventType = nodeEventDelete + node = &flowv1.Node{ + NodeId: evt.ID.Bytes(), + FlowId: evt.ParentID.Bytes(), + } + flowID = evt.ParentID + } + + if node != nil { + p.nodeStream.Publish(NodeTopic{FlowID: flowID}, NodeEvent{ + Type: eventType, + FlowID: flowID, + Node: node, + }) + } +} diff --git a/packages/server/internal/api/rflowv2/rflowv2_copy_paste.go b/packages/server/internal/api/rflowv2/rflowv2_copy_paste.go index 92d7c2246..5ed3c2b9c 100644 --- a/packages/server/internal/api/rflowv2/rflowv2_copy_paste.go +++ b/packages/server/internal/api/rflowv2/rflowv2_copy_paste.go @@ -194,6 +194,26 @@ func (s *FlowServiceV2RPC) FlowNodesCopy( bundle.FlowWaitNodes = append(bundle.FlowWaitNodes, *d) } } + case mflow.NODE_KIND_SUB_FLOW_TRIGGER: + if s.nsfts != nil { + if d, err := s.nsfts.GetNodeSubFlowTrigger(ctx, n.ID); err == nil && d != nil { + bundle.FlowSubFlowTriggerNodes = append(bundle.FlowSubFlowTriggerNodes, *d) + } + } + case mflow.NODE_KIND_SUB_FLOW_RETURN: + if s.nsfrs != nil { + if d, err := s.nsfrs.GetNodeSubFlowReturn(ctx, n.ID); err == nil && d != nil { + bundle.FlowSubFlowReturnNodes = append(bundle.FlowSubFlowReturnNodes, *d) + } + } + case mflow.NODE_KIND_RUN_SUB_FLOW: + if s.nrsfs != nil { + if d, err := s.nrsfs.GetNodeRunSubFlow(ctx, n.ID); err == nil && d != nil { + bundle.FlowRunSubFlowNodes = append(bundle.FlowRunSubFlowNodes, *d) + } + } + case mflow.NODE_KIND_WEBHOOK_TRIGGER: + // Not yet implemented } } @@ -450,6 +470,21 @@ func (s *FlowServiceV2RPC) FlowNodesPaste( parsed.FlowWaitNodes[i].FlowNodeID = newID } } + for i := range parsed.FlowSubFlowTriggerNodes { + if newID, ok := nodeIDMapping[parsed.FlowSubFlowTriggerNodes[i].FlowNodeID]; ok { + parsed.FlowSubFlowTriggerNodes[i].FlowNodeID = newID + } + } + for i := range parsed.FlowSubFlowReturnNodes { + if newID, ok := nodeIDMapping[parsed.FlowSubFlowReturnNodes[i].FlowNodeID]; ok { + parsed.FlowSubFlowReturnNodes[i].FlowNodeID = newID + } + } + for i := range parsed.FlowRunSubFlowNodes { + if newID, ok := nodeIDMapping[parsed.FlowRunSubFlowNodes[i].FlowNodeID]; ok { + parsed.FlowRunSubFlowNodes[i].FlowNodeID = newID + } + } // Remap variable references in expression fields when node names changed if len(nameMapping) > 0 { @@ -515,6 +550,18 @@ func (s *FlowServiceV2RPC) FlowNodesPaste( for i := range parsed.WebSocketHeaders { parsed.WebSocketHeaders[i].Value = remapVarRefs(parsed.WebSocketHeaders[i].Value, nameMapping) } + for i := range parsed.FlowSubFlowReturnNodes { + for j := range parsed.FlowSubFlowReturnNodes[i].Outputs { + parsed.FlowSubFlowReturnNodes[i].Outputs[j].Expression = remapVarRefs( + parsed.FlowSubFlowReturnNodes[i].Outputs[j].Expression, nameMapping) + } + } + for i := range parsed.FlowRunSubFlowNodes { + for j := range parsed.FlowRunSubFlowNodes[i].Inputs { + parsed.FlowRunSubFlowNodes[i].Inputs[j].Expression = remapVarRefs( + parsed.FlowRunSubFlowNodes[i].Inputs[j].Expression, nameMapping) + } + } } // Remap edges @@ -933,6 +980,30 @@ func (s *FlowServiceV2RPC) FlowNodesPaste( } } } + if s.nsfts != nil { + for _, n := range parsed.FlowSubFlowTriggerNodes { + w := sflow.NewNodeSubFlowTriggerWriter(tx) + if err := w.CreateNodeSubFlowTrigger(ctx, n); err != nil { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to create sub-flow trigger node: %w", err)) + } + } + } + if s.nsfrs != nil { + for _, n := range parsed.FlowSubFlowReturnNodes { + w := sflow.NewNodeSubFlowReturnWriter(tx) + if err := w.CreateNodeSubFlowReturn(ctx, n); err != nil { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to create sub-flow return node: %w", err)) + } + } + } + if s.nrsfs != nil { + for _, n := range parsed.FlowRunSubFlowNodes { + w := sflow.NewNodeRunSubFlowWriter(tx) + if err := w.CreateNodeRunSubFlow(ctx, n); err != nil { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to create run sub-flow node: %w", err)) + } + } + } // Create edges for _, e := range validEdges { diff --git a/packages/server/internal/api/rflowv2/rflowv2_exec_test.go b/packages/server/internal/api/rflowv2/rflowv2_exec_test.go index 2eb1e5a75..c1b9f9953 100644 --- a/packages/server/internal/api/rflowv2/rflowv2_exec_test.go +++ b/packages/server/internal/api/rflowv2/rflowv2_exec_test.go @@ -80,6 +80,9 @@ func setupTestService(t *testing.T) (*FlowServiceV2RPC, *gen.Queries, context.Co nil, // NodeWsConnectionService nil, // NodeWsSendService nil, // NodeWaitService + nil, // NodeSubFlowTriggerService + nil, // NodeSubFlowReturnService + nil, // NodeRunSubFlowService nil, // WebSocketService nil, // WebSocketHeaderService nil, // GraphQLService diff --git a/packages/server/internal/api/rflowv2/rflowv2_flow.go b/packages/server/internal/api/rflowv2/rflowv2_flow.go index 7d464c54d..37fc3ccef 100644 --- a/packages/server/internal/api/rflowv2/rflowv2_flow.go +++ b/packages/server/internal/api/rflowv2/rflowv2_flow.go @@ -35,14 +35,23 @@ func (s *FlowServiceV2RPC) FlowCollection( ctx context.Context, _ *connect.Request[emptypb.Empty], ) (*connect.Response[flowv1.FlowCollectionResponse], error) { - flows, err := s.listAccessibleFlows(ctx) + workspaces, err := s.listUserWorkspaces(ctx) if err != nil { return nil, err } - items := make([]*flowv1.Flow, 0, len(flows)) - for _, flow := range flows { - items = append(items, serializeFlow(flow)) + var items []*flowv1.Flow + for _, ws := range workspaces { + flows, err := s.fsReader.GetFlowsByWorkspaceID(ctx, ws.ID) + if err != nil { + if errors.Is(err, sflow.ErrNoFlowFound) { + continue + } + return nil, connect.NewError(connect.CodeInternal, err) + } + for _, flow := range flows { + items = append(items, serializeFlow(flow)) + } } return connect.NewResponse(&flowv1.FlowCollectionResponse{Items: items}), nil @@ -544,9 +553,12 @@ func (s *FlowServiceV2RPC) FlowDuplicate(ctx context.Context, req *connect.Reque aiProvider *mflow.NodeAiProvider memoryNode *mflow.NodeMemory graphqlNode *mflow.NodeGraphQL - wsConnectionNode *mflow.NodeWsConnection - wsSendNode *mflow.NodeWsSend - waitNode *mflow.NodeWait + wsConnectionNode *mflow.NodeWsConnection + wsSendNode *mflow.NodeWsSend + waitNode *mflow.NodeWait + subFlowTriggerNode *mflow.NodeSubFlowTrigger + subFlowReturnNode *mflow.NodeSubFlowReturn + runSubFlowNode *mflow.NodeRunSubFlow } details := make([]nodeDetail, 0, len(sourceNodes)) for _, n := range sourceNodes { @@ -621,6 +633,26 @@ func (s *FlowServiceV2RPC) FlowDuplicate(ctx context.Context, req *connect.Reque detail.waitNode = d } } + case mflow.NODE_KIND_SUB_FLOW_TRIGGER: + if s.nsfts != nil { + if d, err := s.nsfts.GetNodeSubFlowTrigger(ctx, n.ID); err == nil && d != nil { + detail.subFlowTriggerNode = d + } + } + case mflow.NODE_KIND_SUB_FLOW_RETURN: + if s.nsfrs != nil { + if d, err := s.nsfrs.GetNodeSubFlowReturn(ctx, n.ID); err == nil && d != nil { + detail.subFlowReturnNode = d + } + } + case mflow.NODE_KIND_RUN_SUB_FLOW: + if s.nrsfs != nil { + if d, err := s.nrsfs.GetNodeRunSubFlow(ctx, n.ID); err == nil && d != nil { + detail.runSubFlowNode = d + } + } + case mflow.NODE_KIND_WEBHOOK_TRIGGER: + // Not yet implemented } details = append(details, detail) } @@ -785,6 +817,30 @@ func (s *FlowServiceV2RPC) FlowDuplicate(ctx context.Context, req *connect.Reque return nil, connect.NewError(connect.CodeInternal, err) } } + if d.subFlowTriggerNode != nil && s.nsfts != nil { + node := *d.subFlowTriggerNode + node.FlowNodeID = newNodeID + writer := s.nsfts.TX(tx) + if err := writer.CreateNodeSubFlowTrigger(ctx, node); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + } + if d.subFlowReturnNode != nil && s.nsfrs != nil { + node := *d.subFlowReturnNode + node.FlowNodeID = newNodeID + writer := s.nsfrs.TX(tx) + if err := writer.CreateNodeSubFlowReturn(ctx, node); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + } + if d.runSubFlowNode != nil && s.nrsfs != nil { + node := *d.runSubFlowNode + node.FlowNodeID = newNodeID + writer := s.nrsfs.TX(tx) + if err := writer.CreateNodeRunSubFlow(ctx, node); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + } } // Track created edges for event publishing diff --git a/packages/server/internal/api/rflowv2/rflowv2_node_condition_test.go b/packages/server/internal/api/rflowv2/rflowv2_node_condition_test.go index f1a523190..e494bfb42 100644 --- a/packages/server/internal/api/rflowv2/rflowv2_node_condition_test.go +++ b/packages/server/internal/api/rflowv2/rflowv2_node_condition_test.go @@ -76,6 +76,9 @@ func TestNodeCondition_CRUD(t *testing.T) { nil, // NodeWsConnectionService nil, // NodeWsSendService nil, // NodeWaitService + nil, // NodeSubFlowTriggerService + nil, // NodeSubFlowReturnService + nil, // NodeRunSubFlowService nil, // WebSocketService nil, // WebSocketHeaderService nil, // GraphQLService diff --git a/packages/server/internal/api/rflowv2/rflowv2_node_exec_test.go b/packages/server/internal/api/rflowv2/rflowv2_node_exec_test.go index 297edd26b..344c78c35 100644 --- a/packages/server/internal/api/rflowv2/rflowv2_node_exec_test.go +++ b/packages/server/internal/api/rflowv2/rflowv2_node_exec_test.go @@ -76,6 +76,9 @@ func TestNodeExecution_Collection(t *testing.T) { nil, // NodeWsConnectionService nil, // NodeWsSendService nil, // NodeWaitService + nil, // NodeSubFlowTriggerService + nil, // NodeSubFlowReturnService + nil, // NodeRunSubFlowService nil, // WebSocketService nil, // WebSocketHeaderService nil, // GraphQLService @@ -232,6 +235,9 @@ func TestNodeExecution_Collection_VersionFlow(t *testing.T) { nil, // NodeWsConnectionService nil, // NodeWsSendService nil, // NodeWaitService + nil, // NodeSubFlowTriggerService + nil, // NodeSubFlowReturnService + nil, // NodeRunSubFlowService nil, // WebSocketService nil, // WebSocketHeaderService nil, // GraphQLService diff --git a/packages/server/internal/api/rflowv2/rflowv2_node_run_sub_flow.go b/packages/server/internal/api/rflowv2/rflowv2_node_run_sub_flow.go new file mode 100644 index 000000000..ce86a6bc5 --- /dev/null +++ b/packages/server/internal/api/rflowv2/rflowv2_node_run_sub_flow.go @@ -0,0 +1,516 @@ +//nolint:revive // exported +package rflowv2 + +import ( + "context" + "database/sql" + "errors" + "fmt" + "sync" + + "connectrpc.com/connect" + emptypb "google.golang.org/protobuf/types/known/emptypb" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/mutation" + flowv1 "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/flow/v1" +) + +type nodeRunSubFlowWithFlow struct { + nodeRunSubFlow mflow.NodeRunSubFlow + flowID idwrap.IDWrap + baseNode *mflow.Node +} + +func (s *FlowServiceV2RPC) NodeRunSubFlowCollection( + ctx context.Context, + _ *connect.Request[emptypb.Empty], +) (*connect.Response[flowv1.NodeRunSubFlowCollectionResponse], error) { + flows, err := s.listAccessibleFlows(ctx) + if err != nil { + return nil, err + } + + var items []*flowv1.NodeRunSubFlow + for _, flow := range flows { + nodes, err := s.nsReader.GetNodesByFlowID(ctx, flow.ID) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return nil, connect.NewError(connect.CodeInternal, err) + } + for _, node := range nodes { + if node.NodeKind != mflow.NODE_KIND_RUN_SUB_FLOW { + continue + } + nodeRunSubFlow, err := s.nrsfs.GetNodeRunSubFlow(ctx, node.ID) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + continue + } + return nil, connect.NewError(connect.CodeInternal, err) + } + if nodeRunSubFlow == nil { + continue + } + items = append(items, serializeNodeRunSubFlow(*nodeRunSubFlow)) + } + } + + return connect.NewResponse(&flowv1.NodeRunSubFlowCollectionResponse{Items: items}), nil +} + +func (s *FlowServiceV2RPC) NodeRunSubFlowInsert( + ctx context.Context, + req *connect.Request[flowv1.NodeRunSubFlowInsertRequest], +) (*connect.Response[emptypb.Empty], error) { + type insertData struct { + nodeID idwrap.IDWrap + targetFlowID *idwrap.IDWrap + targetFlowName string + inputs []mflow.SubFlowInputMapping + baseNode *mflow.Node + flowID idwrap.IDWrap + workspaceID idwrap.IDWrap + } + var validatedItems []insertData + + for _, item := range req.Msg.GetItems() { + nodeID, err := idwrap.NewFromBytes(item.GetNodeId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid node id: %w", err)) + } + + baseNode, _ := s.ns.GetNode(ctx, nodeID) + + var flowID idwrap.IDWrap + var workspaceID idwrap.IDWrap + if baseNode != nil { + flowID = baseNode.FlowID + flow, err := s.fsReader.GetFlow(ctx, flowID) + if err == nil { + workspaceID = flow.WorkspaceID + } + } + + var targetFlowID *idwrap.IDWrap + if targetBytes := item.GetTargetFlowId(); len(targetBytes) > 0 { + id, err := idwrap.NewFromBytes(targetBytes) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid target flow id: %w", err)) + } + targetFlowID = &id + } + + validatedItems = append(validatedItems, insertData{ + nodeID: nodeID, + targetFlowID: targetFlowID, + targetFlowName: item.GetTargetFlowName(), + inputs: protoToSubFlowInputMappings(item.GetInputs()), + baseNode: baseNode, + flowID: flowID, + workspaceID: workspaceID, + }) + } + + if len(validatedItems) == 0 { + return connect.NewResponse(&emptypb.Empty{}), nil + } + + mut := mutation.New(s.DB, mutation.WithPublisher(s.mutationPublisher())) + if err := mut.Begin(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer mut.Rollback() + + nrsfsWriter := s.nrsfs.TX(mut.TX()) + + for _, data := range validatedItems { + nodeRunSubFlow := mflow.NodeRunSubFlow{ + FlowNodeID: data.nodeID, + TargetFlowID: data.targetFlowID, + TargetFlowName: data.targetFlowName, + Inputs: data.inputs, + } + + if err := nrsfsWriter.CreateNodeRunSubFlow(ctx, nodeRunSubFlow); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + if data.baseNode != nil { + mut.Track(mutation.Event{ + Entity: mutation.EntityFlowNodeRunSubFlow, + Op: mutation.OpInsert, + ID: data.nodeID, + WorkspaceID: data.workspaceID, + ParentID: data.flowID, + Payload: nodeRunSubFlowWithFlow{ + nodeRunSubFlow: nodeRunSubFlow, + flowID: data.flowID, + baseNode: data.baseNode, + }, + }) + } + } + + if err := mut.Commit(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func (s *FlowServiceV2RPC) NodeRunSubFlowUpdate( + ctx context.Context, + req *connect.Request[flowv1.NodeRunSubFlowUpdateRequest], +) (*connect.Response[emptypb.Empty], error) { + type updateData struct { + nodeID idwrap.IDWrap + targetFlowID *idwrap.IDWrap + targetFlowName string + inputs []mflow.SubFlowInputMapping + baseNode *mflow.Node + workspaceID idwrap.IDWrap + } + var validatedItems []updateData + + for _, item := range req.Msg.GetItems() { + nodeID, err := idwrap.NewFromBytes(item.GetNodeId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid node id: %w", err)) + } + + nodeModel, err := s.ensureNodeAccess(ctx, nodeID) + if err != nil { + return nil, err + } + + flow, err := s.fsReader.GetFlow(ctx, nodeModel.FlowID) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + existing, err := s.nrsfs.GetNodeRunSubFlow(ctx, nodeID) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + targetFlowID := existing.TargetFlowID + if union := item.GetTargetFlowId(); union != nil { + switch union.GetKind() { + case flowv1.NodeRunSubFlowUpdate_TargetFlowIdUnion_KIND_UNSET: + targetFlowID = nil + case flowv1.NodeRunSubFlowUpdate_TargetFlowIdUnion_KIND_VALUE: + if valueBytes := union.GetValue(); len(valueBytes) > 0 { + id, err := idwrap.NewFromBytes(valueBytes) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid target flow id: %w", err)) + } + targetFlowID = &id + } + } + } + + targetFlowName := existing.TargetFlowName + if item.TargetFlowName != nil { + targetFlowName = *item.TargetFlowName + } + + inputs := existing.Inputs + if item.Inputs != nil { + inputs = protoToSubFlowInputMappings(item.Inputs) + } + + validatedItems = append(validatedItems, updateData{ + nodeID: nodeID, + targetFlowID: targetFlowID, + targetFlowName: targetFlowName, + inputs: inputs, + baseNode: nodeModel, + workspaceID: flow.WorkspaceID, + }) + } + + if len(validatedItems) == 0 { + return connect.NewResponse(&emptypb.Empty{}), nil + } + + mut := mutation.New(s.DB, mutation.WithPublisher(s.mutationPublisher())) + if err := mut.Begin(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer mut.Rollback() + + nrsfsWriter := s.nrsfs.TX(mut.TX()) + + for _, data := range validatedItems { + nodeRunSubFlow := mflow.NodeRunSubFlow{ + FlowNodeID: data.nodeID, + TargetFlowID: data.targetFlowID, + TargetFlowName: data.targetFlowName, + Inputs: data.inputs, + } + + if err := nrsfsWriter.UpdateNodeRunSubFlow(ctx, nodeRunSubFlow); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + mut.Track(mutation.Event{ + Entity: mutation.EntityFlowNodeRunSubFlow, + Op: mutation.OpUpdate, + ID: data.nodeID, + WorkspaceID: data.workspaceID, + ParentID: data.baseNode.FlowID, + Payload: nodeRunSubFlowWithFlow{ + nodeRunSubFlow: nodeRunSubFlow, + flowID: data.baseNode.FlowID, + baseNode: data.baseNode, + }, + }) + } + + if err := mut.Commit(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func (s *FlowServiceV2RPC) NodeRunSubFlowDelete( + ctx context.Context, + req *connect.Request[flowv1.NodeRunSubFlowDeleteRequest], +) (*connect.Response[emptypb.Empty], error) { + type deleteData struct { + nodeID idwrap.IDWrap + flowID idwrap.IDWrap + } + var validatedItems []deleteData + + for _, item := range req.Msg.GetItems() { + nodeID, err := idwrap.NewFromBytes(item.GetNodeId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid node id: %w", err)) + } + + nodeModel, err := s.ensureNodeAccess(ctx, nodeID) + if err != nil { + return nil, err + } + + validatedItems = append(validatedItems, deleteData{ + nodeID: nodeID, + flowID: nodeModel.FlowID, + }) + } + + if len(validatedItems) == 0 { + return connect.NewResponse(&emptypb.Empty{}), nil + } + + mut := mutation.New(s.DB, mutation.WithPublisher(s.mutationPublisher())) + if err := mut.Begin(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer mut.Rollback() + + for _, data := range validatedItems { + mut.Track(mutation.Event{ + Entity: mutation.EntityFlowNodeRunSubFlow, + Op: mutation.OpDelete, + ID: data.nodeID, + ParentID: data.flowID, + }) + if err := mut.Queries().DeleteFlowNodeRunSubFlow(ctx, data.nodeID); err != nil && !errors.Is(err, sql.ErrNoRows) { + return nil, connect.NewError(connect.CodeInternal, err) + } + } + + if err := mut.Commit(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func (s *FlowServiceV2RPC) NodeRunSubFlowSync( + ctx context.Context, + _ *connect.Request[emptypb.Empty], + stream *connect.ServerStream[flowv1.NodeRunSubFlowSyncResponse], +) error { + if stream == nil { + return connect.NewError(connect.CodeInternal, errors.New("stream is required")) + } + return s.streamNodeRunSubFlowSync(ctx, func(resp *flowv1.NodeRunSubFlowSyncResponse) error { + return stream.Send(resp) + }) +} + +func (s *FlowServiceV2RPC) streamNodeRunSubFlowSync( + ctx context.Context, + send func(*flowv1.NodeRunSubFlowSyncResponse) error, +) error { + if s.nodeStream == nil { + return connect.NewError(connect.CodeUnavailable, errors.New("node stream not configured")) + } + + var flowSet sync.Map + + filter := func(topic NodeTopic) bool { + if _, ok := flowSet.Load(topic.FlowID.String()); ok { + return true + } + if err := s.ensureFlowAccess(ctx, topic.FlowID); err != nil { + return false + } + flowSet.Store(topic.FlowID.String(), struct{}{}) + return true + } + + events, err := s.nodeStream.Subscribe(ctx, filter) + if err != nil { + return connect.NewError(connect.CodeInternal, err) + } + + for { + select { + case evt, ok := <-events: + if !ok { + return nil + } + resp, err := s.nodeRunSubFlowEventToSyncResponse(ctx, evt.Payload) + if err != nil { + return connect.NewError(connect.CodeInternal, fmt.Errorf("failed to convert run sub flow node event: %w", err)) + } + if resp == nil { + continue + } + if err := send(resp); err != nil { + return err + } + case <-ctx.Done(): + return ctx.Err() + } + } +} + +func (s *FlowServiceV2RPC) nodeRunSubFlowEventToSyncResponse( + ctx context.Context, + evt NodeEvent, +) (*flowv1.NodeRunSubFlowSyncResponse, error) { + if evt.Node == nil { + return nil, nil + } + + if evt.Node.GetKind() != flowv1.NodeKind_NODE_KIND_RUN_SUB_FLOW { + return nil, nil + } + + nodeID, err := idwrap.NewFromBytes(evt.Node.GetNodeId()) + if err != nil { + return nil, fmt.Errorf("invalid node id: %w", err) + } + + nodeRunSubFlow, err := s.nrsfs.GetNodeRunSubFlow(ctx, nodeID) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return nil, err + } + + var syncEvent *flowv1.NodeRunSubFlowSync + switch evt.Type { + case nodeEventInsert: + if nodeRunSubFlow == nil { + return nil, nil + } + syncEvent = &flowv1.NodeRunSubFlowSync{ + Value: &flowv1.NodeRunSubFlowSync_ValueUnion{ + Kind: flowv1.NodeRunSubFlowSync_ValueUnion_KIND_INSERT, + Insert: &flowv1.NodeRunSubFlowSyncInsert{ + NodeId: nodeID.Bytes(), + TargetFlowId: idwrapPtrToBytes(nodeRunSubFlow.TargetFlowID), + TargetFlowName: nodeRunSubFlow.TargetFlowName, + Inputs: subFlowInputMappingsToProto(nodeRunSubFlow.Inputs), + }, + }, + } + case nodeEventUpdate: + if nodeRunSubFlow == nil { + return nil, nil + } + var targetFlowIDUnion *flowv1.NodeRunSubFlowSyncUpdate_TargetFlowIdUnion + if nodeRunSubFlow.TargetFlowID != nil { + targetFlowIDUnion = &flowv1.NodeRunSubFlowSyncUpdate_TargetFlowIdUnion{ + Kind: flowv1.NodeRunSubFlowSyncUpdate_TargetFlowIdUnion_KIND_VALUE, + Value: nodeRunSubFlow.TargetFlowID.Bytes(), + } + } + syncEvent = &flowv1.NodeRunSubFlowSync{ + Value: &flowv1.NodeRunSubFlowSync_ValueUnion{ + Kind: flowv1.NodeRunSubFlowSync_ValueUnion_KIND_UPDATE, + Update: &flowv1.NodeRunSubFlowSyncUpdate{ + NodeId: nodeID.Bytes(), + TargetFlowId: targetFlowIDUnion, + TargetFlowName: &nodeRunSubFlow.TargetFlowName, + Inputs: subFlowInputMappingsToProto(nodeRunSubFlow.Inputs), + }, + }, + } + case nodeEventDelete: + syncEvent = &flowv1.NodeRunSubFlowSync{ + Value: &flowv1.NodeRunSubFlowSync_ValueUnion{ + Kind: flowv1.NodeRunSubFlowSync_ValueUnion_KIND_DELETE, + Delete: &flowv1.NodeRunSubFlowSyncDelete{ + NodeId: nodeID.Bytes(), + }, + }, + } + default: + return nil, nil + } + + return &flowv1.NodeRunSubFlowSyncResponse{ + Items: []*flowv1.NodeRunSubFlowSync{syncEvent}, + }, nil +} + +func serializeNodeRunSubFlow(n mflow.NodeRunSubFlow) *flowv1.NodeRunSubFlow { + return &flowv1.NodeRunSubFlow{ + NodeId: n.FlowNodeID.Bytes(), + TargetFlowId: idwrapPtrToBytes(n.TargetFlowID), + TargetFlowName: n.TargetFlowName, + Inputs: subFlowInputMappingsToProto(n.Inputs), + } +} + +func idwrapPtrToBytes(id *idwrap.IDWrap) []byte { + if id == nil { + return nil + } + return id.Bytes() +} + +func subFlowInputMappingsToProto(inputs []mflow.SubFlowInputMapping) []*flowv1.SubFlowInputMapping { + if len(inputs) == 0 { + return nil + } + result := make([]*flowv1.SubFlowInputMapping, len(inputs)) + for i, m := range inputs { + result[i] = &flowv1.SubFlowInputMapping{ + ParamName: m.ParamName, + Expression: m.Expression, + } + } + return result +} + +func protoToSubFlowInputMappings(inputs []*flowv1.SubFlowInputMapping) []mflow.SubFlowInputMapping { + if len(inputs) == 0 { + return nil + } + result := make([]mflow.SubFlowInputMapping, len(inputs)) + for i, m := range inputs { + result[i] = mflow.SubFlowInputMapping{ + ParamName: m.GetParamName(), + Expression: m.GetExpression(), + } + } + return result +} diff --git a/packages/server/internal/api/rflowv2/rflowv2_node_sub_flow_return.go b/packages/server/internal/api/rflowv2/rflowv2_node_sub_flow_return.go new file mode 100644 index 000000000..c25e6e99a --- /dev/null +++ b/packages/server/internal/api/rflowv2/rflowv2_node_sub_flow_return.go @@ -0,0 +1,454 @@ +//nolint:revive // exported +package rflowv2 + +import ( + "context" + "database/sql" + "errors" + "fmt" + "sync" + + "connectrpc.com/connect" + emptypb "google.golang.org/protobuf/types/known/emptypb" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/mutation" + flowv1 "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/flow/v1" +) + +type nodeSubFlowReturnWithFlow struct { + nodeSubFlowReturn mflow.NodeSubFlowReturn + flowID idwrap.IDWrap + baseNode *mflow.Node +} + +func (s *FlowServiceV2RPC) NodeSubFlowReturnCollection( + ctx context.Context, + _ *connect.Request[emptypb.Empty], +) (*connect.Response[flowv1.NodeSubFlowReturnCollectionResponse], error) { + flows, err := s.listAccessibleFlows(ctx) + if err != nil { + return nil, err + } + + var items []*flowv1.NodeSubFlowReturn + for _, flow := range flows { + nodes, err := s.nsReader.GetNodesByFlowID(ctx, flow.ID) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return nil, connect.NewError(connect.CodeInternal, err) + } + for _, node := range nodes { + if node.NodeKind != mflow.NODE_KIND_SUB_FLOW_RETURN { + continue + } + nodeSubFlowReturn, err := s.nsfrs.GetNodeSubFlowReturn(ctx, node.ID) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + continue + } + return nil, connect.NewError(connect.CodeInternal, err) + } + if nodeSubFlowReturn == nil { + continue + } + items = append(items, serializeNodeSubFlowReturn(*nodeSubFlowReturn)) + } + } + + return connect.NewResponse(&flowv1.NodeSubFlowReturnCollectionResponse{Items: items}), nil +} + +func (s *FlowServiceV2RPC) NodeSubFlowReturnInsert( + ctx context.Context, + req *connect.Request[flowv1.NodeSubFlowReturnInsertRequest], +) (*connect.Response[emptypb.Empty], error) { + type insertData struct { + nodeID idwrap.IDWrap + outputs []mflow.SubFlowOutput + baseNode *mflow.Node + flowID idwrap.IDWrap + workspaceID idwrap.IDWrap + } + var validatedItems []insertData + + for _, item := range req.Msg.GetItems() { + nodeID, err := idwrap.NewFromBytes(item.GetNodeId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid node id: %w", err)) + } + + baseNode, _ := s.ns.GetNode(ctx, nodeID) + + var flowID idwrap.IDWrap + var workspaceID idwrap.IDWrap + if baseNode != nil { + flowID = baseNode.FlowID + flow, err := s.fsReader.GetFlow(ctx, flowID) + if err == nil { + workspaceID = flow.WorkspaceID + } + } + + validatedItems = append(validatedItems, insertData{ + nodeID: nodeID, + outputs: protoToSubFlowOutputs(item.GetOutputs()), + baseNode: baseNode, + flowID: flowID, + workspaceID: workspaceID, + }) + } + + if len(validatedItems) == 0 { + return connect.NewResponse(&emptypb.Empty{}), nil + } + + mut := mutation.New(s.DB, mutation.WithPublisher(s.mutationPublisher())) + if err := mut.Begin(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer mut.Rollback() + + nsfrsWriter := s.nsfrs.TX(mut.TX()) + + for _, data := range validatedItems { + nodeSubFlowReturn := mflow.NodeSubFlowReturn{ + FlowNodeID: data.nodeID, + Outputs: data.outputs, + } + + if err := nsfrsWriter.CreateNodeSubFlowReturn(ctx, nodeSubFlowReturn); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + if data.baseNode != nil { + mut.Track(mutation.Event{ + Entity: mutation.EntityFlowNodeSubFlowReturn, + Op: mutation.OpInsert, + ID: data.nodeID, + WorkspaceID: data.workspaceID, + ParentID: data.flowID, + Payload: nodeSubFlowReturnWithFlow{ + nodeSubFlowReturn: nodeSubFlowReturn, + flowID: data.flowID, + baseNode: data.baseNode, + }, + }) + } + } + + if err := mut.Commit(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func (s *FlowServiceV2RPC) NodeSubFlowReturnUpdate( + ctx context.Context, + req *connect.Request[flowv1.NodeSubFlowReturnUpdateRequest], +) (*connect.Response[emptypb.Empty], error) { + type updateData struct { + nodeID idwrap.IDWrap + outputs []mflow.SubFlowOutput + baseNode *mflow.Node + workspaceID idwrap.IDWrap + } + var validatedItems []updateData + + for _, item := range req.Msg.GetItems() { + nodeID, err := idwrap.NewFromBytes(item.GetNodeId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid node id: %w", err)) + } + + nodeModel, err := s.ensureNodeAccess(ctx, nodeID) + if err != nil { + return nil, err + } + + flow, err := s.fsReader.GetFlow(ctx, nodeModel.FlowID) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + existing, err := s.nsfrs.GetNodeSubFlowReturn(ctx, nodeID) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + outputs := existing.Outputs + if item.Outputs != nil { + outputs = protoToSubFlowOutputs(item.Outputs) + } + + validatedItems = append(validatedItems, updateData{ + nodeID: nodeID, + outputs: outputs, + baseNode: nodeModel, + workspaceID: flow.WorkspaceID, + }) + } + + if len(validatedItems) == 0 { + return connect.NewResponse(&emptypb.Empty{}), nil + } + + mut := mutation.New(s.DB, mutation.WithPublisher(s.mutationPublisher())) + if err := mut.Begin(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer mut.Rollback() + + nsfrsWriter := s.nsfrs.TX(mut.TX()) + + for _, data := range validatedItems { + nodeSubFlowReturn := mflow.NodeSubFlowReturn{ + FlowNodeID: data.nodeID, + Outputs: data.outputs, + } + + if err := nsfrsWriter.UpdateNodeSubFlowReturn(ctx, nodeSubFlowReturn); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + mut.Track(mutation.Event{ + Entity: mutation.EntityFlowNodeSubFlowReturn, + Op: mutation.OpUpdate, + ID: data.nodeID, + WorkspaceID: data.workspaceID, + ParentID: data.baseNode.FlowID, + Payload: nodeSubFlowReturnWithFlow{ + nodeSubFlowReturn: nodeSubFlowReturn, + flowID: data.baseNode.FlowID, + baseNode: data.baseNode, + }, + }) + } + + if err := mut.Commit(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func (s *FlowServiceV2RPC) NodeSubFlowReturnDelete( + ctx context.Context, + req *connect.Request[flowv1.NodeSubFlowReturnDeleteRequest], +) (*connect.Response[emptypb.Empty], error) { + type deleteData struct { + nodeID idwrap.IDWrap + flowID idwrap.IDWrap + } + var validatedItems []deleteData + + for _, item := range req.Msg.GetItems() { + nodeID, err := idwrap.NewFromBytes(item.GetNodeId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid node id: %w", err)) + } + + nodeModel, err := s.ensureNodeAccess(ctx, nodeID) + if err != nil { + return nil, err + } + + validatedItems = append(validatedItems, deleteData{ + nodeID: nodeID, + flowID: nodeModel.FlowID, + }) + } + + if len(validatedItems) == 0 { + return connect.NewResponse(&emptypb.Empty{}), nil + } + + mut := mutation.New(s.DB, mutation.WithPublisher(s.mutationPublisher())) + if err := mut.Begin(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer mut.Rollback() + + for _, data := range validatedItems { + mut.Track(mutation.Event{ + Entity: mutation.EntityFlowNodeSubFlowReturn, + Op: mutation.OpDelete, + ID: data.nodeID, + ParentID: data.flowID, + }) + if err := mut.Queries().DeleteFlowNodeSubFlowReturn(ctx, data.nodeID); err != nil && !errors.Is(err, sql.ErrNoRows) { + return nil, connect.NewError(connect.CodeInternal, err) + } + } + + if err := mut.Commit(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func (s *FlowServiceV2RPC) NodeSubFlowReturnSync( + ctx context.Context, + _ *connect.Request[emptypb.Empty], + stream *connect.ServerStream[flowv1.NodeSubFlowReturnSyncResponse], +) error { + if stream == nil { + return connect.NewError(connect.CodeInternal, errors.New("stream is required")) + } + return s.streamNodeSubFlowReturnSync(ctx, func(resp *flowv1.NodeSubFlowReturnSyncResponse) error { + return stream.Send(resp) + }) +} + +func (s *FlowServiceV2RPC) streamNodeSubFlowReturnSync( + ctx context.Context, + send func(*flowv1.NodeSubFlowReturnSyncResponse) error, +) error { + if s.nodeStream == nil { + return connect.NewError(connect.CodeUnavailable, errors.New("node stream not configured")) + } + + var flowSet sync.Map + + filter := func(topic NodeTopic) bool { + if _, ok := flowSet.Load(topic.FlowID.String()); ok { + return true + } + if err := s.ensureFlowAccess(ctx, topic.FlowID); err != nil { + return false + } + flowSet.Store(topic.FlowID.String(), struct{}{}) + return true + } + + events, err := s.nodeStream.Subscribe(ctx, filter) + if err != nil { + return connect.NewError(connect.CodeInternal, err) + } + + for { + select { + case evt, ok := <-events: + if !ok { + return nil + } + resp, err := s.nodeSubFlowReturnEventToSyncResponse(ctx, evt.Payload) + if err != nil { + return connect.NewError(connect.CodeInternal, fmt.Errorf("failed to convert sub flow return node event: %w", err)) + } + if resp == nil { + continue + } + if err := send(resp); err != nil { + return err + } + case <-ctx.Done(): + return ctx.Err() + } + } +} + +func (s *FlowServiceV2RPC) nodeSubFlowReturnEventToSyncResponse( + ctx context.Context, + evt NodeEvent, +) (*flowv1.NodeSubFlowReturnSyncResponse, error) { + if evt.Node == nil { + return nil, nil + } + + if evt.Node.GetKind() != flowv1.NodeKind_NODE_KIND_SUB_FLOW_RETURN { + return nil, nil + } + + nodeID, err := idwrap.NewFromBytes(evt.Node.GetNodeId()) + if err != nil { + return nil, fmt.Errorf("invalid node id: %w", err) + } + + nodeSubFlowReturn, err := s.nsfrs.GetNodeSubFlowReturn(ctx, nodeID) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return nil, err + } + + var syncEvent *flowv1.NodeSubFlowReturnSync + switch evt.Type { + case nodeEventInsert: + if nodeSubFlowReturn == nil { + return nil, nil + } + syncEvent = &flowv1.NodeSubFlowReturnSync{ + Value: &flowv1.NodeSubFlowReturnSync_ValueUnion{ + Kind: flowv1.NodeSubFlowReturnSync_ValueUnion_KIND_INSERT, + Insert: &flowv1.NodeSubFlowReturnSyncInsert{ + NodeId: nodeID.Bytes(), + Outputs: subFlowOutputsToProto(nodeSubFlowReturn.Outputs), + }, + }, + } + case nodeEventUpdate: + if nodeSubFlowReturn == nil { + return nil, nil + } + syncEvent = &flowv1.NodeSubFlowReturnSync{ + Value: &flowv1.NodeSubFlowReturnSync_ValueUnion{ + Kind: flowv1.NodeSubFlowReturnSync_ValueUnion_KIND_UPDATE, + Update: &flowv1.NodeSubFlowReturnSyncUpdate{ + NodeId: nodeID.Bytes(), + Outputs: subFlowOutputsToProto(nodeSubFlowReturn.Outputs), + }, + }, + } + case nodeEventDelete: + syncEvent = &flowv1.NodeSubFlowReturnSync{ + Value: &flowv1.NodeSubFlowReturnSync_ValueUnion{ + Kind: flowv1.NodeSubFlowReturnSync_ValueUnion_KIND_DELETE, + Delete: &flowv1.NodeSubFlowReturnSyncDelete{ + NodeId: nodeID.Bytes(), + }, + }, + } + default: + return nil, nil + } + + return &flowv1.NodeSubFlowReturnSyncResponse{ + Items: []*flowv1.NodeSubFlowReturnSync{syncEvent}, + }, nil +} + +func serializeNodeSubFlowReturn(n mflow.NodeSubFlowReturn) *flowv1.NodeSubFlowReturn { + return &flowv1.NodeSubFlowReturn{ + NodeId: n.FlowNodeID.Bytes(), + Outputs: subFlowOutputsToProto(n.Outputs), + } +} + +func subFlowOutputsToProto(outputs []mflow.SubFlowOutput) []*flowv1.SubFlowOutput { + if len(outputs) == 0 { + return nil + } + result := make([]*flowv1.SubFlowOutput, len(outputs)) + for i, o := range outputs { + result[i] = &flowv1.SubFlowOutput{ + Name: o.Name, + Expression: o.Expression, + } + } + return result +} + +func protoToSubFlowOutputs(outputs []*flowv1.SubFlowOutput) []mflow.SubFlowOutput { + if len(outputs) == 0 { + return nil + } + result := make([]mflow.SubFlowOutput, len(outputs)) + for i, o := range outputs { + result[i] = mflow.SubFlowOutput{ + Name: o.GetName(), + Expression: o.GetExpression(), + } + } + return result +} diff --git a/packages/server/internal/api/rflowv2/rflowv2_node_sub_flow_trigger.go b/packages/server/internal/api/rflowv2/rflowv2_node_sub_flow_trigger.go new file mode 100644 index 000000000..f536fb965 --- /dev/null +++ b/packages/server/internal/api/rflowv2/rflowv2_node_sub_flow_trigger.go @@ -0,0 +1,458 @@ +//nolint:revive // exported +package rflowv2 + +import ( + "context" + "database/sql" + "errors" + "fmt" + "sync" + + "connectrpc.com/connect" + emptypb "google.golang.org/protobuf/types/known/emptypb" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/mutation" + flowv1 "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/flow/v1" +) + +type nodeSubFlowTriggerWithFlow struct { + nodeSubFlowTrigger mflow.NodeSubFlowTrigger + flowID idwrap.IDWrap + baseNode *mflow.Node +} + +func (s *FlowServiceV2RPC) NodeSubFlowTriggerCollection( + ctx context.Context, + _ *connect.Request[emptypb.Empty], +) (*connect.Response[flowv1.NodeSubFlowTriggerCollectionResponse], error) { + flows, err := s.listAccessibleFlows(ctx) + if err != nil { + return nil, err + } + + var items []*flowv1.NodeSubFlowTrigger + for _, flow := range flows { + nodes, err := s.nsReader.GetNodesByFlowID(ctx, flow.ID) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return nil, connect.NewError(connect.CodeInternal, err) + } + for _, node := range nodes { + if node.NodeKind != mflow.NODE_KIND_SUB_FLOW_TRIGGER { + continue + } + nodeSubFlowTrigger, err := s.nsfts.GetNodeSubFlowTrigger(ctx, node.ID) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + continue + } + return nil, connect.NewError(connect.CodeInternal, err) + } + if nodeSubFlowTrigger == nil { + continue + } + items = append(items, serializeNodeSubFlowTrigger(*nodeSubFlowTrigger)) + } + } + + return connect.NewResponse(&flowv1.NodeSubFlowTriggerCollectionResponse{Items: items}), nil +} + +func (s *FlowServiceV2RPC) NodeSubFlowTriggerInsert( + ctx context.Context, + req *connect.Request[flowv1.NodeSubFlowTriggerInsertRequest], +) (*connect.Response[emptypb.Empty], error) { + type insertData struct { + nodeID idwrap.IDWrap + params []mflow.SubFlowParam + baseNode *mflow.Node + flowID idwrap.IDWrap + workspaceID idwrap.IDWrap + } + var validatedItems []insertData + + for _, item := range req.Msg.GetItems() { + nodeID, err := idwrap.NewFromBytes(item.GetNodeId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid node id: %w", err)) + } + + baseNode, _ := s.ns.GetNode(ctx, nodeID) + + var flowID idwrap.IDWrap + var workspaceID idwrap.IDWrap + if baseNode != nil { + flowID = baseNode.FlowID + flow, err := s.fsReader.GetFlow(ctx, flowID) + if err == nil { + workspaceID = flow.WorkspaceID + } + } + + validatedItems = append(validatedItems, insertData{ + nodeID: nodeID, + params: protoToSubFlowParams(item.GetParams()), + baseNode: baseNode, + flowID: flowID, + workspaceID: workspaceID, + }) + } + + if len(validatedItems) == 0 { + return connect.NewResponse(&emptypb.Empty{}), nil + } + + mut := mutation.New(s.DB, mutation.WithPublisher(s.mutationPublisher())) + if err := mut.Begin(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer mut.Rollback() + + nsftsWriter := s.nsfts.TX(mut.TX()) + + for _, data := range validatedItems { + nodeSubFlowTrigger := mflow.NodeSubFlowTrigger{ + FlowNodeID: data.nodeID, + Params: data.params, + } + + if err := nsftsWriter.CreateNodeSubFlowTrigger(ctx, nodeSubFlowTrigger); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + if data.baseNode != nil { + mut.Track(mutation.Event{ + Entity: mutation.EntityFlowNodeSubFlowTrigger, + Op: mutation.OpInsert, + ID: data.nodeID, + WorkspaceID: data.workspaceID, + ParentID: data.flowID, + Payload: nodeSubFlowTriggerWithFlow{ + nodeSubFlowTrigger: nodeSubFlowTrigger, + flowID: data.flowID, + baseNode: data.baseNode, + }, + }) + } + } + + if err := mut.Commit(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func (s *FlowServiceV2RPC) NodeSubFlowTriggerUpdate( + ctx context.Context, + req *connect.Request[flowv1.NodeSubFlowTriggerUpdateRequest], +) (*connect.Response[emptypb.Empty], error) { + type updateData struct { + nodeID idwrap.IDWrap + params []mflow.SubFlowParam + baseNode *mflow.Node + workspaceID idwrap.IDWrap + } + var validatedItems []updateData + + for _, item := range req.Msg.GetItems() { + nodeID, err := idwrap.NewFromBytes(item.GetNodeId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid node id: %w", err)) + } + + nodeModel, err := s.ensureNodeAccess(ctx, nodeID) + if err != nil { + return nil, err + } + + flow, err := s.fsReader.GetFlow(ctx, nodeModel.FlowID) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + existing, err := s.nsfts.GetNodeSubFlowTrigger(ctx, nodeID) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + params := existing.Params + if item.Params != nil { + params = protoToSubFlowParams(item.Params) + } + + validatedItems = append(validatedItems, updateData{ + nodeID: nodeID, + params: params, + baseNode: nodeModel, + workspaceID: flow.WorkspaceID, + }) + } + + if len(validatedItems) == 0 { + return connect.NewResponse(&emptypb.Empty{}), nil + } + + mut := mutation.New(s.DB, mutation.WithPublisher(s.mutationPublisher())) + if err := mut.Begin(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer mut.Rollback() + + nsftsWriter := s.nsfts.TX(mut.TX()) + + for _, data := range validatedItems { + nodeSubFlowTrigger := mflow.NodeSubFlowTrigger{ + FlowNodeID: data.nodeID, + Params: data.params, + } + + if err := nsftsWriter.UpdateNodeSubFlowTrigger(ctx, nodeSubFlowTrigger); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + mut.Track(mutation.Event{ + Entity: mutation.EntityFlowNodeSubFlowTrigger, + Op: mutation.OpUpdate, + ID: data.nodeID, + WorkspaceID: data.workspaceID, + ParentID: data.baseNode.FlowID, + Payload: nodeSubFlowTriggerWithFlow{ + nodeSubFlowTrigger: nodeSubFlowTrigger, + flowID: data.baseNode.FlowID, + baseNode: data.baseNode, + }, + }) + } + + if err := mut.Commit(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func (s *FlowServiceV2RPC) NodeSubFlowTriggerDelete( + ctx context.Context, + req *connect.Request[flowv1.NodeSubFlowTriggerDeleteRequest], +) (*connect.Response[emptypb.Empty], error) { + type deleteData struct { + nodeID idwrap.IDWrap + flowID idwrap.IDWrap + } + var validatedItems []deleteData + + for _, item := range req.Msg.GetItems() { + nodeID, err := idwrap.NewFromBytes(item.GetNodeId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid node id: %w", err)) + } + + nodeModel, err := s.ensureNodeAccess(ctx, nodeID) + if err != nil { + return nil, err + } + + validatedItems = append(validatedItems, deleteData{ + nodeID: nodeID, + flowID: nodeModel.FlowID, + }) + } + + if len(validatedItems) == 0 { + return connect.NewResponse(&emptypb.Empty{}), nil + } + + mut := mutation.New(s.DB, mutation.WithPublisher(s.mutationPublisher())) + if err := mut.Begin(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + defer mut.Rollback() + + for _, data := range validatedItems { + mut.Track(mutation.Event{ + Entity: mutation.EntityFlowNodeSubFlowTrigger, + Op: mutation.OpDelete, + ID: data.nodeID, + ParentID: data.flowID, + }) + if err := mut.Queries().DeleteFlowNodeSubFlowTrigger(ctx, data.nodeID); err != nil && !errors.Is(err, sql.ErrNoRows) { + return nil, connect.NewError(connect.CodeInternal, err) + } + } + + if err := mut.Commit(ctx); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +func (s *FlowServiceV2RPC) NodeSubFlowTriggerSync( + ctx context.Context, + _ *connect.Request[emptypb.Empty], + stream *connect.ServerStream[flowv1.NodeSubFlowTriggerSyncResponse], +) error { + if stream == nil { + return connect.NewError(connect.CodeInternal, errors.New("stream is required")) + } + return s.streamNodeSubFlowTriggerSync(ctx, func(resp *flowv1.NodeSubFlowTriggerSyncResponse) error { + return stream.Send(resp) + }) +} + +func (s *FlowServiceV2RPC) streamNodeSubFlowTriggerSync( + ctx context.Context, + send func(*flowv1.NodeSubFlowTriggerSyncResponse) error, +) error { + if s.nodeStream == nil { + return connect.NewError(connect.CodeUnavailable, errors.New("node stream not configured")) + } + + var flowSet sync.Map + + filter := func(topic NodeTopic) bool { + if _, ok := flowSet.Load(topic.FlowID.String()); ok { + return true + } + if err := s.ensureFlowAccess(ctx, topic.FlowID); err != nil { + return false + } + flowSet.Store(topic.FlowID.String(), struct{}{}) + return true + } + + events, err := s.nodeStream.Subscribe(ctx, filter) + if err != nil { + return connect.NewError(connect.CodeInternal, err) + } + + for { + select { + case evt, ok := <-events: + if !ok { + return nil + } + resp, err := s.nodeSubFlowTriggerEventToSyncResponse(ctx, evt.Payload) + if err != nil { + return connect.NewError(connect.CodeInternal, fmt.Errorf("failed to convert sub flow trigger node event: %w", err)) + } + if resp == nil { + continue + } + if err := send(resp); err != nil { + return err + } + case <-ctx.Done(): + return ctx.Err() + } + } +} + +func (s *FlowServiceV2RPC) nodeSubFlowTriggerEventToSyncResponse( + ctx context.Context, + evt NodeEvent, +) (*flowv1.NodeSubFlowTriggerSyncResponse, error) { + if evt.Node == nil { + return nil, nil + } + + if evt.Node.GetKind() != flowv1.NodeKind_NODE_KIND_SUB_FLOW_TRIGGER { + return nil, nil + } + + nodeID, err := idwrap.NewFromBytes(evt.Node.GetNodeId()) + if err != nil { + return nil, fmt.Errorf("invalid node id: %w", err) + } + + nodeSubFlowTrigger, err := s.nsfts.GetNodeSubFlowTrigger(ctx, nodeID) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return nil, err + } + + var syncEvent *flowv1.NodeSubFlowTriggerSync + switch evt.Type { + case nodeEventInsert: + if nodeSubFlowTrigger == nil { + return nil, nil + } + syncEvent = &flowv1.NodeSubFlowTriggerSync{ + Value: &flowv1.NodeSubFlowTriggerSync_ValueUnion{ + Kind: flowv1.NodeSubFlowTriggerSync_ValueUnion_KIND_INSERT, + Insert: &flowv1.NodeSubFlowTriggerSyncInsert{ + NodeId: nodeID.Bytes(), + Params: subFlowParamsToProto(nodeSubFlowTrigger.Params), + }, + }, + } + case nodeEventUpdate: + if nodeSubFlowTrigger == nil { + return nil, nil + } + syncEvent = &flowv1.NodeSubFlowTriggerSync{ + Value: &flowv1.NodeSubFlowTriggerSync_ValueUnion{ + Kind: flowv1.NodeSubFlowTriggerSync_ValueUnion_KIND_UPDATE, + Update: &flowv1.NodeSubFlowTriggerSyncUpdate{ + NodeId: nodeID.Bytes(), + Params: subFlowParamsToProto(nodeSubFlowTrigger.Params), + }, + }, + } + case nodeEventDelete: + syncEvent = &flowv1.NodeSubFlowTriggerSync{ + Value: &flowv1.NodeSubFlowTriggerSync_ValueUnion{ + Kind: flowv1.NodeSubFlowTriggerSync_ValueUnion_KIND_DELETE, + Delete: &flowv1.NodeSubFlowTriggerSyncDelete{ + NodeId: nodeID.Bytes(), + }, + }, + } + default: + return nil, nil + } + + return &flowv1.NodeSubFlowTriggerSyncResponse{ + Items: []*flowv1.NodeSubFlowTriggerSync{syncEvent}, + }, nil +} + +func serializeNodeSubFlowTrigger(n mflow.NodeSubFlowTrigger) *flowv1.NodeSubFlowTrigger { + return &flowv1.NodeSubFlowTrigger{ + NodeId: n.FlowNodeID.Bytes(), + Params: subFlowParamsToProto(n.Params), + } +} + +func subFlowParamsToProto(params []mflow.SubFlowParam) []*flowv1.SubFlowParam { + if len(params) == 0 { + return nil + } + result := make([]*flowv1.SubFlowParam, len(params)) + for i, p := range params { + result[i] = &flowv1.SubFlowParam{ + Name: p.Name, + Type: p.Type, + DefaultValue: p.DefaultValue, + Required: p.Required, + } + } + return result +} + +func protoToSubFlowParams(params []*flowv1.SubFlowParam) []mflow.SubFlowParam { + if len(params) == 0 { + return nil + } + result := make([]mflow.SubFlowParam, len(params)) + for i, p := range params { + result[i] = mflow.SubFlowParam{ + Name: p.GetName(), + Type: p.GetType(), + DefaultValue: p.GetDefaultValue(), + Required: p.GetRequired(), + } + } + return result +} diff --git a/packages/server/internal/api/rflowv2/rflowv2_testutil_test.go b/packages/server/internal/api/rflowv2/rflowv2_testutil_test.go index 8ad0571fc..a501ec98b 100644 --- a/packages/server/internal/api/rflowv2/rflowv2_testutil_test.go +++ b/packages/server/internal/api/rflowv2/rflowv2_testutil_test.go @@ -96,6 +96,9 @@ func NewRFlowTestContext(t *testing.T) *RFlowTestContext { nil, // NodeWsConnectionService - not needed for non-WS tests nil, // NodeWsSendService - not needed for non-WS tests nil, // NodeWaitService - not needed for non-wait tests + nil, // NodeSubFlowTriggerService - not needed for non-subflow tests + nil, // NodeSubFlowReturnService - not needed for non-subflow tests + nil, // NodeRunSubFlowService - not needed for non-subflow tests nil, // WebSocketService - not needed for non-WS tests nil, // WebSocketHeaderService - not needed for non-WS tests nil, // GraphQLService - not needed for non-GraphQL tests diff --git a/packages/server/internal/api/rimportv2/integrity.go b/packages/server/internal/api/rimportv2/integrity.go index 4b39052af..df9a0f3c5 100644 --- a/packages/server/internal/api/rimportv2/integrity.go +++ b/packages/server/internal/api/rimportv2/integrity.go @@ -105,7 +105,7 @@ func ValidateImportIntegrity( report.AddError("file", file.ID, "ContentID", *file.ContentID, fmt.Sprintf("file references non-existent HTTP (type=%s)", file.ContentType)) } - case mfile.ContentTypeGraphQL: + case mfile.ContentTypeGraphQL, mfile.ContentTypeGraphQLDelta: // GraphQL files reference GraphQL IDs - validation not yet implemented continue case mfile.ContentTypeWebSocket: @@ -178,7 +178,7 @@ func ValidateTranslationResult(result *TranslationResult) *IntegrityReport { report.AddError("file", file.ID, "ContentID", *file.ContentID, fmt.Sprintf("file references HTTP not in translation result (type=%s)", file.ContentType)) } - case mfile.ContentTypeGraphQL: + case mfile.ContentTypeGraphQL, mfile.ContentTypeGraphQLDelta: // GraphQL files reference GraphQL IDs - validation not yet implemented continue case mfile.ContentTypeWebSocket: diff --git a/packages/server/internal/api/rimportv2/rimportv2_event.go b/packages/server/internal/api/rimportv2/rimportv2_event.go index 9b6ca468a..8cb5a50cb 100644 --- a/packages/server/internal/api/rimportv2/rimportv2_event.go +++ b/packages/server/internal/api/rimportv2/rimportv2_event.go @@ -74,7 +74,7 @@ func (h *ImportV2RPC) publishEvents(ctx context.Context, results *ImportResults) kind = eventsync.KindFlowFile case mfile.ContentTypeFolder: kind = eventsync.KindFolder - case mfile.ContentTypeHTTP, mfile.ContentTypeHTTPDelta, mfile.ContentTypeCredential, mfile.ContentTypeGraphQL, mfile.ContentTypeWebSocket: + case mfile.ContentTypeHTTP, mfile.ContentTypeHTTPDelta, mfile.ContentTypeCredential, mfile.ContentTypeGraphQL, mfile.ContentTypeGraphQLDelta, mfile.ContentTypeWebSocket: // Keep default KindHTTPFile } diff --git a/packages/server/internal/api/rreference/rreference.go b/packages/server/internal/api/rreference/rreference.go index 350c73969..acdc4147a 100644 --- a/packages/server/internal/api/rreference/rreference.go +++ b/packages/server/internal/api/rreference/rreference.go @@ -52,6 +52,9 @@ type ReferenceServiceRPC struct { // graphql graphqlResponseReader *sgraphql.GraphQLResponseService + + // sub-flow + nodeSubFlowTriggerService *sflow.NodeSubFlowTriggerService } type ReferenceServiceRPCReaders struct { @@ -66,7 +69,8 @@ type ReferenceServiceRPCReaders struct { FlowEdge *sflow.EdgeReader NodeExecution *sflow.NodeExecutionReader HttpResponse *shttp.HttpResponseReader - GraphQLResponse *sgraphql.GraphQLResponseService + GraphQLResponse *sgraphql.GraphQLResponseService + NodeSubFlowTrigger *sflow.NodeSubFlowTriggerService } func (r *ReferenceServiceRPCReaders) Validate() error { @@ -145,7 +149,8 @@ func NewReferenceServiceRPC(deps ReferenceServiceRPCDeps) *ReferenceServiceRPC { flowEdgeReader: deps.Readers.FlowEdge, nodeExecutionReader: deps.Readers.NodeExecution, httpResponseReader: deps.Readers.HttpResponse, - graphqlResponseReader: deps.Readers.GraphQLResponse, + graphqlResponseReader: deps.Readers.GraphQLResponse, + nodeSubFlowTriggerService: deps.Readers.NodeSubFlowTrigger, } } @@ -154,6 +159,32 @@ func CreateService(srv *ReferenceServiceRPC, options []connect.HandlerOption) (* return &api.Service{Path: path, Handler: handler}, nil } +// subFlowTriggerParamMap builds a variable map from sub-flow trigger params. +// This mirrors the runtime structure written by nsubflowtrigger.RunSync. +func (s *ReferenceServiceRPC) subFlowTriggerParamMap(ctx context.Context, nodeID idwrap.IDWrap) map[string]interface{} { + if s.nodeSubFlowTriggerService == nil { + return map[string]interface{}{} + } + trigger, err := s.nodeSubFlowTriggerService.GetNodeSubFlowTrigger(ctx, nodeID) + if err != nil || trigger == nil { + return map[string]interface{}{} + } + m := make(map[string]interface{}, len(trigger.Params)) + for _, p := range trigger.Params { + switch p.Type { + case "number": + m[p.Name] = 0 + case "boolean": + m[p.Name] = false + case "json": + m[p.Name] = map[string]interface{}{} + default: + m[p.Name] = "" + } + } + return m +} + var ( ErrExampleNotFound = errors.New("example not found") ErrNodeNotFound = errors.New("node not found") @@ -606,6 +637,25 @@ func (c *ReferenceServiceRPC) HandleNode(ctx context.Context, nodeID idwrap.IDWr if err := appendNodeRef(nodeVarRef, fmt.Sprintf("node %q ws send schema", node.Name)); err != nil { return nil, connect.NewError(connect.CodeInternal, err) } + + case mflow.NODE_KIND_RUN_SUB_FLOW: + // RunSubFlow outputs are dynamic, defined by the target flow's SubFlowReturn node + nodeVarsMap := map[string]interface{}{} + nodeVarRef := reference.NewReferenceFromInterfaceWithKey(nodeVarsMap, node.Name) + if err := appendNodeRef(nodeVarRef, fmt.Sprintf("node %q run sub-flow schema", node.Name)); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + case mflow.NODE_KIND_SUB_FLOW_TRIGGER: + nodeVarsMap := c.subFlowTriggerParamMap(ctx, node.ID) + nodeVarRef := reference.NewReferenceFromInterfaceWithKey(nodeVarsMap, node.Name) + if err := appendNodeRef(nodeVarRef, fmt.Sprintf("node %q sub-flow trigger schema", node.Name)); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + case mflow.NODE_KIND_SUB_FLOW_RETURN: + // Terminal node — no output variables for downstream nodes + default: // Other node types (JS, CONDITION, etc.) don't have default schemas } @@ -938,6 +988,19 @@ func (c *ReferenceServiceRPC) ReferenceCompletion(ctx context.Context, req *conn "metrics": map[string]interface{}{}, } creator.AddWithKey(node.Name, nodeVarsMap) + + case mflow.NODE_KIND_RUN_SUB_FLOW: + // RunSubFlow outputs are dynamic, defined by target flow's SubFlowReturn + nodeVarsMap := map[string]interface{}{} + creator.AddWithKey(node.Name, nodeVarsMap) + + case mflow.NODE_KIND_SUB_FLOW_TRIGGER: + nodeVarsMap := c.subFlowTriggerParamMap(ctx, node.ID) + creator.AddWithKey(node.Name, nodeVarsMap) + + case mflow.NODE_KIND_SUB_FLOW_RETURN: + // Terminal node — no output for downstream nodes + default: // Other node types don't have default schemas for completion } @@ -1468,6 +1531,18 @@ func (c *ReferenceServiceRPC) ReferenceValue(ctx context.Context, req *connect.R "connectionNode": "string", } lookup.AddWithKey(node.Name, nodeVarsMap) + + case mflow.NODE_KIND_RUN_SUB_FLOW: + nodeVarsMap := map[string]interface{}{} + lookup.AddWithKey(node.Name, nodeVarsMap) + + case mflow.NODE_KIND_SUB_FLOW_TRIGGER: + nodeVarsMap := c.subFlowTriggerParamMap(ctx, node.ID) + lookup.AddWithKey(node.Name, nodeVarsMap) + + case mflow.NODE_KIND_SUB_FLOW_RETURN: + // Terminal node — no output for downstream nodes + default: // Other node types (JS, CONDITION, etc.) don't have default schemas } diff --git a/packages/server/internal/converter/converter.go b/packages/server/internal/converter/converter.go index 21290b230..0bc09337e 100644 --- a/packages/server/internal/converter/converter.go +++ b/packages/server/internal/converter/converter.go @@ -391,6 +391,14 @@ func ToAPINodeKind(kind mflow.NodeKind) flowv1.NodeKind { return flowv1.NodeKind_NODE_KIND_WS_SEND case mflow.NODE_KIND_WAIT: return flowv1.NodeKind_NODE_KIND_WAIT + case mflow.NODE_KIND_WEBHOOK_TRIGGER: + return flowv1.NodeKind_NODE_KIND_WEBHOOK_TRIGGER + case mflow.NODE_KIND_SUB_FLOW_TRIGGER: + return flowv1.NodeKind_NODE_KIND_SUB_FLOW_TRIGGER + case mflow.NODE_KIND_SUB_FLOW_RETURN: + return flowv1.NodeKind_NODE_KIND_SUB_FLOW_RETURN + case mflow.NODE_KIND_RUN_SUB_FLOW: + return flowv1.NodeKind_NODE_KIND_RUN_SUB_FLOW default: return flowv1.NodeKind_NODE_KIND_UNSPECIFIED } diff --git a/packages/server/internal/migrations/01KK7EDJ_add_sub_flow_tables.go b/packages/server/internal/migrations/01KK7EDJ_add_sub_flow_tables.go new file mode 100644 index 000000000..c6d32738b --- /dev/null +++ b/packages/server/internal/migrations/01KK7EDJ_add_sub_flow_tables.go @@ -0,0 +1,79 @@ +package migrations + +import ( + "context" + "database/sql" + "fmt" + + "github.com/the-dev-tools/dev-tools/packages/server/internal/migrate" +) + +const MigrationAddSubFlowTablesID = "01KK7EDJV31GSEJFTN11H5WGFH" + +const MigrationAddSubFlowTablesChecksum = "sha256:add-sub-flow-tables-v1" + +func init() { + if err := migrate.Register(migrate.Migration{ + ID: MigrationAddSubFlowTablesID, + Checksum: MigrationAddSubFlowTablesChecksum, + Description: "Add sub-flow node tables (trigger, return, run)", + Apply: applySubFlowTables, + Validate: validateSubFlowTables, + RequiresBackup: false, + }); err != nil { + panic("failed to register sub-flow tables migration: " + err.Error()) + } +} + +func applySubFlowTables(ctx context.Context, tx *sql.Tx) error { + if _, err := tx.ExecContext(ctx, ` + CREATE TABLE IF NOT EXISTS flow_node_sub_flow_trigger ( + flow_node_id BLOB NOT NULL PRIMARY KEY, + params BLOB NOT NULL DEFAULT '[]' + ) + `); err != nil { + return fmt.Errorf("create flow_node_sub_flow_trigger table: %w", err) + } + + if _, err := tx.ExecContext(ctx, ` + CREATE TABLE IF NOT EXISTS flow_node_sub_flow_return ( + flow_node_id BLOB NOT NULL PRIMARY KEY, + outputs BLOB NOT NULL DEFAULT '[]' + ) + `); err != nil { + return fmt.Errorf("create flow_node_sub_flow_return table: %w", err) + } + + if _, err := tx.ExecContext(ctx, ` + CREATE TABLE IF NOT EXISTS flow_node_run_sub_flow ( + flow_node_id BLOB NOT NULL PRIMARY KEY, + target_flow_id BLOB, + target_flow_name TEXT NOT NULL DEFAULT '', + inputs BLOB NOT NULL DEFAULT '[]', + FOREIGN KEY (target_flow_id) REFERENCES flow (id) ON DELETE SET NULL + ) + `); err != nil { + return fmt.Errorf("create flow_node_run_sub_flow table: %w", err) + } + + return nil +} + +func validateSubFlowTables(ctx context.Context, db *sql.DB) error { + tables := []string{ + "flow_node_sub_flow_trigger", + "flow_node_sub_flow_return", + "flow_node_run_sub_flow", + } + for _, table := range tables { + var name string + err := db.QueryRowContext(ctx, ` + SELECT name FROM sqlite_master + WHERE type='table' AND name=? + `, table).Scan(&name) + if err != nil { + return fmt.Errorf("%s table not found: %w", table, err) + } + } + return nil +} diff --git a/packages/server/pkg/expression/eval.go b/packages/server/pkg/expression/eval.go index 7a92d1750..e4e359c76 100644 --- a/packages/server/pkg/expression/eval.go +++ b/packages/server/pkg/expression/eval.go @@ -44,28 +44,40 @@ func (e *UnifiedEnv) Eval(ctx context.Context, exprStr string) (any, error) { // EvalInterpolated first interpolates {{ }} patterns, then evaluates the result. // Use this when you need both interpolation AND expression evaluation. +// +// For single {{ expr }} patterns, typed values (arrays, maps, numbers, bools) are +// preserved without stringification. For multi-expression strings like "{{ a }} + {{ b }}", +// interpolation produces a string which is then evaluated as an expression. func (e *UnifiedEnv) EvalInterpolated(ctx context.Context, exprStr string) (any, error) { if e == nil { return nil, ErrNilEnv } - // Fast path: skip interpolation if no {{ }} patterns - interpolated := exprStr if HasVars(exprStr) { - var err error - interpolated, err = e.Interpolate(exprStr) + // Use ResolveValue which preserves typed values for single {{ expr }} patterns + // and interpolates multi-expression strings. + val, err := e.ResolveValue(exprStr) if err != nil { return nil, err } - // If the entire string was just a variable reference that got replaced, - // and the result is not a valid expression, return the interpolated value - if !looksLikeExpression(interpolated) { - return interpolated, nil + // If the resolved value is not a string (e.g. array, map, number, bool), + // return it directly — no further expression evaluation needed. + str, isString := val.(string) + if !isString { + return val, nil + } + + // For string results, check if it looks like an expression to evaluate + // (e.g. "5 + 3" from "{{ a }} + {{ b }}" interpolation). + if looksLikeExpression(str) { + return e.Eval(ctx, str) } + + return str, nil } - return e.Eval(ctx, interpolated) + return e.Eval(ctx, exprStr) } // EvalBool evaluates a pure expr-lang expression and returns the result as a boolean. diff --git a/packages/server/pkg/flow/flowbuilder/builder.go b/packages/server/pkg/flow/flowbuilder/builder.go index 3248fdedd..1443cef22 100644 --- a/packages/server/pkg/flow/flowbuilder/builder.go +++ b/packages/server/pkg/flow/flowbuilder/builder.go @@ -20,6 +20,9 @@ import ( "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/naiprovider" "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/nrequest" "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/nstart" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/nrunsubflow" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/nsubflowreturn" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/nsubflowtrigger" "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/nwait" "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/nwsconnection" "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/nwssend" @@ -51,7 +54,11 @@ type Builder struct { NodeGraphQL *sflow.NodeGraphQLService NodeWsConnection *sflow.NodeWsConnectionService NodeWsSend *sflow.NodeWsSendService - NodeWait *sflow.NodeWaitService + NodeWait *sflow.NodeWaitService + NodeSubFlowTrigger *sflow.NodeSubFlowTriggerService + NodeSubFlowReturn *sflow.NodeSubFlowReturnService + NodeRunSubFlow *sflow.NodeRunSubFlowService + SubFlowExecutor nrunsubflow.SubFlowExecutor WebSocket *swebsocket.WebSocketService WebSocketHeader *swebsocket.WebSocketHeaderService GraphQL *sgraphql.GraphQLService @@ -81,6 +88,9 @@ func New( nwcs *sflow.NodeWsConnectionService, nwss *sflow.NodeWsSendService, nwaits *sflow.NodeWaitService, + nsfts *sflow.NodeSubFlowTriggerService, + nsfrs *sflow.NodeSubFlowReturnService, + nrsfs *sflow.NodeRunSubFlowService, wsSvc *swebsocket.WebSocketService, wsHeaderSvc *swebsocket.WebSocketHeaderService, gqls *sgraphql.GraphQLService, @@ -107,6 +117,9 @@ func New( NodeWsConnection: nwcs, NodeWsSend: nwss, NodeWait: nwaits, + NodeSubFlowTrigger: nsfts, + NodeSubFlowReturn: nsfrs, + NodeRunSubFlow: nrsfs, WebSocket: wsSvc, WebSocketHeader: wsHeaderSvc, GraphQL: gqls, @@ -380,6 +393,48 @@ func (b *Builder) BuildNodes( } } flowNodeMap[nodeModel.ID] = nwait.New(nodeModel.ID, nodeModel.Name, durationMs) + case mflow.NODE_KIND_SUB_FLOW_TRIGGER: + var params []mflow.SubFlowParam + if b.NodeSubFlowTrigger != nil { + cfg, err := b.NodeSubFlowTrigger.GetNodeSubFlowTrigger(ctx, nodeModel.ID) + if err != nil { + return nil, nil, fmt.Errorf("get sub-flow trigger config: %w", err) + } + if cfg != nil { + params = cfg.Params + } + } + flowNodeMap[nodeModel.ID] = nsubflowtrigger.New(nodeModel.ID, nodeModel.Name, params) + startNodeIDs = append(startNodeIDs, nodeModel.ID) + case mflow.NODE_KIND_SUB_FLOW_RETURN: + var outputs []mflow.SubFlowOutput + if b.NodeSubFlowReturn != nil { + cfg, err := b.NodeSubFlowReturn.GetNodeSubFlowReturn(ctx, nodeModel.ID) + if err != nil { + return nil, nil, fmt.Errorf("get sub-flow return config: %w", err) + } + if cfg != nil { + outputs = cfg.Outputs + } + } + flowNodeMap[nodeModel.ID] = nsubflowreturn.New(nodeModel.ID, nodeModel.Name, outputs) + case mflow.NODE_KIND_RUN_SUB_FLOW: + var targetFlowID *idwrap.IDWrap + var targetFlowName string + var inputs []mflow.SubFlowInputMapping + if b.NodeRunSubFlow != nil { + cfg, err := b.NodeRunSubFlow.GetNodeRunSubFlow(ctx, nodeModel.ID) + if err != nil { + return nil, nil, fmt.Errorf("get run sub-flow config: %w", err) + } + if cfg != nil { + targetFlowID = cfg.TargetFlowID + targetFlowName = cfg.TargetFlowName + inputs = cfg.Inputs + } + } + runNode := nrunsubflow.New(nodeModel.ID, nodeModel.Name, targetFlowID, targetFlowName, inputs, b.SubFlowExecutor) + flowNodeMap[nodeModel.ID] = runNode default: return nil, nil, fmt.Errorf("node kind %d not supported", nodeModel.NodeKind) } diff --git a/packages/server/pkg/flow/flowbuilder/subflow_executor.go b/packages/server/pkg/flow/flowbuilder/subflow_executor.go new file mode 100644 index 000000000..c0ee387cd --- /dev/null +++ b/packages/server/pkg/flow/flowbuilder/subflow_executor.go @@ -0,0 +1,215 @@ +//nolint:revive // exported +package flowbuilder + +import ( + "context" + "fmt" + "time" + + "log/slog" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/ngraphql" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/nrequest" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/nrunsubflow" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/runner" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/runner/flowlocalrunner" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/httpclient" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/service/sflow" + "github.com/the-dev-tools/dev-tools/packages/spec/dist/buf/go/api/private/node_js_executor/v1/node_js_executorv1connect" +) + +const maxSubFlowDepth = 10 + +// subFlowCallStackKey is the context key for the sub-flow call stack. +type subFlowCallStackKey struct{} + +// subFlowCallStack tracks active flow IDs to detect circular calls. +type subFlowCallStack struct { + flowIDs []idwrap.IDWrap +} + +func getCallStack(ctx context.Context) *subFlowCallStack { + if cs, ok := ctx.Value(subFlowCallStackKey{}).(*subFlowCallStack); ok { + return cs + } + return &subFlowCallStack{} +} + +func withCallStack(ctx context.Context, cs *subFlowCallStack) context.Context { + return context.WithValue(ctx, subFlowCallStackKey{}, cs) +} + +// SubFlowExecutorImpl implements nrunsubflow.SubFlowExecutor using database +// services. It loads the target flow from the DB, builds nodes using the +// Builder, and runs the flow synchronously via FlowLocalRunner. +type SubFlowExecutorImpl struct { + Builder *Builder + FlowService *sflow.FlowService + EdgeService *sflow.EdgeService + JSClient node_js_executorv1connect.NodeJsExecutorServiceClient + Logger *slog.Logger +} + +var _ nrunsubflow.SubFlowExecutor = (*SubFlowExecutorImpl)(nil) + +func NewSubFlowExecutor( + builder *Builder, + flowService *sflow.FlowService, + edgeService *sflow.EdgeService, + jsClient node_js_executorv1connect.NodeJsExecutorServiceClient, + logger *slog.Logger, +) *SubFlowExecutorImpl { + return &SubFlowExecutorImpl{ + Builder: builder, + FlowService: flowService, + EdgeService: edgeService, + JSClient: jsClient, + Logger: logger, + } +} + +func (e *SubFlowExecutorImpl) ExecuteSubFlow(ctx context.Context, targetFlowID *idwrap.IDWrap, targetFlowName string, inputVars map[string]any) (map[string]any, error) { + // Check call stack depth + stack := getCallStack(ctx) + if len(stack.flowIDs) >= maxSubFlowDepth { + return nil, fmt.Errorf("sub-flow call depth exceeded (max %d)", maxSubFlowDepth) + } + + // Resolve target flow + flow, err := e.resolveFlow(ctx, targetFlowID, targetFlowName) + if err != nil { + return nil, fmt.Errorf("resolve sub-flow: %w", err) + } + + // Check for circular calls + for _, id := range stack.flowIDs { + if id == flow.ID { + return nil, fmt.Errorf("circular sub-flow call detected: flow %q (ID %s)", flow.Name, flow.ID.String()) + } + } + + // Push current flow onto the call stack + newStack := &subFlowCallStack{ + flowIDs: make([]idwrap.IDWrap, len(stack.flowIDs)+1), + } + copy(newStack.flowIDs, stack.flowIDs) + newStack.flowIDs[len(stack.flowIDs)] = flow.ID + ctx = withCallStack(ctx, newStack) + + // Load flow data + nodes, err := e.Builder.Node.GetNodesByFlowID(ctx, flow.ID) + if err != nil { + return nil, fmt.Errorf("get sub-flow nodes: %w", err) + } + + edges, err := e.EdgeService.GetEdgesByFlowID(ctx, flow.ID) + if err != nil { + return nil, fmt.Errorf("get sub-flow edges: %w", err) + } + + flowVars, err := e.Builder.FlowVariable.GetFlowVariablesByFlowID(ctx, flow.ID) + if err != nil { + return nil, fmt.Errorf("get sub-flow variables: %w", err) + } + + // Build base variables (environment + flow variables) + baseVars, err := e.Builder.BuildVariables(ctx, flow.WorkspaceID, flowVars) + if err != nil { + return nil, fmt.Errorf("build sub-flow variables: %w", err) + } + + // Inject input variables (override any existing vars with same name) + for k, v := range inputVars { + baseVars[k] = v + } + + // Create HTTP client and response channels for the sub-flow + httpClient := httpclient.New() + bufSize := len(nodes) * 10 + if bufSize < 10 { + bufSize = 10 + } + + requestRespChan := make(chan nrequest.NodeRequestSideResp, bufSize) + gqlRespChan := make(chan ngraphql.NodeGraphQLSideResp, bufSize) + + // Drain response channels + go func() { + for resp := range requestRespChan { + if resp.Done != nil { + close(resp.Done) + } + } + }() + go func() { + for resp := range gqlRespChan { + if resp.Done != nil { + close(resp.Done) + } + } + }() + defer close(requestRespChan) + defer close(gqlRespChan) + + // Build flow nodes + edgeMap := mflow.NewEdgesMap(edges) + timeout := 60 * time.Second + + flowNodeMap, startNodeIDs, err := e.Builder.BuildNodes( + ctx, flow, nodes, timeout, httpClient, requestRespChan, gqlRespChan, e.JSClient, + ) + if err != nil { + return nil, fmt.Errorf("build sub-flow nodes: %w", err) + } + + // Create and run the flow + flowRunner := flowlocalrunner.CreateFlowRunner( + idwrap.NewMonotonic(), flow.ID, startNodeIDs, flowNodeMap, edgeMap, timeout, e.Logger, + ) + + runErr := flowRunner.RunWithEvents(ctx, runner.FlowEventChannels{}, baseVars) + if runErr != nil { + return nil, fmt.Errorf("sub-flow execution failed: %w", runErr) + } + + // Extract outputs from the SubFlowReturn node + return extractReturnOutputs(nodes, flowNodeMap, baseVars), nil +} + +func (e *SubFlowExecutorImpl) resolveFlow(ctx context.Context, targetFlowID *idwrap.IDWrap, targetFlowName string) (mflow.Flow, error) { + if targetFlowID != nil && *targetFlowID != (idwrap.IDWrap{}) { + flow, err := e.FlowService.GetFlow(ctx, *targetFlowID) + if err == nil { + return flow, nil + } + return mflow.Flow{}, fmt.Errorf("sub-flow ID %s not found: %w", targetFlowID.String(), err) + } + if targetFlowName == "" { + return mflow.Flow{}, fmt.Errorf("sub-flow target not specified: neither ID nor name provided") + } + // Name-based resolution is not supported without a workspace context. + // The YAML converter resolves names to IDs at import time. + return mflow.Flow{}, fmt.Errorf("sub-flow %q not found (name-only resolution requires prior ID assignment)", targetFlowName) +} + +// extractReturnOutputs finds the SubFlowReturn node's outputs in the VarMap. +func extractReturnOutputs(nodes []mflow.Node, flowNodeMap map[idwrap.IDWrap]node.FlowNode, baseVars map[string]any) map[string]any { + for _, n := range nodes { + if n.NodeKind != mflow.NODE_KIND_SUB_FLOW_RETURN { + continue + } + fn, ok := flowNodeMap[n.ID] + if !ok { + continue + } + if outputs, ok := baseVars[fn.GetName()]; ok { + if outputMap, ok := outputs.(map[string]any); ok { + return outputMap + } + } + } + return make(map[string]any) +} diff --git a/packages/server/pkg/flow/flowexec/snapshot.go b/packages/server/pkg/flow/flowexec/snapshot.go index 03c4b2ae6..e837347b6 100644 --- a/packages/server/pkg/flow/flowexec/snapshot.go +++ b/packages/server/pkg/flow/flowexec/snapshot.go @@ -394,3 +394,66 @@ func (s *WaitSnapshot) WriteTx(ctx context.Context, tx *sql.Tx, newNodeID idwrap writer := s.Service.TX(tx) return newData, writer.CreateNodeWait(ctx, newData) } + +// --- SubFlowTrigger --- + +type SubFlowTriggerSnapshot struct{ Service *sflow.NodeSubFlowTriggerService } + +func (s *SubFlowTriggerSnapshot) Kind() mflow.NodeKind { return mflow.NODE_KIND_SUB_FLOW_TRIGGER } + +func (s *SubFlowTriggerSnapshot) Read(ctx context.Context, nodeID idwrap.IDWrap) (any, error) { + return s.Service.GetNodeSubFlowTrigger(ctx, nodeID) +} + +func (s *SubFlowTriggerSnapshot) WriteTx(ctx context.Context, tx *sql.Tx, newNodeID idwrap.IDWrap, config any) (any, error) { + src, _ := config.(*mflow.NodeSubFlowTrigger) + if src == nil { + return nil, nil + } + newData := *src + newData.FlowNodeID = newNodeID + writer := s.Service.TX(tx) + return newData, writer.CreateNodeSubFlowTrigger(ctx, newData) +} + +// --- SubFlowReturn --- + +type SubFlowReturnSnapshot struct{ Service *sflow.NodeSubFlowReturnService } + +func (s *SubFlowReturnSnapshot) Kind() mflow.NodeKind { return mflow.NODE_KIND_SUB_FLOW_RETURN } + +func (s *SubFlowReturnSnapshot) Read(ctx context.Context, nodeID idwrap.IDWrap) (any, error) { + return s.Service.GetNodeSubFlowReturn(ctx, nodeID) +} + +func (s *SubFlowReturnSnapshot) WriteTx(ctx context.Context, tx *sql.Tx, newNodeID idwrap.IDWrap, config any) (any, error) { + src, _ := config.(*mflow.NodeSubFlowReturn) + if src == nil { + return nil, nil + } + newData := *src + newData.FlowNodeID = newNodeID + writer := s.Service.TX(tx) + return newData, writer.CreateNodeSubFlowReturn(ctx, newData) +} + +// --- RunSubFlow --- + +type RunSubFlowSnapshot struct{ Service *sflow.NodeRunSubFlowService } + +func (s *RunSubFlowSnapshot) Kind() mflow.NodeKind { return mflow.NODE_KIND_RUN_SUB_FLOW } + +func (s *RunSubFlowSnapshot) Read(ctx context.Context, nodeID idwrap.IDWrap) (any, error) { + return s.Service.GetNodeRunSubFlow(ctx, nodeID) +} + +func (s *RunSubFlowSnapshot) WriteTx(ctx context.Context, tx *sql.Tx, newNodeID idwrap.IDWrap, config any) (any, error) { + src, _ := config.(*mflow.NodeRunSubFlow) + if src == nil { + return nil, nil + } + newData := *src + newData.FlowNodeID = newNodeID + writer := s.Service.TX(tx) + return newData, writer.CreateNodeRunSubFlow(ctx, newData) +} diff --git a/packages/server/pkg/flow/node/nrunsubflow/nrunsubflow.go b/packages/server/pkg/flow/node/nrunsubflow/nrunsubflow.go new file mode 100644 index 000000000..a228d1bb5 --- /dev/null +++ b/packages/server/pkg/flow/node/nrunsubflow/nrunsubflow.go @@ -0,0 +1,161 @@ +//nolint:revive // exported +package nrunsubflow + +import ( + "context" + "fmt" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/expression" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node/nai" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +// SubFlowExecutor loads and runs a target sub-flow. Implementations live in +// the flowbuilder or CLI packages where they have access to all required services. +type SubFlowExecutor interface { + // ExecuteSubFlow runs the target flow with the given input variables. + // It returns the output variables produced by the sub-flow's Return node. + ExecuteSubFlow(ctx context.Context, targetFlowID *idwrap.IDWrap, targetFlowName string, inputVars map[string]any) (map[string]any, error) +} + +// NodeRunSubFlow invokes another flow from the parent flow. It evaluates input +// expressions, calls the SubFlowExecutor, and writes the sub-flow outputs to +// the parent VarMap under this node's name. +type NodeRunSubFlow struct { + FlowNodeID idwrap.IDWrap + Name string + TargetFlowID *idwrap.IDWrap + TargetFlowName string + Inputs []mflow.SubFlowInputMapping + Executor SubFlowExecutor + + // TargetParams holds the target sub-flow's trigger parameter definitions. + // Populated by the builder when it can resolve the target flow. + // Used by GetAIParams() for AI tool integration. + TargetParams []mflow.SubFlowParam +} + +func New( + id idwrap.IDWrap, + name string, + targetFlowID *idwrap.IDWrap, + targetFlowName string, + inputs []mflow.SubFlowInputMapping, + executor SubFlowExecutor, +) *NodeRunSubFlow { + return &NodeRunSubFlow{ + FlowNodeID: id, + Name: name, + TargetFlowID: targetFlowID, + TargetFlowName: targetFlowName, + Inputs: inputs, + Executor: executor, + } +} + +func (n *NodeRunSubFlow) GetID() idwrap.IDWrap { + return n.FlowNodeID +} + +func (n *NodeRunSubFlow) GetName() string { + return n.Name +} + +func (n *NodeRunSubFlow) RunSync(ctx context.Context, req *node.FlowNodeRequest) node.FlowNodeResult { + if n.Executor == nil { + return node.FlowNodeResult{Err: fmt.Errorf("sub-flow executor not configured for node %s", n.Name)} + } + + // Evaluate input expressions against parent VarMap + varMapCopy := node.DeepCopyVarMap(req) + env := expression.NewUnifiedEnv(varMapCopy) + if req.VariableTracker != nil { + env = env.WithTracking(req.VariableTracker) + } + + inputVars := make(map[string]any, len(n.Inputs)) + for _, input := range n.Inputs { + if input.Expression == "" { + continue + } + val, err := env.EvalInterpolated(ctx, input.Expression) + if err != nil { + return node.FlowNodeResult{ + Err: fmt.Errorf("failed to evaluate sub-flow input '%s' expression '%s': %w", input.ParamName, input.Expression, err), + } + } + inputVars[input.ParamName] = val + } + + // Execute the sub-flow + outputs, err := n.Executor.ExecuteSubFlow(ctx, n.TargetFlowID, n.TargetFlowName, inputVars) + if err != nil { + return node.FlowNodeResult{ + Err: fmt.Errorf("sub-flow execution failed: %w", err), + } + } + + // Write outputs to parent VarMap under this node's name + if outputs == nil { + outputs = make(map[string]interface{}) + } + if req.VariableTracker != nil { + if err := node.WriteNodeVarBulkWithTracking(req, n.Name, outputs, req.VariableTracker); err != nil { + return node.FlowNodeResult{Err: fmt.Errorf("failed to write sub-flow outputs: %w", err)} + } + } else { + if err := node.WriteNodeVarBulk(req, n.Name, outputs); err != nil { + return node.FlowNodeResult{Err: fmt.Errorf("failed to write sub-flow outputs: %w", err)} + } + } + + nextID := mflow.GetNextNodeID(req.EdgeSourceMap, n.FlowNodeID, mflow.HandleUnspecified) + return node.FlowNodeResult{NextNodeID: nextID} +} + +func (n *NodeRunSubFlow) RunAsync(ctx context.Context, req *node.FlowNodeRequest, resultChan chan node.FlowNodeResult) { + resultChan <- n.RunSync(ctx, req) +} + +// GetAIParams implements nai.AIParamProvider. When RunSubFlow is connected to +// an AI node via HandleAiTools, the AI agent can invoke it as a tool. The +// parameter schema comes from the target flow's SubFlowTrigger params. +func (n *NodeRunSubFlow) GetAIParams() []nai.AIParam { + if len(n.TargetParams) == 0 { + return nil + } + + params := make([]nai.AIParam, 0, len(n.TargetParams)) + for _, p := range n.TargetParams { + aiType := p.Type + if aiType == "" { + aiType = nai.AIParamTypeString + } + params = append(params, nai.AIParam{ + Name: p.Name, + Type: aiType, + Required: p.Required, + }) + } + return params +} + +// GetRequiredVariables implements node.VariableIntrospector. +func (n *NodeRunSubFlow) GetRequiredVariables() []string { + var vars []string + for _, input := range n.Inputs { + if input.Expression != "" { + vars = append(vars, expression.ExtractExprIdentifiers(input.Expression)...) + } + } + return vars +} + +// GetOutputVariables implements node.VariableIntrospector. +func (n *NodeRunSubFlow) GetOutputVariables() []string { + // We don't know the exact outputs at build time without resolving the + // target flow, so return a generic indicator. + return []string{"*"} +} diff --git a/packages/server/pkg/flow/node/nsubflowreturn/nsubflowreturn.go b/packages/server/pkg/flow/node/nsubflowreturn/nsubflowreturn.go new file mode 100644 index 000000000..6a2948864 --- /dev/null +++ b/packages/server/pkg/flow/node/nsubflowreturn/nsubflowreturn.go @@ -0,0 +1,97 @@ +//nolint:revive // exported +package nsubflowreturn + +import ( + "context" + "fmt" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/expression" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +// NodeSubFlowReturn is a terminal node in a sub-flow. It evaluates output +// expressions against the sub-flow's VarMap and writes results under the node +// name. The RunSubFlow caller reads these outputs after execution completes. +type NodeSubFlowReturn struct { + FlowNodeID idwrap.IDWrap + Name string + Outputs []mflow.SubFlowOutput +} + +func New(id idwrap.IDWrap, name string, outputs []mflow.SubFlowOutput) *NodeSubFlowReturn { + return &NodeSubFlowReturn{ + FlowNodeID: id, + Name: name, + Outputs: outputs, + } +} + +func (n *NodeSubFlowReturn) GetID() idwrap.IDWrap { + return n.FlowNodeID +} + +func (n *NodeSubFlowReturn) GetName() string { + return n.Name +} + +func (n *NodeSubFlowReturn) RunSync(ctx context.Context, req *node.FlowNodeRequest) node.FlowNodeResult { + varMapCopy := node.DeepCopyVarMap(req) + env := expression.NewUnifiedEnv(varMapCopy) + if req.VariableTracker != nil { + env = env.WithTracking(req.VariableTracker) + } + + outputData := make(map[string]interface{}, len(n.Outputs)) + for _, out := range n.Outputs { + if out.Expression == "" { + outputData[out.Name] = nil + continue + } + val, err := env.EvalInterpolated(ctx, out.Expression) + if err != nil { + return node.FlowNodeResult{ + Err: fmt.Errorf("failed to evaluate sub-flow output '%s' expression '%s': %w", out.Name, out.Expression, err), + } + } + outputData[out.Name] = val + } + + if req.VariableTracker != nil { + if err := node.WriteNodeVarBulkWithTracking(req, n.Name, outputData, req.VariableTracker); err != nil { + return node.FlowNodeResult{Err: fmt.Errorf("failed to write return output: %w", err)} + } + } else { + if err := node.WriteNodeVarBulk(req, n.Name, outputData); err != nil { + return node.FlowNodeResult{Err: fmt.Errorf("failed to write return output: %w", err)} + } + } + + // Terminal node — no next nodes + return node.FlowNodeResult{} +} + +func (n *NodeSubFlowReturn) RunAsync(ctx context.Context, req *node.FlowNodeRequest, resultChan chan node.FlowNodeResult) { + resultChan <- n.RunSync(ctx, req) +} + +// GetRequiredVariables implements node.VariableIntrospector. +func (n *NodeSubFlowReturn) GetRequiredVariables() []string { + var vars []string + for _, out := range n.Outputs { + if out.Expression != "" { + vars = append(vars, expression.ExtractExprIdentifiers(out.Expression)...) + } + } + return vars +} + +// GetOutputVariables implements node.VariableIntrospector. +func (n *NodeSubFlowReturn) GetOutputVariables() []string { + vars := make([]string, 0, len(n.Outputs)) + for _, out := range n.Outputs { + vars = append(vars, out.Name) + } + return vars +} diff --git a/packages/server/pkg/flow/node/nsubflowtrigger/nsubflowtrigger.go b/packages/server/pkg/flow/node/nsubflowtrigger/nsubflowtrigger.go new file mode 100644 index 000000000..eccce725d --- /dev/null +++ b/packages/server/pkg/flow/node/nsubflowtrigger/nsubflowtrigger.go @@ -0,0 +1,133 @@ +//nolint:revive // exported +package nsubflowtrigger + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + "github.com/the-dev-tools/dev-tools/packages/server/pkg/flow/node" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +// NodeSubFlowTrigger is an entry node for sub-flows. It defines input parameters +// that the calling flow must provide. When a sub-flow is invoked, the RunSubFlow +// node injects parameter values into the VarMap before execution starts. This node +// validates required params exist and applies defaults for missing optional params. +type NodeSubFlowTrigger struct { + FlowNodeID idwrap.IDWrap + Name string + Params []mflow.SubFlowParam +} + +func New(id idwrap.IDWrap, name string, params []mflow.SubFlowParam) *NodeSubFlowTrigger { + return &NodeSubFlowTrigger{ + FlowNodeID: id, + Name: name, + Params: params, + } +} + +func (n *NodeSubFlowTrigger) GetID() idwrap.IDWrap { + return n.FlowNodeID +} + +func (n *NodeSubFlowTrigger) GetName() string { + return n.Name +} + +func (n *NodeSubFlowTrigger) IsEntryNode() bool { + return true +} + +func (n *NodeSubFlowTrigger) RunSync(ctx context.Context, req *node.FlowNodeRequest) node.FlowNodeResult { + // Validate required params and apply defaults under a single lock to avoid TOCTOU. + // Input values are already injected into VarMap by the RunSubFlow caller. + req.ReadWriteLock.Lock() + for _, p := range n.Params { + if _, exists := req.VarMap[p.Name]; !exists { + if p.Required { + req.ReadWriteLock.Unlock() + return node.FlowNodeResult{ + Err: fmt.Errorf("missing required sub-flow parameter: %s", p.Name), + } + } + if p.DefaultValue != "" { + req.VarMap[p.Name] = parseDefaultValue(p.DefaultValue, p.Type) + } + } + } + + // Write param metadata under node name for introspection + paramInfo := make(map[string]interface{}, len(n.Params)) + for _, p := range n.Params { + if v, ok := req.VarMap[p.Name]; ok { + paramInfo[p.Name] = v + } + } + req.VarMap[n.Name] = paramInfo + req.ReadWriteLock.Unlock() + + nextID := mflow.GetNextNodeID(req.EdgeSourceMap, n.FlowNodeID, mflow.HandleUnspecified) + return node.FlowNodeResult{NextNodeID: nextID} +} + +func (n *NodeSubFlowTrigger) RunAsync(ctx context.Context, req *node.FlowNodeRequest, resultChan chan node.FlowNodeResult) { + resultChan <- n.RunSync(ctx, req) +} + +// GetRequiredVariables implements node.VariableIntrospector. +func (n *NodeSubFlowTrigger) GetRequiredVariables() []string { + vars := make([]string, 0, len(n.Params)) + for _, p := range n.Params { + vars = append(vars, p.Name) + } + return vars +} + +// GetOutputVariables implements node.VariableIntrospector. +func (n *NodeSubFlowTrigger) GetOutputVariables() []string { + vars := make([]string, 0, len(n.Params)) + for _, p := range n.Params { + vars = append(vars, p.Name) + } + return vars +} + +// parseDefaultValue converts a string default value to the appropriate Go type +// based on the parameter's declared type. +func parseDefaultValue(raw string, typ string) interface{} { + switch typ { + case "number": + d := json.NewDecoder(strings.NewReader(raw)) + d.UseNumber() + var n json.Number + if err := d.Decode(&n); err == nil { + if i, err := n.Int64(); err == nil { + return i + } + if f, err := n.Float64(); err == nil { + return f + } + } + return raw + case "boolean": + switch raw { + case "true": + return true + case "false": + return false + } + return raw + case "json": + var v interface{} + if err := json.Unmarshal([]byte(raw), &v); err == nil { + return v + } + return raw + default: // "string", "any", "" + return raw + } +} diff --git a/packages/server/pkg/ioworkspace/exporter.go b/packages/server/pkg/ioworkspace/exporter.go index bc8fb2bb4..b847054e5 100644 --- a/packages/server/pkg/ioworkspace/exporter.go +++ b/packages/server/pkg/ioworkspace/exporter.go @@ -232,6 +232,9 @@ func (s *IOWorkspaceService) exportFlows(ctx context.Context, opts ExportOptions nodeWsConnectionService := sflow.NewNodeWsConnectionService(s.queries) nodeWsSendService := sflow.NewNodeWsSendService(s.queries) nodeWaitService := sflow.NewNodeWaitService(s.queries) + nodeSubFlowTriggerService := sflow.NewNodeSubFlowTriggerService(s.queries) + nodeSubFlowReturnService := sflow.NewNodeSubFlowReturnService(s.queries) + nodeRunSubFlowService := sflow.NewNodeRunSubFlowService(s.queries) websocketService := swebsocket.New(s.queries, s.logger) websocketHeaderService := swebsocket.NewWebSocketHeaderService(s.queries) @@ -287,7 +290,7 @@ func (s *IOWorkspaceService) exportFlows(ctx context.Context, opts ExportOptions // Export node implementations based on node types for _, node := range nodes { - if err := s.exportNodeImplementation(ctx, node, bundle, nodeRequestService, nodeIfService, nodeForService, nodeForEachService, nodeJSService, nodeAIService, nodeAIProviderService, nodeMemoryService, nodeGraphQLService, nodeWsConnectionService, nodeWsSendService, nodeWaitService, websocketService, websocketHeaderService); err != nil { + if err := s.exportNodeImplementation(ctx, node, bundle, nodeRequestService, nodeIfService, nodeForService, nodeForEachService, nodeJSService, nodeAIService, nodeAIProviderService, nodeMemoryService, nodeGraphQLService, nodeWsConnectionService, nodeWsSendService, nodeWaitService, nodeSubFlowTriggerService, nodeSubFlowReturnService, nodeRunSubFlowService, websocketService, websocketHeaderService); err != nil { return fmt.Errorf("failed to export node implementation for node %s: %w", node.ID.String(), err) } } @@ -308,7 +311,10 @@ func (s *IOWorkspaceService) exportFlows(ctx context.Context, opts ExportOptions "graphql_nodes", len(bundle.FlowGraphQLNodes), "ws_connection_nodes", len(bundle.FlowWsConnectionNodes), "ws_send_nodes", len(bundle.FlowWsSendNodes), - "wait_nodes", len(bundle.FlowWaitNodes)) + "wait_nodes", len(bundle.FlowWaitNodes), + "sub_flow_trigger_nodes", len(bundle.FlowSubFlowTriggerNodes), + "sub_flow_return_nodes", len(bundle.FlowSubFlowReturnNodes), + "run_sub_flow_nodes", len(bundle.FlowRunSubFlowNodes)) return nil } @@ -364,6 +370,9 @@ func (s *IOWorkspaceService) exportNodeImplementation( nodeWsConnectionService sflow.NodeWsConnectionService, nodeWsSendService sflow.NodeWsSendService, nodeWaitService sflow.NodeWaitService, + nodeSubFlowTriggerService sflow.NodeSubFlowTriggerService, + nodeSubFlowReturnService sflow.NodeSubFlowReturnService, + nodeRunSubFlowService sflow.NodeRunSubFlowService, websocketService swebsocket.WebSocketService, websocketHeaderService swebsocket.WebSocketHeaderService, ) error { @@ -492,6 +501,36 @@ func (s *IOWorkspaceService) exportNodeImplementation( if nodeWait != nil { bundle.FlowWaitNodes = append(bundle.FlowWaitNodes, *nodeWait) } + + case mflow.NODE_KIND_SUB_FLOW_TRIGGER: + nodeTrigger, err := nodeSubFlowTriggerService.GetNodeSubFlowTrigger(ctx, node.ID) + if err != nil { + return fmt.Errorf("failed to get sub-flow trigger node: %w", err) + } + if nodeTrigger != nil { + bundle.FlowSubFlowTriggerNodes = append(bundle.FlowSubFlowTriggerNodes, *nodeTrigger) + } + + case mflow.NODE_KIND_SUB_FLOW_RETURN: + nodeReturn, err := nodeSubFlowReturnService.GetNodeSubFlowReturn(ctx, node.ID) + if err != nil { + return fmt.Errorf("failed to get sub-flow return node: %w", err) + } + if nodeReturn != nil { + bundle.FlowSubFlowReturnNodes = append(bundle.FlowSubFlowReturnNodes, *nodeReturn) + } + + case mflow.NODE_KIND_RUN_SUB_FLOW: + nodeRunSubFlow, err := nodeRunSubFlowService.GetNodeRunSubFlow(ctx, node.ID) + if err != nil { + return fmt.Errorf("failed to get run sub-flow node: %w", err) + } + if nodeRunSubFlow != nil { + bundle.FlowRunSubFlowNodes = append(bundle.FlowRunSubFlowNodes, *nodeRunSubFlow) + } + + case mflow.NODE_KIND_WEBHOOK_TRIGGER: + // Not yet implemented } return nil diff --git a/packages/server/pkg/ioworkspace/importer.go b/packages/server/pkg/ioworkspace/importer.go index a34135cf5..d8778ae68 100644 --- a/packages/server/pkg/ioworkspace/importer.go +++ b/packages/server/pkg/ioworkspace/importer.go @@ -40,7 +40,10 @@ type ImportResult struct { FlowGraphQLNodesCreated int FlowWsConnectionNodesCreated int FlowWsSendNodesCreated int - FlowWaitNodesCreated int + FlowWaitNodesCreated int + FlowSubFlowTriggerNodesCreated int + FlowSubFlowReturnNodesCreated int + FlowRunSubFlowNodesCreated int WebSocketsCreated int WebSocketHeadersCreated int GraphQLRequestsCreated int @@ -102,6 +105,9 @@ func (s *IOWorkspaceService) Import(ctx context.Context, tx *sql.Tx, bundle *Wor nodeWsConnectionService := sflow.NewNodeWsConnectionService(s.queries).TX(tx) nodeWsSendService := sflow.NewNodeWsSendService(s.queries).TX(tx) nodeWaitService := sflow.NewNodeWaitService(s.queries).TX(tx) + nodeSubFlowTriggerService := sflow.NewNodeSubFlowTriggerService(s.queries).TX(tx) + nodeSubFlowReturnService := sflow.NewNodeSubFlowReturnService(s.queries).TX(tx) + nodeRunSubFlowService := sflow.NewNodeRunSubFlowService(s.queries).TX(tx) graphqlService := sgraphql.New(s.queries, nil).TX(tx) graphqlHeaderService := sgraphql.NewGraphQLHeaderService(s.queries).TX(tx) @@ -309,6 +315,24 @@ func (s *IOWorkspaceService) Import(ctx context.Context, tx *sql.Tx, bundle *Wor return nil, fmt.Errorf("failed to import flow wait nodes: %w", err) } } + + if len(bundle.FlowSubFlowTriggerNodes) > 0 { + if err := s.importFlowSubFlowTriggerNodes(ctx, nodeSubFlowTriggerService, bundle, opts, result); err != nil { + return nil, fmt.Errorf("failed to import flow sub-flow trigger nodes: %w", err) + } + } + + if len(bundle.FlowSubFlowReturnNodes) > 0 { + if err := s.importFlowSubFlowReturnNodes(ctx, nodeSubFlowReturnService, bundle, opts, result); err != nil { + return nil, fmt.Errorf("failed to import flow sub-flow return nodes: %w", err) + } + } + + if len(bundle.FlowRunSubFlowNodes) > 0 { + if err := s.importFlowRunSubFlowNodes(ctx, nodeRunSubFlowService, bundle, opts, result); err != nil { + return nil, fmt.Errorf("failed to import flow run sub-flow nodes: %w", err) + } + } } return result, nil diff --git a/packages/server/pkg/ioworkspace/importer_flow.go b/packages/server/pkg/ioworkspace/importer_flow.go index 4840ff801..0a297aa76 100644 --- a/packages/server/pkg/ioworkspace/importer_flow.go +++ b/packages/server/pkg/ioworkspace/importer_flow.go @@ -412,6 +412,61 @@ func (s *IOWorkspaceService) importFlowWaitNodes(ctx context.Context, nodeWaitSe return nil } +// importFlowSubFlowTriggerNodes imports flow SubFlowTrigger nodes from the bundle. +func (s *IOWorkspaceService) importFlowSubFlowTriggerNodes(ctx context.Context, service sflow.NodeSubFlowTriggerService, bundle *WorkspaceBundle, _ ImportOptions, result *ImportResult) error { + for _, node := range bundle.FlowSubFlowTriggerNodes { + if newNodeID, ok := result.NodeIDMap[node.FlowNodeID]; ok { + node.FlowNodeID = newNodeID + } + + if err := service.CreateNodeSubFlowTrigger(ctx, node); err != nil { + return fmt.Errorf("failed to create flow SubFlowTrigger node: %w", err) + } + + result.FlowSubFlowTriggerNodesCreated++ + } + return nil +} + +// importFlowSubFlowReturnNodes imports flow SubFlowReturn nodes from the bundle. +func (s *IOWorkspaceService) importFlowSubFlowReturnNodes(ctx context.Context, service sflow.NodeSubFlowReturnService, bundle *WorkspaceBundle, _ ImportOptions, result *ImportResult) error { + for _, node := range bundle.FlowSubFlowReturnNodes { + if newNodeID, ok := result.NodeIDMap[node.FlowNodeID]; ok { + node.FlowNodeID = newNodeID + } + + if err := service.CreateNodeSubFlowReturn(ctx, node); err != nil { + return fmt.Errorf("failed to create flow SubFlowReturn node: %w", err) + } + + result.FlowSubFlowReturnNodesCreated++ + } + return nil +} + +// importFlowRunSubFlowNodes imports flow RunSubFlow nodes from the bundle. +func (s *IOWorkspaceService) importFlowRunSubFlowNodes(ctx context.Context, service sflow.NodeRunSubFlowService, bundle *WorkspaceBundle, _ ImportOptions, result *ImportResult) error { + for _, node := range bundle.FlowRunSubFlowNodes { + if newNodeID, ok := result.NodeIDMap[node.FlowNodeID]; ok { + node.FlowNodeID = newNodeID + } + + // Remap target flow ID if it was remapped during import + if node.TargetFlowID != nil { + if newFlowID, ok := result.FlowIDMap[*node.TargetFlowID]; ok { + node.TargetFlowID = &newFlowID + } + } + + if err := service.CreateNodeRunSubFlow(ctx, node); err != nil { + return fmt.Errorf("failed to create flow RunSubFlow node: %w", err) + } + + result.FlowRunSubFlowNodesCreated++ + } + return nil +} + // importWebSockets imports WebSocket entities from the bundle. func (s *IOWorkspaceService) importWebSockets(ctx context.Context, wsService swebsocket.WebSocketService, bundle *WorkspaceBundle, opts ImportOptions, result *ImportResult) error { for _, ws := range bundle.WebSockets { diff --git a/packages/server/pkg/ioworkspace/layout.go b/packages/server/pkg/ioworkspace/layout.go index 424883c36..287d1b209 100644 --- a/packages/server/pkg/ioworkspace/layout.go +++ b/packages/server/pkg/ioworkspace/layout.go @@ -38,7 +38,8 @@ func (wb *WorkspaceBundle) ensureStartNodeForFlow(flowID idwrap.IDWrap) error { // Check if start node already exists for this flow var startNodeID *idwrap.IDWrap for j := range wb.FlowNodes { - if wb.FlowNodes[j].NodeKind == mflow.NODE_KIND_MANUAL_START && + if (wb.FlowNodes[j].NodeKind == mflow.NODE_KIND_MANUAL_START || + wb.FlowNodes[j].NodeKind == mflow.NODE_KIND_SUB_FLOW_TRIGGER) && wb.FlowNodes[j].FlowID.Compare(flowID) == 0 { startNodeID = &wb.FlowNodes[j].ID break diff --git a/packages/server/pkg/ioworkspace/types.go b/packages/server/pkg/ioworkspace/types.go index 8a8940716..bcafdc798 100644 --- a/packages/server/pkg/ioworkspace/types.go +++ b/packages/server/pkg/ioworkspace/types.go @@ -58,7 +58,10 @@ type WorkspaceBundle struct { FlowGraphQLNodes []mflow.NodeGraphQL FlowWsConnectionNodes []mflow.NodeWsConnection FlowWsSendNodes []mflow.NodeWsSend - FlowWaitNodes []mflow.NodeWait + FlowWaitNodes []mflow.NodeWait + FlowSubFlowTriggerNodes []mflow.NodeSubFlowTrigger + FlowSubFlowReturnNodes []mflow.NodeSubFlowReturn + FlowRunSubFlowNodes []mflow.NodeRunSubFlow // Environments and variables Environments []menv.Env @@ -100,7 +103,10 @@ func (wb *WorkspaceBundle) CountEntities() map[string]int { "flow_graphql_nodes": len(wb.FlowGraphQLNodes), "flow_ws_connection_nodes": len(wb.FlowWsConnectionNodes), "flow_ws_send_nodes": len(wb.FlowWsSendNodes), - "flow_wait_nodes": len(wb.FlowWaitNodes), + "flow_wait_nodes": len(wb.FlowWaitNodes), + "flow_sub_flow_trigger_nodes": len(wb.FlowSubFlowTriggerNodes), + "flow_sub_flow_return_nodes": len(wb.FlowSubFlowReturnNodes), + "flow_run_sub_flow_nodes": len(wb.FlowRunSubFlowNodes), "environments": len(wb.Environments), "environment_vars": len(wb.EnvironmentVars), "credentials": len(wb.Credentials), diff --git a/packages/server/pkg/model/mflow/node.go b/packages/server/pkg/model/mflow/node.go index 35ed7dd76..e9d0e915b 100644 --- a/packages/server/pkg/model/mflow/node.go +++ b/packages/server/pkg/model/mflow/node.go @@ -22,7 +22,10 @@ const ( NODE_KIND_WS_CONNECTION NodeKind = 11 NODE_KIND_WS_SEND NodeKind = 12 NODE_KIND_WAIT NodeKind = 13 - // NODE_KIND_WEBHOOK NodeKind = 14 // reserved for future trigger entry + NODE_KIND_WEBHOOK_TRIGGER NodeKind = 14 + NODE_KIND_SUB_FLOW_TRIGGER NodeKind = 15 + NODE_KIND_SUB_FLOW_RETURN NodeKind = 16 + NODE_KIND_RUN_SUB_FLOW NodeKind = 17 ) type NodeState = int8 diff --git a/packages/server/pkg/model/mflow/node_sub_flow.go b/packages/server/pkg/model/mflow/node_sub_flow.go new file mode 100644 index 000000000..aea1616c7 --- /dev/null +++ b/packages/server/pkg/model/mflow/node_sub_flow.go @@ -0,0 +1,44 @@ +//nolint:revive // exported +package mflow + +import "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + +// SubFlowParam defines a single input parameter for a sub-flow trigger. +type SubFlowParam struct { + Name string `json:"name"` + Type string `json:"type"` // string | number | boolean | json + DefaultValue string `json:"default_value"` // JSON-encoded default + Required bool `json:"required"` +} + +// NodeSubFlowTrigger is the entry node for a sub-flow that receives parameters. +type NodeSubFlowTrigger struct { + FlowNodeID idwrap.IDWrap + Params []SubFlowParam // Stored as JSON blob in DB +} + +// SubFlowOutput defines a single output mapping from a sub-flow. +type SubFlowOutput struct { + Name string `json:"name"` + Expression string `json:"expression"` // Expression evaluated against VarMap +} + +// NodeSubFlowReturn is the terminal node that captures and returns output data. +type NodeSubFlowReturn struct { + FlowNodeID idwrap.IDWrap + Outputs []SubFlowOutput // Stored as JSON blob in DB +} + +// SubFlowInputMapping maps a parent expression to a sub-flow parameter. +type SubFlowInputMapping struct { + ParamName string `json:"param_name"` + Expression string `json:"expression"` // Expression evaluated from parent VarMap +} + +// NodeRunSubFlow orchestrates calling another flow from the parent flow. +type NodeRunSubFlow struct { + FlowNodeID idwrap.IDWrap + TargetFlowID *idwrap.IDWrap + TargetFlowName string + Inputs []SubFlowInputMapping // Stored as JSON blob in DB +} diff --git a/packages/server/pkg/mutation/delete_file.go b/packages/server/pkg/mutation/delete_file.go index 2ae8b8ca5..87dd86881 100644 --- a/packages/server/pkg/mutation/delete_file.go +++ b/packages/server/pkg/mutation/delete_file.go @@ -51,8 +51,8 @@ func (c *Context) DeleteFile(ctx context.Context, file FileDeleteItem) error { if err := c.q.DeleteCredential(ctx, *file.ContentID); err != nil { return err } - case mfile.ContentTypeGraphQL: - // GraphQL - cascade to headers + case mfile.ContentTypeGraphQL, mfile.ContentTypeGraphQLDelta: + // GraphQL / GraphQL Delta - cascade to headers if err := c.DeleteGraphQL(ctx, GraphQLDeleteItem{ ID: *file.ContentID, WorkspaceID: file.WorkspaceID, diff --git a/packages/server/pkg/mutation/event.go b/packages/server/pkg/mutation/event.go index 6e69e7377..4132069e1 100644 --- a/packages/server/pkg/mutation/event.go +++ b/packages/server/pkg/mutation/event.go @@ -42,6 +42,9 @@ const ( EntityFlowNodeWsConnection EntityFlowNodeWsSend EntityFlowNodeWait + EntityFlowNodeSubFlowTrigger + EntityFlowNodeSubFlowReturn + EntityFlowNodeRunSubFlow EntityFlowEdge EntityFlowVariable EntityFlowTag diff --git a/packages/server/pkg/service/sflow/node_run_sub_flow.go b/packages/server/pkg/service/sflow/node_run_sub_flow.go new file mode 100644 index 000000000..2d4bf040c --- /dev/null +++ b/packages/server/pkg/service/sflow/node_run_sub_flow.go @@ -0,0 +1,51 @@ +//nolint:revive // exported +package sflow + +import ( + "context" + "database/sql" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +var ErrNoNodeRunSubFlowFound = sql.ErrNoRows + +type NodeRunSubFlowService struct { + reader *NodeRunSubFlowReader + queries *gen.Queries +} + +func NewNodeRunSubFlowService(queries *gen.Queries) NodeRunSubFlowService { + return NodeRunSubFlowService{ + reader: NewNodeRunSubFlowReaderFromQueries(queries), + queries: queries, + } +} + +func (s NodeRunSubFlowService) TX(tx *sql.Tx) NodeRunSubFlowService { + newQueries := s.queries.WithTx(tx) + return NodeRunSubFlowService{ + reader: NewNodeRunSubFlowReaderFromQueries(newQueries), + queries: newQueries, + } +} + +func (s NodeRunSubFlowService) GetNodeRunSubFlow(ctx context.Context, id idwrap.IDWrap) (*mflow.NodeRunSubFlow, error) { + return s.reader.GetNodeRunSubFlow(ctx, id) +} + +func (s NodeRunSubFlowService) CreateNodeRunSubFlow(ctx context.Context, m mflow.NodeRunSubFlow) error { + return NewNodeRunSubFlowWriterFromQueries(s.queries).CreateNodeRunSubFlow(ctx, m) +} + +func (s NodeRunSubFlowService) UpdateNodeRunSubFlow(ctx context.Context, m mflow.NodeRunSubFlow) error { + return NewNodeRunSubFlowWriterFromQueries(s.queries).UpdateNodeRunSubFlow(ctx, m) +} + +func (s NodeRunSubFlowService) DeleteNodeRunSubFlow(ctx context.Context, id idwrap.IDWrap) error { + return NewNodeRunSubFlowWriterFromQueries(s.queries).DeleteNodeRunSubFlow(ctx, id) +} + +func (s NodeRunSubFlowService) Reader() *NodeRunSubFlowReader { return s.reader } diff --git a/packages/server/pkg/service/sflow/node_run_sub_flow_mapper.go b/packages/server/pkg/service/sflow/node_run_sub_flow_mapper.go new file mode 100644 index 000000000..9c9eb2ef3 --- /dev/null +++ b/packages/server/pkg/service/sflow/node_run_sub_flow_mapper.go @@ -0,0 +1,36 @@ +package sflow + +import ( + "encoding/json" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +func ConvertDBToNodeRunSubFlow(row gen.FlowNodeRunSubFlow) *mflow.NodeRunSubFlow { + var inputs []mflow.SubFlowInputMapping + if len(row.Inputs) > 0 { + _ = json.Unmarshal(row.Inputs, &inputs) + } + + return &mflow.NodeRunSubFlow{ + FlowNodeID: row.FlowNodeID, + TargetFlowID: row.TargetFlowID, + TargetFlowName: row.TargetFlowName, + Inputs: inputs, + } +} + +func ConvertNodeRunSubFlowToDB(m mflow.NodeRunSubFlow) gen.FlowNodeRunSubFlow { + inputs, _ := json.Marshal(m.Inputs) + if inputs == nil { + inputs = []byte("[]") + } + + return gen.FlowNodeRunSubFlow{ + FlowNodeID: m.FlowNodeID, + TargetFlowID: m.TargetFlowID, + TargetFlowName: m.TargetFlowName, + Inputs: inputs, + } +} diff --git a/packages/server/pkg/service/sflow/node_run_sub_flow_reader.go b/packages/server/pkg/service/sflow/node_run_sub_flow_reader.go new file mode 100644 index 000000000..07897a524 --- /dev/null +++ b/packages/server/pkg/service/sflow/node_run_sub_flow_reader.go @@ -0,0 +1,34 @@ +package sflow + +import ( + "context" + "database/sql" + "errors" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +type NodeRunSubFlowReader struct { + queries *gen.Queries +} + +func NewNodeRunSubFlowReader(db *sql.DB) *NodeRunSubFlowReader { + return &NodeRunSubFlowReader{queries: gen.New(db)} +} + +func NewNodeRunSubFlowReaderFromQueries(queries *gen.Queries) *NodeRunSubFlowReader { + return &NodeRunSubFlowReader{queries: queries} +} + +func (r *NodeRunSubFlowReader) GetNodeRunSubFlow(ctx context.Context, id idwrap.IDWrap) (*mflow.NodeRunSubFlow, error) { + row, err := r.queries.GetFlowNodeRunSubFlow(ctx, id) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, nil + } + return nil, err + } + return ConvertDBToNodeRunSubFlow(row), nil +} diff --git a/packages/server/pkg/service/sflow/node_run_sub_flow_writer.go b/packages/server/pkg/service/sflow/node_run_sub_flow_writer.go new file mode 100644 index 000000000..f14f8622f --- /dev/null +++ b/packages/server/pkg/service/sflow/node_run_sub_flow_writer.go @@ -0,0 +1,40 @@ +package sflow + +import ( + "context" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +type NodeRunSubFlowWriter struct { + queries *gen.Queries +} + +func NewNodeRunSubFlowWriter(tx gen.DBTX) *NodeRunSubFlowWriter { + return &NodeRunSubFlowWriter{queries: gen.New(tx)} +} + +func NewNodeRunSubFlowWriterFromQueries(queries *gen.Queries) *NodeRunSubFlowWriter { + return &NodeRunSubFlowWriter{queries: queries} +} + +func (w *NodeRunSubFlowWriter) CreateNodeRunSubFlow(ctx context.Context, m mflow.NodeRunSubFlow) error { + row := ConvertNodeRunSubFlowToDB(m) + return w.queries.CreateFlowNodeRunSubFlow(ctx, gen.CreateFlowNodeRunSubFlowParams(row)) +} + +func (w *NodeRunSubFlowWriter) UpdateNodeRunSubFlow(ctx context.Context, m mflow.NodeRunSubFlow) error { + row := ConvertNodeRunSubFlowToDB(m) + return w.queries.UpdateFlowNodeRunSubFlow(ctx, gen.UpdateFlowNodeRunSubFlowParams{ + TargetFlowID: row.TargetFlowID, + TargetFlowName: row.TargetFlowName, + Inputs: row.Inputs, + FlowNodeID: row.FlowNodeID, + }) +} + +func (w *NodeRunSubFlowWriter) DeleteNodeRunSubFlow(ctx context.Context, id idwrap.IDWrap) error { + return w.queries.DeleteFlowNodeRunSubFlow(ctx, id) +} diff --git a/packages/server/pkg/service/sflow/node_sub_flow_return.go b/packages/server/pkg/service/sflow/node_sub_flow_return.go new file mode 100644 index 000000000..77071cea3 --- /dev/null +++ b/packages/server/pkg/service/sflow/node_sub_flow_return.go @@ -0,0 +1,51 @@ +//nolint:revive // exported +package sflow + +import ( + "context" + "database/sql" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +var ErrNoNodeSubFlowReturnFound = sql.ErrNoRows + +type NodeSubFlowReturnService struct { + reader *NodeSubFlowReturnReader + queries *gen.Queries +} + +func NewNodeSubFlowReturnService(queries *gen.Queries) NodeSubFlowReturnService { + return NodeSubFlowReturnService{ + reader: NewNodeSubFlowReturnReaderFromQueries(queries), + queries: queries, + } +} + +func (s NodeSubFlowReturnService) TX(tx *sql.Tx) NodeSubFlowReturnService { + newQueries := s.queries.WithTx(tx) + return NodeSubFlowReturnService{ + reader: NewNodeSubFlowReturnReaderFromQueries(newQueries), + queries: newQueries, + } +} + +func (s NodeSubFlowReturnService) GetNodeSubFlowReturn(ctx context.Context, id idwrap.IDWrap) (*mflow.NodeSubFlowReturn, error) { + return s.reader.GetNodeSubFlowReturn(ctx, id) +} + +func (s NodeSubFlowReturnService) CreateNodeSubFlowReturn(ctx context.Context, m mflow.NodeSubFlowReturn) error { + return NewNodeSubFlowReturnWriterFromQueries(s.queries).CreateNodeSubFlowReturn(ctx, m) +} + +func (s NodeSubFlowReturnService) UpdateNodeSubFlowReturn(ctx context.Context, m mflow.NodeSubFlowReturn) error { + return NewNodeSubFlowReturnWriterFromQueries(s.queries).UpdateNodeSubFlowReturn(ctx, m) +} + +func (s NodeSubFlowReturnService) DeleteNodeSubFlowReturn(ctx context.Context, id idwrap.IDWrap) error { + return NewNodeSubFlowReturnWriterFromQueries(s.queries).DeleteNodeSubFlowReturn(ctx, id) +} + +func (s NodeSubFlowReturnService) Reader() *NodeSubFlowReturnReader { return s.reader } diff --git a/packages/server/pkg/service/sflow/node_sub_flow_return_mapper.go b/packages/server/pkg/service/sflow/node_sub_flow_return_mapper.go new file mode 100644 index 000000000..ea41b5ab7 --- /dev/null +++ b/packages/server/pkg/service/sflow/node_sub_flow_return_mapper.go @@ -0,0 +1,30 @@ +package sflow + +import ( + "encoding/json" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +func ConvertDBToNodeSubFlowReturn(row gen.FlowNodeSubFlowReturn) *mflow.NodeSubFlowReturn { + var outputs []mflow.SubFlowOutput + if len(row.Outputs) > 0 { + _ = json.Unmarshal(row.Outputs, &outputs) + } + return &mflow.NodeSubFlowReturn{ + FlowNodeID: row.FlowNodeID, + Outputs: outputs, + } +} + +func ConvertNodeSubFlowReturnToDB(m mflow.NodeSubFlowReturn) gen.FlowNodeSubFlowReturn { + outputs, _ := json.Marshal(m.Outputs) + if outputs == nil { + outputs = []byte("[]") + } + return gen.FlowNodeSubFlowReturn{ + FlowNodeID: m.FlowNodeID, + Outputs: outputs, + } +} diff --git a/packages/server/pkg/service/sflow/node_sub_flow_return_reader.go b/packages/server/pkg/service/sflow/node_sub_flow_return_reader.go new file mode 100644 index 000000000..c3bcc3c74 --- /dev/null +++ b/packages/server/pkg/service/sflow/node_sub_flow_return_reader.go @@ -0,0 +1,34 @@ +package sflow + +import ( + "context" + "database/sql" + "errors" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +type NodeSubFlowReturnReader struct { + queries *gen.Queries +} + +func NewNodeSubFlowReturnReader(db *sql.DB) *NodeSubFlowReturnReader { + return &NodeSubFlowReturnReader{queries: gen.New(db)} +} + +func NewNodeSubFlowReturnReaderFromQueries(queries *gen.Queries) *NodeSubFlowReturnReader { + return &NodeSubFlowReturnReader{queries: queries} +} + +func (r *NodeSubFlowReturnReader) GetNodeSubFlowReturn(ctx context.Context, id idwrap.IDWrap) (*mflow.NodeSubFlowReturn, error) { + row, err := r.queries.GetFlowNodeSubFlowReturn(ctx, id) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, nil + } + return nil, err + } + return ConvertDBToNodeSubFlowReturn(row), nil +} diff --git a/packages/server/pkg/service/sflow/node_sub_flow_return_writer.go b/packages/server/pkg/service/sflow/node_sub_flow_return_writer.go new file mode 100644 index 000000000..37cf506b7 --- /dev/null +++ b/packages/server/pkg/service/sflow/node_sub_flow_return_writer.go @@ -0,0 +1,38 @@ +package sflow + +import ( + "context" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +type NodeSubFlowReturnWriter struct { + queries *gen.Queries +} + +func NewNodeSubFlowReturnWriter(tx gen.DBTX) *NodeSubFlowReturnWriter { + return &NodeSubFlowReturnWriter{queries: gen.New(tx)} +} + +func NewNodeSubFlowReturnWriterFromQueries(queries *gen.Queries) *NodeSubFlowReturnWriter { + return &NodeSubFlowReturnWriter{queries: queries} +} + +func (w *NodeSubFlowReturnWriter) CreateNodeSubFlowReturn(ctx context.Context, m mflow.NodeSubFlowReturn) error { + row := ConvertNodeSubFlowReturnToDB(m) + return w.queries.CreateFlowNodeSubFlowReturn(ctx, gen.CreateFlowNodeSubFlowReturnParams(row)) +} + +func (w *NodeSubFlowReturnWriter) UpdateNodeSubFlowReturn(ctx context.Context, m mflow.NodeSubFlowReturn) error { + row := ConvertNodeSubFlowReturnToDB(m) + return w.queries.UpdateFlowNodeSubFlowReturn(ctx, gen.UpdateFlowNodeSubFlowReturnParams{ + Outputs: row.Outputs, + FlowNodeID: row.FlowNodeID, + }) +} + +func (w *NodeSubFlowReturnWriter) DeleteNodeSubFlowReturn(ctx context.Context, id idwrap.IDWrap) error { + return w.queries.DeleteFlowNodeSubFlowReturn(ctx, id) +} diff --git a/packages/server/pkg/service/sflow/node_sub_flow_trigger.go b/packages/server/pkg/service/sflow/node_sub_flow_trigger.go new file mode 100644 index 000000000..c1f715a60 --- /dev/null +++ b/packages/server/pkg/service/sflow/node_sub_flow_trigger.go @@ -0,0 +1,51 @@ +//nolint:revive // exported +package sflow + +import ( + "context" + "database/sql" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +var ErrNoNodeSubFlowTriggerFound = sql.ErrNoRows + +type NodeSubFlowTriggerService struct { + reader *NodeSubFlowTriggerReader + queries *gen.Queries +} + +func NewNodeSubFlowTriggerService(queries *gen.Queries) NodeSubFlowTriggerService { + return NodeSubFlowTriggerService{ + reader: NewNodeSubFlowTriggerReaderFromQueries(queries), + queries: queries, + } +} + +func (s NodeSubFlowTriggerService) TX(tx *sql.Tx) NodeSubFlowTriggerService { + newQueries := s.queries.WithTx(tx) + return NodeSubFlowTriggerService{ + reader: NewNodeSubFlowTriggerReaderFromQueries(newQueries), + queries: newQueries, + } +} + +func (s NodeSubFlowTriggerService) GetNodeSubFlowTrigger(ctx context.Context, id idwrap.IDWrap) (*mflow.NodeSubFlowTrigger, error) { + return s.reader.GetNodeSubFlowTrigger(ctx, id) +} + +func (s NodeSubFlowTriggerService) CreateNodeSubFlowTrigger(ctx context.Context, m mflow.NodeSubFlowTrigger) error { + return NewNodeSubFlowTriggerWriterFromQueries(s.queries).CreateNodeSubFlowTrigger(ctx, m) +} + +func (s NodeSubFlowTriggerService) UpdateNodeSubFlowTrigger(ctx context.Context, m mflow.NodeSubFlowTrigger) error { + return NewNodeSubFlowTriggerWriterFromQueries(s.queries).UpdateNodeSubFlowTrigger(ctx, m) +} + +func (s NodeSubFlowTriggerService) DeleteNodeSubFlowTrigger(ctx context.Context, id idwrap.IDWrap) error { + return NewNodeSubFlowTriggerWriterFromQueries(s.queries).DeleteNodeSubFlowTrigger(ctx, id) +} + +func (s NodeSubFlowTriggerService) Reader() *NodeSubFlowTriggerReader { return s.reader } diff --git a/packages/server/pkg/service/sflow/node_sub_flow_trigger_mapper.go b/packages/server/pkg/service/sflow/node_sub_flow_trigger_mapper.go new file mode 100644 index 000000000..9f9f189d1 --- /dev/null +++ b/packages/server/pkg/service/sflow/node_sub_flow_trigger_mapper.go @@ -0,0 +1,30 @@ +package sflow + +import ( + "encoding/json" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +func ConvertDBToNodeSubFlowTrigger(row gen.FlowNodeSubFlowTrigger) *mflow.NodeSubFlowTrigger { + var params []mflow.SubFlowParam + if len(row.Params) > 0 { + _ = json.Unmarshal(row.Params, ¶ms) + } + return &mflow.NodeSubFlowTrigger{ + FlowNodeID: row.FlowNodeID, + Params: params, + } +} + +func ConvertNodeSubFlowTriggerToDB(m mflow.NodeSubFlowTrigger) gen.FlowNodeSubFlowTrigger { + params, _ := json.Marshal(m.Params) + if params == nil { + params = []byte("[]") + } + return gen.FlowNodeSubFlowTrigger{ + FlowNodeID: m.FlowNodeID, + Params: params, + } +} diff --git a/packages/server/pkg/service/sflow/node_sub_flow_trigger_reader.go b/packages/server/pkg/service/sflow/node_sub_flow_trigger_reader.go new file mode 100644 index 000000000..e97032850 --- /dev/null +++ b/packages/server/pkg/service/sflow/node_sub_flow_trigger_reader.go @@ -0,0 +1,34 @@ +package sflow + +import ( + "context" + "database/sql" + "errors" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +type NodeSubFlowTriggerReader struct { + queries *gen.Queries +} + +func NewNodeSubFlowTriggerReader(db *sql.DB) *NodeSubFlowTriggerReader { + return &NodeSubFlowTriggerReader{queries: gen.New(db)} +} + +func NewNodeSubFlowTriggerReaderFromQueries(queries *gen.Queries) *NodeSubFlowTriggerReader { + return &NodeSubFlowTriggerReader{queries: queries} +} + +func (r *NodeSubFlowTriggerReader) GetNodeSubFlowTrigger(ctx context.Context, id idwrap.IDWrap) (*mflow.NodeSubFlowTrigger, error) { + row, err := r.queries.GetFlowNodeSubFlowTrigger(ctx, id) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, nil + } + return nil, err + } + return ConvertDBToNodeSubFlowTrigger(row), nil +} diff --git a/packages/server/pkg/service/sflow/node_sub_flow_trigger_writer.go b/packages/server/pkg/service/sflow/node_sub_flow_trigger_writer.go new file mode 100644 index 000000000..bc50245fc --- /dev/null +++ b/packages/server/pkg/service/sflow/node_sub_flow_trigger_writer.go @@ -0,0 +1,38 @@ +package sflow + +import ( + "context" + + "github.com/the-dev-tools/dev-tools/packages/db/pkg/sqlc/gen" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/idwrap" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/model/mflow" +) + +type NodeSubFlowTriggerWriter struct { + queries *gen.Queries +} + +func NewNodeSubFlowTriggerWriter(tx gen.DBTX) *NodeSubFlowTriggerWriter { + return &NodeSubFlowTriggerWriter{queries: gen.New(tx)} +} + +func NewNodeSubFlowTriggerWriterFromQueries(queries *gen.Queries) *NodeSubFlowTriggerWriter { + return &NodeSubFlowTriggerWriter{queries: queries} +} + +func (w *NodeSubFlowTriggerWriter) CreateNodeSubFlowTrigger(ctx context.Context, m mflow.NodeSubFlowTrigger) error { + row := ConvertNodeSubFlowTriggerToDB(m) + return w.queries.CreateFlowNodeSubFlowTrigger(ctx, gen.CreateFlowNodeSubFlowTriggerParams(row)) +} + +func (w *NodeSubFlowTriggerWriter) UpdateNodeSubFlowTrigger(ctx context.Context, m mflow.NodeSubFlowTrigger) error { + row := ConvertNodeSubFlowTriggerToDB(m) + return w.queries.UpdateFlowNodeSubFlowTrigger(ctx, gen.UpdateFlowNodeSubFlowTriggerParams{ + Params: row.Params, + FlowNodeID: row.FlowNodeID, + }) +} + +func (w *NodeSubFlowTriggerWriter) DeleteNodeSubFlowTrigger(ctx context.Context, id idwrap.IDWrap) error { + return w.queries.DeleteFlowNodeSubFlowTrigger(ctx, id) +} diff --git a/packages/server/pkg/translate/yamlflowsimplev2/converter.go b/packages/server/pkg/translate/yamlflowsimplev2/converter.go index 60cad4751..59464190c 100644 --- a/packages/server/pkg/translate/yamlflowsimplev2/converter.go +++ b/packages/server/pkg/translate/yamlflowsimplev2/converter.go @@ -74,6 +74,22 @@ func ConvertSimplifiedYAML(data []byte, opts ConvertOptionsV2) (*ioworkspace.Wor mergeFlowData(result, flowData, opts) } + // Resolve RunSubFlow TargetFlowName → TargetFlowID references + if len(result.FlowRunSubFlowNodes) > 0 { + flowNameToID := make(map[string]idwrap.IDWrap, len(result.Flows)) + for _, f := range result.Flows { + flowNameToID[f.Name] = f.ID + } + for i := range result.FlowRunSubFlowNodes { + node := &result.FlowRunSubFlowNodes[i] + if node.TargetFlowID == nil && node.TargetFlowName != "" { + if id, ok := flowNameToID[node.TargetFlowName]; ok { + node.TargetFlowID = &id + } + } + } + } + // Process Environments // Map to track env ID by name for workspace linking envNameMap := make(map[string]idwrap.IDWrap) diff --git a/packages/server/pkg/translate/yamlflowsimplev2/converter_flow.go b/packages/server/pkg/translate/yamlflowsimplev2/converter_flow.go index 8781465eb..b1148c7ee 100644 --- a/packages/server/pkg/translate/yamlflowsimplev2/converter_flow.go +++ b/packages/server/pkg/translate/yamlflowsimplev2/converter_flow.go @@ -278,6 +278,9 @@ func mergeFlowData(result *ioworkspace.WorkspaceBundle, flowData *ioworkspace.Wo result.FlowWsConnectionNodes = append(result.FlowWsConnectionNodes, flowData.FlowWsConnectionNodes...) result.FlowWsSendNodes = append(result.FlowWsSendNodes, flowData.FlowWsSendNodes...) result.FlowWaitNodes = append(result.FlowWaitNodes, flowData.FlowWaitNodes...) + result.FlowSubFlowTriggerNodes = append(result.FlowSubFlowTriggerNodes, flowData.FlowSubFlowTriggerNodes...) + result.FlowSubFlowReturnNodes = append(result.FlowSubFlowReturnNodes, flowData.FlowSubFlowReturnNodes...) + result.FlowRunSubFlowNodes = append(result.FlowRunSubFlowNodes, flowData.FlowRunSubFlowNodes...) result.WebSockets = append(result.WebSockets, flowData.WebSockets...) result.WebSocketHeaders = append(result.WebSocketHeaders, flowData.WebSocketHeaders...) } diff --git a/packages/server/pkg/translate/yamlflowsimplev2/converter_node.go b/packages/server/pkg/translate/yamlflowsimplev2/converter_node.go index 0c5195427..f47cf795e 100644 --- a/packages/server/pkg/translate/yamlflowsimplev2/converter_node.go +++ b/packages/server/pkg/translate/yamlflowsimplev2/converter_node.go @@ -3,6 +3,7 @@ package yamlflowsimplev2 import ( "fmt" + "sort" "strconv" "strings" "time" @@ -46,6 +47,12 @@ func getStepCommon(sw YamlStepWrapper) *YamlStepCommon { return &sw.Wait.YamlStepCommon case sw.ManualStart != nil: return sw.ManualStart + case sw.SubFlowTrigger != nil: + return &sw.SubFlowTrigger.YamlStepCommon + case sw.SubFlowReturn != nil: + return &sw.SubFlowReturn.YamlStepCommon + case sw.RunSubFlow != nil: + return &sw.RunSubFlow.YamlStepCommon default: return nil } @@ -115,6 +122,15 @@ func processSteps(flowEntry YamlFlowFlowV2, templates map[string]YamlRequestDefV case stepWrapper.ManualStart != nil: nodeName = stepWrapper.ManualStart.Name dependsOn = stepWrapper.ManualStart.DependsOn + case stepWrapper.SubFlowTrigger != nil: + nodeName = stepWrapper.SubFlowTrigger.Name + dependsOn = stepWrapper.SubFlowTrigger.DependsOn + case stepWrapper.SubFlowReturn != nil: + nodeName = stepWrapper.SubFlowReturn.Name + dependsOn = stepWrapper.SubFlowReturn.DependsOn + case stepWrapper.RunSubFlow != nil: + nodeName = stepWrapper.RunSubFlow.Name + dependsOn = stepWrapper.RunSubFlow.DependsOn default: return nil, NewYamlFlowErrorV2("empty step definition", "step", i) } @@ -209,6 +225,23 @@ func processSteps(flowEntry YamlFlowFlowV2, templates map[string]YamlRequestDefV if err := processWaitStructStep(stepWrapper.Wait, nodeID, flowID, result); err != nil { return nil, err } + case stepWrapper.SubFlowTrigger != nil: + if err := processSubFlowTriggerStructStep(stepWrapper.SubFlowTrigger, nodeID, flowID, result); err != nil { + return nil, err + } + // SubFlowTrigger is an entry node — use startNodeID like ManualStart + info.id = startNodeID + lastIdx := len(result.FlowNodes) - 1 + result.FlowNodes[lastIdx].ID = startNodeID + startNodeFound = true + case stepWrapper.SubFlowReturn != nil: + if err := processSubFlowReturnStructStep(stepWrapper.SubFlowReturn, nodeID, flowID, result); err != nil { + return nil, err + } + case stepWrapper.RunSubFlow != nil: + if err := processRunSubFlowStructStep(stepWrapper.RunSubFlow, nodeID, flowID, result); err != nil { + return nil, err + } case stepWrapper.ManualStart != nil: info.id = startNodeID createStartNodeWithID(startNodeID, flowID, result) @@ -724,3 +757,90 @@ func processWaitStructStep(step *YamlStepWait, nodeID, flowID idwrap.IDWrap, res result.FlowWaitNodes = append(result.FlowWaitNodes, waitNode) return nil } + +func processSubFlowTriggerStructStep(step *YamlStepSubFlowTrigger, nodeID, flowID idwrap.IDWrap, result *ioworkspace.WorkspaceBundle) error { + flowNode := mflow.Node{ + ID: nodeID, + FlowID: flowID, + Name: step.Name, + NodeKind: mflow.NODE_KIND_SUB_FLOW_TRIGGER, + } + result.FlowNodes = append(result.FlowNodes, flowNode) + + var params []mflow.SubFlowParam + for _, p := range step.Params { + params = append(params, mflow.SubFlowParam{ + Name: p.Name, + Type: p.Type, + DefaultValue: p.DefaultValue, + Required: p.Required, + }) + } + + triggerNode := mflow.NodeSubFlowTrigger{ + FlowNodeID: nodeID, + Params: params, + } + result.FlowSubFlowTriggerNodes = append(result.FlowSubFlowTriggerNodes, triggerNode) + return nil +} + +func processSubFlowReturnStructStep(step *YamlStepSubFlowReturn, nodeID, flowID idwrap.IDWrap, result *ioworkspace.WorkspaceBundle) error { + flowNode := mflow.Node{ + ID: nodeID, + FlowID: flowID, + Name: step.Name, + NodeKind: mflow.NODE_KIND_SUB_FLOW_RETURN, + } + result.FlowNodes = append(result.FlowNodes, flowNode) + + var outputs []mflow.SubFlowOutput + for _, o := range step.Outputs { + outputs = append(outputs, mflow.SubFlowOutput{ + Name: o.Name, + Expression: o.Expression, + }) + } + + returnNode := mflow.NodeSubFlowReturn{ + FlowNodeID: nodeID, + Outputs: outputs, + } + result.FlowSubFlowReturnNodes = append(result.FlowSubFlowReturnNodes, returnNode) + return nil +} + +func processRunSubFlowStructStep(step *YamlStepRunSubFlow, nodeID, flowID idwrap.IDWrap, result *ioworkspace.WorkspaceBundle) error { + if step.Flow == "" { + return NewYamlFlowErrorV2(fmt.Sprintf("run_sub_flow step '%s' missing required flow name", step.Name), "flow", nil) + } + + flowNode := mflow.Node{ + ID: nodeID, + FlowID: flowID, + Name: step.Name, + NodeKind: mflow.NODE_KIND_RUN_SUB_FLOW, + } + result.FlowNodes = append(result.FlowNodes, flowNode) + + var inputs []mflow.SubFlowInputMapping + paramNames := make([]string, 0, len(step.Inputs)) + for paramName := range step.Inputs { + paramNames = append(paramNames, paramName) + } + sort.Strings(paramNames) + for _, paramName := range paramNames { + inputs = append(inputs, mflow.SubFlowInputMapping{ + ParamName: paramName, + Expression: step.Inputs[paramName], + }) + } + + runNode := mflow.NodeRunSubFlow{ + FlowNodeID: nodeID, + TargetFlowName: step.Flow, + Inputs: inputs, + } + result.FlowRunSubFlowNodes = append(result.FlowRunSubFlowNodes, runNode) + return nil +} diff --git a/packages/server/pkg/translate/yamlflowsimplev2/exporter.go b/packages/server/pkg/translate/yamlflowsimplev2/exporter.go index 1e2c08609..2af346778 100644 --- a/packages/server/pkg/translate/yamlflowsimplev2/exporter.go +++ b/packages/server/pkg/translate/yamlflowsimplev2/exporter.go @@ -140,6 +140,21 @@ func MarshalSimplifiedYAML(data *ioworkspace.WorkspaceBundle) ([]byte, error) { waitNodeMap[n.FlowNodeID] = n } + subFlowTriggerNodeMap := make(map[idwrap.IDWrap]mflow.NodeSubFlowTrigger) + for _, n := range data.FlowSubFlowTriggerNodes { + subFlowTriggerNodeMap[n.FlowNodeID] = n + } + + subFlowReturnNodeMap := make(map[idwrap.IDWrap]mflow.NodeSubFlowReturn) + for _, n := range data.FlowSubFlowReturnNodes { + subFlowReturnNodeMap[n.FlowNodeID] = n + } + + runSubFlowNodeMap := make(map[idwrap.IDWrap]mflow.NodeRunSubFlow) + for _, n := range data.FlowRunSubFlowNodes { + runSubFlowNodeMap[n.FlowNodeID] = n + } + wsEntityMap := make(map[idwrap.IDWrap]mwebsocket.WebSocket) for _, ws := range data.WebSockets { wsEntityMap[ws.ID] = ws @@ -366,7 +381,7 @@ func MarshalSimplifiedYAML(data *ioworkspace.WorkspaceBundle) ([]byte, error) { for _, n := range data.FlowNodes { if n.FlowID == flow.ID { flowNodes = append(flowNodes, n) - if n.NodeKind == mflow.NODE_KIND_MANUAL_START { + if n.NodeKind == mflow.NODE_KIND_MANUAL_START || n.NodeKind == mflow.NODE_KIND_SUB_FLOW_TRIGGER { startNodeID = n.ID } } @@ -639,12 +654,68 @@ func MarshalSimplifiedYAML(data *ioworkspace.WorkspaceBundle) ([]byte, error) { DurationMs: strconv.FormatInt(waitNode.DurationMs, 10), } + case mflow.NODE_KIND_SUB_FLOW_TRIGGER: + triggerNode, ok := subFlowTriggerNodeMap[node.ID] + if !ok { + continue + } + triggerStep := &YamlStepSubFlowTrigger{ + YamlStepCommon: common, + } + for _, p := range triggerNode.Params { + triggerStep.Params = append(triggerStep.Params, YamlSubFlowParam{ + Name: p.Name, + Type: p.Type, + DefaultValue: p.DefaultValue, + Required: p.Required, + }) + } + stepWrapper.SubFlowTrigger = triggerStep + + case mflow.NODE_KIND_SUB_FLOW_RETURN: + returnNode, ok := subFlowReturnNodeMap[node.ID] + if !ok { + continue + } + returnStep := &YamlStepSubFlowReturn{ + YamlStepCommon: common, + } + for _, o := range returnNode.Outputs { + returnStep.Outputs = append(returnStep.Outputs, YamlSubFlowOutput{ + Name: o.Name, + Expression: o.Expression, + }) + } + stepWrapper.SubFlowReturn = returnStep + + case mflow.NODE_KIND_RUN_SUB_FLOW: + runNode, ok := runSubFlowNodeMap[node.ID] + if !ok { + continue + } + inputs := make(map[string]string, len(runNode.Inputs)) + for _, input := range runNode.Inputs { + inputs[input.ParamName] = input.Expression + } + runStep := &YamlStepRunSubFlow{ + YamlStepCommon: common, + Flow: runNode.TargetFlowName, + } + if len(inputs) > 0 { + runStep.Inputs = inputs + } + stepWrapper.RunSubFlow = runStep + case mflow.NODE_KIND_MANUAL_START: if node.ID == startNodeID { stepWrapper.ManualStart = &common } else { continue } + + case mflow.NODE_KIND_WEBHOOK_TRIGGER: + // Not yet implemented + continue } // Add to flow @@ -653,7 +724,8 @@ func MarshalSimplifiedYAML(data *ioworkspace.WorkspaceBundle) ([]byte, error) { isValid := stepWrapper.Request != nil || stepWrapper.GraphQL != nil || stepWrapper.If != nil || stepWrapper.For != nil || stepWrapper.ForEach != nil || stepWrapper.JS != nil || stepWrapper.AI != nil || stepWrapper.AIProvider != nil || stepWrapper.AIMemory != nil || stepWrapper.WsConnection != nil || - stepWrapper.WsSend != nil || stepWrapper.Wait != nil || stepWrapper.ManualStart != nil + stepWrapper.WsSend != nil || stepWrapper.Wait != nil || stepWrapper.ManualStart != nil || + stepWrapper.SubFlowTrigger != nil || stepWrapper.SubFlowReturn != nil || stepWrapper.RunSubFlow != nil if isValid { flowYaml.Steps = append(flowYaml.Steps, stepWrapper) } diff --git a/packages/server/pkg/translate/yamlflowsimplev2/types.go b/packages/server/pkg/translate/yamlflowsimplev2/types.go index fb38536eb..89a23bb6c 100644 --- a/packages/server/pkg/translate/yamlflowsimplev2/types.go +++ b/packages/server/pkg/translate/yamlflowsimplev2/types.go @@ -86,8 +86,11 @@ type YamlStepWrapper struct { AIMemory *YamlStepAIMemory `yaml:"ai_memory,omitempty"` WsConnection *YamlStepWsConnection `yaml:"ws_connection,omitempty"` WsSend *YamlStepWsSend `yaml:"ws_send,omitempty"` - Wait *YamlStepWait `yaml:"wait,omitempty"` - ManualStart *YamlStepCommon `yaml:"manual_start,omitempty"` + Wait *YamlStepWait `yaml:"wait,omitempty"` + ManualStart *YamlStepCommon `yaml:"manual_start,omitempty"` + SubFlowTrigger *YamlStepSubFlowTrigger `yaml:"sub_flow_trigger,omitempty"` + SubFlowReturn *YamlStepSubFlowReturn `yaml:"sub_flow_return,omitempty"` + RunSubFlow *YamlStepRunSubFlow `yaml:"run_sub_flow,omitempty"` } // Common fields for all step types @@ -186,6 +189,34 @@ type YamlStepWait struct { DurationMs string `yaml:"duration_ms"` } +type YamlStepSubFlowTrigger struct { + YamlStepCommon `yaml:",inline"` + Params []YamlSubFlowParam `yaml:"params,omitempty"` +} + +type YamlSubFlowParam struct { + Name string `yaml:"name"` + Type string `yaml:"type,omitempty"` + DefaultValue string `yaml:"default_value,omitempty"` + Required bool `yaml:"required,omitempty"` +} + +type YamlStepSubFlowReturn struct { + YamlStepCommon `yaml:",inline"` + Outputs []YamlSubFlowOutput `yaml:"outputs,omitempty"` +} + +type YamlSubFlowOutput struct { + Name string `yaml:"name"` + Expression string `yaml:"expression"` +} + +type YamlStepRunSubFlow struct { + YamlStepCommon `yaml:",inline"` + Flow string `yaml:"flow"` + Inputs map[string]string `yaml:"inputs,omitempty"` +} + // YamlFlowVariableV2 represents a flow variable type YamlFlowVariableV2 struct { Name string `yaml:"name"` @@ -439,8 +470,12 @@ type YamlFlowDataV2 struct { AIProviderNodes []mflow.NodeAiProvider AIMemoryNodes []mflow.NodeMemory GraphQLNodes []mflow.NodeGraphQL - WsConnectionNodes []mflow.NodeWsConnection - WsSendNodes []mflow.NodeWsSend + WsConnectionNodes []mflow.NodeWsConnection + WsSendNodes []mflow.NodeWsSend + WaitNodes []mflow.NodeWait + SubFlowTriggerNodes []mflow.NodeSubFlowTrigger + SubFlowReturnNodes []mflow.NodeSubFlowReturn + RunSubFlowNodes []mflow.NodeRunSubFlow } // YamlVariableV2 represents a variable during parsing diff --git a/packages/server/test/e2e_har_to_cli_test.go b/packages/server/test/e2e_har_to_cli_test.go index 003c1366c..1e3075291 100644 --- a/packages/server/test/e2e_har_to_cli_test.go +++ b/packages/server/test/e2e_har_to_cli_test.go @@ -276,6 +276,9 @@ func TestE2E_HAR_To_CLI_Chain(t *testing.T) { nil, // NodeWsConnectionService nil, // NodeWsSendService nil, // NodeWaitService + nil, // NodeSubFlowTriggerService + nil, // NodeSubFlowReturnService + nil, // NodeRunSubFlowService nil, // WebSocketService nil, // WebSocketHeaderService nil, // GraphQLService diff --git a/packages/spec/api/flow.tsp b/packages/spec/api/flow.tsp index d4e91f4ab..e114531eb 100644 --- a/packages/spec/api/flow.tsp +++ b/packages/spec/api/flow.tsp @@ -100,6 +100,10 @@ enum NodeKind { WsConnection, WsSend, Wait, + WebhookTrigger, + SubFlowTrigger, + SubFlowReturn, + RunSubFlow, } enum AiMemoryType { @@ -316,6 +320,43 @@ model NodeWait { durationMs: int64; } +model SubFlowParam { + name: string; + type: string; + defaultValue: string; + required: boolean; +} + +@TanStackDB.collection +model NodeSubFlowTrigger { + @primaryKey nodeId: Id; + params: SubFlowParam[]; +} + +model SubFlowOutput { + name: string; + expression: string; +} + +@TanStackDB.collection +model NodeSubFlowReturn { + @primaryKey nodeId: Id; + outputs: SubFlowOutput[]; +} + +model SubFlowInputMapping { + paramName: string; + expression: string; +} + +@TanStackDB.collection +model NodeRunSubFlow { + @primaryKey nodeId: Id; + targetFlowId?: Id; + targetFlowName: string; + inputs: SubFlowInputMapping[]; +} + // Copy/Paste operations enum ReferenceMode { CreateCopy, From 20b623942499026c4820688eac5dfd5762a3155f Mon Sep 17 00:00:00 2001 From: moosebay Date: Mon, 9 Mar 2026 02:05:04 +0300 Subject: [PATCH 4/5] fix auto complete --- .../expression/code-mirror/extensions.tsx | 89 ++++--- .../internal/api/rreference/rreference.go | 2 +- .../referencecompletion.go | 139 +++++++++++ .../referencecompletion_test.go | 224 ++++++++++++++++++ 4 files changed, 408 insertions(+), 46 deletions(-) diff --git a/packages/client/src/features/expression/code-mirror/extensions.tsx b/packages/client/src/features/expression/code-mirror/extensions.tsx index 399a1451b..addabb358 100644 --- a/packages/client/src/features/expression/code-mirror/extensions.tsx +++ b/packages/client/src/features/expression/code-mirror/extensions.tsx @@ -114,7 +114,6 @@ interface ReferenceCompletionsProps { reactRender: ReactRender; } -// TODO: fix implementation const referenceCompletions = ({ allowFiles = false, @@ -123,58 +122,59 @@ const referenceCompletions = reactRender, }: ReferenceCompletionsProps): CompletionSource => async (context) => { - // Check for Reference token type first (works in text body) - let token = context.tokenBefore(['Identifier'])?.text.trimStart(); + let token: string | undefined; const isExpression = context.tokenBefore(['String', 'StringExpression']) === null || context.tokenBefore(['Interpolation']) !== null; - if (token === undefined && isExpression) token = ''; + // Extract the full reference path (e.g. "response.body.data[0].name") + // by scanning backwards from the cursor through valid path characters. + const line = context.state.doc.lineAt(context.pos); + const cursorInLine = context.pos - line.from; + const textBefore = line.text.substring(0, cursorInLine); + + if (isExpression) { + // In expression context: scan backwards for the full dotted path + let pathStart = textBefore.length; + for (let i = textBefore.length - 1; i >= 0; i--) { + const ch = textBefore[i]; + if (/[a-zA-Z0-9_.[\]]/.test(ch)) { + pathStart = i; + } else { + break; + } + } + token = textBefore.substring(pathStart); + } - // If no Reference token found, check if we have JSON string content with variables + // If not in expression context, check for {{ }} interpolation in strings if (token === undefined) { - // Look for JSON string tokens that might contain variable references - const line = context.state.doc.lineAt(context.pos); - const lineText = line.text; - - // Find '{{' pattern in the current line before the cursor position - const cursorPosInLine = context.pos - line.from; - const beforeCursor = lineText.substring(0, cursorPosInLine); - const openBraceIndex = beforeCursor.lastIndexOf('{{'); - + const openBraceIndex = textBefore.lastIndexOf('{{'); if (openBraceIndex >= 0) { - // Extract potential variable reference text - token = beforeCursor.substring(openBraceIndex + 2).trim(); + token = textBefore.substring(openBraceIndex + 2).trim(); } } - // Special handling for JSON string context - // Look for tokens of different types that might be inside a JSON string + // Fallback: check for {{ }} inside JSON string tokens if (token === undefined) { - // Get the token at the current position // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any const tree = (context.state as any).syntaxTree; - // Add null check to prevent TypeError if (!tree) return null; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access const tokenAtCursor = tree.resolveInner(context.pos); - // If we're in a string token (JSON or otherwise) // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access if (tokenAtCursor && /string/i.test(tokenAtCursor.type.name)) { // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access const stringContent = context.state.doc.sliceString(tokenAtCursor.from, tokenAtCursor.to); // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access const cursorOffsetInString = context.pos - tokenAtCursor.from; - const textBeforeCursor = stringContent.substring(0, cursorOffsetInString); - - // Check if there's a '{{' before the cursor in this string - const varStartIndex = textBeforeCursor.lastIndexOf('{{'); + const textBeforeCursorInString = stringContent.substring(0, cursorOffsetInString); + const varStartIndex = textBeforeCursorInString.lastIndexOf('{{'); if (varStartIndex >= 0) { - // Extract the variable reference text - token = textBeforeCursor.substring(varStartIndex + 2); + token = textBeforeCursorInString.substring(varStartIndex + 2); } } } @@ -204,8 +204,10 @@ const referenceCompletions = }); } + const items = (await client.referenceCompletion({ ...referenceContext, start: token })).items; + options = pipe( - (await client.referenceCompletion({ ...referenceContext, start: token })).items, + items, Array.map((_): Completion => { const type = pipe( Match.value(_.kind), @@ -223,8 +225,10 @@ const referenceCompletions = Match.orElse(() => undefined!), ); + // endIndex points to the start of the segment name within endToken + // e.g. for endToken="response.body" with endIndex=9, label="body" const label = _.endToken.substring(_.endIndex); - const path = token + label; + const path = _.endToken; const info = () => { if (![ReferenceKind.VALUE, ReferenceKind.VARIABLE].includes(_.kind)) return null; @@ -240,7 +244,6 @@ const referenceCompletions = return { detail, - displayLabel: _.endToken, info, label, type, @@ -249,16 +252,17 @@ const referenceCompletions = Array.appendAll(options), ); + // Calculate how many characters of the current segment the user has already typed. + // All items share the same endIndex since they're at the same level. + const segmentStart = items.length > 0 ? items[0].endIndex : 0; + const partialLength = token.length - segmentStart; + return { - commitCharacters: ['.'], - filter: false, - from: context.pos, - getMatch: (_) => { - if (!_.displayLabel) return []; - const endIndex = _.displayLabel.length - _.label.length; - return [0, endIndex]; - }, + commitCharacters: ['.', '['], + filter: true, + from: context.pos - Math.max(0, partialLength), options, + validFor: /^[a-zA-Z0-9_\]]*$/, }; }; @@ -266,7 +270,7 @@ interface LanguageProps extends ReferenceCompletionsProps { kind?: 'FullExpression' | 'StringExpression' | undefined; } -const language = ({ kind = 'FullExpression', ...props }: LanguageProps) => { +const language = ({ kind = 'FullExpression' }: LanguageProps) => { const lrl = LRLanguage.define({ parser: parser.configure({ top: kind, @@ -292,12 +296,7 @@ const language = ({ kind = 'FullExpression', ...props }: LanguageProps) => { }), }); - return new LanguageSupport(lrl, [ - lrl.data.of({ - // Handle both direct Reference tokens and other contexts - autocomplete: referenceCompletions(props), - }), - ]); + return new LanguageSupport(lrl); }; const expressionBracketSpacing = EditorView.updateListener.of((update) => { diff --git a/packages/server/internal/api/rreference/rreference.go b/packages/server/internal/api/rreference/rreference.go index acdc4147a..914780987 100644 --- a/packages/server/internal/api/rreference/rreference.go +++ b/packages/server/internal/api/rreference/rreference.go @@ -1225,7 +1225,7 @@ func (c *ReferenceServiceRPC) ReferenceCompletion(ctx context.Context, req *conn creator.AddWithKey(k, v) } - items := creator.FindMatchAndCalcCompletionData(req.Msg.Start) + items := creator.FindNextLevelCompletionData(req.Msg.Start) completions, err := convertReferenceCompletionItemsFn(items) if err != nil { diff --git a/packages/server/pkg/referencecompletion/referencecompletion.go b/packages/server/pkg/referencecompletion/referencecompletion.go index ab229196f..afbce2214 100644 --- a/packages/server/pkg/referencecompletion/referencecompletion.go +++ b/packages/server/pkg/referencecompletion/referencecompletion.go @@ -230,6 +230,145 @@ func (c ReferenceCompletionCreator) FindMatchAndCalcCompletionData(query string) return referenceCompletionItems } +// parseQuerySegments splits a query into the resolved prefix (everything up to +// and including the last delimiter) and the partial segment (text being typed +// after the last delimiter). Delimiters are '.' and '['. +func parseQuerySegments(query string) (resolvedPrefix, partial string) { + // Find the last '.' or '[' in the query + lastDot := strings.LastIndex(query, ".") + lastBracket := strings.LastIndex(query, "[") + + lastDelim := lastDot + if lastBracket > lastDelim { + lastDelim = lastBracket + } + + if lastDelim < 0 { + // No delimiter found — entire query is a partial at root level + return "", query + } + + // Include the delimiter in the prefix + return query[:lastDelim+1], query[lastDelim+1:] +} + +// FindNextLevel returns only the immediate next-level children matching the query. +// For "response." it returns ["response.body", "response.status", "response.headers"] +// rather than all descendants. This enables VS Code-style drill-down completion. +func (c ReferenceCompletionCreator) FindNextLevel(query string) []fuzzyfinder.Rank { + resolvedPrefix, partial := parseQuerySegments(query) + lowerPrefix := strings.ToLower(resolvedPrefix) + lowerPartial := strings.ToLower(partial) + + candidates := make(map[string]struct{}) + + for path := range c.PathMap { + lowerPath := strings.ToLower(path) + + // Path must start with the resolved prefix (case-insensitive) + if !strings.HasPrefix(lowerPath, lowerPrefix) { + continue + } + + // Use the actual path's prefix to preserve original casing + actualPrefix := path[:len(resolvedPrefix)] + + // Extract the remainder after the prefix + rest := path[len(actualPrefix):] + if rest == "" { + continue + } + + // Find the next segment boundary (first '.' or '[' after position 0) + boundary := len(rest) + for i := range len(rest) { + if rest[i] == '.' || rest[i] == '[' { + if i == 0 { + continue // skip leading delimiter + } + boundary = i + break + } + // Include closing bracket ']' as part of the segment for array indices + if rest[i] == ']' { + boundary = i + 1 // include the ']' + break + } + } + + nextSegment := rest[:boundary] + lowerSegment := strings.ToLower(nextSegment) + + // Filter by partial match (case-insensitive) + if !strings.HasPrefix(lowerSegment, lowerPartial) { + continue + } + + candidate := actualPrefix + nextSegment + candidates[candidate] = struct{}{} + } + + ranks := make([]fuzzyfinder.Rank, 0, len(candidates)) + for c := range candidates { + ranks = append(ranks, fuzzyfinder.Rank{Target: c}) + } + + sort.Slice(ranks, func(i, j int) bool { + return smartCompare(ranks[i].Target, ranks[j].Target) + }) + + return ranks +} + +// FindNextLevelCompletionData returns completion items for the next level only, +// with proper Kind detection and EndIndex set to the start of the segment name. +func (c ReferenceCompletionCreator) FindNextLevelCompletionData(query string) []ReferenceCompletionItem { + ranks := c.FindNextLevel(query) + resolvedPrefix, _ := parseQuerySegments(query) + + items := make([]ReferenceCompletionItem, len(ranks)) + for i, rank := range ranks { + matchedPath := rank.Target + pathKind := reference.ReferenceKind_REFERENCE_KIND_VALUE + + // Check for children with '.' prefix (map children) + dotPrefix := matchedPath + "." + bracketPrefix := matchedPath + "[" + hasMapChildren := false + hasArrayChildren := false + + for path := range c.PathMap { + if strings.HasPrefix(path, dotPrefix) { + hasMapChildren = true + } + if strings.HasPrefix(path, bracketPrefix) { + hasArrayChildren = true + } + if hasMapChildren && hasArrayChildren { + break + } + } + + if hasArrayChildren { + pathKind = reference.ReferenceKind_REFERENCE_KIND_ARRAY + } else if hasMapChildren { + pathKind = reference.ReferenceKind_REFERENCE_KIND_MAP + } + + details := c.PathMap[matchedPath] + itemCount := int32(details.Count) // nolint:gosec // G115 + + items[i] = ReferenceCompletionItem{ + Kind: pathKind, + EndToken: matchedPath, + EndIndex: int32(len(resolvedPrefix)), // nolint:gosec // G115 + ItemCount: &itemCount, + } + } + + return items +} + type ReferenceCompletionItem struct { Kind reference.ReferenceKind diff --git a/packages/server/pkg/referencecompletion/referencecompletion_test.go b/packages/server/pkg/referencecompletion/referencecompletion_test.go index 89dba189d..6aaf5ee60 100644 --- a/packages/server/pkg/referencecompletion/referencecompletion_test.go +++ b/packages/server/pkg/referencecompletion/referencecompletion_test.go @@ -6,6 +6,7 @@ import ( "sort" "testing" + "github.com/the-dev-tools/dev-tools/packages/server/pkg/reference" "github.com/the-dev-tools/dev-tools/packages/server/pkg/referencecompletion" ) @@ -539,6 +540,229 @@ func TestParsePath(t *testing.T) { }) } } +func TestFindNextLevel(t *testing.T) { + creator := referencecompletion.NewReferenceCompletionCreator() + + data := map[string]any{ + "response": map[string]any{ + "body": map[string]any{ + "data": []any{ + map[string]any{"id": 1, "name": "Alice"}, + map[string]any{"id": 2, "name": "Bob"}, + }, + }, + "status": 200, + "headers": map[string]string{"Content-Type": "application/json"}, + }, + "env": map[string]any{ + "API_KEY": "secret", + }, + } + creator.Add(data) + + tests := []struct { + name string + query string + expected []string + }{ + { + name: "Empty query returns top-level keys only", + query: "", + expected: []string{"env", "response"}, + }, + { + name: "Partial top-level match", + query: "res", + expected: []string{"response"}, + }, + { + name: "Exact top-level match", + query: "response", + expected: []string{"response"}, + }, + { + name: "Dot-drill into object", + query: "response.", + expected: []string{"response.body", "response.headers", "response.status"}, + }, + { + name: "Partial child match", + query: "response.bo", + expected: []string{"response.body"}, + }, + { + name: "Deeper dot-drill", + query: "response.body.", + expected: []string{"response.body.data"}, + }, + { + name: "Exact nested match", + query: "response.body.data", + expected: []string{"response.body.data"}, + }, + { + name: "Array bracket entry", + query: "response.body.data[", + expected: []string{"response.body.data[0]", "response.body.data[1]"}, + }, + { + name: "Partial array index", + query: "response.body.data[0", + expected: []string{"response.body.data[0]"}, + }, + { + name: "Drill into array element", + query: "response.body.data[0].", + expected: []string{"response.body.data[0].id", "response.body.data[0].name"}, + }, + { + name: "Partial key in array element", + query: "response.body.data[0].n", + expected: []string{"response.body.data[0].name"}, + }, + { + name: "Nonexistent prefix with dot", + query: "nonexistent.", + expected: []string{}, + }, + { + name: "Nonexistent partial at valid level", + query: "response.nonexistent", + expected: []string{}, + }, + { + name: "Case insensitive partial", + query: "RES", + expected: []string{"response"}, + }, + { + name: "Case insensitive dot-drill", + query: "Response.", + expected: []string{"response.body", "response.headers", "response.status"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + matches := creator.FindNextLevel(tt.query) + actual := make([]string, len(matches)) + for i, m := range matches { + actual[i] = m.Target + } + sort.Strings(actual) + sort.Strings(tt.expected) + + if !reflect.DeepEqual(tt.expected, actual) { + t.Errorf("FindNextLevel(%q):\n expected: %v\n actual: %v", tt.query, tt.expected, actual) + } + }) + } +} + +func TestFindNextLevelCompletionData(t *testing.T) { + creator := referencecompletion.NewReferenceCompletionCreator() + + data := map[string]any{ + "response": map[string]any{ + "body": map[string]any{ + "data": []any{ + map[string]any{"id": 1, "name": "Alice"}, + map[string]any{"id": 2, "name": "Bob"}, + }, + }, + "status": 200, + "headers": map[string]string{"Content-Type": "application/json"}, + }, + "env": map[string]any{ + "API_KEY": "secret", + }, + } + creator.Add(data) + + tests := []struct { + name string + query string + endToken string + expectedKind reference.ReferenceKind + minItemCount int32 + expectedIndex int32 + }{ + { + name: "Top-level map", + query: "", + endToken: "response", + expectedKind: reference.ReferenceKind_REFERENCE_KIND_MAP, + minItemCount: 3, + expectedIndex: 0, + }, + { + name: "Child map (body has children)", + query: "response.", + endToken: "response.body", + expectedKind: reference.ReferenceKind_REFERENCE_KIND_MAP, + minItemCount: 1, + expectedIndex: 9, + }, + { + name: "Child value (status is leaf)", + query: "response.", + endToken: "response.status", + expectedKind: reference.ReferenceKind_REFERENCE_KIND_VALUE, + minItemCount: 0, + expectedIndex: 9, + }, + { + name: "Array kind", + query: "response.body.", + endToken: "response.body.data", + expectedKind: reference.ReferenceKind_REFERENCE_KIND_ARRAY, + minItemCount: 2, + expectedIndex: 14, + }, + { + name: "Array element is map", + query: "response.body.data[", + endToken: "response.body.data[0]", + expectedKind: reference.ReferenceKind_REFERENCE_KIND_MAP, + minItemCount: 2, + expectedIndex: 19, // len("response.body.data[") = 19 + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + items := creator.FindNextLevelCompletionData(tt.query) + + // Find the specific item + var found *referencecompletion.ReferenceCompletionItem + for i := range items { + if items[i].EndToken == tt.endToken { + found = &items[i] + break + } + } + + if found == nil { + tokens := make([]string, len(items)) + for i, item := range items { + tokens[i] = item.EndToken + } + t.Fatalf("expected item with endToken %q not found in results: %v", tt.endToken, tokens) + } + + if found.Kind != tt.expectedKind { + t.Errorf("Kind: expected %v, got %v", tt.expectedKind, found.Kind) + } + if found.ItemCount != nil && *found.ItemCount < tt.minItemCount { + t.Errorf("ItemCount: expected >= %d, got %d", tt.minItemCount, *found.ItemCount) + } + if found.EndIndex != tt.expectedIndex { + t.Errorf("EndIndex: expected %d, got %d", tt.expectedIndex, found.EndIndex) + } + }) + } +} + func TestReferenceCompletionLookUp_Add_InvalidReflectValue(t *testing.T) { lookup := referencecompletion.NewReferenceCompletionLookup() From 6e09afa255a7e20e1a9eb3c80de3fb1b32a521c2 Mon Sep 17 00:00:00 2001 From: moosebay Date: Fri, 24 Apr 2026 02:51:07 +0300 Subject: [PATCH 5/5] feat(expression): autocomplete for builtins + faker namespace Add inline autocomplete in the {{ }} expression editor for built-in functions (uuid(), uuid("v4"), uuid("v7"), ulid(), now()) with VS Code-style dot-chain completion on now(): .Unix(), .UnixMilli(), .UnixMicro(), .UnixNano(). Introduce a faker namespace backed by go-faker/faker/v4. Typing "faker." opens a 35-entry method list for fake data generation (name, email, phoneNumber, url, ipv4, ipv6, macAddress, username, password, word, sentence, paragraph, date, timestamp, timezone, ccNumber, currency, uuid, randomInt, ...). Also revert better-auth 1.5.4 -> 1.4.21 since 1.5.4 dropped the public runAdapterTest export that packages/auth's adapter tests rely on, and fix an unnecessary bracket-notation assertion flagged by the shared ESLint config. --- .nx/version-plans/desktop-1.0.0.md | 28 ++ .../expression/code-mirror/extensions.tsx | 121 ++++++- packages/server/go.mod | 1 + packages/server/go.sum | 2 + packages/server/pkg/expression/builtins.go | 83 +++++ .../server/pkg/expression/builtins_test.go | 98 ++++++ packages/server/pkg/expression/eval.go | 4 + pnpm-lock.yaml | 304 +++++------------- pnpm-workspace.yaml | 2 +- tools/eslint/config.ts | 2 +- 10 files changed, 415 insertions(+), 230 deletions(-) create mode 100644 .nx/version-plans/desktop-1.0.0.md diff --git a/.nx/version-plans/desktop-1.0.0.md b/.nx/version-plans/desktop-1.0.0.md new file mode 100644 index 000000000..bd7882c7e --- /dev/null +++ b/.nx/version-plans/desktop-1.0.0.md @@ -0,0 +1,28 @@ +--- +desktop: major +--- + +First stable release. + +### New protocols and flow nodes + +- **GraphQL requests**: full request editor with query/variables, dark theme tokens, CLI support, YAML export/import, response history, and delta overrides with assertions. +- **WebSocket**: connection and send flow nodes, request panel, and tables for persisting messages and headers. +- **Wait node**: pause flow execution for a configurable duration. +- **Sub-flow**: new Run Sub Flow node plus SubFlowTrigger and SubFlowReturn, enabling flows to invoke other flows with typed inputs/outputs. + +### Flow engine + +- Flow runner overhaul with improved node execution and error propagation. +- Flow-level error field and node ID mapping for more precise failure attribution. +- Copy/paste support extended to GraphQL, WebSocket, and sub-flow nodes. + +### Expression editor + +- Autocomplete for built-in functions inside `{{ }}`: `uuid()`, `uuid("v4")`, `uuid("v7")`, `ulid()`, `now()`. +- Dot-chain completion on `now()`: `.Unix()`, `.UnixMilli()`, `.UnixMicro()`, `.UnixNano()`. +- New `faker` namespace for fake data — type `faker.` to browse 35 generators including `name()`, `email()`, `phoneNumber()`, `url()`, `ipv4()`, `ipv6()`, `macAddress()`, `username()`, `password()`, `word()`, `sentence()`, `paragraph()`, `date()`, `timestamp()`, `uuid()`, `randomInt(min, max)`. + +### Delta system + +- GraphQL delta support with snapshot/override semantics for name, URL, query, variables, description, headers, and assertions. diff --git a/packages/client/src/features/expression/code-mirror/extensions.tsx b/packages/client/src/features/expression/code-mirror/extensions.tsx index addabb358..c5ddab808 100644 --- a/packages/client/src/features/expression/code-mirror/extensions.tsx +++ b/packages/client/src/features/expression/code-mirror/extensions.tsx @@ -63,6 +63,83 @@ export const useCodeMirrorLanguageExtensions = (language: CodeMirrorLanguage): E return extensions; }; +interface BuiltinMethod { + detail: string; + label: string; +} + +// A builtin is either: +// - callable: root-level function (e.g. `uuid()`), optional method chain on its return (e.g. `now().Unix()`) +// - namespace: root-level identifier holding sub-functions (e.g. `faker.email()`) +interface BuiltinFunction { + detail: string; + kind: 'callable' | 'namespace'; + label: string; + methods?: BuiltinMethod[]; + name: string; +} + +const BUILTIN_FUNCTIONS: BuiltinFunction[] = [ + { detail: 'Generate UUID v4', kind: 'callable', label: 'uuid()', name: 'uuid' }, + { detail: 'Generate UUID v4', kind: 'callable', label: 'uuid("v4")', name: 'uuid' }, + { detail: 'Generate UUID v7', kind: 'callable', label: 'uuid("v7")', name: 'uuid' }, + { detail: 'Generate ULID', kind: 'callable', label: 'ulid()', name: 'ulid' }, + { + detail: 'Current ISO 8601 datetime', + kind: 'callable', + label: 'now()', + methods: [ + { detail: 'Unix timestamp (seconds)', label: 'Unix()' }, + { detail: 'Unix timestamp (milliseconds)', label: 'UnixMilli()' }, + { detail: 'Unix timestamp (microseconds)', label: 'UnixMicro()' }, + { detail: 'Unix timestamp (nanoseconds)', label: 'UnixNano()' }, + ], + name: 'now', + }, + { + detail: 'Fake data generators', + kind: 'namespace', + label: 'faker', + methods: [ + { detail: 'Random full name', label: 'name()' }, + { detail: 'Random first name', label: 'firstName()' }, + { detail: 'Random last name', label: 'lastName()' }, + { detail: 'Random male title', label: 'titleMale()' }, + { detail: 'Random female title', label: 'titleFemale()' }, + { detail: 'Random email', label: 'email()' }, + { detail: 'Random phone number', label: 'phoneNumber()' }, + { detail: 'Random URL', label: 'url()' }, + { detail: 'Random domain name', label: 'domainName()' }, + { detail: 'Random IPv4 address', label: 'ipv4()' }, + { detail: 'Random IPv6 address', label: 'ipv6()' }, + { detail: 'Random MAC address', label: 'macAddress()' }, + { detail: 'Random username', label: 'username()' }, + { detail: 'Random password', label: 'password()' }, + { detail: 'Random word', label: 'word()' }, + { detail: 'Random sentence', label: 'sentence()' }, + { detail: 'Random paragraph', label: 'paragraph()' }, + { detail: 'Random date', label: 'date()' }, + { detail: 'Random time string', label: 'time()' }, + { detail: 'Random month name', label: 'monthName()' }, + { detail: 'Random day of week', label: 'dayOfWeek()' }, + { detail: 'Random day of month', label: 'dayOfMonth()' }, + { detail: 'Random year', label: 'year()' }, + { detail: 'Random century', label: 'century()' }, + { detail: 'Random timestamp', label: 'timestamp()' }, + { detail: 'Random timezone', label: 'timezone()' }, + { detail: 'Random unix time (int64)', label: 'unixTime()' }, + { detail: 'Random credit-card number', label: 'ccNumber()' }, + { detail: 'Random credit-card type', label: 'ccType()' }, + { detail: 'Random currency code', label: 'currency()' }, + { detail: 'Random amount with currency', label: 'amountWithCurrency()' }, + { detail: 'Random hyphenated UUID', label: 'uuid()' }, + { detail: 'Random digit-only UUID', label: 'uuidDigit()' }, + { detail: 'Random int; (max) or (min, max)', label: 'randomInt(min, max)' }, + ], + name: 'faker', + }, +]; + interface CompletionInfoProps { completion: ReferenceCompletion; context: ReferenceContextProps; @@ -134,11 +211,12 @@ const referenceCompletions = const textBefore = line.text.substring(0, cursorInLine); if (isExpression) { - // In expression context: scan backwards for the full dotted path + // In expression context: scan backwards for the full dotted path. + // Parens are included so method chains on builtin calls (e.g. now().Unix) stay intact. let pathStart = textBefore.length; for (let i = textBefore.length - 1; i >= 0; i--) { const ch = textBefore[i]; - if (/[a-zA-Z0-9_.[\]]/.test(ch)) { + if (/[a-zA-Z0-9_.[\]()]/.test(ch)) { pathStart = i; } else { break; @@ -181,6 +259,31 @@ const referenceCompletions = if (token === undefined) return null; + // Method / namespace-member completion for builtins (VS Code-style dot chain). + // - `now().` or `now().Un` → Unix(), UnixMilli(), ... (callable return) + // - `faker.` or `faker.em` → email(), name(), ... (namespace member) + for (const fn of BUILTIN_FUNCTIONS) { + if (!fn.methods) continue; + const marker = fn.kind === 'callable' ? `${fn.name}().` : `${fn.name}.`; + const markerIdx = token.lastIndexOf(marker); + if (markerIdx < 0) continue; + const partial = token.substring(markerIdx + marker.length); + if (!/^\w*$/.test(partial)) continue; + return { + commitCharacters: ['.', '['], + filter: true, + from: context.pos - partial.length, + options: fn.methods.map( + (m): Completion => ({ + detail: m.detail, + label: m.label, + type: 'method', + }), + ), + validFor: /^[a-zA-Z0-9_]*$/, + }; + } + let options: Completion[] = []; const fileToken = '#file:'; @@ -206,6 +309,20 @@ const referenceCompletions = const items = (await client.referenceCompletion({ ...referenceContext, start: token })).items; + // Builtin functions/namespaces appear only at root (no dotted prefix in the current segment). + if (/^\w*$/.test(token)) { + options = [ + ...options, + ...BUILTIN_FUNCTIONS.map( + (fn): Completion => ({ + detail: fn.detail, + label: fn.label, + type: fn.kind === 'namespace' ? 'namespace' : 'function', + }), + ), + ]; + } + options = pipe( items, Array.map((_): Completion => { diff --git a/packages/server/go.mod b/packages/server/go.mod index b1760b14f..66fc84919 100644 --- a/packages/server/go.mod +++ b/packages/server/go.mod @@ -44,6 +44,7 @@ require ( github.com/dlclark/regexp2 v1.11.5 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-faker/faker/v4 v4.7.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/google/generative-ai-go v0.20.1 // indirect diff --git a/packages/server/go.sum b/packages/server/go.sum index b451ff1d3..e2242f8d8 100644 --- a/packages/server/go.sum +++ b/packages/server/go.sum @@ -40,6 +40,8 @@ github.com/expr-lang/expr v1.17.7 h1:Q0xY/e/2aCIp8g9s/LGvMDCC5PxYlvHgDZRQ4y16JX8 github.com/expr-lang/expr v1.17.7/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/go-faker/faker/v4 v4.7.0 h1:VboC02cXHl/NuQh5lM2W8b87yp4iFXIu59x4w0RZi4E= +github.com/go-faker/faker/v4 v4.7.0/go.mod h1:u1dIRP5neLB6kTzgyVjdBOV5R1uP7BdxkcWk7tiKQXk= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= diff --git a/packages/server/pkg/expression/builtins.go b/packages/server/pkg/expression/builtins.go index 97745c0d7..4bff9f585 100644 --- a/packages/server/pkg/expression/builtins.go +++ b/packages/server/pkg/expression/builtins.go @@ -4,6 +4,7 @@ package expression import ( "fmt" + "github.com/go-faker/faker/v4" "github.com/google/uuid" "github.com/oklog/ulid/v2" ) @@ -46,6 +47,88 @@ func helperULID() string { return ulid.Make().String() } +// fakerNamespace returns a map of fake-data generators exposed to expressions +// under the "faker" root identifier. +// +// Usage in expressions: faker.email(), faker.name(), faker.url(), etc. +// +// The map values intentionally use fixed signatures (func() string / func() int64) +// so expr-lang can call them directly — go-faker's native variadic `opts` params +// are not forwarded, we always use defaults. +func fakerNamespace() map[string]any { + return map[string]any{ + // Personal + "name": func() string { return faker.Name() }, + "firstName": func() string { return faker.FirstName() }, + "lastName": func() string { return faker.LastName() }, + "titleMale": func() string { return faker.TitleMale() }, + "titleFemale": func() string { return faker.TitleFemale() }, + + // Contact + "email": func() string { return faker.Email() }, + "phoneNumber": func() string { return faker.Phonenumber() }, + + // Internet + "url": func() string { return faker.URL() }, + "domainName": func() string { return faker.DomainName() }, + "ipv4": func() string { return faker.IPv4() }, + "ipv6": func() string { return faker.IPv6() }, + "macAddress": func() string { return faker.MacAddress() }, + "username": func() string { return faker.Username() }, + "password": func() string { return faker.Password() }, + + // Text + "word": func() string { return faker.Word() }, + "sentence": func() string { return faker.Sentence() }, + "paragraph": func() string { return faker.Paragraph() }, + + // Date / time + "date": func() string { return faker.Date() }, + "time": func() string { return faker.TimeString() }, + "monthName": func() string { return faker.MonthName() }, + "dayOfWeek": func() string { return faker.DayOfWeek() }, + "dayOfMonth": func() string { return faker.DayOfMonth() }, + "year": func() string { return faker.YearString() }, + "century": func() string { return faker.Century() }, + "timestamp": func() string { return faker.Timestamp() }, + "timezone": func() string { return faker.Timezone() }, + "unixTime": faker.RandomUnixTime, + + // Payment + "ccNumber": func() string { return faker.CCNumber() }, + "ccType": func() string { return faker.CCType() }, + "currency": func() string { return faker.Currency() }, + "amountWithCurrency": func() string { return faker.AmountWithCurrency() }, + + // IDs + "uuid": func() string { return faker.UUIDHyphenated() }, + "uuidDigit": func() string { return faker.UUIDDigit() }, + + // Random int — go-faker returns a slice, wrap to return a single int. + // faker.randomInt(max) -> int in [0, max] + // faker.randomInt(min, max) -> int in [min, max] + "randomInt": func(args ...int) (int, error) { + var ns []int + var err error + switch len(args) { + case 1: + ns, err = faker.RandomInt(0, args[0], 1) + case 2: + ns, err = faker.RandomInt(args[0], args[1], 1) + default: + return 0, fmt.Errorf("faker.randomInt: expected 1 or 2 arguments, got %d", len(args)) + } + if err != nil { + return 0, err + } + if len(ns) == 0 { + return 0, fmt.Errorf("faker.randomInt: no values generated") + } + return ns[0], nil + }, + } +} + // helperAI returns the value of varName if it exists, otherwise returns an error. // The description and varType parameters are metadata hints for AI tooling. func (e *UnifiedEnv) helperAI(name, description, varType string) (any, error) { diff --git a/packages/server/pkg/expression/builtins_test.go b/packages/server/pkg/expression/builtins_test.go index 98bb4321c..c958db6d2 100644 --- a/packages/server/pkg/expression/builtins_test.go +++ b/packages/server/pkg/expression/builtins_test.go @@ -314,3 +314,101 @@ func TestBuiltinAI_InterpolationErrorWhenNotFound(t *testing.T) { t.Fatal("expected error when variable not found, got nil") } } + +// ============================================================================= +// Faker Namespace Tests +// ============================================================================= + +func TestBuiltinFaker_EmailReturnsEmailLikeString(t *testing.T) { + env := NewUnifiedEnv(nil) + ctx := context.Background() + + result, err := env.Eval(ctx, "faker.email()") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + str, ok := result.(string) + if !ok { + t.Fatalf("expected string, got %T", result) + } + + if !strings.Contains(str, "@") { + t.Errorf("expected email-like string containing '@', got: %s", str) + } +} + +func TestBuiltinFaker_NameReturnsNonEmpty(t *testing.T) { + env := NewUnifiedEnv(nil) + ctx := context.Background() + + result, err := env.Eval(ctx, "faker.name()") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + str, ok := result.(string) + if !ok { + t.Fatalf("expected string, got %T", result) + } + + if str == "" { + t.Error("expected non-empty name, got empty string") + } +} + +func TestBuiltinFaker_RandomIntInRange(t *testing.T) { + env := NewUnifiedEnv(nil) + ctx := context.Background() + + for i := 0; i < 50; i++ { + result, err := env.Eval(ctx, "faker.randomInt(5, 15)") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + n, ok := result.(int) + if !ok { + t.Fatalf("expected int, got %T", result) + } + + if n < 5 || n > 15 { + t.Errorf("expected value in [5, 15], got %d", n) + } + } +} + +func TestBuiltinFaker_Interpolation(t *testing.T) { + env := NewUnifiedEnv(nil) + + result, err := env.Interpolate("user={{ faker.email() }}") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if !strings.HasPrefix(result, "user=") { + t.Errorf("expected 'user=' prefix, got: %s", result) + } + if !strings.Contains(result, "@") { + t.Errorf("expected '@' in interpolated email, got: %s", result) + } +} + +func TestBuiltinFaker_UUIDHyphenated(t *testing.T) { + env := NewUnifiedEnv(nil) + ctx := context.Background() + + result, err := env.Eval(ctx, "faker.uuid()") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + str, ok := result.(string) + if !ok { + t.Fatalf("expected string, got %T", result) + } + + if !strings.Contains(str, "-") { + t.Errorf("expected hyphenated UUID, got: %s", str) + } +} diff --git a/packages/server/pkg/expression/eval.go b/packages/server/pkg/expression/eval.go index e4e359c76..3310955f4 100644 --- a/packages/server/pkg/expression/eval.go +++ b/packages/server/pkg/expression/eval.go @@ -242,6 +242,9 @@ func (e *UnifiedEnv) buildExprEnv() map[string]any { env["uuid"] = helperUUID env["ulid"] = helperULID + // Add faker namespace for fake-data generators (faker.email(), faker.name(), ...) + env["faker"] = fakerNamespace() + return env } @@ -361,6 +364,7 @@ func isKeyword(s string) bool { "now": true, "date": true, "duration": true, // Custom helper functions "get": true, "has": true, "ai": true, "uuid": true, "ulid": true, + "faker": true, } return keywords[s] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d58464f08..f9413c669 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -217,8 +217,8 @@ catalogs: specifier: 19.1.0-rc.3 version: 19.1.0-rc.3 better-auth: - specifier: 1.5.4 - version: 1.5.4 + specifier: 1.4.21 + version: 1.4.21 builder-util-runtime: specifier: 9.5.1 version: 9.5.1 @@ -617,7 +617,7 @@ importers: version: link:../spec better-auth: specifier: 'catalog:' - version: 1.5.4(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(better-sqlite3@12.6.2)(drizzle-orm@0.41.0(@electric-sql/pglite@0.3.15)(@libsql/client@0.14.0)(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(@types/pg@8.18.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.1.0(socks@2.8.7))(mysql2@3.15.3)(pg@8.20.0)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.10)(vitest@4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + version: 1.4.21(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(better-sqlite3@12.6.2)(drizzle-orm@0.41.0(@electric-sql/pglite@0.3.15)(@libsql/client@0.14.0)(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(@types/pg@8.18.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.1.0(socks@2.8.7))(mysql2@3.15.3)(pg@8.20.0)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.10)(vitest@4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) effect: specifier: 'catalog:' version: 3.19.19 @@ -1877,65 +1877,11 @@ packages: kysely: ^0.28.5 nanostores: ^1.0.1 - '@better-auth/core@1.5.4': - resolution: {integrity: sha512-k5AdwPRQETZn0vdB60EB9CDxxfllpJXKqVxTjyXIUSRz7delNGlU0cR/iRP3VfVJwvYR1NbekphBDNo+KGoEzQ==} - peerDependencies: - '@better-auth/utils': 0.3.1 - '@better-fetch/fetch': 1.1.21 - '@cloudflare/workers-types': '>=4' - better-call: 1.3.2 - jose: ^6.1.0 - kysely: ^0.28.5 - nanostores: ^1.0.1 - peerDependenciesMeta: - '@cloudflare/workers-types': - optional: true - - '@better-auth/drizzle-adapter@1.5.4': - resolution: {integrity: sha512-4M4nMAWrDd3TmpV6dONkJjybBVKRZghe5Oj0NNyDEoXubxastQdO7Sb5B54I1rTx5yoMgsqaB+kbJnu/9UgjQg==} - peerDependencies: - '@better-auth/core': 1.5.4 - '@better-auth/utils': ^0.3.0 - drizzle-orm: '>=0.41.0' - - '@better-auth/kysely-adapter@1.5.4': - resolution: {integrity: sha512-DPww7rIfz6Ed7dZlJSW9xMQ42VKaJLB5Cs+pPqd+UHKRyighKjf3VgvMIcAdFPc4olQ0qRHo3+ZJhFlBCxRhxA==} - peerDependencies: - '@better-auth/core': 1.5.4 - '@better-auth/utils': ^0.3.0 - kysely: ^0.27.0 || ^0.28.0 - - '@better-auth/memory-adapter@1.5.4': - resolution: {integrity: sha512-iiWYut9rbQqiAsgRBtj6+nxanwjapxRgpIJbiS2o81h7b9iclE0AiDA0Foes590gdFQvskNauZcCpuF8ytxthg==} - peerDependencies: - '@better-auth/core': 1.5.4 - '@better-auth/utils': ^0.3.0 - - '@better-auth/mongo-adapter@1.5.4': - resolution: {integrity: sha512-ArzJN5Obk6i6+vLK1HpPzLIcsjxZYXPPUvxVU8eyU5HyoUT2MlswWfPQ8UJAKPn0iq/T4PVp/wZcQMhWk1tuNA==} - peerDependencies: - '@better-auth/core': 1.5.4 - '@better-auth/utils': ^0.3.0 - mongodb: ^6.0.0 || ^7.0.0 - - '@better-auth/prisma-adapter@1.5.4': - resolution: {integrity: sha512-ZQTbcBopw/ezjjbNFsfR3CRp0QciC4tJCarAnB5G9fZtUYbDjfY0vZOxIRmU4kI3x755CXQpGqTrkwmXaMRa3w==} - peerDependencies: - '@better-auth/core': 1.5.4 - '@better-auth/utils': ^0.3.0 - '@prisma/client': ^5.0.0 || ^6.0.0 || ^7.0.0 - prisma: ^5.0.0 || ^6.0.0 || ^7.0.0 - '@better-auth/telemetry@1.4.21': resolution: {integrity: sha512-LX+FGMZnhR2KQZ0idHH1+UwlXvkOl6P8w3Gne4TtjvUCt3QjG9FKIuP9JD3MAmEEkwGt0SoAPHPJEGTjUl3ydg==} peerDependencies: '@better-auth/core': 1.4.21 - '@better-auth/telemetry@1.5.4': - resolution: {integrity: sha512-mGXTY7Ecxo7uvlMr6TFCBUvlH0NUMOeE9LKgPhG4HyhBN6VfCEg/DD9PG0Z2IatmMWQbckkt7ox5A0eBpG9m5w==} - peerDependencies: - '@better-auth/core': 1.5.4 - '@better-auth/utils@0.3.0': resolution: {integrity: sha512-W+Adw6ZA6mgvnSnhOki270rwJ42t4XzSK6YWGF//BbVXL6SwCLWfyzBc1lN2m/4RM28KubdBKQ4X5VMoLRNPQw==} @@ -6054,68 +6000,6 @@ packages: vue: optional: true - better-auth@1.5.4: - resolution: {integrity: sha512-ReykcEKx6Kp9560jG1wtlDBnftA7L7xb3ZZdDWm5yGXKKe2pUf+oBjH0fqekrkRII0m4XBVQbQ0mOrFv+3FdYg==} - peerDependencies: - '@lynx-js/react': '*' - '@prisma/client': ^5.0.0 || ^6.0.0 || ^7.0.0 - '@sveltejs/kit': ^2.0.0 - '@tanstack/react-start': ^1.0.0 - '@tanstack/solid-start': ^1.0.0 - better-sqlite3: ^12.0.0 - drizzle-kit: '>=0.31.4' - drizzle-orm: '>=0.41.0' - mongodb: ^6.0.0 || ^7.0.0 - mysql2: ^3.0.0 - next: ^14.0.0 || ^15.0.0 || ^16.0.0 - pg: ^8.0.0 - prisma: ^5.0.0 || ^6.0.0 || ^7.0.0 - react: ^18.0.0 || ^19.0.0 - react-dom: ^18.0.0 || ^19.0.0 - solid-js: ^1.0.0 - svelte: ^4.0.0 || ^5.0.0 - vitest: ^2.0.0 || ^3.0.0 || ^4.0.0 - vue: ^3.0.0 - peerDependenciesMeta: - '@lynx-js/react': - optional: true - '@prisma/client': - optional: true - '@sveltejs/kit': - optional: true - '@tanstack/react-start': - optional: true - '@tanstack/solid-start': - optional: true - better-sqlite3: - optional: true - drizzle-kit: - optional: true - drizzle-orm: - optional: true - mongodb: - optional: true - mysql2: - optional: true - next: - optional: true - pg: - optional: true - prisma: - optional: true - react: - optional: true - react-dom: - optional: true - solid-js: - optional: true - svelte: - optional: true - vitest: - optional: true - vue: - optional: true - better-call@1.1.8: resolution: {integrity: sha512-XMQ2rs6FNXasGNfMjzbyroSwKwYbZ/T3IxruSS6U2MJRsSYh3wYtG3o6H00ZlKZ/C/UPOAD97tqgQJNsxyeTXw==} peerDependencies: @@ -12111,59 +11995,12 @@ snapshots: nanostores: 1.1.1 zod: 4.3.6 - '@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1)': - dependencies: - '@better-auth/utils': 0.3.1 - '@better-fetch/fetch': 1.1.21 - '@standard-schema/spec': 1.1.0 - better-call: 1.3.2(zod@4.3.6) - jose: 6.2.0 - kysely: 0.28.11 - nanostores: 1.1.1 - zod: 4.3.6 - - '@better-auth/drizzle-adapter@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(drizzle-orm@0.41.0(@electric-sql/pglite@0.3.15)(@libsql/client@0.14.0)(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(@types/pg@8.18.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))': - dependencies: - '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1) - '@better-auth/utils': 0.3.1 - drizzle-orm: 0.41.0(@electric-sql/pglite@0.3.15)(@libsql/client@0.14.0)(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(@types/pg@8.18.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)) - - '@better-auth/kysely-adapter@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(kysely@0.28.11)': - dependencies: - '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1) - '@better-auth/utils': 0.3.1 - kysely: 0.28.11 - - '@better-auth/memory-adapter@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)': - dependencies: - '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1) - '@better-auth/utils': 0.3.1 - - '@better-auth/mongo-adapter@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(mongodb@7.1.0(socks@2.8.7))': - dependencies: - '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1) - '@better-auth/utils': 0.3.1 - mongodb: 7.1.0(socks@2.8.7) - - '@better-auth/prisma-adapter@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))': - dependencies: - '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1) - '@better-auth/utils': 0.3.1 - '@prisma/client': 5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)) - prisma: 7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) - '@better-auth/telemetry@1.4.21(@better-auth/core@1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))': dependencies: '@better-auth/core': 1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1) '@better-auth/utils': 0.3.0 '@better-fetch/fetch': 1.1.21 - '@better-auth/telemetry@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))': - dependencies: - '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1) - '@better-auth/utils': 0.3.1 - '@better-fetch/fetch': 1.1.21 - '@better-auth/utils@0.3.0': {} '@better-auth/utils@0.3.1': {} @@ -12522,12 +12359,15 @@ snapshots: '@electric-sql/pglite-socket@0.0.20(@electric-sql/pglite@0.3.15)': dependencies: '@electric-sql/pglite': 0.3.15 + optional: true '@electric-sql/pglite-tools@0.2.20(@electric-sql/pglite@0.3.15)': dependencies: '@electric-sql/pglite': 0.3.15 + optional: true - '@electric-sql/pglite@0.3.15': {} + '@electric-sql/pglite@0.3.15': + optional: true '@electron/asar@3.4.1': dependencies: @@ -12996,6 +12836,7 @@ snapshots: '@hono/node-server@1.19.9(hono@4.11.4)': dependencies: hono: 4.11.4 + optional: true '@hookform/devtools@4.4.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: @@ -13688,6 +13529,7 @@ snapshots: '@mongodb-js/saslprep@1.4.6': dependencies: sparse-bitfield: 3.0.3 + optional: true '@mrleebo/prisma-ast@0.13.1': dependencies: @@ -14338,10 +14180,13 @@ snapshots: empathic: 2.0.0 transitivePeerDependencies: - magicast + optional: true - '@prisma/debug@7.2.0': {} + '@prisma/debug@7.2.0': + optional: true - '@prisma/debug@7.4.2': {} + '@prisma/debug@7.4.2': + optional: true '@prisma/dev@0.20.0(typescript@5.9.3)': dependencies: @@ -14364,8 +14209,10 @@ snapshots: zeptomatch: 2.1.0 transitivePeerDependencies: - typescript + optional: true - '@prisma/engines-version@7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919': {} + '@prisma/engines-version@7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919': + optional: true '@prisma/engines@7.4.2': dependencies: @@ -14373,28 +14220,34 @@ snapshots: '@prisma/engines-version': 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 '@prisma/fetch-engine': 7.4.2 '@prisma/get-platform': 7.4.2 + optional: true '@prisma/fetch-engine@7.4.2': dependencies: '@prisma/debug': 7.4.2 '@prisma/engines-version': 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 '@prisma/get-platform': 7.4.2 + optional: true '@prisma/get-platform@7.2.0': dependencies: '@prisma/debug': 7.2.0 + optional: true '@prisma/get-platform@7.4.2': dependencies: '@prisma/debug': 7.4.2 + optional: true - '@prisma/query-plan-executor@7.2.0': {} + '@prisma/query-plan-executor@7.2.0': + optional: true '@prisma/studio-core@0.13.1(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@types/react': 19.2.14 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) + optional: true '@react-aria/autocomplete@3.0.0-rc.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: @@ -16358,11 +16211,13 @@ snapshots: '@types/verror@1.10.11': optional: true - '@types/webidl-conversions@7.0.3': {} + '@types/webidl-conversions@7.0.3': + optional: true '@types/whatwg-url@13.0.0': dependencies: '@types/webidl-conversions': 7.0.3 + optional: true '@types/ws@8.18.1': dependencies: @@ -17105,7 +16960,8 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 - aws-ssl-profiles@1.1.2: {} + aws-ssl-profiles@1.1.2: + optional: true axe-core@4.11.1: {} @@ -17264,43 +17120,9 @@ snapshots: solid-js: 1.9.10 vitest: 4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) - better-auth@1.5.4(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(better-sqlite3@12.6.2)(drizzle-orm@0.41.0(@electric-sql/pglite@0.3.15)(@libsql/client@0.14.0)(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(@types/pg@8.18.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.1.0(socks@2.8.7))(mysql2@3.15.3)(pg@8.20.0)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.10)(vitest@4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): - dependencies: - '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1) - '@better-auth/drizzle-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(drizzle-orm@0.41.0(@electric-sql/pglite@0.3.15)(@libsql/client@0.14.0)(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(@types/pg@8.18.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))) - '@better-auth/kysely-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(kysely@0.28.11) - '@better-auth/memory-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1) - '@better-auth/mongo-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(mongodb@7.1.0(socks@2.8.7)) - '@better-auth/prisma-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)) - '@better-auth/telemetry': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1)) - '@better-auth/utils': 0.3.1 - '@better-fetch/fetch': 1.1.21 - '@noble/ciphers': 2.1.1 - '@noble/hashes': 2.0.1 - better-call: 1.3.2(zod@4.3.6) - defu: 6.1.4 - jose: 6.2.0 - kysely: 0.28.11 - nanostores: 1.1.1 - zod: 4.3.6 - optionalDependencies: - '@prisma/client': 5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)) - better-sqlite3: 12.6.2 - drizzle-orm: 0.41.0(@electric-sql/pglite@0.3.15)(@libsql/client@0.14.0)(@prisma/client@5.22.0(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(@types/pg@8.18.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)) - mongodb: 7.1.0(socks@2.8.7) - mysql2: 3.15.3 - pg: 8.20.0 - prisma: 7.4.2(@types/react@19.2.14)(better-sqlite3@12.6.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - solid-js: 1.9.10 - vitest: 4.0.18(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) - transitivePeerDependencies: - - '@cloudflare/workers-types' - better-call@1.1.8(zod@4.3.6): dependencies: - '@better-auth/utils': 0.3.0 + '@better-auth/utils': 0.3.1 '@better-fetch/fetch': 1.1.21 rou3: 0.7.12 set-cookie-parser: 2.7.2 @@ -17387,7 +17209,8 @@ snapshots: node-releases: 2.0.36 update-browserslist-db: 1.2.3(browserslist@4.28.1) - bson@7.2.0: {} + bson@7.2.0: + optional: true btoa@1.2.1: {} @@ -17481,6 +17304,7 @@ snapshots: perfect-debounce: 1.0.0 pkg-types: 2.3.0 rc9: 2.1.2 + optional: true c12@3.3.3: dependencies: @@ -17990,7 +17814,8 @@ snapshots: deep-is@0.1.4: {} - deepmerge-ts@7.1.5: {} + deepmerge-ts@7.1.5: + optional: true deepmerge@4.3.1: {} @@ -18029,7 +17854,8 @@ snapshots: delegates@1.0.0: {} - denque@2.1.0: {} + denque@2.1.0: + optional: true depd@1.1.2: {} @@ -18166,6 +17992,7 @@ snapshots: dependencies: '@standard-schema/spec': 1.1.0 fast-check: 3.23.2 + optional: true effect@3.19.19: dependencies: @@ -19009,6 +18836,7 @@ snapshots: generate-function@2.3.1: dependencies: is-property: 1.0.2 + optional: true generator-function@2.0.1: {} @@ -19035,7 +18863,8 @@ snapshots: hasown: 2.0.2 math-intrinsics: 1.1.0 - get-port-please@3.2.0: {} + get-port-please@3.2.0: + optional: true get-proto@1.0.1: dependencies: @@ -19184,9 +19013,11 @@ snapshots: graceful-fs@4.2.11: {} - grammex@3.1.12: {} + grammex@3.1.12: + optional: true - graphmatch@1.1.1: {} + graphmatch@1.1.1: + optional: true has-bigints@1.1.0: {} @@ -19250,7 +19081,8 @@ snapshots: dependencies: parse-passwd: 1.0.0 - hono@4.11.4: {} + hono@4.11.4: + optional: true hosted-git-info@4.1.0: dependencies: @@ -19340,7 +19172,8 @@ snapshots: - debug - supports-color - http-status-codes@2.3.0: {} + http-status-codes@2.3.0: + optional: true http2-wrapper@1.0.3: dependencies: @@ -19539,7 +19372,8 @@ snapshots: is-plain-object@5.0.0: {} - is-property@1.0.2: {} + is-property@1.0.2: + optional: true is-reference@1.2.1: dependencies: @@ -19910,7 +19744,8 @@ snapshots: long-timeout@0.1.1: {} - long@5.3.2: {} + long@5.3.2: + optional: true longest-streak@3.1.0: {} @@ -19938,7 +19773,8 @@ snapshots: dependencies: yallist: 4.0.0 - lru.min@1.1.4: {} + lru.min@1.1.4: + optional: true luxon@3.7.2: {} @@ -20160,7 +19996,8 @@ snapshots: media-typer@1.1.0: {} - memory-pager@1.5.0: {} + memory-pager@1.5.0: + optional: true merge-descriptors@1.0.3: {} @@ -20490,6 +20327,7 @@ snapshots: dependencies: '@types/whatwg-url': 13.0.0 whatwg-url: 14.2.0 + optional: true mongodb@7.1.0(socks@2.8.7): dependencies: @@ -20498,6 +20336,7 @@ snapshots: mongodb-connection-string-url: 7.0.1 optionalDependencies: socks: 2.8.7 + optional: true ms@2.0.0: {} @@ -20536,6 +20375,7 @@ snapshots: named-placeholders: 1.1.6 seq-queue: 0.0.5 sqlstring: 2.3.3 + optional: true mz@2.7.0: dependencies: @@ -20546,6 +20386,7 @@ snapshots: named-placeholders@1.1.6: dependencies: lru.min: 1.1.4 + optional: true nanoid@3.3.11: {} @@ -20979,7 +20820,8 @@ snapshots: pend@1.2.0: {} - perfect-debounce@1.0.0: {} + perfect-debounce@1.0.0: + optional: true perfect-debounce@2.1.0: {} @@ -21129,7 +20971,8 @@ snapshots: dependencies: xtend: 4.0.2 - postgres@3.4.7: {} + postgres@3.4.7: + optional: true postject@1.0.0-alpha.6: dependencies: @@ -21185,6 +21028,7 @@ snapshots: - magicast - react - react-dom + optional: true proc-log@5.0.0: {} @@ -21623,7 +21467,8 @@ snapshots: mdast-util-to-markdown: 2.1.2 unified: 11.0.5 - remeda@2.33.4: {} + remeda@2.33.4: + optional: true require-directory@2.1.1: {} @@ -21827,7 +21672,8 @@ snapshots: transitivePeerDependencies: - supports-color - seq-queue@0.0.5: {} + seq-queue@0.0.5: + optional: true serialize-error@7.0.1: dependencies: @@ -22004,6 +21850,7 @@ snapshots: sparse-bitfield@3.0.3: dependencies: memory-pager: 1.5.0 + optional: true split2@4.2.0: {} @@ -22012,7 +21859,8 @@ snapshots: sprintf-js@1.1.3: optional: true - sqlstring@2.3.3: {} + sqlstring@2.3.3: + optional: true ssri@12.0.0: dependencies: @@ -22446,6 +22294,7 @@ snapshots: tr46@5.1.1: dependencies: punycode: 2.3.1 + optional: true tree-kill@1.2.2: {} @@ -22916,7 +22765,8 @@ snapshots: webidl-conversions@3.0.1: {} - webidl-conversions@7.0.0: {} + webidl-conversions@7.0.0: + optional: true webpack-sources@3.3.4: {} @@ -22995,6 +22845,7 @@ snapshots: dependencies: tr46: 5.1.1 webidl-conversions: 7.0.0 + optional: true whatwg-url@5.0.0: dependencies: @@ -23149,6 +23000,7 @@ snapshots: dependencies: grammex: 3.1.12 graphmatch: 1.1.1 + optional: true zip-stream@6.0.1: dependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index fcaab6fcd..c1eae3d36 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -79,7 +79,7 @@ catalog: '@vitejs/plugin-react': 5.1.4 '@xyflow/react': 12.10.1 babel-plugin-react-compiler: 19.1.0-rc.3 - better-auth: 1.5.4 + better-auth: 1.4.21 builder-util-runtime: 9.5.1 effect: 3.19.19 electron: 40.8.0 diff --git a/tools/eslint/config.ts b/tools/eslint/config.ts index 7030b7aed..dd7a021e0 100644 --- a/tools/eslint/config.ts +++ b/tools/eslint/config.ts @@ -59,7 +59,7 @@ const react = defineConfig( const tailwind = defineConfig({ plugins: { 'better-tailwindcss': tailwindPlugin }, - rules: tailwindPlugin.configs['recommended']!.rules, + rules: tailwindPlugin.configs.recommended.rules, settings: { 'better-tailwindcss': { entryPoint: resolve(root, 'packages/ui/src/styles/index.css'),