├── adapter ├── .gitignore ├── src │ ├── index.ts │ ├── client.ts │ ├── services │ │ └── docker.ts │ └── message │ │ └── index.ts ├── package.json ├── tsconfig.json └── pnpm-lock.yaml └── balancer ├── internal ├── utils │ └── result.go ├── message │ └── new.go └── services │ ├── new.go │ ├── proxy.go │ └── balance.go ├── cmd └── main.go ├── go.mod └── go.sum /adapter/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | node_modules -------------------------------------------------------------------------------- /balancer/internal/utils/result.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "encoding/json" 4 | 5 | type Message struct { 6 | M string `json:"message"` 7 | } 8 | 9 | func Success() ([]byte, error) { 10 | result, err := json.Marshal(Message{ 11 | M: "success", 12 | }) 13 | if err != nil { 14 | return []byte{}, err 15 | } 16 | 17 | return result, nil 18 | } 19 | 20 | func Error(err error) []byte { 21 | result, _ := json.Marshal(Message{ 22 | M: err.Error(), 23 | }) 24 | 25 | return result 26 | } 27 | -------------------------------------------------------------------------------- /adapter/src/index.ts: -------------------------------------------------------------------------------- 1 | import NatsMessage from "./message"; 2 | import { DockerAdapter } from "./services/docker"; 3 | 4 | async function main() { 5 | const docker = new DockerAdapter(); 6 | const nc = new NatsMessage(); 7 | await nc.connect("nats://localhost:4222"); 8 | 9 | nc.addSub( 10 | "adapter:docker:create-container", 11 | nc.errorHandler(docker.createContainer), 12 | ); 13 | nc.addSub( 14 | "adapter:docker:run-container", 15 | nc.errorHandler(docker.runContainer), 16 | ); 17 | } 18 | 19 | main(); 20 | -------------------------------------------------------------------------------- /balancer/cmd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "balancer/internal/message" 5 | "balancer/internal/services" 6 | ) 7 | 8 | func main() { 9 | service := services.New() 10 | msg := message.New("nats://localhost:4222/") 11 | 12 | msg.AddSubs("balancer:launch:http", service.LaunchHttp) 13 | msg.AddSubs("balancer:launch:https", service.LaunchHttps) 14 | msg.AddSubs("balancer:add:domain", service.AddApp) 15 | msg.AddSubs("balancer:remove:app", service.RemoveApp) 16 | msg.AddSubs("balancer:change:container", service.ChangeContainer) 17 | 18 | select {} 19 | } 20 | -------------------------------------------------------------------------------- /adapter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "platform", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "dev": "tsx src/index.ts", 9 | "client": "tsx src/client.ts" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "dockerode": "^4.0.2", 16 | "nats": "^2.28.2", 17 | "tsx": "^4.19.0", 18 | "zod": "^3.23.8" 19 | }, 20 | "devDependencies": { 21 | "@types/dockerode": "^3.3.31", 22 | "typescript": "^5.5.4" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /adapter/src/client.ts: -------------------------------------------------------------------------------- 1 | import NatsMessage from "./message"; 2 | 3 | // only for clearfy how nats server works and test the methods, dont use in prod 4 | async function main() { 5 | const nc = new NatsMessage(); 6 | 7 | await nc.connect("nats://localhost:4222"); 8 | 9 | const id = await nc.request( 10 | "adapter:docker:create-container", 11 | JSON.stringify({ 12 | image_name: "redis", 13 | container_name: "myredis", 14 | }), 15 | ); 16 | 17 | nc.publish( 18 | "adapter:docker:run-container", 19 | JSON.stringify({ 20 | id: id, 21 | }), 22 | ); 23 | } 24 | 25 | main(); 26 | -------------------------------------------------------------------------------- /balancer/internal/message/new.go: -------------------------------------------------------------------------------- 1 | package message 2 | 3 | import ( 4 | "balancer/internal/utils" 5 | "log" 6 | 7 | "github.com/nats-io/nats.go" 8 | ) 9 | 10 | type Message struct { 11 | client *nats.Conn 12 | } 13 | 14 | func New(addr string) *Message { 15 | nc, err := nats.Connect(addr) 16 | if err != nil { 17 | log.Fatalln("failed to connect NATS") 18 | } 19 | return &Message{ 20 | client: nc, 21 | } 22 | } 23 | 24 | // Adds new subscriber to NATS server 25 | func (m *Message) AddSubs(topic string, callback func(data []byte) ([]byte, error)) { 26 | m.client.Subscribe(topic, func(msg *nats.Msg) { 27 | answer, err := callback(msg.Data) 28 | if err != nil { 29 | msg.Respond(utils.Error(err)) 30 | return 31 | } 32 | msg.Respond(answer) 33 | }) 34 | } 35 | -------------------------------------------------------------------------------- /balancer/go.mod: -------------------------------------------------------------------------------- 1 | module balancer 2 | 3 | go 1.22.1 4 | 5 | require ( 6 | github.com/caddyserver/certmagic v0.21.3 // indirect 7 | github.com/caddyserver/zerossl v0.1.3 // indirect 8 | github.com/gorilla/mux v1.8.1 // indirect 9 | github.com/gorilla/websocket v1.5.3 // indirect 10 | github.com/klauspost/compress v1.17.2 // indirect 11 | github.com/klauspost/cpuid/v2 v2.2.7 // indirect 12 | github.com/libdns/libdns v0.2.2 // indirect 13 | github.com/mholt/acmez/v2 v2.0.1 // indirect 14 | github.com/miekg/dns v1.1.59 // indirect 15 | github.com/nats-io/nats.go v1.37.0 // indirect 16 | github.com/nats-io/nkeys v0.4.7 // indirect 17 | github.com/nats-io/nuid v1.0.1 // indirect 18 | github.com/zeebo/blake3 v0.2.3 // indirect 19 | go.uber.org/multierr v1.11.0 // indirect 20 | go.uber.org/zap v1.27.0 // indirect 21 | golang.org/x/crypto v0.23.0 // indirect 22 | golang.org/x/mod v0.17.0 // indirect 23 | golang.org/x/net v0.25.0 // indirect 24 | golang.org/x/sync v0.7.0 // indirect 25 | golang.org/x/sys v0.20.0 // indirect 26 | golang.org/x/text v0.15.0 // indirect 27 | golang.org/x/tools v0.21.0 // indirect 28 | ) 29 | -------------------------------------------------------------------------------- /adapter/src/services/docker.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import DockerSDK from "dockerode"; 3 | 4 | // DockerAdapter provides api to docker sdk 5 | export class DockerAdapter { 6 | private client: DockerSDK; 7 | constructor() { 8 | this.client = new DockerSDK(); 9 | } 10 | 11 | // creates new container with existing image, be sure that image is pulled. It returns id of container 12 | createContainer = async (data: string) => { 13 | const info = CreateContainerSchema.parse(JSON.parse(data)); 14 | const container = await this.client.createContainer({ 15 | Image: info.image_name, 16 | name: info.container_name, 17 | }); 18 | return container.id; 19 | }; 20 | 21 | // Runs container with id 22 | runContainer = async (data: string) => { 23 | const info = RunContainerSchema.parse(JSON.parse(data)); 24 | const container = this.client.getContainer(info.id); 25 | container.start(); 26 | }; 27 | } 28 | export const RunContainerSchema = z.object({ 29 | id: z.string(), 30 | }); 31 | export const CreateContainerSchema = z.object({ 32 | image_name: z.string(), 33 | container_name: z.string(), 34 | }); 35 | -------------------------------------------------------------------------------- /balancer/internal/services/new.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import ( 4 | "balancer/internal/utils" 5 | "encoding/json" 6 | "log" 7 | "net/http" 8 | "sync" 9 | 10 | "github.com/caddyserver/certmagic" 11 | "github.com/gorilla/mux" 12 | ) 13 | 14 | type AppType struct { 15 | Port string `json:"port"` 16 | Path string `json:"path"` 17 | ContainerName string `json:"container_name"` 18 | } 19 | 20 | type DomainType struct { 21 | Domain string `json:"domain"` 22 | Apps []AppType `json:"apps"` 23 | } 24 | 25 | type Service struct { 26 | mu *sync.RWMutex 27 | isProxyLaunched bool 28 | domains []DomainType 29 | } 30 | 31 | func New() *Service { 32 | return &Service{ 33 | mu: new(sync.RWMutex), 34 | isProxyLaunched: false, 35 | domains: []DomainType{}, 36 | } 37 | } 38 | 39 | type LaunchData struct { 40 | Email string `json:"email"` 41 | Domain string `json:"domain"` 42 | } 43 | 44 | func (s *Service) LaunchHttp(data []byte) ([]byte, error) { 45 | // Routers 46 | router := mux.NewRouter() 47 | router.PathPrefix("/").HandlerFunc(s.Proxy) 48 | server := &http.Server{ 49 | Addr: ":80", 50 | Handler: router, 51 | } 52 | 53 | // Serve listener 54 | go log.Fatal(server.ListenAndServe()) 55 | 56 | return utils.Success() 57 | } 58 | 59 | func (s *Service) LaunchHttps(data []byte) ([]byte, error) { 60 | var body LaunchData 61 | err := json.Unmarshal(data, &body) 62 | if err != nil { 63 | return []byte{}, err 64 | } 65 | // Configure CertMagic 66 | certmagic.DefaultACME.AltHTTPPort = -1 67 | certmagic.DefaultACME.DisableHTTPChallenge = true 68 | certmagic.DefaultACME.Email = body.Email 69 | certmagic.Default.Storage = &certmagic.FileStorage{Path: "/certs/storage"} 70 | domains := []string{body.Domain} 71 | 72 | // Start server 73 | router := mux.NewRouter() 74 | router.PathPrefix("/").HandlerFunc(s.Proxy) 75 | go log.Fatal(certmagic.HTTPS(domains, router)) 76 | 77 | return utils.Success() 78 | } 79 | -------------------------------------------------------------------------------- /adapter/src/message/index.ts: -------------------------------------------------------------------------------- 1 | import { connect, NatsConnection, StringCodec, Codec, NatsError } from "nats"; 2 | 3 | export default class NatsMessage { 4 | private _nc: NatsConnection | null = null; 5 | private _decoder: Codec; 6 | 7 | constructor() { 8 | this._decoder = StringCodec(); 9 | } 10 | 11 | // connect creates new connection to nats server 12 | connect = async (addr: string) => { 13 | try { 14 | this._nc = await connect({ servers: addr }); 15 | console.log("Connected to NATS"); 16 | } catch (error) { 17 | console.error("Failed to connect to NATS:", error); 18 | throw error; 19 | } 20 | }; 21 | 22 | // addsub adds new subscriber to the topic, callback can return data to response or null 23 | addSub( 24 | topic: string, 25 | callback: (err: NatsError | null, msg: string) => Promise 26 | ) { 27 | if (!this._nc) { 28 | throw new Error("Not connected to NATS"); 29 | } 30 | 31 | this._nc.subscribe(topic, { 32 | callback: (err, msg) => { 33 | callback(err, msg.json()).then((value) => { 34 | if (value === undefined) return; 35 | msg.respond(value); 36 | }); 37 | }, 38 | }); 39 | } 40 | 41 | // publish pushs new message to the topic 42 | publish(topic: string, data: any) { 43 | if (!this._nc) { 44 | throw new Error("Not connected to NATS"); 45 | } 46 | 47 | const encodedData = this._decoder.encode(JSON.stringify(data)); 48 | this._nc.publish(topic, encodedData); 49 | } 50 | 51 | close = async (): Promise => { 52 | if (this._nc) { 53 | await this._nc.close(); 54 | console.log("NATS connection closed"); 55 | } 56 | }; 57 | 58 | request = async (topic: string, data: any) => { 59 | if (!this._nc) { 60 | throw new Error("Not connected to NATS"); 61 | } 62 | const reply = await this._nc.request(topic, JSON.stringify(data)); 63 | return this._decoder.decode(reply.data); 64 | }; 65 | 66 | errorHandler(cb: (message: string) => Promise) { 67 | return async ( 68 | err: NatsError | null, 69 | msg: string 70 | ): Promise => { 71 | if (err !== null) { 72 | this.publish("adapter:error", err); 73 | } else { 74 | return cb(msg); 75 | } 76 | }; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /balancer/internal/services/proxy.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import ( 4 | "io" 5 | "net/http" 6 | "net/url" 7 | 8 | "github.com/gorilla/websocket" 9 | ) 10 | 11 | // Defines who should process the request 12 | func (s *Service) Proxy(w http.ResponseWriter, r *http.Request) { 13 | if websocket.IsWebSocketUpgrade(r) { 14 | s.wsProxy(w, r) 15 | } else { 16 | s.httpProxy(w, r) 17 | } 18 | } 19 | 20 | // Http proxy handler 21 | func (s *Service) httpProxy(w http.ResponseWriter, r *http.Request) { 22 | proxyUrl, err := s.getServiceUrl(r.Host, r.URL.Path) 23 | if err != nil { 24 | w.WriteHeader(http.StatusInternalServerError) 25 | w.Write([]byte(err.Error())) 26 | return 27 | } 28 | parsed, err := url.Parse(proxyUrl) 29 | if err != nil { 30 | w.WriteHeader(http.StatusInternalServerError) 31 | w.Write([]byte(err.Error())) 32 | return 33 | } 34 | r.URL.Scheme = parsed.Scheme 35 | r.URL.Host = parsed.Host 36 | 37 | proxy := &http.Transport{ 38 | Proxy: http.ProxyURL(parsed), 39 | } 40 | proxyReq, err := proxy.RoundTrip(r) 41 | if err != nil { 42 | http.Error(w, "Bad Gateway", http.StatusBadGateway) 43 | return 44 | } 45 | defer proxyReq.Body.Close() 46 | 47 | copyHeader(w.Header(), proxyReq.Header) 48 | w.WriteHeader(proxyReq.StatusCode) 49 | io.Copy(w, proxyReq.Body) 50 | } 51 | 52 | // Websockets proxy handler 53 | func (s *Service) wsProxy(w http.ResponseWriter, r *http.Request) { 54 | proxyUrl, err := s.getServiceUrl(r.Host, r.URL.Path) 55 | if err != nil { 56 | w.WriteHeader(http.StatusInternalServerError) 57 | w.Write([]byte(err.Error())) 58 | return 59 | } 60 | u := url.URL{Scheme: "ws", Host: proxyUrl[7:], Path: r.URL.Path} 61 | 62 | connBackend, _, err := websocket.DefaultDialer.Dial(u.String(), nil) 63 | if err != nil { 64 | http.Error(w, "Could not connect to backend", http.StatusInternalServerError) 65 | return 66 | } 67 | defer connBackend.Close() 68 | 69 | upgrader := websocket.Upgrader{} 70 | connClient, err := upgrader.Upgrade(w, r, nil) 71 | if err != nil { 72 | return 73 | } 74 | defer connClient.Close() 75 | 76 | go func() { 77 | for { 78 | _, msg, err := connBackend.ReadMessage() 79 | if err != nil { 80 | return 81 | } 82 | connClient.WriteMessage(websocket.TextMessage, msg) 83 | } 84 | }() 85 | 86 | for { 87 | _, msg, err := connClient.ReadMessage() 88 | if err != nil { 89 | return 90 | } 91 | connBackend.WriteMessage(websocket.TextMessage, msg) 92 | } 93 | } 94 | 95 | // Copyes headers to new response 96 | func copyHeader(dst, src http.Header) { 97 | for k, vv := range src { 98 | for _, v := range vv { 99 | dst.Add(k, v) 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /balancer/internal/services/balance.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import ( 4 | "balancer/internal/utils" 5 | "encoding/json" 6 | "errors" 7 | "strings" 8 | ) 9 | 10 | type AddAppBody struct { 11 | Domain string `json:"domain"` 12 | Container string `json:"container"` 13 | Port string `json:"port"` 14 | Path string `json:"path"` 15 | } 16 | 17 | func (s *Service) AddApp(data []byte) ([]byte, error) { 18 | // Json body 19 | var body AddAppBody 20 | err := json.Unmarshal(data, &body) 21 | if err != nil { 22 | return []byte{}, err 23 | } 24 | 25 | s.mu.Lock() 26 | defer s.mu.Unlock() 27 | 28 | // If there is already domain in system 29 | for i, dom := range s.domains { 30 | if dom.Domain == body.Domain { 31 | s.domains[i].Apps = append(s.domains[i].Apps, AppType{ 32 | Port: body.Port, 33 | Path: body.Path, 34 | ContainerName: body.Container, 35 | }) 36 | return utils.Success() 37 | } 38 | } 39 | 40 | // if there isnt domain, we will add new domain 41 | s.domains = append(s.domains, DomainType{ 42 | Domain: body.Domain, 43 | Apps: []AppType{ 44 | { 45 | Port: body.Port, 46 | Path: body.Path, 47 | ContainerName: body.Container, 48 | }, 49 | }, 50 | }) 51 | 52 | return utils.Success() 53 | } 54 | 55 | type ChangeContainerBody struct { 56 | Original string `json:"original_name"` 57 | New string `json:"new_name"` 58 | } 59 | 60 | func (s *Service) ChangeContainer(data []byte) ([]byte, error) { 61 | // Body 62 | var body ChangeContainerBody 63 | err := json.Unmarshal(data, &body) 64 | if err != nil { 65 | return []byte{}, err 66 | } 67 | 68 | // Change container name 69 | for i, v := range s.domains { 70 | for j, a := range v.Apps { 71 | if body.Original == a.ContainerName { 72 | s.domains[i].Apps[j].ContainerName = body.New 73 | } 74 | } 75 | } 76 | 77 | return utils.Success() 78 | } 79 | 80 | type RemoveAppBody struct { 81 | Domain string `json:"domain"` 82 | Container string `json:"container"` 83 | } 84 | 85 | func (s *Service) RemoveApp(data []byte) ([]byte, error) { 86 | // body 87 | var body RemoveAppBody 88 | err := json.Unmarshal(data, &body) 89 | if err != nil { 90 | return []byte{}, err 91 | } 92 | 93 | // Create new array with only not deleted apps 94 | apps := make([]AppType, 0) 95 | for i, v := range s.domains { 96 | if body.Domain == v.Domain { 97 | for _, a := range v.Apps { 98 | if body.Container != a.ContainerName { 99 | apps = append(apps, a) 100 | } 101 | } 102 | 103 | s.domains[i].Apps = apps 104 | } 105 | 106 | } 107 | return utils.Success() 108 | } 109 | 110 | // Returns an url to service in docker network by domain name and path 111 | func (s *Service) getServiceUrl(host string, path string) (string, error) { 112 | s.mu.RLock() 113 | defer s.mu.RUnlock() 114 | var matchedApp *AppType 115 | var longestMatch int 116 | for _, dom := range s.domains { 117 | if dom.Domain == host { 118 | for _, app := range dom.Apps { 119 | if strings.HasPrefix(path, app.Path) { 120 | if len(app.Path) > longestMatch { 121 | longestMatch = len(app.Path) 122 | matchedApp = &app 123 | } 124 | } 125 | } 126 | } 127 | } 128 | 129 | if matchedApp == nil { 130 | return "", errors.New("not found") 131 | } 132 | return "http://" + matchedApp.ContainerName + ":" + matchedApp.Port, nil 133 | } 134 | -------------------------------------------------------------------------------- /balancer/go.sum: -------------------------------------------------------------------------------- 1 | github.com/caddyserver/certmagic v0.21.3 h1:pqRRry3yuB4CWBVq9+cUqu+Y6E2z8TswbhNx1AZeYm0= 2 | github.com/caddyserver/certmagic v0.21.3/go.mod h1:Zq6pklO9nVRl3DIFUw9gVUfXKdpc/0qwTUAQMBlfgtI= 3 | github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA= 4 | github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4= 5 | github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= 6 | github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= 7 | github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= 8 | github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 9 | github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= 10 | github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= 11 | github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= 12 | github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= 13 | github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= 14 | github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s= 15 | github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= 16 | github.com/mholt/acmez/v2 v2.0.1 h1:3/3N0u1pLjMK4sNEAFSI+bcvzbPhRpY383sy1kLHJ6k= 17 | github.com/mholt/acmez/v2 v2.0.1/go.mod h1:fX4c9r5jYwMyMsC+7tkYRxHibkOTgta5DIFGoe67e1U= 18 | github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs= 19 | github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk= 20 | github.com/nats-io/nats.go v1.37.0 h1:07rauXbVnnJvv1gfIyghFEo6lUcYRY0WXc3x7x0vUxE= 21 | github.com/nats-io/nats.go v1.37.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= 22 | github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= 23 | github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= 24 | github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= 25 | github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= 26 | github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= 27 | github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg= 28 | github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ= 29 | github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= 30 | go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= 31 | go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= 32 | go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= 33 | go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= 34 | golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= 35 | golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= 36 | golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= 37 | golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= 38 | golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= 39 | golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 40 | golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= 41 | golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= 42 | golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= 43 | golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 44 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 45 | golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= 46 | golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 47 | golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= 48 | golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 49 | golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= 50 | golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 51 | golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= 52 | golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= 53 | -------------------------------------------------------------------------------- /adapter/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 26 | 27 | /* Modules */ 28 | "module": "commonjs", /* Specify what module code is generated. */ 29 | // "rootDir": "./", /* Specify the root folder within your source files. */ 30 | // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ 31 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 35 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 36 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 37 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 38 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ 39 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ 40 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ 41 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ 42 | // "resolveJsonModule": true, /* Enable importing .json files. */ 43 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ 44 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 45 | 46 | /* JavaScript Support */ 47 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 48 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 49 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 50 | 51 | /* Emit */ 52 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 53 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 54 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 55 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 56 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 57 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 58 | // "outDir": "./", /* Specify an output folder for all emitted files. */ 59 | // "removeComments": true, /* Disable emitting comments. */ 60 | // "noEmit": true, /* Disable emitting files from a compilation. */ 61 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 62 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 63 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 64 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 65 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 66 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 67 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 68 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 69 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 70 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 71 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 72 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 73 | 74 | /* Interop Constraints */ 75 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 76 | // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ 77 | // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ 78 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 79 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 80 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 81 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 82 | 83 | /* Type Checking */ 84 | "strict": true, /* Enable all strict type-checking options. */ 85 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 86 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 87 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 88 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 89 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 90 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 91 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 92 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 93 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 94 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 95 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 96 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 97 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 98 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 99 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 100 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 101 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 102 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 103 | 104 | /* Completeness */ 105 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 106 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /adapter/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | dockerode: 9 | specifier: ^4.0.2 10 | version: 4.0.2 11 | nats: 12 | specifier: ^2.28.2 13 | version: 2.28.2 14 | tsx: 15 | specifier: ^4.19.0 16 | version: 4.19.0 17 | zod: 18 | specifier: ^3.23.8 19 | version: 3.23.8 20 | 21 | devDependencies: 22 | '@types/dockerode': 23 | specifier: ^3.3.31 24 | version: 3.3.31 25 | typescript: 26 | specifier: ^5.5.4 27 | version: 5.5.4 28 | 29 | packages: 30 | 31 | /@balena/dockerignore@1.0.2: 32 | resolution: {integrity: sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==} 33 | dev: false 34 | 35 | /@esbuild/aix-ppc64@0.23.1: 36 | resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} 37 | engines: {node: '>=18'} 38 | cpu: [ppc64] 39 | os: [aix] 40 | requiresBuild: true 41 | dev: false 42 | optional: true 43 | 44 | /@esbuild/android-arm64@0.23.1: 45 | resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} 46 | engines: {node: '>=18'} 47 | cpu: [arm64] 48 | os: [android] 49 | requiresBuild: true 50 | dev: false 51 | optional: true 52 | 53 | /@esbuild/android-arm@0.23.1: 54 | resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} 55 | engines: {node: '>=18'} 56 | cpu: [arm] 57 | os: [android] 58 | requiresBuild: true 59 | dev: false 60 | optional: true 61 | 62 | /@esbuild/android-x64@0.23.1: 63 | resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} 64 | engines: {node: '>=18'} 65 | cpu: [x64] 66 | os: [android] 67 | requiresBuild: true 68 | dev: false 69 | optional: true 70 | 71 | /@esbuild/darwin-arm64@0.23.1: 72 | resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} 73 | engines: {node: '>=18'} 74 | cpu: [arm64] 75 | os: [darwin] 76 | requiresBuild: true 77 | dev: false 78 | optional: true 79 | 80 | /@esbuild/darwin-x64@0.23.1: 81 | resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} 82 | engines: {node: '>=18'} 83 | cpu: [x64] 84 | os: [darwin] 85 | requiresBuild: true 86 | dev: false 87 | optional: true 88 | 89 | /@esbuild/freebsd-arm64@0.23.1: 90 | resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} 91 | engines: {node: '>=18'} 92 | cpu: [arm64] 93 | os: [freebsd] 94 | requiresBuild: true 95 | dev: false 96 | optional: true 97 | 98 | /@esbuild/freebsd-x64@0.23.1: 99 | resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} 100 | engines: {node: '>=18'} 101 | cpu: [x64] 102 | os: [freebsd] 103 | requiresBuild: true 104 | dev: false 105 | optional: true 106 | 107 | /@esbuild/linux-arm64@0.23.1: 108 | resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} 109 | engines: {node: '>=18'} 110 | cpu: [arm64] 111 | os: [linux] 112 | requiresBuild: true 113 | dev: false 114 | optional: true 115 | 116 | /@esbuild/linux-arm@0.23.1: 117 | resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} 118 | engines: {node: '>=18'} 119 | cpu: [arm] 120 | os: [linux] 121 | requiresBuild: true 122 | dev: false 123 | optional: true 124 | 125 | /@esbuild/linux-ia32@0.23.1: 126 | resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} 127 | engines: {node: '>=18'} 128 | cpu: [ia32] 129 | os: [linux] 130 | requiresBuild: true 131 | dev: false 132 | optional: true 133 | 134 | /@esbuild/linux-loong64@0.23.1: 135 | resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} 136 | engines: {node: '>=18'} 137 | cpu: [loong64] 138 | os: [linux] 139 | requiresBuild: true 140 | dev: false 141 | optional: true 142 | 143 | /@esbuild/linux-mips64el@0.23.1: 144 | resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} 145 | engines: {node: '>=18'} 146 | cpu: [mips64el] 147 | os: [linux] 148 | requiresBuild: true 149 | dev: false 150 | optional: true 151 | 152 | /@esbuild/linux-ppc64@0.23.1: 153 | resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} 154 | engines: {node: '>=18'} 155 | cpu: [ppc64] 156 | os: [linux] 157 | requiresBuild: true 158 | dev: false 159 | optional: true 160 | 161 | /@esbuild/linux-riscv64@0.23.1: 162 | resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} 163 | engines: {node: '>=18'} 164 | cpu: [riscv64] 165 | os: [linux] 166 | requiresBuild: true 167 | dev: false 168 | optional: true 169 | 170 | /@esbuild/linux-s390x@0.23.1: 171 | resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} 172 | engines: {node: '>=18'} 173 | cpu: [s390x] 174 | os: [linux] 175 | requiresBuild: true 176 | dev: false 177 | optional: true 178 | 179 | /@esbuild/linux-x64@0.23.1: 180 | resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} 181 | engines: {node: '>=18'} 182 | cpu: [x64] 183 | os: [linux] 184 | requiresBuild: true 185 | dev: false 186 | optional: true 187 | 188 | /@esbuild/netbsd-x64@0.23.1: 189 | resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} 190 | engines: {node: '>=18'} 191 | cpu: [x64] 192 | os: [netbsd] 193 | requiresBuild: true 194 | dev: false 195 | optional: true 196 | 197 | /@esbuild/openbsd-arm64@0.23.1: 198 | resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} 199 | engines: {node: '>=18'} 200 | cpu: [arm64] 201 | os: [openbsd] 202 | requiresBuild: true 203 | dev: false 204 | optional: true 205 | 206 | /@esbuild/openbsd-x64@0.23.1: 207 | resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} 208 | engines: {node: '>=18'} 209 | cpu: [x64] 210 | os: [openbsd] 211 | requiresBuild: true 212 | dev: false 213 | optional: true 214 | 215 | /@esbuild/sunos-x64@0.23.1: 216 | resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} 217 | engines: {node: '>=18'} 218 | cpu: [x64] 219 | os: [sunos] 220 | requiresBuild: true 221 | dev: false 222 | optional: true 223 | 224 | /@esbuild/win32-arm64@0.23.1: 225 | resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} 226 | engines: {node: '>=18'} 227 | cpu: [arm64] 228 | os: [win32] 229 | requiresBuild: true 230 | dev: false 231 | optional: true 232 | 233 | /@esbuild/win32-ia32@0.23.1: 234 | resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} 235 | engines: {node: '>=18'} 236 | cpu: [ia32] 237 | os: [win32] 238 | requiresBuild: true 239 | dev: false 240 | optional: true 241 | 242 | /@esbuild/win32-x64@0.23.1: 243 | resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} 244 | engines: {node: '>=18'} 245 | cpu: [x64] 246 | os: [win32] 247 | requiresBuild: true 248 | dev: false 249 | optional: true 250 | 251 | /@types/docker-modem@3.0.6: 252 | resolution: {integrity: sha512-yKpAGEuKRSS8wwx0joknWxsmLha78wNMe9R2S3UNsVOkZded8UqOrV8KoeDXoXsjndxwyF3eIhyClGbO1SEhEg==} 253 | dependencies: 254 | '@types/node': 22.5.1 255 | '@types/ssh2': 1.15.1 256 | dev: true 257 | 258 | /@types/dockerode@3.3.31: 259 | resolution: {integrity: sha512-42R9eoVqJDSvVspV89g7RwRqfNExgievLNWoHkg7NoWIqAmavIbgQBb4oc0qRtHkxE+I3Xxvqv7qVXFABKPBTg==} 260 | dependencies: 261 | '@types/docker-modem': 3.0.6 262 | '@types/node': 22.5.1 263 | '@types/ssh2': 1.15.1 264 | dev: true 265 | 266 | /@types/node@18.19.47: 267 | resolution: {integrity: sha512-1f7dB3BL/bpd9tnDJrrHb66Y+cVrhxSOTGorRNdHwYTUlTay3HuTDPKo9a/4vX9pMQkhYBcAbL4jQdNlhCFP9A==} 268 | dependencies: 269 | undici-types: 5.26.5 270 | dev: true 271 | 272 | /@types/node@22.5.1: 273 | resolution: {integrity: sha512-KkHsxej0j9IW1KKOOAA/XBA0z08UFSrRQHErzEfA3Vgq57eXIMYboIlHJuYIfd+lwCQjtKqUu3UnmKbtUc9yRw==} 274 | dependencies: 275 | undici-types: 6.19.8 276 | dev: true 277 | 278 | /@types/ssh2@1.15.1: 279 | resolution: {integrity: sha512-ZIbEqKAsi5gj35y4P4vkJYly642wIbY6PqoN0xiyQGshKUGXR9WQjF/iF9mXBQ8uBKy3ezfsCkcoHKhd0BzuDA==} 280 | dependencies: 281 | '@types/node': 18.19.47 282 | dev: true 283 | 284 | /asn1@0.2.6: 285 | resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} 286 | dependencies: 287 | safer-buffer: 2.1.2 288 | dev: false 289 | 290 | /base64-js@1.5.1: 291 | resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} 292 | dev: false 293 | 294 | /bcrypt-pbkdf@1.0.2: 295 | resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} 296 | dependencies: 297 | tweetnacl: 0.14.5 298 | dev: false 299 | 300 | /bl@4.1.0: 301 | resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} 302 | dependencies: 303 | buffer: 5.7.1 304 | inherits: 2.0.4 305 | readable-stream: 3.6.2 306 | dev: false 307 | 308 | /buffer@5.7.1: 309 | resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} 310 | dependencies: 311 | base64-js: 1.5.1 312 | ieee754: 1.2.1 313 | dev: false 314 | 315 | /buildcheck@0.0.6: 316 | resolution: {integrity: sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A==} 317 | engines: {node: '>=10.0.0'} 318 | requiresBuild: true 319 | dev: false 320 | optional: true 321 | 322 | /chownr@1.1.4: 323 | resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} 324 | dev: false 325 | 326 | /cpu-features@0.0.10: 327 | resolution: {integrity: sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==} 328 | engines: {node: '>=10.0.0'} 329 | requiresBuild: true 330 | dependencies: 331 | buildcheck: 0.0.6 332 | nan: 2.20.0 333 | dev: false 334 | optional: true 335 | 336 | /debug@4.3.6: 337 | resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==} 338 | engines: {node: '>=6.0'} 339 | peerDependencies: 340 | supports-color: '*' 341 | peerDependenciesMeta: 342 | supports-color: 343 | optional: true 344 | dependencies: 345 | ms: 2.1.2 346 | dev: false 347 | 348 | /docker-modem@5.0.3: 349 | resolution: {integrity: sha512-89zhop5YVhcPEt5FpUFGr3cDyceGhq/F9J+ZndQ4KfqNvfbJpPMfgeixFgUj5OjCYAboElqODxY5Z1EBsSa6sg==} 350 | engines: {node: '>= 8.0'} 351 | dependencies: 352 | debug: 4.3.6 353 | readable-stream: 3.6.2 354 | split-ca: 1.0.1 355 | ssh2: 1.15.0 356 | transitivePeerDependencies: 357 | - supports-color 358 | dev: false 359 | 360 | /dockerode@4.0.2: 361 | resolution: {integrity: sha512-9wM1BVpVMFr2Pw3eJNXrYYt6DT9k0xMcsSCjtPvyQ+xa1iPg/Mo3T/gUcwI0B2cczqCeCYRPF8yFYDwtFXT0+w==} 362 | engines: {node: '>= 8.0'} 363 | dependencies: 364 | '@balena/dockerignore': 1.0.2 365 | docker-modem: 5.0.3 366 | tar-fs: 2.0.1 367 | transitivePeerDependencies: 368 | - supports-color 369 | dev: false 370 | 371 | /end-of-stream@1.4.4: 372 | resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} 373 | dependencies: 374 | once: 1.4.0 375 | dev: false 376 | 377 | /esbuild@0.23.1: 378 | resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} 379 | engines: {node: '>=18'} 380 | hasBin: true 381 | requiresBuild: true 382 | optionalDependencies: 383 | '@esbuild/aix-ppc64': 0.23.1 384 | '@esbuild/android-arm': 0.23.1 385 | '@esbuild/android-arm64': 0.23.1 386 | '@esbuild/android-x64': 0.23.1 387 | '@esbuild/darwin-arm64': 0.23.1 388 | '@esbuild/darwin-x64': 0.23.1 389 | '@esbuild/freebsd-arm64': 0.23.1 390 | '@esbuild/freebsd-x64': 0.23.1 391 | '@esbuild/linux-arm': 0.23.1 392 | '@esbuild/linux-arm64': 0.23.1 393 | '@esbuild/linux-ia32': 0.23.1 394 | '@esbuild/linux-loong64': 0.23.1 395 | '@esbuild/linux-mips64el': 0.23.1 396 | '@esbuild/linux-ppc64': 0.23.1 397 | '@esbuild/linux-riscv64': 0.23.1 398 | '@esbuild/linux-s390x': 0.23.1 399 | '@esbuild/linux-x64': 0.23.1 400 | '@esbuild/netbsd-x64': 0.23.1 401 | '@esbuild/openbsd-arm64': 0.23.1 402 | '@esbuild/openbsd-x64': 0.23.1 403 | '@esbuild/sunos-x64': 0.23.1 404 | '@esbuild/win32-arm64': 0.23.1 405 | '@esbuild/win32-ia32': 0.23.1 406 | '@esbuild/win32-x64': 0.23.1 407 | dev: false 408 | 409 | /fs-constants@1.0.0: 410 | resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} 411 | dev: false 412 | 413 | /fsevents@2.3.3: 414 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 415 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 416 | os: [darwin] 417 | requiresBuild: true 418 | dev: false 419 | optional: true 420 | 421 | /get-tsconfig@4.8.0: 422 | resolution: {integrity: sha512-Pgba6TExTZ0FJAn1qkJAjIeKoDJ3CsI2ChuLohJnZl/tTU8MVrq3b+2t5UOPfRa4RMsorClBjJALkJUMjG1PAw==} 423 | dependencies: 424 | resolve-pkg-maps: 1.0.0 425 | dev: false 426 | 427 | /ieee754@1.2.1: 428 | resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} 429 | dev: false 430 | 431 | /inherits@2.0.4: 432 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 433 | dev: false 434 | 435 | /mkdirp-classic@0.5.3: 436 | resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} 437 | dev: false 438 | 439 | /ms@2.1.2: 440 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 441 | dev: false 442 | 443 | /nan@2.20.0: 444 | resolution: {integrity: sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==} 445 | requiresBuild: true 446 | dev: false 447 | optional: true 448 | 449 | /nats@2.28.2: 450 | resolution: {integrity: sha512-02cvR8EPach+0BfVaQjPgsbPFn6uMjEQAuvXS2ppg8jiWEm2KYdfmeFmtshiU9b2+kFh3LSEKMEaIfRgk3K8tw==} 451 | engines: {node: '>= 14.0.0'} 452 | dependencies: 453 | nkeys.js: 1.1.0 454 | dev: false 455 | 456 | /nkeys.js@1.1.0: 457 | resolution: {integrity: sha512-tB/a0shZL5UZWSwsoeyqfTszONTt4k2YS0tuQioMOD180+MbombYVgzDUYHlx+gejYK6rgf08n/2Df99WY0Sxg==} 458 | engines: {node: '>=10.0.0'} 459 | dependencies: 460 | tweetnacl: 1.0.3 461 | dev: false 462 | 463 | /once@1.4.0: 464 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} 465 | dependencies: 466 | wrappy: 1.0.2 467 | dev: false 468 | 469 | /pump@3.0.0: 470 | resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} 471 | dependencies: 472 | end-of-stream: 1.4.4 473 | once: 1.4.0 474 | dev: false 475 | 476 | /readable-stream@3.6.2: 477 | resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} 478 | engines: {node: '>= 6'} 479 | dependencies: 480 | inherits: 2.0.4 481 | string_decoder: 1.3.0 482 | util-deprecate: 1.0.2 483 | dev: false 484 | 485 | /resolve-pkg-maps@1.0.0: 486 | resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} 487 | dev: false 488 | 489 | /safe-buffer@5.2.1: 490 | resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} 491 | dev: false 492 | 493 | /safer-buffer@2.1.2: 494 | resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} 495 | dev: false 496 | 497 | /split-ca@1.0.1: 498 | resolution: {integrity: sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==} 499 | dev: false 500 | 501 | /ssh2@1.15.0: 502 | resolution: {integrity: sha512-C0PHgX4h6lBxYx7hcXwu3QWdh4tg6tZZsTfXcdvc5caW/EMxaB4H9dWsl7qk+F7LAW762hp8VbXOX7x4xUYvEw==} 503 | engines: {node: '>=10.16.0'} 504 | requiresBuild: true 505 | dependencies: 506 | asn1: 0.2.6 507 | bcrypt-pbkdf: 1.0.2 508 | optionalDependencies: 509 | cpu-features: 0.0.10 510 | nan: 2.20.0 511 | dev: false 512 | 513 | /string_decoder@1.3.0: 514 | resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} 515 | dependencies: 516 | safe-buffer: 5.2.1 517 | dev: false 518 | 519 | /tar-fs@2.0.1: 520 | resolution: {integrity: sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA==} 521 | dependencies: 522 | chownr: 1.1.4 523 | mkdirp-classic: 0.5.3 524 | pump: 3.0.0 525 | tar-stream: 2.2.0 526 | dev: false 527 | 528 | /tar-stream@2.2.0: 529 | resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} 530 | engines: {node: '>=6'} 531 | dependencies: 532 | bl: 4.1.0 533 | end-of-stream: 1.4.4 534 | fs-constants: 1.0.0 535 | inherits: 2.0.4 536 | readable-stream: 3.6.2 537 | dev: false 538 | 539 | /tsx@4.19.0: 540 | resolution: {integrity: sha512-bV30kM7bsLZKZIOCHeMNVMJ32/LuJzLVajkQI/qf92J2Qr08ueLQvW00PUZGiuLPP760UINwupgUj8qrSCPUKg==} 541 | engines: {node: '>=18.0.0'} 542 | hasBin: true 543 | dependencies: 544 | esbuild: 0.23.1 545 | get-tsconfig: 4.8.0 546 | optionalDependencies: 547 | fsevents: 2.3.3 548 | dev: false 549 | 550 | /tweetnacl@0.14.5: 551 | resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} 552 | dev: false 553 | 554 | /tweetnacl@1.0.3: 555 | resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==} 556 | dev: false 557 | 558 | /typescript@5.5.4: 559 | resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} 560 | engines: {node: '>=14.17'} 561 | hasBin: true 562 | dev: true 563 | 564 | /undici-types@5.26.5: 565 | resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} 566 | dev: true 567 | 568 | /undici-types@6.19.8: 569 | resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} 570 | dev: true 571 | 572 | /util-deprecate@1.0.2: 573 | resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} 574 | dev: false 575 | 576 | /wrappy@1.0.2: 577 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} 578 | dev: false 579 | 580 | /zod@3.23.8: 581 | resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} 582 | dev: false 583 | --------------------------------------------------------------------------------