├── .gitignore ├── Dockerfile ├── backend └── backend.go ├── bin ├── check.sh ├── delete.sh ├── dev.sh ├── dev_frontend.sh ├── ensure.sh ├── logs.sh ├── preview.sh └── quick.sh ├── demo.gif ├── env.sh.template ├── frontend ├── package-lock.json ├── package.json ├── public │ ├── favicon.png │ └── index.html ├── shadow-cljs.edn └── src │ ├── frontend.cljs │ └── proxy.clj ├── go.mod ├── go.sum ├── infra.yaml ├── license.txt ├── readme.md └── screenshot.png /.gitignore: -------------------------------------------------------------------------------- 1 | env*.sh 2 | frontend/public/index.html.gz 3 | frontend/public/js/ 4 | frontend/node_modules/ 5 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM archlinux:latest 2 | 3 | RUN pacman -Syu --noconfirm 4 | 5 | RUN pacman -Sy --noconfirm \ 6 | entr \ 7 | gcc \ 8 | git \ 9 | go \ 10 | jdk-openjdk \ 11 | npm \ 12 | which \ 13 | zip 14 | 15 | RUN go install github.com/nathants/libaws@latest && \ 16 | mv -fv ~/go/bin/* /usr/local/bin 17 | -------------------------------------------------------------------------------- /backend/backend.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "compress/gzip" 6 | "context" 7 | "crypto/sha256" 8 | "encoding/base64" 9 | "encoding/hex" 10 | "encoding/json" 11 | "fmt" 12 | "mime" 13 | "net/http" 14 | "os" 15 | "path/filepath" 16 | "runtime/debug" 17 | "strings" 18 | "sync" 19 | "time" 20 | 21 | "github.com/aws/aws-lambda-go/events" 22 | "github.com/aws/aws-lambda-go/lambda" 23 | "github.com/aws/aws-sdk-go-v2/aws" 24 | "github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue" 25 | "github.com/aws/aws-sdk-go-v2/service/dynamodb" 26 | ddbtypes "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" 27 | sdkLambda "github.com/aws/aws-sdk-go-v2/service/lambda" 28 | sdkLambdaTypes "github.com/aws/aws-sdk-go-v2/service/lambda/types" 29 | "github.com/aws/aws-sdk-go-v2/service/s3" 30 | "github.com/dustin/go-humanize" 31 | uuid "github.com/gofrs/uuid" 32 | "github.com/nathants/go-dynamolock" 33 | "github.com/nathants/libaws/lib" 34 | ) 35 | 36 | type WebsocketKey struct { 37 | ID string `json:"id" dynamodbav:"id"` 38 | } 39 | 40 | type WebsocketData struct { 41 | ConnectionID string `json:"connection-id" dynamodbav:"connection-id"` 42 | Timestamp string `json:"timestamp" dynamodbav:"timestamp"` 43 | } 44 | 45 | type Websocket struct { 46 | WebsocketKey 47 | WebsocketData 48 | } 49 | 50 | func index() events.APIGatewayProxyResponse { 51 | headers := map[string]string{ 52 | "Content-Type": "text/html; charset=UTF-8", 53 | "Content-Security-Policy": "frame-ancestors 'none'; object-src 'none'; base-uri 'none';", 54 | "X-Content-Type-Options": "nosniff", 55 | "Strict-Transport-Security": "max-age=31536000; includeSubDomains;", 56 | "Referrer-Policy": "strict-origin", 57 | } 58 | indexBytes, err := os.ReadFile("frontend/public/index.html.gz") 59 | if err == nil { 60 | headers["Content-Encoding"] = "gzip" 61 | } else { 62 | indexBytes, err = os.ReadFile("frontend/public/index.html") 63 | if err != nil { 64 | panic(err) 65 | } 66 | } 67 | return events.APIGatewayProxyResponse{ 68 | Body: base64.StdEncoding.EncodeToString(indexBytes), 69 | IsBase64Encoded: true, 70 | StatusCode: 200, 71 | Headers: headers, 72 | } 73 | } 74 | 75 | func static(path string) events.APIGatewayProxyResponse { 76 | data, err := os.ReadFile("frontend/public" + path) 77 | if err != nil { 78 | return events.APIGatewayProxyResponse{ 79 | StatusCode: 404, 80 | } 81 | } 82 | headers := map[string]string{ 83 | "Content-Type": mime.TypeByExtension("." + last(strings.Split(path, "."))), 84 | } 85 | var body string 86 | if len(data) > 4*1024*1024 { 87 | var buf bytes.Buffer 88 | w := gzip.NewWriter(&buf) 89 | _, err = w.Write(data) 90 | if err != nil { 91 | panic(err) 92 | } 93 | err = w.Close() 94 | if err != nil { 95 | panic(err) 96 | } 97 | body = base64.StdEncoding.EncodeToString(buf.Bytes()) 98 | headers["Content-Encoding"] = "gzip" 99 | } else { 100 | body = base64.StdEncoding.EncodeToString(data) 101 | } 102 | return events.APIGatewayProxyResponse{ 103 | Body: body, 104 | IsBase64Encoded: true, 105 | StatusCode: 200, 106 | Headers: headers, 107 | } 108 | } 109 | 110 | func last(xs []string) string { 111 | return xs[len(xs)-1] 112 | } 113 | 114 | func notfound() events.APIGatewayProxyResponse { 115 | return events.APIGatewayProxyResponse{ 116 | Body: "404", 117 | StatusCode: 404, 118 | } 119 | } 120 | 121 | func httpVersionGet(_ context.Context, _ *events.APIGatewayProxyRequest, res chan<- events.APIGatewayProxyResponse) { 122 | val := map[string]string{} 123 | err := filepath.Walk(".", func(file string, _ os.FileInfo, err error) error { 124 | if err != nil { 125 | return err 126 | } 127 | info, err := os.Stat(file) 128 | if err != nil { 129 | panic(err) 130 | } 131 | if info.IsDir() { 132 | return nil 133 | } 134 | data, err := os.ReadFile(file) 135 | if err != nil { 136 | panic(err) 137 | } 138 | hash := sha256.Sum256(data) 139 | hashHex := hex.EncodeToString(hash[:]) 140 | size := humanize.Bytes(uint64(info.Size())) 141 | val[file] = fmt.Sprintf("%s %s", hashHex, size) 142 | return nil 143 | }) 144 | if err != nil { 145 | panic(err) 146 | } 147 | data, err := json.Marshal(val) 148 | if err != nil { 149 | panic(err) 150 | } 151 | res <- events.APIGatewayProxyResponse{ 152 | StatusCode: 200, 153 | Body: string(data), 154 | } 155 | } 156 | 157 | func handleApiEvent(ctx context.Context, event *events.APIGatewayProxyRequest, res chan<- events.APIGatewayProxyResponse) { 158 | if event.Path == "/" { 159 | res <- index() 160 | return 161 | } 162 | if event.Path == "/_version" { 163 | httpVersionGet(ctx, event, res) 164 | return 165 | } 166 | if strings.HasPrefix(event.Path, "/js/main.js") || 167 | strings.HasPrefix(event.Path, "/favicon.") { 168 | res <- static(event.Path) 169 | return 170 | } 171 | if strings.HasPrefix(event.Path, "/api/") { 172 | if event.HTTPMethod == http.MethodOptions { 173 | res <- events.APIGatewayProxyResponse{ 174 | StatusCode: 200, 175 | } 176 | return 177 | } 178 | if event.Path == "/api/time" && event.HTTPMethod == http.MethodGet { 179 | httpTimeGet(ctx, event, res) 180 | return 181 | } else if event.Path == "/api/data" && event.HTTPMethod == http.MethodPost { 182 | httpDataPost(ctx, event, res) 183 | return 184 | } 185 | res <- notfound() 186 | return 187 | } 188 | res <- notfound() 189 | } 190 | 191 | type dataPostRequest struct { 192 | Data string `json:"data"` 193 | MoreData string `json:"more-data"` 194 | } 195 | 196 | type dataPostResponse struct { 197 | Message string `json:"message"` 198 | } 199 | 200 | func httpDataPost(_ context.Context, req *events.APIGatewayProxyRequest, res chan<- events.APIGatewayProxyResponse) { 201 | input := dataPostRequest{} 202 | err := json.Unmarshal([]byte(req.Body), &input) 203 | if err != nil { 204 | panic(err) 205 | } 206 | output := dataPostResponse{ 207 | Message: fmt.Sprintln("thanks for", input.Data, "and", input.MoreData), 208 | } 209 | data, err := json.Marshal(output) 210 | if err != nil { 211 | panic(err) 212 | } 213 | time.Sleep(1*time.Second) // so we can see the linear-progress on the frontend 214 | res <- events.APIGatewayProxyResponse{ 215 | StatusCode: 200, 216 | Body: string(data), 217 | Headers: map[string]string{ 218 | "Content-Type": "application/json", 219 | }, 220 | } 221 | } 222 | 223 | type timeGetReponse struct { 224 | Time int `json:"time"` 225 | } 226 | 227 | func httpTimeGet(_ context.Context, _ *events.APIGatewayProxyRequest, res chan<- events.APIGatewayProxyResponse) { 228 | resp := timeGetReponse{ 229 | Time: int(time.Now().UTC().Unix()), 230 | } 231 | data, err := json.Marshal(resp) 232 | if err != nil { 233 | panic(err) 234 | } 235 | time.Sleep(1*time.Second) 236 | res <- events.APIGatewayProxyResponse{ 237 | StatusCode: 200, 238 | Body: string(data), 239 | Headers: map[string]string{"Content-Type": "application/json"}, 240 | } 241 | } 242 | 243 | func logRecover(r any, res chan<- events.APIGatewayProxyResponse) { 244 | stack := string(debug.Stack()) 245 | lib.Logger.Println(r) 246 | lib.Logger.Println(stack) 247 | res <- events.APIGatewayProxyResponse{ 248 | StatusCode: 500, 249 | Body: fmt.Sprint(r) + "\n" + stack, 250 | } 251 | } 252 | 253 | func handleWebsocketEvent(ctx context.Context, event *events.APIGatewayWebsocketProxyRequest, res chan<- events.APIGatewayProxyResponse) { 254 | record := Websocket{ 255 | WebsocketKey: WebsocketKey{ 256 | ID: fmt.Sprintf("websocket.%s", event.RequestContext.Identity.SourceIP), 257 | }, 258 | WebsocketData: WebsocketData{ 259 | Timestamp: time.Now().UTC().Format(time.RFC3339), 260 | }, 261 | } 262 | switch event.RequestContext.RouteKey { 263 | case "$connect": 264 | item, err := attributevalue.MarshalMap(record.WebsocketKey) 265 | if err != nil { 266 | panic(err) 267 | } 268 | out, err := lib.DynamoDBClient().GetItem(ctx, &dynamodb.GetItemInput{ 269 | Key: item, 270 | TableName: aws.String(os.Getenv("PROJECT_NAME")), 271 | }) 272 | if err != nil { 273 | panic(err) 274 | } 275 | if len(out.Item) != 0 { 276 | err = attributevalue.UnmarshalMap(out.Item, &record) 277 | if err != nil { 278 | panic(err) 279 | } 280 | connectionID := record.ConnectionID 281 | if connectionID != "" { 282 | _ = lib.ApiWebsocketClose(ctx, os.Getenv("PROJECT_DOMAIN_WEBSOCKET"), connectionID) 283 | } 284 | } 285 | record.ConnectionID = event.RequestContext.ConnectionID 286 | item, err = attributevalue.MarshalMap(record) 287 | if err != nil { 288 | panic(err) 289 | } 290 | _, err = lib.DynamoDBClient().PutItem(ctx, &dynamodb.PutItemInput{ 291 | Item: item, 292 | TableName: aws.String(os.Getenv("PROJECT_NAME")), 293 | }) 294 | if err != nil { 295 | panic(err) 296 | } 297 | invokeWebsocketSender() 298 | res <- events.APIGatewayProxyResponse{StatusCode: 200} 299 | return 300 | case "$default": 301 | data, err := json.Marshal(map[string]string{ 302 | "thanks for": event.Body, 303 | }) 304 | if err != nil { 305 | panic(err) 306 | } 307 | err = lib.ApiWebsocketSend(ctx, os.Getenv("PROJECT_DOMAIN_WEBSOCKET"), event.RequestContext.ConnectionID, data) 308 | if err != nil { 309 | panic(err) 310 | } 311 | res <- events.APIGatewayProxyResponse{StatusCode: 200} 312 | return 313 | case "$disconnect": 314 | connectionID := event.RequestContext.ConnectionID 315 | _ = lib.ApiWebsocketClose(ctx, os.Getenv("PROJECT_DOMAIN_WEBSOCKET"), connectionID) 316 | item, err := attributevalue.MarshalMap(record.WebsocketKey) 317 | if err != nil { 318 | panic(err) 319 | } 320 | _, err = lib.DynamoDBClient().DeleteItem(ctx, &dynamodb.DeleteItemInput{ 321 | Key: item, 322 | TableName: aws.String(os.Getenv("PROJECT_NAME")), 323 | }) 324 | if err != nil { 325 | panic(err) 326 | } 327 | res <- events.APIGatewayProxyResponse{StatusCode: 200} 328 | return 329 | default: 330 | panic(lib.PformatAlways(event)) 331 | } 332 | } 333 | 334 | func websocketRouteKey(event map[string]any) string { 335 | val, ok := event["requestContext"].(map[string]any) 336 | if ok { 337 | routeKey, ok := val["routeKey"].(string) 338 | if ok { 339 | return routeKey 340 | } 341 | } 342 | return "" 343 | } 344 | 345 | func websocketConnectionID(event map[string]any) string { 346 | val, ok := event["requestContext"].(map[string]any) 347 | if ok { 348 | connectionID, ok := val["connectionId"].(string) 349 | if ok { 350 | return connectionID 351 | } 352 | } 353 | return "" 354 | } 355 | 356 | func invokeWebsocketSender() { 357 | data, err := json.Marshal(map[string]string{ 358 | "detail-type": "websocket-sender", 359 | }) 360 | if err != nil { 361 | panic(err) 362 | } 363 | invokeOut, err := lib.LambdaClient().Invoke(context.Background(), &sdkLambda.InvokeInput{ 364 | FunctionName: aws.String(os.Getenv("AWS_LAMBDA_FUNCTION_NAME")), 365 | InvocationType: sdkLambdaTypes.InvocationTypeEvent, 366 | LogType: sdkLambdaTypes.LogTypeNone, 367 | Payload: data, 368 | }) 369 | if err != nil { 370 | panic(err) 371 | } 372 | if invokeOut.StatusCode != 202 { 373 | panic(fmt.Sprintf("status %d", invokeOut.StatusCode)) 374 | } 375 | } 376 | 377 | type Data struct { 378 | Value string 379 | } 380 | 381 | func websocketSender(ctx context.Context, res chan<- events.APIGatewayProxyResponse) { 382 | defer func() { 383 | if r := recover(); r != nil { 384 | logRecover(r, res) 385 | } 386 | }() 387 | startTime := time.Now() 388 | table := os.Getenv("PROJECT_NAME") 389 | lockId := "lock.sender" 390 | maxAge := time.Second * 10 391 | heartbeat := time.Second * 5 392 | unlock, _, data, err := dynamolock.Lock[dynamolock.LockData](ctx, table, lockId, maxAge, heartbeat) 393 | if err != nil { 394 | // another sender is already running 395 | return 396 | } 397 | defer func() { 398 | err := unlock(data) 399 | if err != nil { 400 | panic(err) 401 | } 402 | }() 403 | for { 404 | // scan db for all open websockets 405 | count := 0 406 | var start map[string]ddbtypes.AttributeValue 407 | for { 408 | out, err := lib.DynamoDBClient().Scan(ctx, &dynamodb.ScanInput{ 409 | TableName: aws.String(os.Getenv("PROJECT_NAME")), 410 | ExclusiveStartKey: start, 411 | }) 412 | if err != nil { 413 | lib.Logger.Println("error:", err) 414 | return 415 | } 416 | for _, item := range out.Items { 417 | val := Websocket{} 418 | err := attributevalue.UnmarshalMap(item, &val) 419 | if err != nil { 420 | lib.Logger.Println("error:", err) 421 | return 422 | } 423 | if strings.HasPrefix(val.ID, "websocket.") { 424 | t, err := time.Parse(time.RFC3339, val.Timestamp) 425 | if err != nil || time.Since(t) > 130*time.Minute { 426 | _ = lib.ApiWebsocketClose(ctx, os.Getenv("PROJECT_DOMAIN_WEBSOCKET"), val.ConnectionID) 427 | item, err := attributevalue.MarshalMap(val.WebsocketKey) 428 | if err != nil { 429 | lib.Logger.Println("error:", err) 430 | continue 431 | } 432 | _, err = lib.DynamoDBClient().DeleteItem(ctx, &dynamodb.DeleteItemInput{ 433 | Key: item, 434 | TableName: aws.String(os.Getenv("PROJECT_NAME")), 435 | }) 436 | if err != nil { 437 | lib.Logger.Println("error:", err) 438 | continue 439 | } 440 | } else { 441 | // send the current time to each open websocket 442 | count++ 443 | go func(val Websocket) { 444 | defer func() { 445 | if r := recover(); r != nil { 446 | logRecover(r, res) 447 | } 448 | }() 449 | data, err := json.Marshal(map[string]string{"time": timestamp()}) 450 | if err != nil { 451 | lib.Logger.Println("error:", err) 452 | return 453 | } 454 | _ = lib.ApiWebsocketSend(ctx, os.Getenv("PROJECT_DOMAIN_WEBSOCKET"), val.ConnectionID, data) 455 | }(val) 456 | } 457 | } 458 | } 459 | if len(out.LastEvaluatedKey) == 0 { 460 | break 461 | } 462 | start = out.LastEvaluatedKey 463 | } 464 | // when no open connections, exit 465 | if count == 0 { 466 | return 467 | } 468 | time.Sleep(1 * time.Second) 469 | // start a new sender before this lambda times out 470 | if time.Since(startTime) > 14*time.Minute { 471 | invokeWebsocketSender() 472 | return 473 | } 474 | } 475 | } 476 | 477 | func handle(ctx context.Context, event map[string]any, res chan<- events.APIGatewayProxyResponse) { 478 | defer func() { 479 | if r := recover(); r != nil { 480 | logRecover(r, res) 481 | } 482 | }() 483 | if event["detail-type"] == "websocket-sender" { 484 | websocketSender(ctx, res) 485 | res <- events.APIGatewayProxyResponse{StatusCode: 200} 486 | return 487 | } else if websocketConnectionID(event) != "" { 488 | websocketEvent := &events.APIGatewayWebsocketProxyRequest{} 489 | data, err := json.Marshal(event) 490 | if err != nil { 491 | panic(err) 492 | } 493 | err = json.Unmarshal(data, &websocketEvent) 494 | if err != nil { 495 | panic(err) 496 | } 497 | handleWebsocketEvent(ctx, websocketEvent, res) 498 | return 499 | } 500 | _, ok := event["path"] 501 | if !ok { 502 | res <- notfound() 503 | return 504 | } 505 | apiEvent := &events.APIGatewayProxyRequest{} 506 | data, err := json.Marshal(event) 507 | if err != nil { 508 | panic(err) 509 | } 510 | err = json.Unmarshal(data, &apiEvent) 511 | if err != nil { 512 | panic(err) 513 | } 514 | handleApiEvent(ctx, apiEvent, res) 515 | } 516 | 517 | func sourceIP(event map[string]any) string { 518 | req, ok := event["requestContext"].(map[string]any) 519 | if ok { 520 | identity, ok := req["identity"].(map[string]any) 521 | if ok { 522 | sourceIP, ok := identity["sourceIp"].(string) 523 | if ok { 524 | return sourceIP 525 | } 526 | } 527 | } 528 | return "" 529 | } 530 | 531 | func timestamp() string { 532 | return time.Now().UTC().Format(time.RFC3339) 533 | } 534 | 535 | func handleRequest(ctx context.Context, event map[string]any) (events.APIGatewayProxyResponse, error) { 536 | setupLogging(ctx) 537 | defer lib.Logger.Flush() 538 | start := time.Now() 539 | res := make(chan events.APIGatewayProxyResponse) 540 | go handle(ctx, event, res) 541 | r := <-res 542 | routeKey := websocketRouteKey(event) 543 | path, pathOk := event["path"] 544 | if event["detail-type"] == "websocket-sender" { 545 | lib.Logger.Println("websocket-sender", time.Since(start), timestamp()) 546 | } else if routeKey != "" { 547 | lib.Logger.Println("websocket", r.StatusCode, routeKey, time.Since(start), sourceIP(event), timestamp()) 548 | } else if pathOk { 549 | method := event["httpMethod"] 550 | lib.Logger.Println("http", r.StatusCode, method, path, time.Since(start), sourceIP(event), timestamp()) 551 | } else { 552 | lib.Logger.Println("async", time.Since(start), timestamp()) 553 | } 554 | return r, nil 555 | } 556 | 557 | func setupLogging(ctx context.Context) { 558 | lock := sync.RWMutex{} 559 | var lines []string 560 | uid := uuid.Must(uuid.NewV4()).String() 561 | count := 0 562 | lib.Logger = &lib.LoggerStruct{ 563 | Print: func(args ...any) { 564 | lock.Lock() 565 | defer lock.Unlock() 566 | lines = append(lines, fmt.Sprint(args...)) 567 | }, 568 | Flush: func() { 569 | lock.Lock() 570 | defer lock.Unlock() 571 | if len(lines) == 0 { 572 | return 573 | } 574 | text := strings.Join(lines, "") 575 | lines = nil 576 | unix := time.Now().Unix() 577 | key := fmt.Sprintf("logs/%d.%s.%03d", unix, uid, count) 578 | count++ 579 | err := lib.Retry(context.Background(), func() error { 580 | _, err := lib.S3Client().PutObject(context.Background(), &s3.PutObjectInput{ 581 | Bucket: aws.String(os.Getenv("PROJECT_BUCKET")), 582 | Key: aws.String(key), 583 | Body: bytes.NewReader([]byte(text)), 584 | }) 585 | return err 586 | }) 587 | if err != nil { 588 | fmt.Println("error:", err) 589 | } 590 | }, 591 | } 592 | go func() { 593 | // defer func() {}() 594 | for { 595 | select { 596 | case <-ctx.Done(): 597 | return 598 | case <-time.After(5 * time.Second): 599 | lib.Logger.Flush() 600 | } 601 | } 602 | }() 603 | } 604 | 605 | func main() { 606 | lambda.Start(handleRequest) 607 | } 608 | -------------------------------------------------------------------------------- /bin/check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | out=$(mktemp) 4 | trap "rm $out &>/dev/null || true" EXIT 5 | 6 | bash -c "cd frontend && npx shadow-cljs compile app 2>&1 | grep -v '^\[' > $out" & 7 | pid=$! 8 | trap "kill -9 $pid &>/dev/null || true" EXIT 9 | 10 | set -eou pipefail 11 | 12 | which staticcheck >/dev/null || (cd ~ && go install honnef.co/go/tools/cmd/staticcheck@latest) 13 | which golint >/dev/null || (cd ~ && go install golang.org/x/lint/golint@latest) 14 | which ineffassign >/dev/null || (cd ~ && go install github.com/gordonklaus/ineffassign@latest) 15 | which errcheck >/dev/null || (cd ~ && go install github.com/kisielk/errcheck@latest) 16 | which bodyclose >/dev/null || (cd ~ && go install github.com/timakin/bodyclose@latest) 17 | which nargs >/dev/null || (cd ~ && go install github.com/alexkohler/nargs/cmd/nargs@latest) 18 | which go-hasdefault >/dev/null || (cd ~ && go install github.com/nathants/go-hasdefault@latest) 19 | which go-hasdefer >/dev/null || (cd ~ && go install github.com/nathants/go-hasdefer@latest) 20 | which govulncheck >/dev/null || (cd ~ && go install golang.org/x/vuln/cmd/govulncheck@latest) 21 | 22 | echo govulncheck 23 | govulncheck ./... 24 | 25 | echo go-hasdefer 26 | go-hasdefer $(find -type f -name "*.go") || true 27 | 28 | echo go-hasdefault 29 | go-hasdefault $(find -type f -name "*.go") || true 30 | 31 | echo go fmt 32 | go fmt ./... >/dev/null 33 | 34 | echo nargs 35 | nargs ./... 36 | 37 | echo bodyclose 38 | go vet -vettool=$(which bodyclose) ./... 39 | 40 | echo go lint 41 | golint ./... | grep -v -e unexported -e "should be" || true 42 | 43 | echo static check 44 | staticcheck ./... 45 | 46 | echo ineffassign 47 | ineffassign ./... 48 | 49 | echo errcheck 50 | errcheck ./... 51 | 52 | echo go vet 53 | go vet ./... 54 | 55 | echo go build 56 | go build -o /dev/null backend/backend.go 57 | 58 | wait $pid 59 | echo shadow-cljs compile 60 | if cat $out | grep -v 'being replaced by: ' | grep -i -e warning -e error &>/dev/null; then 61 | cat $out 62 | exit 1 63 | fi 64 | -------------------------------------------------------------------------------- /bin/delete.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | source ${1:-env.sh} 5 | 6 | libaws infra-rm infra.yaml 2>&1 | sed 's/^/libaws: /' 7 | -------------------------------------------------------------------------------- /bin/dev.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | source ${1:-env.sh} 5 | 6 | # auto reload frontend 7 | bash bin/dev_frontend.sh ${1:-env.sh} 2>&1 | sed 's/^/shadow-cljs: /' & 8 | pid=$! 9 | trap "kill $pid &>/dev/null || true" EXIT 10 | 11 | # auto reload backend 12 | find -name "*.go" -o -name "go.*" | entr -r bash bin/quick.sh ${1:-env.sh} 2>&1 | sed 's/^/libaws: /' 13 | -------------------------------------------------------------------------------- /bin/dev_frontend.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | source ${1:-env.sh} 5 | 6 | cd frontend 7 | npm ci 8 | npx shadow-cljs watch app 9 | -------------------------------------------------------------------------------- /bin/ensure.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | source ${1:-env.sh} 5 | 6 | # inline js and add csp to the markup from frontend/public/index.html 7 | inline() { 8 | path=$1 9 | js=$(cat $path) 10 | hash=$(echo -n "$js" | openssl sha256 -binary | openssl base64) 11 | cat < 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | EOF 27 | } 28 | 29 | if [ -z "${NOJS:-}" ] || [ ! -f frontend/public/index.html.gz ]; then 30 | ( 31 | cd frontend 32 | npm ci 33 | rm -rf public/js/ 34 | npx shadow-cljs release app 35 | ) 2>&1 | sed 's/^/shadow-cljs: /' 36 | inline frontend/public/js/main.js | gzip --best > frontend/public/index.html.gz 37 | rm -rf frontend/public/js/* 38 | fi 39 | 40 | libaws infra-ensure infra.yaml 2>&1 | sed 's/^/libaws: /' 41 | -------------------------------------------------------------------------------- /bin/logs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | source ${1:-env.sh} 5 | 6 | seen=$(mktemp) 7 | trap "rm -f $seen || true" EXIT 8 | 9 | while true; do 10 | 11 | # list all logs younger than n minutes 12 | libaws s3-ls -s $PROJECT_BUCKET/logs/$(date --utc --date="${start:-1 minute ago}" +%s) | awk '{print $4}' | while read log; do 13 | 14 | # if we haven't already seen it 15 | if ! grep $log $seen &>/dev/null; then 16 | 17 | # echo new source 18 | echo logs: s3://$PROJECT_BUCKET/$log 1>&2 19 | 20 | 21 | # print it 22 | if [ -n "${serial:-}" ]; then 23 | libaws s3-get s3://$PROJECT_BUCKET/$log 24 | else 25 | 26 | # check max concurrency 27 | while true; do 28 | if [ $(ps -ef | grep "libaws s3-get s3://$PROJECT_BUCKET" | wc -l) -lt 64 ]; then 29 | break 30 | fi 31 | sleep .1 32 | done 33 | libaws s3-get s3://$PROJECT_BUCKET/$log & 34 | fi 35 | 36 | # mark it as seen, and prune old seen data 37 | updated_seen=$(mktemp) 38 | awk "\$1 > $(date --utc --date="5 minutes ago" +%s) {print}" $seen > $updated_seen 39 | echo $(date --utc +%s) $log >> $updated_seen 40 | mv -f $updated_seen $seen 41 | 42 | fi 43 | 44 | done 45 | 46 | # if start specified exit immediately 47 | if [ -n "${start:-}" ]; then 48 | break 49 | fi 50 | 51 | sleep 1 52 | done 53 | -------------------------------------------------------------------------------- /bin/preview.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | source ${1:-env.sh} 5 | 6 | touch frontend/public/index.html.gz 7 | touch frontend/public/favicon.png 8 | 9 | libaws infra-ensure infra.yaml --preview | sed 's/^/libaws: /' 10 | -------------------------------------------------------------------------------- /bin/quick.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eou pipefail 3 | 4 | source ${1:-env.sh} 5 | 6 | echo rebuild ${PROJECT_NAME} 7 | 8 | mkdir -p frontend/public/ 9 | touch frontend/public/index.html.gz 10 | touch frontend/public/favicon.png 11 | 12 | time libaws infra-ensure infra.yaml --quick ${PROJECT_NAME} 13 | -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathants/aws-gocljs/155bd13d7faa176dcff0bc25194f04f3c695bde7/demo.gif -------------------------------------------------------------------------------- /env.sh.template: -------------------------------------------------------------------------------- 1 | [ AWS_ACCOUNT_ID = $(libaws aws-account) ] || { echo wrong account; exit 1; } # fail if not in the right account 2 | 3 | export AWS_DEFAULT_REGION=$(libaws aws-region) 4 | export PROJECT_NAME=APP 5 | export PROJECT_DOMAIN=APP.DOMAIN.com 6 | export PROJECT_DOMAIN_WEBSOCKET=ws-APP.DOMAIN.com 7 | export PROJECT_URL=https://$PROJECT_DOMAIN 8 | export PROJECT_BUCKET=DOMAIN-APP-bucket 9 | -------------------------------------------------------------------------------- /frontend/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.0.1", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "frontend", 9 | "version": "0.0.1", 10 | "dependencies": { 11 | "@emotion/react": "11.14.0", 12 | "@emotion/styled": "11.14.0", 13 | "@mui/material": "7.0.2", 14 | "@primer/octicons-react": "19.15.1", 15 | "localforage": "1.10.0", 16 | "react": "18.3.1", 17 | "react-dom": "18.3.1", 18 | "react-syntax-highlighter": "15.6.1" 19 | }, 20 | "devDependencies": { 21 | "shadow-cljs": "2.28.23" 22 | } 23 | }, 24 | "node_modules/@babel/code-frame": { 25 | "version": "7.26.2", 26 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", 27 | "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", 28 | "license": "MIT", 29 | "dependencies": { 30 | "@babel/helper-validator-identifier": "^7.25.9", 31 | "js-tokens": "^4.0.0", 32 | "picocolors": "^1.0.0" 33 | }, 34 | "engines": { 35 | "node": ">=6.9.0" 36 | } 37 | }, 38 | "node_modules/@babel/generator": { 39 | "version": "7.27.0", 40 | "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz", 41 | "integrity": "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==", 42 | "license": "MIT", 43 | "dependencies": { 44 | "@babel/parser": "^7.27.0", 45 | "@babel/types": "^7.27.0", 46 | "@jridgewell/gen-mapping": "^0.3.5", 47 | "@jridgewell/trace-mapping": "^0.3.25", 48 | "jsesc": "^3.0.2" 49 | }, 50 | "engines": { 51 | "node": ">=6.9.0" 52 | } 53 | }, 54 | "node_modules/@babel/helper-module-imports": { 55 | "version": "7.25.9", 56 | "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", 57 | "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", 58 | "license": "MIT", 59 | "dependencies": { 60 | "@babel/traverse": "^7.25.9", 61 | "@babel/types": "^7.25.9" 62 | }, 63 | "engines": { 64 | "node": ">=6.9.0" 65 | } 66 | }, 67 | "node_modules/@babel/helper-string-parser": { 68 | "version": "7.25.9", 69 | "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", 70 | "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", 71 | "license": "MIT", 72 | "engines": { 73 | "node": ">=6.9.0" 74 | } 75 | }, 76 | "node_modules/@babel/helper-validator-identifier": { 77 | "version": "7.25.9", 78 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", 79 | "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", 80 | "license": "MIT", 81 | "engines": { 82 | "node": ">=6.9.0" 83 | } 84 | }, 85 | "node_modules/@babel/parser": { 86 | "version": "7.27.0", 87 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", 88 | "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", 89 | "license": "MIT", 90 | "dependencies": { 91 | "@babel/types": "^7.27.0" 92 | }, 93 | "bin": { 94 | "parser": "bin/babel-parser.js" 95 | }, 96 | "engines": { 97 | "node": ">=6.0.0" 98 | } 99 | }, 100 | "node_modules/@babel/runtime": { 101 | "version": "7.27.0", 102 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", 103 | "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", 104 | "license": "MIT", 105 | "dependencies": { 106 | "regenerator-runtime": "^0.14.0" 107 | }, 108 | "engines": { 109 | "node": ">=6.9.0" 110 | } 111 | }, 112 | "node_modules/@babel/template": { 113 | "version": "7.27.0", 114 | "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz", 115 | "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==", 116 | "license": "MIT", 117 | "dependencies": { 118 | "@babel/code-frame": "^7.26.2", 119 | "@babel/parser": "^7.27.0", 120 | "@babel/types": "^7.27.0" 121 | }, 122 | "engines": { 123 | "node": ">=6.9.0" 124 | } 125 | }, 126 | "node_modules/@babel/traverse": { 127 | "version": "7.27.0", 128 | "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz", 129 | "integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==", 130 | "license": "MIT", 131 | "dependencies": { 132 | "@babel/code-frame": "^7.26.2", 133 | "@babel/generator": "^7.27.0", 134 | "@babel/parser": "^7.27.0", 135 | "@babel/template": "^7.27.0", 136 | "@babel/types": "^7.27.0", 137 | "debug": "^4.3.1", 138 | "globals": "^11.1.0" 139 | }, 140 | "engines": { 141 | "node": ">=6.9.0" 142 | } 143 | }, 144 | "node_modules/@babel/types": { 145 | "version": "7.27.0", 146 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", 147 | "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", 148 | "license": "MIT", 149 | "dependencies": { 150 | "@babel/helper-string-parser": "^7.25.9", 151 | "@babel/helper-validator-identifier": "^7.25.9" 152 | }, 153 | "engines": { 154 | "node": ">=6.9.0" 155 | } 156 | }, 157 | "node_modules/@emotion/babel-plugin": { 158 | "version": "11.13.5", 159 | "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", 160 | "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", 161 | "license": "MIT", 162 | "dependencies": { 163 | "@babel/helper-module-imports": "^7.16.7", 164 | "@babel/runtime": "^7.18.3", 165 | "@emotion/hash": "^0.9.2", 166 | "@emotion/memoize": "^0.9.0", 167 | "@emotion/serialize": "^1.3.3", 168 | "babel-plugin-macros": "^3.1.0", 169 | "convert-source-map": "^1.5.0", 170 | "escape-string-regexp": "^4.0.0", 171 | "find-root": "^1.1.0", 172 | "source-map": "^0.5.7", 173 | "stylis": "4.2.0" 174 | } 175 | }, 176 | "node_modules/@emotion/cache": { 177 | "version": "11.14.0", 178 | "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", 179 | "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", 180 | "license": "MIT", 181 | "dependencies": { 182 | "@emotion/memoize": "^0.9.0", 183 | "@emotion/sheet": "^1.4.0", 184 | "@emotion/utils": "^1.4.2", 185 | "@emotion/weak-memoize": "^0.4.0", 186 | "stylis": "4.2.0" 187 | } 188 | }, 189 | "node_modules/@emotion/hash": { 190 | "version": "0.9.2", 191 | "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", 192 | "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", 193 | "license": "MIT" 194 | }, 195 | "node_modules/@emotion/is-prop-valid": { 196 | "version": "1.3.1", 197 | "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz", 198 | "integrity": "sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==", 199 | "license": "MIT", 200 | "dependencies": { 201 | "@emotion/memoize": "^0.9.0" 202 | } 203 | }, 204 | "node_modules/@emotion/memoize": { 205 | "version": "0.9.0", 206 | "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", 207 | "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", 208 | "license": "MIT" 209 | }, 210 | "node_modules/@emotion/react": { 211 | "version": "11.14.0", 212 | "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", 213 | "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", 214 | "license": "MIT", 215 | "dependencies": { 216 | "@babel/runtime": "^7.18.3", 217 | "@emotion/babel-plugin": "^11.13.5", 218 | "@emotion/cache": "^11.14.0", 219 | "@emotion/serialize": "^1.3.3", 220 | "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", 221 | "@emotion/utils": "^1.4.2", 222 | "@emotion/weak-memoize": "^0.4.0", 223 | "hoist-non-react-statics": "^3.3.1" 224 | }, 225 | "peerDependencies": { 226 | "react": ">=16.8.0" 227 | }, 228 | "peerDependenciesMeta": { 229 | "@types/react": { 230 | "optional": true 231 | } 232 | } 233 | }, 234 | "node_modules/@emotion/serialize": { 235 | "version": "1.3.3", 236 | "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", 237 | "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", 238 | "license": "MIT", 239 | "dependencies": { 240 | "@emotion/hash": "^0.9.2", 241 | "@emotion/memoize": "^0.9.0", 242 | "@emotion/unitless": "^0.10.0", 243 | "@emotion/utils": "^1.4.2", 244 | "csstype": "^3.0.2" 245 | } 246 | }, 247 | "node_modules/@emotion/sheet": { 248 | "version": "1.4.0", 249 | "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", 250 | "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", 251 | "license": "MIT" 252 | }, 253 | "node_modules/@emotion/styled": { 254 | "version": "11.14.0", 255 | "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.0.tgz", 256 | "integrity": "sha512-XxfOnXFffatap2IyCeJyNov3kiDQWoR08gPUQxvbL7fxKryGBKUZUkG6Hz48DZwVrJSVh9sJboyV1Ds4OW6SgA==", 257 | "license": "MIT", 258 | "dependencies": { 259 | "@babel/runtime": "^7.18.3", 260 | "@emotion/babel-plugin": "^11.13.5", 261 | "@emotion/is-prop-valid": "^1.3.0", 262 | "@emotion/serialize": "^1.3.3", 263 | "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", 264 | "@emotion/utils": "^1.4.2" 265 | }, 266 | "peerDependencies": { 267 | "@emotion/react": "^11.0.0-rc.0", 268 | "react": ">=16.8.0" 269 | }, 270 | "peerDependenciesMeta": { 271 | "@types/react": { 272 | "optional": true 273 | } 274 | } 275 | }, 276 | "node_modules/@emotion/unitless": { 277 | "version": "0.10.0", 278 | "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", 279 | "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", 280 | "license": "MIT" 281 | }, 282 | "node_modules/@emotion/use-insertion-effect-with-fallbacks": { 283 | "version": "1.2.0", 284 | "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", 285 | "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", 286 | "license": "MIT", 287 | "peerDependencies": { 288 | "react": ">=16.8.0" 289 | } 290 | }, 291 | "node_modules/@emotion/utils": { 292 | "version": "1.4.2", 293 | "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", 294 | "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", 295 | "license": "MIT" 296 | }, 297 | "node_modules/@emotion/weak-memoize": { 298 | "version": "0.4.0", 299 | "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", 300 | "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", 301 | "license": "MIT" 302 | }, 303 | "node_modules/@jridgewell/gen-mapping": { 304 | "version": "0.3.8", 305 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", 306 | "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", 307 | "license": "MIT", 308 | "dependencies": { 309 | "@jridgewell/set-array": "^1.2.1", 310 | "@jridgewell/sourcemap-codec": "^1.4.10", 311 | "@jridgewell/trace-mapping": "^0.3.24" 312 | }, 313 | "engines": { 314 | "node": ">=6.0.0" 315 | } 316 | }, 317 | "node_modules/@jridgewell/resolve-uri": { 318 | "version": "3.1.2", 319 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", 320 | "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", 321 | "license": "MIT", 322 | "engines": { 323 | "node": ">=6.0.0" 324 | } 325 | }, 326 | "node_modules/@jridgewell/set-array": { 327 | "version": "1.2.1", 328 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", 329 | "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", 330 | "license": "MIT", 331 | "engines": { 332 | "node": ">=6.0.0" 333 | } 334 | }, 335 | "node_modules/@jridgewell/sourcemap-codec": { 336 | "version": "1.5.0", 337 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", 338 | "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", 339 | "license": "MIT" 340 | }, 341 | "node_modules/@jridgewell/trace-mapping": { 342 | "version": "0.3.25", 343 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", 344 | "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", 345 | "license": "MIT", 346 | "dependencies": { 347 | "@jridgewell/resolve-uri": "^3.1.0", 348 | "@jridgewell/sourcemap-codec": "^1.4.14" 349 | } 350 | }, 351 | "node_modules/@mui/core-downloads-tracker": { 352 | "version": "7.0.2", 353 | "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.0.2.tgz", 354 | "integrity": "sha512-TfeFU9TgN1N06hyb/pV/63FfO34nijZRMqgHk0TJ3gkl4Fbd+wZ73+ZtOd7jag6hMmzO9HSrBc6Vdn591nhkAg==", 355 | "license": "MIT", 356 | "funding": { 357 | "type": "opencollective", 358 | "url": "https://opencollective.com/mui-org" 359 | } 360 | }, 361 | "node_modules/@mui/material": { 362 | "version": "7.0.2", 363 | "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.0.2.tgz", 364 | "integrity": "sha512-rjJlJ13+3LdLfobRplkXbjIFEIkn6LgpetgU/Cs3Xd8qINCCQK9qXQIjjQ6P0FXFTPFzEVMj0VgBR1mN+FhOcA==", 365 | "license": "MIT", 366 | "dependencies": { 367 | "@babel/runtime": "^7.27.0", 368 | "@mui/core-downloads-tracker": "^7.0.2", 369 | "@mui/system": "^7.0.2", 370 | "@mui/types": "^7.4.1", 371 | "@mui/utils": "^7.0.2", 372 | "@popperjs/core": "^2.11.8", 373 | "@types/react-transition-group": "^4.4.12", 374 | "clsx": "^2.1.1", 375 | "csstype": "^3.1.3", 376 | "prop-types": "^15.8.1", 377 | "react-is": "^19.1.0", 378 | "react-transition-group": "^4.4.5" 379 | }, 380 | "engines": { 381 | "node": ">=14.0.0" 382 | }, 383 | "funding": { 384 | "type": "opencollective", 385 | "url": "https://opencollective.com/mui-org" 386 | }, 387 | "peerDependencies": { 388 | "@emotion/react": "^11.5.0", 389 | "@emotion/styled": "^11.3.0", 390 | "@mui/material-pigment-css": "^7.0.2", 391 | "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", 392 | "react": "^17.0.0 || ^18.0.0 || ^19.0.0", 393 | "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" 394 | }, 395 | "peerDependenciesMeta": { 396 | "@emotion/react": { 397 | "optional": true 398 | }, 399 | "@emotion/styled": { 400 | "optional": true 401 | }, 402 | "@mui/material-pigment-css": { 403 | "optional": true 404 | }, 405 | "@types/react": { 406 | "optional": true 407 | } 408 | } 409 | }, 410 | "node_modules/@mui/private-theming": { 411 | "version": "7.0.2", 412 | "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.0.2.tgz", 413 | "integrity": "sha512-6lt8heDC9wN8YaRqEdhqnm0cFCv08AMf4IlttFvOVn7ZdKd81PNpD/rEtPGLLwQAFyyKSxBG4/2XCgpbcdNKiA==", 414 | "license": "MIT", 415 | "dependencies": { 416 | "@babel/runtime": "^7.27.0", 417 | "@mui/utils": "^7.0.2", 418 | "prop-types": "^15.8.1" 419 | }, 420 | "engines": { 421 | "node": ">=14.0.0" 422 | }, 423 | "funding": { 424 | "type": "opencollective", 425 | "url": "https://opencollective.com/mui-org" 426 | }, 427 | "peerDependencies": { 428 | "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", 429 | "react": "^17.0.0 || ^18.0.0 || ^19.0.0" 430 | }, 431 | "peerDependenciesMeta": { 432 | "@types/react": { 433 | "optional": true 434 | } 435 | } 436 | }, 437 | "node_modules/@mui/styled-engine": { 438 | "version": "7.0.2", 439 | "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.0.2.tgz", 440 | "integrity": "sha512-11Bt4YdHGlh7sB8P75S9mRCUxTlgv7HGbr0UKz6m6Z9KLeiw1Bm9y/t3iqLLVMvSHYB6zL8X8X+LmfTE++gyBw==", 441 | "license": "MIT", 442 | "dependencies": { 443 | "@babel/runtime": "^7.27.0", 444 | "@emotion/cache": "^11.13.5", 445 | "@emotion/serialize": "^1.3.3", 446 | "@emotion/sheet": "^1.4.0", 447 | "csstype": "^3.1.3", 448 | "prop-types": "^15.8.1" 449 | }, 450 | "engines": { 451 | "node": ">=14.0.0" 452 | }, 453 | "funding": { 454 | "type": "opencollective", 455 | "url": "https://opencollective.com/mui-org" 456 | }, 457 | "peerDependencies": { 458 | "@emotion/react": "^11.4.1", 459 | "@emotion/styled": "^11.3.0", 460 | "react": "^17.0.0 || ^18.0.0 || ^19.0.0" 461 | }, 462 | "peerDependenciesMeta": { 463 | "@emotion/react": { 464 | "optional": true 465 | }, 466 | "@emotion/styled": { 467 | "optional": true 468 | } 469 | } 470 | }, 471 | "node_modules/@mui/system": { 472 | "version": "7.0.2", 473 | "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.0.2.tgz", 474 | "integrity": "sha512-yFUraAWYWuKIISPPEVPSQ1NLeqmTT4qiQ+ktmyS8LO/KwHxB+NNVOacEZaIofh5x1NxY8rzphvU5X2heRZ/RDA==", 475 | "license": "MIT", 476 | "dependencies": { 477 | "@babel/runtime": "^7.27.0", 478 | "@mui/private-theming": "^7.0.2", 479 | "@mui/styled-engine": "^7.0.2", 480 | "@mui/types": "^7.4.1", 481 | "@mui/utils": "^7.0.2", 482 | "clsx": "^2.1.1", 483 | "csstype": "^3.1.3", 484 | "prop-types": "^15.8.1" 485 | }, 486 | "engines": { 487 | "node": ">=14.0.0" 488 | }, 489 | "funding": { 490 | "type": "opencollective", 491 | "url": "https://opencollective.com/mui-org" 492 | }, 493 | "peerDependencies": { 494 | "@emotion/react": "^11.5.0", 495 | "@emotion/styled": "^11.3.0", 496 | "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", 497 | "react": "^17.0.0 || ^18.0.0 || ^19.0.0" 498 | }, 499 | "peerDependenciesMeta": { 500 | "@emotion/react": { 501 | "optional": true 502 | }, 503 | "@emotion/styled": { 504 | "optional": true 505 | }, 506 | "@types/react": { 507 | "optional": true 508 | } 509 | } 510 | }, 511 | "node_modules/@mui/types": { 512 | "version": "7.4.1", 513 | "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.1.tgz", 514 | "integrity": "sha512-gUL8IIAI52CRXP/MixT1tJKt3SI6tVv4U/9soFsTtAsHzaJQptZ42ffdHZV3niX1ei0aUgMvOxBBN0KYqdG39g==", 515 | "license": "MIT", 516 | "dependencies": { 517 | "@babel/runtime": "^7.27.0" 518 | }, 519 | "peerDependencies": { 520 | "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" 521 | }, 522 | "peerDependenciesMeta": { 523 | "@types/react": { 524 | "optional": true 525 | } 526 | } 527 | }, 528 | "node_modules/@mui/utils": { 529 | "version": "7.0.2", 530 | "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.0.2.tgz", 531 | "integrity": "sha512-72gcuQjPzhj/MLmPHLCgZjy2VjOH4KniR/4qRtXTTXIEwbkgcN+Y5W/rC90rWtMmZbjt9svZev/z+QHUI4j74w==", 532 | "license": "MIT", 533 | "dependencies": { 534 | "@babel/runtime": "^7.27.0", 535 | "@mui/types": "^7.4.1", 536 | "@types/prop-types": "^15.7.14", 537 | "clsx": "^2.1.1", 538 | "prop-types": "^15.8.1", 539 | "react-is": "^19.1.0" 540 | }, 541 | "engines": { 542 | "node": ">=14.0.0" 543 | }, 544 | "funding": { 545 | "type": "opencollective", 546 | "url": "https://opencollective.com/mui-org" 547 | }, 548 | "peerDependencies": { 549 | "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", 550 | "react": "^17.0.0 || ^18.0.0 || ^19.0.0" 551 | }, 552 | "peerDependenciesMeta": { 553 | "@types/react": { 554 | "optional": true 555 | } 556 | } 557 | }, 558 | "node_modules/@popperjs/core": { 559 | "version": "2.11.8", 560 | "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", 561 | "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", 562 | "license": "MIT", 563 | "funding": { 564 | "type": "opencollective", 565 | "url": "https://opencollective.com/popperjs" 566 | } 567 | }, 568 | "node_modules/@primer/octicons-react": { 569 | "version": "19.15.1", 570 | "resolved": "https://registry.npmjs.org/@primer/octicons-react/-/octicons-react-19.15.1.tgz", 571 | "integrity": "sha512-U9g8sj2ON2cKF1jvs3cEfhW51BNkOXjbdi5qPMSY5e4T7KVKR1gK9BZ/gpB4oTqkjoL2dikaWXdnH8vhwyR6lg==", 572 | "license": "MIT", 573 | "engines": { 574 | "node": ">=8" 575 | }, 576 | "peerDependencies": { 577 | "react": ">=16.3" 578 | } 579 | }, 580 | "node_modules/@types/hast": { 581 | "version": "2.3.10", 582 | "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", 583 | "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", 584 | "license": "MIT", 585 | "dependencies": { 586 | "@types/unist": "^2" 587 | } 588 | }, 589 | "node_modules/@types/parse-json": { 590 | "version": "4.0.2", 591 | "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", 592 | "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", 593 | "license": "MIT" 594 | }, 595 | "node_modules/@types/prop-types": { 596 | "version": "15.7.14", 597 | "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", 598 | "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", 599 | "license": "MIT" 600 | }, 601 | "node_modules/@types/react": { 602 | "version": "19.1.0", 603 | "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.0.tgz", 604 | "integrity": "sha512-UaicktuQI+9UKyA4njtDOGBD/67t8YEBt2xdfqu8+gP9hqPUPsiXlNPcpS2gVdjmis5GKPG3fCxbQLVgxsQZ8w==", 605 | "license": "MIT", 606 | "peer": true, 607 | "dependencies": { 608 | "csstype": "^3.0.2" 609 | } 610 | }, 611 | "node_modules/@types/react-transition-group": { 612 | "version": "4.4.12", 613 | "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", 614 | "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", 615 | "license": "MIT", 616 | "peerDependencies": { 617 | "@types/react": "*" 618 | } 619 | }, 620 | "node_modules/@types/unist": { 621 | "version": "2.0.11", 622 | "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", 623 | "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", 624 | "license": "MIT" 625 | }, 626 | "node_modules/asn1.js": { 627 | "version": "4.10.1", 628 | "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", 629 | "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", 630 | "dev": true, 631 | "license": "MIT", 632 | "dependencies": { 633 | "bn.js": "^4.0.0", 634 | "inherits": "^2.0.1", 635 | "minimalistic-assert": "^1.0.0" 636 | } 637 | }, 638 | "node_modules/asn1.js/node_modules/bn.js": { 639 | "version": "4.12.1", 640 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", 641 | "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", 642 | "dev": true, 643 | "license": "MIT" 644 | }, 645 | "node_modules/assert": { 646 | "version": "1.5.1", 647 | "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.1.tgz", 648 | "integrity": "sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==", 649 | "dev": true, 650 | "license": "MIT", 651 | "dependencies": { 652 | "object.assign": "^4.1.4", 653 | "util": "^0.10.4" 654 | } 655 | }, 656 | "node_modules/assert/node_modules/inherits": { 657 | "version": "2.0.3", 658 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 659 | "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", 660 | "dev": true, 661 | "license": "ISC" 662 | }, 663 | "node_modules/assert/node_modules/util": { 664 | "version": "0.10.4", 665 | "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", 666 | "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", 667 | "dev": true, 668 | "license": "MIT", 669 | "dependencies": { 670 | "inherits": "2.0.3" 671 | } 672 | }, 673 | "node_modules/babel-plugin-macros": { 674 | "version": "3.1.0", 675 | "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", 676 | "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", 677 | "license": "MIT", 678 | "dependencies": { 679 | "@babel/runtime": "^7.12.5", 680 | "cosmiconfig": "^7.0.0", 681 | "resolve": "^1.19.0" 682 | }, 683 | "engines": { 684 | "node": ">=10", 685 | "npm": ">=6" 686 | } 687 | }, 688 | "node_modules/base64-js": { 689 | "version": "1.5.1", 690 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 691 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 692 | "dev": true, 693 | "funding": [ 694 | { 695 | "type": "github", 696 | "url": "https://github.com/sponsors/feross" 697 | }, 698 | { 699 | "type": "patreon", 700 | "url": "https://www.patreon.com/feross" 701 | }, 702 | { 703 | "type": "consulting", 704 | "url": "https://feross.org/support" 705 | } 706 | ], 707 | "license": "MIT" 708 | }, 709 | "node_modules/bn.js": { 710 | "version": "5.2.1", 711 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", 712 | "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", 713 | "dev": true, 714 | "license": "MIT" 715 | }, 716 | "node_modules/brorand": { 717 | "version": "1.1.0", 718 | "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", 719 | "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", 720 | "dev": true, 721 | "license": "MIT" 722 | }, 723 | "node_modules/browserify-aes": { 724 | "version": "1.2.0", 725 | "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", 726 | "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", 727 | "dev": true, 728 | "license": "MIT", 729 | "dependencies": { 730 | "buffer-xor": "^1.0.3", 731 | "cipher-base": "^1.0.0", 732 | "create-hash": "^1.1.0", 733 | "evp_bytestokey": "^1.0.3", 734 | "inherits": "^2.0.1", 735 | "safe-buffer": "^5.0.1" 736 | } 737 | }, 738 | "node_modules/browserify-cipher": { 739 | "version": "1.0.1", 740 | "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", 741 | "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", 742 | "dev": true, 743 | "license": "MIT", 744 | "dependencies": { 745 | "browserify-aes": "^1.0.4", 746 | "browserify-des": "^1.0.0", 747 | "evp_bytestokey": "^1.0.0" 748 | } 749 | }, 750 | "node_modules/browserify-des": { 751 | "version": "1.0.2", 752 | "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", 753 | "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", 754 | "dev": true, 755 | "license": "MIT", 756 | "dependencies": { 757 | "cipher-base": "^1.0.1", 758 | "des.js": "^1.0.0", 759 | "inherits": "^2.0.1", 760 | "safe-buffer": "^5.1.2" 761 | } 762 | }, 763 | "node_modules/browserify-rsa": { 764 | "version": "4.1.1", 765 | "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", 766 | "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", 767 | "dev": true, 768 | "license": "MIT", 769 | "dependencies": { 770 | "bn.js": "^5.2.1", 771 | "randombytes": "^2.1.0", 772 | "safe-buffer": "^5.2.1" 773 | }, 774 | "engines": { 775 | "node": ">= 0.10" 776 | } 777 | }, 778 | "node_modules/browserify-sign": { 779 | "version": "4.2.3", 780 | "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", 781 | "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", 782 | "dev": true, 783 | "license": "ISC", 784 | "dependencies": { 785 | "bn.js": "^5.2.1", 786 | "browserify-rsa": "^4.1.0", 787 | "create-hash": "^1.2.0", 788 | "create-hmac": "^1.1.7", 789 | "elliptic": "^6.5.5", 790 | "hash-base": "~3.0", 791 | "inherits": "^2.0.4", 792 | "parse-asn1": "^5.1.7", 793 | "readable-stream": "^2.3.8", 794 | "safe-buffer": "^5.2.1" 795 | }, 796 | "engines": { 797 | "node": ">= 0.12" 798 | } 799 | }, 800 | "node_modules/browserify-zlib": { 801 | "version": "0.2.0", 802 | "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", 803 | "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", 804 | "dev": true, 805 | "license": "MIT", 806 | "dependencies": { 807 | "pako": "~1.0.5" 808 | } 809 | }, 810 | "node_modules/buffer": { 811 | "version": "4.9.2", 812 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", 813 | "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", 814 | "dev": true, 815 | "license": "MIT", 816 | "dependencies": { 817 | "base64-js": "^1.0.2", 818 | "ieee754": "^1.1.4", 819 | "isarray": "^1.0.0" 820 | } 821 | }, 822 | "node_modules/buffer-xor": { 823 | "version": "1.0.3", 824 | "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", 825 | "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", 826 | "dev": true, 827 | "license": "MIT" 828 | }, 829 | "node_modules/builtin-status-codes": { 830 | "version": "3.0.0", 831 | "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", 832 | "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", 833 | "dev": true, 834 | "license": "MIT" 835 | }, 836 | "node_modules/call-bind": { 837 | "version": "1.0.8", 838 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", 839 | "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", 840 | "dev": true, 841 | "license": "MIT", 842 | "dependencies": { 843 | "call-bind-apply-helpers": "^1.0.0", 844 | "es-define-property": "^1.0.0", 845 | "get-intrinsic": "^1.2.4", 846 | "set-function-length": "^1.2.2" 847 | }, 848 | "engines": { 849 | "node": ">= 0.4" 850 | }, 851 | "funding": { 852 | "url": "https://github.com/sponsors/ljharb" 853 | } 854 | }, 855 | "node_modules/call-bind-apply-helpers": { 856 | "version": "1.0.2", 857 | "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", 858 | "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", 859 | "dev": true, 860 | "license": "MIT", 861 | "dependencies": { 862 | "es-errors": "^1.3.0", 863 | "function-bind": "^1.1.2" 864 | }, 865 | "engines": { 866 | "node": ">= 0.4" 867 | } 868 | }, 869 | "node_modules/call-bound": { 870 | "version": "1.0.4", 871 | "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", 872 | "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", 873 | "dev": true, 874 | "license": "MIT", 875 | "dependencies": { 876 | "call-bind-apply-helpers": "^1.0.2", 877 | "get-intrinsic": "^1.3.0" 878 | }, 879 | "engines": { 880 | "node": ">= 0.4" 881 | }, 882 | "funding": { 883 | "url": "https://github.com/sponsors/ljharb" 884 | } 885 | }, 886 | "node_modules/callsites": { 887 | "version": "3.1.0", 888 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 889 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 890 | "license": "MIT", 891 | "engines": { 892 | "node": ">=6" 893 | } 894 | }, 895 | "node_modules/character-entities": { 896 | "version": "1.2.4", 897 | "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", 898 | "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", 899 | "license": "MIT", 900 | "funding": { 901 | "type": "github", 902 | "url": "https://github.com/sponsors/wooorm" 903 | } 904 | }, 905 | "node_modules/character-entities-legacy": { 906 | "version": "1.1.4", 907 | "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", 908 | "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", 909 | "license": "MIT", 910 | "funding": { 911 | "type": "github", 912 | "url": "https://github.com/sponsors/wooorm" 913 | } 914 | }, 915 | "node_modules/character-reference-invalid": { 916 | "version": "1.1.4", 917 | "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", 918 | "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", 919 | "license": "MIT", 920 | "funding": { 921 | "type": "github", 922 | "url": "https://github.com/sponsors/wooorm" 923 | } 924 | }, 925 | "node_modules/cipher-base": { 926 | "version": "1.0.6", 927 | "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz", 928 | "integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==", 929 | "dev": true, 930 | "license": "MIT", 931 | "dependencies": { 932 | "inherits": "^2.0.4", 933 | "safe-buffer": "^5.2.1" 934 | }, 935 | "engines": { 936 | "node": ">= 0.10" 937 | } 938 | }, 939 | "node_modules/clsx": { 940 | "version": "2.1.1", 941 | "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", 942 | "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", 943 | "license": "MIT", 944 | "engines": { 945 | "node": ">=6" 946 | } 947 | }, 948 | "node_modules/comma-separated-tokens": { 949 | "version": "1.0.8", 950 | "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", 951 | "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", 952 | "license": "MIT", 953 | "funding": { 954 | "type": "github", 955 | "url": "https://github.com/sponsors/wooorm" 956 | } 957 | }, 958 | "node_modules/console-browserify": { 959 | "version": "1.2.0", 960 | "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", 961 | "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", 962 | "dev": true 963 | }, 964 | "node_modules/constants-browserify": { 965 | "version": "1.0.0", 966 | "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", 967 | "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", 968 | "dev": true, 969 | "license": "MIT" 970 | }, 971 | "node_modules/convert-source-map": { 972 | "version": "1.9.0", 973 | "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", 974 | "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", 975 | "license": "MIT" 976 | }, 977 | "node_modules/core-util-is": { 978 | "version": "1.0.3", 979 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", 980 | "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", 981 | "dev": true, 982 | "license": "MIT" 983 | }, 984 | "node_modules/cosmiconfig": { 985 | "version": "7.1.0", 986 | "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", 987 | "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", 988 | "license": "MIT", 989 | "dependencies": { 990 | "@types/parse-json": "^4.0.0", 991 | "import-fresh": "^3.2.1", 992 | "parse-json": "^5.0.0", 993 | "path-type": "^4.0.0", 994 | "yaml": "^1.10.0" 995 | }, 996 | "engines": { 997 | "node": ">=10" 998 | } 999 | }, 1000 | "node_modules/create-ecdh": { 1001 | "version": "4.0.4", 1002 | "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", 1003 | "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", 1004 | "dev": true, 1005 | "license": "MIT", 1006 | "dependencies": { 1007 | "bn.js": "^4.1.0", 1008 | "elliptic": "^6.5.3" 1009 | } 1010 | }, 1011 | "node_modules/create-ecdh/node_modules/bn.js": { 1012 | "version": "4.12.1", 1013 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", 1014 | "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", 1015 | "dev": true, 1016 | "license": "MIT" 1017 | }, 1018 | "node_modules/create-hash": { 1019 | "version": "1.2.0", 1020 | "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", 1021 | "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", 1022 | "dev": true, 1023 | "license": "MIT", 1024 | "dependencies": { 1025 | "cipher-base": "^1.0.1", 1026 | "inherits": "^2.0.1", 1027 | "md5.js": "^1.3.4", 1028 | "ripemd160": "^2.0.1", 1029 | "sha.js": "^2.4.0" 1030 | } 1031 | }, 1032 | "node_modules/create-hmac": { 1033 | "version": "1.1.7", 1034 | "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", 1035 | "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", 1036 | "dev": true, 1037 | "license": "MIT", 1038 | "dependencies": { 1039 | "cipher-base": "^1.0.3", 1040 | "create-hash": "^1.1.0", 1041 | "inherits": "^2.0.1", 1042 | "ripemd160": "^2.0.0", 1043 | "safe-buffer": "^5.0.1", 1044 | "sha.js": "^2.4.8" 1045 | } 1046 | }, 1047 | "node_modules/crypto-browserify": { 1048 | "version": "3.12.1", 1049 | "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", 1050 | "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", 1051 | "dev": true, 1052 | "license": "MIT", 1053 | "dependencies": { 1054 | "browserify-cipher": "^1.0.1", 1055 | "browserify-sign": "^4.2.3", 1056 | "create-ecdh": "^4.0.4", 1057 | "create-hash": "^1.2.0", 1058 | "create-hmac": "^1.1.7", 1059 | "diffie-hellman": "^5.0.3", 1060 | "hash-base": "~3.0.4", 1061 | "inherits": "^2.0.4", 1062 | "pbkdf2": "^3.1.2", 1063 | "public-encrypt": "^4.0.3", 1064 | "randombytes": "^2.1.0", 1065 | "randomfill": "^1.0.4" 1066 | }, 1067 | "engines": { 1068 | "node": ">= 0.10" 1069 | }, 1070 | "funding": { 1071 | "url": "https://github.com/sponsors/ljharb" 1072 | } 1073 | }, 1074 | "node_modules/csstype": { 1075 | "version": "3.1.3", 1076 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", 1077 | "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", 1078 | "license": "MIT" 1079 | }, 1080 | "node_modules/debug": { 1081 | "version": "4.4.0", 1082 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", 1083 | "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", 1084 | "license": "MIT", 1085 | "dependencies": { 1086 | "ms": "^2.1.3" 1087 | }, 1088 | "engines": { 1089 | "node": ">=6.0" 1090 | }, 1091 | "peerDependenciesMeta": { 1092 | "supports-color": { 1093 | "optional": true 1094 | } 1095 | } 1096 | }, 1097 | "node_modules/define-data-property": { 1098 | "version": "1.1.4", 1099 | "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", 1100 | "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", 1101 | "dev": true, 1102 | "license": "MIT", 1103 | "dependencies": { 1104 | "es-define-property": "^1.0.0", 1105 | "es-errors": "^1.3.0", 1106 | "gopd": "^1.0.1" 1107 | }, 1108 | "engines": { 1109 | "node": ">= 0.4" 1110 | }, 1111 | "funding": { 1112 | "url": "https://github.com/sponsors/ljharb" 1113 | } 1114 | }, 1115 | "node_modules/define-properties": { 1116 | "version": "1.2.1", 1117 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", 1118 | "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", 1119 | "dev": true, 1120 | "license": "MIT", 1121 | "dependencies": { 1122 | "define-data-property": "^1.0.1", 1123 | "has-property-descriptors": "^1.0.0", 1124 | "object-keys": "^1.1.1" 1125 | }, 1126 | "engines": { 1127 | "node": ">= 0.4" 1128 | }, 1129 | "funding": { 1130 | "url": "https://github.com/sponsors/ljharb" 1131 | } 1132 | }, 1133 | "node_modules/des.js": { 1134 | "version": "1.1.0", 1135 | "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", 1136 | "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", 1137 | "dev": true, 1138 | "license": "MIT", 1139 | "dependencies": { 1140 | "inherits": "^2.0.1", 1141 | "minimalistic-assert": "^1.0.0" 1142 | } 1143 | }, 1144 | "node_modules/diffie-hellman": { 1145 | "version": "5.0.3", 1146 | "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", 1147 | "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", 1148 | "dev": true, 1149 | "license": "MIT", 1150 | "dependencies": { 1151 | "bn.js": "^4.1.0", 1152 | "miller-rabin": "^4.0.0", 1153 | "randombytes": "^2.0.0" 1154 | } 1155 | }, 1156 | "node_modules/diffie-hellman/node_modules/bn.js": { 1157 | "version": "4.12.1", 1158 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", 1159 | "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", 1160 | "dev": true, 1161 | "license": "MIT" 1162 | }, 1163 | "node_modules/dom-helpers": { 1164 | "version": "5.2.1", 1165 | "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", 1166 | "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", 1167 | "license": "MIT", 1168 | "dependencies": { 1169 | "@babel/runtime": "^7.8.7", 1170 | "csstype": "^3.0.2" 1171 | } 1172 | }, 1173 | "node_modules/domain-browser": { 1174 | "version": "1.2.0", 1175 | "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", 1176 | "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", 1177 | "dev": true, 1178 | "license": "MIT", 1179 | "engines": { 1180 | "node": ">=0.4", 1181 | "npm": ">=1.2" 1182 | } 1183 | }, 1184 | "node_modules/dunder-proto": { 1185 | "version": "1.0.1", 1186 | "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", 1187 | "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", 1188 | "dev": true, 1189 | "license": "MIT", 1190 | "dependencies": { 1191 | "call-bind-apply-helpers": "^1.0.1", 1192 | "es-errors": "^1.3.0", 1193 | "gopd": "^1.2.0" 1194 | }, 1195 | "engines": { 1196 | "node": ">= 0.4" 1197 | } 1198 | }, 1199 | "node_modules/elliptic": { 1200 | "version": "6.6.1", 1201 | "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", 1202 | "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", 1203 | "dev": true, 1204 | "license": "MIT", 1205 | "dependencies": { 1206 | "bn.js": "^4.11.9", 1207 | "brorand": "^1.1.0", 1208 | "hash.js": "^1.0.0", 1209 | "hmac-drbg": "^1.0.1", 1210 | "inherits": "^2.0.4", 1211 | "minimalistic-assert": "^1.0.1", 1212 | "minimalistic-crypto-utils": "^1.0.1" 1213 | } 1214 | }, 1215 | "node_modules/elliptic/node_modules/bn.js": { 1216 | "version": "4.12.1", 1217 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", 1218 | "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", 1219 | "dev": true, 1220 | "license": "MIT" 1221 | }, 1222 | "node_modules/error-ex": { 1223 | "version": "1.3.2", 1224 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", 1225 | "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", 1226 | "license": "MIT", 1227 | "dependencies": { 1228 | "is-arrayish": "^0.2.1" 1229 | } 1230 | }, 1231 | "node_modules/es-define-property": { 1232 | "version": "1.0.1", 1233 | "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", 1234 | "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", 1235 | "dev": true, 1236 | "license": "MIT", 1237 | "engines": { 1238 | "node": ">= 0.4" 1239 | } 1240 | }, 1241 | "node_modules/es-errors": { 1242 | "version": "1.3.0", 1243 | "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", 1244 | "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", 1245 | "dev": true, 1246 | "license": "MIT", 1247 | "engines": { 1248 | "node": ">= 0.4" 1249 | } 1250 | }, 1251 | "node_modules/es-object-atoms": { 1252 | "version": "1.1.1", 1253 | "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", 1254 | "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", 1255 | "dev": true, 1256 | "license": "MIT", 1257 | "dependencies": { 1258 | "es-errors": "^1.3.0" 1259 | }, 1260 | "engines": { 1261 | "node": ">= 0.4" 1262 | } 1263 | }, 1264 | "node_modules/escape-string-regexp": { 1265 | "version": "4.0.0", 1266 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 1267 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 1268 | "license": "MIT", 1269 | "engines": { 1270 | "node": ">=10" 1271 | }, 1272 | "funding": { 1273 | "url": "https://github.com/sponsors/sindresorhus" 1274 | } 1275 | }, 1276 | "node_modules/events": { 1277 | "version": "3.3.0", 1278 | "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", 1279 | "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", 1280 | "dev": true, 1281 | "license": "MIT", 1282 | "engines": { 1283 | "node": ">=0.8.x" 1284 | } 1285 | }, 1286 | "node_modules/evp_bytestokey": { 1287 | "version": "1.0.3", 1288 | "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", 1289 | "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", 1290 | "dev": true, 1291 | "license": "MIT", 1292 | "dependencies": { 1293 | "md5.js": "^1.3.4", 1294 | "safe-buffer": "^5.1.1" 1295 | } 1296 | }, 1297 | "node_modules/fault": { 1298 | "version": "1.0.4", 1299 | "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", 1300 | "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", 1301 | "license": "MIT", 1302 | "dependencies": { 1303 | "format": "^0.2.0" 1304 | }, 1305 | "funding": { 1306 | "type": "github", 1307 | "url": "https://github.com/sponsors/wooorm" 1308 | } 1309 | }, 1310 | "node_modules/find-root": { 1311 | "version": "1.1.0", 1312 | "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", 1313 | "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", 1314 | "license": "MIT" 1315 | }, 1316 | "node_modules/format": { 1317 | "version": "0.2.2", 1318 | "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", 1319 | "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", 1320 | "engines": { 1321 | "node": ">=0.4.x" 1322 | } 1323 | }, 1324 | "node_modules/function-bind": { 1325 | "version": "1.1.2", 1326 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 1327 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 1328 | "license": "MIT", 1329 | "funding": { 1330 | "url": "https://github.com/sponsors/ljharb" 1331 | } 1332 | }, 1333 | "node_modules/get-intrinsic": { 1334 | "version": "1.3.0", 1335 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", 1336 | "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", 1337 | "dev": true, 1338 | "license": "MIT", 1339 | "dependencies": { 1340 | "call-bind-apply-helpers": "^1.0.2", 1341 | "es-define-property": "^1.0.1", 1342 | "es-errors": "^1.3.0", 1343 | "es-object-atoms": "^1.1.1", 1344 | "function-bind": "^1.1.2", 1345 | "get-proto": "^1.0.1", 1346 | "gopd": "^1.2.0", 1347 | "has-symbols": "^1.1.0", 1348 | "hasown": "^2.0.2", 1349 | "math-intrinsics": "^1.1.0" 1350 | }, 1351 | "engines": { 1352 | "node": ">= 0.4" 1353 | }, 1354 | "funding": { 1355 | "url": "https://github.com/sponsors/ljharb" 1356 | } 1357 | }, 1358 | "node_modules/get-proto": { 1359 | "version": "1.0.1", 1360 | "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", 1361 | "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", 1362 | "dev": true, 1363 | "license": "MIT", 1364 | "dependencies": { 1365 | "dunder-proto": "^1.0.1", 1366 | "es-object-atoms": "^1.0.0" 1367 | }, 1368 | "engines": { 1369 | "node": ">= 0.4" 1370 | } 1371 | }, 1372 | "node_modules/globals": { 1373 | "version": "11.12.0", 1374 | "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", 1375 | "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", 1376 | "license": "MIT", 1377 | "engines": { 1378 | "node": ">=4" 1379 | } 1380 | }, 1381 | "node_modules/gopd": { 1382 | "version": "1.2.0", 1383 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", 1384 | "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", 1385 | "dev": true, 1386 | "license": "MIT", 1387 | "engines": { 1388 | "node": ">= 0.4" 1389 | }, 1390 | "funding": { 1391 | "url": "https://github.com/sponsors/ljharb" 1392 | } 1393 | }, 1394 | "node_modules/has-property-descriptors": { 1395 | "version": "1.0.2", 1396 | "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", 1397 | "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", 1398 | "dev": true, 1399 | "license": "MIT", 1400 | "dependencies": { 1401 | "es-define-property": "^1.0.0" 1402 | }, 1403 | "funding": { 1404 | "url": "https://github.com/sponsors/ljharb" 1405 | } 1406 | }, 1407 | "node_modules/has-symbols": { 1408 | "version": "1.1.0", 1409 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", 1410 | "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", 1411 | "dev": true, 1412 | "license": "MIT", 1413 | "engines": { 1414 | "node": ">= 0.4" 1415 | }, 1416 | "funding": { 1417 | "url": "https://github.com/sponsors/ljharb" 1418 | } 1419 | }, 1420 | "node_modules/hash-base": { 1421 | "version": "3.0.5", 1422 | "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", 1423 | "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", 1424 | "dev": true, 1425 | "license": "MIT", 1426 | "dependencies": { 1427 | "inherits": "^2.0.4", 1428 | "safe-buffer": "^5.2.1" 1429 | }, 1430 | "engines": { 1431 | "node": ">= 0.10" 1432 | } 1433 | }, 1434 | "node_modules/hash.js": { 1435 | "version": "1.1.7", 1436 | "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", 1437 | "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", 1438 | "dev": true, 1439 | "license": "MIT", 1440 | "dependencies": { 1441 | "inherits": "^2.0.3", 1442 | "minimalistic-assert": "^1.0.1" 1443 | } 1444 | }, 1445 | "node_modules/hasown": { 1446 | "version": "2.0.2", 1447 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", 1448 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", 1449 | "license": "MIT", 1450 | "dependencies": { 1451 | "function-bind": "^1.1.2" 1452 | }, 1453 | "engines": { 1454 | "node": ">= 0.4" 1455 | } 1456 | }, 1457 | "node_modules/hast-util-parse-selector": { 1458 | "version": "2.2.5", 1459 | "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", 1460 | "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", 1461 | "license": "MIT", 1462 | "funding": { 1463 | "type": "opencollective", 1464 | "url": "https://opencollective.com/unified" 1465 | } 1466 | }, 1467 | "node_modules/hastscript": { 1468 | "version": "6.0.0", 1469 | "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", 1470 | "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", 1471 | "license": "MIT", 1472 | "dependencies": { 1473 | "@types/hast": "^2.0.0", 1474 | "comma-separated-tokens": "^1.0.0", 1475 | "hast-util-parse-selector": "^2.0.0", 1476 | "property-information": "^5.0.0", 1477 | "space-separated-tokens": "^1.0.0" 1478 | }, 1479 | "funding": { 1480 | "type": "opencollective", 1481 | "url": "https://opencollective.com/unified" 1482 | } 1483 | }, 1484 | "node_modules/highlight.js": { 1485 | "version": "10.7.3", 1486 | "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", 1487 | "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", 1488 | "license": "BSD-3-Clause", 1489 | "engines": { 1490 | "node": "*" 1491 | } 1492 | }, 1493 | "node_modules/highlightjs-vue": { 1494 | "version": "1.0.0", 1495 | "resolved": "https://registry.npmjs.org/highlightjs-vue/-/highlightjs-vue-1.0.0.tgz", 1496 | "integrity": "sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==", 1497 | "license": "CC0-1.0" 1498 | }, 1499 | "node_modules/hmac-drbg": { 1500 | "version": "1.0.1", 1501 | "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", 1502 | "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", 1503 | "dev": true, 1504 | "license": "MIT", 1505 | "dependencies": { 1506 | "hash.js": "^1.0.3", 1507 | "minimalistic-assert": "^1.0.0", 1508 | "minimalistic-crypto-utils": "^1.0.1" 1509 | } 1510 | }, 1511 | "node_modules/hoist-non-react-statics": { 1512 | "version": "3.3.2", 1513 | "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", 1514 | "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", 1515 | "license": "BSD-3-Clause", 1516 | "dependencies": { 1517 | "react-is": "^16.7.0" 1518 | } 1519 | }, 1520 | "node_modules/hoist-non-react-statics/node_modules/react-is": { 1521 | "version": "16.13.1", 1522 | "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", 1523 | "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", 1524 | "license": "MIT" 1525 | }, 1526 | "node_modules/https-browserify": { 1527 | "version": "1.0.0", 1528 | "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", 1529 | "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", 1530 | "dev": true, 1531 | "license": "MIT" 1532 | }, 1533 | "node_modules/ieee754": { 1534 | "version": "1.2.1", 1535 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 1536 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", 1537 | "dev": true, 1538 | "funding": [ 1539 | { 1540 | "type": "github", 1541 | "url": "https://github.com/sponsors/feross" 1542 | }, 1543 | { 1544 | "type": "patreon", 1545 | "url": "https://www.patreon.com/feross" 1546 | }, 1547 | { 1548 | "type": "consulting", 1549 | "url": "https://feross.org/support" 1550 | } 1551 | ], 1552 | "license": "BSD-3-Clause" 1553 | }, 1554 | "node_modules/immediate": { 1555 | "version": "3.0.6", 1556 | "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", 1557 | "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", 1558 | "license": "MIT" 1559 | }, 1560 | "node_modules/import-fresh": { 1561 | "version": "3.3.1", 1562 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", 1563 | "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", 1564 | "license": "MIT", 1565 | "dependencies": { 1566 | "parent-module": "^1.0.0", 1567 | "resolve-from": "^4.0.0" 1568 | }, 1569 | "engines": { 1570 | "node": ">=6" 1571 | }, 1572 | "funding": { 1573 | "url": "https://github.com/sponsors/sindresorhus" 1574 | } 1575 | }, 1576 | "node_modules/inherits": { 1577 | "version": "2.0.4", 1578 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1579 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 1580 | "dev": true, 1581 | "license": "ISC" 1582 | }, 1583 | "node_modules/is-alphabetical": { 1584 | "version": "1.0.4", 1585 | "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", 1586 | "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", 1587 | "license": "MIT", 1588 | "funding": { 1589 | "type": "github", 1590 | "url": "https://github.com/sponsors/wooorm" 1591 | } 1592 | }, 1593 | "node_modules/is-alphanumerical": { 1594 | "version": "1.0.4", 1595 | "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", 1596 | "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", 1597 | "license": "MIT", 1598 | "dependencies": { 1599 | "is-alphabetical": "^1.0.0", 1600 | "is-decimal": "^1.0.0" 1601 | }, 1602 | "funding": { 1603 | "type": "github", 1604 | "url": "https://github.com/sponsors/wooorm" 1605 | } 1606 | }, 1607 | "node_modules/is-arrayish": { 1608 | "version": "0.2.1", 1609 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", 1610 | "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", 1611 | "license": "MIT" 1612 | }, 1613 | "node_modules/is-core-module": { 1614 | "version": "2.16.1", 1615 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", 1616 | "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", 1617 | "license": "MIT", 1618 | "dependencies": { 1619 | "hasown": "^2.0.2" 1620 | }, 1621 | "engines": { 1622 | "node": ">= 0.4" 1623 | }, 1624 | "funding": { 1625 | "url": "https://github.com/sponsors/ljharb" 1626 | } 1627 | }, 1628 | "node_modules/is-decimal": { 1629 | "version": "1.0.4", 1630 | "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", 1631 | "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", 1632 | "license": "MIT", 1633 | "funding": { 1634 | "type": "github", 1635 | "url": "https://github.com/sponsors/wooorm" 1636 | } 1637 | }, 1638 | "node_modules/is-hexadecimal": { 1639 | "version": "1.0.4", 1640 | "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", 1641 | "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", 1642 | "license": "MIT", 1643 | "funding": { 1644 | "type": "github", 1645 | "url": "https://github.com/sponsors/wooorm" 1646 | } 1647 | }, 1648 | "node_modules/isarray": { 1649 | "version": "1.0.0", 1650 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 1651 | "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", 1652 | "dev": true, 1653 | "license": "MIT" 1654 | }, 1655 | "node_modules/isexe": { 1656 | "version": "2.0.0", 1657 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1658 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", 1659 | "dev": true, 1660 | "license": "ISC" 1661 | }, 1662 | "node_modules/js-tokens": { 1663 | "version": "4.0.0", 1664 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 1665 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 1666 | "license": "MIT" 1667 | }, 1668 | "node_modules/jsesc": { 1669 | "version": "3.1.0", 1670 | "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", 1671 | "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", 1672 | "license": "MIT", 1673 | "bin": { 1674 | "jsesc": "bin/jsesc" 1675 | }, 1676 | "engines": { 1677 | "node": ">=6" 1678 | } 1679 | }, 1680 | "node_modules/json-parse-even-better-errors": { 1681 | "version": "2.3.1", 1682 | "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", 1683 | "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", 1684 | "license": "MIT" 1685 | }, 1686 | "node_modules/lie": { 1687 | "version": "3.1.1", 1688 | "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", 1689 | "integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==", 1690 | "license": "MIT", 1691 | "dependencies": { 1692 | "immediate": "~3.0.5" 1693 | } 1694 | }, 1695 | "node_modules/lines-and-columns": { 1696 | "version": "1.2.4", 1697 | "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", 1698 | "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", 1699 | "license": "MIT" 1700 | }, 1701 | "node_modules/localforage": { 1702 | "version": "1.10.0", 1703 | "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz", 1704 | "integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==", 1705 | "license": "Apache-2.0", 1706 | "dependencies": { 1707 | "lie": "3.1.1" 1708 | } 1709 | }, 1710 | "node_modules/loose-envify": { 1711 | "version": "1.4.0", 1712 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", 1713 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", 1714 | "license": "MIT", 1715 | "dependencies": { 1716 | "js-tokens": "^3.0.0 || ^4.0.0" 1717 | }, 1718 | "bin": { 1719 | "loose-envify": "cli.js" 1720 | } 1721 | }, 1722 | "node_modules/lowlight": { 1723 | "version": "1.20.0", 1724 | "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", 1725 | "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", 1726 | "license": "MIT", 1727 | "dependencies": { 1728 | "fault": "^1.0.0", 1729 | "highlight.js": "~10.7.0" 1730 | }, 1731 | "funding": { 1732 | "type": "github", 1733 | "url": "https://github.com/sponsors/wooorm" 1734 | } 1735 | }, 1736 | "node_modules/math-intrinsics": { 1737 | "version": "1.1.0", 1738 | "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", 1739 | "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", 1740 | "dev": true, 1741 | "license": "MIT", 1742 | "engines": { 1743 | "node": ">= 0.4" 1744 | } 1745 | }, 1746 | "node_modules/md5.js": { 1747 | "version": "1.3.5", 1748 | "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", 1749 | "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", 1750 | "dev": true, 1751 | "license": "MIT", 1752 | "dependencies": { 1753 | "hash-base": "^3.0.0", 1754 | "inherits": "^2.0.1", 1755 | "safe-buffer": "^5.1.2" 1756 | } 1757 | }, 1758 | "node_modules/miller-rabin": { 1759 | "version": "4.0.1", 1760 | "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", 1761 | "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", 1762 | "dev": true, 1763 | "license": "MIT", 1764 | "dependencies": { 1765 | "bn.js": "^4.0.0", 1766 | "brorand": "^1.0.1" 1767 | }, 1768 | "bin": { 1769 | "miller-rabin": "bin/miller-rabin" 1770 | } 1771 | }, 1772 | "node_modules/miller-rabin/node_modules/bn.js": { 1773 | "version": "4.12.1", 1774 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", 1775 | "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", 1776 | "dev": true, 1777 | "license": "MIT" 1778 | }, 1779 | "node_modules/minimalistic-assert": { 1780 | "version": "1.0.1", 1781 | "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", 1782 | "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", 1783 | "dev": true, 1784 | "license": "ISC" 1785 | }, 1786 | "node_modules/minimalistic-crypto-utils": { 1787 | "version": "1.0.1", 1788 | "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", 1789 | "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", 1790 | "dev": true, 1791 | "license": "MIT" 1792 | }, 1793 | "node_modules/ms": { 1794 | "version": "2.1.3", 1795 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1796 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 1797 | "license": "MIT" 1798 | }, 1799 | "node_modules/node-libs-browser": { 1800 | "version": "2.2.1", 1801 | "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", 1802 | "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", 1803 | "dev": true, 1804 | "license": "MIT", 1805 | "dependencies": { 1806 | "assert": "^1.1.1", 1807 | "browserify-zlib": "^0.2.0", 1808 | "buffer": "^4.3.0", 1809 | "console-browserify": "^1.1.0", 1810 | "constants-browserify": "^1.0.0", 1811 | "crypto-browserify": "^3.11.0", 1812 | "domain-browser": "^1.1.1", 1813 | "events": "^3.0.0", 1814 | "https-browserify": "^1.0.0", 1815 | "os-browserify": "^0.3.0", 1816 | "path-browserify": "0.0.1", 1817 | "process": "^0.11.10", 1818 | "punycode": "^1.2.4", 1819 | "querystring-es3": "^0.2.0", 1820 | "readable-stream": "^2.3.3", 1821 | "stream-browserify": "^2.0.1", 1822 | "stream-http": "^2.7.2", 1823 | "string_decoder": "^1.0.0", 1824 | "timers-browserify": "^2.0.4", 1825 | "tty-browserify": "0.0.0", 1826 | "url": "^0.11.0", 1827 | "util": "^0.11.0", 1828 | "vm-browserify": "^1.0.1" 1829 | } 1830 | }, 1831 | "node_modules/object-assign": { 1832 | "version": "4.1.1", 1833 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 1834 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", 1835 | "license": "MIT", 1836 | "engines": { 1837 | "node": ">=0.10.0" 1838 | } 1839 | }, 1840 | "node_modules/object-inspect": { 1841 | "version": "1.13.4", 1842 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", 1843 | "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", 1844 | "dev": true, 1845 | "license": "MIT", 1846 | "engines": { 1847 | "node": ">= 0.4" 1848 | }, 1849 | "funding": { 1850 | "url": "https://github.com/sponsors/ljharb" 1851 | } 1852 | }, 1853 | "node_modules/object-keys": { 1854 | "version": "1.1.1", 1855 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 1856 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", 1857 | "dev": true, 1858 | "license": "MIT", 1859 | "engines": { 1860 | "node": ">= 0.4" 1861 | } 1862 | }, 1863 | "node_modules/object.assign": { 1864 | "version": "4.1.7", 1865 | "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", 1866 | "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", 1867 | "dev": true, 1868 | "license": "MIT", 1869 | "dependencies": { 1870 | "call-bind": "^1.0.8", 1871 | "call-bound": "^1.0.3", 1872 | "define-properties": "^1.2.1", 1873 | "es-object-atoms": "^1.0.0", 1874 | "has-symbols": "^1.1.0", 1875 | "object-keys": "^1.1.1" 1876 | }, 1877 | "engines": { 1878 | "node": ">= 0.4" 1879 | }, 1880 | "funding": { 1881 | "url": "https://github.com/sponsors/ljharb" 1882 | } 1883 | }, 1884 | "node_modules/os-browserify": { 1885 | "version": "0.3.0", 1886 | "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", 1887 | "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", 1888 | "dev": true, 1889 | "license": "MIT" 1890 | }, 1891 | "node_modules/pako": { 1892 | "version": "1.0.11", 1893 | "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", 1894 | "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", 1895 | "dev": true, 1896 | "license": "(MIT AND Zlib)" 1897 | }, 1898 | "node_modules/parent-module": { 1899 | "version": "1.0.1", 1900 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 1901 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 1902 | "license": "MIT", 1903 | "dependencies": { 1904 | "callsites": "^3.0.0" 1905 | }, 1906 | "engines": { 1907 | "node": ">=6" 1908 | } 1909 | }, 1910 | "node_modules/parse-asn1": { 1911 | "version": "5.1.7", 1912 | "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz", 1913 | "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", 1914 | "dev": true, 1915 | "license": "ISC", 1916 | "dependencies": { 1917 | "asn1.js": "^4.10.1", 1918 | "browserify-aes": "^1.2.0", 1919 | "evp_bytestokey": "^1.0.3", 1920 | "hash-base": "~3.0", 1921 | "pbkdf2": "^3.1.2", 1922 | "safe-buffer": "^5.2.1" 1923 | }, 1924 | "engines": { 1925 | "node": ">= 0.10" 1926 | } 1927 | }, 1928 | "node_modules/parse-entities": { 1929 | "version": "2.0.0", 1930 | "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", 1931 | "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", 1932 | "license": "MIT", 1933 | "dependencies": { 1934 | "character-entities": "^1.0.0", 1935 | "character-entities-legacy": "^1.0.0", 1936 | "character-reference-invalid": "^1.0.0", 1937 | "is-alphanumerical": "^1.0.0", 1938 | "is-decimal": "^1.0.0", 1939 | "is-hexadecimal": "^1.0.0" 1940 | }, 1941 | "funding": { 1942 | "type": "github", 1943 | "url": "https://github.com/sponsors/wooorm" 1944 | } 1945 | }, 1946 | "node_modules/parse-json": { 1947 | "version": "5.2.0", 1948 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", 1949 | "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", 1950 | "license": "MIT", 1951 | "dependencies": { 1952 | "@babel/code-frame": "^7.0.0", 1953 | "error-ex": "^1.3.1", 1954 | "json-parse-even-better-errors": "^2.3.0", 1955 | "lines-and-columns": "^1.1.6" 1956 | }, 1957 | "engines": { 1958 | "node": ">=8" 1959 | }, 1960 | "funding": { 1961 | "url": "https://github.com/sponsors/sindresorhus" 1962 | } 1963 | }, 1964 | "node_modules/path-browserify": { 1965 | "version": "0.0.1", 1966 | "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", 1967 | "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", 1968 | "dev": true, 1969 | "license": "MIT" 1970 | }, 1971 | "node_modules/path-parse": { 1972 | "version": "1.0.7", 1973 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 1974 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 1975 | "license": "MIT" 1976 | }, 1977 | "node_modules/path-type": { 1978 | "version": "4.0.0", 1979 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", 1980 | "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", 1981 | "license": "MIT", 1982 | "engines": { 1983 | "node": ">=8" 1984 | } 1985 | }, 1986 | "node_modules/pbkdf2": { 1987 | "version": "3.1.2", 1988 | "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", 1989 | "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", 1990 | "dev": true, 1991 | "license": "MIT", 1992 | "dependencies": { 1993 | "create-hash": "^1.1.2", 1994 | "create-hmac": "^1.1.4", 1995 | "ripemd160": "^2.0.1", 1996 | "safe-buffer": "^5.0.1", 1997 | "sha.js": "^2.4.8" 1998 | }, 1999 | "engines": { 2000 | "node": ">=0.12" 2001 | } 2002 | }, 2003 | "node_modules/picocolors": { 2004 | "version": "1.1.1", 2005 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", 2006 | "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", 2007 | "license": "ISC" 2008 | }, 2009 | "node_modules/prismjs": { 2010 | "version": "1.30.0", 2011 | "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", 2012 | "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", 2013 | "license": "MIT", 2014 | "engines": { 2015 | "node": ">=6" 2016 | } 2017 | }, 2018 | "node_modules/process": { 2019 | "version": "0.11.10", 2020 | "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", 2021 | "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", 2022 | "dev": true, 2023 | "license": "MIT", 2024 | "engines": { 2025 | "node": ">= 0.6.0" 2026 | } 2027 | }, 2028 | "node_modules/process-nextick-args": { 2029 | "version": "2.0.1", 2030 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 2031 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", 2032 | "dev": true, 2033 | "license": "MIT" 2034 | }, 2035 | "node_modules/prop-types": { 2036 | "version": "15.8.1", 2037 | "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", 2038 | "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", 2039 | "license": "MIT", 2040 | "dependencies": { 2041 | "loose-envify": "^1.4.0", 2042 | "object-assign": "^4.1.1", 2043 | "react-is": "^16.13.1" 2044 | } 2045 | }, 2046 | "node_modules/prop-types/node_modules/react-is": { 2047 | "version": "16.13.1", 2048 | "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", 2049 | "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", 2050 | "license": "MIT" 2051 | }, 2052 | "node_modules/property-information": { 2053 | "version": "5.6.0", 2054 | "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", 2055 | "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", 2056 | "license": "MIT", 2057 | "dependencies": { 2058 | "xtend": "^4.0.0" 2059 | }, 2060 | "funding": { 2061 | "type": "github", 2062 | "url": "https://github.com/sponsors/wooorm" 2063 | } 2064 | }, 2065 | "node_modules/public-encrypt": { 2066 | "version": "4.0.3", 2067 | "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", 2068 | "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", 2069 | "dev": true, 2070 | "license": "MIT", 2071 | "dependencies": { 2072 | "bn.js": "^4.1.0", 2073 | "browserify-rsa": "^4.0.0", 2074 | "create-hash": "^1.1.0", 2075 | "parse-asn1": "^5.0.0", 2076 | "randombytes": "^2.0.1", 2077 | "safe-buffer": "^5.1.2" 2078 | } 2079 | }, 2080 | "node_modules/public-encrypt/node_modules/bn.js": { 2081 | "version": "4.12.1", 2082 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", 2083 | "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", 2084 | "dev": true, 2085 | "license": "MIT" 2086 | }, 2087 | "node_modules/punycode": { 2088 | "version": "1.4.1", 2089 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 2090 | "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", 2091 | "dev": true, 2092 | "license": "MIT" 2093 | }, 2094 | "node_modules/qs": { 2095 | "version": "6.14.0", 2096 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", 2097 | "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", 2098 | "dev": true, 2099 | "license": "BSD-3-Clause", 2100 | "dependencies": { 2101 | "side-channel": "^1.1.0" 2102 | }, 2103 | "engines": { 2104 | "node": ">=0.6" 2105 | }, 2106 | "funding": { 2107 | "url": "https://github.com/sponsors/ljharb" 2108 | } 2109 | }, 2110 | "node_modules/querystring-es3": { 2111 | "version": "0.2.1", 2112 | "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", 2113 | "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", 2114 | "dev": true, 2115 | "engines": { 2116 | "node": ">=0.4.x" 2117 | } 2118 | }, 2119 | "node_modules/randombytes": { 2120 | "version": "2.1.0", 2121 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 2122 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 2123 | "dev": true, 2124 | "license": "MIT", 2125 | "dependencies": { 2126 | "safe-buffer": "^5.1.0" 2127 | } 2128 | }, 2129 | "node_modules/randomfill": { 2130 | "version": "1.0.4", 2131 | "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", 2132 | "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", 2133 | "dev": true, 2134 | "license": "MIT", 2135 | "dependencies": { 2136 | "randombytes": "^2.0.5", 2137 | "safe-buffer": "^5.1.0" 2138 | } 2139 | }, 2140 | "node_modules/react": { 2141 | "version": "18.3.1", 2142 | "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", 2143 | "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", 2144 | "license": "MIT", 2145 | "dependencies": { 2146 | "loose-envify": "^1.1.0" 2147 | }, 2148 | "engines": { 2149 | "node": ">=0.10.0" 2150 | } 2151 | }, 2152 | "node_modules/react-dom": { 2153 | "version": "18.3.1", 2154 | "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", 2155 | "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", 2156 | "license": "MIT", 2157 | "dependencies": { 2158 | "loose-envify": "^1.1.0", 2159 | "scheduler": "^0.23.2" 2160 | }, 2161 | "peerDependencies": { 2162 | "react": "^18.3.1" 2163 | } 2164 | }, 2165 | "node_modules/react-is": { 2166 | "version": "19.1.0", 2167 | "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz", 2168 | "integrity": "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==", 2169 | "license": "MIT" 2170 | }, 2171 | "node_modules/react-syntax-highlighter": { 2172 | "version": "15.6.1", 2173 | "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.6.1.tgz", 2174 | "integrity": "sha512-OqJ2/vL7lEeV5zTJyG7kmARppUjiB9h9udl4qHQjjgEos66z00Ia0OckwYfRxCSFrW8RJIBnsBwQsHZbVPspqg==", 2175 | "license": "MIT", 2176 | "dependencies": { 2177 | "@babel/runtime": "^7.3.1", 2178 | "highlight.js": "^10.4.1", 2179 | "highlightjs-vue": "^1.0.0", 2180 | "lowlight": "^1.17.0", 2181 | "prismjs": "^1.27.0", 2182 | "refractor": "^3.6.0" 2183 | }, 2184 | "peerDependencies": { 2185 | "react": ">= 0.14.0" 2186 | } 2187 | }, 2188 | "node_modules/react-transition-group": { 2189 | "version": "4.4.5", 2190 | "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", 2191 | "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", 2192 | "license": "BSD-3-Clause", 2193 | "dependencies": { 2194 | "@babel/runtime": "^7.5.5", 2195 | "dom-helpers": "^5.0.1", 2196 | "loose-envify": "^1.4.0", 2197 | "prop-types": "^15.6.2" 2198 | }, 2199 | "peerDependencies": { 2200 | "react": ">=16.6.0", 2201 | "react-dom": ">=16.6.0" 2202 | } 2203 | }, 2204 | "node_modules/readable-stream": { 2205 | "version": "2.3.8", 2206 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", 2207 | "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", 2208 | "dev": true, 2209 | "license": "MIT", 2210 | "dependencies": { 2211 | "core-util-is": "~1.0.0", 2212 | "inherits": "~2.0.3", 2213 | "isarray": "~1.0.0", 2214 | "process-nextick-args": "~2.0.0", 2215 | "safe-buffer": "~5.1.1", 2216 | "string_decoder": "~1.1.1", 2217 | "util-deprecate": "~1.0.1" 2218 | } 2219 | }, 2220 | "node_modules/readable-stream/node_modules/safe-buffer": { 2221 | "version": "5.1.2", 2222 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 2223 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 2224 | "dev": true, 2225 | "license": "MIT" 2226 | }, 2227 | "node_modules/readable-stream/node_modules/string_decoder": { 2228 | "version": "1.1.1", 2229 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 2230 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 2231 | "dev": true, 2232 | "license": "MIT", 2233 | "dependencies": { 2234 | "safe-buffer": "~5.1.0" 2235 | } 2236 | }, 2237 | "node_modules/readline-sync": { 2238 | "version": "1.4.10", 2239 | "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.10.tgz", 2240 | "integrity": "sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw==", 2241 | "dev": true, 2242 | "license": "MIT", 2243 | "engines": { 2244 | "node": ">= 0.8.0" 2245 | } 2246 | }, 2247 | "node_modules/refractor": { 2248 | "version": "3.6.0", 2249 | "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", 2250 | "integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==", 2251 | "license": "MIT", 2252 | "dependencies": { 2253 | "hastscript": "^6.0.0", 2254 | "parse-entities": "^2.0.0", 2255 | "prismjs": "~1.27.0" 2256 | }, 2257 | "funding": { 2258 | "type": "github", 2259 | "url": "https://github.com/sponsors/wooorm" 2260 | } 2261 | }, 2262 | "node_modules/refractor/node_modules/prismjs": { 2263 | "version": "1.27.0", 2264 | "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz", 2265 | "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==", 2266 | "license": "MIT", 2267 | "engines": { 2268 | "node": ">=6" 2269 | } 2270 | }, 2271 | "node_modules/regenerator-runtime": { 2272 | "version": "0.14.1", 2273 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", 2274 | "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", 2275 | "license": "MIT" 2276 | }, 2277 | "node_modules/resolve": { 2278 | "version": "1.22.10", 2279 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", 2280 | "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", 2281 | "license": "MIT", 2282 | "dependencies": { 2283 | "is-core-module": "^2.16.0", 2284 | "path-parse": "^1.0.7", 2285 | "supports-preserve-symlinks-flag": "^1.0.0" 2286 | }, 2287 | "bin": { 2288 | "resolve": "bin/resolve" 2289 | }, 2290 | "engines": { 2291 | "node": ">= 0.4" 2292 | }, 2293 | "funding": { 2294 | "url": "https://github.com/sponsors/ljharb" 2295 | } 2296 | }, 2297 | "node_modules/resolve-from": { 2298 | "version": "4.0.0", 2299 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 2300 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 2301 | "license": "MIT", 2302 | "engines": { 2303 | "node": ">=4" 2304 | } 2305 | }, 2306 | "node_modules/ripemd160": { 2307 | "version": "2.0.2", 2308 | "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", 2309 | "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", 2310 | "dev": true, 2311 | "license": "MIT", 2312 | "dependencies": { 2313 | "hash-base": "^3.0.0", 2314 | "inherits": "^2.0.1" 2315 | } 2316 | }, 2317 | "node_modules/safe-buffer": { 2318 | "version": "5.2.1", 2319 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 2320 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 2321 | "dev": true, 2322 | "funding": [ 2323 | { 2324 | "type": "github", 2325 | "url": "https://github.com/sponsors/feross" 2326 | }, 2327 | { 2328 | "type": "patreon", 2329 | "url": "https://www.patreon.com/feross" 2330 | }, 2331 | { 2332 | "type": "consulting", 2333 | "url": "https://feross.org/support" 2334 | } 2335 | ], 2336 | "license": "MIT" 2337 | }, 2338 | "node_modules/scheduler": { 2339 | "version": "0.23.2", 2340 | "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", 2341 | "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", 2342 | "license": "MIT", 2343 | "dependencies": { 2344 | "loose-envify": "^1.1.0" 2345 | } 2346 | }, 2347 | "node_modules/set-function-length": { 2348 | "version": "1.2.2", 2349 | "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", 2350 | "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", 2351 | "dev": true, 2352 | "license": "MIT", 2353 | "dependencies": { 2354 | "define-data-property": "^1.1.4", 2355 | "es-errors": "^1.3.0", 2356 | "function-bind": "^1.1.2", 2357 | "get-intrinsic": "^1.2.4", 2358 | "gopd": "^1.0.1", 2359 | "has-property-descriptors": "^1.0.2" 2360 | }, 2361 | "engines": { 2362 | "node": ">= 0.4" 2363 | } 2364 | }, 2365 | "node_modules/setimmediate": { 2366 | "version": "1.0.5", 2367 | "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", 2368 | "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", 2369 | "dev": true, 2370 | "license": "MIT" 2371 | }, 2372 | "node_modules/sha.js": { 2373 | "version": "2.4.11", 2374 | "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", 2375 | "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", 2376 | "dev": true, 2377 | "license": "(MIT AND BSD-3-Clause)", 2378 | "dependencies": { 2379 | "inherits": "^2.0.1", 2380 | "safe-buffer": "^5.0.1" 2381 | }, 2382 | "bin": { 2383 | "sha.js": "bin.js" 2384 | } 2385 | }, 2386 | "node_modules/shadow-cljs": { 2387 | "version": "2.28.23", 2388 | "resolved": "https://registry.npmjs.org/shadow-cljs/-/shadow-cljs-2.28.23.tgz", 2389 | "integrity": "sha512-SM7LeLctZLLCm6Y3NxWOH4GvHqHDZ6Jz9bUgfpJrk1jMADqIp3rliD6Rrd12gLX2b9/oEh6UyD7X+yw6O1++sw==", 2390 | "dev": true, 2391 | "license": "ISC", 2392 | "dependencies": { 2393 | "node-libs-browser": "^2.2.1", 2394 | "readline-sync": "^1.4.7", 2395 | "shadow-cljs-jar": "1.3.4", 2396 | "source-map-support": "^0.4.15", 2397 | "which": "^1.3.1", 2398 | "ws": "^7.4.6" 2399 | }, 2400 | "bin": { 2401 | "shadow-cljs": "cli/runner.js" 2402 | }, 2403 | "engines": { 2404 | "node": ">=6.0.0" 2405 | } 2406 | }, 2407 | "node_modules/shadow-cljs-jar": { 2408 | "version": "1.3.4", 2409 | "resolved": "https://registry.npmjs.org/shadow-cljs-jar/-/shadow-cljs-jar-1.3.4.tgz", 2410 | "integrity": "sha512-cZB2pzVXBnhpJ6PQdsjO+j/MksR28mv4QD/hP/2y1fsIa9Z9RutYgh3N34FZ8Ktl4puAXaIGlct+gMCJ5BmwmA==", 2411 | "dev": true, 2412 | "license": "ISC" 2413 | }, 2414 | "node_modules/side-channel": { 2415 | "version": "1.1.0", 2416 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", 2417 | "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", 2418 | "dev": true, 2419 | "license": "MIT", 2420 | "dependencies": { 2421 | "es-errors": "^1.3.0", 2422 | "object-inspect": "^1.13.3", 2423 | "side-channel-list": "^1.0.0", 2424 | "side-channel-map": "^1.0.1", 2425 | "side-channel-weakmap": "^1.0.2" 2426 | }, 2427 | "engines": { 2428 | "node": ">= 0.4" 2429 | }, 2430 | "funding": { 2431 | "url": "https://github.com/sponsors/ljharb" 2432 | } 2433 | }, 2434 | "node_modules/side-channel-list": { 2435 | "version": "1.0.0", 2436 | "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", 2437 | "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", 2438 | "dev": true, 2439 | "license": "MIT", 2440 | "dependencies": { 2441 | "es-errors": "^1.3.0", 2442 | "object-inspect": "^1.13.3" 2443 | }, 2444 | "engines": { 2445 | "node": ">= 0.4" 2446 | }, 2447 | "funding": { 2448 | "url": "https://github.com/sponsors/ljharb" 2449 | } 2450 | }, 2451 | "node_modules/side-channel-map": { 2452 | "version": "1.0.1", 2453 | "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", 2454 | "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", 2455 | "dev": true, 2456 | "license": "MIT", 2457 | "dependencies": { 2458 | "call-bound": "^1.0.2", 2459 | "es-errors": "^1.3.0", 2460 | "get-intrinsic": "^1.2.5", 2461 | "object-inspect": "^1.13.3" 2462 | }, 2463 | "engines": { 2464 | "node": ">= 0.4" 2465 | }, 2466 | "funding": { 2467 | "url": "https://github.com/sponsors/ljharb" 2468 | } 2469 | }, 2470 | "node_modules/side-channel-weakmap": { 2471 | "version": "1.0.2", 2472 | "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", 2473 | "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", 2474 | "dev": true, 2475 | "license": "MIT", 2476 | "dependencies": { 2477 | "call-bound": "^1.0.2", 2478 | "es-errors": "^1.3.0", 2479 | "get-intrinsic": "^1.2.5", 2480 | "object-inspect": "^1.13.3", 2481 | "side-channel-map": "^1.0.1" 2482 | }, 2483 | "engines": { 2484 | "node": ">= 0.4" 2485 | }, 2486 | "funding": { 2487 | "url": "https://github.com/sponsors/ljharb" 2488 | } 2489 | }, 2490 | "node_modules/source-map": { 2491 | "version": "0.5.7", 2492 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", 2493 | "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", 2494 | "license": "BSD-3-Clause", 2495 | "engines": { 2496 | "node": ">=0.10.0" 2497 | } 2498 | }, 2499 | "node_modules/source-map-support": { 2500 | "version": "0.4.18", 2501 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", 2502 | "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", 2503 | "dev": true, 2504 | "license": "MIT", 2505 | "dependencies": { 2506 | "source-map": "^0.5.6" 2507 | } 2508 | }, 2509 | "node_modules/space-separated-tokens": { 2510 | "version": "1.1.5", 2511 | "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", 2512 | "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", 2513 | "license": "MIT", 2514 | "funding": { 2515 | "type": "github", 2516 | "url": "https://github.com/sponsors/wooorm" 2517 | } 2518 | }, 2519 | "node_modules/stream-browserify": { 2520 | "version": "2.0.2", 2521 | "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", 2522 | "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", 2523 | "dev": true, 2524 | "license": "MIT", 2525 | "dependencies": { 2526 | "inherits": "~2.0.1", 2527 | "readable-stream": "^2.0.2" 2528 | } 2529 | }, 2530 | "node_modules/stream-http": { 2531 | "version": "2.8.3", 2532 | "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", 2533 | "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", 2534 | "dev": true, 2535 | "license": "MIT", 2536 | "dependencies": { 2537 | "builtin-status-codes": "^3.0.0", 2538 | "inherits": "^2.0.1", 2539 | "readable-stream": "^2.3.6", 2540 | "to-arraybuffer": "^1.0.0", 2541 | "xtend": "^4.0.0" 2542 | } 2543 | }, 2544 | "node_modules/string_decoder": { 2545 | "version": "1.3.0", 2546 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 2547 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 2548 | "dev": true, 2549 | "license": "MIT", 2550 | "dependencies": { 2551 | "safe-buffer": "~5.2.0" 2552 | } 2553 | }, 2554 | "node_modules/stylis": { 2555 | "version": "4.2.0", 2556 | "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", 2557 | "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", 2558 | "license": "MIT" 2559 | }, 2560 | "node_modules/supports-preserve-symlinks-flag": { 2561 | "version": "1.0.0", 2562 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 2563 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 2564 | "license": "MIT", 2565 | "engines": { 2566 | "node": ">= 0.4" 2567 | }, 2568 | "funding": { 2569 | "url": "https://github.com/sponsors/ljharb" 2570 | } 2571 | }, 2572 | "node_modules/timers-browserify": { 2573 | "version": "2.0.12", 2574 | "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", 2575 | "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", 2576 | "dev": true, 2577 | "license": "MIT", 2578 | "dependencies": { 2579 | "setimmediate": "^1.0.4" 2580 | }, 2581 | "engines": { 2582 | "node": ">=0.6.0" 2583 | } 2584 | }, 2585 | "node_modules/to-arraybuffer": { 2586 | "version": "1.0.1", 2587 | "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", 2588 | "integrity": "sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==", 2589 | "dev": true, 2590 | "license": "MIT" 2591 | }, 2592 | "node_modules/tty-browserify": { 2593 | "version": "0.0.0", 2594 | "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", 2595 | "integrity": "sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==", 2596 | "dev": true, 2597 | "license": "MIT" 2598 | }, 2599 | "node_modules/url": { 2600 | "version": "0.11.4", 2601 | "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", 2602 | "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", 2603 | "dev": true, 2604 | "license": "MIT", 2605 | "dependencies": { 2606 | "punycode": "^1.4.1", 2607 | "qs": "^6.12.3" 2608 | }, 2609 | "engines": { 2610 | "node": ">= 0.4" 2611 | } 2612 | }, 2613 | "node_modules/util": { 2614 | "version": "0.11.1", 2615 | "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", 2616 | "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", 2617 | "dev": true, 2618 | "license": "MIT", 2619 | "dependencies": { 2620 | "inherits": "2.0.3" 2621 | } 2622 | }, 2623 | "node_modules/util-deprecate": { 2624 | "version": "1.0.2", 2625 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 2626 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", 2627 | "dev": true, 2628 | "license": "MIT" 2629 | }, 2630 | "node_modules/util/node_modules/inherits": { 2631 | "version": "2.0.3", 2632 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 2633 | "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", 2634 | "dev": true, 2635 | "license": "ISC" 2636 | }, 2637 | "node_modules/vm-browserify": { 2638 | "version": "1.1.2", 2639 | "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", 2640 | "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", 2641 | "dev": true, 2642 | "license": "MIT" 2643 | }, 2644 | "node_modules/which": { 2645 | "version": "1.3.1", 2646 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 2647 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 2648 | "dev": true, 2649 | "license": "ISC", 2650 | "dependencies": { 2651 | "isexe": "^2.0.0" 2652 | }, 2653 | "bin": { 2654 | "which": "bin/which" 2655 | } 2656 | }, 2657 | "node_modules/ws": { 2658 | "version": "7.5.10", 2659 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", 2660 | "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", 2661 | "dev": true, 2662 | "license": "MIT", 2663 | "engines": { 2664 | "node": ">=8.3.0" 2665 | }, 2666 | "peerDependencies": { 2667 | "bufferutil": "^4.0.1", 2668 | "utf-8-validate": "^5.0.2" 2669 | }, 2670 | "peerDependenciesMeta": { 2671 | "bufferutil": { 2672 | "optional": true 2673 | }, 2674 | "utf-8-validate": { 2675 | "optional": true 2676 | } 2677 | } 2678 | }, 2679 | "node_modules/xtend": { 2680 | "version": "4.0.2", 2681 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 2682 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", 2683 | "license": "MIT", 2684 | "engines": { 2685 | "node": ">=0.4" 2686 | } 2687 | }, 2688 | "node_modules/yaml": { 2689 | "version": "1.10.2", 2690 | "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", 2691 | "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", 2692 | "license": "ISC", 2693 | "engines": { 2694 | "node": ">= 6" 2695 | } 2696 | } 2697 | } 2698 | } 2699 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.0.1", 4 | "private": true, 5 | "devDependencies": { 6 | "shadow-cljs": "2.28.23" 7 | }, 8 | "dependencies": { 9 | "@emotion/react": "11.14.0", 10 | "@emotion/styled": "11.14.0", 11 | "@mui/material": "7.0.2", 12 | "@primer/octicons-react": "19.15.1", 13 | "localforage": "1.10.0", 14 | "react": "18.3.1", 15 | "react-dom": "18.3.1", 16 | "react-syntax-highlighter": "15.6.1" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /frontend/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathants/aws-gocljs/155bd13d7faa176dcff0bc25194f04f3c695bde7/frontend/public/favicon.png -------------------------------------------------------------------------------- /frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /frontend/shadow-cljs.edn: -------------------------------------------------------------------------------- 1 | {:source-paths ["src"] 2 | :dependencies [[cljs-http "0.1.48"] 3 | [garden "1.3.10"] 4 | [funcool/bide "1.7.0"] 5 | [reagent "1.3.0"] 6 | [haslett "0.2.0"]] 7 | :nrepl {:port 3333} 8 | :dev-http {8000 {:root "public" 9 | :proxy-url #shadow/env "PROJECT_URL" 10 | :proxy-predicate proxy/proxy-predicate}} 11 | :builds {:app {:target :browser 12 | :output-dir "public/js" 13 | :js-options {:js-provider :shadow} 14 | :modules {:main {:init-fn frontend/main}} 15 | :closure-defines {frontend/ws-domain #shadow/env "PROJECT_DOMAIN_WEBSOCKET"} 16 | :compiler-options {:warnings {:redef false}}}}} 17 | -------------------------------------------------------------------------------- /frontend/src/frontend.cljs: -------------------------------------------------------------------------------- 1 | (ns frontend 2 | (:require-macros [cljs.core.async.macros :refer [go go-loop]]) 3 | (:require [cljs-http.client :as http] 4 | [cljs.core.async :refer [! chan timeout] :as a] 5 | [cljs.pprint :as pp] 6 | [reagent.dom :as reagent.dom] 7 | [reagent.core :as reagent] 8 | [reagent.impl.template :as rtpl] 9 | [bide.core :as bide] 10 | [garden.core :as garden] 11 | [garden.stylesheet :as gs] 12 | [clojure.string :as s] 13 | [haslett.client :as ws] 14 | ["react-syntax-highlighter/dist/esm/languages/prism/go$default" :as go-prism] 15 | ["react-syntax-highlighter/dist/esm/languages/prism/markdown$default" :as markdown-prism] 16 | ["react-syntax-highlighter/dist/esm/prism-light.js$default" :as SyntaxHighlighter] 17 | ["react-syntax-highlighter/dist/esm/styles/prism/darcula$default" :as prism-theme] 18 | ["react" :as react] 19 | ["@mui/material" :as mui] 20 | ["@primer/octicons-react" :as octo])) 21 | 22 | (def adapt reagent/adapt-react-class) 23 | 24 | (set! *warn-on-infer* true) 25 | 26 | (defn log [& args] 27 | (apply js/console.log (map clj->js args))) 28 | 29 | (defn event-key ^str [^js/KeyboardEvent e] 30 | (.-key e)) 31 | 32 | (defn focus [^js/Object e] 33 | (.focus e)) 34 | 35 | (defn query-selector ^js/Object [^js/Object e ^str q] 36 | (.querySelector e q)) 37 | 38 | (defn blur-active [] 39 | (.blur (.-activeElement js/document))) 40 | 41 | (defn target-value [^js/Event e] 42 | (.-value (.-target e))) 43 | 44 | (defn prevent-default [^js/Event e] 45 | (.preventDefault e)) 46 | 47 | (defonce state 48 | (reagent/atom 49 | {:modal-open false 50 | :search-focus false 51 | :key-listener false 52 | :mouse-listener false 53 | :search-text "" 54 | :page nil 55 | :time nil 56 | :drawer-open false})) 57 | 58 | (def solarized-base03 "#002b36") 59 | (def solarized-base02 "#073642") 60 | (def solarized-base01 "#586e75") 61 | (def solarized-base00 "#657b83") 62 | (def solarized-base0 "#839496") 63 | (def solarized-base1 "#93a1a1") 64 | (def solarized-base2 "#eee8d5") 65 | (def solarized-base3 "#fdf6e3") 66 | 67 | (def solarized-yellow "#b58900") 68 | (def solarized-orange "#cb4b16") 69 | (def solarized-red "#dc322f") 70 | (def solarized-magenta "#d33682") 71 | (def solarized-violet "#6c71c4") 72 | (def solarized-blue "#268bd2") 73 | (def solarized-cyan "#2aa198") 74 | (def solarized-green "#859900") 75 | 76 | (def style 77 | (garden/css 78 | [:body {:background-color "rgb(240, 240, 240)" 79 | :overflow-x "hidden"}] 80 | 81 | [:.bg-color {:background-color "rgb(230, 230, 230)"}] 82 | ["*" {:font-family "monospace !important"}] 83 | [:.MuiIconButton-root {:border-radius "10%"}] 84 | [:.MuiAppBar-colorPrimary {:background-color "rgb(230, 230, 230)"}] 85 | [".menu-button .MuiSvgIcon-root" {:width "40px" 86 | :height "40px"}] 87 | [".menu-button:hover" {:color solarized-blue}] 88 | (gs/at-media {:max-width "600px"} 89 | [:.mobile-hide {:display "none !important"}] 90 | [:.desktop-hide {:display "block !important"}]) 91 | (gs/at-media {:min-width "601px"} 92 | [:.mobile-hide {:display "block !important"}] 93 | [:.desktop-hide {:display "none !important"}]))) 94 | 95 | (def card-style 96 | {:style {:padding "20px" 97 | :margin-bottom "10px"} 98 | :class "bg-color"}) 99 | 100 | (def max-retries 7) 101 | 102 | (defn api-delete [route json-params] 103 | (go-loop [i 0] 104 | (let [resp ( mui/Card card-style 137 | [:> mui/Typography 138 | "just ship fullstack web on aws!"]]) 139 | 140 | (.registerLanguage SyntaxHighlighter "go" go-prism) 141 | (.registerLanguage SyntaxHighlighter "markdown" markdown-prism) 142 | 143 | (defn lang [file] 144 | (condp = (last (s/split (last (s/split (:name file) #"/")) #"\.")) 145 | "md" "markdown" 146 | "go" "go" 147 | nil)) 148 | 149 | (defn component-file-content [file] 150 | (condp = (last (s/split (last (s/split (:name file) #"/")) #"\.")) 151 | "gif" [:img {:src (str "data:image/png;base64," (:content file)) 152 | :style {:width "100%"}}] 153 | "png" [:img {:src (str "data:image/png;base64," (:content file)) 154 | :style {:width "100%"}}] 155 | "jpg" [:img {:src (str "data:image/png;base64," (:content file)) 156 | :style {:width "100%"}}] 157 | "jpeg" [:img {:src (str "data:image/png;base64," (:content file)) 158 | :style {:width "100%"}}] 159 | [(adapt SyntaxHighlighter) 160 | {:language (lang file) 161 | :style prism-theme 162 | :custom-style {:background nil} 163 | :show-line-numbers true} 164 | (s/replace (:content file) #"\t" " ")])) 165 | 166 | (def files-rows [{:id 1 167 | :name "cmd/" 168 | :size 0 169 | :modified "2025-04-12"} 170 | {:id 2 171 | :name "server.go" 172 | :size 224 173 | :modified "2025-04-11"} 174 | {:id 3 175 | :name "go.mod" 176 | :size 45 177 | :modified "2025-04-10"} 178 | {:id 4 179 | :name "README.md" 180 | :size 128 181 | :modified "2025-04-09"}]) 182 | 183 | (def files-subdir-rows {"cmd" [{:id 10 184 | :name "main.go" 185 | :size 300 186 | :modified "2025-04-12"} 187 | {:id 20 188 | :name "cli.go" 189 | :size 140 190 | :modified "2025-04-11"}]}) 191 | 192 | (def files-contents {"server.go" ["package main" 193 | "" 194 | "import (" 195 | " \"net/http\"" 196 | " \"fmt\"" 197 | ")" 198 | "" 199 | "func main() {" 200 | " http.HandleFunc(\"/\", func(w http.ResponseWriter, r *http.Request) {" 201 | " fmt.Fprintln(w, \"Hello, world!\")" 202 | " })" 203 | " http.ListenAndServe(\":8080\", nil)" 204 | "}"] 205 | "main.go" ["package main" 206 | "" 207 | "import \"fmt\"" 208 | "" 209 | "func main() {" 210 | " fmt.Println(\"CLI entrypoint\")" 211 | "}"] 212 | "cli.go" ["package main" 213 | "" 214 | "func doSomething() {}"] 215 | "go.mod" ["module example.com/myapp" 216 | "" 217 | "go 1.22"] 218 | "README.md" ["# MyApp" 219 | "" 220 | "Some documentation..."]}) 221 | 222 | (defn component-files [] 223 | (let [parts (:parts @state) 224 | subpath (when (> (count parts) 1) 225 | (s/join "/" (drop 1 parts)))] 226 | (if subpath 227 | (if (= subpath "cmd") 228 | (let [sub-files (get files-subdir-rows subpath [])] 229 | [:> mui/Card card-style 230 | [:> mui/Box 231 | {:style {:border "1px solid #d0d7de" 232 | :border-radius "6px" 233 | :margin-top "0" 234 | :overflow "hidden"}} 235 | [:div 236 | {:style {:padding "8px" 237 | :border-bottom "1px solid #d0d7de" 238 | :display "flex"}} 239 | [:div 240 | [:a 241 | {:href "#/files" 242 | :style {:margin-left "6px" 243 | :color "rgb(50,50,50)" 244 | :text-decoration "none" 245 | :display "inline-flex" 246 | :align-items "center" 247 | :cursor "pointer"}} 248 | "repo"] 249 | (when subpath 250 | (let [crumb-parts (s/split subpath #"/") 251 | cnt (count crumb-parts)] 252 | [:<> 253 | (doall 254 | (map-indexed 255 | (fn [idx c] 256 | (if (< idx (dec cnt)) 257 | [:<> 258 | " / " 259 | [:a 260 | {:href (str "#/files/" (s/join "/" (take (inc idx) crumb-parts))) 261 | :style {:margin-left "3px" 262 | :color "rgb(50,50,50)" 263 | :text-decoration "none" 264 | :display "inline-flex" 265 | :align-items "center" 266 | :cursor "pointer"}} 267 | c]] 268 | [:<> 269 | " / " 270 | [:span 271 | {:style {:margin-left "3px" 272 | :display "inline-flex" 273 | :align-items "center"}} 274 | c]])) 275 | crumb-parts))]))]] 276 | (for [row sub-files] 277 | ^{:key (:id row)} 278 | [:div 279 | {:style {:padding "8px" 280 | :border-bottom "1px solid #d0d7de" 281 | :display "flex" 282 | :&:hover {:background-color "#f6f8fa"}}} 283 | [:div 284 | {:style {:flex "1" 285 | :display "flex" 286 | :align-items "center"}} 287 | (if (s/ends-with? (:name row) "/") 288 | [:> octo/FileDirectoryFillIcon {:style {:color "#57606a"}}] 289 | [:> octo/FileIcon {:style {:color "#57606a"}}]) 290 | [:a 291 | {:href (str "#/files/" subpath "/" (:name row)) 292 | :style {:margin-left "6px" 293 | :color "rgb(50,50,50)" 294 | :text-decoration "none" 295 | :display "inline-flex" 296 | :align-items "center" 297 | :cursor "pointer"}} 298 | [:> mui/Typography (:name row)]]] 299 | [:div 300 | {:style {:flex "1" 301 | :display "flex" 302 | :justify-content "center" 303 | :align-items "center"}} 304 | [:> mui/Typography (str (:size row) " bytes")]] 305 | [:div 306 | {:style {:flex "1" 307 | :display "flex" 308 | :justify-content "flex-end" 309 | :align-items "center"}} 310 | [:> mui/Typography (:modified row)]]])]]) 311 | (let [raw-contents (get files-contents (last (s/split subpath #"/")) 312 | ["No content found."]) 313 | file {:name subpath 314 | :content (if (coll? raw-contents) 315 | (s/join "\n" raw-contents) 316 | raw-contents)}] 317 | [:> mui/Card card-style 318 | [:> mui/Box 319 | {:style {:border "1px solid #d0d7de" 320 | :border-radius "6px" 321 | :margin-top "0" 322 | :overflow "hidden" 323 | :overflow-x "auto"}} 324 | [:div 325 | {:style {:padding "8px" 326 | :border-bottom "1px solid #d0d7de" 327 | :display "flex"}} 328 | [:div 329 | [:a 330 | {:href "#/files" 331 | :style {:margin-left "6px" 332 | :color "rgb(50,50,50)" 333 | :text-decoration "none" 334 | :display "inline-flex" 335 | :align-items "center" 336 | :cursor "pointer"}} 337 | "repo"] 338 | (when subpath 339 | (let [crumb-parts (s/split subpath #"/") 340 | cnt (count crumb-parts)] 341 | [:<> 342 | (doall 343 | (map-indexed 344 | (fn [idx c] 345 | (if (< idx (dec cnt)) 346 | ^{:key idx} 347 | [:<> 348 | " / " 349 | [:a 350 | {:href (str "#/files/" (s/join "/" (take (inc idx) crumb-parts))) 351 | :style {:margin-left "3px" 352 | :color "rgb(50,50,50)" 353 | :text-decoration "none" 354 | :display "inline-flex" 355 | :align-items "center" 356 | :cursor "pointer"}} 357 | c]] 358 | ^{:key idx} 359 | [:<> 360 | " / " 361 | [:span 362 | {:style {:margin-left "3px" 363 | :display "inline-flex" 364 | :align-items "center"}} 365 | c]])) 366 | crumb-parts))]))]] 367 | [component-file-content file]]])) 368 | [:> mui/Card card-style 369 | [:> mui/Box 370 | {:style {:border "1px solid #d0d7de" 371 | :border-radius "6px" 372 | :margin-top "0" 373 | :overflow "hidden"}} 374 | [:div 375 | {:style {:padding "8px" 376 | :border-bottom "1px solid #d0d7de" 377 | :display "flex"}} 378 | [:div 379 | [:a 380 | {:href "#/files" 381 | :style {:margin-left "6px" 382 | :text-decoration "none" 383 | :color "rgb(50,50,50)" 384 | :display "inline-flex" 385 | :align-items "center" 386 | :cursor "pointer"}} 387 | "repo"]]] 388 | (for [row files-rows] 389 | ^{:key (:id row)} 390 | [:div 391 | {:style {:padding "8px" 392 | :border-bottom "1px solid #d0d7de" 393 | :display "flex" 394 | :&:hover {:background-color "#f6f8fa"}}} 395 | [:div 396 | {:style {:flex "1" 397 | :display "flex" 398 | :align-items "center"}} 399 | (if (s/ends-with? (:name row) "/") 400 | [:> octo/FileDirectoryFillIcon {:style {:color "#57606a"}}] 401 | [:> octo/FileIcon {:style {:color "#57606a"}}]) 402 | [:a 403 | {:href (str "#/files/" (:name row)) 404 | :style {:margin-left "6px" 405 | :color "rgb(50,50,50)" 406 | :text-decoration "none" 407 | :display "inline-flex" 408 | :align-items "center" 409 | :cursor "pointer"}} 410 | [:> mui/Typography (:name row)]]] 411 | [:div 412 | {:style {:flex "1" 413 | :display "flex" 414 | :justify-content "center" 415 | :align-items "center"}} 416 | [:> mui/Typography (str (:size row) " bytes")]] 417 | [:div 418 | {:style {:flex "1" 419 | :display "flex" 420 | :justify-content "flex-end" 421 | :align-items "center"}} 422 | [:> mui/Typography (:modified row)]]])]]))) 423 | 424 | (defn component-search [] 425 | [:<> 426 | (for [line (remove s/blank? (s/split (:search-text @state) #"/"))] 427 | ^{:key line} 428 | [:> mui/Card card-style 429 | [:> mui/Typography line]])]) 430 | 431 | (goog-define ws-domain "") ;; defined via environment variable PROJECT_DOMAIN_WEBSOCKET 432 | 433 | (defn start-websocket [] 434 | (go 435 | (let [uid (js/Date.now) 436 | url (str "wss://" ws-domain) 437 | new-stream #(go (let [stream (clj (js/JSON.parse data) :keywordize-keys true)] 444 | (swap! state assoc :websocket-time (:time val)) 445 | (when (= stream (:websocket-stream @state)) 446 | (recur stream)))) 447 | (:close-status stream) ([close-status] (recur ( mui/Card card-style 451 | [:> mui/Typography "time: " (:websocket-time @state)]]) 452 | 453 | (defn component-api [] 454 | [:<> 455 | [:> mui/Card card-style 456 | [:> mui/Button {:full-width true 457 | :variant :contained 458 | :on-click #(do (swap! state merge {:api-progress true 459 | :api-resp nil}) 460 | (go (let [resp ( mui/Card card-style 467 | [:> mui/LinearProgress 468 | {:style {:width "100%" 469 | :height "20px"}}]]) 470 | (when-let [resp (:api-resp @state)] 471 | [:> mui/Card card-style 472 | [:> mui/Typography 473 | (str "status: " (:status resp))] 474 | [:> mui/Typography {:style {:margin-top "10px"}} 475 | (str "time: " (:time (:body resp)))]])]) 476 | 477 | (defn component-not-found [] 478 | [:div 479 | [:p "404"]]) 480 | 481 | (defn component-menu-button 482 | [page-name page-component icon & {:keys [drawer?] 483 | :or {drawer? false}}] 484 | (let [drawer-open? (:drawer-open @state)] 485 | [:> mui/IconButton 486 | {:id page-name 487 | :disable-ripple true 488 | :class "menu-button" 489 | :href (str "#/" page-name) 490 | :on-click #(when drawer-open? 491 | (swap! state assoc :drawer-open false)) 492 | :style (merge {:padding "15px" 493 | :padding-bottom "5px"} 494 | (if (= page-component (:page @state)) 495 | {:color solarized-red}))} 496 | (if drawer? 497 | [:> mui/Grid 498 | {:style {:display "flex" 499 | :align-items "center" 500 | :justify-content "flex-start"}} 501 | [icon] 502 | [:> mui/Typography 503 | {:style {:font-weight 700 504 | :margin-left "6px" 505 | :margin-top "0px" 506 | :margin-bottom "0px"}} 507 | page-name]] 508 | [:> mui/Grid 509 | {:style {:display "flex" 510 | :flex-direction "column" 511 | :align-items "center"}} 512 | [icon] 513 | [:> mui/Typography 514 | {:style {:font-weight 700 515 | :margin-top "3px" 516 | :margin-bottom "5px"}} 517 | page-name]])])) 518 | 519 | (defn component-help [] 520 | [:> mui/Grid {:spacing 0 521 | :align-items "center" 522 | :justify "center" 523 | :style {:display "flex" 524 | :flex-direction "column" 525 | :justify-content "center" 526 | :min-height "100vh"}} 527 | [:> mui/Card {:style {:padding "20px"}} 528 | [:strong "keyboard shortcuts"] 529 | [:ul {:style {:padding-left "25px" 530 | :list-style-type :none}} 531 | [:li "/ search"]]]]) 532 | 533 | (def search-ref (atom nil)) 534 | 535 | ;; For some reason the new MUI doesn't pass ref in the props, 536 | ;; but we can get it using forwardRef? 537 | ;; This is someone incovenient as we need to convert props to Cljs 538 | ;; but reactify-component would also do that. 539 | (def ^:private input-component 540 | (react/forwardRef 541 | (fn [props ref] 542 | (reagent/as-element 543 | [:input (-> (js->clj props :keywordize-keys true) 544 | (assoc :ref ref))])))) 545 | 546 | (def ^:private textarea-component 547 | (react/forwardRef 548 | (fn [props ref] 549 | (reagent/as-element 550 | [:textarea (-> (js->clj props :keywordize-keys true) 551 | (assoc :ref ref))])))) 552 | 553 | ;; To fix cursor jumping when controlled input value is changed, 554 | ;; use wrapper input element created by Reagent instead of 555 | ;; letting Material-UI to create input element directly using React. 556 | ;; Create-element + convert-props-value is the same as what adapt-react-class does. 557 | (defn text-field [props & children] 558 | (let [props (-> props 559 | (assoc-in [:InputProps :inputComponent] 560 | (cond 561 | (and (:multiline props) (:rows props) (not (:maxRows props))) 562 | textarea-component 563 | 564 | ;; FIXME: Autosize multiline field is broken. 565 | (:multiline props) 566 | nil 567 | 568 | ;; Select doesn't require cursor fix so default can be used. 569 | (:select props) 570 | nil 571 | 572 | :else 573 | input-component)) 574 | ;; FIXME: Internal fn should not be used 575 | ;; clj->js is not enough as prop on-change -> onChange, class -> classNames etc should be handled 576 | rtpl/convert-prop-value)] 577 | (apply reagent/create-element mui/TextField props (map reagent/as-element children)))) 578 | 579 | (defn component-form [] 580 | [:<> 581 | [:> mui/Card card-style 582 | [text-field 583 | {:label "enter your data" 584 | :id "data" 585 | :variant :outlined 586 | :full-width true 587 | :focused (:data-focus @state) 588 | :value (:data-text @state) 589 | :on-focus #(swap! state assoc :data-focus true) 590 | :on-blur #(swap! state assoc :data-focus false) 591 | :on-change #(swap! state assoc :data-text (target-value %)) 592 | :style {:margin-bottom "20px" 593 | :min-width "150px"}}] 594 | [text-field 595 | {:label "enter more of your data" 596 | :id "more-data" 597 | :full-width true 598 | :variant :outlined 599 | :focused (:more-data-focus @state) 600 | :value (:more-data-text @state) 601 | :on-focus #(swap! state assoc :more-data-focus true) 602 | :on-blur #(swap! state assoc :more-data-focus false) 603 | :on-change #(swap! state assoc :more-data-text (target-value %)) 604 | :style {:margin-bottom "20px" 605 | :min-width "150px"}}] 606 | [:> mui/Button {:full-width true 607 | :variant :contained 608 | :on-click #(do (swap! state merge {:form-progress true 609 | :form-resp nil}) 610 | (go (let [req {:data (:data-text @state) 611 | :more-data (:more-data-text @state)} 612 | resp ( mui/Card card-style 619 | [:> mui/LinearProgress 620 | {:style {:width "100%" 621 | :height "20px"}}]]) 622 | (when-let [resp (:form-resp @state)] 623 | [:> mui/Card card-style 624 | [:> mui/Typography 625 | (str "status: " (:status resp))] 626 | [:> mui/Typography {:style {:margin-top "10px"}} 627 | (str "message: " (:message (:body resp)))]])]) 628 | 629 | (defn component-drawer [] 630 | [:> mui/Drawer 631 | {:anchor "left" 632 | :open (:drawer-open @state) 633 | :on-close #(swap! state assoc :drawer-open false)} 634 | [:> mui/Box 635 | {:style {:width "100%" :height "100%"} 636 | :on-click (fn [e] 637 | (when (identical? (.-target e) (.-currentTarget e)) 638 | (swap! state assoc :drawer-open false)))} 639 | [:> mui/List 640 | {:disable-padding true 641 | :style {:padding 0}} 642 | [:> mui/ListItem {:style {:margin-top "20px"}} 643 | [component-menu-button "home" component-home (adapt octo/HomeIcon) :drawer? true]] 644 | [:> mui/ListItem 645 | [component-menu-button "files" component-files (adapt octo/FileDirectoryIcon) :drawer? true]] 646 | [:> mui/ListItem 647 | [component-menu-button "api" component-api (adapt octo/GlobeIcon) :drawer? true]] 648 | [:> mui/ListItem 649 | [component-menu-button "form" component-form (adapt octo/DatabaseIcon) :drawer? true]] 650 | [:> mui/ListItem 651 | [component-menu-button "websocket" component-websocket (adapt octo/ServerIcon) :drawer? true]]]]]) 652 | 653 | (defn component-hamburger-button [] 654 | [:> mui/IconButton 655 | {:disable-ripple true 656 | :class "menu-button desktop-hide" 657 | :style {:padding "17px" 658 | :padding-bottom "13px"} 659 | :on-click #(swap! state update :drawer-open not)} 660 | [:> mui/Grid 661 | {:style {:display "flex" :flex-direction "column" :align-items "center"}} 662 | [(adapt octo/ThreeBarsIcon)] 663 | [:> mui/Typography 664 | {:style {:font-weight 700 665 | :margin-top "0px" 666 | :margin-bottom "0px"}} 667 | "menu"]]]) 668 | 669 | (defn component-main [] 670 | [:<> 671 | [:> mui/AppBar 672 | {:position "relative"} 673 | [:> mui/Toolbar 674 | {:style {:padding 0 675 | :white-space "nowrap" 676 | :overflow "hidden"}} 677 | [:div {:class "mobile-hide" 678 | :style {:display "flex" 679 | :flex-wrap "nowrap"}} 680 | [component-menu-button "home" component-home (adapt octo/HomeIcon)] 681 | [component-menu-button "files" component-files (adapt octo/FileDirectoryIcon)] 682 | [component-menu-button "api" component-api (adapt octo/GlobeIcon)] 683 | [component-menu-button "form" component-form (adapt octo/DatabaseIcon)] 684 | [component-menu-button "websocket" component-websocket (adapt octo/ServerIcon)]] 685 | [component-hamburger-button] 686 | [text-field 687 | {:label "search" 688 | :ref #(reset! search-ref %) 689 | :variant :outlined 690 | :id "search" 691 | :full-width true 692 | :focused (:search-focus @state) 693 | :value (:search-text @state) 694 | :on-focus #(swap! state assoc :search-focus true) 695 | :on-blur #(swap! state assoc :search-focus false) 696 | :on-change #(swap! state assoc :search-text (target-value %)) 697 | :style {:margin-right "20px" 698 | :margin-left "5px" 699 | :min-width "150px"}}]]] 700 | [component-drawer] 701 | [:> mui/Container {:id "content" :max-width false :style {:padding 0 :margin-top "10px"}} 702 | [(:page @state)]]]) 703 | 704 | (defn component-root [] 705 | [:<> 706 | [:style style] 707 | (if (:modal-open @state) 708 | [component-help] 709 | [component-main])]) 710 | 711 | (defn mousedown-listener [e] 712 | nil) 713 | 714 | (defn navigate-to [page] 715 | (let [a (js/document.createElement "a")] 716 | (.setAttribute a "href" (str "/#" page)) 717 | (.click a) 718 | (.remove a))) 719 | 720 | (defn keydown-listener [e] 721 | (cond 722 | (:modal-open @state) (swap! state assoc :modal-open false) 723 | (= "Enter" (event-key e)) (when (:search-focus @state) 724 | (swap! state update-in [:search-text] str "/Enter")) 725 | (= "?" (event-key e)) (swap! state assoc :modal-open true) 726 | (#{"INPUT" "TEXTAREA"} (.-tagName js/document.activeElement)) nil 727 | (= "/" (event-key e)) (when-not (:search-focus @state) 728 | (focus (query-selector @search-ref "input")) 729 | (swap! state merge {:search-focus true}) 730 | (prevent-default e)) 731 | :else nil)) 732 | 733 | (defn url [] 734 | (last (s/split js/window.location.href #"#/"))) 735 | 736 | (defn href-parts [] 737 | (s/split (url) #"/")) 738 | 739 | (defn defwatch [key f] 740 | (add-watch state key (fn [key atom old new] 741 | (when (not= (get old key) 742 | (get new key)) 743 | (f (get new key)))))) 744 | 745 | (defwatch :search-text 746 | (fn [text] 747 | (navigate-to (str "/search/")))) 748 | 749 | (defwatch :search-focus 750 | (fn [focus] 751 | (when (and focus (not (s/starts-with? (url) "/search/"))) 752 | (navigate-to "/search/")))) 753 | 754 | (defn on-navigate [component data] 755 | (when (= component-api component) 756 | (swap! state assoc :time nil) 757 | (go (let [resp ( [:proxy-predicate ex config]) 6 | (s/starts-with? (.getRequestPath ex) "/api/")) 7 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module aws-gocljs 2 | 3 | go 1.24 4 | 5 | toolchain go1.24.1 6 | 7 | require ( 8 | github.com/aws/aws-lambda-go v1.48.0 9 | github.com/aws/aws-sdk-go-v2 v1.36.3 10 | github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.18.12 11 | github.com/aws/aws-sdk-go-v2/service/dynamodb v1.42.4 12 | github.com/aws/aws-sdk-go-v2/service/lambda v1.71.2 13 | github.com/aws/aws-sdk-go-v2/service/s3 v1.79.2 14 | github.com/dustin/go-humanize v1.0.1 15 | github.com/gofrs/uuid v4.4.0+incompatible 16 | github.com/nathants/go-dynamolock v0.0.0-20250409081145-4131e1e4f1e8 17 | github.com/nathants/libaws v0.0.0-20250412062845-cfd1a2575af2 18 | ) 19 | 20 | require ( 21 | github.com/avast/retry-go v3.0.0+incompatible // indirect 22 | github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 // indirect 23 | github.com/aws/aws-sdk-go-v2/config v1.29.13 // indirect 24 | github.com/aws/aws-sdk-go-v2/credentials v1.17.66 // indirect 25 | github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression v1.7.76 // indirect 26 | github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect 27 | github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect 28 | github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect 29 | github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect 30 | github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 // indirect 31 | github.com/aws/aws-sdk-go-v2/service/acm v1.31.2 // indirect 32 | github.com/aws/aws-sdk-go-v2/service/apigatewaymanagementapi v1.24.2 // indirect 33 | github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.27.1 // indirect 34 | github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.44.2 // indirect 35 | github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.47.2 // indirect 36 | github.com/aws/aws-sdk-go-v2/service/codecommit v1.28.2 // indirect 37 | github.com/aws/aws-sdk-go-v2/service/costexplorer v1.48.1 // indirect 38 | github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.25.3 // indirect 39 | github.com/aws/aws-sdk-go-v2/service/ec2 v1.211.2 // indirect 40 | github.com/aws/aws-sdk-go-v2/service/ecr v1.43.2 // indirect 41 | github.com/aws/aws-sdk-go-v2/service/ecs v1.54.5 // indirect 42 | github.com/aws/aws-sdk-go-v2/service/eventbridge v1.38.0 // indirect 43 | github.com/aws/aws-sdk-go-v2/service/iam v1.41.1 // indirect 44 | github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect 45 | github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0 // indirect 46 | github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.15 // indirect 47 | github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect 48 | github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 // indirect 49 | github.com/aws/aws-sdk-go-v2/service/organizations v1.38.2 // indirect 50 | github.com/aws/aws-sdk-go-v2/service/route53 v1.51.0 // indirect 51 | github.com/aws/aws-sdk-go-v2/service/ses v1.30.2 // indirect 52 | github.com/aws/aws-sdk-go-v2/service/sns v1.34.3 // indirect 53 | github.com/aws/aws-sdk-go-v2/service/sqs v1.38.4 // indirect 54 | github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 // indirect 55 | github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 // indirect 56 | github.com/aws/aws-sdk-go-v2/service/sts v1.33.18 // indirect 57 | github.com/aws/smithy-go v1.22.2 // indirect 58 | github.com/golang/protobuf v1.5.3 // indirect 59 | github.com/mattn/go-isatty v0.0.20 // indirect 60 | github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a // indirect 61 | github.com/r3labs/diff/v2 v2.15.1 // indirect 62 | github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect 63 | golang.org/x/crypto v0.37.0 // indirect 64 | golang.org/x/sync v0.13.0 // indirect 65 | golang.org/x/sys v0.32.0 // indirect 66 | google.golang.org/appengine v1.6.8 // indirect 67 | google.golang.org/protobuf v1.31.0 // indirect 68 | gopkg.in/yaml.v3 v3.0.1 // indirect 69 | ) 70 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= 2 | github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= 3 | github.com/aws/aws-lambda-go v1.48.0 h1:1aZUYsrJu0yo5fC4z+Rba1KhNImXcJcvHu763BxoyIo= 4 | github.com/aws/aws-lambda-go v1.48.0/go.mod h1:dpMpZgvWx5vuQJfBt0zqBha60q7Dd7RfgJv23DymV8A= 5 | github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM= 6 | github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg= 7 | github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 h1:zAybnyUQXIZ5mok5Jqwlf58/TFE7uvd3IAsa1aF9cXs= 8 | github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10/go.mod h1:qqvMj6gHLR/EXWZw4ZbqlPbQUyenf4h82UQUlKc+l14= 9 | github.com/aws/aws-sdk-go-v2/config v1.29.13 h1:RgdPqWoE8nPpIekpVpDJsBckbqT4Liiaq9f35pbTh1Y= 10 | github.com/aws/aws-sdk-go-v2/config v1.29.13/go.mod h1:NI28qs/IOUIRhsR7GQ/JdexoqRN9tDxkIrYZq0SOF44= 11 | github.com/aws/aws-sdk-go-v2/credentials v1.17.66 h1:aKpEKaTy6n4CEJeYI1MNj97oSDLi4xro3UzQfwf5RWE= 12 | github.com/aws/aws-sdk-go-v2/credentials v1.17.66/go.mod h1:xQ5SusDmHb/fy55wU0QqTy0yNfLqxzec59YcsRZB+rI= 13 | github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.18.12 h1:mwAIR3fhxhSzXFj530LNCBe0JocYVQx6GuJpQiA+QOs= 14 | github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.18.12/go.mod h1:9cWrNL8q7ApFmZzKhnb63ub4zrdMzOGQVn/kxvagfeE= 15 | github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression v1.7.76 h1:E+nmaDmRGhuS2aoMr/vKbwVeckh9BcRqTRL3410ma4U= 16 | github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression v1.7.76/go.mod h1:kGgsBYLBBc663c5xifxCQWGMYfZaT7Kr7UWqBiU+qes= 17 | github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mlnXuFrO4cOd3HLBroh1paFw= 18 | github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M= 19 | github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q= 20 | github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY= 21 | github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0= 22 | github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q= 23 | github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= 24 | github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= 25 | github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 h1:ZNTqv4nIdE/DiBfUUfXcLZ/Spcuz+RjeziUtNJackkM= 26 | github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34/go.mod h1:zf7Vcd1ViW7cPqYWEHLHJkS50X0JS2IKz9Cgaj6ugrs= 27 | github.com/aws/aws-sdk-go-v2/service/acm v1.31.2 h1:CVJXpbU1zZJPi3XEiaKXCi4mvdl1yLHvDV0CWE31QmQ= 28 | github.com/aws/aws-sdk-go-v2/service/acm v1.31.2/go.mod h1:3sKYAgRbuBa2QMYGh/WEclwnmfx+QoPhhX25PdSQSQM= 29 | github.com/aws/aws-sdk-go-v2/service/apigatewaymanagementapi v1.24.2 h1:K8klcITUtmyEqBPjSq/rg0St/CsMUwfLwETjC3B4hUk= 30 | github.com/aws/aws-sdk-go-v2/service/apigatewaymanagementapi v1.24.2/go.mod h1:zJtUxSHKzEvu7CeiViuk5MgDNTWaCSxrGtkJhzO3+A8= 31 | github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.27.1 h1:h+C/Mrb+17iTaCmGuhMAGxxl6Cc7Wf2GqQ7/HG5wiXA= 32 | github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.27.1/go.mod h1:x70T2BgvD2nDaQJCtfg8xuOAxJBILWVog8hxph4DAhk= 33 | github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.44.2 h1:VaR7NCUhvDtn14Idz6krMY32gXtq5FtYjHqz90xyYs4= 34 | github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.44.2/go.mod h1:HJlcOk+S/wjJuR/8jPa8GhnEKdKqqiQ5wjsE1PjuO1o= 35 | github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.47.2 h1:caIDFGKezQQA/kali05x3NF2DVwzjtOFjvNvFnEeCm4= 36 | github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.47.2/go.mod h1:uo14VBn5cNk/BPGTPz3kyLBxgpgOObgO8lmz+H7Z4Ck= 37 | github.com/aws/aws-sdk-go-v2/service/codecommit v1.28.2 h1:enL75gIdaPAoBztv/GDuMgOocEUpO2jYc45qp2Uweqs= 38 | github.com/aws/aws-sdk-go-v2/service/codecommit v1.28.2/go.mod h1:JsdLne5QNlqJdCQFm2DbHLNmNfEWSU7HnTuvi8SIl+E= 39 | github.com/aws/aws-sdk-go-v2/service/costexplorer v1.48.1 h1:ltZEIOBhpGaxkHGD9/FM1f0e3Pre55ulqPurIf4ggBE= 40 | github.com/aws/aws-sdk-go-v2/service/costexplorer v1.48.1/go.mod h1:zaYyuzR0Q8BI9yXtH5Jy9D7394t/96+cq/4qXZPUMxk= 41 | github.com/aws/aws-sdk-go-v2/service/dynamodb v1.42.4 h1:5GjCSGIpndYU/tVABz+4XnAcluU6wrjlPzAAgFUDG98= 42 | github.com/aws/aws-sdk-go-v2/service/dynamodb v1.42.4/go.mod h1:yYaWRnVSPyAmexW5t7G3TcuYoalYfT+xQwzWsvtUQ7M= 43 | github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.25.3 h1:GHC1WTF3ZBZy+gvz2qtYB6ttALVx35hlwc4IzOIUY7g= 44 | github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.25.3/go.mod h1:lUqWdw5/esjPTkITXhN4C66o1ltwDq2qQ12j3SOzhVg= 45 | github.com/aws/aws-sdk-go-v2/service/ec2 v1.211.2 h1:KMoQ43HysbPqs1vufMn9h2UcUyc2WCMaKxYhExKJZuo= 46 | github.com/aws/aws-sdk-go-v2/service/ec2 v1.211.2/go.mod h1:ouvGEfHbLaIlWwpDpOVWPWR+YwO0HDv3vm5tYLq8ImY= 47 | github.com/aws/aws-sdk-go-v2/service/ecr v1.43.2 h1:G6Rj8A8zgukXWSSB8evVE8az2S3Ci/Q3CpSMxJsK4G0= 48 | github.com/aws/aws-sdk-go-v2/service/ecr v1.43.2/go.mod h1:iQ1skgw1XRK+6Lgkb0I9ODatAP72WoTILh0zXQ5DtbU= 49 | github.com/aws/aws-sdk-go-v2/service/ecs v1.54.5 h1:d45Llkjk+redBUe+0YKVxVnndE2pnVSnE8E3wFQjGZg= 50 | github.com/aws/aws-sdk-go-v2/service/ecs v1.54.5/go.mod h1:wAtdeFanDuF9Re/ge4DRDaYe3Wy1OGrU7jG042UcuI4= 51 | github.com/aws/aws-sdk-go-v2/service/eventbridge v1.38.0 h1:481QZ+k5Gs0kAh2srAXUXfy8Mvo8bnTtwvXxkh46iW8= 52 | github.com/aws/aws-sdk-go-v2/service/eventbridge v1.38.0/go.mod h1:QiEUHcyXhCdsTzHAbfmgwlFEmW3WgfqL4L1bS+E9IlA= 53 | github.com/aws/aws-sdk-go-v2/service/iam v1.41.1 h1:Kq3R+K49y23CGC5UQF3Vpw5oZEQk5gF/nn+MekPD0ZY= 54 | github.com/aws/aws-sdk-go-v2/service/iam v1.41.1/go.mod h1:mPJkGQzeCoPs82ElNILor2JzZgYENr4UaSKUT8K27+c= 55 | github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE= 56 | github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA= 57 | github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0 h1:lguz0bmOoGzozP9XfRJR1QIayEYo+2vP/No3OfLF0pU= 58 | github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0/go.mod h1:iu6FSzgt+M2/x3Dk8zhycdIcHjEFb36IS8HVUVFoMg0= 59 | github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.15 h1:M1R1rud7HzDrfCdlBQ7NjnRsDNEhXO/vGhuD189Ggmk= 60 | github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.15/go.mod h1:uvFKBSq9yMPV4LGAi7N4awn4tLY+hKE35f8THes2mzQ= 61 | github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM= 62 | github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY= 63 | github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 h1:moLQUoVq91LiqT1nbvzDukyqAlCv89ZmwaHw/ZFlFZg= 64 | github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15/go.mod h1:ZH34PJUc8ApjBIfgQCFvkWcUDBtl/WTD+uiYHjd8igA= 65 | github.com/aws/aws-sdk-go-v2/service/lambda v1.71.2 h1:z926KZ1Ysi8Mbi4biJSAIRFdKemwQpO9M0QUTRLDaXA= 66 | github.com/aws/aws-sdk-go-v2/service/lambda v1.71.2/go.mod h1:c27kk10S36lBYgbG1jR3opn4OAS5Y/4wjJa1GiHK/X4= 67 | github.com/aws/aws-sdk-go-v2/service/organizations v1.38.2 h1:/uA5NXZAiMZGz/tKHEVbTAr1IgFmIozvBgnT7dpypYc= 68 | github.com/aws/aws-sdk-go-v2/service/organizations v1.38.2/go.mod h1:iYC/SPpI4WveHr4ZzPFWTmXRODyJub5Aif75W7Ll+yM= 69 | github.com/aws/aws-sdk-go-v2/service/route53 v1.51.0 h1:pK3YJIgOzYqctprqQ67kGSjeL+77r9Ue/4/gBonsGNc= 70 | github.com/aws/aws-sdk-go-v2/service/route53 v1.51.0/go.mod h1:kGYOjvTa0Vw0qxrqrOLut1vMnui6qLxqv/SX3vYeM8Y= 71 | github.com/aws/aws-sdk-go-v2/service/s3 v1.79.2 h1:tWUG+4wZqdMl/znThEk9tcCy8tTMxq8dW0JTgamohrY= 72 | github.com/aws/aws-sdk-go-v2/service/s3 v1.79.2/go.mod h1:U5SNqwhXB3Xe6F47kXvWihPl/ilGaEDe8HD/50Z9wxc= 73 | github.com/aws/aws-sdk-go-v2/service/ses v1.30.2 h1:idN+0zMCMQw0VtCHavmq0n/uaNeLi851q3XTa86oxHE= 74 | github.com/aws/aws-sdk-go-v2/service/ses v1.30.2/go.mod h1:eZW5lSNTE1tQfMpl6crr/YVJYgEcnk2JQoodg6E63qM= 75 | github.com/aws/aws-sdk-go-v2/service/sns v1.34.3 h1:iJtp/KnPsgMO4TSGfjqi3oGr+R73W7xWqDXHCbqdnv8= 76 | github.com/aws/aws-sdk-go-v2/service/sns v1.34.3/go.mod h1:PJtxxMdj747j8DeZENRTTYAz/lx/pADn/U0k7YNNiUY= 77 | github.com/aws/aws-sdk-go-v2/service/sqs v1.38.4 h1:rxG8LzVTNCOUppzbQAWfEEDJg4knmnH7zZGEnf7QOrs= 78 | github.com/aws/aws-sdk-go-v2/service/sqs v1.38.4/go.mod h1:Bar4MrRxeqdn6XIh8JGfiXuFRmyrrsZNTJotxEJmWW0= 79 | github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 h1:1Gw+9ajCV1jogloEv1RRnvfRFia2cL6c9cuKV2Ps+G8= 80 | github.com/aws/aws-sdk-go-v2/service/sso v1.25.3/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI= 81 | github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 h1:hXmVKytPfTy5axZ+fYbR5d0cFmC3JvwLm5kM83luako= 82 | github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs= 83 | github.com/aws/aws-sdk-go-v2/service/sts v1.33.18 h1:xz7WvTMfSStb9Y8NpCT82FXLNC3QasqBfuAFHY4Pk5g= 84 | github.com/aws/aws-sdk-go-v2/service/sts v1.33.18/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4= 85 | github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= 86 | github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= 87 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 88 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 89 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 90 | github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= 91 | github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 92 | github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= 93 | github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 94 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 95 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 96 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 97 | github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= 98 | github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 99 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 100 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 101 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 102 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 103 | github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a h1:eU8j/ClY2Ty3qdHnn0TyW3ivFoPC/0F1gQZz8yTxbbE= 104 | github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a/go.mod h1:v8eSC2SMp9/7FTKUncp7fH9IwPfw+ysMObcEz5FWheQ= 105 | github.com/nathants/go-dynamolock v0.0.0-20250409081145-4131e1e4f1e8 h1:wHnzbCVkwvH6FVLdV++ECKPFdUa4MZESjABR9QmPWu0= 106 | github.com/nathants/go-dynamolock v0.0.0-20250409081145-4131e1e4f1e8/go.mod h1:opncjB/Wt0dhsKfcx1aeG/7LFa7SmC6S/m0ZVFd8H0Y= 107 | github.com/nathants/libaws v0.0.0-20250412062845-cfd1a2575af2 h1:Hq+LR8SjBqCfXmbbm4gTDNCpRvSWYhtINbxngNvXL3E= 108 | github.com/nathants/libaws v0.0.0-20250412062845-cfd1a2575af2/go.mod h1:bMPZ5l7iSQ88sohzOrPc8/KV1y2Yu6t/h1RSdQoIdsM= 109 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 110 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 111 | github.com/r3labs/diff/v2 v2.15.1 h1:EOrVqPUzi+njlumoqJwiS/TgGgmZo83619FNDB9xQUg= 112 | github.com/r3labs/diff/v2 v2.15.1/go.mod h1:I8noH9Fc2fjSaMxqF3G2lhDdC0b+JXCfyx85tWFM9kc= 113 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 114 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 115 | github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= 116 | github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= 117 | github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= 118 | github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= 119 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 120 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 121 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 122 | golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= 123 | golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= 124 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 125 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 126 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 127 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 128 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 129 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 130 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 131 | golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= 132 | golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= 133 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 134 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 135 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 136 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 137 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 138 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 139 | golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= 140 | golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 141 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 142 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 143 | golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= 144 | golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= 145 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 146 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 147 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 148 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 149 | golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= 150 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 151 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 152 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 153 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 154 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 155 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 156 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 157 | google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= 158 | google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= 159 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 160 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 161 | google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= 162 | google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 163 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 164 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 165 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 166 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 167 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 168 | -------------------------------------------------------------------------------- /infra.yaml: -------------------------------------------------------------------------------- 1 | name: ${PROJECT_NAME} 2 | 3 | dynamodb: 4 | ${PROJECT_NAME}: 5 | key: 6 | - id:s:hash 7 | 8 | s3: 9 | ${PROJECT_BUCKET}: 10 | attr: 11 | - cors=true 12 | - acl=private 13 | - ttldays=14 14 | 15 | lambda: 16 | ${PROJECT_NAME}: 17 | entrypoint: backend/backend.go 18 | attr: 19 | - concurrency=0 20 | - memory=128 21 | - timeout=900 22 | - logs-ttl-days=7 23 | trigger: 24 | - type: api 25 | attr: 26 | - dns=${PROJECT_DOMAIN} 27 | - type: websocket 28 | attr: 29 | - dns=${PROJECT_DOMAIN_WEBSOCKET} 30 | policy: 31 | - AWSLambdaBasicExecutionRole 32 | allow: 33 | - dynamodb:* arn:aws:dynamodb:${AWS_DEFAULT_REGION}:*:table/${PROJECT_NAME} 34 | - s3:* arn:aws:s3:::${PROJECT_BUCKET} 35 | - s3:* arn:aws:s3:::${PROJECT_BUCKET}/* 36 | - execute-api:ManageConnections arn:aws:execute-api:${AWS_DEFAULT_REGION}:*:${WEBSOCKET_ID}/*/*/* 37 | - lambda:InvokeFunction arn:aws:lambda:*:*:function:${PROJECT_NAME} 38 | include: 39 | - frontend/public/index.html.gz 40 | - frontend/public/favicon.png 41 | env: 42 | - PROJECT_NAME=${PROJECT_NAME} 43 | - PROJECT_DOMAIN=${PROJECT_DOMAIN} 44 | - PROJECT_DOMAIN_WEBSOCKET=${PROJECT_DOMAIN_WEBSOCKET} 45 | - PROJECT_URL=${PROJECT_URL} 46 | - PROJECT_BUCKET=${PROJECT_BUCKET} 47 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2022-present Nathan Todd-Stone 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # aws-gocljs 2 | 3 | ## why 4 | 5 | so you can just ship fullstack web on aws. 6 | 7 | ![](https://github.com/nathants/aws-gocljs/raw/master/screenshot.png) 8 | 9 | ## how 10 | 11 | start with working implementations of everything, then [iterate](#demo). 12 | 13 | fast and reliable [automation](https://github.com/nathants/aws-gocljs/tree/master/bin). 14 | 15 | easy browser [testing](https://github.com/nathants/py-webengine). 16 | 17 | the tightest possible security [policy](https://github.com/nathants/aws-gocljs/blob/master/bin/ensure.sh), no other js can ever run. 18 | 19 | ## what 20 | 21 | a project scaffold for a fullstack webapp on aws with an [infrastructure set](https://github.com/nathants/aws-gocljs/tree/master/infra.yaml) ready-to-deploy with [libaws](https://github.com/nathants/libaws). 22 | 23 | the project scaffold contains: 24 | - a go lambda backend. 25 | - a clojurescript [react](http://reagent-project.github.io/) frontend. 26 | - s3 and dynamodb for state. 27 | - http and websocket apis. 28 | - [logging](https://github.com/nathants/aws-gocljs/tree/master/bin/logs.sh). 29 | - [devops](https://github.com/nathants/aws-gocljs/tree/master/bin). 30 | 31 | a live demo is [here](https://gocljs.nathants.com). 32 | 33 | ## lambda zip 34 | 35 | the lambda zip contains only 3 files: 36 | 37 | ```bash 38 | >> ls -lh | awk '{print $9, $5}' | column -t 39 | 40 | favicon.png 2.7K # favicon 41 | index.html.gz 296K # web app 42 | main 15M # go binary 43 | ``` 44 | 45 | the index.html.gz: 46 | 47 | ```html 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 |
57 | 60 | 61 | 62 | ``` 63 | 64 | the lambda zip itself: 65 | 66 | ```bash 67 | >> ls -lh | awk '{print $9, $5}' 68 | lambda.zip 4.6M 69 | ``` 70 | 71 | ## demo 72 | 73 | ![](https://github.com/nathants/aws-gocljs/raw/master/demo.gif) 74 | 75 | ## dependencies 76 | 77 | use the included [Dockerfile](./Dockerfile) or install the following dependencies: 78 | - npm 79 | - jdk 80 | - go 81 | - bash 82 | - [entr](https://formulae.brew.sh/formula/entr) 83 | - [libaws](https://github.com/nathants/libaws) 84 | 85 | ## aws prerequisites 86 | 87 | - aws [route53](https://console.aws.amazon.com/route53/v2/hostedzones) has the domain or its parent from env.sh 88 | 89 | - aws [acm](https://us-west-2.console.aws.amazon.com/acm/home) has a wildcard cert for the domain or its parent from env.sh 90 | 91 | ## install 92 | 93 | ```bash 94 | git clone https://github.com/nathants/aws-gocljs 95 | cd aws-gocljs 96 | cp env.sh.template env.sh # update values 97 | ``` 98 | 99 | ## usage 100 | 101 | ```bash 102 | bash bin/check.sh # lint 103 | bash bin/preview.sh # preview changes to aws infra 104 | bash bin/ensure.sh # ensure aws infra 105 | bash bin/dev.sh # iterate on backend and frontend 106 | bash bin/logs.sh # tail the logs 107 | bash bin/delete.sh # delete aws infra 108 | ``` 109 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathants/aws-gocljs/155bd13d7faa176dcff0bc25194f04f3c695bde7/screenshot.png --------------------------------------------------------------------------------