From 4d1ad717adb9538acd30ee0a3a50fcedd4c1d58d Mon Sep 17 00:00:00 2001 From: Arjun Patel Date: Wed, 1 Apr 2026 10:32:15 -0700 Subject: [PATCH] support huddles (#106) * add token endpoint for livekit * fix: invalid type passed to hook * fix: inject livekit env variables for orion * fix: show controls indicator above stream # shortcut * return livekit server url from api * simple huddle implementation with streams * set human name in livekit room context * simplify deployment tooling * join huddle with audio automatically * feat: show when there is an active huddle This introduces a webhook which listens to events from livekit and updates our firestore stream particle. It keeps the client simple, reacting to changes to firestore docs. * use headphones icon for huddles * fix: screenshare not working in electron The default VideoConference component from livekit doesn't support screenshare in electron. This attempts to compose our own layout with livekit components ourselves and introduces our own flow for screenshare. --- go/Makefile | 35 +- go/README.md | 32 ++ go/cmd/orion/main.go | 18 +- go/deploy_dev.sh | 7 - go/deploy_prod.sh | 7 - go/go.mod | 115 +++++-- go/go.sum | 317 ++++++++++++++---- go/internal/handler/handler.go | 158 ++++++++- go/internal/livekit/client.go | 78 +++++ go/internal/particle/firestore_types.go | 9 +- go/k8s/dev/orion.yaml | 17 + go/k8s/prod/orion.yaml | 15 + go/migrate_dev.sh | 11 - go/migrate_prod.sh | 11 - go/skaffold.yaml | 64 ++-- js/package.json | 3 + js/src/api/client.ts | 7 + js/src/api/types.ts | 10 + js/src/electron.d.ts | 13 +- .../features/compose/controls-indicator.tsx | 5 +- js/src/features/network-root.tsx | 2 +- .../features/particles/particle-list-view.tsx | 16 +- js/src/features/particles/stream-card.tsx | 18 +- js/src/features/particles/stream-view.tsx | 73 +++- js/src/huddle/HuddleApp.tsx | 47 --- js/src/huddle_window/HuddleApp.tsx | 208 ++++++++++++ js/src/huddle_window/ScreenPicker.tsx | 117 +++++++ js/src/huddle_window/renderer.tsx | 2 +- js/src/lib/firestore-particles.ts | 1 + js/src/main.ts | 25 +- js/src/preload.ts | 11 +- js/yarn.lock | 149 +++++++- 32 files changed, 1358 insertions(+), 243 deletions(-) create mode 100644 go/README.md delete mode 100755 go/deploy_dev.sh delete mode 100755 go/deploy_prod.sh create mode 100644 go/internal/livekit/client.go delete mode 100755 go/migrate_dev.sh delete mode 100755 go/migrate_prod.sh delete mode 100644 js/src/huddle/HuddleApp.tsx create mode 100644 js/src/huddle_window/HuddleApp.tsx create mode 100644 js/src/huddle_window/ScreenPicker.tsx diff --git a/go/Makefile b/go/Makefile index 97f900b..868512b 100644 --- a/go/Makefile +++ b/go/Makefile @@ -8,19 +8,13 @@ generate: test: go test -json ./... | docker run -i ghcr.io/gotesttools/gotestfmt:latest -.PHONY: migrate-dev -migrate-dev: - ./migrate_dev.sh - -.PHONY: migrate-prod -migrate-prod: - ./migrate_prod.sh - # ex: make create-migration ARG="create_users_table" create-migration: echo "Creating migration with name $(ARG)" docker run -v ./migrations:/migrations --network host migrate/migrate create -ext sql -seq -dir /migrations $(ARG) +# ---- Database access ---- + dev-database: kubectl run postgres-client \ --rm -it --image=postgres:latest \ @@ -35,11 +29,30 @@ prod-database: --context prod \ --command -- /bin/bash -c "psql \$$LLINK_POSTGRES_CONNECTION_URL" +# ---- Migrations ---- +# NOTE: if you run into issues with 'dirty' migrations: https://github.com/golang-migrate/migrate/issues/282#issuecomment-530743258 + +DEV_REPO := us-west2-docker.pkg.dev/flowy-dev-440017/deployments +PROD_REPO := us-west2-docker.pkg.dev/flowy-prod-440017/deployments + +.PHONY: migrate-dev +migrate-dev: + kubectl delete job migrations --ignore-not-found --context=dev + SKAFFOLD_DEFAULT_REPO=$(DEV_REPO) skaffold run -p migrations --kube-context dev + +.PHONY: migrate-prod +migrate-prod: + kubectl delete job migrations --ignore-not-found --context=prod + SKAFFOLD_DEFAULT_REPO=$(PROD_REPO) skaffold run -p migrations --kube-context prod --tail + +# ---- Deploy ---- +# Use MODULE=orion or MODULE=worker to deploy a single service, e.g.: +# make deploy-dev MODULE=orion + .PHONY: deploy-dev deploy-dev: generate test - ./deploy_dev.sh + SKAFFOLD_DEFAULT_REPO=$(DEV_REPO) skaffold run -p dev $(if $(MODULE),-m $(MODULE)) --kube-context dev --port-forward --tail .PHONY: deploy-prod deploy-prod: generate test - ./deploy_prod.sh - + SKAFFOLD_DEFAULT_REPO=$(PROD_REPO) skaffold run -p prod $(if $(MODULE),-m $(MODULE)) --kube-context prod --port-forward --tail diff --git a/go/README.md b/go/README.md new file mode 100644 index 0000000..d0b86cf --- /dev/null +++ b/go/README.md @@ -0,0 +1,32 @@ +# Orion + +API server and worker services for llink. + +## Deploy + +```bash +# Deploy all services +make deploy-dev +make deploy-prod + +# Deploy a single service +make deploy-dev MODULE=orion +make deploy-dev MODULE=worker +``` + +## Migrations + +```bash +make migrate-dev +make migrate-prod + +# Create a new migration +make create-migration ARG="create_users_table" +``` + +## Database Access + +```bash +make dev-database +make prod-database +``` diff --git a/go/cmd/orion/main.go b/go/cmd/orion/main.go index df35195..abb7f5b 100644 --- a/go/cmd/orion/main.go +++ b/go/cmd/orion/main.go @@ -7,6 +7,7 @@ import ( "net/http" "os" + "cloud.google.com/go/firestore" "cloud.google.com/go/storage" pbaero "github.com/flowy-live/llink/genproto/aero" "github.com/flowy-live/llink/internal" @@ -15,6 +16,7 @@ import ( "github.com/flowy-live/llink/internal/depot" "github.com/flowy-live/llink/internal/handler" "github.com/flowy-live/llink/internal/human" + "github.com/flowy-live/llink/internal/livekit" "github.com/flowy-live/llink/internal/middleware" "github.com/flowy-live/llink/internal/network" "github.com/flowy-live/llink/internal/particle" @@ -77,9 +79,19 @@ func main() { BucketName: gcsBucket, }) waitlistSvc := waitlist.NewService(db.Pool(), aeroSvc) + livekitClient := livekit.NewClient() + + // Initialize Firestore client (for webhook-driven updates) + gcpProject := utils.MustGetEnv("GCP_PROJECT") + firestoreClient, err := firestore.NewClient(ctx, gcpProject) + if err != nil { + slog.Error("failed to create Firestore client", "error", err) + os.Exit(1) + } + defer firestoreClient.Close() // Initialize handler - h := handler.NewHandler(authSvc, humanSvc, networkSvc, particleSvc, depotSvc, waitlistSvc) + h := handler.NewHandler(authSvc, humanSvc, networkSvc, particleSvc, depotSvc, waitlistSvc, livekitClient, firestoreClient) // Helper to wrap handlers with auth middleware withAuth := func(hf http.HandlerFunc) http.Handler { @@ -100,6 +112,7 @@ func main() { mux.HandleFunc("POST /auth/request-code", h.RequestSignInCode) mux.HandleFunc("POST /auth/sign-in", h.SignIn) mux.HandleFunc("POST /waitlist", h.AddToWaitlist) + mux.HandleFunc("POST /livekit/webhook", h.HandleLivekitWebhook) // ========================================================================== // Protected routes (auth required) @@ -130,6 +143,9 @@ func main() { mux.Handle("POST /depot/upload", withAuth(h.PrepareUpload)) mux.Handle("POST /depot/objects/{id}/confirm", withAuth(h.ConfirmUpload)) + // LiveKit + mux.Handle("POST /livekit/token", withAuth(h.GetLivekitToken)) + // Waitlist (admin-only) mux.Handle("GET /waitlist", withAuth(h.GetWaitlist)) mux.Handle("GET /waitlist/{email}", withAuth(h.GetWaitlistEntry)) diff --git a/go/deploy_dev.sh b/go/deploy_dev.sh deleted file mode 100755 index 779e6de..0000000 --- a/go/deploy_dev.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -set -e - -export KUBE_CONTEXT=dev -export SKAFFOLD_DEFAULT_REPO=us-west2-docker.pkg.dev/flowy-dev-440017/deployments -skaffold run -p dev --kube-context $KUBE_CONTEXT --port-forward --tail diff --git a/go/deploy_prod.sh b/go/deploy_prod.sh deleted file mode 100755 index a7e4492..0000000 --- a/go/deploy_prod.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -set -e - -export KUBE_CONTEXT=prod -export SKAFFOLD_DEFAULT_REPO=us-west2-docker.pkg.dev/flowy-prod-440017/deployments -skaffold run -p prod --kube-context $KUBE_CONTEXT --port-forward --tail diff --git a/go/go.mod b/go/go.mod index 934136d..89fd4a3 100644 --- a/go/go.mod +++ b/go/go.mod @@ -1,49 +1,60 @@ module github.com/flowy-live/llink -go 1.25 +go 1.25.0 require ( + cloud.google.com/go/firestore v1.21.0 cloud.google.com/go/storage v1.59.1 + github.com/deepgram/deepgram-go-sdk/v3 v3.5.0 github.com/golang-migrate/migrate/v4 v4.19.1 github.com/google/uuid v1.6.0 github.com/jackc/pgx/v5 v5.7.2 + github.com/livekit/protocol v1.45.1 + github.com/livekit/server-sdk-go/v2 v2.16.1 github.com/redis/go-redis/v9 v9.17.2 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.11.1 github.com/testcontainers/testcontainers-go v0.40.0 github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0 go.jetify.com/typeid v1.3.0 - google.golang.org/grpc v1.78.0 + go.uber.org/mock v0.6.0 + google.golang.org/grpc v1.79.1 google.golang.org/protobuf v1.36.11 ) require ( - cel.dev/expr v0.24.0 // indirect + buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260209202127-80ab13bee0bf.1 // indirect + buf.build/go/protovalidate v1.1.2 // indirect + buf.build/go/protoyaml v0.6.0 // indirect + cel.dev/expr v0.25.1 // indirect cloud.google.com/go v0.123.0 // indirect cloud.google.com/go/auth v0.17.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.9.0 // indirect - cloud.google.com/go/firestore v1.21.0 // indirect cloud.google.com/go/iam v1.5.3 // indirect cloud.google.com/go/longrunning v0.7.0 // indirect cloud.google.com/go/monitoring v1.24.2 // indirect dario.cat/mergo v1.0.2 // indirect - github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect + github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/antlr4-go/antlr/v4 v4.13.1 // indirect + github.com/benbjohnson/clock v1.3.5 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bep/debounce v1.2.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f // indirect + github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/containerd/log v0.1.0 // indirect - github.com/containerd/platforms v0.2.1 // indirect + github.com/containerd/platforms v1.0.0-rc.2 // indirect github.com/cpuguy83/dockercfg v0.3.2 // indirect + github.com/creack/pty v1.1.24 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/deepgram/deepgram-go-sdk v1.9.0 // indirect - github.com/deepgram/deepgram-go-sdk/v3 v3.5.0 // indirect + github.com/dennwc/iters v1.2.2 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/distribution/reference v0.6.0 // indirect github.com/docker/docker v28.5.1+incompatible // indirect @@ -51,70 +62,118 @@ require ( github.com/docker/go-units v0.5.0 // indirect github.com/dvonthenen/websocket v1.5.1-dyv.2 // indirect github.com/ebitengine/purego v0.8.4 // indirect - github.com/envoyproxy/go-control-plane/envoy v1.35.0 // indirect - github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect - github.com/fatih/color v1.15.0 // indirect + github.com/envoyproxy/go-control-plane/envoy v1.36.0 // indirect + github.com/envoyproxy/protoc-gen-validate v1.3.0 // indirect + github.com/fatih/color v1.16.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/frostbyte73/core v0.1.1 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/gammazero/deque v1.2.1 // indirect + github.com/go-jose/go-jose/v3 v3.0.4 // indirect github.com/go-jose/go-jose/v4 v4.1.3 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/gofrs/uuid/v5 v5.2.0 // indirect + github.com/google/cel-go v0.27.0 // indirect github.com/google/s2a-go v0.1.9 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.7 // indirect github.com/googleapis/gax-go/v2 v2.15.0 // indirect github.com/gorilla/schema v1.3.0 // indirect + github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect - github.com/klauspost/compress v1.18.0 // indirect + github.com/jxskiss/base62 v1.1.0 // indirect + github.com/klauspost/compress v1.18.4 // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/lib/pq v1.10.9 // indirect + github.com/lithammer/shortuuid/v4 v4.2.0 // indirect + github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731 // indirect + github.com/livekit/mediatransportutil v0.0.0-20251128105421-19c7a7b81c22 // indirect + github.com/livekit/psrpc v0.7.1 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/magefile/mage v1.15.0 // indirect github.com/magiconair/properties v1.8.10 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/go-archive v0.1.0 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.6.0 // indirect github.com/moby/sys/user v0.4.0 // indirect github.com/moby/sys/userns v0.1.0 // indirect - github.com/moby/term v0.5.0 // indirect + github.com/moby/term v0.5.2 // indirect github.com/morikuni/aec v1.0.0 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/nats-io/nats.go v1.48.0 // indirect + github.com/nats-io/nkeys v0.4.15 // indirect + github.com/nats-io/nuid v1.0.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect + github.com/pion/datachannel v1.6.0 // indirect + github.com/pion/dtls/v3 v3.1.2 // indirect + github.com/pion/ice/v4 v4.2.0 // indirect + github.com/pion/interceptor v0.1.44 // indirect + github.com/pion/logging v0.2.4 // indirect + github.com/pion/mdns/v2 v2.1.0 // indirect + github.com/pion/randutil v0.1.0 // indirect + github.com/pion/rtcp v1.2.16 // indirect + github.com/pion/rtp v1.10.1 // indirect + github.com/pion/sctp v1.9.2 // indirect + github.com/pion/sdp/v3 v3.0.17 // indirect + github.com/pion/srtp/v3 v3.0.10 // indirect + github.com/pion/stun/v3 v3.1.1 // indirect + github.com/pion/transport/v4 v4.0.1 // indirect + github.com/pion/turn/v4 v4.1.4 // indirect + github.com/pion/webrtc/v4 v4.2.6 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/prometheus/client_golang v1.22.0 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.64.0 // indirect + github.com/prometheus/procfs v0.19.2 // indirect + github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect github.com/shirou/gopsutil/v4 v4.25.6 // indirect github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect + github.com/twitchtv/twirp v8.1.3+incompatible // indirect + github.com/wlynxg/anet v0.0.5 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect + github.com/zeebo/xxh3 v1.1.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/detectors/gcp v1.38.0 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.39.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect - go.opentelemetry.io/otel v1.38.0 // indirect - go.opentelemetry.io/otel/metric v1.38.0 // indirect - go.opentelemetry.io/otel/sdk v1.38.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect - go.opentelemetry.io/otel/trace v1.38.0 // indirect - go.uber.org/mock v0.6.0 // indirect - golang.org/x/crypto v0.45.0 // indirect - golang.org/x/net v0.47.0 // indirect + go.opentelemetry.io/otel v1.40.0 // indirect + go.opentelemetry.io/otel/metric v1.40.0 // indirect + go.opentelemetry.io/otel/sdk v1.40.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.40.0 // indirect + go.opentelemetry.io/otel/trace v1.40.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.1 // indirect + go.uber.org/zap/exp v0.3.0 // indirect + golang.org/x/crypto v0.48.0 // indirect + golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a // indirect + golang.org/x/mod v0.33.0 // indirect + golang.org/x/net v0.50.0 // indirect golang.org/x/oauth2 v0.34.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/text v0.32.0 // indirect + golang.org/x/sys v0.41.0 // indirect + golang.org/x/text v0.34.0 // indirect golang.org/x/time v0.14.0 // indirect google.golang.org/api v0.256.0 // indirect google.golang.org/genproto v0.0.0-20250922171735-9219d122eba9 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/klog/v2 v2.110.1 // indirect ) diff --git a/go/go.sum b/go/go.sum index 70d5f49..000cd72 100644 --- a/go/go.sum +++ b/go/go.sum @@ -1,5 +1,11 @@ -cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= -cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260209202127-80ab13bee0bf.1 h1:PMmTMyvHScV9Mn8wc6ASge9uRcHy0jtqPd+fM35LmsQ= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260209202127-80ab13bee0bf.1/go.mod h1:tvtbpgaVXZX4g6Pn+AnzFycuRK3MOz5HJfEGeEllXYM= +buf.build/go/protovalidate v1.1.2 h1:83vYHoY8f34hB8MeitGaYE3CGVPFxwdEUuskh5qQpA0= +buf.build/go/protovalidate v1.1.2/go.mod h1:Ez3z+w4c+wG+EpW8ovgZaZPnPl2XVF6kaxgcv1NG/QE= +buf.build/go/protoyaml v0.6.0 h1:Nzz1lvcXF8YgNZXk+voPPwdU8FjDPTUV4ndNTXN0n2w= +buf.build/go/protoyaml v0.6.0/go.mod h1:RgUOsBu/GYKLDSIRgQXniXbNgFlGEZnQpRAUdLAFV2Q= +cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= +cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= cloud.google.com/go/auth v0.17.0 h1:74yCm7hCj2rUyyAocqnFzsAYXgJhrG26XCFimrc/Kz4= @@ -26,8 +32,8 @@ dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 h1:lhhYARPUu3LmHysQ/igznQphfzynnqI3D75oUyw1HXk= @@ -38,42 +44,60 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapp github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= +github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= +github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= +github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= +github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= +github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= +github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4= +github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f h1:Y8xYupdHxryycyPlc9Y+bSQAYZnetRJ70VMVKm5CKI0= -github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f/go.mod h1:HlzOvOjVBOfTGSRXRyY0OiCS/3J1akRGQQpRO/7zyF4= +github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w= +github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI= +github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= +github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= -github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= -github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= +github.com/containerd/platforms v1.0.0-rc.2 h1:0SPgaNZPVWGEi4grZdV8VRYQn78y+nm6acgLGv/QzE4= +github.com/containerd/platforms v1.0.0-rc.2/go.mod h1:J71L7B+aiM5SdIEqmd9wp6THLVRzJGXfNuWCZCllLA4= github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= -github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= -github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= +github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= 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= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deepgram/deepgram-go-sdk v1.9.0 h1:FlJ1iJ//+Cz0goWGWU/Ms2jjM/wMBqyNAk+5bcAsptU= -github.com/deepgram/deepgram-go-sdk v1.9.0/go.mod h1:il+6HLmvxa47EG12LG6VwzaHcyI8Lo+yfBsOcDq3R8s= github.com/deepgram/deepgram-go-sdk/v3 v3.5.0 h1:ug48j1DVNRKrkXti18/aFT3NP5HV2Q2CN3QMwTvHmy4= github.com/deepgram/deepgram-go-sdk/v3 v3.5.0/go.mod h1:wVr0PDvlJFWVLUmf65u+K80SJVf/PUWvkFFubGPW/As= +github.com/dennwc/iters v1.2.2 h1:XH2/Etihiy9ZvPOVCR+icQXeYlhbvS7k0qro4x/2qQo= +github.com/dennwc/iters v1.2.2/go.mod h1:M9KuuMBeyEXYTmB7EnI9SCyALFCmPWOIxn5W1L0CjGg= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dhui/dktest v0.4.6 h1:+DPKyScKSEp3VLtbMDHcUq6V5Lm5zfZZVb0Sk7Ahom4= github.com/dhui/dktest v0.4.6/go.mod h1:JHTSYDtKkvFNFHJKqCzVzqXecyv+tKt8EzceOmQOgbU= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/cli v29.0.0+incompatible h1:KgsN2RUFMNM8wChxryicn4p46BdQWpXOA1XLGBGPGAw= +github.com/docker/cli v29.0.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/docker v28.5.1+incompatible h1:Bm8DchhSD2J6PsFzxC35TZo4TLGR2PdW/E69rU45NhM= github.com/docker/docker v28.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= @@ -84,18 +108,26 @@ github.com/dvonthenen/websocket v1.5.1-dyv.2 h1:OXlWJJkeHt8k4+MEI0Y8SQjY2ihHYD2z github.com/dvonthenen/websocket v1.5.1-dyv.2/go.mod h1:q2GbopbpFJvBP4iqVvqwwahVmvu2HnCfdqCWDoQVKMM= github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= -github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329 h1:K+fnvUM0VZ7ZFJf0n4L/BRlnsb9pL/GuDG6FqaH+PwM= -github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329/go.mod h1:Alz8LEClvR7xKsrq3qzoc4N0guvVNSS8KmSChGYr9hs= -github.com/envoyproxy/go-control-plane/envoy v1.35.0 h1:ixjkELDE+ru6idPxcHLj8LBVc2bFP7iBytj353BoHUo= -github.com/envoyproxy/go-control-plane/envoy v1.35.0/go.mod h1:09qwbGVuSWWAyN5t/b3iyVfz5+z8QWGrzkoqm/8SbEs= +github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA= +github.com/envoyproxy/go-control-plane v0.14.0/go.mod h1:NcS5X47pLl/hfqxU70yPwL9ZMkUlwlKxtAohpi2wBEU= +github.com/envoyproxy/go-control-plane/envoy v1.36.0 h1:yg/JjO5E7ubRyKX3m07GF3reDNEnfOboJ0QySbH736g= +github.com/envoyproxy/go-control-plane/envoy v1.36.0/go.mod h1:ty89S1YCCVruQAm9OtKeEkQLTb+Lkz0k8v9W0Oxsv98= github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= -github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= -github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/envoyproxy/protoc-gen-validate v1.3.0 h1:TvGH1wof4H33rezVKWSpqKz5NXWg5VPuZ0uONDT6eb4= +github.com/envoyproxy/protoc-gen-validate v1.3.0/go.mod h1:HvYl7zwPa5mffgyeTUHA9zHIH36nmrm7oCbo4YKoSWA= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/frostbyte73/core v0.1.1 h1:ChhJOR7bAKOCPbA+lqDLE2cGKlCG5JXsDvvQr4YaJIA= +github.com/frostbyte73/core v0.1.1/go.mod h1:mhfOtR+xWAvwXiwor7jnqPMnu4fxbv1F2MwZ0BEpzZo= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/gammazero/deque v1.2.1 h1:9fnQVFCCZ9/NOc7ccTNqzoKd1tCWOqeI05/lPqFPMGQ= +github.com/gammazero/deque v1.2.1/go.mod h1:5nSFkzVm+afG9+gy0VIowlqVAW4N8zNcMne+CMQVD2g= +github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY= +github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -106,19 +138,26 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gofrs/uuid/v5 v5.2.0 h1:qw1GMx6/y8vhVsx626ImfKMuS5CvJmhIKKtuyvfajMM= github.com/gofrs/uuid/v5 v5.2.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/golang-migrate/migrate/v4 v4.19.1 h1:OCyb44lFuQfYXYLx1SCxPZQGU7mcaZ7gH9yH4jSFbBA= github.com/golang-migrate/migrate/v4 v4.19.1/go.mod h1:CTcgfjxhaUtsLipnLoQRWCrjYXycRz/g5+RWDuYgPrE= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/cel-go v0.27.0 h1:e7ih85+4qVrBuqQWTW4FKSqZYokVuc3HnhH5keboFTo= +github.com/google/cel-go v0.27.0/go.mod h1:tTJ11FWqnhw5KKpnWpvW9CJC3Y9GK4EIS0WXnBbebzw= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.7 h1:zrn2Ee/nWmHulBx5sAVrGgAa0f2/R35S4DJwfFaUPFQ= @@ -127,8 +166,16 @@ github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81 github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc= github.com/gorilla/schema v1.3.0 h1:rbciOzXAx3IB8stEFnfTwO3sYa6EWlQk79XdyustPDA= github.com/gorilla/schema v1.3.0/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4 h1:kEISI/Gx67NzH3nJxAmY/dGac80kKZgZt134u7Y/k1s= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4/go.mod h1:6Nz966r3vQYCqIzWsuEl9d7cf7mRhtDmm++sOxlnfxI= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= +github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f h1:7LYC+Yfkj3CTRcShK0KOL/w6iTiKyqqBA9a41Wnggw8= github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f/go.mod h1:pFlLw2CfqZiIBOx6BuCeRLCrfxBJipTY0nIOF/VbGcI= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= @@ -139,29 +186,51 @@ github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI= github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/jxskiss/base62 v1.1.0 h1:A5zbF8v8WXx2xixnAKD2w+abC+sIzYJX+nxmhA6HWFw= +github.com/jxskiss/base62 v1.1.0/go.mod h1:HhWAlUXvxKThfOlZbcuFzsqwtF5TcqS9ru3y5GfjWAc= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lithammer/shortuuid/v4 v4.2.0 h1:LMFOzVB3996a7b8aBuEXxqOBflbfPQAiVzkIcHO0h8c= +github.com/lithammer/shortuuid/v4 v4.2.0/go.mod h1:D5noHZ2oFw/YaKCfGy0YxyE7M0wMbezmMjPdhyEFe6Y= +github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731 h1:9x+U2HGLrSw5ATTo469PQPkqzdoU7be46ryiCDO3boc= +github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731/go.mod h1:Rs3MhFwutWhGwmY1VQsygw28z5bWcnEYmS1OG9OxjOQ= +github.com/livekit/mediatransportutil v0.0.0-20251128105421-19c7a7b81c22 h1:dzCBxOGLLWVtQhL7OYK2EGN+5Q+23Mq/jfz4vQisirA= +github.com/livekit/mediatransportutil v0.0.0-20251128105421-19c7a7b81c22/go.mod h1:mSNtYzSf6iY9xM3UX42VEI+STHvMgHmrYzEHPcdhB8A= +github.com/livekit/protocol v1.45.1 h1:4cbynsPZW32gS2z6nUWfAfr4YaTUwZSKUiLpSpjX+lQ= +github.com/livekit/protocol v1.45.1/go.mod h1:63AUi0vQak6Y6gPqSBHLc+ExYTUwEqF/m4b2IRW1iO0= +github.com/livekit/psrpc v0.7.1 h1:ms37az0QTD3UXIWuUC5D/SkmKOlRMVRsI261eBWu/Vw= +github.com/livekit/psrpc v0.7.1/go.mod h1:bZ4iHFQptTkbPnB0LasvRNu/OBYXEu1NA6O5BMFo9kk= +github.com/livekit/server-sdk-go/v2 v2.16.1 h1:ZkIA9OdVvQ6Up1uW/RtQ0YJUgYMJ6+ywOmDg0jX7bTg= +github.com/livekit/server-sdk-go/v2 v2.16.1/go.mod h1:oQbYijcbPzfjBAOzoq7tz9Ktqur8JNRCd923VP8xOQQ= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= +github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mdelapenya/tlscert v0.2.0 h1:7H81W6Z/4weDvZBNOfQte5GpIMo0lGYEeWbkGp5LJHI= github.com/mdelapenya/tlscert v0.2.0/go.mod h1:O4njj3ELLnJjGdkN7M/vIVCpZ+Cf0L6muqOG4tLSl8o= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ= github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo= +github.com/moby/moby/api v1.52.0 h1:00BtlJY4MXkkt84WhUZPRqt5TvPbgig2FZvTbe3igYg= +github.com/moby/moby/api v1.52.0/go.mod h1:8mb+ReTlisw4pS6BRzCMts5M49W5M7bKt1cJy/YbAqc= +github.com/moby/moby/client v0.1.0 h1:nt+hn6O9cyJQqq5UWnFGqsZRTS/JirUqzPjEl0Bdc/8= +github.com/moby/moby/client v0.1.0/go.mod h1:O+/tw5d4a1Ha/ZA/tPxIZJapJRUS6LNZ1wiVRxYHyUE= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw= @@ -172,14 +241,60 @@ github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= -github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= +github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/nats-io/nats.go v1.48.0 h1:pSFyXApG+yWU/TgbKCjmm5K4wrHu86231/w84qRVR+U= +github.com/nats-io/nats.go v1.48.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g= +github.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4= +github.com/nats-io/nkeys v0.4.15/go.mod h1:CpMchTXC9fxA5zrMo4KpySxNjiDVvr8ANOSZdiNfUrs= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= +github.com/opencontainers/runc v1.3.3 h1:qlmBbbhu+yY0QM7jqfuat7M1H3/iXjju3VkP9lkFQr4= +github.com/opencontainers/runc v1.3.3/go.mod h1:D7rL72gfWxVs9cJ2/AayxB0Hlvn9g0gaF1R7uunumSI= +github.com/ory/dockertest/v3 v3.12.0 h1:3oV9d0sDzlSQfHtIaB5k6ghUCVMVLpAY8hwrqoCyRCw= +github.com/ory/dockertest/v3 v3.12.0/go.mod h1:aKNDTva3cp8dwOWwb9cWuX84aH5akkxXRvO7KCwWVjE= +github.com/pion/datachannel v1.6.0 h1:XecBlj+cvsxhAMZWFfFcPyUaDZtd7IJvrXqlXD/53i0= +github.com/pion/datachannel v1.6.0/go.mod h1:ur+wzYF8mWdC+Mkis5Thosk+u/VOL287apDNEbFpsIk= +github.com/pion/dtls/v3 v3.1.2 h1:gqEdOUXLtCGW+afsBLO0LtDD8GnuBBjEy6HRtyofZTc= +github.com/pion/dtls/v3 v3.1.2/go.mod h1:Hw/igcX4pdY69z1Hgv5x7wJFrUkdgHwAn/Q/uo7YHRo= +github.com/pion/ice/v4 v4.2.0 h1:jJC8S+CvXCCvIQUgx+oNZnoUpt6zwc34FhjWwCU4nlw= +github.com/pion/ice/v4 v4.2.0/go.mod h1:EgjBGxDgmd8xB0OkYEVFlzQuEI7kWSCFu+mULqaisy4= +github.com/pion/interceptor v0.1.44 h1:sNlZwM8dWXU9JQAkJh8xrarC0Etn8Oolcniukmuy0/I= +github.com/pion/interceptor v0.1.44/go.mod h1:4atVlBkcgXuUP+ykQF0qOCGU2j7pQzX2ofvPRFsY5RY= +github.com/pion/logging v0.2.4 h1:tTew+7cmQ+Mc1pTBLKH2puKsOvhm32dROumOZ655zB8= +github.com/pion/logging v0.2.4/go.mod h1:DffhXTKYdNZU+KtJ5pyQDjvOAh/GsNSyv1lbkFbe3so= +github.com/pion/mdns/v2 v2.1.0 h1:3IJ9+Xio6tWYjhN6WwuY142P/1jA0D5ERaIqawg/fOY= +github.com/pion/mdns/v2 v2.1.0/go.mod h1:pcez23GdynwcfRU1977qKU0mDxSeucttSHbCSfFOd9A= +github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= +github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= +github.com/pion/rtcp v1.2.16 h1:fk1B1dNW4hsI78XUCljZJlC4kZOPk67mNRuQ0fcEkSo= +github.com/pion/rtcp v1.2.16/go.mod h1:/as7VKfYbs5NIb4h6muQ35kQF/J0ZVNz2Z3xKoCBYOo= +github.com/pion/rtp v1.10.1 h1:xP1prZcCTUuhO2c83XtxyOHJteISg6o8iPsE2acaMtA= +github.com/pion/rtp v1.10.1/go.mod h1:rF5nS1GqbR7H/TCpKwylzeq6yDM+MM6k+On5EgeThEM= +github.com/pion/sctp v1.9.2 h1:HxsOzEV9pWoeggv7T5kewVkstFNcGvhMPx0GvUOUQXo= +github.com/pion/sctp v1.9.2/go.mod h1:OTOlsQ5EDQ6mQ0z4MUGXt2CgQmKyafBEXhUVqLRB6G8= +github.com/pion/sdp/v3 v3.0.17 h1:9SfLAW/fF1XC8yRqQ3iWGzxkySxup4k4V7yN8Fs8nuo= +github.com/pion/sdp/v3 v3.0.17/go.mod h1:9tyKzznud3qiweZcD86kS0ff1pGYB3VX+Bcsmkx6IXo= +github.com/pion/srtp/v3 v3.0.10 h1:tFirkpBb3XccP5VEXLi50GqXhv5SKPxqrdlhDCJlZrQ= +github.com/pion/srtp/v3 v3.0.10/go.mod h1:3mOTIB0cq9qlbn59V4ozvv9ClW/BSEbRp4cY0VtaR7M= +github.com/pion/stun/v3 v3.1.1 h1:CkQxveJ4xGQjulGSROXbXq94TAWu8gIX2dT+ePhUkqw= +github.com/pion/stun/v3 v3.1.1/go.mod h1:qC1DfmcCTQjl9PBaMa5wSn3x9IPmKxSdcCsxBcDBndM= +github.com/pion/transport/v3 v3.1.1 h1:Tr684+fnnKlhPceU+ICdrw6KKkTms+5qHMgw6bIkYOM= +github.com/pion/transport/v3 v3.1.1/go.mod h1:+c2eewC5WJQHiAA46fkMMzoYZSuGzA/7E2FPrOYHctQ= +github.com/pion/transport/v4 v4.0.1 h1:sdROELU6BZ63Ab7FrOLn13M6YdJLY20wldXW2Cu2k8o= +github.com/pion/transport/v4 v4.0.1/go.mod h1:nEuEA4AD5lPdcIegQDpVLgNoDGreqM/YqmEx3ovP4jM= +github.com/pion/turn/v4 v4.1.4 h1:EU11yMXKIsK43FhcUnjLlrhE4nboHZq+TXBIi3QpcxQ= +github.com/pion/turn/v4 v4.1.4/go.mod h1:ES1DXVFKnOhuDkqn9hn5VJlSWmZPaRJLyBXoOeO/BmQ= +github.com/pion/webrtc/v4 v4.2.6 h1:e9H/du7PbYA2qMJkqKp9Ou2z5Igb/6qbKSeEeUCVv0M= +github.com/pion/webrtc/v4 v4.2.6/go.mod h1:+GAy0jwidoZAHsgjsx77sH09spnV0YWjpB3ROAXmz5A= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= @@ -189,12 +304,26 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.64.0 h1:pdZeA+g617P7oGv1CzdTzyeShxAGrTBsolKNOLQPGO4= +github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= +github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg= +github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= github.com/redis/go-redis/v9 v9.17.2 h1:P2EGsA4qVIM3Pp+aPocCJ7DguDHhqrXNhVcEp4ViluI= github.com/redis/go-redis/v9 v9.17.2/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370= +github.com/rodaine/protogofakeit v0.1.1 h1:ZKouljuRM3A+TArppfBqnH8tGZHOwM/pjvtXe9DaXH8= +github.com/rodaine/protogofakeit v0.1.1/go.mod h1:pXn/AstBYMaSfc1/RqH3N82pBuxtWgejz1AlYpY1mI0= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/shirou/gopsutil/v4 v4.25.6 h1:kLysI2JsKorfaFPcYmcJqbzROzsBWEOAtw6A7dIfqXs= github.com/shirou/gopsutil/v4 v4.25.6/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c= +github.com/shoenig/test v1.7.0 h1:eWcHtTXa6QLnBvm0jgEabMRN/uJ4DMV3M8xUGgRkZmk= +github.com/shoenig/test v1.7.0/go.mod h1:UxJ6u/x2v/TNs/LoLxBNJRV9DiwBBKYxXSyczsBHFoI= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= @@ -214,61 +343,129 @@ github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFA github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/twitchtv/twirp v8.1.3+incompatible h1:+F4TdErPgSUbMZMwp13Q/KgDVuI7HJXP61mNV3/7iuU= +github.com/twitchtv/twirp v8.1.3+incompatible/go.mod h1:RRJoFSAmTEh2weEqWtpPE3vFK5YBhA6bqp2l1kfCC5A= +github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU= +github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= +github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= +github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s= go.jetify.com/typeid v1.3.0 h1:fuWV7oxO4mSsgpxwhaVpFXgt0IfjogR29p+XAjDCVKY= go.jetify.com/typeid v1.3.0/go.mod h1:CtVGyt2+TSp4Rq5+ARLvGsJqdNypKBAC6INQ9TLPlmk= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/contrib/detectors/gcp v1.38.0 h1:ZoYbqX7OaA/TAikspPl3ozPI6iY6LiIY9I8cUfm+pJs= -go.opentelemetry.io/contrib/detectors/gcp v1.38.0/go.mod h1:SU+iU7nu5ud4oCb3LQOhIZ3nRLj6FNVrKgtflbaf2ts= +go.opentelemetry.io/contrib/detectors/gcp v1.39.0 h1:kWRNZMsfBHZ+uHjiH4y7Etn2FK26LAGkNFw7RHv1DhE= +go.opentelemetry.io/contrib/detectors/gcp v1.39.0/go.mod h1:t/OGqzHBa5v6RHZwrDBJ2OirWc+4q/w2fTbLZwAKjTk= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= -go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= -go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= +go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= +go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w= -go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= -go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= -go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= -go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= -go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= -go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= -go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= -go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= -go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os= -go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo= +go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= +go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= +go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8= +go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE= +go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw= +go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= +go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= +go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= +go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= +go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= -golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= +go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap/exp v0.3.0 h1:6JYzdifzYkGmTdRR59oYH+Ng7k49H9qVpWwNSsGJj3U= +go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= +golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= +golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a h1:ovFr6Z0MNmU7nH8VaX5xqw+05ST2uO1exVfZPVqRC5o= +golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= +golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= -golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= -golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= +golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= @@ -276,12 +473,12 @@ google.golang.org/api v0.256.0 h1:u6Khm8+F9sxbCTYNoBHg6/Hwv0N/i+V94MvkOSor6oI= google.golang.org/api v0.256.0/go.mod h1:KIgPhksXADEKJlnEoRa9qAII4rXcy40vfI8HRqcU964= google.golang.org/genproto v0.0.0-20250922171735-9219d122eba9 h1:LvZVVaPE0JSqL+ZWb6ErZfnEOKIqqFWUJE2D0fObSmc= google.golang.org/genproto v0.0.0-20250922171735-9219d122eba9/go.mod h1:QFOrLhdAe2PsTp3vQY4quuLKTi9j3XG3r6JPPaw7MSc= -google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b h1:uA40e2M6fYRBf0+8uN5mLlqUtV192iiksiICIBkYJ1E= -google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:Xa7le7qx2vmqB/SzWUBa7KdMjpdpAHlh5QCSnjessQk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b h1:Mv8VFug0MP9e5vUxfBcE3vUkV6CImK3cMNMIDFjmzxU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= -google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= -google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= +google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 h1:JLQynH/LBHfCTSbDWl+py8C+Rg/k1OVH3xfcaiANuF0= +google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:kSJwQxqmFXeo79zOmbrALdflXQeAYcUbgS7PbpMknCY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= +google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY= +google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/go/internal/handler/handler.go b/go/internal/handler/handler.go index c59687c..1e9e95f 100644 --- a/go/internal/handler/handler.go +++ b/go/internal/handler/handler.go @@ -4,37 +4,46 @@ import ( "context" "encoding/json" "errors" + "fmt" "log/slog" "net/http" + "strings" "time" + "cloud.google.com/go/firestore" "github.com/flowy-live/llink/internal/auth" "github.com/flowy-live/llink/internal/depot" "github.com/flowy-live/llink/internal/human" + "github.com/flowy-live/llink/internal/livekit" "github.com/flowy-live/llink/internal/middleware" "github.com/flowy-live/llink/internal/network" "github.com/flowy-live/llink/internal/particle" "github.com/flowy-live/llink/internal/utils" "github.com/flowy-live/llink/internal/waitlist" + "github.com/livekit/protocol/webhook" ) type Handler struct { - authSvc auth.AuthService - humanSvc human.Service - networkSvc network.Service - particleSvc particle.Service - depotSvc depot.Service - waitlistSvc waitlist.Service + authSvc auth.AuthService + humanSvc human.Service + networkSvc network.Service + particleSvc particle.Service + depotSvc depot.Service + waitlistSvc waitlist.Service + livekitClient livekit.Client + firestoreClient *firestore.Client } -func NewHandler(authSvc auth.AuthService, humanSvc human.Service, networkSvc network.Service, particleSvc particle.Service, depotSvc depot.Service, waitlistSvc waitlist.Service) *Handler { +func NewHandler(authSvc auth.AuthService, humanSvc human.Service, networkSvc network.Service, particleSvc particle.Service, depotSvc depot.Service, waitlistSvc waitlist.Service, livekitClient livekit.Client, firestoreClient *firestore.Client) *Handler { return &Handler{ - authSvc: authSvc, - humanSvc: humanSvc, - networkSvc: networkSvc, - particleSvc: particleSvc, - depotSvc: depotSvc, - waitlistSvc: waitlistSvc, + authSvc: authSvc, + humanSvc: humanSvc, + networkSvc: networkSvc, + particleSvc: particleSvc, + depotSvc: depotSvc, + waitlistSvc: waitlistSvc, + livekitClient: livekitClient, + firestoreClient: firestoreClient, } } @@ -109,6 +118,18 @@ type RevokeInvitationRequest struct { Email string `json:"email"` } +// LiveKit DTOs + +type GetLivekitTokenRequest struct { + NetworkId string `json:"network_id"` + StreamId string `json:"stream_id"` +} + +type GetLivekitTokenResponse struct { + Token string `json:"token"` + ServerUrl string `json:"server_url"` +} + // Depot DTOs type PrepareUploadRequest struct { @@ -1040,6 +1061,117 @@ func (h *Handler) networkToDTO(ctx context.Context, n *network.Network) (Network }, nil } +// ============================================================================ +// LiveKit Handlers +// ============================================================================ + +func (h *Handler) GetLivekitToken(w http.ResponseWriter, r *http.Request) { + humanId, ok := middleware.HumanIdFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + humanEmail, ok := middleware.EmailFromContext(r.Context()) + if !ok { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + var req GetLivekitTokenRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "invalid request body", http.StatusBadRequest) + return + } + + if req.NetworkId == "" { + http.Error(w, "network_id is required", http.StatusBadRequest) + return + } + if req.StreamId == "" { + http.Error(w, "stream_id is required", http.StatusBadRequest) + return + } + + // Compose room name encoding both network and stream IDs for webhook resolution + roomName := req.NetworkId + "/" + req.StreamId + + token, err := h.livekitClient.GetJoinToken(roomName, humanId, humanEmail) + if err != nil { + slog.Error("failed to generate livekit token", "error", err, "humanId", humanId, "roomName", roomName) + http.Error(w, "failed to generate token", http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(GetLivekitTokenResponse{Token: token, ServerUrl: h.livekitClient.ServerUrl()}) +} + +// HandleLivekitWebhook processes LiveKit webhook events for huddle presence. +// It verifies the webhook signature (not user auth), then updates the stream +// particle's huddle_active_participants field in Firestore. +func (h *Handler) HandleLivekitWebhook(w http.ResponseWriter, r *http.Request) { + event, err := webhook.ReceiveWebhookEvent(r, h.livekitClient.KeyProvider()) + if err != nil { + slog.Error("failed to verify livekit webhook", "error", err) + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + eventType := event.GetEvent() + slog.Info("received livekit webhook", "event", eventType, "room", event.GetRoom().GetName()) + + switch eventType { + case "participant_joined", "participant_left", "room_finished": + // Handle these events + default: + w.WriteHeader(http.StatusOK) + return + } + + // Parse room name to extract networkId and streamId + roomName := event.GetRoom().GetName() + parts := strings.SplitN(roomName, "/", 2) + if len(parts) != 2 { + slog.Error("invalid room name format", "room", roomName) + http.Error(w, "invalid room name", http.StatusBadRequest) + return + } + networkId, streamId := parts[0], parts[1] + docPath := fmt.Sprintf("networks/%s/children/%s", networkId, streamId) + docRef := h.firestoreClient.Doc(docPath) + ctx := r.Context() + + var participantIds []string + + if eventType == "room_finished" { + // Room is done — clear the participants + participantIds = []string{} + } else { + // Use ListParticipants for authoritative state (avoids drift from missed webhooks) + participants, err := h.livekitClient.ListParticipants(ctx, roomName) + if err != nil { + slog.Error("failed to list participants", "error", err, "room", roomName) + // Return 200 so LiveKit doesn't retry + w.WriteHeader(http.StatusOK) + return + } + + participantIds = make([]string, 0, len(participants)) + for _, p := range participants { + participantIds = append(participantIds, p.Identity) + } + } + + _, err = docRef.Update(ctx, []firestore.Update{ + {Path: "huddle_active_participants", Value: participantIds}, + }) + if err != nil { + slog.Error("failed to update huddle participants in firestore", "error", err, "path", docPath) + } + + w.WriteHeader(http.StatusOK) +} + func extractBearerToken(r *http.Request) string { authHeader := r.Header.Get("Authorization") if authHeader == "" { diff --git a/go/internal/livekit/client.go b/go/internal/livekit/client.go new file mode 100644 index 0000000..8cce5eb --- /dev/null +++ b/go/internal/livekit/client.go @@ -0,0 +1,78 @@ +package livekit + +import ( + "context" + "time" + + "github.com/flowy-live/llink/internal/utils" + "github.com/livekit/protocol/auth" + "github.com/livekit/protocol/livekit" + lksdk "github.com/livekit/server-sdk-go/v2" +) + +type Client interface { + // GetJoinToken generates a JWT for a participant to join a room. + // Name will show up in the participant data. + GetJoinToken(roomId string, humanId string, name string) (string, error) + ServerUrl() string + // ListParticipants returns the current participants in a room. + ListParticipants(ctx context.Context, roomName string) ([]*livekit.ParticipantInfo, error) + // KeyProvider returns the key provider for verifying webhook signatures. + KeyProvider() auth.KeyProvider +} + +type clientImpl struct { + apiSecret string + apiKey string + hostUrl string + roomService *lksdk.RoomServiceClient + keyProvider auth.KeyProvider +} + +func NewClient() Client { + apiKey := utils.MustGetEnv("LIVEKIT_API_KEY") + apiSecret := utils.MustGetEnv("LIVEKIT_API_SECRET") + hostUrl := utils.MustGetEnv("LIVEKIT_URL") + + roomService := lksdk.NewRoomServiceClient(hostUrl, apiKey, apiSecret) + + return &clientImpl{ + apiSecret: apiSecret, + apiKey: apiKey, + hostUrl: hostUrl, + roomService: roomService, + keyProvider: auth.NewSimpleKeyProvider(apiKey, apiSecret), + } +} + +func (c *clientImpl) ServerUrl() string { + return c.hostUrl +} + +func (c *clientImpl) GetJoinToken(room, humanId, name string) (string, error) { + at := auth.NewAccessToken(c.apiKey, c.apiSecret) + grant := &auth.VideoGrant{ + RoomJoin: true, + Room: room, + } + at.SetVideoGrant(grant). + SetIdentity(humanId). + SetName(name). + SetValidFor(time.Hour) + + return at.ToJWT() +} + +func (c *clientImpl) ListParticipants(ctx context.Context, roomName string) ([]*livekit.ParticipantInfo, error) { + resp, err := c.roomService.ListParticipants(ctx, &livekit.ListParticipantsRequest{ + Room: roomName, + }) + if err != nil { + return nil, err + } + return resp.Participants, nil +} + +func (c *clientImpl) KeyProvider() auth.KeyProvider { + return c.keyProvider +} diff --git a/go/internal/particle/firestore_types.go b/go/internal/particle/firestore_types.go index dbae226..82d5869 100644 --- a/go/internal/particle/firestore_types.go +++ b/go/internal/particle/firestore_types.go @@ -46,8 +46,9 @@ type FirestoreStreamParticle struct { CreatedByHumanId string `firestore:"created_by_human_id"` Type string `firestore:"type"` // Properties FirestoreStreamParticleProperties `firestore:"properties"` - CreatedAt time.Time `firestore:"created_at,serverTimestamp"` - LastChildCreatedAt *time.Time `firestore:"last_child_created_at,omitempty"` - VisibleTo []string `firestore:"visible_to"` - UpdatedAt *time.Time `firestore:"updated_at,omitempty"` + CreatedAt time.Time `firestore:"created_at,serverTimestamp"` + LastChildCreatedAt *time.Time `firestore:"last_child_created_at,omitempty"` + VisibleTo []string `firestore:"visible_to"` + UpdatedAt *time.Time `firestore:"updated_at,omitempty"` + HuddleActiveParticipants []string `firestore:"huddle_active_participants,omitempty"` } diff --git a/go/k8s/dev/orion.yaml b/go/k8s/dev/orion.yaml index 76aa4d1..fe5a099 100644 --- a/go/k8s/dev/orion.yaml +++ b/go/k8s/dev/orion.yaml @@ -29,6 +29,8 @@ spec: memory: "52Mi" cpu: 50m env: + - name: "GCP_PROJECT" + value: "flowy-dev-440017" - name: "PORT" value: "8080" - name: "AERO_ADDR" @@ -44,6 +46,21 @@ spec: value: "iam-for-gke-sa@flowy-dev-440017.iam.gserviceaccount.com" - name: "REDIS_HOST" value: "10.138.57.187" + - name: "LIVEKIT_API_KEY" + valueFrom: + secretKeyRef: + name: shared-secrets + key: LIVEKIT_API_KEY + - name: "LIVEKIT_API_SECRET" + valueFrom: + secretKeyRef: + name: shared-secrets + key: LIVEKIT_API_SECRET + - name: "LIVEKIT_URL" + valueFrom: + secretKeyRef: + name: shared-secrets + key: LIVEKIT_URL --- diff --git a/go/k8s/prod/orion.yaml b/go/k8s/prod/orion.yaml index c660d19..dad1db7 100644 --- a/go/k8s/prod/orion.yaml +++ b/go/k8s/prod/orion.yaml @@ -41,6 +41,21 @@ spec: value: "iam-for-gke-sa@flowy-prod-440017.iam.gserviceaccount.com" - name: "REDIS_HOST" value: "10.204.2.99" + - name: "LIVEKIT_API_KEY" + valueFrom: + secretKeyRef: + name: shared-secrets + key: LIVEKIT_API_KEY + - name: "LIVEKIT_API_SECRET" + valueFrom: + secretKeyRef: + name: shared-secrets + key: LIVEKIT_API_SECRET + - name: "LIVEKIT_URL" + valueFrom: + secretKeyRef: + name: shared-secrets + key: LIVEKIT_URL --- diff --git a/go/migrate_dev.sh b/go/migrate_dev.sh deleted file mode 100755 index e31add5..0000000 --- a/go/migrate_dev.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -set -e - -echo "# NOTE: if you run into issues with 'dirty' migrations: https://github.com/golang-migrate/migrate/issues/282#issuecomment-530743258" - -export KUBE_CONTEXT=dev -export SKAFFOLD_DEFAULT_REPO=us-west2-docker.pkg.dev/flowy-dev-440017/deployments -kubectl delete job migrations --ignore-not-found --context=$KUBE_CONTEXT -skaffold run -p migrations --kube-context $KUBE_CONTEXT - diff --git a/go/migrate_prod.sh b/go/migrate_prod.sh deleted file mode 100755 index dbaac65..0000000 --- a/go/migrate_prod.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -set -e - -echo "# NOTE: if you run into issues with 'dirty' migrations: https://github.com/golang-migrate/migrate/issues/282#issuecomment-530743258" - -export KUBE_CONTEXT=prod -export SKAFFOLD_DEFAULT_REPO=us-west2-docker.pkg.dev/flowy-prod-440017/deployments -kubectl delete job migrations --ignore-not-found --context=$KUBE_CONTEXT -skaffold run -p migrations --kube-context $KUBE_CONTEXT --tail - diff --git a/go/skaffold.yaml b/go/skaffold.yaml index cd35a7f..0b8d805 100644 --- a/go/skaffold.yaml +++ b/go/skaffold.yaml @@ -1,14 +1,12 @@ apiVersion: skaffold/v4beta11 kind: Config metadata: - name: llink-services + name: migrations build: local: {} tagPolicy: gitCommit: variant: AbbrevCommitSha - -# NOTE: we use different profiles for a simpler mental model profiles: - name: migrations build: @@ -22,45 +20,73 @@ profiles: - k8s/migrations.yaml deploy: kubectl: {} - +--- +apiVersion: skaffold/v4beta11 +kind: Config +metadata: + name: orion +build: + local: {} + tagPolicy: + gitCommit: + variant: AbbrevCommitSha +profiles: - name: dev build: - hooks: - before: - # already run in make test - # - command: ["go", "test", "./..."] artifacts: - image: orion context: . docker: dockerfile: Dockerfile - - image: particleprocessorworker - context: . - docker: - dockerfile: Dockerfile.particleprocessorworker manifests: rawYaml: - - k8s/dev/* + - k8s/dev/orion.yaml deploy: kubectl: {} - - name: prod build: - hooks: - before: - # already run in make test - # - command: ["go", "test", "./..."] artifacts: - image: orion context: . docker: dockerfile: Dockerfile + manifests: + rawYaml: + - k8s/prod/orion.yaml + deploy: + kubectl: {} +--- +apiVersion: skaffold/v4beta11 +kind: Config +metadata: + name: worker +build: + local: {} + tagPolicy: + gitCommit: + variant: AbbrevCommitSha +profiles: + - name: dev + build: + artifacts: - image: particleprocessorworker context: . docker: dockerfile: Dockerfile.particleprocessorworker manifests: rawYaml: - - k8s/prod/* + - k8s/dev/particleprocessorworker.yaml + deploy: + kubectl: {} + - name: prod + build: + artifacts: + - image: particleprocessorworker + context: . + docker: + dockerfile: Dockerfile.particleprocessorworker + manifests: + rawYaml: + - k8s/prod/particleprocessorworker.yaml deploy: kubectl: {} diff --git a/js/package.json b/js/package.json index 197bddf..8da7e0d 100644 --- a/js/package.json +++ b/js/package.json @@ -49,11 +49,14 @@ "vite": "^5.4.21" }, "dependencies": { + "@livekit/components-react": "^2.9.20", + "@livekit/components-styles": "^1.2.0", "@tanstack/react-query": "^5.90.21", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "electron-squirrel-startup": "^1.0.1", "firebase": "^12.10.0", + "livekit-client": "^2.18.0", "lucide-react": "^0.575.0", "next-themes": "^0.4.6", "radix-ui": "^1.4.3", diff --git a/js/src/api/client.ts b/js/src/api/client.ts index 0adcd26..bac9f8f 100644 --- a/js/src/api/client.ts +++ b/js/src/api/client.ts @@ -2,6 +2,7 @@ import { useSessionStore } from "@/stores/session-store"; import type { z } from "zod"; import { DepotObjectSchema, + GetLivekitTokenResponseSchema, HumanSchema, ListInvitationsResponseSchema, ListNetworksResponseSchema, @@ -211,6 +212,12 @@ class ApiClient { async revokeInvitation(networkId: string, data: RevokeInvitationRequest): Promise { await this.requestVoid("DELETE", `/networks/${networkId}/invitations`, data); } + + // --- LiveKit --- + + async getLivekitToken(networkId: string, streamId: string) { + return this.request(GetLivekitTokenResponseSchema, "POST", "/livekit/token", { network_id: networkId, stream_id: streamId }); + } } export const apiClient = new ApiClient({ diff --git a/js/src/api/types.ts b/js/src/api/types.ts index 61edebf..3e7ef23 100644 --- a/js/src/api/types.ts +++ b/js/src/api/types.ts @@ -184,6 +184,8 @@ export const ParticleSchema = z.discriminatedUnion("type", [ // Timestamp of the most recent child particle // used for sorting streams by recent activity without needing to query subcollections last_child_created_at: z.coerce.date().optional(), + // Array of humanIds currently in the huddle (updated via LiveKit webhooks) + huddle_active_participants: z.array(z.string()).optional(), }), ParticleBaseSchema.extend({ type: z.literal("folder"), properties: FolderPropertiesSchema, @@ -209,6 +211,14 @@ export function isContainerType(type: ParticleType): boolean { return CONTAINER_TYPES.has(type); } +// --- LiveKit types --- + +export const GetLivekitTokenResponseSchema = z.object({ + token: z.string(), + server_url: z.string(), +}); +export type GetLivekitTokenResponse = z.infer; + // --- Auth types --- const RequestCodeRequestSchema = z.object({ diff --git a/js/src/electron.d.ts b/js/src/electron.d.ts index af2a989..3823276 100644 --- a/js/src/electron.d.ts +++ b/js/src/electron.d.ts @@ -2,15 +2,26 @@ import type { LinkMetadata } from './lib/link-metadata'; import type { AutoplayPayload } from './lib/autoplay-ipc'; declare global { + interface ScreenSource { + id: string; + name: string; + thumbnailDataUrl: string; + appIconDataUrl: string | null; + } + interface Window { electronWindow: { minimize: () => void; maximize: () => void; fullscreen: () => void; close: () => void; - openHuddle: () => void; + openHuddle: (data: { token: string; serverUrl: string }) => void; closeHuddle: () => void; }; + electronHuddle: { + onConnect: (callback: (data: { token: string; serverUrl: string }) => void) => () => void; + getScreenSources: () => Promise; + }; electronAutoplay: { play: (payload: AutoplayPayload) => void; dismiss: () => void; diff --git a/js/src/features/compose/controls-indicator.tsx b/js/src/features/compose/controls-indicator.tsx index 6a40622..81bde3d 100644 --- a/js/src/features/compose/controls-indicator.tsx +++ b/js/src/features/compose/controls-indicator.tsx @@ -1,5 +1,6 @@ import { Video, Mic, Paperclip } from "lucide-react"; import { useMediaSettingsStore } from "@/stores/media-settings-store"; +import { PropsWithChildren } from "react"; interface ControlsIndicatorProps { type: "reply" | "new"; @@ -12,7 +13,8 @@ export default function ControlsIndicator({ attachmentCount = 0, showEscape = false, onOpenAttachments, -}: ControlsIndicatorProps) { + children +}: PropsWithChildren) { const recordingMode = useMediaSettingsStore((s) => s.recordingMode); const setRecordingMode = useMediaSettingsStore((s) => s.setRecordingMode); @@ -82,6 +84,7 @@ export default function ControlsIndicator({ {attachmentCount} {attachmentCount === 1 ? "attachment" : "attachments"} )} + {children} ); } diff --git a/js/src/features/network-root.tsx b/js/src/features/network-root.tsx index 4f37daa..174bc76 100644 --- a/js/src/features/network-root.tsx +++ b/js/src/features/network-root.tsx @@ -71,7 +71,7 @@ export default function NetworkRoot() { -
+
diff --git a/js/src/features/particles/particle-list-view.tsx b/js/src/features/particles/particle-list-view.tsx index a1ac5d4..dd8df4a 100644 --- a/js/src/features/particles/particle-list-view.tsx +++ b/js/src/features/particles/particle-list-view.tsx @@ -10,6 +10,7 @@ import { CircleCheck, StickyNote, Timer, + Headphones, type LucideIcon, } from "lucide-react"; import { cn } from "@/lib/utils"; @@ -94,13 +95,17 @@ function StreamRow({ const userId = user?.id ?? ""; const network = useNetwork(networkId); - useStreamAutoplay(latestChild, particle, networkId, network); + useStreamAutoplay(latestChild, particle, networkId, network ?? undefined); const expiringSoon = useExpiringSoon( particle.last_child_created_at, network?.message_retention_hours ?? 24, ); + const hasActiveHuddle = + particle.huddle_active_participants && particle.huddle_active_participants.length > 0; + const huddleCount = particle.huddle_active_participants?.length ?? 0; + const isDM = particle.visible_to.length === 2 && particle.visible_to.every((v) => v.startsWith("human:")); @@ -162,6 +167,7 @@ function StreamRow({ className={cn( "flex w-full items-center gap-3 px-4 py-3 text-left cursor-pointer transition-colors hover:bg-accent", isSelected && "bg-accent", + hasActiveHuddle && "bg-gradient-to-r from-red-500/10 to-transparent", )} > {shortcutKey && ( @@ -188,7 +194,13 @@ function StreamRow({ > {particle.properties.name}

-
+
+ {hasActiveHuddle && ( + + + {huddleCount} + + )} {expiringSoon && ( )} diff --git a/js/src/features/particles/stream-card.tsx b/js/src/features/particles/stream-card.tsx index 040707e..b8ac66e 100644 --- a/js/src/features/particles/stream-card.tsx +++ b/js/src/features/particles/stream-card.tsx @@ -1,5 +1,5 @@ import { forwardRef, useMemo } from "react"; -import { Timer } from "lucide-react"; +import { Timer, Headphones } from "lucide-react"; import { cn, getInitials } from "@/lib/utils"; import { useLiveLatestChild } from "@/hooks/use-particle"; import { useAuthStore } from "@/stores/auth-store"; @@ -27,13 +27,17 @@ export const StreamCard = forwardRef(function S const userId = useAuthStore((s) => s.user?.id) ?? ""; const network = useNetwork(networkId); - useStreamAutoplay(latestChild, particle, networkId, network); + useStreamAutoplay(latestChild, particle, networkId, network ?? undefined); const expiringSoon = useExpiringSoon( particle.last_child_created_at, network?.message_retention_hours ?? 24, ); + const hasActiveHuddle = + particle.huddle_active_participants && particle.huddle_active_participants.length > 0; + const huddleCount = particle.huddle_active_participants?.length ?? 0; + const isDM = particle.visible_to.length === 2 && particle.visible_to.every((v) => v.startsWith("human:")); @@ -94,10 +98,14 @@ export const StreamCard = forwardRef(function S "cursor-pointer overflow-hidden rounded-xl ring-1 ring-foreground/10 transition-all hover:ring-foreground/20", isUnseen && "ring-2 ring-primary", isSelected && "ring-2 ring-ring", + hasActiveHuddle && "ring-2 ring-red-500/70", )} > {/* Preview area */}
+ {hasActiveHuddle && ( +
+ )} {shortcutKey && ( {shortcutKey} @@ -141,6 +149,12 @@ export const StreamCard = forwardRef(function S {particle.properties.name}
+ {hasActiveHuddle && ( + + + {huddleCount} + + )} {expiringSoon && ( )} diff --git a/js/src/features/particles/stream-view.tsx b/js/src/features/particles/stream-view.tsx index 60e59a6..0450868 100644 --- a/js/src/features/particles/stream-view.tsx +++ b/js/src/features/particles/stream-view.tsx @@ -1,6 +1,7 @@ import { useState, useEffect, useEffectEvent, useCallback } from "react"; import { useNavigate } from "react-router-dom"; import { useAuthStore } from "@/stores/auth-store"; +import { apiClient } from "@/api/client"; import type { Particle } from "@/api/types"; import { parseParticlePath, type ParticlePath } from "@/lib/particle-path"; import { ComposeOverlay } from "@/features/compose/compose-overlay"; @@ -19,6 +20,7 @@ import { WindowControls } from "@/components/window-controls"; import { RelativeTimestamp } from "@/components/relative-timestamp"; import { useStreamPlayback } from "@/hooks/use-stream-playback"; import { usePrefetchAdjacentMedia } from "@/hooks/use-prefetch-adjacent-media"; +import { getInitials } from "@/lib/utils"; function getParticleDisplayName(particle: Particle): string { switch (particle.type) { @@ -170,12 +172,19 @@ export function StreamView({ path, streamParticle }: StreamViewProps) { e.preventDefault(); navigate(`/${networkId}`); break; + case "h": { + e.preventDefault(); + apiClient.getLivekitToken(networkId, streamParticle.id).then(({ token, server_url }) => { + window.electronWindow.openHuddle({ token, serverUrl: server_url }); + }); + break; + } } } window.addEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown); }, - [composeActive, next, prev, navigate, networkId], + [composeActive, next, prev, navigate, networkId, streamParticle.id], ); // Click-to-navigate: left 30% = prev, right 70% = next @@ -204,7 +213,14 @@ export function StreamView({ path, streamParticle }: StreamViewProps) {

No particles in this stream yet

- + + + + H + {" "} + huddle + + - + + + + H + {" "} + huddle + +
); @@ -310,6 +330,16 @@ export function StreamView({ path, streamParticle }: StreamViewProps) { function TopBar({ networkId, particle, streamParticle }: { networkId: string; particle: Particle | null; streamParticle: Particle & { type: "stream" } }) { const navigate = useNavigate(); + const network = useNetwork(networkId); + + const huddleParticipants = streamParticle.huddle_active_participants ?? []; + const hasActiveHuddle = huddleParticipants.length > 0; + + const handleJoinHuddle = () => { + apiClient.getLivekitToken(networkId, streamParticle.id).then(({ token, server_url }) => { + window.electronWindow.openHuddle({ token, serverUrl: server_url }); + }); + }; return (
@@ -336,6 +366,37 @@ function TopBar({ networkId, particle, streamParticle }: { networkId: string; pa + {hasActiveHuddle && ( + + )} + - - -
-
- ); -} diff --git a/js/src/huddle_window/HuddleApp.tsx b/js/src/huddle_window/HuddleApp.tsx new file mode 100644 index 0000000..499d8b4 --- /dev/null +++ b/js/src/huddle_window/HuddleApp.tsx @@ -0,0 +1,208 @@ +import '@livekit/components-styles'; + +import { + CarouselLayout, + Chat, + ControlBar, + FocusLayout, + FocusLayoutContainer, + GridLayout, + LayoutContextProvider, + LiveKitRoom, + ParticipantTile, + RoomAudioRenderer, + StartAudio, + isTrackReference, + useCreateLayoutContext, + usePinnedTracks, + useRoomContext, + useTracks, + ScreenShareIcon, + ScreenShareStopIcon, +} from '@livekit/components-react'; +import { RoomEvent, Track } from 'livekit-client'; +import { useState, useEffect, useRef, useCallback } from 'react'; +import { ScreenPicker } from './ScreenPicker'; + +export function HuddleApp() { + const [connection, setConnection] = useState<{ token: string; serverUrl: string } | null>(null); + + useEffect(() => { + return window.electronHuddle.onConnect((data) => { + setConnection(data); + }); + }, []); + + const handleDisconnected = () => { + window.electronWindow.closeHuddle(); + }; + + if (!connection) { + return ( +
+

Connecting to huddle...

+
+ ); + } + + return ( + + + + ); +} + +function HuddleContent() { + const room = useRoomContext(); + const [showPicker, setShowPicker] = useState(false); + const [isSharing, setIsSharing] = useState(false); + const [widgetState, setWidgetState] = useState({ showChat: false, unreadMessages: 0 }); + + const tracks = useTracks( + [ + { source: Track.Source.Camera, withPlaceholder: true }, + { source: Track.Source.ScreenShare, withPlaceholder: false }, + ], + { updateOnlyOn: [RoomEvent.ActiveSpeakersChanged], onlySubscribed: false }, + ); + + const layoutContext = useCreateLayoutContext(); + const screenShareTracks = tracks + .filter(isTrackReference) + .filter((t) => t.publication.source === Track.Source.ScreenShare); + + const pinnedTracks = usePinnedTracks(layoutContext); + const focusTrack = pinnedTracks?.[0]; + const remainingTracks = tracks.filter( + (t) => + !focusTrack || + t.participant.identity !== focusTrack.participant.identity || + t.source !== focusTrack.source, + ); + + // Auto-pin/unpin screen share tracks (same logic as VideoConference) + const lastAutoPin = useRef<{ trackSid: string } | null>(null); + useEffect(() => { + if ( + screenShareTracks.some((t) => t.publication.isSubscribed) && + lastAutoPin.current === null + ) { + layoutContext.pin.dispatch?.({ msg: 'set_pin', trackReference: screenShareTracks[0] }); + lastAutoPin.current = { trackSid: screenShareTracks[0].publication.trackSid }; + } else if ( + lastAutoPin.current && + !screenShareTracks.some( + (t) => t.publication.trackSid === lastAutoPin.current?.trackSid, + ) + ) { + layoutContext.pin.dispatch?.({ msg: 'clear_pin' }); + lastAutoPin.current = null; + } + }, [ + screenShareTracks.map((t) => `${t.publication.trackSid}_${t.publication.isSubscribed}`).join(), + ]); + + // Sync isSharing state with actual track state + useEffect(() => { + const onLocalTrackUnpublished = () => { + const pub = room.localParticipant.getTrackPublication(Track.Source.ScreenShare); + if (!pub) setIsSharing(false); + }; + room.on(RoomEvent.LocalTrackUnpublished, onLocalTrackUnpublished); + return () => { + room.off(RoomEvent.LocalTrackUnpublished, onLocalTrackUnpublished); + }; + }, [room]); + + const handleScreenShare = useCallback( + async (sourceId: string) => { + setShowPicker(false); + try { + const stream = await navigator.mediaDevices.getUserMedia({ + audio: false, + video: { + mandatory: { + chromeMediaSource: 'desktop', + chromeMediaSourceId: sourceId, + }, + } as MediaTrackConstraints, + }); + const videoTrack = stream.getVideoTracks()[0]; + await room.localParticipant.publishTrack(videoTrack, { + source: Track.Source.ScreenShare, + }); + setIsSharing(true); + videoTrack.onended = () => stopScreenShare(); + } catch (err) { + console.error('Failed to start screen share:', err); + } + }, + [room], + ); + + const stopScreenShare = useCallback(async () => { + const pub = room.localParticipant.getTrackPublication(Track.Source.ScreenShare); + if (pub?.track) { + await room.localParticipant.unpublishTrack(pub.track.mediaStreamTrack); + pub.track.stop(); + } + setIsSharing(false); + }, [room]); + + return ( +
+ +
+ {focusTrack ? ( +
+ + + + + + +
+ ) : ( +
+ + + +
+ )} +
+ + +
+
+ +
+ + + {showPicker && ( + setShowPicker(false)} + /> + )} +
+ ); +} diff --git a/js/src/huddle_window/ScreenPicker.tsx b/js/src/huddle_window/ScreenPicker.tsx new file mode 100644 index 0000000..4cfea99 --- /dev/null +++ b/js/src/huddle_window/ScreenPicker.tsx @@ -0,0 +1,117 @@ +import { useState, useEffect } from 'react'; + +interface ScreenPickerProps { + onSelect: (sourceId: string) => void; + onCancel: () => void; +} + +export function ScreenPicker({ onSelect, onCancel }: ScreenPickerProps) { + const [sources, setSources] = useState([]); + const [selectedId, setSelectedId] = useState(null); + const [loading, setLoading] = useState(true); + + useEffect(() => { + window.electronHuddle.getScreenSources().then((result) => { + setSources(result); + setLoading(false); + }); + }, []); + + const screens = sources.filter((s) => s.id.startsWith('screen:')); + const windows = sources.filter((s) => s.id.startsWith('window:')); + + return ( +
+
+
+

Share your screen

+ +
+ +
+ {loading ? ( +

Loading sources…

+ ) : ( + <> + {screens.length > 0 && ( + + )} + {windows.length > 0 && ( + + )} + + )} +
+ +
+ + +
+
+
+ ); +} + +function SourceSection({ + title, + sources, + selectedId, + onSelect, +}: { + title: string; + sources: ScreenSource[]; + selectedId: string | null; + onSelect: (id: string) => void; +}) { + return ( +
+

{title}

+
+ {sources.map((source) => ( + + ))} +
+
+ ); +} diff --git a/js/src/huddle_window/renderer.tsx b/js/src/huddle_window/renderer.tsx index 49ee87c..771a288 100644 --- a/js/src/huddle_window/renderer.tsx +++ b/js/src/huddle_window/renderer.tsx @@ -1,5 +1,5 @@ import { createRoot } from 'react-dom/client'; -import { HuddleApp } from '@/huddle/HuddleApp'; +import { HuddleApp } from './HuddleApp'; import '@/styles/globals.css'; const root = createRoot(document.getElementById('root')!); diff --git a/js/src/lib/firestore-particles.ts b/js/src/lib/firestore-particles.ts index 9ec698d..10ebcbb 100644 --- a/js/src/lib/firestore-particles.ts +++ b/js/src/lib/firestore-particles.ts @@ -62,6 +62,7 @@ const particleConverter: FirestoreDataConverter = { ) : undefined, last_child_created_at: raw.last_child_created_at ? (raw.last_child_created_at as Timestamp).toDate() : undefined, + huddle_active_participants: raw.huddle_active_participants ?? undefined, }); case "folder": return ParticleSchema.parse({ diff --git a/js/src/main.ts b/js/src/main.ts index a513c3c..3886dae 100644 --- a/js/src/main.ts +++ b/js/src/main.ts @@ -1,4 +1,4 @@ -import { app, BrowserWindow, ipcMain, screen, session, shell } from 'electron'; +import { app, BrowserWindow, desktopCapturer, ipcMain, screen, session, shell } from 'electron'; import path from 'node:path'; import started from 'electron-squirrel-startup'; import { updateElectronApp, UpdateSourceType } from 'update-electron-app'; @@ -141,13 +141,34 @@ ipcMain.on('window:fullscreen', (event) => { }); // Secondary window IPC handlers -ipcMain.on('window:open-huddle', () => { +ipcMain.on('window:open-huddle', (_event, data: { token: string; serverUrl: string }) => { createHuddleWindow(); + // Send connection data once the huddle window is ready + huddleWindow?.webContents.once('did-finish-load', () => { + huddleWindow?.webContents.send('huddle:connect', data); + }); + // If already loaded, send immediately + if (!huddleWindow?.webContents.isLoading()) { + huddleWindow?.webContents.send('huddle:connect', data); + } }); ipcMain.on('window:close-huddle', () => { huddleWindow?.close(); }); +ipcMain.handle('screen:get-sources', async () => { + const sources = await desktopCapturer.getSources({ + types: ['screen', 'window'], + thumbnailSize: { width: 320, height: 180 }, + }); + return sources.map((source) => ({ + id: source.id, + name: source.name, + thumbnailDataUrl: source.thumbnail.toDataURL(), + appIconDataUrl: source.appIcon?.toDataURL() ?? null, + })); +}); + // Autoplay IPC handlers ipcMain.on('autoplay:play', (_event, payload) => { if (!autoplayWindow) createAutoplayWindow(); diff --git a/js/src/preload.ts b/js/src/preload.ts index 3eb5c94..28f9b72 100644 --- a/js/src/preload.ts +++ b/js/src/preload.ts @@ -7,10 +7,19 @@ contextBridge.exposeInMainWorld('electronWindow', { maximize: () => ipcRenderer.send('window:maximize'), fullscreen: () => ipcRenderer.send('window:fullscreen'), close: () => ipcRenderer.send('window:close'), - openHuddle: () => ipcRenderer.send('window:open-huddle'), + openHuddle: (data: { token: string; serverUrl: string }) => ipcRenderer.send('window:open-huddle', data), closeHuddle: () => ipcRenderer.send('window:close-huddle'), }); +contextBridge.exposeInMainWorld('electronHuddle', { + onConnect: (callback: (data: { token: string; serverUrl: string }) => void) => { + const handler = (_event: Electron.IpcRendererEvent, data: { token: string; serverUrl: string }) => callback(data); + ipcRenderer.on('huddle:connect', handler); + return () => { ipcRenderer.removeListener('huddle:connect', handler); }; + }, + getScreenSources: () => ipcRenderer.invoke('screen:get-sources'), +}); + contextBridge.exposeInMainWorld('electronAutoplay', { play: (payload: unknown) => ipcRenderer.send('autoplay:play', payload), dismiss: () => ipcRenderer.send('autoplay:dismiss'), diff --git a/js/yarn.lock b/js/yarn.lock index 9cc740c..8d756f1 100644 --- a/js/yarn.lock +++ b/js/yarn.lock @@ -273,6 +273,11 @@ "@babel/helper-string-parser" "^7.27.1" "@babel/helper-validator-identifier" "^7.28.5" +"@bufbuild/protobuf@^1.10.0": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@bufbuild/protobuf/-/protobuf-1.10.1.tgz#1d76d15290c0212076c15ede94d15157ba0c6344" + integrity sha512-wJ8ReQbHxsAfXhrf9ixl0aYbZorRuOWpBNzm8pL8ftmSxQx/wnJD5Eg861NwJU/czy2VXFIebCeZnZrI9rktIQ== + "@dotenvx/dotenvx@^1.48.4": version "1.52.0" resolved "https://registry.yarnpkg.com/@dotenvx/dotenvx/-/dotenvx-1.52.0.tgz#39cb1a70eead336171d9de4cc9de4aa23b709547" @@ -1262,6 +1267,13 @@ resolved "https://registry.yarnpkg.com/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.5.tgz#39cf5a600450cb42f1f0b507cc385459bf103b27" integrity sha512-+uGNN7rkfn41HLO0vekTFhTxk61eKa8mTpRGLO0QSqlQdKvIoGAvLp3ppdVIWbTGYJWM6Kp0iN+PjMIOcnVqTw== +"@floating-ui/core@^1.7.3": + version "1.7.5" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.7.5.tgz#d4af157a03330af5a60e69da7a4692507ada0622" + integrity sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ== + dependencies: + "@floating-ui/utils" "^0.2.11" + "@floating-ui/core@^1.7.4": version "1.7.4" resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.7.4.tgz#4a006a6e01565c0f87ba222c317b056a2cffd2f4" @@ -1269,6 +1281,14 @@ dependencies: "@floating-ui/utils" "^0.2.10" +"@floating-ui/dom@1.7.4": + version "1.7.4" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.7.4.tgz#ee667549998745c9c3e3e84683b909c31d6c9a77" + integrity sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA== + dependencies: + "@floating-ui/core" "^1.7.3" + "@floating-ui/utils" "^0.2.10" + "@floating-ui/dom@^1.7.5": version "1.7.5" resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.7.5.tgz#60bfc83a4d1275b2a90db76bf42ca2a5f2c231c2" @@ -1289,6 +1309,11 @@ resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.10.tgz#a2a1e3812d14525f725d011a73eceb41fef5bc1c" integrity sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ== +"@floating-ui/utils@^0.2.11": + version "0.2.11" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.11.tgz#a269e055e40e2f45873bae9d1a2fdccbd314ea3f" + integrity sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg== + "@gar/promisify@^1.1.3": version "1.1.3" resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" @@ -1601,6 +1626,43 @@ dependencies: "@inquirer/type" "^1.5.5" +"@livekit/components-core@0.12.13": + version "0.12.13" + resolved "https://registry.yarnpkg.com/@livekit/components-core/-/components-core-0.12.13.tgz#83d935719453c6831086daffebfc434137ea6497" + integrity sha512-DQmi84afHoHjZ62wm8y+XPNIDHTwFHAltjd3lmyXj8UZHOY7wcza4vFt1xnghJOD5wLRY58L1dkAgAw59MgWvw== + dependencies: + "@floating-ui/dom" "1.7.4" + loglevel "1.9.1" + rxjs "7.8.2" + +"@livekit/components-react@^2.9.20": + version "2.9.20" + resolved "https://registry.yarnpkg.com/@livekit/components-react/-/components-react-2.9.20.tgz#d01ecff4ed2440f2443894bd709accb3086cb1a9" + integrity sha512-hjkYOsJj9Jbghb7wM5cI8HoVisKeL6Zcy1VnRWTLm0sqVbto8GJp/17T4Udx85mCPY6Jgh8I1Cv0yVzgz7CQtg== + dependencies: + "@livekit/components-core" "0.12.13" + clsx "2.1.1" + events "^3.3.0" + jose "^6.0.12" + usehooks-ts "3.1.1" + +"@livekit/components-styles@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@livekit/components-styles/-/components-styles-1.2.0.tgz#eaff70405910a428ad580dc19910fa97b5019fef" + integrity sha512-74/rt0lDh6aHmOPmWAeDE9C4OrNW9RIdmhX/YRbovQBVNGNVWojRjl3FgQZ5LPFXO6l1maKB4JhXcBFENVxVvw== + +"@livekit/mutex@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@livekit/mutex/-/mutex-1.1.1.tgz#72492b611d55be8130ba2271b7a436d94b1bc6d4" + integrity sha512-EsshAucklmpuUAfkABPxJNhzj9v2sG7JuzFDL4ML1oJQSV14sqrpTYnsaOudMAw9yOaW53NU3QQTlUQoRs4czw== + +"@livekit/protocol@1.44.0": + version "1.44.0" + resolved "https://registry.yarnpkg.com/@livekit/protocol/-/protocol-1.44.0.tgz#f94a34690dc7dcf1a808f0095f2e480c471747d9" + integrity sha512-/vfhDUGcUKO8Q43r6i+5FrDhl5oZjm/X3U4x2Iciqvgn5C8qbj+57YPcWSJ1kyIZm5Cm6AV2nAPjMm3ETD/iyg== + dependencies: + "@bufbuild/protobuf" "^1.10.0" + "@malept/cross-spawn-promise@^1.0.0": version "1.1.1" resolved "https://registry.yarnpkg.com/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz#504af200af6b98e198bce768bc1730c6936ae01d" @@ -3850,7 +3912,7 @@ clone@^1.0.2: resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== -clsx@^2.1.1: +clsx@2.1.1, clsx@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== @@ -4719,7 +4781,7 @@ eventemitter3@^5.0.1: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.4.tgz#a86d66170433712dde814707ac52b5271ceb1feb" integrity sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw== -events@^3.2.0: +events@^3.2.0, events@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== @@ -6070,6 +6132,11 @@ jiti@^2.4.2, jiti@^2.6.1: resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.6.1.tgz#178ef2fc9a1a594248c20627cd820187a4d78d92" integrity sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ== +jose@^6.0.12, jose@^6.1.0: + version "6.2.2" + resolved "https://registry.yarnpkg.com/jose/-/jose-6.2.2.tgz#d6b5279b89b3e88d531c202e3fbe351f39a44aac" + integrity sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ== + jose@^6.1.3: version "6.1.3" resolved "https://registry.yarnpkg.com/jose/-/jose-6.1.3.tgz#8453d7be88af7bb7d64a0481d6a35a0145ba3ea5" @@ -6300,6 +6367,21 @@ listr2@^7.0.2: rfdc "^1.3.0" wrap-ansi "^8.1.0" +livekit-client@^2.18.0: + version "2.18.0" + resolved "https://registry.yarnpkg.com/livekit-client/-/livekit-client-2.18.0.tgz#7c9793ba70a55ebf664146f3a448c05652193365" + integrity sha512-wjH4y0rw5fnkPmmaxutPhD4XcAq6goQszS8lw9PEpGXVwiRE6sI/ZH+mOT/s8AHJnEC3tjmfiMZ4MQt8BlaWew== + dependencies: + "@livekit/mutex" "1.1.1" + "@livekit/protocol" "1.44.0" + events "^3.3.0" + jose "^6.1.0" + loglevel "^1.9.2" + sdp-transform "^2.15.0" + tslib "2.8.1" + typed-emitter "^2.1.0" + webrtc-adapter "^9.0.1" + load-json-file@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" @@ -6335,6 +6417,11 @@ lodash.camelcase@^4.3.0: resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== + lodash.get@^4.0.0: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" @@ -6377,6 +6464,16 @@ log-update@^5.0.1: strip-ansi "^7.0.1" wrap-ansi "^8.0.1" +loglevel@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.9.1.tgz#d63976ac9bcd03c7c873116d41c2a85bafff1be7" + integrity sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg== + +loglevel@^1.9.2: + version "1.9.2" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.9.2.tgz#c2e028d6c757720107df4e64508530db6621ba08" + integrity sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg== + long@^5.0.0: version "5.3.2" resolved "https://registry.yarnpkg.com/long/-/long-5.3.2.tgz#1d84463095999262d7d7b7f8bfd4a8cc55167f83" @@ -7737,6 +7834,13 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +rxjs@7.8.2, rxjs@^7.5.2: + version "7.8.2" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.2.tgz#955bc473ed8af11a002a2be52071bf475638607b" + integrity sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA== + dependencies: + tslib "^2.1.0" + safe-array-concat@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.3.tgz#c9e54ec4f603b0bbb8e7e5007a5ee7aecd1538c3" @@ -7790,6 +7894,16 @@ schema-utils@^4.3.0, schema-utils@^4.3.3: ajv-formats "^2.1.1" ajv-keywords "^5.1.0" +sdp-transform@^2.15.0: + version "2.15.0" + resolved "https://registry.yarnpkg.com/sdp-transform/-/sdp-transform-2.15.0.tgz#79d37a2481916f36a0534e07b32ceaa87f71df42" + integrity sha512-KrOH82c/W+GYQ0LHqtr3caRpM3ITglq3ljGUIb8LTki7ByacJZ9z+piSGiwZDsRyhQbYBOBJgr2k6X4BZXi3Kw== + +sdp@^3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/sdp/-/sdp-3.2.1.tgz#a2f79eecd7c5adb90d54e1bc9812775d80f3c06c" + integrity sha512-lwsAIzOPlH8/7IIjjz3K0zYBk7aBVVcvjMwt3M4fLxpjMYyy7i3I97SLHebgn4YBjirkzfp3RvRDWSKsh/+WFw== + semver-compare@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" @@ -8494,16 +8608,16 @@ tsconfig-paths@^4.2.0: minimist "^1.2.6" strip-bom "^3.0.0" +tslib@2.8.1, tslib@^2.0.0, tslib@^2.0.1, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + tslib@^1.8.1: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.0, tslib@^2.0.1, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.8.1: - version "2.8.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" - integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== - tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" @@ -8604,6 +8718,13 @@ typed-array-length@^1.0.7: possible-typed-array-names "^1.0.0" reflect.getprototypeof "^1.0.6" +typed-emitter@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/typed-emitter/-/typed-emitter-2.1.0.tgz#ca78e3d8ef1476f228f548d62e04e3d4d3fd77fb" + integrity sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA== + optionalDependencies: + rxjs "^7.5.2" + typescript@^5.9.3: version "5.9.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f" @@ -8721,6 +8842,13 @@ use-sync-external-store@^1.5.0: resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz#b174bfa65cb2b526732d9f2ac0a408027876f32d" integrity sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w== +usehooks-ts@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/usehooks-ts/-/usehooks-ts-3.1.1.tgz#0bb7f38f36f8219ee4509cc5e944ae610fb97656" + integrity sha512-I4diPp9Cq6ieSUH2wu+fDAVQO43xwtulo+fKEidHUwZPnYImbtkTjzIJYcDcJqxgmX31GVqNFURodvcgHcW0pA== + dependencies: + lodash.debounce "^4.0.8" + username@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/username/-/username-5.1.0.tgz#a7f9325adce2d0166448cdd55d4985b1360f2508" @@ -8839,6 +8967,13 @@ webpack@^5.69.1: watchpack "^2.5.1" webpack-sources "^3.3.3" +webrtc-adapter@^9.0.1: + version "9.0.4" + resolved "https://registry.yarnpkg.com/webrtc-adapter/-/webrtc-adapter-9.0.4.tgz#8456a5388e4947093611332e09337dedd28b1522" + integrity sha512-5ZZY1+lGq8LEKuDlg9M2RPJHlH3R7OVwyHqMcUsLKCgd9Wvf+QrFTCItkXXYPmrJn8H6gRLXbSgxLLdexiqHxw== + dependencies: + sdp "^3.2.0" + websocket-driver@>=0.5.1: version "0.7.4" resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760"