├── .dockerignore ├── frontend ├── html-src │ ├── _footer.html │ ├── channel.html │ ├── _header.html │ └── index.html ├── .gitignore ├── static-src │ ├── icon.png │ ├── favicon.ico │ ├── images │ │ ├── notebook.png │ │ └── register.png │ ├── service-worker.js │ └── icon.svg ├── serve.sh ├── build-env.sh ├── src │ ├── config.ts │ ├── util.ts │ ├── main.tsx │ ├── quickstart │ │ ├── create_channel_stage.tsx │ │ ├── completed_stage.tsx │ │ ├── quickstart_flow.tsx │ │ └── subscribe_stage.tsx │ ├── api.ts │ ├── subscription.ts │ └── channel.tsx ├── package.json ├── tsconfig.json ├── build.sh ├── webpack.config.js └── yarn.lock ├── .gitignore ├── frontend.sh ├── Makefile ├── README.md ├── deployment ├── build.sh ├── deploy.yaml └── Dockerfile ├── src ├── database.rs ├── model.rs ├── main.rs ├── server_state.rs ├── rate_limiter.rs ├── logging.rs ├── migrate.rs ├── vapid.rs └── server.rs ├── Cargo.toml ├── LICENSE ├── test-notify.ipynb └── Cargo.lock /.dockerignore: -------------------------------------------------------------------------------- 1 | target 2 | frontend/node_modules 3 | -------------------------------------------------------------------------------- /frontend/html-src/_footer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /frontend/html-src/channel.html: -------------------------------------------------------------------------------- 1 |
2 | JavaScript is required. 3 |
-------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | export.json 3 | credentials.json 4 | .env 5 | /static 6 | .ipynb_checkpoints 7 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | public 2 | static 3 | .env 4 | dist 5 | tracker.html 6 | node_modules 7 | .vscode -------------------------------------------------------------------------------- /frontend/static-src/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notify-run/notify-run-rs/HEAD/frontend/static-src/icon.png -------------------------------------------------------------------------------- /frontend.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | rm -rf static 6 | cd frontend 7 | ./build.sh 8 | mv public ../static 9 | -------------------------------------------------------------------------------- /frontend/static-src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notify-run/notify-run-rs/HEAD/frontend/static-src/favicon.ico -------------------------------------------------------------------------------- /frontend/serve.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -a 4 | source .env 5 | 6 | ./build.sh 7 | ./node_modules/.bin/webpack-dev-server 8 | -------------------------------------------------------------------------------- /frontend/static-src/images/notebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notify-run/notify-run-rs/HEAD/frontend/static-src/images/notebook.png -------------------------------------------------------------------------------- /frontend/static-src/images/register.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notify-run/notify-run-rs/HEAD/frontend/static-src/images/register.png -------------------------------------------------------------------------------- /frontend/build-env.sh: -------------------------------------------------------------------------------- 1 | if [ -f .env ]; then 2 | echo "Loading .env file." 3 | set -a 4 | source .env 5 | else 6 | echo "No .env found, skipping." 7 | fi 8 | 9 | source build.sh 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifneq (,$(wildcard ./.env)) 2 | include .env 3 | export 4 | endif 5 | 6 | .PHONY: serve 7 | 8 | serve: 9 | cargo run -- serve 10 | 11 | ngrok: 12 | ngrok http --subdomain=notify 8080 13 | -------------------------------------------------------------------------------- /frontend/src/config.ts: -------------------------------------------------------------------------------- 1 | export namespace Config { 2 | export const API_SERVER = process.env.NOTIFY_API_SERVER || location.origin; 3 | export const WEB_SERVER = process.env.NOTIFY_WEB_SERVER || location.origin; 4 | } -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "notify-run", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "dependencies": { 6 | "@types/node": "^10.12.18", 7 | "@types/react": "^16.0.35", 8 | "@types/react-dom": "^16.0.3", 9 | "react": "^16.7.0", 10 | "react-dom": "^16.7.0" 11 | }, 12 | "devDependencies": { 13 | "ts-loader": "^9.2.6", 14 | "typescript": "^4.4.4", 15 | "webpack": "^5.59.1", 16 | "webpack-cli": "^4.9.1" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/util.ts: -------------------------------------------------------------------------------- 1 | export function urlB64ToUint8Array(base64String: string) { 2 | const padding = '='.repeat((4 - base64String.length % 4) % 4); 3 | const base64 = (base64String + padding) 4 | .replace(/\-/g, '+') 5 | .replace(/_/g, '/'); 6 | 7 | const rawData = window.atob(base64); 8 | const outputArray = new Uint8Array(rawData.length); 9 | 10 | for (let i = 0; i < rawData.length; ++i) { 11 | outputArray[i] = rawData.charCodeAt(i); 12 | } 13 | return outputArray; 14 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # notify-run-rs 2 | 3 | This is a rewrite of the [notify.run](https://notify.run) server in Rust for performance. It uses Google Firebase as a backend. 4 | 5 | Although the server remains open-source, self-hosting of a notify.run server is no longer a use-case that I prioritize. In particular, non-Firebase databases 6 | will probably never be supported, and documentation is sparse (although all scripts used for production deployment are now part of this repo). 7 | 8 | The prior (Python) server is [archived here](https://github.com/notify-run/notify-run-server). 9 | -------------------------------------------------------------------------------- /deployment/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | gcloud auth list 4 | 5 | # Sync down ------------------------------- 6 | gsutil cp \ 7 | gs://notify-run-build-cache/target.tar.gz \ 8 | ./ 9 | tar -xf target.tar.gz 10 | 11 | set -e 12 | 13 | # Run build ------------------------------- 14 | cargo test --release 15 | cargo build --release 16 | 17 | # Sync up --------------------------------- 18 | tar -zcf target.tar.gz target 19 | ! gsutil -o GSUtil:parallel_composite_upload_threshold=150M cp \ 20 | target.tar.gz \ 21 | gs://notify-run-build-cache/target.tar.gz 22 | 23 | mv target/release/notify-run ./ 24 | rm -rf target 25 | rm -rf target.tar.gz 26 | rm -rf ~/.cargo 27 | -------------------------------------------------------------------------------- /deployment/deploy.yaml: -------------------------------------------------------------------------------- 1 | steps: 2 | - name: 'gcr.io/kaniko-project/executor:v1.6.0' 3 | args: 4 | - '--dockerfile=deployment/Dockerfile' 5 | - '--destination=gcr.io/notify-run/server:$COMMIT_SHA' 6 | - '--cache=true' 7 | - '--cache-ttl=336h' 8 | - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk:slim' 9 | args: 10 | - run 11 | - services 12 | - update 13 | - new-notify-run-server 14 | - '--platform=managed' 15 | - '--image=gcr.io/notify-run/server:$COMMIT_SHA' 16 | - '--region=us-east4' 17 | - '--quiet' 18 | id: Deploy 19 | entrypoint: gcloud 20 | timeout: 3000s 21 | options: 22 | machineType: E2_HIGHCPU_8 23 | -------------------------------------------------------------------------------- /frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es5", 5 | "lib": [ 6 | "es6", 7 | "dom" 8 | ], 9 | "sourceMap": true, 10 | "allowJs": true, 11 | "jsx": "react", 12 | "noImplicitReturns": true, 13 | "noImplicitThis": true, 14 | "noImplicitAny": true, 15 | "strictNullChecks": true 16 | }, 17 | "exclude": [ 18 | "node_modules", 19 | "build", 20 | "scripts", 21 | "acceptance-tests", 22 | "webpack", 23 | "jest", 24 | "src/setupTests.ts" 25 | ], 26 | "types": [ 27 | "typePatches", 28 | "node" 29 | ] 30 | } -------------------------------------------------------------------------------- /frontend/src/main.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as ReactDOM from 'react-dom'; 3 | 4 | import { QuickStartFlow } from './quickstart/quickstart_flow'; 5 | import { ChannelPage } from './channel'; 6 | 7 | window.addEventListener('load', () => { 8 | let quickstartContainer = document.getElementById('quickstart'); 9 | if (quickstartContainer) { 10 | ReactDOM.render( 11 | , 12 | quickstartContainer 13 | ); 14 | } 15 | 16 | let match = document.location.pathname.match('/c/([A-Za-z0-9]+)/?'); 17 | if (match) { 18 | let channelId = match[1]; 19 | let channelContainer = document.getElementById('channel'); 20 | ReactDOM.render( 21 | , 22 | channelContainer 23 | ); 24 | } 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd "$(dirname "$0")" 4 | set -e 5 | 6 | export NODE_OPTIONS=--openssl-legacy-provider 7 | 8 | echo "Cleaning up old environment." 9 | rm -rf dist static public 10 | 11 | echo "Installing environment." 12 | npm install 13 | 14 | echo "Bundling JavaScript." 15 | ./node_modules/.bin/webpack 16 | 17 | cp -R static-src static 18 | 19 | echo "${NOTIFY_TRACKER}" > tracker.html 20 | 21 | echo "Generating HTML files." 22 | gen_html() { 23 | cat html-src/_header.html html-src/${1}.html tracker.html html-src/_footer.html > static/${1}.html 24 | } 25 | 26 | gen_html index 27 | gen_html channel 28 | 29 | echo "Merging with static files." 30 | mkdir -p public/ 31 | cp -R dist/* static/* public/ 32 | 33 | echo "Generating redirects file." 34 | echo "/c/* /channel.html 200" >> public/_redirects 35 | echo "/* ${NOTIFY_API_PROXY}/:splat 200" >> public/_redirects 36 | 37 | -------------------------------------------------------------------------------- /frontend/src/quickstart/create_channel_stage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | interface CreateChannelStageProps { 4 | onCreateChannel: () => void; 5 | loading: boolean; 6 | error: boolean; 7 | } 8 | 9 | export class CreateChannelStage extends React.Component { 10 | render() { 11 | return
12 |

All notifications are sent to a channel, which is how 13 | notify.run knows how to route them. To get started, create a channel. 14 |

15 | 16 | { 17 | this.props.error ? ( 18 |
Server error.
19 | ) : (this.props.loading ?
: null) 20 | } 21 |
; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /frontend/static-src/service-worker.js: -------------------------------------------------------------------------------- 1 | self.addEventListener('notificationclick', function (event) { 2 | if (event.notification.data.action) { 3 | clients.openWindow(event.notification.data.action); 4 | } 5 | }); 6 | 7 | self.addEventListener('push', function (event) { 8 | let data = event.data.json(); 9 | 10 | let title_body = data.message.split('\n'); 11 | let title = title_body.shift(); 12 | let body = title_body.join('\n'); 13 | 14 | let options = { 15 | body: body, 16 | icon: '/static/icon.png', 17 | //tag: data.channel, 18 | data: data.data, 19 | //renotify: true, 20 | vibrate: data.vibrate, 21 | silent: data.silent 22 | }; 23 | 24 | console.log(JSON.stringify(event.data.json())) 25 | console.log(JSON.stringify(options)) 26 | 27 | const promiseChain = self.registration.showNotification(title, options); 28 | 29 | event.waitUntil(promiseChain); 30 | }); -------------------------------------------------------------------------------- /frontend/webpack.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | const path = require('path'); 3 | 4 | module.exports = { 5 | mode: 'production', 6 | context: path.resolve('src'), 7 | entry: './main.tsx', 8 | output: { 9 | path: path.resolve('dist'), 10 | filename: 'main.js' 11 | }, 12 | devtool: "source-map", 13 | plugins: [ 14 | new webpack.EnvironmentPlugin({ 15 | 'NOTIFY_API_SERVER': null, 16 | 'NOTIFY_WEB_SERVER': null 17 | }), 18 | ], 19 | resolve: { 20 | extensions: [".ts", ".tsx", ".js", ".json"] 21 | }, 22 | module: { 23 | rules: [ 24 | { 25 | test: /\.[tj]sx?$/, 26 | loader: 'ts-loader', 27 | exclude: /node_modules/ 28 | }, 29 | ] 30 | }, 31 | devServer: { 32 | contentBase: path.join(__dirname, 'static'), 33 | historyApiFallback: { 34 | index: '/channel.html' 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/database.rs: -------------------------------------------------------------------------------- 1 | use crate::{get_creds_and_project, model::Channel}; 2 | use async_trait::async_trait; 3 | use deadpool::managed; 4 | use std::convert::Infallible; 5 | use tiny_firestore_odm::{Collection, Database}; 6 | 7 | pub struct NotifyDatabase { 8 | db: Database, 9 | } 10 | 11 | impl NotifyDatabase { 12 | pub fn channels(&self) -> Collection { 13 | self.db.collection("channels") 14 | } 15 | } 16 | 17 | pub struct NotifyDatabaseManager; 18 | 19 | #[async_trait] 20 | impl managed::Manager for NotifyDatabaseManager { 21 | type Type = NotifyDatabase; 22 | type Error = Infallible; 23 | 24 | async fn create(&self) -> Result { 25 | let (token_source, project_id) = get_creds_and_project().await; 26 | let db = Database::new(token_source, &project_id).await; 27 | 28 | Ok(NotifyDatabase { db }) 29 | } 30 | 31 | async fn recycle(&self, _: &mut NotifyDatabase) -> managed::RecycleResult { 32 | Ok(()) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/model.rs: -------------------------------------------------------------------------------- 1 | use chrono::{DateTime, Utc}; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | pub const MESSAGES_COLLECTION: &str = "messages"; 5 | pub const SUBSCRIPTIONS_COLLECTION: &str = "subscriptions"; 6 | 7 | #[derive(Serialize, Deserialize, Debug)] 8 | pub struct Subscription { 9 | pub endpoint: String, 10 | pub auth: String, 11 | pub p256dh: String, 12 | } 13 | 14 | #[derive(Serialize, Deserialize, Debug)] 15 | pub struct Channel { 16 | #[serde(with = "firestore_serde_timestamp::timestamp")] 17 | pub created: DateTime, 18 | 19 | pub created_agent: String, 20 | pub created_ip: String, 21 | } 22 | 23 | #[derive(Serialize, Deserialize, Debug)] 24 | pub struct Message { 25 | pub message: String, 26 | pub sender_ip: String, 27 | 28 | #[serde(with = "firestore_serde_timestamp::timestamp")] 29 | pub message_time: DateTime, 30 | 31 | pub result: Vec, 32 | } 33 | 34 | #[derive(Serialize, Deserialize, Debug)] 35 | pub struct MessageResult { 36 | pub endpoint_domain: String, 37 | pub result_status: String, 38 | } 39 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "notify-run" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | anyhow = "1.0.44" 8 | async-trait = "0.1.51" 9 | axum = { version = "0.3.0", features = ["headers"] } 10 | base64 = "0.13.0" 11 | chrono = "0.4.19" 12 | clap = "3.0.0-beta.5" 13 | deadpool = { version = "0.9.0", features = ["managed"] } 14 | firestore-serde = "0.1.1" 15 | firestore-serde-timestamp = "0.1.0" 16 | futures = "0.3.17" 17 | google-authz = "0.0.2" 18 | governor = "0.3.2" 19 | headers = "0.3.5" 20 | http-body = "0.4.4" 21 | nonzero_ext = "0.3.0" 22 | qrcode = "0.12.0" 23 | serde = { version = "1.0.130", features = ["derive"] } 24 | serde_json = "1.0.68" 25 | serde_urlencoded = "0.7.0" 26 | tiny-firestore-odm = "0.2.6" 27 | tokio = { version = "1.12.0", features = ["rt-multi-thread", "time"] } 28 | tokio-stream = "0.1.7" 29 | tower = "0.4.10" 30 | tower-http = { version = "0.1.1", features = ["fs", "trace"] } 31 | tracing = "0.1.29" 32 | tracing-stackdriver = "0.2.0" 33 | tracing-subscriber = "0.2.25" 34 | web-push = { version="0.9.1", features = ["hyper-client"], default_features=false } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 notify-run 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /deployment/Dockerfile: -------------------------------------------------------------------------------- 1 | # ========================================= 2 | # Build Frontend 3 | # ========================================= 4 | FROM node:alpine as frontend-builder 5 | 6 | WORKDIR /work 7 | 8 | ADD frontend . 9 | 10 | RUN ./build.sh 11 | 12 | # ========================================= 13 | # Build Rust Codebase 14 | # ========================================= 15 | FROM rust:latest as backend-builder 16 | 17 | RUN echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] http://packages.cloud.google.com/apt cloud-sdk main" \ 18 | | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list \ 19 | && curl https://packages.cloud.google.com/apt/doc/apt-key.gpg \ 20 | | apt-key --keyring /usr/share/keyrings/cloud.google.gpg \ 21 | add - && apt-get update -y && apt-get install google-cloud-sdk -y 22 | 23 | WORKDIR /work 24 | 25 | COPY . . 26 | 27 | RUN /bin/sh deployment/build.sh 28 | 29 | # ========================================= 30 | # Run 31 | # ========================================= 32 | FROM debian:bullseye-slim 33 | 34 | WORKDIR /work 35 | 36 | RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates 37 | 38 | COPY --from=backend-builder /work/notify-run ./ 39 | COPY --from=frontend-builder /work/public ./static 40 | 41 | ENTRYPOINT ["/work/notify-run", "serve"] 42 | -------------------------------------------------------------------------------- /frontend/static-src/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /frontend/src/quickstart/completed_stage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Config } from '../config'; 3 | 4 | interface CompletedStageProps { 5 | channelId: string; 6 | } 7 | 8 | export class CompletedStage extends React.Component { 9 | render() { 10 | let channelLink = `${Config.WEB_SERVER}/c/${this.props.channelId}`; 11 | let channelEndpoint = `${Config.API_SERVER}/${this.props.channelId}` 12 | return
13 |

14 | Your channel is ready to be used! 15 |

16 |

17 | To send a message with curl, run the following command in a terminal: 18 |

19 |
$ curl {channelEndpoint} -d "Hello from notify.run"
20 |

21 | If you have pip, you can also install and run the notify-run package 22 | and use the command-line interface: 23 |

24 |
{`$ pip install notify-run
25 | $ notify-run configure ${channelEndpoint}
26 | $ notify-run send "Hello from notify.run"`}
27 |

28 | You can always 29 | visit {channelLink} to 30 | view a log of recent messages or subscribe new devices. 31 |

32 |
; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | 3 | use anyhow::Result; 4 | use clap::Parser; 5 | use google_authz::{Credentials, TokenSource}; 6 | use logging::init_logging; 7 | use migrate::migrate; 8 | use server::serve; 9 | use tiny_firestore_odm::Database; 10 | 11 | mod database; 12 | mod logging; 13 | mod migrate; 14 | mod model; 15 | mod rate_limiter; 16 | mod server; 17 | mod server_state; 18 | mod vapid; 19 | 20 | #[derive(Parser)] 21 | struct Opts { 22 | #[clap(subcommand)] 23 | subcmd: SubCommand, 24 | } 25 | 26 | #[derive(Parser)] 27 | enum SubCommand { 28 | Migrate { 29 | source: PathBuf, 30 | }, 31 | Serve { 32 | #[clap(short, long)] 33 | port: Option, 34 | }, 35 | } 36 | 37 | pub async fn get_creds_and_project() -> (TokenSource, String) { 38 | let creds = Credentials::default().await; 39 | let project_id = std::env::var("GCP_PROJECT_ID").expect("Expected GCP_PROJECT_ID env var."); 40 | 41 | (creds.into(), project_id) 42 | } 43 | 44 | async fn get_db() -> Database { 45 | let (token_source, project_id) = get_creds_and_project().await; 46 | Database::new(token_source, &project_id).await 47 | } 48 | 49 | #[tokio::main] 50 | async fn main() -> Result<()> { 51 | init_logging(); 52 | 53 | let opts = Opts::parse(); 54 | 55 | let subcommand = opts.subcmd; 56 | 57 | match subcommand { 58 | SubCommand::Migrate { source } => { 59 | migrate(source, get_db().await).await?; 60 | } 61 | SubCommand::Serve { port } => { 62 | serve(port).await?; 63 | } 64 | } 65 | 66 | Ok(()) 67 | } 68 | -------------------------------------------------------------------------------- /test-notify.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "id": "21b4cd2a", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "from notify_run import Notify" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": null, 16 | "id": "7945e882", 17 | "metadata": {}, 18 | "outputs": [], 19 | "source": [ 20 | "notify = Notify(api_server=\"https://notify.ngrok.io/\")" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": null, 26 | "id": "e3485363", 27 | "metadata": {}, 28 | "outputs": [], 29 | "source": [ 30 | "notify.register()" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": null, 36 | "id": "e88f54bc", 37 | "metadata": {}, 38 | "outputs": [], 39 | "source": [ 40 | "notify.__dict__" 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": null, 46 | "id": "0efe9cc3", 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "notify.send('ok4', 'https://google.com/')" 51 | ] 52 | } 53 | ], 54 | "metadata": { 55 | "kernelspec": { 56 | "display_name": "Python 3 (ipykernel)", 57 | "language": "python", 58 | "name": "python3" 59 | }, 60 | "language_info": { 61 | "codemirror_mode": { 62 | "name": "ipython", 63 | "version": 3 64 | }, 65 | "file_extension": ".py", 66 | "mimetype": "text/x-python", 67 | "name": "python", 68 | "nbconvert_exporter": "python", 69 | "pygments_lexer": "ipython3", 70 | "version": "3.8.5" 71 | } 72 | }, 73 | "nbformat": 4, 74 | "nbformat_minor": 5 75 | } 76 | -------------------------------------------------------------------------------- /src/server_state.rs: -------------------------------------------------------------------------------- 1 | use std::convert::Infallible; 2 | 3 | use base64::URL_SAFE; 4 | use deadpool::managed::{Object, PoolError}; 5 | 6 | use crate::database::NotifyDatabaseManager; 7 | 8 | #[derive(Clone)] 9 | pub struct ServerState { 10 | pool: deadpool::managed::Pool, 11 | pub server_base: String, 12 | pub vapid_pubkey: String, 13 | pub vapid_privkey: Vec, 14 | } 15 | 16 | impl ServerState { 17 | pub async fn new() -> Self { 18 | let pool = deadpool::managed::Pool::::builder(NotifyDatabaseManager) 19 | .build() 20 | .unwrap(); 21 | 22 | let vapid_pubkey = 23 | std::env::var("NOTIFY_VAPID_PUBKEY").expect("Expected NOTIFY_VAPID_PUBKEY env var."); 24 | let vapid_privkey_b64 = 25 | std::env::var("NOTIFY_VAPID_PRIVKEY").expect("Expected NOTIFY_VAPID_PRIVKEY env var."); 26 | let server_base = 27 | std::env::var("NOTIFY_API_SERVER").expect("Expected NOTIFY_API_SERVER env var."); 28 | 29 | let vapid_privkey = base64::decode_config(&vapid_privkey_b64, URL_SAFE) 30 | .expect("Could not decode VAPID private key as base64."); 31 | 32 | ServerState { 33 | pool, 34 | vapid_privkey, 35 | vapid_pubkey, 36 | server_base, 37 | } 38 | } 39 | 40 | pub async fn db(&self) -> Result, PoolError> { 41 | self.pool.get().await 42 | } 43 | 44 | pub fn channel_page_url(&self, channel_id: &str) -> String { 45 | format!("{}/c/{}", self.server_base, channel_id) 46 | } 47 | 48 | pub fn endpoint_url(&self, channel_id: &str) -> String { 49 | format!("{}/{}", self.server_base, channel_id) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /frontend/src/api.ts: -------------------------------------------------------------------------------- 1 | import { Config } from './config'; 2 | import { Subscription } from './subscription'; 3 | 4 | export type MessageResult = {endpoint_domain: string, result_message: string, result_status: string, subscription: string} 5 | export type Message = { channelId: string, message: string, time: string, result?: MessageResult[]}; 6 | export type ChannelResponse = { 7 | channelId: string, 8 | pubKey: string, 9 | messages?: Message[], 10 | subscriptions: string[], 11 | error?: string, 12 | }; 13 | 14 | export namespace NotifyAPI { 15 | function request(path: string, requestInit?: {}) { 16 | return fetch(Config.API_SERVER + path, requestInit).then((c) => { 17 | if (c.ok) { 18 | return c.json() 19 | } else if (c.status == 404) { 20 | throw new Error("Not found.") 21 | } else { 22 | throw new Error("Error reaching API server.") 23 | } 24 | }); 25 | } 26 | 27 | export function registerChannel(): Promise { 28 | return request('/api/register_channel', { method: 'POST' }); 29 | } 30 | 31 | export function subscribe(channelId: string, subscription: Subscription): Promise { 32 | let req = { 33 | method: 'POST', 34 | body: JSON.stringify(subscription), 35 | headers: new Headers({ 36 | 'Content-Type': 'application/json' 37 | }) 38 | } 39 | 40 | return request(`/${channelId}/subscribe`, req); 41 | } 42 | 43 | export function fetchChannel(channelId: string): Promise { 44 | return request(`/${channelId}/json`); 45 | } 46 | 47 | export function getURLOfQR(channelId: string): string { 48 | return `${Config.API_SERVER}/${channelId}/qr.svg`; 49 | } 50 | } -------------------------------------------------------------------------------- /frontend/src/quickstart/quickstart_flow.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { NotifyAPI, ChannelResponse } from '../api'; 3 | import { CreateChannelStage } from './create_channel_stage'; 4 | import { SubscribeStage } from './subscribe_stage'; 5 | import { CompletedStage } from './completed_stage'; 6 | 7 | interface QuickStartFlowState { 8 | channelId?: string, 9 | pubKey?: string, 10 | channelReady: boolean, 11 | loading: boolean, 12 | error: boolean, 13 | } 14 | 15 | export class QuickStartFlow extends React.Component<{}, QuickStartFlowState> { 16 | constructor(props: {}) { 17 | super(props); 18 | 19 | this.state = { 20 | channelId: undefined, 21 | pubKey: undefined, 22 | channelReady: false, 23 | loading: false, 24 | error: false, 25 | }; 26 | } 27 | 28 | createChannel() { 29 | this.setState({ 30 | loading: true, 31 | }); 32 | 33 | NotifyAPI.registerChannel().then((rcr: ChannelResponse) => { 34 | this.setState({ 35 | loading: false, 36 | channelId: rcr.channelId, 37 | pubKey: rcr.pubKey, 38 | }) 39 | }).catch(() => this.setState({error: true})); 40 | } 41 | 42 | channelReady() { 43 | this.setState({ 44 | channelReady: true, 45 | }); 46 | } 47 | 48 | render() { 49 | if (this.state.channelId === undefined || this.state.pubKey === undefined) { 50 | return ; 51 | } else if (!this.state.channelReady) { 52 | return 56 | } else { 57 | return ; 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /frontend/html-src/_header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | notify.run 6 | 7 | 8 | 9 | 10 | 11 | 17 | 18 | 19 | 20 |
21 | 22 |

23 | notify.run 24 |

25 |
26 | 27 |
28 |
29 | October 30, 2021 update: notify.run is back! 30 |
31 |

You may have noticed frequent outages over the last two weeks. 32 | There was an uptick in usage which stressed the small but mighty infrastructure that powers 33 | notify.run. 34 |

35 | 36 |

To keep pace with usage, I've overhauled the server:

37 |
    38 |
  • I completely rewrote the server in Rust.
  • 39 |
  • I moved it from a single self-managed server to Google Cloud Run, which autoscales.
  • 40 |
  • It now uses Firestore rather than DynamoDB, which had been a bottleneck.
  • 41 |
  • I implemented an IP-based rate limit of 20 API calls per minute. The vast majority 42 | of users will never hit this limit, but they'll get more reliable service because of it. 43 |
  • 44 |
45 | 46 |

-- Paul

47 |
-------------------------------------------------------------------------------- /frontend/src/subscription.ts: -------------------------------------------------------------------------------- 1 | import { NotifyAPI } from './api'; 2 | import { urlB64ToUint8Array } from './util'; 3 | 4 | type Keys = { p256dh: string, auth: string }; 5 | 6 | export class Subscription { 7 | constructor( 8 | public id: string, 9 | public subscription: PushSubscription, 10 | ) { } 11 | 12 | static fromPushSubscriptionAsync(ps: PushSubscription): PromiseLike { 13 | let buf: Uint8Array = new (window as any).TextEncoder('utf-8').encode(ps.endpoint); 14 | return crypto.subtle.digest('SHA-1', buf).then((digest) => { 15 | let digArray = Array.from(new Uint8Array(digest)); 16 | let digHex = digArray.map(b => ('00' + b.toString(16)).slice(-2)).join(''); 17 | let keys = { 18 | auth: ps.getKey('auth'), 19 | p256dh: ps.getKey('p256dh'), 20 | } 21 | return new Subscription(digHex, ps); 22 | }); 23 | } 24 | } 25 | 26 | 27 | export class SubscriptionManager { 28 | constructor(private pubKey: string) { 29 | 30 | } 31 | 32 | getSubscription(): Promise { 33 | if (typeof navigator.serviceWorker === 'undefined') { 34 | return new Promise((resolve, reject) => reject()); 35 | } 36 | 37 | return navigator.serviceWorker.ready 38 | .then((serviceWorkerRegistration) => 39 | serviceWorkerRegistration.pushManager.getSubscription() 40 | ) 41 | .then(Subscription.fromPushSubscriptionAsync); 42 | } 43 | 44 | checkBrowserSupport(): boolean { 45 | return (('Notification' in window) && 46 | ('serviceWorker' in navigator) && 47 | ('PushManager' in window)); 48 | } 49 | 50 | checkPermission(): boolean { 51 | return (Notification as any).permission !== 'denied'; 52 | } 53 | 54 | subscribe(channelId: string): Promise { 55 | return navigator.serviceWorker.register('/static/service-worker.js') 56 | .then((registration) => { 57 | const subscribeOptions = { 58 | userVisibleOnly: true, 59 | applicationServerKey: urlB64ToUint8Array(this.pubKey) 60 | }; 61 | return registration.pushManager.subscribe(subscribeOptions); 62 | }) 63 | .then(Subscription.fromPushSubscriptionAsync) 64 | .then((pushSubscription) => { 65 | NotifyAPI.subscribe(channelId, pushSubscription); 66 | }); 67 | } 68 | } -------------------------------------------------------------------------------- /src/rate_limiter.rs: -------------------------------------------------------------------------------- 1 | use axum::{ 2 | body::{box_body, Body, BoxBody}, 3 | http::{Request, Response}, 4 | }; 5 | use futures::future::BoxFuture; 6 | use governor::{clock::DefaultClock, state::keyed::DashMapStateStore, Quota, RateLimiter}; 7 | use std::sync::Arc; 8 | use tower::Service; 9 | 10 | #[derive(Clone)] 11 | pub struct RateLimiterMiddleware { 12 | rate_limiter: Arc, DefaultClock>>, 13 | inner: S, 14 | quota: Quota, 15 | } 16 | 17 | impl RateLimiterMiddleware { 18 | pub fn new(inner: S, quota: Quota) -> Self { 19 | RateLimiterMiddleware { 20 | rate_limiter: Arc::new(RateLimiter::dashmap(quota)), 21 | inner, 22 | quota, 23 | } 24 | } 25 | } 26 | 27 | impl Service> for RateLimiterMiddleware 28 | where 29 | S: Service, Response = Response> + Clone + Send + 'static, 30 | S::Future: Send + 'static, 31 | ReqBody: Send + 'static, 32 | { 33 | type Response = Response; 34 | 35 | type Error = S::Error; 36 | 37 | type Future = BoxFuture<'static, Result>; 38 | 39 | fn poll_ready( 40 | &mut self, 41 | cx: &mut std::task::Context<'_>, 42 | ) -> std::task::Poll> { 43 | self.inner.poll_ready(cx) 44 | } 45 | 46 | fn call(&mut self, req: Request) -> Self::Future { 47 | // https://github.com/tower-rs/tower/issues/547 48 | let clone = self.inner.clone(); 49 | let mut inner = std::mem::replace(&mut self.inner, clone); 50 | 51 | let rate_limiter = self.rate_limiter.clone(); 52 | let quota = self.quota; 53 | 54 | Box::pin(async move { 55 | let ip = req 56 | .headers() 57 | .get("x-forwarded-for") 58 | .map(|d| d.to_str().ok()) 59 | .flatten() 60 | .unwrap_or("unknown") 61 | .to_owned(); 62 | 63 | if rate_limiter.check_key(&ip).is_err() { 64 | let res = Response::builder() 65 | .status(429) 66 | .body(box_body(Body::from(format!( 67 | "Rate limit of API calls exceeded. {:?}", 68 | quota 69 | )))) 70 | .expect("Couldn't build body."); 71 | 72 | tracing::warn!(%ip, "Rate limited."); 73 | 74 | return Ok(res); 75 | } 76 | 77 | let res = inner.call(req).await?; 78 | 79 | Ok(res) 80 | }) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/logging.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | 3 | use axum::http::StatusCode; 4 | use tracing_stackdriver::Stackdriver; 5 | use tracing_subscriber::layer::SubscriberExt; 6 | use tracing_subscriber::{EnvFilter, Registry}; 7 | 8 | const LOG_MODULES: &[&str] = &["notify_run"]; 9 | 10 | pub fn init_logging() { 11 | let mut env_filter = EnvFilter::default(); 12 | 13 | for module in LOG_MODULES { 14 | env_filter = env_filter.add_directive( 15 | format!("{}=info", module) 16 | .parse() 17 | .expect("Could not parse logging directive"), 18 | ); 19 | } 20 | 21 | if std::env::var("LOG_JSON").is_ok() { 22 | let stackdriver = Stackdriver::default(); 23 | let subscriber = Registry::default().with(stackdriver).with(env_filter); 24 | 25 | tracing::subscriber::set_global_default(subscriber) 26 | .expect("Could not set up global logger"); 27 | } else { 28 | tracing_subscriber::fmt().with_env_filter(env_filter).init(); 29 | } 30 | } 31 | 32 | pub type WebResult = std::result::Result; 33 | 34 | pub trait LogError { 35 | fn log_error_internal(self) -> WebResult; 36 | fn log_error_bad_request(self) -> WebResult; 37 | fn log_error_not_found(self) -> WebResult; 38 | fn log_error_forbidden(self) -> WebResult; 39 | } 40 | 41 | impl LogError for Result 42 | where 43 | E: Debug, 44 | { 45 | fn log_error_not_found(self) -> WebResult { 46 | match self { 47 | Ok(v) => Ok(v), 48 | Err(error) => { 49 | tracing::error!(?error, "Error: {:?}", error); 50 | 51 | Err(StatusCode::NOT_FOUND) 52 | } 53 | } 54 | } 55 | 56 | fn log_error_forbidden(self) -> WebResult { 57 | match self { 58 | Ok(v) => Ok(v), 59 | Err(error) => { 60 | tracing::error!(?error, "Error: {:?}", error); 61 | 62 | Err(StatusCode::FORBIDDEN) 63 | } 64 | } 65 | } 66 | 67 | fn log_error_internal(self) -> WebResult { 68 | match self { 69 | Ok(v) => Ok(v), 70 | Err(error) => { 71 | tracing::error!(?error, "Error: {:?}", error); 72 | 73 | Err(StatusCode::INTERNAL_SERVER_ERROR) 74 | } 75 | } 76 | } 77 | 78 | fn log_error_bad_request(self) -> WebResult { 79 | match self { 80 | Ok(v) => Ok(v), 81 | Err(error) => { 82 | tracing::error!(?error, "Error: {:?}", error); 83 | 84 | Err(StatusCode::BAD_REQUEST) 85 | } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/migrate.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result; 2 | use chrono::{NaiveDateTime, TimeZone, Utc}; 3 | use serde::Deserialize; 4 | use std::{collections::HashMap, fs::read_to_string, path::PathBuf}; 5 | use tiny_firestore_odm::{Collection, Database}; 6 | 7 | use crate::model::Channel; 8 | 9 | #[derive(Deserialize)] 10 | struct DynamoExport { 11 | #[serde(rename = "Items")] 12 | items: Vec, 13 | } 14 | 15 | #[derive(Deserialize)] 16 | struct DynamoString { 17 | #[serde(rename = "S")] 18 | value: String, 19 | } 20 | 21 | #[derive(Deserialize)] 22 | struct DynamoValue { 23 | #[serde(rename = "M")] 24 | value: T, 25 | } 26 | 27 | #[derive(Deserialize)] 28 | struct Keys { 29 | auth: DynamoString, 30 | p256dh: DynamoString, 31 | } 32 | 33 | #[derive(Deserialize)] 34 | struct Subscription { 35 | endpoint: DynamoString, 36 | keys: DynamoValue, 37 | } 38 | 39 | #[derive(Deserialize)] 40 | struct ChannelMeta { 41 | agent: DynamoString, 42 | ip: DynamoString, 43 | } 44 | 45 | #[derive(Deserialize)] 46 | struct Item { 47 | created: DynamoString, 48 | #[serde(rename = "channelId")] 49 | channel_id: DynamoString, 50 | subscriptions: DynamoValue>>, 51 | meta: DynamoValue, 52 | } 53 | 54 | pub async fn migrate(path: PathBuf, db: Database) -> Result<()> { 55 | let migrate_json = read_to_string(path)?; 56 | 57 | let channels: Collection = db.collection("channels"); 58 | 59 | let migrate: DynamoExport = serde_json::from_str(&migrate_json)?; 60 | 61 | for (index, item) in migrate.items.into_iter().enumerate() { 62 | let channel_id = item.channel_id.value; 63 | let _span = tracing::info_span!("Channel", %channel_id).entered(); 64 | let created_naive = 65 | NaiveDateTime::parse_from_str(&item.created.value, "%Y-%m-%d %H:%M:%S.%f")?; 66 | let created = Utc.from_utc_datetime(&created_naive); 67 | 68 | let channel = Channel { 69 | created, 70 | created_agent: item.meta.value.agent.value, 71 | created_ip: item.meta.value.ip.value, 72 | }; 73 | 74 | tracing::info!(%index, "Inserting channel."); 75 | let created = channels.try_create(&channel, &*channel_id).await?; 76 | tracing::info!(%created, "Success (channel)."); 77 | 78 | for (subscription_id, subscription) in item.subscriptions.value { 79 | let _span = tracing::info_span!("Subscription", %subscription_id).entered(); 80 | let subscriptions: Collection = 81 | channels.subcollection(&channel_id, "subscriptions"); 82 | 83 | let sub = crate::model::Subscription { 84 | endpoint: subscription.value.endpoint.value, 85 | auth: subscription.value.keys.value.auth.value, 86 | p256dh: subscription.value.keys.value.p256dh.value, 87 | }; 88 | 89 | tracing::info!("Inserting subscription."); 90 | let created = subscriptions.try_create(&sub, &*subscription_id).await?; 91 | tracing::info!(%created, "Success (subscription)."); 92 | } 93 | } 94 | 95 | Ok(()) 96 | } 97 | -------------------------------------------------------------------------------- /frontend/src/quickstart/subscribe_stage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { Config } from '../config'; 4 | import { SubscriptionManager } from '../subscription'; 5 | 6 | 7 | interface SubscribeStageProps { 8 | onChannelReady: () => void; 9 | channelId: string; 10 | pubKey: string; 11 | } 12 | 13 | interface SubscribeStageState { 14 | subscribed: boolean, 15 | supported: boolean, 16 | err?: Error, 17 | } 18 | 19 | export class SubscribeStage extends React.Component { 20 | subscriptionManager: SubscriptionManager; 21 | 22 | constructor(props: SubscribeStageProps) { 23 | super(props); 24 | 25 | this.subscriptionManager = new SubscriptionManager(this.props.pubKey); 26 | 27 | this.state = { 28 | subscribed: false, 29 | supported: this.subscriptionManager.checkBrowserSupport() 30 | }; 31 | } 32 | 33 | onSubscribe() { 34 | this.subscriptionManager.subscribe(this.props.channelId).then(() => { 35 | this.setState({ 36 | subscribed: true, 37 | }) 38 | }).catch((e: Error) => { 39 | this.setState({ 40 | err: e 41 | }); 42 | }); 43 | } 44 | 45 | render() { 46 | return
47 |
48 |
49 |

50 | Your new channel is called {this.props.channelId}. 51 |

52 |

53 | To receive notifications on a device (such as a desktop or phone), subscribe them 54 | to your channel. If multiple devices are subscribed to the same channel, 55 | they will all receive notifications. 56 |

57 | { 58 | this.state.supported ? 59 |

Use the button below to subscribe on this device. To subscribe on 60 | a different device, open the URL below or scan this QR code. 61 |

: 62 |

The device or browser you are using does not support the Web Push API, but you can 63 | receive notifications on another device by opening the URL below or scanning the 64 | QR code. 65 |

66 | } 67 | 68 |
{`${Config.WEB_SERVER}/c/${this.props.channelId}\n`}
69 |
70 |

71 | { 72 | this.state.supported ? ( 73 | this.state.subscribed ? 74 | : 76 | 78 | ) : '' 79 | } 80 | 81 |

82 |
83 |
84 | 85 |
86 |
87 | { 88 | this.state.err ? 89 |
90 |
{this.state.err.name}
91 |

{this.state.err.message}

92 |
: '' 93 | } 94 |
; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /frontend/html-src/index.html: -------------------------------------------------------------------------------- 1 |

2 | notify.run lets you send notifications to your own phone or desktop with minimal fuss. This is primarily useful 3 | for tracking the progress of long-running compute jobs. 4 |

5 | 6 |

Quick Start

7 | 8 |
9 |
10 | 11 |

How it Works

12 | 13 |

Each user of notify.run is assigned a 14 | channel, identified by a random string. Devices which support the 15 | Web Push API, including Chrome and Firefox for desktop and Android, can subscribe to notifications on a channel and 16 | show a pop-up notification. Other devices, such as iOS Safari, do not yet support the API needed for background notifications, 17 | but they can still be used to see a list of recent notifications. 18 |

19 | 20 |

21 | Each channel has its own HTTPS endpoint. When you 22 | POST a message to that endpoint, notify.run relays it to every subscription on that channel. 23 |

24 |

25 | notify.run uses standard APIs for both sending and subscribing to notifications, which means that it can be used without 26 | installling any software. If you prefer, you can use the command-line tool and Python package to simplify integration 27 | with your workflow.

28 | 29 |

Integrations

30 | 31 |

Command-line interface

32 | 33 |

34 | The command-line interface and Python API are part of the 35 | notify-run Python package. You can install both using the 36 | pip package manager 37 |

38 | 39 |
pip install notify-run
40 | 41 |

42 | Once it has been installed, you can register a new channel like so: 43 |

44 | 45 |
notify-run register
46 | 47 |

48 | Alternatively, you can configure it to use a channel that already exists: 49 |

50 | 51 |
notify-run configure https://notify.run/[channel name]
52 | 53 |

54 | The configuration is stored in the 55 | ~/.config/notify-run file in your home directory. It will be picked up by subsequent runs of 56 | notify-run as well as the 57 | notify_run 58 | Python module. 59 |

60 | 61 |

Jupyter

62 | 63 | 64 | 65 |

When used inside a Jupyter notebook, the subscribe link is clickable and a QR code is displayed. 66 |

67 | 68 |

Keras

69 | 70 |

Notify includes a callback for 71 | Keras which sends a progress notification at the end of each epoch. After configuring an endpoint above, import 72 | NotifyCallback from 73 | notify_run.keras and pass it in the callback parameter to a Keras 74 | fit method.

75 | 76 |
from notify_run.keras import NotifyCallback
 77 | # model is a Keras model that you have created elsewhere.
 78 | model.fit(x, y, callbacks=[NotifyCallback()])
79 | 80 |

Open source

81 | 82 |

83 | This public instance is freely provided for your convenience, but does not have an 84 | SLA 85 | and should not be used for notification messages containing private data. 86 | Usage is tracked to prevent abuse, and rate limited to 20 API requests per minute. 87 |

88 | 89 |

90 | The server is written in Rust 91 | and available under an MIT license. Self-hosting is possible, but is not a prioritized 92 | use case. 93 |

94 | 95 |

Issues and Questions

96 | 97 |

98 | If you find bugs or have other questions, please 99 | file a bug report, 100 | send me an email, or 101 | tweet at me. 102 |

103 | -------------------------------------------------------------------------------- /src/vapid.rs: -------------------------------------------------------------------------------- 1 | use std::io::Cursor; 2 | 3 | use crate::model::Subscription; 4 | use anyhow::Result; 5 | use serde::{Deserialize, Serialize}; 6 | use web_push::{ 7 | ContentEncoding, SubscriptionInfo, VapidSignatureBuilder, WebPushClient, WebPushMessageBuilder, 8 | }; 9 | 10 | #[derive(Serialize, PartialEq, Debug)] 11 | pub struct MessagePayloadData { 12 | /// URL to open when notification is clicked. 13 | action: String, 14 | } 15 | 16 | #[derive(Serialize, PartialEq, Debug)] 17 | pub struct MessagePayload { 18 | pub message: String, 19 | vibrate: bool, 20 | silent: bool, 21 | channel: String, 22 | data: MessagePayloadData, 23 | } 24 | 25 | #[derive(Deserialize)] 26 | struct MessageFormData { 27 | message: String, 28 | action: Option, 29 | } 30 | 31 | impl MessagePayload { 32 | pub fn parse_new(message: &str, channel: &str, default_action: &str) -> Self { 33 | let message = match serde_urlencoded::from_str::(message) { 34 | Ok(message) => message, 35 | Err(_) => MessageFormData { 36 | message: message.to_string(), 37 | action: None, 38 | }, 39 | }; 40 | 41 | MessagePayload { 42 | message: message.message, 43 | channel: channel.to_string(), 44 | silent: false, 45 | vibrate: false, 46 | data: MessagePayloadData { 47 | action: message.action.unwrap_or_else(|| default_action.to_string()), 48 | }, 49 | } 50 | } 51 | } 52 | 53 | pub async fn send_message( 54 | message: &MessagePayload, 55 | subscription: &Subscription, 56 | vapid_privkey: &[u8], 57 | ) -> Result<()> { 58 | let subscription_info = SubscriptionInfo::new( 59 | subscription.endpoint.clone(), 60 | subscription.p256dh.clone(), 61 | subscription.auth.clone(), 62 | ); 63 | 64 | let cursor = Cursor::new(&vapid_privkey); 65 | let sig_builder = VapidSignatureBuilder::from_der_no_sub(cursor)?; 66 | 67 | let signature = sig_builder 68 | .add_sub_info(&subscription_info) 69 | .build() 70 | .unwrap(); 71 | 72 | let mut builder = WebPushMessageBuilder::new(&subscription_info)?; 73 | let payload_json = serde_json::to_string(message)?; 74 | builder.set_payload(ContentEncoding::Aes128Gcm, payload_json.as_bytes()); 75 | builder.set_vapid_signature(signature); 76 | 77 | let client = WebPushClient::new()?; 78 | client.send(builder.build()?).await?; 79 | 80 | Ok(()) 81 | } 82 | 83 | #[cfg(test)] 84 | mod test { 85 | use super::*; 86 | 87 | #[test] 88 | pub fn test_parse_plain_message() { 89 | let payload = MessagePayload::parse_new("my message", "abcdef", "http://blah/c/abcdef"); 90 | 91 | assert_eq!( 92 | MessagePayload { 93 | message: "my message".to_string(), 94 | channel: "abcdef".to_string(), 95 | vibrate: false, 96 | silent: false, 97 | data: MessagePayloadData { 98 | action: "http://blah/c/abcdef".to_string() 99 | } 100 | }, 101 | payload 102 | ); 103 | } 104 | 105 | #[test] 106 | pub fn test_parse_message() { 107 | let payload = MessagePayload::parse_new( 108 | "message=this+is+my+message", 109 | "abcdef", 110 | "http://blah/c/abcdef", 111 | ); 112 | 113 | assert_eq!( 114 | MessagePayload { 115 | message: "this is my message".to_string(), 116 | channel: "abcdef".to_string(), 117 | vibrate: false, 118 | silent: false, 119 | data: MessagePayloadData { 120 | action: "http://blah/c/abcdef".to_string() 121 | } 122 | }, 123 | payload 124 | ); 125 | } 126 | 127 | #[test] 128 | pub fn test_parse_message_with_action() { 129 | let payload = MessagePayload::parse_new( 130 | "message=this+is+my+message&action=https://www.example.com/", 131 | "abcdef", 132 | "http://blah/c/abcdef", 133 | ); 134 | 135 | assert_eq!( 136 | MessagePayload { 137 | message: "this is my message".to_string(), 138 | channel: "abcdef".to_string(), 139 | vibrate: false, 140 | silent: false, 141 | data: MessagePayloadData { 142 | action: "https://www.example.com/".to_string() 143 | } 144 | }, 145 | payload 146 | ); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /frontend/src/channel.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { NotifyAPI, Message, ChannelResponse } from './api'; 4 | import { SubscriptionManager } from './subscription'; 5 | import { Config } from './config'; 6 | 7 | 8 | interface MessageListProps { 9 | messages: Message[], 10 | } 11 | 12 | class MessageList extends React.Component { 13 | render() { 14 | if (this.props.messages.length == 0) { 15 | return
Messages to this channel will appear here.
; 16 | } 17 | 18 | return
19 |
20 | { 21 | this.props.messages.map((message: Message, i: number) => 22 |
23 |
24 |
25 | {message.message} 26 |
{message.time}
27 |
28 | { 29 | message.result ? message.result.map((result) => 30 |
31 | { 32 | result.result_status == '201' ? 33 | 34 | : 35 | } 36 | {result.endpoint_domain}: {result.result_status}
37 | ) : null 38 | } 39 |
40 |
) 41 | } 42 |
; 43 | } 44 | } 45 | 46 | interface ChannelPageProps { 47 | channelId: string, 48 | } 49 | 50 | interface ChannelPageState { 51 | messages: Message[], 52 | loading: boolean, 53 | subscribed: boolean, 54 | subscribeDisabled: boolean, 55 | error?: string, 56 | } 57 | 58 | export class ChannelPage extends React.Component { 59 | subscriptionManager: SubscriptionManager; 60 | 61 | constructor(props: any) { 62 | super(props); 63 | 64 | this.state = { 65 | messages: [], 66 | loading: true, 67 | subscribed: false, 68 | subscribeDisabled: false 69 | }; 70 | } 71 | 72 | loadChannel() { 73 | NotifyAPI.fetchChannel(this.props.channelId).then((response) => { 74 | if (response.error) { 75 | if (this.state.loading) { 76 | this.setState({ 77 | loading: false, 78 | error: response.error 79 | }) 80 | } 81 | return 82 | } 83 | 84 | this.subscriptionManager = new SubscriptionManager(response.pubKey); 85 | this.subscriptionManager.getSubscription().then((k) => { 86 | let subscribed = (response.subscriptions.indexOf(k.id) >= 0); 87 | this.setState({ 88 | subscribed: subscribed, 89 | }); 90 | }).catch(() => { 91 | // This exacerbates #10; disabling for now. 92 | /* 93 | this.setState({ 94 | subscribeDisabled: true 95 | }) 96 | */ 97 | }); 98 | 99 | this.setState({ 100 | messages: response.messages || [], 101 | loading: false, 102 | }); 103 | }).catch((reason) => { 104 | if (this.state.loading) { 105 | this.setState({ 106 | loading: false, 107 | error: reason.message, 108 | }) 109 | } 110 | }) 111 | } 112 | 113 | componentDidMount() { 114 | document.title = `channel ${this.props.channelId}`; 115 | 116 | this.loadChannel(); 117 | 118 | setInterval(this.loadChannel.bind(this), 30 * 1000); 119 | } 120 | 121 | onSubscribe() { 122 | this.subscriptionManager.subscribe(this.props.channelId).then(() => { 123 | this.setState({ 124 | subscribed: true, 125 | }) 126 | }).catch((e: Error) => { 127 | console.log(e); 128 | }); 129 | } 130 | 131 | render() { 132 | if (this.state.loading) { 133 | return
; 134 | } else if (this.state.error) { 135 | return
{this.state.error}
136 | } 137 | 138 | let channelEndpoint = `${Config.API_SERVER}/${this.props.channelId}` 139 | let webLink = `${Config.WEB_SERVER}/c/${this.props.channelId}`; 140 | return
141 |

Channel {this.props.channelId}

142 |

Recent messages

143 | 144 | 145 |

Send Messages

146 |

To send the channel a message, run this command:

147 | 148 |
curl {channelEndpoint} -d "message goes here"
149 | 150 |

Add Subscription

151 | 152 |

Subscribe on this device using the button below.

153 |

{ 154 | this.state.subscribeDisabled ? 155 | : 157 | (this.state.subscribed ? 158 | : 160 | 162 | ) 163 | } 164 |

165 |

Subscribe on another device by opening {webLink} or scanning the QR code below.

166 | 167 | 168 |
169 | } 170 | } 171 | -------------------------------------------------------------------------------- /src/server.rs: -------------------------------------------------------------------------------- 1 | use crate::logging::LogError; 2 | use crate::model::{ 3 | Channel, Message, MessageResult, Subscription, MESSAGES_COLLECTION, SUBSCRIPTIONS_COLLECTION, 4 | }; 5 | use crate::rate_limiter::RateLimiterMiddleware; 6 | use crate::server_state::ServerState; 7 | use crate::vapid::{send_message, MessagePayload}; 8 | use axum::body::{Body, Bytes}; 9 | use axum::extract::{ConnectInfo, TypedHeader}; 10 | use axum::http::{Response, Uri}; 11 | use axum::{ 12 | extract::{Extension, Path}, 13 | routing::{get, post}, 14 | http::StatusCode, 15 | AddExtensionLayer, Json, Router, 16 | error_handling::HandleErrorExt, 17 | }; 18 | use chrono::{DateTime, Utc}; 19 | use futures::future::join_all; 20 | use governor::Quota; 21 | use headers::{HeaderMap, HeaderName, HeaderValue, UserAgent}; 22 | use nonzero_ext::nonzero; 23 | use qrcode::render::svg; 24 | use serde::{Deserialize, Serialize}; 25 | use std::convert::Infallible; 26 | use std::net::SocketAddr; 27 | use std::str::FromStr; 28 | use std::time::Duration; 29 | use tiny_firestore_odm::Collection; 30 | use tokio::time::timeout; 31 | use tower::layer::layer_fn; 32 | use tower_http::services::ServeDir; 33 | use tower_http::services::ServeFile; 34 | 35 | /// Timeout (seconds) of external service when invoking push request. 36 | const TIMEOUT_SECS: u64 = 10; 37 | 38 | /// Rate limit on calls that access database. 39 | const MAX_REQUESTS_PER_MINUTE: u32 = 10; 40 | 41 | #[derive(Serialize)] 42 | struct MessageInfo { 43 | message: String, 44 | result: Vec, 45 | time: DateTime, 46 | } 47 | 48 | #[derive(Serialize)] 49 | struct ChannelInfo { 50 | #[serde(rename = "channelId")] 51 | channel_id: String, 52 | 53 | messages: Vec, 54 | 55 | time: String, 56 | 57 | #[serde(rename = "pubKey")] 58 | pub_key: String, 59 | 60 | endpoint: String, 61 | channel_page: String, 62 | } 63 | 64 | async fn register_channel( 65 | ConnectInfo(addr): ConnectInfo, 66 | TypedHeader(user_agent): TypedHeader, 67 | server_state: Extension, 68 | ) -> Result, StatusCode> { 69 | let db = server_state.db().await.log_error_internal()?; 70 | let ip: String = addr.ip().to_string(); 71 | 72 | let channels = db.channels(); 73 | 74 | let channel_id = channels 75 | .create(&Channel { 76 | created: Utc::now(), 77 | created_agent: user_agent.to_string(), 78 | created_ip: ip.clone(), 79 | }) 80 | .await 81 | .log_error_internal()? 82 | .leaf_name() 83 | .to_string(); 84 | 85 | tracing::info!(%channel_id, %ip, "Channel created."); 86 | 87 | Ok(Json(ChannelInfo { 88 | messages: Vec::new(), 89 | time: "".to_string(), 90 | pub_key: server_state.vapid_pubkey.to_string(), 91 | endpoint: server_state.endpoint_url(&channel_id), 92 | channel_page: server_state.channel_page_url(&channel_id), 93 | channel_id, 94 | })) 95 | } 96 | 97 | async fn info( 98 | server_state: Extension, 99 | Path(channel_id): Path, 100 | ) -> Result, StatusCode> { 101 | let db = server_state.db().await.log_error_internal()?; 102 | 103 | let channels = db.channels(); 104 | channels.get(&*channel_id).await.log_error_not_found()?; 105 | 106 | let messages: Collection = channels.subcollection(&channel_id, MESSAGES_COLLECTION); 107 | 108 | let messages = messages 109 | .list() 110 | .with_order_by("message_time desc") 111 | .with_page_size(10) 112 | .get_page() 113 | .await; 114 | 115 | Ok(Json(ChannelInfo { 116 | messages: messages 117 | .into_iter() 118 | .map(|d| MessageInfo { 119 | message: d.value.message, 120 | result: d.value.result, 121 | time: d.value.message_time, 122 | }) 123 | .collect(), 124 | time: "".to_string(), 125 | pub_key: server_state.vapid_pubkey.to_string(), 126 | endpoint: server_state.endpoint_url(&channel_id), 127 | channel_page: server_state.channel_page_url(&channel_id), 128 | channel_id, 129 | })) 130 | } 131 | 132 | async fn send_message_with_timeout( 133 | payload: &MessagePayload, 134 | subscription: Subscription, 135 | privkey: &[u8], 136 | duration: Duration, 137 | ) -> MessageResult { 138 | let result = timeout(duration, send_message(payload, &subscription, privkey)).await; 139 | 140 | let result_status = match result { 141 | Ok(Ok(_)) => "201".to_string(), 142 | Ok(Err(e)) => e.to_string(), 143 | Err(_) => "Timed out.".to_string(), 144 | }; 145 | 146 | let endpoint_domain = Uri::from_str(&subscription.endpoint) 147 | .ok() 148 | .map(|d| d.authority().map(|d| d.to_string())) 149 | .flatten() 150 | .unwrap_or_default(); 151 | 152 | MessageResult { 153 | result_status, 154 | endpoint_domain, 155 | } 156 | } 157 | 158 | async fn send( 159 | server_state: Extension, 160 | Path(channel_id): Path, 161 | message: String, 162 | ConnectInfo(addr): ConnectInfo, 163 | ) -> Result { 164 | let db = server_state.db().await.log_error_internal()?; 165 | 166 | let channels = db.channels(); 167 | channels.get(&*channel_id).await.log_error_not_found()?; 168 | 169 | // Send to subscriptions. 170 | 171 | let subscriptions: Collection = 172 | channels.subcollection(&channel_id, SUBSCRIPTIONS_COLLECTION); 173 | 174 | let payload = MessagePayload::parse_new( 175 | &message, 176 | &*channel_id, 177 | &server_state.channel_page_url(&*channel_id), 178 | ); 179 | // let mut message_result = Vec::new(); 180 | let mut futures = Vec::new(); 181 | 182 | let subscriptions = subscriptions.list().with_page_size(10).get_page().await; 183 | for subscription in subscriptions { 184 | futures.push(send_message_with_timeout( 185 | &payload, 186 | subscription.value, 187 | &server_state.vapid_privkey, 188 | Duration::from_secs(TIMEOUT_SECS), 189 | )); 190 | } 191 | 192 | let message_result = join_all(futures.into_iter()).await; 193 | 194 | tracing::info!(%channel_id, ?message_result, "Message sent."); 195 | 196 | // Store message. 197 | let messages: Collection = channels.subcollection(&channel_id, MESSAGES_COLLECTION); 198 | 199 | messages 200 | .create(&Message { 201 | message: payload.message.to_string(), 202 | message_time: Utc::now(), 203 | sender_ip: addr.ip().to_string(), 204 | result: message_result, 205 | }) 206 | .await 207 | .log_error_internal()?; 208 | 209 | Ok("ok".to_string()) 210 | } 211 | 212 | #[derive(Deserialize)] 213 | struct SubscriptionRequestKeys { 214 | auth: String, 215 | p256dh: String, 216 | } 217 | 218 | #[derive(Deserialize)] 219 | struct SubscriptionRequestSubscription { 220 | endpoint: String, 221 | keys: SubscriptionRequestKeys, 222 | } 223 | 224 | #[derive(Deserialize)] 225 | struct SubscriptionRequest { 226 | id: String, 227 | subscription: SubscriptionRequestSubscription, 228 | } 229 | 230 | async fn subscribe( 231 | subscription: Json, 232 | server_state: Extension, 233 | Path(channel_id): Path, 234 | ) -> Result, StatusCode> { 235 | let db = server_state.db().await.log_error_internal()?; 236 | 237 | let channels = db.channels(); 238 | channels.get(&*channel_id).await.log_error_not_found()?; 239 | 240 | let subscriptions: Collection = 241 | channels.subcollection(&channel_id, SUBSCRIPTIONS_COLLECTION); 242 | 243 | let subscription_id = subscription.id.clone(); 244 | 245 | subscriptions 246 | .try_create( 247 | &Subscription { 248 | endpoint: subscription.0.subscription.endpoint, 249 | auth: subscription.0.subscription.keys.auth, 250 | p256dh: subscription.0.subscription.keys.p256dh, 251 | }, 252 | &*subscription_id, 253 | ) 254 | .await 255 | .log_error_internal()?; 256 | 257 | Ok(Json(())) 258 | } 259 | 260 | async fn render_qr_code( 261 | server_state: Extension, 262 | Path(channel_id): Path, 263 | ) -> (HeaderMap, Bytes) { 264 | let url = format!("{}/c/{}", server_state.server_base, channel_id); 265 | 266 | let img: String = qrcode::QrCode::new(url.as_bytes()) 267 | .unwrap() 268 | .render() 269 | .min_dimensions(200, 200) 270 | .dark_color(svg::Color("#000000")) 271 | .light_color(svg::Color("#ffffff")) 272 | .build(); 273 | 274 | let mut headers = HeaderMap::new(); 275 | headers.insert( 276 | HeaderName::from_static("content-type"), 277 | HeaderValue::from_static("image/svg+xml"), 278 | ); 279 | 280 | let b = Bytes::from(img); 281 | 282 | (headers, b) 283 | } 284 | 285 | fn static_routes() -> Router { 286 | Router::new() 287 | .route( 288 | "/", 289 | axum::routing::service_method_routing::get(ServeFile::new("static/index.html")) 290 | .handle_error(|_| Ok::<_, Infallible>(StatusCode::NOT_FOUND)), 291 | ) 292 | .nest( 293 | "/static", 294 | axum::routing::service_method_routing::get(ServeDir::new("static/")) 295 | .handle_error(|_| Ok::<_, Infallible>(StatusCode::NOT_FOUND)), 296 | ) 297 | .nest( 298 | "/c/:channel_id", 299 | axum::routing::service_method_routing::get(ServeFile::new("static/channel.html")) 300 | .handle_error(|_| Ok::<_, Infallible>(StatusCode::NOT_FOUND)), 301 | ) 302 | } 303 | 304 | pub async fn redirect( 305 | server_state: Extension, 306 | Path(channel_id): Path, 307 | ) -> Response { 308 | if channel_id.len() > 6 && channel_id.chars().all(|c| char::is_ascii_alphanumeric(&c)) { 309 | let new_location = server_state.channel_page_url(&*channel_id); 310 | Response::builder() 311 | .status(302) 312 | .header( 313 | HeaderName::from_static("location"), 314 | HeaderValue::from_str(&new_location).unwrap(), 315 | ) 316 | .body(Body::empty()) 317 | .unwrap() 318 | } else { 319 | Response::builder().status(404).body(Body::empty()).unwrap() 320 | } 321 | } 322 | 323 | /// Bad JavaScript clients access /undefined so frequently that we short-circuit it. 324 | pub async fn undefined() -> (StatusCode, &'static str) { 325 | (StatusCode::NOT_FOUND, "No such channel.") 326 | } 327 | 328 | /// The old service worker was not in the /static/ directory and still persists on some clients. 329 | pub async fn moved_service_worker(server_state: Extension) -> Response { 330 | Response::builder() 331 | .status(301) 332 | .header( 333 | HeaderName::from_static("location"), 334 | HeaderValue::from_str(&format!( 335 | "{}/static/service-worker.js", 336 | server_state.server_base 337 | )) 338 | .unwrap(), 339 | ) 340 | .body(Body::empty()) 341 | .unwrap() 342 | } 343 | 344 | async fn active_routes() -> Router { 345 | let server_state = ServerState::new().await; 346 | 347 | Router::new() 348 | .route("/service-worker.js", get(moved_service_worker)) 349 | .route("/:channel_id/qr.svg", get(render_qr_code)) 350 | .route("/:channel_id/json", get(info)) 351 | .route("/:channel_id/subscribe", post(subscribe)) 352 | .route("/api/register_channel", post(register_channel)) 353 | .route("/register_channel", post(register_channel)) // Used by py client. 354 | .route("/:channel_id", get(redirect).post(send)) 355 | .layer(AddExtensionLayer::new(server_state)) 356 | .layer(layer_fn(|inner| { 357 | RateLimiterMiddleware::new(inner, Quota::per_minute(nonzero!(MAX_REQUESTS_PER_MINUTE))) 358 | })) 359 | } 360 | 361 | pub async fn serve(port: Option) -> anyhow::Result<()> { 362 | let port: u16 = if let Some(port) = port { 363 | port 364 | } else if let Ok(port) = std::env::var("PORT") { 365 | port.parse()? 366 | } else { 367 | 8080 368 | }; 369 | 370 | let app = Router::new() 371 | .route("/undefined", get(undefined).post(undefined)) 372 | .merge(active_routes().await) 373 | .fallback(static_routes()); 374 | 375 | let addr = SocketAddr::from(([0, 0, 0, 0], port)); 376 | tracing::info!("listening on {}", addr); 377 | axum::Server::bind(&addr) 378 | .serve(app.into_make_service_with_connect_info::()) 379 | .await?; 380 | 381 | Ok(()) 382 | } 383 | -------------------------------------------------------------------------------- /frontend/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@discoveryjs/json-ext@^0.5.0": 6 | "integrity" "sha512-6nFkfkmSeV/rqSaS4oWHgmpnYw194f6hmWF5is6b0J1naJZoiD0NTc9AiUwPHvWsowkjuHErCZT1wa0jg+BLIA==" 7 | "resolved" "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.5.tgz" 8 | "version" "0.5.5" 9 | 10 | "@types/eslint-scope@^3.7.0": 11 | "integrity" "sha512-SCFeogqiptms4Fg29WpOTk5nHIzfpKCemSN63ksBQYKTcXoJEmJagV+DhVmbapZzY4/5YaOV1nZwrsU79fFm1g==" 12 | "resolved" "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.1.tgz" 13 | "version" "3.7.1" 14 | dependencies: 15 | "@types/eslint" "*" 16 | "@types/estree" "*" 17 | 18 | "@types/eslint@*": 19 | "integrity" "sha512-KubbADPkfoU75KgKeKLsFHXnU4ipH7wYg0TRT33NK3N3yiu7jlFAAoygIWBV+KbuHx/G+AvuGX6DllnK35gfJA==" 20 | "resolved" "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.2.tgz" 21 | "version" "7.28.2" 22 | dependencies: 23 | "@types/estree" "*" 24 | "@types/json-schema" "*" 25 | 26 | "@types/estree@*", "@types/estree@^0.0.50": 27 | "integrity" "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==" 28 | "resolved" "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz" 29 | "version" "0.0.50" 30 | 31 | "@types/json-schema@*", "@types/json-schema@^7.0.8": 32 | "integrity" "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==" 33 | "resolved" "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz" 34 | "version" "7.0.9" 35 | 36 | "@types/node@*", "@types/node@^10.12.18": 37 | "integrity" "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==" 38 | "resolved" "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz" 39 | "version" "10.17.60" 40 | 41 | "@types/prop-types@*": 42 | "integrity" "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" 43 | "resolved" "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz" 44 | "version" "15.7.4" 45 | 46 | "@types/react-dom@^16.0.3": 47 | "integrity" "sha512-FIX2AVmPTGP30OUJ+0vadeIFJJ07Mh1m+U0rxfgyW34p3rTlXI+nlenvAxNn4BP36YyI9IJ/+UJ7Wu22N1pI7A==" 48 | "resolved" "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.14.tgz" 49 | "version" "16.9.14" 50 | dependencies: 51 | "@types/react" "^16" 52 | 53 | "@types/react@^16", "@types/react@^16.0.35": 54 | "integrity" "sha512-NHSXGpkJLcP5slugb/l0PhXoPRbHPvTpMraP9n8WS4mTP4cr/Y9QfK9reGq5WFKGYV73dM1uN4eDpqrr74fyQg==" 55 | "resolved" "https://registry.npmjs.org/@types/react/-/react-16.14.19.tgz" 56 | "version" "16.14.19" 57 | dependencies: 58 | "@types/prop-types" "*" 59 | "@types/scheduler" "*" 60 | "csstype" "^3.0.2" 61 | 62 | "@types/scheduler@*": 63 | "integrity" "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" 64 | "resolved" "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz" 65 | "version" "0.16.2" 66 | 67 | "@webassemblyjs/ast@1.11.1": 68 | "integrity" "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==" 69 | "resolved" "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz" 70 | "version" "1.11.1" 71 | dependencies: 72 | "@webassemblyjs/helper-numbers" "1.11.1" 73 | "@webassemblyjs/helper-wasm-bytecode" "1.11.1" 74 | 75 | "@webassemblyjs/floating-point-hex-parser@1.11.1": 76 | "integrity" "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==" 77 | "resolved" "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz" 78 | "version" "1.11.1" 79 | 80 | "@webassemblyjs/helper-api-error@1.11.1": 81 | "integrity" "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==" 82 | "resolved" "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz" 83 | "version" "1.11.1" 84 | 85 | "@webassemblyjs/helper-buffer@1.11.1": 86 | "integrity" "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==" 87 | "resolved" "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz" 88 | "version" "1.11.1" 89 | 90 | "@webassemblyjs/helper-numbers@1.11.1": 91 | "integrity" "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==" 92 | "resolved" "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz" 93 | "version" "1.11.1" 94 | dependencies: 95 | "@webassemblyjs/floating-point-hex-parser" "1.11.1" 96 | "@webassemblyjs/helper-api-error" "1.11.1" 97 | "@xtuc/long" "4.2.2" 98 | 99 | "@webassemblyjs/helper-wasm-bytecode@1.11.1": 100 | "integrity" "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==" 101 | "resolved" "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz" 102 | "version" "1.11.1" 103 | 104 | "@webassemblyjs/helper-wasm-section@1.11.1": 105 | "integrity" "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==" 106 | "resolved" "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz" 107 | "version" "1.11.1" 108 | dependencies: 109 | "@webassemblyjs/ast" "1.11.1" 110 | "@webassemblyjs/helper-buffer" "1.11.1" 111 | "@webassemblyjs/helper-wasm-bytecode" "1.11.1" 112 | "@webassemblyjs/wasm-gen" "1.11.1" 113 | 114 | "@webassemblyjs/ieee754@1.11.1": 115 | "integrity" "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==" 116 | "resolved" "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz" 117 | "version" "1.11.1" 118 | dependencies: 119 | "@xtuc/ieee754" "^1.2.0" 120 | 121 | "@webassemblyjs/leb128@1.11.1": 122 | "integrity" "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==" 123 | "resolved" "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz" 124 | "version" "1.11.1" 125 | dependencies: 126 | "@xtuc/long" "4.2.2" 127 | 128 | "@webassemblyjs/utf8@1.11.1": 129 | "integrity" "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==" 130 | "resolved" "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz" 131 | "version" "1.11.1" 132 | 133 | "@webassemblyjs/wasm-edit@1.11.1": 134 | "integrity" "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==" 135 | "resolved" "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz" 136 | "version" "1.11.1" 137 | dependencies: 138 | "@webassemblyjs/ast" "1.11.1" 139 | "@webassemblyjs/helper-buffer" "1.11.1" 140 | "@webassemblyjs/helper-wasm-bytecode" "1.11.1" 141 | "@webassemblyjs/helper-wasm-section" "1.11.1" 142 | "@webassemblyjs/wasm-gen" "1.11.1" 143 | "@webassemblyjs/wasm-opt" "1.11.1" 144 | "@webassemblyjs/wasm-parser" "1.11.1" 145 | "@webassemblyjs/wast-printer" "1.11.1" 146 | 147 | "@webassemblyjs/wasm-gen@1.11.1": 148 | "integrity" "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==" 149 | "resolved" "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz" 150 | "version" "1.11.1" 151 | dependencies: 152 | "@webassemblyjs/ast" "1.11.1" 153 | "@webassemblyjs/helper-wasm-bytecode" "1.11.1" 154 | "@webassemblyjs/ieee754" "1.11.1" 155 | "@webassemblyjs/leb128" "1.11.1" 156 | "@webassemblyjs/utf8" "1.11.1" 157 | 158 | "@webassemblyjs/wasm-opt@1.11.1": 159 | "integrity" "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==" 160 | "resolved" "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz" 161 | "version" "1.11.1" 162 | dependencies: 163 | "@webassemblyjs/ast" "1.11.1" 164 | "@webassemblyjs/helper-buffer" "1.11.1" 165 | "@webassemblyjs/wasm-gen" "1.11.1" 166 | "@webassemblyjs/wasm-parser" "1.11.1" 167 | 168 | "@webassemblyjs/wasm-parser@1.11.1": 169 | "integrity" "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==" 170 | "resolved" "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz" 171 | "version" "1.11.1" 172 | dependencies: 173 | "@webassemblyjs/ast" "1.11.1" 174 | "@webassemblyjs/helper-api-error" "1.11.1" 175 | "@webassemblyjs/helper-wasm-bytecode" "1.11.1" 176 | "@webassemblyjs/ieee754" "1.11.1" 177 | "@webassemblyjs/leb128" "1.11.1" 178 | "@webassemblyjs/utf8" "1.11.1" 179 | 180 | "@webassemblyjs/wast-printer@1.11.1": 181 | "integrity" "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==" 182 | "resolved" "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz" 183 | "version" "1.11.1" 184 | dependencies: 185 | "@webassemblyjs/ast" "1.11.1" 186 | "@xtuc/long" "4.2.2" 187 | 188 | "@webpack-cli/configtest@^1.1.0": 189 | "integrity" "sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg==" 190 | "resolved" "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.0.tgz" 191 | "version" "1.1.0" 192 | 193 | "@webpack-cli/info@^1.4.0": 194 | "integrity" "sha512-F6b+Man0rwE4n0409FyAJHStYA5OIZERxmnUfLVwv0mc0V1wLad3V7jqRlMkgKBeAq07jUvglacNaa6g9lOpuw==" 195 | "resolved" "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.0.tgz" 196 | "version" "1.4.0" 197 | dependencies: 198 | "envinfo" "^7.7.3" 199 | 200 | "@webpack-cli/serve@^1.6.0": 201 | "integrity" "sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA==" 202 | "resolved" "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.0.tgz" 203 | "version" "1.6.0" 204 | 205 | "@xtuc/ieee754@^1.2.0": 206 | "integrity" "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" 207 | "resolved" "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz" 208 | "version" "1.2.0" 209 | 210 | "@xtuc/long@4.2.2": 211 | "integrity" "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" 212 | "resolved" "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz" 213 | "version" "4.2.2" 214 | 215 | "acorn-import-assertions@^1.7.6": 216 | "integrity" "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==" 217 | "resolved" "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz" 218 | "version" "1.8.0" 219 | 220 | "acorn@^8", "acorn@^8.4.1": 221 | "integrity" "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==" 222 | "resolved" "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz" 223 | "version" "8.5.0" 224 | 225 | "ajv-keywords@^3.5.2": 226 | "integrity" "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==" 227 | "resolved" "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz" 228 | "version" "3.5.2" 229 | 230 | "ajv@^6.12.5", "ajv@^6.9.1": 231 | "integrity" "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==" 232 | "resolved" "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" 233 | "version" "6.12.6" 234 | dependencies: 235 | "fast-deep-equal" "^3.1.1" 236 | "fast-json-stable-stringify" "^2.0.0" 237 | "json-schema-traverse" "^0.4.1" 238 | "uri-js" "^4.2.2" 239 | 240 | "ansi-styles@^4.1.0": 241 | "integrity" "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==" 242 | "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" 243 | "version" "4.3.0" 244 | dependencies: 245 | "color-convert" "^2.0.1" 246 | 247 | "braces@^3.0.1": 248 | "integrity" "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==" 249 | "resolved" "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" 250 | "version" "3.0.2" 251 | dependencies: 252 | "fill-range" "^7.0.1" 253 | 254 | "browserslist@^4.14.5": 255 | "integrity" "sha512-I3ekeB92mmpctWBoLXe0d5wPS2cBuRvvW0JyyJHMrk9/HmP2ZjrTboNAZ8iuGqaEIlKguljbQY32OkOJIRrgoA==" 256 | "resolved" "https://registry.npmjs.org/browserslist/-/browserslist-4.17.5.tgz" 257 | "version" "4.17.5" 258 | dependencies: 259 | "caniuse-lite" "^1.0.30001271" 260 | "electron-to-chromium" "^1.3.878" 261 | "escalade" "^3.1.1" 262 | "node-releases" "^2.0.1" 263 | "picocolors" "^1.0.0" 264 | 265 | "buffer-from@^1.0.0": 266 | "integrity" "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" 267 | "resolved" "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" 268 | "version" "1.1.2" 269 | 270 | "caniuse-lite@^1.0.30001271": 271 | "integrity" "sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA==" 272 | "resolved" "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001271.tgz" 273 | "version" "1.0.30001271" 274 | 275 | "chalk@^4.1.0": 276 | "integrity" "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==" 277 | "resolved" "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" 278 | "version" "4.1.2" 279 | dependencies: 280 | "ansi-styles" "^4.1.0" 281 | "supports-color" "^7.1.0" 282 | 283 | "chrome-trace-event@^1.0.2": 284 | "integrity" "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" 285 | "resolved" "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz" 286 | "version" "1.0.3" 287 | 288 | "clone-deep@^4.0.1": 289 | "integrity" "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==" 290 | "resolved" "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz" 291 | "version" "4.0.1" 292 | dependencies: 293 | "is-plain-object" "^2.0.4" 294 | "kind-of" "^6.0.2" 295 | "shallow-clone" "^3.0.0" 296 | 297 | "color-convert@^2.0.1": 298 | "integrity" "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==" 299 | "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" 300 | "version" "2.0.1" 301 | dependencies: 302 | "color-name" "~1.1.4" 303 | 304 | "color-name@~1.1.4": 305 | "integrity" "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" 306 | "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" 307 | "version" "1.1.4" 308 | 309 | "colorette@^2.0.14": 310 | "integrity" "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==" 311 | "resolved" "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz" 312 | "version" "2.0.16" 313 | 314 | "commander@^2.20.0": 315 | "integrity" "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" 316 | "resolved" "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" 317 | "version" "2.20.3" 318 | 319 | "commander@^7.0.0": 320 | "integrity" "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" 321 | "resolved" "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz" 322 | "version" "7.2.0" 323 | 324 | "cross-spawn@^7.0.3": 325 | "integrity" "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==" 326 | "resolved" "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" 327 | "version" "7.0.3" 328 | dependencies: 329 | "path-key" "^3.1.0" 330 | "shebang-command" "^2.0.0" 331 | "which" "^2.0.1" 332 | 333 | "csstype@^3.0.2": 334 | "integrity" "sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw==" 335 | "resolved" "https://registry.npmjs.org/csstype/-/csstype-3.0.9.tgz" 336 | "version" "3.0.9" 337 | 338 | "electron-to-chromium@^1.3.878": 339 | "integrity" "sha512-O6yxWCN9ph2AdspAIszBnd9v8s11hQx8ub9w4UGApzmNRnoKhbulOWqbO8THEQec/aEHtvy+donHZMlh6l1rbA==" 340 | "resolved" "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.878.tgz" 341 | "version" "1.3.878" 342 | 343 | "enhanced-resolve@^5.0.0", "enhanced-resolve@^5.8.3": 344 | "integrity" "sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA==" 345 | "resolved" "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz" 346 | "version" "5.8.3" 347 | dependencies: 348 | "graceful-fs" "^4.2.4" 349 | "tapable" "^2.2.0" 350 | 351 | "envinfo@^7.7.3": 352 | "integrity" "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==" 353 | "resolved" "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz" 354 | "version" "7.8.1" 355 | 356 | "es-module-lexer@^0.9.0": 357 | "integrity" "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==" 358 | "resolved" "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz" 359 | "version" "0.9.3" 360 | 361 | "escalade@^3.1.1": 362 | "integrity" "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" 363 | "resolved" "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" 364 | "version" "3.1.1" 365 | 366 | "eslint-scope@5.1.1": 367 | "integrity" "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==" 368 | "resolved" "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" 369 | "version" "5.1.1" 370 | dependencies: 371 | "esrecurse" "^4.3.0" 372 | "estraverse" "^4.1.1" 373 | 374 | "esrecurse@^4.3.0": 375 | "integrity" "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==" 376 | "resolved" "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" 377 | "version" "4.3.0" 378 | dependencies: 379 | "estraverse" "^5.2.0" 380 | 381 | "estraverse@^4.1.1": 382 | "integrity" "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" 383 | "resolved" "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" 384 | "version" "4.3.0" 385 | 386 | "estraverse@^5.2.0": 387 | "integrity" "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" 388 | "resolved" "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz" 389 | "version" "5.2.0" 390 | 391 | "events@^3.2.0": 392 | "integrity" "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" 393 | "resolved" "https://registry.npmjs.org/events/-/events-3.3.0.tgz" 394 | "version" "3.3.0" 395 | 396 | "execa@^5.0.0": 397 | "integrity" "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==" 398 | "resolved" "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz" 399 | "version" "5.1.1" 400 | dependencies: 401 | "cross-spawn" "^7.0.3" 402 | "get-stream" "^6.0.0" 403 | "human-signals" "^2.1.0" 404 | "is-stream" "^2.0.0" 405 | "merge-stream" "^2.0.0" 406 | "npm-run-path" "^4.0.1" 407 | "onetime" "^5.1.2" 408 | "signal-exit" "^3.0.3" 409 | "strip-final-newline" "^2.0.0" 410 | 411 | "fast-deep-equal@^3.1.1": 412 | "integrity" "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" 413 | "resolved" "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" 414 | "version" "3.1.3" 415 | 416 | "fast-json-stable-stringify@^2.0.0": 417 | "integrity" "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" 418 | "resolved" "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" 419 | "version" "2.1.0" 420 | 421 | "fastest-levenshtein@^1.0.12": 422 | "integrity" "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==" 423 | "resolved" "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz" 424 | "version" "1.0.12" 425 | 426 | "fill-range@^7.0.1": 427 | "integrity" "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==" 428 | "resolved" "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" 429 | "version" "7.0.1" 430 | dependencies: 431 | "to-regex-range" "^5.0.1" 432 | 433 | "find-up@^4.0.0": 434 | "integrity" "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==" 435 | "resolved" "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" 436 | "version" "4.1.0" 437 | dependencies: 438 | "locate-path" "^5.0.0" 439 | "path-exists" "^4.0.0" 440 | 441 | "function-bind@^1.1.1": 442 | "integrity" "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 443 | "resolved" "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" 444 | "version" "1.1.1" 445 | 446 | "get-stream@^6.0.0": 447 | "integrity" "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" 448 | "resolved" "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" 449 | "version" "6.0.1" 450 | 451 | "glob-to-regexp@^0.4.1": 452 | "integrity" "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" 453 | "resolved" "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz" 454 | "version" "0.4.1" 455 | 456 | "graceful-fs@^4.1.2", "graceful-fs@^4.2.4": 457 | "integrity" "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" 458 | "resolved" "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz" 459 | "version" "4.2.8" 460 | 461 | "has-flag@^4.0.0": 462 | "integrity" "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" 463 | "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" 464 | "version" "4.0.0" 465 | 466 | "has@^1.0.3": 467 | "integrity" "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==" 468 | "resolved" "https://registry.npmjs.org/has/-/has-1.0.3.tgz" 469 | "version" "1.0.3" 470 | dependencies: 471 | "function-bind" "^1.1.1" 472 | 473 | "human-signals@^2.1.0": 474 | "integrity" "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" 475 | "resolved" "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" 476 | "version" "2.1.0" 477 | 478 | "import-local@^3.0.2": 479 | "integrity" "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==" 480 | "resolved" "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz" 481 | "version" "3.0.3" 482 | dependencies: 483 | "pkg-dir" "^4.2.0" 484 | "resolve-cwd" "^3.0.0" 485 | 486 | "interpret@^2.2.0": 487 | "integrity" "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==" 488 | "resolved" "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz" 489 | "version" "2.2.0" 490 | 491 | "is-core-module@^2.2.0": 492 | "integrity" "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==" 493 | "resolved" "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz" 494 | "version" "2.8.0" 495 | dependencies: 496 | "has" "^1.0.3" 497 | 498 | "is-number@^7.0.0": 499 | "integrity" "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" 500 | "resolved" "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" 501 | "version" "7.0.0" 502 | 503 | "is-plain-object@^2.0.4": 504 | "integrity" "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==" 505 | "resolved" "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz" 506 | "version" "2.0.4" 507 | dependencies: 508 | "isobject" "^3.0.1" 509 | 510 | "is-stream@^2.0.0": 511 | "integrity" "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" 512 | "resolved" "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" 513 | "version" "2.0.1" 514 | 515 | "isexe@^2.0.0": 516 | "integrity" "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" 517 | "resolved" "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" 518 | "version" "2.0.0" 519 | 520 | "isobject@^3.0.1": 521 | "integrity" "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" 522 | "resolved" "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz" 523 | "version" "3.0.1" 524 | 525 | "jest-worker@^27.0.6": 526 | "integrity" "sha512-ks3WCzsiZaOPJl/oMsDjaf0TRiSv7ctNgs0FqRr2nARsovz6AWWy4oLElwcquGSz692DzgZQrCLScPNs5YlC4g==" 527 | "resolved" "https://registry.npmjs.org/jest-worker/-/jest-worker-27.3.1.tgz" 528 | "version" "27.3.1" 529 | dependencies: 530 | "@types/node" "*" 531 | "merge-stream" "^2.0.0" 532 | "supports-color" "^8.0.0" 533 | 534 | "js-tokens@^3.0.0 || ^4.0.0": 535 | "integrity" "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" 536 | "resolved" "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" 537 | "version" "4.0.0" 538 | 539 | "json-parse-better-errors@^1.0.2": 540 | "integrity" "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" 541 | "resolved" "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz" 542 | "version" "1.0.2" 543 | 544 | "json-schema-traverse@^0.4.1": 545 | "integrity" "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 546 | "resolved" "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" 547 | "version" "0.4.1" 548 | 549 | "kind-of@^6.0.2": 550 | "integrity" "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" 551 | "resolved" "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" 552 | "version" "6.0.3" 553 | 554 | "loader-runner@^4.2.0": 555 | "integrity" "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==" 556 | "resolved" "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz" 557 | "version" "4.2.0" 558 | 559 | "locate-path@^5.0.0": 560 | "integrity" "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==" 561 | "resolved" "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" 562 | "version" "5.0.0" 563 | dependencies: 564 | "p-locate" "^4.1.0" 565 | 566 | "loose-envify@^1.1.0", "loose-envify@^1.4.0": 567 | "integrity" "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==" 568 | "resolved" "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" 569 | "version" "1.4.0" 570 | dependencies: 571 | "js-tokens" "^3.0.0 || ^4.0.0" 572 | 573 | "lru-cache@^6.0.0": 574 | "integrity" "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==" 575 | "resolved" "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" 576 | "version" "6.0.0" 577 | dependencies: 578 | "yallist" "^4.0.0" 579 | 580 | "merge-stream@^2.0.0": 581 | "integrity" "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" 582 | "resolved" "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" 583 | "version" "2.0.0" 584 | 585 | "micromatch@^4.0.0": 586 | "integrity" "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==" 587 | "resolved" "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz" 588 | "version" "4.0.4" 589 | dependencies: 590 | "braces" "^3.0.1" 591 | "picomatch" "^2.2.3" 592 | 593 | "mime-db@1.50.0": 594 | "integrity" "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==" 595 | "resolved" "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz" 596 | "version" "1.50.0" 597 | 598 | "mime-types@^2.1.27": 599 | "integrity" "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==" 600 | "resolved" "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz" 601 | "version" "2.1.33" 602 | dependencies: 603 | "mime-db" "1.50.0" 604 | 605 | "mimic-fn@^2.1.0": 606 | "integrity" "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" 607 | "resolved" "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" 608 | "version" "2.1.0" 609 | 610 | "neo-async@^2.6.2": 611 | "integrity" "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" 612 | "resolved" "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz" 613 | "version" "2.6.2" 614 | 615 | "node-releases@^2.0.1": 616 | "integrity" "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==" 617 | "resolved" "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz" 618 | "version" "2.0.1" 619 | 620 | "npm-run-path@^4.0.1": 621 | "integrity" "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==" 622 | "resolved" "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz" 623 | "version" "4.0.1" 624 | dependencies: 625 | "path-key" "^3.0.0" 626 | 627 | "object-assign@^4.1.1": 628 | "integrity" "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" 629 | "resolved" "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" 630 | "version" "4.1.1" 631 | 632 | "onetime@^5.1.2": 633 | "integrity" "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==" 634 | "resolved" "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" 635 | "version" "5.1.2" 636 | dependencies: 637 | "mimic-fn" "^2.1.0" 638 | 639 | "p-limit@^2.2.0": 640 | "integrity" "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==" 641 | "resolved" "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" 642 | "version" "2.3.0" 643 | dependencies: 644 | "p-try" "^2.0.0" 645 | 646 | "p-limit@^3.1.0": 647 | "integrity" "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==" 648 | "resolved" "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" 649 | "version" "3.1.0" 650 | dependencies: 651 | "yocto-queue" "^0.1.0" 652 | 653 | "p-locate@^4.1.0": 654 | "integrity" "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==" 655 | "resolved" "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz" 656 | "version" "4.1.0" 657 | dependencies: 658 | "p-limit" "^2.2.0" 659 | 660 | "p-try@^2.0.0": 661 | "integrity" "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" 662 | "resolved" "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" 663 | "version" "2.2.0" 664 | 665 | "path-exists@^4.0.0": 666 | "integrity" "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" 667 | "resolved" "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" 668 | "version" "4.0.0" 669 | 670 | "path-key@^3.0.0", "path-key@^3.1.0": 671 | "integrity" "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" 672 | "resolved" "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" 673 | "version" "3.1.1" 674 | 675 | "path-parse@^1.0.6": 676 | "integrity" "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" 677 | "resolved" "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" 678 | "version" "1.0.7" 679 | 680 | "picocolors@^1.0.0": 681 | "integrity" "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" 682 | "resolved" "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" 683 | "version" "1.0.0" 684 | 685 | "picomatch@^2.2.3": 686 | "integrity" "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" 687 | "resolved" "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz" 688 | "version" "2.3.0" 689 | 690 | "pkg-dir@^4.2.0": 691 | "integrity" "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==" 692 | "resolved" "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz" 693 | "version" "4.2.0" 694 | dependencies: 695 | "find-up" "^4.0.0" 696 | 697 | "prop-types@^15.6.2": 698 | "integrity" "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==" 699 | "resolved" "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz" 700 | "version" "15.7.2" 701 | dependencies: 702 | "loose-envify" "^1.4.0" 703 | "object-assign" "^4.1.1" 704 | "react-is" "^16.8.1" 705 | 706 | "punycode@^2.1.0": 707 | "integrity" "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" 708 | "resolved" "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz" 709 | "version" "2.1.1" 710 | 711 | "randombytes@^2.1.0": 712 | "integrity" "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==" 713 | "resolved" "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" 714 | "version" "2.1.0" 715 | dependencies: 716 | "safe-buffer" "^5.1.0" 717 | 718 | "react-dom@^16.7.0": 719 | "integrity" "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==" 720 | "resolved" "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz" 721 | "version" "16.14.0" 722 | dependencies: 723 | "loose-envify" "^1.1.0" 724 | "object-assign" "^4.1.1" 725 | "prop-types" "^15.6.2" 726 | "scheduler" "^0.19.1" 727 | 728 | "react-is@^16.8.1": 729 | "integrity" "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" 730 | "resolved" "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" 731 | "version" "16.13.1" 732 | 733 | "react@^16.14.0", "react@^16.7.0": 734 | "integrity" "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==" 735 | "resolved" "https://registry.npmjs.org/react/-/react-16.14.0.tgz" 736 | "version" "16.14.0" 737 | dependencies: 738 | "loose-envify" "^1.1.0" 739 | "object-assign" "^4.1.1" 740 | "prop-types" "^15.6.2" 741 | 742 | "rechoir@^0.7.0": 743 | "integrity" "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==" 744 | "resolved" "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz" 745 | "version" "0.7.1" 746 | dependencies: 747 | "resolve" "^1.9.0" 748 | 749 | "resolve-cwd@^3.0.0": 750 | "integrity" "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==" 751 | "resolved" "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz" 752 | "version" "3.0.0" 753 | dependencies: 754 | "resolve-from" "^5.0.0" 755 | 756 | "resolve-from@^5.0.0": 757 | "integrity" "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" 758 | "resolved" "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz" 759 | "version" "5.0.0" 760 | 761 | "resolve@^1.9.0": 762 | "integrity" "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==" 763 | "resolved" "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz" 764 | "version" "1.20.0" 765 | dependencies: 766 | "is-core-module" "^2.2.0" 767 | "path-parse" "^1.0.6" 768 | 769 | "safe-buffer@^5.1.0": 770 | "integrity" "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 771 | "resolved" "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" 772 | "version" "5.1.2" 773 | 774 | "scheduler@^0.19.1": 775 | "integrity" "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==" 776 | "resolved" "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz" 777 | "version" "0.19.1" 778 | dependencies: 779 | "loose-envify" "^1.1.0" 780 | "object-assign" "^4.1.1" 781 | 782 | "schema-utils@^3.1.0", "schema-utils@^3.1.1": 783 | "integrity" "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==" 784 | "resolved" "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz" 785 | "version" "3.1.1" 786 | dependencies: 787 | "@types/json-schema" "^7.0.8" 788 | "ajv" "^6.12.5" 789 | "ajv-keywords" "^3.5.2" 790 | 791 | "semver@^7.3.4": 792 | "integrity" "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==" 793 | "resolved" "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz" 794 | "version" "7.3.5" 795 | dependencies: 796 | "lru-cache" "^6.0.0" 797 | 798 | "serialize-javascript@^6.0.0": 799 | "integrity" "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==" 800 | "resolved" "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz" 801 | "version" "6.0.0" 802 | dependencies: 803 | "randombytes" "^2.1.0" 804 | 805 | "shallow-clone@^3.0.0": 806 | "integrity" "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==" 807 | "resolved" "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz" 808 | "version" "3.0.1" 809 | dependencies: 810 | "kind-of" "^6.0.2" 811 | 812 | "shebang-command@^2.0.0": 813 | "integrity" "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==" 814 | "resolved" "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" 815 | "version" "2.0.0" 816 | dependencies: 817 | "shebang-regex" "^3.0.0" 818 | 819 | "shebang-regex@^3.0.0": 820 | "integrity" "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" 821 | "resolved" "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" 822 | "version" "3.0.0" 823 | 824 | "signal-exit@^3.0.3": 825 | "integrity" "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==" 826 | "resolved" "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz" 827 | "version" "3.0.5" 828 | 829 | "source-map-support@~0.5.20": 830 | "integrity" "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==" 831 | "resolved" "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz" 832 | "version" "0.5.20" 833 | dependencies: 834 | "buffer-from" "^1.0.0" 835 | "source-map" "^0.6.0" 836 | 837 | "source-map@^0.6.0", "source-map@^0.6.1": 838 | "integrity" "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" 839 | "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" 840 | "version" "0.6.1" 841 | 842 | "source-map@~0.7.2": 843 | "integrity" "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" 844 | "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz" 845 | "version" "0.7.3" 846 | 847 | "strip-final-newline@^2.0.0": 848 | "integrity" "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" 849 | "resolved" "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" 850 | "version" "2.0.0" 851 | 852 | "supports-color@^7.1.0": 853 | "integrity" "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==" 854 | "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" 855 | "version" "7.2.0" 856 | dependencies: 857 | "has-flag" "^4.0.0" 858 | 859 | "supports-color@^8.0.0": 860 | "integrity" "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==" 861 | "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" 862 | "version" "8.1.1" 863 | dependencies: 864 | "has-flag" "^4.0.0" 865 | 866 | "tapable@^2.1.1", "tapable@^2.2.0": 867 | "integrity" "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" 868 | "resolved" "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz" 869 | "version" "2.2.1" 870 | 871 | "terser-webpack-plugin@^5.1.3": 872 | "integrity" "sha512-E2CkNMN+1cho04YpdANyRrn8CyN4yMy+WdFKZIySFZrGXZxJwJP6PMNGGc/Mcr6qygQHUUqRxnAPmi0M9f00XA==" 873 | "resolved" "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.2.4.tgz" 874 | "version" "5.2.4" 875 | dependencies: 876 | "jest-worker" "^27.0.6" 877 | "p-limit" "^3.1.0" 878 | "schema-utils" "^3.1.1" 879 | "serialize-javascript" "^6.0.0" 880 | "source-map" "^0.6.1" 881 | "terser" "^5.7.2" 882 | 883 | "terser@^5.7.2": 884 | "integrity" "sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ==" 885 | "resolved" "https://registry.npmjs.org/terser/-/terser-5.9.0.tgz" 886 | "version" "5.9.0" 887 | dependencies: 888 | "commander" "^2.20.0" 889 | "source-map" "~0.7.2" 890 | "source-map-support" "~0.5.20" 891 | 892 | "to-regex-range@^5.0.1": 893 | "integrity" "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==" 894 | "resolved" "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" 895 | "version" "5.0.1" 896 | dependencies: 897 | "is-number" "^7.0.0" 898 | 899 | "ts-loader@^9.2.6": 900 | "integrity" "sha512-QMTC4UFzHmu9wU2VHZEmWWE9cUajjfcdcws+Gh7FhiO+Dy0RnR1bNz0YCHqhI0yRowCE9arVnNxYHqELOy9Hjw==" 901 | "resolved" "https://registry.npmjs.org/ts-loader/-/ts-loader-9.2.6.tgz" 902 | "version" "9.2.6" 903 | dependencies: 904 | "chalk" "^4.1.0" 905 | "enhanced-resolve" "^5.0.0" 906 | "micromatch" "^4.0.0" 907 | "semver" "^7.3.4" 908 | 909 | "typescript@*", "typescript@^4.4.4": 910 | "integrity" "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==" 911 | "resolved" "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz" 912 | "version" "4.4.4" 913 | 914 | "uri-js@^4.2.2": 915 | "integrity" "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==" 916 | "resolved" "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" 917 | "version" "4.4.1" 918 | dependencies: 919 | "punycode" "^2.1.0" 920 | 921 | "watchpack@^2.2.0": 922 | "integrity" "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==" 923 | "resolved" "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz" 924 | "version" "2.2.0" 925 | dependencies: 926 | "glob-to-regexp" "^0.4.1" 927 | "graceful-fs" "^4.1.2" 928 | 929 | "webpack-cli@^4.9.1", "webpack-cli@4.x.x": 930 | "integrity" "sha512-JYRFVuyFpzDxMDB+v/nanUdQYcZtqFPGzmlW4s+UkPMFhSpfRNmf1z4AwYcHJVdvEFAM7FFCQdNTpsBYhDLusQ==" 931 | "resolved" "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.1.tgz" 932 | "version" "4.9.1" 933 | dependencies: 934 | "@discoveryjs/json-ext" "^0.5.0" 935 | "@webpack-cli/configtest" "^1.1.0" 936 | "@webpack-cli/info" "^1.4.0" 937 | "@webpack-cli/serve" "^1.6.0" 938 | "colorette" "^2.0.14" 939 | "commander" "^7.0.0" 940 | "execa" "^5.0.0" 941 | "fastest-levenshtein" "^1.0.12" 942 | "import-local" "^3.0.2" 943 | "interpret" "^2.2.0" 944 | "rechoir" "^0.7.0" 945 | "webpack-merge" "^5.7.3" 946 | 947 | "webpack-merge@^5.7.3": 948 | "integrity" "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==" 949 | "resolved" "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz" 950 | "version" "5.8.0" 951 | dependencies: 952 | "clone-deep" "^4.0.1" 953 | "wildcard" "^2.0.0" 954 | 955 | "webpack-sources@^3.2.0": 956 | "integrity" "sha512-t6BMVLQ0AkjBOoRTZgqrWm7xbXMBzD+XDq2EZ96+vMfn3qKgsvdXZhbPZ4ElUOpdv4u+iiGe+w3+J75iy/bYGA==" 957 | "resolved" "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.1.tgz" 958 | "version" "3.2.1" 959 | 960 | "webpack@^5.0.0", "webpack@^5.1.0", "webpack@^5.59.1", "webpack@4.x.x || 5.x.x": 961 | "integrity" "sha512-I01IQV9K96FlpXX3V0L4nvd7gb0r7thfuu1IfT2P4uOHOA77nKARAKDYGe/tScSHKnffNIyQhLC8kRXzY4KEHQ==" 962 | "resolved" "https://registry.npmjs.org/webpack/-/webpack-5.59.1.tgz" 963 | "version" "5.59.1" 964 | dependencies: 965 | "@types/eslint-scope" "^3.7.0" 966 | "@types/estree" "^0.0.50" 967 | "@webassemblyjs/ast" "1.11.1" 968 | "@webassemblyjs/wasm-edit" "1.11.1" 969 | "@webassemblyjs/wasm-parser" "1.11.1" 970 | "acorn" "^8.4.1" 971 | "acorn-import-assertions" "^1.7.6" 972 | "browserslist" "^4.14.5" 973 | "chrome-trace-event" "^1.0.2" 974 | "enhanced-resolve" "^5.8.3" 975 | "es-module-lexer" "^0.9.0" 976 | "eslint-scope" "5.1.1" 977 | "events" "^3.2.0" 978 | "glob-to-regexp" "^0.4.1" 979 | "graceful-fs" "^4.2.4" 980 | "json-parse-better-errors" "^1.0.2" 981 | "loader-runner" "^4.2.0" 982 | "mime-types" "^2.1.27" 983 | "neo-async" "^2.6.2" 984 | "schema-utils" "^3.1.0" 985 | "tapable" "^2.1.1" 986 | "terser-webpack-plugin" "^5.1.3" 987 | "watchpack" "^2.2.0" 988 | "webpack-sources" "^3.2.0" 989 | 990 | "which@^2.0.1": 991 | "integrity" "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==" 992 | "resolved" "https://registry.npmjs.org/which/-/which-2.0.2.tgz" 993 | "version" "2.0.2" 994 | dependencies: 995 | "isexe" "^2.0.0" 996 | 997 | "wildcard@^2.0.0": 998 | "integrity" "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==" 999 | "resolved" "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz" 1000 | "version" "2.0.0" 1001 | 1002 | "yallist@^4.0.0": 1003 | "integrity" "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" 1004 | "resolved" "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" 1005 | "version" "4.0.0" 1006 | 1007 | "yocto-queue@^0.1.0": 1008 | "integrity" "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" 1009 | "resolved" "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" 1010 | "version" "0.1.0" 1011 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "Inflector" 7 | version = "0.11.4" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" 10 | dependencies = [ 11 | "lazy_static", 12 | "regex", 13 | ] 14 | 15 | [[package]] 16 | name = "ahash" 17 | version = "0.3.8" 18 | source = "registry+https://github.com/rust-lang/crates.io-index" 19 | checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217" 20 | 21 | [[package]] 22 | name = "aho-corasick" 23 | version = "0.7.18" 24 | source = "registry+https://github.com/rust-lang/crates.io-index" 25 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 26 | dependencies = [ 27 | "memchr", 28 | ] 29 | 30 | [[package]] 31 | name = "ansi_term" 32 | version = "0.12.1" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" 35 | dependencies = [ 36 | "winapi", 37 | ] 38 | 39 | [[package]] 40 | name = "anyhow" 41 | version = "1.0.44" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" 44 | 45 | [[package]] 46 | name = "async-stream" 47 | version = "0.3.2" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625" 50 | dependencies = [ 51 | "async-stream-impl", 52 | "futures-core", 53 | ] 54 | 55 | [[package]] 56 | name = "async-stream-impl" 57 | version = "0.3.2" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308" 60 | dependencies = [ 61 | "proc-macro2", 62 | "quote", 63 | "syn", 64 | ] 65 | 66 | [[package]] 67 | name = "async-trait" 68 | version = "0.1.51" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" 71 | dependencies = [ 72 | "proc-macro2", 73 | "quote", 74 | "syn", 75 | ] 76 | 77 | [[package]] 78 | name = "atty" 79 | version = "0.2.14" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 82 | dependencies = [ 83 | "hermit-abi", 84 | "libc", 85 | "winapi", 86 | ] 87 | 88 | [[package]] 89 | name = "autocfg" 90 | version = "0.1.7" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" 93 | 94 | [[package]] 95 | name = "autocfg" 96 | version = "1.0.1" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 99 | 100 | [[package]] 101 | name = "axum" 102 | version = "0.3.0" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | checksum = "49c3f630b925c7a85089ff794fdce495c88c80d38710f31eb9817c8399fd77ce" 105 | dependencies = [ 106 | "async-trait", 107 | "bitflags", 108 | "bytes", 109 | "futures-util", 110 | "headers", 111 | "http", 112 | "http-body", 113 | "hyper", 114 | "matchit", 115 | "mime", 116 | "percent-encoding", 117 | "pin-project-lite", 118 | "serde", 119 | "serde_json", 120 | "serde_urlencoded", 121 | "sync_wrapper", 122 | "tokio", 123 | "tokio-util", 124 | "tower", 125 | "tower-http", 126 | "tower-layer", 127 | "tower-service", 128 | ] 129 | 130 | [[package]] 131 | name = "base64" 132 | version = "0.12.3" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" 135 | 136 | [[package]] 137 | name = "base64" 138 | version = "0.13.0" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 141 | 142 | [[package]] 143 | name = "base64ct" 144 | version = "1.1.1" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "e6b4d9b1225d28d360ec6a231d65af1fd99a2a095154c8040689617290569c5c" 147 | 148 | [[package]] 149 | name = "bitflags" 150 | version = "1.3.2" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 153 | 154 | [[package]] 155 | name = "block-buffer" 156 | version = "0.9.0" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 159 | dependencies = [ 160 | "generic-array", 161 | ] 162 | 163 | [[package]] 164 | name = "bumpalo" 165 | version = "3.8.0" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" 168 | 169 | [[package]] 170 | name = "bytecount" 171 | version = "0.6.2" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | checksum = "72feb31ffc86498dacdbd0fcebb56138e7177a8cc5cea4516031d15ae85a742e" 174 | 175 | [[package]] 176 | name = "bytemuck" 177 | version = "1.7.2" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b" 180 | 181 | [[package]] 182 | name = "byteorder" 183 | version = "1.4.3" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 186 | 187 | [[package]] 188 | name = "bytes" 189 | version = "1.1.0" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" 192 | 193 | [[package]] 194 | name = "cargo-platform" 195 | version = "0.1.2" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" 198 | dependencies = [ 199 | "serde", 200 | ] 201 | 202 | [[package]] 203 | name = "cargo_metadata" 204 | version = "0.12.3" 205 | source = "registry+https://github.com/rust-lang/crates.io-index" 206 | checksum = "7714a157da7991e23d90686b9524b9e12e0407a108647f52e9328f4b3d51ac7f" 207 | dependencies = [ 208 | "cargo-platform", 209 | "semver", 210 | "semver-parser", 211 | "serde", 212 | "serde_json", 213 | ] 214 | 215 | [[package]] 216 | name = "cc" 217 | version = "1.0.71" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd" 220 | 221 | [[package]] 222 | name = "cfg-if" 223 | version = "1.0.0" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 226 | 227 | [[package]] 228 | name = "checked_int_cast" 229 | version = "1.0.0" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "17cc5e6b5ab06331c33589842070416baa137e8b0eb912b008cfd4a78ada7919" 232 | 233 | [[package]] 234 | name = "chrono" 235 | version = "0.4.19" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" 238 | dependencies = [ 239 | "libc", 240 | "num-integer", 241 | "num-traits", 242 | "serde", 243 | "time", 244 | "winapi", 245 | ] 246 | 247 | [[package]] 248 | name = "clap" 249 | version = "3.0.0-beta.5" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | checksum = "feff3878564edb93745d58cf63e17b63f24142506e7a20c87a5521ed7bfb1d63" 252 | dependencies = [ 253 | "atty", 254 | "bitflags", 255 | "clap_derive", 256 | "indexmap", 257 | "lazy_static", 258 | "os_str_bytes", 259 | "strsim", 260 | "termcolor", 261 | "textwrap", 262 | "unicase", 263 | ] 264 | 265 | [[package]] 266 | name = "clap_derive" 267 | version = "3.0.0-beta.5" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "8b15c6b4f786ffb6192ffe65a36855bc1fc2444bcd0945ae16748dcd6ed7d0d3" 270 | dependencies = [ 271 | "heck", 272 | "proc-macro-error", 273 | "proc-macro2", 274 | "quote", 275 | "syn", 276 | ] 277 | 278 | [[package]] 279 | name = "coarsetime" 280 | version = "0.1.20" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | checksum = "5b6ec6f6e80e839eb22bd61b18f19a8f2ae3f8bda9cf0fdce9dd96c9c5df8393" 283 | dependencies = [ 284 | "libc", 285 | "once_cell", 286 | "wasi", 287 | "wasm-bindgen", 288 | ] 289 | 290 | [[package]] 291 | name = "color_quant" 292 | version = "1.1.0" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" 295 | 296 | [[package]] 297 | name = "const-oid" 298 | version = "0.6.2" 299 | source = "registry+https://github.com/rust-lang/crates.io-index" 300 | checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b" 301 | 302 | [[package]] 303 | name = "core-foundation" 304 | version = "0.9.2" 305 | source = "registry+https://github.com/rust-lang/crates.io-index" 306 | checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" 307 | dependencies = [ 308 | "core-foundation-sys", 309 | "libc", 310 | ] 311 | 312 | [[package]] 313 | name = "core-foundation-sys" 314 | version = "0.8.3" 315 | source = "registry+https://github.com/rust-lang/crates.io-index" 316 | checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" 317 | 318 | [[package]] 319 | name = "cpufeatures" 320 | version = "0.2.1" 321 | source = "registry+https://github.com/rust-lang/crates.io-index" 322 | checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" 323 | dependencies = [ 324 | "libc", 325 | ] 326 | 327 | [[package]] 328 | name = "crypto-bigint" 329 | version = "0.2.11" 330 | source = "registry+https://github.com/rust-lang/crates.io-index" 331 | checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03" 332 | dependencies = [ 333 | "generic-array", 334 | "rand_core", 335 | "subtle", 336 | "zeroize", 337 | ] 338 | 339 | [[package]] 340 | name = "crypto-mac" 341 | version = "0.8.0" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" 344 | dependencies = [ 345 | "generic-array", 346 | "subtle", 347 | ] 348 | 349 | [[package]] 350 | name = "crypto-mac" 351 | version = "0.11.1" 352 | source = "registry+https://github.com/rust-lang/crates.io-index" 353 | checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" 354 | dependencies = [ 355 | "generic-array", 356 | "subtle", 357 | ] 358 | 359 | [[package]] 360 | name = "ct-codecs" 361 | version = "1.1.1" 362 | source = "registry+https://github.com/rust-lang/crates.io-index" 363 | checksum = "f3b7eb4404b8195a9abb6356f4ac07d8ba267045c8d6d220ac4dc992e6cc75df" 364 | 365 | [[package]] 366 | name = "ct-logs" 367 | version = "0.8.0" 368 | source = "registry+https://github.com/rust-lang/crates.io-index" 369 | checksum = "c1a816186fa68d9e426e3cb4ae4dff1fcd8e4a2c34b781bf7a822574a0d0aac8" 370 | dependencies = [ 371 | "sct", 372 | ] 373 | 374 | [[package]] 375 | name = "dashmap" 376 | version = "4.0.2" 377 | source = "registry+https://github.com/rust-lang/crates.io-index" 378 | checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" 379 | dependencies = [ 380 | "cfg-if", 381 | "num_cpus", 382 | ] 383 | 384 | [[package]] 385 | name = "deadpool" 386 | version = "0.9.1" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "51dc1e92ba8164da131a4753a26cb1e7ebcfe617e56bb3c2b6136049c8ee5730" 389 | dependencies = [ 390 | "async-trait", 391 | "deadpool-runtime", 392 | "num_cpus", 393 | "tokio", 394 | ] 395 | 396 | [[package]] 397 | name = "deadpool-runtime" 398 | version = "0.1.2" 399 | source = "registry+https://github.com/rust-lang/crates.io-index" 400 | checksum = "eaa37046cc0f6c3cc6090fbdbf73ef0b8ef4cfcc37f6befc0020f63e8cf121e1" 401 | 402 | [[package]] 403 | name = "der" 404 | version = "0.4.4" 405 | source = "registry+https://github.com/rust-lang/crates.io-index" 406 | checksum = "28e98c534e9c8a0483aa01d6f6913bc063de254311bd267c9cf535e9b70e15b2" 407 | dependencies = [ 408 | "const-oid", 409 | "crypto-bigint", 410 | "der_derive", 411 | ] 412 | 413 | [[package]] 414 | name = "der_derive" 415 | version = "0.4.1" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "8aed3b3c608dc56cf36c45fe979d04eda51242e6703d8d0bb03426ef7c41db6a" 418 | dependencies = [ 419 | "proc-macro2", 420 | "quote", 421 | "syn", 422 | "synstructure", 423 | ] 424 | 425 | [[package]] 426 | name = "digest" 427 | version = "0.9.0" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 430 | dependencies = [ 431 | "generic-array", 432 | ] 433 | 434 | [[package]] 435 | name = "ecdsa" 436 | version = "0.12.4" 437 | source = "registry+https://github.com/rust-lang/crates.io-index" 438 | checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372" 439 | dependencies = [ 440 | "der", 441 | "elliptic-curve", 442 | "hmac 0.11.0", 443 | "signature", 444 | ] 445 | 446 | [[package]] 447 | name = "ece" 448 | version = "2.1.0" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "ce72a9f609537e2947d2e9ef9d3168e6b29eecaafb6d38dba8575849d5424678" 451 | dependencies = [ 452 | "base64 0.12.3", 453 | "byteorder", 454 | "hex", 455 | "hkdf", 456 | "lazy_static", 457 | "once_cell", 458 | "openssl", 459 | "serde", 460 | "sha2", 461 | "thiserror", 462 | ] 463 | 464 | [[package]] 465 | name = "ed25519-compact" 466 | version = "0.1.11" 467 | source = "registry+https://github.com/rust-lang/crates.io-index" 468 | checksum = "f1f45ef578ef75efffba301628066d951042f6e988f21f8b548928468ba5877b" 469 | dependencies = [ 470 | "ct-codecs", 471 | "getrandom", 472 | ] 473 | 474 | [[package]] 475 | name = "either" 476 | version = "1.6.1" 477 | source = "registry+https://github.com/rust-lang/crates.io-index" 478 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 479 | 480 | [[package]] 481 | name = "elliptic-curve" 482 | version = "0.10.6" 483 | source = "registry+https://github.com/rust-lang/crates.io-index" 484 | checksum = "beca177dcb8eb540133e7680baff45e7cc4d93bf22002676cec549f82343721b" 485 | dependencies = [ 486 | "crypto-bigint", 487 | "ff", 488 | "generic-array", 489 | "group", 490 | "pkcs8", 491 | "rand_core", 492 | "subtle", 493 | "zeroize", 494 | ] 495 | 496 | [[package]] 497 | name = "error-chain" 498 | version = "0.12.4" 499 | source = "registry+https://github.com/rust-lang/crates.io-index" 500 | checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" 501 | dependencies = [ 502 | "version_check", 503 | ] 504 | 505 | [[package]] 506 | name = "ff" 507 | version = "0.10.1" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f" 510 | dependencies = [ 511 | "rand_core", 512 | "subtle", 513 | ] 514 | 515 | [[package]] 516 | name = "firestore-serde" 517 | version = "0.1.1" 518 | source = "registry+https://github.com/rust-lang/crates.io-index" 519 | checksum = "89ce26fdd2c934d08578f53e6f58bc2985b01777bfa09b80840d59afdd5de327" 520 | dependencies = [ 521 | "bytes", 522 | "chrono", 523 | "googapis", 524 | "prost", 525 | "prost-types", 526 | "serde", 527 | "serde_bytes", 528 | ] 529 | 530 | [[package]] 531 | name = "firestore-serde-timestamp" 532 | version = "0.1.0" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "0168163337820d60f6be2fafb3fad2ba2e30d754d66107250868418cfd3c4704" 535 | dependencies = [ 536 | "chrono", 537 | "prost", 538 | "prost-types", 539 | "serde", 540 | "serde_bytes", 541 | ] 542 | 543 | [[package]] 544 | name = "fnv" 545 | version = "1.0.7" 546 | source = "registry+https://github.com/rust-lang/crates.io-index" 547 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 548 | 549 | [[package]] 550 | name = "foreign-types" 551 | version = "0.3.2" 552 | source = "registry+https://github.com/rust-lang/crates.io-index" 553 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 554 | dependencies = [ 555 | "foreign-types-shared", 556 | ] 557 | 558 | [[package]] 559 | name = "foreign-types-shared" 560 | version = "0.1.1" 561 | source = "registry+https://github.com/rust-lang/crates.io-index" 562 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 563 | 564 | [[package]] 565 | name = "form_urlencoded" 566 | version = "1.0.1" 567 | source = "registry+https://github.com/rust-lang/crates.io-index" 568 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 569 | dependencies = [ 570 | "matches", 571 | "percent-encoding", 572 | ] 573 | 574 | [[package]] 575 | name = "futures" 576 | version = "0.3.17" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" 579 | dependencies = [ 580 | "futures-channel", 581 | "futures-core", 582 | "futures-executor", 583 | "futures-io", 584 | "futures-sink", 585 | "futures-task", 586 | "futures-util", 587 | ] 588 | 589 | [[package]] 590 | name = "futures-channel" 591 | version = "0.3.17" 592 | source = "registry+https://github.com/rust-lang/crates.io-index" 593 | checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" 594 | dependencies = [ 595 | "futures-core", 596 | "futures-sink", 597 | ] 598 | 599 | [[package]] 600 | name = "futures-core" 601 | version = "0.3.17" 602 | source = "registry+https://github.com/rust-lang/crates.io-index" 603 | checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" 604 | 605 | [[package]] 606 | name = "futures-executor" 607 | version = "0.3.17" 608 | source = "registry+https://github.com/rust-lang/crates.io-index" 609 | checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" 610 | dependencies = [ 611 | "futures-core", 612 | "futures-task", 613 | "futures-util", 614 | ] 615 | 616 | [[package]] 617 | name = "futures-io" 618 | version = "0.3.17" 619 | source = "registry+https://github.com/rust-lang/crates.io-index" 620 | checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" 621 | 622 | [[package]] 623 | name = "futures-macro" 624 | version = "0.3.17" 625 | source = "registry+https://github.com/rust-lang/crates.io-index" 626 | checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" 627 | dependencies = [ 628 | "autocfg 1.0.1", 629 | "proc-macro-hack", 630 | "proc-macro2", 631 | "quote", 632 | "syn", 633 | ] 634 | 635 | [[package]] 636 | name = "futures-sink" 637 | version = "0.3.17" 638 | source = "registry+https://github.com/rust-lang/crates.io-index" 639 | checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" 640 | 641 | [[package]] 642 | name = "futures-task" 643 | version = "0.3.17" 644 | source = "registry+https://github.com/rust-lang/crates.io-index" 645 | checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" 646 | 647 | [[package]] 648 | name = "futures-timer" 649 | version = "3.0.2" 650 | source = "registry+https://github.com/rust-lang/crates.io-index" 651 | checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" 652 | 653 | [[package]] 654 | name = "futures-util" 655 | version = "0.3.17" 656 | source = "registry+https://github.com/rust-lang/crates.io-index" 657 | checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" 658 | dependencies = [ 659 | "autocfg 1.0.1", 660 | "futures-channel", 661 | "futures-core", 662 | "futures-io", 663 | "futures-macro", 664 | "futures-sink", 665 | "futures-task", 666 | "memchr", 667 | "pin-project-lite", 668 | "pin-utils", 669 | "proc-macro-hack", 670 | "proc-macro-nested", 671 | "slab", 672 | ] 673 | 674 | [[package]] 675 | name = "gcemeta" 676 | version = "0.2.2" 677 | source = "registry+https://github.com/rust-lang/crates.io-index" 678 | checksum = "ba3c7e2740961eb3bd7907366ab68aaf0e6fb685110e8135defaf72046652412" 679 | dependencies = [ 680 | "bytes", 681 | "hyper", 682 | "serde", 683 | "serde_json", 684 | "thiserror", 685 | "tokio", 686 | "tracing", 687 | ] 688 | 689 | [[package]] 690 | name = "generic-array" 691 | version = "0.14.4" 692 | source = "registry+https://github.com/rust-lang/crates.io-index" 693 | checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" 694 | dependencies = [ 695 | "typenum", 696 | "version_check", 697 | ] 698 | 699 | [[package]] 700 | name = "getrandom" 701 | version = "0.2.3" 702 | source = "registry+https://github.com/rust-lang/crates.io-index" 703 | checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" 704 | dependencies = [ 705 | "cfg-if", 706 | "libc", 707 | "wasi", 708 | ] 709 | 710 | [[package]] 711 | name = "glob" 712 | version = "0.3.0" 713 | source = "registry+https://github.com/rust-lang/crates.io-index" 714 | checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" 715 | 716 | [[package]] 717 | name = "googapis" 718 | version = "0.5.0" 719 | source = "registry+https://github.com/rust-lang/crates.io-index" 720 | checksum = "8894a4cb9b32a73030f2c2dd6a251114d5ec62fb786d011850ae98cdfb8d2ff2" 721 | dependencies = [ 722 | "prost", 723 | "prost-types", 724 | "tonic", 725 | ] 726 | 727 | [[package]] 728 | name = "google-authz" 729 | version = "0.0.2" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "94813b19daac0ef90fd8cb5acf24b914a2c54a999b0ed54c63cd0a3c0ac363c0" 732 | dependencies = [ 733 | "bytes", 734 | "gcemeta", 735 | "hyper", 736 | "hyper-rustls", 737 | "jsonwebtoken", 738 | "parking_lot", 739 | "serde", 740 | "serde_json", 741 | "serde_urlencoded", 742 | "thiserror", 743 | "tower-service", 744 | "tracing", 745 | ] 746 | 747 | [[package]] 748 | name = "governor" 749 | version = "0.3.2" 750 | source = "registry+https://github.com/rust-lang/crates.io-index" 751 | checksum = "06c5d2f987ee8f6dff3fa1a352058dc59b990e447e4c7846aa7d804971314f7b" 752 | dependencies = [ 753 | "dashmap", 754 | "futures", 755 | "futures-timer", 756 | "no-std-compat", 757 | "nonzero_ext 0.2.0", 758 | "parking_lot", 759 | "quanta", 760 | "rand", 761 | "smallvec", 762 | ] 763 | 764 | [[package]] 765 | name = "group" 766 | version = "0.10.0" 767 | source = "registry+https://github.com/rust-lang/crates.io-index" 768 | checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912" 769 | dependencies = [ 770 | "ff", 771 | "rand_core", 772 | "subtle", 773 | ] 774 | 775 | [[package]] 776 | name = "h2" 777 | version = "0.3.7" 778 | source = "registry+https://github.com/rust-lang/crates.io-index" 779 | checksum = "7fd819562fcebdac5afc5c113c3ec36f902840b70fd4fc458799c8ce4607ae55" 780 | dependencies = [ 781 | "bytes", 782 | "fnv", 783 | "futures-core", 784 | "futures-sink", 785 | "futures-util", 786 | "http", 787 | "indexmap", 788 | "slab", 789 | "tokio", 790 | "tokio-util", 791 | "tracing", 792 | ] 793 | 794 | [[package]] 795 | name = "hashbrown" 796 | version = "0.8.2" 797 | source = "registry+https://github.com/rust-lang/crates.io-index" 798 | checksum = "e91b62f79061a0bc2e046024cb7ba44b08419ed238ecbd9adbd787434b9e8c25" 799 | dependencies = [ 800 | "ahash", 801 | "autocfg 1.0.1", 802 | ] 803 | 804 | [[package]] 805 | name = "hashbrown" 806 | version = "0.11.2" 807 | source = "registry+https://github.com/rust-lang/crates.io-index" 808 | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" 809 | 810 | [[package]] 811 | name = "headers" 812 | version = "0.3.5" 813 | source = "registry+https://github.com/rust-lang/crates.io-index" 814 | checksum = "a4c4eb0471fcb85846d8b0690695ef354f9afb11cb03cac2e1d7c9253351afb0" 815 | dependencies = [ 816 | "base64 0.13.0", 817 | "bitflags", 818 | "bytes", 819 | "headers-core", 820 | "http", 821 | "httpdate", 822 | "mime", 823 | "sha-1", 824 | ] 825 | 826 | [[package]] 827 | name = "headers-core" 828 | version = "0.2.0" 829 | source = "registry+https://github.com/rust-lang/crates.io-index" 830 | checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" 831 | dependencies = [ 832 | "http", 833 | ] 834 | 835 | [[package]] 836 | name = "heck" 837 | version = "0.3.3" 838 | source = "registry+https://github.com/rust-lang/crates.io-index" 839 | checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" 840 | dependencies = [ 841 | "unicode-segmentation", 842 | ] 843 | 844 | [[package]] 845 | name = "hermit-abi" 846 | version = "0.1.19" 847 | source = "registry+https://github.com/rust-lang/crates.io-index" 848 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 849 | dependencies = [ 850 | "libc", 851 | ] 852 | 853 | [[package]] 854 | name = "hex" 855 | version = "0.4.3" 856 | source = "registry+https://github.com/rust-lang/crates.io-index" 857 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 858 | 859 | [[package]] 860 | name = "hkdf" 861 | version = "0.9.0" 862 | source = "registry+https://github.com/rust-lang/crates.io-index" 863 | checksum = "fe1149865383e4526a43aee8495f9a325f0b806c63ce6427d06336a590abbbc9" 864 | dependencies = [ 865 | "digest", 866 | "hmac 0.8.1", 867 | ] 868 | 869 | [[package]] 870 | name = "hmac" 871 | version = "0.8.1" 872 | source = "registry+https://github.com/rust-lang/crates.io-index" 873 | checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" 874 | dependencies = [ 875 | "crypto-mac 0.8.0", 876 | "digest", 877 | ] 878 | 879 | [[package]] 880 | name = "hmac" 881 | version = "0.11.0" 882 | source = "registry+https://github.com/rust-lang/crates.io-index" 883 | checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" 884 | dependencies = [ 885 | "crypto-mac 0.11.1", 886 | "digest", 887 | ] 888 | 889 | [[package]] 890 | name = "hmac-sha256" 891 | version = "0.1.7" 892 | source = "registry+https://github.com/rust-lang/crates.io-index" 893 | checksum = "bcdc571e566521512579aab40bf807c5066e1765fb36857f16ed7595c13567c6" 894 | dependencies = [ 895 | "digest", 896 | ] 897 | 898 | [[package]] 899 | name = "hmac-sha512" 900 | version = "0.1.9" 901 | source = "registry+https://github.com/rust-lang/crates.io-index" 902 | checksum = "77e806677ce663d0a199541030c816847b36e8dc095f70dae4a4f4ad63da5383" 903 | dependencies = [ 904 | "digest", 905 | ] 906 | 907 | [[package]] 908 | name = "http" 909 | version = "0.2.5" 910 | source = "registry+https://github.com/rust-lang/crates.io-index" 911 | checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b" 912 | dependencies = [ 913 | "bytes", 914 | "fnv", 915 | "itoa", 916 | ] 917 | 918 | [[package]] 919 | name = "http-body" 920 | version = "0.4.4" 921 | source = "registry+https://github.com/rust-lang/crates.io-index" 922 | checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" 923 | dependencies = [ 924 | "bytes", 925 | "http", 926 | "pin-project-lite", 927 | ] 928 | 929 | [[package]] 930 | name = "httparse" 931 | version = "1.5.1" 932 | source = "registry+https://github.com/rust-lang/crates.io-index" 933 | checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" 934 | 935 | [[package]] 936 | name = "httpdate" 937 | version = "1.0.1" 938 | source = "registry+https://github.com/rust-lang/crates.io-index" 939 | checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" 940 | 941 | [[package]] 942 | name = "hyper" 943 | version = "0.14.14" 944 | source = "registry+https://github.com/rust-lang/crates.io-index" 945 | checksum = "2b91bb1f221b6ea1f1e4371216b70f40748774c2fb5971b450c07773fb92d26b" 946 | dependencies = [ 947 | "bytes", 948 | "futures-channel", 949 | "futures-core", 950 | "futures-util", 951 | "h2", 952 | "http", 953 | "http-body", 954 | "httparse", 955 | "httpdate", 956 | "itoa", 957 | "pin-project-lite", 958 | "socket2", 959 | "tokio", 960 | "tower-service", 961 | "tracing", 962 | "want", 963 | ] 964 | 965 | [[package]] 966 | name = "hyper-rustls" 967 | version = "0.22.1" 968 | source = "registry+https://github.com/rust-lang/crates.io-index" 969 | checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" 970 | dependencies = [ 971 | "ct-logs", 972 | "futures-util", 973 | "hyper", 974 | "log", 975 | "rustls", 976 | "rustls-native-certs", 977 | "tokio", 978 | "tokio-rustls", 979 | "webpki", 980 | ] 981 | 982 | [[package]] 983 | name = "hyper-timeout" 984 | version = "0.4.1" 985 | source = "registry+https://github.com/rust-lang/crates.io-index" 986 | checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" 987 | dependencies = [ 988 | "hyper", 989 | "pin-project-lite", 990 | "tokio", 991 | "tokio-io-timeout", 992 | ] 993 | 994 | [[package]] 995 | name = "hyper-tls" 996 | version = "0.5.0" 997 | source = "registry+https://github.com/rust-lang/crates.io-index" 998 | checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" 999 | dependencies = [ 1000 | "bytes", 1001 | "hyper", 1002 | "native-tls", 1003 | "tokio", 1004 | "tokio-native-tls", 1005 | ] 1006 | 1007 | [[package]] 1008 | name = "image" 1009 | version = "0.23.14" 1010 | source = "registry+https://github.com/rust-lang/crates.io-index" 1011 | checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1" 1012 | dependencies = [ 1013 | "bytemuck", 1014 | "byteorder", 1015 | "color_quant", 1016 | "num-iter", 1017 | "num-rational", 1018 | "num-traits", 1019 | ] 1020 | 1021 | [[package]] 1022 | name = "indexmap" 1023 | version = "1.7.0" 1024 | source = "registry+https://github.com/rust-lang/crates.io-index" 1025 | checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" 1026 | dependencies = [ 1027 | "autocfg 1.0.1", 1028 | "hashbrown 0.11.2", 1029 | ] 1030 | 1031 | [[package]] 1032 | name = "instant" 1033 | version = "0.1.12" 1034 | source = "registry+https://github.com/rust-lang/crates.io-index" 1035 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 1036 | dependencies = [ 1037 | "cfg-if", 1038 | ] 1039 | 1040 | [[package]] 1041 | name = "itertools" 1042 | version = "0.10.1" 1043 | source = "registry+https://github.com/rust-lang/crates.io-index" 1044 | checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" 1045 | dependencies = [ 1046 | "either", 1047 | ] 1048 | 1049 | [[package]] 1050 | name = "itoa" 1051 | version = "0.4.8" 1052 | source = "registry+https://github.com/rust-lang/crates.io-index" 1053 | checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" 1054 | 1055 | [[package]] 1056 | name = "js-sys" 1057 | version = "0.3.55" 1058 | source = "registry+https://github.com/rust-lang/crates.io-index" 1059 | checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" 1060 | dependencies = [ 1061 | "wasm-bindgen", 1062 | ] 1063 | 1064 | [[package]] 1065 | name = "jsonwebtoken" 1066 | version = "7.2.0" 1067 | source = "registry+https://github.com/rust-lang/crates.io-index" 1068 | checksum = "afabcc15e437a6484fc4f12d0fd63068fe457bf93f1c148d3d9649c60b103f32" 1069 | dependencies = [ 1070 | "base64 0.12.3", 1071 | "pem", 1072 | "ring", 1073 | "serde", 1074 | "serde_json", 1075 | "simple_asn1", 1076 | ] 1077 | 1078 | [[package]] 1079 | name = "jwt-simple" 1080 | version = "0.10.6" 1081 | source = "registry+https://github.com/rust-lang/crates.io-index" 1082 | checksum = "2fb385d1fd9c591d7888b5e6e8f5d20ff04fc26362de2f26476662ff4aa1ae7d" 1083 | dependencies = [ 1084 | "anyhow", 1085 | "coarsetime", 1086 | "ct-codecs", 1087 | "ed25519-compact", 1088 | "hmac-sha256", 1089 | "hmac-sha512", 1090 | "k256", 1091 | "p256", 1092 | "rand", 1093 | "rsa", 1094 | "serde", 1095 | "serde_json", 1096 | "thiserror", 1097 | "zeroize", 1098 | ] 1099 | 1100 | [[package]] 1101 | name = "k256" 1102 | version = "0.9.6" 1103 | source = "registry+https://github.com/rust-lang/crates.io-index" 1104 | checksum = "903ae2481bcdfdb7b68e0a9baa4b7c9aff600b9ae2e8e5bb5833b8c91ab851ea" 1105 | dependencies = [ 1106 | "cfg-if", 1107 | "ecdsa", 1108 | "elliptic-curve", 1109 | "sha2", 1110 | ] 1111 | 1112 | [[package]] 1113 | name = "lazy_static" 1114 | version = "1.4.0" 1115 | source = "registry+https://github.com/rust-lang/crates.io-index" 1116 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 1117 | dependencies = [ 1118 | "spin", 1119 | ] 1120 | 1121 | [[package]] 1122 | name = "libc" 1123 | version = "0.2.106" 1124 | source = "registry+https://github.com/rust-lang/crates.io-index" 1125 | checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673" 1126 | 1127 | [[package]] 1128 | name = "libm" 1129 | version = "0.2.1" 1130 | source = "registry+https://github.com/rust-lang/crates.io-index" 1131 | checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" 1132 | 1133 | [[package]] 1134 | name = "lock_api" 1135 | version = "0.4.5" 1136 | source = "registry+https://github.com/rust-lang/crates.io-index" 1137 | checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" 1138 | dependencies = [ 1139 | "scopeguard", 1140 | ] 1141 | 1142 | [[package]] 1143 | name = "log" 1144 | version = "0.4.14" 1145 | source = "registry+https://github.com/rust-lang/crates.io-index" 1146 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 1147 | dependencies = [ 1148 | "cfg-if", 1149 | ] 1150 | 1151 | [[package]] 1152 | name = "matchers" 1153 | version = "0.0.1" 1154 | source = "registry+https://github.com/rust-lang/crates.io-index" 1155 | checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" 1156 | dependencies = [ 1157 | "regex-automata", 1158 | ] 1159 | 1160 | [[package]] 1161 | name = "matches" 1162 | version = "0.1.9" 1163 | source = "registry+https://github.com/rust-lang/crates.io-index" 1164 | checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" 1165 | 1166 | [[package]] 1167 | name = "matchit" 1168 | version = "0.4.4" 1169 | source = "registry+https://github.com/rust-lang/crates.io-index" 1170 | checksum = "58b6f41fdfbec185dd3dff58b51e323f5bc61692c0de38419a957b0dcfccca3c" 1171 | 1172 | [[package]] 1173 | name = "memchr" 1174 | version = "2.4.1" 1175 | source = "registry+https://github.com/rust-lang/crates.io-index" 1176 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 1177 | 1178 | [[package]] 1179 | name = "mime" 1180 | version = "0.3.16" 1181 | source = "registry+https://github.com/rust-lang/crates.io-index" 1182 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 1183 | 1184 | [[package]] 1185 | name = "mime_guess" 1186 | version = "2.0.3" 1187 | source = "registry+https://github.com/rust-lang/crates.io-index" 1188 | checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212" 1189 | dependencies = [ 1190 | "mime", 1191 | "unicase", 1192 | ] 1193 | 1194 | [[package]] 1195 | name = "mio" 1196 | version = "0.7.14" 1197 | source = "registry+https://github.com/rust-lang/crates.io-index" 1198 | checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" 1199 | dependencies = [ 1200 | "libc", 1201 | "log", 1202 | "miow", 1203 | "ntapi", 1204 | "winapi", 1205 | ] 1206 | 1207 | [[package]] 1208 | name = "miow" 1209 | version = "0.3.7" 1210 | source = "registry+https://github.com/rust-lang/crates.io-index" 1211 | checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" 1212 | dependencies = [ 1213 | "winapi", 1214 | ] 1215 | 1216 | [[package]] 1217 | name = "native-tls" 1218 | version = "0.2.8" 1219 | source = "registry+https://github.com/rust-lang/crates.io-index" 1220 | checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" 1221 | dependencies = [ 1222 | "lazy_static", 1223 | "libc", 1224 | "log", 1225 | "openssl", 1226 | "openssl-probe", 1227 | "openssl-sys", 1228 | "schannel", 1229 | "security-framework", 1230 | "security-framework-sys", 1231 | "tempfile", 1232 | ] 1233 | 1234 | [[package]] 1235 | name = "no-std-compat" 1236 | version = "0.4.1" 1237 | source = "registry+https://github.com/rust-lang/crates.io-index" 1238 | checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" 1239 | dependencies = [ 1240 | "hashbrown 0.8.2", 1241 | ] 1242 | 1243 | [[package]] 1244 | name = "nonzero_ext" 1245 | version = "0.2.0" 1246 | source = "registry+https://github.com/rust-lang/crates.io-index" 1247 | checksum = "44a1290799eababa63ea60af0cbc3f03363e328e58f32fb0294798ed3e85f444" 1248 | 1249 | [[package]] 1250 | name = "nonzero_ext" 1251 | version = "0.3.0" 1252 | source = "registry+https://github.com/rust-lang/crates.io-index" 1253 | checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" 1254 | 1255 | [[package]] 1256 | name = "notify-run" 1257 | version = "0.1.0" 1258 | dependencies = [ 1259 | "anyhow", 1260 | "async-trait", 1261 | "axum", 1262 | "base64 0.13.0", 1263 | "chrono", 1264 | "clap", 1265 | "deadpool", 1266 | "firestore-serde", 1267 | "firestore-serde-timestamp", 1268 | "futures", 1269 | "google-authz", 1270 | "governor", 1271 | "headers", 1272 | "http-body", 1273 | "nonzero_ext 0.3.0", 1274 | "qrcode", 1275 | "serde", 1276 | "serde_json", 1277 | "serde_urlencoded", 1278 | "tiny-firestore-odm", 1279 | "tokio", 1280 | "tokio-stream", 1281 | "tower", 1282 | "tower-http", 1283 | "tracing", 1284 | "tracing-stackdriver", 1285 | "tracing-subscriber", 1286 | "web-push", 1287 | ] 1288 | 1289 | [[package]] 1290 | name = "ntapi" 1291 | version = "0.3.6" 1292 | source = "registry+https://github.com/rust-lang/crates.io-index" 1293 | checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" 1294 | dependencies = [ 1295 | "winapi", 1296 | ] 1297 | 1298 | [[package]] 1299 | name = "num-bigint" 1300 | version = "0.2.6" 1301 | source = "registry+https://github.com/rust-lang/crates.io-index" 1302 | checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" 1303 | dependencies = [ 1304 | "autocfg 1.0.1", 1305 | "num-integer", 1306 | "num-traits", 1307 | ] 1308 | 1309 | [[package]] 1310 | name = "num-bigint-dig" 1311 | version = "0.7.0" 1312 | source = "registry+https://github.com/rust-lang/crates.io-index" 1313 | checksum = "4547ee5541c18742396ae2c895d0717d0f886d8823b8399cdaf7b07d63ad0480" 1314 | dependencies = [ 1315 | "autocfg 0.1.7", 1316 | "byteorder", 1317 | "lazy_static", 1318 | "libm", 1319 | "num-integer", 1320 | "num-iter", 1321 | "num-traits", 1322 | "rand", 1323 | "smallvec", 1324 | "zeroize", 1325 | ] 1326 | 1327 | [[package]] 1328 | name = "num-integer" 1329 | version = "0.1.44" 1330 | source = "registry+https://github.com/rust-lang/crates.io-index" 1331 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 1332 | dependencies = [ 1333 | "autocfg 1.0.1", 1334 | "num-traits", 1335 | ] 1336 | 1337 | [[package]] 1338 | name = "num-iter" 1339 | version = "0.1.42" 1340 | source = "registry+https://github.com/rust-lang/crates.io-index" 1341 | checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" 1342 | dependencies = [ 1343 | "autocfg 1.0.1", 1344 | "num-integer", 1345 | "num-traits", 1346 | ] 1347 | 1348 | [[package]] 1349 | name = "num-rational" 1350 | version = "0.3.2" 1351 | source = "registry+https://github.com/rust-lang/crates.io-index" 1352 | checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" 1353 | dependencies = [ 1354 | "autocfg 1.0.1", 1355 | "num-integer", 1356 | "num-traits", 1357 | ] 1358 | 1359 | [[package]] 1360 | name = "num-traits" 1361 | version = "0.2.14" 1362 | source = "registry+https://github.com/rust-lang/crates.io-index" 1363 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 1364 | dependencies = [ 1365 | "autocfg 1.0.1", 1366 | "libm", 1367 | ] 1368 | 1369 | [[package]] 1370 | name = "num_cpus" 1371 | version = "1.13.0" 1372 | source = "registry+https://github.com/rust-lang/crates.io-index" 1373 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 1374 | dependencies = [ 1375 | "hermit-abi", 1376 | "libc", 1377 | ] 1378 | 1379 | [[package]] 1380 | name = "once_cell" 1381 | version = "1.8.0" 1382 | source = "registry+https://github.com/rust-lang/crates.io-index" 1383 | checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" 1384 | 1385 | [[package]] 1386 | name = "opaque-debug" 1387 | version = "0.3.0" 1388 | source = "registry+https://github.com/rust-lang/crates.io-index" 1389 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 1390 | 1391 | [[package]] 1392 | name = "openssl" 1393 | version = "0.10.38" 1394 | source = "registry+https://github.com/rust-lang/crates.io-index" 1395 | checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" 1396 | dependencies = [ 1397 | "bitflags", 1398 | "cfg-if", 1399 | "foreign-types", 1400 | "libc", 1401 | "once_cell", 1402 | "openssl-sys", 1403 | ] 1404 | 1405 | [[package]] 1406 | name = "openssl-probe" 1407 | version = "0.1.4" 1408 | source = "registry+https://github.com/rust-lang/crates.io-index" 1409 | checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" 1410 | 1411 | [[package]] 1412 | name = "openssl-sys" 1413 | version = "0.9.70" 1414 | source = "registry+https://github.com/rust-lang/crates.io-index" 1415 | checksum = "c6517987b3f8226b5da3661dad65ff7f300cc59fb5ea8333ca191fc65fde3edf" 1416 | dependencies = [ 1417 | "autocfg 1.0.1", 1418 | "cc", 1419 | "libc", 1420 | "pkg-config", 1421 | "vcpkg", 1422 | ] 1423 | 1424 | [[package]] 1425 | name = "os_str_bytes" 1426 | version = "4.2.0" 1427 | source = "registry+https://github.com/rust-lang/crates.io-index" 1428 | checksum = "addaa943333a514159c80c97ff4a93306530d965d27e139188283cd13e06a799" 1429 | dependencies = [ 1430 | "memchr", 1431 | ] 1432 | 1433 | [[package]] 1434 | name = "p256" 1435 | version = "0.9.0" 1436 | source = "registry+https://github.com/rust-lang/crates.io-index" 1437 | checksum = "d053368e1bae4c8a672953397bd1bd7183dde1c72b0b7612a15719173148d186" 1438 | dependencies = [ 1439 | "ecdsa", 1440 | "elliptic-curve", 1441 | "sha2", 1442 | ] 1443 | 1444 | [[package]] 1445 | name = "parking_lot" 1446 | version = "0.11.2" 1447 | source = "registry+https://github.com/rust-lang/crates.io-index" 1448 | checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" 1449 | dependencies = [ 1450 | "instant", 1451 | "lock_api", 1452 | "parking_lot_core", 1453 | ] 1454 | 1455 | [[package]] 1456 | name = "parking_lot_core" 1457 | version = "0.8.5" 1458 | source = "registry+https://github.com/rust-lang/crates.io-index" 1459 | checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" 1460 | dependencies = [ 1461 | "cfg-if", 1462 | "instant", 1463 | "libc", 1464 | "redox_syscall", 1465 | "smallvec", 1466 | "winapi", 1467 | ] 1468 | 1469 | [[package]] 1470 | name = "pem" 1471 | version = "0.8.3" 1472 | source = "registry+https://github.com/rust-lang/crates.io-index" 1473 | checksum = "fd56cbd21fea48d0c440b41cd69c589faacade08c992d9a54e471b79d0fd13eb" 1474 | dependencies = [ 1475 | "base64 0.13.0", 1476 | "once_cell", 1477 | "regex", 1478 | ] 1479 | 1480 | [[package]] 1481 | name = "pem-rfc7468" 1482 | version = "0.2.3" 1483 | source = "registry+https://github.com/rust-lang/crates.io-index" 1484 | checksum = "8f22eb0e3c593294a99e9ff4b24cf6b752d43f193aa4415fe5077c159996d497" 1485 | dependencies = [ 1486 | "base64ct", 1487 | ] 1488 | 1489 | [[package]] 1490 | name = "percent-encoding" 1491 | version = "2.1.0" 1492 | source = "registry+https://github.com/rust-lang/crates.io-index" 1493 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 1494 | 1495 | [[package]] 1496 | name = "pest" 1497 | version = "2.1.3" 1498 | source = "registry+https://github.com/rust-lang/crates.io-index" 1499 | checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" 1500 | dependencies = [ 1501 | "ucd-trie", 1502 | ] 1503 | 1504 | [[package]] 1505 | name = "pin-project" 1506 | version = "1.0.8" 1507 | source = "registry+https://github.com/rust-lang/crates.io-index" 1508 | checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08" 1509 | dependencies = [ 1510 | "pin-project-internal", 1511 | ] 1512 | 1513 | [[package]] 1514 | name = "pin-project-internal" 1515 | version = "1.0.8" 1516 | source = "registry+https://github.com/rust-lang/crates.io-index" 1517 | checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389" 1518 | dependencies = [ 1519 | "proc-macro2", 1520 | "quote", 1521 | "syn", 1522 | ] 1523 | 1524 | [[package]] 1525 | name = "pin-project-lite" 1526 | version = "0.2.7" 1527 | source = "registry+https://github.com/rust-lang/crates.io-index" 1528 | checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" 1529 | 1530 | [[package]] 1531 | name = "pin-utils" 1532 | version = "0.1.0" 1533 | source = "registry+https://github.com/rust-lang/crates.io-index" 1534 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1535 | 1536 | [[package]] 1537 | name = "pkcs1" 1538 | version = "0.2.4" 1539 | source = "registry+https://github.com/rust-lang/crates.io-index" 1540 | checksum = "116bee8279d783c0cf370efa1a94632f2108e5ef0bb32df31f051647810a4e2c" 1541 | dependencies = [ 1542 | "der", 1543 | "pem-rfc7468", 1544 | "zeroize", 1545 | ] 1546 | 1547 | [[package]] 1548 | name = "pkcs8" 1549 | version = "0.7.6" 1550 | source = "registry+https://github.com/rust-lang/crates.io-index" 1551 | checksum = "ee3ef9b64d26bad0536099c816c6734379e45bbd5f14798def6809e5cc350447" 1552 | dependencies = [ 1553 | "der", 1554 | "pem-rfc7468", 1555 | "pkcs1", 1556 | "spki", 1557 | "zeroize", 1558 | ] 1559 | 1560 | [[package]] 1561 | name = "pkg-config" 1562 | version = "0.3.22" 1563 | source = "registry+https://github.com/rust-lang/crates.io-index" 1564 | checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f" 1565 | 1566 | [[package]] 1567 | name = "ppv-lite86" 1568 | version = "0.2.15" 1569 | source = "registry+https://github.com/rust-lang/crates.io-index" 1570 | checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" 1571 | 1572 | [[package]] 1573 | name = "proc-macro-error" 1574 | version = "1.0.4" 1575 | source = "registry+https://github.com/rust-lang/crates.io-index" 1576 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 1577 | dependencies = [ 1578 | "proc-macro-error-attr", 1579 | "proc-macro2", 1580 | "quote", 1581 | "syn", 1582 | "version_check", 1583 | ] 1584 | 1585 | [[package]] 1586 | name = "proc-macro-error-attr" 1587 | version = "1.0.4" 1588 | source = "registry+https://github.com/rust-lang/crates.io-index" 1589 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 1590 | dependencies = [ 1591 | "proc-macro2", 1592 | "quote", 1593 | "version_check", 1594 | ] 1595 | 1596 | [[package]] 1597 | name = "proc-macro-hack" 1598 | version = "0.5.19" 1599 | source = "registry+https://github.com/rust-lang/crates.io-index" 1600 | checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" 1601 | 1602 | [[package]] 1603 | name = "proc-macro-nested" 1604 | version = "0.1.7" 1605 | source = "registry+https://github.com/rust-lang/crates.io-index" 1606 | checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" 1607 | 1608 | [[package]] 1609 | name = "proc-macro2" 1610 | version = "1.0.32" 1611 | source = "registry+https://github.com/rust-lang/crates.io-index" 1612 | checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" 1613 | dependencies = [ 1614 | "unicode-xid", 1615 | ] 1616 | 1617 | [[package]] 1618 | name = "prost" 1619 | version = "0.8.0" 1620 | source = "registry+https://github.com/rust-lang/crates.io-index" 1621 | checksum = "de5e2533f59d08fcf364fd374ebda0692a70bd6d7e66ef97f306f45c6c5d8020" 1622 | dependencies = [ 1623 | "bytes", 1624 | "prost-derive", 1625 | ] 1626 | 1627 | [[package]] 1628 | name = "prost-derive" 1629 | version = "0.8.0" 1630 | source = "registry+https://github.com/rust-lang/crates.io-index" 1631 | checksum = "600d2f334aa05acb02a755e217ef1ab6dea4d51b58b7846588b747edec04efba" 1632 | dependencies = [ 1633 | "anyhow", 1634 | "itertools", 1635 | "proc-macro2", 1636 | "quote", 1637 | "syn", 1638 | ] 1639 | 1640 | [[package]] 1641 | name = "prost-types" 1642 | version = "0.8.0" 1643 | source = "registry+https://github.com/rust-lang/crates.io-index" 1644 | checksum = "603bbd6394701d13f3f25aada59c7de9d35a6a5887cfc156181234a44002771b" 1645 | dependencies = [ 1646 | "bytes", 1647 | "prost", 1648 | ] 1649 | 1650 | [[package]] 1651 | name = "pulldown-cmark" 1652 | version = "0.8.0" 1653 | source = "registry+https://github.com/rust-lang/crates.io-index" 1654 | checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8" 1655 | dependencies = [ 1656 | "bitflags", 1657 | "memchr", 1658 | "unicase", 1659 | ] 1660 | 1661 | [[package]] 1662 | name = "qrcode" 1663 | version = "0.12.0" 1664 | source = "registry+https://github.com/rust-lang/crates.io-index" 1665 | checksum = "16d2f1455f3630c6e5107b4f2b94e74d76dea80736de0981fd27644216cff57f" 1666 | dependencies = [ 1667 | "checked_int_cast", 1668 | "image", 1669 | ] 1670 | 1671 | [[package]] 1672 | name = "quanta" 1673 | version = "0.4.1" 1674 | source = "registry+https://github.com/rust-lang/crates.io-index" 1675 | checksum = "d98dc777a7a39b76b1a26ae9d3f691f4c1bc0455090aa0b64dfa8cb7fc34c135" 1676 | dependencies = [ 1677 | "libc", 1678 | "winapi", 1679 | ] 1680 | 1681 | [[package]] 1682 | name = "quote" 1683 | version = "1.0.10" 1684 | source = "registry+https://github.com/rust-lang/crates.io-index" 1685 | checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" 1686 | dependencies = [ 1687 | "proc-macro2", 1688 | ] 1689 | 1690 | [[package]] 1691 | name = "rand" 1692 | version = "0.8.4" 1693 | source = "registry+https://github.com/rust-lang/crates.io-index" 1694 | checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" 1695 | dependencies = [ 1696 | "libc", 1697 | "rand_chacha", 1698 | "rand_core", 1699 | "rand_hc", 1700 | ] 1701 | 1702 | [[package]] 1703 | name = "rand_chacha" 1704 | version = "0.3.1" 1705 | source = "registry+https://github.com/rust-lang/crates.io-index" 1706 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1707 | dependencies = [ 1708 | "ppv-lite86", 1709 | "rand_core", 1710 | ] 1711 | 1712 | [[package]] 1713 | name = "rand_core" 1714 | version = "0.6.3" 1715 | source = "registry+https://github.com/rust-lang/crates.io-index" 1716 | checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" 1717 | dependencies = [ 1718 | "getrandom", 1719 | ] 1720 | 1721 | [[package]] 1722 | name = "rand_hc" 1723 | version = "0.3.1" 1724 | source = "registry+https://github.com/rust-lang/crates.io-index" 1725 | checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" 1726 | dependencies = [ 1727 | "rand_core", 1728 | ] 1729 | 1730 | [[package]] 1731 | name = "redox_syscall" 1732 | version = "0.2.10" 1733 | source = "registry+https://github.com/rust-lang/crates.io-index" 1734 | checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" 1735 | dependencies = [ 1736 | "bitflags", 1737 | ] 1738 | 1739 | [[package]] 1740 | name = "regex" 1741 | version = "1.5.4" 1742 | source = "registry+https://github.com/rust-lang/crates.io-index" 1743 | checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" 1744 | dependencies = [ 1745 | "aho-corasick", 1746 | "memchr", 1747 | "regex-syntax", 1748 | ] 1749 | 1750 | [[package]] 1751 | name = "regex-automata" 1752 | version = "0.1.10" 1753 | source = "registry+https://github.com/rust-lang/crates.io-index" 1754 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 1755 | dependencies = [ 1756 | "regex-syntax", 1757 | ] 1758 | 1759 | [[package]] 1760 | name = "regex-syntax" 1761 | version = "0.6.25" 1762 | source = "registry+https://github.com/rust-lang/crates.io-index" 1763 | checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" 1764 | 1765 | [[package]] 1766 | name = "remove_dir_all" 1767 | version = "0.5.3" 1768 | source = "registry+https://github.com/rust-lang/crates.io-index" 1769 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" 1770 | dependencies = [ 1771 | "winapi", 1772 | ] 1773 | 1774 | [[package]] 1775 | name = "ring" 1776 | version = "0.16.20" 1777 | source = "registry+https://github.com/rust-lang/crates.io-index" 1778 | checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" 1779 | dependencies = [ 1780 | "cc", 1781 | "libc", 1782 | "once_cell", 1783 | "spin", 1784 | "untrusted", 1785 | "web-sys", 1786 | "winapi", 1787 | ] 1788 | 1789 | [[package]] 1790 | name = "rsa" 1791 | version = "0.5.0" 1792 | source = "registry+https://github.com/rust-lang/crates.io-index" 1793 | checksum = "e05c2603e2823634ab331437001b411b9ed11660fbc4066f3908c84a9439260d" 1794 | dependencies = [ 1795 | "byteorder", 1796 | "digest", 1797 | "lazy_static", 1798 | "num-bigint-dig", 1799 | "num-integer", 1800 | "num-iter", 1801 | "num-traits", 1802 | "pkcs1", 1803 | "pkcs8", 1804 | "rand", 1805 | "subtle", 1806 | "zeroize", 1807 | ] 1808 | 1809 | [[package]] 1810 | name = "rustls" 1811 | version = "0.19.1" 1812 | source = "registry+https://github.com/rust-lang/crates.io-index" 1813 | checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" 1814 | dependencies = [ 1815 | "base64 0.13.0", 1816 | "log", 1817 | "ring", 1818 | "sct", 1819 | "webpki", 1820 | ] 1821 | 1822 | [[package]] 1823 | name = "rustls-native-certs" 1824 | version = "0.5.0" 1825 | source = "registry+https://github.com/rust-lang/crates.io-index" 1826 | checksum = "5a07b7c1885bd8ed3831c289b7870b13ef46fe0e856d288c30d9cc17d75a2092" 1827 | dependencies = [ 1828 | "openssl-probe", 1829 | "rustls", 1830 | "schannel", 1831 | "security-framework", 1832 | ] 1833 | 1834 | [[package]] 1835 | name = "ryu" 1836 | version = "1.0.5" 1837 | source = "registry+https://github.com/rust-lang/crates.io-index" 1838 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 1839 | 1840 | [[package]] 1841 | name = "same-file" 1842 | version = "1.0.6" 1843 | source = "registry+https://github.com/rust-lang/crates.io-index" 1844 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 1845 | dependencies = [ 1846 | "winapi-util", 1847 | ] 1848 | 1849 | [[package]] 1850 | name = "schannel" 1851 | version = "0.1.19" 1852 | source = "registry+https://github.com/rust-lang/crates.io-index" 1853 | checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" 1854 | dependencies = [ 1855 | "lazy_static", 1856 | "winapi", 1857 | ] 1858 | 1859 | [[package]] 1860 | name = "scopeguard" 1861 | version = "1.1.0" 1862 | source = "registry+https://github.com/rust-lang/crates.io-index" 1863 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1864 | 1865 | [[package]] 1866 | name = "sct" 1867 | version = "0.6.1" 1868 | source = "registry+https://github.com/rust-lang/crates.io-index" 1869 | checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" 1870 | dependencies = [ 1871 | "ring", 1872 | "untrusted", 1873 | ] 1874 | 1875 | [[package]] 1876 | name = "sec1_decode" 1877 | version = "0.1.0" 1878 | source = "registry+https://github.com/rust-lang/crates.io-index" 1879 | checksum = "b6326ddc956378a0739200b2c30892dccaf198992dfd7323274690b9e188af23" 1880 | dependencies = [ 1881 | "der", 1882 | "pem", 1883 | "thiserror", 1884 | ] 1885 | 1886 | [[package]] 1887 | name = "security-framework" 1888 | version = "2.4.2" 1889 | source = "registry+https://github.com/rust-lang/crates.io-index" 1890 | checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87" 1891 | dependencies = [ 1892 | "bitflags", 1893 | "core-foundation", 1894 | "core-foundation-sys", 1895 | "libc", 1896 | "security-framework-sys", 1897 | ] 1898 | 1899 | [[package]] 1900 | name = "security-framework-sys" 1901 | version = "2.4.2" 1902 | source = "registry+https://github.com/rust-lang/crates.io-index" 1903 | checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" 1904 | dependencies = [ 1905 | "core-foundation-sys", 1906 | "libc", 1907 | ] 1908 | 1909 | [[package]] 1910 | name = "semver" 1911 | version = "0.11.0" 1912 | source = "registry+https://github.com/rust-lang/crates.io-index" 1913 | checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" 1914 | dependencies = [ 1915 | "semver-parser", 1916 | "serde", 1917 | ] 1918 | 1919 | [[package]] 1920 | name = "semver-parser" 1921 | version = "0.10.2" 1922 | source = "registry+https://github.com/rust-lang/crates.io-index" 1923 | checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" 1924 | dependencies = [ 1925 | "pest", 1926 | ] 1927 | 1928 | [[package]] 1929 | name = "serde" 1930 | version = "1.0.130" 1931 | source = "registry+https://github.com/rust-lang/crates.io-index" 1932 | checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" 1933 | dependencies = [ 1934 | "serde_derive", 1935 | ] 1936 | 1937 | [[package]] 1938 | name = "serde_bytes" 1939 | version = "0.11.5" 1940 | source = "registry+https://github.com/rust-lang/crates.io-index" 1941 | checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9" 1942 | dependencies = [ 1943 | "serde", 1944 | ] 1945 | 1946 | [[package]] 1947 | name = "serde_derive" 1948 | version = "1.0.130" 1949 | source = "registry+https://github.com/rust-lang/crates.io-index" 1950 | checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" 1951 | dependencies = [ 1952 | "proc-macro2", 1953 | "quote", 1954 | "syn", 1955 | ] 1956 | 1957 | [[package]] 1958 | name = "serde_json" 1959 | version = "1.0.68" 1960 | source = "registry+https://github.com/rust-lang/crates.io-index" 1961 | checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" 1962 | dependencies = [ 1963 | "itoa", 1964 | "ryu", 1965 | "serde", 1966 | ] 1967 | 1968 | [[package]] 1969 | name = "serde_urlencoded" 1970 | version = "0.7.0" 1971 | source = "registry+https://github.com/rust-lang/crates.io-index" 1972 | checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" 1973 | dependencies = [ 1974 | "form_urlencoded", 1975 | "itoa", 1976 | "ryu", 1977 | "serde", 1978 | ] 1979 | 1980 | [[package]] 1981 | name = "sha-1" 1982 | version = "0.9.8" 1983 | source = "registry+https://github.com/rust-lang/crates.io-index" 1984 | checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" 1985 | dependencies = [ 1986 | "block-buffer", 1987 | "cfg-if", 1988 | "cpufeatures", 1989 | "digest", 1990 | "opaque-debug", 1991 | ] 1992 | 1993 | [[package]] 1994 | name = "sha2" 1995 | version = "0.9.8" 1996 | source = "registry+https://github.com/rust-lang/crates.io-index" 1997 | checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" 1998 | dependencies = [ 1999 | "block-buffer", 2000 | "cfg-if", 2001 | "cpufeatures", 2002 | "digest", 2003 | "opaque-debug", 2004 | ] 2005 | 2006 | [[package]] 2007 | name = "sharded-slab" 2008 | version = "0.1.4" 2009 | source = "registry+https://github.com/rust-lang/crates.io-index" 2010 | checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" 2011 | dependencies = [ 2012 | "lazy_static", 2013 | ] 2014 | 2015 | [[package]] 2016 | name = "signature" 2017 | version = "1.3.2" 2018 | source = "registry+https://github.com/rust-lang/crates.io-index" 2019 | checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4" 2020 | dependencies = [ 2021 | "digest", 2022 | "rand_core", 2023 | ] 2024 | 2025 | [[package]] 2026 | name = "simple_asn1" 2027 | version = "0.4.1" 2028 | source = "registry+https://github.com/rust-lang/crates.io-index" 2029 | checksum = "692ca13de57ce0613a363c8c2f1de925adebc81b04c923ac60c5488bb44abe4b" 2030 | dependencies = [ 2031 | "chrono", 2032 | "num-bigint", 2033 | "num-traits", 2034 | ] 2035 | 2036 | [[package]] 2037 | name = "skeptic" 2038 | version = "0.13.6" 2039 | source = "registry+https://github.com/rust-lang/crates.io-index" 2040 | checksum = "188b810342d98f23f0bb875045299f34187b559370b041eb11520c905370a888" 2041 | dependencies = [ 2042 | "bytecount", 2043 | "cargo_metadata", 2044 | "error-chain", 2045 | "glob", 2046 | "pulldown-cmark", 2047 | "tempfile", 2048 | "walkdir", 2049 | ] 2050 | 2051 | [[package]] 2052 | name = "slab" 2053 | version = "0.4.5" 2054 | source = "registry+https://github.com/rust-lang/crates.io-index" 2055 | checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" 2056 | 2057 | [[package]] 2058 | name = "smallvec" 2059 | version = "1.7.0" 2060 | source = "registry+https://github.com/rust-lang/crates.io-index" 2061 | checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" 2062 | 2063 | [[package]] 2064 | name = "socket2" 2065 | version = "0.4.2" 2066 | source = "registry+https://github.com/rust-lang/crates.io-index" 2067 | checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" 2068 | dependencies = [ 2069 | "libc", 2070 | "winapi", 2071 | ] 2072 | 2073 | [[package]] 2074 | name = "spin" 2075 | version = "0.5.2" 2076 | source = "registry+https://github.com/rust-lang/crates.io-index" 2077 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 2078 | 2079 | [[package]] 2080 | name = "spki" 2081 | version = "0.4.1" 2082 | source = "registry+https://github.com/rust-lang/crates.io-index" 2083 | checksum = "5c01a0c15da1b0b0e1494112e7af814a678fec9bd157881b49beac661e9b6f32" 2084 | dependencies = [ 2085 | "der", 2086 | ] 2087 | 2088 | [[package]] 2089 | name = "strsim" 2090 | version = "0.10.0" 2091 | source = "registry+https://github.com/rust-lang/crates.io-index" 2092 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 2093 | 2094 | [[package]] 2095 | name = "subtle" 2096 | version = "2.4.1" 2097 | source = "registry+https://github.com/rust-lang/crates.io-index" 2098 | checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" 2099 | 2100 | [[package]] 2101 | name = "syn" 2102 | version = "1.0.81" 2103 | source = "registry+https://github.com/rust-lang/crates.io-index" 2104 | checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" 2105 | dependencies = [ 2106 | "proc-macro2", 2107 | "quote", 2108 | "unicode-xid", 2109 | ] 2110 | 2111 | [[package]] 2112 | name = "sync_wrapper" 2113 | version = "0.1.1" 2114 | source = "registry+https://github.com/rust-lang/crates.io-index" 2115 | checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" 2116 | 2117 | [[package]] 2118 | name = "synstructure" 2119 | version = "0.12.6" 2120 | source = "registry+https://github.com/rust-lang/crates.io-index" 2121 | checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" 2122 | dependencies = [ 2123 | "proc-macro2", 2124 | "quote", 2125 | "syn", 2126 | "unicode-xid", 2127 | ] 2128 | 2129 | [[package]] 2130 | name = "tempfile" 2131 | version = "3.2.0" 2132 | source = "registry+https://github.com/rust-lang/crates.io-index" 2133 | checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" 2134 | dependencies = [ 2135 | "cfg-if", 2136 | "libc", 2137 | "rand", 2138 | "redox_syscall", 2139 | "remove_dir_all", 2140 | "winapi", 2141 | ] 2142 | 2143 | [[package]] 2144 | name = "termcolor" 2145 | version = "1.1.2" 2146 | source = "registry+https://github.com/rust-lang/crates.io-index" 2147 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" 2148 | dependencies = [ 2149 | "winapi-util", 2150 | ] 2151 | 2152 | [[package]] 2153 | name = "textwrap" 2154 | version = "0.14.2" 2155 | source = "registry+https://github.com/rust-lang/crates.io-index" 2156 | checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" 2157 | dependencies = [ 2158 | "unicode-width", 2159 | ] 2160 | 2161 | [[package]] 2162 | name = "thiserror" 2163 | version = "1.0.30" 2164 | source = "registry+https://github.com/rust-lang/crates.io-index" 2165 | checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" 2166 | dependencies = [ 2167 | "thiserror-impl", 2168 | ] 2169 | 2170 | [[package]] 2171 | name = "thiserror-impl" 2172 | version = "1.0.30" 2173 | source = "registry+https://github.com/rust-lang/crates.io-index" 2174 | checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" 2175 | dependencies = [ 2176 | "proc-macro2", 2177 | "quote", 2178 | "syn", 2179 | ] 2180 | 2181 | [[package]] 2182 | name = "thread_local" 2183 | version = "1.1.3" 2184 | source = "registry+https://github.com/rust-lang/crates.io-index" 2185 | checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd" 2186 | dependencies = [ 2187 | "once_cell", 2188 | ] 2189 | 2190 | [[package]] 2191 | name = "time" 2192 | version = "0.1.44" 2193 | source = "registry+https://github.com/rust-lang/crates.io-index" 2194 | checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" 2195 | dependencies = [ 2196 | "libc", 2197 | "wasi", 2198 | "winapi", 2199 | ] 2200 | 2201 | [[package]] 2202 | name = "tiny-firestore-odm" 2203 | version = "0.2.6" 2204 | source = "registry+https://github.com/rust-lang/crates.io-index" 2205 | checksum = "b51868f22ad560bb652d068ee7fd88662f061c83612c74a52348a998a5cb46fd" 2206 | dependencies = [ 2207 | "anyhow", 2208 | "bytes", 2209 | "firestore-serde", 2210 | "googapis", 2211 | "google-authz", 2212 | "http", 2213 | "hyper", 2214 | "serde", 2215 | "skeptic", 2216 | "tokio", 2217 | "tokio-stream", 2218 | "tonic", 2219 | "tower-service", 2220 | ] 2221 | 2222 | [[package]] 2223 | name = "tokio" 2224 | version = "1.13.0" 2225 | source = "registry+https://github.com/rust-lang/crates.io-index" 2226 | checksum = "588b2d10a336da58d877567cd8fb8a14b463e2104910f8132cd054b4b96e29ee" 2227 | dependencies = [ 2228 | "autocfg 1.0.1", 2229 | "bytes", 2230 | "libc", 2231 | "memchr", 2232 | "mio", 2233 | "num_cpus", 2234 | "parking_lot", 2235 | "pin-project-lite", 2236 | "tokio-macros", 2237 | "winapi", 2238 | ] 2239 | 2240 | [[package]] 2241 | name = "tokio-io-timeout" 2242 | version = "1.1.1" 2243 | source = "registry+https://github.com/rust-lang/crates.io-index" 2244 | checksum = "90c49f106be240de154571dd31fbe48acb10ba6c6dd6f6517ad603abffa42de9" 2245 | dependencies = [ 2246 | "pin-project-lite", 2247 | "tokio", 2248 | ] 2249 | 2250 | [[package]] 2251 | name = "tokio-macros" 2252 | version = "1.5.1" 2253 | source = "registry+https://github.com/rust-lang/crates.io-index" 2254 | checksum = "114383b041aa6212c579467afa0075fbbdd0718de036100bc0ba7961d8cb9095" 2255 | dependencies = [ 2256 | "proc-macro2", 2257 | "quote", 2258 | "syn", 2259 | ] 2260 | 2261 | [[package]] 2262 | name = "tokio-native-tls" 2263 | version = "0.3.0" 2264 | source = "registry+https://github.com/rust-lang/crates.io-index" 2265 | checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" 2266 | dependencies = [ 2267 | "native-tls", 2268 | "tokio", 2269 | ] 2270 | 2271 | [[package]] 2272 | name = "tokio-rustls" 2273 | version = "0.22.0" 2274 | source = "registry+https://github.com/rust-lang/crates.io-index" 2275 | checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" 2276 | dependencies = [ 2277 | "rustls", 2278 | "tokio", 2279 | "webpki", 2280 | ] 2281 | 2282 | [[package]] 2283 | name = "tokio-stream" 2284 | version = "0.1.8" 2285 | source = "registry+https://github.com/rust-lang/crates.io-index" 2286 | checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" 2287 | dependencies = [ 2288 | "futures-core", 2289 | "pin-project-lite", 2290 | "tokio", 2291 | ] 2292 | 2293 | [[package]] 2294 | name = "tokio-util" 2295 | version = "0.6.9" 2296 | source = "registry+https://github.com/rust-lang/crates.io-index" 2297 | checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" 2298 | dependencies = [ 2299 | "bytes", 2300 | "futures-core", 2301 | "futures-sink", 2302 | "log", 2303 | "pin-project-lite", 2304 | "tokio", 2305 | ] 2306 | 2307 | [[package]] 2308 | name = "tonic" 2309 | version = "0.5.2" 2310 | source = "registry+https://github.com/rust-lang/crates.io-index" 2311 | checksum = "796c5e1cd49905e65dd8e700d4cb1dffcbfdb4fc9d017de08c1a537afd83627c" 2312 | dependencies = [ 2313 | "async-stream", 2314 | "async-trait", 2315 | "base64 0.13.0", 2316 | "bytes", 2317 | "futures-core", 2318 | "futures-util", 2319 | "h2", 2320 | "http", 2321 | "http-body", 2322 | "hyper", 2323 | "hyper-timeout", 2324 | "percent-encoding", 2325 | "pin-project", 2326 | "prost", 2327 | "prost-derive", 2328 | "tokio", 2329 | "tokio-rustls", 2330 | "tokio-stream", 2331 | "tokio-util", 2332 | "tower", 2333 | "tower-layer", 2334 | "tower-service", 2335 | "tracing", 2336 | "tracing-futures", 2337 | ] 2338 | 2339 | [[package]] 2340 | name = "tower" 2341 | version = "0.4.10" 2342 | source = "registry+https://github.com/rust-lang/crates.io-index" 2343 | checksum = "c00e500fff5fa1131c866b246041a6bf96da9c965f8fe4128cb1421f23e93c00" 2344 | dependencies = [ 2345 | "futures-core", 2346 | "futures-util", 2347 | "indexmap", 2348 | "pin-project", 2349 | "pin-project-lite", 2350 | "rand", 2351 | "slab", 2352 | "tokio", 2353 | "tokio-stream", 2354 | "tokio-util", 2355 | "tower-layer", 2356 | "tower-service", 2357 | "tracing", 2358 | ] 2359 | 2360 | [[package]] 2361 | name = "tower-http" 2362 | version = "0.1.1" 2363 | source = "registry+https://github.com/rust-lang/crates.io-index" 2364 | checksum = "0b7b56efe69aa0ad2b5da6b942e57ea9f6fe683b7a314d4ff48662e2c8838de1" 2365 | dependencies = [ 2366 | "bytes", 2367 | "futures-core", 2368 | "futures-util", 2369 | "http", 2370 | "http-body", 2371 | "mime", 2372 | "mime_guess", 2373 | "pin-project", 2374 | "tokio", 2375 | "tokio-util", 2376 | "tower-layer", 2377 | "tower-service", 2378 | "tracing", 2379 | ] 2380 | 2381 | [[package]] 2382 | name = "tower-layer" 2383 | version = "0.3.1" 2384 | source = "registry+https://github.com/rust-lang/crates.io-index" 2385 | checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" 2386 | 2387 | [[package]] 2388 | name = "tower-service" 2389 | version = "0.3.1" 2390 | source = "registry+https://github.com/rust-lang/crates.io-index" 2391 | checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" 2392 | 2393 | [[package]] 2394 | name = "tracing" 2395 | version = "0.1.29" 2396 | source = "registry+https://github.com/rust-lang/crates.io-index" 2397 | checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" 2398 | dependencies = [ 2399 | "cfg-if", 2400 | "log", 2401 | "pin-project-lite", 2402 | "tracing-attributes", 2403 | "tracing-core", 2404 | ] 2405 | 2406 | [[package]] 2407 | name = "tracing-attributes" 2408 | version = "0.1.18" 2409 | source = "registry+https://github.com/rust-lang/crates.io-index" 2410 | checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" 2411 | dependencies = [ 2412 | "proc-macro2", 2413 | "quote", 2414 | "syn", 2415 | ] 2416 | 2417 | [[package]] 2418 | name = "tracing-core" 2419 | version = "0.1.21" 2420 | source = "registry+https://github.com/rust-lang/crates.io-index" 2421 | checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" 2422 | dependencies = [ 2423 | "lazy_static", 2424 | ] 2425 | 2426 | [[package]] 2427 | name = "tracing-futures" 2428 | version = "0.2.5" 2429 | source = "registry+https://github.com/rust-lang/crates.io-index" 2430 | checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" 2431 | dependencies = [ 2432 | "pin-project", 2433 | "tracing", 2434 | ] 2435 | 2436 | [[package]] 2437 | name = "tracing-log" 2438 | version = "0.1.2" 2439 | source = "registry+https://github.com/rust-lang/crates.io-index" 2440 | checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" 2441 | dependencies = [ 2442 | "lazy_static", 2443 | "log", 2444 | "tracing-core", 2445 | ] 2446 | 2447 | [[package]] 2448 | name = "tracing-serde" 2449 | version = "0.1.2" 2450 | source = "registry+https://github.com/rust-lang/crates.io-index" 2451 | checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b" 2452 | dependencies = [ 2453 | "serde", 2454 | "tracing-core", 2455 | ] 2456 | 2457 | [[package]] 2458 | name = "tracing-stackdriver" 2459 | version = "0.2.0" 2460 | source = "registry+https://github.com/rust-lang/crates.io-index" 2461 | checksum = "3f384c66e353b31924b58f5a88d72de08ae34614d7622802c732a8cc63874608" 2462 | dependencies = [ 2463 | "Inflector", 2464 | "chrono", 2465 | "futures", 2466 | "serde", 2467 | "serde_json", 2468 | "thiserror", 2469 | "tracing-core", 2470 | "tracing-futures", 2471 | "tracing-serde", 2472 | "tracing-subscriber", 2473 | ] 2474 | 2475 | [[package]] 2476 | name = "tracing-subscriber" 2477 | version = "0.2.25" 2478 | source = "registry+https://github.com/rust-lang/crates.io-index" 2479 | checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" 2480 | dependencies = [ 2481 | "ansi_term", 2482 | "chrono", 2483 | "lazy_static", 2484 | "matchers", 2485 | "regex", 2486 | "serde", 2487 | "serde_json", 2488 | "sharded-slab", 2489 | "smallvec", 2490 | "thread_local", 2491 | "tracing", 2492 | "tracing-core", 2493 | "tracing-log", 2494 | "tracing-serde", 2495 | ] 2496 | 2497 | [[package]] 2498 | name = "try-lock" 2499 | version = "0.2.3" 2500 | source = "registry+https://github.com/rust-lang/crates.io-index" 2501 | checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" 2502 | 2503 | [[package]] 2504 | name = "typenum" 2505 | version = "1.14.0" 2506 | source = "registry+https://github.com/rust-lang/crates.io-index" 2507 | checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" 2508 | 2509 | [[package]] 2510 | name = "ucd-trie" 2511 | version = "0.1.3" 2512 | source = "registry+https://github.com/rust-lang/crates.io-index" 2513 | checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" 2514 | 2515 | [[package]] 2516 | name = "unicase" 2517 | version = "2.6.0" 2518 | source = "registry+https://github.com/rust-lang/crates.io-index" 2519 | checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" 2520 | dependencies = [ 2521 | "version_check", 2522 | ] 2523 | 2524 | [[package]] 2525 | name = "unicode-segmentation" 2526 | version = "1.8.0" 2527 | source = "registry+https://github.com/rust-lang/crates.io-index" 2528 | checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" 2529 | 2530 | [[package]] 2531 | name = "unicode-width" 2532 | version = "0.1.9" 2533 | source = "registry+https://github.com/rust-lang/crates.io-index" 2534 | checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" 2535 | 2536 | [[package]] 2537 | name = "unicode-xid" 2538 | version = "0.2.2" 2539 | source = "registry+https://github.com/rust-lang/crates.io-index" 2540 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 2541 | 2542 | [[package]] 2543 | name = "untrusted" 2544 | version = "0.7.1" 2545 | source = "registry+https://github.com/rust-lang/crates.io-index" 2546 | checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" 2547 | 2548 | [[package]] 2549 | name = "vcpkg" 2550 | version = "0.2.15" 2551 | source = "registry+https://github.com/rust-lang/crates.io-index" 2552 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 2553 | 2554 | [[package]] 2555 | name = "version_check" 2556 | version = "0.9.3" 2557 | source = "registry+https://github.com/rust-lang/crates.io-index" 2558 | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" 2559 | 2560 | [[package]] 2561 | name = "walkdir" 2562 | version = "2.3.2" 2563 | source = "registry+https://github.com/rust-lang/crates.io-index" 2564 | checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" 2565 | dependencies = [ 2566 | "same-file", 2567 | "winapi", 2568 | "winapi-util", 2569 | ] 2570 | 2571 | [[package]] 2572 | name = "want" 2573 | version = "0.3.0" 2574 | source = "registry+https://github.com/rust-lang/crates.io-index" 2575 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" 2576 | dependencies = [ 2577 | "log", 2578 | "try-lock", 2579 | ] 2580 | 2581 | [[package]] 2582 | name = "wasi" 2583 | version = "0.10.0+wasi-snapshot-preview1" 2584 | source = "registry+https://github.com/rust-lang/crates.io-index" 2585 | checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" 2586 | 2587 | [[package]] 2588 | name = "wasm-bindgen" 2589 | version = "0.2.78" 2590 | source = "registry+https://github.com/rust-lang/crates.io-index" 2591 | checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" 2592 | dependencies = [ 2593 | "cfg-if", 2594 | "wasm-bindgen-macro", 2595 | ] 2596 | 2597 | [[package]] 2598 | name = "wasm-bindgen-backend" 2599 | version = "0.2.78" 2600 | source = "registry+https://github.com/rust-lang/crates.io-index" 2601 | checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" 2602 | dependencies = [ 2603 | "bumpalo", 2604 | "lazy_static", 2605 | "log", 2606 | "proc-macro2", 2607 | "quote", 2608 | "syn", 2609 | "wasm-bindgen-shared", 2610 | ] 2611 | 2612 | [[package]] 2613 | name = "wasm-bindgen-macro" 2614 | version = "0.2.78" 2615 | source = "registry+https://github.com/rust-lang/crates.io-index" 2616 | checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" 2617 | dependencies = [ 2618 | "quote", 2619 | "wasm-bindgen-macro-support", 2620 | ] 2621 | 2622 | [[package]] 2623 | name = "wasm-bindgen-macro-support" 2624 | version = "0.2.78" 2625 | source = "registry+https://github.com/rust-lang/crates.io-index" 2626 | checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" 2627 | dependencies = [ 2628 | "proc-macro2", 2629 | "quote", 2630 | "syn", 2631 | "wasm-bindgen-backend", 2632 | "wasm-bindgen-shared", 2633 | ] 2634 | 2635 | [[package]] 2636 | name = "wasm-bindgen-shared" 2637 | version = "0.2.78" 2638 | source = "registry+https://github.com/rust-lang/crates.io-index" 2639 | checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" 2640 | 2641 | [[package]] 2642 | name = "web-push" 2643 | version = "0.9.1" 2644 | source = "registry+https://github.com/rust-lang/crates.io-index" 2645 | checksum = "8c66a87a8076f911051065ce6f6655554ec731405494bdcd3467346fe6820ac0" 2646 | dependencies = [ 2647 | "base64 0.13.0", 2648 | "chrono", 2649 | "ece", 2650 | "http", 2651 | "hyper", 2652 | "hyper-tls", 2653 | "jwt-simple", 2654 | "log", 2655 | "pem", 2656 | "pkcs8", 2657 | "sec1_decode", 2658 | "serde", 2659 | "serde_derive", 2660 | "serde_json", 2661 | ] 2662 | 2663 | [[package]] 2664 | name = "web-sys" 2665 | version = "0.3.55" 2666 | source = "registry+https://github.com/rust-lang/crates.io-index" 2667 | checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" 2668 | dependencies = [ 2669 | "js-sys", 2670 | "wasm-bindgen", 2671 | ] 2672 | 2673 | [[package]] 2674 | name = "webpki" 2675 | version = "0.21.4" 2676 | source = "registry+https://github.com/rust-lang/crates.io-index" 2677 | checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" 2678 | dependencies = [ 2679 | "ring", 2680 | "untrusted", 2681 | ] 2682 | 2683 | [[package]] 2684 | name = "winapi" 2685 | version = "0.3.9" 2686 | source = "registry+https://github.com/rust-lang/crates.io-index" 2687 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2688 | dependencies = [ 2689 | "winapi-i686-pc-windows-gnu", 2690 | "winapi-x86_64-pc-windows-gnu", 2691 | ] 2692 | 2693 | [[package]] 2694 | name = "winapi-i686-pc-windows-gnu" 2695 | version = "0.4.0" 2696 | source = "registry+https://github.com/rust-lang/crates.io-index" 2697 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2698 | 2699 | [[package]] 2700 | name = "winapi-util" 2701 | version = "0.1.5" 2702 | source = "registry+https://github.com/rust-lang/crates.io-index" 2703 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 2704 | dependencies = [ 2705 | "winapi", 2706 | ] 2707 | 2708 | [[package]] 2709 | name = "winapi-x86_64-pc-windows-gnu" 2710 | version = "0.4.0" 2711 | source = "registry+https://github.com/rust-lang/crates.io-index" 2712 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2713 | 2714 | [[package]] 2715 | name = "zeroize" 2716 | version = "1.4.2" 2717 | source = "registry+https://github.com/rust-lang/crates.io-index" 2718 | checksum = "bf68b08513768deaa790264a7fac27a58cbf2705cfcdc9448362229217d7e970" 2719 | dependencies = [ 2720 | "zeroize_derive", 2721 | ] 2722 | 2723 | [[package]] 2724 | name = "zeroize_derive" 2725 | version = "1.2.0" 2726 | source = "registry+https://github.com/rust-lang/crates.io-index" 2727 | checksum = "bdff2024a851a322b08f179173ae2ba620445aef1e838f0c196820eade4ae0c7" 2728 | dependencies = [ 2729 | "proc-macro2", 2730 | "quote", 2731 | "syn", 2732 | "synstructure", 2733 | ] 2734 | --------------------------------------------------------------------------------