From 2240985aa114fab0b7483bcfe805c7d36118ad3e Mon Sep 17 00:00:00 2001 From: Gisle Aune Date: Thu, 31 Dec 2020 17:49:54 +0100 Subject: [PATCH] first commit --- .drone.yml | 99 + .gitignore | 2 + api/common.go | 21 + api/goal.go | 141 + api/group.go | 90 + api/item.go | 98 + api/log.go | 115 + api/project.go | 101 + api/task.go | 111 + cmd/stufflog2-lambda/main.go | 51 + cmd/stufflog2-local/main.go | 74 + database/database.go | 28 + database/postgres/db.go | 51 + database/postgres/goals.go | 115 + database/postgres/group.go | 96 + database/postgres/item.go | 100 + database/postgres/logs.go | 108 + database/postgres/project.go | 104 + database/postgres/tasks.go | 109 + go.mod | 20 + go.sum | 333 ++ internal/auth/auth.go | 71 + internal/generate/ids.go | 52 + internal/slerrors/badrequest.go | 18 + internal/slerrors/forbidden.go | 22 + internal/slerrors/gin.go | 35 + internal/slerrors/notfound.go | 18 + .../20201218170259_create_table_group.sql | 15 + .../20201218170301_create_table_item.sql | 16 + .../20201218170319_create_table_project.sql | 18 + .../20201218170338_create_table_task.sql | 20 + .../20201218170348_create_table_log.sql | 16 + .../20201218170417_create_table_goal.sql | 18 + ...01223121327_create_index_item_group_id.sql | 9 + ...0201223125438_create_index_log_task_id.sql | 9 + ...223125556_create_index_goal_start_time.sql | 9 + ...01223125559_create_index_goal_end_time.sql | 9 + ...01223125934_create_index_group_user_id.sql | 9 + ...201223125938_create_index_item_user_id.sql | 9 + ...223125947_create_index_project_user_id.sql | 9 + ...201223125957_create_index_task_user_id.sql | 9 + ...0201223130003_create_index_log_user_id.sql | 9 + ...201223130007_create_index_goal_user_id.sql | 9 + ...5724_create_index_project_created_time.sql | 9 + ...201223135812_create_index_task_item_id.sql | 9 + ...223140113_create_index_log_logged_time.sql | 9 + ...0201225175922_create_index_log_item_id.sql | 9 + models/goal.go | 73 + models/group.go | 47 + models/item.go | 50 + models/log.go | 50 + models/project.go | 68 + models/task.go | 74 + serverless.yml | 115 + services/loader.go | 508 ++ svelte-ui/.gitignore | 7 + svelte-ui/package-lock.json | 4368 +++++++++++++++++ svelte-ui/package.json | 43 + svelte-ui/public/favicon.png | Bin 0 -> 3127 bytes svelte-ui/public/global.css | 62 + svelte-ui/public/index.html | 17 + svelte-ui/rollup.config.js | 99 + svelte-ui/src/App.svelte | 77 + svelte-ui/src/clients/amplify.ts | 46 + svelte-ui/src/clients/stufflog.ts | 260 + svelte-ui/src/components/Boi.svelte | 53 + svelte-ui/src/components/DateSpan.svelte | 17 + svelte-ui/src/components/DaysLeft.svelte | 87 + svelte-ui/src/components/GoalEntry.svelte | 93 + svelte-ui/src/components/GroupEntry.svelte | 84 + svelte-ui/src/components/GroupSelect.svelte | 30 + svelte-ui/src/components/Icon.svelte | 22 + svelte-ui/src/components/IconSelect.svelte | 56 + svelte-ui/src/components/ItemEntry.svelte | 86 + svelte-ui/src/components/ItemSelect.svelte | 31 + svelte-ui/src/components/LogEntry.svelte | 95 + svelte-ui/src/components/Menu.svelte | 44 + svelte-ui/src/components/Modal.svelte | 215 + svelte-ui/src/components/ModalRoute.svelte | 10 + svelte-ui/src/components/Option.svelte | 38 + svelte-ui/src/components/OptionRow.svelte | 10 + svelte-ui/src/components/Progress.svelte | 80 + svelte-ui/src/components/ProjectEntry.svelte | 94 + svelte-ui/src/components/TaskEntry.svelte | 161 + svelte-ui/src/external/icons.ts | 138 + svelte-ui/src/forms/GoalForm.svelte | 112 + svelte-ui/src/forms/GroupForm.svelte | 90 + svelte-ui/src/forms/ItemAddForm.svelte | 54 + svelte-ui/src/forms/ItemDeleteForm.svelte | 50 + svelte-ui/src/forms/ItemEditForm.svelte | 56 + svelte-ui/src/forms/LogAddForm.svelte | 71 + svelte-ui/src/forms/LogDeleteForm.svelte | 56 + svelte-ui/src/forms/LogEditForm.svelte | 59 + svelte-ui/src/forms/LoginForm.svelte | 74 + svelte-ui/src/forms/ProjectAddForm.svelte | 54 + svelte-ui/src/forms/ProjectDeleteForm.svelte | 56 + svelte-ui/src/forms/ProjectEditForm.svelte | 60 + svelte-ui/src/forms/TaskAddForm.svelte | 72 + svelte-ui/src/forms/TaskDeleteForm.svelte | 60 + svelte-ui/src/forms/TaskEditForm.svelte | 63 + svelte-ui/src/main.ts | 8 + svelte-ui/src/models/goal.ts | 47 + svelte-ui/src/models/group.ts | 24 + svelte-ui/src/models/item.ts | 27 + svelte-ui/src/models/log.ts | 30 + svelte-ui/src/models/project.ts | 37 + svelte-ui/src/models/task.ts | 40 + svelte-ui/src/pages/FrontPage.svelte | 80 + svelte-ui/src/pages/GoalPage.svelte | 34 + svelte-ui/src/pages/GroupPage.svelte | 32 + svelte-ui/src/pages/LogsPage.svelte | 105 + svelte-ui/src/pages/ProjectPage.svelte | 34 + svelte-ui/src/stores/auth.ts | 24 + svelte-ui/src/stores/goal.ts | 36 + svelte-ui/src/stores/group.ts | 35 + svelte-ui/src/stores/logs.ts | 37 + svelte-ui/src/stores/modal.ts | 46 + svelte-ui/src/stores/project.ts | 36 + svelte-ui/src/utils/time.ts | 45 + svelte-ui/tsconfig.json | 10 + 120 files changed, 11574 insertions(+) create mode 100644 .drone.yml create mode 100644 .gitignore create mode 100644 api/common.go create mode 100644 api/goal.go create mode 100644 api/group.go create mode 100644 api/item.go create mode 100644 api/log.go create mode 100644 api/project.go create mode 100644 api/task.go create mode 100644 cmd/stufflog2-lambda/main.go create mode 100644 cmd/stufflog2-local/main.go create mode 100644 database/database.go create mode 100644 database/postgres/db.go create mode 100644 database/postgres/goals.go create mode 100644 database/postgres/group.go create mode 100644 database/postgres/item.go create mode 100644 database/postgres/logs.go create mode 100644 database/postgres/project.go create mode 100644 database/postgres/tasks.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/auth/auth.go create mode 100644 internal/generate/ids.go create mode 100644 internal/slerrors/badrequest.go create mode 100644 internal/slerrors/forbidden.go create mode 100644 internal/slerrors/gin.go create mode 100644 internal/slerrors/notfound.go create mode 100644 migrations/postgres/20201218170259_create_table_group.sql create mode 100644 migrations/postgres/20201218170301_create_table_item.sql create mode 100644 migrations/postgres/20201218170319_create_table_project.sql create mode 100644 migrations/postgres/20201218170338_create_table_task.sql create mode 100644 migrations/postgres/20201218170348_create_table_log.sql create mode 100644 migrations/postgres/20201218170417_create_table_goal.sql create mode 100644 migrations/postgres/20201223121327_create_index_item_group_id.sql create mode 100644 migrations/postgres/20201223125438_create_index_log_task_id.sql create mode 100644 migrations/postgres/20201223125556_create_index_goal_start_time.sql create mode 100644 migrations/postgres/20201223125559_create_index_goal_end_time.sql create mode 100644 migrations/postgres/20201223125934_create_index_group_user_id.sql create mode 100644 migrations/postgres/20201223125938_create_index_item_user_id.sql create mode 100644 migrations/postgres/20201223125947_create_index_project_user_id.sql create mode 100644 migrations/postgres/20201223125957_create_index_task_user_id.sql create mode 100644 migrations/postgres/20201223130003_create_index_log_user_id.sql create mode 100644 migrations/postgres/20201223130007_create_index_goal_user_id.sql create mode 100644 migrations/postgres/20201223135724_create_index_project_created_time.sql create mode 100644 migrations/postgres/20201223135812_create_index_task_item_id.sql create mode 100644 migrations/postgres/20201223140113_create_index_log_logged_time.sql create mode 100644 migrations/postgres/20201225175922_create_index_log_item_id.sql create mode 100644 models/goal.go create mode 100644 models/group.go create mode 100644 models/item.go create mode 100644 models/log.go create mode 100644 models/project.go create mode 100644 models/task.go create mode 100644 serverless.yml create mode 100644 services/loader.go create mode 100644 svelte-ui/.gitignore create mode 100644 svelte-ui/package-lock.json create mode 100644 svelte-ui/package.json create mode 100644 svelte-ui/public/favicon.png create mode 100644 svelte-ui/public/global.css create mode 100644 svelte-ui/public/index.html create mode 100644 svelte-ui/rollup.config.js create mode 100644 svelte-ui/src/App.svelte create mode 100644 svelte-ui/src/clients/amplify.ts create mode 100644 svelte-ui/src/clients/stufflog.ts create mode 100644 svelte-ui/src/components/Boi.svelte create mode 100644 svelte-ui/src/components/DateSpan.svelte create mode 100644 svelte-ui/src/components/DaysLeft.svelte create mode 100644 svelte-ui/src/components/GoalEntry.svelte create mode 100644 svelte-ui/src/components/GroupEntry.svelte create mode 100644 svelte-ui/src/components/GroupSelect.svelte create mode 100644 svelte-ui/src/components/Icon.svelte create mode 100644 svelte-ui/src/components/IconSelect.svelte create mode 100644 svelte-ui/src/components/ItemEntry.svelte create mode 100644 svelte-ui/src/components/ItemSelect.svelte create mode 100644 svelte-ui/src/components/LogEntry.svelte create mode 100644 svelte-ui/src/components/Menu.svelte create mode 100644 svelte-ui/src/components/Modal.svelte create mode 100644 svelte-ui/src/components/ModalRoute.svelte create mode 100644 svelte-ui/src/components/Option.svelte create mode 100644 svelte-ui/src/components/OptionRow.svelte create mode 100644 svelte-ui/src/components/Progress.svelte create mode 100644 svelte-ui/src/components/ProjectEntry.svelte create mode 100644 svelte-ui/src/components/TaskEntry.svelte create mode 100644 svelte-ui/src/external/icons.ts create mode 100644 svelte-ui/src/forms/GoalForm.svelte create mode 100644 svelte-ui/src/forms/GroupForm.svelte create mode 100644 svelte-ui/src/forms/ItemAddForm.svelte create mode 100644 svelte-ui/src/forms/ItemDeleteForm.svelte create mode 100644 svelte-ui/src/forms/ItemEditForm.svelte create mode 100644 svelte-ui/src/forms/LogAddForm.svelte create mode 100644 svelte-ui/src/forms/LogDeleteForm.svelte create mode 100644 svelte-ui/src/forms/LogEditForm.svelte create mode 100644 svelte-ui/src/forms/LoginForm.svelte create mode 100644 svelte-ui/src/forms/ProjectAddForm.svelte create mode 100644 svelte-ui/src/forms/ProjectDeleteForm.svelte create mode 100644 svelte-ui/src/forms/ProjectEditForm.svelte create mode 100644 svelte-ui/src/forms/TaskAddForm.svelte create mode 100644 svelte-ui/src/forms/TaskDeleteForm.svelte create mode 100644 svelte-ui/src/forms/TaskEditForm.svelte create mode 100644 svelte-ui/src/main.ts create mode 100644 svelte-ui/src/models/goal.ts create mode 100644 svelte-ui/src/models/group.ts create mode 100644 svelte-ui/src/models/item.ts create mode 100644 svelte-ui/src/models/log.ts create mode 100644 svelte-ui/src/models/project.ts create mode 100644 svelte-ui/src/models/task.ts create mode 100644 svelte-ui/src/pages/FrontPage.svelte create mode 100644 svelte-ui/src/pages/GoalPage.svelte create mode 100644 svelte-ui/src/pages/GroupPage.svelte create mode 100644 svelte-ui/src/pages/LogsPage.svelte create mode 100644 svelte-ui/src/pages/ProjectPage.svelte create mode 100644 svelte-ui/src/stores/auth.ts create mode 100644 svelte-ui/src/stores/goal.ts create mode 100644 svelte-ui/src/stores/group.ts create mode 100644 svelte-ui/src/stores/logs.ts create mode 100644 svelte-ui/src/stores/modal.ts create mode 100644 svelte-ui/src/stores/project.ts create mode 100644 svelte-ui/src/utils/time.ts create mode 100644 svelte-ui/tsconfig.json diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..f89417b --- /dev/null +++ b/.drone.yml @@ -0,0 +1,99 @@ +name: lektura-red + +kind: pipeline +type: docker + +steps: + - name: backend-build + image: golang:1.15 + depends_on: [] + commands: + - go mod download + - CGO_ENABLED=0 go build -ldflags "-w -s" -o build/api/handler cmd/stufflog2-lambda/main.go + + - name: backend-test + image: golang:1.15 + depends_on: [] + commands: + - go test -v ./... + + - name: backend-migrate + image: golang:1.15 + depends_on: [] + environment: + DB_CONNECT: + from:secret: db_connect + commands: + - go get -u github.com/pressly/goose/... + - cd migrations/postgres + - goose postgres "$DB_CONNECT" up + + - name: backend-deploy + image: node:14.14.0 + depends_on: + - backend-build + - backend-test + - backend-migrate + environment: + AWS_ACCESS_KEY_ID: + from_secret: aws_access_key_id + AWS_SECRET_ACCESS_KEY: + from_secret: aws_secret_access_key + AWS_DEFAULT_REGION: + from_secret: aws_region + AMI_ROLE: + from_secret: ami_role + S3_WEBUI_BUCKET: + from_secret: s3_webui_bucket + DOMAIN_NAME: + from_secret: domain_name + CERTIFICATE_NAME: + from_secret: certificate_name + CERTIFICATE_ARN: + from_secret: certificate_arn + HOSTED_ZONE_ID: + from_secret: hosted_zone_id + DB_DRIVER: + from_secret: db_driver + DB_CONNECT: + from:secret: db_connect + commands: + - apt-get update > /dev/null 2>&1 + - apt-get -y install awscli zip > /dev/null 2>&1 + - npm install -g serverless > /dev/null 2>&1 + - npm install -g serverless-domain-manager > /dev/null 2>&1 + - npm install -g serverless-apigateway-service-proxy > /dev/null 2>&1 + - serverless deploy + + - name: frontend-build + image: node:14.14.0 + depends_on: [] + environment: + AWS_AMPLIFY_REGION: + from_secret: aws_region + AWS_AMPLIFY_USER_POOL_ID: + from_secret: aws_amplify_user_pool_id + AWS_AMPLIFY_USER_POOL_WEB_CLIENT_ID: + from_secret: aws_amplify_user_pool_web_client_id + + commands: + - cd svelte-ui + - npm install + - npm run build + + - name: frontend-deploy + image: amazon/aws-cli:latest + depends_on: + - frontend-build + environment: + AWS_ACCESS_KEY_ID: + from_secret: aws_access_key_id + AWS_SECRET_ACCESS_KEY: + from_secret: aws_secret_access_key + AWS_DEFAULT_REGION: + from_secret: aws_region + S3_WEBUI_BUCKET: + from_secret: s3_webui_bucket + commands: + - cd webui/build + - aws s3 sync . s3://$S3_WEBUI_BUCKET \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f086293 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/stufflog2-* +/.idea \ No newline at end of file diff --git a/api/common.go b/api/common.go new file mode 100644 index 0000000..3be45bc --- /dev/null +++ b/api/common.go @@ -0,0 +1,21 @@ +package api + +import ( + "github.com/gin-gonic/gin" + "github.com/gissleh/stufflog/internal/slerrors" +) + +func handler(key string, callback func(c *gin.Context) (interface{}, error)) gin.HandlerFunc { + return func(c *gin.Context) { + res, err := callback(c) + if err != nil { + slerrors.Respond(c, err) + return + } + + resJson := make(map[string]interface{}, 1) + resJson[key] = res + + c.JSON(200, resJson) + } +} diff --git a/api/goal.go b/api/goal.go new file mode 100644 index 0000000..7a61943 --- /dev/null +++ b/api/goal.go @@ -0,0 +1,141 @@ +package api + +import ( + "github.com/gin-gonic/gin" + "github.com/gissleh/stufflog/database" + "github.com/gissleh/stufflog/internal/auth" + "github.com/gissleh/stufflog/internal/generate" + "github.com/gissleh/stufflog/internal/slerrors" + "github.com/gissleh/stufflog/models" + "github.com/gissleh/stufflog/services" + "time" +) + +func Goal(g *gin.RouterGroup, db database.Database) { + l := services.Loader{DB: db} + + g.GET("/", handler("goals", func(c *gin.Context) (interface{}, error) { + filter := models.GoalFilter{} + if value := c.Query("minTime"); value != "" { + minTime, err := time.Parse(time.RFC3339Nano, value) + if err != nil { + return nil, slerrors.BadRequest("Invalid minTime") + } + minTime = minTime.UTC() + + filter.MinTime = &minTime + } else { + lastMonth := time.Now().Add(-30 * 24 * time.Hour).UTC() + filter.MinTime = &lastMonth + } + if value := c.Query("maxTime"); value != "" { + maxTime, err := time.Parse(time.RFC3339Nano, value) + if err != nil { + return nil, slerrors.BadRequest("Invalid maxTime") + } + maxTime = maxTime.UTC() + + filter.MaxTime = &maxTime + } + if value := c.Query("includesTime"); value != "" { + includesTime, err := time.Parse(time.RFC3339Nano, value) + if err != nil { + return nil, slerrors.BadRequest("Invalid includesTime") + } + includesTime = includesTime.UTC() + + filter.IncludesTime = &includesTime + } + + return l.ListGoals(c.Request.Context(), filter) + })) + + g.GET("/:id", handler("goal", func(c *gin.Context) (interface{}, error) { + return l.FindGoal(c.Request.Context(), c.Param("id")) + })) + + g.POST("/", handler("goal", func(c *gin.Context) (interface{}, error) { + goal := models.Goal{} + err := c.BindJSON(&goal) + if err != nil { + return nil, slerrors.BadRequest("Invalid JSON") + } + goal.ID = generate.GoalID() + goal.UserID = auth.UserID(c) + + if goal.Amount <= 0 { + return nil, slerrors.BadRequest("Goal amount must be more than 0.") + } + if goal.StartTime.IsZero() { + return nil, slerrors.BadRequest("Start time must be set.") + } + if goal.EndTime.IsZero() { + return nil, slerrors.BadRequest("End time must be set.") + } + if !goal.EndTime.After(goal.StartTime) { + return nil, slerrors.BadRequest("Start time must be before end time.") + } + + goal.StartTime = goal.StartTime.UTC() + goal.EndTime = goal.EndTime.UTC() + + group, err := db.Groups().Find(c.Request.Context(), goal.GroupID) + if err != nil { + return nil, err + } + goal.GroupID = group.ID + + err = db.Goals().Insert(c.Request.Context(), goal) + if err != nil { + return nil, err + } + + return l.FindGoal(c.Request.Context(), goal.ID) + })) + + g.PUT("/:id", handler("goal", func(c *gin.Context) (interface{}, error) { + update := models.GoalUpdate{} + err := c.BindJSON(&update) + if err != nil { + return nil, slerrors.BadRequest("Invalid JSON") + } + + goal, err := l.FindGoal(c.Request.Context(), c.Param("id")) + if err != nil { + return nil, err + } + + goal.StartTime = goal.StartTime.UTC() + goal.EndTime = goal.EndTime.UTC() + + goal.Update(update) + + if goal.Amount <= 0 { + return nil, slerrors.BadRequest("Goal amount must be more than 0.") + } + if !goal.EndTime.After(goal.StartTime) { + return nil, slerrors.BadRequest("Start time must be before end time.") + } + + err = db.Goals().Update(c.Request.Context(), goal.Goal) + if err != nil { + return nil, err + } + + return goal, nil + })) + + g.DELETE("/:id", handler("goal", func(c *gin.Context) (interface{}, error) { + goal, err := l.FindGoal(c.Request.Context(), c.Param("id")) + if err != nil { + return nil, err + } + + err = db.Goals().Delete(c.Request.Context(), goal.Goal) + if err != nil { + return nil, err + } + + return goal, nil + })) +} diff --git a/api/group.go b/api/group.go new file mode 100644 index 0000000..961242d --- /dev/null +++ b/api/group.go @@ -0,0 +1,90 @@ +package api + +import ( + "github.com/gin-gonic/gin" + "github.com/gissleh/stufflog/database" + "github.com/gissleh/stufflog/internal/auth" + "github.com/gissleh/stufflog/internal/generate" + "github.com/gissleh/stufflog/internal/slerrors" + "github.com/gissleh/stufflog/models" + "github.com/gissleh/stufflog/services" +) + +func Group(g *gin.RouterGroup, db database.Database) { + l := services.Loader{DB: db} + + g.GET("/", handler("groups", func(c *gin.Context) (interface{}, error) { + return l.ListGroups(c, models.GroupFilter{}) + })) + + g.GET("/:id", handler("group", func(c *gin.Context) (interface{}, error) { + return l.FindGroup(c, c.Param("id")) + })) + + g.POST("/", handler("group", func(c *gin.Context) (interface{}, error) { + group := models.Group{} + err := c.BindJSON(&group) + if err != nil { + return nil, slerrors.BadRequest("Invalid JSON") + } + group.ID = generate.GroupID() + group.UserID = auth.UserID(c) + + err = db.Groups().Insert(c.Request.Context(), group) + if err != nil { + return nil, err + } + + return &models.GroupResult{ + Group: group, + Items: []*models.Item{}, + }, nil + })) + + g.PUT("/:id", handler("group", func(c *gin.Context) (interface{}, error) { + update := models.GroupUpdate{} + err := c.BindJSON(&update) + if err != nil { + return nil, slerrors.BadRequest("Invalid JSON") + } + + group, err := db.Groups().Find(c.Request.Context(), c.Param("id")) + if err != nil { + return nil, err + } else if auth.UserID(c) != group.UserID { + return nil, slerrors.NotFound("Item") + } + + group.Update(update) + err = db.Groups().Update(c.Request.Context(), *group) + if err != nil { + return nil, err + } + + return l.FindGroup(c, group.ID) + })) + + g.DELETE("/:id", handler("group", func(c *gin.Context) (interface{}, error) { + group, err := l.FindGroup(c, c.Param("id")) + if err != nil { + return nil, err + } + if len(group.Items) > 0 { + return nil, slerrors.Forbidden("cannot delete non-empty group.") + } + goals, err := db.Goals().List(c.Request.Context(), models.GoalFilter{GroupIDs: []string{group.ID}}) + if err != nil { + return nil, err + } + if len(goals) > 0 { + return nil, slerrors.Forbidden("cannot delete group with goals.") + } + + err = db.Groups().Delete(c.Request.Context(), group.Group) + if err != nil { + return nil, err + } + + return group, nil + })) +} diff --git a/api/item.go b/api/item.go new file mode 100644 index 0000000..eb3dc2b --- /dev/null +++ b/api/item.go @@ -0,0 +1,98 @@ +package api + +import ( + "github.com/gin-gonic/gin" + "github.com/gissleh/stufflog/database" + "github.com/gissleh/stufflog/internal/auth" + "github.com/gissleh/stufflog/internal/generate" + "github.com/gissleh/stufflog/internal/slerrors" + "github.com/gissleh/stufflog/models" + "github.com/gissleh/stufflog/services" +) + +func Item(g *gin.RouterGroup, db database.Database) { + l := services.Loader{DB: db} + + g.GET("/", handler("items", func(c *gin.Context) (interface{}, error) { + return l.ListItems(c, models.ItemFilter{}) + })) + + g.GET("/:id", handler("item", func(c *gin.Context) (interface{}, error) { + return l.FindItem(c, c.Param("id")) + })) + + g.POST("/", handler("item", func(c *gin.Context) (interface{}, error) { + item := models.Item{} + err := c.BindJSON(&item) + if err != nil { + return nil, slerrors.BadRequest("Invalid JSON") + } + + group, err := db.Groups().Find(c.Request.Context(), item.GroupID) + if err != nil { + return nil, err + } else if auth.UserID(c) != group.UserID { + return nil, slerrors.NotFound("Group") + } + + item.ID = generate.ItemID() + item.UserID = auth.UserID(c) + item.GroupID = group.ID + + err = db.Items().Insert(c.Request.Context(), item) + if err != nil { + return nil, err + } + + return &models.ItemResult{ + Item: item, + Group: group, + }, nil + })) + + g.PUT("/:id", handler("item", func(c *gin.Context) (interface{}, error) { + update := models.ItemUpdate{} + err := c.BindJSON(&update) + if err != nil { + return nil, slerrors.BadRequest("Invalid JSON") + } + + item, err := l.FindItem(c.Request.Context(), c.Param("id")) + if err != nil { + return nil, err + } + + item.Update(update) + err = db.Items().Update(c.Request.Context(), item.Item) + if err != nil { + return nil, err + } + + return item, nil + })) + + g.DELETE("/:id", handler("item", func(c *gin.Context) (interface{}, error) { + item, err := l.FindItem(c.Request.Context(), c.Param("id")) + if err != nil { + return nil, err + } + + tasks, err := db.Tasks().List(c.Request.Context(), models.TaskFilter{ + UserID: auth.UserID(c), + ItemIDs: []string{item.ID}, + }) + if err != nil { + return nil, err + } + if len(tasks) > 0 { + return nil, slerrors.Forbidden("cannot delete item referenced in tasks.") + } + + err = db.Items().Delete(c.Request.Context(), item.Item) + if err != nil { + return nil, err + } + + return item, nil + })) +} diff --git a/api/log.go b/api/log.go new file mode 100644 index 0000000..6d1921e --- /dev/null +++ b/api/log.go @@ -0,0 +1,115 @@ +package api + +import ( + "github.com/gin-gonic/gin" + "github.com/gissleh/stufflog/database" + "github.com/gissleh/stufflog/internal/auth" + "github.com/gissleh/stufflog/internal/generate" + "github.com/gissleh/stufflog/internal/slerrors" + "github.com/gissleh/stufflog/models" + "github.com/gissleh/stufflog/services" + "time" +) + +func Log(g *gin.RouterGroup, db database.Database) { + l := services.Loader{DB: db} + + g.GET("/", handler("logs", func(c *gin.Context) (interface{}, error) { + filter := models.LogFilter{} + if value := c.Query("minTime"); value != "" { + minTime, err := time.Parse(time.RFC3339Nano, value) + if err != nil { + return nil, slerrors.BadRequest("Invalid minTime") + } + minTime = minTime.UTC() + + filter.MinTime = &minTime + } else { + lastMonth := time.Now().Add(-30 * 24 * time.Hour).UTC() + filter.MinTime = &lastMonth + } + if value := c.Query("maxTime"); value != "" { + maxTime, err := time.Parse(time.RFC3339Nano, value) + if err != nil { + return nil, slerrors.BadRequest("Invalid maxTime") + } + maxTime = maxTime.UTC() + + filter.MaxTime = &maxTime + } + + return l.ListLogs(c, filter) + })) + + g.GET("/:id", handler("log", func(c *gin.Context) (interface{}, error) { + return l.FindLog(c, c.Param("id")) + })) + + g.POST("/", handler("log", func(c *gin.Context) (interface{}, error) { + log := models.Log{} + err := c.BindJSON(&log) + if err != nil { + return nil, slerrors.BadRequest("Invalid JSON") + } + + task, err := l.FindTask(c.Request.Context(), log.TaskID) + if err != nil { + return nil, err + } + + log.ID = generate.LogID() + log.UserID = auth.UserID(c) + log.TaskID = task.ID + log.ItemID = task.ItemID + if log.LoggedTime.IsZero() { + log.LoggedTime = time.Now().UTC() + } else { + log.LoggedTime = log.LoggedTime.UTC() + } + + err = db.Logs().Insert(c.Request.Context(), log) + if err != nil { + return nil, err + } + + return &models.LogResult{ + Log: log, + Task: &task.Task, + }, nil + })) + + g.PUT("/:id", handler("log", func(c *gin.Context) (interface{}, error) { + update := models.LogUpdate{} + err := c.BindJSON(&update) + if err != nil { + return nil, slerrors.BadRequest("Invalid JSON") + } + + log, err := l.FindLog(c.Request.Context(), c.Param("id")) + if err != nil { + return nil, err + } + + log.Update(update) + err = db.Logs().Update(c.Request.Context(), log.Log) + if err != nil { + return nil, err + } + + return log, nil + })) + + g.DELETE("/:id", handler("log", func(c *gin.Context) (interface{}, error) { + log, err := l.FindLog(c.Request.Context(), c.Param("id")) + if err != nil { + return nil, err + } + + err = db.Logs().Delete(c.Request.Context(), log.Log) + if err != nil { + return nil, err + } + + return log, nil + })) +} diff --git a/api/project.go b/api/project.go new file mode 100644 index 0000000..cac29dd --- /dev/null +++ b/api/project.go @@ -0,0 +1,101 @@ +package api + +import ( + "github.com/gin-gonic/gin" + "github.com/gissleh/stufflog/database" + "github.com/gissleh/stufflog/internal/auth" + "github.com/gissleh/stufflog/internal/generate" + "github.com/gissleh/stufflog/internal/slerrors" + "github.com/gissleh/stufflog/models" + "github.com/gissleh/stufflog/services" + "time" +) + +func Project(g *gin.RouterGroup, db database.Database) { + l := services.Loader{DB: db} + + defaultActive := true + + g.GET("/", handler("projects", func(c *gin.Context) (interface{}, error) { + filter := models.ProjectFilter{} + if setting := c.Query("active"); setting != "" { + active := setting == "true" + filter.Active = &active + } else { + filter.Active = &defaultActive + } + if setting := c.Query("expiring"); setting != "" { + filter.Expiring = setting == "true" + } + + return l.ListProjects(c, filter) + })) + + g.GET("/:id", handler("project", func(c *gin.Context) (interface{}, error) { + return l.FindProject(c, c.Param("id")) + })) + + g.POST("/", handler("project", func(c *gin.Context) (interface{}, error) { + project := models.Project{} + err := c.BindJSON(&project) + if err != nil { + return nil, slerrors.BadRequest("Invalid JSON") + } + if project.EndTime != nil && project.EndTime.Before(time.Now()) { + return nil, slerrors.BadRequest("Project end time must be later than current time.") + } + + project.ID = generate.ProjectID() + project.UserID = auth.UserID(c) + project.CreatedTime = time.Now().UTC() + + err = db.Projects().Insert(c.Request.Context(), project) + if err != nil { + return nil, err + } + + return &models.ProjectResult{ + Project: project, + Tasks: []*models.TaskResult{}, + }, nil + })) + + g.PUT("/:id", handler("project", func(c *gin.Context) (interface{}, error) { + update := models.ProjectUpdate{} + err := c.BindJSON(&update) + if err != nil { + return nil, slerrors.BadRequest("Invalid JSON") + } + + project, err := l.FindProject(c.Request.Context(), c.Param("id")) + if err != nil { + return nil, err + } + + project.Update(update) + err = db.Projects().Update(c.Request.Context(), project.Project) + if err != nil { + return nil, err + } + + return project, nil + })) + + g.DELETE("/:id", handler("project", func(c *gin.Context) (interface{}, error) { + project, err := l.FindProject(c.Request.Context(), c.Param("id")) + if err != nil { + return nil, err + } + + if len(project.Tasks) > 0 { + return nil, slerrors.Forbidden("cannot delete non-empty projects.") + } + + err = db.Projects().Delete(c.Request.Context(), project.Project) + if err != nil { + return nil, err + } + + return project, nil + })) +} diff --git a/api/task.go b/api/task.go new file mode 100644 index 0000000..d339f1c --- /dev/null +++ b/api/task.go @@ -0,0 +1,111 @@ +package api + +import ( + "github.com/gin-gonic/gin" + "github.com/gissleh/stufflog/database" + "github.com/gissleh/stufflog/internal/auth" + "github.com/gissleh/stufflog/internal/generate" + "github.com/gissleh/stufflog/internal/slerrors" + "github.com/gissleh/stufflog/models" + "github.com/gissleh/stufflog/services" + "time" +) + +func Task(g *gin.RouterGroup, db database.Database) { + l := services.Loader{DB: db} + + defaultActive := true + + g.GET("/", handler("tasks", func(c *gin.Context) (interface{}, error) { + filter := models.TaskFilter{} + if setting := c.Query("active"); setting != "" { + active := setting == "true" + filter.Active = &active + } else { + filter.Active = &defaultActive + } + + return l.ListTasks(c, filter) + })) + + g.GET("/:id", handler("task", func(c *gin.Context) (interface{}, error) { + return l.FindTask(c, c.Param("id")) + })) + + g.POST("/", handler("task", func(c *gin.Context) (interface{}, error) { + task := models.Task{} + err := c.BindJSON(&task) + if err != nil { + return nil, slerrors.BadRequest("Invalid JSON") + } + if task.EndTime != nil && task.EndTime.Before(time.Now()) { + return nil, slerrors.BadRequest("Project end time must be later than current time.") + } + + project, err := l.FindProject(c.Request.Context(), task.ProjectID) + if err != nil { + return nil, err + } + item, err := l.FindItem(c.Request.Context(), task.ItemID) + if err != nil { + return nil, err + } + + task.ID = generate.TaskID() + task.UserID = auth.UserID(c) + task.CreatedTime = time.Now().UTC() + task.ItemID = item.ID + task.ProjectID = project.ID + + err = db.Tasks().Insert(c.Request.Context(), task) + if err != nil { + return nil, err + } + + return &models.TaskResult{ + Task: task, + Logs: []*models.Log{}, + Item: &item.Item, + CompletedAmount: 0, + }, nil + })) + + g.PUT("/:id", handler("task", func(c *gin.Context) (interface{}, error) { + update := models.TaskUpdate{} + err := c.BindJSON(&update) + if err != nil { + return nil, slerrors.BadRequest("Invalid JSON") + } + + task, err := l.FindTask(c.Request.Context(), c.Param("id")) + if err != nil { + return nil, err + } + + task.Update(update) + err = db.Tasks().Update(c.Request.Context(), task.Task) + if err != nil { + return nil, err + } + + return task, nil + })) + + g.DELETE("/:id", handler("task", func(c *gin.Context) (interface{}, error) { + task, err := l.FindTask(c.Request.Context(), c.Param("id")) + if err != nil { + return nil, err + } + + if len(task.Logs) > 0 { + return nil, slerrors.Forbidden("cannot delete tasks with logs.") + } + + err = db.Tasks().Delete(c.Request.Context(), task.Task) + if err != nil { + return nil, err + } + + return task, nil + })) +} diff --git a/cmd/stufflog2-lambda/main.go b/cmd/stufflog2-lambda/main.go new file mode 100644 index 0000000..c7eb84c --- /dev/null +++ b/cmd/stufflog2-lambda/main.go @@ -0,0 +1,51 @@ +package main + +import ( + "context" + "github.com/aws/aws-lambda-go/events" + "github.com/aws/aws-lambda-go/lambda" + ginadapter "github.com/awslabs/aws-lambda-go-api-proxy/gin" + "github.com/gin-gonic/gin" + "github.com/gissleh/stufflog/api" + "github.com/gissleh/stufflog/database" + "github.com/gissleh/stufflog/internal/auth" + "log" + "os" +) + +func env(key string, defaultValue string) string { + e := os.Getenv(key) + if e == "" { + return defaultValue + } + + return e +} + +func main() { + dbDriver := env("DB_DRIVER", "postgres") + dbConnect := env("DB_CONNECT", "") + + gin.SetMode(gin.ReleaseMode) + + db, err := database.Open(context.Background(), dbDriver, dbConnect) + if err != nil { + log.Println("Failed to open database:", err) + os.Exit(1) + } + + server := gin.New() + server.Use(auth.TrustingJwtParserMiddleware()) + + api.Group(server.Group("/api/group"), db) + api.Item(server.Group("/api/item"), db) + api.Project(server.Group("/api/project"), db) + api.Task(server.Group("/api/task"), db) + api.Log(server.Group("/api/log"), db) + api.Goal(server.Group("/api/goal"), db) + + ginLambda := ginadapter.New(server) + lambda.Start(func(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) { + return ginLambda.ProxyWithContext(ctx, request) + }) +} diff --git a/cmd/stufflog2-local/main.go b/cmd/stufflog2-local/main.go new file mode 100644 index 0000000..c7f3185 --- /dev/null +++ b/cmd/stufflog2-local/main.go @@ -0,0 +1,74 @@ +package main + +import ( + "context" + "github.com/gin-gonic/gin" + "github.com/gissleh/stufflog/api" + "github.com/gissleh/stufflog/database" + "github.com/gissleh/stufflog/internal/auth" + "log" + "os" + "os/signal" + "syscall" +) + +func env(key string, defaultValue string) string { + e := os.Getenv(key) + if e == "" { + return defaultValue + } + + return e +} + +func main() { + dbDriver := env("DB_DRIVER", "postgres") + dbConnect := env("DB_CONNECT", "host=localhost user=stufflog2 password=stufflog2_dev_password dbname=stufflog2 sslmode=disable") + serverListen := env("SERVER_LISTEN", ":8000") + useDummyUuid := env("USE_DUMMY_UUID", "no") + dummyUuid := env("DUMMY_UUID", "9d3214f1-6321-403e-ab87-764ad1a1252d") + + db, err := database.Open(context.Background(), dbDriver, dbConnect) + if err != nil { + log.Println("Failed to open database:", err) + os.Exit(1) + } + + server := gin.New() + if useDummyUuid == "yes" { + server.Use(auth.DummyMiddleware(dummyUuid)) + } else { + server.Use(auth.TrustingJwtParserMiddleware()) + } + + api.Group(server.Group("/api/group"), db) + api.Item(server.Group("/api/item"), db) + api.Project(server.Group("/api/project"), db) + api.Task(server.Group("/api/task"), db) + api.Log(server.Group("/api/log"), db) + api.Goal(server.Group("/api/goal"), db) + + exitSignal := make(chan os.Signal) + signal.Notify(exitSignal, os.Interrupt, os.Kill, syscall.SIGTERM) + + errCh := make(chan error) + go func() { + err := server.Run(serverListen) + if err != nil { + errCh <- err + } + }() + + select { + case sig := <-exitSignal: + { + log.Println("Received signal", sig) + os.Exit(0) + } + case err := <-errCh: + { + log.Println("Server run failed:", err) + os.Exit(2) + } + } +} diff --git a/database/database.go b/database/database.go new file mode 100644 index 0000000..4a5af86 --- /dev/null +++ b/database/database.go @@ -0,0 +1,28 @@ +package database + +import ( + "context" + "errors" + "github.com/gissleh/stufflog/database/postgres" + "github.com/gissleh/stufflog/models" +) + +var ErrUnsupportedDriver = errors.New("usupported driver") + +type Database interface { + Goals() models.GoalRepository + Groups() models.GroupRepository + Items() models.ItemRepository + Logs() models.LogRepository + Projects() models.ProjectRepository + Tasks() models.TaskRepository +} + +func Open(ctx context.Context, driver string, connect string) (Database, error) { + switch driver { + case "postgres": + return postgres.Setup(ctx, connect) + default: + return nil, ErrUnsupportedDriver + } +} diff --git a/database/postgres/db.go b/database/postgres/db.go new file mode 100644 index 0000000..ddcb30a --- /dev/null +++ b/database/postgres/db.go @@ -0,0 +1,51 @@ +package postgres + +import ( + "context" + "github.com/gissleh/stufflog/models" + "github.com/jmoiron/sqlx" + + _ "github.com/lib/pq" +) + +type Database struct { + db *sqlx.DB +} + +func (d *Database) Goals() models.GoalRepository { + return &goalRepository{db: d.db} +} + +func (d *Database) Groups() models.GroupRepository { + return &groupRepository{db: d.db} +} + +func (d *Database) Items() models.ItemRepository { + return &itemRepository{db: d.db} +} + +func (d *Database) Logs() models.LogRepository { + return &logRepository{db: d.db} +} + +func (d *Database) Projects() models.ProjectRepository { + return &projectRepository{db: d.db} +} + +func (d *Database) Tasks() models.TaskRepository { + return &taskRepository{db: d.db} +} + +func Setup(ctx context.Context, connect string) (*Database, error) { + db, err := sqlx.ConnectContext(ctx, "postgres", connect) + if err != nil { + return nil, err + } + + err = db.PingContext(ctx) + if err != nil { + return nil, err + } + + return &Database{db: db}, nil +} diff --git a/database/postgres/goals.go b/database/postgres/goals.go new file mode 100644 index 0000000..6c2f658 --- /dev/null +++ b/database/postgres/goals.go @@ -0,0 +1,115 @@ +package postgres + +import ( + "context" + "database/sql" + "github.com/Masterminds/squirrel" + "github.com/gissleh/stufflog/internal/slerrors" + "github.com/gissleh/stufflog/models" + "github.com/jmoiron/sqlx" +) + +type goalRepository struct { + db *sqlx.DB +} + +func (r *goalRepository) Find(ctx context.Context, id string) (*models.Goal, error) { + res := models.Goal{} + err := r.db.GetContext(ctx, &res, "SELECT * FROM goal WHERE goal_id=$1", id) + if err != nil { + if err == sql.ErrNoRows { + return nil, slerrors.NotFound("Goal") + } + + return nil, err + } + + return &res, nil +} + +func (r *goalRepository) List(ctx context.Context, filter models.GoalFilter) ([]*models.Goal, error) { + sq := squirrel.Select("*").From("goal").PlaceholderFormat(squirrel.Dollar) + sq = sq.Where(squirrel.Eq{"user_id": filter.UserID}) + if len(filter.IDs) > 0 { + sq = sq.Where(squirrel.Eq{"goal_id": filter.IDs}) + } + if filter.MinTime != nil { + sq = sq.Where(squirrel.GtOrEq{ + "end_time": *filter.MinTime, + }) + } + if filter.MaxTime != nil { + sq = sq.Where(squirrel.LtOrEq{ + "start_time": *filter.MaxTime, + }) + } + if filter.IncludesTime != nil { + sq = sq.Where(squirrel.LtOrEq{ + "start_time": *filter.IncludesTime, + }).Where(squirrel.GtOrEq{ + "end_time": *filter.IncludesTime, + }) + } + + sq = sq.OrderBy("start_time", "end_time", "name") + + query, args, err := sq.ToSql() + if err != nil { + return nil, err + } + + res := make([]*models.Goal, 0, 8) + err = r.db.SelectContext(ctx, &res, query, args...) + if err != nil { + if err == sql.ErrNoRows { + return res, nil + } + return nil, err + } + + return res, nil +} + +func (r *goalRepository) Insert(ctx context.Context, goal models.Goal) error { + _, err := r.db.NamedExecContext(ctx, ` + INSERT INTO goal ( + goal_id, user_id, group_id, amount, start_time, end_time, name, description + ) VALUES ( + :goal_id, :user_id, :group_id, :amount, :start_time, :end_time, :name, :description + ) + `, &goal) + if err != nil { + return err + } + + return nil +} + +func (r *goalRepository) Update(ctx context.Context, goal models.Goal) error { + _, err := r.db.NamedExecContext(ctx, ` + UPDATE goal SET + amount=:amount, + start_time=:start_time, + end_time=:end_time, + name=:name, + description=:description + WHERE goal_id=:goal_id + `, &goal) + if err != nil { + return err + } + + return nil +} + +func (r *goalRepository) Delete(ctx context.Context, goal models.Goal) error { + _, err := r.db.ExecContext(ctx, `DELETE FROM goal WHERE goal_id=$1`, goal.ID) + if err != nil { + if err == sql.ErrNoRows { + return slerrors.NotFound("Goal") + } + return err + } + + return nil +} diff --git a/database/postgres/group.go b/database/postgres/group.go new file mode 100644 index 0000000..fb573c7 --- /dev/null +++ b/database/postgres/group.go @@ -0,0 +1,96 @@ +package postgres + +import ( + "context" + "database/sql" + "github.com/Masterminds/squirrel" + "github.com/gissleh/stufflog/internal/slerrors" + "github.com/gissleh/stufflog/models" + "github.com/jmoiron/sqlx" +) + +type groupRepository struct { + db *sqlx.DB +} + +func (r *groupRepository) Find(ctx context.Context, id string) (*models.Group, error) { + res := models.Group{} + err := r.db.GetContext(ctx, &res, "SELECT * FROM \"group\" WHERE group_id=$1", id) + if err != nil { + if err == sql.ErrNoRows { + return nil, slerrors.NotFound("Group") + } + + return nil, err + } + + return &res, nil +} + +func (r *groupRepository) List(ctx context.Context, filter models.GroupFilter) ([]*models.Group, error) { + sq := squirrel.Select("*").From("\"group\"").PlaceholderFormat(squirrel.Dollar) + sq = sq.Where(squirrel.Eq{"user_id": filter.UserID}) + if len(filter.IDs) > 0 { + sq = sq.Where(squirrel.Eq{"group_id": filter.IDs}) + } + + sq = sq.OrderBy("name") + + query, args, err := sq.ToSql() + if err != nil { + return nil, err + } + + res := make([]*models.Group, 0, 8) + err = r.db.SelectContext(ctx, &res, query, args...) + if err != nil { + if err == sql.ErrNoRows { + return []*models.Group{}, nil + } + return nil, err + } + + return res, nil +} + +func (r *groupRepository) Insert(ctx context.Context, group models.Group) error { + _, err := r.db.NamedExecContext(ctx, ` + INSERT INTO "group" ( + group_id, user_id, name, icon, description + ) VALUES ( + :group_id, :user_id, :name, :icon, :description + ) + `, &group) + if err != nil { + return err + } + + return nil +} + +func (r *groupRepository) Update(ctx context.Context, group models.Group) error { + _, err := r.db.NamedExecContext(ctx, ` + UPDATE "group" SET + name=:name, + icon=:icon, + description=:description + WHERE group_id=:group_id + `, &group) + if err != nil { + return err + } + + return nil +} + +func (r *groupRepository) Delete(ctx context.Context, group models.Group) error { + _, err := r.db.ExecContext(ctx, `DELETE FROM "group" WHERE group_id=$1`, group.ID) + if err != nil { + if err == sql.ErrNoRows { + return slerrors.NotFound("Group") + } + return err + } + + return nil +} diff --git a/database/postgres/item.go b/database/postgres/item.go new file mode 100644 index 0000000..95cba09 --- /dev/null +++ b/database/postgres/item.go @@ -0,0 +1,100 @@ +package postgres + +import ( + "context" + "database/sql" + "github.com/Masterminds/squirrel" + "github.com/gissleh/stufflog/internal/slerrors" + "github.com/gissleh/stufflog/models" + "github.com/jmoiron/sqlx" +) + +type itemRepository struct { + db *sqlx.DB +} + +func (r *itemRepository) Find(ctx context.Context, id string) (*models.Item, error) { + res := models.Item{} + err := r.db.GetContext(ctx, &res, "SELECT item.*, g.icon FROM item INNER JOIN \"group\" AS g ON item.group_id = g.group_id WHERE item_id=$1", id) + if err != nil { + if err == sql.ErrNoRows { + return nil, slerrors.NotFound("Item") + } + + return nil, err + } + + return &res, nil +} + +func (r *itemRepository) List(ctx context.Context, filter models.ItemFilter) ([]*models.Item, error) { + sq := squirrel.Select("item.*", "g.icon").From("item").PlaceholderFormat(squirrel.Dollar) + sq = sq.Where(squirrel.Eq{"item.user_id": filter.UserID}) + if len(filter.IDs) > 0 { + sq = sq.Where(squirrel.Eq{"item.item_id": filter.IDs}) + } + if len(filter.GroupIDs) > 0 { + sq = sq.Where(squirrel.Eq{"item.group_id": filter.GroupIDs}) + } + + sq = sq.InnerJoin("\"group\" AS g ON item.group_id = g.group_id") + sq = sq.OrderBy("item.group_weight", "item.name") + + query, args, err := sq.ToSql() + if err != nil { + return nil, err + } + + res := make([]*models.Item, 0, 8) + err = r.db.SelectContext(ctx, &res, query, args...) + if err != nil { + if err == sql.ErrNoRows { + return res, nil + } + return nil, err + } + + return res, nil +} + +func (r *itemRepository) Insert(ctx context.Context, item models.Item) error { + _, err := r.db.NamedExecContext(ctx, ` + INSERT INTO item ( + item_id, user_id, group_id, group_weight, name, description + ) VALUES ( + :item_id, :user_id, :group_id, :group_weight, :name, :description + ) + `, &item) + if err != nil { + return err + } + + return nil +} + +func (r *itemRepository) Update(ctx context.Context, item models.Item) error { + _, err := r.db.NamedExecContext(ctx, ` + UPDATE item SET + group_weight = :group_weight, + name = :name, + description = :description + WHERE item_id=:item_id + `, &item) + if err != nil { + return err + } + + return nil +} + +func (r *itemRepository) Delete(ctx context.Context, item models.Item) error { + _, err := r.db.ExecContext(ctx, `DELETE FROM item WHERE item_id=$1`, item.ID) + if err != nil { + if err == sql.ErrNoRows { + return slerrors.NotFound("Item") + } + return err + } + + return nil +} diff --git a/database/postgres/logs.go b/database/postgres/logs.go new file mode 100644 index 0000000..c85ebaf --- /dev/null +++ b/database/postgres/logs.go @@ -0,0 +1,108 @@ +package postgres + +import ( + "context" + "database/sql" + "github.com/Masterminds/squirrel" + "github.com/gissleh/stufflog/internal/slerrors" + "github.com/gissleh/stufflog/models" + "github.com/jmoiron/sqlx" +) + +type logRepository struct { + db *sqlx.DB +} + +func (r *logRepository) Find(ctx context.Context, id string) (*models.Log, error) { + res := models.Log{} + err := r.db.GetContext(ctx, &res, "SELECT * FROM log WHERE log_id=$1", id) + if err != nil { + if err == sql.ErrNoRows { + return nil, slerrors.NotFound("Log") + } + + return nil, err + } + + return &res, nil +} + +func (r *logRepository) List(ctx context.Context, filter models.LogFilter) ([]*models.Log, error) { + sq := squirrel.Select("log.*").From("log").PlaceholderFormat(squirrel.Dollar) + sq = sq.Where(squirrel.Eq{"user_id": filter.UserID}) + if len(filter.IDs) > 0 { + sq = sq.Where(squirrel.Eq{"task_id": filter.IDs}) + } + if len(filter.ItemIDs) > 0 { + sq = sq.Where(squirrel.Eq{"item_id": filter.ItemIDs}) + } + if filter.MinTime != nil { + sq = sq.Where(squirrel.GtOrEq{ + "logged_time": *filter.MinTime, + }) + } + if filter.MaxTime != nil { + sq = sq.Where(squirrel.LtOrEq{ + "logged_time": *filter.MaxTime, + }) + } + + sq = sq.OrderBy("logged_time") + + query, args, err := sq.ToSql() + if err != nil { + return nil, err + } + + res := make([]*models.Log, 0, 8) + err = r.db.SelectContext(ctx, &res, query, args...) + if err != nil { + if err == sql.ErrNoRows { + return res, nil + } + return nil, err + } + + return res, nil +} + +func (r *logRepository) Insert(ctx context.Context, log models.Log) error { + _, err := r.db.NamedExecContext(ctx, ` + INSERT INTO log ( + log_id, user_id, task_id, item_id, logged_time, description + ) VALUES ( + :log_id, :user_id, :task_id, :item_id, :logged_time, :description + ) + `, &log) + if err != nil { + return err + } + + return nil +} + +func (r *logRepository) Update(ctx context.Context, log models.Log) error { + _, err := r.db.NamedExecContext(ctx, ` + UPDATE log SET + logged_time=:logged_time, + description=:description + WHERE log_id=:log_id + `, &log) + if err != nil { + return err + } + + return nil +} + +func (r *logRepository) Delete(ctx context.Context, log models.Log) error { + _, err := r.db.ExecContext(ctx, `DELETE FROM log WHERE log_id=$1`, log.ID) + if err != nil { + if err == sql.ErrNoRows { + return slerrors.NotFound("Log") + } + return err + } + + return nil +} diff --git a/database/postgres/project.go b/database/postgres/project.go new file mode 100644 index 0000000..82c658f --- /dev/null +++ b/database/postgres/project.go @@ -0,0 +1,104 @@ +package postgres + +import ( + "context" + "database/sql" + "github.com/Masterminds/squirrel" + "github.com/gissleh/stufflog/internal/slerrors" + "github.com/gissleh/stufflog/models" + "github.com/jmoiron/sqlx" +) + +type projectRepository struct { + db *sqlx.DB +} + +func (r *projectRepository) Find(ctx context.Context, id string) (*models.Project, error) { + res := models.Project{} + err := r.db.GetContext(ctx, &res, "SELECT * FROM project WHERE project_id=$1", id) + if err != nil { + if err == sql.ErrNoRows { + return nil, slerrors.NotFound("Log") + } + + return nil, err + } + + return &res, nil +} + +func (r *projectRepository) List(ctx context.Context, filter models.ProjectFilter) ([]*models.Project, error) { + sq := squirrel.Select("*").From("project").PlaceholderFormat(squirrel.Dollar) + sq = sq.Where(squirrel.Eq{"user_id": filter.UserID}) + if filter.IDs != nil { + sq = sq.Where(squirrel.Eq{"project_id": filter.IDs}) + } + if filter.Active != nil { + sq = sq.Where(squirrel.Eq{"active": *filter.Active}) + } + if filter.Expiring { + sq = sq.Where("end_time IS NOT NULL") + } + + sq = sq.OrderBy("created_time DESC") + + query, args, err := sq.ToSql() + if err != nil { + return nil, err + } + + res := make([]*models.Project, 0, 8) + err = r.db.SelectContext(ctx, &res, query, args...) + if err != nil { + if err == sql.ErrNoRows { + return res, nil + } + return nil, err + } + + return res, nil +} + +func (r *projectRepository) Insert(ctx context.Context, project models.Project) error { + _, err := r.db.NamedExecContext(ctx, ` + INSERT INTO project( + project_id, user_id, name, description, icon, active, created_time, end_time + ) VALUES ( + :project_id, :user_id, :name, :description, :icon, :active, :created_time, :end_time + ) + `, &project) + if err != nil { + return err + } + + return nil +} + +func (r *projectRepository) Update(ctx context.Context, project models.Project) error { + _, err := r.db.NamedExecContext(ctx, ` + UPDATE project SET + name = :name, + description = :description, + icon = :icon, + active = :active, + end_time = :end_time + WHERE project_id=:project_id + `, &project) + if err != nil { + return err + } + + return nil +} + +func (r *projectRepository) Delete(ctx context.Context, project models.Project) error { + _, err := r.db.ExecContext(ctx, `DELETE FROM project WHERE project_id=$1`, project.ID) + if err != nil { + if err == sql.ErrNoRows { + return slerrors.NotFound("Project") + } + return err + } + + return nil +} diff --git a/database/postgres/tasks.go b/database/postgres/tasks.go new file mode 100644 index 0000000..320da66 --- /dev/null +++ b/database/postgres/tasks.go @@ -0,0 +1,109 @@ +package postgres + +import ( + "context" + "database/sql" + "github.com/Masterminds/squirrel" + "github.com/gissleh/stufflog/internal/slerrors" + "github.com/gissleh/stufflog/models" + "github.com/jmoiron/sqlx" +) + +type taskRepository struct { + db *sqlx.DB +} + +func (r *taskRepository) Find(ctx context.Context, id string) (*models.Task, error) { + res := models.Task{} + err := r.db.GetContext(ctx, &res, "SELECT task.*, p.icon FROM task INNER JOIN project AS p ON task.project_id = p.project_id WHERE task_id=$1", id) + if err != nil { + if err == sql.ErrNoRows { + return nil, slerrors.NotFound("Task") + } + + return nil, err + } + + return &res, nil +} + +func (r *taskRepository) List(ctx context.Context, filter models.TaskFilter) ([]*models.Task, error) { + sq := squirrel.Select("task.*", "p.icon").From("task").PlaceholderFormat(squirrel.Dollar) + sq = sq.Where(squirrel.Eq{"task.user_id": filter.UserID}) + if filter.Active != nil { + sq = sq.Where(squirrel.Eq{"task.active": *filter.Active}) + } + if filter.IDs != nil { + sq = sq.Where(squirrel.Eq{"task.task_id": filter.IDs}) + } + if filter.ItemIDs != nil { + sq = sq.Where(squirrel.Eq{"task.item_id": filter.ItemIDs}) + } + if filter.ProjectIDs != nil { + sq = sq.Where(squirrel.Eq{"task.project_id": filter.ProjectIDs}) + } + + sq = sq.InnerJoin("project AS p ON task.project_id = p.project_id") + sq = sq.OrderBy("created_time") + + query, args, err := sq.ToSql() + if err != nil { + return nil, err + } + + res := make([]*models.Task, 0, 8) + err = r.db.SelectContext(ctx, &res, query, args...) + if err != nil { + if err == sql.ErrNoRows { + return res, nil + } + return nil, err + } + + return res, nil +} + +func (r *taskRepository) Insert(ctx context.Context, task models.Task) error { + _, err := r.db.NamedExecContext(ctx, ` + INSERT INTO task ( + task_id, user_id, item_id, project_id, item_amount, name, description, active, created_time, end_time + ) VALUES ( + :task_id, :user_id, :item_id, :project_id, :item_amount, :name, :description, :active, :created_time, :end_time + ) + `, &task) + if err != nil { + return err + } + + return nil +} + +func (r *taskRepository) Update(ctx context.Context, task models.Task) error { + _, err := r.db.NamedExecContext(ctx, ` + UPDATE task SET + item_id = :item_id, + item_amount = :item_amount, + name = :name, + description = :description, + active = :active, + end_time = :end_time + WHERE task_id=:task_id + `, &task) + if err != nil { + return err + } + + return nil +} + +func (r *taskRepository) Delete(ctx context.Context, task models.Task) error { + _, err := r.db.ExecContext(ctx, `DELETE FROM task WHERE task_id=$1`, task.ID) + if err != nil { + if err == sql.ErrNoRows { + return slerrors.NotFound("Task") + } + return err + } + + return nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ebc5438 --- /dev/null +++ b/go.mod @@ -0,0 +1,20 @@ +module github.com/gissleh/stufflog + +go 1.14 + +require ( + github.com/AchievementNetwork/stringset v1.1.0 + github.com/Masterminds/squirrel v1.5.0 + github.com/aws/aws-lambda-go v1.22.0 + github.com/awslabs/aws-lambda-go-api-proxy v0.9.0 + github.com/gin-gonic/gin v1.6.3 + github.com/go-sql-driver/mysql v1.5.0 // indirect + github.com/jmoiron/sqlx v1.2.0 + github.com/lib/pq v1.9.0 + github.com/mattn/go-sqlite3 v1.14.6 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pressly/goose v2.6.0+incompatible // indirect + github.com/ziutek/mymysql v1.5.4 // indirect + golang.org/x/sync v0.0.0-20201207232520-09787c993a3a + google.golang.org/appengine v1.6.7 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..8bea7f5 --- /dev/null +++ b/go.sum @@ -0,0 +1,333 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/AchievementNetwork/stringset v1.1.0 h1:6iGjAlend+mCls1tvEAxOBAUTb6nO6QG1/gfBzmPn+s= +github.com/AchievementNetwork/stringset v1.1.0/go.mod h1:FhOLOVB2mo9zbOR/N+hekGXEnh1VRbJprLlBk/HY71M= +github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= +github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= +github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= +github.com/Masterminds/squirrel v1.5.0 h1:JukIZisrUXadA9pl3rMkjhiamxiB0cXiu+HGp/Y8cY8= +github.com/Masterminds/squirrel v1.5.0/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= +github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= +github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= +github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/aws/aws-lambda-go v1.19.1/go.mod h1:jJmlefzPfGnckuHdXX7/80O3BvUUi12XOkbv4w9SGLU= +github.com/aws/aws-lambda-go v1.22.0 h1:X7BKqIdfoJcbsEIi+Lrt5YjX1HnZexIbNWOQgkYKgfE= +github.com/aws/aws-lambda-go v1.22.0/go.mod h1:jJmlefzPfGnckuHdXX7/80O3BvUUi12XOkbv4w9SGLU= +github.com/awslabs/aws-lambda-go-api-proxy v0.9.0 h1:oawiEVOu1ER3ROpDg8CaQ+V7A52frLGD3taPQjTywng= +github.com/awslabs/aws-lambda-go-api-proxy v0.9.0/go.mod h1:O8jHVv+ga5Kpg8+6i8qSZFp9rnxC1KB/R2yNFNgtFis= +github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chris-ramon/douceur v0.2.0/go.mod h1:wDW5xjJdeoMm1mRt4sD4c/LbF/mWdEpRXQKjTR8nIBE= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= +github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-playground/validator/v10 v10.3.0 h1:nZU+7q+yJoFmwvNgv/LnPUkwPal62+b2xXj0AU1Es7o= +github.com/go-playground/validator/v10 v10.3.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/gofiber/fiber/v2 v2.1.0/go.mod h1:aG+lMkwy3LyVit4CnmYUbUdgjpc3UYOltvlJZ78rgQ0= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= +github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= +github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= +github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= +github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= +github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= +github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA= +github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= +github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= +github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= +github.com/kataras/golog v0.0.18/go.mod h1:jRYl7dFYqP8aQj9VkwdBUXYZSfUktm+YYg1arJILfyw= +github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE= +github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= +github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= +github.com/kataras/pio v0.0.8/go.mod h1:NFfMp2kVP1rmV4N6gH6qgWpuoDKlrOeYi3VrAIWCGsE= +github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= +github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.1/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/labstack/echo/v4 v4.1.17/go.mod h1:Tn2yRQL/UclUalpb5rPdXDevbkJ+lp/2svdyFBg6CHQ= +github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= +github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= +github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= +github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= +github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8= +github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4= +github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= +github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= +github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= +github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= +github.com/microcosm-cc/bluemonday v1.0.3/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pressly/goose v2.6.0+incompatible h1:3f8zIQ8rfgP9tyI0Hmcs2YNAqUCL1c+diLe3iU8Qd/k= +github.com/pressly/goose v2.6.0+incompatible/go.mod h1:m+QHWCqxR3k8D9l7qfzuC/djtlfzxr34mozWDYEu1z8= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.16.0/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl6TwOBhHCA= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= +github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= +github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201016160150-f659759dc4ca h1:mLWBs1i4Qi5cHWGEtn2jieJQ2qtwV/gT0A2zLrmzaoE= +golang.org/x/sys v0.0.0-20201016160150-f659759dc4ca/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/auth/auth.go b/internal/auth/auth.go new file mode 100644 index 0000000..857ce55 --- /dev/null +++ b/internal/auth/auth.go @@ -0,0 +1,71 @@ +package auth + +import ( + "context" + "encoding/base64" + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/gissleh/stufflog/internal/slerrors" + "net/http" + "strings" +) + +var contextKey = struct{}{} + +func UserID(ctx context.Context) string { + if c, ok := ctx.(*gin.Context); ok { + return UserID(c.Request.Context()) + } + + return ctx.Value(&contextKey).(string) +} + +func DummyMiddleware(uuid string) gin.HandlerFunc { + return func(c *gin.Context) { + c.Request = c.Request.WithContext( + context.WithValue(c.Request.Context(), &contextKey, uuid), + ) + } +} + +func abortRequest(c *gin.Context) { + c.AbortWithStatusJSON(http.StatusUnauthorized, slerrors.ErrorResponse{ + Code: http.StatusUnauthorized, + Message: "You're not supposed to be here!", + }) +} + +// TrustingJwtParserMiddleware is meant to be put behind an AWS API gateway that has already +// verified this token. +func TrustingJwtParserMiddleware() gin.HandlerFunc { + return func(c *gin.Context) { + auth := c.GetHeader("Authorization") + split := strings.Split(auth, ".") + + if len(split) >= 3 { + data, err := base64.RawStdEncoding.DecodeString(split[1]) + if err != nil { + abortRequest(c) + return + } + + fields := make(map[string]interface{}) + err = json.Unmarshal(data, &fields) + if err != nil { + abortRequest(c) + return + } + + if sub, ok := fields["sub"].(string); ok { + c.Request = c.Request.WithContext( + context.WithValue(c.Request.Context(), &contextKey, sub), + ) + } else { + abortRequest(c) + return + } + } else { + abortRequest(c) + } + } +} diff --git a/internal/generate/ids.go b/internal/generate/ids.go new file mode 100644 index 0000000..d4f71d6 --- /dev/null +++ b/internal/generate/ids.go @@ -0,0 +1,52 @@ +package generate + +import ( + "crypto/rand" + "encoding/hex" + "log" + "strings" +) + +func id(prefix string, length int) string { + var id [16]byte + var buffer [32]byte + builder := strings.Builder{} + builder.Grow(length + 31) + builder.WriteString(prefix) + + for builder.Len() < length { + _, err := rand.Read(id[:]) + if err != nil { + log.Panicln("generate.id: failed to use OS random:", err) + } + + hex.Encode(buffer[:], id[:]) + builder.Write(buffer[:]) + } + + return builder.String()[:length] +} + +func GroupID() string { + return id("G", 16) +} + +func ItemID() string { + return id("I", 16) +} + +func ProjectID() string { + return id("P", 16) +} + +func TaskID() string { + return id("T", 16) +} + +func LogID() string { + return id("L", 16) +} + +func GoalID() string { + return id("A", 16) +} diff --git a/internal/slerrors/badrequest.go b/internal/slerrors/badrequest.go new file mode 100644 index 0000000..388681b --- /dev/null +++ b/internal/slerrors/badrequest.go @@ -0,0 +1,18 @@ +package slerrors + +type badRequestError struct { + Text string +} + +func (err *badRequestError) Error() string { + return "validation failed: " + err.Text +} + +func BadRequest(text string) error { + return &badRequestError{Text: text} +} + +func IsBadRequest(err error) bool { + _, ok := err.(*badRequestError) + return ok +} diff --git a/internal/slerrors/forbidden.go b/internal/slerrors/forbidden.go new file mode 100644 index 0000000..befb34c --- /dev/null +++ b/internal/slerrors/forbidden.go @@ -0,0 +1,22 @@ +package slerrors + +type forbiddenError struct { + Message string +} + +func (e *forbiddenError) Error() string { + return e.Message +} + +func Forbidden(message string) error { + return &forbiddenError{Message: message} +} + +func IsForbidden(err error) bool { + if err == nil { + return false + } + + _, ok := err.(*forbiddenError) + return ok +} diff --git a/internal/slerrors/gin.go b/internal/slerrors/gin.go new file mode 100644 index 0000000..0af2704 --- /dev/null +++ b/internal/slerrors/gin.go @@ -0,0 +1,35 @@ +package slerrors + +import ( + "github.com/gin-gonic/gin" + "net/http" +) + +type ErrorResponse struct { + Code int `json:"errorCode"` + Message string `json:"errorMessage"` +} + +func Respond(c *gin.Context, err error) { + if IsNotFound(err) { + c.JSON(http.StatusNotFound, ErrorResponse{ + Code: http.StatusNotFound, + Message: err.Error(), + }) + } else if IsForbidden(err) { + c.JSON(http.StatusForbidden, ErrorResponse{ + Code: http.StatusForbidden, + Message: err.Error(), + }) + } else if IsBadRequest(err) { + c.JSON(http.StatusBadRequest, ErrorResponse{ + Code: http.StatusBadRequest, + Message: err.Error(), + }) + } else { + c.JSON(http.StatusInternalServerError, ErrorResponse{ + Code: http.StatusInternalServerError, + Message: err.Error(), + }) + } +} diff --git a/internal/slerrors/notfound.go b/internal/slerrors/notfound.go new file mode 100644 index 0000000..9b493f8 --- /dev/null +++ b/internal/slerrors/notfound.go @@ -0,0 +1,18 @@ +package slerrors + +type notFoundError struct { + Subject string +} + +func (err *notFoundError) Error() string { + return err.Subject + " not found" +} + +func NotFound(subject string) error { + return ¬FoundError{Subject: subject} +} + +func IsNotFound(err error) bool { + _, ok := err.(*notFoundError) + return ok +} diff --git a/migrations/postgres/20201218170259_create_table_group.sql b/migrations/postgres/20201218170259_create_table_group.sql new file mode 100644 index 0000000..e3ed9bf --- /dev/null +++ b/migrations/postgres/20201218170259_create_table_group.sql @@ -0,0 +1,15 @@ +-- +goose Up +-- +goose StatementBegin +CREATE TABLE "group" ( + group_id CHAR(16) PRIMARY KEY, + user_id CHAR(36) NOT NULL, + name TEXT NOT NULL, + icon TEXT NOT NULL, + description TEXT NOT NULL +); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP TABLE "group"; +-- +goose StatementEnd diff --git a/migrations/postgres/20201218170301_create_table_item.sql b/migrations/postgres/20201218170301_create_table_item.sql new file mode 100644 index 0000000..e7652ee --- /dev/null +++ b/migrations/postgres/20201218170301_create_table_item.sql @@ -0,0 +1,16 @@ +-- +goose Up +-- +goose StatementBegin +CREATE TABLE item ( + item_id CHAR(16) PRIMARY KEY, + user_id CHAR(36) NOT NULL, + group_id CHAR(16) NOT NULL, + group_weight INT NOT NULL, + name TEXT NOT NULL, + description TEXT NOT NULL +); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP TABLE item; +-- +goose StatementEnd diff --git a/migrations/postgres/20201218170319_create_table_project.sql b/migrations/postgres/20201218170319_create_table_project.sql new file mode 100644 index 0000000..374d49f --- /dev/null +++ b/migrations/postgres/20201218170319_create_table_project.sql @@ -0,0 +1,18 @@ +-- +goose Up +-- +goose StatementBegin +CREATE TABLE project ( + project_id CHAR(16) PRIMARY KEY, + user_id CHAR(36) NOT NULL, + name TEXT NOT NULL, + description TEXT NOT NULL, + icon TEXT NOT NULL, + active BOOLEAN NOT NULL, + created_time TIMESTAMP NOT NULL, + end_time TIMESTAMP +); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP TABLE project; +-- +goose StatementEnd diff --git a/migrations/postgres/20201218170338_create_table_task.sql b/migrations/postgres/20201218170338_create_table_task.sql new file mode 100644 index 0000000..fef1f44 --- /dev/null +++ b/migrations/postgres/20201218170338_create_table_task.sql @@ -0,0 +1,20 @@ +-- +goose Up +-- +goose StatementBegin +CREATE TABLE task ( + task_id CHAR(16) PRIMARY KEY, + user_id CHAR(36) NOT NULL, + item_id CHAR(16) NOT NULL, + project_id CHAR(16) NOT NULL, + item_amount INT NOT NULL, + name TEXT NOT NULL, + description TEXT NOT NULL, + created_time TIMESTAMP NOT NULL, + active BOOLEAN NOT NULL, + end_time TIMESTAMP +); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP TABLE task; +-- +goose StatementEnd diff --git a/migrations/postgres/20201218170348_create_table_log.sql b/migrations/postgres/20201218170348_create_table_log.sql new file mode 100644 index 0000000..0947e17 --- /dev/null +++ b/migrations/postgres/20201218170348_create_table_log.sql @@ -0,0 +1,16 @@ +-- +goose Up +-- +goose StatementBegin +CREATE TABLE log ( + log_id CHAR(16) PRIMARY KEY, + user_id CHAR(36) NOT NULL, + task_id CHAR(16) NOT NULL, + item_id CHAR(16) NOT NULL, + logged_time TIMESTAMP NOT NULL, + description TEXT NOT NULL +); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP TABLE log; +-- +goose StatementEnd diff --git a/migrations/postgres/20201218170417_create_table_goal.sql b/migrations/postgres/20201218170417_create_table_goal.sql new file mode 100644 index 0000000..b9ae0d5 --- /dev/null +++ b/migrations/postgres/20201218170417_create_table_goal.sql @@ -0,0 +1,18 @@ +-- +goose Up +-- +goose StatementBegin +CREATE TABLE goal ( + goal_id CHAR(16) PRIMARY KEY, + user_id CHAR(36) NOT NULL, + group_id CHAR(16) NOT NULL, + start_time TIMESTAMP NOT NULL, + end_time TIMESTAMP NOT NULL, + amount INTEGER NOT NULL, + name TEXT NOT NULL, + description TEXT NOT NULL +); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP TABLE goal; +-- +goose StatementEnd diff --git a/migrations/postgres/20201223121327_create_index_item_group_id.sql b/migrations/postgres/20201223121327_create_index_item_group_id.sql new file mode 100644 index 0000000..ca8db1b --- /dev/null +++ b/migrations/postgres/20201223121327_create_index_item_group_id.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +CREATE INDEX item_group_id on item(group_id); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP INDEX item_group_id; +-- +goose StatementEnd diff --git a/migrations/postgres/20201223125438_create_index_log_task_id.sql b/migrations/postgres/20201223125438_create_index_log_task_id.sql new file mode 100644 index 0000000..dc7414d --- /dev/null +++ b/migrations/postgres/20201223125438_create_index_log_task_id.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +CREATE INDEX log_task_id on log(task_id); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP INDEX log_task_id; +-- +goose StatementEnd diff --git a/migrations/postgres/20201223125556_create_index_goal_start_time.sql b/migrations/postgres/20201223125556_create_index_goal_start_time.sql new file mode 100644 index 0000000..b16f63d --- /dev/null +++ b/migrations/postgres/20201223125556_create_index_goal_start_time.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +CREATE INDEX goal_start_time on goal(start_time); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP INDEX goal_start_time; +-- +goose StatementEnd diff --git a/migrations/postgres/20201223125559_create_index_goal_end_time.sql b/migrations/postgres/20201223125559_create_index_goal_end_time.sql new file mode 100644 index 0000000..26737b6 --- /dev/null +++ b/migrations/postgres/20201223125559_create_index_goal_end_time.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +CREATE INDEX goal_end_time on goal(end_time); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP INDEX goal_end_time; +-- +goose StatementEnd diff --git a/migrations/postgres/20201223125934_create_index_group_user_id.sql b/migrations/postgres/20201223125934_create_index_group_user_id.sql new file mode 100644 index 0000000..a87611f --- /dev/null +++ b/migrations/postgres/20201223125934_create_index_group_user_id.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +CREATE INDEX group_user_id on "group"(user_id); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP INDEX group_user_id; +-- +goose StatementEnd diff --git a/migrations/postgres/20201223125938_create_index_item_user_id.sql b/migrations/postgres/20201223125938_create_index_item_user_id.sql new file mode 100644 index 0000000..36217cb --- /dev/null +++ b/migrations/postgres/20201223125938_create_index_item_user_id.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +CREATE INDEX item_user_id on item(user_id); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP INDEX item_user_id; +-- +goose StatementEnd diff --git a/migrations/postgres/20201223125947_create_index_project_user_id.sql b/migrations/postgres/20201223125947_create_index_project_user_id.sql new file mode 100644 index 0000000..b048856 --- /dev/null +++ b/migrations/postgres/20201223125947_create_index_project_user_id.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +CREATE INDEX project_user_id on project(user_id); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP INDEX project_user_id; +-- +goose StatementEnd diff --git a/migrations/postgres/20201223125957_create_index_task_user_id.sql b/migrations/postgres/20201223125957_create_index_task_user_id.sql new file mode 100644 index 0000000..0f5c65f --- /dev/null +++ b/migrations/postgres/20201223125957_create_index_task_user_id.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +CREATE INDEX task_user_id on task(user_id); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP INDEX task_user_id; +-- +goose StatementEnd diff --git a/migrations/postgres/20201223130003_create_index_log_user_id.sql b/migrations/postgres/20201223130003_create_index_log_user_id.sql new file mode 100644 index 0000000..7c2bb9c --- /dev/null +++ b/migrations/postgres/20201223130003_create_index_log_user_id.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +CREATE INDEX log_user_id on log(user_id); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP INDEX log_user_id; +-- +goose StatementEnd diff --git a/migrations/postgres/20201223130007_create_index_goal_user_id.sql b/migrations/postgres/20201223130007_create_index_goal_user_id.sql new file mode 100644 index 0000000..e95c8cf --- /dev/null +++ b/migrations/postgres/20201223130007_create_index_goal_user_id.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +CREATE INDEX goal_user_id on goal(user_id); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP INDEX goal_user_id; +-- +goose StatementEnd diff --git a/migrations/postgres/20201223135724_create_index_project_created_time.sql b/migrations/postgres/20201223135724_create_index_project_created_time.sql new file mode 100644 index 0000000..68b6eac --- /dev/null +++ b/migrations/postgres/20201223135724_create_index_project_created_time.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +CREATE INDEX project_created_time on project(created_time); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP INDEX project_created_time; +-- +goose StatementEnd diff --git a/migrations/postgres/20201223135812_create_index_task_item_id.sql b/migrations/postgres/20201223135812_create_index_task_item_id.sql new file mode 100644 index 0000000..dee35f9 --- /dev/null +++ b/migrations/postgres/20201223135812_create_index_task_item_id.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +CREATE INDEX task_item_id on task(item_id); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP INDEX task_item_id; +-- +goose StatementEnd diff --git a/migrations/postgres/20201223140113_create_index_log_logged_time.sql b/migrations/postgres/20201223140113_create_index_log_logged_time.sql new file mode 100644 index 0000000..8e9961f --- /dev/null +++ b/migrations/postgres/20201223140113_create_index_log_logged_time.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +CREATE INDEX log_logged_time on log(logged_time); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP INDEX log_logged_time; +-- +goose StatementEnd diff --git a/migrations/postgres/20201225175922_create_index_log_item_id.sql b/migrations/postgres/20201225175922_create_index_log_item_id.sql new file mode 100644 index 0000000..60065d6 --- /dev/null +++ b/migrations/postgres/20201225175922_create_index_log_item_id.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +CREATE INDEX log_item_id on log(item_id); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP INDEX log_item_id; +-- +goose StatementEnd diff --git a/models/goal.go b/models/goal.go new file mode 100644 index 0000000..009228a --- /dev/null +++ b/models/goal.go @@ -0,0 +1,73 @@ +package models + +import ( + "context" + "time" +) + +type Goal struct { + ID string `json:"id" db:"goal_id"` + UserID string `json:"-" db:"user_id"` + GroupID string `json:"groupId" db:"group_id"` + StartTime time.Time `json:"startTime" db:"start_time"` + EndTime time.Time `json:"endTime" db:"end_time"` + Amount int `json:"amount" db:"amount"` + Name string `json:"name" db:"name"` + Description string `json:"description" db:"description"` +} + +func (goal *Goal) Update(update GoalUpdate) { + if update.Amount != nil { + goal.Amount = *update.Amount + } + if update.StartTime != nil { + goal.StartTime = *update.StartTime + } + if update.EndTime != nil { + goal.EndTime = *update.EndTime + } + if update.Name != nil { + goal.Name = *update.Name + } + if update.Description != nil { + goal.Description = *update.Description + } +} + +type GoalUpdate struct { + StartTime *time.Time `json:"startTime"` + EndTime *time.Time `json:"endTime"` + Amount *int `json:"amount"` + Name *string `json:"name"` + Description *string `json:"description"` +} + +type GoalResult struct { + Goal + Group *Group `json:"group"` + Items []*GoalResultItem `json:"items"` + Logs []*LogResult `json:"logs"` + CompletedAmount int `json:"completedAmount"` +} + +type GoalResultItem struct { + Item + CompletedAmount int `json:"completedAmount"` +} + +type GoalFilter struct { + UserID string + GroupIDs []string + IncludesTime *time.Time + MinTime *time.Time + MaxTime *time.Time + IDs []string +} + +type GoalRepository interface { + Find(ctx context.Context, id string) (*Goal, error) + List(ctx context.Context, filter GoalFilter) ([]*Goal, error) + Insert(ctx context.Context, goal Goal) error + Update(ctx context.Context, goal Goal) error + Delete(ctx context.Context, goal Goal) error +} diff --git a/models/group.go b/models/group.go new file mode 100644 index 0000000..bf31412 --- /dev/null +++ b/models/group.go @@ -0,0 +1,47 @@ +package models + +import "context" + +type Group struct { + ID string `json:"id" db:"group_id"` + UserID string `json:"-" db:"user_id"` + Name string `json:"name" db:"name"` + Icon string `json:"icon" db:"icon"` + Description string `json:"description" db:"description"` +} + +func (g *Group) Update(update GroupUpdate) { + if update.Name != nil { + g.Name = *update.Name + } + if update.Icon != nil { + g.Icon = *update.Icon + } + if update.Description != nil { + g.Description = *update.Description + } +} + +type GroupUpdate struct { + Name *string `json:"name"` + Icon *string `jsoN:"icon"` + Description *string `json:"description"` +} + +type GroupResult struct { + Group + Items []*Item `json:"items"` +} + +type GroupFilter struct { + UserID string + IDs []string +} + +type GroupRepository interface { + Find(ctx context.Context, id string) (*Group, error) + List(ctx context.Context, filter GroupFilter) ([]*Group, error) + Insert(ctx context.Context, group Group) error + Update(ctx context.Context, group Group) error + Delete(ctx context.Context, group Group) error +} diff --git a/models/item.go b/models/item.go new file mode 100644 index 0000000..d3a813d --- /dev/null +++ b/models/item.go @@ -0,0 +1,50 @@ +package models + +import "context" + +type Item struct { + ID string `json:"id" db:"item_id"` + UserID string `json:"-" db:"user_id"` + GroupID string `json:"groupId" db:"group_id"` + GroupWeight int `json:"groupWeight" db:"group_weight"` + Icon string `json:"icon" db:"icon"` + Name string `json:"name" db:"name"` + Description string `json:"description" db:"description"` +} + +func (item *Item) Update(update ItemUpdate) { + if update.GroupWeight != nil { + item.GroupWeight = *update.GroupWeight + } + if update.Name != nil { + item.Name = *update.Name + } + if update.Description != nil { + item.Description = *update.Description + } +} + +type ItemUpdate struct { + GroupWeight *int `json:"groupWeight"` + Name *string `json:"name"` + Description *string `json:"description"` +} + +type ItemResult struct { + Item + Group *Group `json:"group"` +} + +type ItemFilter struct { + UserID string + IDs []string + GroupIDs []string +} + +type ItemRepository interface { + Find(ctx context.Context, id string) (*Item, error) + List(ctx context.Context, filter ItemFilter) ([]*Item, error) + Insert(ctx context.Context, item Item) error + Update(ctx context.Context, item Item) error + Delete(ctx context.Context, item Item) error +} diff --git a/models/log.go b/models/log.go new file mode 100644 index 0000000..881f5ac --- /dev/null +++ b/models/log.go @@ -0,0 +1,50 @@ +package models + +import ( + "context" + "time" +) + +type Log struct { + ID string `json:"id" db:"log_id"` + UserID string `json:"-" db:"user_id"` + TaskID string `json:"taskId" db:"task_id"` + ItemID string `json:"itemId" db:"item_id"` + LoggedTime time.Time `json:"loggedTime" db:"logged_time"` + Description string `json:"description" db:"description"` +} + +func (log *Log) Update(update LogUpdate) { + if update.LoggedTime != nil { + log.LoggedTime = update.LoggedTime.UTC() + } + if update.Description != nil { + log.Description = *update.Description + } +} + +type LogUpdate struct { + LoggedTime *time.Time `json:"loggedTime"` + Description *string `json:"description"` +} + +type LogResult struct { + Log + Task *Task `json:"task"` +} + +type LogFilter struct { + UserID string + IDs []string + ItemIDs []string + MinTime *time.Time + MaxTime *time.Time +} + +type LogRepository interface { + Find(ctx context.Context, id string) (*Log, error) + List(ctx context.Context, filter LogFilter) ([]*Log, error) + Insert(ctx context.Context, log Log) error + Update(ctx context.Context, log Log) error + Delete(ctx context.Context, log Log) error +} diff --git a/models/project.go b/models/project.go new file mode 100644 index 0000000..7496a3d --- /dev/null +++ b/models/project.go @@ -0,0 +1,68 @@ +package models + +import ( + "context" + "time" +) + +type Project struct { + ID string `json:"id" db:"project_id"` + UserID string `json:"-" db:"user_id"` + Name string `json:"name" db:"name"` + Description string `json:"description" db:"description"` + Icon string `json:"icon" db:"icon"` + Active bool `json:"active" db:"active"` + CreatedTime time.Time `json:"createdTime" db:"created_time"` + EndTime *time.Time `json:"endTime" db:"end_time"` +} + +func (project *Project) Update(update ProjectUpdate) { + if update.Name != nil { + project.Name = *update.Name + } + if update.Description != nil { + project.Description = *update.Description + } + if update.Icon != nil { + project.Icon = *update.Icon + } + if update.Active != nil { + project.Active = *update.Active + } + if update.EndTime != nil { + endTimeCopy := update.EndTime.UTC() + project.EndTime = &endTimeCopy + } + if update.ClearEndTime { + project.EndTime = nil + } +} + +type ProjectUpdate struct { + Name *string `json:"name"` + Description *string `json:"description"` + Icon *string `json:"icon"` + Active *bool `json:"active"` + EndTime *time.Time `json:"endTime"` + ClearEndTime bool `json:"clearEndTime"` +} + +type ProjectResult struct { + Project + Tasks []*TaskResult `json:"tasks"` +} + +type ProjectFilter struct { + UserID string + Active *bool + Expiring bool + IDs []string +} + +type ProjectRepository interface { + Find(ctx context.Context, id string) (*Project, error) + List(ctx context.Context, filter ProjectFilter) ([]*Project, error) + Insert(ctx context.Context, project Project) error + Update(ctx context.Context, project Project) error + Delete(ctx context.Context, project Project) error +} diff --git a/models/task.go b/models/task.go new file mode 100644 index 0000000..50971b2 --- /dev/null +++ b/models/task.go @@ -0,0 +1,74 @@ +package models + +import ( + "context" + "time" +) + +type Task struct { + ID string `json:"id" db:"task_id"` + UserID string `json:"-" db:"user_id"` + ItemID string `json:"itemId" db:"item_id"` + ProjectID string `json:"projectId" db:"project_id"` + ItemAmount int `json:"itemAmount" db:"item_amount"` + Name string `json:"name" db:"name"` + Description string `json:"description" db:"description"` + Icon string `json:"icon" db:"icon"` + Active bool `json:"active" db:"active"` + CreatedTime time.Time `json:"createdTime" db:"created_time"` + EndTime *time.Time `json:"endTime" db:"end_time"` +} + +func (task *Task) Update(update TaskUpdate) { + if update.ItemAmount != nil { + task.ItemAmount = *update.ItemAmount + } + if update.Name != nil { + task.Name = *update.Name + } + if update.Description != nil { + task.Description = *update.Description + } + if update.Active != nil { + task.Active = *update.Active + } + if update.EndTime != nil { + endTimeCopy := update.EndTime.UTC() + task.EndTime = &endTimeCopy + } + if update.ClearEndTime { + task.EndTime = nil + } +} + +type TaskUpdate struct { + ItemAmount *int `json:"itemAmount"` + Name *string `json:"name"` + Description *string `json:"description"` + Active *bool `json:"active"` + EndTime *time.Time `json:"endTime"` + ClearEndTime bool `json:"clearEndTime"` +} + +type TaskResult struct { + Task + Item *Item `json:"item"` + Logs []*Log `json:"logs"` + CompletedAmount int `json:"completedAmount"` +} + +type TaskFilter struct { + UserID string + Active *bool + IDs []string + ItemIDs []string + ProjectIDs []string +} + +type TaskRepository interface { + Find(ctx context.Context, id string) (*Task, error) + List(ctx context.Context, filter TaskFilter) ([]*Task, error) + Insert(ctx context.Context, task Task) error + Update(ctx context.Context, task Task) error + Delete(ctx context.Context, task Task) error +} diff --git a/serverless.yml b/serverless.yml new file mode 100644 index 0000000..8faa346 --- /dev/null +++ b/serverless.yml @@ -0,0 +1,115 @@ +service: stufflog2 + +frameworkVersion: '2' + +provider: + name: aws + runtime: go1.x + memorySize: 512 + stage: prod + region: ${env:AWS_DEFAULT_REGION} + role: ${env:AMI_ROLE} + tags: + Name: Stufflog2 + Type: Application + apiGateway: + shouldStartNameWithService: true + minimumCompressionSize: 2048 + versionFunctions: false + environment: + DB_DRIVER: ${env:DB_DRIVER} + DB_CONNECT: ${env:DB_CONNECT} + +functions: + handleApiCalls: + handler: ./build/api/handler + package: + include: + - ./build/api/handler + events: + - http: ANY /api/{proxy+} + timeout: 30 + +package: + individually: true + exclude: + - ./** + +plugins: + - serverless-domain-manager + - serverless-apigateway-service-proxy + +custom: + webuiBucket: ${env:S3_WEBUI_BUCKET} + + apiGatewayServiceProxies: + - s3: + path: / + method: get + action: GetObject + bucket: ${self:custom.webuiBucket} + roleArn: ${self:provider.role} + key: index.html + requestParameters: + 'integration.request.header.cache-control': "'public, max-age=86400, immutable'" + + - s3: + path: /goals + method: get + action: GetObject + bucket: ${self:custom.webuiBucket} + roleArn: ${self:provider.role} + key: index.html + requestParameters: + 'integration.request.header.cache-control': "'public, max-age=86400, immutable'" + + - s3: + path: /projects + method: get + action: GetObject + bucket: ${self:custom.webuiBucket} + roleArn: ${self:provider.role} + key: index.html + requestParameters: + 'integration.request.header.cache-control': "'public, max-age=86400, immutable'" + + - s3: + path: /items + method: get + action: GetObject + bucket: ${self:custom.webuiBucket} + roleArn: ${self:provider.role} + key: index.html + requestParameters: + 'integration.request.header.cache-control': "'public, max-age=86400, immutable'" + + - s3: + path: /logs + method: get + action: GetObject + bucket: ${self:custom.webuiBucket} + roleArn: ${self:provider.role} + key: index.html + requestParameters: + 'integration.request.header.cache-control': "'public, max-age=86400, immutable'" + + - s3: + path: /{myPath+} + method: get + action: GetObject + bucket: ${self:custom.webuiBucket} + roleArn: ${self:provider.role} + requestParameters: + 'integration.request.path.myPath': 'method.request.path.myPath' + 'integration.request.path.object': 'method.request.path.myPath' + 'integration.request.header.cache-control': "'public, max-age=86400, immutable'" + + customDomain: + domainName: ${env:DOMAIN_NAME} + basePath: '' + certificateName: ${env:CERTIFICATE_NAME} + certificateArn: ${env:CERTIFICATE_ARN} + createRoute53Record: true + endpointType: 'regional' + hostedZoneId: ${env:HOSTED_ZONE_ID} + autoDomain: true \ No newline at end of file diff --git a/services/loader.go b/services/loader.go new file mode 100644 index 0000000..37acc64 --- /dev/null +++ b/services/loader.go @@ -0,0 +1,508 @@ +package services + +import ( + "context" + "github.com/AchievementNetwork/stringset" + "github.com/gissleh/stufflog/database" + "github.com/gissleh/stufflog/internal/auth" + "github.com/gissleh/stufflog/internal/slerrors" + "github.com/gissleh/stufflog/models" + "golang.org/x/sync/errgroup" +) + +// Loader loads the stuff. +type Loader struct { + DB database.Database +} + +func (l *Loader) FindGroup(ctx context.Context, id string) (*models.GroupResult, error) { + group, err := l.DB.Groups().Find(ctx, id) + if err != nil { + return nil, err + } + if group.UserID != auth.UserID(ctx) { + return nil, slerrors.NotFound("Goal") + } + + result := &models.GroupResult{Group: *group} + result.Items, err = l.DB.Items().List(ctx, models.ItemFilter{ + UserID: auth.UserID(ctx), + GroupIDs: []string{group.ID}, + }) + if err != nil { + return nil, err + } + + return result, nil +} + +func (l *Loader) ListGroups(ctx context.Context, filter models.GroupFilter) ([]*models.GroupResult, error) { + filter.UserID = auth.UserID(ctx) + groups, err := l.DB.Groups().List(ctx, filter) + if err != nil { + return nil, err + } + + groupIDs := make([]string, 0, len(groups)) + for _, group := range groups { + groupIDs = append(groupIDs, group.ID) + } + items, err := l.DB.Items().List(ctx, models.ItemFilter{ + UserID: auth.UserID(ctx), + GroupIDs: groupIDs, + }) + + results := make([]*models.GroupResult, len(groups)) + for i, group := range groups { + results[i] = &models.GroupResult{Group: *group, Items: []*models.Item{}} + for _, item := range items { + if item.GroupID == group.ID { + results[i].Items = append(results[i].Items, item) + } + } + } + + return results, nil +} + +func (l *Loader) FindItem(ctx context.Context, id string) (*models.ItemResult, error) { + item, err := l.DB.Items().Find(ctx, id) + if err != nil { + return nil, err + } + if item.UserID != auth.UserID(ctx) { + return nil, slerrors.NotFound("Item") + } + + result := &models.ItemResult{Item: *item} + result.Group, err = l.DB.Groups().Find(ctx, item.GroupID) + if err != nil { + return nil, err + } + + return result, nil +} + +func (l *Loader) ListItems(ctx context.Context, filter models.ItemFilter) ([]*models.ItemResult, error) { + filter.UserID = auth.UserID(ctx) + items, err := l.DB.Items().List(ctx, filter) + if err != nil { + return nil, err + } + + groupIDs := make([]string, 0, len(items)) + for _, item := range items { + groupIDs = append(groupIDs, item.GroupID) + } + groups, err := l.DB.Groups().List(ctx, models.GroupFilter{ + UserID: auth.UserID(ctx), + IDs: groupIDs, + }) + + results := make([]*models.ItemResult, len(items)) + for i, item := range items { + results[i] = &models.ItemResult{Item: *item} + for _, group := range groups { + if item.GroupID == group.ID { + results[i].Group = group + break + } + } + } + + return results, nil +} + +func (l *Loader) FindLog(ctx context.Context, id string) (*models.LogResult, error) { + log, err := l.DB.Logs().Find(ctx, id) + if err != nil { + return nil, err + } + if log.UserID != auth.UserID(ctx) { + return nil, slerrors.NotFound("Goal") + } + result := &models.LogResult{ + Log: *log, + Task: nil, + } + + result.Task, _ = l.DB.Tasks().Find(ctx, id) + + return result, nil +} + +func (l *Loader) ListLogs(ctx context.Context, filter models.LogFilter) ([]*models.LogResult, error) { + filter.UserID = auth.UserID(ctx) + logs, err := l.DB.Logs().List(ctx, filter) + if err != nil { + return nil, err + } + + taskIDs := stringset.New() + for _, log := range logs { + taskIDs.Add(log.TaskID) + } + tasks, err := l.DB.Tasks().List(ctx, models.TaskFilter{ + UserID: auth.UserID(ctx), + IDs: taskIDs.Strings(), + }) + if err != nil { + return nil, err + } + + results := make([]*models.LogResult, len(logs)) + for i, log := range logs { + results[i] = &models.LogResult{ + Log: *log, + Task: nil, + } + + for _, task := range tasks { + if task.ID == log.TaskID { + results[i].Task = task + break + } + } + } + + return results, nil +} + +func (l *Loader) FindProject(ctx context.Context, id string) (*models.ProjectResult, error) { + project, err := l.DB.Projects().Find(ctx, id) + if err != nil { + return nil, err + } + if project.UserID != auth.UserID(ctx) { + return nil, slerrors.NotFound("Goal") + } + result := &models.ProjectResult{Project: *project} + + tasks, err := l.DB.Tasks().List(ctx, models.TaskFilter{ + UserID: auth.UserID(ctx), + ProjectIDs: []string{project.ID}, + }) + taskIDs := make([]string, 0, len(tasks)) + itemIDs := stringset.New() + for _, task := range tasks { + taskIDs = append(taskIDs, task.ID) + itemIDs.Add(task.ItemID) + } + + logs, err := l.DB.Logs().List(ctx, models.LogFilter{ + UserID: auth.UserID(ctx), + IDs: taskIDs, + }) + if err != nil { + return nil, err + } + items, err := l.DB.Items().List(ctx, models.ItemFilter{ + UserID: auth.UserID(ctx), + IDs: itemIDs.Strings(), + }) + if err != nil { + return nil, err + } + + result.Tasks = make([]*models.TaskResult, len(tasks)) + for i, task := range tasks { + result.Tasks[i] = &models.TaskResult{ + Logs: []*models.Log{}, + } + result.Tasks[i].Task = *task + for _, log := range logs { + if log.TaskID == task.ID { + result.Tasks[i].Logs = append(result.Tasks[i].Logs, log) + } + } + for _, item := range items { + if item.ID == task.ItemID { + result.Tasks[i].Item = item + break + } + } + result.Tasks[i].CompletedAmount = len(result.Tasks[i].Logs) + } + + return result, nil +} + +func (l *Loader) ListProjects(ctx context.Context, filter models.ProjectFilter) ([]*models.ProjectResult, error) { + filter.UserID = auth.UserID(ctx) + projects, err := l.DB.Projects().List(ctx, filter) + if err != nil { + return nil, err + } + projectIDs := make([]string, 0, len(projects)) + for _, project := range projects { + projectIDs = append(projectIDs, project.ID) + } + + tasks, err := l.DB.Tasks().List(ctx, models.TaskFilter{ + UserID: auth.UserID(ctx), + ProjectIDs: projectIDs, + }) + if err != nil { + return nil, err + } + taskIDs := make([]string, 0, len(tasks)) + itemIDs := stringset.New() + for _, task := range tasks { + taskIDs = append(taskIDs, task.ID) + itemIDs.Add(task.ItemID) + } + + logs, err := l.DB.Logs().List(ctx, models.LogFilter{ + UserID: auth.UserID(ctx), + IDs: taskIDs, + }) + if err != nil { + return nil, err + } + + items, err := l.DB.Items().List(ctx, models.ItemFilter{ + UserID: auth.UserID(ctx), + IDs: itemIDs.Strings(), + }) + if err != nil { + return nil, err + } + + results := make([]*models.ProjectResult, len(projects)) + for i, project := range projects { + results[i] = &models.ProjectResult{Project: *project} + results[i].Tasks = make([]*models.TaskResult, 0, 16) + for _, task := range tasks { + if task.ProjectID != project.ID { + continue + } + + taskResult := &models.TaskResult{ + Task: *task, + Logs: []*models.Log{}, + } + for _, log := range logs { + if log.TaskID == task.ID { + taskResult.Logs = append(taskResult.Logs, log) + } + } + for _, item := range items { + if item.ID == task.ItemID { + taskResult.Item = item + break + } + } + taskResult.CompletedAmount = len(taskResult.Logs) + + results[i].Tasks = append(results[i].Tasks, taskResult) + } + } + + return results, nil +} + +func (l *Loader) FindTask(ctx context.Context, id string) (*models.TaskResult, error) { + task, err := l.DB.Tasks().Find(ctx, id) + if err != nil { + return nil, err + } + if task.UserID != auth.UserID(ctx) { + return nil, slerrors.NotFound("Goal") + } + result := &models.TaskResult{Task: *task} + + result.Item, _ = l.DB.Items().Find(ctx, task.ItemID) + result.Logs, err = l.DB.Logs().List(ctx, models.LogFilter{ + UserID: task.UserID, + IDs: []string{task.ID}, + }) + if err != nil { + return nil, err + } + + result.CompletedAmount = len(result.Logs) + + return result, nil +} + +func (l *Loader) ListTasks(ctx context.Context, filter models.TaskFilter) ([]*models.TaskResult, error) { + filter.UserID = auth.UserID(ctx) + tasks, err := l.DB.Tasks().List(ctx, filter) + if err != nil { + return nil, err + } + if len(tasks) == 0 { + return []*models.TaskResult{}, nil + } + + taskIDs := make([]string, 0, len(tasks)) + itemIDs := stringset.New() + for _, task := range tasks { + taskIDs = append(taskIDs, task.ID) + itemIDs.Add(task.ItemID) + } + + logs, err := l.DB.Logs().List(ctx, models.LogFilter{ + UserID: auth.UserID(ctx), + IDs: taskIDs, + }) + if err != nil { + return nil, err + } + + items, err := l.DB.Items().List(ctx, models.ItemFilter{ + UserID: auth.UserID(ctx), + IDs: itemIDs.Strings(), + }) + if err != nil { + return nil, err + } + + results := make([]*models.TaskResult, 0, len(tasks)) + for _, task := range tasks { + result := &models.TaskResult{ + Task: *task, + Logs: []*models.Log{}, + } + + for _, log := range logs { + if log.TaskID != task.ID { + result.Logs = append(result.Logs, log) + } + } + + for _, item := range items { + if item.ID == task.ItemID { + result.Item = item + break + } + } + + result.CompletedAmount = len(result.Logs) + + results = append(results, result) + } + + return results, nil +} + +func (l *Loader) FindGoal(ctx context.Context, id string) (*models.GoalResult, error) { + goal, err := l.DB.Goals().Find(ctx, id) + if err != nil { + return nil, err + } + if goal.UserID != auth.UserID(ctx) { + return nil, slerrors.NotFound("Goal") + } + + return l.populateGoals(ctx, goal) +} + +func (l *Loader) ListGoals(ctx context.Context, filter models.GoalFilter) ([]*models.GoalResult, error) { + filter.UserID = auth.UserID(ctx) + + goals, err := l.DB.Goals().List(ctx, filter) + if err != nil { + return nil, err + } + + results := make([]*models.GoalResult, len(goals)) + eg := errgroup.Group{} + for i := range results { + index := i // Required to avoid race condition. + + eg.Go(func() error { + res, err := l.populateGoals(ctx, goals[index]) + if err != nil { + return err + } + + results[index] = res + + return nil + }) + } + err = eg.Wait() + if err != nil { + return nil, err + } + + return results, nil +} + +func (l *Loader) populateGoals(ctx context.Context, goal *models.Goal) (*models.GoalResult, error) { + userID := auth.UserID(ctx) + result := &models.GoalResult{ + Goal: *goal, + Group: nil, + Items: nil, + Logs: nil, + CompletedAmount: 0, + } + + result.Group, _ = l.DB.Groups().Find(ctx, goal.GroupID) + if result.Group != nil { + // Get items + items, err := l.DB.Items().List(ctx, models.ItemFilter{ + UserID: userID, + GroupIDs: []string{goal.GroupID}, + }) + if err != nil { + return nil, err + } + itemIDs := make([]string, 0, len(items)) + for _, item := range items { + result.Items = append(result.Items, &models.GoalResultItem{ + Item: *item, + CompletedAmount: 0, + }) + + itemIDs = append(itemIDs, item.ID) + } + + // Get logs + logs, err := l.DB.Logs().List(ctx, models.LogFilter{ + UserID: userID, + ItemIDs: itemIDs, + MinTime: &goal.StartTime, + MaxTime: &goal.EndTime, + }) + + // Get tasks + taskIDs := make([]string, 0, len(result.Logs)) + for _, log := range logs { + taskIDs = append(taskIDs, log.TaskID) + } + tasks, err := l.DB.Tasks().List(ctx, models.TaskFilter{ + UserID: userID, + IDs: taskIDs, + }) + + // Apply logs + result.Logs = make([]*models.LogResult, 0, len(logs)) + for _, log := range logs { + resultLog := &models.LogResult{ + Log: *log, + } + + for _, task := range tasks { + if task.ID == log.TaskID { + resultLog.Task = task + + for _, item := range result.Items { + if task.ItemID == item.ID { + item.CompletedAmount += 1 + result.CompletedAmount += item.GroupWeight + break + } + } + + break + } + } + result.Logs = append(result.Logs, resultLog) + } + } + + return result, nil +} diff --git a/svelte-ui/.gitignore b/svelte-ui/.gitignore new file mode 100644 index 0000000..a85ba51 --- /dev/null +++ b/svelte-ui/.gitignore @@ -0,0 +1,7 @@ +/node_modules/ +/public/build/ +/build.env +/.idea +/.vscode + +.DS_Store diff --git a/svelte-ui/package-lock.json b/svelte-ui/package-lock.json new file mode 100644 index 0000000..5d846e5 --- /dev/null +++ b/svelte-ui/package-lock.json @@ -0,0 +1,4368 @@ +{ + "name": "@gisle/stufflog2-svelte-ui", + "version": "0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@aws-amplify/analytics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@aws-amplify/analytics/-/analytics-4.0.4.tgz", + "integrity": "sha512-a71GAbOxM/pJtG1iahxhNMHe7Zwj5uOGOHKwkC1fEAC46SoQmHWCm+/5StnZ6lmTpsOxpNWGMH/MUk2Osky+2A==", + "dev": true, + "requires": { + "@aws-amplify/cache": "3.1.41", + "@aws-amplify/core": "3.8.8", + "@aws-sdk/client-firehose": "1.0.0-rc.4", + "@aws-sdk/client-kinesis": "1.0.0-rc.4", + "@aws-sdk/client-personalize-events": "1.0.0-rc.4", + "@aws-sdk/client-pinpoint": "1.0.0-rc.4", + "@aws-sdk/util-utf8-browser": "1.0.0-rc.3", + "lodash": "^4.17.20", + "uuid": "^3.2.1" + } + }, + "@aws-amplify/api": { + "version": "3.2.16", + "resolved": "https://registry.npmjs.org/@aws-amplify/api/-/api-3.2.16.tgz", + "integrity": "sha512-yqNFipI7E0IEaO7Z8HfAWgXQeJR+M77P7W1ppuj4y4Mkcz8SaIBD1ILCCP4dT9i9L6mCptxXJg9a/0tzbNIPAQ==", + "dev": true, + "requires": { + "@aws-amplify/api-graphql": "1.2.16", + "@aws-amplify/api-rest": "1.2.16" + } + }, + "@aws-amplify/api-graphql": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@aws-amplify/api-graphql/-/api-graphql-1.2.16.tgz", + "integrity": "sha512-mAMYyJVxOy4RcDNhFUvFSgUuCuumVRD2HZkLOOmyXkEj8ZRu6LbNLkpBYPpI3XaiEkGOJD2WQe25B+cJDtvNpA==", + "dev": true, + "requires": { + "@aws-amplify/api-rest": "1.2.16", + "@aws-amplify/auth": "3.4.16", + "@aws-amplify/cache": "3.1.41", + "@aws-amplify/core": "3.8.8", + "@aws-amplify/pubsub": "3.2.14", + "graphql": "14.0.0", + "uuid": "^3.2.1", + "zen-observable-ts": "0.8.19" + } + }, + "@aws-amplify/api-rest": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@aws-amplify/api-rest/-/api-rest-1.2.16.tgz", + "integrity": "sha512-pB7LZvh6A1txnXKwuqjZZiQg+NcrpdhCxCKb09yOWM9AgbefxcvSFNmWuJYl256/ySD6wkgFJdAVmppulXbJOA==", + "dev": true, + "requires": { + "@aws-amplify/core": "3.8.8", + "axios": "0.19.0" + } + }, + "@aws-amplify/auth": { + "version": "3.4.16", + "resolved": "https://registry.npmjs.org/@aws-amplify/auth/-/auth-3.4.16.tgz", + "integrity": "sha512-bG998WecLH5J+PvlTdtCZPme9/008EtY329FFhWavlb8uG3TaZz3IJ8Kfm8xN7tGAK8KFo8Ldx93fEQBe1VXMw==", + "dev": true, + "requires": { + "@aws-amplify/cache": "3.1.41", + "@aws-amplify/core": "3.8.8", + "amazon-cognito-identity-js": "4.5.6", + "crypto-js": "^3.3.0" + } + }, + "@aws-amplify/cache": { + "version": "3.1.41", + "resolved": "https://registry.npmjs.org/@aws-amplify/cache/-/cache-3.1.41.tgz", + "integrity": "sha512-hdTLhKCmu51aIG6uZZhYCpe15n6E0isGzuouloTShzuA7bcWUo8GyRYqOS2xkIZhwpFW116ThShjfn8iFgwUiQ==", + "dev": true, + "requires": { + "@aws-amplify/core": "3.8.8" + } + }, + "@aws-amplify/core": { + "version": "3.8.8", + "resolved": "https://registry.npmjs.org/@aws-amplify/core/-/core-3.8.8.tgz", + "integrity": "sha512-lwgYUYuZhFdNtOXmsyqrCPGJkrqe66FlSggBobeQB0KOvtBVrxyWl0pTqcCLdVs+Krxmct6gLiNFcxhHeXDAng==", + "dev": true, + "requires": { + "@aws-crypto/sha256-js": "1.0.0-alpha.0", + "@aws-sdk/client-cognito-identity": "1.0.0-rc.4", + "@aws-sdk/credential-provider-cognito-identity": "1.0.0-rc.4", + "@aws-sdk/node-http-handler": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "@aws-sdk/util-hex-encoding": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-browser": "1.0.0-rc.3", + "universal-cookie": "^4.0.4", + "url": "^0.11.0", + "zen-observable-ts": "0.8.19" + } + }, + "@aws-amplify/datastore": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@aws-amplify/datastore/-/datastore-2.9.2.tgz", + "integrity": "sha512-2RGDuYIw1AimIlvoXIjeKrAGlOBuiecwdJ8nk9s3J5gjkVfdVIWdyrS99Q2e3kuudtV+qCjEUTrZdpaZV/Yujw==", + "dev": true, + "requires": { + "@aws-amplify/api": "3.2.16", + "@aws-amplify/core": "3.8.8", + "@aws-amplify/pubsub": "3.2.14", + "idb": "5.0.6", + "immer": "6.0.1", + "ulid": "2.3.0", + "uuid": "3.3.2", + "zen-observable-ts": "0.8.19", + "zen-push": "0.2.1" + }, + "dependencies": { + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + } + } + }, + "@aws-amplify/interactions": { + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/@aws-amplify/interactions/-/interactions-3.3.16.tgz", + "integrity": "sha512-IDYMdp6xol/P3EfPxP/fB0ecoIxSe4T0QM3J41gUoS/m0y6cLhVRG3024RkmRbGYiFvYK8gZtX7nO2SQSZmK5g==", + "dev": true, + "requires": { + "@aws-amplify/core": "3.8.8", + "@aws-sdk/client-lex-runtime-service": "1.0.0-rc.4" + } + }, + "@aws-amplify/predictions": { + "version": "3.2.16", + "resolved": "https://registry.npmjs.org/@aws-amplify/predictions/-/predictions-3.2.16.tgz", + "integrity": "sha512-ChBUGa+Xx98aG8KUtgVy87cVjsIS3xj7TEDAl1fL+dTKMX3XA0oDzMRGQCGdLbh9u0SEuBIixrRcim/ocDDL/A==", + "dev": true, + "requires": { + "@aws-amplify/core": "3.8.8", + "@aws-amplify/storage": "3.3.16", + "@aws-sdk/client-comprehend": "1.0.0-rc.4", + "@aws-sdk/client-polly": "1.0.0-rc.4", + "@aws-sdk/client-rekognition": "1.0.0-rc.4", + "@aws-sdk/client-textract": "1.0.0-rc.4", + "@aws-sdk/client-translate": "1.0.0-rc.4", + "@aws-sdk/eventstream-marshaller": "1.0.0-rc.3", + "@aws-sdk/util-utf8-node": "1.0.0-rc.3", + "uuid": "^3.2.1" + } + }, + "@aws-amplify/pubsub": { + "version": "3.2.14", + "resolved": "https://registry.npmjs.org/@aws-amplify/pubsub/-/pubsub-3.2.14.tgz", + "integrity": "sha512-t5V38S9a+FuKKSQs5SIk9er9i4TtH7221CnSNgKqakMUXbwJVp7gVL+e3OQ0hdVPmeaFtq1ovneJhCtMy2uXBQ==", + "dev": true, + "requires": { + "@aws-amplify/auth": "3.4.16", + "@aws-amplify/cache": "3.1.41", + "@aws-amplify/core": "3.8.8", + "graphql": "14.0.0", + "paho-mqtt": "^1.1.0", + "uuid": "^3.2.1", + "zen-observable-ts": "0.8.19" + } + }, + "@aws-amplify/storage": { + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/@aws-amplify/storage/-/storage-3.3.16.tgz", + "integrity": "sha512-SliC3XaUteZ421sE3Pfp/gPjqXJFFXa11f7+e6QwfcG2SlH0k+SbBVuhhfI83JDdlDCxHFur3ELuLpRhtLXl1g==", + "dev": true, + "requires": { + "@aws-amplify/core": "3.8.8", + "@aws-sdk/client-s3": "1.0.0-rc.4", + "@aws-sdk/s3-request-presigner": "1.0.0-rc.4", + "@aws-sdk/util-create-request": "1.0.0-rc.4", + "@aws-sdk/util-format-url": "1.0.0-rc.4", + "axios": "0.19.0", + "events": "^3.1.0", + "sinon": "^7.5.0" + } + }, + "@aws-amplify/ui": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@aws-amplify/ui/-/ui-2.0.2.tgz", + "integrity": "sha512-OLdZmUCVK29+JV8PrkgVPjg+GIFtBnNjhC0JSRgrps+ynOFkibMQQPKeFXlTYtlukuCuepCelPSkjxvhcLq2ZA==", + "dev": true + }, + "@aws-amplify/xr": { + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/@aws-amplify/xr/-/xr-2.2.16.tgz", + "integrity": "sha512-QxjgcNg/kM6vVPgzb5lBBKViIfXT7zMdKtpArqqM6EbopQtUJCfcjVecI/4burVd4cDxiXMRx9d8zS1mbxXZtw==", + "dev": true, + "requires": { + "@aws-amplify/core": "3.8.8" + } + }, + "@aws-crypto/crc32": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-1.0.0.tgz", + "integrity": "sha512-wr4EyCv3ZfLH3Sg7FErV6e/cLhpk9rUP/l5322y8PRgpQsItdieaLbtE4aDOR+dxl8U7BG9FIwWXH4TleTDZ9A==", + "dev": true, + "requires": { + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-crypto/ie11-detection": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-1.0.0.tgz", + "integrity": "sha512-kCKVhCF1oDxFYgQrxXmIrS5oaWulkvRcPz+QBDMsUr2crbF4VGgGT6+uQhSwJFdUAQ2A//Vq+uT83eJrkzFgXA==", + "dev": true, + "requires": { + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-crypto/sha256-browser": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-1.0.0.tgz", + "integrity": "sha512-uSufui4ZktC5lYX6bDxgBgNboxGyw9V9V+rlcNsNTxh4YPhOdCslwJMGntiWOBRGAgXhhvWi7FqnTS2SaT3cpg==", + "dev": true, + "requires": { + "@aws-crypto/ie11-detection": "^1.0.0", + "@aws-crypto/sha256-js": "^1.0.0", + "@aws-crypto/supports-web-crypto": "^1.0.0", + "@aws-sdk/types": "^1.0.0-rc.1", + "@aws-sdk/util-locate-window": "^1.0.0-rc.1", + "@aws-sdk/util-utf8-browser": "^1.0.0-rc.1", + "tslib": "^1.11.1" + }, + "dependencies": { + "@aws-crypto/sha256-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-1.0.0.tgz", + "integrity": "sha512-89kqtFs/tdHBFHEBXZ4UXlCISswvEor3BVVOriR68Tbk1Qe1zBOZtfbSOt3CDT69z88x5uM558YW9k8I1xei5A==", + "dev": true, + "requires": { + "@aws-sdk/types": "^1.0.0-rc.1", + "@aws-sdk/util-utf8-browser": "^1.0.0-rc.1", + "tslib": "^1.11.1" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-crypto/sha256-js": { + "version": "1.0.0-alpha.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-1.0.0-alpha.0.tgz", + "integrity": "sha512-GidX2lccEtHZw8mXDKJQj6tea7qh3pAnsNSp1eZNxsN4MMu2OvSraPSqiB1EihsQkZBMg0IiZPpZHoACUX/QMQ==", + "dev": true, + "requires": { + "@aws-sdk/types": "^1.0.0-alpha.0", + "@aws-sdk/util-utf8-browser": "^1.0.0-alpha.0", + "tslib": "^1.9.3" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-crypto/supports-web-crypto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-1.0.0.tgz", + "integrity": "sha512-IHLfv+WmVH89EW4n6a5eE8/hUlz6qkWGMn/v4r5ZgzcXdTC5nolii2z3k46y01hWRiC2PPhOdeSLzMUCUMco7g==", + "dev": true, + "requires": { + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/abort-controller": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-1.0.0-rc.3.tgz", + "integrity": "sha512-+os/c2PDtDzaeAMqH3f03EDwMAesxy3O5lFcT2vr43iiQkXRnYwaWFD4QPwDQGzKDjksPKSa6iag4OjzGf0ezA==", + "dev": true, + "requires": { + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/chunked-blob-reader": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/chunked-blob-reader/-/chunked-blob-reader-1.0.0-rc.3.tgz", + "integrity": "sha512-d4B6mOYxZqo+y2op5BwEsG0wxewyNhVmyvfdQfhaJowNjhZpQ6vhYkh3umOarLwyC72dNScKBQYLnOsf5chtDg==", + "dev": true, + "requires": { + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/chunked-blob-reader-native": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/chunked-blob-reader-native/-/chunked-blob-reader-native-1.0.0-rc.3.tgz", + "integrity": "sha512-ouuN4cBmwfVPVVQeBhKm18BHkBK/ZVn0VDE4WXVMqu3WjNBxulKYCvJ7mkxi1oWWzp+RGa1TwIQuancB1IHrdA==", + "dev": true, + "requires": { + "@aws-sdk/util-base64-browser": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/client-cognito-identity": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-1.0.0-rc.4.tgz", + "integrity": "sha512-GR71ns7JDvxgih2l0D2I7QZZe5c+ld7quIu4JxNHQVVA6Or/pPpYoMp5GaqN5EwQoVYcivOs32UaE0O5VywqBg==", + "dev": true, + "requires": { + "@aws-crypto/sha256-browser": "^1.0.0", + "@aws-crypto/sha256-js": "^1.0.0", + "@aws-sdk/config-resolver": "1.0.0-rc.3", + "@aws-sdk/credential-provider-node": "1.0.0-rc.3", + "@aws-sdk/fetch-http-handler": "1.0.0-rc.3", + "@aws-sdk/hash-node": "1.0.0-rc.3", + "@aws-sdk/invalid-dependency": "1.0.0-rc.3", + "@aws-sdk/middleware-content-length": "1.0.0-rc.3", + "@aws-sdk/middleware-host-header": "1.0.0-rc.3", + "@aws-sdk/middleware-logger": "1.0.0-rc.4", + "@aws-sdk/middleware-retry": "1.0.0-rc.4", + "@aws-sdk/middleware-serde": "1.0.0-rc.3", + "@aws-sdk/middleware-signing": "1.0.0-rc.3", + "@aws-sdk/middleware-stack": "1.0.0-rc.4", + "@aws-sdk/middleware-user-agent": "1.0.0-rc.3", + "@aws-sdk/node-config-provider": "1.0.0-rc.3", + "@aws-sdk/node-http-handler": "1.0.0-rc.3", + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/smithy-client": "1.0.0-rc.4", + "@aws-sdk/types": "1.0.0-rc.3", + "@aws-sdk/url-parser-browser": "1.0.0-rc.3", + "@aws-sdk/url-parser-node": "1.0.0-rc.3", + "@aws-sdk/util-base64-browser": "1.0.0-rc.3", + "@aws-sdk/util-base64-node": "1.0.0-rc.3", + "@aws-sdk/util-body-length-browser": "1.0.0-rc.3", + "@aws-sdk/util-body-length-node": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-browser": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-node": "1.0.0-rc.3", + "@aws-sdk/util-utf8-browser": "1.0.0-rc.3", + "@aws-sdk/util-utf8-node": "1.0.0-rc.3", + "tslib": "^2.0.0" + }, + "dependencies": { + "@aws-crypto/sha256-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-1.0.0.tgz", + "integrity": "sha512-89kqtFs/tdHBFHEBXZ4UXlCISswvEor3BVVOriR68Tbk1Qe1zBOZtfbSOt3CDT69z88x5uM558YW9k8I1xei5A==", + "dev": true, + "requires": { + "@aws-sdk/types": "^1.0.0-rc.1", + "@aws-sdk/util-utf8-browser": "^1.0.0-rc.1", + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + } + } + }, + "@aws-sdk/client-comprehend": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-comprehend/-/client-comprehend-1.0.0-rc.4.tgz", + "integrity": "sha512-Lz+Zi6rl5cYFrcaz/sOzc+w0exoL/CRKLCMh8uod+n4yzIqvYhMaDNArO+ePQNy/6hMZhRhG8I7c3zwZsxT+zA==", + "dev": true, + "requires": { + "@aws-crypto/sha256-browser": "^1.0.0", + "@aws-crypto/sha256-js": "^1.0.0", + "@aws-sdk/config-resolver": "1.0.0-rc.3", + "@aws-sdk/credential-provider-node": "1.0.0-rc.3", + "@aws-sdk/fetch-http-handler": "1.0.0-rc.3", + "@aws-sdk/hash-node": "1.0.0-rc.3", + "@aws-sdk/invalid-dependency": "1.0.0-rc.3", + "@aws-sdk/middleware-content-length": "1.0.0-rc.3", + "@aws-sdk/middleware-host-header": "1.0.0-rc.3", + "@aws-sdk/middleware-logger": "1.0.0-rc.4", + "@aws-sdk/middleware-retry": "1.0.0-rc.4", + "@aws-sdk/middleware-serde": "1.0.0-rc.3", + "@aws-sdk/middleware-signing": "1.0.0-rc.3", + "@aws-sdk/middleware-stack": "1.0.0-rc.4", + "@aws-sdk/middleware-user-agent": "1.0.0-rc.3", + "@aws-sdk/node-config-provider": "1.0.0-rc.3", + "@aws-sdk/node-http-handler": "1.0.0-rc.3", + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/smithy-client": "1.0.0-rc.4", + "@aws-sdk/types": "1.0.0-rc.3", + "@aws-sdk/url-parser-browser": "1.0.0-rc.3", + "@aws-sdk/url-parser-node": "1.0.0-rc.3", + "@aws-sdk/util-base64-browser": "1.0.0-rc.3", + "@aws-sdk/util-base64-node": "1.0.0-rc.3", + "@aws-sdk/util-body-length-browser": "1.0.0-rc.3", + "@aws-sdk/util-body-length-node": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-browser": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-node": "1.0.0-rc.3", + "@aws-sdk/util-utf8-browser": "1.0.0-rc.3", + "@aws-sdk/util-utf8-node": "1.0.0-rc.3", + "tslib": "^2.0.0", + "uuid": "^3.0.0" + }, + "dependencies": { + "@aws-crypto/sha256-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-1.0.0.tgz", + "integrity": "sha512-89kqtFs/tdHBFHEBXZ4UXlCISswvEor3BVVOriR68Tbk1Qe1zBOZtfbSOt3CDT69z88x5uM558YW9k8I1xei5A==", + "dev": true, + "requires": { + "@aws-sdk/types": "^1.0.0-rc.1", + "@aws-sdk/util-utf8-browser": "^1.0.0-rc.1", + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + } + } + }, + "@aws-sdk/client-firehose": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-firehose/-/client-firehose-1.0.0-rc.4.tgz", + "integrity": "sha512-nveeqbomzqi1Udn9AN/B9Ko/buSLl65ma0rrJn5wtxK1qYny7YuFS32YQ0WD4Cqru2MPprNCDOWurBjczWOuBQ==", + "dev": true, + "requires": { + "@aws-crypto/sha256-browser": "^1.0.0", + "@aws-crypto/sha256-js": "^1.0.0", + "@aws-sdk/config-resolver": "1.0.0-rc.3", + "@aws-sdk/credential-provider-node": "1.0.0-rc.3", + "@aws-sdk/fetch-http-handler": "1.0.0-rc.3", + "@aws-sdk/hash-node": "1.0.0-rc.3", + "@aws-sdk/invalid-dependency": "1.0.0-rc.3", + "@aws-sdk/middleware-content-length": "1.0.0-rc.3", + "@aws-sdk/middleware-host-header": "1.0.0-rc.3", + "@aws-sdk/middleware-logger": "1.0.0-rc.4", + "@aws-sdk/middleware-retry": "1.0.0-rc.4", + "@aws-sdk/middleware-serde": "1.0.0-rc.3", + "@aws-sdk/middleware-signing": "1.0.0-rc.3", + "@aws-sdk/middleware-stack": "1.0.0-rc.4", + "@aws-sdk/middleware-user-agent": "1.0.0-rc.3", + "@aws-sdk/node-config-provider": "1.0.0-rc.3", + "@aws-sdk/node-http-handler": "1.0.0-rc.3", + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/smithy-client": "1.0.0-rc.4", + "@aws-sdk/types": "1.0.0-rc.3", + "@aws-sdk/url-parser-browser": "1.0.0-rc.3", + "@aws-sdk/url-parser-node": "1.0.0-rc.3", + "@aws-sdk/util-base64-browser": "1.0.0-rc.3", + "@aws-sdk/util-base64-node": "1.0.0-rc.3", + "@aws-sdk/util-body-length-browser": "1.0.0-rc.3", + "@aws-sdk/util-body-length-node": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-browser": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-node": "1.0.0-rc.3", + "@aws-sdk/util-utf8-browser": "1.0.0-rc.3", + "@aws-sdk/util-utf8-node": "1.0.0-rc.3", + "tslib": "^2.0.0" + }, + "dependencies": { + "@aws-crypto/sha256-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-1.0.0.tgz", + "integrity": "sha512-89kqtFs/tdHBFHEBXZ4UXlCISswvEor3BVVOriR68Tbk1Qe1zBOZtfbSOt3CDT69z88x5uM558YW9k8I1xei5A==", + "dev": true, + "requires": { + "@aws-sdk/types": "^1.0.0-rc.1", + "@aws-sdk/util-utf8-browser": "^1.0.0-rc.1", + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + } + } + }, + "@aws-sdk/client-kinesis": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-kinesis/-/client-kinesis-1.0.0-rc.4.tgz", + "integrity": "sha512-mlzx8rPkQT6dbkPpzicII7zmF+V8SyqoDp5HvswTsK6D6ePoKnXx5g5vdtOelpZ9AE8AnnxGU1vVDRSUnDMV4A==", + "dev": true, + "requires": { + "@aws-crypto/sha256-browser": "^1.0.0", + "@aws-crypto/sha256-js": "^1.0.0", + "@aws-sdk/config-resolver": "1.0.0-rc.3", + "@aws-sdk/credential-provider-node": "1.0.0-rc.3", + "@aws-sdk/eventstream-serde-browser": "1.0.0-rc.3", + "@aws-sdk/eventstream-serde-config-resolver": "1.0.0-rc.3", + "@aws-sdk/eventstream-serde-node": "1.0.0-rc.3", + "@aws-sdk/fetch-http-handler": "1.0.0-rc.3", + "@aws-sdk/hash-node": "1.0.0-rc.3", + "@aws-sdk/invalid-dependency": "1.0.0-rc.3", + "@aws-sdk/middleware-content-length": "1.0.0-rc.3", + "@aws-sdk/middleware-host-header": "1.0.0-rc.3", + "@aws-sdk/middleware-logger": "1.0.0-rc.4", + "@aws-sdk/middleware-retry": "1.0.0-rc.4", + "@aws-sdk/middleware-serde": "1.0.0-rc.3", + "@aws-sdk/middleware-signing": "1.0.0-rc.3", + "@aws-sdk/middleware-stack": "1.0.0-rc.4", + "@aws-sdk/middleware-user-agent": "1.0.0-rc.3", + "@aws-sdk/node-config-provider": "1.0.0-rc.3", + "@aws-sdk/node-http-handler": "1.0.0-rc.3", + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/smithy-client": "1.0.0-rc.4", + "@aws-sdk/types": "1.0.0-rc.3", + "@aws-sdk/url-parser-browser": "1.0.0-rc.3", + "@aws-sdk/url-parser-node": "1.0.0-rc.3", + "@aws-sdk/util-base64-browser": "1.0.0-rc.3", + "@aws-sdk/util-base64-node": "1.0.0-rc.3", + "@aws-sdk/util-body-length-browser": "1.0.0-rc.3", + "@aws-sdk/util-body-length-node": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-browser": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-node": "1.0.0-rc.3", + "@aws-sdk/util-utf8-browser": "1.0.0-rc.3", + "@aws-sdk/util-utf8-node": "1.0.0-rc.3", + "tslib": "^2.0.0" + }, + "dependencies": { + "@aws-crypto/sha256-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-1.0.0.tgz", + "integrity": "sha512-89kqtFs/tdHBFHEBXZ4UXlCISswvEor3BVVOriR68Tbk1Qe1zBOZtfbSOt3CDT69z88x5uM558YW9k8I1xei5A==", + "dev": true, + "requires": { + "@aws-sdk/types": "^1.0.0-rc.1", + "@aws-sdk/util-utf8-browser": "^1.0.0-rc.1", + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + } + } + }, + "@aws-sdk/client-lex-runtime-service": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-runtime-service/-/client-lex-runtime-service-1.0.0-rc.4.tgz", + "integrity": "sha512-kizyULuN216b7Q4tMWiLsCBC747MWKh5Q7RyqbRygH1wVidyIwnNTnnlFzrjAc0fP0SC7/SWO58hE3ptCwVLtA==", + "dev": true, + "requires": { + "@aws-crypto/sha256-browser": "^1.0.0", + "@aws-crypto/sha256-js": "^1.0.0", + "@aws-sdk/config-resolver": "1.0.0-rc.3", + "@aws-sdk/credential-provider-node": "1.0.0-rc.3", + "@aws-sdk/fetch-http-handler": "1.0.0-rc.3", + "@aws-sdk/hash-node": "1.0.0-rc.3", + "@aws-sdk/invalid-dependency": "1.0.0-rc.3", + "@aws-sdk/middleware-content-length": "1.0.0-rc.3", + "@aws-sdk/middleware-host-header": "1.0.0-rc.3", + "@aws-sdk/middleware-logger": "1.0.0-rc.4", + "@aws-sdk/middleware-retry": "1.0.0-rc.4", + "@aws-sdk/middleware-serde": "1.0.0-rc.3", + "@aws-sdk/middleware-signing": "1.0.0-rc.3", + "@aws-sdk/middleware-stack": "1.0.0-rc.4", + "@aws-sdk/middleware-user-agent": "1.0.0-rc.3", + "@aws-sdk/node-config-provider": "1.0.0-rc.3", + "@aws-sdk/node-http-handler": "1.0.0-rc.3", + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/smithy-client": "1.0.0-rc.4", + "@aws-sdk/types": "1.0.0-rc.3", + "@aws-sdk/url-parser-browser": "1.0.0-rc.3", + "@aws-sdk/url-parser-node": "1.0.0-rc.3", + "@aws-sdk/util-base64-browser": "1.0.0-rc.3", + "@aws-sdk/util-base64-node": "1.0.0-rc.3", + "@aws-sdk/util-body-length-browser": "1.0.0-rc.3", + "@aws-sdk/util-body-length-node": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-browser": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-node": "1.0.0-rc.3", + "@aws-sdk/util-utf8-browser": "1.0.0-rc.3", + "@aws-sdk/util-utf8-node": "1.0.0-rc.3", + "tslib": "^2.0.0" + }, + "dependencies": { + "@aws-crypto/sha256-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-1.0.0.tgz", + "integrity": "sha512-89kqtFs/tdHBFHEBXZ4UXlCISswvEor3BVVOriR68Tbk1Qe1zBOZtfbSOt3CDT69z88x5uM558YW9k8I1xei5A==", + "dev": true, + "requires": { + "@aws-sdk/types": "^1.0.0-rc.1", + "@aws-sdk/util-utf8-browser": "^1.0.0-rc.1", + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + } + } + }, + "@aws-sdk/client-personalize-events": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-personalize-events/-/client-personalize-events-1.0.0-rc.4.tgz", + "integrity": "sha512-ues2/k7hbmFattKDP76NRNjldhEFjQitzqg3ix1NGuO0a/Ob5g4Vjgb5TZIt5p1nn+cVYPFjHPB1XNRSY2Xy/w==", + "dev": true, + "requires": { + "@aws-crypto/sha256-browser": "^1.0.0", + "@aws-crypto/sha256-js": "^1.0.0", + "@aws-sdk/config-resolver": "1.0.0-rc.3", + "@aws-sdk/credential-provider-node": "1.0.0-rc.3", + "@aws-sdk/fetch-http-handler": "1.0.0-rc.3", + "@aws-sdk/hash-node": "1.0.0-rc.3", + "@aws-sdk/invalid-dependency": "1.0.0-rc.3", + "@aws-sdk/middleware-content-length": "1.0.0-rc.3", + "@aws-sdk/middleware-host-header": "1.0.0-rc.3", + "@aws-sdk/middleware-logger": "1.0.0-rc.4", + "@aws-sdk/middleware-retry": "1.0.0-rc.4", + "@aws-sdk/middleware-serde": "1.0.0-rc.3", + "@aws-sdk/middleware-signing": "1.0.0-rc.3", + "@aws-sdk/middleware-stack": "1.0.0-rc.4", + "@aws-sdk/middleware-user-agent": "1.0.0-rc.3", + "@aws-sdk/node-config-provider": "1.0.0-rc.3", + "@aws-sdk/node-http-handler": "1.0.0-rc.3", + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/smithy-client": "1.0.0-rc.4", + "@aws-sdk/types": "1.0.0-rc.3", + "@aws-sdk/url-parser-browser": "1.0.0-rc.3", + "@aws-sdk/url-parser-node": "1.0.0-rc.3", + "@aws-sdk/util-base64-browser": "1.0.0-rc.3", + "@aws-sdk/util-base64-node": "1.0.0-rc.3", + "@aws-sdk/util-body-length-browser": "1.0.0-rc.3", + "@aws-sdk/util-body-length-node": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-browser": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-node": "1.0.0-rc.3", + "@aws-sdk/util-utf8-browser": "1.0.0-rc.3", + "@aws-sdk/util-utf8-node": "1.0.0-rc.3", + "tslib": "^2.0.0" + }, + "dependencies": { + "@aws-crypto/sha256-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-1.0.0.tgz", + "integrity": "sha512-89kqtFs/tdHBFHEBXZ4UXlCISswvEor3BVVOriR68Tbk1Qe1zBOZtfbSOt3CDT69z88x5uM558YW9k8I1xei5A==", + "dev": true, + "requires": { + "@aws-sdk/types": "^1.0.0-rc.1", + "@aws-sdk/util-utf8-browser": "^1.0.0-rc.1", + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + } + } + }, + "@aws-sdk/client-pinpoint": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-pinpoint/-/client-pinpoint-1.0.0-rc.4.tgz", + "integrity": "sha512-PdcSP6lboIRo/vK3ITGnlQB2OTH4hvlTSX5Wo0D52YqVrE+EYCAXkukPnQpnO3mrlnLlVjqxqKe2Ara3u7eyUw==", + "dev": true, + "requires": { + "@aws-crypto/sha256-browser": "^1.0.0", + "@aws-crypto/sha256-js": "^1.0.0", + "@aws-sdk/config-resolver": "1.0.0-rc.3", + "@aws-sdk/credential-provider-node": "1.0.0-rc.3", + "@aws-sdk/fetch-http-handler": "1.0.0-rc.3", + "@aws-sdk/hash-node": "1.0.0-rc.3", + "@aws-sdk/invalid-dependency": "1.0.0-rc.3", + "@aws-sdk/middleware-content-length": "1.0.0-rc.3", + "@aws-sdk/middleware-host-header": "1.0.0-rc.3", + "@aws-sdk/middleware-logger": "1.0.0-rc.4", + "@aws-sdk/middleware-retry": "1.0.0-rc.4", + "@aws-sdk/middleware-serde": "1.0.0-rc.3", + "@aws-sdk/middleware-signing": "1.0.0-rc.3", + "@aws-sdk/middleware-stack": "1.0.0-rc.4", + "@aws-sdk/middleware-user-agent": "1.0.0-rc.3", + "@aws-sdk/node-config-provider": "1.0.0-rc.3", + "@aws-sdk/node-http-handler": "1.0.0-rc.3", + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/smithy-client": "1.0.0-rc.4", + "@aws-sdk/types": "1.0.0-rc.3", + "@aws-sdk/url-parser-browser": "1.0.0-rc.3", + "@aws-sdk/url-parser-node": "1.0.0-rc.3", + "@aws-sdk/util-base64-browser": "1.0.0-rc.3", + "@aws-sdk/util-base64-node": "1.0.0-rc.3", + "@aws-sdk/util-body-length-browser": "1.0.0-rc.3", + "@aws-sdk/util-body-length-node": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-browser": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-node": "1.0.0-rc.3", + "@aws-sdk/util-utf8-browser": "1.0.0-rc.3", + "@aws-sdk/util-utf8-node": "1.0.0-rc.3", + "tslib": "^2.0.0" + }, + "dependencies": { + "@aws-crypto/sha256-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-1.0.0.tgz", + "integrity": "sha512-89kqtFs/tdHBFHEBXZ4UXlCISswvEor3BVVOriR68Tbk1Qe1zBOZtfbSOt3CDT69z88x5uM558YW9k8I1xei5A==", + "dev": true, + "requires": { + "@aws-sdk/types": "^1.0.0-rc.1", + "@aws-sdk/util-utf8-browser": "^1.0.0-rc.1", + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + } + } + }, + "@aws-sdk/client-polly": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-polly/-/client-polly-1.0.0-rc.4.tgz", + "integrity": "sha512-fPLs0vHvSP9tO2Ga2qcTWmHxVIOYGEWIt0il3Shh/3oT/9pCbp5YWwCCUaDhADbomXthIM0T4OtmiZ2/plGoEQ==", + "dev": true, + "requires": { + "@aws-crypto/sha256-browser": "^1.0.0", + "@aws-crypto/sha256-js": "^1.0.0", + "@aws-sdk/config-resolver": "1.0.0-rc.3", + "@aws-sdk/credential-provider-node": "1.0.0-rc.3", + "@aws-sdk/fetch-http-handler": "1.0.0-rc.3", + "@aws-sdk/hash-node": "1.0.0-rc.3", + "@aws-sdk/invalid-dependency": "1.0.0-rc.3", + "@aws-sdk/middleware-content-length": "1.0.0-rc.3", + "@aws-sdk/middleware-host-header": "1.0.0-rc.3", + "@aws-sdk/middleware-logger": "1.0.0-rc.4", + "@aws-sdk/middleware-retry": "1.0.0-rc.4", + "@aws-sdk/middleware-serde": "1.0.0-rc.3", + "@aws-sdk/middleware-signing": "1.0.0-rc.3", + "@aws-sdk/middleware-stack": "1.0.0-rc.4", + "@aws-sdk/middleware-user-agent": "1.0.0-rc.3", + "@aws-sdk/node-config-provider": "1.0.0-rc.3", + "@aws-sdk/node-http-handler": "1.0.0-rc.3", + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/smithy-client": "1.0.0-rc.4", + "@aws-sdk/types": "1.0.0-rc.3", + "@aws-sdk/url-parser-browser": "1.0.0-rc.3", + "@aws-sdk/url-parser-node": "1.0.0-rc.3", + "@aws-sdk/util-base64-browser": "1.0.0-rc.3", + "@aws-sdk/util-base64-node": "1.0.0-rc.3", + "@aws-sdk/util-body-length-browser": "1.0.0-rc.3", + "@aws-sdk/util-body-length-node": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-browser": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-node": "1.0.0-rc.3", + "@aws-sdk/util-utf8-browser": "1.0.0-rc.3", + "@aws-sdk/util-utf8-node": "1.0.0-rc.3", + "tslib": "^2.0.0" + }, + "dependencies": { + "@aws-crypto/sha256-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-1.0.0.tgz", + "integrity": "sha512-89kqtFs/tdHBFHEBXZ4UXlCISswvEor3BVVOriR68Tbk1Qe1zBOZtfbSOt3CDT69z88x5uM558YW9k8I1xei5A==", + "dev": true, + "requires": { + "@aws-sdk/types": "^1.0.0-rc.1", + "@aws-sdk/util-utf8-browser": "^1.0.0-rc.1", + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + } + } + }, + "@aws-sdk/client-rekognition": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-rekognition/-/client-rekognition-1.0.0-rc.4.tgz", + "integrity": "sha512-8pUogGeKYUSVKopG9grA8KwvAYlrKwpGUO8kiNU78gJut5gLTGxiHIHvuufbgRHmGiXeWrP+WwWghX9F6q2V9w==", + "dev": true, + "requires": { + "@aws-crypto/sha256-browser": "^1.0.0", + "@aws-crypto/sha256-js": "^1.0.0", + "@aws-sdk/config-resolver": "1.0.0-rc.3", + "@aws-sdk/credential-provider-node": "1.0.0-rc.3", + "@aws-sdk/fetch-http-handler": "1.0.0-rc.3", + "@aws-sdk/hash-node": "1.0.0-rc.3", + "@aws-sdk/invalid-dependency": "1.0.0-rc.3", + "@aws-sdk/middleware-content-length": "1.0.0-rc.3", + "@aws-sdk/middleware-host-header": "1.0.0-rc.3", + "@aws-sdk/middleware-logger": "1.0.0-rc.4", + "@aws-sdk/middleware-retry": "1.0.0-rc.4", + "@aws-sdk/middleware-serde": "1.0.0-rc.3", + "@aws-sdk/middleware-signing": "1.0.0-rc.3", + "@aws-sdk/middleware-stack": "1.0.0-rc.4", + "@aws-sdk/middleware-user-agent": "1.0.0-rc.3", + "@aws-sdk/node-config-provider": "1.0.0-rc.3", + "@aws-sdk/node-http-handler": "1.0.0-rc.3", + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/smithy-client": "1.0.0-rc.4", + "@aws-sdk/types": "1.0.0-rc.3", + "@aws-sdk/url-parser-browser": "1.0.0-rc.3", + "@aws-sdk/url-parser-node": "1.0.0-rc.3", + "@aws-sdk/util-base64-browser": "1.0.0-rc.3", + "@aws-sdk/util-base64-node": "1.0.0-rc.3", + "@aws-sdk/util-body-length-browser": "1.0.0-rc.3", + "@aws-sdk/util-body-length-node": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-browser": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-node": "1.0.0-rc.3", + "@aws-sdk/util-utf8-browser": "1.0.0-rc.3", + "@aws-sdk/util-utf8-node": "1.0.0-rc.3", + "tslib": "^2.0.0" + }, + "dependencies": { + "@aws-crypto/sha256-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-1.0.0.tgz", + "integrity": "sha512-89kqtFs/tdHBFHEBXZ4UXlCISswvEor3BVVOriR68Tbk1Qe1zBOZtfbSOt3CDT69z88x5uM558YW9k8I1xei5A==", + "dev": true, + "requires": { + "@aws-sdk/types": "^1.0.0-rc.1", + "@aws-sdk/util-utf8-browser": "^1.0.0-rc.1", + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + } + } + }, + "@aws-sdk/client-s3": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-1.0.0-rc.4.tgz", + "integrity": "sha512-P7iTjtBkBCWfmpnJdd8yYWNFcj5rDbCX1bnFli3uCf+y7gKHUlQiS6j8tgjvTzbUDxhFVjCP3a4zhSact0PZOA==", + "dev": true, + "requires": { + "@aws-crypto/sha256-browser": "^1.0.0", + "@aws-crypto/sha256-js": "^1.0.0", + "@aws-sdk/config-resolver": "1.0.0-rc.3", + "@aws-sdk/credential-provider-node": "1.0.0-rc.3", + "@aws-sdk/eventstream-serde-browser": "1.0.0-rc.3", + "@aws-sdk/eventstream-serde-config-resolver": "1.0.0-rc.3", + "@aws-sdk/eventstream-serde-node": "1.0.0-rc.3", + "@aws-sdk/fetch-http-handler": "1.0.0-rc.3", + "@aws-sdk/hash-blob-browser": "1.0.0-rc.3", + "@aws-sdk/hash-node": "1.0.0-rc.3", + "@aws-sdk/hash-stream-node": "1.0.0-rc.3", + "@aws-sdk/invalid-dependency": "1.0.0-rc.3", + "@aws-sdk/md5-js": "1.0.0-rc.3", + "@aws-sdk/middleware-apply-body-checksum": "1.0.0-rc.3", + "@aws-sdk/middleware-bucket-endpoint": "1.0.0-rc.4", + "@aws-sdk/middleware-content-length": "1.0.0-rc.3", + "@aws-sdk/middleware-expect-continue": "1.0.0-rc.3", + "@aws-sdk/middleware-host-header": "1.0.0-rc.3", + "@aws-sdk/middleware-location-constraint": "1.0.0-rc.3", + "@aws-sdk/middleware-logger": "1.0.0-rc.4", + "@aws-sdk/middleware-retry": "1.0.0-rc.4", + "@aws-sdk/middleware-sdk-s3": "1.0.0-rc.3", + "@aws-sdk/middleware-serde": "1.0.0-rc.3", + "@aws-sdk/middleware-signing": "1.0.0-rc.3", + "@aws-sdk/middleware-ssec": "1.0.0-rc.3", + "@aws-sdk/middleware-stack": "1.0.0-rc.4", + "@aws-sdk/middleware-user-agent": "1.0.0-rc.3", + "@aws-sdk/node-config-provider": "1.0.0-rc.3", + "@aws-sdk/node-http-handler": "1.0.0-rc.3", + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/smithy-client": "1.0.0-rc.4", + "@aws-sdk/types": "1.0.0-rc.3", + "@aws-sdk/url-parser-browser": "1.0.0-rc.3", + "@aws-sdk/url-parser-node": "1.0.0-rc.3", + "@aws-sdk/util-base64-browser": "1.0.0-rc.3", + "@aws-sdk/util-base64-node": "1.0.0-rc.3", + "@aws-sdk/util-body-length-browser": "1.0.0-rc.3", + "@aws-sdk/util-body-length-node": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-browser": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-node": "1.0.0-rc.3", + "@aws-sdk/util-utf8-browser": "1.0.0-rc.3", + "@aws-sdk/util-utf8-node": "1.0.0-rc.3", + "@aws-sdk/xml-builder": "1.0.0-rc.3", + "fast-xml-parser": "^3.16.0", + "tslib": "^2.0.0" + }, + "dependencies": { + "@aws-crypto/sha256-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-1.0.0.tgz", + "integrity": "sha512-89kqtFs/tdHBFHEBXZ4UXlCISswvEor3BVVOriR68Tbk1Qe1zBOZtfbSOt3CDT69z88x5uM558YW9k8I1xei5A==", + "dev": true, + "requires": { + "@aws-sdk/types": "^1.0.0-rc.1", + "@aws-sdk/util-utf8-browser": "^1.0.0-rc.1", + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + } + } + }, + "@aws-sdk/client-textract": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-textract/-/client-textract-1.0.0-rc.4.tgz", + "integrity": "sha512-Hf8B4lhLo6W7EdTaqLaMM5JCLlaR91rzSaPsb+1YoPtB4C2tcG7S94/yRxXEL1/Pok/mrtFN7mZ9Zcg23BtrVQ==", + "dev": true, + "requires": { + "@aws-crypto/sha256-browser": "^1.0.0", + "@aws-crypto/sha256-js": "^1.0.0", + "@aws-sdk/config-resolver": "1.0.0-rc.3", + "@aws-sdk/credential-provider-node": "1.0.0-rc.3", + "@aws-sdk/fetch-http-handler": "1.0.0-rc.3", + "@aws-sdk/hash-node": "1.0.0-rc.3", + "@aws-sdk/invalid-dependency": "1.0.0-rc.3", + "@aws-sdk/middleware-content-length": "1.0.0-rc.3", + "@aws-sdk/middleware-host-header": "1.0.0-rc.3", + "@aws-sdk/middleware-logger": "1.0.0-rc.4", + "@aws-sdk/middleware-retry": "1.0.0-rc.4", + "@aws-sdk/middleware-serde": "1.0.0-rc.3", + "@aws-sdk/middleware-signing": "1.0.0-rc.3", + "@aws-sdk/middleware-stack": "1.0.0-rc.4", + "@aws-sdk/middleware-user-agent": "1.0.0-rc.3", + "@aws-sdk/node-config-provider": "1.0.0-rc.3", + "@aws-sdk/node-http-handler": "1.0.0-rc.3", + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/smithy-client": "1.0.0-rc.4", + "@aws-sdk/types": "1.0.0-rc.3", + "@aws-sdk/url-parser-browser": "1.0.0-rc.3", + "@aws-sdk/url-parser-node": "1.0.0-rc.3", + "@aws-sdk/util-base64-browser": "1.0.0-rc.3", + "@aws-sdk/util-base64-node": "1.0.0-rc.3", + "@aws-sdk/util-body-length-browser": "1.0.0-rc.3", + "@aws-sdk/util-body-length-node": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-browser": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-node": "1.0.0-rc.3", + "@aws-sdk/util-utf8-browser": "1.0.0-rc.3", + "@aws-sdk/util-utf8-node": "1.0.0-rc.3", + "tslib": "^2.0.0" + }, + "dependencies": { + "@aws-crypto/sha256-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-1.0.0.tgz", + "integrity": "sha512-89kqtFs/tdHBFHEBXZ4UXlCISswvEor3BVVOriR68Tbk1Qe1zBOZtfbSOt3CDT69z88x5uM558YW9k8I1xei5A==", + "dev": true, + "requires": { + "@aws-sdk/types": "^1.0.0-rc.1", + "@aws-sdk/util-utf8-browser": "^1.0.0-rc.1", + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + } + } + }, + "@aws-sdk/client-translate": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-translate/-/client-translate-1.0.0-rc.4.tgz", + "integrity": "sha512-OqRykzNtuqKSX7fWGVv9060ymD5ZFuTgIjRuftDM+KNyFpHt5qDqyLs6f1a5iwrUxVmqKvV+F13MjOjPNdR4/w==", + "dev": true, + "requires": { + "@aws-crypto/sha256-browser": "^1.0.0", + "@aws-crypto/sha256-js": "^1.0.0", + "@aws-sdk/config-resolver": "1.0.0-rc.3", + "@aws-sdk/credential-provider-node": "1.0.0-rc.3", + "@aws-sdk/fetch-http-handler": "1.0.0-rc.3", + "@aws-sdk/hash-node": "1.0.0-rc.3", + "@aws-sdk/invalid-dependency": "1.0.0-rc.3", + "@aws-sdk/middleware-content-length": "1.0.0-rc.3", + "@aws-sdk/middleware-host-header": "1.0.0-rc.3", + "@aws-sdk/middleware-logger": "1.0.0-rc.4", + "@aws-sdk/middleware-retry": "1.0.0-rc.4", + "@aws-sdk/middleware-serde": "1.0.0-rc.3", + "@aws-sdk/middleware-signing": "1.0.0-rc.3", + "@aws-sdk/middleware-stack": "1.0.0-rc.4", + "@aws-sdk/middleware-user-agent": "1.0.0-rc.3", + "@aws-sdk/node-config-provider": "1.0.0-rc.3", + "@aws-sdk/node-http-handler": "1.0.0-rc.3", + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/smithy-client": "1.0.0-rc.4", + "@aws-sdk/types": "1.0.0-rc.3", + "@aws-sdk/url-parser-browser": "1.0.0-rc.3", + "@aws-sdk/url-parser-node": "1.0.0-rc.3", + "@aws-sdk/util-base64-browser": "1.0.0-rc.3", + "@aws-sdk/util-base64-node": "1.0.0-rc.3", + "@aws-sdk/util-body-length-browser": "1.0.0-rc.3", + "@aws-sdk/util-body-length-node": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-browser": "1.0.0-rc.3", + "@aws-sdk/util-user-agent-node": "1.0.0-rc.3", + "@aws-sdk/util-utf8-browser": "1.0.0-rc.3", + "@aws-sdk/util-utf8-node": "1.0.0-rc.3", + "tslib": "^2.0.0", + "uuid": "^3.0.0" + }, + "dependencies": { + "@aws-crypto/sha256-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-1.0.0.tgz", + "integrity": "sha512-89kqtFs/tdHBFHEBXZ4UXlCISswvEor3BVVOriR68Tbk1Qe1zBOZtfbSOt3CDT69z88x5uM558YW9k8I1xei5A==", + "dev": true, + "requires": { + "@aws-sdk/types": "^1.0.0-rc.1", + "@aws-sdk/util-utf8-browser": "^1.0.0-rc.1", + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + } + } + }, + "@aws-sdk/config-resolver": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-1.0.0-rc.3.tgz", + "integrity": "sha512-twz204J+R5SFUOWe7VPYoF9yZA3HsMujnZKkm7QTunKUYRrrZcG1x6KeArIpk1mKFlrtm1tcab5BqUDUKgm23A==", + "dev": true, + "requires": { + "@aws-sdk/signature-v4": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/credential-provider-cognito-identity": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-1.0.0-rc.4.tgz", + "integrity": "sha512-mT7sePBR/5+d132J7GjKrZPevszL9ZvvUpS/ng9CLzneBmygVZJIujwbPe6H77UH8pqU8xA1PVwBKV9cEISRww==", + "dev": true, + "requires": { + "@aws-sdk/client-cognito-identity": "1.0.0-rc.4", + "@aws-sdk/property-provider": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/credential-provider-env": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-1.0.0-rc.3.tgz", + "integrity": "sha512-QG9YUDy1qjghL6MsXIE4wxXuTDeBsNWcXYIMpuvn5bJSVDmcSmXwVFMyCiYvDlN57zbomWaNvYiq9TS50aw0Ng==", + "dev": true, + "requires": { + "@aws-sdk/property-provider": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/credential-provider-imds": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-imds/-/credential-provider-imds-1.0.0-rc.3.tgz", + "integrity": "sha512-vMRAlXdU4ZUeLGgtXh+MCzyZrdoXA8tJldR5n0glbODAym1Ap6ZQ9Y/apQvaHiMxyTd/PCcPg0cwSmhlnwdhTg==", + "dev": true, + "requires": { + "@aws-sdk/property-provider": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/credential-provider-ini": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-1.0.0-rc.3.tgz", + "integrity": "sha512-3/dvnmtnjGSoBn9MSTtO6/Vpd0RxwA1oOeHlFhswr4ZDMI3Nn8almvUhjtC+wkKKSG+ushkEJaDDPy6P+7xqRA==", + "dev": true, + "requires": { + "@aws-sdk/property-provider": "1.0.0-rc.3", + "@aws-sdk/shared-ini-file-loader": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/credential-provider-node": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-1.0.0-rc.3.tgz", + "integrity": "sha512-UbtN7dMjyUgYyYKSQLAMmx1aGT9HD00bf0suvn9H4lo5piWuJ/30CoBqIl/l2l+6z0AdK2DcGoF5yuLyJSX0ww==", + "dev": true, + "requires": { + "@aws-sdk/credential-provider-env": "1.0.0-rc.3", + "@aws-sdk/credential-provider-imds": "1.0.0-rc.3", + "@aws-sdk/credential-provider-ini": "1.0.0-rc.3", + "@aws-sdk/credential-provider-process": "1.0.0-rc.3", + "@aws-sdk/property-provider": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/credential-provider-process": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-1.0.0-rc.3.tgz", + "integrity": "sha512-gz98CXgAwtsW1CkK9F8SOW1EEHFFHsl3QCBs1i4CErYr08i/2sa1LHOjxyIJ9RMRM0WNPBCLH4btvpajOGtXBA==", + "dev": true, + "requires": { + "@aws-sdk/credential-provider-ini": "1.0.0-rc.3", + "@aws-sdk/property-provider": "1.0.0-rc.3", + "@aws-sdk/shared-ini-file-loader": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/eventstream-marshaller": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-marshaller/-/eventstream-marshaller-1.0.0-rc.3.tgz", + "integrity": "sha512-LBWqTd+VRVBdmBYm/K3ueBHLNOCUlj0uLQOExfvKFTugQ1t3i5JoZKLYNbTJyid8sMmbyq1y/nfM+kAHXguwAQ==", + "dev": true, + "requires": { + "@aws-crypto/crc32": "^1.0.0", + "@aws-sdk/types": "1.0.0-rc.3", + "@aws-sdk/util-hex-encoding": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/eventstream-serde-browser": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-serde-browser/-/eventstream-serde-browser-1.0.0-rc.3.tgz", + "integrity": "sha512-dMWtrnaOBLxEFvEtX7r66Pxh+XipRdDYHHNTSsg3Vaj+cDcCUkur2tplhKaBQY9bElfGB2Rb2R7XsfIxt9PZ0w==", + "dev": true, + "requires": { + "@aws-sdk/eventstream-marshaller": "1.0.0-rc.3", + "@aws-sdk/eventstream-serde-universal": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/eventstream-serde-config-resolver": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-1.0.0-rc.3.tgz", + "integrity": "sha512-hnp8DwEK64p2mwMDyBIgGq7yOaxDe3H1O7xoNmKb/owqQAcV8BxhhbrJYrsXNSeE/lO2zckPcL1imzuKHudTfA==", + "dev": true, + "requires": { + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/eventstream-serde-node": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-serde-node/-/eventstream-serde-node-1.0.0-rc.3.tgz", + "integrity": "sha512-QTIygM8qoVfDv6paFTdyvuAdgUSm/VDFa36OZd+IXSgzoYYrI/psutpYCyt/27oiPH+rFPrOofs9A1mXIWWMhg==", + "dev": true, + "requires": { + "@aws-sdk/eventstream-marshaller": "1.0.0-rc.3", + "@aws-sdk/eventstream-serde-universal": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/eventstream-serde-universal": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-serde-universal/-/eventstream-serde-universal-1.0.0-rc.3.tgz", + "integrity": "sha512-YAQMuEI+J0LEf8tOISYSihkEiEH2YpQpvXkLlWyybmWEa1XjmGaZS5V1HP/xf5cA/HPtIsApCz2VYTY50A/Lxw==", + "dev": true, + "requires": { + "@aws-sdk/eventstream-marshaller": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/fetch-http-handler": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/fetch-http-handler/-/fetch-http-handler-1.0.0-rc.3.tgz", + "integrity": "sha512-1xd4DuW8Su7qHKg9wipVGhscvLsVRhZi9pRLxh13lIKEIt+ryxXzrex1YoxDUnDH3ZI7YhdeLhZIonlgaNT+Gw==", + "dev": true, + "requires": { + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/querystring-builder": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "@aws-sdk/util-base64-browser": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/hash-blob-browser": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/hash-blob-browser/-/hash-blob-browser-1.0.0-rc.3.tgz", + "integrity": "sha512-2lgiclNMd3hiNBjoSh7UuzSY9ucpVF7Z6AmSmERWqN5Sm69u1q8p0RgyyWnKd0JZRelPlB8gBXk4EzxBPSTSLA==", + "dev": true, + "requires": { + "@aws-sdk/chunked-blob-reader": "1.0.0-rc.3", + "@aws-sdk/chunked-blob-reader-native": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/hash-node": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/hash-node/-/hash-node-1.0.0-rc.3.tgz", + "integrity": "sha512-Q3DikdeGA6pih2ftZajlNaHxsNUaKEXneZdxyoaSKyMppEni3eK2Z2ZjzyjDuXflYLkNtj4ylscure+uIKAApg==", + "dev": true, + "requires": { + "@aws-sdk/types": "1.0.0-rc.3", + "@aws-sdk/util-buffer-from": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/hash-stream-node": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/hash-stream-node/-/hash-stream-node-1.0.0-rc.3.tgz", + "integrity": "sha512-ry78JhVXHIUdH/aokQ/YBxQ+26zC5VOgK2XLq9eDdxBTz2sefjwzk3Qs5eY1GZKfyUlKMwdRpCibo9FlPVPJeg==", + "dev": true, + "requires": { + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/invalid-dependency": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/invalid-dependency/-/invalid-dependency-1.0.0-rc.3.tgz", + "integrity": "sha512-Fl71S5Igd5Mi81QklxhhEWzwKbm+QP1kUYoc5nVK2sE+iLqdF9jwg7/ONBN8jISjTD8GPIW7NWL2SQNINNryMw==", + "dev": true, + "requires": { + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/is-array-buffer": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-1.0.0-rc.3.tgz", + "integrity": "sha512-tHFTBiXAgBZmAKaJIL2e2QPR9kA1tZTUJMqKaybWjhXckvb29EgUOLcdK+W2kMSqKIGqEINbAaV7S11ydBtYIg==", + "dev": true, + "requires": { + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/md5-js": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/md5-js/-/md5-js-1.0.0-rc.3.tgz", + "integrity": "sha512-UfHtEs5IWl39yU4X/95605bFMKErWRd+uPgtqEtCWDDGyw4uwUUrkyrhTfJKuUFvTj9ov0Lb03x5QPNDybAelQ==", + "dev": true, + "requires": { + "@aws-sdk/types": "1.0.0-rc.3", + "@aws-sdk/util-utf8-browser": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/middleware-apply-body-checksum": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-apply-body-checksum/-/middleware-apply-body-checksum-1.0.0-rc.3.tgz", + "integrity": "sha512-f8CMcb1mxPWHJvLxegpjF1fwoa/vFjIaRIrXgUoPMhFNICRZPGnzim2o2mGyjWcS39VkM6G7vpmosNv2zc4EJg==", + "dev": true, + "requires": { + "@aws-sdk/is-array-buffer": "1.0.0-rc.3", + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/middleware-bucket-endpoint": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-1.0.0-rc.4.tgz", + "integrity": "sha512-fA5zUz8Q9+mJ6YV+wfQQ/rn5Cj8NkcxECfq6wEoemVNTh2RmLv2vf6t/y7Q1rGZXo+kyW7633Pnofcb7Pja92g==", + "dev": true, + "requires": { + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "@aws-sdk/util-arn-parser": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/middleware-content-length": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-content-length/-/middleware-content-length-1.0.0-rc.3.tgz", + "integrity": "sha512-eQfeMwneYxxF6NMF5AokilQHm3HMUbtBVmybdrrM+vs027DRQBDqcZ2GXwVI93kcS4GaibNnzX804rG2xA2UwA==", + "dev": true, + "requires": { + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/middleware-expect-continue": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-1.0.0-rc.3.tgz", + "integrity": "sha512-rDs68vBn0sSWl3z1ecXSw7n+MeiSW//r6NSAWAmBE58BDjHSfwQ+aB3izpSHDGIiGZO4aasnwZAP7NjzYvxiWQ==", + "dev": true, + "requires": { + "@aws-sdk/middleware-header-default": "1.0.0-rc.3", + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/middleware-header-default": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-header-default/-/middleware-header-default-1.0.0-rc.3.tgz", + "integrity": "sha512-h0zQFCaBzu7SoRRlKYws76C8q8hY/Ja7G6E69X7fGbrcmNFMjm4aZq0eipKvOIg7cGbrcFnyOnWqLlWaL76nwA==", + "dev": true, + "requires": { + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/middleware-host-header": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-1.0.0-rc.3.tgz", + "integrity": "sha512-44aOjB9yd2TCDj8c9sr+8+rhQ63kkuIAcMdbt3P/fXKUWwTAW+bcvknaynya3hLa8B75tEQ112xVBb+HoDR//g==", + "dev": true, + "requires": { + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/middleware-location-constraint": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-1.0.0-rc.3.tgz", + "integrity": "sha512-VdW0/g8SVckRQsz55DrPIzyrF+Qgat3qt+qE9c6Gk7u6XaF05BlG7rbjsStd3Eml+FsKG1KOO3RgDCWvgESmNw==", + "dev": true, + "requires": { + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/middleware-logger": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-1.0.0-rc.4.tgz", + "integrity": "sha512-TfTx9bbYYr2+rXQMHziyWmmvmHVb9Nzxj+V6vJQrOXxjrWvuYf+XM3aHNt8950XzzYmh6pc0+8p5Kk8NDnkM5A==", + "dev": true, + "requires": { + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/middleware-retry": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-1.0.0-rc.4.tgz", + "integrity": "sha512-mIcEkQFiLWENsLGScYLOIa3yxAXrM1ZZoIxcXg1x2durgVCBd3fBC9jLJ5CGyGQAUHZmvhM/7BfjSueTOaV/JQ==", + "dev": true, + "requires": { + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/service-error-classification": "1.0.0-rc.4", + "@aws-sdk/types": "1.0.0-rc.3", + "react-native-get-random-values": "^1.4.0", + "tslib": "^1.8.0", + "uuid": "^3.0.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/middleware-sdk-s3": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-1.0.0-rc.3.tgz", + "integrity": "sha512-TDICHo5wONd4GUgLEtSjlygKRzXBfxkPQcNEGB2Mnbi+xbDa4FNd6XszkOrNMzxtmqD53ub/iDQewcBr9U9HJQ==", + "dev": true, + "requires": { + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/util-arn-parser": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/middleware-serde": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-serde/-/middleware-serde-1.0.0-rc.3.tgz", + "integrity": "sha512-3IK4Hz8YV4+AIGJLjDu3QTKjfHGVIPrY5x4ubFzbGVc6EC9y69y+Yh3425ca3xeAVQFnORQn/707LiNKLlsD8g==", + "dev": true, + "requires": { + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/middleware-signing": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-1.0.0-rc.3.tgz", + "integrity": "sha512-RqIQwPaHvyY38rmIR+A9b3EwIaPPAKA4rmaTGAT1jeS7H65tXJeKc7aAXJWvDn9E1Fj56mOHTOd86FgP45MrUg==", + "dev": true, + "requires": { + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/signature-v4": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/middleware-ssec": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-1.0.0-rc.3.tgz", + "integrity": "sha512-sqv/TELHxAvpqOi7uhfCwLGVyOb1ihehfnSeqsyh2HPphg529ssmDUCF6jsi5maMc3lM/eHQ8LDPSXU9H58wwQ==", + "dev": true, + "requires": { + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/middleware-stack": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-1.0.0-rc.4.tgz", + "integrity": "sha512-UUJSFRV+wJ/V3wt7rX3PA2a4MLkLt23vPKjjC70ETGSGuAcKsuXaZ9ZULZqENO+b3HKcs0eV8LoK/qU06EN8Mg==", + "dev": true, + "requires": { + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/middleware-user-agent": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-1.0.0-rc.3.tgz", + "integrity": "sha512-Zrp3kETrrWgJLlnjkSuetOH5cN5URqLd6WQmhZlEm0isvr+2RyDDOA4wP6JjmMhCmrG02/8/b4pMOPH/vUm/LQ==", + "dev": true, + "requires": { + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/node-config-provider": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-1.0.0-rc.3.tgz", + "integrity": "sha512-1i0fjunUMYP479hAq7D8RugfMmC3KCUzvZA2xtjFQcE31d7YrlfGstwBq/kvNcIcw+yc3r7SC54KzwgqfSSvzA==", + "dev": true, + "requires": { + "@aws-sdk/property-provider": "1.0.0-rc.3", + "@aws-sdk/shared-ini-file-loader": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/node-http-handler": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/node-http-handler/-/node-http-handler-1.0.0-rc.3.tgz", + "integrity": "sha512-hK0NM3PxGVCgKLZoAb8bXFQlOA1JGd2DwfjDdAn4XfIhEH4QfbuFZxjkQhNcDwkKIqzCmlYTbgJvWKRbbFkEXg==", + "dev": true, + "requires": { + "@aws-sdk/abort-controller": "1.0.0-rc.3", + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/querystring-builder": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/property-provider": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-1.0.0-rc.3.tgz", + "integrity": "sha512-WrYlUVaq63k0fYdnIJziphfdTITaTlW0b1qrRzFsqKPRN1AnQenzFs27ZHaaecmFfGg3q1Y2fci3cpyNUBTruQ==", + "dev": true, + "requires": { + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/protocol-http": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-1.0.0-rc.3.tgz", + "integrity": "sha512-paOSLmXvce84BRCx+JIYGpsVCtn3GCGvzLywaPCHeES2OekwD86PJQskCDAlshRPOy/LCdxYVdMt7FrEBuyQrg==", + "dev": true, + "requires": { + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/querystring-builder": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-builder/-/querystring-builder-1.0.0-rc.3.tgz", + "integrity": "sha512-PWTaV+0r/7FlPNjjKJQ/WyT4oRx4tG5efOuzQobb4/Bw2AFqVCzE2DMGx1V8YKqdq3QFckvRuoFDVqftyhF/Jw==", + "dev": true, + "requires": { + "@aws-sdk/types": "1.0.0-rc.3", + "@aws-sdk/util-uri-escape": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/querystring-parser": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-parser/-/querystring-parser-1.0.0-rc.3.tgz", + "integrity": "sha512-TkA/4wM76WzsiMOs0Lxqk33rP+J0YtCjmpGzS+x4oqNbdVYQBpYtbwqN+9nsrOeieCFRWq9QWl6QM4IyJT9gRA==", + "dev": true, + "requires": { + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/s3-request-presigner": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-1.0.0-rc.4.tgz", + "integrity": "sha512-DwwftqEKD7XsiM5sn+CpzhnJ9wjwK3LmXwYW2UvwF1tBTSMrTdGb14AAe8BTvxcsAPEi7Xwlr0f4kFpOlAgV3A==", + "dev": true, + "requires": { + "@aws-sdk/protocol-http": "1.0.0-rc.3", + "@aws-sdk/signature-v4": "1.0.0-rc.3", + "@aws-sdk/smithy-client": "1.0.0-rc.4", + "@aws-sdk/types": "1.0.0-rc.3", + "@aws-sdk/util-create-request": "1.0.0-rc.4", + "@aws-sdk/util-format-url": "1.0.0-rc.4", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/service-error-classification": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-1.0.0-rc.4.tgz", + "integrity": "sha512-NqQkBmy9xxvF/SMuarNdw6Ts+LWU9TRZuerbkAZAS5VhBpaiEfRUX+KqW445F1HxjKJ8LUFBnBfaSZvNcC+GqA==", + "dev": true + }, + "@aws-sdk/shared-ini-file-loader": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-1.0.0-rc.3.tgz", + "integrity": "sha512-wynHRRZENIZUS714NX9cu9BDbxAL7DzOJvPYAj2tgC3bJNt0jkbQxNTePpolwWx7QNwFfQgDbK76LPkIo30dJQ==", + "dev": true, + "requires": { + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/signature-v4": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-1.0.0-rc.3.tgz", + "integrity": "sha512-ARfmXLW4NMmQF5/3xGiasi6nrlvddZauJOgG9t2STTog8gijn+y+V7wh26A7e4vgv1hyE0RdonylbakUH1R4Nw==", + "dev": true, + "requires": { + "@aws-sdk/is-array-buffer": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "@aws-sdk/util-hex-encoding": "1.0.0-rc.3", + "@aws-sdk/util-uri-escape": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/smithy-client": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-1.0.0-rc.4.tgz", + "integrity": "sha512-usblThhr82iOH0zMX5yYJME9pHVPdKpGZaBWgdKPNpnBaIAkkveAx+m1FaMaBXVyjGy9f8hZOtiMY/U+kI+16A==", + "dev": true, + "requires": { + "@aws-sdk/middleware-stack": "1.0.0-rc.4", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/types": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-1.0.0-rc.3.tgz", + "integrity": "sha512-pKKR2SXG8IHbWcmVgFwLUrHqqqFOEuf5JiQmP7dEBjUXqavzDnqFUY7g9PGuM8928IQqL7IXrRsK7R+VbLgodQ==", + "dev": true + }, + "@aws-sdk/url-parser-browser": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/url-parser-browser/-/url-parser-browser-1.0.0-rc.3.tgz", + "integrity": "sha512-bTCB4K1nxX3juaOSRdjUC+nq1KZX1Ipy5pMQoDiRWYCgMgUAcqeWuxlclF3dc8vuhYUWa2A86D5lT3zrP0Gqag==", + "dev": true, + "requires": { + "@aws-sdk/querystring-parser": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/url-parser-node": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/url-parser-node/-/url-parser-node-1.0.0-rc.3.tgz", + "integrity": "sha512-W2No+drp3jCjkr1edSReGNLyXF+a34qHOcy8cJ6ZtPe5eLzCroZ33+w1gJ01r5UboWwzo8Qyz7QPxD5J0zPVzw==", + "dev": true, + "requires": { + "@aws-sdk/querystring-parser": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0", + "url": "^0.11.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/util-arn-parser": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-1.0.0-rc.3.tgz", + "integrity": "sha512-mIXiyBYDAQa9EdaKKU4oQsWAvSWVXAumCH89N5VQfrlRCuaqRUdmE83CJx69wcLFbrZCZmCJD2gcPVG5Ywa+NQ==", + "dev": true, + "requires": { + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/util-base64-browser": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64-browser/-/util-base64-browser-1.0.0-rc.3.tgz", + "integrity": "sha512-peqOSoOCTGlZVX9gC+4SxaSXQqSsjzNfKxKLZwcP/HhHIPU/I+tbnRbH4a2Cx29DsopTngu0GKLuPJEL67bvog==", + "dev": true, + "requires": { + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/util-base64-node": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64-node/-/util-base64-node-1.0.0-rc.3.tgz", + "integrity": "sha512-gz/JScFQ9MMdI59VdJTbgZrnNdTPXOJKesMwoEMH8nMb6/Wi3+KL2NH/GC92hxhuE/JbA1vdrelvCFOED8E1Jg==", + "dev": true, + "requires": { + "@aws-sdk/util-buffer-from": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/util-body-length-browser": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-1.0.0-rc.3.tgz", + "integrity": "sha512-xvMrCo+5DshN4Fu3zar2RxaqPJ/QRAEOChyWEGUqjE+9/cow+uWsqBX3FdeY84mV6dkdcAJLQvP8aVH+v+w+lw==", + "dev": true, + "requires": { + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/util-body-length-node": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-node/-/util-body-length-node-1.0.0-rc.3.tgz", + "integrity": "sha512-q7n3IP5s9TIMao9sK4an+xxBubHqWXoeqCQ5haeDmqQTBiZQYcyQQq61YJRghj2/53SH5MMS1ACncw3kvnO92g==", + "dev": true, + "requires": { + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/util-buffer-from": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-1.0.0-rc.3.tgz", + "integrity": "sha512-43FzXSA3356C/QRCKZSmGTVwH4BgObNJDvF4z5dwwrfqU+tXjnUdnFo5hLsHq+fwjtWuXLkAyi+vz07x3MphvA==", + "dev": true, + "requires": { + "@aws-sdk/is-array-buffer": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/util-create-request": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-create-request/-/util-create-request-1.0.0-rc.4.tgz", + "integrity": "sha512-/Ki/ocJml4Jnh6efDr4w0qmD6W4s/oqnVXieU0qkUezcyJF1dIRTQmxvUdfx0aFZ8HtY5U9ZosajNAhdHjTGVg==", + "dev": true, + "requires": { + "@aws-sdk/middleware-stack": "1.0.0-rc.4", + "@aws-sdk/smithy-client": "1.0.0-rc.4", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/util-format-url": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-1.0.0-rc.4.tgz", + "integrity": "sha512-kqsHkZaCRJCnLlSDXNNNe7g7x6AAQXNiKeF2/qwEraT5kCi1NnWvlaTlA8uL1eOUMjxbw17sG9QMLZUuNKm3ow==", + "dev": true, + "requires": { + "@aws-sdk/querystring-builder": "1.0.0-rc.3", + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/util-hex-encoding": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-1.0.0-rc.3.tgz", + "integrity": "sha512-GXHBBGdAH2HPn18RFMsvXAvBtO8pG0I2PlGHfKhn+ym+UT1lHHYpCd3/PawUVUYnFZrqIj+j48IjFFJ3XMPXyQ==", + "dev": true, + "requires": { + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/util-locate-window": { + "version": "1.0.0-rc.8", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-1.0.0-rc.8.tgz", + "integrity": "sha512-TvqeA4fgmZ0A0x3K+qVj/OSWEFHGZjzpVuyXlm1EYOf7NQ9VWRlokEn1MYKuL+t7al9ZeQyi16D8Dn7DW1eidw==", + "dev": true, + "requires": { + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/util-uri-escape": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-1.0.0-rc.3.tgz", + "integrity": "sha512-PW1Uh5nJ32VKysV6DxyO40gONJR8s0QFeS55apyPUeCYCrdEjwsNvftDWbRJIcVpvkRSrbDezWc5CJC0S8WXjQ==", + "dev": true, + "requires": { + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/util-user-agent-browser": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-1.0.0-rc.3.tgz", + "integrity": "sha512-ev7bjF6QejDTi/UTvBLfiUETrXtuBf5sJl8ocWRUcrCnje5DW5lat2LaC7KWeRppQ4NA//ldavF5ngAxsn8TzA==", + "dev": true, + "requires": { + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/util-user-agent-node": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-1.0.0-rc.3.tgz", + "integrity": "sha512-5ELevKFFsHcyPSOrQ3mgdaNZ+Fr1I4J+/8aKoOiBO1Pnp15/xlVS4GkRiE0uUmAvBbUh1sByMvTo7ITeOBvlxA==", + "dev": true, + "requires": { + "@aws-sdk/types": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/util-utf8-browser": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-1.0.0-rc.3.tgz", + "integrity": "sha512-ypEJ2zsfm844dPSnES5lvS80Jb6hQ7D9iu0TUKQfIVu0LernJaAiSM05UEbktN+bEAoQBi9S64l8JjHVKFWu1Q==", + "dev": true, + "requires": { + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/util-utf8-node": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-node/-/util-utf8-node-1.0.0-rc.3.tgz", + "integrity": "sha512-80BWIgYzdw/cKxUrXf+7IKp07saLfCl7p4Q+zitcTrng9bSbPhjntXBS+dOFrBU2fBUynfI2K+9k5taJRKgOTQ==", + "dev": true, + "requires": { + "@aws-sdk/util-buffer-from": "1.0.0-rc.3", + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@aws-sdk/xml-builder": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-1.0.0-rc.3.tgz", + "integrity": "sha512-WdW/bZLVMNrEdG++m4B4QmZ6KnYsF3V68CDkZKg8IgDOMON4YOqUPBYDHNR8Wtdd1JQFLMDzrcqnXQqLb5dWgA==", + "dev": true, + "requires": { + "tslib": "^1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", + "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@fortawesome/fontawesome-common-types": { + "version": "0.2.32", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.32.tgz", + "integrity": "sha512-ux2EDjKMpcdHBVLi/eWZynnPxs0BtFVXJkgHIxXRl+9ZFaHPvYamAfCzeeQFqHRjuJtX90wVnMRaMQAAlctz3w==", + "dev": true + }, + "@fortawesome/free-solid-svg-icons": { + "version": "5.15.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.1.tgz", + "integrity": "sha512-EFMuKtzRMNbvjab/SvJBaOOpaqJfdSap/Nl6hst7CgrJxwfORR1drdTV6q1Ib/JVzq4xObdTDcT6sqTaXMqfdg==", + "dev": true, + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.32" + } + }, + "@polka/url": { + "version": "1.0.0-next.11", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.11.tgz", + "integrity": "sha512-3NsZsJIA/22P3QUyrEDNA2D133H4j224twJrdipXN38dpnIOzAbUDtOwkcJ5pXmn75w7LSQDjA4tO9dm1XlqlA==" + }, + "@rollup/plugin-alias": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-3.1.1.tgz", + "integrity": "sha512-hNcQY4bpBUIvxekd26DBPgF7BT4mKVNDF5tBG4Zi+3IgwLxGYRY0itHs9D0oLVwXM5pvJDWJlBQro+au8WaUWw==", + "dev": true, + "requires": { + "slash": "^3.0.0" + } + }, + "@rollup/plugin-commonjs": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-16.0.0.tgz", + "integrity": "sha512-LuNyypCP3msCGVQJ7ki8PqYdpjfEkE/xtFa5DqlF+7IBD0JsfMZ87C58heSwIMint58sAUZbt3ITqOmdQv/dXw==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.1.0", + "commondir": "^1.0.1", + "estree-walker": "^2.0.1", + "glob": "^7.1.6", + "is-reference": "^1.2.1", + "magic-string": "^0.25.7", + "resolve": "^1.17.0" + } + }, + "@rollup/plugin-json": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", + "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.0.8" + } + }, + "@rollup/plugin-node-resolve": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-10.0.0.tgz", + "integrity": "sha512-sNijGta8fqzwA1VwUEtTvWCx2E7qC70NMsDh4ZG13byAXYigBNZMxALhKUSycBks5gupJdq0lFrKumFrRZ8H3A==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.17.0" + } + }, + "@rollup/plugin-replace": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.3.4.tgz", + "integrity": "sha512-waBhMzyAtjCL1GwZes2jaE9MjuQ/DQF2BatH3fRivUF3z0JBFrU0U6iBNC/4WR+2rLKhaAhPWDNPYp4mI6RqdQ==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.1.0", + "magic-string": "^0.25.7" + } + }, + "@rollup/plugin-typescript": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-6.1.0.tgz", + "integrity": "sha512-hJxaiE6WyNOsK+fZpbFh9CUijZYqPQuAOWO5khaGTUkM8DYNNyA2TDlgamecE+qLOG1G1+CwbWMAx3rbqpp6xQ==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.1.0", + "resolve": "^1.17.0" + } + }, + "@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "requires": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "dependencies": { + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + } + } + }, + "@sinonjs/commons": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", + "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/formatio": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz", + "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^3.1.0" + } + }, + "@sinonjs/samsam": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", + "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.3.0", + "array-from": "^2.1.1", + "lodash": "^4.17.15" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true + }, + "@tsconfig/svelte": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-1.0.10.tgz", + "integrity": "sha512-EBrpH2iXXfaf/9z81koiDYkp2mlwW2XzFcAqn6qh7VKyP8zBvHHAQzNhY+W9vH5arAjmGAm5g8ElWq6YmXm3ig==", + "dev": true + }, + "@types/cookie": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz", + "integrity": "sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow==", + "dev": true + }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "@types/node": { + "version": "14.14.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.17.tgz", + "integrity": "sha512-G0lD1/7qD60TJ/mZmhog76k7NcpLWkPVGgzkRy3CTlnFu4LUQh5v2Wa661z6vnXmD8EQrnALUyf0VRtrACYztw==", + "dev": true + }, + "@types/pug": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.4.tgz", + "integrity": "sha1-h3L80EGOPNLMFxVV1zAHQVBR9LI=", + "dev": true + }, + "@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/sass": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@types/sass/-/sass-1.16.0.tgz", + "integrity": "sha512-2XZovu4NwcqmtZtsBR5XYLw18T8cBCnU2USFHTnYLLHz9fkhnoEMoDsqShJIOFsFhn5aJHjweiUUdTrDGujegA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dev": true, + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "amazon-cognito-identity-js": { + "version": "4.5.6", + "resolved": "https://registry.npmjs.org/amazon-cognito-identity-js/-/amazon-cognito-identity-js-4.5.6.tgz", + "integrity": "sha512-TdzE4hkBybBCE4waoZysfSxj3zl908XN8ojBdiurq2wv0dEVLsY7zGBFakVuQB/CDYM1QF2/y3q2rHbCPklnOA==", + "dev": true, + "requires": { + "buffer": "4.9.1", + "crypto-js": "^3.3.0", + "fast-base64-decode": "^1.0.0", + "isomorphic-unfetch": "^3.0.0", + "js-cookie": "^2.2.1" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", + "dev": true + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "array-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", + "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", + "dev": true + }, + "async": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", + "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=", + "dev": true + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "aws-amplify": { + "version": "3.3.13", + "resolved": "https://registry.npmjs.org/aws-amplify/-/aws-amplify-3.3.13.tgz", + "integrity": "sha512-w8y+CGRmciLxPXPbdAa1yeMYSgl33YyXN3+m2Bv8rbp9d7e4pt2E7Fn6KtVLONTCxH+opMtdO8Qu3lAUxPVUXg==", + "dev": true, + "requires": { + "@aws-amplify/analytics": "4.0.4", + "@aws-amplify/api": "3.2.16", + "@aws-amplify/auth": "3.4.16", + "@aws-amplify/cache": "3.1.41", + "@aws-amplify/core": "3.8.8", + "@aws-amplify/datastore": "2.9.2", + "@aws-amplify/interactions": "3.3.16", + "@aws-amplify/predictions": "3.2.16", + "@aws-amplify/pubsub": "3.2.14", + "@aws-amplify/storage": "3.3.16", + "@aws-amplify/ui": "2.0.2", + "@aws-amplify/xr": "2.2.16" + } + }, + "axios": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.0.tgz", + "integrity": "sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==", + "dev": true, + "requires": { + "follow-redirects": "1.5.10", + "is-buffer": "^2.0.2" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "buffer": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + } + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "builtin-modules": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", + "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", + "dev": true + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "dev": true + }, + "cache-content-type": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz", + "integrity": "sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==", + "dev": true, + "requires": { + "mime-types": "^2.1.18", + "ylru": "^1.2.0" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chokidar": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", + "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "colorette": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz", + "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==", + "dev": true + }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "console-clear": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/console-clear/-/console-clear-1.1.1.tgz", + "integrity": "sha512-pMD+MVR538ipqkG5JXeOEbKWS5um1H4LUUccUQG68qpeqBYbzYy79Gh55jkd2TtPdRfUaLWdv6LPP//5Zt0aPQ==" + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "dev": true + }, + "cookies": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.8.0.tgz", + "integrity": "sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==", + "dev": true, + "requires": { + "depd": "~2.0.0", + "keygrip": "~1.1.0" + }, + "dependencies": { + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + } + } + }, + "crypto-js": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz", + "integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==", + "dev": true + }, + "cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=", + "dev": true + }, + "date-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/date-time/-/date-time-3.1.0.tgz", + "integrity": "sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==", + "dev": true, + "requires": { + "time-zone": "^1.0.0" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", + "dev": true + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "detect-indent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz", + "integrity": "sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==", + "dev": true + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, + "es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, + "events": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", + "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==", + "dev": true + }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", + "dev": true + }, + "fa-svelte": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fa-svelte/-/fa-svelte-3.1.0.tgz", + "integrity": "sha512-RqBOWwt7sc+ta9GFjbu5GOwKFRzn3rMPPSqvSGpIwsfVnpMjiI5ttv84lwNsCMEYI6/lu/iH21HUcE3TLz8RGQ==", + "dev": true + }, + "fast-base64-decode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz", + "integrity": "sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==", + "dev": true + }, + "fast-xml-parser": { + "version": "3.17.6", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-3.17.6.tgz", + "integrity": "sha512-40WHI/5d2MOzf1sD2bSaTXlPn1lueJLAX6j1xH5dSAr6tNeut8B9ktEL6sjAK9yVON4uNj9//axOdBJUuruCzw==", + "dev": true + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "dev": true, + "requires": { + "debug": "=3.1.0" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=" + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "graphql": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.0.0.tgz", + "integrity": "sha512-HGVcnO6B25YZcSt6ZsH6/N+XkYuPA7yMqJmlJ4JWxWlS4Tr8SHI56R1Ocs8Eor7V7joEZPRXPDH8RRdll1w44Q==", + "dev": true, + "requires": { + "iterall": "^1.2.2" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "http-assert": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.4.1.tgz", + "integrity": "sha512-rdw7q6GTlibqVVbXr0CKelfV5iY8G2HqEUkhSk297BMbSpSL8crXC+9rjKoMcZZEsksX30le6f/4ul4E28gegw==", + "dev": true, + "requires": { + "deep-equal": "~1.0.1", + "http-errors": "~1.7.2" + }, + "dependencies": { + "http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + } + } + }, + "http-errors": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.0.tgz", + "integrity": "sha512-4I8r0C5JDhT5VkvI47QktDW75rNlGVsUf/8hzjCC/wkWI/jdTRmBb9aI7erSG82r1bjKY3F6k28WnsVxB1C73A==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "dependencies": { + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + } + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "idb": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/idb/-/idb-5.0.6.tgz", + "integrity": "sha512-/PFvOWPzRcEPmlDt5jEvzVZVs0wyd/EvGvkDIcbBpGuMMLQKrTPG0TxvE2UJtgZtCQCmOtM2QD7yQJBVEjKGOw==", + "dev": true + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "immer": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-6.0.1.tgz", + "integrity": "sha512-oXwigCKgznQywsXi1VgrqgWbQEU3wievNCVc4Fcwky6mwXU6YHj6JuYp0WEM/B1EphkqsLr0x18lm5OiuemPcA==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true + }, + "is-core-module": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-generator-function": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.8.tgz", + "integrity": "sha512-2Omr/twNtufVZFr1GhxjOMFPAj2sjc/dKaIqBhvo4qciXfJmITGH6ZGd8eZYNHza8t1y0e01AuqRhJwfWp26WQ==", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "requires": { + "@types/estree": "*" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "isomorphic-unfetch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz", + "integrity": "sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==", + "dev": true, + "requires": { + "node-fetch": "^2.6.1", + "unfetch": "^4.2.0" + } + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "iterall": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz", + "integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==", + "dev": true + }, + "jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-cookie": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz", + "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "just-extend": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.1.tgz", + "integrity": "sha512-aWgeGFW67BP3e5181Ep1Fv2v8z//iBJfrvyTnq8wG86vEESwmonn1zPBJ0VfmT9CJq2FIT0VsETtrNFm2a+SHA==", + "dev": true + }, + "keygrip": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", + "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==", + "dev": true, + "requires": { + "tsscmp": "1.0.6" + } + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + }, + "koa": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/koa/-/koa-2.13.0.tgz", + "integrity": "sha512-i/XJVOfPw7npbMv67+bOeXr3gPqOAw6uh5wFyNs3QvJ47tUx3M3V9rIE0//WytY42MKz4l/MXKyGkQ2LQTfLUQ==", + "dev": true, + "requires": { + "accepts": "^1.3.5", + "cache-content-type": "^1.0.0", + "content-disposition": "~0.5.2", + "content-type": "^1.0.4", + "cookies": "~0.8.0", + "debug": "~3.1.0", + "delegates": "^1.0.0", + "depd": "^1.1.2", + "destroy": "^1.0.4", + "encodeurl": "^1.0.2", + "escape-html": "^1.0.3", + "fresh": "~0.5.2", + "http-assert": "^1.3.0", + "http-errors": "^1.6.3", + "is-generator-function": "^1.0.7", + "koa-compose": "^4.1.0", + "koa-convert": "^1.2.0", + "on-finished": "^2.3.0", + "only": "~0.0.2", + "parseurl": "^1.3.2", + "statuses": "^1.5.0", + "type-is": "^1.6.16", + "vary": "^1.1.2" + } + }, + "koa-better-http-proxy": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/koa-better-http-proxy/-/koa-better-http-proxy-0.2.5.tgz", + "integrity": "sha512-HCVidGuAsYwtYeNJmfhdIZSwr8ak48qAwqvP7++dpUIpta+0Z2iWiwkVgDzqymCyo7hUUSd5Yu0XU70dAh2h8A==", + "dev": true, + "requires": { + "es6-promise": "^3.3.1", + "raw-body": "^2.2.0", + "winston": "^2.3.1" + } + }, + "koa-compose": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-4.1.0.tgz", + "integrity": "sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==", + "dev": true + }, + "koa-convert": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/koa-convert/-/koa-convert-1.2.0.tgz", + "integrity": "sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA=", + "dev": true, + "requires": { + "co": "^4.6.0", + "koa-compose": "^3.0.0" + }, + "dependencies": { + "koa-compose": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-3.2.1.tgz", + "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=", + "dev": true, + "requires": { + "any-promise": "^1.1.0" + } + } + } + }, + "koa-mount": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/koa-mount/-/koa-mount-4.0.0.tgz", + "integrity": "sha512-rm71jaA/P+6HeCpoRhmCv8KVBIi0tfGuO/dMKicbQnQW/YJntJ6MnnspkodoA4QstMVEZArsCphmd0bJEtoMjQ==", + "dev": true, + "requires": { + "debug": "^4.0.1", + "koa-compose": "^4.1.0" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "koa-route": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/koa-route/-/koa-route-3.2.0.tgz", + "integrity": "sha1-dimLmaa8+p44yrb+XHmocz51i84=", + "dev": true, + "requires": { + "debug": "*", + "methods": "~1.1.0", + "path-to-regexp": "^1.2.0" + } + }, + "koa-send": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/koa-send/-/koa-send-5.0.1.tgz", + "integrity": "sha512-tmcyQ/wXXuxpDxyNXv5yNNkdAMdFRqwtegBXUaowiQzUKqJehttS0x2j0eOZDQAyloAth5w6wwBImnFzkUz3pQ==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "http-errors": "^1.7.3", + "resolve-path": "^1.4.0" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "koa-static": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/koa-static/-/koa-static-5.0.0.tgz", + "integrity": "sha512-UqyYyH5YEXaJrf9S8E23GoJFQZXkBVJ9zYYMPGz919MSX1KuvAcycIuS0ci150HCoPf4XQVhQ84Qf8xRPWxFaQ==", + "dev": true, + "requires": { + "debug": "^3.1.0", + "koa-send": "^5.0.0" + } + }, + "livereload": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/livereload/-/livereload-0.9.1.tgz", + "integrity": "sha512-9g7sua11kkyZNo2hLRCG3LuZZwqexoyEyecSlV8cAsfAVVCZqLzVir6XDqmH0r+Vzgnd5LrdHDMyjtFnJQLAYw==", + "dev": true, + "requires": { + "chokidar": "^3.3.0", + "livereload-js": "^3.1.0", + "opts": ">= 1.2.0", + "ws": "^6.2.1" + } + }, + "livereload-js": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-3.3.1.tgz", + "integrity": "sha512-CBu1gTEfzVhlOK1WASKAAJ9Qx1fHECTq0SUB67sfxwQssopTyvzqTlgl+c0h9pZ6V+Fzd2rc510ppuNusg9teQ==", + "dev": true + }, + "local-access": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/local-access/-/local-access-1.1.0.tgz", + "integrity": "sha512-XfegD5pyTAfb+GY6chk283Ox5z8WexG56OvM06RWLpAc/UHozO8X6xAxEkIitZOtsSMM1Yr3DkHgW5W+onLhCw==" + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, + "lodash-es": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.20.tgz", + "integrity": "sha512-JD1COMZsq8maT6mnuz1UMV0jvYD0E0aUsSOdrr1/nAG3dhqQXwRRgeW0cSqH1U43INKcqxaiVIQNOUDld7gRDA==", + "dev": true + }, + "lolex": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz", + "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==", + "dev": true + }, + "magic-string": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", + "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "mime": { + "version": "2.4.7", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.7.tgz", + "integrity": "sha512-dhNd1uA2u397uQk3Nv5LM4lm93WYDUXFn3Fu291FJerns4jyTudqhIWe4W04YLy7Uk1tm1Ore04NpjRvQp/NPA==" + }, + "mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "dev": true + }, + "mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "dev": true, + "requires": { + "mime-db": "1.44.0" + } + }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mri": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.6.tgz", + "integrity": "sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ==" + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "dev": true + }, + "nise": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.3.tgz", + "integrity": "sha512-Ymbac/94xeIrMf59REBPOv0thr+CJVFMhrlAkW/gjCIE58BGQdCj0x7KRCb3yz+Ga2Rz3E9XXSvUyyxqqhjQAQ==", + "dev": true, + "requires": { + "@sinonjs/formatio": "^3.2.1", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "lolex": "^5.0.1", + "path-to-regexp": "^1.7.0" + }, + "dependencies": { + "lolex": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", + "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + } + } + }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "only": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/only/-/only-0.0.2.tgz", + "integrity": "sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q=", + "dev": true + }, + "opts": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/opts/-/opts-2.0.2.tgz", + "integrity": "sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg==", + "dev": true + }, + "paho-mqtt": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/paho-mqtt/-/paho-mqtt-1.1.0.tgz", + "integrity": "sha512-KPbL9KAB0ASvhSDbOrZBaccXS+/s7/LIofbPyERww8hM5Ko71GUJQ6Nmg0BWqj8phAIT8zdf/Sd/RftHU9i2HA==", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "requires": { + "isarray": "0.0.1" + } + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "raw-body": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.1.tgz", + "integrity": "sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.3", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + } + } + }, + "react-native-get-random-values": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/react-native-get-random-values/-/react-native-get-random-values-1.5.0.tgz", + "integrity": "sha512-LK+Wb8dEimJkd/dub7qziDmr9Tw4chhpzVeQ6JDo4czgfG4VXbptRyOMdu8503RiMF6y9pTH6ZUTkrrpprqT7w==", + "dev": true, + "requires": { + "fast-base64-decode": "^1.0.0" + } + }, + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "require-relative": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", + "integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=", + "dev": true + }, + "resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "requires": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "resolve-path": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/resolve-path/-/resolve-path-1.4.0.tgz", + "integrity": "sha1-xL2p9e+y/OZSR4c6s2u02DT+Fvc=", + "dev": true, + "requires": { + "http-errors": "~1.6.2", + "path-is-absolute": "1.0.1" + }, + "dependencies": { + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + } + } + }, + "rollup": { + "version": "2.35.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.35.1.tgz", + "integrity": "sha512-q5KxEyWpprAIcainhVy6HfRttD9kutQpHbeqDTWnqAFNJotiojetK6uqmcydNMymBEtC4I8bCYR+J3mTMqeaUA==", + "dev": true, + "requires": { + "fsevents": "~2.1.2" + } + }, + "rollup-plugin-css-only": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-css-only/-/rollup-plugin-css-only-3.1.0.tgz", + "integrity": "sha512-TYMOE5uoD76vpj+RTkQLzC9cQtbnJNktHPB507FzRWBVaofg7KhIqq1kGbcVOadARSozWF883Ho9KpSPKH8gqA==", + "dev": true, + "requires": { + "@rollup/pluginutils": "4" + }, + "dependencies": { + "@rollup/pluginutils": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.1.0.tgz", + "integrity": "sha512-TrBhfJkFxA+ER+ew2U2/fHbebhLT/l/2pRk0hfj9KusXUuRXd2v0R58AfaZK9VXDQ4TogOSEmICVrQAA3zFnHQ==", + "dev": true, + "requires": { + "estree-walker": "^2.0.1", + "picomatch": "^2.2.2" + } + } + } + }, + "rollup-plugin-dev": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/rollup-plugin-dev/-/rollup-plugin-dev-1.1.3.tgz", + "integrity": "sha512-HHdbEPx8MxF8N0mClfFL7peZATExFIBqdl97F4Sa3sx4lotnSqSO+HtFDCgHJ3aNK12jXFpuohQkXfX7fudJYg==", + "dev": true, + "requires": { + "colorette": "^1.2.1", + "date-time": "^3.1.0", + "koa": "^2.13.0", + "koa-better-http-proxy": "^0.2.5", + "koa-mount": "^4.0.0", + "koa-route": "^3.2.0", + "koa-send": "^5.0.1", + "koa-static": "^5.0.0", + "ms": "^2.1.2" + } + }, + "rollup-plugin-livereload": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-livereload/-/rollup-plugin-livereload-2.0.0.tgz", + "integrity": "sha512-oC/8NqumGYuphkqrfszOHUUIwzKsaHBICw6QRwT5uD07gvePTS+HW+GFwu6f9K8W02CUuTvtIM9AWJrbj4wE1A==", + "dev": true, + "requires": { + "livereload": "^0.9.1" + } + }, + "rollup-plugin-svelte": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-svelte/-/rollup-plugin-svelte-7.0.0.tgz", + "integrity": "sha512-cw4yv/5v1NQV3nPbpOJtikgkB+9mfSJaqKUdq7x5fVQJnwLtcdc2JOszBs5pBY+SemTs5pmJbdEMseEavbUtjQ==", + "dev": true, + "requires": { + "require-relative": "^0.8.7", + "rollup-pluginutils": "^2.8.2" + } + }, + "rollup-plugin-terser": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", + "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "jest-worker": "^26.2.1", + "serialize-javascript": "^4.0.0", + "terser": "^5.0.0" + } + }, + "rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "dev": true, + "requires": { + "estree-walker": "^0.6.1" + }, + "dependencies": { + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + } + } + }, + "sade": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.7.4.tgz", + "integrity": "sha512-y5yauMD93rX840MwUJr7C1ysLFBgMspsdTo4UVrDg3fXDvtwOyIqykhVAAm6fk/3au77773itJStObgK+LKaiA==", + "requires": { + "mri": "^1.1.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "semiver": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/semiver/-/semiver-1.1.0.tgz", + "integrity": "sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg==" + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, + "sinon": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.5.0.tgz", + "integrity": "sha512-AoD0oJWerp0/rY9czP/D6hDTTUYGpObhZjMpd7Cl/A6+j0xBE+ayL/ldfggkBXUs0IkvIiM1ljM8+WkOc5k78Q==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.4.0", + "@sinonjs/formatio": "^3.2.1", + "@sinonjs/samsam": "^3.3.3", + "diff": "^3.5.0", + "lolex": "^4.2.0", + "nise": "^1.5.2", + "supports-color": "^5.5.0" + } + }, + "sirv": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.10.tgz", + "integrity": "sha512-H5EZCoZaggEUQy8ocKsF7WAToGuZhjJlLvM3XOef46CbdIgbNeQ1p32N1PCuCjkVYwrAVOSMacN6CXXgIzuspg==", + "requires": { + "@polka/url": "^1.0.0-next.9", + "mime": "^2.3.1", + "totalist": "^1.0.0" + } + }, + "sirv-cli": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/sirv-cli/-/sirv-cli-1.0.10.tgz", + "integrity": "sha512-8mLTRkvzpZXMyUZJ1whf84YHN/mm2r2+j5sU1ZYr5n2jA8VkFItNPk53oysOo+0QxBVp9aUjggkAsQp1d7L3OQ==", + "requires": { + "console-clear": "^1.1.0", + "get-port": "^3.2.0", + "kleur": "^3.0.0", + "local-access": "^1.0.1", + "sade": "^1.6.0", + "semiver": "^1.0.0", + "sirv": "^1.0.10", + "tinydate": "^1.0.0" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "requires": { + "min-indent": "^1.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "svelte": { + "version": "3.31.0", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.31.0.tgz", + "integrity": "sha512-r+n8UJkDqoQm1b+3tA3Lh6mHXKpcfOSOuEuIo5gE2W9wQYi64RYX/qE6CZBDDsP/H4M+N426JwY7XGH4xASvGQ==", + "dev": true + }, + "svelte-calendar": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svelte-calendar/-/svelte-calendar-2.0.4.tgz", + "integrity": "sha512-a9TGBCc17qrvgdO79py2whwvtgaZzOHiMMygc2aNyYzETQI/H60g3kmHyq+llDf+wSEFWqy0LO71rBrzBCfRFA==", + "dev": true, + "requires": { + "timeUtils": "^2.0.0" + } + }, + "svelte-check": { + "version": "1.1.23", + "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-1.1.23.tgz", + "integrity": "sha512-mPIUStnwCn1PUG9Ps4shy5w46IbPXMhKigWlrfyNwV6SyDYGM+qT/DEf7+J30v47DzW3iTeR70cQu/C72IOh2g==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "chokidar": "^3.4.1", + "glob": "^7.1.6", + "import-fresh": "^3.2.1", + "minimist": "^1.2.5", + "source-map": "^0.7.3", + "svelte-preprocess": "^4.0.0", + "typescript": "*" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "svelte-preprocess": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-4.6.1.tgz", + "integrity": "sha512-s7KdhR2pOsffyOzZIMEb315f6pfgeDnOWN47m6YKFeSEx3NMf/79Znc3vuG/Ai79SL/vsi86WDrjFPLGRfDesg==", + "dev": true, + "requires": { + "@types/pug": "^2.0.4", + "@types/sass": "^1.16.0", + "detect-indent": "^6.0.0", + "strip-indent": "^3.0.0" + } + }, + "svelte-routing": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/svelte-routing/-/svelte-routing-1.4.2.tgz", + "integrity": "sha512-CSCKRLeOp9vjsDGGOEgL9DPm9HZLgZuTNehyTCl3K+6fCVH1Aw/K/WicavAVNcbsHmdR4wgF//0YVR9hrcdvGA==", + "dev": true + }, + "svelte-time-picker": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/svelte-time-picker/-/svelte-time-picker-1.0.6.tgz", + "integrity": "sha512-hiPxf9XTktCbFxgfbRytM5od+VwDSMnih6UKhg1onSPIQA+J92yM/9i45dPlYWA5ihvxAA1sfU84gZ2HpEH9sQ==", + "dev": true + }, + "terser": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.5.1.tgz", + "integrity": "sha512-6VGWZNVP2KTUcltUQJ25TtNjx/XgdDsBDKGt8nN0MpydU36LmbPPcMBd2kmtZNNGVVDLg44k7GKeHHj+4zPIBQ==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.7.2", + "source-map-support": "~0.5.19" + } + }, + "time-zone": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-1.0.0.tgz", + "integrity": "sha1-mcW/VZWJZq9tBtg73zgA3IL67F0=", + "dev": true + }, + "timeUtils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/timeUtils/-/timeUtils-2.0.0.tgz", + "integrity": "sha512-rk1y/5ix4HczK3q4caEvo2iIhgRIHL6g85sX2rPNse8sKUATzYEAX1jAYYsW139aAcn1b24jV4By0SLmosQVyA==", + "dev": true + }, + "tinydate": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tinydate/-/tinydate-1.3.0.tgz", + "integrity": "sha512-7cR8rLy2QhYHpsBDBVYnnWXm8uRTr38RoZakFSW7Bs7PzfMPNZthuMLkwqZv7MTu8lhQ91cOFYS5a7iFj2oR3w==" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true + }, + "totalist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", + "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==" + }, + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==", + "dev": true + }, + "tsscmp": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", + "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==", + "dev": true + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typescript": { + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", + "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", + "dev": true + }, + "ulid": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ulid/-/ulid-2.3.0.tgz", + "integrity": "sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw==", + "dev": true + }, + "unfetch": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz", + "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==", + "dev": true + }, + "universal-cookie": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/universal-cookie/-/universal-cookie-4.0.4.tgz", + "integrity": "sha512-lbRVHoOMtItjWbM7TwDLdl8wug7izB0tq3/YVKhT/ahB4VDvWMyvnADfnJI8y6fSvsjh51Ix7lTGC6Tn4rMPhw==", + "dev": true, + "requires": { + "@types/cookie": "^0.3.3", + "cookie": "^0.4.0" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "winston": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.5.tgz", + "integrity": "sha512-TWoamHt5yYvsMarGlGEQE59SbJHqGsZV8/lwC+iCcGeAe0vUaOh+Lv6SYM17ouzC/a/LB1/hz/7sxFBtlu1l4A==", + "dev": true, + "requires": { + "async": "~1.0.0", + "colors": "1.0.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "stack-trace": "0.0.x" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + }, + "ylru": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ylru/-/ylru-1.2.1.tgz", + "integrity": "sha512-faQrqNMzcPCHGVC2aaOINk13K+aaBDUPjGWl0teOXywElLjyVAB6Oe2jj62jHYtwsU49jXhScYbvPENK+6zAvQ==", + "dev": true + }, + "zen-observable": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz", + "integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==", + "dev": true + }, + "zen-observable-ts": { + "version": "0.8.19", + "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.19.tgz", + "integrity": "sha512-u1a2rpE13G+jSzrg3aiCqXU5tN2kw41b+cBZGmnc+30YimdkKiDj9bTowcB41eL77/17RF/h+393AuVgShyheQ==", + "dev": true, + "requires": { + "tslib": "^1.9.3", + "zen-observable": "^0.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "zen-push": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/zen-push/-/zen-push-0.2.1.tgz", + "integrity": "sha512-Qv4qvc8ZIue51B/0zmeIMxpIGDVhz4GhJALBvnKs/FRa2T7jy4Ori9wFwaHVt0zWV7MIFglKAHbgnVxVTw7U1w==", + "dev": true, + "requires": { + "zen-observable": "^0.7.0" + }, + "dependencies": { + "zen-observable": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.7.1.tgz", + "integrity": "sha512-OI6VMSe0yeqaouIXtedC+F55Sr6r9ppS7+wTbSexkYdHbdt4ctTuPNXP/rwm7GTVI63YBc+EBT0b0tl7YnJLRg==", + "dev": true + } + } + } + } +} diff --git a/svelte-ui/package.json b/svelte-ui/package.json new file mode 100644 index 0000000..74f16a3 --- /dev/null +++ b/svelte-ui/package.json @@ -0,0 +1,43 @@ +{ + "name": "@gisle/stufflog2-svelte-ui", + "version": "0.0.1", + "private": true, + "scripts": { + "build": "rollup -c", + "dev": "rollup -c -w", + "start": "sirv public", + "validate": "svelte-check" + }, + "devDependencies": { + "@fortawesome/free-solid-svg-icons": "^5.15.1", + "@rollup/plugin-alias": "^3.1.1", + "@rollup/plugin-commonjs": "^16.0.0", + "@rollup/plugin-json": "^4.1.0", + "@rollup/plugin-node-resolve": "^10.0.0", + "@rollup/plugin-replace": "^2.3.4", + "@rollup/plugin-typescript": "^6.0.0", + "@tsconfig/svelte": "^1.0.0", + "@types/node": "^14.14.17", + "amazon-cognito-identity-js": "^4.5.6", + "aws-amplify": "^3.3.13", + "fa-svelte": "^3.1.0", + "lodash-es": "^4.17.20", + "rollup": "^2.3.4", + "rollup-plugin-css-only": "^3.1.0", + "rollup-plugin-dev": "^1.1.3", + "rollup-plugin-livereload": "^2.0.0", + "rollup-plugin-svelte": "^7.0.0", + "rollup-plugin-terser": "^7.0.0", + "svelte": "^3.0.0", + "svelte-calendar": "^2.0.4", + "svelte-check": "^1.0.0", + "svelte-preprocess": "^4.0.0", + "svelte-routing": "^1.4.2", + "svelte-time-picker": "^1.0.6", + "tslib": "^2.0.0", + "typescript": "^3.9.3" + }, + "dependencies": { + "sirv-cli": "^1.0.0" + } +} diff --git a/svelte-ui/public/favicon.png b/svelte-ui/public/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..7e6f5eb5a2f1f1c882d265cf479de25caa925645 GIT binary patch literal 3127 zcmV-749N3|P)i z7)}s4L53SJCkR}iVi00SFk;`MXX*#X*kkwKs@nFGS}c;=?XFjU|G$3t^5sjIVS2G+ zw)WGF83CpoGXhLGW(1gW%uV|X7>1P6VhCX=Ux)Lb!*DZ%@I3!{Gsf7d?gtIQ%nQiK z3%(LUSkBji;C5Rfgd6$VsF@H`Pk@xtY6t<>FNR-pD}=C~$?)9pdm3XZ36N5PNWYjb z$xd$yNQR9N!dfj-Vd@BwQo^FIIWPPmT&sZyQ$v81(sCBV=PGy{0wltEjB%~h157*t zvbe_!{=I_783x!0t1-r#-d{Y?ae$Q4N_Nd^Ui^@y(%)Gjou6y<3^XJdu{rmUf-Me?)zZ>9OR&6U5H*cK; z$gUlB{g0O4gN0sLSO|Of?hU(l?;h(jA3uH!Z{EBKuV23ouU@^Y6#%v+QG;>e*E}%?wlu-NT4DG zs)z)7WbLr)vGAu(ohrKc^em@OpO&f~6_>E61n_e0_V3@{U3^O;j{`^mNCJUj_>;7v zsMs6Hu3g7+@v+lSo;=yTYFqq}jZmQ-BK8K{C4kqi_i*jBaQE(Au0607V-zKeT;EPg zX(`vrn=L+e74+-Tqeok@_`tDa$G9I|$nTU5H*2V8@y()n*zqM?J1G!-1aX;CfDC9B zTnJ#j_%*n8Qb1)re*Bno7g0RG{Eb;IK14irJYJp$5Z6ac9~b_P?+5t~95~SRG$g?1 znFJ7p$xV&GZ18m~79TGRdfsc-BcX$9yXTR*n)mPD@1~O(_?cT$ZvFPucRmGlq&se0 zKrcUf^k}4hM*biEJOWKzz!qQe;CB_ZtSOO9Owg#lZAc=s65^rb{fZe(TYu_rk!wKkEf}RIt=#Om( zR8mN`DM<^xj~59euMMspBolVN zAPTr8sSDI104orIAdmL$uOXn*6hga1G+0WD0E?UtabxC#VC~vf3|10|phW;yQ3CY8 z2CM=)ErF;xq-YJ5G|um}>*1#E+O_Mu|Nr#qQ&G1P-NMq@f?@*XUcSbV?tX=)ilM-Q zBZP|!Bpv0V;#ojKcpc7$=eqO;#Uy~#?^kNI{vSZfLx&DEt~LTmaKWXcx=joubklI<*Aw z>LtMaQ7DR<1I2LkWvwyu#Rwn~;ezT}_g(@5l3h?W%-a86Y-t#O1PubP+z<%?V5D(U zy57A6{h+{?kOZp7&WKZR+=sznMJ}+Dnpo=C_0%R_x_t~J5T?E_{+))l5v1%52>)d-`iiZyx|5!%M2Fb2dU zW3~MwwpEH9Rhue+k$UIOoo($Ds!NbOyMR36fRHu;*15(YcA7siIZk#%JWz>P!qX1?IUojG&nKR>^gArBt2 zit(ETyZ=@V&7mv_Fi4bABcnwP+jzQuHcfU&BrAV91u-rFvEi7y-KnWsvHH=d2 zgAk(GKm_S8RcTJ>2N3~&Hbwp{Z3NF_Xeh}g4Eke)V&dY{W(3&b1j9t4yK_aYJisZZ{1rcU5- z;eD>K;ndPq&B-8yA_S0F!4ThA&{1{x)H<#?k9a#6Pc6L?V^s0``ynL&D;p(!Nmx`Y zFkHex{4p!Ggm^@DlehW}iHHVi}~u=$&N? z(NEBLQ#UxxAkdW>X9LnqUr#t4Lu0=9L8&o>JsqTtT5|%gb3QA~hr0pED71+iFFr)dZ=Q=E6ng{NE{Z~0)C?deO#?Aj zSDQ$z#TeC2T^|=}6GBo-&$;E{HL3!q3Z-szuf)O=G#zDjin4SSP%o%6+2IT#sLjQa ziyxFFz~LMjWY+_a5H!U6%a<=b7QVP^ z*90a62;bVq{?@)P6^DWd^Yilq4|YTV2Nw!Yu;a1lPI-sxR)rf@Fe5DhDP7FH zZZ%4S*1C30P;|O+jB!1;m|rXT90Sm5*RBbQN`PKu+hDD*S^yE(CdtSfg=z>u$cIj> z + + + + + + Svelte app + + + + + + + + + + diff --git a/svelte-ui/rollup.config.js b/svelte-ui/rollup.config.js new file mode 100644 index 0000000..d409155 --- /dev/null +++ b/svelte-ui/rollup.config.js @@ -0,0 +1,99 @@ +import fs from "fs"; + +import svelte from "rollup-plugin-svelte"; +import commonjs from "@rollup/plugin-commonjs"; +import resolve from "@rollup/plugin-node-resolve"; +import livereload from "rollup-plugin-livereload"; +import { terser } from "rollup-plugin-terser"; +import sveltePreprocess from "svelte-preprocess"; +import typescript from "@rollup/plugin-typescript"; +import css from "rollup-plugin-css-only"; +import dev from "rollup-plugin-dev"; +import replace from "@rollup/plugin-replace"; +import json from "@rollup/plugin-json"; + +const production = !process.env.ROLLUP_WATCH; +const envVariables = fs.readFileSync("build.env", "utf-8") + .split("\n") + .filter(l => l.length > 0) + .map(l => l.trim().split("=")) + .reduce((p, [key, value]) => ({...p, [key]: value}), {}); + +export default { + input: "src/main.ts", + output: { + sourcemap: true, + format: "iife", + name: "app", + file: "public/build/bundle.js" + }, + plugins: [ + svelte({ + preprocess: sveltePreprocess(), + compilerOptions: { + // enable run-time checks when not in production + dev: !production + } + }), + // we"ll extract any component CSS out into + // a separate file - better for performance + css({ output: "bundle.css" }), + + // If you have external dependencies installed from + // npm, you'll most likely need these plugins. In + // some cases you'll need additional configuration - + // consult the documentation for details: + // https://github.com/rollup/plugins/tree/master/packages/commonjs + resolve({ + browser: true, + preferBuiltins: false, + dedupe: ["svelte"], + }), + json(), + commonjs({ + include: 'node_modules/**', + }), + typescript({ + sourceMap: !production, + inlineSources: !production + }), + + replace({ + // 2 level deep object should be stringify + "process.env": JSON.stringify({ + NODE_ENV: production ? "production" : "development", + ...envVariables, + }), + }), + + // Watch the `public` directory and refresh the + // browser on changes when not in production + !production && livereload("public"), + + // Add dev server in development. + !production && dev({ + dirs: ["public"], + spa: "public/index.html", + port: 5000, + proxy: { + "/api/*": "localhost:8000", + }, + }), + + // If we're building for production (npm run build + // instead of npm run dev), minify + production && terser({ + output: { comments: false }, + }) + ], + watch: { + clearScreen: false + }, + onwarn: function(warning) { + // Skip certain warnings + if ( warning.code === "THIS_IS_UNDEFINED" ) { return; } + + // console.warn everything else + console.warn( warning.message ); + } +}; diff --git a/svelte-ui/src/App.svelte b/svelte-ui/src/App.svelte new file mode 100644 index 0000000..3dea91e --- /dev/null +++ b/svelte-ui/src/App.svelte @@ -0,0 +1,77 @@ + + +{#if $authStore.checked} + {#if $authStore.loggedIn} + + +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + {:else} + + {/if} +{/if} + + \ No newline at end of file diff --git a/svelte-ui/src/clients/amplify.ts b/svelte-ui/src/clients/amplify.ts new file mode 100644 index 0000000..c3a7b46 --- /dev/null +++ b/svelte-ui/src/clients/amplify.ts @@ -0,0 +1,46 @@ +import Amplify from "@aws-amplify/core"; +import Auth from "@aws-amplify/auth"; +import type {CognitoAccessToken, CognitoUser} from "amazon-cognito-identity-js"; + +Amplify.configure({ + Auth: { + region: process.env.AWS_AMPLIFY_REGION, + userPoolId: process.env.AWS_AMPLIFY_USER_POOL_ID, + userPoolWebClientId: process.env.AWS_AMPLIFY_USER_POOL_WEB_CLIENT_ID, + }, +}); + +export async function signIn(username: string, password: string): Promise { + const u = await Auth.signIn(username, password); + return u || null; +} + +export async function signOut(): Promise { + await Auth.signOut(); +} + +async function getAccessToken(): Promise { + try { + const u = await Auth.currentSession(); + if (!u || !u.isValid()) { + return null; + } + + return u.getAccessToken(); + } catch (e) { + return null; + } +} + +export async function getJwt(): Promise { + const token = await getAccessToken(); + if (!token) { + throw new Error("unauthorized"); + } + + return token.getJwtToken(); +} + +export async function checkSession(): Promise { + return !!(await getAccessToken()); +} diff --git a/svelte-ui/src/clients/stufflog.ts b/svelte-ui/src/clients/stufflog.ts new file mode 100644 index 0000000..9562c3d --- /dev/null +++ b/svelte-ui/src/clients/stufflog.ts @@ -0,0 +1,260 @@ +import { getJwt } from "./amplify"; +import type { GoalFilter, GoalInput, GoalResult, GoalUpdate } from "../models/goal"; +import type { ProjectFilter, ProjectInput, ProjectResult, ProjectUpdate } from "../models/project"; +import type { TaskInput, TaskResult, TaskUpdate } from "../models/task"; +import type { LogFilter, LogInput, LogResult, LogUpdate } from "../models/log"; +import type { GroupInput, GroupResult, GroupUpdate } from "../models/group"; +import type { ItemInput, ItemResult, ItemUpdate } from "../models/item"; + +export class StufflogClient { + private root: string; + + constructor(root: string) { + this.root = root; + } + + + + async findGoal(id: string): Promise { + const data = await this.fetch("GET", `/api/goal/${id}`); + return data.goal; + } + + async listGoals({minTime, maxTime, includesTime}: GoalFilter): Promise { + let queries = []; + if (minTime != null) { + queries.push(`minTime=${minTime.toISOString()}`); + } + if (maxTime != null) { + queries.push(`maxTime=${maxTime.toISOString()}`); + } + if (includesTime != null) { + queries.push(`includesTime=${includesTime.toISOString()}`); + } + + const query = queries.length > 0 ? `?${queries.join("&")}` : ""; + + const data = await this.fetch("GET", `/api/goal/${query}`); + return data.goals; + } + + async createGoal(input: GoalInput): Promise { + const data = await this.fetch("POST", "/api/goal/", input); + return data.goal; + } + + async updateGoal(id: string, update: GoalUpdate): Promise { + const data = await this.fetch("PUT", `/api/goal/${id}`, update); + return data.goal; + } + + async deleteGoal(id: string): Promise { + const data = await this.fetch("DELETE", `/api/goal/${id}`); + return data.goal; + } + + + + async findProject(id: string): Promise { + const data = await this.fetch("GET", `/api/project/${id}`); + return data.project; + } + + async listProjects({active, expiring}: ProjectFilter): Promise { + let queries = []; + if (active != null) { + queries.push(`active=${active}`); + } + if (expiring != null) { + queries.push(`expiring=${expiring}`); + } + + const query = queries.length > 0 ? `?${queries.join("&")}` : ""; + + const data = await this.fetch("GET", `/api/project/${query}`); + return data.projects; + } + + async createProject(input: ProjectInput): Promise { + const data = await this.fetch("POST", "/api/project/", input); + return data.project; + } + + async updateProject(id: string, update: ProjectUpdate): Promise { + const data = await this.fetch("PUT", `/api/project/${id}`, update); + return data.project; + } + + async deleteProject(id: string): Promise { + const data = await this.fetch("DELETE", `/api/project/${id}`); + return data.project; + } + + + + async findLog(id: string): Promise { + const data = await this.fetch("GET", `/api/log/${id}`); + return data.log; + } + + async listLogs({minTime, maxTime}: LogFilter): Promise { + let queries = []; + if (minTime != null) { + queries.push(`minTime=${minTime.toISOString()}`); + } + if (maxTime != null) { + queries.push(`maxTime=${maxTime.toISOString()}`); + } + + const query = queries.length > 0 ? `?${queries.join("&")}` : ""; + + const data = await this.fetch("GET", `/api/log/${query}`); + return data.logs; + } + + async createLog(input: LogInput): Promise { + const data = await this.fetch("POST", "/api/log/", input); + return data.log; + } + + async updateLog(id: string, update: LogUpdate): Promise { + const data = await this.fetch("PUT", `/api/log/${id}`, update); + return data.log; + } + + async deleteLog(id: string): Promise { + const data = await this.fetch("DELETE", `/api/log/${id}`); + return data.log; + } + + + + async findTask(id: string): Promise { + const data = await this.fetch("GET", `/api/task/${id}`); + return data.task; + } + + async listTasks(active?: boolean): Promise { + let query = (active != null) ? `?active=${active}` : ""; + + const data = await this.fetch("GET", `/api/task/${query}`); + return data.tasks; + } + + async createTask(input: TaskInput): Promise { + const data = await this.fetch("POST", "/api/task/", input); + return data.task; + } + + async updateTask(id: string, update: TaskUpdate): Promise { + const data = await this.fetch("PUT", `/api/task/${id}`, update); + return data.task; + } + + async deleteTask(id: string): Promise { + const data = await this.fetch("DELETE", `/api/task/${id}`); + return data.task; + } + + + + async findGroup(id: string): Promise { + const data = await this.fetch("GET", `/api/group/${id}`); + return data.group; + } + + async listGroups(): Promise { + const data = await this.fetch("GET", "/api/group/"); + return data.groups; + } + + async createGroup(input: GroupInput): Promise { + const data = await this.fetch("POST", "/api/group/", input); + return data.group; + } + + async updateGroup(id: string, update: GroupUpdate): Promise { + const data = await this.fetch("PUT", `/api/group/${id}`, update); + return data.group; + } + + async deleteGroup(id: string): Promise { + const data = await this.fetch("DELETE", `/api/group/${id}`); + return data.group; + } + + + + async findItem(id: string): Promise { + const data = await this.fetch("GET", `/api/item/${id}`); + return data.item; + } + + async listItems(): Promise { + const data = await this.fetch("GET", "/api/item/"); + return data.projects; + } + + async createItem(input: ItemInput): Promise { + const data = await this.fetch("POST", "/api/item/", input); + return data.item; + } + + async updateItem(id: string, update: ItemUpdate): Promise { + const data = await this.fetch("PUT", `/api/item/${id}`, update); + return data.item; + } + + async deleteItem(id: string): Promise { + const data = await this.fetch("DELETE", `/api/item/${id}`); + return data.item; + } + + + + async fetch(method: string, path: string, body?: object) { + const fullPath = this.root + path; + const req: RequestInit = {method, headers: {}} + + if (body != null) { + const data = new Blob([JSON.stringify(body)]) + + req.headers["Content-Type"] = req; + req.headers["Content-Length"] = data.size; + req.body = data; + } + + console.warn("AUTH SKIPPED, remember to change back in prod!") + req.headers["Authorization"] = `Bearer ${await getJwt()}`; + + const res = await fetch(fullPath, req); + if (!res.ok) { + if ((res.headers.get("Content-Type") || "").includes("application/json")) { + const data = await res.json(); + throw new StuffLogError(data.errorCode, data.errorMessage) + } else { + const text = await res.text(); + throw new StuffLogError(res.status, text) + } + } + + return res.json(); + } +} + +export class StuffLogError { + public code: number + public message: string + + constructor(code: number, message: string) { + this.code = code; + this.message = message; + } + + toString() { + return `Error ${this.code}: ${this.message}`; + } +} + +const stuffLogClient = new StufflogClient(""); +export default stuffLogClient \ No newline at end of file diff --git a/svelte-ui/src/components/Boi.svelte b/svelte-ui/src/components/Boi.svelte new file mode 100644 index 0000000..055a266 --- /dev/null +++ b/svelte-ui/src/components/Boi.svelte @@ -0,0 +1,53 @@ + + +
+ + \ No newline at end of file diff --git a/svelte-ui/src/components/DateSpan.svelte b/svelte-ui/src/components/DateSpan.svelte new file mode 100644 index 0000000..f93c0fc --- /dev/null +++ b/svelte-ui/src/components/DateSpan.svelte @@ -0,0 +1,17 @@ + + +{timeStr} + + \ No newline at end of file diff --git a/svelte-ui/src/components/DaysLeft.svelte b/svelte-ui/src/components/DaysLeft.svelte new file mode 100644 index 0000000..104f62e --- /dev/null +++ b/svelte-ui/src/components/DaysLeft.svelte @@ -0,0 +1,87 @@ + + + + {#if (overdue)} + {amountStr} {unit} ago + {:else if (started)} + {amountStr} {unit} left + {:else} + In {amountStr} {unit} + {/if} + + + \ No newline at end of file diff --git a/svelte-ui/src/components/GoalEntry.svelte b/svelte-ui/src/components/GoalEntry.svelte new file mode 100644 index 0000000..838d3cc --- /dev/null +++ b/svelte-ui/src/components/GoalEntry.svelte @@ -0,0 +1,93 @@ + + +
+
+
+
+
{goal.name}
+
+ +
+
+ {#if showAllOptions} +
+

{goal.description}

+
+ + + + + {/if} +
+ +
+
+
+ + \ No newline at end of file diff --git a/svelte-ui/src/components/GroupEntry.svelte b/svelte-ui/src/components/GroupEntry.svelte new file mode 100644 index 0000000..c9d0fb1 --- /dev/null +++ b/svelte-ui/src/components/GroupEntry.svelte @@ -0,0 +1,84 @@ + + +
+
+
+
+
{group.name}
+
+ {#if showAllOptions} +
+

{group.description}

+
+ + + + + + {/if} +
+ {#each group.items as item (item.id)} + + {/each} +
+
+
+ + diff --git a/svelte-ui/src/components/GroupSelect.svelte b/svelte-ui/src/components/GroupSelect.svelte new file mode 100644 index 0000000..93e1895 --- /dev/null +++ b/svelte-ui/src/components/GroupSelect.svelte @@ -0,0 +1,30 @@ + + + \ No newline at end of file diff --git a/svelte-ui/src/components/Icon.svelte b/svelte-ui/src/components/Icon.svelte new file mode 100644 index 0000000..b0fd683 --- /dev/null +++ b/svelte-ui/src/components/Icon.svelte @@ -0,0 +1,22 @@ + + +{#if block} +
+ +
+{:else} + +{/if} + + \ No newline at end of file diff --git a/svelte-ui/src/components/IconSelect.svelte b/svelte-ui/src/components/IconSelect.svelte new file mode 100644 index 0000000..4aa8691 --- /dev/null +++ b/svelte-ui/src/components/IconSelect.svelte @@ -0,0 +1,56 @@ + + +
+ {#each iconNames as iconName (iconName)} +
{if (!disabled) { value = iconName }}}> + +
+ {/each} +
+ + \ No newline at end of file diff --git a/svelte-ui/src/components/ItemEntry.svelte b/svelte-ui/src/components/ItemEntry.svelte new file mode 100644 index 0000000..4f8de73 --- /dev/null +++ b/svelte-ui/src/components/ItemEntry.svelte @@ -0,0 +1,86 @@ + + +
+
+
+
+ {item.groupWeight} +
+
{item.name}
+
+
+

{item.description}

+ + + + + +
+
+
+ + diff --git a/svelte-ui/src/components/ItemSelect.svelte b/svelte-ui/src/components/ItemSelect.svelte new file mode 100644 index 0000000..5f6aaf6 --- /dev/null +++ b/svelte-ui/src/components/ItemSelect.svelte @@ -0,0 +1,31 @@ + + + \ No newline at end of file diff --git a/svelte-ui/src/components/LogEntry.svelte b/svelte-ui/src/components/LogEntry.svelte new file mode 100644 index 0000000..9437ca2 --- /dev/null +++ b/svelte-ui/src/components/LogEntry.svelte @@ -0,0 +1,95 @@ + + +
+
+
+
+ +
+
{log.task.name}
+
{formatTime(log.loggedTime)}
+
+
+

{log.description}

+ + + + + +
+
+
+ + diff --git a/svelte-ui/src/components/Menu.svelte b/svelte-ui/src/components/Menu.svelte new file mode 100644 index 0000000..953a198 --- /dev/null +++ b/svelte-ui/src/components/Menu.svelte @@ -0,0 +1,44 @@ + + + + + diff --git a/svelte-ui/src/components/Modal.svelte b/svelte-ui/src/components/Modal.svelte new file mode 100644 index 0000000..80976d3 --- /dev/null +++ b/svelte-ui/src/components/Modal.svelte @@ -0,0 +1,215 @@ + + +{#if show} + +{/if} + + \ No newline at end of file diff --git a/svelte-ui/src/components/ModalRoute.svelte b/svelte-ui/src/components/ModalRoute.svelte new file mode 100644 index 0000000..8f64b40 --- /dev/null +++ b/svelte-ui/src/components/ModalRoute.svelte @@ -0,0 +1,10 @@ + + +{#if $modalStore.name === name} + +{/if} \ No newline at end of file diff --git a/svelte-ui/src/components/Option.svelte b/svelte-ui/src/components/Option.svelte new file mode 100644 index 0000000..52d63e5 --- /dev/null +++ b/svelte-ui/src/components/Option.svelte @@ -0,0 +1,38 @@ + + +
+ + \ No newline at end of file diff --git a/svelte-ui/src/components/OptionRow.svelte b/svelte-ui/src/components/OptionRow.svelte new file mode 100644 index 0000000..b91989d --- /dev/null +++ b/svelte-ui/src/components/OptionRow.svelte @@ -0,0 +1,10 @@ +
+ +
+ + \ No newline at end of file diff --git a/svelte-ui/src/components/Progress.svelte b/svelte-ui/src/components/Progress.svelte new file mode 100644 index 0000000..44b3eec --- /dev/null +++ b/svelte-ui/src/components/Progress.svelte @@ -0,0 +1,80 @@ + + + + +
+ {#each {length: ons} as _} +
+ {/each} + {#each {length: offs} as _} +
+ {/each} +
+ + \ No newline at end of file diff --git a/svelte-ui/src/components/ProjectEntry.svelte b/svelte-ui/src/components/ProjectEntry.svelte new file mode 100644 index 0000000..2b59780 --- /dev/null +++ b/svelte-ui/src/components/ProjectEntry.svelte @@ -0,0 +1,94 @@ + + +
+
+
+
+
{project.name}
+ {#if (project.endTime != null)} +
+ +
+ {/if} +
+ {#if showAllOptions} +
+

{project.description}

+
+ + + + + + {/if} +
+ {#each project.tasks as task (task.id)} + + {/each} +
+
+
+ + diff --git a/svelte-ui/src/components/TaskEntry.svelte b/svelte-ui/src/components/TaskEntry.svelte new file mode 100644 index 0000000..4588ebd --- /dev/null +++ b/svelte-ui/src/components/TaskEntry.svelte @@ -0,0 +1,161 @@ + + +
+
+
+ {#if !task.active} +
+ +
+ {:else} +
+ {task.completedAmount} / {task.itemAmount} +
+ {/if} +
{task.name}
+ {#if (task.endTime != null)} +
+ +
+ {/if} +
+
+

{task.description}

+
+
+ +
+
{task.item.name} ({task.item.groupWeight})
+
+ + {#if task.logs.length > 0} + + {/if} + + {#if showAllOptions} + + + {/if} + + {#if showLogs && task.logs.length > 0} +
+ {#each task.logs as log (log.id)} +
+
+
{log.description}
+
+ {/each} +
+ {/if} +
+
+
+ + diff --git a/svelte-ui/src/external/icons.ts b/svelte-ui/src/external/icons.ts new file mode 100644 index 0000000..42c0ea9 --- /dev/null +++ b/svelte-ui/src/external/icons.ts @@ -0,0 +1,138 @@ +import { faQuestion } from "@fortawesome/free-solid-svg-icons/faQuestion"; +import { faPlus } from "@fortawesome/free-solid-svg-icons/faPlus"; +import { faCube } from "@fortawesome/free-solid-svg-icons/faCube"; +import { faCubes } from "@fortawesome/free-solid-svg-icons/faCubes"; +import { faBook } from "@fortawesome/free-solid-svg-icons/faBook"; +import { faBookOpen } from "@fortawesome/free-solid-svg-icons/faBookOpen"; +import { faBookDead } from "@fortawesome/free-solid-svg-icons/faBookDead"; +import { faPen } from "@fortawesome/free-solid-svg-icons/faPen"; +import { faPencilAlt } from "@fortawesome/free-solid-svg-icons/faPencilAlt"; +import { faDiceD20 } from "@fortawesome/free-solid-svg-icons/faDiceD20"; +import { faDiceD6 } from "@fortawesome/free-solid-svg-icons/faDiceD6"; +import { faDungeon } from "@fortawesome/free-solid-svg-icons/faDungeon"; +import { faGamepad } from "@fortawesome/free-solid-svg-icons/faGamepad"; +import { faHeadphones } from "@fortawesome/free-solid-svg-icons/faHeadphones"; +import { faLanguage } from "@fortawesome/free-solid-svg-icons/faLanguage"; +import { faCode } from "@fortawesome/free-solid-svg-icons/faCode"; +import { faCodeBranch } from "@fortawesome/free-solid-svg-icons/faCodeBranch"; +import { faGuitar } from "@fortawesome/free-solid-svg-icons/faGuitar"; +import { faMusic } from "@fortawesome/free-solid-svg-icons/faMusic"; +import { faArchive } from "@fortawesome/free-solid-svg-icons/faArchive"; +import { faCheck } from "@fortawesome/free-solid-svg-icons/faCheck"; +import { faDrawPolygon } from "@fortawesome/free-solid-svg-icons/faDrawPolygon"; +import { faComment } from "@fortawesome/free-solid-svg-icons/faComment"; +import { faDatabase } from "@fortawesome/free-solid-svg-icons/faDatabase"; +import { faCog } from "@fortawesome/free-solid-svg-icons/faCog"; +import { faLink } from "@fortawesome/free-solid-svg-icons/faLink"; +import { faStar } from "@fortawesome/free-solid-svg-icons/faStar"; +import { faStarOfLife } from "@fortawesome/free-solid-svg-icons/faStarOfLife"; +import { faSun } from "@fortawesome/free-solid-svg-icons/faSun"; +import { faHdd } from "@fortawesome/free-solid-svg-icons/faHdd"; +import { faServer } from "@fortawesome/free-solid-svg-icons/faServer"; +import { faBlender } from "@fortawesome/free-solid-svg-icons/faBlender"; +import { faCross } from "@fortawesome/free-solid-svg-icons/faCross"; +import { faTimes } from "@fortawesome/free-solid-svg-icons/faTimes"; +import { faSkullCrossbones } from "@fortawesome/free-solid-svg-icons/faSkullCrossbones"; +import { faCrosshairs } from "@fortawesome/free-solid-svg-icons/faCrosshairs"; +import { faLaptop } from "@fortawesome/free-solid-svg-icons/faLaptop"; +import { faMemory } from "@fortawesome/free-solid-svg-icons/faMemory"; +import { faKeyboard } from "@fortawesome/free-solid-svg-icons/faKeyboard"; +import { faCookie } from "@fortawesome/free-solid-svg-icons/faCookie"; +import { faMicrochip } from "@fortawesome/free-solid-svg-icons/faMicrochip"; +import { faClipboard } from "@fortawesome/free-solid-svg-icons/faClipboard"; +import { faPizzaSlice } from "@fortawesome/free-solid-svg-icons/faPizzaSlice"; +import { faPaperclip } from "@fortawesome/free-solid-svg-icons/faPaperclip"; +import { faReceipt } from "@fortawesome/free-solid-svg-icons/faReceipt"; +import { faSuperscript } from "@fortawesome/free-solid-svg-icons/faSuperscript"; +import { faCouch } from "@fortawesome/free-solid-svg-icons/faCouch"; +import { faTerminal } from "@fortawesome/free-solid-svg-icons/faTerminal"; +import { faGift } from "@fortawesome/free-solid-svg-icons/faGift"; +import { faGifts } from "@fortawesome/free-solid-svg-icons/faGifts"; +import { faImage } from "@fortawesome/free-solid-svg-icons/faImage"; +import { faImages } from "@fortawesome/free-solid-svg-icons/faImages"; +import { faDragon } from "@fortawesome/free-solid-svg-icons/faDragon"; +import { faLightbulb } from "@fortawesome/free-solid-svg-icons/faLightbulb"; +import { faTools } from "@fortawesome/free-solid-svg-icons/faTools"; +import { faHammer } from "@fortawesome/free-solid-svg-icons/faHammer"; +import { faScrewdriver } from "@fortawesome/free-solid-svg-icons/faScrewdriver"; +import { faWrench } from "@fortawesome/free-solid-svg-icons/faWrench"; +import { faBug } from "@fortawesome/free-solid-svg-icons/faBug"; +import { faUtensils } from "@fortawesome/free-solid-svg-icons/faUtensils"; +import { faHome } from "@fortawesome/free-solid-svg-icons/faHome"; +import { faIgloo } from "@fortawesome/free-solid-svg-icons/faIgloo"; +import { faWarehouse } from "@fortawesome/free-solid-svg-icons/faWarehouse"; +import { faToiletPaperSlash } from "@fortawesome/free-solid-svg-icons/faToiletPaperSlash"; + +const icons = { + "question": faQuestion, + "plus": faPlus, + "cube": faCube, + "cubes": faCubes, + "book": faBook, + "book_open": faBookOpen, + "book_dead": faBookDead, + "pen": faPen, + "pencil_alt": faPencilAlt, + "draw_poligon": faDrawPolygon, + "dice_d20": faDiceD20, + "dice_d6": faDiceD6, + "dungeon": faDungeon, + "gamepad": faGamepad, + "headphones": faHeadphones, + "language": faLanguage, + "code": faCode, + "code_branch": faCodeBranch, + "guitar": faGuitar, + "archive": faArchive, + "check": faCheck, + "music": faMusic, + "comment": faComment, + "database": faDatabase, + "cog": faCog, + "link": faLink, + "star": faStar, + "star_of_life": faStarOfLife, + "sun": faSun, + "hdd": faHdd, + "server": faServer, + "blender": faBlender, + "cross": faCross, + "times": faTimes, + "crosshairs": faCrosshairs, + "skull_crossbones": faSkullCrossbones, + "laptop": faLaptop, + "memory": faMemory, + "keyboard": faKeyboard, + "cookie": faCookie, + "microchip": faMicrochip, + "clipboard": faClipboard, + "pizza_slice": faPizzaSlice, + "paperclip": faPaperclip, + "receipt": faReceipt, + "superscript": faSuperscript, + "couch": faCouch, + "terminal": faTerminal, + "gift": faGift, + "gifts": faGifts, + "image": faImage, + "images": faImages, + "dragon": faDragon, + "lightbulb": faLightbulb, + "tools": faTools, + "hammer": faHammer, + "screwdriver": faScrewdriver, + "wrench": faWrench, + "bug": faBug, + "utensils": faUtensils, + "home": faHome, + "igloo": faIgloo, + "warehouse": faWarehouse, + "toilet_paper_slash": faToiletPaperSlash, +}; + +export type IconName = keyof typeof icons; + +export const iconNames = Object.keys(icons).sort() as IconName[]; +export const DEFAULT_ICON = iconNames[0] as IconName; + +export default icons; diff --git a/svelte-ui/src/forms/GoalForm.svelte b/svelte-ui/src/forms/GoalForm.svelte new file mode 100644 index 0000000..82f8913 --- /dev/null +++ b/svelte-ui/src/forms/GoalForm.svelte @@ -0,0 +1,112 @@ + + + +
+ + + +