diff --git a/.easignore b/.easignore
new file mode 100644
index 00000000..2a5ce273
--- /dev/null
+++ b/.easignore
@@ -0,0 +1,18 @@
+node_modules/**/*
+npm-debug.*
+
+.expo/*
+*/coverage
+*/.env
+*/playstore_secret.json
+
+frontend/web-build/
+frontend/dist
+
+api/lib
+
+# macOS
+.DS_Store
+
+# Ignoring other directories
+/documentation
diff --git a/.expo/settings.json b/.expo/settings.json
deleted file mode 100644
index 92bc513b..00000000
--- a/.expo/settings.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "hostType": "lan",
- "lanType": "ip",
- "dev": true,
- "minify": false,
- "urlRandomness": null,
- "https": false
-}
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 86c2ad04..7022ec5e 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -1,3 +1,12 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: ''
+assignees: ''
+
+---
+
---
name: Troubleshooting or Bug Report
about: Create a report to help us improve
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index d1c1ace9..a3834879 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1,10 +1,10 @@
# Type of PR
-- [ ] Bug fix (_non-breaking change which fixes an issue_)
-- [ ] New feature (_adding a feature following a feature-request issue_)
-- [ ] Improvement (_improving an existing feature - includes `style:` and `perf:`commits_)
-- [ ] Refactor (_rewriting existing code without any feature change_)
-- [ ] (!) This change is or requires a documentation update
+- [ ] ๐ Bug fix (_non-breaking change which fixes an issue_)
+- [ ] ๐งโโ๏ธ New feature (_adding a feature following a feature-request issue_)
+- [ ] ๐จ Improvement (_improving an existing feature - includes `style:` and `perf:`commits_)
+- [ ] ๐๏ธ Refactor (_rewriting existing code without any feature change_)
+- [ ] โ๏ธ (!) This change is or requires a documentation update
# Description
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 7dc90a4b..3fb0781e 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -2,25 +2,25 @@ name: CI
on:
push:
- branches: [master, alpha-v2]
+ branches: [master, v2.0.0-beta]
pull_request:
- branches: [master, alpha-v2]
+ branches: [master, v2.0.0-beta]
jobs:
build:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- - uses: actions/setup-node@v1
+ - uses: actions/setup-node@v3
with:
node-version: '16.x'
- name: Get yarn cache directory path
id: yarn-cache-dir-path
- run: echo "::set-output name=dir::$(yarn cache dir)"
+ run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
- - uses: actions/cache@v1
+ - uses: actions/cache@v3
id: yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
diff --git a/.tool-versions b/.tool-versions
new file mode 100644
index 00000000..4df66bbf
--- /dev/null
+++ b/.tool-versions
@@ -0,0 +1 @@
+nodejs 16.20.0
\ No newline at end of file
diff --git a/PROJECT.md b/PROJECT.md
new file mode 100644
index 00000000..7c053e7a
--- /dev/null
+++ b/PROJECT.md
@@ -0,0 +1,63 @@
+# Internal Project Documentation
+
+## Usage of `git`
+
+As of Monday, July 3, 2023, usage of `rebase` and force pushing are no longer permitted on this project.
+
+`git merge` is the acceptable approach for resolving conflicts.
+
+### Example Scenario
+
+Typically what you'll do is `merge` the current branch with another branch (often `master`).
+
+For example, let's suppose you've been working on a feature branch named `feature/push-notifications`.
+
+Since you started making changes, `master` has received quite a few commits (from other PRs being merged in).
+
+In fact, you even need to incorporate some of those changes into your branch.
+
+_This approach is step-by-step and very explicit. There are shortcuts to accomplish this. In this case, we list out every step just to be clear._
+
+#### Step 1: Checkout `master` and pull down the latest changes
+
+You need to ensure your local copy of `master` is up-to-date with what's on the remote.
+
+```
+git checkout master && git pull
+```
+
+#### Step 2: Switch back to your branch
+
+Now that `master` is up-to-date, switch back to `feature/push-notifications`.
+
+```
+git checkout feature/push-notifications
+```
+
+#### Step 3: Merge with `master` to synchronize your branch with it
+
+```
+git merge master
+```
+
+#### Step 4: Resolve any merge conflicts and commit the changes
+
+If there are no [conflicts](https://www.atlassian.com/git/tutorials/using-branches/merge-conflicts), the `merge` command will automatically reconcile the differences between the two branches with a specific merge strategy it selects.
+
+If there are changes that need to be resolved, it depends on your development environment. If you're using VS Code, it will automatically parse the files with [conflict markers](https://wincent.com/wiki/Understanding_Git_conflict_markers) and give you a basic UI on top of them to help decide which changes to keep.
+
+Note that sometimes, you may need to accept both changes and make further revisions manually to ensure that the final merged code is correct and hasn't broken anything / erased any changes.
+
+When making a manual merge, you will need to commit the changes you have made to perform the merge. Make sure this is done before attempting to push.
+
+#### Step 5: Push the updated branch
+
+Check `git log` (or a similar interface in your IDE) to view the most recent commit, and ensure it contains all of the latest merged changes.
+
+Once you have verified this, you can push your updated branch to the remote. It should now be synchronized with `master`.
+
+```
+git push
+```
+
+_Note, if you have not configured a default remote, this command may be something like `git push origin feature/push-notifications`._
diff --git a/README.md b/README.md
index d5446558..11a3ebe0 100644
--- a/README.md
+++ b/README.md
@@ -50,11 +50,13 @@ This will simultaneously launch two processes:
- The Prose GraphQL API Server
- The local Expo dev server, which will enable you to launch the React Native app from your device
-The `quickstart` commands are designed to point at an existing Discourse server, [Discourse Meta](https://meta.discourse.org).
+The `quickstart` commands are designed to point at an existing **public** Discourse server, [Discourse Meta](https://meta.discourse.org).
Configuring it to point at your own Discourse site will take additional configuration.
-You can learn more about this in the [Lexicon Documentation](https://docs.lexicon.is/quick-start).
+We guide you through the basics of this in the next section below.
+
+You can also learn more about this process in detail in the [Lexicon Documentation](https://docs.lexicon.is/quick-start).
## Example: Specifying a custom Discourse Site URL
@@ -62,36 +64,52 @@ This is a brief example to demonstrate how to quickly point the project at a cus
In the example below, we'll use the [Rust Users forum](https://users.rust-lang.org).
-If you'd like, simply change that URL to the URL for your Discourse site in order to follow along with your own site.
+You can also follow along using your own site if you'd like.
After running `yarn && yarn generate` from the project root, execute the following:
```
$ echo "PROSE_DISCOURSE_HOST=https://users.rust-lang.org" > api/.env
-$ echo "MOBILE_PROSE_URL=http://localhost" > frontend/.env
```
-The above statements setup the required environment variables for the Prose GraphQL API and the frontend.
+The above command sets the required environment variable for the Prose GraphQL API.
+
+Next, open up `frontend/Config.ts`, and set the value at `config.localDevelopment.proseUrl` to `http://localhost`.
+
+```ts
+const config = {
+ localDevelopment: {
+ proseUrl: 'http://localhost',
+ },
+ // ...
+};
+```
+
+This instructs the frontend to attempt to connect to a Prose GraphQL API running at `http://localhost`.
-- The API (via `PROSE_DISCOURSE_HOST`) has been instructed to attempt to connect to a Discourse instance at `https://users.rust-lang.org`.
+To bring it all together:
-- The frontend (via `MOBILE_HOST_PROSE`) has been instructed to attempt to connect to a Prose GraphQL API running at `http://localhost` (port 80).
+- The frontend (via `localDevelopment.proseUrl`) has been instructed to connect to a Prose GraphQL API running at `http://localhost` (port 80).
+
+- The Prose GraphQL API (via `PROSE_DISCOURSE_HOST`) has been instructed to connect to a Discourse instance at `https://users.rust-lang.org`.
+
+- When you launch the Mobile App via [Expo Go](https://expo.dev/client), it will reach out to the API running at `http://localhost`, which will contact the Discourse server at `https://users.rust-lang.org`, and the content of that server will appear in the Mobile App.
### Important Notes
-The API default config instructs the server to listen on a hostname of `0.0.0.0` (the public interface) and port 80.
+The API's default config instructs the server to listen on a hostname of `0.0.0.0` (the public interface) and port 80.
-The frontend takes some additional steps so that you can use the app on your mobile device... (Read More)
+The frontend takes some additional steps so that you can test the app with Expo Go on your mobile device... (Read More)
This may seem confusing at first, but it actually saves you a bit of time.
-In this scenario, the frontend app is running on your mobile device via Expo Go, and the Prose GraphQL API is running on your development machine (e.g. laptop).
+In this scenario, the frontend app is running on your mobile device via Expo Go, and the Prose GraphQL API is running on your development machine (e.g., your laptop).
So, how could we expect the mobile app to be able to locate a server running on a different device, when we have only told the frontend app to attempt to connect to the API on `localhost`? The API isn't running on your mobile device.
The traditional way to deal with this is to force you to manually lookup your local IP address on the network that your mobile device is also connected to. It would be a value like `192.168.0.53`.
-Then, you'd have to update `frontend/.env` with that value.
+Then, you'd have to update `frontend/Config.ts` with that value.
Even worse, if your local IP address ever changes, everything would break, and you'd have to update the environment variable again.
@@ -126,7 +144,7 @@ forwarding Discourse requests to https://users.rust-lang.org
๐ก ๐ง Yoga - Running GraphQL Server at http://0.0.0.0:8999/graphql
```
-### Start Expo to run the frontend app
+### Start Expo Go to run the frontend app
After that, **in a separate shell**, start Expo to run the frontend app:
@@ -173,23 +191,3 @@ If you'd like to contribute to it, or just want to browse it locally, you can ru
yarn docs:install
yarn docs:start
```
-
-### Note: Node 16 required
-
-Our tooling, Docusaurus v2, requires Node version 16 in order to work with it.
-
-You can check your current Node version by running the following command:
-
-```
-$ node --version
-v14.17.0
-```
-
-In order to make this process simpler, we recommend installing [nvm](https://github.com/nvm-sh/nvm) (Node version manager) onto your development machine.
-
-Then you'll be able to quickly switch between versions without issue:
-
-```
-$ nvm use 14
-Now using node v14.17.0 (npm v8.15.1)
-```
diff --git a/api/.gitignore b/api/.gitignore
index a918b7e4..d705776d 100644
--- a/api/.gitignore
+++ b/api/.gitignore
@@ -3,3 +3,4 @@ node_modules/**/*
coverage/
src/generated/
.env
+logs/
diff --git a/api/deploy/Dockerfile b/api/deploy/Dockerfile
index 14be7558..beef3819 100644
--- a/api/deploy/Dockerfile
+++ b/api/deploy/Dockerfile
@@ -1,4 +1,4 @@
-FROM keymetrics/pm2:12-alpine
+FROM keymetrics/pm2:16-alpine
WORKDIR /app
@@ -13,6 +13,8 @@ RUN yarn
COPY tsconfig.json ./
COPY ./src ./src
+RUN yarn generate
+
RUN yarn build
COPY pm2.json .
diff --git a/api/docs/logging.md b/api/docs/logging.md
new file mode 100644
index 00000000..f0d23d52
--- /dev/null
+++ b/api/docs/logging.md
@@ -0,0 +1,49 @@
+# Basic Logger
+
+Last updated: 2023/08/28
+
+## Motivation
+
+The Prose API needs a proper logging solution so that users of Lexicon who deploy it can monitor the service for issues. Based on our research, we decided to use Winston for our logger. Winston logger offers a versatile and efficient solution for logging. With support for multiple transport options, customizable log formatting, and different log levels, Winston provides developers with the flexibility to tailor their logging to specific needs.
+
+## Setup
+
+Winston is just a single dependency with the package name [winston](https://github.com/winstonjs/winston), so we added it to the project with `yarn add winston` from within the `api/` directory.
+
+## Transports
+
+In logging, a transport is a destination where logs are stored or displayed, such as a file, console, database, etc. In our logging setup, we mainly use the file transport. But during development, we also add the console transport. We chose the file transport because it offers a simple setup that logs directly into a file. We chose this over transports like [Http and Stream](https://github.com/winstonjs/winston/blob/master/docs/transports.md#built-in-to-winston) because server logs can sometimes contains sensitive information, so we don't want expose the logs on the open internet.
+
+We set up the file transport using a library called [winston-daily-rotate-file](https://github.com/winstonjs/winston-daily-rotate-file), which rotates the log file based on time. In addition to configuring the rotation frequency, we can also specify the maximum file size, the maximum number of files to retain, the number of days to keep files, and more.
+
+Referring to the guidance provided by the [OWASP Logging Cheatsheet](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html), there are some important points to consider when storing logs in a file system:
+
+1. It is preferable to use a separate partition than those used by the operating system, other application files and user generated content.
+2. Apply strict permissions concerning which users can access the directories, and the permissions of files within the directories.
+3. In web applications, the logs should not be exposed in web-accessible locations, and if done so, should have restricted access and be configured with a plain text MIME type (not HTML).
+
+## Approach
+
+We make logging easier by directly connecting the logger to the `GraphQL Yoga` instance using a plugin called `useLogger`, which helps us keep all log calls in one central place.
+
+```
+useLogger({
+ logFn: (eventName, events) => {
+ // Event could be `execute-start` / `execute-end` / `subscribe-start` / `subscribe-end`
+ // `args` will include the arguments passed to execute/subscribe (in case of "start" event)
+ // and additional result in case of "end" event.
+ switch (eventName) {
+ case 'execute-end':
+ case 'subscribe-end':
+ // Do logging
+ break;
+ }
+ },
+})
+```
+
+We categorize our logs into two distinct files, one exclusively for 'error' level logs, and the other for a compilation of logs across all levels.
+
+## Future Improvement
+
+At the moment, our loggers are mainly used to catch any GraphQL errors that are thrown on the server side. But in the future, we're thinking about logging additional types of server errors, like runtime or network issues.
diff --git a/api/docs/typescript.md b/api/docs/typescript.md
new file mode 100644
index 00000000..7b582678
--- /dev/null
+++ b/api/docs/typescript.md
@@ -0,0 +1,14 @@
+# Typescript Usage
+
+The Prose GraphQL makes use of Typescript in multiple ways:
+
+- Nexus for schema generation, which generates Typescript types for use in the resolvers
+- Manual type definitions
+- As of Tuesday, August 15, 2023, we began incrementally adopting usage of [zod](https://github.com/colinhacks/zod) for type definitions and validation
+- @ts-reset for additional type safety checks
+
+Generally, this codebase strives to be as type-safe as possible, and we are always improving upon this.
+
+The original implementation was not very careful with types, and as such there are still cases of implicit any, type assertions, and other bad practices.
+
+Our adoption of tools like zod and @ts-reset are intended to help progressively address lingering type saftey issues.
diff --git a/api/package.json b/api/package.json
index eca1edb6..3f57cdc3 100644
--- a/api/package.json
+++ b/api/package.json
@@ -3,49 +3,63 @@
"version": "1.0.0",
"scripts": {
"start": "yarn build && node lib/index.js",
- "quickstart": "yarn generate && env PROSE_DISCOURSE_HOST=https://meta.discourse.org PROSE_APP_HOSTNAME=0.0.0.0 PROSE_APP_PORT=8929 ts-node-dev --no-notify --respawn --transpile-only src/index.ts",
+ "quickstart": "yarn generate && cross-env PROSE_DISCOURSE_HOST=https://meta.discourse.org PROSE_APP_HOSTNAME=0.0.0.0 PROSE_APP_PORT=8929 ts-node-dev --no-notify --respawn --transpile-only src/index.ts",
"dev": "yarn generate && ts-node-dev --no-notify --respawn --transpile-only src/index.ts",
"typecheck": "tsc --noEmit -p .",
"format": "prettier --write \"src/**/*.{ts,tsx}\"",
"format:check": "prettier --check \"src/**/*.{ts,tsx}\"",
- "generate:schema": "env SKIP_VALIDATION=true ts-node --transpile-only src/schema.ts",
+ "generate:schema": "cross-env SKIP_VALIDATION=true ts-node --transpile-only src/schema.ts",
"generate": "yarn generate:schema",
"lint": "eslint --max-warnings 0 \"src/**/*.{ts,tsx}\"",
- "jest": "env PROSE_DISCOURSE_HOST=https://meta.discourse.org jest --coverage --passWithNoTests",
+ "jest": "cross-env PROSE_DISCOURSE_HOST=https://meta.discourse.org jest --coverage --passWithNoTests",
"test": "yarn lint && yarn typecheck && yarn format:check && yarn build && yarn jest",
"build": "tsc --outDir lib/"
},
"dependencies": {
- "@nexus/schema": "^0.15.0",
+ "@envelop/core": "^1.0.3",
+ "@graphql-authz/core": "^1.2.1",
+ "@graphql-authz/envelop-plugin": "^1.0.3",
+ "@graphql-yoga/node": "^2.13.8",
"axios": "^0.21.2",
"axios-cookiejar-support": "^1.0.0",
"camelcase-keys": "^6.2.2",
"dotenv": "^8.2.0",
- "form-data": "^3.0.0",
- "graphql-shield": "6.1.0",
- "graphql-upload": "8.0.7",
- "graphql-yoga": "^1.18.3",
+ "form-data": "^4.0.0",
+ "graphql": "^16.5.0",
+ "nexus": "^1.4.0-next.11",
"querystring": "^0.2.0",
+ "set-cookie-parser": "^2.5.1",
"snakecase-keys": "^3.2.0",
- "tough-cookie": "^4.0.0"
+ "tough-cookie": "^4.1.3",
+ "winston": "^3.10.0",
+ "winston-daily-rotate-file": "^4.7.1",
+ "zod": "^3.22.0"
},
"devDependencies": {
+ "@total-typescript/ts-reset": "^0.4.2",
"@types/form-data": "^2.5.0",
- "@types/graphql-upload": "^8.0.3",
"@types/jest": "^26.0.9",
"@types/node": "^14.0.27",
+ "@types/set-cookie-parser": "^2.4.2",
"@types/tough-cookie": "^4.0.0",
"@types/ws": "^7.2.6",
+ "cross-env": "^7.0.3",
"eslint": "^7.6.0",
- "eslint-config-kodefox": "^0.2.2",
+ "eslint-config-kodefox": "^1.2.0",
"jest": "^26.2.2",
"prettier": "^2.0.5",
"ts-jest": "^26.1.4",
"ts-node-dev": "^1.0.0-pre.56",
- "typescript": "^3.9.7"
+ "typescript": "4.7.4"
},
"eslintConfig": {
- "extends": "kodefox"
+ "extends": "kodefox",
+ "rules": {
+ "operator-assignment": [
+ "warn",
+ "always"
+ ]
+ }
},
"prettier": {
"singleQuote": true,
diff --git a/api/reset.d.ts b/api/reset.d.ts
new file mode 100644
index 00000000..faedef42
--- /dev/null
+++ b/api/reset.d.ts
@@ -0,0 +1,2 @@
+// Do not add any other lines of code to this file!
+import '@total-typescript/ts-reset';
diff --git a/api/src/__tests__/api.ts b/api/src/__tests__/api.ts
new file mode 100644
index 00000000..46b5c501
--- /dev/null
+++ b/api/src/__tests__/api.ts
@@ -0,0 +1,21 @@
+import { DEFAULT_PROSE_APP_PORT, getAppPort } from '../constants';
+
+describe('getAppPort', () => {
+ it('should return the default port value when the params are undefined', () => {
+ expect(getAppPort(undefined, undefined)).toEqual(DEFAULT_PROSE_APP_PORT);
+ });
+ it('should return one of the params in number when the other one is undefined', () => {
+ expect(getAppPort('8929', undefined)).toEqual(8929);
+ expect(getAppPort(undefined, '8929')).toEqual(8929);
+ });
+ it('should return the first param in number when both params are provided', () => {
+ expect(getAppPort('8929', '1234')).toEqual(8929);
+ });
+ it('should return the number param when the other one is not a number', () => {
+ expect(getAppPort('8929', 'lexicon')).toEqual(8929);
+ expect(getAppPort('lexicon', '1234')).toEqual(1234);
+ });
+ it('should return the default port value when both params are not numbers', () => {
+ expect(getAppPort('lexicon', 'cool')).toEqual(DEFAULT_PROSE_APP_PORT);
+ });
+});
diff --git a/api/src/__tests__/getPosterTypeDetails.ts b/api/src/__tests__/getPosterTypeDetails.ts
new file mode 100644
index 00000000..b391bb45
--- /dev/null
+++ b/api/src/__tests__/getPosterTypeDetails.ts
@@ -0,0 +1,133 @@
+import { getPosterTypeDetails } from '../helpers/getPosterTypeDetails';
+
+describe('getPosterTypeDetails', () => {
+ describe('English', () => {
+ it('handles a string where original poster is not first', () => {
+ const result = getPosterTypeDetails('Frequent Poster, Original Poster');
+ expect(result).toEqual({
+ isAuthor: true,
+ isFrequentPoster: true,
+ isMostRecentPoster: false,
+ });
+ });
+ it('handles uppercase', () => {
+ const result = getPosterTypeDetails('ORIGINAL POSTER');
+ expect(result).toEqual({
+ isAuthor: true,
+ isFrequentPoster: false,
+ isMostRecentPoster: false,
+ });
+ });
+ it('handles lowercase', () => {
+ const result = getPosterTypeDetails(
+ 'original poster, most recent poster',
+ );
+ expect(result).toEqual({
+ isAuthor: true,
+ isFrequentPoster: false,
+ isMostRecentPoster: true,
+ });
+ });
+ it('handles empty string', () => {
+ const result = getPosterTypeDetails('');
+ expect(result).toEqual({
+ isAuthor: false,
+ isFrequentPoster: false,
+ isMostRecentPoster: false,
+ });
+ });
+ it('handles all three types', () => {
+ const result = getPosterTypeDetails(
+ 'original poster, most recent poster, frequent poster',
+ );
+ expect(result).toEqual({
+ isAuthor: true,
+ isFrequentPoster: true,
+ isMostRecentPoster: true,
+ });
+ });
+ it('handles multiple spaces between entries', () => {
+ const result = getPosterTypeDetails(
+ ' original poster, most recent poster, frequent poster ',
+ );
+ expect(result).toEqual({
+ isAuthor: true,
+ isFrequentPoster: true,
+ isMostRecentPoster: true,
+ });
+ });
+
+ it('handles empty string', () => {
+ const result = getPosterTypeDetails('');
+ expect(result).toEqual({
+ isAuthor: false,
+ isFrequentPoster: false,
+ isMostRecentPoster: false,
+ });
+ });
+ });
+ describe('Simplified Chinese', () => {
+ it('handles a string where original poster is not first', () => {
+ const result = getPosterTypeDetails('้ข็นๅๅธไบบใๅๅงๅๅธไบบ');
+
+ expect(result).toEqual({
+ isAuthor: true,
+ isFrequentPoster: true,
+ isMostRecentPoster: false,
+ });
+ });
+
+ it('handles all three types', () => {
+ const result = getPosterTypeDetails(
+ 'ๅๅงๅๅธไบบใ ๆๆฐๅๅธไบบใ ้ข็นๅๅธไบบ',
+ );
+ expect(result).toEqual({
+ isAuthor: true,
+ isFrequentPoster: true,
+ isMostRecentPoster: true,
+ });
+ });
+ it('handles multiple spaces between entries', () => {
+ const result = getPosterTypeDetails(
+ ' ๅๅงๅๅธไบบใ ๆๆฐๅๅธไบบใ ้ข็นๅๅธไบบ ',
+ );
+ expect(result).toEqual({
+ isAuthor: true,
+ isFrequentPoster: true,
+ isMostRecentPoster: true,
+ });
+ });
+ });
+ describe('Traditional Chinese', () => {
+ it('handles a string where original poster is not first', () => {
+ const result = getPosterTypeDetails('้ ป็น็ผๆ่
ใๅๅงไฝ่
');
+
+ expect(result).toEqual({
+ isAuthor: true,
+ isFrequentPoster: true,
+ isMostRecentPoster: false,
+ });
+ });
+
+ it('handles all three types', () => {
+ const result = getPosterTypeDetails(
+ 'ๅๅงไฝ่
ใ ็ถๅๅคง้จๅ่ฒผๆไฝ่
ใ ้ ป็น็ผๆ่
',
+ );
+ expect(result).toEqual({
+ isAuthor: true,
+ isFrequentPoster: true,
+ isMostRecentPoster: true,
+ });
+ });
+ it('handles multiple spaces between entries', () => {
+ const result = getPosterTypeDetails(
+ ' ๅๅงไฝ่
ใ ็ถๅๅคง้จๅ่ฒผๆไฝ่
ใ ้ ป็น็ผๆ่
',
+ );
+ expect(result).toEqual({
+ isAuthor: true,
+ isFrequentPoster: true,
+ isMostRecentPoster: true,
+ });
+ });
+ });
+});
diff --git a/api/src/__tests__/getTopicAuthor.ts b/api/src/__tests__/getTopicAuthor.ts
new file mode 100644
index 00000000..4f693d69
--- /dev/null
+++ b/api/src/__tests__/getTopicAuthor.ts
@@ -0,0 +1,100 @@
+import {
+ getTopicAuthor,
+ getTopicAuthorUserId,
+} from '../helpers/getTopicAuthor';
+import { TopicPoster } from '../types';
+
+function getUserWithId(
+ userId: number | null,
+ description: string,
+): TopicPoster {
+ return {
+ userId,
+ description,
+ extras: null,
+ user: null,
+ };
+}
+
+function getUserWithObject(userId: number, description: string): TopicPoster {
+ return {
+ ...getUserWithId(null, description),
+ user: {
+ id: userId,
+ username: 'bill',
+ name: 'Bill',
+ avatarTemplate: 'avatar.jpg',
+ },
+ };
+}
+
+describe('getTopicAuthor', () => {
+ it('returns the author of the topic when present', () => {
+ const posters: Array = [
+ getUserWithId(1, 'Frequent Poster'),
+ getUserWithId(2, 'Most Recent Poster'),
+ getUserWithId(3, 'Frequent Poster, Original Poster'),
+ ];
+
+ expect(getTopicAuthor(posters)).toEqual(posters[2]);
+ });
+
+ it('returns the first author when multiple are somehow present', () => {
+ const posters: Array = [
+ getUserWithId(1, 'Original Poster'),
+ getUserWithId(2, 'Most Recent Poster'),
+ getUserWithId(3, 'Frequent Poster, Original Poster'),
+ ];
+
+ expect(getTopicAuthor(posters)).toEqual(posters[0]);
+ });
+
+ it('returns undefined when no author is present', () => {
+ const posters: Array = [
+ getUserWithId(1, 'Frequent Poster'),
+ getUserWithId(2, 'Frequent Poster'),
+ getUserWithId(3, 'Frequent Poster, Most Recent Poster'),
+ ];
+
+ expect(getTopicAuthor(posters)).toBeUndefined();
+ });
+
+ it('returns undefined for an empty array', () => {
+ expect(getTopicAuthor([])).toBeUndefined();
+ });
+});
+
+describe('getTopicAuthorUserId', () => {
+ it(`returns the author's userId when present`, () => {
+ const posters: Array = [
+ getUserWithId(1, 'Frequent Poster'),
+ getUserWithId(2, 'Most Recent Poster'),
+ getUserWithId(3, 'Frequent Poster, Original Poster'),
+ ];
+ expect(getTopicAuthorUserId(posters)).toEqual(3);
+ });
+
+ it(`returns the author's user.id when present`, () => {
+ const posters: Array = [
+ getUserWithId(1, 'Frequent Poster'),
+ getUserWithId(2, 'Most Recent Poster'),
+ getUserWithObject(3, 'Frequent Poster, Original Poster'),
+ ];
+ expect(getTopicAuthorUserId(posters)).toEqual(3);
+ });
+
+ it(`prefers the author's userId when the user object is set too`, () => {
+ const posters: Array = [
+ getUserWithId(1, 'Frequent Poster'),
+ getUserWithId(2, 'Most Recent Poster'),
+ {
+ ...getUserWithObject(
+ Number.MAX_VALUE,
+ 'Frequent Poster, Original Poster',
+ ),
+ userId: 3,
+ },
+ ];
+ expect(getTopicAuthorUserId(posters)).toEqual(3);
+ });
+});
diff --git a/api/src/__tests__/getTopicPostPath.ts b/api/src/__tests__/getTopicPostPath.ts
index 42bb0d8c..214f8f0c 100644
--- a/api/src/__tests__/getTopicPostPath.ts
+++ b/api/src/__tests__/getTopicPostPath.ts
@@ -1,33 +1,13 @@
import { getTopicPostPath } from '../helpers';
-it('Have input post and pointer', () => {
- const inputPost = [2, 3, 4];
- const postPointer = 2;
- const expectedOutput = '/posts';
- let topicUrl = getTopicPostPath(inputPost, postPointer);
- expect(topicUrl).toEqual(expectedOutput);
+it('should return posts when the input is array of numbers', () => {
+ expect(getTopicPostPath([2, 3, 4])).toEqual('/posts');
});
-it('Have input post without pointer', () => {
- const inputPost = [2, 3, 4];
- const postPointer = undefined;
- const expectedOutput = '/posts';
- let topicUrl = getTopicPostPath(inputPost, postPointer);
- expect(topicUrl).toEqual(expectedOutput);
+it('should return post pointer when the input is number', () => {
+ expect(getTopicPostPath(2)).toEqual('/2');
});
-it('Have input post pointer', () => {
- const inputPost = undefined;
- const postPointer = 2;
- const expectedOutput = '/2';
- let topicUrl = getTopicPostPath(inputPost, postPointer);
- expect(topicUrl).toEqual(expectedOutput);
-});
-
-it('Does not have input', () => {
- const inputPost = undefined;
- const postPointer = undefined;
- const expectedOutput = '';
- let topicUrl = getTopicPostPath(inputPost, postPointer);
- expect(topicUrl).toEqual(expectedOutput);
+it('should return empty string when the input is undefined', () => {
+ expect(getTopicPostPath(undefined)).toEqual('');
});
diff --git a/api/src/__tests__/getUpdatedLikedTopic.ts b/api/src/__tests__/getUpdatedLikedTopic.ts
new file mode 100644
index 00000000..df01eea1
--- /dev/null
+++ b/api/src/__tests__/getUpdatedLikedTopic.ts
@@ -0,0 +1,30 @@
+import { getUpdatedLikedTopic } from '../helpers';
+
+const likeCount = 5;
+const currentLikedTopicResponse = {
+ id: 12,
+ topicId: 1,
+ liked: false,
+ postId: 2,
+ likeCount,
+};
+
+it('should increase likeCount and return data in LikedTopic response', () => {
+ expect(
+ getUpdatedLikedTopic({ currentLikedTopicResponse, isLiked: true }),
+ ).toEqual({
+ ...currentLikedTopicResponse,
+ liked: true,
+ likeCount: likeCount + 1,
+ });
+});
+
+it('should decrease likeCount and return data in LikedTopic response', () => {
+ expect(
+ getUpdatedLikedTopic({ currentLikedTopicResponse, isLiked: false }),
+ ).toEqual({
+ ...currentLikedTopicResponse,
+ liked: false,
+ likeCount: likeCount - 1,
+ });
+});
diff --git a/api/src/__tests__/processRawContent.ts b/api/src/__tests__/processRawContent.ts
index 076a62e0..beebca59 100644
--- a/api/src/__tests__/processRawContent.ts
+++ b/api/src/__tests__/processRawContent.ts
@@ -1,24 +1,26 @@
-import { getPostImageUrl } from '../helpers';
+import {
+ generateMarkdownContent,
+ getCompleteImageVideoUrls,
+ getEmojiImageUrls,
+} from '../helpers';
-describe('getPostImageUrl return image urls from html tags', () => {
- it('should return last url from srcset in img tag', () => {
+describe('getCompleteImageUrls return image urls from html tags', () => {
+ it('should return the last url from srcset in img tag if any', () => {
expect(
- getPostImageUrl(
+ getCompleteImageVideoUrls(
`
-
`,
),
).toEqual([
'https://wiki.kfox.io/uploads/default/optimized/example_2_666x1000.jpeg',
- 'https://wiki.kfox.io/uploads/default/optimized/example_2_666x1000.jpg',
]);
});
it('should return image url in anchor tag if no srcset found', () => {
expect(
- getPostImageUrl(
+ getCompleteImageVideoUrls(
`
@@ -44,7 +46,7 @@ describe('getPostImageUrl return image urls from html tags', () => {
});
it('should return image url in img tag if no anchor tag found', () => {
expect(
- getPostImageUrl(
+ getCompleteImageVideoUrls(
`
@@ -61,4 +63,126 @@ describe('getPostImageUrl return image urls from html tags', () => {
'https://wiki.kfox.io/example.png',
]);
});
+ it('should return one image url for each image tag. The url will be from srcset if any, or from href tag if any, or from img src', () => {
+ expect(
+ getCompleteImageVideoUrls(
+ `
+
+
+
+
+
+ `,
+ ),
+ ).toEqual([
+ 'https://wiki.kfox.io/uploads/default/original.jpeg',
+ 'https://wiki.kfox.io/uploads/default/optimized/1X/test_2_1380x828.jpeg',
+ 'https://wiki.kfox.io/uploads/default/original/test2.jpeg',
+ ]);
+ });
+});
+
+describe('generateMarkdownContent returns markdown content with complete urls, obtained from cooked content', () => {
+ const rawContent = 'Hello Lexicon! ![image](upload://shortUrl.com)';
+ const shortImageUrl = '![image](upload://shortUrl.com)';
+ const cookedContent =
+ 'Hello Lexicon!
';
+ const markdownContent =
+ 'Hello Lexicon! ![image](https://wiki.kfox.io/example.png)';
+
+ it('should return raw content when there are no image urls in cooked content', () => {
+ expect(generateMarkdownContent(rawContent, 'Hello Lexicon!
')).toBe(
+ rawContent,
+ );
+ });
+ it('should return raw content when there is no short url in raw content', () => {
+ const rawContentWithNoImage = 'Hello Lexicon!';
+ expect(generateMarkdownContent(rawContentWithNoImage, cookedContent)).toBe(
+ rawContentWithNoImage,
+ );
+ });
+
+ it('should return raw content with short urls and complete urls when the total number of short urls is more than the complete urls in the cooked data', () => {
+ expect(
+ generateMarkdownContent(`${rawContent} ${shortImageUrl}`, cookedContent),
+ ).toBe(`${markdownContent} ${shortImageUrl}`);
+ });
+ it('should return raw content with no short url when the total number of short urls is less than the complete urls in cooked data', () => {
+ const completeImageUrl =
+ ' ';
+ expect(
+ generateMarkdownContent(
+ rawContent,
+ `${cookedContent} ${completeImageUrl}`,
+ ),
+ ).toBe(markdownContent);
+ });
+
+ it('should return raw content with no short url when the total number of short urls is the same as the complete urls in the cooked data', () => {
+ expect(generateMarkdownContent(rawContent, cookedContent)).toBe(
+ markdownContent,
+ );
+ });
+ it('should only replace short urls and return raw content with complete urls when there are short and complete urls in raw data', () => {
+ const completeImageUrl =
+ '![second image](https://wiki.kfox.io/secondExample.png)';
+ const secondCompleteUrlInCooked =
+ ' ';
+ const secondCompleteUrlInMarkdown =
+ '![image](https://wiki.kfox.io/example3.png)';
+ expect(
+ generateMarkdownContent(
+ `${rawContent} ${completeImageUrl} ${shortImageUrl}`,
+ `${cookedContent} ${secondCompleteUrlInCooked}`,
+ ),
+ ).toBe(
+ `${markdownContent} ${completeImageUrl} ${secondCompleteUrlInMarkdown}`,
+ );
+ });
+});
+
+describe('generate emoji url from image tag', () => {
+ it('it should return image url from image tags', () => {
+ const content =
+ ' ';
+ const content2 =
+ 'Test.
';
+
+ const content3 =
+ ' ';
+
+ expect(getEmojiImageUrls(content)).toEqual([
+ {
+ emojiTitle: ':smile:',
+ emojiUrl:
+ 'https://kflounge-staging.kfox.io/images/emoji/twitter/smile.png',
+ },
+ ]);
+ expect(getEmojiImageUrls(content2)).toEqual([
+ {
+ emojiTitle: ':high_heel:',
+ emojiUrl:
+ 'https://kflounge-staging.kfox.io/images/emoji/twitter/high_heel.png',
+ },
+ {
+ emojiTitle: ':man:t5:',
+ emojiUrl:
+ 'https://kflounge-staging.kfox.io/images/emoji/twitter/man/5.png',
+ },
+ ]);
+ expect(getEmojiImageUrls(content3)).toEqual([]);
+ });
});
diff --git a/api/src/__tests__/resolvers/utils.ts b/api/src/__tests__/resolvers/utils.ts
new file mode 100644
index 00000000..ca0226ef
--- /dev/null
+++ b/api/src/__tests__/resolvers/utils.ts
@@ -0,0 +1,119 @@
+import { PROSE_DISCOURSE_HOST } from '../../constants';
+import {
+ getNormalizedUrlTemplate,
+ NormalizedUrlTemplateVariant,
+} from '../../resolvers/utils';
+
+describe('getNormalizedUrlTemplate', () => {
+ const tests: Array<[string, NormalizedUrlTemplateVariant]> = [
+ ['avatarTemplate', 'regularAvatar'],
+ ['actingAvatarTemplate', 'actingAvatar'],
+ ['systemAvatarTemplate', 'systemAvatar'],
+ ['url', 'url'],
+ ];
+
+ tests.forEach(([property, variant]) => {
+ /**
+ * Helper function to make Typescript happy. Without this, it complains
+ * about the object not containing at least one of the expected keys.
+ *
+ * This occurs even if we annote tests like:
+ * ```
+ * type TemplateField = 'avatarTemplate' | 'actingAvatarTemplate' | ...;
+ * const tests: [TemplateField, NormalizedUrlTemplateVariant][] = [ ... ];
+ * ```
+ *
+ * So instead, we check each case and fallback to the last case of `url` if
+ * none of the others matched.
+ */
+ function getParameter(url: string) {
+ if (property === 'avatarTemplate') {
+ return { avatarTemplate: url };
+ }
+
+ if (property === 'actingAvatarTemplate') {
+ return { actingAvatarTemplate: url };
+ }
+
+ if (property === 'systemAvatarTemplate') {
+ return { systemAvatarTemplate: url };
+ }
+
+ return { url };
+ }
+
+ describe(property, () => {
+ it('does not append host when http is already present', () => {
+ const input = 'https://discourse.host/site/images/1.jpg';
+ const parameter = getParameter(input);
+
+ const result = getNormalizedUrlTemplate(parameter, variant);
+ expect(result).toStrictEqual(input);
+ });
+
+ it('appends host when http is not present', () => {
+ const input = '/thumbnails/32x32/user-5.jpg';
+ const parameter = getParameter(input);
+
+ const result = getNormalizedUrlTemplate(parameter, variant);
+
+ expect(result).toStrictEqual(`${PROSE_DISCOURSE_HOST}${input}`);
+ });
+ });
+ });
+
+ it('returns an empty URL when no URL field was provided', () => {
+ // Justification: ignore the fact that TS won't let us pass an empty
+ // object just to double-check how it behaves.
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ const result = getNormalizedUrlTemplate({}, 'url');
+ expect(result).toStrictEqual('');
+ });
+
+ it('returns an empty URL when an empty URL was provided', () => {
+ const result = getNormalizedUrlTemplate({ url: '' }, 'url');
+ expect(result).toStrictEqual('');
+ });
+
+ it('returns an empty URL when the variant does not match the URL field', () => {
+ const input = '/images/1.jpg';
+ const result = getNormalizedUrlTemplate(
+ { systemAvatarTemplate: input },
+ 'actingAvatar',
+ );
+ expect(result).toStrictEqual('');
+ });
+
+ it('defaults the variant to regularAvatar when no variant is provided', () => {
+ const input = '/images/1.jpg';
+ const result = getNormalizedUrlTemplate({ avatarTemplate: input });
+ expect(result).toStrictEqual(`${PROSE_DISCOURSE_HOST}${input}`);
+ });
+
+ /** PRURLS (Protocol-relative URLs) allow specifying a URL without the protocol.
+ * For example, https://google.com might be specified as `//google.com`. It is a
+ * method for linking to a website that offers both HTTP and HTTPS.
+ *
+ * The test below tests for what is basically a bug. If we later want to
+ * support these URLs, we should revamp the function to support checking for
+ * PRURLs as well. For now, this just serves as an example of how it would
+ * behave if we encountered one.
+ */
+ it('poorly appends the path for PRURLs', () => {
+ const result = getNormalizedUrlTemplate(
+ { url: '//discourse.host/site/images/1.jpg' },
+ 'url',
+ );
+ expect(result).toStrictEqual(
+ 'https://meta.discourse.org//discourse.host/site/images/1.jpg',
+ );
+ });
+
+ it('handles http:// as expected', () => {
+ const avatarTemplate = 'http://meta.discourse.org/site/images/1.png';
+ const result = getNormalizedUrlTemplate({ avatarTemplate });
+
+ expect(result).toStrictEqual(avatarTemplate);
+ });
+});
diff --git a/api/src/client.ts b/api/src/client.ts
index 0ac0104d..b9f9e546 100644
--- a/api/src/client.ts
+++ b/api/src/client.ts
@@ -1,9 +1,17 @@
+import { ServerResponse } from 'http';
+
import axios, { AxiosResponse } from 'axios';
import axiosCookieJarSupport from 'axios-cookiejar-support';
import { CookieJar } from 'tough-cookie';
+import setCookie from 'set-cookie-parser';
-import { PROSE_DISCOURSE_HOST } from './constants';
-import { getCsrfSession } from './helpers/auth';
+import { CUSTOM_HEADER_TOKEN, PROSE_DISCOURSE_HOST } from './constants';
+import {
+ cookiesStringify,
+ generateToken,
+ getCsrfSession,
+ getModifiedUserAgent,
+} from './helpers';
export const discourseClient = axios.create({
baseURL: PROSE_DISCOURSE_HOST,
@@ -13,8 +21,22 @@ export const discourseClient = axios.create({
axiosCookieJarSupport(discourseClient);
discourseClient.defaults.jar = new CookieJar();
-export async function getClient(cookies?: string) {
+type GetClientParams = {
+ cookies?: string;
+ userAgent?: string;
+ context: {
+ request: Request;
+ response: ServerResponse;
+ };
+};
+
+export async function getClient(params: GetClientParams) {
+ const { cookies, userAgent, context } = params;
let client = discourseClient;
+ client.defaults.headers = {
+ 'User-Agent': getModifiedUserAgent(userAgent),
+ };
+
if (cookies) {
let { csrf } = await getCsrfSession(cookies);
client = axios.create({
@@ -26,10 +48,12 @@ export async function getClient(cookies?: string) {
client.defaults.jar = new CookieJar();
client.defaults.headers = {
Cookie: cookies,
- 'x-csrf-token': csrf,
withCredentials: true,
+ 'User-Agent': getModifiedUserAgent(userAgent),
+ 'x-csrf-token': csrf,
};
}
+
client.interceptors.response.use(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(response: AxiosResponse) => {
@@ -38,6 +62,28 @@ export async function getClient(cookies?: string) {
throw new Error('Not found or private.');
}
+ let cookies = response.headers['set-cookie'];
+
+ /**
+ * This condition is used to check if there is a valid cookie.
+ * For the cookie to be refreshed, it must contain an _t cookie and
+ * it ensures that the cookie format is correct, excluding cookies from the login API,
+ * which uses the `session.json` endpoint.
+ */
+
+ if (
+ cookies &&
+ // eslint-disable-next-line no-underscore-dangle
+ setCookie.parse(cookies, { map: true })._t &&
+ !response.request.path.includes('session.json')
+ ) {
+ let stringCookie = cookiesStringify(cookies);
+ let token = generateToken(stringCookie);
+
+ if (!context.response.headersSent) {
+ context.response.setHeader(CUSTOM_HEADER_TOKEN, token);
+ }
+ }
return response;
},
);
diff --git a/api/src/constants/api.ts b/api/src/constants/api.ts
index bc14341e..54d72532 100644
--- a/api/src/constants/api.ts
+++ b/api/src/constants/api.ts
@@ -10,7 +10,7 @@ import { EXIT_CODE_INVALID_ARGUMENT } from './exitCodes';
const shouldValidate = process.env.SKIP_VALIDATION === undefined;
const DEFAULT_PROSE_APP_HOSTNAME = '0.0.0.0';
-const DEFAULT_PROSE_APP_PORT = 80;
+export const DEFAULT_PROSE_APP_PORT = 80;
// Per Express's requirement, ensure that the hostname does not have the scheme (http://, etc.)
// included in it.
@@ -38,21 +38,33 @@ if (shouldValidate) {
}
}
-function getAppPort() {
- const { PROSE_APP_PORT } = process.env;
- if (!PROSE_APP_PORT) {
+export function getAppPort(nodePort?: string, prosePort?: string) {
+ const definedPort = nodePort ?? prosePort;
+ if (!definedPort) {
return DEFAULT_PROSE_APP_PORT;
}
- const parsed = Number.parseInt(PROSE_APP_PORT, 10);
- if (Number.isNaN(parsed)) {
+ let parsed = Number.parseInt(definedPort, 10);
+ if (!Number.isNaN(parsed)) {
+ return parsed;
+ }
+
+ // Check prose port if the definedPort value is different from prose port
+ if (!prosePort || definedPort === prosePort) {
return DEFAULT_PROSE_APP_PORT;
}
+ parsed = Number.parseInt(prosePort, 10);
+ if (Number.isNaN(parsed)) {
+ return DEFAULT_PROSE_APP_PORT;
+ }
return parsed;
}
-export const PROSE_APP_PORT = getAppPort();
+export const PROSE_APP_PORT = getAppPort(
+ process.env.PORT,
+ process.env.PROSE_APP_PORT,
+);
export const PROSE_APP_HOSTNAME =
process.env.PROSE_APP_HOSTNAME ?? DEFAULT_PROSE_APP_HOSTNAME;
diff --git a/api/src/constants/discourse.ts b/api/src/constants/discourse.ts
new file mode 100644
index 00000000..e723bf3a
--- /dev/null
+++ b/api/src/constants/discourse.ts
@@ -0,0 +1,10 @@
+export const FIRST_POST_NUMBER = 1;
+export const LIKE_ACTION_ID = 2;
+export const UNCATEGORIZED_CATEGORY_ID = 1;
+
+export const errorTypes = {
+ invalidAccess: 'invalid_access',
+ unauthenticatedAccess: 'not_logged_in',
+};
+
+export const REFRESH_TOKEN_COOKIE_FIELD = '_t=';
diff --git a/api/src/constants/errorMessage.ts b/api/src/constants/errorMessage.ts
index 76184e93..d476702a 100644
--- a/api/src/constants/errorMessage.ts
+++ b/api/src/constants/errorMessage.ts
@@ -1,3 +1,5 @@
export const EditPostError =
'That post was created too long ago. It can no longer be edited or deleted.';
export const ChangeUsernameError = 'Username must be unique';
+export const privateTopic =
+ 'The topic cannot be accessed as it is a private topic.';
diff --git a/api/src/constants/index.ts b/api/src/constants/index.ts
index c3ba396d..2f7adb64 100644
--- a/api/src/constants/index.ts
+++ b/api/src/constants/index.ts
@@ -1,4 +1,5 @@
export * from './api';
+export * from './discourse';
export * from './errorMessage';
export * from './exitCodes';
export * from './server';
diff --git a/api/src/constants/server.ts b/api/src/constants/server.ts
index dd9170aa..e84b3600 100644
--- a/api/src/constants/server.ts
+++ b/api/src/constants/server.ts
@@ -5,5 +5,11 @@ config();
const ACCEPTED_LANGUAGE = 'en-US';
const CONTENT_FORM_URLENCODED = 'application/x-www-form-urlencoded';
const CONTENT_JSON = 'application/json';
+const CUSTOM_HEADER_TOKEN = 'X-Prose-Latest-Token';
-export { ACCEPTED_LANGUAGE, CONTENT_FORM_URLENCODED, CONTENT_JSON };
+export {
+ ACCEPTED_LANGUAGE,
+ CONTENT_FORM_URLENCODED,
+ CONTENT_JSON,
+ CUSTOM_HEADER_TOKEN,
+};
diff --git a/api/src/helpers/auth.ts b/api/src/helpers/auth.ts
index 07fa43de..a266a5a5 100644
--- a/api/src/helpers/auth.ts
+++ b/api/src/helpers/auth.ts
@@ -8,6 +8,7 @@ import { discourseClient } from '../client';
import { CONTENT_FORM_URLENCODED } from '../constants';
import { cookiesStringify } from './cookiesStringify';
+import { SessionExpiredError } from './customErrors';
async function getCsrfSession(cookies?: string) {
let {
@@ -29,7 +30,7 @@ type Credentials = {
secondFactorToken?: string | null;
};
type CsrfSession = { csrf: string; initialSessionCookie: string };
-type AuthRequest = Credentials & CsrfSession;
+type AuthRequest = Credentials & CsrfSession & { client: AxiosInstance };
function generateToken(cookies: string) {
const buffer = Buffer.from(cookies);
@@ -38,11 +39,12 @@ function generateToken(cookies: string) {
return token;
}
-function decodeToken(token?: string) {
+function decodeToken(token: string | null) {
if (!token) {
return '';
}
- const base64TokenRegex = /^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$/;
+ const base64TokenRegex =
+ /^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$/;
let isValidToken = base64TokenRegex.test(token);
if (!isValidToken) {
return '';
@@ -61,6 +63,7 @@ async function authenticate(authRequest: AuthRequest) {
login,
password,
secondFactorToken,
+ client,
} = authRequest;
let config = {
@@ -80,11 +83,7 @@ async function authenticate(authRequest: AuthRequest) {
}
let body = stringify({ login, password, ...secondFactorLogin });
- let { data, headers } = await discourseClient.post(
- '/session.json',
- body,
- config,
- );
+ let { data, headers } = await client.post('/session.json', body, config);
let { error, failed } = data;
if (failed) {
return {
@@ -116,19 +115,13 @@ async function getHpChallenge(csrfSession: CsrfSession) {
};
let data;
let headers;
- let {
- data: oldVersionData,
- headers: oldVersionHeaders,
- } = await discourseClient.get('/users/hp.json', config);
- let {
- errors: oldVersionErrors,
- error_type: oldVersionErrorType,
- } = oldVersionData;
+ let { data: oldVersionData, headers: oldVersionHeaders } =
+ await discourseClient.get('/users/hp.json', config);
+ let { errors: oldVersionErrors, error_type: oldVersionErrorType } =
+ oldVersionData;
if (oldVersionErrors && oldVersionErrorType === 'not_found') {
- let {
- data: newVersionData,
- headers: newVersionHeaders,
- } = await discourseClient.get('/session/hp.json', config);
+ let { data: newVersionData, headers: newVersionHeaders } =
+ await discourseClient.get('/session/hp.json', config);
data = newVersionData;
headers = newVersionHeaders;
} else {
@@ -151,7 +144,7 @@ async function getHpChallenge(csrfSession: CsrfSession) {
async function checkSession(authClient: AxiosInstance) {
let sessionCookie: string = authClient.defaults.headers.Cookie;
if (!sessionCookie) {
- throw new Error('Session not found.');
+ throw new SessionExpiredError();
}
try {
let { data, headers } = await authClient.get('/session/current.json');
@@ -173,7 +166,7 @@ async function checkSession(authClient: AxiosInstance) {
token,
};
} catch (e) {
- throw new Error('Session not found.');
+ throw new SessionExpiredError();
}
}
diff --git a/api/src/helpers/cookiesStringify.ts b/api/src/helpers/cookiesStringify.ts
index bbe36780..d6d8cc7f 100644
--- a/api/src/helpers/cookiesStringify.ts
+++ b/api/src/helpers/cookiesStringify.ts
@@ -1,12 +1,18 @@
+import setCookie from 'set-cookie-parser';
+
export function cookiesStringify(cookies: Array) {
let cookieString = '';
if (Array.isArray(cookies)) {
for (let cookie of cookies) {
- cookieString = cookieString + cookie + ';';
+ cookieString = cookieString + joinCookieString(cookie) + ';';
}
}
if (typeof cookies === 'string') {
- cookieString = cookies;
+ cookieString = joinCookieString(cookies);
}
return cookieString;
}
+
+function joinCookieString(cookie: string): string {
+ return setCookie.splitCookiesString(cookie).join(';');
+}
diff --git a/api/src/helpers/customErrors.ts b/api/src/helpers/customErrors.ts
new file mode 100644
index 00000000..58219f0c
--- /dev/null
+++ b/api/src/helpers/customErrors.ts
@@ -0,0 +1,15 @@
+export class AuthorizationError extends Error {
+ constructor() {
+ super('Authorization Failed');
+ }
+}
+export class SessionExpiredError extends Error {
+ constructor() {
+ super('Session Expired');
+ }
+}
+export class InvalidAccessError extends Error {
+ constructor() {
+ super('Invalid Access');
+ }
+}
diff --git a/api/src/helpers/errorHandler.ts b/api/src/helpers/errorHandler.ts
index 2a55e5f8..7ccf7016 100644
--- a/api/src/helpers/errorHandler.ts
+++ b/api/src/helpers/errorHandler.ts
@@ -1,21 +1,39 @@
import { AxiosError } from 'axios';
-import { ChangeUsernameError, EditPostError } from '../constants';
+import { ChangeUsernameError, EditPostError, errorTypes } from '../constants';
-export function errorHandler(e: AxiosError) {
+import {
+ AuthorizationError,
+ SessionExpiredError,
+ InvalidAccessError,
+} from './customErrors';
+
+export function errorHandler(unknownError: unknown) {
+ const e = unknownError as AxiosError;
let status = e.response?.status;
let errors = e.response?.data?.errors;
+ let errorType = e.response?.data?.error_type;
let failed = e.response?.data?.failed;
+ let cookie = e.response?.config.headers.Cookie;
if (errors) {
- if (errors === EditPostError) {
- throw new Error(
- 'This post can no longer be edited because it was created more than 30 days ago.',
- );
+ if (errors[0] === EditPostError) {
+ throw new Error("You've passed the time limit to edit this post.");
}
if (Array.isArray(errors) && errors[0] === ChangeUsernameError) {
throw new Error('This username is already taken');
}
+ const { invalidAccess, unauthenticatedAccess } = errorTypes;
+ if (errorType === invalidAccess) {
+ throw new InvalidAccessError();
+ }
+ if (errorType === unauthenticatedAccess) {
+ // If the token was provided and we encountered one of these errors, it means the token was invalid
+ if (cookie?.includes('_t=')) {
+ throw new SessionExpiredError();
+ }
+ throw new AuthorizationError();
+ }
throw new Error(errors);
}
if (failed) {
diff --git a/api/src/helpers/fetchLikeActivities.ts b/api/src/helpers/fetchLikeActivities.ts
new file mode 100644
index 00000000..c42233a0
--- /dev/null
+++ b/api/src/helpers/fetchLikeActivities.ts
@@ -0,0 +1,42 @@
+import camelcaseKeys from 'camelcase-keys';
+import { AxiosInstance } from 'axios';
+
+import { UserAction } from '../types';
+
+type Params = {
+ username: string;
+ client: AxiosInstance;
+};
+
+export const USER_ACTIONS_URL = '/user_actions.json';
+const LIKE_POST_FILTER = '1';
+const PAGE_SIZE = 30;
+
+export async function fetchLikeActivities(params: Params) {
+ const { username, client } = params;
+
+ let hasMore = true;
+ let userActions: Array = [];
+ let currentOffset = 0;
+
+ while (hasMore) {
+ const fetchConfig = {
+ params: {
+ username,
+ filter: LIKE_POST_FILTER,
+ offset: currentOffset,
+ },
+ };
+ const { data: userActivityResult } = await client.get(
+ USER_ACTIONS_URL,
+ fetchConfig,
+ );
+ const currentUserActions = userActivityResult.user_actions;
+ currentOffset += PAGE_SIZE;
+ userActions = [...userActions, ...currentUserActions];
+ if (currentUserActions.length < PAGE_SIZE) {
+ hasMore = false;
+ }
+ }
+ return camelcaseKeys(userActions, { deep: true });
+}
diff --git a/api/src/helpers/fetchPost.ts b/api/src/helpers/fetchPost.ts
new file mode 100644
index 00000000..f288e4a6
--- /dev/null
+++ b/api/src/helpers/fetchPost.ts
@@ -0,0 +1,21 @@
+import { AxiosInstance } from 'axios';
+import camelcaseKeys from 'camelcase-keys';
+
+import { ACCEPTED_LANGUAGE } from '../constants';
+
+type Params = {
+ client: AxiosInstance;
+ postId: number;
+};
+
+const config = {
+ headers: { 'Accept-Language': ACCEPTED_LANGUAGE },
+ params: { include_raw: true },
+};
+
+export async function fetchPost(params: Params) {
+ const { client, postId } = params;
+ let url = `/posts/${postId}.json`;
+ let { data } = await client.get(url, config);
+ return camelcaseKeys(data, { deep: true });
+}
diff --git a/api/src/helpers/getModifiedUserAgent.ts b/api/src/helpers/getModifiedUserAgent.ts
new file mode 100644
index 00000000..b108fafe
--- /dev/null
+++ b/api/src/helpers/getModifiedUserAgent.ts
@@ -0,0 +1,26 @@
+const mobileDevices = ['Android', 'Mobile', 'iPad', 'iPhone', 'iPod'];
+
+/**
+ * Returns a string for the `User Agent` header.
+ * Discourse uses the `User Agent` header to log recently used
+ * devices in the Discourse web app. The `User Agent` header
+ * contains information about the browser, the OS, and the device.
+ * We set the browser default fallback to `DiscourseHub`, because
+ * it isn't provided when a request is received from the mobile app.
+ * `DiscourseHub` is chosen because it is what Discourse's mobile app
+ * uses, and it is the closest `User Agent` string supported by Discourse.
+ *
+ * @param originalUserAgent - The original `User Agent` value from the request header
+ * @returns Modified `User Agent`
+ */
+
+export function getModifiedUserAgent(originalUserAgent?: string) {
+ if (!originalUserAgent) {
+ return '';
+ }
+
+ let isMobile = mobileDevices.some((device) =>
+ originalUserAgent?.includes(device),
+ );
+ return `${originalUserAgent} ${isMobile ? 'DiscourseHub' : ''}`;
+}
diff --git a/api/src/helpers/getPosterTypeDetails.ts b/api/src/helpers/getPosterTypeDetails.ts
new file mode 100644
index 00000000..fd5154b8
--- /dev/null
+++ b/api/src/helpers/getPosterTypeDetails.ts
@@ -0,0 +1,41 @@
+import { z } from 'zod';
+
+import { getPosterType, i18nSeparatorsRegex } from '../locale';
+import {
+ FrequentPoster,
+ MostRecentPoster,
+ OriginalPoster,
+ UnknownPosterType,
+} from '../types';
+
+export const PosterTypeDetails = z.object({
+ isAuthor: z.boolean(),
+ isFrequentPoster: z.boolean(),
+ isMostRecentPoster: z.boolean(),
+});
+export type PosterTypeDetails = z.infer;
+
+export function getPosterTypeDetails(description: string): PosterTypeDetails {
+ if (!description) {
+ return {
+ isAuthor: false,
+ isFrequentPoster: false,
+ isMostRecentPoster: false,
+ };
+ }
+
+ const items = description.split(i18nSeparatorsRegex);
+
+ const posterTypes = items.map((item) => {
+ const lowercased = item.toLowerCase().trim();
+ const knownMatch = getPosterType(lowercased);
+
+ return knownMatch ?? UnknownPosterType.value;
+ });
+
+ return {
+ isAuthor: posterTypes.includes(OriginalPoster.value),
+ isFrequentPoster: posterTypes.includes(FrequentPoster.value),
+ isMostRecentPoster: posterTypes.includes(MostRecentPoster.value),
+ };
+}
diff --git a/api/src/helpers/getTopicAuthor.ts b/api/src/helpers/getTopicAuthor.ts
new file mode 100644
index 00000000..54a275e5
--- /dev/null
+++ b/api/src/helpers/getTopicAuthor.ts
@@ -0,0 +1,20 @@
+import { TopicPoster } from '../types';
+
+import { getPosterTypeDetails } from './getPosterTypeDetails';
+
+export function getTopicAuthor(
+ posters: Readonly>,
+): TopicPoster | undefined {
+ return posters.find((poster) => {
+ const { isAuthor } = getPosterTypeDetails(poster.description);
+ return isAuthor;
+ });
+}
+
+export function getTopicAuthorUserId(
+ posters: Readonly>,
+): number | undefined {
+ const author = getTopicAuthor(posters);
+
+ return author?.userId ?? author?.user?.id;
+}
diff --git a/api/src/helpers/getTopicPostPath.ts b/api/src/helpers/getTopicPostPath.ts
deleted file mode 100644
index 49c5ecba..00000000
--- a/api/src/helpers/getTopicPostPath.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-export function getTopicPostPath(
- post?: Array | null,
- postPointer?: number | null,
-) {
- if (post) {
- return '/posts';
- }
- return postPointer ? `/${postPointer}` : '';
-}
diff --git a/api/src/helpers/getUpdatedLikedTopic.ts b/api/src/helpers/getUpdatedLikedTopic.ts
new file mode 100644
index 00000000..5e19c697
--- /dev/null
+++ b/api/src/helpers/getUpdatedLikedTopic.ts
@@ -0,0 +1,18 @@
+import { LikedTopic } from '../types';
+
+type Params = {
+ currentLikedTopicResponse: LikedTopic;
+ isLiked: boolean;
+};
+
+export function getUpdatedLikedTopic(params: Params) {
+ const { currentLikedTopicResponse, isLiked: liked } = params;
+
+ const { likeCount: prevLikeCount } = currentLikedTopicResponse;
+ const likeCount = liked ? prevLikeCount + 1 : prevLikeCount - 1;
+ return {
+ ...currentLikedTopicResponse,
+ likeCount,
+ liked,
+ };
+}
diff --git a/api/src/helpers/index.ts b/api/src/helpers/index.ts
index 489732e0..66448a4a 100644
--- a/api/src/helpers/index.ts
+++ b/api/src/helpers/index.ts
@@ -1,8 +1,13 @@
export * from './auth';
export * from './cookiesStringify';
+export * from './customErrors';
export * from './errorHandler';
-export * from './getTopicPostPath';
+export * from './fetchLikeActivities';
+export * from './fetchPost';
+export * from './getModifiedUserAgent';
export * from './getTopicTimings';
+export * from './getUpdatedLikedTopic';
export * from './parseTopicUrl';
export * from './privateMessagesMerger';
export * from './processRawContent';
+export * from './topicDetail';
diff --git a/api/src/helpers/likeErroHandler.ts b/api/src/helpers/likeErroHandler.ts
new file mode 100644
index 00000000..19bbbe96
--- /dev/null
+++ b/api/src/helpers/likeErroHandler.ts
@@ -0,0 +1,53 @@
+import { AxiosError } from 'axios';
+
+import { LIKE_ACTION_ID } from '../constants';
+import { ActionsSummary } from '../types';
+
+export type LikableEntity = 'post' | 'topic';
+type Params = {
+ actionsSummary: ActionsSummary | null;
+ likableEntity: LikableEntity;
+ like: boolean;
+};
+
+/**
+ * Custom Like Error Handler-
+ * Discourse provides unhelpful error message for this matter.
+ * This function checks the actions summary of the post
+ * to find the reason why the like action failed.
+ */
+export function likeErrorHandler(e: AxiosError, params: Params) {
+ let { actionsSummary, likableEntity, like } = params;
+
+ const likeActionSummary = actionsSummary?.find(
+ (actionSummary: { id: number }) => actionSummary.id === LIKE_ACTION_ID,
+ );
+
+ // Like action summary is not provided for the post author
+ if (!likeActionSummary) {
+ throw new Error(
+ `You're not permitted to do like actions to your own ${likableEntity}.`,
+ );
+ }
+
+ const { acted: prevLiked = false, canUndo: canUnlike = false } =
+ likeActionSummary;
+
+ // Proposed action and current like state is the same
+ if (like === prevLiked) {
+ throw new Error(
+ like
+ ? `You've liked this ${likableEntity} before.`
+ : `You can't unlike a ${likableEntity} you haven't liked before.`,
+ );
+ }
+ // Already passed the time limit to unlike
+ if (!like && !canUnlike) {
+ throw new Error(
+ `You've passed the time limit to unlike this ${likableEntity}.`,
+ );
+ }
+
+ // Throw handled error from Discourse, such as too many actions error
+ throw e;
+}
diff --git a/api/src/helpers/processRawContent.ts b/api/src/helpers/processRawContent.ts
index b1c58e22..7656dae1 100644
--- a/api/src/helpers/processRawContent.ts
+++ b/api/src/helpers/processRawContent.ts
@@ -1,10 +1,20 @@
+import '@total-typescript/ts-reset';
+
import { PROSE_DISCOURSE_UPLOAD_HOST } from '../constants';
-const imageRegex = //g;
-const anchoredImageRegex = //g;
+const imageRegex = //g;
const srcSetRegex = /srcset="(.+?)"/g;
const imageUrlRegex = /(https?:\/\/[^ ]*\.(?:jpe?g|png|gif|heic|heif))/g;
const mentionRegex = /@(.*?)<\/a>/g;
+const imageMarkdownRegex = /(!\[.*?\]\()(upload:\/\/\S*)(\))/g;
+const imageVideoTagRegex =
+ /(?: ]*src(?:set)?=")(.+?)"|(?: ]* href="(https?:\/\/[^ ]*\.(?:jpe?g|png|gif|heic|heif|mov|mp4|webm|avi|wmv|flv|webp))")([^$]+?)<\/a>/g;
+
+const emojiBBCodeRegex = /(?<=^|\s):\w+:(?:t\d+:)?/g;
+const emojiImageTagRegex = //g;
+const emojiTitleRegex = /title="([^"]+)"/g;
function handleRegexResult(
result: RegExpMatchArray,
@@ -26,7 +36,7 @@ function handleRegexResult(
});
return optimizedUrl.map((item) => item.replace(transparantRegex, ''));
} else if (
- regex === anchoredImageRegex ||
+ regex === anchoredImageVideoRegex ||
regex === imageRegex ||
regex === mentionRegex
) {
@@ -35,26 +45,118 @@ function handleRegexResult(
}
}
+export function getCompleteImageVideoUrls(
+ content: string,
+ host: string = PROSE_DISCOURSE_UPLOAD_HOST,
+): Array | undefined {
+ // Get all image tags in content
+ let imageVideoTags = content.match(imageVideoTagRegex);
+ // Get complete url from each image tag
+ return imageVideoTags?.map((imageVideoTag) =>
+ getPostImageUrl(imageVideoTag, host),
+ );
+}
+
export function getPostImageUrl(
content: string,
host: string = PROSE_DISCOURSE_UPLOAD_HOST,
-): Array | undefined {
+): string | undefined {
+ // Return only the first element of array because only one url is found
let result = content.match(srcSetRegex) ?? undefined;
+
if (result) {
- return handleRegexResult(result, host, srcSetRegex);
+ return handleRegexResult(result, host, srcSetRegex)?.[0];
}
- result = content.match(anchoredImageRegex) ?? undefined;
+ result = content.match(anchoredImageVideoRegex) ?? undefined;
if (result) {
- return handleRegexResult(result, host, anchoredImageRegex);
+ return handleRegexResult(result, host, anchoredImageVideoRegex)?.[0];
}
result = content.match(imageRegex) ?? undefined;
+
if (result) {
- return handleRegexResult(result, host, imageRegex);
+ return handleRegexResult(result, host, imageRegex)?.[0];
}
}
+type EmojiResult = { emojiUrl: string; emojiTitle: string };
+
+/**
+ * Converts list of emoji image tags into an array of objects containing the URL and name of each emoji image.
+ * Example:
+ * Input: " "
+ * Output: [{emojiUrl: "https://kflounge-staging.kfox.io/images/emoji/twitter/smile.png",emojiTitle: ":smile:"}]
+ *
+ * @param {string} content - The input string containing img tags for emoji images.
+ * @returns {Array<{emojiUrl: string, emojiTitle: string}>} - An array of objects, each with properties for the URL and name of an emoji.
+ */
+
+export function getEmojiImageUrls(content: string): Array {
+ let emojiTags = content.match(emojiImageTagRegex);
+
+ let maybeEmojiResults =
+ emojiTags?.map((item) => {
+ const emojiUrl = item.match(imageUrlRegex)?.[0];
+ const emojiTitle = item.match(emojiTitleRegex)?.[0];
+ if (!emojiUrl || !emojiTitle) {
+ return undefined;
+ }
+ let valueEmojiTitle = emojiTitle.split('=')[1];
+ const replaceValueEmojiTitle = valueEmojiTitle
+ ? valueEmojiTitle.replace(/"/g, '')
+ : undefined;
+ return {
+ emojiUrl,
+ emojiTitle: replaceValueEmojiTitle || '',
+ };
+ }) ?? [];
+
+ let emojiResults = maybeEmojiResults?.filter(Boolean);
+
+ return emojiResults;
+}
+
+export function generateMarkdownContent(raw: string, cooked: string) {
+ const imageUrls = getCompleteImageVideoUrls(cooked) ?? [];
+
+ const emojiBBcode = raw.match(emojiBBCodeRegex);
+
+ if (emojiBBcode?.length) {
+ const emojiUrls = getEmojiImageUrls(cooked);
+ raw = raw.replace(emojiBBCodeRegex, (name: string) => {
+ let url = emojiUrls.find((value) => value.emojiTitle.includes(name));
+
+ return url?.emojiUrl ? `![emoji-${name}](${url.emojiUrl})` : name;
+ });
+ }
+
+ const validImageUrls = imageUrls.filter((item) => item);
+ if (!validImageUrls.length) {
+ return raw;
+ }
+
+ let imageCount = 0;
+ const markdown = raw.replace(
+ imageMarkdownRegex,
+ (
+ _: string,
+ imageName: string,
+ shortUrl: string,
+ closeParenthesis: string,
+ ) => {
+ const modifiedImageMarkdown = `${imageName}${
+ validImageUrls?.[imageCount] ?? shortUrl
+ }${closeParenthesis}`;
+ imageCount += 1;
+
+ return modifiedImageMarkdown;
+ },
+ );
+
+ return markdown;
+}
+
export function getMention(
content: string,
host: string = PROSE_DISCOURSE_UPLOAD_HOST,
diff --git a/api/src/helpers/topicDetail.ts b/api/src/helpers/topicDetail.ts
new file mode 100644
index 00000000..f20e8433
--- /dev/null
+++ b/api/src/helpers/topicDetail.ts
@@ -0,0 +1,71 @@
+import { AxiosInstance } from 'axios';
+import camelcaseKeys from 'camelcase-keys';
+import { intArg, list, nullable } from 'nexus';
+
+import { ACCEPTED_LANGUAGE } from '../constants';
+
+type FetchTopicDetailParams = {
+ client: AxiosInstance;
+ postIds?: Array | null;
+ postNumber?: number | null;
+ topicId: number;
+};
+
+type TopicDetailOptionalArgs = {
+ postIds?: Array | null;
+ postNumber?: number | null;
+ includeFirstPost?: boolean | null;
+};
+
+export function getTopicPostPath(postIdsOrPostNumber?: number | Array) {
+ if (!postIdsOrPostNumber) {
+ return '';
+ }
+
+ if (Array.isArray(postIdsOrPostNumber)) {
+ return '/posts';
+ }
+
+ const postNumber = postIdsOrPostNumber;
+ return `/${postNumber}`;
+}
+
+export async function fetchTopicDetail(params: FetchTopicDetailParams) {
+ const { client, postIds, postNumber, topicId } = params;
+
+ const config = {
+ headers: { 'Accept-Language': ACCEPTED_LANGUAGE },
+ params: { post_ids: postIds, include_raw: true, track_visit: true },
+ };
+
+ let postPath = getTopicPostPath(postIds ?? postNumber ?? undefined);
+ let url = `/t/${topicId}${postPath}.json`;
+ let { data } = await client.get(url, config);
+
+ return camelcaseKeys(data, { deep: true });
+}
+
+export function getTopicDetailBaseArgs() {
+ return {
+ postIds: nullable(list(intArg())),
+ topicId: intArg(),
+ postNumber: nullable(intArg()),
+ };
+}
+
+export function validateTopicDetailOptionalArgs(
+ params: TopicDetailOptionalArgs,
+) {
+ const { postIds, postNumber, includeFirstPost } = params;
+ if (postIds && postNumber) {
+ throw new Error(
+ 'Please provide either only the post IDs or the post number',
+ );
+ }
+
+ if (postIds && includeFirstPost) {
+ throw new Error(
+ 'The first post cannot be included when post IDs are provided',
+ );
+ }
+}
diff --git a/api/src/locale/index.ts b/api/src/locale/index.ts
new file mode 100644
index 00000000..cb72a3e7
--- /dev/null
+++ b/api/src/locale/index.ts
@@ -0,0 +1,48 @@
+import {
+ FrequentPoster,
+ MostRecentPoster,
+ OriginalPoster,
+ PosterType,
+} from '../types';
+
+// source: github.com:discourse/discourse -> config/locales/server.en.yml
+// source: github.com:discourse/discourse -> config/locales/server.zh_CN.yml
+// key: `poster_description_joiner`
+export const i18nSeparatorsRegex = /,|ใ/;
+
+const i18nPosterTypes = {
+ // source: github.com:discourse/discourse -> config/locales/server.en.yml
+ en: {
+ 'original poster': OriginalPoster.value,
+ 'most recent poster': MostRecentPoster.value,
+ 'frequent poster': FrequentPoster.value,
+ },
+ // source: github.com:discourse/discourse -> config/locales/server.zh_CN.yml
+ zh: {
+ ๅๅงๅๅธไบบ: OriginalPoster.value,
+ ๆๆฐๅๅธไบบ: MostRecentPoster.value,
+ ้ข็นๅๅธไบบ: FrequentPoster.value,
+ },
+ zh_cn: {
+ ๅๅงๅๅธไบบ: OriginalPoster.value,
+ ๆๆฐๅๅธไบบ: MostRecentPoster.value,
+ ้ข็นๅๅธไบบ: FrequentPoster.value,
+ },
+ // source: github.com:discourse/discourse -> config/locales/server.zh_TW.yml
+ zh_tw: {
+ ๅๅงไฝ่
: OriginalPoster.value,
+ ็ถๅๅคง้จๅ่ฒผๆไฝ่
: MostRecentPoster.value,
+ ้ ป็น็ผๆ่
: FrequentPoster.value,
+ },
+};
+
+const posterTypeMap: Record = {
+ ...i18nPosterTypes.en,
+ ...i18nPosterTypes.zh,
+ ...i18nPosterTypes.zh_cn,
+ ...i18nPosterTypes.zh_tw,
+};
+
+export const getPosterType = (type: string): PosterType | undefined => {
+ return posterTypeMap[type];
+};
diff --git a/api/src/logger.ts b/api/src/logger.ts
new file mode 100644
index 00000000..04317b7e
--- /dev/null
+++ b/api/src/logger.ts
@@ -0,0 +1,39 @@
+import { createLogger, format, transports } from 'winston';
+import DailyRotateFile from 'winston-daily-rotate-file';
+
+//
+// This transport will rotate files on a daily basis
+// and store each file for a maximum of 14 days.
+//
+// The date pattern is the indicator of the frequency.
+// YYYY-MM-DD means it will rotate every day.
+// YYYY-MM-DD-HH meand is will rotate every hour and so on.
+//
+const rotateFileTransport: DailyRotateFile = new DailyRotateFile({
+ filename: 'logs/errors-%DATE%.log',
+ datePattern: 'YYYY-MM-DD',
+ zippedArchive: true,
+ maxFiles: '14d',
+ level: 'error',
+});
+
+export const logger = createLogger({
+ level: 'info',
+ format: format.combine(format.splat(), format.simple()),
+ transports: [
+ new transports.File({ filename: 'logs/combined.log' }),
+ rotateFileTransport,
+ ],
+});
+
+//
+// If we're not in production then log to the `console` with the format:
+// `${info.level}: ${info.message} JSON.stringify({ ...rest }) `
+//
+if (process.env.NODE_ENV !== 'production') {
+ logger.add(
+ new transports.Console({
+ format: format.simple(),
+ }),
+ );
+}
diff --git a/api/src/middlewares/permission.ts b/api/src/middlewares/permission.ts
deleted file mode 100644
index 1d3a8d70..00000000
--- a/api/src/middlewares/permission.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import { rule, shield } from 'graphql-shield';
-
-import { Context } from '../types';
-
-let isAuthenticated = rule()(async (_, __, ctx: Context) => {
- return ctx.isAuth;
-});
-
-let permissions = shield(
- {
- Query: {
- notification: isAuthenticated,
- privateMessage: isAuthenticated,
- badge: isAuthenticated,
- },
- Mutation: {
- timings: isAuthenticated,
- newPrivateMessage: isAuthenticated,
- newTopic: isAuthenticated,
- reply: isAuthenticated,
- editPost: isAuthenticated,
- editTopic: isAuthenticated,
- addEmail: isAuthenticated,
- changeEmail: isAuthenticated,
- deleteEmail: isAuthenticated,
- setPrimaryEmail: isAuthenticated,
- bookmarkPost: isAuthenticated,
- changeUsername: isAuthenticated,
- flagPost: isAuthenticated,
- likePost: isAuthenticated,
- upload: isAuthenticated,
- editProfile: isAuthenticated,
- saveProfilePicture: isAuthenticated,
- },
- },
- {
- fallbackError: 'You need to be logged in to do that.',
- },
-);
-
-export { permissions };
diff --git a/api/src/resolvers/auth/changePasswordMutation.ts b/api/src/resolvers/auth/changePasswordMutation.ts
index fdfca382..f659a843 100644
--- a/api/src/resolvers/auth/changePasswordMutation.ts
+++ b/api/src/resolvers/auth/changePasswordMutation.ts
@@ -1,4 +1,4 @@
-import { FieldResolver, mutationField, stringArg } from '@nexus/schema';
+import { FieldResolver, mutationField, stringArg } from 'nexus';
import { CONTENT_JSON } from '../../constants';
import { errorHandler, getCsrfSession } from '../../helpers';
@@ -39,7 +39,7 @@ export let changePasswordResolver: FieldResolver<
export let changePasswordMutation = mutationField('changePassword', {
type: 'String',
args: {
- login: stringArg({ required: true }),
+ login: stringArg(),
},
resolve: changePasswordResolver,
});
diff --git a/api/src/resolvers/auth/loginMutation.ts b/api/src/resolvers/auth/loginMutation.ts
index 19dcda50..84f6687d 100644
--- a/api/src/resolvers/auth/loginMutation.ts
+++ b/api/src/resolvers/auth/loginMutation.ts
@@ -1,11 +1,12 @@
-import { FieldResolver, mutationField, stringArg } from '@nexus/schema';
+import { FieldResolver, mutationField, nullable, stringArg } from 'nexus';
import { authenticate, getCsrfSession } from '../../helpers';
+import { Context } from '../../types';
export let loginMutationResolver: FieldResolver<'Mutation', 'login'> = async (
_,
{ email, password, secondFactorToken },
- __,
+ { client }: Context,
) => {
try {
let csrfSession = await getCsrfSession();
@@ -14,8 +15,10 @@ export let loginMutationResolver: FieldResolver<'Mutation', 'login'> = async (
login: email,
password,
secondFactorToken,
+ client,
});
- } catch (error) {
+ } catch (unknownError) {
+ const error = unknownError as Error;
throw new Error(`LoginError: ${error.message}`);
}
};
@@ -23,9 +26,11 @@ export let loginMutationResolver: FieldResolver<'Mutation', 'login'> = async (
export let loginMutation = mutationField('login', {
type: 'LoginOutputUnion',
args: {
- email: stringArg({ required: true }),
- password: stringArg({ required: true }),
- secondFactorToken: stringArg(),
+ email: stringArg(),
+ password: stringArg(),
+
+ // 2FA must be enabled individually by each user, so it must be nullable.
+ secondFactorToken: nullable(stringArg()),
},
resolve: loginMutationResolver,
});
diff --git a/api/src/resolvers/auth/logoutMutation.ts b/api/src/resolvers/auth/logoutMutation.ts
index e54ed01c..e7e26747 100644
--- a/api/src/resolvers/auth/logoutMutation.ts
+++ b/api/src/resolvers/auth/logoutMutation.ts
@@ -1,12 +1,51 @@
-import { FieldResolver, mutationField, stringArg } from '@nexus/schema';
+import { FieldResolver, mutationField, stringArg, nullable } from 'nexus';
import { Context } from '../../types';
+import { ACCEPTED_LANGUAGE, CONTENT_JSON } from '../../constants';
+import { logger } from '../../logger';
export let logoutMutationResolver: FieldResolver<'Mutation', 'logout'> = async (
_,
- { username },
+ { username, pushNotificationsToken },
context: Context,
) => {
+ if (pushNotificationsToken) {
+ try {
+ const config = {
+ headers: {
+ 'Accept-Language': ACCEPTED_LANGUAGE,
+ 'Content-Type': CONTENT_JSON,
+ },
+ };
+ await context.client.post(
+ `/lexicon/push_notifications/delete_subscribe.json`,
+ {
+ push_notifications_token: pushNotificationsToken,
+ },
+ config,
+ );
+ } catch (error) {
+ /**
+ * No action is taken when an error occurs
+ * No action is required because we want the session to be successfully deleted even if there are errors when hitting the API to delete the token in the plugin.
+ * For example, if we haven't installed the plugin, it will result in a 404 error when attempting to hit the delete_subscribe API.
+ * Similarly, if there is an internal issue with the plugin, it may lead to a 500 error.
+ */
+
+ if (error instanceof Error) {
+ logger.log(
+ 'Error',
+ `Error when hit delete token plugin API ====> ${error.message}`,
+ );
+ } else {
+ logger.log(
+ 'Error',
+ `Unknown error when hit delete token plugin API ====> ${error}`,
+ );
+ }
+ }
+ }
+
try {
await context.client.delete(`/session/${username}.json`);
return 'success';
@@ -18,7 +57,8 @@ export let logoutMutationResolver: FieldResolver<'Mutation', 'logout'> = async (
export let logoutMutation = mutationField('logout', {
type: 'String',
args: {
- username: stringArg({ required: true }),
+ username: stringArg(),
+ pushNotificationsToken: nullable(stringArg()),
},
resolve: logoutMutationResolver,
});
diff --git a/api/src/resolvers/auth/refreshTokenQuery.ts b/api/src/resolvers/auth/refreshTokenQuery.ts
index 0327bcbb..db872f88 100644
--- a/api/src/resolvers/auth/refreshTokenQuery.ts
+++ b/api/src/resolvers/auth/refreshTokenQuery.ts
@@ -1,4 +1,4 @@
-import { FieldResolver, queryField } from '@nexus/schema';
+import { FieldResolver, queryField } from 'nexus';
import { checkSession } from '../../helpers';
import { Context } from '../../types';
@@ -12,7 +12,8 @@ export let refreshTokenQueryResolver: FieldResolver<
throw new Error('Not authorized');
}
return checkSession(context.client);
- } catch (error) {
+ } catch (unknownError) {
+ const error = unknownError as Error;
throw new Error(`Session not found: ${error.message}`);
}
};
diff --git a/api/src/resolvers/auth/registerMutation.ts b/api/src/resolvers/auth/registerMutation.ts
index db6d82dc..fc1c823e 100644
--- a/api/src/resolvers/auth/registerMutation.ts
+++ b/api/src/resolvers/auth/registerMutation.ts
@@ -2,7 +2,7 @@ import { stringify } from 'querystring';
import camelcaseKeys from 'camelcase-keys';
import snakecaseKeys from 'snakecase-keys';
-import { FieldResolver, mutationField, arg } from '@nexus/schema';
+import { FieldResolver, mutationField, arg, nullable } from 'nexus';
import { discourseClient } from '../../client';
import { CONTENT_FORM_URLENCODED } from '../../constants';
@@ -42,7 +42,7 @@ export let registerMutationResolver: FieldResolver<
export let registerMutation = mutationField('register', {
type: 'RegisterOutput',
args: {
- registerInput: arg({ type: 'RegisterInput' }),
+ registerInput: nullable(arg({ type: 'RegisterInput' })),
},
resolve: registerMutationResolver,
});
diff --git a/api/src/resolvers/email/addEmailMutation.ts b/api/src/resolvers/email/addEmailMutation.ts
index 4b167510..3b1120f3 100644
--- a/api/src/resolvers/email/addEmailMutation.ts
+++ b/api/src/resolvers/email/addEmailMutation.ts
@@ -1,6 +1,6 @@
import { stringify } from 'querystring';
-import { FieldResolver, mutationField, stringArg } from '@nexus/schema';
+import { FieldResolver, mutationField, stringArg } from 'nexus';
import { CONTENT_FORM_URLENCODED } from '../../constants';
import { errorHandler } from '../../helpers';
@@ -34,8 +34,8 @@ export let addEmailMutation: FieldResolver<'Mutation', 'addEmail'> = async (
export let addEmail = mutationField('addEmail', {
type: 'String',
args: {
- email: stringArg({ required: true }),
- username: stringArg({ required: true }),
+ email: stringArg(),
+ username: stringArg(),
},
resolve: addEmailMutation,
});
diff --git a/api/src/resolvers/email/changeEmailMutation.ts b/api/src/resolvers/email/changeEmailMutation.ts
index 23510c2f..8e15c404 100644
--- a/api/src/resolvers/email/changeEmailMutation.ts
+++ b/api/src/resolvers/email/changeEmailMutation.ts
@@ -1,4 +1,4 @@
-import { FieldResolver, mutationField, stringArg } from '@nexus/schema';
+import { FieldResolver, mutationField, stringArg } from 'nexus';
import { CONTENT_JSON } from '../../constants';
import { errorHandler } from '../../helpers';
@@ -25,8 +25,8 @@ export let changeEmailResolver: FieldResolver<
export let changeEmailMutation = mutationField('changeEmail', {
type: 'String',
args: {
- newEmail: stringArg({ required: true }),
- username: stringArg({ required: true }),
+ newEmail: stringArg(),
+ username: stringArg(),
},
resolve: changeEmailResolver,
});
diff --git a/api/src/resolvers/email/deleteEmailMutation.ts b/api/src/resolvers/email/deleteEmailMutation.ts
index b89ab7ce..1d592ff5 100644
--- a/api/src/resolvers/email/deleteEmailMutation.ts
+++ b/api/src/resolvers/email/deleteEmailMutation.ts
@@ -1,4 +1,4 @@
-import { FieldResolver, mutationField, stringArg } from '@nexus/schema';
+import { FieldResolver, mutationField, stringArg } from 'nexus';
import { CONTENT_JSON } from '../../constants';
import { errorHandler } from '../../helpers';
@@ -32,8 +32,8 @@ export let deleteEmailResolver: FieldResolver<
export let deleteEmailMutation = mutationField('deleteEmail', {
type: 'String',
args: {
- selectedEmail: stringArg({ required: true }),
- username: stringArg({ required: true }),
+ selectedEmail: stringArg(),
+ username: stringArg(),
},
resolve: deleteEmailResolver,
});
diff --git a/api/src/resolvers/email/setPrimaryEmailMutation.ts b/api/src/resolvers/email/setPrimaryEmailMutation.ts
index d5bc429f..681603b2 100644
--- a/api/src/resolvers/email/setPrimaryEmailMutation.ts
+++ b/api/src/resolvers/email/setPrimaryEmailMutation.ts
@@ -1,4 +1,4 @@
-import { FieldResolver, mutationField, stringArg } from '@nexus/schema';
+import { FieldResolver, mutationField, stringArg } from 'nexus';
import { CONTENT_JSON } from '../../constants';
import { errorHandler } from '../../helpers';
@@ -33,8 +33,8 @@ export let setPrimaryEmailResolver: FieldResolver<
export let setPrimaryEmailMutation = mutationField('setPrimaryEmail', {
type: 'String',
args: {
- selectedEmail: stringArg({ required: true }),
- username: stringArg({ required: true }),
+ selectedEmail: stringArg(),
+ username: stringArg(),
},
resolve: setPrimaryEmailResolver,
});
diff --git a/api/src/resolvers/health/healthQuery.ts b/api/src/resolvers/health/healthQuery.ts
new file mode 100644
index 00000000..2f88475c
--- /dev/null
+++ b/api/src/resolvers/health/healthQuery.ts
@@ -0,0 +1,40 @@
+import { FieldResolver, queryField } from 'nexus';
+import { AxiosError } from 'axios';
+
+import { Context } from '../../types';
+import { PROSE_DISCOURSE_HOST } from '../../constants';
+import { logger } from '../../logger';
+
+let healthQueryResolver: FieldResolver<'Query', 'health'> = async (
+ _,
+ __,
+ context: Context,
+) => {
+ let discourseError: Error | undefined;
+ let isDiscourseReachable = true;
+ try {
+ await context.client.get('/site.json');
+ } catch (error) {
+ let e = error as AxiosError;
+ discourseError = e;
+ if (e.response === undefined) {
+ isDiscourseReachable = false;
+ }
+ logger.log(
+ 'error',
+ discourseError?.toString() ?? 'An unknown Discourse error occurred',
+ );
+ }
+ return {
+ isDiscourseReachable,
+ discourseError: discourseError?.toString(),
+ discourseHost: PROSE_DISCOURSE_HOST,
+ };
+};
+
+let healthQuery = queryField('health', {
+ type: 'HealthCheck',
+ resolve: healthQueryResolver,
+});
+
+export { healthQuery };
diff --git a/api/src/resolvers/index.ts b/api/src/resolvers/index.ts
index 684e2294..4acdf36a 100644
--- a/api/src/resolvers/index.ts
+++ b/api/src/resolvers/index.ts
@@ -22,11 +22,12 @@ export * from './topics/editPostMutation';
export * from './topics/editTopicMutation';
export * from './topics/flagPostMutation';
export * from './topics/leaveMessageMutation';
-export * from './topics/likePostMutation';
+export * from './topics/likeTopicOrPostMutation';
export * from './topics/newPrivateMessageMutation';
export * from './topics/newTopicMutation';
export * from './topics/postQuery';
export * from './topics/postRawQuery';
+export * from './topics/privateMessageDetailQuery';
export * from './topics/privateMessageQuery';
export * from './topics/repliesQuery';
export * from './topics/replyingToQuery';
@@ -48,3 +49,5 @@ export * from './user/searchUserQuery';
export * from './user/singleBadgeQuery';
export * from './user/userActivityQuery';
export * from './user/userProfileQuery';
+
+export * from './health/healthQuery';
diff --git a/api/src/resolvers/notifications/markReadMutation.ts b/api/src/resolvers/notifications/markReadMutation.ts
index 93528f13..f1b5e687 100644
--- a/api/src/resolvers/notifications/markReadMutation.ts
+++ b/api/src/resolvers/notifications/markReadMutation.ts
@@ -1,4 +1,4 @@
-import { FieldResolver, mutationField, intArg } from '@nexus/schema';
+import { FieldResolver, mutationField, intArg, nullable } from 'nexus';
import { ACCEPTED_LANGUAGE, CONTENT_JSON } from '../../constants';
import { errorHandler } from '../../helpers';
@@ -30,7 +30,7 @@ export let markReadMutation: FieldResolver<'Mutation', 'markRead'> = async (
export let markRead = mutationField('markRead', {
type: 'String',
args: {
- notificationId: intArg(),
+ notificationId: nullable(intArg()),
},
resolve: markReadMutation,
});
diff --git a/api/src/resolvers/notifications/notificationQuery.ts b/api/src/resolvers/notifications/notificationQuery.ts
index 54382236..3caaf2f0 100644
--- a/api/src/resolvers/notifications/notificationQuery.ts
+++ b/api/src/resolvers/notifications/notificationQuery.ts
@@ -1,5 +1,5 @@
import camelcaseKeys from 'camelcase-keys';
-import { FieldResolver, queryField, intArg } from '@nexus/schema';
+import { FieldResolver, queryField, intArg } from 'nexus';
import { errorHandler } from '../../helpers';
import { Context } from '../../types';
@@ -32,7 +32,7 @@ let notificationQueryResolver: FieldResolver<'Query', 'notification'> = async (
let notificationQuery = queryField('notification', {
type: 'Notifications',
args: {
- page: intArg({ required: true }),
+ page: intArg(),
},
resolve: notificationQueryResolver,
});
diff --git a/api/src/resolvers/notifications/pushNotificationMutation.ts b/api/src/resolvers/notifications/pushNotificationMutation.ts
index 6b3353d6..9ce4b446 100644
--- a/api/src/resolvers/notifications/pushNotificationMutation.ts
+++ b/api/src/resolvers/notifications/pushNotificationMutation.ts
@@ -1,14 +1,18 @@
-/* eslint-disable @typescript-eslint/camelcase */
-import { FieldResolver, mutationField, stringArg } from '@nexus/schema';
+import axios from 'axios';
+import { FieldResolver, mutationField, stringArg } from 'nexus';
import { ACCEPTED_LANGUAGE, CONTENT_JSON } from '../../constants';
import { errorHandler } from '../../helpers';
import { Context } from '../../types';
-export let pushNotificationMutation: FieldResolver<
+export let pushNotificationsMutation: FieldResolver<
'Mutation',
- 'pushNotification'
-> = async (_, { expoPnToken, applicationName, platform }, context: Context) => {
+ 'pushNotifications'
+> = async (
+ _,
+ { PushNotificationsToken, applicationName, platform, experienceId },
+ context: Context,
+) => {
const config = {
headers: {
'Accept-Language': ACCEPTED_LANGUAGE,
@@ -17,26 +21,32 @@ export let pushNotificationMutation: FieldResolver<
};
try {
await context.client.post(
- `/expo_pn/subscribe.json`,
+ `/lexicon/push_notifications/subscribe.json`,
{
- expo_pn_token: expoPnToken,
+ push_notifications_token: PushNotificationsToken,
application_name: applicationName,
platform: platform,
+ experience_id: experienceId,
},
config,
);
return 'success';
} catch (e) {
+ if (axios.isAxiosError(e) && e.response?.status === 404) {
+ // mean discourse instance doesn't have lexicon plugin
+ return 'lexicon plugin not installed';
+ }
throw errorHandler(e);
}
};
-export let pushNotification = mutationField('pushNotification', {
+export let pushNotification = mutationField('pushNotifications', {
type: 'String',
args: {
- expoPnToken: stringArg(),
+ PushNotificationsToken: stringArg(),
+ experienceId: stringArg(),
applicationName: stringArg(),
platform: stringArg(),
},
- resolve: pushNotificationMutation,
+ resolve: pushNotificationsMutation,
});
diff --git a/api/src/resolvers/site/aboutQuery.ts b/api/src/resolvers/site/aboutQuery.ts
index 3ae9fb7a..aa76e836 100644
--- a/api/src/resolvers/site/aboutQuery.ts
+++ b/api/src/resolvers/site/aboutQuery.ts
@@ -1,4 +1,4 @@
-import { FieldResolver, queryField } from '@nexus/schema';
+import { FieldResolver, queryField } from 'nexus';
import { errorHandler } from '../../helpers';
import { Context } from '../../types';
diff --git a/api/src/resolvers/site/siteQuery.ts b/api/src/resolvers/site/siteQuery.ts
index d766292d..9dd8d742 100644
--- a/api/src/resolvers/site/siteQuery.ts
+++ b/api/src/resolvers/site/siteQuery.ts
@@ -1,8 +1,9 @@
import camelcaseKey from 'camelcase-keys';
-import { FieldResolver, queryField } from '@nexus/schema';
+import { FieldResolver, queryField } from 'nexus';
import { errorHandler } from '../../helpers';
import { Context } from '../../types';
+import { UNCATEGORIZED_CATEGORY_ID } from '../../constants';
let siteResolver: FieldResolver<'Query', 'site'> = async (
_,
@@ -17,6 +18,8 @@ let siteResolver: FieldResolver<'Query', 'site'> = async (
can_tag_topics: canTagTopics,
topic_flag_types: topicFlagTypes,
post_action_types: postActionTypes,
+ uncategorized_category_id:
+ uncategorizedCategoryId = UNCATEGORIZED_CATEGORY_ID,
...siteData
},
} = await context.client.get(siteUrl);
@@ -50,6 +53,8 @@ let siteResolver: FieldResolver<'Query', 'site'> = async (
min_username_length: minUsernameLength = 0,
min_password_length: minPasswordLength = 0,
full_name_required: fullNameRequired = false,
+ default_composer_category: defaultComposerCategory = '',
+ allow_uncategorized_topics: allowUncategorizedTopics = false,
},
} = await context.client.get(siteSettingsUrl);
@@ -68,6 +73,9 @@ let siteResolver: FieldResolver<'Query', 'site'> = async (
fullNameRequired,
topicFlagTypes,
postActionTypes,
+ defaultComposerCategory,
+ allowUncategorizedTopics,
+ uncategorizedCategoryId,
...camelcaseKey(siteData, { deep: true }),
};
} catch (error) {
diff --git a/api/src/resolvers/topics/bookmarkPostMutation.ts b/api/src/resolvers/topics/bookmarkPostMutation.ts
index 59d0e7cd..46f73e4b 100644
--- a/api/src/resolvers/topics/bookmarkPostMutation.ts
+++ b/api/src/resolvers/topics/bookmarkPostMutation.ts
@@ -7,7 +7,8 @@ import {
arg,
intArg,
stringArg,
-} from '@nexus/schema';
+ nullable,
+} from 'nexus';
import { ACCEPTED_LANGUAGE, CONTENT_FORM_URLENCODED } from '../../constants';
import { errorHandler } from '../../helpers';
@@ -39,10 +40,10 @@ export let bookmarkPostResolver: FieldResolver<
export let bookmarkPostMutation = mutationField('bookmarkPost', {
type: 'BookmarkOutput',
args: {
- postId: intArg({ required: true }),
- reminderType: arg({ type: 'BookmarkReminderEnum' }),
- reminderAt: stringArg(),
- name: stringArg(),
+ postId: intArg(),
+ reminderType: nullable(arg({ type: 'BookmarkReminderEnum' })),
+ reminderAt: nullable(stringArg()),
+ name: nullable(stringArg()),
},
resolve: bookmarkPostResolver,
});
diff --git a/api/src/resolvers/topics/categoryQuery.ts b/api/src/resolvers/topics/categoryQuery.ts
index ae163b3c..8dca06b2 100644
--- a/api/src/resolvers/topics/categoryQuery.ts
+++ b/api/src/resolvers/topics/categoryQuery.ts
@@ -1,5 +1,5 @@
import camelcaseKeys from 'camelcase-keys';
-import { FieldResolver, queryField } from '@nexus/schema';
+import { FieldResolver, queryField } from 'nexus';
import { errorHandler } from '../../helpers';
import { Context } from '../../types';
diff --git a/api/src/resolvers/topics/editPostMutation.ts b/api/src/resolvers/topics/editPostMutation.ts
index d76feb35..f2d7d2ff 100644
--- a/api/src/resolvers/topics/editPostMutation.ts
+++ b/api/src/resolvers/topics/editPostMutation.ts
@@ -1,6 +1,6 @@
import camelcaseKey from 'camelcase-keys';
import snakecaseKey from 'snakecase-keys';
-import { FieldResolver, mutationField, arg, intArg } from '@nexus/schema';
+import { FieldResolver, mutationField, arg, intArg } from 'nexus';
import { errorHandler } from '../../helpers';
import { Context } from '../../types';
@@ -33,8 +33,8 @@ export let editPostResolver: FieldResolver<'Mutation', 'editPost'> = async (
export let editPostMutation = mutationField('editPost', {
type: 'Post',
args: {
- postId: intArg({ required: true }),
- postInput: arg({ type: 'EditPostInput', required: true }),
+ postId: intArg(),
+ postInput: arg({ type: 'EditPostInput' }),
},
resolve: editPostResolver,
});
diff --git a/api/src/resolvers/topics/editTopicMutation.ts b/api/src/resolvers/topics/editTopicMutation.ts
index f530a2f8..9ec9a054 100644
--- a/api/src/resolvers/topics/editTopicMutation.ts
+++ b/api/src/resolvers/topics/editTopicMutation.ts
@@ -1,6 +1,6 @@
import camelcaseKey from 'camelcase-keys';
import snakecaseKey from 'snakecase-keys';
-import { FieldResolver, mutationField, arg, intArg } from '@nexus/schema';
+import { FieldResolver, mutationField, arg, intArg } from 'nexus';
import { errorHandler } from '../../helpers';
import { Context } from '../../types';
@@ -33,8 +33,8 @@ export let editTopicMutation: FieldResolver<'Mutation', 'editTopic'> = async (
export let editTopic = mutationField('editTopic', {
type: 'BasicTopic',
args: {
- topicInput: arg({ type: 'EditTopicInput', required: true }),
- topicId: intArg({ required: true }),
+ topicInput: arg({ type: 'EditTopicInput' }),
+ topicId: intArg(),
},
resolve: editTopicMutation,
});
diff --git a/api/src/resolvers/topics/flagPostMutation.ts b/api/src/resolvers/topics/flagPostMutation.ts
index 4e04a2db..f8b5542a 100644
--- a/api/src/resolvers/topics/flagPostMutation.ts
+++ b/api/src/resolvers/topics/flagPostMutation.ts
@@ -1,7 +1,13 @@
import { stringify } from 'querystring';
import camelcaseKeys from 'camelcase-keys';
-import { FieldResolver, mutationField, intArg, stringArg } from '@nexus/schema';
+import {
+ FieldResolver,
+ mutationField,
+ intArg,
+ stringArg,
+ nullable,
+} from 'nexus';
import { ACCEPTED_LANGUAGE, CONTENT_FORM_URLENCODED } from '../../constants';
import { errorHandler } from '../../helpers';
@@ -20,7 +26,6 @@ export let flagPostResolver: FieldResolver<'Mutation', 'flagPost'> = async (
};
let body = {
id: postId,
- // eslint-disable-next-line @typescript-eslint/camelcase
post_action_type_id: postActionTypeId,
};
try {
@@ -38,9 +43,9 @@ export let flagPostResolver: FieldResolver<'Mutation', 'flagPost'> = async (
export let flagPostMutation = mutationField('flagPost', {
type: 'Post',
args: {
- postId: intArg({ required: true }),
- postActionTypeId: intArg({ required: true }),
- message: stringArg(),
+ postId: intArg(),
+ postActionTypeId: intArg(),
+ message: nullable(stringArg()),
//you can add flagTopic in args
},
resolve: flagPostResolver,
diff --git a/api/src/resolvers/topics/leaveMessageMutation.ts b/api/src/resolvers/topics/leaveMessageMutation.ts
index 088fa4d3..a0ecdecd 100644
--- a/api/src/resolvers/topics/leaveMessageMutation.ts
+++ b/api/src/resolvers/topics/leaveMessageMutation.ts
@@ -4,7 +4,8 @@ import {
booleanArg,
intArg,
stringArg,
-} from '@nexus/schema';
+ nullable,
+} from 'nexus';
import { ACCEPTED_LANGUAGE, CONTENT_JSON } from '../../constants';
import { errorHandler } from '../../helpers';
@@ -41,9 +42,9 @@ export let leaveMessageResolver: FieldResolver<
export let leaveMessageMutation = mutationField('leaveMessage', {
type: 'String',
args: {
- topicId: intArg({ required: true }),
- owner: booleanArg(),
- username: stringArg({ required: true }),
+ topicId: intArg(),
+ owner: nullable(booleanArg()),
+ username: stringArg(),
},
resolve: leaveMessageResolver,
});
diff --git a/api/src/resolvers/topics/likePostMutation.ts b/api/src/resolvers/topics/likePostMutation.ts
deleted file mode 100644
index 6d4baee6..00000000
--- a/api/src/resolvers/topics/likePostMutation.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-import { stringify } from 'querystring';
-
-import camelcaseKeys from 'camelcase-keys';
-import {
- FieldResolver,
- mutationField,
- booleanArg,
- intArg,
-} from '@nexus/schema';
-
-import { ACCEPTED_LANGUAGE, CONTENT_FORM_URLENCODED } from '../../constants';
-import { errorHandler } from '../../helpers';
-import { Context } from '../../types';
-
-export let likePostResolver: FieldResolver<'Mutation', 'likePost'> = async (
- _,
- { postId, unlike, postList },
- context: Context,
-) => {
- let body = {
- // eslint-disable-next-line @typescript-eslint/camelcase
- post_action_type_id: 2,
- };
- const config = {
- headers: {
- 'Accept-Language': ACCEPTED_LANGUAGE,
- 'Content-Type': CONTENT_FORM_URLENCODED,
- },
- params: unlike && body,
- };
-
- const postConfig = {
- headers: {
- 'Accept-Language': ACCEPTED_LANGUAGE,
- },
- // eslint-disable-next-line @typescript-eslint/camelcase
- params: { post_ids: null, include_raw: true },
- };
-
- try {
- if (postList) {
- let url = `/t/${postId}.json`;
- let { data: topicDetailResult } = await context.client.get(
- url,
- postConfig,
- );
- let selectedTopic = camelcaseKeys(topicDetailResult, { deep: true });
- let post = selectedTopic.postStream.posts[0];
- postId = post.id;
- let { canUndo, acted } = post.actionsSummary.find(
- (actionSummary: { id: number }) => actionSummary.id === 2,
- );
- if (!canUndo && acted) {
- throw new Error('Already passed the time limit to unlike');
- }
- }
- if (unlike) {
- let { data } = await context.client.delete(
- `/post_actions/${postId}.json`,
- config,
- );
- return camelcaseKeys(data, { deep: true });
- } else {
- Object.assign(body, { id: postId });
- let { data } = await context.client.post(
- `/post_actions.json`,
- stringify(body),
- config,
- );
- return camelcaseKeys(data, { deep: true });
- }
- } catch (e) {
- errorHandler(e);
- }
-};
-
-export let likePostMutation = mutationField('likePost', {
- type: 'Post',
- args: {
- postId: intArg({ required: true }),
- unlike: booleanArg(),
- postList: booleanArg(),
- //you can add flagTopic in args
- },
- resolve: likePostResolver,
-});
diff --git a/api/src/resolvers/topics/likeTopicOrPostMutation.ts b/api/src/resolvers/topics/likeTopicOrPostMutation.ts
new file mode 100644
index 00000000..08bc32a0
--- /dev/null
+++ b/api/src/resolvers/topics/likeTopicOrPostMutation.ts
@@ -0,0 +1,139 @@
+import {
+ FieldResolver,
+ mutationField,
+ booleanArg,
+ intArg,
+ nullable,
+} from 'nexus';
+import camelcaseKeys from 'camelcase-keys';
+import { AxiosError } from 'axios';
+
+import {
+ ACCEPTED_LANGUAGE,
+ CONTENT_JSON,
+ errorTypes,
+ LIKE_ACTION_ID,
+} from '../../constants';
+import {
+ errorHandler,
+ getUpdatedLikedTopic,
+ fetchTopicDetail,
+ fetchPost,
+} from '../../helpers';
+import { LikableEntity, likeErrorHandler } from '../../helpers/likeErroHandler';
+import { ActionsSummary, Context, LikedTopic } from '../../types';
+
+export let likeTopicOrPostResolver: FieldResolver<
+ 'Mutation',
+ 'likeTopicOrPost'
+> = async (_, { postId, topicId, unlike }, { client }: Context) => {
+ const body = {
+ post_action_type_id: LIKE_ACTION_ID,
+ };
+ const config = {
+ headers: {
+ 'Accept-Language': ACCEPTED_LANGUAGE,
+ 'Content-Type': CONTENT_JSON,
+ },
+ params: unlike ? body : undefined,
+ };
+
+ try {
+ if ((!postId && !topicId) || (postId && topicId)) {
+ throw new Error('Please provide either only the post ID or the topic ID');
+ }
+
+ let likableEntity: LikableEntity = 'post';
+ let currentLikedTopicResponse: LikedTopic | null = null;
+ let actionsSummary: ActionsSummary | null = null;
+
+ // Get the first post actions summary and ID of the topic
+ if (topicId) {
+ const { likeCount, postStream } = await fetchTopicDetail({
+ topicId,
+ client,
+ });
+ likableEntity = 'topic';
+ const post = postStream.posts[0];
+ postId = post.id;
+ if (!postId) {
+ throw new Error('Unable to find the first post of this topic');
+ }
+ actionsSummary = post.actionsSummary;
+ currentLikedTopicResponse = {
+ postId,
+ topicId,
+ likeCount,
+ id: postId,
+ liked: !unlike,
+ };
+ }
+
+ // Try-catch block to handle like mutation error
+ try {
+ // Unliking topic or post
+ if (unlike) {
+ let { data } = await client.delete(
+ `/post_actions/${postId}.json`,
+ config,
+ );
+
+ if (topicId && currentLikedTopicResponse) {
+ return getUpdatedLikedTopic({
+ currentLikedTopicResponse,
+ isLiked: false,
+ });
+ }
+ return camelcaseKeys(data, { deep: true });
+ }
+
+ // Liking topic or post
+ let likeRequestData = { ...body, id: postId };
+ let { data } = await client.post(
+ `/post_actions.json`,
+ likeRequestData,
+ config,
+ );
+
+ if (topicId && currentLikedTopicResponse) {
+ return getUpdatedLikedTopic({
+ currentLikedTopicResponse,
+ isLiked: true,
+ });
+ }
+ return camelcaseKeys(data, { deep: true });
+ } catch (unknownError) {
+ const e = unknownError as AxiosError;
+ let errorType = e?.response?.data?.error_type;
+ // Let the error handler handle this
+ if (errorType === errorTypes.unauthenticatedAccess) {
+ throw e;
+ }
+
+ /**
+ * Get actions summary from the specified post ID
+ * only when content type is post, because we already have
+ * the actionsSummary from topic detail when content
+ * type is topic
+ */
+ if (likableEntity === 'post' && postId) {
+ const post = await fetchPost({ client, postId });
+ actionsSummary = post.actionsSummary;
+ }
+ likeErrorHandler(e, { actionsSummary, likableEntity, like: !unlike });
+ }
+ } catch (e) {
+ errorHandler(e);
+ }
+};
+
+export let likeTopicOrPostMutation = mutationField('likeTopicOrPost', {
+ type: 'LikeOutputUnion',
+ args: {
+ postId: nullable(intArg()),
+ topicId: nullable(intArg()),
+ unlike: nullable(booleanArg()),
+ //you can add flagTopic in args
+ },
+ resolve: likeTopicOrPostResolver,
+});
diff --git a/api/src/resolvers/topics/newPrivateMessageMutation.ts b/api/src/resolvers/topics/newPrivateMessageMutation.ts
index 7ad2dd1a..a4d9aecd 100644
--- a/api/src/resolvers/topics/newPrivateMessageMutation.ts
+++ b/api/src/resolvers/topics/newPrivateMessageMutation.ts
@@ -2,7 +2,7 @@ import { stringify } from 'querystring';
import camelcaseKey from 'camelcase-keys';
import snakecaseKey from 'snakecase-keys';
-import { FieldResolver, mutationField, arg } from '@nexus/schema';
+import { FieldResolver, mutationField, arg } from 'nexus';
import { CONTENT_FORM_URLENCODED } from '../../constants';
import { errorHandler } from '../../helpers';
@@ -39,7 +39,6 @@ export let newPrivateMessageMutation = mutationField('newPrivateMessage', {
args: {
newPrivateMessageInput: arg({
type: 'NewPrivateMessageInput',
- required: true,
}),
},
resolve: newPrivateMessageResolver,
diff --git a/api/src/resolvers/topics/newTopicMutation.ts b/api/src/resolvers/topics/newTopicMutation.ts
index 87c08f50..5d0d9538 100644
--- a/api/src/resolvers/topics/newTopicMutation.ts
+++ b/api/src/resolvers/topics/newTopicMutation.ts
@@ -1,6 +1,6 @@
import camelcaseKey from 'camelcase-keys';
import snakecaseKey from 'snakecase-keys';
-import { FieldResolver, mutationField, arg } from '@nexus/schema';
+import { FieldResolver, mutationField, arg } from 'nexus';
import { ACCEPTED_LANGUAGE, CONTENT_JSON } from '../../constants';
import { errorHandler } from '../../helpers';
@@ -36,7 +36,7 @@ export let newTopicResolver: FieldResolver<'Mutation', 'newTopic'> = async (
export let newTopicMutation = mutationField('newTopic', {
type: 'Post',
args: {
- newTopicInput: arg({ type: 'NewTopicInput', required: true }),
+ newTopicInput: arg({ type: 'NewTopicInput' }),
},
resolve: newTopicResolver,
});
diff --git a/api/src/resolvers/topics/postQuery.ts b/api/src/resolvers/topics/postQuery.ts
index f5f4d84a..5dad44be 100644
--- a/api/src/resolvers/topics/postQuery.ts
+++ b/api/src/resolvers/topics/postQuery.ts
@@ -1,29 +1,15 @@
-import camelcaseKey from 'camelcase-keys';
-import { FieldResolver, queryField, intArg } from '@nexus/schema';
+import { FieldResolver, queryField, intArg } from 'nexus';
-import { errorHandler } from '../../helpers';
+import { errorHandler, fetchPost } from '../../helpers';
import { Context } from '../../types';
-import { ACCEPTED_LANGUAGE } from '../../constants';
export let postQueryResolver: FieldResolver<'Query', 'post'> = async (
_,
{ postId },
- context: Context,
+ { client }: Context,
) => {
- const config = {
- headers: {
- 'Accept-Language': ACCEPTED_LANGUAGE,
- },
- params: {
- // eslint-disable-next-line @typescript-eslint/camelcase
- include_raw: true,
- },
- };
try {
- let url = `/posts/${postId}.json`;
- let { data: postResult } = await context.client.get(url, config);
-
- return camelcaseKey(postResult, { deep: true });
+ return await fetchPost({ client, postId });
} catch (error) {
throw errorHandler(error);
}
@@ -32,7 +18,7 @@ export let postQueryResolver: FieldResolver<'Query', 'post'> = async (
let postQuery = queryField('post', {
type: 'Post',
args: {
- postId: intArg({ required: true }),
+ postId: intArg(),
},
resolve: postQueryResolver,
});
diff --git a/api/src/resolvers/topics/postRawQuery.ts b/api/src/resolvers/topics/postRawQuery.ts
index b51db485..3f761828 100644
--- a/api/src/resolvers/topics/postRawQuery.ts
+++ b/api/src/resolvers/topics/postRawQuery.ts
@@ -1,7 +1,10 @@
-import camelcaseKey from 'camelcase-keys';
-import { FieldResolver, queryField, intArg } from '@nexus/schema';
+import { FieldResolver, queryField, intArg } from 'nexus';
-import { errorHandler, getMention, getPostImageUrl } from '../../helpers';
+import {
+ errorHandler,
+ generateMarkdownContent,
+ getMention,
+} from '../../helpers';
import { Context } from '../../types';
import { ACCEPTED_LANGUAGE } from '../../constants';
@@ -11,13 +14,8 @@ export const postRawQueryResolver: FieldResolver<'Query', 'postRaw'> = async (
context: Context,
) => {
const config = {
- headers: {
- 'Accept-Language': ACCEPTED_LANGUAGE,
- },
- params: {
- // eslint-disable-next-line @typescript-eslint/camelcase
- include_raw: true,
- },
+ headers: { 'Accept-Language': ACCEPTED_LANGUAGE },
+ params: { include_raw: true },
};
try {
@@ -29,12 +27,9 @@ export const postRawQueryResolver: FieldResolver<'Query', 'postRaw'> = async (
data: { cooked },
} = await context.client.get(urlCooked);
- let listOfCooked = getPostImageUrl(cooked) ?? [];
- let listOfMention = getMention(cooked) ?? [];
-
- let postResult = { raw, listOfCooked, listOfMention };
-
- return camelcaseKey(postResult, { deep: true });
+ const markdownContent = generateMarkdownContent(raw, cooked);
+ const mentions = getMention(cooked) ?? [];
+ return { raw, markdownContent, mentions };
} catch (error) {
throw errorHandler(error);
}
@@ -42,6 +37,6 @@ export const postRawQueryResolver: FieldResolver<'Query', 'postRaw'> = async (
export const postRawQuery = queryField('postRaw', {
type: 'PostRaw',
- args: { postId: intArg({ required: true }) },
+ args: { postId: intArg() },
resolve: postRawQueryResolver,
});
diff --git a/api/src/resolvers/topics/privateMessageDetailQuery.ts b/api/src/resolvers/topics/privateMessageDetailQuery.ts
new file mode 100644
index 00000000..24570506
--- /dev/null
+++ b/api/src/resolvers/topics/privateMessageDetailQuery.ts
@@ -0,0 +1,45 @@
+import { FieldResolver, queryField } from 'nexus';
+
+import {
+ validateTopicDetailOptionalArgs,
+ errorHandler,
+ fetchTopicDetail,
+ getTopicDetailBaseArgs,
+} from '../../helpers';
+import { Context } from '../../types';
+
+// TODO: Move message detail handler from frontend to this endpoint #837
+let privateMessageDetailQueryResolver: FieldResolver<
+ 'Query',
+ 'privateMessageDetail'
+> = async (_, { topicId, postIds, postNumber }, { client }: Context) => {
+ try {
+ validateTopicDetailOptionalArgs({ postIds, postNumber });
+ return await fetchTopicDetail({
+ client,
+ topicId,
+ postIds,
+ postNumber,
+ });
+ } catch (error) {
+ throw errorHandler(error);
+ }
+};
+
+/**
+ * By specifying postNumber, Discourse API will return posts
+ * with the following conditions:
+ * if total post < 20: all posts
+ * else if postNumber <= 5: the first 20 posts
+ * else if postNumber > total post - 20 + 5: 20 latest posts
+ * else if postNumber > 5: 20 posts starting from postNumber - 5
+ * Note that 20 is the maximum post counts per fetch
+ * and 5 is the value from Discourse
+ */
+let privateMessageDetailQuery = queryField('privateMessageDetail', {
+ type: 'PrivateMessageDetailOutput',
+ args: getTopicDetailBaseArgs(),
+ resolve: privateMessageDetailQueryResolver,
+});
+
+export { privateMessageDetailQuery };
diff --git a/api/src/resolvers/topics/privateMessageQuery.ts b/api/src/resolvers/topics/privateMessageQuery.ts
index 7e117c59..9136500f 100644
--- a/api/src/resolvers/topics/privateMessageQuery.ts
+++ b/api/src/resolvers/topics/privateMessageQuery.ts
@@ -1,5 +1,5 @@
import camelcaseKeys from 'camelcase-keys';
-import { FieldResolver, queryField, intArg, stringArg } from '@nexus/schema';
+import { FieldResolver, queryField, intArg, stringArg, nullable } from 'nexus';
import { errorHandler, privateMessagesMerger } from '../../helpers';
import { Context, PMOutput } from '../../types';
@@ -46,8 +46,8 @@ let privateMessageQueryResolver: FieldResolver<
let privateMessageQuery = queryField('privateMessage', {
type: 'PrivateMessageOutput',
args: {
- username: stringArg({ required: true }),
- page: intArg(),
+ username: stringArg(),
+ page: nullable(intArg()),
},
resolve: privateMessageQueryResolver,
});
diff --git a/api/src/resolvers/topics/repliesQuery.ts b/api/src/resolvers/topics/repliesQuery.ts
index 5f0200ba..8ecb5c55 100644
--- a/api/src/resolvers/topics/repliesQuery.ts
+++ b/api/src/resolvers/topics/repliesQuery.ts
@@ -1,4 +1,4 @@
-import { FieldResolver, queryField, intArg } from '@nexus/schema';
+import { FieldResolver, queryField, intArg, list } from 'nexus';
import { errorHandler } from '../../helpers';
import { Context } from '../../types';
@@ -33,10 +33,9 @@ let repliesQueryResolver: FieldResolver<'Query', 'replies'> = async (
};
let repliesQuery = queryField('replies', {
- type: 'Post',
- list: true,
+ type: list('Post'),
args: {
- postId: intArg({ required: true }),
+ postId: intArg(),
},
resolve: repliesQueryResolver,
});
diff --git a/api/src/resolvers/topics/replyMutation.ts b/api/src/resolvers/topics/replyMutation.ts
index f3b73665..b08cc3de 100644
--- a/api/src/resolvers/topics/replyMutation.ts
+++ b/api/src/resolvers/topics/replyMutation.ts
@@ -3,7 +3,7 @@ import { stringify } from 'querystring';
import FormData from 'form-data';
import camelcaseKey from 'camelcase-keys';
import snakecaseKey from 'snakecase-keys';
-import { FieldResolver, mutationField, arg, intArg } from '@nexus/schema';
+import { FieldResolver, mutationField, arg, intArg, nullable } from 'nexus';
import { CONTENT_FORM_URLENCODED } from '../../constants';
import { errorHandler } from '../../helpers';
@@ -16,9 +16,7 @@ export let replyResolver: FieldResolver<'Mutation', 'reply'> = async (
) => {
let replyInputSnake = snakecaseKey({ ...replyInput, archetype: 'regular' });
const config = {
- headers: {
- 'Content-Type': CONTENT_FORM_URLENCODED,
- },
+ headers: { 'Content-Type': CONTENT_FORM_URLENCODED },
};
try {
@@ -27,18 +25,17 @@ export let replyResolver: FieldResolver<'Mutation', 'reply'> = async (
throw new Error('Upload avatar must include user id.');
}
const form = new FormData();
- let { createReadStream } = await file;
- let fileStream = createReadStream();
- form.append('files[]', fileStream);
+
+ const fileBuffer = Buffer.from(await file.arrayBuffer());
+
+ form.append('files[]', fileBuffer, file.name);
form.append('type', type);
if (userId) {
form.append('user_id', userId);
}
const config = {
- headers: {
- ...form.getHeaders(),
- },
+ headers: form.getHeaders(),
};
let url = `/uploads.json`;
let { data } = await context.client.post(url, form, config);
@@ -67,10 +64,10 @@ export let replyResolver: FieldResolver<'Mutation', 'reply'> = async (
export let replyMutation = mutationField('reply', {
type: 'Post',
args: {
- replyInput: arg({ type: 'ReplyInput', required: true }),
- file: arg({ type: 'Upload' }),
- type: arg({ type: 'UploadTypeEnum' }),
- userId: intArg(),
+ replyInput: arg({ type: 'ReplyInput' }),
+ file: nullable(arg({ type: 'File' })),
+ type: nullable(arg({ type: 'UploadTypeEnum' })),
+ userId: nullable(intArg()),
},
resolve: replyResolver,
});
diff --git a/api/src/resolvers/topics/replyingToQuery.ts b/api/src/resolvers/topics/replyingToQuery.ts
index b9a50a49..10b5d725 100644
--- a/api/src/resolvers/topics/replyingToQuery.ts
+++ b/api/src/resolvers/topics/replyingToQuery.ts
@@ -1,4 +1,4 @@
-import { FieldResolver, queryField, intArg } from '@nexus/schema';
+import { FieldResolver, queryField, intArg, nullable } from 'nexus';
import { ACCEPTED_LANGUAGE } from '../../constants';
import { errorHandler } from '../../helpers';
@@ -17,7 +17,6 @@ let replyingToQueryResolver: FieldResolver<'Query', 'replyingTo'> = async (
'Accept-Language': ACCEPTED_LANGUAGE,
},
params: {
- // eslint-disable-next-line @typescript-eslint/camelcase
max_replies: 1,
},
};
@@ -45,7 +44,8 @@ let replyingToQueryResolver: FieldResolver<'Query', 'replyingTo'> = async (
let replyingToQuery = queryField('replyingTo', {
type: 'Post',
args: {
- postId: intArg({ required: true }),
+ postId: intArg(),
+ replyToPostId: nullable(intArg()), //unused args on backend but needed as FE workaround to fetch local state
},
resolve: replyingToQueryResolver,
});
diff --git a/api/src/resolvers/topics/searchQuery.ts b/api/src/resolvers/topics/searchQuery.ts
index 6fbe7d97..13279879 100644
--- a/api/src/resolvers/topics/searchQuery.ts
+++ b/api/src/resolvers/topics/searchQuery.ts
@@ -1,5 +1,5 @@
import camelcaseKey from 'camelcase-keys';
-import { FieldResolver, queryField, intArg, stringArg } from '@nexus/schema';
+import { FieldResolver, queryField, intArg, stringArg, nullable } from 'nexus';
import { errorHandler } from '../../helpers';
import { Context } from '../../types';
@@ -41,9 +41,9 @@ let searchQueryResolver: FieldResolver<'Query', 'search'> = async (
let searchQuery = queryField('search', {
type: 'SearchOutput',
args: {
- search: stringArg({ required: true }),
- page: intArg({ required: true }),
- order: stringArg(),
+ search: stringArg(),
+ page: intArg(),
+ order: nullable(stringArg()),
},
resolve: searchQueryResolver,
});
diff --git a/api/src/resolvers/topics/searchTagsQuery.ts b/api/src/resolvers/topics/searchTagsQuery.ts
index cf10f0df..09a006e2 100644
--- a/api/src/resolvers/topics/searchTagsQuery.ts
+++ b/api/src/resolvers/topics/searchTagsQuery.ts
@@ -1,6 +1,13 @@
import camelcaseKey from 'camelcase-keys';
import snakecaseKeys from 'snakecase-keys';
-import { FieldResolver, queryField, intArg, stringArg } from '@nexus/schema';
+import {
+ FieldResolver,
+ queryField,
+ intArg,
+ stringArg,
+ list,
+ nullable,
+} from 'nexus';
import { errorHandler } from '../../helpers';
import { Context } from '../../types';
@@ -36,12 +43,11 @@ let searchTagResolver: FieldResolver<'Query', 'searchTag'> = async (
};
let searchTagQuery = queryField('searchTag', {
- type: 'Tag',
- list: true,
+ type: list('Tag'),
args: {
- q: stringArg({ required: true }),
- limit: intArg(),
- selectedTags: stringArg({ list: true }),
+ q: stringArg(),
+ limit: nullable(intArg()),
+ selectedTags: nullable(list(stringArg())),
},
resolve: searchTagResolver,
});
diff --git a/api/src/resolvers/topics/timingsMutation.ts b/api/src/resolvers/topics/timingsMutation.ts
index c6682cdf..eca79949 100644
--- a/api/src/resolvers/topics/timingsMutation.ts
+++ b/api/src/resolvers/topics/timingsMutation.ts
@@ -1,5 +1,5 @@
import snakecaseKey from 'snakecase-keys';
-import { FieldResolver, mutationField, intArg } from '@nexus/schema';
+import { FieldResolver, mutationField, intArg, list } from 'nexus';
import { errorHandler, getTopicTimings } from '../../helpers';
import { Context } from '../../types';
@@ -31,8 +31,8 @@ export let timingsResolver: FieldResolver<'Mutation', 'timings'> = async (
export let timingsMutation = mutationField('timings', {
type: 'String',
args: {
- postNumbers: intArg({ list: true, required: true }),
- topicId: intArg({ required: true }),
+ postNumbers: list(intArg()),
+ topicId: intArg(),
},
resolve: timingsResolver,
});
diff --git a/api/src/resolvers/topics/topicDetailQuery.ts b/api/src/resolvers/topics/topicDetailQuery.ts
index c8f2abe9..9d1f1354 100644
--- a/api/src/resolvers/topics/topicDetailQuery.ts
+++ b/api/src/resolvers/topics/topicDetailQuery.ts
@@ -1,40 +1,77 @@
-/* eslint-disable @typescript-eslint/camelcase */
-import camelcaseKey from 'camelcase-keys';
-import { FieldResolver, queryField, intArg } from '@nexus/schema';
+import { FieldResolver, queryField, booleanArg, nullable } from 'nexus';
-import { errorHandler, getTopicPostPath } from '../../helpers';
+import { FIRST_POST_NUMBER, LIKE_ACTION_ID } from '../../constants';
+import {
+ validateTopicDetailOptionalArgs,
+ errorHandler,
+ fetchPost,
+ fetchTopicDetail,
+ getTopicDetailBaseArgs,
+} from '../../helpers';
import { Context } from '../../types';
-import { ACCEPTED_LANGUAGE } from '../../constants';
let topicDetailQueryResolver: FieldResolver<'Query', 'topicDetail'> = async (
_,
- { topicId, posts, postPointer },
- context: Context,
+ { topicId, postIds, postNumber, includeFirstPost },
+ { client }: Context,
) => {
- const config = {
- headers: {
- 'Accept-Language': ACCEPTED_LANGUAGE,
- },
- params: { post_ids: posts, include_raw: true },
- };
-
try {
- let postPath = getTopicPostPath(posts, postPointer);
- let url = `/t/${topicId}${postPath}.json`;
- let { data: topicDetailResult } = await context.client.get(url, config);
+ validateTopicDetailOptionalArgs({ postIds, postNumber, includeFirstPost });
+ const data = await fetchTopicDetail({
+ client,
+ topicId,
+ postIds,
+ postNumber,
+ });
+ const firstPostOfData = data.postStream.posts[0];
+ if (firstPostOfData) {
+ let isLiked = !!firstPostOfData.actionsSummary.find(
+ ({ id }: { id: number }) => {
+ return id === LIKE_ACTION_ID;
+ },
+ )?.acted;
+ data.liked = isLiked;
+ }
+
+ if (firstPostOfData.postNumber === FIRST_POST_NUMBER) {
+ data.postStream.posts = data.postStream.posts.slice(1);
+ if (includeFirstPost) {
+ data.postStream.firstPost = firstPostOfData;
+ }
+ return data;
+ }
+
+ if (!includeFirstPost) {
+ return data;
+ }
- return camelcaseKey(topicDetailResult, { deep: true });
- } catch (error) {
+ const firstPostId = data.postStream.stream?.[0];
+ if (!firstPostId) {
+ throw new Error('First post ID is not provided in topic stream');
+ }
+ const firstPostOfTopic = await fetchPost({ client, postId: firstPostId });
+ data.postStream.firstPost = firstPostOfTopic;
+ return data;
+ } catch (error: unknown) {
throw errorHandler(error);
}
};
+/**
+ * By specifying postNumber, Discourse API will return posts
+ * with the following conditions:
+ * if total post <= 20: all posts
+ * else if postNumber <= 5: the first 20 posts
+ * else if postNumber > total post - 20 + 5: 20 latest posts
+ * else if postNumber > 5: 20 posts starting from postNumber - 5
+ * Note that 20 is the maximum post counts per fetch
+ * and 5 is the value from Discourse
+ */
let topicDetailQuery = queryField('topicDetail', {
type: 'TopicDetailOutput',
args: {
- posts: intArg({ list: true }),
- topicId: intArg({ required: true }),
- postPointer: intArg(),
+ ...getTopicDetailBaseArgs(),
+ includeFirstPost: nullable(booleanArg()),
},
resolve: topicDetailQueryResolver,
});
diff --git a/api/src/resolvers/topics/topicsQuery.ts b/api/src/resolvers/topics/topicsQuery.ts
index 1170bf4c..4ae4e685 100644
--- a/api/src/resolvers/topics/topicsQuery.ts
+++ b/api/src/resolvers/topics/topicsQuery.ts
@@ -5,16 +5,21 @@ import {
arg,
intArg,
stringArg,
-} from '@nexus/schema';
+ nullable,
+} from 'nexus';
-import { errorHandler, parseTopicUrl } from '../../helpers';
-import { Context } from '../../types';
-import { ACCEPTED_LANGUAGE } from '../../constants';
+import {
+ errorHandler,
+ fetchLikeActivities,
+ parseTopicUrl,
+} from '../../helpers';
+import { Context, Topic, UserIcon } from '../../types';
+import { ACCEPTED_LANGUAGE, FIRST_POST_NUMBER } from '../../constants';
let topicsQueryResolver: FieldResolver<'Query', 'topics'> = async (
_,
- { page, ...filterInput },
- context: Context,
+ { page, username, ...filterInput },
+ { client, isAuth }: Context,
) => {
const config = {
headers: {
@@ -25,12 +30,44 @@ let topicsQueryResolver: FieldResolver<'Query', 'topics'> = async (
},
};
try {
- let { data: topicResult } = await context.client.get(
+ let { data: topicResult } = await client.get(
`/${parseTopicUrl(filterInput)}.json`,
config,
);
- return camelcaseKey(topicResult, { deep: true });
+ const topics = camelcaseKey(topicResult, { deep: true });
+ if (isAuth && username) {
+ // Determine `liked` value based on whether users like the first post of the topic
+ const activities = await fetchLikeActivities({ username, client });
+
+ // TODO: Do more research to find the best solution #783
+ const likedFirstPostInTopics = new Set();
+ activities.forEach(({ postNumber, topicId }) => {
+ if (postNumber === FIRST_POST_NUMBER) {
+ likedFirstPostInTopics.add(topicId);
+ }
+ });
+ topics.topicList.topics = topics.topicList.topics.map((topic: Topic) => {
+ const { id, liked } = topic;
+
+ let updatedLiked = liked ? likedFirstPostInTopics.has(id) : false;
+ return { ...topic, liked: updatedLiked };
+ });
+ }
+
+ let { users }: { users: Array } = topics;
+ topics.topicList.topics = topics.topicList.topics.map((topic: Topic) => {
+ const { posters } = topic;
+ let postersWithUser = posters.map((poster) => {
+ return {
+ ...poster,
+ user: poster.user ?? users.find(({ id }) => id === poster.userId),
+ };
+ });
+ return { ...topic, posters: postersWithUser };
+ });
+
+ return topics;
} catch (error) {
throw errorHandler(error);
}
@@ -39,11 +76,12 @@ let topicsQueryResolver: FieldResolver<'Query', 'topics'> = async (
let topicsQuery = queryField('topics', {
type: 'TopicsOutput',
args: {
- sort: arg({ type: 'TopicsSortEnum', required: true }),
- categoryId: intArg(),
- topPeriod: arg({ type: 'TopPeriodEnum' }),
- tag: stringArg(),
- page: intArg(),
+ sort: arg({ type: 'TopicsSortEnum' }),
+ categoryId: nullable(intArg()),
+ topPeriod: nullable(arg({ type: 'TopPeriodEnum' })),
+ tag: nullable(stringArg()),
+ page: nullable(intArg()),
+ username: nullable(stringArg()),
},
resolve: topicsQueryResolver,
});
diff --git a/api/src/resolvers/upload/lookupUrlsQuery.ts b/api/src/resolvers/upload/lookupUrlsQuery.ts
index 5d8f6d6c..413416bc 100644
--- a/api/src/resolvers/upload/lookupUrlsQuery.ts
+++ b/api/src/resolvers/upload/lookupUrlsQuery.ts
@@ -1,5 +1,5 @@
import camelcaseKeys from 'camelcase-keys';
-import { FieldResolver, queryField, stringArg } from '@nexus/schema';
+import { FieldResolver, list, queryField, stringArg } from 'nexus';
import { ACCEPTED_LANGUAGE, CONTENT_JSON } from '../../constants';
import { errorHandler } from '../../helpers';
@@ -11,7 +11,6 @@ let lookupUrlsQueryResolver: FieldResolver<'Query', 'lookupUrls'> = async (
context: Context,
) => {
let body = {
- // eslint-disable-next-line @typescript-eslint/camelcase
short_urls: shortUrls,
};
const config = {
@@ -35,10 +34,9 @@ let lookupUrlsQueryResolver: FieldResolver<'Query', 'lookupUrls'> = async (
};
let lookupUrlsQuery = queryField('lookupUrls', {
- type: 'LookupUrl',
- list: true,
+ type: list('LookupUrl'),
args: {
- shortUrls: stringArg({ required: true, list: true }),
+ shortUrls: list(stringArg()),
},
resolve: lookupUrlsQueryResolver,
});
diff --git a/api/src/resolvers/upload/uploadMutation.ts b/api/src/resolvers/upload/uploadMutation.ts
index 6f5dacc0..790fed4e 100644
--- a/api/src/resolvers/upload/uploadMutation.ts
+++ b/api/src/resolvers/upload/uploadMutation.ts
@@ -1,6 +1,6 @@
import camelcaseKeys from 'camelcase-keys';
import FormData from 'form-data';
-import { FieldResolver, mutationField, arg, intArg } from '@nexus/schema';
+import { FieldResolver, mutationField, arg, intArg, nullable } from 'nexus';
import { errorHandler } from '../../helpers';
import { Context } from '../../types';
@@ -14,9 +14,10 @@ export let uploadResolver: FieldResolver<'Mutation', 'upload'> = async (
throw new Error('Upload avatar must include user id.');
}
const form = new FormData();
- let { createReadStream } = await file;
- let fileStream = createReadStream();
- form.append('files[]', fileStream);
+
+ const fileBuffer = Buffer.from(await file.arrayBuffer());
+
+ form.append('files[]', fileBuffer, file.name);
form.append('type', type);
if (userId) {
form.append('user_id', userId);
@@ -41,10 +42,10 @@ export let uploadResolver: FieldResolver<'Mutation', 'upload'> = async (
export let uploadMutation = mutationField('upload', {
type: 'UploadOutput',
args: {
- file: arg({ type: 'Upload', required: true }),
- type: arg({ type: 'UploadTypeEnum', required: true }),
- userId: intArg(),
- token: intArg(),
+ file: arg({ type: 'File' }),
+ type: arg({ type: 'UploadTypeEnum' }),
+ userId: nullable(intArg()),
+ token: nullable(intArg()),
},
resolve: uploadResolver,
});
diff --git a/api/src/resolvers/user/badgeQuery.ts b/api/src/resolvers/user/badgeQuery.ts
index 7493e120..3bfe8b39 100644
--- a/api/src/resolvers/user/badgeQuery.ts
+++ b/api/src/resolvers/user/badgeQuery.ts
@@ -1,5 +1,5 @@
import camelcaseKeys from 'camelcase-keys';
-import { FieldResolver, queryField } from '@nexus/schema';
+import { FieldResolver, queryField } from 'nexus';
import { errorHandler } from '../../helpers';
import { Context } from '../../types';
diff --git a/api/src/resolvers/user/changeUsernameMutation.ts b/api/src/resolvers/user/changeUsernameMutation.ts
index d712302c..c199fbae 100644
--- a/api/src/resolvers/user/changeUsernameMutation.ts
+++ b/api/src/resolvers/user/changeUsernameMutation.ts
@@ -1,7 +1,7 @@
import { stringify } from 'querystring';
import snakecaseKeys from 'snakecase-keys';
-import { FieldResolver, mutationField, stringArg } from '@nexus/schema';
+import { FieldResolver, mutationField, stringArg } from 'nexus';
import { CONTENT_FORM_URLENCODED } from '../../constants';
import { errorHandler } from '../../helpers';
@@ -32,8 +32,8 @@ export let changeUsernameResolver: FieldResolver<
export let changeUsernameMutation = mutationField('changeUsername', {
type: 'ChangeUsernameOutput',
args: {
- newUsername: stringArg({ required: true }),
- oldUsername: stringArg({ required: true }),
+ newUsername: stringArg(),
+ oldUsername: stringArg(),
},
resolve: changeUsernameResolver,
});
diff --git a/api/src/resolvers/user/editProfileMutation.ts b/api/src/resolvers/user/editProfileMutation.ts
index 8cded8a4..2eb86754 100644
--- a/api/src/resolvers/user/editProfileMutation.ts
+++ b/api/src/resolvers/user/editProfileMutation.ts
@@ -6,7 +6,8 @@ import {
arg,
intArg,
stringArg,
-} from '@nexus/schema';
+ nullable,
+} from 'nexus';
import { ACCEPTED_LANGUAGE, CONTENT_JSON } from '../../constants';
import { errorHandler } from '../../helpers';
@@ -67,10 +68,10 @@ export let editProfileMutation: FieldResolver<
export let editProfile = mutationField('editProfile', {
type: 'UserDetail',
args: {
- editProfileInput: arg({ type: 'EditProfileInput' }),
- username: stringArg({ required: true }),
- newUsername: stringArg(),
- uploadId: intArg(),
+ editProfileInput: nullable(arg({ type: 'EditProfileInput' })),
+ username: stringArg(),
+ newUsername: nullable(stringArg()),
+ uploadId: nullable(intArg()),
},
resolve: editProfileMutation,
});
diff --git a/api/src/resolvers/user/saveProfilePictureMutation.ts b/api/src/resolvers/user/saveProfilePictureMutation.ts
index 90a05e1b..cee364ab 100644
--- a/api/src/resolvers/user/saveProfilePictureMutation.ts
+++ b/api/src/resolvers/user/saveProfilePictureMutation.ts
@@ -1,4 +1,4 @@
-import { FieldResolver, mutationField, intArg, stringArg } from '@nexus/schema';
+import { FieldResolver, mutationField, intArg, stringArg } from 'nexus';
import { ACCEPTED_LANGUAGE, CONTENT_JSON } from '../../constants';
import { errorHandler } from '../../helpers';
@@ -15,7 +15,6 @@ export let saveProfilePictureResolver: FieldResolver<
},
};
let body = {
- // eslint-disable-next-line @typescript-eslint/camelcase
upload_id: uploadId,
type: 'uploaded',
};
@@ -34,8 +33,8 @@ export let saveProfilePictureResolver: FieldResolver<
export let saveProfilePictureMutation = mutationField('saveProfilePicture', {
type: 'String',
args: {
- uploadId: intArg({ required: true }),
- username: stringArg({ required: true }),
+ uploadId: intArg(),
+ username: stringArg(),
},
resolve: saveProfilePictureResolver,
});
diff --git a/api/src/resolvers/user/searchUserQuery.ts b/api/src/resolvers/user/searchUserQuery.ts
index c39e1d06..1c0d227b 100644
--- a/api/src/resolvers/user/searchUserQuery.ts
+++ b/api/src/resolvers/user/searchUserQuery.ts
@@ -1,6 +1,6 @@
import camelcaseKey from 'camelcase-keys';
import snakecaseKeys from 'snakecase-keys';
-import { FieldResolver, queryField, stringArg } from '@nexus/schema';
+import { FieldResolver, queryField, stringArg } from 'nexus';
import { errorHandler } from '../../helpers';
import { Context } from '../../types';
@@ -42,7 +42,7 @@ let searchUserQueryResolver: FieldResolver<'Query', 'searchUser'> = async (
let searchUserQuery = queryField('searchUser', {
type: 'SearchUserOutput',
args: {
- search: stringArg({ required: true }),
+ search: stringArg(),
},
resolve: searchUserQueryResolver,
});
diff --git a/api/src/resolvers/user/singleBadgeQuery.ts b/api/src/resolvers/user/singleBadgeQuery.ts
index 08e5f157..dd23fd53 100644
--- a/api/src/resolvers/user/singleBadgeQuery.ts
+++ b/api/src/resolvers/user/singleBadgeQuery.ts
@@ -1,5 +1,5 @@
import camelcaseKeys from 'camelcase-keys';
-import { FieldResolver, queryField, intArg } from '@nexus/schema';
+import { FieldResolver, queryField, intArg } from 'nexus';
import { errorHandler } from '../../helpers';
import { Context } from '../../types';
@@ -21,7 +21,7 @@ let singleBadgeQueryResolver: FieldResolver<'Query', 'singleBadge'> = async (
let singleBadgeQuery = queryField('singleBadge', {
type: 'SingleBadgeOutput',
args: {
- id: intArg({ required: true }),
+ id: intArg(),
},
resolve: singleBadgeQueryResolver,
});
diff --git a/api/src/resolvers/user/userActivityQuery.ts b/api/src/resolvers/user/userActivityQuery.ts
index 81c504de..5564cc2a 100644
--- a/api/src/resolvers/user/userActivityQuery.ts
+++ b/api/src/resolvers/user/userActivityQuery.ts
@@ -1,8 +1,15 @@
import camelcaseKeys from 'camelcase-keys';
-import { FieldResolver, queryField, intArg, stringArg } from '@nexus/schema';
-
-import { errorHandler } from '../../helpers';
-import { Context, UserAction } from '../../types';
+import {
+ FieldResolver,
+ queryField,
+ intArg,
+ stringArg,
+ list,
+ nullable,
+} from 'nexus';
+
+import { errorHandler, USER_ACTIONS_URL } from '../../helpers';
+import { Context } from '../../types';
let userActivityQueryResolver: FieldResolver<'Query', 'userActivity'> = async (
_,
@@ -21,64 +28,34 @@ let userActivityQueryResolver: FieldResolver<'Query', 'userActivity'> = async (
offset,
username,
filter,
- // eslint-disable-next-line @typescript-eslint/camelcase
no_results_help_key: 'user_activity.no_default',
};
const config = {
params: body,
};
- let url = '/user_actions.json';
-
try {
- if (filter === '1') {
- let fetchAll = true;
- let userAction: Array = [];
- let fetchAllOffset = 0;
-
- while (fetchAll) {
- let fetchAllBody = {
- offset: fetchAllOffset,
- username,
- filter,
- };
-
- const fetchAllConfig = {
- params: fetchAllBody,
- };
- let { data: userActivityResult } = await context.client.get(
- url,
- fetchAllConfig,
- );
- let tempUserAction = userActivityResult.user_actions;
- fetchAllOffset = fetchAllOffset + 30;
- userAction = [...userAction, ...tempUserAction];
- if (tempUserAction.length < 30) {
- fetchAll = false;
- }
- }
- return camelcaseKeys(userAction, { deep: true });
- } else {
- let { data: userActivityResult } = await context.client.get(url, config);
- let userAction = userActivityResult.user_actions;
- if (!userAction) {
- return [];
- } else {
- return camelcaseKeys(userAction, { deep: true });
- }
+ let { data: userActivityResult } = await context.client.get(
+ USER_ACTIONS_URL,
+ config,
+ );
+ let userActions = userActivityResult.user_actions;
+ if (!userActions) {
+ return [];
}
+
+ return camelcaseKeys(userActions, { deep: true });
} catch (error) {
throw errorHandler(error);
}
};
let userActivityQuery = queryField('userActivity', {
- type: 'UserActions',
- list: true,
+ type: list('UserActions'),
args: {
- username: stringArg({ required: true }),
- offset: intArg({ required: true }),
- filter: stringArg(),
+ username: stringArg(),
+ offset: intArg(),
+ filter: nullable(stringArg()),
},
resolve: userActivityQueryResolver,
});
diff --git a/api/src/resolvers/user/userProfileQuery.ts b/api/src/resolvers/user/userProfileQuery.ts
index 7959b26e..ff1f8dce 100644
--- a/api/src/resolvers/user/userProfileQuery.ts
+++ b/api/src/resolvers/user/userProfileQuery.ts
@@ -1,6 +1,6 @@
import { AxiosResponse } from 'axios';
import camelcaseKey from 'camelcase-keys';
-import { FieldResolver, queryField, stringArg } from '@nexus/schema';
+import { FieldResolver, queryField, stringArg } from 'nexus';
import { errorHandler } from '../../helpers';
import { Context, NotificationOutput } from '../../types';
@@ -17,11 +17,8 @@ let userProfileQueryResolver: FieldResolver<'Query', 'userProfile'> = async (
let thereIsUnreadNotif = false;
if (camelcasedData.user.hasOwnProperty('email')) {
- let {
- data: notifData,
- }: AxiosResponse = await context.client.get(
- '/notifications.json?filter=unread&limit=30',
- );
+ let { data: notifData }: AxiosResponse =
+ await context.client.get('/notifications.json?filter=unread&limit=30');
thereIsUnreadNotif = !!notifData.notifications.length;
}
@@ -34,7 +31,7 @@ let userProfileQueryResolver: FieldResolver<'Query', 'userProfile'> = async (
let userProfileQuery = queryField('userProfile', {
type: 'UserProfileOutput',
args: {
- username: stringArg({ required: true }),
+ username: stringArg(),
},
resolve: userProfileQueryResolver,
});
diff --git a/api/src/resolvers/utils.ts b/api/src/resolvers/utils.ts
new file mode 100644
index 00000000..073ad094
--- /dev/null
+++ b/api/src/resolvers/utils.ts
@@ -0,0 +1,48 @@
+import { PROSE_DISCOURSE_UPLOAD_HOST } from '../constants';
+
+export type WithUrlTemplate =
+ | { avatarTemplate: string }
+ | { actingAvatarTemplate: string }
+ | { systemAvatarTemplate: string }
+ | { url: string };
+
+export type NormalizedUrlTemplateVariant =
+ | 'regularAvatar'
+ | 'actingAvatar'
+ | 'systemAvatar'
+ | 'url';
+
+export function getNormalizedUrlTemplate(
+ instance: WithUrlTemplate,
+ variant: NormalizedUrlTemplateVariant = 'regularAvatar',
+) {
+ let urlTemplate = '';
+
+ if (variant === 'regularAvatar') {
+ if ('avatarTemplate' in instance) {
+ urlTemplate = instance.avatarTemplate;
+ }
+ } else if (variant === 'actingAvatar') {
+ if ('actingAvatarTemplate' in instance) {
+ urlTemplate = instance.actingAvatarTemplate;
+ }
+ } else if (variant === 'url') {
+ if ('url' in instance) {
+ urlTemplate = instance.url;
+ }
+ } else {
+ if ('systemAvatarTemplate' in instance) {
+ urlTemplate = instance.systemAvatarTemplate;
+ }
+ }
+
+ if (!urlTemplate) {
+ // TODO: #764 Add a Basic Logger
+ // console.debug('url template was empty for instance', instance);
+ return '';
+ }
+
+ return urlTemplate.includes('http')
+ ? urlTemplate
+ : PROSE_DISCOURSE_UPLOAD_HOST.concat(urlTemplate);
+}
diff --git a/api/src/scalars/BookmarkReminderEnum.ts b/api/src/scalars/BookmarkReminderEnum.ts
index ed628d3a..2ae85ff4 100644
--- a/api/src/scalars/BookmarkReminderEnum.ts
+++ b/api/src/scalars/BookmarkReminderEnum.ts
@@ -1,4 +1,4 @@
-import { enumType } from '@nexus/schema';
+import { enumType } from 'nexus';
export let BookmarkReminderEnum = enumType({
name: 'BookmarkReminderEnum',
diff --git a/api/src/scalars/File.ts b/api/src/scalars/File.ts
new file mode 100644
index 00000000..814c6592
--- /dev/null
+++ b/api/src/scalars/File.ts
@@ -0,0 +1,18 @@
+import { GraphQLError } from 'graphql';
+import { scalarType } from 'nexus';
+
+export const FileScalar = scalarType({
+ name: 'File',
+ asNexusMethod: 'file',
+ description: 'The `File` scalar type represents a file upload.',
+ sourceType: 'File',
+ parseValue(value) {
+ return value;
+ },
+ parseLiteral(node) {
+ throw new GraphQLError('Upload literal unsupported.', { nodes: node });
+ },
+ serialize() {
+ throw new GraphQLError('Upload serialization unsupported.');
+ },
+});
diff --git a/api/src/scalars/LikeOutputUnion.ts b/api/src/scalars/LikeOutputUnion.ts
new file mode 100644
index 00000000..c31d06c8
--- /dev/null
+++ b/api/src/scalars/LikeOutputUnion.ts
@@ -0,0 +1,11 @@
+import { unionType } from 'nexus';
+
+export const LikeOutputUnion = unionType({
+ name: 'LikeOutputUnion',
+ definition(t) {
+ t.members('LikedTopic', 'Post');
+ },
+ resolveType: (item) => {
+ return item.hasOwnProperty('actionsSummary') ? 'Post' : 'LikedTopic';
+ },
+});
diff --git a/api/src/scalars/LoginOutputUnion.ts b/api/src/scalars/LoginOutputUnion.ts
index 85f85e9d..258fa50d 100644
--- a/api/src/scalars/LoginOutputUnion.ts
+++ b/api/src/scalars/LoginOutputUnion.ts
@@ -1,14 +1,14 @@
-import { unionType } from '@nexus/schema';
+import { unionType } from 'nexus';
export let LoginOutputUnion = unionType({
name: 'LoginOutputUnion',
definition(t) {
t.members('LoginOutput', 'SecondFactorRequired');
- t.resolveType((item) => {
- if (item.hasOwnProperty('secondFactorRequired')) {
- return 'SecondFactorRequired';
- }
- return 'LoginOutput';
- });
+ },
+ resolveType: (item) => {
+ if (item.hasOwnProperty('secondFactorRequired')) {
+ return 'SecondFactorRequired';
+ }
+ return 'LoginOutput';
},
});
diff --git a/api/src/scalars/NotificationDataType.ts b/api/src/scalars/NotificationDataType.ts
index a81f520c..971a020f 100644
--- a/api/src/scalars/NotificationDataType.ts
+++ b/api/src/scalars/NotificationDataType.ts
@@ -1,10 +1,10 @@
-import { objectType, unionType } from '@nexus/schema';
+import { objectType, unionType } from 'nexus';
export const UnknownNotification = objectType({
// This will handle if notif data are unknown
name: 'UnknownNotification',
definition(t) {
- t.string('text', { nullable: true });
+ t.nullable.string('text');
},
});
@@ -19,21 +19,21 @@ export let NotificationDataType = unionType({
'InviteeAccept',
'UnknownNotification',
);
- t.resolveType((item) => {
- switch (true) {
- case item.hasOwnProperty('badgeId'):
- return 'BadgeNotification';
- case item.hasOwnProperty('originalPostId'):
- return 'ActionPostNotification';
- case item.hasOwnProperty('groupId'):
- return 'AdminMessageNotification';
- case item.hasOwnProperty('topicTitle'):
- return 'AdminMessageInvitation';
- case item.hasOwnProperty('displayUsername'):
- return 'InviteeAccept';
- default:
- return 'UnknownNotification';
- }
- });
+ },
+ resolveType: (item) => {
+ switch (true) {
+ case item.hasOwnProperty('badgeId'):
+ return 'BadgeNotification';
+ case item.hasOwnProperty('originalPostId'):
+ return 'ActionPostNotification';
+ case item.hasOwnProperty('groupId'):
+ return 'AdminMessageNotification';
+ case item.hasOwnProperty('topicTitle'):
+ return 'AdminMessageInvitation';
+ case item.hasOwnProperty('displayUsername'):
+ return 'InviteeAccept';
+ default:
+ return 'UnknownNotification';
+ }
},
});
diff --git a/api/src/scalars/TopPeriodEnum.ts b/api/src/scalars/TopPeriodEnum.ts
index 8bffcff2..5fde0fe0 100644
--- a/api/src/scalars/TopPeriodEnum.ts
+++ b/api/src/scalars/TopPeriodEnum.ts
@@ -1,4 +1,4 @@
-import { enumType } from '@nexus/schema';
+import { enumType } from 'nexus';
export let TopPeriodEnum = enumType({
name: 'TopPeriodEnum',
diff --git a/api/src/scalars/TopicsSortEnum.ts b/api/src/scalars/TopicsSortEnum.ts
index a6b08fc6..aeca1086 100644
--- a/api/src/scalars/TopicsSortEnum.ts
+++ b/api/src/scalars/TopicsSortEnum.ts
@@ -1,4 +1,4 @@
-import { enumType } from '@nexus/schema';
+import { enumType } from 'nexus';
export let TopicsSortEnum = enumType({
name: 'TopicsSortEnum',
diff --git a/api/src/scalars/Upload.ts b/api/src/scalars/Upload.ts
deleted file mode 100644
index d6c45407..00000000
--- a/api/src/scalars/Upload.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import { GraphQLUpload } from 'graphql-upload';
-
-export const Upload = GraphQLUpload;
diff --git a/api/src/scalars/UploadTypeEnum.ts b/api/src/scalars/UploadTypeEnum.ts
index 2f4b2384..b68ec3fa 100644
--- a/api/src/scalars/UploadTypeEnum.ts
+++ b/api/src/scalars/UploadTypeEnum.ts
@@ -1,4 +1,4 @@
-import { enumType } from '@nexus/schema';
+import { enumType } from 'nexus';
export let UploadTypeEnum = enumType({
name: 'UploadTypeEnum',
diff --git a/api/src/scalars/UserUnion.ts b/api/src/scalars/UserUnion.ts
index d7c53c38..fbca1e95 100644
--- a/api/src/scalars/UserUnion.ts
+++ b/api/src/scalars/UserUnion.ts
@@ -1,14 +1,14 @@
-import { unionType } from '@nexus/schema';
+import { unionType } from 'nexus';
export let UserUnion = unionType({
name: 'UserUnion',
definition(t) {
t.members('UserLite', 'UserDetail');
- t.resolveType((item) => {
- if (item.hasOwnProperty('email')) {
- return 'UserDetail';
- }
- return 'UserLite';
- });
+ },
+ resolveType: (item) => {
+ if (item.hasOwnProperty('email')) {
+ return 'UserDetail';
+ }
+ return 'UserLite';
},
});
diff --git a/api/src/scalars/index.ts b/api/src/scalars/index.ts
index bae19fce..8287d081 100644
--- a/api/src/scalars/index.ts
+++ b/api/src/scalars/index.ts
@@ -1,8 +1,9 @@
export * from './BookmarkReminderEnum';
+export * from './LikeOutputUnion';
export * from './LoginOutputUnion';
export * from './NotificationDataType';
export * from './TopicsSortEnum';
export * from './TopPeriodEnum';
-export * from './Upload';
+export * from './File';
export * from './UploadTypeEnum';
export * from './UserUnion';
diff --git a/api/src/schema.ts b/api/src/schema.ts
index 710fd800..a3c2d29f 100644
--- a/api/src/schema.ts
+++ b/api/src/schema.ts
@@ -1,12 +1,16 @@
import * as path from 'path';
-import { makeSchema } from '@nexus/schema';
+import { makeSchema } from 'nexus';
import * as Resolvers from './resolvers';
import * as Scalars from './scalars';
import * as Types from './typeSchemas';
let schema = makeSchema({
+ nonNullDefaults: {
+ output: true,
+ input: true,
+ },
types: [Resolvers, Types, Scalars],
outputs: {
schema: __dirname + '/generated/schema.graphql',
diff --git a/api/src/server/banner.ts b/api/src/server/banner.ts
index d7d2201e..32333b36 100644
--- a/api/src/server/banner.ts
+++ b/api/src/server/banner.ts
@@ -1,31 +1,11 @@
-import {
- PROSE_DISCOURSE_HOST,
- PROSE_APP_PORT,
- PROSE_APP_HOSTNAME,
-} from '../constants';
+import { PROSE_DISCOURSE_HOST } from '../constants';
export function getServerBanner() {
const messageTitle = '-- Prose GraphQL Discourse API --';
- let scheme = 'http://';
-
- // Don't append a port suffix to the server banner unless one is set.
- let portSuffix = PROSE_APP_PORT ? `:${PROSE_APP_PORT}` : '';
-
- // If `PROSE_APP_PORT` is 443, don't print it in the banner.
- // `https://myprosehost.com` looks better than `https://myprosehost.com:443`.
- if (PROSE_APP_PORT === 443) {
- scheme = 'https://';
- portSuffix = '';
- }
-
- // Compose the host we're listening on as the provided hostname followed by the port suffix.
- const displayHost = `${scheme}${PROSE_APP_HOSTNAME}${portSuffix}`;
-
- const messageListening = `listening at ${displayHost}`;
const messageForwarding = `forwarding Discourse requests to ${PROSE_DISCOURSE_HOST}`;
- const lines = [messageTitle, messageListening, messageForwarding];
+ const lines = [messageTitle, messageForwarding];
return lines.join('\n');
}
diff --git a/api/src/server/graphql.ts b/api/src/server/graphql.ts
deleted file mode 100644
index ec6c2201..00000000
--- a/api/src/server/graphql.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import { GraphQLServer } from 'graphql-yoga';
-import { ContextParameters } from 'graphql-yoga/dist/types';
-
-import { getClient } from '../client';
-import { decodeToken } from '../helpers/auth';
-import { permissions } from '../middlewares/permission';
-import { schema } from '../schema';
-
-export const graphQLServer = new GraphQLServer({
- schema,
- context: async ({ request }: ContextParameters) => {
- let authorization = request.header('Authorization');
- let cookie = decodeToken(authorization);
- if (cookie.includes('_t=')) {
- return {
- client: await getClient(cookie),
- isAuth: true,
- };
- }
- return {
- client: await getClient(),
- isAuth: false,
- };
- },
- middlewares: [permissions],
-});
diff --git a/api/src/server/graphql/index.ts b/api/src/server/graphql/index.ts
new file mode 100644
index 00000000..15a21fa4
--- /dev/null
+++ b/api/src/server/graphql/index.ts
@@ -0,0 +1,86 @@
+import {
+ createServer as createYogaServer,
+ useLogger,
+} from '@graphql-yoga/node';
+
+import { getClient } from '../../client';
+import { decodeToken } from '../../helpers/auth';
+import { schema } from '../../schema';
+import { Context } from '../../types';
+import { errorHandler } from '../../helpers';
+import { logger } from '../../logger';
+import { REFRESH_TOKEN_COOKIE_FIELD } from '../../constants';
+
+import { authPlugin } from './plugins';
+
+export function createServer(hostname: string, port: number) {
+ const graphQLServer = createYogaServer({
+ schema,
+ hostname,
+ port,
+
+ // The default behavior of GraphQL Yoga is to mask error messages.
+ // However, the Lexicon frontend makes use of these, and Discourse has several
+ // useful error messages, so here we instruct GraphQL Yoga to not mask the errors.
+ maskedErrors: false,
+
+ context: async ({ request, res }): Promise => {
+ try {
+ let authorization = request.headers.get('Authorization');
+ let cookie = decodeToken(authorization);
+ const userAgent = request.headers.get('User-Agent') ?? '';
+
+ if (cookie.includes(REFRESH_TOKEN_COOKIE_FIELD)) {
+ return {
+ client: await getClient({
+ cookies: cookie,
+ userAgent,
+ context: { request, response: res },
+ }),
+ isAuth: true,
+ };
+ }
+
+ return {
+ client: await getClient({
+ userAgent,
+ context: { request, response: res },
+ }),
+ isAuth: false,
+ };
+ } catch (error) {
+ errorHandler(error);
+ throw error; // avoid no return type, this shouldn't be reachable as errorHandler already throw
+ }
+ },
+ endpoint: '/',
+ plugins: [
+ authPlugin,
+ useLogger({
+ skipIntrospection: true,
+ logFn: (eventName, events) => {
+ switch (eventName) {
+ case 'execute-end':
+ case 'subscribe-end':
+ if ((events.result.errors?.length ?? 0) < 1) {
+ break;
+ }
+ for (let error of events.result.errors) {
+ const dateTime = new Date();
+ logger.log(
+ 'error',
+ '[%s] [%s] %s',
+ dateTime.toUTCString(),
+ error.path[0],
+ error.message,
+ );
+ }
+ break;
+ }
+ },
+ }),
+ ],
+ });
+
+ return graphQLServer;
+}
diff --git a/api/src/server/graphql/plugins.ts b/api/src/server/graphql/plugins.ts
new file mode 100644
index 00000000..361a90ca
--- /dev/null
+++ b/api/src/server/graphql/plugins.ts
@@ -0,0 +1,99 @@
+import { AuthSchema, preExecRule } from '@graphql-authz/core';
+import { authZEnvelopPlugin } from '@graphql-authz/envelop-plugin';
+
+import { Context } from '../../types';
+
+/**
+ * ## About the `plugins.ts` file
+ *
+ * `plugins` are intended to be used with our GraphQL server, GraphQL Yoga, which
+ * internally leverages Envelop for its plugin system.
+ *
+ * Envelop is a library that serves as a GraphQL plugin system.
+ *
+ * `graphql-authz` is one such plugin that is compatible with Envelop. It provides a
+ * powerful and flexible authorization solution.
+ *
+ * `graphql-authz` works by wrapping the GraphQL execution phase. This allows you to run
+ * authorization logic before and after this phase, via Pre-exec Rules and Post-exec Rules.
+ *
+ * - The pre-execution phase is for static auth rules based on context & input.
+ * - The post-execution phase is for flexible auth rules based on the execution result.
+ *
+ * This is currently the only plugin that we require for this project. We use it to ensure
+ * that the user is authenticated in order to perform certain queries and mutations.
+ *
+ * When a request does not include authenticated information for one of these operations,
+ * it returns a simple message "You need to be logged in to do that."
+ *
+ * This mirrors the message that Discourse returns in this situation, so it may not
+ * be necessary. But it may be allowing us to provide a more uniform response. It is a
+ * topic that can be investigated if necessary.
+ *
+ * All of the authenticated queries and mutations are specified below.
+ *
+ * These primarily consist of mutations, since those are typically the only operations
+ * in Discourse that require an authenticated user. The exceptions to this are the queries
+ * for notifications, private messages, and badges (which don't make sense for an anonymous
+ * user).
+ *
+ * Also, the `login` mutation does not require an authenticated user, as that is
+ * the way in which a user becomes authenticated.
+ */
+
+// Create our Rule, which simply checks the context to see if the user is authenticated.
+// If they are not, return `unauthenticatedMessage` as the error message.
+const unauthenticatedMessage = 'You need to be logged in to do that.';
+const configureRule = preExecRule({ error: unauthenticatedMessage });
+const IsAuthenticated = configureRule(({ isAuth }: Context) => isAuth);
+
+// This function generates the necessary boilerplate for the authzEnvelopPlugin
+// so that we can generate the `authSchema` that it expects.
+//
+// `authZEnvelopPlugin` allows us to reference our rule by its string-literal
+// representation, which is mapped when we declare the `rules` variable below.
+function getAuthenticatedSchema(keys: Array) {
+ return keys.reduce(
+ (accumulator, current) => ({
+ ...accumulator,
+ [current]: { __authz: { rules: ['IsAuthenticated'] } },
+ }),
+ {},
+ );
+}
+
+// Below we define the queries and mutations that require authentication.
+const guardedQueries = ['notification', 'privateMessage', 'badge'];
+const guardedMutations = [
+ 'timings',
+ 'newPrivateMessage',
+ 'newTopic',
+ 'reply',
+ 'editPost',
+ 'editTopic',
+ 'addEmail',
+ 'changeEmail',
+ 'deleteEmail',
+ 'setPrimaryEmail',
+ 'bookmarkPost',
+ 'changeUsername',
+ 'flagPost',
+ 'likeTopicOrPost',
+ 'upload',
+ 'editProfile',
+ 'saveProfilePicture',
+];
+
+const authenticatedSchema: AuthSchema = {
+ Mutation: getAuthenticatedSchema(guardedMutations),
+ Query: getAuthenticatedSchema(guardedQueries),
+};
+
+// Define the rules for our `authZEnvelopPlugin`, in this case just
+// our `IsAuthenticated` rule from above.
+const rules = { IsAuthenticated } as const;
+
+export const authPlugin = authZEnvelopPlugin({
+ rules,
+ authSchema: authenticatedSchema,
+});
diff --git a/api/src/server/index.ts b/api/src/server/index.ts
index cab6320a..462f8779 100644
--- a/api/src/server/index.ts
+++ b/api/src/server/index.ts
@@ -1,36 +1,16 @@
/* eslint-disable no-console */
-import { Server } from 'http';
-
import { PROSE_APP_PORT, PROSE_APP_HOSTNAME } from '../constants';
import { checkDiscourseReachability } from './validate';
-import { graphQLServer } from './graphql';
+import { createServer } from './graphql';
import { getServerBanner } from './banner';
-// `graphql-yoga` doesn't seem to support providing a custom hostname to Express (in its latest published release).
-// Here, we write a helper function to use the underlying parts of `graphql-yoga` to pass
-// the correct parameters to Express.
-//
-// Note: `graphql-yoga` has recently changed maintainers, and they don't seem to intend to make any releases,
-// even with the existing useful changes, until they have done a huge refactor based around their tool, Envelop.
-let httpServer: Server;
-function start() {
- httpServer = graphQLServer.createHttpServer({ port: PROSE_APP_PORT });
-
- httpServer.listen(PROSE_APP_PORT, PROSE_APP_HOSTNAME, () =>
- console.log(getServerBanner()),
- );
-}
-
-function stop() {
- if (!httpServer) {
- return;
- }
+const server = createServer(PROSE_APP_HOSTNAME, PROSE_APP_PORT);
+async function stop() {
console.log('\nProse GraphQL: Waiting for open requests to finish...');
- httpServer.close(() => {
- console.log('Stopping the Prose GraphQL Server.');
- });
+ await server.stop();
+ console.log('Stopping the Prose GraphQL Server.');
}
export async function run() {
@@ -38,5 +18,6 @@ export async function run() {
process.on('SIGTERM', stop);
process.on('SIGHUP', stop);
- start();
+ console.log('\n', getServerBanner(), '\n');
+ await server.start();
}
diff --git a/api/src/typeSchemas/About.ts b/api/src/typeSchemas/About.ts
index e9f0479d..d24aedeb 100644
--- a/api/src/typeSchemas/About.ts
+++ b/api/src/typeSchemas/About.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let About = objectType({
name: 'About',
diff --git a/api/src/typeSchemas/ActionPostNotification.ts b/api/src/typeSchemas/ActionPostNotification.ts
index c7ed2f0e..b442e38f 100644
--- a/api/src/typeSchemas/ActionPostNotification.ts
+++ b/api/src/typeSchemas/ActionPostNotification.ts
@@ -1,14 +1,14 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let ActionPostNotification = objectType({
name: 'ActionPostNotification',
definition(t) {
t.string('topicTitle');
t.int('originalPostId');
- t.int('originalPostType', { nullable: true });
+ t.nullable.int('originalPostType');
t.string('originalUsername');
- t.int('revisionNumber', { nullable: true });
+ t.nullable.int('revisionNumber');
t.string('displayUsername');
- t.string('count', { nullable: true });
+ t.nullable.string('count');
},
});
diff --git a/api/src/typeSchemas/ActionSummary.ts b/api/src/typeSchemas/ActionSummary.ts
index 4a67ed94..5ad89e77 100644
--- a/api/src/typeSchemas/ActionSummary.ts
+++ b/api/src/typeSchemas/ActionSummary.ts
@@ -1,13 +1,13 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let ActionSummary = objectType({
name: 'ActionSummary',
definition(t) {
t.int('id');
- t.boolean('hidden', { nullable: true });
- t.int('count', { nullable: true });
- t.boolean('canAct', { nullable: true });
- t.boolean('acted', { nullable: true });
- t.boolean('canUndo', { nullable: true });
+ t.nullable.boolean('hidden');
+ t.nullable.int('count');
+ t.nullable.boolean('canAct');
+ t.nullable.boolean('acted');
+ t.nullable.boolean('canUndo');
},
});
diff --git a/api/src/typeSchemas/AdminMessageInvitation.ts b/api/src/typeSchemas/AdminMessageInvitation.ts
index cbedd79a..950cb4ef 100644
--- a/api/src/typeSchemas/AdminMessageInvitation.ts
+++ b/api/src/typeSchemas/AdminMessageInvitation.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let AdminMessageInvitation = objectType({
name: 'AdminMessageInvitation',
diff --git a/api/src/typeSchemas/AdminMessageNotification.ts b/api/src/typeSchemas/AdminMessageNotification.ts
index 0e3b7743..09a21f13 100644
--- a/api/src/typeSchemas/AdminMessageNotification.ts
+++ b/api/src/typeSchemas/AdminMessageNotification.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let AdminMessageNotification = objectType({
name: 'AdminMessageNotification',
diff --git a/api/src/typeSchemas/AssociatedAccounts.ts b/api/src/typeSchemas/AssociatedAccounts.ts
index c76bca2e..5b739cb6 100644
--- a/api/src/typeSchemas/AssociatedAccounts.ts
+++ b/api/src/typeSchemas/AssociatedAccounts.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let AssociatedAccounts = objectType({
name: 'AssociatedAccounts',
diff --git a/api/src/typeSchemas/Badge.ts b/api/src/typeSchemas/Badge.ts
index e73265c1..f7691844 100644
--- a/api/src/typeSchemas/Badge.ts
+++ b/api/src/typeSchemas/Badge.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let Badge = objectType({
name: 'Badge',
@@ -10,7 +10,7 @@ export let Badge = objectType({
t.boolean('allowTitle');
t.boolean('multipleGrant');
t.string('icon');
- t.string('image', { nullable: true });
+ t.nullable.string('image');
t.boolean('listable');
t.boolean('enabled');
t.int('badgeGroupingId');
@@ -18,7 +18,7 @@ export let Badge = objectType({
t.string('slug');
t.boolean('manuallyGrantable');
t.int('badgeTypeId');
- t.boolean('hasBadge', { nullable: true });
- t.string('longDescription', { nullable: true });
+ t.nullable.boolean('hasBadge');
+ t.nullable.string('longDescription');
},
});
diff --git a/api/src/typeSchemas/BadgeGroupings.ts b/api/src/typeSchemas/BadgeGroupings.ts
index df9906d5..64b05ca9 100644
--- a/api/src/typeSchemas/BadgeGroupings.ts
+++ b/api/src/typeSchemas/BadgeGroupings.ts
@@ -1,12 +1,12 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let BadgeGroupings = objectType({
name: 'BadgeGroupings',
definition(t) {
- t.string('description', { nullable: true }),
- t.int('id'),
- t.string('name'),
- t.int('position'),
- t.boolean('system');
+ t.nullable.string('description');
+ t.int('id');
+ t.string('name');
+ t.int('position');
+ t.boolean('system');
},
});
diff --git a/api/src/typeSchemas/BadgeNotification.ts b/api/src/typeSchemas/BadgeNotification.ts
index ec56ded6..61fa2253 100644
--- a/api/src/typeSchemas/BadgeNotification.ts
+++ b/api/src/typeSchemas/BadgeNotification.ts
@@ -1,12 +1,12 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let BadgeNotification = objectType({
name: 'BadgeNotification',
definition(t) {
t.int('badgeId');
t.string('badgeName');
- t.string('badgeSlug', { nullable: true });
- t.boolean('badgeTitle', { nullable: true });
+ t.nullable.string('badgeSlug');
+ t.nullable.boolean('badgeTitle');
t.string('username');
},
});
diff --git a/api/src/typeSchemas/BadgeOutput.ts b/api/src/typeSchemas/BadgeOutput.ts
index f4a2ef5e..686ad399 100644
--- a/api/src/typeSchemas/BadgeOutput.ts
+++ b/api/src/typeSchemas/BadgeOutput.ts
@@ -1,10 +1,10 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let BadgeOutput = objectType({
name: 'BadgeOutput',
definition(t) {
- t.field('badgeGroupings', { type: 'BadgeGroupings', list: true });
- t.field('badgeTypes', { type: 'BadgeType', list: true });
- t.field('badges', { type: 'Badge', list: true });
+ t.list.field('badgeGroupings', { type: 'BadgeGroupings' });
+ t.list.field('badgeTypes', { type: 'BadgeType' });
+ t.list.field('badges', { type: 'Badge' });
},
});
diff --git a/api/src/typeSchemas/BadgeType.ts b/api/src/typeSchemas/BadgeType.ts
index 368434f7..7fe576ff 100644
--- a/api/src/typeSchemas/BadgeType.ts
+++ b/api/src/typeSchemas/BadgeType.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let BadgeType = objectType({
name: 'BadgeType',
diff --git a/api/src/typeSchemas/BasicTopic.ts b/api/src/typeSchemas/BasicTopic.ts
index e59078b0..c05d726c 100644
--- a/api/src/typeSchemas/BasicTopic.ts
+++ b/api/src/typeSchemas/BasicTopic.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let BasicTopic = objectType({
name: 'BasicTopic',
diff --git a/api/src/typeSchemas/BookmarkOutput.ts b/api/src/typeSchemas/BookmarkOutput.ts
index ddff5952..ba4f103b 100644
--- a/api/src/typeSchemas/BookmarkOutput.ts
+++ b/api/src/typeSchemas/BookmarkOutput.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let BookmarkOutput = objectType({
name: 'BookmarkOutput',
diff --git a/api/src/typeSchemas/Categories.ts b/api/src/typeSchemas/Categories.ts
index 3a2eb102..ed7062a3 100644
--- a/api/src/typeSchemas/Categories.ts
+++ b/api/src/typeSchemas/Categories.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let Categories = objectType({
name: 'Categories',
@@ -6,10 +6,10 @@ export let Categories = objectType({
t.string('color');
t.string('defaultListFilter');
t.string('defaultTopPeriod');
- t.string('defaultView', { nullable: true });
+ t.nullable.string('defaultView');
t.string('description');
t.string('descriptionExcerpt');
- t.string('descriptionText', { nullable: true });
+ t.nullable.string('descriptionText');
t.boolean('hasChildren');
t.int('id');
t.int('minimunRequiredTags');
@@ -23,19 +23,19 @@ export let Categories = objectType({
t.boolean('readRestricted');
t.boolean('showSubcategoryList');
t.string('slug');
- t.boolean('sortAscending', { nullable: true });
- t.boolean('sortOrder', { nullable: true });
+ t.nullable.boolean('sortAscending');
+ t.nullable.boolean('sortOrder');
t.string('subcategoryListStyle');
t.string('textColor');
t.int('topicCount');
- t.string('topicTemplate', { nullable: true });
+ t.nullable.string('topicTemplate');
t.string('topicUrl');
t.int('topicsAllTime');
t.int('topicsDay');
t.int('topicsMonth');
t.int('topicsWeek');
t.int('topicsYear');
- t.int('uploadedBackground', { nullable: true });
- t.int('uploadedLogo', { nullable: true });
+ t.nullable.int('uploadedBackground');
+ t.nullable.int('uploadedLogo');
},
});
diff --git a/api/src/typeSchemas/CategoryList.ts b/api/src/typeSchemas/CategoryList.ts
index 0ad4ca92..30f2c3cc 100644
--- a/api/src/typeSchemas/CategoryList.ts
+++ b/api/src/typeSchemas/CategoryList.ts
@@ -1,13 +1,13 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let CategoryList = objectType({
name: 'CategoryList',
definition(t) {
t.boolean('canCreateCategory');
t.boolean('canCreateTopic');
- t.field('categories', { type: 'Categories', list: true });
- t.boolean('draft', { nullable: true });
+ t.list.field('categories', { type: 'Categories' });
+ t.nullable.boolean('draft');
t.string('draftKey');
- t.int('draftSequence', { nullable: true });
+ t.nullable.int('draftSequence');
},
});
diff --git a/api/src/typeSchemas/ChangeUsernameOutput.ts b/api/src/typeSchemas/ChangeUsernameOutput.ts
index 1700a127..7dbae91a 100644
--- a/api/src/typeSchemas/ChangeUsernameOutput.ts
+++ b/api/src/typeSchemas/ChangeUsernameOutput.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let ChangeUsernameOutput = objectType({
name: 'ChangeUsernameOutput',
diff --git a/api/src/typeSchemas/EditPostInput.ts b/api/src/typeSchemas/EditPostInput.ts
index bed2ac72..95a87b4f 100644
--- a/api/src/typeSchemas/EditPostInput.ts
+++ b/api/src/typeSchemas/EditPostInput.ts
@@ -1,10 +1,10 @@
-import { inputObjectType } from '@nexus/schema';
+import { inputObjectType } from 'nexus';
export let EditPostInput = inputObjectType({
name: 'EditPostInput',
definition(t) {
- t.string('raw', { required: true });
- t.string('rawOld');
- t.string('editReason', { nullable: true });
+ t.string('raw');
+ t.nullable.string('rawOld');
+ t.nullable.string('editReason');
},
});
diff --git a/api/src/typeSchemas/EditProfileInput.ts b/api/src/typeSchemas/EditProfileInput.ts
index 120eb5b8..9d11a3e4 100644
--- a/api/src/typeSchemas/EditProfileInput.ts
+++ b/api/src/typeSchemas/EditProfileInput.ts
@@ -1,12 +1,12 @@
-import { inputObjectType } from '@nexus/schema';
+import { inputObjectType } from 'nexus';
export let EditProfileInput = inputObjectType({
name: 'EditProfileInput',
definition(t) {
- t.string('name');
- t.string('bioRaw');
- t.string('website');
- t.string('location');
- t.string('dateOfBirth');
+ t.nullable.string('name');
+ t.nullable.string('bioRaw');
+ t.nullable.string('website');
+ t.nullable.string('location');
+ t.nullable.string('dateOfBirth');
},
});
diff --git a/api/src/typeSchemas/EditTopicInput.ts b/api/src/typeSchemas/EditTopicInput.ts
index 729b45ef..f3c4f257 100644
--- a/api/src/typeSchemas/EditTopicInput.ts
+++ b/api/src/typeSchemas/EditTopicInput.ts
@@ -1,11 +1,11 @@
-import { inputObjectType } from '@nexus/schema';
+import { inputObjectType } from 'nexus';
export let EditTopicInput = inputObjectType({
name: 'EditTopicInput',
definition(t) {
- t.int('categoryId');
- t.string('featureLink'); //still not sure about the type of this var
- t.string('tags', { list: true });
- t.string('title');
+ t.nullable.int('categoryId');
+ t.nullable.string('featureLink'); // TODO: still not sure about the type of this var
+ t.nullable.list.string('tags');
+ t.nullable.string('title');
},
});
diff --git a/api/src/typeSchemas/Group.ts b/api/src/typeSchemas/Group.ts
index d415238e..f18d1d27 100644
--- a/api/src/typeSchemas/Group.ts
+++ b/api/src/typeSchemas/Group.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let Group = objectType({
name: 'Group',
@@ -12,22 +12,22 @@ export let Group = objectType({
t.int('messageableLevel');
t.int('visibilityLevel');
t.boolean('primaryGroup');
- t.string('title', { nullable: true });
- t.boolean('grantTrustLevel', { nullable: true });
- t.string('flairUrl', { nullable: true });
- t.string('flairBgColor', { nullable: true });
- t.string('bioCooked', { nullable: true });
- t.string('flairColor', { nullable: true });
- t.string('bioExcerpt', { nullable: true });
+ t.nullable.string('title');
+ t.nullable.boolean('grantTrustLevel');
+ t.nullable.string('flairUrl');
+ t.nullable.string('flairBgColor');
+ t.nullable.string('bioCooked');
+ t.nullable.string('flairColor');
+ t.nullable.string('bioExcerpt');
t.boolean('publicAdmission');
t.boolean('publicExit');
t.boolean('allowMembershipRequests');
- t.string('fullName', { nullable: true });
+ t.nullable.string('fullName');
t.int('defaultNotificationLevel');
- t.string('membershipRequestTemplate', { nullable: true });
+ t.nullable.string('membershipRequestTemplate');
t.int('membersVisibilityLevel');
t.boolean('canSeeMembers');
t.boolean('publishReadState');
- t.boolean('hasMessages', { nullable: true });
+ t.nullable.boolean('hasMessages');
},
});
diff --git a/api/src/typeSchemas/GroupUser.ts b/api/src/typeSchemas/GroupUser.ts
index c605dbcb..df53c518 100644
--- a/api/src/typeSchemas/GroupUser.ts
+++ b/api/src/typeSchemas/GroupUser.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let GroupUser = objectType({
name: 'GroupUser',
@@ -6,6 +6,8 @@ export let GroupUser = objectType({
t.int('groupId');
t.int('userId');
t.int('notificationLevel');
- t.boolean('owner', { nullable: true }); // If Admin change it's null
+
+ // If this change is done by an admin, the value is null.
+ t.nullable.boolean('owner');
},
});
diff --git a/api/src/typeSchemas/GroupUsers.ts b/api/src/typeSchemas/GroupUsers.ts
index 5f3eee68..76a72af6 100644
--- a/api/src/typeSchemas/GroupUsers.ts
+++ b/api/src/typeSchemas/GroupUsers.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let GroupUsers = objectType({
name: 'GroupUsers',
diff --git a/api/src/typeSchemas/GroupedSearchResult.ts b/api/src/typeSchemas/GroupedSearchResult.ts
index 17e0ce8d..e26c3fd7 100644
--- a/api/src/typeSchemas/GroupedSearchResult.ts
+++ b/api/src/typeSchemas/GroupedSearchResult.ts
@@ -1,20 +1,20 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let GroupedSearchResult = objectType({
name: 'GroupedSearchResult',
definition(t) {
t.boolean('canCreateTopic');
- t.int('categoryIds', { list: true });
- t.int('groupIds', { list: true });
- t.boolean('moreCategories', { nullable: true });
- t.boolean('moreFullPageResults', { nullable: true });
- t.boolean('morePosts', { nullable: true });
- t.boolean('moreUsers', { nullable: true });
- t.int('postIds', { list: true });
+ t.list.int('categoryIds');
+ t.list.int('groupIds');
+ t.nullable.boolean('moreCategories');
+ t.nullable.boolean('moreFullPageResults');
+ t.nullable.boolean('morePosts');
+ t.nullable.boolean('moreUsers');
+ t.list.int('postIds');
t.int('searchLogId');
- t.int('tagIds', { list: true });
+ t.list.int('tagIds');
t.string('term');
- t.int('userIds', { list: true });
+ t.list.int('userIds');
},
});
diff --git a/api/src/typeSchemas/HealthCheck.ts b/api/src/typeSchemas/HealthCheck.ts
new file mode 100644
index 00000000..1e435b22
--- /dev/null
+++ b/api/src/typeSchemas/HealthCheck.ts
@@ -0,0 +1,10 @@
+import { objectType } from 'nexus';
+
+export let HealthCheck = objectType({
+ name: 'HealthCheck',
+ definition(t) {
+ t.boolean('isDiscourseReachable');
+ t.string('discourseHost');
+ t.nullable.string('discourseError');
+ },
+});
diff --git a/api/src/typeSchemas/InviteeAccept.ts b/api/src/typeSchemas/InviteeAccept.ts
index 7b844c26..adec1a1e 100644
--- a/api/src/typeSchemas/InviteeAccept.ts
+++ b/api/src/typeSchemas/InviteeAccept.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let InviteeAccept = objectType({
name: 'InviteeAccept',
diff --git a/api/src/typeSchemas/LikedTopic.ts b/api/src/typeSchemas/LikedTopic.ts
new file mode 100644
index 00000000..7cfc4e06
--- /dev/null
+++ b/api/src/typeSchemas/LikedTopic.ts
@@ -0,0 +1,12 @@
+import { objectType } from 'nexus';
+
+export let LikedTopic = objectType({
+ name: 'LikedTopic',
+ definition(t) {
+ t.int('id');
+ t.int('postId');
+ t.int('topicId');
+ t.int('likeCount');
+ t.boolean('liked');
+ },
+});
diff --git a/api/src/typeSchemas/LinkCount.ts b/api/src/typeSchemas/LinkCount.ts
index 370aed45..ef21e4c4 100644
--- a/api/src/typeSchemas/LinkCount.ts
+++ b/api/src/typeSchemas/LinkCount.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let LinkCount = objectType({
name: 'LinkCount',
diff --git a/api/src/typeSchemas/LoginOutput.ts b/api/src/typeSchemas/LoginOutput.ts
index a6adcb8b..7751c4d6 100644
--- a/api/src/typeSchemas/LoginOutput.ts
+++ b/api/src/typeSchemas/LoginOutput.ts
@@ -1,13 +1,13 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let LoginOutput = objectType({
name: 'LoginOutput',
definition(t) {
- t.field('userBadges', { type: 'UserBadge', list: true });
- t.field('badges', { type: 'Badge', list: true, nullable: true });
- t.field('badgeTypes', { type: 'BadgeType', list: true, nullable: true });
- t.field('users', { type: 'UserIconStatus', list: true, nullable: true });
- t.field('topics', { type: 'UserTopic', list: true, nullable: true });
+ t.list.field('userBadges', { type: 'UserBadge' });
+ t.nullable.list.field('badges', { type: 'Badge' });
+ t.nullable.list.field('badgeTypes', { type: 'BadgeType' });
+ t.nullable.list.field('users', { type: 'UserIconStatus' });
+ t.nullable.list.field('topics', { type: 'UserTopic' });
t.field('user', { type: 'UserLite' });
// Auth
t.string('token');
diff --git a/api/src/typeSchemas/LookupUrl.ts b/api/src/typeSchemas/LookupUrl.ts
index 7f68a3aa..ab40ba34 100644
--- a/api/src/typeSchemas/LookupUrl.ts
+++ b/api/src/typeSchemas/LookupUrl.ts
@@ -1,14 +1,14 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
-import { PROSE_DISCOURSE_UPLOAD_HOST } from '../constants';
+import { getNormalizedUrlTemplate } from '../resolvers/utils';
export let LookupUrl = objectType({
name: 'LookupUrl',
definition(t) {
t.string('shortUrl');
- t.string('url', (lookup) => {
- let { url } = 'url' in lookup ? lookup : { url: '' };
- return PROSE_DISCOURSE_UPLOAD_HOST + url;
+ t.string('url', {
+ resolve: (instance) => getNormalizedUrlTemplate(instance, 'url'),
+ sourceType: 'string',
});
t.string('shortPath');
},
diff --git a/api/src/typeSchemas/MessageParticipant.ts b/api/src/typeSchemas/MessageParticipant.ts
index bfc98925..7bf6a647 100644
--- a/api/src/typeSchemas/MessageParticipant.ts
+++ b/api/src/typeSchemas/MessageParticipant.ts
@@ -1,11 +1,11 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let MessageParticipant = objectType({
name: 'MessageParticipant',
definition(t) {
t.int('userId');
- t.string('extras', { nullable: true });
- t.string('description', { nullable: true });
- t.int('primaryGroupid', { nullable: true });
+ t.nullable.string('extras');
+ t.nullable.string('description');
+ t.nullable.int('primaryGroupid');
},
});
diff --git a/api/src/typeSchemas/NotificationDetail.ts b/api/src/typeSchemas/NotificationDetail.ts
index eb4c23d8..da93de59 100644
--- a/api/src/typeSchemas/NotificationDetail.ts
+++ b/api/src/typeSchemas/NotificationDetail.ts
@@ -1,15 +1,15 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let NotificationDetail = objectType({
name: 'NotificationDetail',
definition(t) {
t.int('id');
- t.int('notificationType', { nullable: true });
+ t.nullable.int('notificationType');
t.boolean('read');
t.string('createdAt');
- t.int('postNumber', { nullable: true });
- t.int('topicId', { nullable: true });
- t.string('fancyTitle', { nullable: true });
+ t.nullable.int('postNumber');
+ t.nullable.int('topicId');
+ t.nullable.string('fancyTitle');
t.string('slug');
t.field('data', { type: 'NotificationDataType' });
},
diff --git a/api/src/typeSchemas/Notifications.ts b/api/src/typeSchemas/Notifications.ts
index 84708423..583826a6 100644
--- a/api/src/typeSchemas/Notifications.ts
+++ b/api/src/typeSchemas/Notifications.ts
@@ -1,15 +1,13 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let Notifications = objectType({
name: 'Notifications',
definition(t) {
- t.field('notifications', {
+ t.nullable.list.field('notifications', {
type: 'NotificationDetail',
- list: true,
- nullable: true,
});
- t.int('totalRowsNotifications', { nullable: true });
- t.int('seenNotificationId', { nullable: true });
- t.string('loadMoreNotifications', { nullable: true });
+ t.nullable.int('totalRowsNotifications');
+ t.nullable.int('seenNotificationId');
+ t.nullable.string('loadMoreNotifications');
},
});
diff --git a/api/src/typeSchemas/Participant.ts b/api/src/typeSchemas/Participant.ts
index c0844e39..d7d456b6 100644
--- a/api/src/typeSchemas/Participant.ts
+++ b/api/src/typeSchemas/Participant.ts
@@ -1,24 +1,21 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
-import { PROSE_DISCOURSE_UPLOAD_HOST } from '../constants';
+import { getNormalizedUrlTemplate } from '../resolvers/utils';
export let Participant = objectType({
name: 'Participant',
definition(t) {
t.int('id');
t.string('username');
- t.string('name', { nullable: true });
- t.string('avatarTemplate', (participant) => {
- let { avatarTemplate } =
- 'avatarTemplate' in participant ? participant : { avatarTemplate: '' };
- return avatarTemplate.includes('http')
- ? avatarTemplate
- : PROSE_DISCOURSE_UPLOAD_HOST.concat(avatarTemplate);
+ t.nullable.string('name');
+ t.string('avatarTemplate', {
+ resolve: (participant) => getNormalizedUrlTemplate(participant),
+ sourceType: 'string',
});
t.int('postCount');
- t.string('primaryGroupName', { nullable: true });
- t.string('primaryGroupFlairUrl', { nullable: true });
- t.string('primaryGroupFlairColor', { nullable: true });
- t.string('primaryGroupFlairBgColor', { nullable: true });
+ t.nullable.string('primaryGroupName');
+ t.nullable.string('primaryGroupFlairUrl');
+ t.nullable.string('primaryGroupFlairColor');
+ t.nullable.string('primaryGroupFlairBgColor');
},
});
diff --git a/api/src/typeSchemas/Post.ts b/api/src/typeSchemas/Post.ts
index 96a934e8..7e59c9e2 100644
--- a/api/src/typeSchemas/Post.ts
+++ b/api/src/typeSchemas/Post.ts
@@ -1,38 +1,44 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
-import { PROSE_DISCOURSE_UPLOAD_HOST } from '../constants';
-import { getMention, getPostImageUrl } from '../helpers';
+import { generateMarkdownContent, getMention } from '../helpers';
+import { getNormalizedUrlTemplate } from '../resolvers/utils';
export let Post = objectType({
name: 'Post',
definition(t) {
t.int('id');
- t.string('name', { nullable: true });
+ t.nullable.string('name');
t.string('username');
- t.string('avatarTemplate', (post) => {
- let { avatarTemplate } =
- 'avatarTemplate' in post ? post : { avatarTemplate: '' };
- return avatarTemplate.includes('http')
- ? avatarTemplate
- : PROSE_DISCOURSE_UPLOAD_HOST.concat(avatarTemplate);
+ t.string('avatarTemplate', {
+ resolve: (post) => getNormalizedUrlTemplate(post),
+ sourceType: 'string',
});
t.string('createdAt');
t.string('cooked');
-
- t.list.string('listOfCooked', {
- resolve: (post) => getPostImageUrl(post.cooked) || null,
- nullable: true,
- });
- t.list.string('listOfMention', {
+ t.nullable.list.string('mentions', {
resolve: (post) => getMention(post.cooked) || null,
- nullable: true,
});
- t.string('raw', { nullable: true }); // from Post(mutation) doesn't have raw even with include_raw: true
+ t.nullable.string('raw'); // from Post(mutation) doesn't have raw even with include_raw: true
+ t.nullable.string('markdownContent', {
+ resolve: (post) => {
+ let { raw = '' } = 'raw' in post ? post : {};
+ let { cooked = '' } = 'cooked' in post ? post : {};
+
+ if (!raw) {
+ return null;
+ }
+ if (!cooked) {
+ return raw;
+ }
+
+ return generateMarkdownContent(raw, cooked);
+ },
+ });
t.int('postNumber');
t.int('postType');
t.string('updatedAt');
t.int('replyCount');
- t.int('replyToPostNumber', { nullable: true });
+ t.nullable.int('replyToPostNumber');
t.int('quoteCount');
t.int('incomingLinkCount');
t.int('reads');
@@ -40,37 +46,41 @@ export let Post = objectType({
t.boolean('yours');
t.int('topicId');
t.string('topicSlug');
- t.string('displayUsername', { nullable: true });
- t.string('primaryGroupName', { nullable: true });
- t.string('primaryGroupFlairUrl', { nullable: true });
- t.string('primaryGroupFlairColor', { nullable: true });
- t.string('primaryGroupFlairBgColor', { nullable: true });
+ t.nullable.string('displayUsername');
+ t.nullable.string('primaryGroupName');
+ t.nullable.string('primaryGroupFlairUrl');
+ t.nullable.string('primaryGroupFlairColor');
+ t.nullable.string('primaryGroupFlairBgColor');
t.int('version');
t.boolean('canEdit');
t.boolean('canDelete');
t.boolean('canRecover');
t.boolean('canWiki');
- t.boolean('bookmarked', { nullable: true });
- t.field('actionsSummary', {
+ t.nullable.boolean('bookmarked');
+ t.nullable.list.field('actionsSummary', {
type: 'ActionSummary',
- list: true,
- nullable: true,
});
t.boolean('moderator');
t.boolean('admin');
t.boolean('staff');
t.int('userId');
- t.int('draftSequence', { nullable: true }); // Get Post doesn't have draft sequence
+
+ // Nullable because when getting a post, there is no draft sequence.
+ t.nullable.int('draftSequence');
+
t.boolean('hidden');
t.int('trustLevel');
t.boolean('userDeleted');
t.boolean('canViewEditHistory');
t.boolean('wiki');
- t.int('reviewableId', { nullable: true });
- t.float('reviewableScoreCount', { nullable: true });
- t.float('reviewableScorePendingCount', { nullable: true });
- t.field('linkCounts', { type: 'LinkCount', list: true, nullable: true }); // if post have link like image link
- t.string('actionCode', { nullable: true });
- t.string('actionCodeWho', { nullable: true });
+ t.nullable.int('reviewableId');
+ t.nullable.float('reviewableScoreCount');
+ t.nullable.float('reviewableScorePendingCount');
+
+ // The post can have an link, such as an image link
+ t.nullable.list.field('linkCounts', { type: 'LinkCount' });
+
+ t.nullable.string('actionCode');
+ t.nullable.string('actionCodeWho');
},
});
diff --git a/api/src/typeSchemas/PostInput.ts b/api/src/typeSchemas/PostInput.ts
index 4f5ad7a5..8295c9a0 100644
--- a/api/src/typeSchemas/PostInput.ts
+++ b/api/src/typeSchemas/PostInput.ts
@@ -1,30 +1,30 @@
-import { inputObjectType } from '@nexus/schema';
+import { inputObjectType } from 'nexus';
export let ReplyInput = inputObjectType({
name: 'ReplyInput',
definition(t) {
- t.string('raw', { required: true });
- t.int('topicId', { required: true });
- t.int('replyToPostNumber');
+ t.string('raw');
+ t.int('topicId');
+ t.nullable.int('replyToPostNumber');
},
});
export let NewPrivateMessageInput = inputObjectType({
name: 'NewPrivateMessageInput',
definition(t) {
- t.string('raw', { required: true });
- t.int('category');
- t.string('targetRecipients', { list: true, required: true });
- t.string('title', { required: true });
+ t.string('raw');
+ t.nullable.int('category');
+ t.list.string('targetRecipients');
+ t.string('title');
},
});
export let NewTopicInput = inputObjectType({
name: 'NewTopicInput',
definition(t) {
- t.string('raw', { required: true });
- t.int('category');
- t.string('title', { required: true });
- t.string('tags', { list: true });
+ t.string('raw');
+ t.nullable.int('category');
+ t.string('title');
+ t.nullable.list.string('tags');
},
});
diff --git a/api/src/typeSchemas/PostRaw.ts b/api/src/typeSchemas/PostRaw.ts
index 72b6283b..1c7b8e1b 100644
--- a/api/src/typeSchemas/PostRaw.ts
+++ b/api/src/typeSchemas/PostRaw.ts
@@ -1,10 +1,10 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export const PostRaw = objectType({
name: 'PostRaw',
definition: (t) => {
t.string('raw');
- t.list.string('listOfCooked');
- t.list.string('listOfMention');
+ t.string('markdownContent');
+ t.list.string('mentions');
},
});
diff --git a/api/src/typeSchemas/PostStream.ts b/api/src/typeSchemas/PostStream.ts
index addf0b68..8fafe186 100644
--- a/api/src/typeSchemas/PostStream.ts
+++ b/api/src/typeSchemas/PostStream.ts
@@ -1,9 +1,10 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let PostStream = objectType({
name: 'PostStream',
definition(t) {
- t.field('posts', { type: 'Post', list: true });
- t.int('stream', { nullable: true, list: true });
+ t.list.field('posts', { type: 'Post' });
+ t.nullable.list.int('stream');
+ t.nullable.field('firstPost', { type: 'Post' });
},
});
diff --git a/api/src/typeSchemas/PrivateMessageDetailOutput.ts b/api/src/typeSchemas/PrivateMessageDetailOutput.ts
new file mode 100644
index 00000000..4f1057ef
--- /dev/null
+++ b/api/src/typeSchemas/PrivateMessageDetailOutput.ts
@@ -0,0 +1,10 @@
+import { objectType } from 'nexus';
+
+import { BaseTopicDetailOutput } from './TopicDetailOutput';
+
+export let PrivateMessageDetailOutput = objectType({
+ name: 'PrivateMessageDetailOutput',
+ definition(t) {
+ t.implements(BaseTopicDetailOutput);
+ },
+});
diff --git a/api/src/typeSchemas/PrivateMessageOutput.ts b/api/src/typeSchemas/PrivateMessageOutput.ts
index 52221021..8da7a7dd 100644
--- a/api/src/typeSchemas/PrivateMessageOutput.ts
+++ b/api/src/typeSchemas/PrivateMessageOutput.ts
@@ -1,10 +1,10 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let PrivateMessageOutput = objectType({
name: 'PrivateMessageOutput',
definition(t) {
- t.int('primaryGroups', { nullable: true, list: true });
+ t.nullable.list.int('primaryGroups');
t.field('topicList', { type: 'TopicList' });
- t.field('users', { type: 'UserIcon', list: true, nullable: true });
+ t.nullable.list.field('users', { type: 'UserIcon' });
},
});
diff --git a/api/src/typeSchemas/PrivateMessagePostStream.ts b/api/src/typeSchemas/PrivateMessagePostStream.ts
new file mode 100644
index 00000000..59001e8f
--- /dev/null
+++ b/api/src/typeSchemas/PrivateMessagePostStream.ts
@@ -0,0 +1,9 @@
+import { objectType } from 'nexus';
+
+export let PrivateMessagePostStream = objectType({
+ name: 'PrivateMessagePostStream',
+ definition(t) {
+ t.list.field('posts', { type: 'Post' });
+ t.nullable.list.int('stream');
+ },
+});
diff --git a/api/src/typeSchemas/RefreshTokenOutput.ts b/api/src/typeSchemas/RefreshTokenOutput.ts
index 1fb7e6a5..00645ffb 100644
--- a/api/src/typeSchemas/RefreshTokenOutput.ts
+++ b/api/src/typeSchemas/RefreshTokenOutput.ts
@@ -1,11 +1,11 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let RefreshTokenOutput = objectType({
name: 'RefreshTokenOutput',
definition(t) {
t.int('id');
t.string('username');
- t.string('name', { nullable: true });
+ t.nullable.string('name');
// Auth
t.string('token');
},
diff --git a/api/src/typeSchemas/RegisterInput.ts b/api/src/typeSchemas/RegisterInput.ts
index f8111b3a..24035458 100644
--- a/api/src/typeSchemas/RegisterInput.ts
+++ b/api/src/typeSchemas/RegisterInput.ts
@@ -1,11 +1,11 @@
-import { inputObjectType } from '@nexus/schema';
+import { inputObjectType } from 'nexus';
export let RegisterInput = inputObjectType({
name: 'RegisterInput',
definition(t) {
- t.string('email', { required: true });
- t.string('username', { required: true });
- t.string('password', { required: true });
- t.string('name');
+ t.string('email');
+ t.string('username');
+ t.string('password');
+ t.nullable.string('name');
},
});
diff --git a/api/src/typeSchemas/RegisterOutput.ts b/api/src/typeSchemas/RegisterOutput.ts
index f0cb6e6b..84d88188 100644
--- a/api/src/typeSchemas/RegisterOutput.ts
+++ b/api/src/typeSchemas/RegisterOutput.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let RegisterOutput = objectType({
name: 'RegisterOutput',
diff --git a/api/src/typeSchemas/RemindersFrequency.ts b/api/src/typeSchemas/RemindersFrequency.ts
index 4303e605..9a121562 100644
--- a/api/src/typeSchemas/RemindersFrequency.ts
+++ b/api/src/typeSchemas/RemindersFrequency.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let RemindersFrequency = objectType({
name: 'RemindersFrequency',
diff --git a/api/src/typeSchemas/SearchGroup.ts b/api/src/typeSchemas/SearchGroup.ts
index 345ecab0..28cce299 100644
--- a/api/src/typeSchemas/SearchGroup.ts
+++ b/api/src/typeSchemas/SearchGroup.ts
@@ -1,9 +1,9 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let SearchGroup = objectType({
name: 'SearchGroup',
definition(t) {
- t.string('fullName', { nullable: true });
+ t.nullable.string('fullName');
t.string('name');
},
});
diff --git a/api/src/typeSchemas/SearchOutput.ts b/api/src/typeSchemas/SearchOutput.ts
index 02de2282..2e3494cd 100644
--- a/api/src/typeSchemas/SearchOutput.ts
+++ b/api/src/typeSchemas/SearchOutput.ts
@@ -1,11 +1,11 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let SearchOutput = objectType({
name: 'SearchOutput',
definition(t) {
t.field('groupedSearchResult', { type: 'GroupedSearchResult' });
- t.field('posts', { type: 'SearchPost', list: true });
- t.field('topics', { type: 'SearchTopic', list: true });
+ t.list.field('posts', { type: 'SearchPost' });
+ t.list.field('topics', { type: 'SearchTopic' });
},
});
diff --git a/api/src/typeSchemas/SearchPost.ts b/api/src/typeSchemas/SearchPost.ts
index 2ab12069..cbe10259 100644
--- a/api/src/typeSchemas/SearchPost.ts
+++ b/api/src/typeSchemas/SearchPost.ts
@@ -1,21 +1,18 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
-import { PROSE_DISCOURSE_UPLOAD_HOST } from '../constants';
+import { getNormalizedUrlTemplate } from '../resolvers/utils';
export let SearchPost = objectType({
name: 'SearchPost',
definition(t) {
t.int('id');
- t.string('avatarTemplate', (searchPost) => {
- let { avatarTemplate } =
- 'avatarTemplate' in searchPost ? searchPost : { avatarTemplate: '' };
- return avatarTemplate.includes('http')
- ? avatarTemplate
- : PROSE_DISCOURSE_UPLOAD_HOST.concat(avatarTemplate);
+ t.string('avatarTemplate', {
+ resolve: (searchPost) => getNormalizedUrlTemplate(searchPost),
+ sourceType: 'string',
});
t.string('blurb');
t.string('createdAt');
- t.string('name', { nullable: true });
+ t.nullable.string('name');
t.string('username');
t.int('likeCount');
t.int('postNumber');
diff --git a/api/src/typeSchemas/SearchTopic.ts b/api/src/typeSchemas/SearchTopic.ts
index d51c3584..5591ede6 100644
--- a/api/src/typeSchemas/SearchTopic.ts
+++ b/api/src/typeSchemas/SearchTopic.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let SearchTopic = objectType({
name: 'SearchTopic',
@@ -11,24 +11,30 @@ export let SearchTopic = objectType({
t.int('replyCount');
t.int('highestPostNumber');
t.string('createdAt');
- t.string('lastPostedAt', { nullable: true });
+ t.nullable.string('lastPostedAt');
t.boolean('bumped');
t.string('bumpedAt');
- t.string('archetype', { nullable: true });
+ t.nullable.string('archetype');
t.boolean('unseen');
t.boolean('pinned');
- t.string('excerpt', { nullable: true }); // Must be activated
+
+ // Nullable because this is a feature that must be turned in
+ // in Discourse in order to be set.
+ t.nullable.string('excerpt');
+
t.boolean('visible');
t.boolean('closed');
t.boolean('archived');
- t.boolean('bookmarked', { nullable: true });
- t.boolean('liked', { nullable: true });
- t.string('tags', { nullable: true, list: true });
- t.int('categoryId', { nullable: true });
- t.int('lastReadPostNumber', { nullable: true }); // Only available when logged in
- t.int('newPosts', { nullable: true }); // Only available when logged in
- t.int('notificationLevel', { nullable: true }); // Only available when logged in
- t.int('unread', { nullable: true }); // Only available when logged in
+ t.nullable.boolean('bookmarked');
+ t.nullable.boolean('liked');
+ t.nullable.list.string('tags');
+ t.nullable.int('categoryId');
+
+ // The below properties are only available when logged in.
+ t.nullable.int('lastReadPostNumber');
+ t.nullable.int('newPosts');
+ t.nullable.int('notificationLevel');
+ t.nullable.int('unread');
},
});
diff --git a/api/src/typeSchemas/SearchUser.ts b/api/src/typeSchemas/SearchUser.ts
index 992fec29..de6a50ac 100644
--- a/api/src/typeSchemas/SearchUser.ts
+++ b/api/src/typeSchemas/SearchUser.ts
@@ -1,18 +1,15 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
-import { PROSE_DISCOURSE_UPLOAD_HOST } from '../constants';
+import { getNormalizedUrlTemplate } from '../resolvers/utils';
export let SearchUser = objectType({
name: 'SearchUser',
definition(t) {
- t.string('avatarTemplate', (searchUser) => {
- let { avatarTemplate } =
- 'avatarTemplate' in searchUser ? searchUser : { avatarTemplate: '' };
- return avatarTemplate.includes('http')
- ? avatarTemplate
- : PROSE_DISCOURSE_UPLOAD_HOST.concat(avatarTemplate);
+ t.string('avatarTemplate', {
+ resolve: (searchUser) => getNormalizedUrlTemplate(searchUser),
+ sourceType: 'string',
});
- t.string('name', { nullable: true });
+ t.nullable.string('name');
t.string('username');
},
});
diff --git a/api/src/typeSchemas/SearchUserOutput.ts b/api/src/typeSchemas/SearchUserOutput.ts
index 23bce202..afd36c63 100644
--- a/api/src/typeSchemas/SearchUserOutput.ts
+++ b/api/src/typeSchemas/SearchUserOutput.ts
@@ -1,9 +1,11 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let SearchUserOutput = objectType({
name: 'SearchUserOutput',
definition(t) {
- t.field('groups', { type: 'SearchGroup', list: true, nullable: true }); // You can't see groups if not logged in
- t.field('users', { type: 'SearchUser', list: true });
+ t.list.field('users', { type: 'SearchUser' });
+
+ // Nullable because groups are not visible to unauthenticated users.
+ t.nullable.list.field('groups', { type: 'SearchGroup' });
},
});
diff --git a/api/src/typeSchemas/SecondFactorRequired.ts b/api/src/typeSchemas/SecondFactorRequired.ts
index 818550a4..353f86ea 100644
--- a/api/src/typeSchemas/SecondFactorRequired.ts
+++ b/api/src/typeSchemas/SecondFactorRequired.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let SecondFactorRequired = objectType({
name: 'SecondFactorRequired',
diff --git a/api/src/typeSchemas/SingleBadgeOutput.ts b/api/src/typeSchemas/SingleBadgeOutput.ts
index a9d8ba95..6554a4f2 100644
--- a/api/src/typeSchemas/SingleBadgeOutput.ts
+++ b/api/src/typeSchemas/SingleBadgeOutput.ts
@@ -1,9 +1,9 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let SingleBadgeOutput = objectType({
name: 'SingleBadgeOutput',
definition(t) {
- t.field('badgeTypes', { type: 'BadgeType', list: true });
+ t.list.field('badgeTypes', { type: 'BadgeType' });
t.field('badge', { type: 'Badge' });
},
});
diff --git a/api/src/typeSchemas/SiteSetting.ts b/api/src/typeSchemas/SiteSetting.ts
index c00d7a47..478e3f0e 100644
--- a/api/src/typeSchemas/SiteSetting.ts
+++ b/api/src/typeSchemas/SiteSetting.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let SiteSetting = objectType({
name: 'SiteSetting',
@@ -7,7 +7,7 @@ export let SiteSetting = objectType({
t.boolean('canTagTopics');
t.boolean('canSignUp');
t.string('authorizedExtensions');
- t.int('uncategorizedCategoryId', { nullable: true });
+ t.int('uncategorizedCategoryId');
t.int('minSearchLength');
t.boolean('taggingEnabled');
t.int('maxTagLength');
@@ -16,13 +16,13 @@ export let SiteSetting = objectType({
t.int('minUsernameLength');
t.int('minPasswordLength');
t.boolean('fullNameRequired');
- t.field('topicFlagTypes', {
+ t.string('defaultComposerCategory');
+ t.boolean('allowUncategorizedTopics');
+ t.list.field('topicFlagTypes', {
type: 'TopicFlagTypes',
- list: true,
});
- t.field('postActionTypes', {
+ t.list.field('postActionTypes', {
type: 'TopicFlagTypes',
- list: true,
});
},
});
diff --git a/api/src/typeSchemas/Tag.ts b/api/src/typeSchemas/Tag.ts
index 9f8d53b4..21db4db8 100644
--- a/api/src/typeSchemas/Tag.ts
+++ b/api/src/typeSchemas/Tag.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let Tag = objectType({
name: 'Tag',
@@ -6,7 +6,7 @@ export let Tag = objectType({
t.int('count');
t.string('id');
t.int('pmCount');
- t.boolean('targetTag', { nullable: true });
+ t.nullable.boolean('targetTag');
t.string('text');
},
});
diff --git a/api/src/typeSchemas/TagFilter.ts b/api/src/typeSchemas/TagFilter.ts
index 8693343b..be55c3cd 100644
--- a/api/src/typeSchemas/TagFilter.ts
+++ b/api/src/typeSchemas/TagFilter.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let TagFilter = objectType({
name: 'TagFilter',
diff --git a/api/src/typeSchemas/Topic.ts b/api/src/typeSchemas/Topic.ts
index 09d2f508..c6671dc7 100644
--- a/api/src/typeSchemas/Topic.ts
+++ b/api/src/typeSchemas/Topic.ts
@@ -1,8 +1,6 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
-type Poster = {
- description: string;
-};
+import { getTopicAuthorUserId } from '../helpers/getTopicAuthor';
export let Topic = objectType({
name: 'Topic',
@@ -15,60 +13,52 @@ export let Topic = objectType({
t.int('replyCount');
t.int('highestPostNumber');
t.string('createdAt');
- t.string('lastPostedAt', { nullable: true });
+ t.nullable.string('lastPostedAt');
t.boolean('bumped');
t.string('bumpedAt');
t.string('archetype');
- t.string('imageUrl', { nullable: true });
+ t.nullable.string('imageUrl');
t.boolean('unseen');
t.boolean('pinned');
- t.string('excerpt', { nullable: true }); // Must be activated
+
+ // Nullable because this is a feature that must be turned in
+ // in Discourse in order to be set.
+ t.nullable.string('excerpt');
+
t.boolean('visible');
t.boolean('closed');
t.boolean('archived');
- t.boolean('bookmarked', { nullable: true });
- t.boolean('liked', { nullable: true });
- t.string('tags', { nullable: true, list: true });
+ t.nullable.boolean('bookmarked');
+ t.nullable.boolean('liked');
+ t.nullable.list.string('tags');
t.int('views');
t.int('likeCount');
- t.int('allowedUserCount', { nullable: true }); // On PM
- t.int('lastReadPostNumber', { nullable: true }); // Only available when logged in
- t.int('newPosts', { nullable: true }); // Only available when logged in
- t.int('notificationLevel', { nullable: true }); // Only available when logged in
- t.int('unread', { nullable: true }); // Only available when logged in
- t.boolean('hasSummary', { nullable: true }); // Nullable in suggested topic
- t.string('lastPosterUsername', { nullable: true }); // recomended topic doesn't have dis
- t.int('categoryId', { nullable: true });
- t.boolean('pinnedGlobally', { nullable: true }); // Nullable in suggested topic
- t.field('posters', { type: 'TopicPoster', list: true });
- t.field('participants', {
- type: 'MessageParticipant',
- list: true,
- nullable: true,
- });
- t.int('authorUserId', {
- nullable: true,
- resolve: ({ posters }) => {
- const author = posters.find((p: Poster) =>
- p.description.toLowerCase().includes('original poster'),
- );
- return author?.userId || author?.user?.id || null;
- },
- });
- t.int('frequentPosterUserId', {
- nullable: true,
- resolve: ({ posters }) => {
- const frequentPoster = posters.find((p: Poster) =>
- p.description.toLowerCase().includes('frequent poster'),
- );
+ // For PMs
+ t.nullable.int('allowedUserCount');
- return frequentPoster?.userId || frequentPoster?.user?.id || null;
- },
+ // The following properties are only available when logged in.
+ t.nullable.int('lastReadPostNumber');
+ t.nullable.int('newPosts');
+ t.nullable.int('notificationLevel');
+ t.nullable.int('unread');
+ t.nullable.int('categoryId');
+
+ // The following fields are nullable when the topic is being
+ // presented as a suggested topic.
+ t.nullable.string('lastPosterUsername');
+ t.nullable.boolean('pinnedGlobally');
+ t.nullable.boolean('hasSummary');
+
+ t.list.field('posters', { type: 'TopicPoster' });
+ t.nullable.list.field('participants', {
+ type: 'MessageParticipant',
+ });
+ t.nullable.int('authorUserId', {
+ resolve: ({ posters }) => getTopicAuthorUserId(posters) ?? null,
});
// Note: Comment out for maybe next phase
- // t.int('recentPosterUserId', {
- // nullable: true,
+ // t.nullable.int('recentPosterUserId', {
// resolve: ({ posters }) => {
// const recentPoster = posters.find((p: Poster) =>
// p.description.toLowerCase().includes('most recent poster'),
diff --git a/api/src/typeSchemas/TopicDetail.ts b/api/src/typeSchemas/TopicDetail.ts
index eeb56a35..de7f4af9 100644
--- a/api/src/typeSchemas/TopicDetail.ts
+++ b/api/src/typeSchemas/TopicDetail.ts
@@ -1,13 +1,13 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let TopicDetail = objectType({
name: 'TopicDetail',
definition(t) {
t.int('notificationLevel');
- t.field('participants', { type: 'Participant', list: true });
- t.field('allowedUsers', { type: 'UserIcon', list: true, nullable: true });
+ t.list.field('participants', { type: 'Participant' });
+ t.nullable.list.field('allowedUsers', { type: 'UserIcon' });
t.field('createdBy', { type: 'UserIcon' });
t.field('lastPoster', { type: 'UserIcon' });
- t.boolean('canEdit', { nullable: true });
+ t.nullable.boolean('canEdit');
},
});
diff --git a/api/src/typeSchemas/TopicDetailOutput.ts b/api/src/typeSchemas/TopicDetailOutput.ts
index 5b067377..25861e1e 100644
--- a/api/src/typeSchemas/TopicDetailOutput.ts
+++ b/api/src/typeSchemas/TopicDetailOutput.ts
@@ -1,49 +1,53 @@
-import { objectType } from '@nexus/schema';
+import { interfaceType, objectType } from 'nexus';
-export let TopicDetailOutput = objectType({
- name: 'TopicDetailOutput',
+export const BaseTopicDetailOutput = interfaceType({
+ name: 'BaseTopicDetailOutput',
definition(t) {
t.int('id');
- t.string('title', { nullable: true });
- t.string('fancyTitle', { nullable: true });
- t.int('postsCount', { nullable: true });
- t.int('timelineLookup', { list: [true, true], nullable: true });
- t.string('slug', { nullable: true });
- t.int('replyCount', { nullable: true });
- t.int('highestPostNumber', { nullable: true });
- t.int('currentPostNumber', { nullable: true });
- t.string('createdAt', { nullable: true });
- t.string('lastPostedAt', { nullable: true });
- t.string('archetype', { nullable: true });
- t.boolean('pinned', { nullable: true });
- t.boolean('visible', { nullable: true });
- t.boolean('closed', { nullable: true });
- t.boolean('archived', { nullable: true });
- t.boolean('bookmarked', { nullable: true });
- t.boolean('liked', { nullable: true });
- t.string('tags', { nullable: true, list: true });
- t.int('views', { nullable: true });
- t.int('likeCount', { nullable: true });
- t.boolean('hasSummary', { nullable: true });
- t.int('categoryId', { nullable: true });
- t.boolean('pinnedGlobally', { nullable: true });
- t.string('pinnedAt', { nullable: true });
- t.string('pinnedUntil', { nullable: true });
- t.int('wordCount', { nullable: true });
- t.string('deletedAt', { nullable: true });
- t.int('userId', { nullable: true });
- t.string('draftKey', { nullable: true });
- t.field('actionsSummary', {
- type: 'ActionSummary',
- list: true,
- nullable: true,
- });
- t.int('chunkSize', { nullable: true });
- t.int('messageBusLastId', { nullable: true });
- t.int('participantCount', { nullable: true });
- t.boolean('showReadIndicator', { nullable: true });
- t.field('details', { type: 'TopicDetail', nullable: true });
- t.field('suggestedTopics', { type: 'Topic', list: true, nullable: true });
+ t.nullable.string('title');
+ t.nullable.string('fancyTitle');
+ t.nullable.int('postsCount');
+ t.nullable.list.list.int('timelineLookup');
+ t.nullable.string('slug');
+ t.nullable.int('replyCount');
+ t.nullable.int('highestPostNumber');
+ t.nullable.int('currentPostNumber');
+ t.nullable.string('createdAt');
+ t.nullable.string('lastPostedAt');
+ t.nullable.string('archetype');
+ t.nullable.boolean('pinned');
+ t.nullable.boolean('visible');
+ t.nullable.boolean('closed');
+ t.nullable.boolean('archived');
+ t.nullable.boolean('bookmarked');
+ t.nullable.boolean('liked');
+ t.nullable.list.string('tags');
+ t.nullable.int('views');
+ t.nullable.int('likeCount');
+ t.nullable.boolean('hasSummary');
+ t.nullable.int('categoryId');
+ t.nullable.boolean('pinnedGlobally');
+ t.nullable.string('pinnedAt');
+ t.nullable.string('pinnedUntil');
+ t.nullable.int('wordCount');
+ t.nullable.string('deletedAt');
+ t.nullable.int('userId');
+ t.nullable.string('draftKey');
+ t.nullable.list.field('actionsSummary', { type: 'ActionSummary' });
+ t.nullable.int('chunkSize');
+ t.nullable.int('messageBusLastId');
+ t.nullable.int('participantCount');
+ t.nullable.boolean('showReadIndicator');
+ t.nullable.field('details', { type: 'TopicDetail' });
+ t.nullable.list.field('suggestedTopics', { type: 'Topic' });
t.field('postStream', { type: 'PostStream' });
},
+ resolveType: () => null,
+});
+
+export let TopicDetailOutput = objectType({
+ name: 'TopicDetailOutput',
+ definition(t) {
+ t.implements(BaseTopicDetailOutput);
+ },
});
diff --git a/api/src/typeSchemas/TopicFlagTypes.ts b/api/src/typeSchemas/TopicFlagTypes.ts
index 62d79b7d..801411a9 100644
--- a/api/src/typeSchemas/TopicFlagTypes.ts
+++ b/api/src/typeSchemas/TopicFlagTypes.ts
@@ -1,15 +1,15 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let TopicFlagTypes = objectType({
name: 'TopicFlagTypes',
definition(t) {
t.string('description');
t.int('id');
- t.boolean('isCustomFlag', { nullable: true });
- t.boolean('isFlag', { nullable: true });
- t.string('longForm', { nullable: true });
+ t.nullable.boolean('isCustomFlag');
+ t.nullable.boolean('isFlag');
+ t.nullable.string('longForm');
t.string('name');
t.string('nameKey');
- t.string('shortDescription', { nullable: true });
+ t.nullable.string('shortDescription');
},
});
diff --git a/api/src/typeSchemas/TopicList.ts b/api/src/typeSchemas/TopicList.ts
index 6c703fd7..b06ec831 100644
--- a/api/src/typeSchemas/TopicList.ts
+++ b/api/src/typeSchemas/TopicList.ts
@@ -1,16 +1,16 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let TopicList = objectType({
name: 'TopicList',
definition(t) {
t.boolean('canCreateTopic');
- t.boolean('draft', { nullable: true });
+ t.nullable.boolean('draft');
t.string('draftKey');
- t.int('draftSequence', { nullable: true });
- t.string('forPeriod', { nullable: true });
+ t.nullable.int('draftSequence');
+ t.nullable.string('forPeriod');
t.int('perPage');
- t.string('topTags', { list: true });
- t.field('tags', { type: 'TagFilter', list: true, nullable: true });
- t.field('topics', { type: 'Topic', list: true, nullable: true });
+ t.list.string('topTags');
+ t.nullable.list.field('tags', { type: 'TagFilter' });
+ t.nullable.list.field('topics', { type: 'Topic' });
},
});
diff --git a/api/src/typeSchemas/TopicPoster.ts b/api/src/typeSchemas/TopicPoster.ts
index e94d2fcf..872eb4c0 100644
--- a/api/src/typeSchemas/TopicPoster.ts
+++ b/api/src/typeSchemas/TopicPoster.ts
@@ -1,11 +1,11 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let TopicPoster = objectType({
name: 'TopicPoster',
definition(t) {
- t.string('extras', { nullable: true });
+ t.nullable.string('extras');
t.string('description');
- t.int('userId', { nullable: true });
- t.field('user', { type: 'UserIcon', nullable: true });
+ t.nullable.int('userId');
+ t.nullable.field('user', { type: 'UserIcon' });
},
});
diff --git a/api/src/typeSchemas/TopicsOutput.ts b/api/src/typeSchemas/TopicsOutput.ts
index 95ea8240..cac372b4 100644
--- a/api/src/typeSchemas/TopicsOutput.ts
+++ b/api/src/typeSchemas/TopicsOutput.ts
@@ -1,9 +1,9 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let TopicsOutput = objectType({
name: 'TopicsOutput',
definition(t) {
- t.field('users', { type: 'UserIcon', list: true, nullable: true });
- t.field('topicList', { type: 'TopicList', nullable: true });
+ t.nullable.list.field('users', { type: 'UserIcon' });
+ t.nullable.field('topicList', { type: 'TopicList' });
},
});
diff --git a/api/src/typeSchemas/UpdateProfile.ts b/api/src/typeSchemas/UpdateProfile.ts
index 2d1eea5e..b570b649 100644
--- a/api/src/typeSchemas/UpdateProfile.ts
+++ b/api/src/typeSchemas/UpdateProfile.ts
@@ -1,10 +1,10 @@
-import { inputObjectType } from '@nexus/schema';
+import { inputObjectType } from 'nexus';
export let UpdateProfile = inputObjectType({
name: 'UpdateProfile',
definition(t) {
- t.string('name');
- t.string('title', { nullable: true });
- t.int('primaryGroupId', { nullable: true });
+ t.nullable.string('name');
+ t.nullable.string('title');
+ t.nullable.int('primaryGroupId');
},
});
diff --git a/api/src/typeSchemas/UploadOutput.ts b/api/src/typeSchemas/UploadOutput.ts
index 92dc8ee1..5148a2c2 100644
--- a/api/src/typeSchemas/UploadOutput.ts
+++ b/api/src/typeSchemas/UploadOutput.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let UploadOutput = objectType({
name: 'UploadOutput',
@@ -13,9 +13,9 @@ export let UploadOutput = objectType({
t.int('thumbnailHeight');
t.string('extension');
t.string('shortUrl');
- t.string('shortPath', { nullable: true });
+ t.nullable.string('shortPath');
t.string('humanFilesize');
- t.int('retainHours', { nullable: true });
- t.int('token', { nullable: true });
+ t.nullable.int('retainHours');
+ t.nullable.int('token');
},
});
diff --git a/api/src/typeSchemas/UserActions.ts b/api/src/typeSchemas/UserActions.ts
index 7a6b85d2..a3aea65c 100644
--- a/api/src/typeSchemas/UserActions.ts
+++ b/api/src/typeSchemas/UserActions.ts
@@ -1,43 +1,36 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
-import { PROSE_DISCOURSE_UPLOAD_HOST } from '../constants';
+import { getNormalizedUrlTemplate } from '../resolvers/utils';
export let UserActions = objectType({
name: 'UserActions',
definition(t) {
- t.string('actingAvatarTemplate', (userActions) => {
- let { actingAvatarTemplate } =
- 'actingAvatarTemplate' in userActions
- ? userActions
- : { actingAvatarTemplate: '' };
- return actingAvatarTemplate.includes('http')
- ? actingAvatarTemplate
- : PROSE_DISCOURSE_UPLOAD_HOST.concat(actingAvatarTemplate);
+ t.string('actingAvatarTemplate', {
+ resolve: (userActions) =>
+ getNormalizedUrlTemplate(userActions, 'actingAvatar'),
+ sourceType: 'string',
});
- t.string('actingName', { nullable: true });
+ t.nullable.string('actingName');
t.int('actingUserId');
- t.int('actionCode', { nullable: true });
+ t.nullable.int('actionCode');
t.int('actionType');
t.boolean('archived');
- t.string('avatarTemplate', (userActions) => {
- let { avatarTemplate } =
- 'avatarTemplate' in userActions ? userActions : { avatarTemplate: '' };
- return avatarTemplate.includes('http')
- ? avatarTemplate
- : PROSE_DISCOURSE_UPLOAD_HOST.concat(avatarTemplate);
+ t.string('avatarTemplate', {
+ resolve: (userActions) => getNormalizedUrlTemplate(userActions),
+ sourceType: 'string',
});
- t.int('categoryId', { nullable: true });
+ t.nullable.int('categoryId');
t.boolean('closed');
t.string('createdAt');
t.boolean('deleted');
t.string('excerpt');
- t.string('hidden', { nullable: true });
- t.string('name', { nullable: true });
- t.int('postId', { nullable: true });
+ t.nullable.boolean('hidden');
+ t.nullable.string('name');
+ t.nullable.int('postId');
t.int('postNumber');
- t.int('postType', { nullable: true });
+ t.nullable.int('postType');
t.string('slug');
- t.string('targetName', { nullable: true });
+ t.nullable.string('targetName');
t.int('targetUserId');
t.string('targetUsername');
t.string('title');
diff --git a/api/src/typeSchemas/UserAuthToken.ts b/api/src/typeSchemas/UserAuthToken.ts
index 7cfebf1f..1c620755 100644
--- a/api/src/typeSchemas/UserAuthToken.ts
+++ b/api/src/typeSchemas/UserAuthToken.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let UserAuthToken = objectType({
name: 'UserAuthToken',
diff --git a/api/src/typeSchemas/UserAuthTokens.ts b/api/src/typeSchemas/UserAuthTokens.ts
index 469f374d..e54e9276 100644
--- a/api/src/typeSchemas/UserAuthTokens.ts
+++ b/api/src/typeSchemas/UserAuthTokens.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let UserAuthTokens = objectType({
name: 'UserAuthTokens',
diff --git a/api/src/typeSchemas/UserBadge.ts b/api/src/typeSchemas/UserBadge.ts
index d1f06509..5d0961e8 100644
--- a/api/src/typeSchemas/UserBadge.ts
+++ b/api/src/typeSchemas/UserBadge.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let UserBadge = objectType({
name: 'UserBadge',
@@ -7,11 +7,11 @@ export let UserBadge = objectType({
t.string('grantedAt');
t.string('createdAt');
t.int('count');
- t.int('postId', { nullable: true });
- t.int('postNumber', { nullable: true });
+ t.nullable.int('postId');
+ t.nullable.int('postNumber');
t.int('badgeId');
t.int('userId');
t.int('grantedById');
- t.int('topicId', { nullable: true });
+ t.nullable.int('topicId');
},
});
diff --git a/api/src/typeSchemas/UserDetail.ts b/api/src/typeSchemas/UserDetail.ts
index cfcb1952..679fca28 100644
--- a/api/src/typeSchemas/UserDetail.ts
+++ b/api/src/typeSchemas/UserDetail.ts
@@ -1,26 +1,23 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
-import { PROSE_DISCOURSE_UPLOAD_HOST } from '../constants';
+import { getNormalizedUrlTemplate } from '../resolvers/utils';
export let UserDetail = objectType({
name: 'UserDetail',
definition(t) {
t.int('id');
t.string('username');
- t.string('name', { nullable: true });
+ t.nullable.string('name');
t.string('email');
- t.string('avatarTemplate', (userDetail) => {
- let { avatarTemplate } =
- 'avatarTemplate' in userDetail ? userDetail : { avatarTemplate: '' };
- return avatarTemplate.includes('http')
- ? avatarTemplate
- : PROSE_DISCOURSE_UPLOAD_HOST.concat(avatarTemplate);
+ t.string('avatarTemplate', {
+ resolve: (userDetail) => getNormalizedUrlTemplate(userDetail),
+ sourceType: 'string',
});
- t.string('lastPostedAt', { nullable: true }); // New user doens't have last Posted
- t.string('lastSeenAt', { nullable: true });
+ t.nullable.string('lastPostedAt'); // New user doens't have last Posted
+ t.nullable.string('lastSeenAt');
t.string('createdAt');
- t.string('secondaryEmails', { list: true, nullable: true });
- t.string('unconfirmedEmails', { list: true, nullable: true });
+ t.nullable.list.string('secondaryEmails');
+ t.nullable.list.string('unconfirmedEmails');
t.boolean('ignored');
t.boolean('muted');
t.boolean('canIgnoreUser');
@@ -30,23 +27,23 @@ export let UserDetail = objectType({
t.int('trustLevel');
t.boolean('moderator');
t.boolean('admin');
- t.string('title', { nullable: true });
+ t.nullable.string('title');
t.int('badgeCount');
t.int('timeRead');
t.int('recentTimeRead');
- t.int('primaryGroupId', { nullable: true });
- t.string('primaryGroupName', { nullable: true });
- t.string('primaryGroupFlairUrl', { nullable: true });
- t.string('primaryGroupFlairBgColor', { nullable: true });
- t.string('primaryGroupFlairColor', { nullable: true });
- t.field('featuredTopic', { type: 'UserFeaturedTopic', nullable: true });
- t.string('bioExcerpt', { nullable: true });
- t.string('bioCooked', { nullable: true });
- t.string('bioRaw', { nullable: true });
- t.string('dateOfBirth', { nullable: true });
- t.string('website', { nullable: true });
- t.string('websiteName', { nullable: true });
- t.string('location', { nullable: true });
+ t.nullable.int('primaryGroupId');
+ t.nullable.string('primaryGroupName');
+ t.nullable.string('primaryGroupFlairUrl');
+ t.nullable.string('primaryGroupFlairBgColor');
+ t.nullable.string('primaryGroupFlairColor');
+ t.nullable.field('featuredTopic', { type: 'UserFeaturedTopic' });
+ t.nullable.string('bioExcerpt');
+ t.nullable.string('bioCooked');
+ t.nullable.string('bioRaw');
+ t.nullable.string('dateOfBirth');
+ t.nullable.string('website');
+ t.nullable.string('websiteName');
+ t.nullable.string('location');
t.boolean('canEdit');
t.boolean('canEditUsername');
t.boolean('canEditEmail');
@@ -54,47 +51,40 @@ export let UserDetail = objectType({
t.boolean('canChangeBio');
t.boolean('canChangeLocation');
t.boolean('canChangeWebsite');
- t.int('uploadedAvatarId', { nullable: true });
+ t.nullable.int('uploadedAvatarId');
t.boolean('hasTitleBadges');
t.boolean('secondFactorEnabled');
- t.boolean('secondFactorBackupEnabled', { nullable: true }); // If Admin change it's null
+ t.nullable.boolean('secondFactorBackupEnabled'); // If Admin change it's null
t.int('pendingCount');
t.int('profileViewCount');
t.boolean('canUploadProfileHeader');
t.boolean('canUploadUserCardBackground');
- t.string('locale', { nullable: true });
+ t.nullable.string('locale');
t.int('mailingListPostsPerDay');
- t.int('mutedCategoryIds', { list: true });
- t.int('regularCategoryIds', { list: true });
- t.int('trackedCategoryIds', { list: true });
- t.int('watchedCategoryIds', { list: true });
- t.int('watchedFirstPostCategoryIds', { list: true });
- t.string('watchedTags', { list: true });
- t.string('watchingFirstPostTags', { list: true });
- t.string('trackedTags', { list: true });
- t.string('mutedTags', { list: true });
- t.string('systemAvatarTemplate', (userDetail) => {
- let { systemAvatarTemplate } =
- 'systemAvatarTemplate' in userDetail
- ? userDetail
- : { systemAvatarTemplate: '' };
- return systemAvatarTemplate.includes('http')
- ? systemAvatarTemplate
- : PROSE_DISCOURSE_UPLOAD_HOST.concat(systemAvatarTemplate);
+ t.list.int('mutedCategoryIds');
+ t.list.int('regularCategoryIds');
+ t.list.int('trackedCategoryIds');
+ t.list.int('watchedCategoryIds');
+ t.list.int('watchedFirstPostCategoryIds');
+ t.list.string('watchedTags');
+ t.list.string('watchingFirstPostTags');
+ t.list.string('trackedTags');
+ t.list.string('mutedTags');
+ t.string('systemAvatarTemplate', {
+ resolve: (userDetail) =>
+ getNormalizedUrlTemplate(userDetail, 'systemAvatar'),
});
- t.string('mutedUsernames', { list: true });
- t.string('ignoredUsernames', { list: true });
- t.string('allowedPmUsernames', { list: true });
- t.int('featuredUserBadgeIds', { nullable: true, list: true });
- t.field('invitedBy', { type: 'UserIcon', nullable: true });
- t.field('groups', { type: 'Group', list: true });
- t.field('groupUsers', { type: 'GroupUser', list: true });
- t.field('remindersFrequency', {
+ t.list.string('mutedUsernames');
+ t.list.string('ignoredUsernames');
+ t.list.string('allowedPmUsernames');
+ t.nullable.list.int('featuredUserBadgeIds');
+ t.nullable.field('invitedBy', { type: 'UserIcon' });
+ t.list.field('groups', { type: 'Group' });
+ t.list.field('groupUsers', { type: 'GroupUser' });
+ t.nullable.list.field('remindersFrequency', {
type: 'RemindersFrequency',
- list: true,
- nullable: true,
});
- t.field('userAuthTokens', { type: 'UserAuthToken', list: true });
+ t.list.field('userAuthTokens', { type: 'UserAuthToken' });
t.field('userOption', { type: 'UserOption' });
},
});
diff --git a/api/src/typeSchemas/UserFeaturedTopic.ts b/api/src/typeSchemas/UserFeaturedTopic.ts
index 95ebbce3..8015cde8 100644
--- a/api/src/typeSchemas/UserFeaturedTopic.ts
+++ b/api/src/typeSchemas/UserFeaturedTopic.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let UserFeaturedTopic = objectType({
name: 'UserFeaturedTopic',
@@ -6,11 +6,11 @@ export let UserFeaturedTopic = objectType({
t.int('id');
t.int('userId');
t.int('lastPostUserId');
- t.int('featuredUser1Id', { nullable: true });
- t.int('featuredUser2Id', { nullable: true });
- t.int('featuredUser3Id', { nullable: true });
- t.int('featuredUser4Id', { nullable: true });
- t.int('deletedById', { nullable: true });
+ t.nullable.int('featuredUser1Id');
+ t.nullable.int('featuredUser2Id');
+ t.nullable.int('featuredUser3Id');
+ t.nullable.int('featuredUser4Id');
+ t.nullable.int('deletedById');
t.string('title');
t.string('fancyTitle');
t.string('slug');
@@ -19,12 +19,12 @@ export let UserFeaturedTopic = objectType({
t.int('highestPostNumber');
t.string('createdAt');
t.string('lastPostedAt');
- t.string('updatedAt', { nullable: true });
+ t.nullable.string('updatedAt');
t.string('bumpedAt');
t.string('archetype');
- t.string('pinnedAt', { nullable: true });
- t.string('pinnedUntil', { nullable: true });
- t.string('excerpt', { nullable: true }); // Must be activated
+ t.nullable.string('pinnedAt');
+ t.nullable.string('pinnedUntil');
+ t.nullable.string('excerpt'); // Must be activated
t.boolean('visible');
t.boolean('closed');
t.boolean('archived');
@@ -40,7 +40,7 @@ export let UserFeaturedTopic = objectType({
t.float('score');
t.float('reviewableScore');
t.float('percentRank');
- t.int('categoryId', { nullable: true });
+ t.nullable.int('categoryId');
t.boolean('pinnedGlobally');
},
});
diff --git a/api/src/typeSchemas/UserIcon.ts b/api/src/typeSchemas/UserIcon.ts
index d73c1fe2..edca4e70 100644
--- a/api/src/typeSchemas/UserIcon.ts
+++ b/api/src/typeSchemas/UserIcon.ts
@@ -1,19 +1,16 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
-import { PROSE_DISCOURSE_UPLOAD_HOST } from '../constants';
+import { getNormalizedUrlTemplate } from '../resolvers/utils';
export let UserIcon = objectType({
name: 'UserIcon',
definition(t) {
t.int('id');
t.string('username');
- t.string('name', { nullable: true });
- t.string('avatarTemplate', (userIcon) => {
- let { avatarTemplate } =
- 'avatarTemplate' in userIcon ? userIcon : { avatarTemplate: '' };
- return avatarTemplate.includes('http')
- ? avatarTemplate
- : PROSE_DISCOURSE_UPLOAD_HOST.concat(avatarTemplate);
+ t.nullable.string('name');
+ t.string('avatarTemplate', {
+ resolve: (userIcon) => getNormalizedUrlTemplate(userIcon),
+ sourceType: 'string',
});
},
});
diff --git a/api/src/typeSchemas/UserIconStatus.ts b/api/src/typeSchemas/UserIconStatus.ts
index 6da5765d..079f9f93 100644
--- a/api/src/typeSchemas/UserIconStatus.ts
+++ b/api/src/typeSchemas/UserIconStatus.ts
@@ -1,21 +1,16 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
-import { PROSE_DISCOURSE_UPLOAD_HOST } from '../constants';
+import { getNormalizedUrlTemplate } from '../resolvers/utils';
export let UserIconStatus = objectType({
name: 'UserIconStatus',
definition(t) {
t.int('id');
t.string('username');
- t.string('name', { nullable: true });
- t.string('avatarTemplate', (userIconStatus) => {
- let { avatarTemplate } =
- 'avatarTemplate' in userIconStatus
- ? userIconStatus
- : { avatarTemplate: '' };
- return avatarTemplate.includes('http')
- ? avatarTemplate
- : PROSE_DISCOURSE_UPLOAD_HOST.concat(avatarTemplate);
+ t.nullable.string('name');
+ t.string('avatarTemplate', {
+ resolve: (userIconStatus) => getNormalizedUrlTemplate(userIconStatus),
+ sourceType: 'string',
});
t.boolean('moderator');
t.boolean('admin');
diff --git a/api/src/typeSchemas/UserLite.ts b/api/src/typeSchemas/UserLite.ts
index d59d9e7d..a7ee3e13 100644
--- a/api/src/typeSchemas/UserLite.ts
+++ b/api/src/typeSchemas/UserLite.ts
@@ -1,22 +1,23 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
-import { PROSE_DISCOURSE_UPLOAD_HOST } from '../constants';
+import { getNormalizedUrlTemplate } from '../resolvers/utils';
export let UserLite = objectType({
name: 'UserLite',
definition(t) {
t.int('id');
t.string('username');
- t.string('name', { nullable: true });
- t.string('avatarTemplate', (userLite) => {
- let { avatarTemplate } =
- 'avatarTemplate' in userLite ? userLite : { avatarTemplate: '' };
- return avatarTemplate.includes('http')
- ? avatarTemplate
- : PROSE_DISCOURSE_UPLOAD_HOST.concat(avatarTemplate);
+ t.nullable.string('name');
+ t.string('avatarTemplate', {
+ resolve: (userLite) => getNormalizedUrlTemplate(userLite),
+ sourceType: 'string',
});
- t.string('lastPostedAt', { nullable: true }); // New user doens't have last Posted
- t.string('lastSeenAt', { nullable: true }); // New user doens't have last Posted
+
+ // The following 2 fields aren't present for new users, because the user
+ // won't have posted anything yet to have "last posted" fields.
+ t.nullable.string('lastPostedAt');
+ t.nullable.string('lastSeenAt');
+
t.string('createdAt');
t.boolean('ignored');
t.boolean('muted');
@@ -27,41 +28,41 @@ export let UserLite = objectType({
t.int('trustLevel');
t.boolean('moderator');
t.boolean('admin');
- t.string('title', { nullable: true });
+ t.nullable.string('title');
t.int('badgeCount');
t.int('timeRead');
t.int('recentTimeRead');
- t.int('primaryGroupId', { nullable: true });
- t.string('primaryGroupName', { nullable: true });
- t.string('primaryGroupFlairUrl', { nullable: true });
- t.string('primaryGroupFlairBgColor', { nullable: true });
- t.string('primaryGroupFlairColor', { nullable: true });
- t.field('featuredTopic', { type: 'UserFeaturedTopic', nullable: true });
- t.string('bioRaw', { nullable: true });
- t.string('bioExcerpt', { nullable: true });
- t.string('bioCooked', { nullable: true });
- t.string('website', { nullable: true });
- t.string('websiteName', { nullable: true });
- t.string('location', { nullable: true });
+ t.nullable.int('primaryGroupId');
+ t.nullable.string('primaryGroupName');
+ t.nullable.string('primaryGroupFlairUrl');
+ t.nullable.string('primaryGroupFlairBgColor');
+ t.nullable.string('primaryGroupFlairColor');
+ t.nullable.field('featuredTopic', { type: 'UserFeaturedTopic' });
+ t.nullable.string('bioRaw');
+ t.nullable.string('bioExcerpt');
+ t.nullable.string('bioCooked');
+ t.nullable.string('website');
+ t.nullable.string('websiteName');
+ t.nullable.string('location');
t.boolean('canEdit');
t.boolean('canEditUsername');
t.boolean('canEditEmail');
t.boolean('canEditName');
- t.int('uploadedAvatarId', { nullable: true });
+ t.nullable.int('uploadedAvatarId');
t.int('pendingCount');
t.int('profileViewCount');
t.boolean('canUploadProfileHeader');
t.boolean('canUploadUserCardBackground');
t.int('mailingListPostsPerDay');
- t.string('dateOfBirth', { nullable: true });
- t.int('featuredUserBadgeIds', { nullable: true, list: true });
- t.field('invitedBy', { type: 'UserIcon', nullable: true });
- t.field('groups', { type: 'Group', list: true });
- t.field('remindersFrequency', {
+ t.nullable.string('dateOfBirth');
+ t.nullable.list.int('featuredUserBadgeIds');
+ t.nullable.field('invitedBy', { type: 'UserIcon' });
+ t.list.field('groups', { type: 'Group' });
+
+ // Nullable because a user from the login endpoint won't have this set.
+ t.nullable.list.field('remindersFrequency', {
type: 'RemindersFrequency',
- list: true,
- nullable: true,
- }); // User from login endpoint doesn't have this
+ });
},
});
/**
diff --git a/api/src/typeSchemas/UserOption.ts b/api/src/typeSchemas/UserOption.ts
index 4691d2a4..a215af33 100644
--- a/api/src/typeSchemas/UserOption.ts
+++ b/api/src/typeSchemas/UserOption.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let UserOption = objectType({
name: 'UserOption',
@@ -22,7 +22,7 @@ export let UserOption = objectType({
t.boolean('emailInReplyTo');
t.int('likeNotificationFrequency');
t.boolean('includeTl0InDigests');
- t.int('themeIds', { list: true });
+ t.list.int('themeIds');
t.int('themeKeySeq');
t.boolean('allowPrivateMessages');
t.boolean('enableAllowedPmUsers');
diff --git a/api/src/typeSchemas/UserOptions.ts b/api/src/typeSchemas/UserOptions.ts
index eaab4627..eee96e14 100644
--- a/api/src/typeSchemas/UserOptions.ts
+++ b/api/src/typeSchemas/UserOptions.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let UserOptions = objectType({
name: 'UserOptions',
@@ -6,8 +6,8 @@ export let UserOptions = objectType({
t.boolean('allowPrivateMessages');
t.int('autoTrackTopicsAfterMsecs');
t.boolean('automaticallyUnpinTopics');
- t.int('colorSchemeId', { nullable: true });
- t.int('darkSchemeId', { nullable: true });
+ t.nullable.int('colorSchemeId');
+ t.nullable.int('darkSchemeId');
t.int('digestAfterMinutes');
t.boolean('dynamicFavicon');
t.boolean('emailDigests');
@@ -20,7 +20,7 @@ export let UserOptions = objectType({
t.boolean('enableQuoting');
t.boolean('externalLinksInNewTab');
t.boolean('hideProfileAndPresence');
- t.int('homepageId', { nullable: true });
+ t.nullable.int('homepageId');
t.boolean('includeTl0InDigests');
t.int('likeNotificationFrequency');
t.boolean('mailingListMode');
diff --git a/api/src/typeSchemas/UserProfileOutput.ts b/api/src/typeSchemas/UserProfileOutput.ts
index 831e9a14..da2df7d6 100644
--- a/api/src/typeSchemas/UserProfileOutput.ts
+++ b/api/src/typeSchemas/UserProfileOutput.ts
@@ -1,13 +1,13 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let UserProfileOutput = objectType({
name: 'UserProfileOutput',
definition(t) {
- t.field('userBadges', { type: 'UserBadge', list: true });
- t.field('badges', { type: 'Badge', list: true, nullable: true });
- t.field('badgeTypes', { type: 'BadgeType', list: true, nullable: true });
- t.field('users', { type: 'UserIconStatus', list: true, nullable: true });
- t.field('topics', { type: 'UserTopic', list: true, nullable: true });
+ t.list.field('userBadges', { type: 'UserBadge' });
+ t.nullable.list.field('badges', { type: 'Badge' });
+ t.nullable.list.field('badgeTypes', { type: 'BadgeType' });
+ t.nullable.list.field('users', { type: 'UserIconStatus' });
+ t.nullable.list.field('topics', { type: 'UserTopic' });
t.field('user', { type: 'UserUnion' });
t.boolean('unreadNotification');
},
diff --git a/api/src/typeSchemas/UserTopic.ts b/api/src/typeSchemas/UserTopic.ts
index 0593ad82..efeec11a 100644
--- a/api/src/typeSchemas/UserTopic.ts
+++ b/api/src/typeSchemas/UserTopic.ts
@@ -1,4 +1,4 @@
-import { objectType } from '@nexus/schema';
+import { objectType } from 'nexus';
export let UserTopic = objectType({
name: 'UserTopic',
diff --git a/api/src/typeSchemas/index.ts b/api/src/typeSchemas/index.ts
index 5e4b838d..b74a318e 100644
--- a/api/src/typeSchemas/index.ts
+++ b/api/src/typeSchemas/index.ts
@@ -22,6 +22,7 @@ export * from './GroupedSearchResult';
export * from './GroupUser';
export * from './GroupUsers';
export * from './InviteeAccept';
+export * from './LikedTopic';
export * from './LinkCount';
export * from './LoginOutput';
export * from './LookupUrl';
@@ -33,7 +34,9 @@ export * from './Post';
export * from './PostInput';
export * from './PostRaw';
export * from './PostStream';
+export * from './PrivateMessageDetailOutput';
export * from './PrivateMessageOutput';
+export * from './PrivateMessagePostStream';
export * from './RefreshTokenOutput';
export * from './RegisterInput';
export * from './RegisterOutput';
@@ -71,3 +74,4 @@ export * from './UserOption';
export * from './UserOptions';
export * from './UserProfileOutput';
export * from './UserTopic';
+export * from './HealthCheck';
diff --git a/api/src/types/dataTypes.ts b/api/src/types/dataTypes.ts
index 0137dcaf..ba424541 100644
--- a/api/src/types/dataTypes.ts
+++ b/api/src/types/dataTypes.ts
@@ -1,16 +1,44 @@
-export type UserIcon = {
+import { z } from 'zod';
+
+export type LikedTopic = {
id: number;
- username: string;
- name?: string | null;
- avatarTemplate: string;
+ topicId: number;
+ postId: number;
+ likeCount: number;
+ liked: boolean;
};
-type TopicPoster = {
- extras?: string | null;
- description: string;
- userId?: number | null;
- user: UserIcon;
-};
+export const MostRecentPoster = z.literal('MostRecentPoster');
+export const OriginalPoster = z.literal('OriginalPoster');
+export const FrequentPoster = z.literal('FrequentPoster');
+export const UnknownPosterType = z.literal('UnknownPosterType');
+export const PosterType = z.union([
+ FrequentPoster,
+ MostRecentPoster,
+ OriginalPoster,
+ UnknownPosterType,
+]);
+export type PosterType = z.infer;
+
+export const UserIcon = z.object({
+ id: z.number(),
+ username: z.string(),
+ name: z.optional(z.nullable(z.string())),
+ avatarTemplate: z.string(),
+});
+
+export type UserIcon = z.infer;
+
+// TODO: #1174: get to the bottom of why we have both `userId` and
+// `user`, and why both can be nullable. Seems we made a mistake somewhere.
+export const TopicPoster = z.object({
+ extras: z.optional(z.nullable(z.string())),
+ description: z.string(),
+ userId: z.optional(z.nullable(z.number())),
+ user: z.optional(z.nullable(UserIcon)),
+});
+
+export type TopicPoster = z.infer;
export type Topic = {
id: number;
@@ -47,7 +75,6 @@ export type Topic = {
pinnedGlobally: boolean | null;
posters: Array;
authorUserId?: number | null;
- frequentPosterUserId?: number | null;
};
type TagFilter = {
@@ -115,3 +142,13 @@ export type UserAction = {
topicId: number;
userId: number;
};
+
+type ActionSummary = {
+ id: number;
+ hidden?: boolean;
+ acted?: boolean;
+ canUndo?: boolean;
+ canAct?: boolean;
+ count?: number;
+};
+export type ActionsSummary = Array;
diff --git a/api/src/types/serverTypes.ts b/api/src/types/serverTypes.ts
index a7489b5f..ba801096 100644
--- a/api/src/types/serverTypes.ts
+++ b/api/src/types/serverTypes.ts
@@ -1,5 +1,6 @@
import { AxiosInstance } from 'axios';
+// eslint-disable-next-line @typescript-eslint/ban-types
export type Root = object | undefined;
export type Context = {
diff --git a/api/tsconfig.json b/api/tsconfig.json
index 2e70bfac..670fe669 100644
--- a/api/tsconfig.json
+++ b/api/tsconfig.json
@@ -7,7 +7,7 @@
"resolveJsonModule": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
- "esModuleInterop": true
+ "esModuleInterop": true,
},
- "include": ["src/**/*"]
+ "include": ["src/**/*", "reset.d.ts"]
}
diff --git a/api/yarn.lock b/api/yarn.lock
index a17c8d45..ab3a11d5 100644
--- a/api/yarn.lock
+++ b/api/yarn.lock
@@ -2,285 +2,473 @@
# yarn lockfile v1
-"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a"
- integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==
+"@ampproject/remapping@^2.1.0":
+ version "2.2.0"
+ resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz"
+ integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==
+ dependencies:
+ "@jridgewell/gen-mapping" "^0.1.0"
+ "@jridgewell/trace-mapping" "^0.3.9"
+
+"@babel/code-frame@7.12.11":
+ version "7.12.11"
+ resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz"
+ integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==
dependencies:
"@babel/highlight" "^7.10.4"
-"@babel/core@^7.1.0", "@babel/core@^7.7.5":
- version "7.11.1"
- resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.11.1.tgz#2c55b604e73a40dc21b0e52650b11c65cf276643"
- integrity sha512-XqF7F6FWQdKGGWAzGELL+aCO1p+lRY5Tj5/tbT3St1G8NaH70jhhDIKknIZaDans0OQBG5wRAldROLHSt44BgQ==
- dependencies:
- "@babel/code-frame" "^7.10.4"
- "@babel/generator" "^7.11.0"
- "@babel/helper-module-transforms" "^7.11.0"
- "@babel/helpers" "^7.10.4"
- "@babel/parser" "^7.11.1"
- "@babel/template" "^7.10.4"
- "@babel/traverse" "^7.11.0"
- "@babel/types" "^7.11.0"
+"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.18.6":
+ version "7.18.6"
+ resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz"
+ integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==
+ dependencies:
+ "@babel/highlight" "^7.18.6"
+
+"@babel/compat-data@^7.18.8":
+ version "7.18.13"
+ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.13.tgz"
+ integrity sha512-5yUzC5LqyTFp2HLmDoxGQelcdYgSpP9xsnMWBphAscOdFrHSAVbLNzWiy32sVNDqJRDiJK6klfDnAgu6PAGSHw==
+
+"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.7.5":
+ version "7.18.13"
+ resolved "https://registry.npmjs.org/@babel/core/-/core-7.18.13.tgz"
+ integrity sha512-ZisbOvRRusFktksHSG6pjj1CSvkPkcZq/KHD45LAkVP/oiHJkNBZWfpvlLmX8OtHDG8IuzsFlVRWo08w7Qxn0A==
+ dependencies:
+ "@ampproject/remapping" "^2.1.0"
+ "@babel/code-frame" "^7.18.6"
+ "@babel/generator" "^7.18.13"
+ "@babel/helper-compilation-targets" "^7.18.9"
+ "@babel/helper-module-transforms" "^7.18.9"
+ "@babel/helpers" "^7.18.9"
+ "@babel/parser" "^7.18.13"
+ "@babel/template" "^7.18.10"
+ "@babel/traverse" "^7.18.13"
+ "@babel/types" "^7.18.13"
convert-source-map "^1.7.0"
debug "^4.1.0"
- gensync "^1.0.0-beta.1"
- json5 "^2.1.2"
- lodash "^4.17.19"
- resolve "^1.3.2"
- semver "^5.4.1"
- source-map "^0.5.0"
-
-"@babel/generator@^7.11.0":
- version "7.11.0"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.0.tgz#4b90c78d8c12825024568cbe83ee6c9af193585c"
- integrity sha512-fEm3Uzw7Mc9Xi//qU20cBKatTfs2aOtKqmvy/Vm7RkJEGFQ4xc9myCfbXxqK//ZS8MR/ciOHw6meGASJuKmDfQ==
- dependencies:
- "@babel/types" "^7.11.0"
- jsesc "^2.5.1"
- source-map "^0.5.0"
-
-"@babel/helper-function-name@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a"
- integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==
- dependencies:
- "@babel/helper-get-function-arity" "^7.10.4"
- "@babel/template" "^7.10.4"
- "@babel/types" "^7.10.4"
-
-"@babel/helper-get-function-arity@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2"
- integrity sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==
- dependencies:
- "@babel/types" "^7.10.4"
-
-"@babel/helper-member-expression-to-functions@^7.10.4":
- version "7.11.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz#ae69c83d84ee82f4b42f96e2a09410935a8f26df"
- integrity sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q==
- dependencies:
- "@babel/types" "^7.11.0"
-
-"@babel/helper-module-imports@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620"
- integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==
- dependencies:
- "@babel/types" "^7.10.4"
-
-"@babel/helper-module-transforms@^7.11.0":
- version "7.11.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz#b16f250229e47211abdd84b34b64737c2ab2d359"
- integrity sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg==
- dependencies:
- "@babel/helper-module-imports" "^7.10.4"
- "@babel/helper-replace-supers" "^7.10.4"
- "@babel/helper-simple-access" "^7.10.4"
- "@babel/helper-split-export-declaration" "^7.11.0"
- "@babel/template" "^7.10.4"
- "@babel/types" "^7.11.0"
- lodash "^4.17.19"
-
-"@babel/helper-optimise-call-expression@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673"
- integrity sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==
- dependencies:
- "@babel/types" "^7.10.4"
-
-"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375"
- integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==
-
-"@babel/helper-replace-supers@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz#d585cd9388ea06e6031e4cd44b6713cbead9e6cf"
- integrity sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A==
- dependencies:
- "@babel/helper-member-expression-to-functions" "^7.10.4"
- "@babel/helper-optimise-call-expression" "^7.10.4"
- "@babel/traverse" "^7.10.4"
- "@babel/types" "^7.10.4"
+ gensync "^1.0.0-beta.2"
+ json5 "^2.2.1"
+ semver "^6.3.0"
-"@babel/helper-simple-access@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz#0f5ccda2945277a2a7a2d3a821e15395edcf3461"
- integrity sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw==
+"@babel/generator@^7.18.13":
+ version "7.18.13"
+ resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.18.13.tgz"
+ integrity sha512-CkPg8ySSPuHTYPJYo7IRALdqyjM9HCbt/3uOBEFbzyGVP6Mn8bwFPB0jX6982JVNBlYzM1nnPkfjuXSOPtQeEQ==
dependencies:
- "@babel/template" "^7.10.4"
- "@babel/types" "^7.10.4"
+ "@babel/types" "^7.18.13"
+ "@jridgewell/gen-mapping" "^0.3.2"
+ jsesc "^2.5.1"
-"@babel/helper-split-export-declaration@^7.11.0":
- version "7.11.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f"
- integrity sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==
+"@babel/helper-compilation-targets@^7.18.9":
+ version "7.18.9"
+ resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz"
+ integrity sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==
dependencies:
- "@babel/types" "^7.11.0"
-
-"@babel/helper-validator-identifier@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2"
- integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==
-
-"@babel/helpers@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.10.4.tgz#2abeb0d721aff7c0a97376b9e1f6f65d7a475044"
- integrity sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA==
- dependencies:
- "@babel/template" "^7.10.4"
- "@babel/traverse" "^7.10.4"
- "@babel/types" "^7.10.4"
+ "@babel/compat-data" "^7.18.8"
+ "@babel/helper-validator-option" "^7.18.6"
+ browserslist "^4.20.2"
+ semver "^6.3.0"
-"@babel/highlight@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143"
- integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==
- dependencies:
- "@babel/helper-validator-identifier" "^7.10.4"
+"@babel/helper-environment-visitor@^7.18.9":
+ version "7.18.9"
+ resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz"
+ integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==
+
+"@babel/helper-function-name@^7.18.9":
+ version "7.18.9"
+ resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz"
+ integrity sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==
+ dependencies:
+ "@babel/template" "^7.18.6"
+ "@babel/types" "^7.18.9"
+
+"@babel/helper-hoist-variables@^7.18.6":
+ version "7.18.6"
+ resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz"
+ integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==
+ dependencies:
+ "@babel/types" "^7.18.6"
+
+"@babel/helper-module-imports@^7.18.6":
+ version "7.18.6"
+ resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz"
+ integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==
+ dependencies:
+ "@babel/types" "^7.18.6"
+
+"@babel/helper-module-transforms@^7.18.9":
+ version "7.18.9"
+ resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz"
+ integrity sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==
+ dependencies:
+ "@babel/helper-environment-visitor" "^7.18.9"
+ "@babel/helper-module-imports" "^7.18.6"
+ "@babel/helper-simple-access" "^7.18.6"
+ "@babel/helper-split-export-declaration" "^7.18.6"
+ "@babel/helper-validator-identifier" "^7.18.6"
+ "@babel/template" "^7.18.6"
+ "@babel/traverse" "^7.18.9"
+ "@babel/types" "^7.18.9"
+
+"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0":
+ version "7.18.9"
+ resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz"
+ integrity sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==
+
+"@babel/helper-simple-access@^7.18.6":
+ version "7.18.6"
+ resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz"
+ integrity sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==
+ dependencies:
+ "@babel/types" "^7.18.6"
+
+"@babel/helper-split-export-declaration@^7.18.6":
+ version "7.18.6"
+ resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz"
+ integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==
+ dependencies:
+ "@babel/types" "^7.18.6"
+
+"@babel/helper-string-parser@^7.18.10":
+ version "7.18.10"
+ resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz"
+ integrity sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==
+
+"@babel/helper-validator-identifier@^7.18.6":
+ version "7.18.6"
+ resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz"
+ integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==
+
+"@babel/helper-validator-option@^7.18.6":
+ version "7.18.6"
+ resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz"
+ integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==
+
+"@babel/helpers@^7.18.9":
+ version "7.18.9"
+ resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.9.tgz"
+ integrity sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==
+ dependencies:
+ "@babel/template" "^7.18.6"
+ "@babel/traverse" "^7.18.9"
+ "@babel/types" "^7.18.9"
+
+"@babel/highlight@^7.10.4", "@babel/highlight@^7.18.6":
+ version "7.18.6"
+ resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz"
+ integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.18.6"
chalk "^2.0.0"
js-tokens "^4.0.0"
-"@babel/parser@^7.1.0", "@babel/parser@^7.10.4", "@babel/parser@^7.11.0", "@babel/parser@^7.11.1":
- version "7.11.3"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.3.tgz#9e1eae46738bcd08e23e867bab43e7b95299a8f9"
- integrity sha512-REo8xv7+sDxkKvoxEywIdsNFiZLybwdI7hcT5uEPyQrSMB4YQ973BfC9OOrD/81MaIjh6UxdulIQXkjmiH3PcA==
+"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.10", "@babel/parser@^7.18.13":
+ version "7.18.13"
+ resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.18.13.tgz"
+ integrity sha512-dgXcIfMuQ0kgzLB2b9tRZs7TTFFaGM2AbtA4fJgUUYukzGH4jwsS7hzQHEGs67jdehpm22vkgKwvbU+aEflgwg==
"@babel/plugin-syntax-async-generators@^7.8.4":
version "7.8.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz"
integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
"@babel/plugin-syntax-bigint@^7.8.3":
version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz"
integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
"@babel/plugin-syntax-class-properties@^7.8.3":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz#6644e6a0baa55a61f9e3231f6c9eeb6ee46c124c"
- integrity sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA==
+ version "7.12.13"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz"
+ integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.12.13"
"@babel/plugin-syntax-import-meta@^7.8.3":
version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz"
integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==
dependencies:
"@babel/helper-plugin-utils" "^7.10.4"
"@babel/plugin-syntax-json-strings@^7.8.3":
version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz"
integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
"@babel/plugin-syntax-logical-assignment-operators@^7.8.3":
version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz"
integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==
dependencies:
"@babel/helper-plugin-utils" "^7.10.4"
"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3":
version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz"
integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
"@babel/plugin-syntax-numeric-separator@^7.8.3":
version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz"
integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==
dependencies:
"@babel/helper-plugin-utils" "^7.10.4"
"@babel/plugin-syntax-object-rest-spread@^7.8.3":
version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz"
integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
"@babel/plugin-syntax-optional-catch-binding@^7.8.3":
version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz"
integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
"@babel/plugin-syntax-optional-chaining@^7.8.3":
version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz"
integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
-"@babel/runtime@^7.0.0":
- version "7.11.2"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736"
- integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==
- dependencies:
- regenerator-runtime "^0.13.4"
-
-"@babel/template@^7.10.4", "@babel/template@^7.3.3":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278"
- integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==
- dependencies:
- "@babel/code-frame" "^7.10.4"
- "@babel/parser" "^7.10.4"
- "@babel/types" "^7.10.4"
-
-"@babel/traverse@^7.1.0", "@babel/traverse@^7.10.4", "@babel/traverse@^7.11.0":
- version "7.11.0"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.11.0.tgz#9b996ce1b98f53f7c3e4175115605d56ed07dd24"
- integrity sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg==
- dependencies:
- "@babel/code-frame" "^7.10.4"
- "@babel/generator" "^7.11.0"
- "@babel/helper-function-name" "^7.10.4"
- "@babel/helper-split-export-declaration" "^7.11.0"
- "@babel/parser" "^7.11.0"
- "@babel/types" "^7.11.0"
+"@babel/plugin-syntax-top-level-await@^7.8.3":
+ version "7.14.5"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz"
+ integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.14.5"
+
+"@babel/template@^7.18.10", "@babel/template@^7.18.6", "@babel/template@^7.3.3":
+ version "7.18.10"
+ resolved "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz"
+ integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==
+ dependencies:
+ "@babel/code-frame" "^7.18.6"
+ "@babel/parser" "^7.18.10"
+ "@babel/types" "^7.18.10"
+
+"@babel/traverse@^7.1.0", "@babel/traverse@^7.18.13", "@babel/traverse@^7.18.9", "@babel/traverse@^7.7.4":
+ version "7.18.13"
+ resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.13.tgz"
+ integrity sha512-N6kt9X1jRMLPxxxPYWi7tgvJRH/rtoU+dbKAPDM44RFHiMH8igdsaSBgFeskhSl/kLWLDUvIh1RXCrTmg0/zvA==
+ dependencies:
+ "@babel/code-frame" "^7.18.6"
+ "@babel/generator" "^7.18.13"
+ "@babel/helper-environment-visitor" "^7.18.9"
+ "@babel/helper-function-name" "^7.18.9"
+ "@babel/helper-hoist-variables" "^7.18.6"
+ "@babel/helper-split-export-declaration" "^7.18.6"
+ "@babel/parser" "^7.18.13"
+ "@babel/types" "^7.18.13"
debug "^4.1.0"
globals "^11.1.0"
- lodash "^4.17.19"
-"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.11.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3":
- version "7.11.0"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.0.tgz#2ae6bf1ba9ae8c3c43824e5861269871b206e90d"
- integrity sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==
+"@babel/types@^7.0.0", "@babel/types@^7.18.10", "@babel/types@^7.18.13", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.3.0", "@babel/types@^7.3.3":
+ version "7.18.13"
+ resolved "https://registry.npmjs.org/@babel/types/-/types-7.18.13.tgz"
+ integrity sha512-ePqfTihzW0W6XAU+aMw2ykilisStJfDnsejDCXRchCcMJ4O0+8DhPXf2YUbZ6wjBlsEmZwLK/sPweWtu8hcJYQ==
dependencies:
- "@babel/helper-validator-identifier" "^7.10.4"
- lodash "^4.17.19"
+ "@babel/helper-string-parser" "^7.18.10"
+ "@babel/helper-validator-identifier" "^7.18.6"
to-fast-properties "^2.0.0"
"@bcoe/v8-coverage@^0.2.3":
version "0.2.3"
- resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
+ resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
"@cnakazawa/watch@^1.0.3":
version "1.0.4"
- resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a"
+ resolved "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz"
integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==
dependencies:
exec-sh "^0.3.2"
minimist "^1.2.0"
+"@colors/colors@1.5.0":
+ version "1.5.0"
+ resolved "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz"
+ integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
+
+"@dabh/diagnostics@^2.0.2":
+ version "2.0.3"
+ resolved "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz"
+ integrity sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==
+ dependencies:
+ colorspace "1.1.x"
+ enabled "2.0.x"
+ kuler "^2.0.0"
+
+"@envelop/core@^1.0.3":
+ version "1.7.1"
+ resolved "https://registry.npmjs.org/@envelop/core/-/core-1.7.1.tgz"
+ integrity sha512-ZxeQs4G0FOzoFAH+zskubx5aM9kx6BiUvcSI9Lo3MfYBmnK7cjwcwDdwk6Mq48QDuAeVdGfDmQz+BiWg0k2GmQ==
+ dependencies:
+ "@envelop/types" "1.5.1"
+
+"@envelop/core@^2.5.0":
+ version "2.5.0"
+ resolved "https://registry.npmjs.org/@envelop/core/-/core-2.5.0.tgz"
+ integrity sha512-nlDC9q75bjvS/ajbkkVlwGPSYlWhZOQ6StxMTEjvUVefL4o49NpMlGgxfN2mJ64y1CJ3MI/bIemZ3jOHmiv3Og==
+ dependencies:
+ "@envelop/types" "2.3.1"
+
+"@envelop/parser-cache@^4.6.0":
+ version "4.6.0"
+ resolved "https://registry.npmjs.org/@envelop/parser-cache/-/parser-cache-4.6.0.tgz"
+ integrity sha512-Oi3nX76tk5L7K6MdpPr4AjtpMW1XoyISeiaodYD8WxUWY7JzOA7qetuYguUZv/lK5VaLMsJuoWAwxbu1JKEe9A==
+ dependencies:
+ lru-cache "^6.0.0"
+
+"@envelop/types@1.5.1":
+ version "1.5.1"
+ resolved "https://registry.npmjs.org/@envelop/types/-/types-1.5.1.tgz"
+ integrity sha512-NrwLVzyNqiSzgRRqOxkU2IgRc5hSGS73VsgxqchU3jl36rYo7AXVAnITkytmB9wk+jN2vUOVvayLkaTXooARwg==
+
+"@envelop/types@2.3.1":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@envelop/types/-/types-2.3.1.tgz"
+ integrity sha512-c5VLCVVRJ2R9LpDHg/N2BO2l4veaJhklquW+FX8GfzXU79DPWe8WmX4MbM6ABUZmSLOJkYInifHrnlqAoucxpQ==
+
+"@envelop/validation-cache@^4.6.0":
+ version "4.6.0"
+ resolved "https://registry.npmjs.org/@envelop/validation-cache/-/validation-cache-4.6.0.tgz"
+ integrity sha512-Xn5u/tQHid6GzWDenCJkIn5GsDm2fUCNnAudN1BGjXcRvAEFfTHuchpp1PJxvRAqGdYjznng+NkOcqrP5brQrw==
+ dependencies:
+ lru-cache "^6.0.0"
+
+"@eslint/eslintrc@^0.4.3":
+ version "0.4.3"
+ resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz"
+ integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==
+ dependencies:
+ ajv "^6.12.4"
+ debug "^4.1.1"
+ espree "^7.3.0"
+ globals "^13.9.0"
+ ignore "^4.0.6"
+ import-fresh "^3.2.1"
+ js-yaml "^3.13.1"
+ minimatch "^3.0.4"
+ strip-json-comments "^3.1.1"
+
+"@graphql-authz/core@1.2.1", "@graphql-authz/core@^1.2.1":
+ version "1.2.1"
+ resolved "https://registry.npmjs.org/@graphql-authz/core/-/core-1.2.1.tgz"
+ integrity sha512-OSpYHmYGSN1FWQ9aoa/FIOlX0Gntph1DZfKBBOxKryYSKnVcAcm6X2mjr6kTnEWQ8BAzQDLWuD74AIsJNHqsCA==
+
+"@graphql-authz/envelop-plugin@^1.0.3":
+ version "1.0.3"
+ resolved "https://registry.npmjs.org/@graphql-authz/envelop-plugin/-/envelop-plugin-1.0.3.tgz"
+ integrity sha512-s3MHzuL7pZOCxGyy5ATD70Cb3KRp8xAIXkg73eZmcL7L/FSFHKXFan0rq9NheoxR2db3hjpChLmwIihKLsVH5Q==
+ dependencies:
+ "@graphql-authz/core" "1.2.1"
+
+"@graphql-tools/merge@8.3.3":
+ version "8.3.3"
+ resolved "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.3.3.tgz"
+ integrity sha512-EfULshN2s2s2mhBwbV9WpGnoehRLe7eIMdZrKfHhxlBWOvtNUd3KSCN0PUdAMd7lj1jXUW9KYdn624JrVn6qzg==
+ dependencies:
+ "@graphql-tools/utils" "8.10.0"
+ tslib "^2.4.0"
+
+"@graphql-tools/schema@^9.0.0":
+ version "9.0.1"
+ resolved "https://registry.npmjs.org/@graphql-tools/schema/-/schema-9.0.1.tgz"
+ integrity sha512-Y6apeiBmvXEz082IAuS/ainnEEQrzMECP1MRIV72eo2WPa6ZtLYPycvIbd56Z5uU2LKP4XcWRgK6WUbCyN16Rw==
+ dependencies:
+ "@graphql-tools/merge" "8.3.3"
+ "@graphql-tools/utils" "8.10.0"
+ tslib "^2.4.0"
+ value-or-promise "1.0.11"
+
+"@graphql-tools/utils@8.10.0", "@graphql-tools/utils@^8.8.0":
+ version "8.10.0"
+ resolved "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.10.0.tgz"
+ integrity sha512-yI+V373FdXQbYfqdarehn9vRWDZZYuvyQ/xwiv5ez2BbobHrqsexF7qs56plLRaQ8ESYpVAjMQvJWe9s23O0Jg==
+ dependencies:
+ tslib "^2.4.0"
+
+"@graphql-typed-document-node/core@^3.1.1":
+ version "3.1.1"
+ resolved "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz"
+ integrity sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==
+
+"@graphql-yoga/common@^2.12.8":
+ version "2.12.8"
+ resolved "https://registry.npmjs.org/@graphql-yoga/common/-/common-2.12.8.tgz"
+ integrity sha512-c/dd/c9mX/A1chA2N7I/bWIf7LrZGPJbCjMUyq35cXZ2xLWaXs6d1aDS4qbsJjb6JplBu6KX6HAZTFY06UJ7ow==
+ dependencies:
+ "@envelop/core" "^2.5.0"
+ "@envelop/parser-cache" "^4.6.0"
+ "@envelop/validation-cache" "^4.6.0"
+ "@graphql-tools/schema" "^9.0.0"
+ "@graphql-tools/utils" "^8.8.0"
+ "@graphql-typed-document-node/core" "^3.1.1"
+ "@graphql-yoga/subscription" "^2.2.3"
+ "@whatwg-node/fetch" "^0.2.6"
+ dset "^3.1.1"
+ tslib "^2.3.1"
+
+"@graphql-yoga/node@^2.13.8":
+ version "2.13.9"
+ resolved "https://registry.npmjs.org/@graphql-yoga/node/-/node-2.13.9.tgz"
+ integrity sha512-3UWG7ueHherpdPOMYX6kHXh/nzJZQHfRUeeipI7Ig/HS9DYEJlSHyg0RRkTMIa0GkB2sAvAzRWDIQSORhnjZ/g==
+ dependencies:
+ "@envelop/core" "^2.5.0"
+ "@graphql-tools/utils" "^8.8.0"
+ "@graphql-yoga/common" "^2.12.8"
+ "@graphql-yoga/subscription" "^2.2.3"
+ "@whatwg-node/fetch" "^0.2.6"
+ tslib "^2.3.1"
+
+"@graphql-yoga/subscription@^2.2.3":
+ version "2.2.3"
+ resolved "https://registry.npmjs.org/@graphql-yoga/subscription/-/subscription-2.2.3.tgz"
+ integrity sha512-It/Dfh+nW2ClTtmOylAa+o7fbKIRYRTH6jfKLj3YB75tkv/rFZ70bjlChDCrEMa46I+zDMg7+cdkrQOXov2fDg==
+ dependencies:
+ "@graphql-yoga/typed-event-target" "^0.1.1"
+ "@repeaterjs/repeater" "^3.0.4"
+ tslib "^2.3.1"
+
+"@graphql-yoga/typed-event-target@^0.1.1":
+ version "0.1.1"
+ resolved "https://registry.npmjs.org/@graphql-yoga/typed-event-target/-/typed-event-target-0.1.1.tgz"
+ integrity sha512-l23kLKHKhfD7jmv4OUlzxMTihSqgIjGWCSb0KdlLkeiaF2jjuo8pRhX200hFTrtjRHGSYS1fx2lltK/xWci+vw==
+ dependencies:
+ "@repeaterjs/repeater" "^3.0.4"
+ tslib "^2.3.1"
+
+"@humanwhocodes/config-array@^0.5.0":
+ version "0.5.0"
+ resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz"
+ integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==
+ dependencies:
+ "@humanwhocodes/object-schema" "^1.2.0"
+ debug "^4.1.1"
+ minimatch "^3.0.4"
+
+"@humanwhocodes/object-schema@^1.2.0":
+ version "1.2.1"
+ resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz"
+ integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
+
"@istanbuljs/load-nyc-config@^1.0.0":
version "1.1.0"
- resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
+ resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz"
integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==
dependencies:
camelcase "^5.3.1"
@@ -290,97 +478,97 @@
resolve-from "^5.0.0"
"@istanbuljs/schema@^0.1.2":
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd"
- integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==
+ version "0.1.3"
+ resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz"
+ integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==
-"@jest/console@^26.2.0":
- version "26.2.0"
- resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.2.0.tgz#d18f2659b90930e7ec3925fb7209f1ba2cf463f0"
- integrity sha512-mXQfx3nSLwiHm1i7jbu+uvi+vvpVjNGzIQYLCfsat9rapC+MJkS4zBseNrgJE0vU921b3P67bQzhduphjY3Tig==
+"@jest/console@^26.6.2":
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz"
+ integrity sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==
dependencies:
- "@jest/types" "^26.2.0"
+ "@jest/types" "^26.6.2"
"@types/node" "*"
chalk "^4.0.0"
- jest-message-util "^26.2.0"
- jest-util "^26.2.0"
+ jest-message-util "^26.6.2"
+ jest-util "^26.6.2"
slash "^3.0.0"
-"@jest/core@^26.2.2":
- version "26.2.2"
- resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.2.2.tgz#63de01ffce967618003dd7a0164b05c8041b81a9"
- integrity sha512-UwA8gNI8aeV4FHGfGAUfO/DHjrFVvlBravF1Tm9Kt6qFE+6YHR47kFhgdepOFpADEKstyO+MVdPvkV6/dyt9sA==
+"@jest/core@^26.6.3":
+ version "26.6.3"
+ resolved "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz"
+ integrity sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==
dependencies:
- "@jest/console" "^26.2.0"
- "@jest/reporters" "^26.2.2"
- "@jest/test-result" "^26.2.0"
- "@jest/transform" "^26.2.2"
- "@jest/types" "^26.2.0"
+ "@jest/console" "^26.6.2"
+ "@jest/reporters" "^26.6.2"
+ "@jest/test-result" "^26.6.2"
+ "@jest/transform" "^26.6.2"
+ "@jest/types" "^26.6.2"
"@types/node" "*"
ansi-escapes "^4.2.1"
chalk "^4.0.0"
exit "^0.1.2"
graceful-fs "^4.2.4"
- jest-changed-files "^26.2.0"
- jest-config "^26.2.2"
- jest-haste-map "^26.2.2"
- jest-message-util "^26.2.0"
+ jest-changed-files "^26.6.2"
+ jest-config "^26.6.3"
+ jest-haste-map "^26.6.2"
+ jest-message-util "^26.6.2"
jest-regex-util "^26.0.0"
- jest-resolve "^26.2.2"
- jest-resolve-dependencies "^26.2.2"
- jest-runner "^26.2.2"
- jest-runtime "^26.2.2"
- jest-snapshot "^26.2.2"
- jest-util "^26.2.0"
- jest-validate "^26.2.0"
- jest-watcher "^26.2.0"
+ jest-resolve "^26.6.2"
+ jest-resolve-dependencies "^26.6.3"
+ jest-runner "^26.6.3"
+ jest-runtime "^26.6.3"
+ jest-snapshot "^26.6.2"
+ jest-util "^26.6.2"
+ jest-validate "^26.6.2"
+ jest-watcher "^26.6.2"
micromatch "^4.0.2"
p-each-series "^2.1.0"
rimraf "^3.0.0"
slash "^3.0.0"
strip-ansi "^6.0.0"
-"@jest/environment@^26.2.0":
- version "26.2.0"
- resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.2.0.tgz#f6faee1630fcc2fad208953164bccb31dbe0e45f"
- integrity sha512-oCgp9NmEiJ5rbq9VI/v/yYLDpladAAVvFxZgNsnJxOETuzPZ0ZcKKHYjKYwCtPOP1WCrM5nmyuOhMStXFGHn+g==
+"@jest/environment@^26.6.2":
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz"
+ integrity sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==
dependencies:
- "@jest/fake-timers" "^26.2.0"
- "@jest/types" "^26.2.0"
+ "@jest/fake-timers" "^26.6.2"
+ "@jest/types" "^26.6.2"
"@types/node" "*"
- jest-mock "^26.2.0"
+ jest-mock "^26.6.2"
-"@jest/fake-timers@^26.2.0":
- version "26.2.0"
- resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.2.0.tgz#b485c57dc4c74d61406a339807a9af4bac74b75a"
- integrity sha512-45Gfe7YzYTKqTayBrEdAF0qYyAsNRBzfkV0IyVUm3cx7AsCWlnjilBM4T40w7IXT5VspOgMPikQlV0M6gHwy/g==
+"@jest/fake-timers@^26.6.2":
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz"
+ integrity sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==
dependencies:
- "@jest/types" "^26.2.0"
+ "@jest/types" "^26.6.2"
"@sinonjs/fake-timers" "^6.0.1"
"@types/node" "*"
- jest-message-util "^26.2.0"
- jest-mock "^26.2.0"
- jest-util "^26.2.0"
+ jest-message-util "^26.6.2"
+ jest-mock "^26.6.2"
+ jest-util "^26.6.2"
-"@jest/globals@^26.2.0":
- version "26.2.0"
- resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.2.0.tgz#ad78f1104f250c1a4bf5184a2ba51facc59b23f6"
- integrity sha512-Hoc6ScEIPaym7RNytIL2ILSUWIGKlwEv+JNFof9dGYOdvPjb2evEURSslvCMkNuNg1ECEClTE8PH7ULlMJntYA==
+"@jest/globals@^26.6.2":
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz"
+ integrity sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==
dependencies:
- "@jest/environment" "^26.2.0"
- "@jest/types" "^26.2.0"
- expect "^26.2.0"
+ "@jest/environment" "^26.6.2"
+ "@jest/types" "^26.6.2"
+ expect "^26.6.2"
-"@jest/reporters@^26.2.2":
- version "26.2.2"
- resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.2.2.tgz#5a8632ab410f4fc57782bc05dcf115e91818e869"
- integrity sha512-7854GPbdFTAorWVh+RNHyPO9waRIN6TcvCezKVxI1khvFq9YjINTW7J3WU+tbR038Ynn6WjYred6vtT0YmIWVQ==
+"@jest/reporters@^26.6.2":
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz"
+ integrity sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==
dependencies:
"@bcoe/v8-coverage" "^0.2.3"
- "@jest/console" "^26.2.0"
- "@jest/test-result" "^26.2.0"
- "@jest/transform" "^26.2.2"
- "@jest/types" "^26.2.0"
+ "@jest/console" "^26.6.2"
+ "@jest/test-result" "^26.6.2"
+ "@jest/transform" "^26.6.2"
+ "@jest/types" "^26.6.2"
chalk "^4.0.0"
collect-v8-coverage "^1.0.0"
exit "^0.1.2"
@@ -391,133 +579,201 @@
istanbul-lib-report "^3.0.0"
istanbul-lib-source-maps "^4.0.0"
istanbul-reports "^3.0.2"
- jest-haste-map "^26.2.2"
- jest-resolve "^26.2.2"
- jest-util "^26.2.0"
- jest-worker "^26.2.1"
+ jest-haste-map "^26.6.2"
+ jest-resolve "^26.6.2"
+ jest-util "^26.6.2"
+ jest-worker "^26.6.2"
slash "^3.0.0"
source-map "^0.6.0"
string-length "^4.0.1"
terminal-link "^2.0.0"
- v8-to-istanbul "^4.1.3"
+ v8-to-istanbul "^7.0.0"
optionalDependencies:
- node-notifier "^7.0.0"
+ node-notifier "^8.0.0"
-"@jest/source-map@^26.1.0":
- version "26.1.0"
- resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.1.0.tgz#a6a020d00e7d9478f4b690167c5e8b77e63adb26"
- integrity sha512-XYRPYx4eEVX15cMT9mstnO7hkHP3krNtKfxUYd8L7gbtia8JvZZ6bMzSwa6IQJENbudTwKMw5R1BePRD+bkEmA==
+"@jest/source-map@^26.6.2":
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz"
+ integrity sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==
dependencies:
callsites "^3.0.0"
graceful-fs "^4.2.4"
source-map "^0.6.0"
-"@jest/test-result@^26.2.0":
- version "26.2.0"
- resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.2.0.tgz#51c9b165c8851cfcf7a3466019114785e154f76b"
- integrity sha512-kgPlmcVafpmfyQEu36HClK+CWI6wIaAWDHNxfQtGuKsgoa2uQAYdlxjMDBEa3CvI40+2U3v36gQF6oZBkoKatw==
+"@jest/test-result@^26.6.2":
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz"
+ integrity sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==
dependencies:
- "@jest/console" "^26.2.0"
- "@jest/types" "^26.2.0"
+ "@jest/console" "^26.6.2"
+ "@jest/types" "^26.6.2"
"@types/istanbul-lib-coverage" "^2.0.0"
collect-v8-coverage "^1.0.0"
-"@jest/test-sequencer@^26.2.2":
- version "26.2.2"
- resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.2.2.tgz#5e8091f2e6c61fdf242af566cb820a4eadc6c4af"
- integrity sha512-SliZWon5LNqV/lVXkeowSU6L8++FGOu3f43T01L1Gv6wnFDP00ER0utV9jyK9dVNdXqfMNCN66sfcyar/o7BNw==
+"@jest/test-sequencer@^26.6.3":
+ version "26.6.3"
+ resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz"
+ integrity sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==
dependencies:
- "@jest/test-result" "^26.2.0"
+ "@jest/test-result" "^26.6.2"
graceful-fs "^4.2.4"
- jest-haste-map "^26.2.2"
- jest-runner "^26.2.2"
- jest-runtime "^26.2.2"
+ jest-haste-map "^26.6.2"
+ jest-runner "^26.6.3"
+ jest-runtime "^26.6.3"
-"@jest/transform@^26.2.2":
- version "26.2.2"
- resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.2.2.tgz#86c005c8d5d749ac54d8df53ea58675fffe7a97e"
- integrity sha512-c1snhvi5wRVre1XyoO3Eef5SEWpuBCH/cEbntBUd9tI5sNYiBDmO0My/lc5IuuGYKp/HFIHV1eZpSx5yjdkhKw==
+"@jest/transform@^26.6.2":
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz"
+ integrity sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==
dependencies:
"@babel/core" "^7.1.0"
- "@jest/types" "^26.2.0"
+ "@jest/types" "^26.6.2"
babel-plugin-istanbul "^6.0.0"
chalk "^4.0.0"
convert-source-map "^1.4.0"
fast-json-stable-stringify "^2.0.0"
graceful-fs "^4.2.4"
- jest-haste-map "^26.2.2"
+ jest-haste-map "^26.6.2"
jest-regex-util "^26.0.0"
- jest-util "^26.2.0"
+ jest-util "^26.6.2"
micromatch "^4.0.2"
pirates "^4.0.1"
slash "^3.0.0"
source-map "^0.6.1"
write-file-atomic "^3.0.0"
-"@jest/types@^25.5.0":
- version "25.5.0"
- resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.5.0.tgz#4d6a4793f7b9599fc3680877b856a97dbccf2a9d"
- integrity sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw==
- dependencies:
- "@types/istanbul-lib-coverage" "^2.0.0"
- "@types/istanbul-reports" "^1.1.1"
- "@types/yargs" "^15.0.0"
- chalk "^3.0.0"
-
-"@jest/types@^26.2.0":
- version "26.2.0"
- resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.2.0.tgz#b28ca1fb517a4eb48c0addea7fcd9edc4ab45721"
- integrity sha512-lvm3rJvctxd7+wxKSxxbzpDbr4FXDLaC57WEKdUIZ2cjTYuxYSc0zlyD7Z4Uqr5VdKxRUrtwIkiqBuvgf8uKJA==
+"@jest/types@^26.6.2":
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz"
+ integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==
dependencies:
"@types/istanbul-lib-coverage" "^2.0.0"
- "@types/istanbul-reports" "^1.1.1"
+ "@types/istanbul-reports" "^3.0.0"
"@types/node" "*"
"@types/yargs" "^15.0.0"
chalk "^4.0.0"
-"@nexus/schema@^0.15.0":
- version "0.15.0"
- resolved "https://registry.yarnpkg.com/@nexus/schema/-/schema-0.15.0.tgz#4f444417a1163a09d732e5b3b203f22780f4ae63"
- integrity sha512-Q3JYHlxvQ24z5vGfDbEOT7Q+zIFYvnuPv14jNdQ/KCRk6YQODPD/nSQilfFJW+9CBIhZhWZACjbeALRKFLCwjg==
+"@jridgewell/gen-mapping@^0.1.0":
+ version "0.1.1"
+ resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz"
+ integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==
+ dependencies:
+ "@jridgewell/set-array" "^1.0.0"
+ "@jridgewell/sourcemap-codec" "^1.4.10"
+
+"@jridgewell/gen-mapping@^0.3.2":
+ version "0.3.2"
+ resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz"
+ integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
dependencies:
- iterall "^1.2.2"
- tslib "^1.9.3"
+ "@jridgewell/set-array" "^1.0.1"
+ "@jridgewell/sourcemap-codec" "^1.4.10"
+ "@jridgewell/trace-mapping" "^0.3.9"
+
+"@jridgewell/resolve-uri@^3.0.3":
+ version "3.1.0"
+ resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz"
+ integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
+
+"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1":
+ version "1.1.2"
+ resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz"
+ integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
+
+"@jridgewell/sourcemap-codec@^1.4.10":
+ version "1.4.14"
+ resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz"
+ integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
+
+"@jridgewell/trace-mapping@^0.3.9":
+ version "0.3.15"
+ resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz"
+ integrity sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==
+ dependencies:
+ "@jridgewell/resolve-uri" "^3.0.3"
+ "@jridgewell/sourcemap-codec" "^1.4.10"
+
+"@nodelib/fs.scandir@2.1.5":
+ version "2.1.5"
+ resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz"
+ integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
+ dependencies:
+ "@nodelib/fs.stat" "2.0.5"
+ run-parallel "^1.1.9"
+
+"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
+ version "2.0.5"
+ resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
+ integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
+
+"@nodelib/fs.walk@^1.2.3":
+ version "1.2.8"
+ resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz"
+ integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
+ dependencies:
+ "@nodelib/fs.scandir" "2.1.5"
+ fastq "^1.6.0"
+
+"@peculiar/asn1-schema@^2.1.6":
+ version "2.3.0"
+ resolved "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.0.tgz"
+ integrity sha512-DtNLAG4vmDrdSJFPe7rypkcj597chNQL7u+2dBtYo5mh7VW2+im6ke+O0NVr8W1f4re4C3F71LhoMb0Yxqa48Q==
+ dependencies:
+ asn1js "^3.0.5"
+ pvtsutils "^1.3.2"
+ tslib "^2.4.0"
+
+"@peculiar/json-schema@^1.1.12":
+ version "1.1.12"
+ resolved "https://registry.npmjs.org/@peculiar/json-schema/-/json-schema-1.1.12.tgz"
+ integrity sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==
+ dependencies:
+ tslib "^2.0.0"
+
+"@peculiar/webcrypto@^1.4.0":
+ version "1.4.0"
+ resolved "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.0.tgz"
+ integrity sha512-U58N44b2m3OuTgpmKgf0LPDOmP3bhwNz01vAnj1mBwxBASRhptWYK+M3zG+HBkDqGQM+bFsoIihTW8MdmPXEqg==
+ dependencies:
+ "@peculiar/asn1-schema" "^2.1.6"
+ "@peculiar/json-schema" "^1.1.12"
+ pvtsutils "^1.3.2"
+ tslib "^2.4.0"
+ webcrypto-core "^1.7.4"
+
+"@repeaterjs/repeater@^3.0.4":
+ version "3.0.4"
+ resolved "https://registry.npmjs.org/@repeaterjs/repeater/-/repeater-3.0.4.tgz"
+ integrity sha512-AW8PKd6iX3vAZ0vA43nOUOnbq/X5ihgU+mSXXqunMkeQADGiqw/PY0JNeYtD5sr0PAy51YPgAPbDoeapv9r8WA==
"@sinonjs/commons@^1.7.0":
- version "1.8.1"
- resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.1.tgz#e7df00f98a203324f6dc7cc606cad9d4a8ab2217"
- integrity sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==
+ version "1.8.3"
+ resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz"
+ integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==
dependencies:
type-detect "4.0.8"
"@sinonjs/fake-timers@^6.0.1":
version "6.0.1"
- resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40"
+ resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz"
integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==
dependencies:
"@sinonjs/commons" "^1.7.0"
"@tootallnate/once@1":
version "1.1.2"
- resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
+ resolved "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz"
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
-"@types/accepts@*":
- version "1.3.5"
- resolved "https://registry.yarnpkg.com/@types/accepts/-/accepts-1.3.5.tgz#c34bec115cfc746e04fe5a059df4ce7e7b391575"
- integrity sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==
- dependencies:
- "@types/node" "*"
-
-"@types/aws-lambda@8.10.13":
- version "8.10.13"
- resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.13.tgz#92cc06b1cc88b5d0b327d2671dcf3daea96923a5"
- integrity sha512-a1sC60Bqll4N2RYnd4+XuynrVd8LO+uZrgwCVaAER0ldMQ00LRM4iTjU2ulPoQF6P5bHZK5hL/6IF9088VJhUA==
+"@total-typescript/ts-reset@^0.4.2":
+ version "0.4.2"
+ resolved "https://registry.npmjs.org/@total-typescript/ts-reset/-/ts-reset-0.4.2.tgz"
+ integrity sha512-vqd7ZUDSrXFVT1n8b2kc3LnklncDQFPvR58yUS1kEP23/nHPAO9l1lMjUfnPrXYYk4Hj54rrLKMW5ipwk7k09A==
"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7":
- version "7.1.9"
- resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.9.tgz#77e59d438522a6fb898fa43dc3455c6e72f3963d"
- integrity sha512-sY2RsIJ5rpER1u3/aQ8OFSI7qGIy8o1NEEbgb2UaJcvOtXOMpd39ko723NBpjQFg9SIX7TXtjejZVGeIMLhoOw==
+ version "7.1.19"
+ resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz"
+ integrity sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==
dependencies:
"@babel/parser" "^7.1.0"
"@babel/types" "^7.0.0"
@@ -526,679 +782,504 @@
"@types/babel__traverse" "*"
"@types/babel__generator@*":
- version "7.6.1"
- resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.1.tgz#4901767b397e8711aeb99df8d396d7ba7b7f0e04"
- integrity sha512-bBKm+2VPJcMRVwNhxKu8W+5/zT7pwNEqeokFOmbvVSqGzFneNxYcEBro9Ac7/N9tlsaPYnZLK8J1LWKkMsLAew==
+ version "7.6.4"
+ resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz"
+ integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==
dependencies:
"@babel/types" "^7.0.0"
"@types/babel__template@*":
- version "7.0.2"
- resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.0.2.tgz#4ff63d6b52eddac1de7b975a5223ed32ecea9307"
- integrity sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==
+ version "7.4.1"
+ resolved "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz"
+ integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==
dependencies:
"@babel/parser" "^7.1.0"
"@babel/types" "^7.0.0"
-"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6":
- version "7.0.13"
- resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.0.13.tgz#1874914be974a492e1b4cb00585cabb274e8ba18"
- integrity sha512-i+zS7t6/s9cdQvbqKDARrcbrPvtJGlbYsMkazo03nTAK3RX9FNrLllXys22uiTGJapPOTZTQ35nHh4ISph4SLQ==
+"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6":
+ version "7.18.0"
+ resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.0.tgz"
+ integrity sha512-v4Vwdko+pgymgS+A2UIaJru93zQd85vIGWObM5ekZNdXCKtDYqATlEYnWgfo86Q6I1Lh0oXnksDnMU1cwmlPDw==
dependencies:
"@babel/types" "^7.3.0"
-"@types/body-parser@*":
- version "1.19.0"
- resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f"
- integrity sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==
- dependencies:
- "@types/connect" "*"
- "@types/node" "*"
-
-"@types/color-name@^1.1.1":
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
- integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==
-
-"@types/connect@*":
- version "3.4.33"
- resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546"
- integrity sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==
- dependencies:
- "@types/node" "*"
-
-"@types/content-disposition@*":
- version "0.5.3"
- resolved "https://registry.yarnpkg.com/@types/content-disposition/-/content-disposition-0.5.3.tgz#0aa116701955c2faa0717fc69cd1596095e49d96"
- integrity sha512-P1bffQfhD3O4LW0ioENXUhZ9OIa0Zn+P7M+pWgkCKaT53wVLSq0mrKksCID/FGHpFhRSxRGhgrQmfhRuzwtKdg==
-
-"@types/cookies@*":
- version "0.7.4"
- resolved "https://registry.yarnpkg.com/@types/cookies/-/cookies-0.7.4.tgz#26dedf791701abc0e36b5b79a5722f40e455f87b"
- integrity sha512-oTGtMzZZAVuEjTwCjIh8T8FrC8n/uwy+PG0yTvQcdZ7etoel7C7/3MSd7qrukENTgQtotG7gvBlBojuVs7X5rw==
- dependencies:
- "@types/connect" "*"
- "@types/express" "*"
- "@types/keygrip" "*"
- "@types/node" "*"
-
-"@types/cors@^2.8.4":
- version "2.8.7"
- resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.7.tgz#ab2f47f1cba93bce27dfd3639b006cc0e5600889"
- integrity sha512-sOdDRU3oRS7LBNTIqwDkPJyq0lpHYcbMTt0TrjzsXbk/e37hcLTH6eZX7CdbDeN0yJJvzw9hFBZkbtCSbk/jAQ==
- dependencies:
- "@types/express" "*"
-
-"@types/eslint-visitor-keys@^1.0.0":
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
- integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==
-
-"@types/express-serve-static-core@*":
- version "4.17.9"
- resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.9.tgz#2d7b34dcfd25ec663c25c85d76608f8b249667f1"
- integrity sha512-DG0BYg6yO+ePW+XoDENYz8zhNGC3jDDEpComMYn7WJc4mY1Us8Rw9ax2YhJXxpyk2SF47PQAoQ0YyVT1a0bEkA==
- dependencies:
- "@types/node" "*"
- "@types/qs" "*"
- "@types/range-parser" "*"
-
-"@types/express@*", "@types/express@^4.11.1":
- version "4.17.7"
- resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.7.tgz#42045be6475636d9801369cd4418ef65cdb0dd59"
- integrity sha512-dCOT5lcmV/uC2J9k0rPafATeeyz+99xTt54ReX11/LObZgfzJqZNcW27zGhYyX+9iSEGXGt5qLPwRSvBZcLvtQ==
- dependencies:
- "@types/body-parser" "*"
- "@types/express-serve-static-core" "*"
- "@types/qs" "*"
- "@types/serve-static" "*"
-
"@types/form-data@^2.5.0":
version "2.5.0"
- resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-2.5.0.tgz#5025f7433016f923348434c40006d9a797c1b0e8"
+ resolved "https://registry.npmjs.org/@types/form-data/-/form-data-2.5.0.tgz"
integrity sha512-23/wYiuckYYtFpL+4RPWiWmRQH2BjFuqCUi2+N3amB1a1Drv+i/byTrGvlLwRVLFNAZbwpbQ7JvTK+VCAPMbcg==
dependencies:
form-data "*"
-"@types/fs-capacitor@*":
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/@types/fs-capacitor/-/fs-capacitor-2.0.0.tgz#17113e25817f584f58100fb7a08eed288b81956e"
- integrity sha512-FKVPOCFbhCvZxpVAMhdBdTfVfXUpsh15wFHgqOKxh9N9vzWZVuWCSijZ5T4U34XYNnuj2oduh6xcs1i+LPI+BQ==
- dependencies:
- "@types/node" "*"
-
"@types/graceful-fs@^4.1.2":
- version "4.1.3"
- resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.3.tgz#039af35fe26bec35003e8d86d2ee9c586354348f"
- integrity sha512-AiHRaEB50LQg0pZmm659vNBb9f4SJ0qrAnteuzhSeAUcJKxoYgEnprg/83kppCnc2zvtCKbdZry1a5pVY3lOTQ==
+ version "4.1.5"
+ resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz"
+ integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==
dependencies:
"@types/node" "*"
-"@types/graphql-deduplicator@^2.0.0":
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/@types/graphql-deduplicator/-/graphql-deduplicator-2.0.0.tgz#9e577b8f3feb3d067b0ca756f4a1fb356d533922"
- integrity sha512-swUwj5hWF1yFzbUXStLJrUa0ksAt11B8+SwhsAjQAX0LYJ1LLioAyuDcJ9bovWbsNzIXJYXLvljSPQw8nR728w==
-
-"@types/graphql-upload@^8.0.3":
- version "8.0.4"
- resolved "https://registry.yarnpkg.com/@types/graphql-upload/-/graphql-upload-8.0.4.tgz#23a8ffb3d2fe6e0ee07e6f16ee9d9d5e995a2f4f"
- integrity sha512-0TRyJD2o8vbkmJF8InppFcPVcXKk+Rvlg/xvpHBIndSJYpmDWfmtx/ZAtl4f3jR2vfarpTqYgj8MZuJssSoU7Q==
- dependencies:
- "@types/express" "*"
- "@types/fs-capacitor" "*"
- "@types/koa" "*"
- graphql "^15.3.0"
-
-"@types/graphql@^14.0.0":
- version "14.5.0"
- resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-14.5.0.tgz#a545fb3bc8013a3547cf2f07f5e13a33642b75d6"
- integrity sha512-MOkzsEp1Jk5bXuAsHsUi6BVv0zCO+7/2PTiZMXWDSsMXvNU6w/PLMQT2vHn8hy2i0JqojPz1Sz6rsFjHtsU0lA==
- dependencies:
- graphql "*"
-
-"@types/http-assert@*":
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/@types/http-assert/-/http-assert-1.5.1.tgz#d775e93630c2469c2f980fc27e3143240335db3b"
- integrity sha512-PGAK759pxyfXE78NbKxyfRcWYA/KwW17X290cNev/qAsn9eQIxkH4shoNBafH37wewhDG/0p1cHPbK6+SzZjWQ==
-
-"@types/http-errors@*":
- version "1.8.0"
- resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-1.8.0.tgz#682477dbbbd07cd032731cb3b0e7eaee3d026b69"
- integrity sha512-2aoSC4UUbHDj2uCsCxcG/vRMXey/m17bC7UwitVm5hn22nI8O8Y9iDpA76Orc+DWkQ4zZrOKEshCqR/jSuXAHA==
-
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762"
- integrity sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==
+ version "2.0.4"
+ resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz"
+ integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==
"@types/istanbul-lib-report@*":
version "3.0.0"
- resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686"
+ resolved "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz"
integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==
dependencies:
"@types/istanbul-lib-coverage" "*"
-"@types/istanbul-reports@^1.1.1":
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz#e875cc689e47bce549ec81f3df5e6f6f11cfaeb2"
- integrity sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==
+"@types/istanbul-reports@^3.0.0":
+ version "3.0.1"
+ resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz"
+ integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==
dependencies:
- "@types/istanbul-lib-coverage" "*"
"@types/istanbul-lib-report" "*"
"@types/jest@^26.0.9":
- version "26.0.9"
- resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.9.tgz#0543b57da5f0cd949c5f423a00c56c492289c989"
- integrity sha512-k4qFfJ5AUKrWok5KYXp2EPm89b0P/KZpl7Vg4XuOTVVQEhLDBDBU3iBFrjjdgd8fLw96aAtmnwhXHl63bWeBQQ==
+ version "26.0.24"
+ resolved "https://registry.npmjs.org/@types/jest/-/jest-26.0.24.tgz"
+ integrity sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w==
dependencies:
- jest-diff "^25.2.1"
- pretty-format "^25.2.1"
+ jest-diff "^26.0.0"
+ pretty-format "^26.0.0"
-"@types/json-schema@^7.0.3":
- version "7.0.5"
- resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd"
- integrity sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==
+"@types/json-schema@^7.0.7":
+ version "7.0.11"
+ resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz"
+ integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==
"@types/json5@^0.0.29":
version "0.0.29"
- resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
- integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
-
-"@types/keygrip@*":
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/@types/keygrip/-/keygrip-1.0.2.tgz#513abfd256d7ad0bf1ee1873606317b33b1b2a72"
- integrity sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw==
-
-"@types/koa-compose@*":
- version "3.2.5"
- resolved "https://registry.yarnpkg.com/@types/koa-compose/-/koa-compose-3.2.5.tgz#85eb2e80ac50be95f37ccf8c407c09bbe3468e9d"
- integrity sha512-B8nG/OoE1ORZqCkBVsup/AKcvjdgoHnfi4pZMn5UwAPCbhk/96xyv284eBYW8JlQbQ7zDmnpFr68I/40mFoIBQ==
- dependencies:
- "@types/koa" "*"
-
-"@types/koa@*":
- version "2.11.4"
- resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.11.4.tgz#8af02a069a9f8e08fa47b8da28d982e652f69cfb"
- integrity sha512-Etqs0kdqbuAsNr5k6mlZQelpZKVwMu9WPRHVVTLnceZlhr0pYmblRNJbCgoCMzKWWePldydU0AYEOX4Q9fnGUQ==
- dependencies:
- "@types/accepts" "*"
- "@types/content-disposition" "*"
- "@types/cookies" "*"
- "@types/http-assert" "*"
- "@types/http-errors" "*"
- "@types/keygrip" "*"
- "@types/koa-compose" "*"
- "@types/node" "*"
+ resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz"
+ integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
-"@types/mime@*":
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.3.tgz#c893b73721db73699943bfc3653b1deb7faa4a3a"
- integrity sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==
+"@types/node@*":
+ version "18.7.13"
+ resolved "https://registry.npmjs.org/@types/node/-/node-18.7.13.tgz"
+ integrity sha512-46yIhxSe5xEaJZXWdIBP7GU4HDTG8/eo0qd9atdiL+lFpA03y8KS+lkTN834TWJj5767GbWv4n/P6efyTFt1Dw==
-"@types/node@*", "@types/node@^14.0.27":
- version "14.0.27"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.27.tgz#a151873af5a5e851b51b3b065c9e63390a9e0eb1"
- integrity sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g==
+"@types/node@^14.0.27":
+ version "14.18.26"
+ resolved "https://registry.npmjs.org/@types/node/-/node-14.18.26.tgz"
+ integrity sha512-0b+utRBSYj8L7XAp0d+DX7lI4cSmowNaaTkk6/1SKzbKkG+doLuPusB9EOvzLJ8ahJSk03bTLIL6cWaEd4dBKA==
"@types/normalize-package-data@^2.4.0":
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
- integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
+ version "2.4.1"
+ resolved "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz"
+ integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==
"@types/prettier@^2.0.0":
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.0.2.tgz#5bb52ee68d0f8efa9cc0099920e56be6cc4e37f3"
- integrity sha512-IkVfat549ggtkZUthUzEX49562eGikhSYeVGX97SkMFn+sTZrgRewXjQ4tPKFPCykZHkX1Zfd9OoELGqKU2jJA==
-
-"@types/qs@*":
- version "6.9.4"
- resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.4.tgz#a59e851c1ba16c0513ea123830dd639a0a15cb6a"
- integrity sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ==
+ version "2.7.0"
+ resolved "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.0.tgz"
+ integrity sha512-RI1L7N4JnW5gQw2spvL7Sllfuf1SaHdrZpCHiBlCXjIlufi1SMNnbu2teze3/QE67Fg2tBlH7W+mi4hVNk4p0A==
-"@types/range-parser@*":
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
- integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==
-
-"@types/serve-static@*":
- version "1.13.5"
- resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.5.tgz#3d25d941a18415d3ab092def846e135a08bbcf53"
- integrity sha512-6M64P58N+OXjU432WoLLBQxbA0LRGBCRm7aAGQJ+SMC1IMl0dgRVi9EFfoDcS2a7Xogygk/eGN94CfwU9UF7UQ==
+"@types/set-cookie-parser@^2.4.2":
+ version "2.4.2"
+ resolved "https://registry.npmjs.org/@types/set-cookie-parser/-/set-cookie-parser-2.4.2.tgz"
+ integrity sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==
dependencies:
- "@types/express-serve-static-core" "*"
- "@types/mime" "*"
+ "@types/node" "*"
-"@types/stack-utils@^1.0.1":
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
- integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==
+"@types/stack-utils@^2.0.0":
+ version "2.0.1"
+ resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz"
+ integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==
"@types/strip-bom@^3.0.0":
version "3.0.0"
- resolved "https://registry.yarnpkg.com/@types/strip-bom/-/strip-bom-3.0.0.tgz#14a8ec3956c2e81edb7520790aecf21c290aebd2"
- integrity sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I=
+ resolved "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz"
+ integrity sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==
"@types/strip-json-comments@0.0.30":
version "0.0.30"
- resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1"
+ resolved "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz"
integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==
"@types/tough-cookie@^4.0.0":
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.0.tgz#fef1904e4668b6e5ecee60c52cc6a078ffa6697d"
- integrity sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==
+ version "4.0.2"
+ resolved "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz"
+ integrity sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==
+
+"@types/triple-beam@^1.3.2":
+ version "1.3.2"
+ resolved "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.2.tgz"
+ integrity sha512-txGIh+0eDFzKGC25zORnswy+br1Ha7hj5cMVwKIU7+s0U2AxxJru/jZSMU6OC9MJWP6+pc/hc6ZjyZShpsyY2g==
"@types/ws@^7.2.6":
- version "7.2.6"
- resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.2.6.tgz#516cbfb818310f87b43940460e065eb912a4178d"
- integrity sha512-Q07IrQUSNpr+cXU4E4LtkSIBPie5GLZyyMC1QtQYRLWz701+XcoVygGUZgvLqElq1nU4ICldMYPnexlBsg3dqQ==
+ version "7.4.7"
+ resolved "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz"
+ integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==
dependencies:
"@types/node" "*"
"@types/yargs-parser@*":
- version "15.0.0"
- resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d"
- integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==
+ version "21.0.0"
+ resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz"
+ integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==
"@types/yargs@^15.0.0":
- version "15.0.5"
- resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.5.tgz#947e9a6561483bdee9adffc983e91a6902af8b79"
- integrity sha512-Dk/IDOPtOgubt/IaevIUbTgV7doaKkoorvOyYM2CMwuDyP89bekI7H4xLIwunNYiK9jhCkmc6pUrJk3cj2AB9w==
+ version "15.0.14"
+ resolved "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz"
+ integrity sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==
dependencies:
"@types/yargs-parser" "*"
-"@types/yup@0.26.23":
- version "0.26.23"
- resolved "https://registry.yarnpkg.com/@types/yup/-/yup-0.26.23.tgz#00721a3b675e7609e5bcccb94234e86b754bcd04"
- integrity sha512-+tipAL6prdInS/avA6QityIFBDvHnqk1Tv9L5JMEws5IZC6agymBGAoDsrPyYp42wGcktyQtYKv9kvGPEKd4Qg==
-
-"@types/zen-observable@^0.5.3":
- version "0.5.4"
- resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.5.4.tgz#b863a4191e525206819e008097ebf0fb2e3a1cdc"
- integrity sha512-sW6xN96wUak4tgc89d0tbTg7QDGYhGv5hvQIS6h4mRCd8h2btiZ80loPU8cyLwsBbA4ZeQt0FjvUhJ4rNhdsGg==
-
-"@typescript-eslint/eslint-plugin@^2.7.0":
- version "2.34.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz#6f8ce8a46c7dea4a6f1d171d2bb8fbae6dac2be9"
- integrity sha512-4zY3Z88rEE99+CNvTbXSyovv2z9PNOVffTWD2W8QF5s2prBQtwN2zadqERcrHpcR7O/+KMI3fcTAmUUhK/iQcQ==
+"@typescript-eslint/eslint-plugin@^4.28.2":
+ version "4.33.0"
+ resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz"
+ integrity sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==
dependencies:
- "@typescript-eslint/experimental-utils" "2.34.0"
+ "@typescript-eslint/experimental-utils" "4.33.0"
+ "@typescript-eslint/scope-manager" "4.33.0"
+ debug "^4.3.1"
functional-red-black-tree "^1.0.1"
- regexpp "^3.0.0"
- tsutils "^3.17.1"
-
-"@typescript-eslint/experimental-utils@2.34.0":
- version "2.34.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz#d3524b644cdb40eebceca67f8cf3e4cc9c8f980f"
- integrity sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA==
- dependencies:
- "@types/json-schema" "^7.0.3"
- "@typescript-eslint/typescript-estree" "2.34.0"
- eslint-scope "^5.0.0"
- eslint-utils "^2.0.0"
-
-"@typescript-eslint/parser@^2.7.0":
- version "2.34.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.34.0.tgz#50252630ca319685420e9a39ca05fe185a256bc8"
- integrity sha512-03ilO0ucSD0EPTw2X4PntSIRFtDPWjrVq7C3/Z3VQHRC7+13YB55rcJI3Jt+YgeHbjUdJPcPa7b23rXCBokuyA==
- dependencies:
- "@types/eslint-visitor-keys" "^1.0.0"
- "@typescript-eslint/experimental-utils" "2.34.0"
- "@typescript-eslint/typescript-estree" "2.34.0"
- eslint-visitor-keys "^1.1.0"
-
-"@typescript-eslint/typescript-estree@2.34.0":
- version "2.34.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz#14aeb6353b39ef0732cc7f1b8285294937cf37d5"
- integrity sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg==
- dependencies:
- debug "^4.1.1"
- eslint-visitor-keys "^1.1.0"
- glob "^7.1.6"
+ ignore "^5.1.8"
+ regexpp "^3.1.0"
+ semver "^7.3.5"
+ tsutils "^3.21.0"
+
+"@typescript-eslint/experimental-utils@4.33.0":
+ version "4.33.0"
+ resolved "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz"
+ integrity sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==
+ dependencies:
+ "@types/json-schema" "^7.0.7"
+ "@typescript-eslint/scope-manager" "4.33.0"
+ "@typescript-eslint/types" "4.33.0"
+ "@typescript-eslint/typescript-estree" "4.33.0"
+ eslint-scope "^5.1.1"
+ eslint-utils "^3.0.0"
+
+"@typescript-eslint/parser@^4.28.0":
+ version "4.33.0"
+ resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz"
+ integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==
+ dependencies:
+ "@typescript-eslint/scope-manager" "4.33.0"
+ "@typescript-eslint/types" "4.33.0"
+ "@typescript-eslint/typescript-estree" "4.33.0"
+ debug "^4.3.1"
+
+"@typescript-eslint/scope-manager@4.33.0":
+ version "4.33.0"
+ resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz"
+ integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==
+ dependencies:
+ "@typescript-eslint/types" "4.33.0"
+ "@typescript-eslint/visitor-keys" "4.33.0"
+
+"@typescript-eslint/types@4.33.0":
+ version "4.33.0"
+ resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz"
+ integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==
+
+"@typescript-eslint/typescript-estree@4.33.0":
+ version "4.33.0"
+ resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz"
+ integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==
+ dependencies:
+ "@typescript-eslint/types" "4.33.0"
+ "@typescript-eslint/visitor-keys" "4.33.0"
+ debug "^4.3.1"
+ globby "^11.0.3"
is-glob "^4.0.1"
- lodash "^4.17.15"
- semver "^7.3.2"
- tsutils "^3.17.1"
-
-"@wry/equality@^0.1.2":
- version "0.1.11"
- resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.1.11.tgz#35cb156e4a96695aa81a9ecc4d03787bc17f1790"
- integrity sha512-mwEVBDUVODlsQQ5dfuLUS5/Tf7jqUKyhKYHmVi4fPB6bDMOfWvUPJmKgS1Z7Za/sOI3vzWt4+O7yCiL/70MogA==
- dependencies:
- tslib "^1.9.3"
+ semver "^7.3.5"
+ tsutils "^3.21.0"
+
+"@typescript-eslint/visitor-keys@4.33.0":
+ version "4.33.0"
+ resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz"
+ integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==
+ dependencies:
+ "@typescript-eslint/types" "4.33.0"
+ eslint-visitor-keys "^2.0.0"
+
+"@whatwg-node/fetch@^0.2.6":
+ version "0.2.9"
+ resolved "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.2.9.tgz"
+ integrity sha512-h+ehuqE/ZqJdRy+xywHyKpBIPmST0ms8Itgf4gGSu10pJrmod3/t9DbG/GlATvLBE4pvqYHrxKAKo3NNQVJc3g==
+ dependencies:
+ "@peculiar/webcrypto" "^1.4.0"
+ abort-controller "^3.0.0"
+ busboy "^1.6.0"
+ event-target-polyfill "^0.0.3"
+ form-data-encoder "^1.7.1"
+ formdata-node "^4.3.1"
+ node-fetch "^2.6.7"
+ undici "^5.8.0"
+ web-streams-polyfill "^3.2.0"
abab@^2.0.3, abab@^2.0.5:
version "2.0.6"
- resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291"
+ resolved "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz"
integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==
-accepts@~1.3.7:
- version "1.3.7"
- resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
- integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
+abort-controller@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz"
+ integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==
dependencies:
- mime-types "~2.1.24"
- negotiator "0.6.2"
+ event-target-shim "^5.0.0"
acorn-globals@^6.0.0:
version "6.0.0"
- resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45"
+ resolved "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz"
integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==
dependencies:
acorn "^7.1.1"
acorn-walk "^7.1.1"
-acorn-jsx@^5.2.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe"
- integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==
+acorn-jsx@^5.3.1:
+ version "5.3.2"
+ resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
+ integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
acorn-walk@^7.1.1:
version "7.2.0"
- resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc"
+ resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz"
integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
-acorn@^7.1.1, acorn@^7.3.1:
+acorn@^7.1.1, acorn@^7.4.0:
version "7.4.1"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
+ resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
acorn@^8.2.4:
version "8.8.0"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8"
+ resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz"
integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==
agent-base@6:
version "6.0.2"
- resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
+ resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz"
integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==
dependencies:
debug "4"
-ajv@^6.10.0, ajv@^6.10.2:
- version "6.12.3"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.3.tgz#18c5af38a111ddeb4f2697bd78d68abc1cabd706"
- integrity sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==
+ajv@^6.10.0, ajv@^6.12.4:
+ version "6.12.6"
+ resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz"
+ integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
dependencies:
fast-deep-equal "^3.1.1"
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
+ajv@^8.0.1:
+ version "8.11.0"
+ resolved "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz"
+ integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==
+ dependencies:
+ fast-deep-equal "^3.1.1"
+ json-schema-traverse "^1.0.0"
+ require-from-string "^2.0.2"
+ uri-js "^4.2.2"
+
ansi-colors@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
- integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
+ version "4.1.3"
+ resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz"
+ integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==
ansi-escapes@^4.2.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61"
- integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==
+ version "4.3.2"
+ resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz"
+ integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==
dependencies:
- type-fest "^0.11.0"
-
-ansi-regex@^4.1.0:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed"
- integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==
+ type-fest "^0.21.3"
-ansi-regex@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
- integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==
+ansi-regex@^5.0.0, ansi-regex@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz"
+ integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
-ansi-styles@^3.2.0, ansi-styles@^3.2.1:
+ansi-styles@^3.2.1:
version "3.2.1"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+ resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz"
integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
dependencies:
color-convert "^1.9.0"
ansi-styles@^4.0.0, ansi-styles@^4.1.0:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359"
- integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==
+ version "4.3.0"
+ resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz"
+ integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
dependencies:
- "@types/color-name" "^1.1.1"
color-convert "^2.0.1"
anymatch@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
+ resolved "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz"
integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==
dependencies:
micromatch "^3.1.4"
normalize-path "^2.1.1"
-anymatch@^3.0.3, anymatch@~3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142"
- integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==
+anymatch@^3.0.3, anymatch@~3.1.2:
+ version "3.1.2"
+ resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz"
+ integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
dependencies:
normalize-path "^3.0.0"
picomatch "^2.0.4"
-apollo-cache-control@^0.1.0:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/apollo-cache-control/-/apollo-cache-control-0.1.1.tgz#173d14ceb3eb9e7cb53de7eb8b61bee6159d4171"
- integrity sha512-XJQs167e9u+e5ybSi51nGYr70NPBbswdvTEHtbtXbwkZ+n9t0SLPvUcoqceayOSwjK1XYOdU/EKPawNdb3rLQA==
- dependencies:
- graphql-extensions "^0.0.x"
-
-apollo-link@^1.2.14:
- version "1.2.14"
- resolved "https://registry.yarnpkg.com/apollo-link/-/apollo-link-1.2.14.tgz#3feda4b47f9ebba7f4160bef8b977ba725b684d9"
- integrity sha512-p67CMEFP7kOG1JZ0ZkYZwRDa369w5PIjtMjvrQd/HnIV8FRsHRqLqK+oAZQnFa1DDdZtOtHTi+aMIW6EatC2jg==
- dependencies:
- apollo-utilities "^1.3.0"
- ts-invariant "^0.4.0"
- tslib "^1.9.3"
- zen-observable-ts "^0.8.21"
-
-apollo-server-core@^1.3.6, apollo-server-core@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-1.4.0.tgz#4faff7f110bfdd6c3f47008302ae24140f94c592"
- integrity sha512-BP1Vh39krgEjkQxbjTdBURUjLHbFq1zeOChDJgaRsMxGtlhzuLWwwC6lLdPatN8jEPbeHq8Tndp9QZ3iQZOKKA==
- dependencies:
- apollo-cache-control "^0.1.0"
- apollo-tracing "^0.1.0"
- graphql-extensions "^0.0.x"
-
-apollo-server-express@^1.3.6:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/apollo-server-express/-/apollo-server-express-1.4.0.tgz#7d7c58d6d6f9892b83fe575669093bb66738b125"
- integrity sha512-zkH00nxhLnJfO0HgnNPBTfZw8qI5ILaPZ5TecMCI9+Y9Ssr2b0bFr9pBRsXy9eudPhI+/O4yqegSUsnLdF/CPw==
- dependencies:
- apollo-server-core "^1.4.0"
- apollo-server-module-graphiql "^1.4.0"
-
-apollo-server-lambda@1.3.6:
- version "1.3.6"
- resolved "https://registry.yarnpkg.com/apollo-server-lambda/-/apollo-server-lambda-1.3.6.tgz#bdaac37f143c6798e40b8ae75580ba673cea260e"
- integrity sha1-varDfxQ8Z5jkC4rnVYC6ZzzqJg4=
- dependencies:
- apollo-server-core "^1.3.6"
- apollo-server-module-graphiql "^1.3.4"
-
-apollo-server-module-graphiql@^1.3.4, apollo-server-module-graphiql@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/apollo-server-module-graphiql/-/apollo-server-module-graphiql-1.4.0.tgz#c559efa285578820709f1769bb85d3b3eed3d8ec"
- integrity sha512-GmkOcb5he2x5gat+TuiTvabnBf1m4jzdecal3XbXBh/Jg+kx4hcvO3TTDFQ9CuTprtzdcVyA11iqG7iOMOt7vA==
-
-apollo-tracing@^0.1.0:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/apollo-tracing/-/apollo-tracing-0.1.4.tgz#5b8ae1b01526b160ee6e552a7f131923a9aedcc7"
- integrity sha512-Uv+1nh5AsNmC3m130i2u3IqbS+nrxyVV3KYimH5QKsdPjxxIQB3JAT+jJmpeDxBel8gDVstNmCh82QSLxLSIdQ==
- dependencies:
- graphql-extensions "~0.0.9"
-
-apollo-upload-server@^7.0.0:
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/apollo-upload-server/-/apollo-upload-server-7.1.0.tgz#21e07b52252b3749b913468599813e13cfca805f"
- integrity sha512-cD9ReCeyurYwZyEDqJYb5TOc9dt8yhPzS+MtrY3iJdqw+pqiiyPngAvVXHjN+Ca7Lajvom4/AT/PBrYVDMM3Kw==
- dependencies:
- busboy "^0.2.14"
- fs-capacitor "^1.0.0"
- http-errors "^1.7.0"
- object-path "^0.11.4"
-
-apollo-utilities@^1.0.1, apollo-utilities@^1.3.0:
- version "1.3.4"
- resolved "https://registry.yarnpkg.com/apollo-utilities/-/apollo-utilities-1.3.4.tgz#6129e438e8be201b6c55b0f13ce49d2c7175c9cf"
- integrity sha512-pk2hiWrCXMAy2fRPwEyhvka+mqwzeP60Jr1tRYi5xru+3ko94HI9o6lK0CT33/w4RDlxWchmdhDCrvdr+pHCig==
- dependencies:
- "@wry/equality" "^0.1.2"
- fast-json-stable-stringify "^2.0.0"
- ts-invariant "^0.4.0"
- tslib "^1.10.0"
-
arg@^4.1.0:
version "4.1.3"
- resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
+ resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz"
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
argparse@^1.0.7:
version "1.0.10"
- resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
+ resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz"
integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
dependencies:
sprintf-js "~1.0.2"
arr-diff@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
- integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=
+ resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz"
+ integrity sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==
arr-flatten@^1.1.0:
version "1.1.0"
- resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
+ resolved "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz"
integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==
arr-union@^3.1.0:
version "3.1.0"
- resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
- integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=
-
-array-find-index@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
- integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=
-
-array-flatten@1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
- integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
+ resolved "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz"
+ integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==
-array-includes@^3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348"
- integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==
+array-includes@^3.1.4, array-includes@^3.1.5:
+ version "3.1.5"
+ resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz"
+ integrity sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==
dependencies:
- define-properties "^1.1.3"
- es-abstract "^1.17.0"
- is-string "^1.0.5"
+ call-bind "^1.0.2"
+ define-properties "^1.1.4"
+ es-abstract "^1.19.5"
+ get-intrinsic "^1.1.1"
+ is-string "^1.0.7"
+
+array-union@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz"
+ integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
array-unique@^0.3.2:
version "0.3.2"
- resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
- integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
+ resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz"
+ integrity sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==
-array.prototype.flat@^1.2.3:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b"
- integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==
+array.prototype.flat@^1.2.5:
+ version "1.3.0"
+ resolved "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz"
+ integrity sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==
dependencies:
+ call-bind "^1.0.2"
define-properties "^1.1.3"
- es-abstract "^1.17.0-next.1"
+ es-abstract "^1.19.2"
+ es-shim-unscopables "^1.0.0"
-array.prototype.flatmap@^1.2.3:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.3.tgz#1c13f84a178566042dd63de4414440db9222e443"
- integrity sha512-OOEk+lkePcg+ODXIpvuU9PAryCikCJyo7GlDG1upleEpQRx6mzL9puEBkozQ5iAx20KV0l3DbyQwqciJtqe5Pg==
+array.prototype.flatmap@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz"
+ integrity sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==
dependencies:
+ call-bind "^1.0.2"
define-properties "^1.1.3"
- es-abstract "^1.17.0-next.1"
- function-bind "^1.1.1"
+ es-abstract "^1.19.2"
+ es-shim-unscopables "^1.0.0"
+
+asn1js@^3.0.1, asn1js@^3.0.5:
+ version "3.0.5"
+ resolved "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz"
+ integrity sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==
+ dependencies:
+ pvtsutils "^1.3.2"
+ pvutils "^1.1.3"
+ tslib "^2.4.0"
assign-symbols@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
- integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=
+ resolved "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz"
+ integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==
-astral-regex@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
- integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==
+astral-regex@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz"
+ integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
-async-limiter@~1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
- integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
+async@^3.2.3:
+ version "3.2.4"
+ resolved "https://registry.npmjs.org/async/-/async-3.2.4.tgz"
+ integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==
asynckit@^0.4.0:
version "0.4.0"
- resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+ resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz"
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
atob@^2.1.2:
version "2.1.2"
- resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
+ resolved "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz"
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
axios-cookiejar-support@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/axios-cookiejar-support/-/axios-cookiejar-support-1.0.0.tgz#9fceb20d3dd541eec1eb1a346bf3265a3b6e7bca"
- integrity sha512-9pBlIU5jfrGZTnUQlt8symShviSTOSlOKGtryHx76lJPnKIXDqUT3JDAjJ1ywOQLyfiWrthIt4iJiVP2L2S4jA==
+ version "1.0.1"
+ resolved "https://registry.npmjs.org/axios-cookiejar-support/-/axios-cookiejar-support-1.0.1.tgz"
+ integrity sha512-IZJxnAJ99XxiLqNeMOqrPbfR7fRyIfaoSLdPUf4AMQEGkH8URs0ghJK/xtqBsD+KsSr3pKl4DEQjCn834pHMig==
dependencies:
is-redirect "^1.0.0"
pify "^5.0.0"
axios@^0.21.2:
- version "0.21.2"
- resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.2.tgz#21297d5084b2aeeb422f5d38e7be4fbb82239017"
- integrity sha512-87otirqUw3e8CzHTMO+/9kh/FSgXt/eVDvipijwDtEuwbkySWZ9SBm6VEubmJ/kLKEoLQV/POhxXFb66bfekfg==
+ version "0.21.4"
+ resolved "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz"
+ integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==
dependencies:
follow-redirects "^1.14.0"
-babel-jest@^26.2.2:
- version "26.2.2"
- resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.2.2.tgz#70f618f2d7016ed71b232241199308985462f812"
- integrity sha512-JmLuePHgA+DSOdOL8lPxCgD2LhPPm+rdw1vnxR73PpIrnmKCS2/aBhtkAcxQWuUcW2hBrH8MJ3LKXE7aWpNZyA==
+babel-jest@^26.6.3:
+ version "26.6.3"
+ resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz"
+ integrity sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==
dependencies:
- "@jest/transform" "^26.2.2"
- "@jest/types" "^26.2.0"
+ "@jest/transform" "^26.6.2"
+ "@jest/types" "^26.6.2"
"@types/babel__core" "^7.1.7"
babel-plugin-istanbul "^6.0.0"
- babel-preset-jest "^26.2.0"
+ babel-preset-jest "^26.6.2"
chalk "^4.0.0"
graceful-fs "^4.2.4"
slash "^3.0.0"
babel-plugin-istanbul@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765"
- integrity sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==
+ version "6.1.1"
+ resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz"
+ integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
"@istanbuljs/load-nyc-config" "^1.0.0"
"@istanbuljs/schema" "^0.1.2"
- istanbul-lib-instrument "^4.0.0"
+ istanbul-lib-instrument "^5.0.4"
test-exclude "^6.0.0"
-babel-plugin-jest-hoist@^26.2.0:
- version "26.2.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.2.0.tgz#bdd0011df0d3d513e5e95f76bd53b51147aca2dd"
- integrity sha512-B/hVMRv8Nh1sQ1a3EY8I0n4Y1Wty3NrR5ebOyVT302op+DOAau+xNEImGMsUWOC3++ZlMooCytKz+NgN8aKGbA==
+babel-plugin-jest-hoist@^26.6.2:
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz"
+ integrity sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==
dependencies:
"@babel/template" "^7.3.3"
"@babel/types" "^7.3.3"
"@types/babel__core" "^7.0.0"
"@types/babel__traverse" "^7.0.6"
-babel-preset-current-node-syntax@^0.1.2:
- version "0.1.3"
- resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.3.tgz#b4b547acddbf963cba555ba9f9cbbb70bfd044da"
- integrity sha512-uyexu1sVwcdFnyq9o8UQYsXwXflIh8LvrF5+cKrYam93ned1CStffB3+BEcsxGSgagoA3GEyjDqO4a/58hyPYQ==
+babel-preset-current-node-syntax@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz"
+ integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==
dependencies:
"@babel/plugin-syntax-async-generators" "^7.8.4"
"@babel/plugin-syntax-bigint" "^7.8.3"
@@ -1211,28 +1292,24 @@ babel-preset-current-node-syntax@^0.1.2:
"@babel/plugin-syntax-object-rest-spread" "^7.8.3"
"@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
"@babel/plugin-syntax-optional-chaining" "^7.8.3"
+ "@babel/plugin-syntax-top-level-await" "^7.8.3"
-babel-preset-jest@^26.2.0:
- version "26.2.0"
- resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.2.0.tgz#f198201a4e543a43eb40bc481e19736e095fd3e0"
- integrity sha512-R1k8kdP3R9phYQugXeNnK/nvCGlBzG4m3EoIIukC80GXb6wCv2XiwPhK6K9MAkQcMszWBYvl2Wm+yigyXFQqXg==
+babel-preset-jest@^26.6.2:
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz"
+ integrity sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==
dependencies:
- babel-plugin-jest-hoist "^26.2.0"
- babel-preset-current-node-syntax "^0.1.2"
-
-backo2@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
- integrity sha1-MasayLEpNjRj41s+u2n038+6eUc=
+ babel-plugin-jest-hoist "^26.6.2"
+ babel-preset-current-node-syntax "^1.0.0"
balanced-match@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
- integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
+ integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
base@^0.11.1:
version "0.11.2"
- resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
+ resolved "https://registry.npmjs.org/base/-/base-0.11.2.tgz"
integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==
dependencies:
cache-base "^1.0.1"
@@ -1244,36 +1321,13 @@ base@^0.11.1:
pascalcase "^0.1.1"
binary-extensions@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9"
- integrity sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==
-
-body-parser-graphql@1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/body-parser-graphql/-/body-parser-graphql-1.1.0.tgz#80a80353c7cb623562fd375750dfe018d75f0f7c"
- integrity sha512-bOBF4n1AnUjcY1SzLeibeIx4XOuYqEkjn/Lm4yKhnN6KedoXMv4hVqgcKHGRnxOMJP64tErqrQU+4cihhpbJXg==
- dependencies:
- body-parser "^1.18.2"
-
-body-parser@1.19.0, body-parser@^1.18.2:
- version "1.19.0"
- resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
- integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
- dependencies:
- bytes "3.1.0"
- content-type "~1.0.4"
- debug "2.6.9"
- depd "~1.1.2"
- http-errors "1.7.2"
- iconv-lite "0.4.24"
- on-finished "~2.3.0"
- qs "6.7.0"
- raw-body "2.4.0"
- type-is "~1.6.17"
+ version "2.2.0"
+ resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz"
+ integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
brace-expansion@^1.1.7:
version "1.1.11"
- resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+ resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz"
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
dependencies:
balanced-match "^1.0.0"
@@ -1281,7 +1335,7 @@ brace-expansion@^1.1.7:
braces@^2.3.1:
version "2.3.2"
- resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
+ resolved "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz"
integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==
dependencies:
arr-flatten "^1.1.0"
@@ -1295,60 +1349,57 @@ braces@^2.3.1:
split-string "^3.0.2"
to-regex "^3.0.1"
-braces@^3.0.1, braces@~3.0.2:
+braces@^3.0.2, braces@~3.0.2:
version "3.0.2"
- resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
+ resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
dependencies:
fill-range "^7.0.1"
browser-process-hrtime@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626"
+ resolved "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz"
integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==
+browserslist@^4.20.2:
+ version "4.21.3"
+ resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz"
+ integrity sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==
+ dependencies:
+ caniuse-lite "^1.0.30001370"
+ electron-to-chromium "^1.4.202"
+ node-releases "^2.0.6"
+ update-browserslist-db "^1.0.5"
+
bs-logger@0.x:
version "0.2.6"
- resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8"
+ resolved "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz"
integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==
dependencies:
fast-json-stable-stringify "2.x"
bser@2.1.1:
version "2.1.1"
- resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05"
+ resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz"
integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==
dependencies:
node-int64 "^0.4.0"
buffer-from@1.x, buffer-from@^1.0.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
- integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
-
-busboy@^0.2.14:
- version "0.2.14"
- resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453"
- integrity sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=
- dependencies:
- dicer "0.2.5"
- readable-stream "1.1.x"
+ version "1.1.2"
+ resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz"
+ integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
-busboy@^0.3.1:
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.3.1.tgz#170899274c5bf38aae27d5c62b71268cd585fd1b"
- integrity sha512-y7tTxhGKXcyBxRKAni+awqx8uqaJKrSFSNFSeRG5CsWNdmy2BIK+6VGWEW7TZnIO/533mtMEA4rOevQV815YJw==
+busboy@^1.6.0:
+ version "1.6.0"
+ resolved "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz"
+ integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==
dependencies:
- dicer "0.3.0"
-
-bytes@3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
- integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
+ streamsearch "^1.1.0"
cache-base@^1.0.1:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
+ resolved "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz"
integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==
dependencies:
collection-visit "^1.0.0"
@@ -1361,103 +1412,100 @@ cache-base@^1.0.1:
union-value "^1.0.0"
unset-value "^1.0.0"
+call-bind@^1.0.0, call-bind@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz"
+ integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
+ dependencies:
+ function-bind "^1.1.1"
+ get-intrinsic "^1.0.2"
+
callsites@^3.0.0:
version "3.1.0"
- resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
+ resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz"
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
-camelcase-keys@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
- integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc=
- dependencies:
- camelcase "^2.0.0"
- map-obj "^1.0.0"
-
camelcase-keys@^6.2.2:
version "6.2.2"
- resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0"
+ resolved "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz"
integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==
dependencies:
camelcase "^5.3.1"
map-obj "^4.0.0"
quick-lru "^4.0.1"
-camelcase@^2.0.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
- integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=
-
camelcase@^5.0.0, camelcase@^5.3.1:
version "5.3.1"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
+ resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz"
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
camelcase@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.0.0.tgz#5259f7c30e35e278f1bdc2a4d91230b37cad981e"
- integrity sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w==
+ version "6.3.0"
+ resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz"
+ integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
+
+caniuse-lite@^1.0.30001370:
+ version "1.0.30001383"
+ resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001383.tgz"
+ integrity sha512-swMpEoTp5vDoGBZsYZX7L7nXHe6dsHxi9o6/LKf/f0LukVtnrxly5GVb/fWdCDTqi/yw6Km6tiJ0pmBacm0gbg==
capture-exit@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4"
+ resolved "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz"
integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==
dependencies:
rsvp "^4.8.4"
chalk@^2.0.0:
version "2.4.2"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
+ resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
dependencies:
ansi-styles "^3.2.1"
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
-chalk@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4"
- integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==
- dependencies:
- ansi-styles "^4.1.0"
- supports-color "^7.1.0"
-
chalk@^4.0.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a"
- integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==
+ version "4.1.2"
+ resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
+ integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
dependencies:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
char-regex@^1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
+ resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz"
integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==
-chokidar@^3.4.0:
- version "3.4.2"
- resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.2.tgz#38dc8e658dec3809741eb3ef7bb0a47fe424232d"
- integrity sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==
+chokidar@^3.5.1:
+ version "3.5.3"
+ resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz"
+ integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
dependencies:
- anymatch "~3.1.1"
+ anymatch "~3.1.2"
braces "~3.0.2"
- glob-parent "~5.1.0"
+ glob-parent "~5.1.2"
is-binary-path "~2.1.0"
is-glob "~4.0.1"
normalize-path "~3.0.0"
- readdirp "~3.4.0"
+ readdirp "~3.6.0"
optionalDependencies:
- fsevents "~2.1.2"
+ fsevents "~2.3.2"
ci-info@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
+ resolved "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz"
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
+cjs-module-lexer@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz"
+ integrity sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==
+
class-utils@^0.3.5:
version "0.3.6"
- resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
+ resolved "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz"
integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==
dependencies:
arr-union "^3.1.0"
@@ -1467,7 +1515,7 @@ class-utils@^0.3.5:
cliui@^6.0.0:
version "6.0.0"
- resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1"
+ resolved "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz"
integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==
dependencies:
string-width "^4.2.0"
@@ -1476,123 +1524,114 @@ cliui@^6.0.0:
co@^4.6.0:
version "4.6.0"
- resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
- integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=
+ resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz"
+ integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==
collect-v8-coverage@^1.0.0:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59"
+ resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz"
integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==
collection-visit@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
- integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=
+ resolved "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz"
+ integrity sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==
dependencies:
map-visit "^1.0.0"
object-visit "^1.0.0"
-color-convert@^1.9.0:
+color-convert@^1.9.0, color-convert@^1.9.3:
version "1.9.3"
- resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+ resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz"
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
dependencies:
color-name "1.1.3"
color-convert@^2.0.1:
version "2.0.1"
- resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+ resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz"
integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
dependencies:
color-name "~1.1.4"
color-name@1.1.3:
version "1.1.3"
- resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
- integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
+ resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
+ integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
-color-name@~1.1.4:
+color-name@^1.0.0, color-name@~1.1.4:
version "1.1.4"
- resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+ resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+color-string@^1.6.0:
+ version "1.9.1"
+ resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz"
+ integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==
+ dependencies:
+ color-name "^1.0.0"
+ simple-swizzle "^0.2.2"
+
+color@^3.1.3:
+ version "3.2.1"
+ resolved "https://registry.npmjs.org/color/-/color-3.2.1.tgz"
+ integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==
+ dependencies:
+ color-convert "^1.9.3"
+ color-string "^1.6.0"
+
+colorspace@1.1.x:
+ version "1.1.4"
+ resolved "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz"
+ integrity sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==
+ dependencies:
+ color "^3.1.3"
+ text-hex "1.0.x"
+
combined-stream@^1.0.8:
version "1.0.8"
- resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
+ resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz"
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
dependencies:
delayed-stream "~1.0.0"
component-emitter@^1.2.1:
version "1.3.0"
- resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
+ resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz"
integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
concat-map@0.0.1:
version "0.0.1"
- resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
- integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
-
-contains-path@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a"
- integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=
-
-content-disposition@0.5.3:
- version "0.5.3"
- resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
- integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
- dependencies:
- safe-buffer "5.1.2"
-
-content-type@~1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
- integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
+ resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
+ integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
- version "1.7.0"
- resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
- integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==
+ version "1.8.0"
+ resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz"
+ integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==
dependencies:
safe-buffer "~5.1.1"
-cookie-signature@1.0.6:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
- integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
-
-cookie@0.4.0:
- version "0.4.0"
- resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
- integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
-
copy-descriptor@^0.1.0:
version "0.1.1"
- resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
- integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
+ resolved "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz"
+ integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==
-core-js@^2.5.3:
- version "2.6.11"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c"
- integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==
-
-core-util-is@~1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
- integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
+create-require@^1.1.0:
+ version "1.1.1"
+ resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz"
+ integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
-cors@^2.8.4:
- version "2.8.5"
- resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
- integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
+cross-env@^7.0.3:
+ version "7.0.3"
+ resolved "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz"
+ integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==
dependencies:
- object-assign "^4"
- vary "^1"
+ cross-spawn "^7.0.1"
cross-spawn@^6.0.0:
version "6.0.5"
- resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
+ resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz"
integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
dependencies:
nice-try "^1.0.4"
@@ -1601,9 +1640,9 @@ cross-spawn@^6.0.0:
shebang-command "^1.2.0"
which "^1.2.9"
-cross-spawn@^7.0.0, cross-spawn@^7.0.2:
+cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2:
version "7.0.3"
- resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
+ resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
dependencies:
path-key "^3.1.0"
@@ -1612,120 +1651,101 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2:
cssom@^0.4.4:
version "0.4.4"
- resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10"
+ resolved "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz"
integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==
cssom@~0.3.6:
version "0.3.8"
- resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a"
+ resolved "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz"
integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==
cssstyle@^2.3.0:
version "2.3.0"
- resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852"
+ resolved "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz"
integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==
dependencies:
cssom "~0.3.6"
-currently-unhandled@^0.4.1:
- version "0.4.1"
- resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
- integrity sha1-mI3zP+qxke95mmE2nddsF635V+o=
- dependencies:
- array-find-index "^1.0.1"
-
data-urls@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b"
+ resolved "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz"
integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==
dependencies:
abab "^2.0.3"
whatwg-mimetype "^2.3.0"
whatwg-url "^8.0.0"
-dateformat@~1.0.4-1.2.3:
- version "1.0.12"
- resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-1.0.12.tgz#9f124b67594c937ff706932e4a642cca8dbbfee9"
- integrity sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=
+debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1:
+ version "4.3.4"
+ resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"
+ integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies:
- get-stdin "^4.0.1"
- meow "^3.3.0"
+ ms "2.1.2"
-debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
+debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
version "2.6.9"
- resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+ resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
dependencies:
ms "2.0.0"
-debug@4:
- version "4.3.4"
- resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
- integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
- dependencies:
- ms "2.1.2"
-
-debug@^4.0.1, debug@^4.1.0, debug@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
- integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
+debug@^3.2.7:
+ version "3.2.7"
+ resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz"
+ integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
dependencies:
ms "^2.1.1"
-decamelize@^1.1.2, decamelize@^1.2.0:
+decamelize@^1.2.0:
version "1.2.0"
- resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
- integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
+ resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz"
+ integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==
decimal.js@^10.2.1:
- version "10.3.1"
- resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783"
- integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==
+ version "10.4.0"
+ resolved "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.0.tgz"
+ integrity sha512-Nv6ENEzyPQ6AItkGwLE2PGKinZZ9g59vSh2BeH6NqPu0OTKZ5ruJsVqh/orbAnqXc9pBbgXAIrc2EyaCj8NpGg==
decode-uri-component@^0.2.0:
version "0.2.0"
- resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
- integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
-
-deep-is@^0.1.3:
- version "0.1.3"
- resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
- integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
+ resolved "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz"
+ integrity sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==
-deep-is@~0.1.3:
+deep-is@^0.1.3, deep-is@~0.1.3:
version "0.1.4"
- resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
+ resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz"
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
deepmerge@^4.2.2:
version "4.2.2"
- resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
+ resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz"
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
-define-properties@^1.1.2, define-properties@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
- integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
+define-properties@^1.1.3, define-properties@^1.1.4:
+ version "1.1.4"
+ resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz"
+ integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==
dependencies:
- object-keys "^1.0.12"
+ has-property-descriptors "^1.0.0"
+ object-keys "^1.1.1"
define-property@^0.2.5:
version "0.2.5"
- resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
- integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=
+ resolved "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz"
+ integrity sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==
dependencies:
is-descriptor "^0.1.0"
define-property@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6"
- integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY=
+ resolved "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz"
+ integrity sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==
dependencies:
is-descriptor "^1.0.0"
define-property@^2.0.2:
version "2.0.2"
- resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d"
+ resolved "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz"
integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==
dependencies:
is-descriptor "^1.0.2"
@@ -1733,190 +1753,178 @@ define-property@^2.0.2:
delayed-stream@~1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+ resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
-depd@~1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
- integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
-
-deprecated-decorator@^0.1.6:
- version "0.1.6"
- resolved "https://registry.yarnpkg.com/deprecated-decorator/-/deprecated-decorator-0.1.6.tgz#00966317b7a12fe92f3cc831f7583af329b86c37"
- integrity sha1-AJZjF7ehL+kvPMgx91g68ym4bDc=
-
-destroy@~1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
- integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
-
detect-newline@^3.0.0:
version "3.1.0"
- resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
+ resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz"
integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==
-dicer@0.2.5:
- version "0.2.5"
- resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f"
- integrity sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=
- dependencies:
- readable-stream "1.1.x"
- streamsearch "0.1.2"
-
-dicer@0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.3.0.tgz#eacd98b3bfbf92e8ab5c2fdb71aaac44bb06b872"
- integrity sha512-MdceRRWqltEG2dZqO769g27N/3PXfcKl04VhYnBlo2YhH7zPi88VebsjTKclaOyiuMaGU72hTfw3VkUitGcVCA==
- dependencies:
- streamsearch "0.1.2"
-
-diff-sequences@^25.2.6:
- version "25.2.6"
- resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd"
- integrity sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg==
-
-diff-sequences@^26.0.0:
- version "26.0.0"
- resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.0.0.tgz#0760059a5c287637b842bd7085311db7060e88a6"
- integrity sha512-JC/eHYEC3aSS0vZGjuoc4vHA0yAQTzhQQldXMeMF+JlxLGJlCO38Gma82NV9gk1jGFz8mDzUMeaKXvjRRdJ2dg==
+diff-sequences@^26.6.2:
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz"
+ integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==
diff@^4.0.1:
version "4.0.2"
- resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
+ resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz"
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
-doctrine@1.5.0:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
- integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=
+dir-glob@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz"
+ integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
dependencies:
- esutils "^2.0.2"
- isarray "^1.0.0"
+ path-type "^4.0.0"
doctrine@^2.1.0:
version "2.1.0"
- resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
+ resolved "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz"
integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==
dependencies:
esutils "^2.0.2"
doctrine@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
+ resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz"
integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
dependencies:
esutils "^2.0.2"
domexception@^2.0.1:
version "2.0.1"
- resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304"
+ resolved "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz"
integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==
dependencies:
webidl-conversions "^5.0.0"
dotenv@^8.2.0:
- version "8.2.0"
- resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a"
- integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==
+ version "8.6.0"
+ resolved "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz"
+ integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==
+
+dset@^3.1.1:
+ version "3.1.2"
+ resolved "https://registry.npmjs.org/dset/-/dset-3.1.2.tgz"
+ integrity sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q==
dynamic-dedupe@^0.3.0:
version "0.3.0"
- resolved "https://registry.yarnpkg.com/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz#06e44c223f5e4e94d78ef9db23a6515ce2f962a1"
- integrity sha1-BuRMIj9eTpTXjvnbI6ZRXOL5YqE=
+ resolved "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz"
+ integrity sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==
dependencies:
xtend "^4.0.0"
-ee-first@1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
- integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
+electron-to-chromium@^1.4.202:
+ version "1.4.230"
+ resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.230.tgz"
+ integrity sha512-3pwjAK0qHSDN9+YAF4fJknsSruP7mpjdWzUSruIJD/JCH77pEh0SorEyb3xVaKkfwk2tzjOt2D8scJ0KAdfXLA==
emittery@^0.7.1:
- version "0.7.1"
- resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.1.tgz#c02375a927a40948c0345cc903072597f5270451"
- integrity sha512-d34LN4L6h18Bzz9xpoku2nPwKxCPlPMr3EEKTkoEBi+1/+b0lcRkRJ1UVyyZaKNeqGR3swcGl6s390DNO4YVgQ==
-
-emoji-regex@^7.0.1:
- version "7.0.3"
- resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
- integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
+ version "0.7.2"
+ resolved "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz"
+ integrity sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==
emoji-regex@^8.0.0:
version "8.0.0"
- resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
+ resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz"
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
-encodeurl@~1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
- integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
+enabled@2.0.x:
+ version "2.0.0"
+ resolved "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz"
+ integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==
end-of-stream@^1.1.0:
version "1.4.4"
- resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
+ resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz"
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
dependencies:
once "^1.4.0"
enquirer@^2.3.5:
version "2.3.6"
- resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d"
+ resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz"
integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==
dependencies:
ansi-colors "^4.1.1"
-error-ex@^1.2.0, error-ex@^1.3.1:
+error-ex@^1.3.1:
version "1.3.2"
- resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
+ resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz"
integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
dependencies:
is-arrayish "^0.2.1"
-es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.5:
- version "1.17.6"
- resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a"
- integrity sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==
+es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.5:
+ version "1.20.1"
+ resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz"
+ integrity sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==
dependencies:
+ call-bind "^1.0.2"
es-to-primitive "^1.2.1"
function-bind "^1.1.1"
+ function.prototype.name "^1.1.5"
+ get-intrinsic "^1.1.1"
+ get-symbol-description "^1.0.0"
has "^1.0.3"
- has-symbols "^1.0.1"
- is-callable "^1.2.0"
- is-regex "^1.1.0"
- object-inspect "^1.7.0"
+ has-property-descriptors "^1.0.0"
+ has-symbols "^1.0.3"
+ internal-slot "^1.0.3"
+ is-callable "^1.2.4"
+ is-negative-zero "^2.0.2"
+ is-regex "^1.1.4"
+ is-shared-array-buffer "^1.0.2"
+ is-string "^1.0.7"
+ is-weakref "^1.0.2"
+ object-inspect "^1.12.0"
object-keys "^1.1.1"
- object.assign "^4.1.0"
- string.prototype.trimend "^1.0.1"
- string.prototype.trimstart "^1.0.1"
+ object.assign "^4.1.2"
+ regexp.prototype.flags "^1.4.3"
+ string.prototype.trimend "^1.0.5"
+ string.prototype.trimstart "^1.0.5"
+ unbox-primitive "^1.0.2"
+
+es-shim-unscopables@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz"
+ integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==
+ dependencies:
+ has "^1.0.3"
es-to-primitive@^1.2.1:
version "1.2.1"
- resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
+ resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz"
integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
dependencies:
is-callable "^1.1.4"
is-date-object "^1.0.1"
is-symbol "^1.0.2"
-escape-html@~1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
- integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
+escalade@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz"
+ integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
escape-string-regexp@^1.0.5:
version "1.0.5"
- resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
- integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
+ resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
+ integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
escape-string-regexp@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344"
+ resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz"
integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==
+escape-string-regexp@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz"
+ integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
+
escodegen@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd"
+ resolved "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz"
integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==
dependencies:
esprima "^4.0.1"
@@ -1926,155 +1934,174 @@ escodegen@^2.0.0:
optionalDependencies:
source-map "~0.6.1"
-eslint-config-kodefox@^0.2.2:
- version "0.2.2"
- resolved "https://registry.yarnpkg.com/eslint-config-kodefox/-/eslint-config-kodefox-0.2.2.tgz#0adb0555369685b804fe30b66e2ef77e1bb9cec6"
- integrity sha512-R0cAFvsfCIhbt/xiaDOZp8JlE95Gtrdkm1hJZvNcbODdxUPRMJW89PaC+RDjo+Sv5mXQuxfitHiumUx5xlW+bA==
- dependencies:
- "@typescript-eslint/eslint-plugin" "^2.7.0"
- "@typescript-eslint/parser" "^2.7.0"
- eslint-config-prettier "^6.5.0"
- eslint-plugin-eslint-comments "^3.1.2"
- eslint-plugin-import "^2.20.1"
- eslint-plugin-prettier "^3.1.1"
+eslint-config-kodefox@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.npmjs.org/eslint-config-kodefox/-/eslint-config-kodefox-1.2.0.tgz"
+ integrity sha512-CjSTQe3Q/nAXLxEs+PiZBRw8OvL8MNQTydpJ17TOZLHmYKtWXM58zdYAXuGslrSYetF9zwCuXqjhfeVhcG7t7w==
+ dependencies:
+ "@typescript-eslint/eslint-plugin" "^4.28.2"
+ "@typescript-eslint/parser" "^4.28.0"
+ eslint-config-prettier "^6.15.0"
+ eslint-plugin-eslint-comments "^3.2.0"
+ eslint-plugin-import "^2.22.1"
+ eslint-plugin-prettier "^3.1.4"
optionalDependencies:
- eslint-plugin-react "^7.16.0"
- eslint-plugin-react-hooks "^2.2.0"
- eslint-plugin-react-native "^3.8.1"
+ eslint-plugin-react "^7.21.5"
+ eslint-plugin-react-hooks "^4.2.0"
+ eslint-plugin-react-native "^3.10.0"
-eslint-config-prettier@^6.5.0:
- version "6.11.0"
- resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz#f6d2238c1290d01c859a8b5c1f7d352a0b0da8b1"
- integrity sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA==
+eslint-config-prettier@^6.15.0:
+ version "6.15.0"
+ resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz"
+ integrity sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw==
dependencies:
get-stdin "^6.0.0"
-eslint-import-resolver-node@^0.3.3:
- version "0.3.4"
- resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717"
- integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==
+eslint-import-resolver-node@^0.3.6:
+ version "0.3.6"
+ resolved "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz"
+ integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==
dependencies:
- debug "^2.6.9"
- resolve "^1.13.1"
+ debug "^3.2.7"
+ resolve "^1.20.0"
-eslint-module-utils@^2.6.0:
- version "2.6.0"
- resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz#579ebd094f56af7797d19c9866c9c9486629bfa6"
- integrity sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==
+eslint-module-utils@^2.7.3:
+ version "2.7.4"
+ resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz"
+ integrity sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==
dependencies:
- debug "^2.6.9"
- pkg-dir "^2.0.0"
+ debug "^3.2.7"
-eslint-plugin-eslint-comments@^3.1.2:
+eslint-plugin-eslint-comments@^3.2.0:
version "3.2.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz#9e1cd7b4413526abb313933071d7aba05ca12ffa"
+ resolved "https://registry.npmjs.org/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz"
integrity sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==
dependencies:
escape-string-regexp "^1.0.5"
ignore "^5.0.5"
-eslint-plugin-import@^2.20.1:
- version "2.22.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz#92f7736fe1fde3e2de77623c838dd992ff5ffb7e"
- integrity sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg==
+eslint-plugin-import@^2.22.1:
+ version "2.26.0"
+ resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz"
+ integrity sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==
dependencies:
- array-includes "^3.1.1"
- array.prototype.flat "^1.2.3"
- contains-path "^0.1.0"
+ array-includes "^3.1.4"
+ array.prototype.flat "^1.2.5"
debug "^2.6.9"
- doctrine "1.5.0"
- eslint-import-resolver-node "^0.3.3"
- eslint-module-utils "^2.6.0"
+ doctrine "^2.1.0"
+ eslint-import-resolver-node "^0.3.6"
+ eslint-module-utils "^2.7.3"
has "^1.0.3"
- minimatch "^3.0.4"
- object.values "^1.1.1"
- read-pkg-up "^2.0.0"
- resolve "^1.17.0"
- tsconfig-paths "^3.9.0"
-
-eslint-plugin-prettier@^3.1.1:
- version "3.1.4"
- resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.4.tgz#168ab43154e2ea57db992a2cd097c828171f75c2"
- integrity sha512-jZDa8z76klRqo+TdGDTFJSavwbnWK2ZpqGKNZ+VvweMW516pDUMmQ2koXvxEE4JhzNvTv+radye/bWGBmA6jmg==
+ is-core-module "^2.8.1"
+ is-glob "^4.0.3"
+ minimatch "^3.1.2"
+ object.values "^1.1.5"
+ resolve "^1.22.0"
+ tsconfig-paths "^3.14.1"
+
+eslint-plugin-prettier@^3.1.4:
+ version "3.4.1"
+ resolved "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz"
+ integrity sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==
dependencies:
prettier-linter-helpers "^1.0.0"
-eslint-plugin-react-hooks@^2.2.0:
- version "2.5.1"
- resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-2.5.1.tgz#4ef5930592588ce171abeb26f400c7fbcbc23cd0"
- integrity sha512-Y2c4b55R+6ZzwtTppKwSmK/Kar8AdLiC2f9NADCuxbcTgPPg41Gyqa6b9GppgXSvCtkRw43ZE86CT5sejKC6/g==
+eslint-plugin-react-hooks@^4.2.0:
+ version "4.6.0"
+ resolved "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz"
+ integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==
eslint-plugin-react-native-globals@^0.1.1:
version "0.1.2"
- resolved "https://registry.yarnpkg.com/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz#ee1348bc2ceb912303ce6bdbd22e2f045ea86ea2"
+ resolved "https://registry.npmjs.org/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz"
integrity sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g==
-eslint-plugin-react-native@^3.8.1:
- version "3.8.1"
- resolved "https://registry.yarnpkg.com/eslint-plugin-react-native/-/eslint-plugin-react-native-3.8.1.tgz#92811e37191ecb0d29c0f0a0c9e5c943ee573821"
- integrity sha512-6Z4s4nvgFRdda/1s1+uu4a6EMZwEjjJ9Bk/1yBImv0fd9U2CsGu2cUakAtV83cZKhizbWhSouXoaK4JtlScdFg==
+eslint-plugin-react-native@^3.10.0:
+ version "3.11.0"
+ resolved "https://registry.npmjs.org/eslint-plugin-react-native/-/eslint-plugin-react-native-3.11.0.tgz"
+ integrity sha512-7F3OTwrtQPfPFd+VygqKA2VZ0f2fz0M4gJmry/TRE18JBb94/OtMxwbL7Oqwu7FGyrdeIOWnXQbBAveMcSTZIA==
dependencies:
+ "@babel/traverse" "^7.7.4"
eslint-plugin-react-native-globals "^0.1.1"
-eslint-plugin-react@^7.16.0:
- version "7.20.5"
- resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.20.5.tgz#29480f3071f64a04b2c3d99d9b460ce0f76fb857"
- integrity sha512-ajbJfHuFnpVNJjhyrfq+pH1C0gLc2y94OiCbAXT5O0J0YCKaFEHDV8+3+mDOr+w8WguRX+vSs1bM2BDG0VLvCw==
+eslint-plugin-react@^7.21.5:
+ version "7.31.0"
+ resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.0.tgz"
+ integrity sha512-BWriBttYYCnfb4RO9SB91Og8uA9CPcBMl5UlCOCtuYW1UjhN3QypzEcEHky4ZIRZDKjbO2Blh9BjP8E7W/b1SA==
dependencies:
- array-includes "^3.1.1"
- array.prototype.flatmap "^1.2.3"
+ array-includes "^3.1.5"
+ array.prototype.flatmap "^1.3.0"
doctrine "^2.1.0"
- has "^1.0.3"
- jsx-ast-utils "^2.4.1"
- object.entries "^1.1.2"
- object.fromentries "^2.0.2"
- object.values "^1.1.1"
- prop-types "^15.7.2"
- resolve "^1.17.0"
- string.prototype.matchall "^4.0.2"
-
-eslint-scope@^5.0.0, eslint-scope@^5.1.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.0.tgz#d0f971dfe59c69e0cada684b23d49dbf82600ce5"
- integrity sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==
+ estraverse "^5.3.0"
+ jsx-ast-utils "^2.4.1 || ^3.0.0"
+ minimatch "^3.1.2"
+ object.entries "^1.1.5"
+ object.fromentries "^2.0.5"
+ object.hasown "^1.1.1"
+ object.values "^1.1.5"
+ prop-types "^15.8.1"
+ resolve "^2.0.0-next.3"
+ semver "^6.3.0"
+ string.prototype.matchall "^4.0.7"
+
+eslint-scope@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz"
+ integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
dependencies:
- esrecurse "^4.1.0"
+ esrecurse "^4.3.0"
estraverse "^4.1.1"
-eslint-utils@^2.0.0, eslint-utils@^2.1.0:
+eslint-utils@^2.1.0:
version "2.1.0"
- resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27"
+ resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz"
integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
dependencies:
eslint-visitor-keys "^1.1.0"
+eslint-utils@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz"
+ integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==
+ dependencies:
+ eslint-visitor-keys "^2.0.0"
+
eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0:
version "1.3.0"
- resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e"
+ resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz"
integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==
+eslint-visitor-keys@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz"
+ integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
+
eslint@^7.6.0:
- version "7.6.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.6.0.tgz#522d67cfaea09724d96949c70e7a0550614d64d6"
- integrity sha512-QlAManNtqr7sozWm5TF4wIH9gmUm2hE3vNRUvyoYAa4y1l5/jxD/PQStEjBMQtCqZmSep8UxrcecI60hOpe61w==
+ version "7.32.0"
+ resolved "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz"
+ integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==
dependencies:
- "@babel/code-frame" "^7.0.0"
+ "@babel/code-frame" "7.12.11"
+ "@eslint/eslintrc" "^0.4.3"
+ "@humanwhocodes/config-array" "^0.5.0"
ajv "^6.10.0"
chalk "^4.0.0"
cross-spawn "^7.0.2"
debug "^4.0.1"
doctrine "^3.0.0"
enquirer "^2.3.5"
- eslint-scope "^5.1.0"
+ escape-string-regexp "^4.0.0"
+ eslint-scope "^5.1.1"
eslint-utils "^2.1.0"
- eslint-visitor-keys "^1.3.0"
- espree "^7.2.0"
- esquery "^1.2.0"
+ eslint-visitor-keys "^2.0.0"
+ espree "^7.3.1"
+ esquery "^1.4.0"
esutils "^2.0.2"
- file-entry-cache "^5.0.1"
+ fast-deep-equal "^3.1.3"
+ file-entry-cache "^6.0.1"
functional-red-black-tree "^1.0.1"
- glob-parent "^5.0.0"
- globals "^12.1.0"
+ glob-parent "^5.1.2"
+ globals "^13.6.0"
ignore "^4.0.6"
import-fresh "^3.0.0"
imurmurhash "^0.1.4"
@@ -2082,7 +2109,7 @@ eslint@^7.6.0:
js-yaml "^3.13.1"
json-stable-stringify-without-jsonify "^1.0.1"
levn "^0.4.1"
- lodash "^4.17.19"
+ lodash.merge "^4.6.2"
minimatch "^3.0.4"
natural-compare "^1.4.0"
optionator "^0.9.1"
@@ -2091,76 +2118,71 @@ eslint@^7.6.0:
semver "^7.2.1"
strip-ansi "^6.0.0"
strip-json-comments "^3.1.0"
- table "^5.2.3"
+ table "^6.0.9"
text-table "^0.2.0"
v8-compile-cache "^2.0.3"
-espree@^7.2.0:
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/espree/-/espree-7.2.0.tgz#1c263d5b513dbad0ac30c4991b93ac354e948d69"
- integrity sha512-H+cQ3+3JYRMEIOl87e7QdHX70ocly5iW4+dttuR8iYSPr/hXKFb+7dBsZ7+u1adC4VrnPlTkv0+OwuPnDop19g==
+espree@^7.3.0, espree@^7.3.1:
+ version "7.3.1"
+ resolved "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz"
+ integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==
dependencies:
- acorn "^7.3.1"
- acorn-jsx "^5.2.0"
+ acorn "^7.4.0"
+ acorn-jsx "^5.3.1"
eslint-visitor-keys "^1.3.0"
esprima@^4.0.0, esprima@^4.0.1:
version "4.0.1"
- resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
+ resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz"
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
-esquery@^1.2.0:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57"
- integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==
+esquery@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz"
+ integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==
dependencies:
estraverse "^5.1.0"
-esrecurse@^4.1.0:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf"
- integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==
+esrecurse@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz"
+ integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
dependencies:
- estraverse "^4.1.0"
+ estraverse "^5.2.0"
-estraverse@^4.1.0, estraverse@^4.1.1:
+estraverse@^4.1.1:
version "4.3.0"
- resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
+ resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz"
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
-estraverse@^5.1.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880"
- integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==
-
-estraverse@^5.2.0:
+estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0:
version "5.3.0"
- resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
+ resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz"
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
esutils@^2.0.2:
version "2.0.3"
- resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
+ resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz"
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
-etag@~1.8.1:
- version "1.8.1"
- resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
- integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
+event-target-polyfill@^0.0.3:
+ version "0.0.3"
+ resolved "https://registry.npmjs.org/event-target-polyfill/-/event-target-polyfill-0.0.3.tgz"
+ integrity sha512-ZMc6UuvmbinrCk4RzGyVmRyIsAyxMRlp4CqSrcQRO8Dy0A9ldbiRy5kdtBj4OtP7EClGdqGfIqo9JmOClMsGLQ==
-eventemitter3@^3.1.0:
- version "3.1.2"
- resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7"
- integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==
+event-target-shim@^5.0.0:
+ version "5.0.1"
+ resolved "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz"
+ integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==
exec-sh@^0.3.2:
- version "0.3.4"
- resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5"
- integrity sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==
+ version "0.3.6"
+ resolved "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz"
+ integrity sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==
execa@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
+ resolved "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz"
integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==
dependencies:
cross-spawn "^6.0.0"
@@ -2172,9 +2194,9 @@ execa@^1.0.0:
strip-eof "^1.0.0"
execa@^4.0.0:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/execa/-/execa-4.0.3.tgz#0a34dabbad6d66100bd6f2c576c8669403f317f2"
- integrity sha512-WFDXGHckXPWZX19t1kCsXzOpqX9LWYNqn4C+HqZlk/V0imTkzJZqf87ZBhvpHaftERYknpk0fjSylnXVlVgI0A==
+ version "4.1.0"
+ resolved "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz"
+ integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==
dependencies:
cross-spawn "^7.0.0"
get-stream "^5.0.0"
@@ -2188,13 +2210,13 @@ execa@^4.0.0:
exit@^0.1.2:
version "0.1.2"
- resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
- integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=
+ resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz"
+ integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==
expand-brackets@^2.1.4:
version "2.1.4"
- resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
- integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI=
+ resolved "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz"
+ integrity sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==
dependencies:
debug "^2.3.3"
define-property "^0.2.5"
@@ -2204,72 +2226,36 @@ expand-brackets@^2.1.4:
snapdragon "^0.8.1"
to-regex "^3.0.1"
-expect@^26.2.0:
- version "26.2.0"
- resolved "https://registry.yarnpkg.com/expect/-/expect-26.2.0.tgz#0140dd9cc7376d7833852e9cda88c05414f1efba"
- integrity sha512-8AMBQ9UVcoUXt0B7v+5/U5H6yiUR87L6eKCfjE3spx7Ya5lF+ebUo37MCFBML2OiLfkX1sxmQOZhIDonyVTkcw==
+expect@^26.6.2:
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz"
+ integrity sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==
dependencies:
- "@jest/types" "^26.2.0"
+ "@jest/types" "^26.6.2"
ansi-styles "^4.0.0"
- jest-get-type "^26.0.0"
- jest-matcher-utils "^26.2.0"
- jest-message-util "^26.2.0"
+ jest-get-type "^26.3.0"
+ jest-matcher-utils "^26.6.2"
+ jest-message-util "^26.6.2"
jest-regex-util "^26.0.0"
-express@^4.16.3:
- version "4.17.1"
- resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
- integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
- dependencies:
- accepts "~1.3.7"
- array-flatten "1.1.1"
- body-parser "1.19.0"
- content-disposition "0.5.3"
- content-type "~1.0.4"
- cookie "0.4.0"
- cookie-signature "1.0.6"
- debug "2.6.9"
- depd "~1.1.2"
- encodeurl "~1.0.2"
- escape-html "~1.0.3"
- etag "~1.8.1"
- finalhandler "~1.1.2"
- fresh "0.5.2"
- merge-descriptors "1.0.1"
- methods "~1.1.2"
- on-finished "~2.3.0"
- parseurl "~1.3.3"
- path-to-regexp "0.1.7"
- proxy-addr "~2.0.5"
- qs "6.7.0"
- range-parser "~1.2.1"
- safe-buffer "5.1.2"
- send "0.17.1"
- serve-static "1.14.1"
- setprototypeof "1.1.1"
- statuses "~1.5.0"
- type-is "~1.6.18"
- utils-merge "1.0.1"
- vary "~1.1.2"
-
extend-shallow@^2.0.1:
version "2.0.1"
- resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
- integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=
+ resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz"
+ integrity sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==
dependencies:
is-extendable "^0.1.0"
extend-shallow@^3.0.0, extend-shallow@^3.0.2:
version "3.0.2"
- resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8"
- integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=
+ resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz"
+ integrity sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==
dependencies:
assign-symbols "^1.0.0"
is-extendable "^1.0.1"
extglob@^2.0.4:
version "2.0.4"
- resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
+ resolved "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz"
integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==
dependencies:
array-unique "^0.3.2"
@@ -2281,44 +2267,74 @@ extglob@^2.0.4:
snapdragon "^0.8.1"
to-regex "^3.0.1"
-fast-deep-equal@^3.1.1:
+fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
- resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
+ resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
fast-diff@^1.1.2:
version "1.2.0"
- resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
+ resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz"
integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
+fast-glob@^3.2.9:
+ version "3.2.11"
+ resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz"
+ integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==
+ dependencies:
+ "@nodelib/fs.stat" "^2.0.2"
+ "@nodelib/fs.walk" "^1.2.3"
+ glob-parent "^5.1.2"
+ merge2 "^1.3.0"
+ micromatch "^4.0.4"
+
fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0:
version "2.1.0"
- resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
+ resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz"
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6:
version "2.0.6"
- resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
- integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
+ resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz"
+ integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
+
+fastq@^1.6.0:
+ version "1.13.0"
+ resolved "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz"
+ integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==
+ dependencies:
+ reusify "^1.0.4"
fb-watchman@^2.0.0:
version "2.0.1"
- resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85"
+ resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz"
integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==
dependencies:
bser "2.1.1"
-file-entry-cache@^5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c"
- integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==
+fecha@^4.2.0:
+ version "4.2.3"
+ resolved "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz"
+ integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==
+
+file-entry-cache@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz"
+ integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==
+ dependencies:
+ flat-cache "^3.0.4"
+
+file-stream-rotator@^0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/file-stream-rotator/-/file-stream-rotator-0.6.1.tgz#007019e735b262bb6c6f0197e58e5c87cb96cec3"
+ integrity sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ==
dependencies:
- flat-cache "^2.0.1"
+ moment "^2.29.1"
fill-range@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
- integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=
+ resolved "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz"
+ integrity sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==
dependencies:
extend-shallow "^2.0.1"
is-number "^3.0.0"
@@ -2327,371 +2343,272 @@ fill-range@^4.0.0:
fill-range@^7.0.1:
version "7.0.1"
- resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
+ resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz"
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
dependencies:
to-regex-range "^5.0.1"
-finalhandler@~1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
- integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
- dependencies:
- debug "2.6.9"
- encodeurl "~1.0.2"
- escape-html "~1.0.3"
- on-finished "~2.3.0"
- parseurl "~1.3.3"
- statuses "~1.5.0"
- unpipe "~1.0.0"
-
-find-up@^1.0.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
- integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=
- dependencies:
- path-exists "^2.0.0"
- pinkie-promise "^2.0.0"
-
-find-up@^2.0.0, find-up@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
- integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c=
- dependencies:
- locate-path "^2.0.0"
-
find-up@^4.0.0, find-up@^4.1.0:
version "4.1.0"
- resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
+ resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz"
integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
dependencies:
locate-path "^5.0.0"
path-exists "^4.0.0"
-flat-cache@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0"
- integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==
+flat-cache@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz"
+ integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==
dependencies:
- flatted "^2.0.0"
- rimraf "2.6.3"
- write "1.0.3"
+ flatted "^3.1.0"
+ rimraf "^3.0.2"
-flatted@^2.0.0:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138"
- integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==
+flatted@^3.1.0:
+ version "3.2.7"
+ resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz"
+ integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==
-fn-name@~2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/fn-name/-/fn-name-2.0.1.tgz#5214d7537a4d06a4a301c0cc262feb84188002e7"
- integrity sha1-UhTXU3pNBqSjAcDMJi/rhBiAAuc=
+fn.name@1.x.x:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz"
+ integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==
follow-redirects@^1.14.0:
version "1.15.1"
- resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5"
+ resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz"
integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==
for-in@^1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
- integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
+ resolved "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz"
+ integrity sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==
+
+form-data-encoder@^1.7.1:
+ version "1.7.2"
+ resolved "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz"
+ integrity sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==
+
+form-data@*, form-data@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz"
+ integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "^1.0.8"
+ mime-types "^2.1.12"
-form-data@*, form-data@^3.0.0:
+form-data@^3.0.0:
version "3.0.1"
- resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f"
+ resolved "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz"
integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
mime-types "^2.1.12"
-forwarded@~0.1.2:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
- integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=
+formdata-node@^4.3.1:
+ version "4.4.1"
+ resolved "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz"
+ integrity sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==
+ dependencies:
+ node-domexception "1.0.0"
+ web-streams-polyfill "4.0.0-beta.3"
fragment-cache@^0.2.1:
version "0.2.1"
- resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
- integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=
+ resolved "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz"
+ integrity sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==
dependencies:
map-cache "^0.2.2"
-fresh@0.5.2:
- version "0.5.2"
- resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
- integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
-
-fs-capacitor@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/fs-capacitor/-/fs-capacitor-1.0.1.tgz#ff9dbfa14dfaf4472537720f19c3088ed9278df0"
- integrity sha512-XdZK0Q78WP29Vm3FGgJRhRhrBm51PagovzWtW2kJ3Q6cYJbGtZqWSGTSPwvtEkyjIirFd7b8Yes/dpOYjt4RRQ==
-
-fs-capacitor@^2.0.4:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/fs-capacitor/-/fs-capacitor-2.0.4.tgz#5a22e72d40ae5078b4fe64fe4d08c0d3fc88ad3c"
- integrity sha512-8S4f4WsCryNw2mJJchi46YgB6CR5Ze+4L1h8ewl9tEpL4SJ3ZO+c/bS4BWhB8bK+O3TMqhuZarTitd0S0eh2pA==
-
fs.realpath@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
- integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
+ resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
+ integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
-fsevents@^2.1.2, fsevents@~2.1.2:
- version "2.1.3"
- resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e"
- integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==
+fsevents@^2.1.2, fsevents@~2.3.2:
+ version "2.3.2"
+ resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz"
+ integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
function-bind@^1.1.1:
version "1.1.1"
- resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
+ resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+function.prototype.name@^1.1.5:
+ version "1.1.5"
+ resolved "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz"
+ integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==
+ dependencies:
+ call-bind "^1.0.2"
+ define-properties "^1.1.3"
+ es-abstract "^1.19.0"
+ functions-have-names "^1.2.2"
+
functional-red-black-tree@^1.0.1:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
- integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
+ resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz"
+ integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==
+
+functions-have-names@^1.2.2:
+ version "1.2.3"
+ resolved "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz"
+ integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==
-gensync@^1.0.0-beta.1:
- version "1.0.0-beta.1"
- resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269"
- integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==
+gensync@^1.0.0-beta.2:
+ version "1.0.0-beta.2"
+ resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz"
+ integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
get-caller-file@^2.0.1:
version "2.0.5"
- resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
+ resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
+get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1:
+ version "1.1.2"
+ resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz"
+ integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==
+ dependencies:
+ function-bind "^1.1.1"
+ has "^1.0.3"
+ has-symbols "^1.0.3"
+
get-package-type@^0.1.0:
version "0.1.0"
- resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a"
+ resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz"
integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==
-get-stdin@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
- integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=
-
get-stdin@^6.0.0:
version "6.0.0"
- resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b"
+ resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz"
integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==
get-stream@^4.0.0:
version "4.1.0"
- resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
+ resolved "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz"
integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
dependencies:
pump "^3.0.0"
get-stream@^5.0.0:
version "5.2.0"
- resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
+ resolved "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz"
integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
dependencies:
pump "^3.0.0"
+get-symbol-description@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz"
+ integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==
+ dependencies:
+ call-bind "^1.0.2"
+ get-intrinsic "^1.1.1"
+
get-value@^2.0.3, get-value@^2.0.6:
version "2.0.6"
- resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
- integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
+ resolved "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz"
+ integrity sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==
-glob-parent@^5.0.0, glob-parent@~5.1.0:
+glob-parent@^5.1.2, glob-parent@~5.1.2:
version "5.1.2"
- resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
+ resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz"
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
dependencies:
is-glob "^4.0.1"
-glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
- version "7.1.6"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
- integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
+glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4:
+ version "7.2.3"
+ resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz"
+ integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
- minimatch "^3.0.4"
+ minimatch "^3.1.1"
once "^1.3.0"
path-is-absolute "^1.0.0"
globals@^11.1.0:
version "11.12.0"
- resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
+ resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz"
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
-globals@^12.1.0:
- version "12.4.0"
- resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8"
- integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==
- dependencies:
- type-fest "^0.8.1"
-
-graceful-fs@^4.1.2, graceful-fs@^4.2.4:
- version "4.2.4"
- resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
- integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==
-
-graphql-deduplicator@^2.0.1:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/graphql-deduplicator/-/graphql-deduplicator-2.0.6.tgz#83ba9225235531de7be47fdf9fa6d6395d48565c"
- integrity sha512-sm9tNL+9qqIrKBb7Ovy8opUE+WKuK/r+hvcP49VL8Kop6slRJn7a5vW2wRNrMfZAZ5p9KHmJ3AkB/3j+Q6d+LA==
-
-graphql-extensions@^0.0.x, graphql-extensions@~0.0.9:
- version "0.0.10"
- resolved "https://registry.yarnpkg.com/graphql-extensions/-/graphql-extensions-0.0.10.tgz#34bdb2546d43f6a5bc89ab23c295ec0466c6843d"
- integrity sha512-TnQueqUDCYzOSrpQb3q1ngDSP2otJSF+9yNLrQGPzkMsvnQ+v6e2d5tl+B35D4y+XpmvVnAn4T3ZK28mkILveA==
- dependencies:
- core-js "^2.5.3"
- source-map-support "^0.5.1"
-
-graphql-import@^0.7.0:
- version "0.7.1"
- resolved "https://registry.yarnpkg.com/graphql-import/-/graphql-import-0.7.1.tgz#4add8d91a5f752d764b0a4a7a461fcd93136f223"
- integrity sha512-YpwpaPjRUVlw2SN3OPljpWbVRWAhMAyfSba5U47qGMOSsPLi2gYeJtngGpymjm9nk57RFWEpjqwh4+dpYuFAPw==
- dependencies:
- lodash "^4.17.4"
- resolve-from "^4.0.0"
-
-graphql-middleware@4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/graphql-middleware/-/graphql-middleware-4.0.1.tgz#8c627b22cc046a47e9474a813cf9e0bd50fa0c4b"
- integrity sha512-r9r+pcHV4yZW7LAOcjQYTbNY6nR9SrLgpVZKbrtgXxpQW/MUc1N8q3PESciebvp5s0EEUgRchcRjUkyaArCIFw==
- dependencies:
- graphql-tools "^4.0.5"
-
-graphql-playground-html@1.6.12:
- version "1.6.12"
- resolved "https://registry.yarnpkg.com/graphql-playground-html/-/graphql-playground-html-1.6.12.tgz#8b3b34ab6013e2c877f0ceaae478fafc8ca91b85"
- integrity sha512-yOYFwwSMBL0MwufeL8bkrNDgRE7eF/kTHiwrqn9FiR9KLcNIl1xw9l9a+6yIRZM56JReQOHpbQFXTZn1IuSKRg==
-
-graphql-playground-middleware-express@1.7.11:
- version "1.7.11"
- resolved "https://registry.yarnpkg.com/graphql-playground-middleware-express/-/graphql-playground-middleware-express-1.7.11.tgz#bbffd784a37133bfa7165bdd8f429081dbf4bcf6"
- integrity sha512-sKItB4s3FxqlwCgXdMfwRAfssSoo31bcFsGAAg/HzaZLicY6CDlofKXP8G5iPDerB6NaoAcAaBLutLzl9sd4fQ==
- dependencies:
- graphql-playground-html "1.6.12"
-
-graphql-playground-middleware-lambda@1.7.12:
- version "1.7.12"
- resolved "https://registry.yarnpkg.com/graphql-playground-middleware-lambda/-/graphql-playground-middleware-lambda-1.7.12.tgz#1b06440a288dbcd53f935b43e5b9ca2738a06305"
- integrity sha512-fJ1Y0Ck5ctmfaQFoWv7vNnVP7We19P3miVmOT85YPrjpzbMYv0wPfxm4Zjt8nnqXr0KU9nGW53tz3K7/Lvzxtw==
+globals@^13.6.0, globals@^13.9.0:
+ version "13.17.0"
+ resolved "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz"
+ integrity sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==
dependencies:
- graphql-playground-html "1.6.12"
+ type-fest "^0.20.2"
-graphql-shield@6.1.0:
- version "6.1.0"
- resolved "https://registry.yarnpkg.com/graphql-shield/-/graphql-shield-6.1.0.tgz#7298af72167e7c9fd19a36fac9b425b94025a393"
- integrity sha512-dIZ6ABnUn3XQtIzw9/9f8wFmZoY5XZlsHgkxSKF+N/oXmKvQoi11J5/y/jxJTBmKYi/2JZ12C1JjDn5TOopn+w==
+globby@^11.0.3:
+ version "11.1.0"
+ resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz"
+ integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
dependencies:
- "@types/yup" "0.26.23"
- lightercollective "^0.3.0"
- object-hash "^1.3.1"
- yup "^0.27.0"
+ array-union "^2.1.0"
+ dir-glob "^3.0.1"
+ fast-glob "^3.2.9"
+ ignore "^5.2.0"
+ merge2 "^1.4.1"
+ slash "^3.0.0"
-graphql-subscriptions@^0.5.8:
- version "0.5.8"
- resolved "https://registry.yarnpkg.com/graphql-subscriptions/-/graphql-subscriptions-0.5.8.tgz#13a6143c546bce390404657dc73ca501def30aa7"
- integrity sha512-0CaZnXKBw2pwnIbvmVckby5Ge5e2ecmjofhYCdyeACbCly2j3WXDP/pl+s+Dqd2GQFC7y99NB+53jrt55CKxYQ==
- dependencies:
- iterall "^1.2.1"
+graceful-fs@^4.2.4:
+ version "4.2.10"
+ resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz"
+ integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
-graphql-tools@^4.0.0, graphql-tools@^4.0.5:
- version "4.0.8"
- resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-4.0.8.tgz#e7fb9f0d43408fb0878ba66b522ce871bafe9d30"
- integrity sha512-MW+ioleBrwhRjalKjYaLQbr+920pHBgy9vM/n47sswtns8+96sRn5M/G+J1eu7IMeKWiN/9p6tmwCHU7552VJg==
- dependencies:
- apollo-link "^1.2.14"
- apollo-utilities "^1.0.1"
- deprecated-decorator "^0.1.6"
- iterall "^1.1.3"
- uuid "^3.1.0"
-
-graphql-upload@8.0.7:
- version "8.0.7"
- resolved "https://registry.yarnpkg.com/graphql-upload/-/graphql-upload-8.0.7.tgz#8644264e241529552ea4b3797e7ee15809cf01a3"
- integrity sha512-gi2yygbDPXbHPC7H0PNPqP++VKSoNoJO4UrXWq4T0Bi4IhyUd3Ycop/FSxhx2svWIK3jdXR/i0vi91yR1aAF0g==
- dependencies:
- busboy "^0.3.1"
- fs-capacitor "^2.0.4"
- http-errors "^1.7.2"
- object-path "^0.11.4"
-
-graphql-upload@^8.0.0:
- version "8.1.0"
- resolved "https://registry.yarnpkg.com/graphql-upload/-/graphql-upload-8.1.0.tgz#6d0ab662db5677a68bfb1f2c870ab2544c14939a"
- integrity sha512-U2OiDI5VxYmzRKw0Z2dmfk0zkqMRaecH9Smh1U277gVgVe9Qn+18xqf4skwr4YJszGIh7iQDZ57+5ygOK9sM/Q==
- dependencies:
- busboy "^0.3.1"
- fs-capacitor "^2.0.4"
- http-errors "^1.7.3"
- object-path "^0.11.4"
-
-graphql-yoga@^1.18.3:
- version "1.18.3"
- resolved "https://registry.yarnpkg.com/graphql-yoga/-/graphql-yoga-1.18.3.tgz#047fa511dbef63cf6d6ea7c06a71202d37444844"
- integrity sha512-tR6JYbwLSBVu0Z8M7BIyt1PHhhexmRwneYM8Ru/g2pixrtsWbelBFAXU7bDPhXrqZ49Zxt2zLJ60x3bLNGo/bQ==
- dependencies:
- "@types/aws-lambda" "8.10.13"
- "@types/cors" "^2.8.4"
- "@types/express" "^4.11.1"
- "@types/graphql" "^14.0.0"
- "@types/graphql-deduplicator" "^2.0.0"
- "@types/zen-observable" "^0.5.3"
- apollo-server-express "^1.3.6"
- apollo-server-lambda "1.3.6"
- apollo-upload-server "^7.0.0"
- body-parser-graphql "1.1.0"
- cors "^2.8.4"
- express "^4.16.3"
- graphql "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0"
- graphql-deduplicator "^2.0.1"
- graphql-import "^0.7.0"
- graphql-middleware "4.0.1"
- graphql-playground-middleware-express "1.7.11"
- graphql-playground-middleware-lambda "1.7.12"
- graphql-subscriptions "^0.5.8"
- graphql-tools "^4.0.0"
- graphql-upload "^8.0.0"
- subscriptions-transport-ws "^0.9.8"
-
-graphql@*, graphql@^15.3.0:
- version "15.3.0"
- resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.3.0.tgz#3ad2b0caab0d110e3be4a5a9b2aa281e362b5278"
- integrity sha512-GTCJtzJmkFLWRfFJuoo9RWWa/FfamUHgiFosxi/X1Ani4AVWbeyBenZTNX6dM+7WSbbFfTo/25eh0LLkwHMw2w==
-
-"graphql@^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0":
- version "14.7.0"
- resolved "https://registry.yarnpkg.com/graphql/-/graphql-14.7.0.tgz#7fa79a80a69be4a31c27dda824dc04dac2035a72"
- integrity sha512-l0xWZpoPKpppFzMfvVyFmp9vLN7w/ZZJPefUicMCepfJeQ8sMcztloGYY9DfjVPo6tIUDzU5Hw3MUbIjj9AVVA==
- dependencies:
- iterall "^1.2.2"
+graphql@^16.5.0:
+ version "16.6.0"
+ resolved "https://registry.npmjs.org/graphql/-/graphql-16.6.0.tgz"
+ integrity sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==
growly@^1.3.0:
version "1.3.0"
- resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
- integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=
+ resolved "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz"
+ integrity sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==
+
+has-bigints@^1.0.1, has-bigints@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz"
+ integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==
has-flag@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
- integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
+ resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz"
+ integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
has-flag@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
+ resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
-has-symbols@^1.0.0, has-symbols@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
- integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
+has-property-descriptors@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz"
+ integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==
+ dependencies:
+ get-intrinsic "^1.1.1"
+
+has-symbols@^1.0.2, has-symbols@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz"
+ integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
+
+has-tostringtag@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz"
+ integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==
+ dependencies:
+ has-symbols "^1.0.2"
has-value@^0.3.1:
version "0.3.1"
- resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
- integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=
+ resolved "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz"
+ integrity sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==
dependencies:
get-value "^2.0.3"
has-values "^0.1.4"
@@ -2699,8 +2616,8 @@ has-value@^0.3.1:
has-value@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177"
- integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=
+ resolved "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz"
+ integrity sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==
dependencies:
get-value "^2.0.6"
has-values "^1.0.0"
@@ -2708,77 +2625,44 @@ has-value@^1.0.0:
has-values@^0.1.4:
version "0.1.4"
- resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771"
- integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E=
+ resolved "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz"
+ integrity sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==
has-values@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f"
- integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=
+ resolved "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz"
+ integrity sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==
dependencies:
is-number "^3.0.0"
kind-of "^4.0.0"
has@^1.0.3:
version "1.0.3"
- resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
+ resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz"
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
dependencies:
function-bind "^1.1.1"
hosted-git-info@^2.1.4:
- version "2.8.8"
- resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488"
- integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==
+ version "2.8.9"
+ resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz"
+ integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
html-encoding-sniffer@^2.0.1:
version "2.0.1"
- resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3"
+ resolved "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz"
integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==
dependencies:
whatwg-encoding "^1.0.5"
html-escaper@^2.0.0:
version "2.0.2"
- resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
+ resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz"
integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
-http-errors@1.7.2:
- version "1.7.2"
- resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
- integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
- dependencies:
- depd "~1.1.2"
- inherits "2.0.3"
- setprototypeof "1.1.1"
- statuses ">= 1.5.0 < 2"
- toidentifier "1.0.0"
-
-http-errors@^1.7.0, http-errors@^1.7.2, http-errors@^1.7.3:
- version "1.8.0"
- resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.0.tgz#75d1bbe497e1044f51e4ee9e704a62f28d336507"
- integrity sha512-4I8r0C5JDhT5VkvI47QktDW75rNlGVsUf/8hzjCC/wkWI/jdTRmBb9aI7erSG82r1bjKY3F6k28WnsVxB1C73A==
- dependencies:
- depd "~1.1.2"
- inherits "2.0.4"
- setprototypeof "1.2.0"
- statuses ">= 1.5.0 < 2"
- toidentifier "1.0.0"
-
-http-errors@~1.7.2:
- version "1.7.3"
- resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
- integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==
- dependencies:
- depd "~1.1.2"
- inherits "2.0.4"
- setprototypeof "1.1.1"
- statuses ">= 1.5.0 < 2"
- toidentifier "1.0.0"
-
http-proxy-agent@^4.0.1:
version "4.0.1"
- resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a"
+ resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz"
integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==
dependencies:
"@tootallnate/once" "1"
@@ -2787,7 +2671,7 @@ http-proxy-agent@^4.0.1:
https-proxy-agent@^5.0.0:
version "5.0.1"
- resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
+ resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz"
integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==
dependencies:
agent-base "6"
@@ -2795,151 +2679,163 @@ https-proxy-agent@^5.0.0:
human-signals@^1.1.1:
version "1.1.1"
- resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
+ resolved "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz"
integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
iconv-lite@0.4.24:
version "0.4.24"
- resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
+ resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz"
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
dependencies:
safer-buffer ">= 2.1.2 < 3"
ignore@^4.0.6:
version "4.0.6"
- resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
+ resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz"
integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
-ignore@^5.0.5:
- version "5.1.8"
- resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
- integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
+ignore@^5.0.5, ignore@^5.1.8, ignore@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz"
+ integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==
-import-fresh@^3.0.0:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66"
- integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==
+import-fresh@^3.0.0, import-fresh@^3.2.1:
+ version "3.3.0"
+ resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz"
+ integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
dependencies:
parent-module "^1.0.0"
resolve-from "^4.0.0"
import-local@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.2.tgz#a8cfd0431d1de4a2199703d003e3e62364fa6db6"
- integrity sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==
+ version "3.1.0"
+ resolved "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz"
+ integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==
dependencies:
pkg-dir "^4.2.0"
resolve-cwd "^3.0.0"
imurmurhash@^0.1.4:
version "0.1.4"
- resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
- integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
-
-indent-string@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80"
- integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=
- dependencies:
- repeating "^2.0.0"
+ resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz"
+ integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
inflight@^1.0.4:
version "1.0.6"
- resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
- integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
+ resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz"
+ integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
dependencies:
once "^1.3.0"
wrappy "1"
-inherits@2, inherits@2.0.4, inherits@~2.0.1:
+inherits@2, inherits@^2.0.3:
version "2.0.4"
- resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+ resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
-inherits@2.0.3:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
- integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
-
-internal-slot@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.2.tgz#9c2e9fb3cd8e5e4256c6f45fe310067fcfa378a3"
- integrity sha512-2cQNfwhAfJIkU4KZPkDI+Gj5yNNnbqi40W9Gge6dfnk4TocEVm00B3bdiL+JINrbGJil2TeHvM4rETGzk/f/0g==
+internal-slot@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz"
+ integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==
dependencies:
- es-abstract "^1.17.0-next.1"
+ get-intrinsic "^1.1.0"
has "^1.0.3"
- side-channel "^1.0.2"
-
-ipaddr.js@1.9.1:
- version "1.9.1"
- resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
- integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
+ side-channel "^1.0.4"
is-accessor-descriptor@^0.1.6:
version "0.1.6"
- resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
- integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=
+ resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz"
+ integrity sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==
dependencies:
kind-of "^3.0.2"
is-accessor-descriptor@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656"
+ resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz"
integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==
dependencies:
kind-of "^6.0.0"
is-arrayish@^0.2.1:
version "0.2.1"
- resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
- integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
+ resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz"
+ integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
+
+is-arrayish@^0.3.1:
+ version "0.3.2"
+ resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz"
+ integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
+
+is-bigint@^1.0.1:
+ version "1.0.4"
+ resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz"
+ integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==
+ dependencies:
+ has-bigints "^1.0.1"
is-binary-path@~2.1.0:
version "2.1.0"
- resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
+ resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz"
integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
dependencies:
binary-extensions "^2.0.0"
+is-boolean-object@^1.1.0:
+ version "1.1.2"
+ resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz"
+ integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==
+ dependencies:
+ call-bind "^1.0.2"
+ has-tostringtag "^1.0.0"
+
is-buffer@^1.1.5:
version "1.1.6"
- resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
+ resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
-is-callable@^1.1.4, is-callable@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb"
- integrity sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==
+is-callable@^1.1.4, is-callable@^1.2.4:
+ version "1.2.4"
+ resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz"
+ integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==
is-ci@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c"
+ resolved "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz"
integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==
dependencies:
ci-info "^2.0.0"
+is-core-module@^2.8.1, is-core-module@^2.9.0:
+ version "2.10.0"
+ resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz"
+ integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==
+ dependencies:
+ has "^1.0.3"
+
is-data-descriptor@^0.1.4:
version "0.1.4"
- resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
- integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=
+ resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz"
+ integrity sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==
dependencies:
kind-of "^3.0.2"
is-data-descriptor@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7"
+ resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz"
integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==
dependencies:
kind-of "^6.0.0"
is-date-object@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e"
- integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==
+ version "1.0.5"
+ resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz"
+ integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==
+ dependencies:
+ has-tostringtag "^1.0.0"
is-descriptor@^0.1.0:
version "0.1.6"
- resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
+ resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz"
integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==
dependencies:
is-accessor-descriptor "^0.1.6"
@@ -2948,7 +2844,7 @@ is-descriptor@^0.1.0:
is-descriptor@^1.0.0, is-descriptor@^1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec"
+ resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz"
integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==
dependencies:
is-accessor-descriptor "^1.0.0"
@@ -2956,169 +2852,178 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2:
kind-of "^6.0.2"
is-docker@^2.0.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.1.1.tgz#4125a88e44e450d384e09047ede71adc2d144156"
- integrity sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==
+ version "2.2.1"
+ resolved "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz"
+ integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==
is-extendable@^0.1.0, is-extendable@^0.1.1:
version "0.1.1"
- resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
- integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=
+ resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz"
+ integrity sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==
is-extendable@^1.0.1:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4"
+ resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz"
integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==
dependencies:
is-plain-object "^2.0.4"
is-extglob@^2.1.1:
version "2.1.1"
- resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+ resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz"
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
-is-finite@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3"
- integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==
-
-is-fullwidth-code-point@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
- integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
-
is-fullwidth-code-point@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
+ resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz"
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
is-generator-fn@^2.0.0:
version "2.1.0"
- resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118"
+ resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz"
integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==
-is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1:
+is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
version "4.0.3"
- resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
+ resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz"
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
dependencies:
is-extglob "^2.1.1"
+is-negative-zero@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz"
+ integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==
+
+is-number-object@^1.0.4:
+ version "1.0.7"
+ resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz"
+ integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==
+ dependencies:
+ has-tostringtag "^1.0.0"
+
is-number@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
- integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=
+ resolved "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz"
+ integrity sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==
dependencies:
kind-of "^3.0.2"
is-number@^7.0.0:
version "7.0.0"
- resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+ resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
is-plain-object@^2.0.3, is-plain-object@^2.0.4:
version "2.0.4"
- resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
+ resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz"
integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
dependencies:
isobject "^3.0.1"
is-potential-custom-element-name@^1.0.1:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5"
+ resolved "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz"
integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==
is-redirect@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24"
- integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=
+ resolved "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz"
+ integrity sha512-cr/SlUEe5zOGmzvj9bUyC4LVvkNVAXu4GytXLNMr1pny+a65MpQ9IJzFHD5vi7FyJgb4qt27+eS3TuQnqB+RQw==
-is-regex@^1.1.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9"
- integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==
+is-regex@^1.1.4:
+ version "1.1.4"
+ resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz"
+ integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==
dependencies:
- has-symbols "^1.0.1"
+ call-bind "^1.0.2"
+ has-tostringtag "^1.0.0"
+
+is-shared-array-buffer@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz"
+ integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==
+ dependencies:
+ call-bind "^1.0.2"
is-stream@^1.1.0:
version "1.1.0"
- resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
- integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
+ resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz"
+ integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==
is-stream@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3"
- integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==
+ version "2.0.1"
+ resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz"
+ integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
-is-string@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6"
- integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==
+is-string@^1.0.5, is-string@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz"
+ integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==
+ dependencies:
+ has-tostringtag "^1.0.0"
-is-symbol@^1.0.2:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937"
- integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==
+is-symbol@^1.0.2, is-symbol@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz"
+ integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==
dependencies:
- has-symbols "^1.0.1"
+ has-symbols "^1.0.2"
is-typedarray@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
- integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
+ resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz"
+ integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==
-is-utf8@^0.2.0:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
- integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
+is-weakref@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz"
+ integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==
+ dependencies:
+ call-bind "^1.0.2"
is-windows@^1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
+ resolved "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz"
integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
is-wsl@^2.2.0:
version "2.2.0"
- resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271"
+ resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz"
integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==
dependencies:
is-docker "^2.0.0"
-isarray@0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
- integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
-
-isarray@1.0.0, isarray@^1.0.0:
+isarray@1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
- integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
+ resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
+ integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==
isexe@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
- integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
+ resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz"
+ integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
isobject@^2.0.0:
version "2.1.0"
- resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
- integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=
+ resolved "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz"
+ integrity sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==
dependencies:
isarray "1.0.0"
isobject@^3.0.0, isobject@^3.0.1:
version "3.0.1"
- resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
- integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
+ resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz"
+ integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==
-istanbul-lib-coverage@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec"
- integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==
+istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz"
+ integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==
-istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3:
+istanbul-lib-instrument@^4.0.3:
version "4.0.3"
- resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d"
+ resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz"
integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==
dependencies:
"@babel/core" "^7.7.5"
@@ -3126,9 +3031,20 @@ istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3:
istanbul-lib-coverage "^3.0.0"
semver "^6.3.0"
+istanbul-lib-instrument@^5.0.4:
+ version "5.2.0"
+ resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz"
+ integrity sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==
+ dependencies:
+ "@babel/core" "^7.12.3"
+ "@babel/parser" "^7.14.7"
+ "@istanbuljs/schema" "^0.1.2"
+ istanbul-lib-coverage "^3.2.0"
+ semver "^6.3.0"
+
istanbul-lib-report@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6"
+ resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz"
integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==
dependencies:
istanbul-lib-coverage "^3.0.0"
@@ -3136,428 +3052,416 @@ istanbul-lib-report@^3.0.0:
supports-color "^7.1.0"
istanbul-lib-source-maps@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz#75743ce6d96bb86dc7ee4352cf6366a23f0b1ad9"
- integrity sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==
+ version "4.0.1"
+ resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz"
+ integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==
dependencies:
debug "^4.1.1"
istanbul-lib-coverage "^3.0.0"
source-map "^0.6.1"
istanbul-reports@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b"
- integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==
+ version "3.1.5"
+ resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz"
+ integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==
dependencies:
html-escaper "^2.0.0"
istanbul-lib-report "^3.0.0"
-iterall@^1.1.3, iterall@^1.2.1, iterall@^1.2.2:
+iterall@^1.3.0:
version "1.3.0"
- resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea"
+ resolved "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz"
integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==
-jest-changed-files@^26.2.0:
- version "26.2.0"
- resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.2.0.tgz#b4946201defe0c919a2f3d601e9f98cb21dacc15"
- integrity sha512-+RyJb+F1K/XBLIYiL449vo5D+CvlHv29QveJUWNPXuUicyZcq+tf1wNxmmFeRvAU1+TzhwqczSjxnCCFt7+8iA==
+jest-changed-files@^26.6.2:
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz"
+ integrity sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==
dependencies:
- "@jest/types" "^26.2.0"
+ "@jest/types" "^26.6.2"
execa "^4.0.0"
throat "^5.0.0"
-jest-cli@^26.2.2:
- version "26.2.2"
- resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.2.2.tgz#4c273e5474baafac1eb15fd25aaafb4703f5ffbc"
- integrity sha512-vVcly0n/ijZvdy6gPQiQt0YANwX2hLTPQZHtW7Vi3gcFdKTtif7YpI85F8R8JYy5DFSWz4x1OW0arnxlziu5Lw==
+jest-cli@^26.6.3:
+ version "26.6.3"
+ resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz"
+ integrity sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==
dependencies:
- "@jest/core" "^26.2.2"
- "@jest/test-result" "^26.2.0"
- "@jest/types" "^26.2.0"
+ "@jest/core" "^26.6.3"
+ "@jest/test-result" "^26.6.2"
+ "@jest/types" "^26.6.2"
chalk "^4.0.0"
exit "^0.1.2"
graceful-fs "^4.2.4"
import-local "^3.0.2"
is-ci "^2.0.0"
- jest-config "^26.2.2"
- jest-util "^26.2.0"
- jest-validate "^26.2.0"
+ jest-config "^26.6.3"
+ jest-util "^26.6.2"
+ jest-validate "^26.6.2"
prompts "^2.0.1"
- yargs "^15.3.1"
+ yargs "^15.4.1"
-jest-config@^26.2.2:
- version "26.2.2"
- resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.2.2.tgz#f3ebc7e2bc3f49de8ed3f8007152f345bb111917"
- integrity sha512-2lhxH0y4YFOijMJ65usuf78m7+9/8+hAb1PZQtdRdgnQpAb4zP6KcVDDktpHEkspBKnc2lmFu+RQdHukUUbiTg==
+jest-config@^26.6.3:
+ version "26.6.3"
+ resolved "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz"
+ integrity sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==
dependencies:
"@babel/core" "^7.1.0"
- "@jest/test-sequencer" "^26.2.2"
- "@jest/types" "^26.2.0"
- babel-jest "^26.2.2"
+ "@jest/test-sequencer" "^26.6.3"
+ "@jest/types" "^26.6.2"
+ babel-jest "^26.6.3"
chalk "^4.0.0"
deepmerge "^4.2.2"
glob "^7.1.1"
graceful-fs "^4.2.4"
- jest-environment-jsdom "^26.2.0"
- jest-environment-node "^26.2.0"
- jest-get-type "^26.0.0"
- jest-jasmine2 "^26.2.2"
+ jest-environment-jsdom "^26.6.2"
+ jest-environment-node "^26.6.2"
+ jest-get-type "^26.3.0"
+ jest-jasmine2 "^26.6.3"
jest-regex-util "^26.0.0"
- jest-resolve "^26.2.2"
- jest-util "^26.2.0"
- jest-validate "^26.2.0"
+ jest-resolve "^26.6.2"
+ jest-util "^26.6.2"
+ jest-validate "^26.6.2"
micromatch "^4.0.2"
- pretty-format "^26.2.0"
-
-jest-diff@^25.2.1:
- version "25.5.0"
- resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.5.0.tgz#1dd26ed64f96667c068cef026b677dfa01afcfa9"
- integrity sha512-z1kygetuPiREYdNIumRpAHY6RXiGmp70YHptjdaxTWGmA085W3iCnXNx0DhflK3vwrKmrRWyY1wUpkPMVxMK7A==
- dependencies:
- chalk "^3.0.0"
- diff-sequences "^25.2.6"
- jest-get-type "^25.2.6"
- pretty-format "^25.5.0"
+ pretty-format "^26.6.2"
-jest-diff@^26.2.0:
- version "26.2.0"
- resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.2.0.tgz#dee62c771adbb23ae585f3f1bd289a6e8ef4f298"
- integrity sha512-Wu4Aopi2nzCsHWLBlD48TgRy3Z7OsxlwvHNd1YSnHc7q1NJfrmyCPoUXrTIrydQOG5ApaYpsAsdfnMbJqV1/wQ==
+jest-diff@^26.0.0, jest-diff@^26.6.2:
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz"
+ integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==
dependencies:
chalk "^4.0.0"
- diff-sequences "^26.0.0"
- jest-get-type "^26.0.0"
- pretty-format "^26.2.0"
+ diff-sequences "^26.6.2"
+ jest-get-type "^26.3.0"
+ pretty-format "^26.6.2"
jest-docblock@^26.0.0:
version "26.0.0"
- resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5"
+ resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz"
integrity sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==
dependencies:
detect-newline "^3.0.0"
-jest-each@^26.2.0:
- version "26.2.0"
- resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.2.0.tgz#aec8efa01d072d7982c900e74940863385fa884e"
- integrity sha512-gHPCaho1twWHB5bpcfnozlc6mrMi+VAewVPNgmwf81x2Gzr6XO4dl+eOrwPWxbkYlgjgrYjWK2xgKnixbzH3Ew==
+jest-each@^26.6.2:
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz"
+ integrity sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==
dependencies:
- "@jest/types" "^26.2.0"
+ "@jest/types" "^26.6.2"
chalk "^4.0.0"
- jest-get-type "^26.0.0"
- jest-util "^26.2.0"
- pretty-format "^26.2.0"
-
-jest-environment-jsdom@^26.2.0:
- version "26.2.0"
- resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.2.0.tgz#6443a6f3569297dcaa4371dddf93acaf167302dc"
- integrity sha512-sDG24+5M4NuIGzkI3rJW8XUlrpkvIdE9Zz4jhD8OBnVxAw+Y1jUk9X+lAOD48nlfUTlnt3lbAI3k2Ox+WF3S0g==
- dependencies:
- "@jest/environment" "^26.2.0"
- "@jest/fake-timers" "^26.2.0"
- "@jest/types" "^26.2.0"
+ jest-get-type "^26.3.0"
+ jest-util "^26.6.2"
+ pretty-format "^26.6.2"
+
+jest-environment-jsdom@^26.6.2:
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz"
+ integrity sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q==
+ dependencies:
+ "@jest/environment" "^26.6.2"
+ "@jest/fake-timers" "^26.6.2"
+ "@jest/types" "^26.6.2"
"@types/node" "*"
- jest-mock "^26.2.0"
- jest-util "^26.2.0"
- jsdom "^16.2.2"
-
-jest-environment-node@^26.2.0:
- version "26.2.0"
- resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.2.0.tgz#fee89e06bdd4bed3f75ee2978d73ede9bb57a681"
- integrity sha512-4M5ExTYkJ19efBzkiXtBi74JqKLDciEk4CEsp5tTjWGYMrlKFQFtwIVG3tW1OGE0AlXhZjuHPwubuRYY4j4uOw==
- dependencies:
- "@jest/environment" "^26.2.0"
- "@jest/fake-timers" "^26.2.0"
- "@jest/types" "^26.2.0"
+ jest-mock "^26.6.2"
+ jest-util "^26.6.2"
+ jsdom "^16.4.0"
+
+jest-environment-node@^26.6.2:
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz"
+ integrity sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==
+ dependencies:
+ "@jest/environment" "^26.6.2"
+ "@jest/fake-timers" "^26.6.2"
+ "@jest/types" "^26.6.2"
"@types/node" "*"
- jest-mock "^26.2.0"
- jest-util "^26.2.0"
+ jest-mock "^26.6.2"
+ jest-util "^26.6.2"
-jest-get-type@^25.2.6:
- version "25.2.6"
- resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877"
- integrity sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig==
+jest-get-type@^26.3.0:
+ version "26.3.0"
+ resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz"
+ integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==
-jest-get-type@^26.0.0:
- version "26.0.0"
- resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.0.0.tgz#381e986a718998dbfafcd5ec05934be538db4039"
- integrity sha512-zRc1OAPnnws1EVfykXOj19zo2EMw5Hi6HLbFCSjpuJiXtOWAYIjNsHVSbpQ8bDX7L5BGYGI8m+HmKdjHYFF0kg==
-
-jest-haste-map@^26.2.2:
- version "26.2.2"
- resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.2.2.tgz#6d4267b1903854bfdf6a871419f35a82f03ae71e"
- integrity sha512-3sJlMSt+NHnzCB+0KhJ1Ut4zKJBiJOlbrqEYNdRQGlXTv8kqzZWjUKQRY3pkjmlf+7rYjAV++MQ4D6g4DhAyOg==
+jest-haste-map@^26.6.2:
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz"
+ integrity sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==
dependencies:
- "@jest/types" "^26.2.0"
+ "@jest/types" "^26.6.2"
"@types/graceful-fs" "^4.1.2"
"@types/node" "*"
anymatch "^3.0.3"
fb-watchman "^2.0.0"
graceful-fs "^4.2.4"
jest-regex-util "^26.0.0"
- jest-serializer "^26.2.0"
- jest-util "^26.2.0"
- jest-worker "^26.2.1"
+ jest-serializer "^26.6.2"
+ jest-util "^26.6.2"
+ jest-worker "^26.6.2"
micromatch "^4.0.2"
sane "^4.0.3"
walker "^1.0.7"
optionalDependencies:
fsevents "^2.1.2"
-jest-jasmine2@^26.2.2:
- version "26.2.2"
- resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.2.2.tgz#d82b1721fac2b153a4f8b3f0c95e81e702812de2"
- integrity sha512-Q8AAHpbiZMVMy4Hz9j1j1bg2yUmPa1W9StBvcHqRaKa9PHaDUMwds8LwaDyzP/2fkybcTQE4+pTMDOG9826tEw==
+jest-jasmine2@^26.6.3:
+ version "26.6.3"
+ resolved "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz"
+ integrity sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==
dependencies:
"@babel/traverse" "^7.1.0"
- "@jest/environment" "^26.2.0"
- "@jest/source-map" "^26.1.0"
- "@jest/test-result" "^26.2.0"
- "@jest/types" "^26.2.0"
+ "@jest/environment" "^26.6.2"
+ "@jest/source-map" "^26.6.2"
+ "@jest/test-result" "^26.6.2"
+ "@jest/types" "^26.6.2"
"@types/node" "*"
chalk "^4.0.0"
co "^4.6.0"
- expect "^26.2.0"
+ expect "^26.6.2"
is-generator-fn "^2.0.0"
- jest-each "^26.2.0"
- jest-matcher-utils "^26.2.0"
- jest-message-util "^26.2.0"
- jest-runtime "^26.2.2"
- jest-snapshot "^26.2.2"
- jest-util "^26.2.0"
- pretty-format "^26.2.0"
+ jest-each "^26.6.2"
+ jest-matcher-utils "^26.6.2"
+ jest-message-util "^26.6.2"
+ jest-runtime "^26.6.3"
+ jest-snapshot "^26.6.2"
+ jest-util "^26.6.2"
+ pretty-format "^26.6.2"
throat "^5.0.0"
-jest-leak-detector@^26.2.0:
- version "26.2.0"
- resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.2.0.tgz#073ee6d8db7a9af043e7ce99d8eea17a4fb0cc50"
- integrity sha512-aQdzTX1YiufkXA1teXZu5xXOJgy7wZQw6OJ0iH5CtQlOETe6gTSocaYKUNui1SzQ91xmqEUZ/WRavg9FD82rtQ==
+jest-leak-detector@^26.6.2:
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz"
+ integrity sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==
dependencies:
- jest-get-type "^26.0.0"
- pretty-format "^26.2.0"
+ jest-get-type "^26.3.0"
+ pretty-format "^26.6.2"
-jest-matcher-utils@^26.2.0:
- version "26.2.0"
- resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.2.0.tgz#b107af98c2b8c557ffd46c1adf06f794aa52d622"
- integrity sha512-2cf/LW2VFb3ayPHrH36ZDjp9+CAeAe/pWBAwsV8t3dKcrINzXPVxq8qMWOxwt5BaeBCx4ZupVGH7VIgB8v66vQ==
+jest-matcher-utils@^26.6.2:
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz"
+ integrity sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==
dependencies:
chalk "^4.0.0"
- jest-diff "^26.2.0"
- jest-get-type "^26.0.0"
- pretty-format "^26.2.0"
+ jest-diff "^26.6.2"
+ jest-get-type "^26.3.0"
+ pretty-format "^26.6.2"
-jest-message-util@^26.2.0:
- version "26.2.0"
- resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.2.0.tgz#757fbc1323992297092bb9016a71a2eb12fd22ea"
- integrity sha512-g362RhZaJuqeqG108n1sthz5vNpzTNy926eNDszo4ncRbmmcMRIUAZibnd6s5v2XSBCChAxQtCoN25gnzp7JbQ==
+jest-message-util@^26.6.2:
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz"
+ integrity sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==
dependencies:
"@babel/code-frame" "^7.0.0"
- "@jest/types" "^26.2.0"
- "@types/stack-utils" "^1.0.1"
+ "@jest/types" "^26.6.2"
+ "@types/stack-utils" "^2.0.0"
chalk "^4.0.0"
graceful-fs "^4.2.4"
micromatch "^4.0.2"
+ pretty-format "^26.6.2"
slash "^3.0.0"
stack-utils "^2.0.2"
-jest-mock@^26.2.0:
- version "26.2.0"
- resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.2.0.tgz#a1b3303ab38c34aa1dbbc16ab57cdc1a59ed50d1"
- integrity sha512-XeC7yWtWmWByoyVOHSsE7NYsbXJLtJNgmhD7z4MKumKm6ET0si81bsSLbQ64L5saK3TgsHo2B/UqG5KNZ1Sp/Q==
+jest-mock@^26.6.2:
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz"
+ integrity sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==
dependencies:
- "@jest/types" "^26.2.0"
+ "@jest/types" "^26.6.2"
"@types/node" "*"
jest-pnp-resolver@^1.2.2:
version "1.2.2"
- resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c"
+ resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz"
integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==
jest-regex-util@^26.0.0:
version "26.0.0"
- resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28"
+ resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz"
integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==
-jest-resolve-dependencies@^26.2.2:
- version "26.2.2"
- resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.2.2.tgz#2ad3cd9281730e9a5c487cd846984c5324e47929"
- integrity sha512-S5vufDmVbQXnpP7435gr710xeBGUFcKNpNswke7RmFvDQtmqPjPVU/rCeMlEU0p6vfpnjhwMYeaVjKZAy5QYJA==
+jest-resolve-dependencies@^26.6.3:
+ version "26.6.3"
+ resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz"
+ integrity sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==
dependencies:
- "@jest/types" "^26.2.0"
+ "@jest/types" "^26.6.2"
jest-regex-util "^26.0.0"
- jest-snapshot "^26.2.2"
+ jest-snapshot "^26.6.2"
-jest-resolve@^26.2.2:
- version "26.2.2"
- resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.2.2.tgz#324a20a516148d61bffa0058ed0c77c510ecfd3e"
- integrity sha512-ye9Tj/ILn/0OgFPE/3dGpQPUqt4dHwIocxt5qSBkyzxQD8PbL0bVxBogX2FHxsd3zJA7V2H/cHXnBnNyyT9YoQ==
+jest-resolve@^26.6.2:
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz"
+ integrity sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==
dependencies:
- "@jest/types" "^26.2.0"
+ "@jest/types" "^26.6.2"
chalk "^4.0.0"
graceful-fs "^4.2.4"
jest-pnp-resolver "^1.2.2"
- jest-util "^26.2.0"
+ jest-util "^26.6.2"
read-pkg-up "^7.0.1"
- resolve "^1.17.0"
+ resolve "^1.18.1"
slash "^3.0.0"
-jest-runner@^26.2.2:
- version "26.2.2"
- resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.2.2.tgz#6d03d057886e9c782e10b2cf37443f902fe0e39e"
- integrity sha512-/qb6ptgX+KQ+aNMohJf1We695kaAfuu3u3ouh66TWfhTpLd9WbqcF6163d/tMoEY8GqPztXPLuyG0rHRVDLxCA==
+jest-runner@^26.6.3:
+ version "26.6.3"
+ resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz"
+ integrity sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==
dependencies:
- "@jest/console" "^26.2.0"
- "@jest/environment" "^26.2.0"
- "@jest/test-result" "^26.2.0"
- "@jest/types" "^26.2.0"
+ "@jest/console" "^26.6.2"
+ "@jest/environment" "^26.6.2"
+ "@jest/test-result" "^26.6.2"
+ "@jest/types" "^26.6.2"
"@types/node" "*"
chalk "^4.0.0"
emittery "^0.7.1"
exit "^0.1.2"
graceful-fs "^4.2.4"
- jest-config "^26.2.2"
+ jest-config "^26.6.3"
jest-docblock "^26.0.0"
- jest-haste-map "^26.2.2"
- jest-leak-detector "^26.2.0"
- jest-message-util "^26.2.0"
- jest-resolve "^26.2.2"
- jest-runtime "^26.2.2"
- jest-util "^26.2.0"
- jest-worker "^26.2.1"
+ jest-haste-map "^26.6.2"
+ jest-leak-detector "^26.6.2"
+ jest-message-util "^26.6.2"
+ jest-resolve "^26.6.2"
+ jest-runtime "^26.6.3"
+ jest-util "^26.6.2"
+ jest-worker "^26.6.2"
source-map-support "^0.5.6"
throat "^5.0.0"
-jest-runtime@^26.2.2:
- version "26.2.2"
- resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.2.2.tgz#2480ff79320680a643031dd21998d7c63d83ab68"
- integrity sha512-a8VXM3DxCDnCIdl9+QucWFfQ28KdqmyVFqeKLigHdErtsx56O2ZIdQkhFSuP1XtVrG9nTNHbKxjh5XL1UaFDVQ==
- dependencies:
- "@jest/console" "^26.2.0"
- "@jest/environment" "^26.2.0"
- "@jest/fake-timers" "^26.2.0"
- "@jest/globals" "^26.2.0"
- "@jest/source-map" "^26.1.0"
- "@jest/test-result" "^26.2.0"
- "@jest/transform" "^26.2.2"
- "@jest/types" "^26.2.0"
+jest-runtime@^26.6.3:
+ version "26.6.3"
+ resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz"
+ integrity sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==
+ dependencies:
+ "@jest/console" "^26.6.2"
+ "@jest/environment" "^26.6.2"
+ "@jest/fake-timers" "^26.6.2"
+ "@jest/globals" "^26.6.2"
+ "@jest/source-map" "^26.6.2"
+ "@jest/test-result" "^26.6.2"
+ "@jest/transform" "^26.6.2"
+ "@jest/types" "^26.6.2"
"@types/yargs" "^15.0.0"
chalk "^4.0.0"
+ cjs-module-lexer "^0.6.0"
collect-v8-coverage "^1.0.0"
exit "^0.1.2"
glob "^7.1.3"
graceful-fs "^4.2.4"
- jest-config "^26.2.2"
- jest-haste-map "^26.2.2"
- jest-message-util "^26.2.0"
- jest-mock "^26.2.0"
+ jest-config "^26.6.3"
+ jest-haste-map "^26.6.2"
+ jest-message-util "^26.6.2"
+ jest-mock "^26.6.2"
jest-regex-util "^26.0.0"
- jest-resolve "^26.2.2"
- jest-snapshot "^26.2.2"
- jest-util "^26.2.0"
- jest-validate "^26.2.0"
+ jest-resolve "^26.6.2"
+ jest-snapshot "^26.6.2"
+ jest-util "^26.6.2"
+ jest-validate "^26.6.2"
slash "^3.0.0"
strip-bom "^4.0.0"
- yargs "^15.3.1"
+ yargs "^15.4.1"
-jest-serializer@^26.2.0:
- version "26.2.0"
- resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.2.0.tgz#92dcae5666322410f4bf50211dd749274959ddac"
- integrity sha512-V7snZI9IVmyJEu0Qy0inmuXgnMWDtrsbV2p9CRAcmlmPVwpC2ZM8wXyYpiugDQnwLHx0V4+Pnog9Exb3UO8M6Q==
+jest-serializer@^26.6.2:
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz"
+ integrity sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==
dependencies:
"@types/node" "*"
graceful-fs "^4.2.4"
-jest-snapshot@^26.2.2:
- version "26.2.2"
- resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.2.2.tgz#9d2eda083a4a1017b157e351868749bd63211799"
- integrity sha512-NdjD8aJS7ePu268Wy/n/aR1TUisG0BOY+QOW4f6h46UHEKOgYmmkvJhh2BqdVZQ0BHSxTMt04WpCf9njzx8KtA==
+jest-snapshot@^26.6.2:
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz"
+ integrity sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==
dependencies:
"@babel/types" "^7.0.0"
- "@jest/types" "^26.2.0"
+ "@jest/types" "^26.6.2"
+ "@types/babel__traverse" "^7.0.4"
"@types/prettier" "^2.0.0"
chalk "^4.0.0"
- expect "^26.2.0"
+ expect "^26.6.2"
graceful-fs "^4.2.4"
- jest-diff "^26.2.0"
- jest-get-type "^26.0.0"
- jest-haste-map "^26.2.2"
- jest-matcher-utils "^26.2.0"
- jest-message-util "^26.2.0"
- jest-resolve "^26.2.2"
+ jest-diff "^26.6.2"
+ jest-get-type "^26.3.0"
+ jest-haste-map "^26.6.2"
+ jest-matcher-utils "^26.6.2"
+ jest-message-util "^26.6.2"
+ jest-resolve "^26.6.2"
natural-compare "^1.4.0"
- pretty-format "^26.2.0"
+ pretty-format "^26.6.2"
semver "^7.3.2"
-jest-util@26.x, jest-util@^26.2.0:
- version "26.2.0"
- resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.2.0.tgz#0597d2a27c559340957609f106c408c17c1d88ac"
- integrity sha512-YmDwJxLZ1kFxpxPfhSJ0rIkiZOM0PQbRcfH0TzJOhqCisCAsI1WcmoQqO83My9xeVA2k4n+rzg2UuexVKzPpig==
+jest-util@^26.1.0, jest-util@^26.6.2:
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz"
+ integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==
dependencies:
- "@jest/types" "^26.2.0"
+ "@jest/types" "^26.6.2"
"@types/node" "*"
chalk "^4.0.0"
graceful-fs "^4.2.4"
is-ci "^2.0.0"
micromatch "^4.0.2"
-jest-validate@^26.2.0:
- version "26.2.0"
- resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.2.0.tgz#97fedf3e7984b7608854cbf925b9ca6ebcbdb78a"
- integrity sha512-8XKn3hM6VIVmLNuyzYLCPsRCT83o8jMZYhbieh4dAyKLc4Ypr36rVKC+c8WMpWkfHHpGnEkvWUjjIAyobEIY/Q==
+jest-validate@^26.6.2:
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz"
+ integrity sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==
dependencies:
- "@jest/types" "^26.2.0"
+ "@jest/types" "^26.6.2"
camelcase "^6.0.0"
chalk "^4.0.0"
- jest-get-type "^26.0.0"
+ jest-get-type "^26.3.0"
leven "^3.1.0"
- pretty-format "^26.2.0"
+ pretty-format "^26.6.2"
-jest-watcher@^26.2.0:
- version "26.2.0"
- resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.2.0.tgz#45bdf2fecadd19c0a501f3b071a474dca636825b"
- integrity sha512-674Boco4Joe0CzgKPL6K4Z9LgyLx+ZvW2GilbpYb8rFEUkmDGgsZdv1Hv5rxsRpb1HLgKUOL/JfbttRCuFdZXQ==
+jest-watcher@^26.6.2:
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz"
+ integrity sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==
dependencies:
- "@jest/test-result" "^26.2.0"
- "@jest/types" "^26.2.0"
+ "@jest/test-result" "^26.6.2"
+ "@jest/types" "^26.6.2"
"@types/node" "*"
ansi-escapes "^4.2.1"
chalk "^4.0.0"
- jest-util "^26.2.0"
+ jest-util "^26.6.2"
string-length "^4.0.1"
-jest-worker@^26.2.1:
- version "26.2.1"
- resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.2.1.tgz#5d630ab93f666b53f911615bc13e662b382bd513"
- integrity sha512-+XcGMMJDTeEGncRb5M5Zq9P7K4sQ1sirhjdOxsN1462h6lFo9w59bl2LVQmdGEEeU3m+maZCkS2Tcc9SfCHO4A==
+jest-worker@^26.6.2:
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz"
+ integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==
dependencies:
"@types/node" "*"
merge-stream "^2.0.0"
supports-color "^7.0.0"
jest@^26.2.2:
- version "26.2.2"
- resolved "https://registry.yarnpkg.com/jest/-/jest-26.2.2.tgz#a022303887b145147204c5f66e6a5c832333c7e7"
- integrity sha512-EkJNyHiAG1+A8pqSz7cXttoVa34hOEzN/MrnJhYnfp5VHxflVcf2pu3oJSrhiy6LfIutLdWo+n6q63tjcoIeig==
+ version "26.6.3"
+ resolved "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz"
+ integrity sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==
dependencies:
- "@jest/core" "^26.2.2"
+ "@jest/core" "^26.6.3"
import-local "^3.0.2"
- jest-cli "^26.2.2"
+ jest-cli "^26.6.3"
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+ resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
js-yaml@^3.13.1:
- version "3.14.0"
- resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482"
- integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==
+ version "3.14.1"
+ resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz"
+ integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==
dependencies:
argparse "^1.0.7"
esprima "^4.0.0"
-jsdom@^16.2.2:
+jsdom@^16.4.0:
version "16.7.0"
- resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710"
+ resolved "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz"
integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==
dependencies:
abab "^2.0.5"
@@ -3590,83 +3494,91 @@ jsdom@^16.2.2:
jsesc@^2.5.1:
version "2.5.2"
- resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
+ resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz"
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
-json-parse-better-errors@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
- integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
+json-parse-even-better-errors@^2.3.0:
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz"
+ integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
json-schema-traverse@^0.4.1:
version "0.4.1"
- resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+ resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+json-schema-traverse@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz"
+ integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
+
json-stable-stringify-without-jsonify@^1.0.1:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
- integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
+ resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz"
+ integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
-json5@2.x, json5@^2.1.2:
- version "2.1.3"
- resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43"
- integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==
- dependencies:
- minimist "^1.2.5"
+json5@2.x, json5@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz"
+ integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==
json5@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
- integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz"
+ integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==
dependencies:
minimist "^1.2.0"
-jsx-ast-utils@^2.4.1:
- version "2.4.1"
- resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz#1114a4c1209481db06c690c2b4f488cc665f657e"
- integrity sha512-z1xSldJ6imESSzOjd3NNkieVJKRlKYSOtMG8SFyCj2FIrvSaSuli/WjpBkEzCBoR9bYYYFgqJw61Xhu7Lcgk+w==
+"jsx-ast-utils@^2.4.1 || ^3.0.0":
+ version "3.3.3"
+ resolved "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz"
+ integrity sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==
dependencies:
- array-includes "^3.1.1"
- object.assign "^4.1.0"
+ array-includes "^3.1.5"
+ object.assign "^4.1.3"
kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
version "3.2.2"
- resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
- integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=
+ resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz"
+ integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==
dependencies:
is-buffer "^1.1.5"
kind-of@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
- integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc=
+ resolved "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz"
+ integrity sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==
dependencies:
is-buffer "^1.1.5"
kind-of@^5.0.0:
version "5.1.0"
- resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
+ resolved "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz"
integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
kind-of@^6.0.0, kind-of@^6.0.2:
version "6.0.3"
- resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
+ resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz"
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
kleur@^3.0.3:
version "3.0.3"
- resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
+ resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz"
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
+kuler@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz"
+ integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==
+
leven@^3.1.0:
version "3.1.0"
- resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
+ resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz"
integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==
levn@^0.4.1:
version "0.4.1"
- resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
+ resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz"
integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==
dependencies:
prelude-ls "^1.2.1"
@@ -3674,163 +3586,114 @@ levn@^0.4.1:
levn@~0.3.0:
version "0.3.0"
- resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
+ resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz"
integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==
dependencies:
prelude-ls "~1.1.2"
type-check "~0.3.2"
-lightercollective@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/lightercollective/-/lightercollective-0.3.0.tgz#1f07638642ec645d70bdb69ab2777676f35a28f0"
- integrity sha512-RFOLSUVvwdK3xA0P8o6G7QGXLIyy1L2qv5caEI7zXN5ciaEjbAriRF182kbsoJ1S1TgvpyGcN485fMky6qxOPw==
-
lines-and-columns@^1.1.6:
- version "1.1.6"
- resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
- integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
-
-load-json-file@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
- integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=
- dependencies:
- graceful-fs "^4.1.2"
- parse-json "^2.2.0"
- pify "^2.0.0"
- pinkie-promise "^2.0.0"
- strip-bom "^2.0.0"
-
-load-json-file@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8"
- integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=
- dependencies:
- graceful-fs "^4.1.2"
- parse-json "^2.2.0"
- pify "^2.0.0"
- strip-bom "^3.0.0"
-
-locate-path@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
- integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=
- dependencies:
- p-locate "^2.0.0"
- path-exists "^3.0.0"
+ version "1.2.4"
+ resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz"
+ integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
locate-path@^5.0.0:
version "5.0.0"
- resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
+ resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz"
integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
dependencies:
p-locate "^4.1.0"
-lodash.memoize@4.x:
- version "4.1.2"
- resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
- integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
+lodash.merge@^4.6.2:
+ version "4.6.2"
+ resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz"
+ integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
-lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.4, lodash@^4.7.0:
+lodash.truncate@^4.4.2:
+ version "4.4.2"
+ resolved "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz"
+ integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==
+
+lodash@4.x, lodash@^4.7.0:
version "4.17.21"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+ resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
+logform@^2.3.2, logform@^2.4.0:
+ version "2.5.1"
+ resolved "https://registry.npmjs.org/logform/-/logform-2.5.1.tgz"
+ integrity sha512-9FyqAm9o9NKKfiAKfZoYo9bGXXuwMkxQiQttkT4YjjVtQVIQtK6LmVtlxmCaFswo6N4AfEkHqZTV0taDtPotNg==
+ dependencies:
+ "@colors/colors" "1.5.0"
+ "@types/triple-beam" "^1.3.2"
+ fecha "^4.2.0"
+ ms "^2.1.1"
+ safe-stable-stringify "^2.3.1"
+ triple-beam "^1.3.0"
+
loose-envify@^1.4.0:
version "1.4.0"
- resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
+ resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
-loud-rejection@^1.0.0:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
- integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=
+lru-cache@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz"
+ integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
dependencies:
- currently-unhandled "^0.4.1"
- signal-exit "^3.0.0"
+ yallist "^4.0.0"
make-dir@^3.0.0:
version "3.1.0"
- resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
+ resolved "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz"
integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==
dependencies:
semver "^6.0.0"
make-error@1.x, make-error@^1.1.1:
version "1.3.6"
- resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
+ resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
-makeerror@1.0.x:
- version "1.0.11"
- resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c"
- integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=
+makeerror@1.0.12:
+ version "1.0.12"
+ resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz"
+ integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==
dependencies:
- tmpl "1.0.x"
+ tmpl "1.0.5"
map-cache@^0.2.2:
version "0.2.2"
- resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
- integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=
-
-map-obj@^1.0.0, map-obj@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
- integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=
+ resolved "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz"
+ integrity sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==
-map-obj@^4.0.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.1.0.tgz#b91221b542734b9f14256c0132c897c5d7256fd5"
- integrity sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==
+map-obj@^4.0.0, map-obj@^4.1.0:
+ version "4.3.0"
+ resolved "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz"
+ integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==
map-visit@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"
- integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=
+ resolved "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz"
+ integrity sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==
dependencies:
object-visit "^1.0.0"
-media-typer@0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
- integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
-
-meow@^3.3.0:
- version "3.7.0"
- resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
- integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=
- dependencies:
- camelcase-keys "^2.0.0"
- decamelize "^1.1.2"
- loud-rejection "^1.0.0"
- map-obj "^1.0.1"
- minimist "^1.1.3"
- normalize-package-data "^2.3.4"
- object-assign "^4.0.1"
- read-pkg-up "^1.0.1"
- redent "^1.0.0"
- trim-newlines "^1.0.0"
-
-merge-descriptors@1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
- integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
-
merge-stream@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
+ resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz"
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
-methods@~1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
- integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
+merge2@^1.3.0, merge2@^1.4.1:
+ version "1.4.1"
+ resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
+ integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
micromatch@^3.1.4:
version "3.1.10"
- resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
+ resolved "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz"
integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==
dependencies:
arr-diff "^4.0.0"
@@ -3847,63 +3710,46 @@ micromatch@^3.1.4:
snapdragon "^0.8.1"
to-regex "^3.0.2"
-micromatch@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259"
- integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==
+micromatch@^4.0.2, micromatch@^4.0.4:
+ version "4.0.5"
+ resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz"
+ integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
dependencies:
- braces "^3.0.1"
- picomatch "^2.0.5"
-
-mime-db@1.44.0:
- version "1.44.0"
- resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92"
- integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==
+ braces "^3.0.2"
+ picomatch "^2.3.1"
mime-db@1.52.0:
version "1.52.0"
- resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
+ resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
mime-types@^2.1.12:
version "2.1.35"
- resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
+ resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz"
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
dependencies:
mime-db "1.52.0"
-mime-types@~2.1.24:
- version "2.1.27"
- resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f"
- integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==
- dependencies:
- mime-db "1.44.0"
-
-mime@1.6.0:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
- integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
-
mimic-fn@^2.1.0:
version "2.1.0"
- resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
+ resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
-minimatch@^3.0.4:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
- integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
+minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
+ integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"
-minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5:
+minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6:
version "1.2.6"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
+ resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz"
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
mixin-deep@^1.2.0:
version "1.3.2"
- resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
+ resolved "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz"
integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==
dependencies:
for-in "^1.0.2"
@@ -3911,34 +3757,32 @@ mixin-deep@^1.2.0:
mkdirp@1.x, mkdirp@^1.0.4:
version "1.0.4"
- resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
+ resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
-mkdirp@^0.5.1:
- version "0.5.5"
- resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
- integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
- dependencies:
- minimist "^1.2.5"
+moment@^2.29.1:
+ version "2.29.4"
+ resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
+ integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
ms@2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
- integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
+ resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
+ integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
-ms@2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
- integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
-
-ms@2.1.2, ms@^2.1.1:
+ms@2.1.2:
version "2.1.2"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
+ resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+ms@^2.1.1:
+ version "2.1.3"
+ resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
+ integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
nanomatch@^1.2.9:
version "1.2.13"
- resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
+ resolved "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz"
integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==
dependencies:
arr-diff "^4.0.0"
@@ -3955,44 +3799,59 @@ nanomatch@^1.2.9:
natural-compare@^1.4.0:
version "1.4.0"
- resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
- integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
+ resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz"
+ integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
-negotiator@0.6.2:
- version "0.6.2"
- resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
- integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
+nexus@^1.4.0-next.11:
+ version "1.4.0-next.11"
+ resolved "https://registry.npmjs.org/nexus/-/nexus-1.4.0-next.11.tgz"
+ integrity sha512-Vex7P3aZVNjlZjTZMWyM5XLzNzh+Hu0X5dlt989482qmsXEUD0naRHvgwHzioUDdAPHEx2UpkeDTHa8w/w8FEw==
+ dependencies:
+ iterall "^1.3.0"
+ tslib "^2.0.3"
nice-try@^1.0.4:
version "1.0.5"
- resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
+ resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz"
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
+node-domexception@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz"
+ integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==
+
+node-fetch@^2.6.7:
+ version "2.6.7"
+ resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz"
+ integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
+ dependencies:
+ whatwg-url "^5.0.0"
+
node-int64@^0.4.0:
version "0.4.0"
- resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
- integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=
-
-node-modules-regexp@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40"
- integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=
+ resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz"
+ integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==
-node-notifier@^7.0.0:
- version "7.0.2"
- resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-7.0.2.tgz#3a70b1b70aca5e919d0b1b022530697466d9c675"
- integrity sha512-ux+n4hPVETuTL8+daJXTOC6uKLgMsl1RYfFv7DKRzyvzBapqco0rZZ9g72ZN8VS6V+gvNYHYa/ofcCY8fkJWsA==
+node-notifier@^8.0.0:
+ version "8.0.2"
+ resolved "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz"
+ integrity sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==
dependencies:
growly "^1.3.0"
is-wsl "^2.2.0"
semver "^7.3.2"
shellwords "^0.1.1"
- uuid "^8.2.0"
+ uuid "^8.3.0"
which "^2.0.2"
-normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.5.0:
+node-releases@^2.0.6:
+ version "2.0.6"
+ resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz"
+ integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==
+
+normalize-package-data@^2.5.0:
version "2.5.0"
- resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
+ resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz"
integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
dependencies:
hosted-git-info "^2.1.4"
@@ -4002,146 +3861,147 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-
normalize-path@^2.1.1:
version "2.1.1"
- resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
- integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=
+ resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz"
+ integrity sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==
dependencies:
remove-trailing-separator "^1.0.1"
normalize-path@^3.0.0, normalize-path@~3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
+ resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
npm-run-path@^2.0.0:
version "2.0.2"
- resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
- integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
+ resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz"
+ integrity sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==
dependencies:
path-key "^2.0.0"
npm-run-path@^4.0.0:
version "4.0.1"
- resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
+ resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz"
integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
dependencies:
path-key "^3.0.0"
nwsapi@^2.2.0:
version "2.2.1"
- resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.1.tgz#10a9f268fbf4c461249ebcfe38e359aa36e2577c"
+ resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.1.tgz"
integrity sha512-JYOWTeFoS0Z93587vRJgASD5Ut11fYl5NyihP3KrYBvMe1FRRs6RN7m20SA/16GM4P6hTnZjT+UmDOt38UeXNg==
-object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.1:
+object-assign@^4.1.1:
version "4.1.1"
- resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
- integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
+ resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
+ integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
object-copy@^0.1.0:
version "0.1.0"
- resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
- integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw=
+ resolved "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz"
+ integrity sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==
dependencies:
copy-descriptor "^0.1.0"
define-property "^0.2.5"
kind-of "^3.0.3"
-object-hash@^1.3.1:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.3.1.tgz#fde452098a951cb145f039bb7d455449ddc126df"
- integrity sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==
+object-hash@^2.0.1:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5"
+ integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==
-object-inspect@^1.7.0:
- version "1.8.0"
- resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0"
- integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==
+object-inspect@^1.12.0, object-inspect@^1.9.0:
+ version "1.12.2"
+ resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz"
+ integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==
-object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1:
+object-keys@^1.1.1:
version "1.1.1"
- resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
+ resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz"
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
-object-path@^0.11.4:
- version "0.11.8"
- resolved "https://registry.yarnpkg.com/object-path/-/object-path-0.11.8.tgz#ed002c02bbdd0070b78a27455e8ae01fc14d4742"
- integrity sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==
-
object-visit@^1.0.0:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
- integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=
+ resolved "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz"
+ integrity sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==
dependencies:
isobject "^3.0.0"
-object.assign@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
- integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==
+object.assign@^4.1.2, object.assign@^4.1.3:
+ version "4.1.4"
+ resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz"
+ integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==
dependencies:
- define-properties "^1.1.2"
- function-bind "^1.1.1"
- has-symbols "^1.0.0"
- object-keys "^1.0.11"
+ call-bind "^1.0.2"
+ define-properties "^1.1.4"
+ has-symbols "^1.0.3"
+ object-keys "^1.1.1"
-object.entries@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.2.tgz#bc73f00acb6b6bb16c203434b10f9a7e797d3add"
- integrity sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA==
+object.entries@^1.1.5:
+ version "1.1.5"
+ resolved "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz"
+ integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==
dependencies:
+ call-bind "^1.0.2"
define-properties "^1.1.3"
- es-abstract "^1.17.5"
- has "^1.0.3"
+ es-abstract "^1.19.1"
-object.fromentries@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.2.tgz#4a09c9b9bb3843dd0f89acdb517a794d4f355ac9"
- integrity sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ==
+object.fromentries@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz"
+ integrity sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==
dependencies:
+ call-bind "^1.0.2"
define-properties "^1.1.3"
- es-abstract "^1.17.0-next.1"
- function-bind "^1.1.1"
- has "^1.0.3"
+ es-abstract "^1.19.1"
+
+object.hasown@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.1.tgz"
+ integrity sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==
+ dependencies:
+ define-properties "^1.1.4"
+ es-abstract "^1.19.5"
object.pick@^1.3.0:
version "1.3.0"
- resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
- integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=
+ resolved "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz"
+ integrity sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==
dependencies:
isobject "^3.0.1"
-object.values@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e"
- integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==
- dependencies:
- define-properties "^1.1.3"
- es-abstract "^1.17.0-next.1"
- function-bind "^1.1.1"
- has "^1.0.3"
-
-on-finished@~2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
- integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
+object.values@^1.1.5:
+ version "1.1.5"
+ resolved "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz"
+ integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==
dependencies:
- ee-first "1.1.1"
+ call-bind "^1.0.2"
+ define-properties "^1.1.3"
+ es-abstract "^1.19.1"
once@^1.3.0, once@^1.3.1, once@^1.4.0:
version "1.4.0"
- resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
- integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
+ resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz"
+ integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
dependencies:
wrappy "1"
+one-time@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz"
+ integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==
+ dependencies:
+ fn.name "1.x.x"
+
onetime@^5.1.0:
version "5.1.2"
- resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
+ resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz"
integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
dependencies:
mimic-fn "^2.1.0"
optionator@^0.8.1:
version "0.8.3"
- resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495"
+ resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz"
integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==
dependencies:
deep-is "~0.1.3"
@@ -4153,7 +4013,7 @@ optionator@^0.8.1:
optionator@^0.9.1:
version "0.9.1"
- resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499"
+ resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz"
integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==
dependencies:
deep-is "^0.1.3"
@@ -4164,288 +4024,185 @@ optionator@^0.9.1:
word-wrap "^1.2.3"
p-each-series@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.1.0.tgz#961c8dd3f195ea96c747e636b262b800a6b1af48"
- integrity sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ==
+ version "2.2.0"
+ resolved "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz"
+ integrity sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==
p-finally@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
- integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
-
-p-limit@^1.1.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
- integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==
- dependencies:
- p-try "^1.0.0"
+ resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz"
+ integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==
p-limit@^2.2.0:
version "2.3.0"
- resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
+ resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz"
integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
dependencies:
p-try "^2.0.0"
-p-locate@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
- integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=
- dependencies:
- p-limit "^1.1.0"
-
p-locate@^4.1.0:
version "4.1.0"
- resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
+ resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz"
integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
dependencies:
p-limit "^2.2.0"
-p-try@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
- integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=
-
p-try@^2.0.0:
version "2.2.0"
- resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
+ resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
parent-module@^1.0.0:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
+ resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz"
integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
dependencies:
callsites "^3.0.0"
-parse-json@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
- integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=
- dependencies:
- error-ex "^1.2.0"
-
parse-json@^5.0.0:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.0.1.tgz#7cfe35c1ccd641bce3981467e6c2ece61b3b3878"
- integrity sha512-ztoZ4/DYeXQq4E21v169sC8qWINGpcosGv9XhTDvg9/hWvx/zrFkc9BiWxR58OJLHGk28j5BL0SDLeV2WmFZlQ==
+ version "5.2.0"
+ resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz"
+ integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
dependencies:
"@babel/code-frame" "^7.0.0"
error-ex "^1.3.1"
- json-parse-better-errors "^1.0.1"
+ json-parse-even-better-errors "^2.3.0"
lines-and-columns "^1.1.6"
parse5@6.0.1:
version "6.0.1"
- resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
+ resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz"
integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
-parseurl@~1.3.3:
- version "1.3.3"
- resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
- integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
-
pascalcase@^0.1.1:
version "0.1.1"
- resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
- integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=
-
-path-exists@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
- integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=
- dependencies:
- pinkie-promise "^2.0.0"
-
-path-exists@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
- integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
+ resolved "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz"
+ integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==
path-exists@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
+ resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz"
integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
path-is-absolute@^1.0.0:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
- integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
+ resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz"
+ integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
path-key@^2.0.0, path-key@^2.0.1:
version "2.0.1"
- resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
- integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
+ resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz"
+ integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==
path-key@^3.0.0, path-key@^3.1.0:
version "3.1.1"
- resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
+ resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
-path-parse@^1.0.6:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
- integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
-
-path-to-regexp@0.1.7:
- version "0.1.7"
- resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
- integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
-
-path-type@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
- integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=
- dependencies:
- graceful-fs "^4.1.2"
- pify "^2.0.0"
- pinkie-promise "^2.0.0"
+path-parse@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz"
+ integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
-path-type@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73"
- integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=
- dependencies:
- pify "^2.0.0"
+path-type@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz"
+ integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
-picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1:
- version "2.2.2"
- resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
- integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
+picocolors@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz"
+ integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
-pify@^2.0.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
- integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
+picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
+ integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
pify@^5.0.0:
version "5.0.0"
- resolved "https://registry.yarnpkg.com/pify/-/pify-5.0.0.tgz#1f5eca3f5e87ebec28cc6d54a0e4aaf00acc127f"
+ resolved "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz"
integrity sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==
-pinkie-promise@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
- integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o=
- dependencies:
- pinkie "^2.0.0"
-
-pinkie@^2.0.0:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
- integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
-
pirates@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87"
- integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==
- dependencies:
- node-modules-regexp "^1.0.0"
-
-pkg-dir@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b"
- integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=
- dependencies:
- find-up "^2.1.0"
+ version "4.0.5"
+ resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz"
+ integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==
pkg-dir@^4.2.0:
version "4.2.0"
- resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
+ resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz"
integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
dependencies:
find-up "^4.0.0"
posix-character-classes@^0.1.0:
version "0.1.1"
- resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
- integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
+ resolved "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz"
+ integrity sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==
prelude-ls@^1.2.1:
version "1.2.1"
- resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
+ resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
prelude-ls@~1.1.2:
version "1.1.2"
- resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
+ resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz"
integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==
prettier-linter-helpers@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b"
+ resolved "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz"
integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==
dependencies:
fast-diff "^1.1.2"
prettier@^2.0.5:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.5.tgz#d6d56282455243f2f92cc1716692c08aa31522d4"
- integrity sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==
-
-pretty-format@^25.2.1, pretty-format@^25.5.0:
- version "25.5.0"
- resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.5.0.tgz#7873c1d774f682c34b8d48b6743a2bf2ac55791a"
- integrity sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ==
- dependencies:
- "@jest/types" "^25.5.0"
- ansi-regex "^5.0.0"
- ansi-styles "^4.0.0"
- react-is "^16.12.0"
+ version "2.7.1"
+ resolved "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz"
+ integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==
-pretty-format@^26.2.0:
- version "26.2.0"
- resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.2.0.tgz#83ecc8d7de676ff224225055e72bd64821cec4f1"
- integrity sha512-qi/8IuBu2clY9G7qCXgCdD1Bf9w+sXakdHTRToknzMtVy0g7c4MBWaZy7MfB7ndKZovRO6XRwJiAYqq+MC7SDA==
+pretty-format@^26.0.0, pretty-format@^26.6.2:
+ version "26.6.2"
+ resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz"
+ integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==
dependencies:
- "@jest/types" "^26.2.0"
+ "@jest/types" "^26.6.2"
ansi-regex "^5.0.0"
ansi-styles "^4.0.0"
- react-is "^16.12.0"
+ react-is "^17.0.1"
progress@^2.0.0:
version "2.0.3"
- resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
+ resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
prompts@^2.0.1:
- version "2.3.2"
- resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.3.2.tgz#480572d89ecf39566d2bd3fe2c9fccb7c4c0b068"
- integrity sha512-Q06uKs2CkNYVID0VqwfAl9mipo99zkBv/n2JtWY89Yxa3ZabWSrs0e2KTudKVa3peLUvYXMefDqIleLPVUBZMA==
+ version "2.4.2"
+ resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz"
+ integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==
dependencies:
kleur "^3.0.3"
- sisteransi "^1.0.4"
+ sisteransi "^1.0.5"
-prop-types@^15.7.2:
- version "15.7.2"
- resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
- integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
+prop-types@^15.8.1:
+ version "15.8.1"
+ resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz"
+ integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
dependencies:
loose-envify "^1.4.0"
object-assign "^4.1.1"
- react-is "^16.8.1"
-
-property-expr@^1.5.0:
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-1.5.1.tgz#22e8706894a0c8e28d58735804f6ba3a3673314f"
- integrity sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g==
-
-proxy-addr@~2.0.5:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf"
- integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==
- dependencies:
- forwarded "~0.1.2"
- ipaddr.js "1.9.1"
+ react-is "^16.13.1"
psl@^1.1.33:
version "1.9.0"
- resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7"
+ resolved "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz"
integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==
pump@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
+ resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz"
integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
dependencies:
end-of-stream "^1.1.0"
@@ -4453,90 +4210,63 @@ pump@^3.0.0:
punycode@^2.1.0, punycode@^2.1.1:
version "2.1.1"
- resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
+ resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
-qs@6.7.0:
- version "6.7.0"
- resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
- integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
+pvtsutils@^1.3.2:
+ version "1.3.2"
+ resolved "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.2.tgz"
+ integrity sha512-+Ipe2iNUyrZz+8K/2IOo+kKikdtfhRKzNpQbruF2URmqPtoqAs8g3xS7TJvFF2GcPXjh7DkqMnpVveRFq4PgEQ==
+ dependencies:
+ tslib "^2.4.0"
+
+pvutils@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz"
+ integrity sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==
querystring@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
- integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
+ version "0.2.1"
+ resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.1.tgz"
+ integrity sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==
+
+querystringify@^2.1.1:
+ version "2.2.0"
+ resolved "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz"
+ integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==
+
+queue-microtask@^1.2.2:
+ version "1.2.3"
+ resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz"
+ integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
quick-lru@^4.0.1:
version "4.0.1"
- resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f"
+ resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz"
integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==
-range-parser@~1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
- integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
-
-raw-body@2.4.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332"
- integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==
- dependencies:
- bytes "3.1.0"
- http-errors "1.7.2"
- iconv-lite "0.4.24"
- unpipe "1.0.0"
-
-react-is@^16.12.0, react-is@^16.8.1:
+react-is@^16.13.1:
version "16.13.1"
- resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
+ resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
-read-pkg-up@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
- integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=
- dependencies:
- find-up "^1.0.0"
- read-pkg "^1.0.0"
-
-read-pkg-up@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be"
- integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=
- dependencies:
- find-up "^2.0.0"
- read-pkg "^2.0.0"
+react-is@^17.0.1:
+ version "17.0.2"
+ resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz"
+ integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
read-pkg-up@^7.0.1:
version "7.0.1"
- resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507"
+ resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz"
integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==
dependencies:
find-up "^4.1.0"
read-pkg "^5.2.0"
type-fest "^0.8.1"
-read-pkg@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
- integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=
- dependencies:
- load-json-file "^1.0.0"
- normalize-package-data "^2.3.2"
- path-type "^1.0.0"
-
-read-pkg@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8"
- integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=
- dependencies:
- load-json-file "^2.0.0"
- normalize-package-data "^2.3.2"
- path-type "^2.0.0"
-
read-pkg@^5.2.0:
version "5.2.0"
- resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
+ resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz"
integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==
dependencies:
"@types/normalize-package-data" "^2.4.0"
@@ -4544,169 +4274,185 @@ read-pkg@^5.2.0:
parse-json "^5.0.0"
type-fest "^0.6.0"
-readable-stream@1.1.x:
- version "1.1.14"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
- integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk=
+readable-stream@^3.4.0, readable-stream@^3.6.0:
+ version "3.6.2"
+ resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz"
+ integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
dependencies:
- core-util-is "~1.0.0"
- inherits "~2.0.1"
- isarray "0.0.1"
- string_decoder "~0.10.x"
+ inherits "^2.0.3"
+ string_decoder "^1.1.1"
+ util-deprecate "^1.0.1"
-readdirp@~3.4.0:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.4.0.tgz#9fdccdf9e9155805449221ac645e8303ab5b9ada"
- integrity sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==
+readdirp@~3.6.0:
+ version "3.6.0"
+ resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz"
+ integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
dependencies:
picomatch "^2.2.1"
-redent@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
- integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=
- dependencies:
- indent-string "^2.1.0"
- strip-indent "^1.0.1"
-
-regenerator-runtime@^0.13.4:
- version "0.13.7"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
- integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
-
regex-not@^1.0.0, regex-not@^1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
+ resolved "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz"
integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==
dependencies:
extend-shallow "^3.0.2"
safe-regex "^1.1.0"
-regexp.prototype.flags@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75"
- integrity sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==
+regexp.prototype.flags@^1.4.1, regexp.prototype.flags@^1.4.3:
+ version "1.4.3"
+ resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz"
+ integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==
dependencies:
+ call-bind "^1.0.2"
define-properties "^1.1.3"
- es-abstract "^1.17.0-next.1"
+ functions-have-names "^1.2.2"
-regexpp@^3.0.0, regexpp@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2"
- integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==
+regexpp@^3.1.0:
+ version "3.2.0"
+ resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz"
+ integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
remove-trailing-separator@^1.0.1:
version "1.1.0"
- resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
- integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8=
+ resolved "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz"
+ integrity sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==
repeat-element@^1.1.2:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
- integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==
+ version "1.1.4"
+ resolved "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz"
+ integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==
repeat-string@^1.6.1:
version "1.6.1"
- resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
- integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
-
-repeating@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
- integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=
- dependencies:
- is-finite "^1.0.0"
+ resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz"
+ integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==
require-directory@^2.1.1:
version "2.1.1"
- resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
- integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
+ resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz"
+ integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
+
+require-from-string@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz"
+ integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
require-main-filename@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
+ resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz"
integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
+requires-port@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz"
+ integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==
+
resolve-cwd@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"
+ resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz"
integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==
dependencies:
resolve-from "^5.0.0"
resolve-from@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
+ resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz"
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
resolve-from@^5.0.0:
version "5.0.0"
- resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
+ resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz"
integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
resolve-url@^0.2.1:
version "0.2.1"
- resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
- integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
+ resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz"
+ integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==
+
+resolve@^1.0.0, resolve@^1.10.0, resolve@^1.18.1, resolve@^1.20.0, resolve@^1.22.0:
+ version "1.22.1"
+ resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz"
+ integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
+ dependencies:
+ is-core-module "^2.9.0"
+ path-parse "^1.0.7"
+ supports-preserve-symlinks-flag "^1.0.0"
-resolve@^1.0.0, resolve@^1.10.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.3.2:
- version "1.17.0"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444"
- integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==
+resolve@^2.0.0-next.3:
+ version "2.0.0-next.4"
+ resolved "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz"
+ integrity sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==
dependencies:
- path-parse "^1.0.6"
+ is-core-module "^2.9.0"
+ path-parse "^1.0.7"
+ supports-preserve-symlinks-flag "^1.0.0"
ret@~0.1.10:
version "0.1.15"
- resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
+ resolved "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz"
integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
-rimraf@2.6.3:
- version "2.6.3"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
- integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
- dependencies:
- glob "^7.1.3"
+reusify@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz"
+ integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
rimraf@^2.6.1:
version "2.7.1"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
+ resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz"
integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
dependencies:
glob "^7.1.3"
-rimraf@^3.0.0:
+rimraf@^3.0.0, rimraf@^3.0.2:
version "3.0.2"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
+ resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz"
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
dependencies:
glob "^7.1.3"
rsvp@^4.8.4:
version "4.8.5"
- resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734"
+ resolved "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz"
integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==
-safe-buffer@5.1.2, safe-buffer@~5.1.1:
+run-parallel@^1.1.9:
+ version "1.2.0"
+ resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz"
+ integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
+ dependencies:
+ queue-microtask "^1.2.2"
+
+safe-buffer@~5.1.1:
version "5.1.2"
- resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
+ resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
+safe-buffer@~5.2.0:
+ version "5.2.1"
+ resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"
+ integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+
safe-regex@^1.1.0:
version "1.1.0"
- resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
- integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4=
+ resolved "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz"
+ integrity sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==
dependencies:
ret "~0.1.10"
+safe-stable-stringify@^2.3.1:
+ version "2.4.3"
+ resolved "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz"
+ integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==
+
"safer-buffer@>= 2.1.2 < 3":
version "2.1.2"
- resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+ resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
sane@^4.0.3:
version "4.1.0"
- resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded"
+ resolved "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz"
integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==
dependencies:
"@cnakazawa/watch" "^1.0.3"
@@ -4721,63 +4467,41 @@ sane@^4.0.3:
saxes@^5.0.1:
version "5.0.1"
- resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d"
+ resolved "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz"
integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==
dependencies:
xmlchars "^2.2.0"
-"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0:
- version "5.7.1"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
- integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
+"semver@2 || 3 || 4 || 5", semver@^5.5.0:
+ version "5.7.2"
+ resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz"
+ integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
-semver@7.x, semver@^7.2.1, semver@^7.3.2:
- version "7.3.2"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
- integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
+semver@7.x, semver@^7.2.1, semver@^7.3.2, semver@^7.3.5:
+ version "7.5.4"
+ resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz"
+ integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
+ dependencies:
+ lru-cache "^6.0.0"
semver@^6.0.0, semver@^6.3.0:
- version "6.3.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
- integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
-
-send@0.17.1:
- version "0.17.1"
- resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
- integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==
- dependencies:
- debug "2.6.9"
- depd "~1.1.2"
- destroy "~1.0.4"
- encodeurl "~1.0.2"
- escape-html "~1.0.3"
- etag "~1.8.1"
- fresh "0.5.2"
- http-errors "~1.7.2"
- mime "1.6.0"
- ms "2.1.1"
- on-finished "~2.3.0"
- range-parser "~1.2.1"
- statuses "~1.5.0"
-
-serve-static@1.14.1:
- version "1.14.1"
- resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
- integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
- dependencies:
- encodeurl "~1.0.2"
- escape-html "~1.0.3"
- parseurl "~1.3.3"
- send "0.17.1"
+ version "6.3.1"
+ resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz"
+ integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
set-blocking@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
- integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
+ resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz"
+ integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==
+
+set-cookie-parser@^2.5.1:
+ version "2.5.1"
+ resolved "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.1.tgz"
+ integrity sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==
set-value@^2.0.0, set-value@^2.0.1:
version "2.0.1"
- resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
+ resolved "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz"
integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==
dependencies:
extend-shallow "^2.0.1"
@@ -4785,88 +4509,86 @@ set-value@^2.0.0, set-value@^2.0.1:
is-plain-object "^2.0.3"
split-string "^3.0.1"
-setprototypeof@1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
- integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
-
-setprototypeof@1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
- integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
-
shebang-command@^1.2.0:
version "1.2.0"
- resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
- integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
+ resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz"
+ integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==
dependencies:
shebang-regex "^1.0.0"
shebang-command@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
+ resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz"
integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
dependencies:
shebang-regex "^3.0.0"
shebang-regex@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
- integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
+ resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz"
+ integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==
shebang-regex@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
+ resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
shellwords@^0.1.1:
version "0.1.1"
- resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
+ resolved "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz"
integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==
-side-channel@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.2.tgz#df5d1abadb4e4bf4af1cd8852bf132d2f7876947"
- integrity sha512-7rL9YlPHg7Ancea1S96Pa8/QWb4BtXL/TZvS6B8XFetGBeuhAsfmUspK6DokBeZ64+Kj9TCNRD/30pVz1BvQNA==
+side-channel@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz"
+ integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
dependencies:
- es-abstract "^1.17.0-next.1"
- object-inspect "^1.7.0"
+ call-bind "^1.0.0"
+ get-intrinsic "^1.0.2"
+ object-inspect "^1.9.0"
signal-exit@^3.0.0, signal-exit@^3.0.2:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
- integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
+ version "3.0.7"
+ resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz"
+ integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
+
+simple-swizzle@^0.2.2:
+ version "0.2.2"
+ resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz"
+ integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==
+ dependencies:
+ is-arrayish "^0.3.1"
-sisteransi@^1.0.4:
+sisteransi@^1.0.5:
version "1.0.5"
- resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
+ resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz"
integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==
slash@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
+ resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz"
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
-slice-ansi@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636"
- integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==
+slice-ansi@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz"
+ integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==
dependencies:
- ansi-styles "^3.2.0"
- astral-regex "^1.0.0"
- is-fullwidth-code-point "^2.0.0"
+ ansi-styles "^4.0.0"
+ astral-regex "^2.0.0"
+ is-fullwidth-code-point "^3.0.0"
snakecase-keys@^3.2.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/snakecase-keys/-/snakecase-keys-3.2.0.tgz#3ac428d643c6634eca461192fc7f731378fa7bd1"
- integrity sha512-WTJ0NhCH/37J+PU3fuz0x5b6TvtWQChTcKPOndWoUy0pteKOe0hrHMzSRsJOWSIP48EQkzUEsgQPmrG3W8pFNQ==
+ version "3.2.1"
+ resolved "https://registry.npmjs.org/snakecase-keys/-/snakecase-keys-3.2.1.tgz"
+ integrity sha512-CjU5pyRfwOtaOITYv5C8DzpZ8XA/ieRsDpr93HI2r6e3YInC6moZpSQbmUtg8cTk58tq2x3jcG2gv+p1IZGmMA==
dependencies:
- map-obj "^4.0.0"
+ map-obj "^4.1.0"
to-snake-case "^1.0.0"
snapdragon-node@^2.0.1:
version "2.1.1"
- resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
+ resolved "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz"
integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==
dependencies:
define-property "^1.0.0"
@@ -4875,14 +4597,14 @@ snapdragon-node@^2.0.1:
snapdragon-util@^3.0.1:
version "3.0.1"
- resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2"
+ resolved "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz"
integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==
dependencies:
kind-of "^3.2.0"
snapdragon@^0.8.1:
version "0.8.2"
- resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d"
+ resolved "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz"
integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==
dependencies:
base "^0.11.1"
@@ -4896,7 +4618,7 @@ snapdragon@^0.8.1:
source-map-resolve@^0.5.0:
version "0.5.3"
- resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a"
+ resolved "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz"
integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==
dependencies:
atob "^2.1.2"
@@ -4905,37 +4627,37 @@ source-map-resolve@^0.5.0:
source-map-url "^0.4.0"
urix "^0.1.0"
-source-map-support@^0.5.1, source-map-support@^0.5.12, source-map-support@^0.5.17, source-map-support@^0.5.6:
- version "0.5.19"
- resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
- integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==
+source-map-support@^0.5.12, source-map-support@^0.5.17, source-map-support@^0.5.6:
+ version "0.5.21"
+ resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz"
+ integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
source-map-url@^0.4.0:
- version "0.4.0"
- resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
- integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=
+ version "0.4.1"
+ resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz"
+ integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==
-source-map@^0.5.0, source-map@^0.5.6:
+source-map@^0.5.6:
version "0.5.7"
- resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
- integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
+ resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz"
+ integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==
source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1:
version "0.6.1"
- resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+ resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
source-map@^0.7.3:
- version "0.7.3"
- resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
- integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
+ version "0.7.4"
+ resolved "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz"
+ integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==
spdx-correct@^3.0.0:
version "3.1.1"
- resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9"
+ resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz"
integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==
dependencies:
spdx-expression-parse "^3.0.0"
@@ -4943,237 +4665,198 @@ spdx-correct@^3.0.0:
spdx-exceptions@^2.1.0:
version "2.3.0"
- resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d"
+ resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz"
integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==
spdx-expression-parse@^3.0.0:
version "3.0.1"
- resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679"
+ resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz"
integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==
dependencies:
spdx-exceptions "^2.1.0"
spdx-license-ids "^3.0.0"
spdx-license-ids@^3.0.0:
- version "3.0.5"
- resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654"
- integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==
+ version "3.0.12"
+ resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz"
+ integrity sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==
split-string@^3.0.1, split-string@^3.0.2:
version "3.1.0"
- resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
+ resolved "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz"
integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==
dependencies:
extend-shallow "^3.0.0"
sprintf-js@~1.0.2:
version "1.0.3"
- resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
- integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
+ resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz"
+ integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
+
+stack-trace@0.0.x:
+ version "0.0.10"
+ resolved "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz"
+ integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==
stack-utils@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.2.tgz#5cf48b4557becb4638d0bc4f21d23f5d19586593"
- integrity sha512-0H7QK2ECz3fyZMzQ8rH0j2ykpfbnd20BFtfg/SqVC2+sCTtcw0aDTGB7dk+de4U4uUeuz6nOtJcrkFFLG1B0Rg==
+ version "2.0.5"
+ resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz"
+ integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==
dependencies:
escape-string-regexp "^2.0.0"
static-extend@^0.1.1:
version "0.1.2"
- resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
- integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=
+ resolved "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz"
+ integrity sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==
dependencies:
define-property "^0.2.5"
object-copy "^0.1.0"
-"statuses@>= 1.5.0 < 2", statuses@~1.5.0:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
- integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
-
-streamsearch@0.1.2:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a"
- integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=
+streamsearch@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz"
+ integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
string-length@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.1.tgz#4a973bf31ef77c4edbceadd6af2611996985f8a1"
- integrity sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw==
+ version "4.0.2"
+ resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz"
+ integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==
dependencies:
char-regex "^1.0.2"
strip-ansi "^6.0.0"
-string-width@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
- integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
- dependencies:
- emoji-regex "^7.0.1"
- is-fullwidth-code-point "^2.0.0"
- strip-ansi "^5.1.0"
-
-string-width@^4.1.0, string-width@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5"
- integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==
+string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
+ version "4.2.3"
+ resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
+ integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
- strip-ansi "^6.0.0"
-
-string.prototype.matchall@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.2.tgz#48bb510326fb9fdeb6a33ceaa81a6ea04ef7648e"
- integrity sha512-N/jp6O5fMf9os0JU3E72Qhf590RSRZU/ungsL/qJUYVTNv7hTG0P/dbPjxINVN9jpscu3nzYwKESU3P3RY5tOg==
- dependencies:
- define-properties "^1.1.3"
- es-abstract "^1.17.0"
- has-symbols "^1.0.1"
- internal-slot "^1.0.2"
- regexp.prototype.flags "^1.3.0"
- side-channel "^1.0.2"
+ strip-ansi "^6.0.1"
-string.prototype.trimend@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913"
- integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==
+string.prototype.matchall@^4.0.7:
+ version "4.0.7"
+ resolved "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz"
+ integrity sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==
dependencies:
+ call-bind "^1.0.2"
define-properties "^1.1.3"
- es-abstract "^1.17.5"
-
-string.prototype.trimstart@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54"
- integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==
+ es-abstract "^1.19.1"
+ get-intrinsic "^1.1.1"
+ has-symbols "^1.0.3"
+ internal-slot "^1.0.3"
+ regexp.prototype.flags "^1.4.1"
+ side-channel "^1.0.4"
+
+string.prototype.trimend@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz"
+ integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==
dependencies:
- define-properties "^1.1.3"
- es-abstract "^1.17.5"
+ call-bind "^1.0.2"
+ define-properties "^1.1.4"
+ es-abstract "^1.19.5"
-string_decoder@~0.10.x:
- version "0.10.31"
- resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
- integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=
-
-strip-ansi@^5.1.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
- integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
+string.prototype.trimstart@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz"
+ integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==
dependencies:
- ansi-regex "^4.1.0"
+ call-bind "^1.0.2"
+ define-properties "^1.1.4"
+ es-abstract "^1.19.5"
-strip-ansi@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
- integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==
+string_decoder@^1.1.1:
+ version "1.3.0"
+ resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz"
+ integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
dependencies:
- ansi-regex "^5.0.0"
+ safe-buffer "~5.2.0"
-strip-bom@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
- integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=
+strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
+ integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
- is-utf8 "^0.2.0"
+ ansi-regex "^5.0.1"
strip-bom@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
- integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=
+ resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz"
+ integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==
strip-bom@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878"
+ resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz"
integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==
strip-eof@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
- integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
+ resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz"
+ integrity sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==
strip-final-newline@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
+ resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz"
integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
-strip-indent@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2"
- integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=
- dependencies:
- get-stdin "^4.0.1"
-
strip-json-comments@^2.0.0:
version "2.0.1"
- resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
- integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
+ resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz"
+ integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==
-strip-json-comments@^3.1.0:
+strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
version "3.1.1"
- resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
+ resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
-subscriptions-transport-ws@^0.9.8:
- version "0.9.18"
- resolved "https://registry.yarnpkg.com/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.18.tgz#bcf02320c911fbadb054f7f928e51c6041a37b97"
- integrity sha512-tztzcBTNoEbuErsVQpTN2xUNN/efAZXyCyL5m3x4t6SKrEiTL2N8SaKWBFWM4u56pL79ULif3zjyeq+oV+nOaA==
- dependencies:
- backo2 "^1.0.2"
- eventemitter3 "^3.1.0"
- iterall "^1.2.1"
- symbol-observable "^1.0.4"
- ws "^5.2.0"
-
supports-color@^5.3.0:
version "5.5.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+ resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz"
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
dependencies:
has-flag "^3.0.0"
supports-color@^7.0.0, supports-color@^7.1.0:
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1"
- integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==
+ version "7.2.0"
+ resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz"
+ integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
dependencies:
has-flag "^4.0.0"
supports-hyperlinks@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz#f663df252af5f37c5d49bbd7eeefa9e0b9e59e47"
- integrity sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==
+ version "2.2.0"
+ resolved "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz"
+ integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==
dependencies:
has-flag "^4.0.0"
supports-color "^7.0.0"
-symbol-observable@^1.0.4:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
- integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==
+supports-preserve-symlinks-flag@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz"
+ integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
symbol-tree@^3.2.4:
version "3.2.4"
- resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
+ resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz"
integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==
-synchronous-promise@^2.0.6:
- version "2.0.13"
- resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.13.tgz#9d8c165ddee69c5a6542862b405bc50095926702"
- integrity sha512-R9N6uDkVsghHePKh1TEqbnLddO2IY25OcsksyFp/qBe7XYd0PVbKEWxhcdMhpLzE1I6skj5l4aEZ3CRxcbArlA==
-
-table@^5.2.3:
- version "5.4.6"
- resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e"
- integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==
+table@^6.0.9:
+ version "6.8.0"
+ resolved "https://registry.npmjs.org/table/-/table-6.8.0.tgz"
+ integrity sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==
dependencies:
- ajv "^6.10.2"
- lodash "^4.17.14"
- slice-ansi "^2.1.0"
- string-width "^3.0.0"
+ ajv "^8.0.1"
+ lodash.truncate "^4.4.2"
+ slice-ansi "^4.0.0"
+ string-width "^4.2.3"
+ strip-ansi "^6.0.1"
terminal-link@^2.0.0:
version "2.1.1"
- resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994"
+ resolved "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz"
integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==
dependencies:
ansi-escapes "^4.2.1"
@@ -5181,63 +4864,68 @@ terminal-link@^2.0.0:
test-exclude@^6.0.0:
version "6.0.0"
- resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e"
+ resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz"
integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==
dependencies:
"@istanbuljs/schema" "^0.1.2"
glob "^7.1.4"
minimatch "^3.0.4"
+text-hex@1.0.x:
+ version "1.0.0"
+ resolved "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz"
+ integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==
+
text-table@^0.2.0:
version "0.2.0"
- resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
- integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
+ resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz"
+ integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
throat@^5.0.0:
version "5.0.0"
- resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b"
+ resolved "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz"
integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==
-tmpl@1.0.x:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
- integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=
+tmpl@1.0.5:
+ version "1.0.5"
+ resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz"
+ integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==
to-fast-properties@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
- integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
+ resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz"
+ integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==
to-no-case@^1.0.0:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/to-no-case/-/to-no-case-1.0.2.tgz#c722907164ef6b178132c8e69930212d1b4aa16a"
- integrity sha1-xyKQcWTvaxeBMsjmmTAhLRtKoWo=
+ resolved "https://registry.npmjs.org/to-no-case/-/to-no-case-1.0.2.tgz"
+ integrity sha512-Z3g735FxuZY8rodxV4gH7LxClE4H0hTIyHNIHdk+vpQxjLm0cwnKXq/OFVZ76SOQmto7txVcwSCwkU5kqp+FKg==
to-object-path@^0.3.0:
version "0.3.0"
- resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
- integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=
+ resolved "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz"
+ integrity sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==
dependencies:
kind-of "^3.0.2"
to-regex-range@^2.1.0:
version "2.1.1"
- resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38"
- integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=
+ resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz"
+ integrity sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==
dependencies:
is-number "^3.0.0"
repeat-string "^1.6.1"
to-regex-range@^5.0.1:
version "5.0.1"
- resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
+ resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz"
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
dependencies:
is-number "^7.0.0"
to-regex@^3.0.1, to-regex@^3.0.2:
version "3.0.2"
- resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
+ resolved "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz"
integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==
dependencies:
define-property "^2.0.2"
@@ -5247,84 +4935,72 @@ to-regex@^3.0.1, to-regex@^3.0.2:
to-snake-case@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/to-snake-case/-/to-snake-case-1.0.0.tgz#ce746913897946019a87e62edfaeaea4c608ab8c"
- integrity sha1-znRpE4l5RgGah+Yu366upMYIq4w=
+ resolved "https://registry.npmjs.org/to-snake-case/-/to-snake-case-1.0.0.tgz"
+ integrity sha512-joRpzBAk1Bhi2eGEYBjukEWHOe/IvclOkiJl3DtA91jV6NwQ3MwXA4FHYeqk8BNp/D8bmi9tcNbRu/SozP0jbQ==
dependencies:
to-space-case "^1.0.0"
to-space-case@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/to-space-case/-/to-space-case-1.0.0.tgz#b052daafb1b2b29dc770cea0163e5ec0ebc9fc17"
- integrity sha1-sFLar7Gysp3HcM6gFj5ewOvJ/Bc=
+ resolved "https://registry.npmjs.org/to-space-case/-/to-space-case-1.0.0.tgz"
+ integrity sha512-rLdvwXZ39VOn1IxGL3V6ZstoTbwLRckQmn/U8ZDLuWwIXNpuZDhQ3AiRUlhTbOXFVE9C+dR51wM0CBDhk31VcA==
dependencies:
to-no-case "^1.0.0"
-toidentifier@1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
- integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
-
-toposort@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330"
- integrity sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=
-
-tough-cookie@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4"
- integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==
+tough-cookie@^4.0.0, tough-cookie@^4.1.3:
+ version "4.1.3"
+ resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz"
+ integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==
dependencies:
psl "^1.1.33"
punycode "^2.1.1"
- universalify "^0.1.2"
+ universalify "^0.2.0"
+ url-parse "^1.5.3"
tr46@^2.1.0:
version "2.1.0"
- resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240"
+ resolved "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz"
integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==
dependencies:
punycode "^2.1.1"
+tr46@~0.0.3:
+ version "0.0.3"
+ resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz"
+ integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
+
tree-kill@^1.2.2:
version "1.2.2"
- resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
+ resolved "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz"
integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==
-trim-newlines@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
- integrity sha1-WIeWa7WCpFA6QetST301ARgVphM=
-
-ts-invariant@^0.4.0:
- version "0.4.4"
- resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.4.4.tgz#97a523518688f93aafad01b0e80eb803eb2abd86"
- integrity sha512-uEtWkFM/sdZvRNNDL3Ehu4WVpwaulhwQszV8mrtcdeE8nN00BV9mAmQ88RkrBhFgl9gMgvjJLAQcZbnPXI9mlA==
- dependencies:
- tslib "^1.9.3"
+triple-beam@^1.3.0:
+ version "1.4.1"
+ resolved "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz"
+ integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==
ts-jest@^26.1.4:
- version "26.1.4"
- resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.1.4.tgz#87d41a96016a8efe4b8cc14501d3785459af6fa6"
- integrity sha512-Nd7diUX6NZWfWq6FYyvcIPR/c7GbEF75fH1R6coOp3fbNzbRJBZZAn0ueVS0r8r9ral1VcrpneAFAwB3TsVS1Q==
+ version "26.5.6"
+ resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.6.tgz"
+ integrity sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA==
dependencies:
bs-logger "0.x"
buffer-from "1.x"
fast-json-stable-stringify "2.x"
- jest-util "26.x"
+ jest-util "^26.1.0"
json5 "2.x"
- lodash.memoize "4.x"
+ lodash "4.x"
make-error "1.x"
mkdirp "1.x"
semver "7.x"
- yargs-parser "18.x"
+ yargs-parser "20.x"
ts-node-dev@^1.0.0-pre.56:
- version "1.0.0-pre.56"
- resolved "https://registry.yarnpkg.com/ts-node-dev/-/ts-node-dev-1.0.0-pre.56.tgz#b74c0d1db2d98f005ad73f9eaa0a3c0a231f14da"
- integrity sha512-+2a3FAShOja+W5X6ZxKgf1PG3kOOkHCiYzSu6s3lwhLVxeMBusJudcv7W6cZKOTp7+L7hPkKW97t1CGw7bCDaA==
+ version "1.1.8"
+ resolved "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-1.1.8.tgz"
+ integrity sha512-Q/m3vEwzYwLZKmV6/0VlFxcZzVV/xcgOt+Tx/VjaaRHyiBcFlV0541yrT09QjzzCxlDZ34OzKjrFAynlmtflEg==
dependencies:
- chokidar "^3.4.0"
- dateformat "~1.0.4-1.2.3"
+ chokidar "^3.5.1"
dynamic-dedupe "^0.3.0"
minimist "^1.2.5"
mkdirp "^1.0.4"
@@ -5332,33 +5008,34 @@ ts-node-dev@^1.0.0-pre.56:
rimraf "^2.6.1"
source-map-support "^0.5.12"
tree-kill "^1.2.2"
- ts-node "^8.10.2"
+ ts-node "^9.0.0"
tsconfig "^7.0.0"
-ts-node@^8.10.2:
- version "8.10.2"
- resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.10.2.tgz#eee03764633b1234ddd37f8db9ec10b75ec7fb8d"
- integrity sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==
+ts-node@^9.0.0:
+ version "9.1.1"
+ resolved "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz"
+ integrity sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==
dependencies:
arg "^4.1.0"
+ create-require "^1.1.0"
diff "^4.0.1"
make-error "^1.1.1"
source-map-support "^0.5.17"
yn "3.1.1"
-tsconfig-paths@^3.9.0:
- version "3.9.0"
- resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b"
- integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==
+tsconfig-paths@^3.14.1:
+ version "3.14.1"
+ resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz"
+ integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==
dependencies:
"@types/json5" "^0.0.29"
json5 "^1.0.1"
- minimist "^1.2.0"
+ minimist "^1.2.6"
strip-bom "^3.0.0"
tsconfig@^7.0.0:
version "7.0.0"
- resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-7.0.0.tgz#84538875a4dc216e5c4a5432b3a4dec3d54e91b7"
+ resolved "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz"
integrity sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==
dependencies:
"@types/strip-bom" "^3.0.0"
@@ -5366,75 +5043,94 @@ tsconfig@^7.0.0:
strip-bom "^3.0.0"
strip-json-comments "^2.0.0"
-tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.3:
- version "1.13.0"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
- integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
+tslib@^1.8.1:
+ version "1.14.1"
+ resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz"
+ integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
+
+tslib@^2.0.0, tslib@^2.0.3, tslib@^2.3.1, tslib@^2.4.0:
+ version "2.4.0"
+ resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz"
+ integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
-tsutils@^3.17.1:
- version "3.17.1"
- resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"
- integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==
+tsutils@^3.21.0:
+ version "3.21.0"
+ resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz"
+ integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==
dependencies:
tslib "^1.8.1"
type-check@^0.4.0, type-check@~0.4.0:
version "0.4.0"
- resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
+ resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz"
integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==
dependencies:
prelude-ls "^1.2.1"
type-check@~0.3.2:
version "0.3.2"
- resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
+ resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz"
integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==
dependencies:
prelude-ls "~1.1.2"
type-detect@4.0.8:
version "4.0.8"
- resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
+ resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz"
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
-type-fest@^0.11.0:
- version "0.11.0"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1"
- integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==
+type-fest@^0.20.2:
+ version "0.20.2"
+ resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz"
+ integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
+
+type-fest@^0.21.3:
+ version "0.21.3"
+ resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz"
+ integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
type-fest@^0.6.0:
version "0.6.0"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"
+ resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz"
integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==
type-fest@^0.8.1:
version "0.8.1"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
+ resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz"
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
-type-is@~1.6.17, type-is@~1.6.18:
- version "1.6.18"
- resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
- integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
- dependencies:
- media-typer "0.3.0"
- mime-types "~2.1.24"
-
typedarray-to-buffer@^3.1.5:
version "3.1.5"
- resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
+ resolved "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz"
integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==
dependencies:
is-typedarray "^1.0.0"
-typescript@^3.9.7:
- version "3.9.7"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
- integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
+typescript@4.7.4:
+ version "4.7.4"
+ resolved "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz"
+ integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==
+
+unbox-primitive@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz"
+ integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==
+ dependencies:
+ call-bind "^1.0.2"
+ has-bigints "^1.0.2"
+ has-symbols "^1.0.3"
+ which-boxed-primitive "^1.0.2"
+
+undici@^5.8.0:
+ version "5.19.1"
+ resolved "https://registry.npmjs.org/undici/-/undici-5.19.1.tgz"
+ integrity sha512-YiZ61LPIgY73E7syxCDxxa3LV2yl3sN8spnIuTct60boiiRaE1J8mNWHO8Im2Zi/sFrPusjLlmRPrsyraSqX6A==
+ dependencies:
+ busboy "^1.6.0"
union-value@^1.0.0:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"
+ resolved "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz"
integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==
dependencies:
arr-union "^3.1.0"
@@ -5442,65 +5138,71 @@ union-value@^1.0.0:
is-extendable "^0.1.1"
set-value "^2.0.1"
-universalify@^0.1.2:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
- integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
-
-unpipe@1.0.0, unpipe@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
- integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
+universalify@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz"
+ integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==
unset-value@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
- integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=
+ resolved "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz"
+ integrity sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==
dependencies:
has-value "^0.3.1"
isobject "^3.0.0"
+update-browserslist-db@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz"
+ integrity sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==
+ dependencies:
+ escalade "^3.1.1"
+ picocolors "^1.0.0"
+
uri-js@^4.2.2:
- version "4.2.2"
- resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
- integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
+ version "4.4.1"
+ resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz"
+ integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
dependencies:
punycode "^2.1.0"
urix@^0.1.0:
version "0.1.0"
- resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
- integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
+ resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz"
+ integrity sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==
+
+url-parse@^1.5.3:
+ version "1.5.10"
+ resolved "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz"
+ integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==
+ dependencies:
+ querystringify "^2.1.1"
+ requires-port "^1.0.0"
use@^3.1.0:
version "3.1.1"
- resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
+ resolved "https://registry.npmjs.org/use/-/use-3.1.1.tgz"
integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
-utils-merge@1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
- integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
-
-uuid@^3.1.0:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
- integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
+util-deprecate@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
+ integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
-uuid@^8.2.0:
- version "8.3.0"
- resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.0.tgz#ab738085ca22dc9a8c92725e459b1d507df5d6ea"
- integrity sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ==
+uuid@^8.3.0:
+ version "8.3.2"
+ resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz"
+ integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
v8-compile-cache@^2.0.3:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745"
- integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==
+ version "2.3.0"
+ resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz"
+ integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==
-v8-to-istanbul@^4.1.3:
- version "4.1.4"
- resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-4.1.4.tgz#b97936f21c0e2d9996d4985e5c5156e9d4e49cd6"
- integrity sha512-Rw6vJHj1mbdK8edjR7+zuJrpDtKIgNdAvTSAcpYfgMIw+u2dPDntD3dgN4XQFLU2/fvFQdzj+EeSGfd/jnY5fQ==
+v8-to-istanbul@^7.0.0:
+ version "7.1.2"
+ resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz"
+ integrity sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow==
dependencies:
"@types/istanbul-lib-coverage" "^2.0.1"
convert-source-map "^1.6.0"
@@ -5508,96 +5210,177 @@ v8-to-istanbul@^4.1.3:
validate-npm-package-license@^3.0.1:
version "3.0.4"
- resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
+ resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz"
integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
dependencies:
spdx-correct "^3.0.0"
spdx-expression-parse "^3.0.0"
-vary@^1, vary@~1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
- integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
+value-or-promise@1.0.11:
+ version "1.0.11"
+ resolved "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.11.tgz"
+ integrity sha512-41BrgH+dIbCFXClcSapVs5M6GkENd3gQOJpEfPDNa71LsUGMXDL0jMWpI/Rh7WhX+Aalfz2TTS3Zt5pUsbnhLg==
w3c-hr-time@^1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd"
+ resolved "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz"
integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==
dependencies:
browser-process-hrtime "^1.0.0"
w3c-xmlserializer@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a"
+ resolved "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz"
integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==
dependencies:
xml-name-validator "^3.0.0"
walker@^1.0.7, walker@~1.0.5:
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb"
- integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=
+ version "1.0.8"
+ resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz"
+ integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==
+ dependencies:
+ makeerror "1.0.12"
+
+web-streams-polyfill@4.0.0-beta.3:
+ version "4.0.0-beta.3"
+ resolved "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz"
+ integrity sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==
+
+web-streams-polyfill@^3.2.0:
+ version "3.2.1"
+ resolved "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz"
+ integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==
+
+webcrypto-core@^1.7.4:
+ version "1.7.5"
+ resolved "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.5.tgz"
+ integrity sha512-gaExY2/3EHQlRNNNVSrbG2Cg94Rutl7fAaKILS1w8ZDhGxdFOaw6EbCfHIxPy9vt/xwp5o0VQAx9aySPF6hU1A==
dependencies:
- makeerror "1.0.x"
+ "@peculiar/asn1-schema" "^2.1.6"
+ "@peculiar/json-schema" "^1.1.12"
+ asn1js "^3.0.1"
+ pvtsutils "^1.3.2"
+ tslib "^2.4.0"
+
+webidl-conversions@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz"
+ integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
webidl-conversions@^5.0.0:
version "5.0.0"
- resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff"
+ resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz"
integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==
webidl-conversions@^6.1.0:
version "6.1.0"
- resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514"
+ resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz"
integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==
whatwg-encoding@^1.0.5:
version "1.0.5"
- resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0"
+ resolved "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz"
integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==
dependencies:
iconv-lite "0.4.24"
whatwg-mimetype@^2.3.0:
version "2.3.0"
- resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf"
+ resolved "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz"
integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==
+whatwg-url@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz"
+ integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
+ dependencies:
+ tr46 "~0.0.3"
+ webidl-conversions "^3.0.0"
+
whatwg-url@^8.0.0, whatwg-url@^8.5.0:
version "8.7.0"
- resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77"
+ resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz"
integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==
dependencies:
lodash "^4.7.0"
tr46 "^2.1.0"
webidl-conversions "^6.1.0"
+which-boxed-primitive@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz"
+ integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==
+ dependencies:
+ is-bigint "^1.0.1"
+ is-boolean-object "^1.1.0"
+ is-number-object "^1.0.4"
+ is-string "^1.0.5"
+ is-symbol "^1.0.3"
+
which-module@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
- integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
+ resolved "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz"
+ integrity sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==
which@^1.2.9:
version "1.3.1"
- resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
+ resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
dependencies:
isexe "^2.0.0"
which@^2.0.1, which@^2.0.2:
version "2.0.2"
- resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
+ resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz"
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
dependencies:
isexe "^2.0.0"
+winston-daily-rotate-file@^4.7.1:
+ version "4.7.1"
+ resolved "https://registry.yarnpkg.com/winston-daily-rotate-file/-/winston-daily-rotate-file-4.7.1.tgz#f60a643af87f8867f23170d8cd87dbe3603a625f"
+ integrity sha512-7LGPiYGBPNyGHLn9z33i96zx/bd71pjBn9tqQzO3I4Tayv94WPmBNwKC7CO1wPHdP9uvu+Md/1nr6VSH9h0iaA==
+ dependencies:
+ file-stream-rotator "^0.6.1"
+ object-hash "^2.0.1"
+ triple-beam "^1.3.0"
+ winston-transport "^4.4.0"
+
+winston-transport@^4.4.0, winston-transport@^4.5.0:
+ version "4.5.0"
+ resolved "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz"
+ integrity sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==
+ dependencies:
+ logform "^2.3.2"
+ readable-stream "^3.6.0"
+ triple-beam "^1.3.0"
+
+winston@^3.10.0:
+ version "3.10.0"
+ resolved "https://registry.npmjs.org/winston/-/winston-3.10.0.tgz"
+ integrity sha512-nT6SIDaE9B7ZRO0u3UvdrimG0HkB7dSTAgInQnNR2SOPJ4bvq5q79+pXLftKmP52lJGW15+H5MCK0nM9D3KB/g==
+ dependencies:
+ "@colors/colors" "1.5.0"
+ "@dabh/diagnostics" "^2.0.2"
+ async "^3.2.3"
+ is-stream "^2.0.0"
+ logform "^2.4.0"
+ one-time "^1.0.0"
+ readable-stream "^3.4.0"
+ safe-stable-stringify "^2.3.1"
+ stack-trace "0.0.x"
+ triple-beam "^1.3.0"
+ winston-transport "^4.5.0"
+
word-wrap@^1.2.3, word-wrap@~1.2.3:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
- integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
+ version "1.2.4"
+ resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz"
+ integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==
wrap-ansi@^6.2.0:
version "6.2.0"
- resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
+ resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz"
integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==
dependencies:
ansi-styles "^4.0.0"
@@ -5606,12 +5389,12 @@ wrap-ansi@^6.2.0:
wrappy@1:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
- integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
+ resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
+ integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
write-file-atomic@^3.0.0:
version "3.0.3"
- resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8"
+ resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz"
integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==
dependencies:
imurmurhash "^0.1.4"
@@ -5619,56 +5402,52 @@ write-file-atomic@^3.0.0:
signal-exit "^3.0.2"
typedarray-to-buffer "^3.1.5"
-write@1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3"
- integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==
- dependencies:
- mkdirp "^0.5.1"
-
-ws@^5.2.0:
- version "5.2.3"
- resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.3.tgz#05541053414921bc29c63bee14b8b0dd50b07b3d"
- integrity sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA==
- dependencies:
- async-limiter "~1.0.0"
-
ws@^7.4.6:
version "7.5.9"
- resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591"
+ resolved "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz"
integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==
xml-name-validator@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"
+ resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz"
integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==
xmlchars@^2.2.0:
version "2.2.0"
- resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb"
+ resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz"
integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==
xtend@^4.0.0:
version "4.0.2"
- resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
+ resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
y18n@^4.0.0:
+ version "4.0.3"
+ resolved "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz"
+ integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==
+
+yallist@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
- integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
+ resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz"
+ integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
+
+yargs-parser@20.x:
+ version "20.2.9"
+ resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz"
+ integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
-yargs-parser@18.x, yargs-parser@^18.1.2:
+yargs-parser@^18.1.2:
version "18.1.3"
- resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0"
+ resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz"
integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==
dependencies:
camelcase "^5.0.0"
decamelize "^1.2.0"
-yargs@^15.3.1:
+yargs@^15.4.1:
version "15.4.1"
- resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8"
+ resolved "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz"
integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==
dependencies:
cliui "^6.0.0"
@@ -5685,30 +5464,10 @@ yargs@^15.3.1:
yn@3.1.1:
version "3.1.1"
- resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
+ resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz"
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
-yup@^0.27.0:
- version "0.27.0"
- resolved "https://registry.yarnpkg.com/yup/-/yup-0.27.0.tgz#f8cb198c8e7dd2124beddc2457571329096b06e7"
- integrity sha512-v1yFnE4+u9za42gG/b/081E7uNW9mUj3qtkmelLbW5YPROZzSH/KUUyJu9Wt8vxFJcT9otL/eZopS0YK1L5yPQ==
- dependencies:
- "@babel/runtime" "^7.0.0"
- fn-name "~2.0.1"
- lodash "^4.17.11"
- property-expr "^1.5.0"
- synchronous-promise "^2.0.6"
- toposort "^2.0.2"
-
-zen-observable-ts@^0.8.21:
- version "0.8.21"
- resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.21.tgz#85d0031fbbde1eba3cd07d3ba90da241215f421d"
- integrity sha512-Yj3yXweRc8LdRMrCC8nIc4kkjWecPAUVh0TI0OUrWXx6aX790vLcDlWca6I4vsyCGH3LpWxq0dJRcMOFoVqmeg==
- dependencies:
- tslib "^1.9.3"
- zen-observable "^0.8.0"
-
-zen-observable@^0.8.0:
- version "0.8.15"
- resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15"
- integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==
+zod@^3.22.0:
+ version "3.22.0"
+ resolved "https://registry.npmjs.org/zod/-/zod-3.22.0.tgz"
+ integrity sha512-y5KZY/ssf5n7hCGDGGtcJO/EBJEm5Pa+QQvFBeyMOtnFYOSflalxIFFvdaYevPhePcmcKC4aTbFkCcXN7D0O8Q==
diff --git a/documentation/beta_docs/discourse-features.md b/documentation/beta_docs/discourse-features.md
new file mode 100644
index 00000000..bac3e064
--- /dev/null
+++ b/documentation/beta_docs/discourse-features.md
@@ -0,0 +1,51 @@
+---
+title: Discourse Features Support Lexicon
+---
+
+Below is a table of Discourse features which provides the details and current status about the support for a given feature in Lexicon.
+
+If we missed one, or anything looks out of date here, don't hesitate to submit a Pull Request which updates the table.
+
+**Table Legend**
+
+| Emoji | Meaning |
+| ----- | -------------------------------------------- |
+| โ
| Supported in Lexicon-powered mobile apps |
+| โ | Not supported in Lexicon-powered mobile apps |
+| ๐ง | Requires some configuration |
+| ๐จ | Planned or under development |
+
+| Feature | Description | Supported | Notes |
+| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| 2FA Login | Allow users with 2FA enabled to be prompted for their 2FA code when logging in | โ
| Managing 2FA, such as enabling it or disabling it from within the app, is not currently supported. |
+| Ability to Tag Topics | Create and tag topics to provide relevant metadata for your users. | โ
๐ง | Configuration required: see [Optimal Experience](optimal#enable-topic-tagging). |
+| Topic Previews (Excerpts) | Show an excerpt of the first post in a topic from the Home screen. | โ
๐ง | Configuration required: see [Optimal Experience](optimal#enable-topic-excerpts). |
+| View User Activity | View a user's recent activityโsuch as topics, posts, and likesโin a single feed from their profile. | โ
| The ability to filter by activity is not currently supported. |
+| Topic Metrics | Likes, Views, Replies, and Frequent Posters | โ
| |
+| Topic & Post Actions | Ability to like and edit topics and posts | โ
| |
+| View Top & Latest Topics | A Tab View at the top of the main feed provides the ability to switch between Latest and Top activity | โ
| |
+| Search | Search the current Discourse instance for topics and posts based on keywords, categories, and tags | โ
| |
+| Categories | View the category of a topic and filter topics by a given category | โ
| Categories cannot be created, updated, or deleted. |
+| Attaching Media to Posts | Users can attach media to a post from the app | โ
๐ง | Configuration recommended for supported file extensions-see [Optimal Experience](optimal#configure-upload-extensions) |
+| Standard Markdown | Standard Markdown is supported in the editor and rendered correctly in the mobile app | โ
| Light, incomplete support exists for some of Discourse's custom markup, such as dates. |
+| Sign Up | Allow users to sign up for an account directly through the mobile app, depending on whether your Discourse instance allows new user registration or not | โ
| |
+| Browsing Public Instances | Allow users to immediately access and browse your Discourse instance from the mobile app if it is not private | โ
| Users will be prompted to login upon attempting an authenticated action. |
+| User Profiles | Ability to view users' profiles and edit your own | โ
| Partial Support. The profile screen displays the user's photo, username, Markdown bio on a single line, and recent activity. |
+| Post Flagging | Allow users to flag posts for admins to review | โ
| Admins are not able to review posts in the app, though they will see in-app notifications for flags |
+| In-App Notifications | Allow users to see new notifications from the profile screen of the mobile app and mark all notifications as read | โ
| Some notifications from Discourse are not tappable in the mobile app, such as badge notifications. |
+| Private messaging | Allow users to start private or group messages with one another | โ
| |
+| Mentions | Allow users to mention a user when creating or editing posts and messages. | โ
|
+| Color Mode | Provides light and dark mode support for users. | โ
| Users can manually specify light or dark mode, or allow their device's settings to dictate the current color mode. This does not synchronize with the Discourse web theme (if the user happens to have chosen a Dark theme on the website) |
+| Badges | The ability to see and interact with badges that have been awarded to users on the Discourse instance | โ | |
+| Post Drafts | Enable users to start composing a draft of a post and return to it later | โ | |
+| Groups | Enable users to create and participate in private groups of which only group members can view certain topics | โ | |
+| Admin Features | Discourse provides an entire admin panel for managing and moderating the forum. These features are not available in Lexicon, and may be better suited to a desktop environment. | โ | Editing posts is supported |
+| Post Quotes, Polls, Toggles, and Task Lists | Custom text formatting that enables Discourse-specific features | โ ๐จ | |
+| Discourse Emojis | Utilize emojis when creating a topic, making a post, or sending a reply. | โ
| Unicode-based emojis are of course supported. BBCode emoji is already support in lexicon Beta for example `:smile:` or `:raised_back_of_hand:t5:` |
+| Post Bookmarks | Allow users to bookmark certain posts or topics | โ | |
+| DiscourseConnect (SSO) | Replace Discourse authentication with a Custom Provider | โ | |
+| Custom Authentication Plugins | Login via OAuth2 or other protocols using custom Discourse Plugins | โ | |
+| Real-time Chat | Enable users to initiate conversations using the chat feature, either in a channel or through private messaging. | โ | |
+| User Status | Allow other user in community to see user message status | โ | |
+
+Please note that this table is subject to change as the Lexicon Mobile App evolves, and new features may be added or existing features may be improved based on user feedback and development efforts.
diff --git a/documentation/docs/app-store.md b/documentation/docs/app-store.md
index 5a8104a8..941750d5 100644
--- a/documentation/docs/app-store.md
+++ b/documentation/docs/app-store.md
@@ -13,34 +13,27 @@ In this page, we'll cover the process of publishing it on iOS.
- An Apple Developer account
- An Expo account
- XCode is installed on your development machine
+- EAS CLI 2.6.0 or newer
-To get started with Test Flight and publishing your app, you'll need an **Apple Developer account** account.
+To get started with TestFlight and publishing your app, you'll need an **Apple Developer account**.
-This will enable you to interact with Apple as you go through the process of submitting to Test Flight and, eventually, the App Store.
+This will enable you to interact with Apple as you go through the process of submitting to TestFlight and, eventually, the App Store.
-Similarly, you'll need an [Expo account](https://expo.dev/signup) so you can build your app, download it, and upload it to Apple's servers.
+You'll also need an [Expo account](https://expo.dev/signup) so you can build your app, download it, and upload it to Apple's servers.
Finally, you'll want to have already downloaded and installed [Xcode](https://developer.apple.com/xcode/), which is what you'll use to upload your built app to Apple's servers.
:::note
-If you don't yet have an account, you'll need to enroll in the [Apple Developer Program](https://developer.apple.com/programs/enroll/) first. Note that there is an annual cost associated with this.
-:::
-
-Additionally, you'll want to make sure that you have accounts
-
-## Publish to Test Flight
+If you don't yet have an account with Apple, you'll need to enroll in the [Apple Developer Program](https://developer.apple.com/programs/enroll/) first. Note that there is an annual cost associated with this.
-Test Flight is a key aspect of Apple's Developer Program, which enables developers to provide beta users with access to their app under less-strict review requirements.
-
-With Test Flight, you're able to invite users to test and collect their feedback before releasing your app to the public on the App Store.
-
-You can learn more about Test Flight [here](https://developer.apple.com/testflight/).
+Additionally, you'll want to make sure you have an account with [Expo](https://expo.dev/signup) so you can use features like [EAS Submit](https://docs.expo.dev/submit/introduction/).
+:::
-### Register a new Bundle ID
+## Register a new Bundle ID
-Each App in the App Store has a unique **Bundle Identifier**, or Bundle ID.
+Each app in Apple's App Store has a unique **Bundle Identifier**, or Bundle ID.
-In order to publish the app anywhere, including to Test Flight, you'll need to have a Bundle ID registered for your app with Apple.
+In order to publish the app anywhere, including to TestFlight, you'll need to have a Bundle ID registered for your app with Apple.
Typically, this uses the format of `com..`.
@@ -64,7 +57,7 @@ You can follow these instructions to get one.
- You can leave this section empty.
-### Add New App in App Store Connect
+## Add a New App in App Store Connect
Steps:
@@ -77,32 +70,47 @@ Steps:
- **Platforms**: Select `iOS`.
- - **Name** : The name of your app, as it will appear on the App Store and user's devices.
- - **Primary Language** : The Primary language that will be used if localized app information is not available.
- - **Bundle ID** : Choose the Bundle ID you created above.
+ - **Name**: The name of your app, as it will appear on the App Store and user's devices.
+ - **Primary Language**: The primary language that will be used if localized app information is not available.
+ - **Bundle ID**: Choose the Bundle ID you created above.
- **Note**: double-check that it's correct, because you can not change it afterwards.
- **SKU (Stock Keeping Unit)**: A unique ID to differentiate your app from the others, similar to a product ID.
- - **User Access** Full access means all users will have access to the app, while limited access means that the app can only be accessed by certain roles defined within App Store Connect.
+ - **User Access**: Full access means all users will have access to the app, while limited access means that the app can only be accessed by certain roles defined within App Store Connect.
-### Configuration
+## Configuration
After creating the app in App Store Connect, you'll want to jump back over to the codebase and make some adjustments.
-In particular, you'll want to open `frontend/app.json` and find the `ios` section of the file.
+### Build Config
-```
- "ios": {
- "supportsTablet": false
- },
+:::note
+If you haven't yet installed the EAS CLI, follow the instructions in the [tutorial](tutorial/setup#install-the-eas-cli).
+:::
+
+First, you'll need to ensure you've set your app name and slug in `frontend/app.json`. The [slug](https://docs.expo.dev/workflow/glossary-of-terms/#slug) is used as part of the URL for your app on Expo's web services, so it is recommended to use kebab-case (e.g., `my-lexicon-app`).
+
+Replace these placeholders with your desired values:
+
+```json
+ "name": "",
+ "slug": "",
```
-Then, you'll want to add the information you just registered in App Store Connect:
+Next, configure EAS Build by running this command from the `frontend/` directory:
+```bash
+eas build:configure
```
+
+The EAS CLI will prompt you to specify `android.package` and `ios.bundleIdentifier` if those values are not already provided in `app.json`. You'll want to add the bundle ID you just registered in App Store Connect as the `bundleIdentifier`.
+
+Then you can see that the value has been updated in the `ios` section of `frontend/app.json` file.
+
+```json
"ios": {
"supportsTablet": false,
- "bundleIdentifier": "com.companyname.appname",
"buildNumber": "1.0.0",
+ "bundleIdentifier": "",
"config": {
"usesNonExemptEncryption" : false
}
@@ -115,76 +123,120 @@ We set `usesNonExemptEncryption` to `false` because Lexicon doesn't leverage tha
For further details, please take a look at [this link](https://developer.apple.com/documentation/bundleresources/information_property_list/itsappusesnonexemptencryption) from Apple's documentation.
:::
-### Build your App for iOS
+### Setup Config Values
+
+:::info
+When publishing your app, it is necessary to deploy Prose somewhere publicly accessible, perhaps on a cloud hosting provider like AWS or DigitalOcean. If Prose is only running on your local machine, users that download your app won't be able to use it.
+Check [the documentation](deployment) to deploy Prose if you haven't already.
+:::
-Before publishing, you'll need to build your app by instructing Expo to generate an iOS build, like so:
+Next, configure the **Prose URL** for your build in `Config.ts`. You can set a different URL for each build channel.
+:::note
+In the original release of Lexicon, the **Prose URL** was specified in `frontend/.env`. However, as part of migrating to Expo's EAS feature, we centralized the configuration into `frontend/Config.ts` to save you the trouble of needing to maintain it in more than one place, as suggested in the [Expo documentation](https://docs.expo.dev/build-reference/variables/#can-i-share-environment-variables-defined-in-easjson-with-expo-start-and-eas-update)
+:::
+
+```ts
+const config = {
+ // ...
+ buildChannels: {
+ preview: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ production: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ },
+};
```
-$ expo build:ios
+
+### Setup Apple Dveloper Account
+
+Lastly, please adjust these fields in `eas.json` with your account information to submit the app:
+
+```json
+ "base": {
+ "ios": {
+ "appleId": "",
+ "ascAppId": "",
+ "appleTeamId": ""
+ },
+ ...
+ },
```
-When you run the above command, Expo will prompt you for your Apple ID and password.
+- **appleId**: your apple ID (e.g., `john@gmail.com`).
+- **ascAppId**: your App Store Connect app ID. Find your ascAppID by following [this guide](https://github.com/expo/fyi/blob/main/asc-app-id.md) (e.g., `1234567890`).
+- **appleTeamId**: You can check your apple team ID [here](https://developer.apple.com/account/) (e.g., `12LE34XI45`).
-Expo provides documentation about this step on [Building Standalone Apps](https://docs.expo.io/distribution/building-standalone-apps/#if-you-choose-to-build-for-ios).
+## Build your App for iOS
-Once the above step has completed, login to your account on [Expo](https://expo.io) and download your newly built app.
+Before publishing, you'll need to build your app by instructing Expo to generate an iOS build.
-It is located under **Recent Builds**. You can also simply click on the Builds menu that's located on the left-hand side of the screen.
+It is recommended to build your app with the `preview` profile before releasing to verify that it works as expected. See [this tutorial](tutorial/building) to learn more about build profiles.
-- Click on the project you want to publish. Double-check that the build status is **Finished** and the platform is **iOS**.
-
+Run this command:
-- Download the iOS build by pressing `Download` button on Build artifact section.
-
+```bash
+eas build --platform ios --profile preview
+```
-This will download an IPA file representing your app, which is the format that Apple expects it to be in.
+When you run the above command, Expo will prompt you for your Apple ID and password.
-### Upload your App to Apple
+Once the above step has been completed, login to your account on [Expo](https://expo.dev) and download your newly built app.
-:::note
-You'll need to download the Application Loader developer tool if you haven't done so before.
-:::
+Navigate to your project in the [Expo web console](https://expo.dev), then click on the **Builds** menu located on the left-hand side of the screen.
+
+- Click on the project you want to install.
+
-Now that you've downloaded the IPA file you'll need to upload it to Apple's servers.
+- Download the iOS build by pressing the `Download` button in the `Build Artifact` section.
+
-In order to do this, you'll need to open the Application Loader in XCode.
+This will download a tar file containing your app. Extract the file, then drag it to your simulator to install it. See [this section](tutorial/building#1-preview) of the tutorial to learn about running the app on real devices.
-This is located under the XCode menu in the menubar when XCode is open.
+Once you have verified that the app runs as expected, you can proceed to build it for release:
+```bash
+eas build --platform ios --profile production
```
-XCode > Open Developer Tool > Application Loader
-```
-If Application Loader isn't there, you'll need to download it. Click on "More Developer Tools..." and download it from the Apple Developer Website.
+The approach for a production build is similar to the one used for generating a preview build. However, unlike a preview build, you won't be able to launch the production build in the iOS simulatorโit is intended solely for publishing to the App Store.
+
+Once this process is completed, you can proceed with submitting it to Apple. This process typically involves Apple's TestFlight service.
-Once it's ready, you can proceed with the steps below.
+## Submit to TestFlight
-Upon opening Application Loader, you'll likely be prompted for the credentials of your Apple Developer account.
+TestFlight is a key aspect of Apple's Developer Program, which enables developers to provide beta users with access to their app under less restrictive review requirements.
-Once you've successfully submitted them, you'll be able to select the IPA file from your file system.
+With TestFlight, you're able to invite users to test your app and collect their feedback before releasing it to the public on the App Store. You can learn more about TestFlight [here](https://developer.apple.com/testflight/).
-After selecting it, click "Open" in order to begin uploading the IPA.
+Submitting an iOS app is much easier with EAS Submit. This is covered in more detail in the [tutorial](tutorial/publishing).
-### Submit to Test Flight
+Run the following command to start publishing the app to TestFlight:
+
+```bash
+eas submit --platform ios --profile production
+```
-Once the IPA has been uploaded, you can submit it to Test Flight.
+Once the process has completed successfully, we can check the build in App Store Connect.
-In App Store Connect, click on the Test Flight Tab.
+In App Store Connect, click on the TestFlight Tab.
You'll see the [status](https://help.apple.com/app-store-connect/#/dev3d6869aff) of your built version.
- **Red** indicates that you need to perform some action.
- **Yellow** indicates that some aspect of the process is pendingโeither from you, or from Apple.
-- **Green** indicates that the build is being tested in Test Flight, or is ready to be submitted for review.
+- **Green** indicates that the build is being tested in TestFlight, or is ready to be submitted for review.
-You won't be able to begin beta testing with Test Flight until an tester from Apple verifies your app.
+You won't be able to begin beta testing with TestFlight until an official tester from Apple verifies your app.
In order to allow Apple to properly test your Lexicon-powered app, they'll need to have credentials to login your Discourse site.
Before submitting your app, you'll need to create those credentials in Discourse and specify them in App Store Connect.
- In App Store Connect, click on your app.
-- Click on Test Flight App.
+- Click on TestFlight App.
- Click on Test Information in the sidebar on the left-hand side.
- Fill the required fields, then check the `Sign in required` checkbox, and enter the credentials.
@@ -201,13 +253,13 @@ Similarly, you can specify external users by selecting External Groups, and clic
#### More Information
-Test Flight and App Store Connect are sophisticated tools to help with the process of submitting, testing, and publishing your app.
+TestFlight and App Store Connect are sophisticated tools to help with the process of submitting, testing, and publishing your app.
If you have further questions or just want to learn more, we'd recommend that you make use of Apple's documentation, which is very high quality.
-For more information about Test Flight in general, read the [documentation](https://developer.apple.com/testflight/).
+For more information about TestFlight in general, read the [documentation](https://developer.apple.com/testflight/).
-Similarly, for specific information about beta testing with Test Flight, check out [Testing Apps with TestFlight](https://testflight.apple.com/).
+Similarly, for specific information about beta testing with TestFlight, check out [Testing Apps with TestFlight](https://testflight.apple.com/).
## Publish to the App Store
diff --git a/documentation/docs/concepts.md b/documentation/docs/concepts.md
index cdd178a3..f32b0652 100644
--- a/documentation/docs/concepts.md
+++ b/documentation/docs/concepts.md
@@ -14,18 +14,16 @@ However, [the official documentation](https://docs.discourse.org/) for this API
>
> โ**Discourse API Documentation**
-The core team, as well as members of the [support forum](https://meta.discourse.org), regularly respond to questions about the API by [encouraging developers to reverse-engineer the API](https://meta.discourse.org/t/how-to-reverse-engineer-the-discourse-api/20576). As of this writing, the topic for how to reverse engineer the API has been linked to from nearly 170 other topics on the support forum.
+The core team, as well as members of the [support forum](https://meta.discourse.org), regularly respond to questions about the API by [encouraging developers to reverse-engineer the API](https://meta.discourse.org/t/how-to-reverse-engineer-the-discourse-api/20576). As of this writing, the topic for how to reverse engineer the API has been linked to from nearly 200 other topics on the support forum.
To help you simplify the process for you, Prose strives to normalize a subset of the API. We have done so with the hope that it will save you some time as you develop against Discourse.
-#### GraphQL Playground
+#### GraphiQL
-Prose's GraphQL implementation includes an [interactive GraphQL IDE](https://github.com/graphql/graphql-playground), known as the GraphQL Playground, which allows developers to easily reference the entire documentation and schema.
+Prose's GraphQL implementation includes an [in-browser GraphQL IDE](https://www.graphql-yoga.com/docs/features/graphiql), known as [GraphiQL](https://github.com/graphql/graphiql), which allows developers to easily reference the entire documentation and schema and make queries against a running Discourse instance.
-_You tried to click the Play button on the image, didn't you?_
-
This means you can rapidly get a clear understanding of how a method behavesโand what parameters it requiresโwithout digging through support posts or reverse-engineering the REST API.
#### Why GraphQL?
@@ -46,19 +44,17 @@ Having said that, we chose to build Lexicon with it for two primary reasons.
We find that Expo makes us much more effective as developers, and also provides excellent services to facilitate the entire process of building and publishing React Native apps.
-## Architecture of the Lexicon Stack
-
-While it's a fairly lightweight setup to describe as an application stack, our reference here to the **Lexicon Stack** refers to all of the components needed to produce the Lexicon mobile experience.
+## Lexicon Architecture
The Lexicon Stack is fairly simple, and only consists of 3 major pieces:
- The Lexicon Mobile App
- The Prose GraphQL API
-- A running Discourse instance
+- A running, accessible Discourse instance
Below is a diagram illustrating the typical architecture for a Lexicon-powered mobile app.
-![Architecture Diagram](/img/lexicon-architecture.png)
+
As indicated above, the mobile app makes requests to a deployed Prose GraphQL server.
diff --git a/documentation/docs/dedicated.md b/documentation/docs/dedicated.md
index 34e014b4..75fe8afe 100644
--- a/documentation/docs/dedicated.md
+++ b/documentation/docs/dedicated.md
@@ -243,7 +243,7 @@ Regardless, to emphasize it again, it is **critical** that you don't deploy Pros
When someone navigates to your host which is running Prose, how will their request get routed to Prose?
-If you had exposed Prose directly on port 80โNOT recommendedโand your host's domain name was `myproseserver.com`, then a user would navigate to `http://myproseserver.com` and be greeted with the GraphQL Playground.
+If you had exposed Prose directly on port 80โNOT recommendedโand your host's domain name was `myproseserver.com`, then a user would navigate to `http://myproseserver.com` and be greeted with the [GraphiQL interface](https://www.graphql-yoga.com/docs/features/graphiql).
However, a more common approach is to use a dedicated webserver, such as Nginx or Apache, that acts as a reverse-proxy.
@@ -293,7 +293,7 @@ Otherwise, you'll want to get the IP address of your host, go into your domain p
#### Ready to Go
-At this point, your deployed host should be running Prose correctly. When you navigate to the domain name that you configured it with, you should see the GraphQL Playground, which will allow you to make GraphQL queries against your Discourse instance.
+At this point, your deployed host should be running Prose correctly. When you navigate to the domain name that you configured it with, you should see [GraphiQL](https://www.graphql-yoga.com/docs/features/graphiql), which will allow you to make GraphQL queries against your Discourse instance.
We understand that the details of your deployment can vary quite a bit depending on how you chose to do it.
diff --git a/documentation/docs/discourse-features.md b/documentation/docs/discourse-features.md
index ca052932..3183014a 100644
--- a/documentation/docs/discourse-features.md
+++ b/documentation/docs/discourse-features.md
@@ -18,34 +18,35 @@ For this reason, most admin tasks are still best accomplished using the Discours
### Lexicon Mobile App Features
-| Feature | Description | Supported | Notes |
-| ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------- |
-| 2FA Login | Allow users with 2FA enabled to be prompted for their 2FA code when logging in | โ
| Managing 2FA, such as enabling it or disabling it, is not currently supported. |
-| Ability to Tag Topics | Create and tag topics to provide relevant metadata for your users. | โ
๐ง | Configuration Required-see [Optimal Experience](optimal#enable-topic-tagging). |
-| Topic Previews (Excerpts) | Show an excerpt of the first post in a topic from the Home screen. | โ
๐ง | Configuration Required-see [Optimal Experience](optimal#enable-topic-excerpts). |
-| View User Activity | View a user's recent activityโsuch as topics, posts, and likesโin a single feed from their profile. | โ
| The ability to filter by activity is not currently supported. |
-| Topic Metrics | Likes, Views, Replies, and Frequent Posters | โ
| |
-| Topic & Post Actions | Ability to like and edit topics and posts | โ
| |
-| View Top & Latest Topics | A Tab View at the top of the main feed provides the ability to switch between Latest and Top activity | โ
| |
-| Search | Search the current Discourse instance for topics and posts based on keywords, categories, and tags | โ
| |
-| Categories | View the category of a topic and filter topics by a given category | โ
| Categories cannot be created, updated, or deleted. |
-| Attaching Media to Posts | Users can attach media to a post from the app | โ
๐ง | Configuration Recommended for supported file extensions-see [Optimal Experience](optimal#configure-upload-extensions) |
-| Standard Markdown | Standard Markdown is supported in the editor and rendered correctly in the mobile app | โ
| Light, incomplete support exists for some of Discourse's custom markup, such as dates. |
-| Sign Up | Allow users to sign up for an account directly through the mobile app, depending on whether your Discourse instance allows new user registration or not | โ
| |
-| Browsing Public Instances | Allow users to immediately access and browse your Discourse instance from the mobile app if it is not private | โ
| Users will be prompted to login upon attempting an authenticated action. |
-| User Profiles | Ability to view users' profiles and edit your own | โ
| Partial Support. The profile screen displays the user's photo, username, Markdown bio on a single line, and recent activity. |
-| Post Flagging | Allow users to flag posts for admins to review | โ
| Admins are not able to review posts in the app, though they will see in-app notifications for flags |
-| In-App Notifications | Allow users to see new notifications from the profile screen of the mobile app and mark all notifications as read | โ
| Some notifications from Discourse are not tappable in the mobile app, such as badge notifications. |
-| Private messaging | Allow users to start private or group messages with one another | โ
| |
-| Mentions | Allow users to mention a user when creating or editing posts and messages. | โ
|
-| Color Mode | Provides light and dark mode support for users. | โ
| Users can manually specify light or dark mode, or allow their device's settings to dictate the current color mode. |
-| Push Notifications | Enable users to be directly notified of activity on their mobile devices. | โ๐จ | Under Development |
-| Email Deep Linking | Automatically open the mobile app to a specific post, message, etc. when a link is clicked from an email notification | โ | Complex task that may either require a custom theme or a manual guide |
-| Badges | The ability to see and interact with badges that have been awarded to users on the Discourse instance | โ | |
-| Post Drafts | Enable users to start composing a draft of a post and return to it later | โ | |
-| Groups | Enable users to create and participate in private groups of which only group members can view certain topics | โ | |
-| Admin Features | Discourse provides an entire admin panel for managing and moderating the forum. These features are not available in Lexicon, and may be better suited to a desktop environment. | โ | Editing posts is supported |
-| Post Quotes, Polls, Discourse Emojis, Toggles, and Task Lists | Custom text formatting that enables Discourse-specific features | โ | Unicode-based emojis are of course supported. |
-| Post Bookmarks | Allow users to bookmark certain posts or topics | โ | |
-| Discourse SSO | Replace Discourse authentication with a Custom Provider | โ | |
-| Custom Authentication Plugins | Login via OAuth2 or other protocols using custom Discourse Plugins | โ | |
+| Feature | Description | Supported | Notes |
+| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------- |
+| 2FA Login | Allow users with 2FA enabled to be prompted for their 2FA code when logging in | โ
| Managing 2FA, such as enabling it or disabling it from within the app, is not currently supported |
+| Ability to Tag Topics | Create and tag topics to provide relevant metadata for your users | โ
๐ง | Configuration required: see [Optimal Experience](optimal#enable-topic-tagging) |
+| Topic Previews (Excerpts) | Show an excerpt of the first post in a topic from the Home screen | โ
๐ง | Configuration required: see [Optimal Experience](optimal#enable-topic-excerpts) |
+| View User Activity | View a user's recent activityโsuch as topics, posts, and likesโin a single feed from their profile | โ
| The ability to filter by activity is not currently supported |
+| Topic Metrics | Likes, Views, Replies, and Frequent Posters | โ
| |
+| Topic & Post Actions | Ability to like and edit topics and posts | โ
| |
+| View Top & Latest Topics | A Tab View at the top of the main feed provides the ability to switch between Latest and Top activity | โ
| |
+| Search | Search the current Discourse instance for topics and posts based on keywords, categories, and tags | โ
| |
+| Categories | View the category of a topic and filter topics by a given category | โ
| Categories cannot be created, updated, or deleted |
+| Attaching Media to Posts | Users can attach media to a post from the app | โ
๐ง | Configuration recommended for supported file extensions-see [Optimal Experience](optimal#configure-upload-extensions) |
+| Standard Markdown | Standard Markdown is supported in the editor and rendered correctly in the mobile app | โ
| Light, incomplete support exists for some of Discourse's custom markup, such as dates |
+| Sign Up | Allow users to sign up for an account directly through the mobile app, depending on whether your Discourse instance allows new user registration or not | โ
| |
+| Browsing Public Instances | Allow users to immediately access and browse your Discourse instance from the mobile app if it is not private | โ
| Users will be prompted to login upon attempting an authenticated action |
+| User Profiles | Ability to view users' profiles and edit your own | โ
| Partial support: displays the user's photo, username, Markdown bio on a single line, and recent activity |
+| Post Flagging | Allow users to flag posts for admins to review | โ
| Admins are not able to review posts in the app, though they will see in-app notifications for flags |
+| In-App Notifications | Allow users to see new notifications from the profile screen of the mobile app and mark all notifications as read | โ
| Some notifications from Discourse are not tappable in the mobile app, such as badge notifications |
+| Private messaging | Allow users to start private or group messages with one another | โ
| |
+| Mentions | Allow users to mention a user when creating or editing posts and messages | โ
|
+| Color Scheme | Provides light and dark mode support for users | โ
| Specify color scheme (light mode, dark mode, or system) from within the app (only local to the user's mobile device) |
+| Badges | The ability to see and interact with badges that have been awarded to users on the Discourse instance | โ | |
+| Post Drafts | Enable users to start composing a draft of a post and return to it later | โ | |
+| Groups | Enable users to create and participate in private groups of which only group members can view certain topics | โ | |
+| Admin Features | Discourse admin features generally not available in Lexiconโbetter suited to a desktop environment | โ | Editing posts is supported |
+| Post Quotes, Polls, Toggles, and Task Lists | Custom text formatting that enables Discourse-specific features | โ | |
+| Discourse Emojis | Utilize emojis when creating a topic, making a post, or sending a reply | โ | Unicode-based emojis are of course supported |
+| Post Bookmarks | Allow users to bookmark certain posts or topics | โ | |
+| DiscourseConnect (SSO) | Replace Discourse authentication with a Custom Provider | โ | |
+| Custom Authentication Plugins | Login via OAuth2 or other protocols using custom Discourse Plugins | โ | |
+| Real-time Chat | Enable users to initiate conversations using the chat feature, either in a channel or through private messaging | โ | |
+| User Status | Allow other user in community to see user message status | โ | |
diff --git a/documentation/docs/discourse-plugin-enable.md b/documentation/docs/discourse-plugin-enable.md
new file mode 100644
index 00000000..9c032a6a
--- /dev/null
+++ b/documentation/docs/discourse-plugin-enable.md
@@ -0,0 +1,34 @@
+---
+title: Enable the Lexicon Plugin
+slug: discourse-plugin/enable
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+---
+
+After you have confirmed the plugin has been installed and your Discourse instance is running again, you can follow these steps to enable the plugin:
+
+1. As an admin user, access your Discourse admin dashboard.
+
+2. Navigate to the `Plugins` tab.
+
+You'll notice that the `discourse-lexicon-plugin` is not enabled yet.
+
+
+
+3. Click on the `Settings` button for the `discourse-lexicon-plugin` entry.
+
+4. Select the feature you want to enable and turn it on.
+
+##### Push Notifications
+
+For push notifications, all you need to do is check the box for `lexicon push notifications enabled`. This is covered in [Enable Push Notifications](push-notifications/setup/enable-push-notifications).
+
+##### Email Deep Linking
+
+For email deep linking, you need to fill in your app scheme first before enabling it.
+
+
+
+This is covered in detail in [Enable Email Deep Linking](./email-deep-linking/setup/enable-email-deep-linking.md).
diff --git a/documentation/docs/discourse-plugin-installation.md b/documentation/docs/discourse-plugin-installation.md
new file mode 100644
index 00000000..911770b1
--- /dev/null
+++ b/documentation/docs/discourse-plugin-installation.md
@@ -0,0 +1,82 @@
+---
+title: Plugin Installation
+slug: discourse-plugin/setup
+---
+
+Before you can start using the Lexicon Discourse Plugin, there are a few prerequisites and installation steps you need to follow. This documentation will guide you through the process, ensuring a smooth setup of the plugin on your site.
+
+## Prerequisites
+
+In order to use this plugin, you must have access to your Discourse server in a way which allows you to modify the server's `app.yml`. If a hosting provider is managing Discourse for you, you will have to contact them to request that they install the plugin on your behalf.
+
+Specifically, you will need the ability to install plugins, which means directly modifying `/var/discourse/containers/app.yml` to include the [Lexicon Discourse plugin](https://github.com/lexiconhq/discourse-lexicon-plugin.git), and then rebuilding your site.
+
+## Plugin Installation Steps
+
+### Access your Server
+
+Login to your underlying Discourse host server via SSH.
+
+This is specific to each hosting setup, but typically you will need to use a terminal application such as Terminal on macOS or PuTTY on Windows.
+
+### Open the Discourse `app.yml` file
+
+Feel free to use your terminal editor of choice (vim, emacs, nano, etc.).
+
+:::note
+You may need `sudo` access to edit the file, but it depends on how the server was configured.
+:::
+
+```bash
+vim /var/discourse/containers/app.yml
+```
+
+### Get the Pluginโs Git Clone URL
+
+Discourse plugins are referenced by their reachable Git clone URLs, which typically end with `.git`.
+
+The Git clone URL for the [Lexicon Discourse plugin](https://github.com/lexiconhq/discourse-lexicon-plugin) can be found below:
+
+```
+https://github.com/lexiconhq/discourse-lexicon-plugin.git
+```
+
+Copy it to your clipboard for use in the next step.
+
+### Add the pluginโs repository URL to your containerโs `app.yml` file:
+
+Add the pluginโs Git clone url to the section below.
+
+```
+hooks:
+ after_code:
+ - exec:
+ cd: $home/plugins
+ cmd:
+ - git clone https://github.com/lexiconhq/discourse-lexicon-plugin.git
+```
+
+### Rebuild the container, with caution
+
+:::caution
+Please be aware that rebuilding your site will result in your site going offline for a period of time, typically between 5 to 30 minutes. We advise proceeding carefully and taking precautions outlined below.
+:::
+
+#### Precautionary Measures
+
+1. Before installing the plugin or performing any site rebuild, it is highly recommended to create a backup of your Discourse site.
+1. It is advisable to upgrade your Discourse installation and all existing plugins to their latest versions before attempting to install this plugin.
+1. Although rare, there may be situations where the site does not come back online after the rebuilding process, and requires further troubleshooting to revive.
+ - This is always a risk when installing a plugin or performing any task that requires rebuilding the app.
+ - We recommend that you perform these changes at a time that minimizes the users affected and that you have a well-defined contingency plan in place if something goes wrong.
+
+#### Run Rebuild Command
+
+```bash
+cd /var/discourse
+./launcher rebuild app
+```
+
+### How to Uninstall the Plugin
+
+To remove the plugin, simply remove the Git clone URL line from your `app.yml` file and rebuild your site. Please keep in mind that rebuilding your site will will result in your site going offline for a period of time, and poses the same risks that come with rebuilding the app.
diff --git a/documentation/docs/discourse-plugin.md b/documentation/docs/discourse-plugin.md
new file mode 100644
index 00000000..de85ea89
--- /dev/null
+++ b/documentation/docs/discourse-plugin.md
@@ -0,0 +1,15 @@
+---
+title: Lexicon Discourse Plugin
+slug: discourse-plugin/
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+---
+
+Discourse lacks native mobile app functionalities such as push notifications and deep linking.
+
+To address this, Lexicon has developed a custom Discourse plugin that seamlessly integrates push notifications and deep linking capabilities.
+
+- By leveraging Expo's powerful features, our plugin establishes a secure connection between your Discourse site and Expo's push notification service, delivering real-time updates to users' mobile devices based on your site's activity.
+- Additionally, our plugin generates custom deep links in email notifications, allowing users seamlessly launch your Lexicon-powered mobile app directly from their mobile email client.
diff --git a/documentation/docs/email-deep-linking/intro.md b/documentation/docs/email-deep-linking/intro.md
new file mode 100644
index 00000000..ca863368
--- /dev/null
+++ b/documentation/docs/email-deep-linking/intro.md
@@ -0,0 +1,9 @@
+---
+id: intro
+title: Introduction
+slug: discourse-plugin/email-deep-linking
+---
+
+The Lexicon Discourse plugin provides support for integrating Discourse's email notifications with your Lexicon-powered mobile app. Our plugin modifies links in specific Discourse emails so that when a relevant link is tapped and the user has your Lexicon-powered mobile app installed, it will open the app to the relevant topic or post. Otherwise, it will fall back to opening the topic in the device's web browser as it normally would.
+
+This section of the documentation offers step-by-step instructions to integrate email deep linking into your Discourse site so that your users have a more seamless experience with your Lexicon-powered mobile app.
diff --git a/documentation/docs/email-deep-linking/setup/enable-email-deep-linking.md b/documentation/docs/email-deep-linking/setup/enable-email-deep-linking.md
new file mode 100644
index 00000000..73c7dd3f
--- /dev/null
+++ b/documentation/docs/email-deep-linking/setup/enable-email-deep-linking.md
@@ -0,0 +1,25 @@
+---
+title: Enabling the Lexicon Discourse plugin
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+This guide will walk you through the necessary steps to activate email deep linking on your Discourse site.
+
+## Steps
+
+1. Access your Discourse admin dashboard.
+
+2. Navigate to the `Plugins` section.
+
+
+
+3. Locate the `discourse-lexicon-plugin` and click on the `Settings` button.
+
+4. Fill in the `lexicon app scheme` setting with your app scheme. The app scheme is required to enable email deep linking.
+
+5. Check the `lexicon email deep linking enabled` box in the Lexicon settings section and save your changes.
+
+
+
+Once the email deep linking feature is enabled, you will be able to utilize its functionality in your Discourse instance.
diff --git a/documentation/docs/email-deep-linking/setup/verify-email-deep-linking.md b/documentation/docs/email-deep-linking/setup/verify-email-deep-linking.md
new file mode 100644
index 00000000..0fe7642d
--- /dev/null
+++ b/documentation/docs/email-deep-linking/setup/verify-email-deep-linking.md
@@ -0,0 +1,49 @@
+---
+title: Verify Email Deep Linking
+slug: verify-email-deep-linking
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+:::note
+The steps below assume that **you have already published your Lexicon-powered mobile app** to the App Store and/or Google Play Store **with the correct app scheme**. If you are running the app on your machine locally through Expo, you should not expect the steps to work.
+:::
+
+This guide will provide you with step-by-step instructions to help you validate the functionality of email deep linking within your Lexicon mobile app.
+
+## Pre-requisites
+
+:::note
+If you have not yet fulfilled all of the pre-requisites below, this test will not work as expected.
+:::
+
+In order to test email deep linking properly:
+
+1. You **must** have already published your Lexicon-powered mobile app to the App Store and/or Google Play Store.
+1. You have already installed and configured the Lexicon Discourse plugin on your Discourse site.
+1. You have enabled email deep linking within the Lexicon Discourse plugin settings, and the app scheme matches what you published your app with.
+1. You have at least 1 mobile device with your Lexicon-powered mobile app already installed, with the correct app scheme as it was configured in Discourse.
+1. You have at least 2 separate Discourse accounts to test with.
+1. Ensure your Discourse site allows **mailing list mode**, and that it is turned on for the accounts you are testing with.
+ - If you do not do this, you will have to wait for Discourse to send its next digest email, which could take a while.
+
+## Steps
+
+To test email deep linking within your **published** Lexicon-powered mobile app, follow these steps:
+
+1. Ensure you have access to at least 2 separate accounts on your Discourse instance.
+1. On your mobile device, open your Lexicon-powered mobile app and login using one of your accounts.
+ - **Note**: ensure that your email client on your mobile device will receive emails for this account.
+1. Open your Discourse site in a web browser on your laptop or desktop computer.
+1. Login to your **second** Discourse account in your web browser.
+1. On your mobile device, using the **first** account, create a new post.
+1. Now, on your laptop or desktop computer, using the **second** account, find the post you created on the mobile app and reply to it.
+1. Back on your mobile device, you should receive an email notification from Discourse about the reply from the second account.
+1. Click on the button that says `Visit Message` or `Visit Topic`. The label depends on what activity generated the email (see screenshot below).
+1. The link will first open in your mobile web browser. Provided that the Lexicon-powered mobile app is installed and matches the configured app scheme, it should automatically open your app to the relevant topic or message scene.
+
+
+
+
+
+And that's it! You have successfully completed the steps to enable and test email deep linking in your app.
diff --git a/documentation/docs/env-mobile.md b/documentation/docs/env-mobile.md
index df2ed995..79af9933 100644
--- a/documentation/docs/env-mobile.md
+++ b/documentation/docs/env-mobile.md
@@ -1,48 +1,119 @@
---
-title: Environment Variables
+title: Configuration Values
---
-The table below lays out environment variables for the Lexicon Mobile App.
+You can check and set the configuration values in `frontend/Config.ts`.
+
+The table below describes the configuration values for the Lexicon Mobile App.
If there is a default value indicated, you do not need to set it.
-| Environment Variable | Required | Notes | Default Value | Example Value |
-| -------------------- | -------- | ---------------------------------------------------------------- | ------------- | -------------------------- |
-| MOBILE_PROSE_HOST | Yes | The hostname of the Prose Server (must start with http or https) | - | https://prose.myserver.com |
-| MOBILE_PROSE_PORT | No | The port of the Prose Server | (empty) | 8080 |
+| Variable | Required | Notes | Default Value | Example Value(s) |
+| -------------------- | -------- | -------------------------------------------------------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
+| proseUrl | Yes | The url of the Prose Server (must start with http or https) | - | https://prose.myserver.com https://prose.myserver.com:8080 https://prose.myserver.com/subpath https://prose.myserver.com:8080/subpath |
+| inferDevelopmentHost | No | The flag (true / false) to override localhost with the host of the development machine | (empty) | true |
+
+## The `config` object
+
+In the `Config.ts` file, you'll find a `config` object that allows you to specify configuration values by scenario.
+
+The two primary scenarios are:
+
+- `localDevelopment`: when developing against the app locally. This configuration is also used as a fallback for an unknown build channel.
+- `buildChannels`: used to define configuration by build channel when building the app with the EAS CLI.
-## `MOBILE_PROSE_HOST`
+Primarily, you'll only be concerned with configuring `proseUrl` for each of these sections.
-Note that `MOBILE_PROSE_HOST` must always be specified, and must always start with either `http://` or `https://`.
+## `proseUrl`
-Otherwise The Lexicon Mobile App has no idea what server to talk to in order to interact with Discourse.
+:::caution
+`proseUrl` must always be specified, with or without a port number, and must always start with either `http://` or `https://`.
+:::
+
+`proseUrl` is used to specify the URL of the Prose GraphQL API.
+
+The Prose GraphQL API acts a middleman between the Lexicon Mobile App and your Discourse instance. Without it, the mobile app cannot interact with your Discourse instance.
+
+### Example
+
+```ts
+const config = {
+ localDevelopment: {
+ proseUrl: 'http://localhost:8929',
+ },
+ buildChannels: {
+ preview: {
+ proseUrl: 'https://preview.myserver.com',
+ },
+ production: {
+ proseUrl: 'https://prose.myserver.com',
+ },
+ },
+};
+```
+
+With this configuration above, the app will:
+
+- point at `http://localhost:8929` when you run the app using `npm run start`
+- point at `https://preview.myserver.com` when you build the app using `eas build --profile preview`
+- point at `https://prose.myserver.com` when you build the app using `eas build`
+
+`proseUrl` also can include a subpath if desired:
+
+```ts
+const config = {
+ localDevelopment: {
+ proseUrl: 'http://localhost:8929',
+ },
+ buildChannels: {
+ preview: {
+ proseUrl: 'https://preview.myserver.com:8080/subpath',
+ },
+ production: {
+ proseUrl: 'https://myserver.com/api/prose',
+ },
+ },
+};
+```
**Different Behavior in Development**
-If the Mobile App detects that `NODE_ENV` is not `production`, then it will adjust its behavior slightly if `MOBILE_PROSE_HOST` is making use of `localhost` or `127.0.0.1`.
+When running the app locally, if `proseUrl` is set to `http://localhost` or `http://127.0.0.1`, it will replace `proseUrl` with the IP address of your development machine. It does this by using Expo's `debuggerHost` constant.
-In this case, a replacement will be made using Expo's `debuggerHost` constant, which is used to locate the IP address of your development machine.
+_Note: this does not apply when building the app._
This addresses multiple issues:
- Accessing `localhost` from within the Android simulator does not map to your development machine
-- Accessing `localhost` from a device running Expo Go does not map to your development machine, requiring you to manually identify and specify your development machine's IP address with `MOBILE_PROSE_HOST`.
+- Accessing `localhost` from a device running Expo Go does not map to your development machine
+
+Both of these scenarios would otherwise require you to manually identify and specify your development machine's IP address with `proseUrl`. This is bothersome since your machine's IP address can change over time.
If you are interested in more details about this, the implementation of this behavior is available in `frontend/constants/app.ts`.
-## `MOBILE_PROSE_PORT`
+This behavior of automatically overriding those values can be disabled, with `inferDevelopmentHost`, which is covered below.
-`MOBILE_PROSE_PORT` is used to allow explicitly specifying the port number.
+## `inferDevelopmentHost`
-```bash
-MOBILE_PROSE_HOST=http://localhost
-MOBILE_PROSE_PORT=8999
-```
+:::info
+This flag is only valid under `localDevelopment`. It has no effect when used as part of `buildChannels`.
+:::
+
+When in development, by default, the Lexicon Mobile App will check to see if `proseUrl` is set to either `http://localhost` or `http://127.0.0.1`.
+
+When detected, either of those values will be overwritten with the IP address of your development machine.
+
+This is a very useful feature that makes on-device testing simply work out of the box without needing to manually specify your IP address (or update it when it changes).
-If it is not set, only `MOBILE_PROSE_HOST` will be used to derive the host of the Prose
+For scenarios where this behavior is not desirable, `inferDevelopmentHost` can be used as a flag to disable this behavior. It can be disabled by specifying the value as `false`.
-This presents a situation where you could omit `MOBILE_PROSE_PORT` and still specify a port number, if you desired:
+When set to `false`, this behavior of overriding `proseUrl` with the development machine's IP address will no longer occur, and the original value will be passed through as-is.
-```bash
-MOBILE_PROSE_HOST=http://localhost:8999
+```ts
+const config = {
+ localDevelopment: {
+ proseUrl: 'http://localhost:8929',
+ inferDevelopmentHost: false,
+ },
+};
```
diff --git a/documentation/docs/play-store.md b/documentation/docs/play-store.md
index f1ac1dfb..dacdfa8c 100644
--- a/documentation/docs/play-store.md
+++ b/documentation/docs/play-store.md
@@ -7,10 +7,12 @@ import useBaseUrl from '@docusaurus/useBaseUrl';
## Prerequisites
:::note
-If you don't already have a Google Developer account, note that there is a $25.00 fee to create one.
+If you don't already have a Google Developer account, note that there is a fee to create one.
:::
- A [Google Developer Account](https://play.google.com/console/signup) to access the [Google Play Console](https://play.google.com/console)
+- An Expo account
+- EAS CLI 2.6.0 or newer
## Google Play Console
@@ -18,67 +20,143 @@ The [Google Play Console](https://play.google.com/console) enables you to setup
Because you're publishing an app that was built using Expo, it is **very important** that you follow [Expo's instructions](https://github.com/expo/fyi/blob/master/first-android-submission.md) for submitting an app to the Google Play store correctly.
-### Configuration
+## App Configuration
-Similar to how you configured your `app.json` in [Publishing to the App Store](app-store), you'll need to adjust the `android` section to include the details specific to your app.
+After setting up your app in the Google Play Console, there are some other adjustments you'll need to make.
+
+### Build Config
+
+Similar to the approach for [Publishing to the App Store](app-store), if you havenโt already, you'll need to set your app name and slug in `frontend/app.json`. The [slug](https://docs.expo.dev/workflow/glossary-of-terms/#slug) is used as part of the URL for your app on Expo's web services, so it is recommended to use kebab-case (e.g., `my-lexicon-app`).
+
+Replace these placeholders with your desired values:
```json
- "android": {
- "package": "com.yourdomain.yourapp",
- "versionCode": 1,
- "permissions": []
- },
+ "name": "",
+ "slug": "",
```
-Above, make sure that you always increment the `versionCode` before building a newer version of your app.
+Then, you need to configure EAS Build by running the following command, or skip to the next [step](play-store#setup-config-values):
-Also, there's one additional detail that you might want to add, depending on your app: permissions.
+```bash
+eas build:configure
+```
+
+The EAS CLI will prompt you to specify `android.package` and `ios.bundleIdentifier` if those values are not already provided in `app.json`.
+
+Next, verify that the `package` name and other details specific to your app are included in the `android` section of `app.json`. Note that the `versionCode` will be automatically updated when you build the app with the `production` profile, so you don't need to increment the version manually.
+
+Also, there's one further detail that you might want to add, depending on your app's permissions.
In the example below, we're providing our app with the ability to read and write to external storage.
```json
- "android": {
- "package": "com.yourdomain.yourapp",
- "versionCode": 1,
+ "android": {
+ "package": "",
"permissions": [ "READ_EXTERNAL_STORAGE" , "WRITE_EXTERNAL_STORAGE" ]
+ "versionCode": 1,
},
-
```
+If your app requires further permissions, be sure to specify them as needed in this part of the configuration.
+
If you don't quite understand how permissions work yet, it's best to check out the [Expo documentation](https://docs.expo.io/versions/latest/sdk/permissions) on this topic in order to get a full understanding.
-### Build your App for Android
+### Setup Config Values
-Because we're working with Expo and React Native, this step isn't too different from building your app for iOS.
+:::info
+When publishing your app, it is necessary to deploy Prose somewhere publicly accessible, perhaps on a cloud hosting provider like AWS or DigitalOcean. If Prose is only running on your local machine, users that download your app won't be able to use it.
+Check [the documentation](deployment) to deploy Prose if you haven't already.
+:::
-From the `frontend/` directory, you'll simply want to run:
+Next, set the **Prose URL** for your builds in `Config.ts`. You can set a different URL for each build channel.
+:::note
+In the original release of Lexicon, the **Prose URL** was specified in `frontend/.env`. However, as part of migrating to Expo's EAS feature, we centralized the configuration into `frontend/Config.ts` to save you the trouble of needing to maintain it in more than one place, as suggested in the [Expo documentation](https://docs.expo.dev/build-reference/variables/#can-i-share-environment-variables-defined-in-easjson-with-expo-start-and-eas-update)
+:::
+
+```ts
+const config = {
+ // ...
+ buildChannels: {
+ preview: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ production: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ },
+};
```
-$ expo build:android
+
+### Add the Play Store Secret File
+
+For the last step, you'll need to provide a `.json` file containing a private key in order to interact with the Play Store. Follow [this guide](https://github.com/expo/fyi/blob/main/creating-google-service-account.md) to generate one. Then, copy the JSON file to your `lexicon/frontend` directory, and rename the file as `playstore_secret.json`.
+
+The JSON file looks like this:
+
+```json
+{
+ "type": "service_account",
+ "project_id": "",
+ "private_key_id": "",
+ "private_key": "-----BEGIN PRIVATE KEY----------END PRIVATE KEY-----\n",
+ "client_email": "",
+ "client_id": "",
+ "auth_uri": "",
+ "token_uri": "",
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
+ "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/lexicon%40api.iam.gserviceaccount.com"
+}
```
-When executing this command, you'll be prompted with the option of building your app as an APK or as a bundle.
+## Build your App for Android
-If you'd like to test the app on your device before publishing it in the Google Play Console, you might want to build it as an APK. This enables you to quickly load it onto your Android device.
+Because we're working with Expo and React Native, this step isn't too different from building your app for iOS.
+
+From the `frontend/` directory, you can run this command to check the app before publishing:
-However, if you're planning to invite beta testers to your app in the Google Play Console, you'll want to build it as a bundle and submit it through there.
+```bash
+eas build --platform android --profile preview
+```
-Upon making your selection, Expo will initiate the build process on their servers, and will provide you with a link to monitor its progress.
+Running `eas build` with the `preview` profile will build the app as an APK. This allows you to quickly load it onto your Android device or emulator. After the build is done, navigate to your project in the [Expo web console](https://expo.dev), then click on the **Builds** menu located on the left-hand side of the screen.
-
+- Click on the project you want to install.
-Once Expo has finished building your app, you can download it to retrieve the APK or Bundle.
+
-Then, you can finish the process of publishing it by following Expo's Android-specific guide, [First Submission of an Android App](https://github.com/expo/fyi/blob/master/first-android-submission.md).
+- Download the app by pressing the `Install` button in the `Build Artifact` section.
-For further information about the `expo build:android` command, check Expo's [documentation](https://docs.expo.io/distribution/uploading-apps/#2-start-the-upload).
+
-### Publish to the Play Store
+You can download and launch the app on your real device, or drag the downloaded APK file to your emulator.
-Unlike the process of publishing an iOS app to the App Store, publishing to the Google Play Store is much simpler.
+Once you have verified that the app runs as expected, you can proceed to build it for release:
+
+```bash
+eas build --platform android --profile production
+```
-At this point, you can take your app live on the Google Play Store, or you can proceed with internal testing on the Google Play Console. It's really up to you.
+The approach for a production build is similar to the one used for generating a preview build. However, unlike a preview build, you won't be able to launch the production build in Android emulatorโit is intended solely for publishing to the Play Store.
+
+Once this process is completed, you can proceed with submitting it to the Play Store.
+
+## Publish to the Play Store
+
+At this point, you can take your app live on the Google Play Store, or you can proceed with internal testing on the Google Play Console.
+
+To proceed with internal testing, run this command:
+
+```bash
+eas submit --platform android --profile staging
+```
+
+To release your app publicly, run this command:
+
+```bash
+eas submit --platform android --profile production
+```
-And, provided that you've now also published your app to the Apple App Store, congratulations!
+You can read more about build profiles [here](tutorial/publishing).
-Your Lexicon-powered app is now live and ready to be downloaded by your users.
+At this point, provided that you've completed all the steps, congratulations! Your Lexicon-powered mobile app is now live and ready to be downloaded by your users.
diff --git a/documentation/docs/push-notifications/introduction.md b/documentation/docs/push-notifications/introduction.md
new file mode 100644
index 00000000..619429c6
--- /dev/null
+++ b/documentation/docs/push-notifications/introduction.md
@@ -0,0 +1,8 @@
+---
+title: Introduction
+slug: /push-notifications
+---
+
+The Lexicon Discourse plugin provides support for native push notifications for your Lexicon-powered mobile app. This works for both Android and iOS, and is handled by Expo's [push notifications service](https://docs.expo.dev/push-notifications/overview/).
+
+This documentation offers step-by-step instructions to seamlessly integrate push notifications into your Discourse site so that your users receive them in your Lexicon-powered mobile app. By following this guide, you will be able to enhance the UX of your users by ensuring they receive timely and engaging notifications about activity on your Discourse site.
diff --git a/documentation/docs/push-notifications/plugin-interaction.md b/documentation/docs/push-notifications/plugin-interaction.md
new file mode 100644
index 00000000..5a424ac4
--- /dev/null
+++ b/documentation/docs/push-notifications/plugin-interaction.md
@@ -0,0 +1,31 @@
+---
+title: How Push Notifications work with Lexicon
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+Below, we outline the interaction between the Lexicon mobile app, Prose, and the Discourse Plugin regarding the implementation of push notifications.
+
+## The Lexicon mobile app
+
+The Lexicon mobile app plays a crucial role in enabling push notifications for your users. When a user logs into their account using the app, a unique token is generated using the [`expo-notifications`](https://docs.expo.dev/versions/latest/sdk/notifications/) library. This token serves as a unique identifier for the user's device. The app then sends this token to the Prose GraphQL API, which makes a separate request to the Lexicon Discourse plugin. The plugin then inserts a record into your Discourse site's databaseโensuring any relevant activity on Discourse triggers a push notification to the user's mobile device.
+
+## Prose
+
+As mentioned elsewhere in the documentation, Prose is an intermediary component that facilitates communication between the Lexicon mobile app and your Discourse site. It serves the key role of providing a GraphQL interface over Discourse, which allows the mobile app to communicate with Discourse via GraphQL.
+
+The latest Prose API exposes a new GraphQL mutation, `pushNotifications`, to receive the unique Expo push token from the mobile app when the user logs in.
+
+Once Prose receives the token from the app, it forwards the token to the Discourse Plugin running on your site.
+
+## Discourse Plugin
+
+The Lexicon Discourse Plugin provides several features. In terms of enabling push notifications, it is responsible for integrating with Expo's [push notifications service](https://docs.expo.dev/push-notifications/overview/). When the Discourse Plugin receives a push token from Prose, it saves the token in your Discourse site's database, associating it with the corresponding user.
+
+Since the Lexicon Discourse plugin has been configured to respond to events within your Discourse site, it is able to dispatch push notifications based on your users' activity.
+
+When a relevant event triggers the need for a push notification, such as a new message or reply, the Discourse Plugin retrieves the associated user's token from your Discourse site's database. Using this token, the plugin sends a push notification request to Expo's push notification service, triggering the delivery of the push notification to the user's device.
+
+## Flowchart
+
+
diff --git a/documentation/docs/push-notifications/setup/enable-push-notifications.md b/documentation/docs/push-notifications/setup/enable-push-notifications.md
new file mode 100644
index 00000000..e08a9070
--- /dev/null
+++ b/documentation/docs/push-notifications/setup/enable-push-notifications.md
@@ -0,0 +1,32 @@
+---
+title: Enable the Lexicon Discourse plugin
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+
+
+
+
+
+Below, we'll walk you through the necessary steps to activate push notifications for your Discourse site.
+
+## Steps
+
+1. Ensure the [Lexicon Discourse plugin](../../discourse-plugin-installation.md) is installed and activated.
+
+1. As an admin user, access your Discourse admin dashboard.
+
+1. Navigate to the Plugins section.
+
+
+
+4. Click on the `Settings` button for the `discourse-lexicon-plugin` entry.
+
+5. Check the `enable Push Notifications` box in the Lexicon settings section and save your changes.
+
+
+
+Once the push notifications setting is enabled, your users will be able to login through the mobile app and start receiving push notifications.
+
+It is important to remember that push notifications are setup specifically when the user logs in through the mobile app. If users are not receiving push notifications, you should instruct them to log out and log back in before attempting any further troubleshooting.
diff --git a/documentation/docs/push-notifications/setup/verify-push-notifications.md b/documentation/docs/push-notifications/setup/verify-push-notifications.md
new file mode 100644
index 00000000..26679ffb
--- /dev/null
+++ b/documentation/docs/push-notifications/setup/verify-push-notifications.md
@@ -0,0 +1,33 @@
+---
+title: Verify Push Notifications
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+
+
+
+
+Below, we'll walk you through how you can validate the functionality of push notifications within your Lexicon-powered mobile app.
+
+:::info
+In order to properly test push notifications, **you will need two separate accounts** on your Discourse site (to generate notifications).
+
+Additionally, **you will need at least one mobile device** for testing purposes.
+:::
+
+## Step
+
+To test push notifications within your Lexicon-powered mobile app, follow these steps:
+
+1. Ensure that you have completed the [Getting Started](../../quick-start) steps for Lexicon.
+1. Start the Lexicon Expo app by navigating to `frontend/` and running `yarn start` from your terminal.
+1. Using the Expo link or QR Code, launch the app on a real mobile device.
+1. Login to the app using one of your accounts.
+1. Using that account, create a post within your Discourse site
+1. Using a separate account, reply to the post to trigger a notification for the first account.
+1. You should receive a push notification on your phone with the reply content from the other account.
+
+
+
+And that's it! The Lexicon Discourse plugin is properly sending push notifications through your Discourse site.
diff --git a/documentation/docs/quick-start.md b/documentation/docs/quick-start.md
index ed5fd52f..c72f310c 100644
--- a/documentation/docs/quick-start.md
+++ b/documentation/docs/quick-start.md
@@ -4,12 +4,17 @@ title: Quick Start
## Prerequisites
-- Node.js 12.19.0 or newer
-- The latest version of NPM or Yarn, compatible with Node 12.19.0 or newer
-- Expo-CLI 3.22.1 or newer
+- Node.js 16.14 or newer
+- The latest version of NPM or Yarn, compatible with Node 16.14 or newer
+- Expo CLI 6.0.6 or newer
+- EAS CLI 2.6.0 or newer to build and publish the App
- An active Discourse site
- If you donโt have one, please follow the instructions in [Development Setup](setup#discourse-host)
+:::note
+Follow the instructions in [Setup Guidance](tutorial/setup) to install the prerequisite depedencies, such as NPM, the Expo CLI, and the EAS CLI.
+:::
+
## Installation
Clone the repository and navigate into it:
@@ -33,10 +38,7 @@ Note that `npm run generate` involves two steps.
- This allows the frontend codebase to stay in sync with, and not duplicate the code for, the types from the `api` directory.
-This is a necessary process from our tooling, [Apollo](https://github.com/apollographql/apollo-tooling).
-
-To learn more about this process, check out the [apollo client:codegen](https://github.com/apollographql/apollo-tooling#apollo-clientcodegen-output) documentation.
-Click [here](https://github.com/apollographql/apollo-tooling#apollo-clientcodegen-output) to learn more about why we do this.
+The code shared from the API is then used by [Apollo](https://github.com/apollographql/apollo-tooling), the GraphQL library we use on the frontend, which enables the Mobile App to query the API correctly.
## Launch the Mobile App
diff --git a/documentation/docs/rationale.md b/documentation/docs/rationale.md
index ec672574..bfb62fa4 100644
--- a/documentation/docs/rationale.md
+++ b/documentation/docs/rationale.md
@@ -22,7 +22,7 @@ In our case, we were looking for a very specific type of experience.
### Who We Are
-The Lexicon Team is part of [KodeFox](https://www.kodefox.com/), a software studio comprising of passionate software engineers, designers, and product managers who regularly build world-class software for our customers.
+The Lexicon Team is part of [KodeFox](https://www.kodefox.com/), a software studio comprised of passionate software engineers, designers, and product managers who regularly build world-class software for our customers.
Interested in custom software development with a personal touch? Drop us a line at [hello@kodefox.com](mailto:hello@kodefox.com).
@@ -36,7 +36,7 @@ However, our clients wanted a seamless, native mobile experience, tailored to th
After digging into the Discourse API documentation, we felt that it was worthy investment to build a mobile-first Discourse experience which also faciliated customizability.
-We were already advocates of the elegant development process provided by React Native and Expo, so we forged ahead, implementing the entire mobile app with these technologies.
+We were already fluent with the elegant development process provided by React Native and Expo, so it was a natural fit for us to build the mobile app with these technologies.
This allowed us to achieve a high ratio of code reuse across iOS and Android, making feature implementations and bug fixes a much simpler process in most cases.
@@ -46,11 +46,11 @@ While we can appreciate the sentiment of figuring things out yourself, we wanted
For this reason, we also chose to build Prose, our GraphQL API layer on top of the Discourse RESTful API. Another motivating factor was our existing fluency with GraphQL.
-This allowed us to quickly iterate on new features with a more modern, well-thought-out API paradigm.
+This allowed us to quickly implement the mobile app with an intuitive API paradigm that we were already very familiar with.
#### How Lexicon can help you
-For starters, if you already run an existing Discourse site and want a native mobile experience for your users, you can very quickly point Lexicon at your site and browse it in real-time from your device.
+If you already run an existing Discourse site and want a native mobile experience for your users, you can very quickly point Lexicon at your site and browse it in real-time from your device.
Check out the [Quick Start](quick-start) page to see a rapid example of spinning up a mobile app for Discourse's own [Meta site](https://meta.discourse.org).
diff --git a/documentation/docs/setup.md b/documentation/docs/setup.md
index ddb84c1e..7ef46648 100644
--- a/documentation/docs/setup.md
+++ b/documentation/docs/setup.md
@@ -4,9 +4,7 @@ title: Development Setup
### Clone the Lexicon Repository
-If you haven't already, make sure you clone the Lexicon repository from Github.
-
-We walk you through this process in [Quick Start Installation](quick-start), so head over there to get started.
+If you haven't already, make sure you [clone the Lexicon repository](quick-start#installation) from Github.
### Setup a Discourse Instance, if necessary
@@ -24,104 +22,118 @@ For detailed instructions on setting up a local development instance of Discours
However, if you already have a deployed instance of Discourse, we'd recommend using that instead.
-### Configure Environment Variables
+### Configuration
-The Lexicon Stack requires multiple environment variables in order to properly interact with your Discourse server.
+The [Lexicon Stack](concepts#architecture-of-the-lexicon-stack) requires some configuration in order to properly interact with your Discourse server.
-In order to run the components of Lexicon, it's recommended that you create and populate `.env` files in two locations within the project:
+This involves configuring both the backend GraphQL API, which interacts with your Discourse instance; as well as the frontend Mobile App, which interacts with the GraphQL API.
-- `api/` (the GraphQL API server)
-- `frontend/` (the React Native app)
+The architecture of this setup is depicted in [Architecture of the Lexicon Stack](concepts#architecture-of-the-lexicon-stack).
-To simplify this process, both directories contain a template file, `.env.example`, which you can copy into `.env` files for each directory:
+#### Backend GraphQL API Configuration
-```
-$ cp frontend/.env.example frontend/.env
-$ cp api/.env.example api/.env
-```
+The [Prose GraphQL API](concepts#prose-discourse-through-graphql) is fairly simple in terms of configuration. In the simplest case, it only needs to know where your Discourse instance is accessible at.
-#### Frontend Environment Variables
-
-:::note
-If the Lexicon Mobile App is already running through Expo, and you adjust these values, you may need to **quit the Expo process and relaunch it** in order to run the Mobile App with the latest values from `frontend/.env`.
+It receives its configuration via a [`.env` file](https://www.codementor.io/@parthibakumarmurugesan/what-is-env-how-to-set-up-and-run-a-env-file-in-node-1pnyxw9yxj) in the root of the `api/` directory.
-If this does not help, try clearing the cache from the frontend directory via `expo r -c`.
-:::
+Here is the simplest configuration of the `api/.env` file:
-Change the value of `MOBILE_PROSE_HOST` in `frontend/.env` to the hostname of your Prose GraphQL APIโwhether local or already deployed somewhere.
+```
+PROSE_DISCOURSE_HOST=https://meta.discourse.org
+```
-In the first case, this would look like:
+It is also worth noting that you can optionally configure the **Hostname** and **Port Number** that the Prose API server listens on, both of which default to **localhost** and **port 80**, respectively.
-```bash
-MOBILE_PROSE_HOST=http://localhost
-MOBILE_PROSE_PORT=8080
```
+PROSE_DISCOURSE_HOST=https://meta.discourse.org
-Alternatively, for a deployed instance, it would look like:
+# Instruct Prose to broadcast publicly instead of on localhost
+PROSE_APP_HOSTNAME=0.0.0.0
-```bash
-MOBILE_PROSE_HOST=https://prose.mysite.com
+# Instruct Prose to listen on port 8929 instead of the default port 80
+PROSE_APP_PORT=8929
```
-#### Prose GraphQL API Environment Variables
+For a comprehensive list of all environment variables that can be used to configure Prose, check out [Prose Environment Variables](env-prose).
-The Prose GraphQL API is fairly simple in terms of configuration. In the simplest case, it only needs to know where your Discourse instance is accessible at.
+#### Frontend Mobile App Configuration
-```
-PROSE_DISCOURSE_HOST=https://meta.discourse.org
-```
+:::note
+In the original release of Lexicon, the **Prose URL** was specified in `frontend/.env`. However, as part of migrating to Expo's EAS feature, we centralized the configuration into `frontend/Config.ts` to save you the trouble of needing to maintain it in more than one place, as suggested in the [Expo documentation](https://docs.expo.dev/build-reference/variables/#can-i-share-environment-variables-defined-in-easjson-with-expo-start-and-eas-update)
+:::
-However, it is also worth noting that you can optionally configure the **Hostname** and **Port Number** that the Prose server listens on, which default to **localhost** and **port 80**, respectively.
+To configure the frontend mobile app, you'll first need to set your app name and slug in `frontend/app.json`. The [slug](https://docs.expo.dev/workflow/glossary-of-terms/#slug) is used as part of the URL for your app on Expo's web services, so it is recommended to use kebab-case (e.g., `my-lexicon-app`).
-```
-PROSE_DISCOURSE_HOST=https://meta.discourse.org
+Replace these placeholders with your desired values:
-# Instruct Prose to broadcast publicly instead of on localhost
-PROSE_APP_HOSTNAME=0.0.0.0
+```json
+ "name": "",
+ "slug": "",
+```
-# Instruct Prose to listen on port 8080 instead of the default port 80
-PROSE_APP_PORT=8080
+Next, change the value of `proseUrl` in `frontend/Config.ts` to the URL of your Prose GraphQL APIโwhether local or already deployed somewhere.
+
+```ts
+const config = {
+ localDevelopment: {
+ proseUrl: 'http://localhost:8929',
+ },
+ buildChannels: {
+ preview: {
+ proseUrl: 'https://preview.myserver.com:8080/subpath',
+ },
+ production: {
+ proseUrl: 'https://myserver.com/api/prose',
+ },
+ },
+};
```
-For a comprehensive list of all environment variables that can be used to configure Prose, check out [Prose Environment Variables](env-prose).
+`localDevelopment.proseUrl` will be used during development when you run the app using `npm run start` or `expo start`, whereas the specific value within `buildChannels` (e.g., `production.proseUrl`) will be used when actually building the app.
#### Development Scenarios
When developing locally, there are at least three scenarios that you may find yourself in.
-Depending on which one applies to you, the config values across `frontend/.env` and `api/.env` may need to be set differently.
+Depending on which one applies to you, the config values across `frontend/Config.ts` and `api/.env` may need to be set differently.
##### Scenario 1: Existing Prose Deployment
-If you've already deployed the Prose GraphQL API to a host that is publicly reachable, you will have already setup `api/.env` to the proper values.
+If you've already deployed the Prose GraphQL API to a host that is publicly reachable, you will have already setup `api/.env` with the proper values.
-In that case, `frontend/.env` only needs updated to point at the deployed GraphQL API.
+In that case, `frontend/Config.ts` only needs updated to point at the deployed GraphQL API.
For example:
+```ts
+const config = {
+ localDevelopment: {
+ proseUrl: 'https://my-deployed-graphql.api',
+ },
+ buildChannels: {
+ preview: {
+ proseUrl: 'https://my-deployed-graphql.api',
+ },
+ production: {
+ proseUrl: 'https://my-deployed-graphql.api',
+ },
+ },
+};
```
-MOBILE_PROSE_HOST=https://my-deployed-graphql.api
-```
+
+In the example above, we have configured the app to point at `https://my-deployed-graphql.api` in all scenarios, including during development when running with `npm run start`.
##### Scenario 2: Run Prose Locally & Access from a Simulator
This approach involves running both the Lexicon Mobile App and the Prose GraphQL API on your development machine. It is accomplished by instructing Expo to launch the Mobile App in the Android or iOS simulator.
-When developing in this way, you can simply set `MOBILE_PROSE_HOST` to `localhost` or `http://127.0.0.1` in both `api/.env` and `frontend/.env`.
-
-Instructing the GraphQL API to listen on `localhost` or `http://127.0.0.1` ensures that others on the same network as your development machine cannot access it. Because the simulator is running on the same device, it should be able to access the GraphQL API.
-
-##### _Brief Note about the Android Simulator_
+When developing this way, you can simply set `localDevelopment.proseUrl` to `http://localhost` in `frontend/Config.ts`. And then in `api/.env`, you can set `PROSE_APP_HOSTNAME` to `0.0.0.0`.
-The Android Simulator is actually unable to access your development machine's network on `http://locahost`.
+Note that if you want to run Prose locally on a specific port, you would need to make sure that the configuration in both `api/.env` and `frontend/Config.ts` reflect that correctly.
-However, we have accounted for this in our business logic when preparing environment variables.
-
-If you run into issues here, take a look at the function, `getProseEndpoint`, in `frontend/src/constants/app.ts`
-
-Feel free to adjust it to work more properly with your setup.
-
-If you're still running into issues with this, please reach out to us on Github. We'd love to make this more robust if we missed a use-case.
+:::caution
+If you configure `PROSE_APP_HOSTNAME` in `api/.env` to only listen on `localhost` or `127.0.0.1` (rather than `0.0.0.0`), it prevents others on the same network as your development machine from accessing it. This includes both your mobile device and the Android simulator, which can lead to connectivity issues when developing locally.
+:::
##### Scenario 3: Run Prose Locally & Access from your Mobile Device
@@ -129,25 +141,35 @@ It can be very useful to develop and debug against the app using your actual mob
In order to do this, you'll need to have your development machine reachable from your mobile device.
-A simple way to make it reachable is to ensure that your mobile device and development machine are on the same network, and then, in `api/.env`, set `MOBILE_PROSE_HOST` to `0.0.0.0`.
+A simple way to make it reachable is to ensure that your mobile device and development machine are on the same network, and then, in `api/.env`, set `PROSE_APP_HOSTNAME` to `0.0.0.0`.
+
+In a regular Expo project, you would be required to update the `localDevelopment.proseUrl` value in `frontend/Config.ts` to contain the hardcoded IP address of your development machine on your network.
-Next, you'll need to update the `MOBILE_PROSE_HOST` value in `frontend/.env` so that the Lexicon app running on your mobile device knows how to reach the GraphQL API running on your development machine.
+However, by setting the value to `http://localhost`, we handle this **automatically** by default, so you don't have to worry about it. Read more about it [here](env-mobile#infer_development_host).
+
+###### Hardcoding your local IP Address
+
+:::info
+This approach is not ideal. If your local IP address ever changes, you'll need to locate it again, and update `Config.ts` to reflect that. For this reason, it's preferable to just use `http://localhost`.
+:::
-In order to do this, you'll need to find out what the **local IP address** of your development machine is on your current network.
+To manually instruct the Mobile App how to locate your development machine, you'll need to find out what the **local IP address** of your development machine is on your current network.
Note that your local IP address is different from your public IP Address.
If you are not sure how to get your local IP address, you can go to [What Is My Browser: Detect Local IP Address](https://www.whatismybrowser.com/detect/what-is-my-local-ip-address) and follow the instructions.
+The website itself may not be able to automatically detect your local IP address, but it will give you instructions on how to locate it within your specific operating system.
+
You will be given an IP address like `10.0.12.121` or `192.168.17.69`.
-You can then update the value of `MOBILE_PROSE_HOST` in `frontend/.env` to your local IP address.
+You can then update the value in `frontend/Config.ts` to your local IP address.
This will allow the app running on your mobile device to properly locate the GraphQL API running on your development machine.
## Configure your Discourse Host
-As mentioned above, you'll need to have setup a Discourse host for the Lexicon Stack to interact with.
+As mentioned above, you'll need to have setup a Discourse host for the GraphQL API to interact with.
We'd like to briefly cover the different approaches to setting up a Discourse Host for development before continuing.
@@ -176,13 +198,17 @@ The only drawback of this approach is that you can only register as a normal use
With this approach, you'd simply configure Prose in `api/.env` to point `PROSE_DISCOURSE_HOST` at one of these instances.
+```bash
+PROSE_DISCOURSE_HOST=https://try.discourse.org
+```
+
## Working with the Codebase
Now that you've prepared everything for development, you can start digging in on the Lexicon codebase.
### Run the Lexicon Mobile App & Prose GraphQL Server
-You can run the Mobile App and test it out with a local Prose server by running this command from the project root:
+You can run the Mobile App and test it out with a local Prose server by running this command **from the project root**:
```
$ npm run dev
@@ -231,25 +257,40 @@ You can run tests across both the frontend and backend codebases sequentially by
$ npm run test
```
-On top of ensuring that all tests have passed, the command will also notify you if there are any type errors or issues from Prettier or ESLint.
+On top of ensuring that all tests have passed, the command will also notify you if there are any Typescript errors or issues from Prettier or ESLint.
-Also note that the process of testing the frontend involves an additional action.
+Also note that the process of running `npm run test` triggers an additional action in the frontend to take place before running the tests.
-This step creates a new folder, `frontend/generated`, which contains all the GraphQL Query and Mutation types for use in the codebase.
+A new folder, `frontend/generated`, is created and populated with all the GraphQL Query and Mutation types for use in the codebase.
-If we did not run this before the tests, the tests would fail due to type errors.
+If we did not run this before the tests, they would fail due to type errors.
### Build & Publish the Lexicon Mobile App
:::note
An Expo account is required in order to use Expo's services. You can create one here: https://expo.io/signup.
-Once you have created your Expo account, please ensure that you are signed in with your current shell session, via `expo login`.
+Once you have created your Expo account, please ensure that you are signed in with your current shell session, via `expo login` or `eas login`.
:::
-You can build the Mobile App via Expo by running command below:
+You are required to configure EAS build first by running:
+```bash
+eas build:configure
```
-$ expo publish
+
+You will then get a prompt from the EAS CLI related to the EAS project IDs: `android.package` and `ios.bundleIdentifier`. EAS will provide you with an existing project ID if you have one or ask you to create a new one. As for `android.package` and `ios.bundleIdentifier`, you can specify those values with `com.companyname.appname`, or any other patterns you might prefer.
+
+Once you're done, verify the `proseUrl` value you will use for the actual build of the app in `Config.ts`.
+
+:::info
+When publishing your app, it is necessary to deploy Prose somewhere publicly accessible, perhaps on a cloud hosting provider like AWS or DigitalOcean. If Prose is only running on your local machine, users that download your app won't be able to use it.
+Check [the documentation](deployment) to deploy Prose if you haven't already.
+:::
+
+Now you can build the Mobile App via Expo (EAS) with the preview build profile by running command below:
+
+```bash
+eas build โplatform all โprofile preview
```
When you do this, the packager will minify all your code and generate two versions of your codeโone for iOS, and one for Androidโand then upload them both to the Expo CDN.
@@ -258,19 +299,61 @@ Additionally, if you haven't yet optimized the app's assets, Expo will ask you i
This has the same effect as manually running `npx expo-optimize` beforehand. It simply compresses all of the image assets in your project to reduce the size of your build.
-When the process has completed, you'll be presented with a link, resembling https://exp.host/@ccheever/an-example.
+When the process is complete, you'll be presented with a shareable QR Code and a URL resembling https://exp.host/@ccheever/an-example, which directs you to the build details in Expo's web console.
At this point, anyone can then use that link to load your project.
+For Android, you can install the app on an emulator or on your physical device. However, for iOS, you can only install it on the iOS simulator. To run the app on a real iOS device, follow the steps in [this part](tutorial/building#1-preview) of the tutorial.
+
+When building your app, it is recommended to build it as a preview build first, and make sure everything runs well before building it for release with the production profile.
+
+To build the app with the production build profile, run this command:
+
+```bash
+eas build โplatform all โprofile production
+```
+
+You will also be presented with links directing you to the build details in Expo.
+
+However, unlike the preview build, the release build cannot be installed directly on your physical device or in an emulator / simulator. You'll need to publish the app and then install it from either the Play Store or App Store.
+
+You can read a more detailed explanation of this process in [this section](tutorial/building) of the tutorial.
+
#### Updates
-If you later want to deploy an update to your version of the Lexicon Mobile App, you can follow the steps above again in order to publish.
+If you later want to deploy an update to your version of the Lexicon Mobile App, you can use the EAS update command.
+
+First, make sure to configure EAS update by running the following command:
+
+```bash
+eas update:configure
+```
+
+This command will automatically add the `expo.runtimeVersion` field to your `app.json` file.
+You'll see a warning in your terminal telling you to add `expo.updates.url` to `app.json`.
+
+Then run this command to update your project:
+
+```bash
+eas update -โbranch
+```
+
+:::note
+The channel name is the same as the build profile, so for the preview builds, you can run:
+
+```bash
+eas update -โbranch preview
+```
+
+:::
+
+Read more about updating your app [here](tutorial/updating).
Once published, the new version will be available to your users the next time they open it.
-For more details on this processโincluding publishing to the App Store and Google Play Storeโfollow the instructions in [Publishing your App](publish-app).
+For more details on this processโincluding publishing to the App Store and Google Play Storeโfollow the instructions in [Publishing your App](tutorial/publishing).
-#### Configure the GraphQL API with Your Discourse Server
+#### Configure the GraphQL API with your Discourse Server
In order for a published version of the app to be able to contact your Discourse server, you'll need to ensure that:
diff --git a/documentation/docs/technologies.md b/documentation/docs/technologies.md
index c4180c4f..838fcffb 100644
--- a/documentation/docs/technologies.md
+++ b/documentation/docs/technologies.md
@@ -18,6 +18,8 @@ White Label the Lexicon Mobile App to give your users the familiar look and feel
Getting started is as easy as spinning up a new server for the Prose GraphQL API, and pointing it at your Discourse instance. No changes are required on your Discourse instance itself.
+However, to enable features like [Push Notifications](./push-notifications) and [Email Deep Linking](./email-deep-linking/), you can install our [Discourse Plugin](./discourse-plugin.md).
+
However, to provide an [optimal experience](optimal) with features like Tagging and Topic Excerpts, you will need to make some light adjustments.
This is covered in detail in [Deploying Prose](deployment).
diff --git a/documentation/docs/troubleshooting-build.md b/documentation/docs/troubleshooting-build.md
new file mode 100644
index 00000000..68d75dad
--- /dev/null
+++ b/documentation/docs/troubleshooting-build.md
@@ -0,0 +1,128 @@
+---
+title: Troubleshooting when trying out the app
+---
+
+
+
+
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+## Troubleshooting Connection and Configuration Issues with URL
+
+
+
+
+
+If you are encountering issues related to the URL, resulting in an error message saying "please connect to network" as shown in the screenshot, it is likely due to incorrect settings. Specifically, if you are attempting to test builds locally on your mobile device and the channel field is not properly configured, the app may continuously fallback to the localDevelopment channel, even if you have set it to something else like "preview."
+
+Here some steps and notes to help resolve this:
+
+- Open the `frontend/Config.ts` file in your project.
+- Locate the `config` object within the file.
+- In the `localDevelopment` section of the `config` object, you can add the Prose URL specific to the channel you are trying to test. This section is used for local development and as a fallback configuration for unknown build channels in EAS Build. Here's an example:
+
+ ```ts
+ const config: Config = {
+ localDevelopment: {
+ proseUrl: 'http://localhost:8929',
+ },
+ buildChannels: {
+ preview: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ production: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ },
+ };
+ ```
+
+- The example above shows that the config consists of two main sections: localDevelopment, which specifies the URL during localDevelopment, and buildChannels, which includes configurations for different channels such as preview and production. For local development, it will hit the Prose API with the URL `http://localhost:8929`. If the buildChannel is unknown or not found, it will always default to localDevelopment.
+- Update the `proseUrl` value within the desired build channel, such as `preview` or `production`, with the valid and reachable URL of your Prose server.
+- Once you have made the necessary changes, save the `frontend/Config.ts` file.
+
+Now, when you run eas build for a specific build channel, such as `eas build --profile=production`, it will utilize the Prose URL specified in the production configuration.
+
+:::note
+It is important to include the URL in the `frontend/app.json` file, which expo-updates will use to fetch update manifests. Failing to set the URL in the `frontend/app.json` file will result in the expo-update constant always returning undefined for the channel, causing the app to consistently utilize the localDevelopment URL after building. You can specify this URL in the expo and updates sections of the app.json file. For more detailed information on how to configure this, please refer to the [expo documentation](https://docs.expo.dev/versions/latest/config/app/#url) for more detail on this.
+
+```json
+"expo": {
+ "updates": {
+ ...,
+ "url": "https://u.expo.dev/"
+ }
+}
+```
+
+This configuration is essential for seamless integration with Config.ts in your project.
+:::
+
+In certain cases, you may encounter an issue related to Prose API URLs when the channel name specified in the `frontend/eas.json` file does not match the corresponding key name defined in the `config` variable in `frontend/Config.ts`. This discrepancy can lead to problems because the channel name from `eas.json` is used to determine the URL that will be utilized. If the names do not match, the default `localDevelopment` URL will be used instead.
+
+To ensure smooth functioning, it is important to use the same channel name in both the `frontend/eas.json` file and the `frontend/Config.ts` file. This will ensure proper mapping of the channel name to the corresponding URL.
+
+Here is an example to illustrate this:
+
+```json
+// frontend/eas.json
+
+"build": {
+ "staging": {
+ "android": {
+ "buildType": "apk"
+ },
+ "channel": "staging"
+ }
+}
+```
+
+```ts
+// frontend/Config.ts;
+
+const config: Config = {
+ localDevelopment: {
+ proseUrl: 'http://localhost:8929',
+ inferDevelopmentHost: true,
+ },
+
+ buildChannels: {
+ preview: {
+ proseUrl: '',
+ },
+ production: {
+ proseUrl: '',
+ },
+ staging: {
+ proseUrl: '',
+ },
+ },
+};
+```
+
+## The app closes abruptly after the splash screen
+
+If you encounter a situation where your app closes abruptly after the splash screen, it is likely that there are missing configurations in your `app.json` file. One common cause is the absence of a scheme definition in `app.json`, which is essential during the app build process.
+
+To resolve this issue, follow these steps:
+
+1. Open your project's `frontend/app.json` file.
+2. Look for the `"expo"` section.
+3. If a scheme is not present add this part in `"expo"` section
+
+```json
+"expo":{
+ "name": "",
+ "slug": "",
+ "scheme": "",
+ "version": "1.0.0"
+}
+```
+
+Replace `""` with the desired scheme name for your app.
+
+4. Save the changes to the `app.json` file.
+5. Rebuild your app and test it again.
+
+By ensuring that the scheme is correctly defined in `app.json`, you should be able to resolve the issue of the app closing after the splash screen.
diff --git a/documentation/docs/tutorial/building.md b/documentation/docs/tutorial/building.md
new file mode 100644
index 00000000..3e261343
--- /dev/null
+++ b/documentation/docs/tutorial/building.md
@@ -0,0 +1,152 @@
+---
+title: Build your App
+---
+
+## EAS Build
+
+EAS Build is the upgraded version of `expo build`. This service helps to build app binaries for your Expo and React Native projects. Read more about it in the Expo documentation [here](https://docs.expo.dev/build/introduction/).
+
+### Configuration
+
+Let's get started by configuring EAS build. Check [here](https://docs.expo.dev/build-reference/build-configuration/) to see the complete guide from Expo.
+
+#### Build Setup
+
+Run this command in `/frontend` directory:
+
+```bash
+eas build:configure
+```
+
+When running that command, the EAS CLI will typically do the following:
+
+1. It will prompt you for the EAS project ID, either to use an existing ID if you have one, or create a new one. Then it will automatically add the `expo.extra.eas.projectId` field in `app.json`.
+2. It will create a new `eas.json` file if one doesnโt already exist. However, we have that set up for you, so you don't need to worry about creating one. ๐
+3. It will prompt you to specify `android.package` and `ios.bundleIdentifier` if those values are not already provided in `app.json`. Note that those two values don't have to be the identical.
+
+You can see that the values in `app.json` are updated after running the command.
+
+#### Configuration Values
+
+:::info
+When publishing your app, it is necessary to deploy Prose somewhere publicly accessible, perhaps on a cloud hosting provider like AWS or DigitalOcean. If Prose is only running on your local machine, users that download your app won't be able to use it.
+Check [the documentation](../deployment.md) to deploy Prose if you haven't already.
+
+In the original release of Lexicon, the **Prose URL** was specified in `frontend/.env`. However, as part of migrating to Expo's EAS feature, we centralized the configuration into `frontend/Config.ts` to save you the trouble of needing to maintain it in more than one place, as suggested in the [Expo documentation](https://docs.expo.dev/build-reference/variables/#can-i-share-environment-variables-defined-in-easjson-with-expo-start-and-eas-update)
+:::
+
+Next, open `Config.ts` and overwrite the placeholder values with the Prose URL you want to use for the build version. You can either set the same values or a different one for each channel. You don't need to adjust the values in `localDevelopment` since that is only used in development, and not when building the app.
+
+```ts
+const config = {
+ // ...
+ buildChannels: {
+ preview: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ production: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ },
+};
+```
+
+### Run a Build
+
+#### Build for Both Platforms
+
+To build on both platforms, you can use either of the commands below:
+
+```bash
+eas build --platform all
+```
+
+```bash
+eas build -p all
+```
+
+#### iOS only
+
+```bash
+eas build --platform ios
+```
+
+#### Android only
+
+```bash
+eas build --platform android
+```
+
+#### Run a build with a specific profile
+
+```bash
+eas build --platform all โ-profile
+```
+
+```bash
+eas build -p all โe
+```
+
+:::note
+Without --profile, the EAS CLI will default to the `production` profile.
+:::
+
+### Build Profiles
+
+Build profiles serve as a way of grouping configuration values for different scenarios when building the mobile app.
+
+You can find more details [here](https://docs.expo.dev/build/eas-json/).
+
+The `eas.json` file can contain multiple build profiles. However, it typically has 3 profiles: **preview**, **development**, and **production**.
+
+#### 1. Preview
+
+Purpose: to internally test the app in production-like circumstances.
+
+It is recommended to try building with the preview profile **_first_** before building your app with the production profile. That way, you can ensure the app runs as expected before itโs ready to be published.
+
+The build type for Android will be an **APK** file, whereas the iOS build will output a format that can be installed on the simulator.
+
+This is because the `ios.simulator` option was specified in `eas.json`:
+
+```json
+ "ios": {
+ "simulator": true
+ },
+```
+
+If you want to run the preview build on a real device, you'll need have an Apple account with Apple Developer Enterprise Program membership, then add the `ios.enterpriseProvisioning` value in `eas.json`:
+
+```json
+ "ios": {
+ "enterpriseProvisioning": "universal"
+ }
+```
+
+For the `preview` build profile, we have already set the distribution mode to [internal](https://docs.expo.dev/build/internal-distribution/). This ensures that EAS build provides shareable URLs for builds, with instructions on how to get them running.
+
+This approach then allows us to test the app without submitting to the App Store or Play Store.
+
+#### 2. Development
+
+Purpose: to make debugging easier. Expo will automatically include developer tools in the build. As you may have figured, this build should never be published to either of the app stores.
+
+Development builds depend on [expo-dev-client](https://docs.expo.dev/development/introduction/), so Expo will prompt us to install the library if needed.
+
+Similar to preview builds, you can add the iOS options mentioned above to run them on a simulator or real device.
+
+#### 3. Production
+
+Purpose: for submission to the App Store and Play Storeโas a public release, or as part of testing in each respective ecosystem.
+
+In order to use builds like this, they must be installed through the respective app stores.
+
+After running builds with this profile, you'll see that the iOS and Android versions have automatically been incremented. As you might expect, this is because `autoIncrement` has been set to `true`.
+
+It is worth noting, however, that this behavior only applies to TestFlight and Internal Testing, so you'll need to be sure to also manually increment the `expo.version` in `app.json` for public release. Expo provides further [documentation](https://docs.expo.dev/build-reference/app-versions/) on this topic.
+
+## The App is Built
+
+Great work! You can now share the installation link with your peers so they can try out the app.
+
+In the next section, you'll learn how to [publish](publishing) your app to the App Store and Play Store! ๐
diff --git a/documentation/docs/tutorial/install-prose.md b/documentation/docs/tutorial/install-prose.md
index 47b8d69e..d6ecec67 100644
--- a/documentation/docs/tutorial/install-prose.md
+++ b/documentation/docs/tutorial/install-prose.md
@@ -18,7 +18,7 @@ Otherwise, it would be unnecessary extra work to get a remote Prose server commu
However, if you've setup your Discourse instance in the cloud, it is up to you if you want to run your Prose server locally or in the cloud as well.
-If you'd like to install it in the cloud, you'll want to setup an additional server - similar to how you would set one up for Discourse. If you're not yet comfortable with this, feel free to jump back to the page, [Setting up a Cloud Server (Optional)](setup-cloud-server).
+If you'd like to install it in the cloud, you'll want to setup an additional server - similar to how you would set one up for Discourse. If you're not yet comfortable with this, feel free to jump back to the page, [Setup a Cloud Server (Optional)](setup-cloud-server).
Bearing all of that in mind, once you have identified where you'd like to host Prose, you should also consider how you'd like to install it onto that machine.
@@ -241,7 +241,7 @@ $ pm2 delete # To delete a process
Now that you've successfully launched Prose, you can actually interact with it in your web browser.
-Because of the libraries that we leveraged in building Prose, it automatically comes with a [GraphQL Playground](https://github.com/graphql/graphql-playground).
+Because of the libraries that we leveraged in building Prose, it automatically comes with [GraphiQL](https://www.graphql-yoga.com/docs/features/graphiql).
This is an in-browser GraphQL IDE that makes it easy to explore the documentation and the schema of the GraphQL API.
@@ -251,7 +251,7 @@ For example, if you launched Prose from your local machine on port 5000, you'd n
Similarly, if you set it up in the cloud, and all you have is an IP address with Prose listening on port 80, you would navigate to something like [http://174.31.92.1](http://174.31.92.1).
-Once the GraphQL Playground loads, you can test out some example queries and mutations, including logging into Discourse through Prose.
+Once the [GraphiQL](https://www.graphql-yoga.com/docs/features/graphiql) interface loads, you can test out some example queries and mutations, including logging into Discourse through Prose.
### Login
diff --git a/documentation/docs/tutorial/intro.md b/documentation/docs/tutorial/intro.md
index 54e0d630..0098344d 100644
--- a/documentation/docs/tutorial/intro.md
+++ b/documentation/docs/tutorial/intro.md
@@ -3,6 +3,10 @@ title: Overview
slug: /tutorial
---
+:::info
+This tutorial **does not** cover the process of actually launching the app, as well as certain details about deploying to production. For support with those tasks, please refer to the documentation.
+:::
+
## Welcome to the Lexicon Tutorial
We're really excited to help you dig in with the Lexicon Stack and learn how to deploy it in a way that benefits you and your users.
@@ -40,6 +44,4 @@ You will also have an understanding of:
- How to configure and run the Lexicon Mobile app on your device or in a simulator
- The next steps needed to make full use of Lexicon
-Please note that this tutorial will not cover the process of actually launching the app, as well as certain details about deploying to production. For support with those tasks, please refer to the documentation.
-
Let's get started!
diff --git a/documentation/docs/tutorial/publishing.md b/documentation/docs/tutorial/publishing.md
new file mode 100644
index 00000000..66005bdd
--- /dev/null
+++ b/documentation/docs/tutorial/publishing.md
@@ -0,0 +1,97 @@
+---
+title: Publish your App
+---
+
+## EAS Submit
+
+EAS Submit is a service for uploading and submitting your application binaries to App Store and/or Play Store.
+Check [here](https://docs.expo.dev/submit/introduction/) to learn more about EAS Submit.
+
+### Prerequisites:
+
+- Registered app in App Store Connect, see the guide [here](../app-store#register-a-new-bundle-id).
+- Registered app in Play Store, see the guide [here](../play-store).
+
+### Configuration
+
+Before submitting, you are required to specify the credentials to publish your app.
+
+#### iOS
+
+For iOS, fill in your account information for `appleId`, `ascAppId`, and `appleTeamId`:
+
+```json
+ "base": {
+ "ios": {
+ "appleId": "",
+ "ascAppId": "",
+ "appleTeamId": ""
+ },
+ ...
+ },
+```
+
+- **appleId**: your apple ID (e.g., `john@gmail.com`).
+- **ascAppId**: your App Store Connect app ID. Find your ascAppID by following [this guide](https://github.com/expo/fyi/blob/main/asc-app-id.md) (e.g., `1234567890`).
+- **appleTeamId**: You can check your apple team ID [here](https://developer.apple.com/account/) (e.g., `12LE34XI45`).
+
+#### Android
+
+For Android, you will need to add a `.json` key file to authenticate with the Google Play Store. Please follow [this guide](https://github.com/expo/fyi/blob/main/creating-google-service-account.md) to generate one. Then, copy the JSON file to your `lexicon/frontend` directory, and rename the file as `playstore_secret.json`.
+
+The JSON file looks like this:
+
+```json
+{
+ "type": "service_account",
+ "project_id": "",
+ "private_key_id": "",
+ "private_key": "-----BEGIN PRIVATE KEY----------END PRIVATE KEY-----\n",
+ "client_email": "",
+ "client_id": "",
+ "auth_uri": "",
+ "token_uri": "",
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
+ "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/lexicon%40api.iam.gserviceaccount.com"
+}
+```
+
+Now that the configuration is done, you can start submitting your app.
+
+### Submitting
+
+Use this command to submit the build:
+
+```bash
+eas submit --platform ios --profile
+```
+
+Then you will see the EAS CLI prompt asking which app you would like to submit.
+
+There are 4 possible options:
+
+- Selecting a build from EAS
+- Providing the URL of an app archive
+- Providing the local path to an app binary file
+- Providing the build ID of an existing build on EAS
+
+If you have built your app using EAS Build or have been following the tutorial from [Build your App](building), then please choose the first option, and select the version you want.
+
+### Submit Profiles
+
+By default, `eas.json` has been configured with two submit profiles, which are **staging** and **production**.
+
+The configuration is mostly the same, the only difference lies in the Android track options.
+
+- Staging infers the track as `internal`. This means submitting with the staging profile will submit the build for internal testing in the Play Store.
+- Production infers the track as `production`, which will submit the build for Public Release in the Play Store.
+
+With iOS, on the other hand, both profiles will be submitted to TestFlight before you can release them publicly.
+
+You can reference the Expo documentation to learn more about [Android-specific](https://docs.expo.dev/submit/eas-json/#android-specific-options) and [iOS-specific](https://docs.expo.dev/submit/eas-json/#ios-specific-options) options.
+
+## Congratulations!
+
+Your app is now available for users to download from both the Play Store and the App Store! ๐ฅณ
+
+To learn more about how to update your published app in the case of a bug, as well as OTA updates, check out the [next and final section](updating) of the tutorial.
diff --git a/documentation/docs/tutorial/setup-cloud-server.md b/documentation/docs/tutorial/setup-cloud-server.md
index 9b2aff33..b69659a4 100644
--- a/documentation/docs/tutorial/setup-cloud-server.md
+++ b/documentation/docs/tutorial/setup-cloud-server.md
@@ -1,5 +1,5 @@
---
-title: Setting up a Cloud Server (Optional)
+title: Setup a Cloud Server (Optional)
---
import useBaseUrl from '@docusaurus/useBaseUrl';
diff --git a/documentation/docs/tutorial/setup-mobile.md b/documentation/docs/tutorial/setup-mobile.md
index ff1b704a..62ab943a 100644
--- a/documentation/docs/tutorial/setup-mobile.md
+++ b/documentation/docs/tutorial/setup-mobile.md
@@ -4,91 +4,108 @@ title: Configure & Launch the Mobile App
import useBaseUrl from '@docusaurus/useBaseUrl';
-After following the **[Install the Prose GraphQL API](install-prose)** section, your GraphQL API should now be connected to your Discourse site.
+After following the **[Setup the Prose GraphQL API](install-prose)** section, your GraphQL API should now be connected to your Discourse site.
Next, we'll guide you through the process of connecting the Lexicon Mobile App to your Discourse site via Prose.
### Mobile App Configuration
+:::note
+In the original release of Lexicon, the **Prose URL** was specified in `frontend/.env`. However, as part of migrating to Expo's EAS feature, we centralized the configuration into `frontend/Config.ts` to save you the trouble of needing to maintain it in more than one place, as suggested in the [Expo documentation](https://docs.expo.dev/build-reference/variables/#can-i-share-environment-variables-defined-in-easjson-with-expo-start-and-eas-update)
+:::
+
Before launching your local version of the Lexicon Mobile App, you'll need to configure it with at least one piece of information.
-The Lexicon Mobile app relies exclusively on a running instance of the Prose GraphQL API in order to retrieve data.
+The Lexicon Mobile app relies exclusively on a running instance of the Prose GraphQL API in order to retrieve data from your Discourse instance.
-Therefore, you'll need to instruct it on where your Prose server is running.
+Therefore, you'll need to instruct it on how to locate your running Prose server.
-In development, it is common to have it running locally. However, if you have already deployed Prose somewhere, you are free to use that.
+In development, it is common to have it running locally. However, if you have already deployed Prose
+somewhere, feel free to use that.
-The environment variable which instructs the Mobile App on how to find your Prose server is `MOBILE_PROSE_HOST`.
+#### Configuring `proseUrl` via `config`
-Additionally, `MOBILE_PROSE_PORT` is present to define a non-standard port number, such as `8080`.
+:::caution
-As is typical with environment variables, there is more than one way to provide this to the process you want to run.
+##### `proseUrl` requirements
-#### Pass the value when launching Expo
+It is worth noting that `proseUrl` **must** start with either `http://` or `https://`.
-:::info
-This only works if you invoke `expo` directly from within `frontend/`. If you use a command like `npm run start`, the environment variable will not be forwarded to Expo.
+If it does not, the Mobile App will throw an error when launching.
:::
-You can pass an environment variable to the `expo start` command.
-
-```bash
-MOBILE_PROSE_HOST=https://prose.myserver.com expo start
+`Config.ts` contains the `config` object, which allows you to specify the Prose URL for each scenario encountered when developing and building the Mobile App.
+
+The specific configuration value which enables this is `proseUrl`, and it is contained within each scenario expressed by the `config` object.
+
+```ts
+const config = {
+ localDevelopment: {
+ proseUrl: 'http://localhost:8929',
+ },
+ buildChannels: {
+ preview: {
+ proseUrl: 'https://preview.myserver.com:8080/subpath',
+ },
+ production: {
+ proseUrl: 'https://myserver.com/api/prose',
+ },
+ },
+};
```
-#### Define a `.env` File (recommended)
+As mentioned earlierโabove, the `config` object allows us to express configuration values for multiple scenarios, which are:
-The preferred way to specify `MOBILE_PROSE_HOST` is to create a `.env` file in the `frontend/` directory.
+- `localDevelopment`: when developing against the app locally. This configuration is also used as a fallback for an unknown build channel.
+- `buildChannels`: used to define configuration by build channel when building the app with the EAS CLI.
-```bash
-MOBILE_PROSE_HOST=http://your.prose.site
+`buildChannels` makes use of Expo's build channels (typically `preview` and `production`) as its keys.
-# The Port Number of your Prose server, if needed
-MOBILE_PROSE_PORT=8999
-```
-
-To do this, from the root of the project, make a copy of `frontend/.env.example`, and name it `frontend/.env`:
+Each key within `buildChannels` maps to a specific Prose URL, which will be used for the build version based on which channel you build for.
-```bash
-cp frontend/.env.example frontend/.env
-```
+From the example above, when we create a `preview` build, the app will be built and configured to contact a Prose server located at `https://preview.myserver.com:8080/subpath`.
-Bear in mind that if you are not running on port 80 or 443, you also need to specify the **port number** via `MOBILE_PROSE_PORT`.
+The example above expresses a setup in which each build has its own deployed Prose server. However, it is also common to use one server for all scenarios, including development.
-For example, if you've started a Prose server **locally** on port `8999`, your `.env` file would contain.
-
-```bash
-MOBILE_PROSE_HOST=http://localhost
-MOBILE_PROSE_PORT=8999
+```ts
+const config = {
+ localDevelopment: {
+ proseUrl: 'https://myserver.com/api/prose',
+ },
+ buildChannels: {
+ preview: {
+ proseUrl: 'https://myserver.com/api/prose',
+ },
+ production: {
+ proseUrl: 'https://myserver.com/api/prose',
+ },
+ },
+};
```
-The Lexicon Mobile app will throw an error upon starting if any of the following is true:
+##### Port Number
-- `MOBILE_PROSE_HOST` is not set
-- `MOBILE_PROSE_HOST` does not start with `http://` or `https://`
+Bear in mind that if your Prose server is not running on port 80 or 443, you also need to specify the **port number** via `proseUrl`.
+
+For example, if you've started a Prose server **locally** on port `8929` and try to run it using `expo start`, your `Config.ts` file would contain `http://myserver.com:8929/api/prose` under `localDevelopment.proseUrl`.
### Launch the Mobile App
Once you have configured everything, you'll want to launch the Mobile App to test that it is speaking to the right Prose server.
-If you have declared a `frontend/.env` file, you can simply run
+To do this, you can simply run the following from the project root:
```bash
npm run --prefix frontend start
```
-If you want to pass in values directly, you should run:
-
-```bash
-cd frontend
-MOBILE_PROSE_HOST=https://prose.yoursite.com expo start
-```
-
The Expo development server should launch, and you can follow the instructions to run the app in a simulator or on your actual device.
-If the app throws a relevant error upon loading, you should double-check the environment variables you specified, according to the message you've received.
+#### Troubleshooting
+
+If the app throws an error upon loading, you should double-check the configuration values you specified, according to the message you've received.
-If the app loads, but you're unable to actually connect, you should check the following:
+If the app loads, but you're unable to actually connect, you should verify the following:
- Your Prose Server is up and running at the location you provided to the Lexicon Mobile App
- Your Prose Server is configured to point at an accessible Discourse instance
@@ -100,4 +117,4 @@ At this point, you've already accomplished a lot.
The Discourse server you started off with is now accessible in a new way from a sleek native mobile app, and you're free to customize it to your heart's content.
-As the last part of the tutorial, we'll briefly get into that very topic: customizing the Mobile App to white label it for your brand.
+In the next part of the tutorial, we'll briefly get into that very topic: customizing the Mobile App to [white label](white-label) it for your brand.
diff --git a/documentation/docs/tutorial/setup.md b/documentation/docs/tutorial/setup.md
index aef9b090..20505940 100644
--- a/documentation/docs/tutorial/setup.md
+++ b/documentation/docs/tutorial/setup.md
@@ -14,7 +14,9 @@ If you are unsure of how to install NodeJS, you can follow the instructions on t
It is recommended that you perform this tutorial using the latest version of Node that is compatible with the the project's version of Expo.
-If your environment doesn't support this, we would recommend making use of [`nvm`](https://github.com/nvm-sh/nvm) to quickly switch between Node versions.
+You can always confirm this by viewing the dependencies in [frontend/package.json](https://github.com/lexiconhq/lexicon/blob/master/frontend/package.json).
+
+If your setup doesn't allow you to easily change your current Node version, we would recommend making use of [`nvm`](https://github.com/nvm-sh/nvm) to quickly switch between Node versions.
### Install yarn, if you prefer
@@ -24,7 +26,7 @@ For the purposes of this tutorial, we will demonstrate all commands using `npm`.
### Clone the Lexicon Repository
-In a preferred location on your development machine, clone the Lexicon repository and `cd` into it.
+In a desirable location on your development machine, clone the Lexicon repository and `cd` into it.
```sh
git clone git@github.com:lexiconhq/lexicon.git
@@ -39,7 +41,7 @@ Next, install Lexicon's dependencies:
npm install
```
-This will install dependencies for both the mobile app and the backend GraphQL API, Prose.
+This will install dependencies for both the Mobile App and the backend GraphQL API, Prose.
### Install the Expo CLI
@@ -47,7 +49,7 @@ This will install dependencies for both the mobile app and the backend GraphQL A
We will later use the Expo CLI to launch the Mobile App - either on your device or in a simulator.
-You can install Expo with the following command:
+You can install the Expo CLI with the following command:
```sh
npm install --global expo-cli
@@ -59,14 +61,35 @@ Then, verify that Expo is available in your `PATH` with the following:
```sh
$ expo --version
-3.28.0
+
+```
+
+### Install the EAS CLI
+
+[Expo Application Services (EAS)](https://expo.dev/eas/) is an integrated set of cloud services for Expo and React Native apps.
+
+We will use the EAS CLI to build and publish the Mobile App.
+
+You can install the EAS CLI with the following command:
+
+```sh
+npm install --global eas-cli
+```
+
+Further information is available in the [Expo docs](https://docs.expo.dev/eas/).
+
+Then, verify that EAS is available in your `PATH` with the following:
+
+```sh
+$ eas --version
+eas-cli/
```
### Ready to Go!
That's all we need for this step.
-Next, there's an optional guide to help you if you're not too familiar with setting up a server on a cloud provider.
+Next, there is an optional guide to help you if you're not too familiar with setting up a server on a cloud provider.
You're free to skip this if you're already adept at this process.
diff --git a/documentation/docs/tutorial/updating.md b/documentation/docs/tutorial/updating.md
new file mode 100644
index 00000000..46fcfdd1
--- /dev/null
+++ b/documentation/docs/tutorial/updating.md
@@ -0,0 +1,68 @@
+---
+title: Update your App
+---
+
+## EAS Update
+
+EAS Update is the successor to `expo publish`. This service helps to update projects using the `expo-updates` library.
+
+In particular, it enables you to push quick fixes to your users in between full-fledged app store submissions.
+
+With EAS Update, there is no need to recompile the app with its non-native parts, such as TypeScript code, styling, or image assets. [Click here](https://docs.expo.dev/eas-update/introduction/) to learn more about EAS Update.
+:::note
+You are required to build the app with [EAS Build](building) before using the EAS Update.
+:::
+
+### Configuration
+
+Let's get started by configuring EAS update. Feel free to check out the [complete guide](https://docs.expo.dev/build-reference/build-configuration/) from Expo for further details.
+
+```bash
+eas update:configure
+```
+
+Running this command will add `expo.updates.url` and `runtimeVersion.policy` in `app.json`.
+
+:::caution
+
+As mentioned in the [Expo documentation](https://docs.expo.dev/build/updates/#previewing-updates-in-development-builds), you can no longer launch your app in Expo Go (using `expo start`) after adding the `runtimeVersion` field in `app.json`. It is recommended to use `expo-dev-client` instead to create a development build.
+
+```bash
+eas -p all -e development
+```
+
+or if you still wish to use Expo Go, please remove `runtimeVersion` field from `app.json` before running `expo start`.
+:::
+
+### Updating
+
+After making the necessary changes, you can push updates using this command:
+
+```bash
+eas update โ-branch โ-message โโ
+```
+
+The branch name here is the same as the build profile name when building the app.
+For example, if you had previously built the app with this command:
+
+```bash
+eas build โp all โe preview
+```
+
+Then you can later update it using:
+
+```bash
+eas update โ-branch preview โ-message โFixing typosโ
+```
+
+Once the update is complete, force close and reopen the installed app twice to view the update.
+
+## All Done! ๐
+
+That's it for the tutorial. Great work.
+
+We hope that this has served as an informative guide to help familiarize you with Lexicon and how you can make use of it.
+
+If you haven't already, check out the [Lexicon Documentation](../) to get a deeper understanding of the project and how it all works.
+
+If you have any questions, comments, feedback, or want to contribute, please reach out to us on Github!
diff --git a/documentation/docs/tutorial/white-label.md b/documentation/docs/tutorial/white-label.md
index 625bac97..f0192667 100644
--- a/documentation/docs/tutorial/white-label.md
+++ b/documentation/docs/tutorial/white-label.md
@@ -14,7 +14,11 @@ Both of these assets often contain your logo in one form or another. For example
### Customizing the Splash Screen
-The assets used for the Splash Screen in Lexicon is located at `frontend/assets/images/splash.png` and `frontend/assets/images/splashDark.png`.
+:::info
+Expo does not currently support dark mode for splash screens.
+:::
+
+The assets used for the splash screen in the Mobile App are located at `frontend/assets/images/splash.png` and `frontend/assets/images/splashDark.png`.
Above, we mention splash screen assets for both Dark Mode and Light Mode.
@@ -61,22 +65,18 @@ The `backgroundColor` field enables you to specify the color of the background b
Customizing the App Icon in Lexicon is nearly the same process as customizing the Splash Screen.
-The asset for the App Icon is located at `frontend/assets/icon.png`. To customize it, simply overwrite that file with your own `icon.png`.
+The image asset for the Mobile App's icon is located at `frontend/assets/icon.png`. To customize it, simply overwrite that file with your own `icon.png`.
## Further Customization
-We get into much more detail about how to White Label your app in the [White Labeling](../white-labeling) section of the documentation.
+We get into more detail about how to white label your app in the [White Labeling](../white-labeling) section of the documentation.
In particular, this includes customizing and extending the theme's color palette, icons, and even fonts.
-Should wish to customize anything not covered in that section, get in touch with us, and we'll see how we can help you make it a reality.
-
-## All Done!
-
-That's it for the tutorial. Great work.
+Should you wish to customize anything not covered in that section, get in touch with us, and we'll see how we can help you make it a reality.
-We hope that this has served as an informative guide to help familiarize you with Lexicon and how you can make use of it.
+## Awesome Work
-If you haven't already, check out the [Lexicon Documentation](../) to get a deeper understanding of the project and how it all works.
+Your app looks cool now ๐. However, it's only accessible to you.
-If you have any questions, comments, feedback, or want to contribute, please reach out to us on Github!
+Next, we'll cover how you can actually [build your app](building), so you can share it with the world.
diff --git a/documentation/docusaurus.config.js b/documentation/docusaurus.config.js
index cf9f5cfe..937e4856 100644
--- a/documentation/docusaurus.config.js
+++ b/documentation/docusaurus.config.js
@@ -16,10 +16,10 @@ module.exports = {
},
items: [
{
- to: '/',
- activeBasePath: 'docs',
+ type: 'doc',
label: 'Documentation',
position: 'left',
+ docId: 'intro',
},
{
type: 'doc',
@@ -32,6 +32,9 @@ module.exports = {
label: 'GitHub',
position: 'right',
},
+ {
+ type: 'docsVersionDropdown',
+ },
],
},
footer: {
@@ -58,8 +61,20 @@ module.exports = {
{
docs: {
sidebarPath: require.resolve('./sidebars.js'),
- editUrl: 'https://github.com/lexiconhq/lexicon/blob/master/documentation/',
+ editUrl:
+ 'https://github.com/lexiconhq/lexicon/blob/master/documentation/',
routeBasePath: '/',
+ onlyIncludeVersions: ['1.0.0', '2.0.0-beta'],
+ versions: {
+ '2.0.0-beta': {
+ path: 'version-2.0.0-beta',
+ banner: 'none',
+ },
+ '1.0.0': {
+ path: 'version-1.0.0',
+ banner: 'none',
+ },
+ },
},
theme: {
customCss: require.resolve('./src/css/custom.css'),
diff --git a/documentation/sidebars.js b/documentation/sidebars.js
index c87aaebb..e345acf2 100644
--- a/documentation/sidebars.js
+++ b/documentation/sidebars.js
@@ -15,7 +15,13 @@ module.exports = {
'White Labeling': ['white-labeling', 'assets', 'theming'],
'Deploying Prose': ['deployment', 'env-prose', 'dedicated'],
'Configuring Discourse': ['optimal'],
- 'Publishing your App': ['app-store', 'play-store', 'lexicon-updates'],
+ 'Publishing your App': [
+ 'app-store',
+ 'play-store',
+ 'lexicon-updates',
+ 'troubleshooting-build',
+ ],
+ Plugin: ['push-notifications/introduction'],
},
tutorial: {
Tutorial: [
@@ -26,6 +32,29 @@ module.exports = {
'tutorial/install-prose',
'tutorial/setup-mobile',
'tutorial/white-label',
+ 'tutorial/building',
+ 'tutorial/publishing',
+ 'tutorial/updating',
],
},
+ plugin: [
+ {
+ type: 'doc',
+ id: 'push-notifications/introduction', // document ID
+ label: 'Introduction', // sidebar label
+ },
+ {
+ type: 'doc',
+ id: 'push-notifications/plugin-interaction', // document ID
+ label: 'How Push Notifications work with Lexicon', // sidebar label
+ },
+ {
+ type: 'category',
+ label: 'Setup',
+ items: [
+ 'push-notifications/setup/enable-push-notifications',
+ 'push-notifications/setup/verify-push-notifications',
+ ],
+ },
+ ],
};
diff --git a/documentation/src/pages/index.js b/documentation/src/pages/index.js
new file mode 100644
index 00000000..19a6bb8d
--- /dev/null
+++ b/documentation/src/pages/index.js
@@ -0,0 +1,6 @@
+import React from 'react';
+import { Redirect } from 'react-router-dom';
+
+export default function Home() {
+ return ;
+}
diff --git a/documentation/static/img/guides/playStore/build-artifact.png b/documentation/static/img/guides/playStore/build-artifact.png
new file mode 100644
index 00000000..5d14e7d9
Binary files /dev/null and b/documentation/static/img/guides/playStore/build-artifact.png differ
diff --git a/documentation/static/img/guides/playStore/builds.png b/documentation/static/img/guides/playStore/builds.png
new file mode 100644
index 00000000..832bfe53
Binary files /dev/null and b/documentation/static/img/guides/playStore/builds.png differ
diff --git a/documentation/static/img/guides/playStore/expo-build.png b/documentation/static/img/guides/playStore/expo-build.png
deleted file mode 100644
index ca271cb0..00000000
Binary files a/documentation/static/img/guides/playStore/expo-build.png and /dev/null differ
diff --git a/documentation/static/img/guides/testFlight/build-artifact.png b/documentation/static/img/guides/testFlight/build-artifact.png
index d16c0a93..491277ac 100644
Binary files a/documentation/static/img/guides/testFlight/build-artifact.png and b/documentation/static/img/guides/testFlight/build-artifact.png differ
diff --git a/documentation/static/img/guides/testFlight/builds.png b/documentation/static/img/guides/testFlight/builds.png
index c68f7dfb..07a14a20 100644
Binary files a/documentation/static/img/guides/testFlight/builds.png and b/documentation/static/img/guides/testFlight/builds.png differ
diff --git a/documentation/static/img/lexicon-architecture.png b/documentation/static/img/lexicon-architecture.png
index 96ab7b7f..c57293ef 100644
Binary files a/documentation/static/img/lexicon-architecture.png and b/documentation/static/img/lexicon-architecture.png differ
diff --git a/documentation/static/img/lexicon-architecture.svg b/documentation/static/img/lexicon-architecture.svg
new file mode 100644
index 00000000..a4dd3609
--- /dev/null
+++ b/documentation/static/img/lexicon-architecture.svg
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/documentation/static/img/push-notifications/push-notifications-flowchart.svg b/documentation/static/img/push-notifications/push-notifications-flowchart.svg
new file mode 100644
index 00000000..4111d279
--- /dev/null
+++ b/documentation/static/img/push-notifications/push-notifications-flowchart.svg
@@ -0,0 +1 @@
+
User logs in to the app
User enables push notifications
Send a private message to another user
Create a post
Receive a reply to the message
Create a notification event
Event intercepted by plugin
Get all user push tokens
Construct a message for each token
Send messages to Expo
Expo sends a push notification to the device
User receives a push notification
\ No newline at end of file
diff --git a/documentation/static/img/screenshot/Discourse-Plugin-Email-notification.png b/documentation/static/img/screenshot/Discourse-Plugin-Email-notification.png
new file mode 100644
index 00000000..d0912808
Binary files /dev/null and b/documentation/static/img/screenshot/Discourse-Plugin-Email-notification.png differ
diff --git a/documentation/static/img/screenshot/Discourse-Plugin-EmailDeepLinking-Settings.png b/documentation/static/img/screenshot/Discourse-Plugin-EmailDeepLinking-Settings.png
new file mode 100644
index 00000000..bafda321
Binary files /dev/null and b/documentation/static/img/screenshot/Discourse-Plugin-EmailDeepLinking-Settings.png differ
diff --git a/documentation/static/img/screenshot/Discourse-Plugin-Enable.png b/documentation/static/img/screenshot/Discourse-Plugin-Enable.png
new file mode 100644
index 00000000..c96f964e
Binary files /dev/null and b/documentation/static/img/screenshot/Discourse-Plugin-Enable.png differ
diff --git a/documentation/static/img/screenshot/Discourse-Plugin-PushNotif-Settings.png b/documentation/static/img/screenshot/Discourse-Plugin-PushNotif-Settings.png
new file mode 100644
index 00000000..816d4c1d
Binary files /dev/null and b/documentation/static/img/screenshot/Discourse-Plugin-PushNotif-Settings.png differ
diff --git a/documentation/static/img/screenshot/Discourse-Plugin-Settings.png b/documentation/static/img/screenshot/Discourse-Plugin-Settings.png
new file mode 100644
index 00000000..79e23b04
Binary files /dev/null and b/documentation/static/img/screenshot/Discourse-Plugin-Settings.png differ
diff --git a/documentation/static/img/screenshot/Mobile-PushNotification.png b/documentation/static/img/screenshot/Mobile-PushNotification.png
new file mode 100644
index 00000000..2a97034d
Binary files /dev/null and b/documentation/static/img/screenshot/Mobile-PushNotification.png differ
diff --git a/documentation/static/img/screenshot/Please_connect_network_error.png b/documentation/static/img/screenshot/Please_connect_network_error.png
new file mode 100644
index 00000000..0bc5385a
Binary files /dev/null and b/documentation/static/img/screenshot/Please_connect_network_error.png differ
diff --git a/documentation/static/img/screenshot/playground.png b/documentation/static/img/screenshot/playground.png
index 3307672c..82c3efb2 100644
Binary files a/documentation/static/img/screenshot/playground.png and b/documentation/static/img/screenshot/playground.png differ
diff --git a/documentation/versioned_docs/version-1.0.0/app-store.md b/documentation/versioned_docs/version-1.0.0/app-store.md
new file mode 100644
index 00000000..941750d5
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/app-store.md
@@ -0,0 +1,276 @@
+---
+title: Publishing to the App Store
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+At this point, you've at least made some minor adjustments to the Lexicon Mobile App, and are ready to publish it so that your users can download it.
+
+In this page, we'll cover the process of publishing it on iOS.
+
+## Prerequisites
+
+- An Apple Developer account
+- An Expo account
+- XCode is installed on your development machine
+- EAS CLI 2.6.0 or newer
+
+To get started with TestFlight and publishing your app, you'll need an **Apple Developer account**.
+
+This will enable you to interact with Apple as you go through the process of submitting to TestFlight and, eventually, the App Store.
+
+You'll also need an [Expo account](https://expo.dev/signup) so you can build your app, download it, and upload it to Apple's servers.
+
+Finally, you'll want to have already downloaded and installed [Xcode](https://developer.apple.com/xcode/), which is what you'll use to upload your built app to Apple's servers.
+
+:::note
+If you don't yet have an account with Apple, you'll need to enroll in the [Apple Developer Program](https://developer.apple.com/programs/enroll/) first. Note that there is an annual cost associated with this.
+
+Additionally, you'll want to make sure you have an account with [Expo](https://expo.dev/signup) so you can use features like [EAS Submit](https://docs.expo.dev/submit/introduction/).
+:::
+
+## Register a new Bundle ID
+
+Each app in Apple's App Store has a unique **Bundle Identifier**, or Bundle ID.
+
+In order to publish the app anywhere, including to TestFlight, you'll need to have a Bundle ID registered for your app with Apple.
+
+Typically, this uses the format of `com..`.
+
+For example, if your company is named Expo, and your app is named Expo Go, your Bundle ID could be:
+
+```
+com.expo.expogo
+```
+
+You can follow these instructions to get one.
+
+- Go to [Certificates, Identifiers & Profiles](https://developer.apple.com/account/resources/identifiers/bundleId/add/bundle).
+- Fill in the following fields, and then click `Continue`
+
+
+ - **Description**: You can insert the app name as its description.
+
+ - **Bundle ID**: Select `Explicit`, and then insert then insert your bundle ID in the input field.
+
+- Capabilities
+
+ - You can leave this section empty.
+
+## Add a New App in App Store Connect
+
+Steps:
+
+- Sign in to your [App Store Connect](https://appstoreconnect.apple.com/) account.
+- Click on `My Apps`.
+
+- Click on the `+` button to add new app.
+
+- Fill out the requested information about your app, and then click `Create`.
+
+
+ - **Platforms**: Select `iOS`.
+ - **Name**: The name of your app, as it will appear on the App Store and user's devices.
+ - **Primary Language**: The primary language that will be used if localized app information is not available.
+ - **Bundle ID**: Choose the Bundle ID you created above.
+ - **Note**: double-check that it's correct, because you can not change it afterwards.
+ - **SKU (Stock Keeping Unit)**: A unique ID to differentiate your app from the others, similar to a product ID.
+ - **User Access**: Full access means all users will have access to the app, while limited access means that the app can only be accessed by certain roles defined within App Store Connect.
+
+## Configuration
+
+After creating the app in App Store Connect, you'll want to jump back over to the codebase and make some adjustments.
+
+### Build Config
+
+:::note
+If you haven't yet installed the EAS CLI, follow the instructions in the [tutorial](tutorial/setup#install-the-eas-cli).
+:::
+
+First, you'll need to ensure you've set your app name and slug in `frontend/app.json`. The [slug](https://docs.expo.dev/workflow/glossary-of-terms/#slug) is used as part of the URL for your app on Expo's web services, so it is recommended to use kebab-case (e.g., `my-lexicon-app`).
+
+Replace these placeholders with your desired values:
+
+```json
+ "name": "",
+ "slug": "",
+```
+
+Next, configure EAS Build by running this command from the `frontend/` directory:
+
+```bash
+eas build:configure
+```
+
+The EAS CLI will prompt you to specify `android.package` and `ios.bundleIdentifier` if those values are not already provided in `app.json`. You'll want to add the bundle ID you just registered in App Store Connect as the `bundleIdentifier`.
+
+Then you can see that the value has been updated in the `ios` section of `frontend/app.json` file.
+
+```json
+ "ios": {
+ "supportsTablet": false,
+ "buildNumber": "1.0.0",
+ "bundleIdentifier": "",
+ "config": {
+ "usesNonExemptEncryption" : false
+ }
+ },
+```
+
+:::note
+We set `usesNonExemptEncryption` to `false` because Lexicon doesn't leverage that feature.
+
+For further details, please take a look at [this link](https://developer.apple.com/documentation/bundleresources/information_property_list/itsappusesnonexemptencryption) from Apple's documentation.
+:::
+
+### Setup Config Values
+
+:::info
+When publishing your app, it is necessary to deploy Prose somewhere publicly accessible, perhaps on a cloud hosting provider like AWS or DigitalOcean. If Prose is only running on your local machine, users that download your app won't be able to use it.
+Check [the documentation](deployment) to deploy Prose if you haven't already.
+:::
+
+Next, configure the **Prose URL** for your build in `Config.ts`. You can set a different URL for each build channel.
+
+:::note
+In the original release of Lexicon, the **Prose URL** was specified in `frontend/.env`. However, as part of migrating to Expo's EAS feature, we centralized the configuration into `frontend/Config.ts` to save you the trouble of needing to maintain it in more than one place, as suggested in the [Expo documentation](https://docs.expo.dev/build-reference/variables/#can-i-share-environment-variables-defined-in-easjson-with-expo-start-and-eas-update)
+:::
+
+```ts
+const config = {
+ // ...
+ buildChannels: {
+ preview: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ production: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ },
+};
+```
+
+### Setup Apple Dveloper Account
+
+Lastly, please adjust these fields in `eas.json` with your account information to submit the app:
+
+```json
+ "base": {
+ "ios": {
+ "appleId": "",
+ "ascAppId": "",
+ "appleTeamId": ""
+ },
+ ...
+ },
+```
+
+- **appleId**: your apple ID (e.g., `john@gmail.com`).
+- **ascAppId**: your App Store Connect app ID. Find your ascAppID by following [this guide](https://github.com/expo/fyi/blob/main/asc-app-id.md) (e.g., `1234567890`).
+- **appleTeamId**: You can check your apple team ID [here](https://developer.apple.com/account/) (e.g., `12LE34XI45`).
+
+## Build your App for iOS
+
+Before publishing, you'll need to build your app by instructing Expo to generate an iOS build.
+
+It is recommended to build your app with the `preview` profile before releasing to verify that it works as expected. See [this tutorial](tutorial/building) to learn more about build profiles.
+
+Run this command:
+
+```bash
+eas build --platform ios --profile preview
+```
+
+When you run the above command, Expo will prompt you for your Apple ID and password.
+
+Once the above step has been completed, login to your account on [Expo](https://expo.dev) and download your newly built app.
+
+Navigate to your project in the [Expo web console](https://expo.dev), then click on the **Builds** menu located on the left-hand side of the screen.
+
+- Click on the project you want to install.
+
+
+- Download the iOS build by pressing the `Download` button in the `Build Artifact` section.
+
+
+This will download a tar file containing your app. Extract the file, then drag it to your simulator to install it. See [this section](tutorial/building#1-preview) of the tutorial to learn about running the app on real devices.
+
+Once you have verified that the app runs as expected, you can proceed to build it for release:
+
+```bash
+eas build --platform ios --profile production
+```
+
+The approach for a production build is similar to the one used for generating a preview build. However, unlike a preview build, you won't be able to launch the production build in the iOS simulatorโit is intended solely for publishing to the App Store.
+
+Once this process is completed, you can proceed with submitting it to Apple. This process typically involves Apple's TestFlight service.
+
+## Submit to TestFlight
+
+TestFlight is a key aspect of Apple's Developer Program, which enables developers to provide beta users with access to their app under less restrictive review requirements.
+
+With TestFlight, you're able to invite users to test your app and collect their feedback before releasing it to the public on the App Store. You can learn more about TestFlight [here](https://developer.apple.com/testflight/).
+
+Submitting an iOS app is much easier with EAS Submit. This is covered in more detail in the [tutorial](tutorial/publishing).
+
+Run the following command to start publishing the app to TestFlight:
+
+```bash
+eas submit --platform ios --profile production
+```
+
+Once the process has completed successfully, we can check the build in App Store Connect.
+
+In App Store Connect, click on the TestFlight Tab.
+
+You'll see the [status](https://help.apple.com/app-store-connect/#/dev3d6869aff) of your built version.
+
+- **Red** indicates that you need to perform some action.
+- **Yellow** indicates that some aspect of the process is pendingโeither from you, or from Apple.
+- **Green** indicates that the build is being tested in TestFlight, or is ready to be submitted for review.
+
+You won't be able to begin beta testing with TestFlight until an official tester from Apple verifies your app.
+
+In order to allow Apple to properly test your Lexicon-powered app, they'll need to have credentials to login your Discourse site.
+
+Before submitting your app, you'll need to create those credentials in Discourse and specify them in App Store Connect.
+
+- In App Store Connect, click on your app.
+- Click on TestFlight App.
+- Click on Test Information in the sidebar on the left-hand side.
+- Fill the required fields, then check the `Sign in required` checkbox, and enter the credentials.
+
+- Please also provide information for a person to contact if the review team needs additional information.
+
+
+### Specify Users for Beta Testing
+
+Beta Test Users can belong to an Internal Group or an External Group.
+
+You can specify internal users by going to the Internal Group section, and clicking on **App Store Connect Users**.
+
+Similarly, you can specify external users by selecting External Groups, and clicking on **Add External Testers**.
+
+#### More Information
+
+TestFlight and App Store Connect are sophisticated tools to help with the process of submitting, testing, and publishing your app.
+
+If you have further questions or just want to learn more, we'd recommend that you make use of Apple's documentation, which is very high quality.
+
+For more information about TestFlight in general, read the [documentation](https://developer.apple.com/testflight/).
+
+Similarly, for specific information about beta testing with TestFlight, check out [Testing Apps with TestFlight](https://testflight.apple.com/).
+
+## Publish to the App Store
+
+Once you've successfully passed Apple's review process and have received enough feedback from your beta testers, you're ready to publish to the App Store and go live! :tada:
+
+As a few final reminders, double-check that...
+
+- Your Discourse instance is online, reachable, and functioning correctly.
+- The built version of your app is configured to point at the correct Prose server.
+- Your Prose server is online, reachable and healthy.
+- Your Prose server is deployed with the [recommended guidlines](dedicated#configure--deploy-prose) for production.
+ - In particular, ensure that its traffic is encrypted using an SSL certificate.
+
+Next, we'll guide you through the process of publishing your app for Android devices on the Google Play Store.
diff --git a/documentation/versioned_docs/version-1.0.0/assets.md b/documentation/versioned_docs/version-1.0.0/assets.md
new file mode 100644
index 00000000..a24dcad0
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/assets.md
@@ -0,0 +1,47 @@
+---
+title: App Icon & Other Assets
+---
+
+The Lexicon Mobile App contains multiple assets that can be replaced in order to White Label it.
+
+The assets that can be modified are as follows:
+
+## App Logo
+
+Used to show the app logo in the application, such as on the Login, Register, and 2FA Scenes.
+
+The assets are located at `frontend/assets/images/logo.png` and `frontend/assets/images/logoDark.png`. The `logo.png` is used in light color scheme and `logoDark.png` is used in dark color scheme. To customize it, simply replace the existing file with your own `logo.png` and `logoDark.png`.
+
+## Favicon
+
+Used to show the app logo.
+
+The asset is located at `frontend/assets/favicon.png`. To customize it, simply replace the existing file with your own `favicon.png`.
+
+## Image Placeholder
+
+Used to temporarily take an image place when it is loading.
+
+The asset is located at `frontend/assets/images/imagePlaceholder.png`. To customize it, simply replace the existing file with your own `imagePlaceholder.png`.
+
+## Icons
+
+Used to display icons inside the application.
+
+The assets are located in the `frontend/assets/icons` folder. If you want to add more or edit the remaining icons, you need to insert the icons to the `frontend/assets/icons/` folder and import them in `frontend/src/icons.ts`.
+
+There are some standards applied to the icons, such as:
+
+#### Uniform Icon Size to Maintain Visual Consistency
+
+The UI is designed around the default base dimensions of 28x28px for icons.
+
+If you adjust this, you may need to modify other aspects of the theme or fonts in order to maintain a clean appearance.
+
+Similarly, if you provide a new icon that does not conform to these dimensions, you may run into visual inconsistencies.
+
+#### SVG Icons have their Fill Color Controlled via `currentColor`
+
+If you are adding a new icon that you expect to interact with theme's colors, ensure that its color is not hard-coded, and is instead set to `currentColor`.
+
+If you are unfamiliar with this concept, take a look at the [MDN Specification on SVG color values](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/color).
diff --git a/documentation/versioned_docs/version-1.0.0/commercial-support.md b/documentation/versioned_docs/version-1.0.0/commercial-support.md
new file mode 100644
index 00000000..9d164810
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/commercial-support.md
@@ -0,0 +1,9 @@
+---
+title: Commercial Support
+---
+
+With official support, you get expert help straight from the core team. We provide app customization, dedicated support, prioritize feature requests, deployment strategies, advice on best practices, design decisions, and team augmentation.
+
+Additionally, we are open to engagements for non-technical site owners looking to customize, deploy, and launch a mobile app for their Discourse users.
+
+Reach out to us for consulting at support@kodefox.com.
diff --git a/documentation/versioned_docs/version-1.0.0/concepts.md b/documentation/versioned_docs/version-1.0.0/concepts.md
new file mode 100644
index 00000000..f32b0652
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/concepts.md
@@ -0,0 +1,63 @@
+---
+title: Concepts and Architecture
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+## Prose: Discourse through GraphQL
+
+It is worth acknowledging upfront that Discourse already provides a traditional, RESTful API for developers out of the box.
+
+However, [the official documentation](https://docs.discourse.org/) for this API points out that it is incomplete, effectively serving as a starting point.
+
+> Note: For any endpoints not listed you can follow the reverse engineer the Discourse API guide to figure out how to use an API endpoint.
+>
+> โ**Discourse API Documentation**
+
+The core team, as well as members of the [support forum](https://meta.discourse.org), regularly respond to questions about the API by [encouraging developers to reverse-engineer the API](https://meta.discourse.org/t/how-to-reverse-engineer-the-discourse-api/20576). As of this writing, the topic for how to reverse engineer the API has been linked to from nearly 200 other topics on the support forum.
+
+To help you simplify the process for you, Prose strives to normalize a subset of the API. We have done so with the hope that it will save you some time as you develop against Discourse.
+
+#### GraphiQL
+
+Prose's GraphQL implementation includes an [in-browser GraphQL IDE](https://www.graphql-yoga.com/docs/features/graphiql), known as [GraphiQL](https://github.com/graphql/graphiql), which allows developers to easily reference the entire documentation and schema and make queries against a running Discourse instance.
+
+
+
+This means you can rapidly get a clear understanding of how a method behavesโand what parameters it requiresโwithout digging through support posts or reverse-engineering the REST API.
+
+#### Why GraphQL?
+
+There is no shortage of articles about both the [benefits](https://www.howtographql.com/basics/1-graphql-is-the-better-rest) and [tradeoffs](https://lwhorton.github.io/2019/08/24/graphql-tradeoffs.html) of GraphQL.
+
+We're well aware that GraphQL isn't some magical solution that solves all the problems of other API paradigms.
+
+Having said that, we chose to build Lexicon with it for two primary reasons.
+
+1. Our team is familiar and fluent with GraphQL, and deeply enjoys working with it.
+
+2. The tooling, libraries, and auto-generated documentation provide out-of-the box benefits which we can pass onto others with no additional effort.
+
+#### Why Expo?
+
+[Expo](https://docs.expo.io/) is both a framework and a platform for building universal React applications. In particular, it provides a superior development experience when building mobile apps with React Native.
+
+We find that Expo makes us much more effective as developers, and also provides excellent services to facilitate the entire process of building and publishing React Native apps.
+
+## Lexicon Architecture
+
+The Lexicon Stack is fairly simple, and only consists of 3 major pieces:
+
+- The Lexicon Mobile App
+- The Prose GraphQL API
+- A running, accessible Discourse instance
+
+Below is a diagram illustrating the typical architecture for a Lexicon-powered mobile app.
+
+
+
+As indicated above, the mobile app makes requests to a deployed Prose GraphQL server.
+
+The Prose server has been configured to point at an active Discourse instance of the developer's choice.
+
+Traffic then flows back from Discourse, through Prose, and returns to the mobile app over a GraphQL interface.
diff --git a/documentation/versioned_docs/version-1.0.0/contributing.md b/documentation/versioned_docs/version-1.0.0/contributing.md
new file mode 100644
index 00000000..0fe6fbe9
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/contributing.md
@@ -0,0 +1,131 @@
+---
+title: Contributing
+---
+
+Thank you for your interest in contributing! :sparkles:
+
+We greatly appreciate the time and effort you're willing to put forth to make Lexicon even better.
+
+There are several ways to help out.
+
+## Reporting Bugs
+
+The best way to let us know about a bug is by [creating a new issue](https://github.com/lexiconhq/lexicon/issues/new) on [Github](https://github.com/lexiconhq/lexicon).
+
+As always, we recommend searching the existing open and closed issues before opening a new one.
+
+When you create the issue, please be sure to include the following:
+
+- A detailed description of the bug and its behavior
+
+- The behavior you expected instead of the bug
+
+- A list of steps for how to reproduce the bug
+
+- Details about the device(s) and version(s) you're observing the bug on
+
+- Screenshots and screen recordings, while not necessary, are very welcome!
+
+Once we've received your bug report, we will triage it and label it accordingly.
+
+## Contribute to the Project
+
+Want the honor of being listed in our contributors section :clap:?
+
+We'd love to get a PR from you addressing an existing issue, adding a feature, or even just improving the documentation.
+
+To get started contributing, follow the instructions below.
+
+### Instructions
+
+**1. Fork the [official Lexicon repository](https://github.com/lexiconhq/lexicon)**
+
+You probably already know the drill - click on **Fork** button on the upper-right corner.
+
+**2. Clone your Fork of Lexicon**
+
+Be sure to clone **_your_** fork to your development machine (as opposed to cloning the main Lexicon repository).
+
+```
+$ git clone https://github.com/YOUR_USERNAME/lexicon.git
+```
+
+If you need further guidance with cloning, head over to our [Quick Start](quick-start#installation) section.
+
+Just bear in mind that the Quick Start section walks you through cloning the Lexicon repository. So make sure you change the URL to your username as referenced above.
+
+**3. Run and connect the app with Prose and a Discourse Host**
+
+For a comprehensive walk-through of this step, follow the instructions in the [**Setup**](setup#discourse-host) section.
+
+If you already have a deployed Prose instance that is pointing at a Discourse instance, you can simply configure the Lexicon Mobile App to point at the address of your Prose deployment.
+
+However, if you don't have that, or if you're planning on making adjustments to the Prose server itself, you'll want to ensure the Lexicon Mobile App is configured to point at a Prose server that you have running locally.
+
+**4. Get Started with your Contribution**
+
+At this point, you should be setup to dig in on the main work of your feature, bugfix, or other contribution.
+
+Remember that it's necessary to have the [**ESLint**](https://eslint.org/docs/user-guide/getting-started) and [**Prettier**](https://prettier.io/) plugins installed in your IDE, as those are required in order for the Pull Request checks to pass.
+
+We would recommend working in [VSCode](https://code.visualstudio.com/), since that is what we used to develop Lexicon. However, it is up to you, you only need to ensure that ESLint and Prettier are functioning properly within your IDE.
+
+**5. Run the Test Suite**
+
+Follow these [**steps**](setup#run-the-test-suite) to run the Lexicon test suite.
+
+In order to speed up the feedback cycle, it is recommended that you ensure that all tests are passing locally before pushing, especially if you already have an open PR.
+
+This is primarily because we have configured our Github project to block PRs from being merged if any of the build steps fail.
+
+If the reviewers see that tests are failing, they aren't able to review it as quickly, and will likely request that you resolve any build issues before requesting review again.
+
+**6. Stage, Commit, and Push your Local Changes**
+
+If you're unfamiliar with this process, please take a look at this [great article](https://github.com/git-guides/#learning--mastering-git-commands) from Github to bring you up to speed.
+
+**7. Create a New Pull Request**
+
+Your code is ready to submit! :tada:
+
+Go to the Lexicon [Pull Requests tab](https://github.com/lexiconhq/lexicon/pulls), and compare the changes between your branch and the master branch.
+
+Double-check and make sure you didn't push anything you don't want included in your PR.
+
+Then, go ahead and create a new Pull Request from your forked repository.
+
+Please be sure to follow the Pull Request template, add related labels, and please mention the issue you are addressing to help us keep track of what's being worked on.
+
+## Share Your Thoughts with Us
+
+We'd love to hear your new ideas! Drop them in the [Issues tab](https://github.com/lexiconhq/lexicon/issues).
+
+## Spread the Word
+
+Let others know about your awesome experience using Lexicon on social media, and tag us on Twitter [@GetLexicon](https://twitter.com/GetLexicon).
+
+And if you build your app using Lexicon, please let us know. We'd love to help you spread the word about what you've built!
+
+## Improve the Documentation
+
+As a closing thought, if you find any issues with the Lexicon documentation, or just think you could make it better, you can get started with these brief instructions below.
+
+To generate and run the documentation locally, from the project root, run:
+
+```sh
+npm run docs:start
+```
+
+Similarly, you can build the documentation using:
+
+```sh
+npm run docs:build
+```
+
+All documentation is in the `documentation/` directory, and the Markdown pages used to generate this site are under `documentation/docs`.
+
+If you end up making a PR to improve the documentation, please be sure to label your PR with the `Documentation` label.
+
+:::note
+Don't hesitate to ask if you have any further questions. We're always happy to help. :smile:
+:::
diff --git a/documentation/versioned_docs/version-1.0.0/customize.md b/documentation/versioned_docs/version-1.0.0/customize.md
new file mode 100644
index 00000000..6797d756
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/customize.md
@@ -0,0 +1,28 @@
+---
+title: Customization
+---
+
+## Theming
+
+As part of its [White Labeling Support](white-labeling), Lexicon allows you to customize the theme of the mobile app.
+You can configure the base and functional colors according to a color scheme of your choosing.
+You're also able to customize icons, fonts, and even the error messages that appear inside of the mobile app.
+To get started with this, check out the [Theming page](theming) under the [White Labeling](white-labeling) section.
+
+## White Labeling the Mobile App Assets
+
+To provide your users with a unique experience that matches your brand, you can customize the splash screen and app icon on their device.
+
+This will replace all Lexicon branding with your own.
+
+Further details can be found in both the [Tutorial](tutorial/white-label) and the [White Labeling Section](white-labeling) of this documentation.
+
+## Enabling Additional Discourse features
+
+As you might already be aware, Discourse is a highly customizable piece of software. Much of it is customizable from the Admin Site Settings page on your Discourse instance.
+
+Some of these settings will translate automatically into the Lexicon Mobile App, such as `authorized extensions`.
+
+In general, we have done our best to get out of the way and use Discourse as the source of truth for how the Lexicon Mobile App should appear and behave.
+
+If you find any settings that Lexicon is not responding to, but you feel it should, please open an issue and let us know.
diff --git a/documentation/versioned_docs/version-1.0.0/dedicated.md b/documentation/versioned_docs/version-1.0.0/dedicated.md
new file mode 100644
index 00000000..75fe8afe
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/dedicated.md
@@ -0,0 +1,300 @@
+---
+title: Hosting & Configuration
+---
+
+As mentioned in the [Overview](deployment), this section is meant to guide you through configuring and deploying Prose on a dedicated instance.
+
+## Decide on Where to Host
+
+First, you'll need to answer the following question. Where would you like to host Prose?
+
+While there are many options that vary by project and developer preferences, the simplest way is often to use a cloud provider of your choice.
+
+In the [Lexicon tutorial](tutorial/setup-cloud-server), we walk you through this process using Digital Ocean.
+
+If you're confused about this step, or don't have a preference, you should take some time to work through it.
+
+However, if you already know what you're doing, feel free to use any cloud provider or hosting solution of your choice.
+
+### Hosting Checklist
+
+Once you've decided on a host, go through the checklist below to verify that everything is setup as expected.
+
+#### โ
Ensure Access & Permissions on the Host
+
+At a minimum, you will need to be able to login to the host. Some cloud providers offer a virtual, web-based terminal, but ideally you can get credentials to login directly.
+
+If your host is in a UNIX-based environment, you should also have permissions to run commands as `sudo`.
+
+A quick way to check this is to simply attempt to run a command with `sudo`:
+
+```sh
+$ sudo ls
+```
+
+However, if you have a restrictive hosting environment, you will just need a way to place the Lexicon source onto the host, install its dependencies, and expose it on a port.
+
+Bear in mind that a restrictive hosting environment is not ideal, especially since the recommended setup makes use of Docker.
+
+#### โ
Ensure the Host is reachable in the way you need it
+
+Typically, this means that your host is accessible on the open internet.
+
+However, you might have different constraints, such as only needing the host to be accessible from within a VPN or a local network.
+
+
+
+Once you have setup a host which is reachable in the way you need it to be, you can begin configuring Prose on it.
+
+## Configure & Deploy Prose
+
+### Without Docker
+
+Naturally, setting up Prose without Docker involves more manual steps and can be platform-specific.
+
+We have already covered this approach well in the tutorial. In particular, you can dig in with it on the page, [Setup the Prose GraphQL API](tutorial/install-prose#install-manually)
+
+### With Docker
+
+The Prose Docker image comes preconfigured to run Prose using **[PM2](https://pm2.keymetrics.io/)**, which is a sophisticated toolset for running Node processes in production.
+
+This is typically a reasonable setup, with which you can even expose the PM2 server directly to requests on the host.
+
+However, if you'd prefer a different setup, perhaps using Nginx as a reverse proxy to the Docker container, feel free to modify the Dockerfile to match your requirements.
+
+#### Install Docker
+
+**[Docker](https://www.docker.com/)** is a containerization framework that makes it easy to build, manage, and deploy your application stack in a way that is safer, more reliable, and reproducible across multiple platforms.
+
+There are countless guides available for installing Docker on a given operating system.
+
+Ubuntu is one of the more common operating systems avaiable through most cloud providers.
+
+Docker provides a [full tutorial](https://docs.docker.com/engine/install/ubuntu/) for this, and even provides a convenience script that you can run in two lines:
+
+```sh
+curl -fsSL https://get.docker.com -o get-docker.sh
+sudo sh get-docker.sh
+```
+
+Whichever path you need to take, just make sure that Docker is up and running on your host before continuing.
+
+#### Configure Environment Variables
+
+A comprehensive list of all Prose environment variables can be found on the [Environment Variables](env-prose) page.
+
+In brief, at a minimum, you'll want to ensure that `PROSE_DISCOURSE_HOST` is set.
+
+Another variable to pay attention to is `PROSE_APP_PORT`. This defaults to port 80, which instructs Prose to listen on that port.
+
+Depending on your setup, you might want it to listen on a different port.
+
+
+
+#### Build Prose from the Dockerfile
+
+If you'd like to use Docker to manually build Prose, run the following command from the **project root**.
+
+This might be of interest to you if you'd like to make some adjustments to the Dockerfile itself.
+
+Alternatively, if you simply wish to pull the latest Prose build from Docker Hub, you can [skip to the next step](#pulling-the-prose-docker-image).
+
+Unless you've made modifications to the Dockerfile and have it stored elsewhere, you can get started building by running:
+
+```bash
+docker build -t prose:latest -f api/deploy/Dockerfile api/
+```
+
+The command searches for the `Dockerfile` at `api/deploy/Dockerfile` because we instructed it to look there with the `-f` flag.
+
+Then, it uses `api/` as the context for the build, which allows the references in the `Dockerfile` to resolve correctly.
+
+By passing the `-t prose:latest` tag, it tags the locally built image as the latest build. This can be useful for identifying and managing the images in a Docker environment over time.
+
+#### Pull the Prose Docker Image
+
+If you'd rather just use the latest release of the Prose image, you can simply run:
+
+```
+docker pull kodefox/prose:latest
+```
+
+#### Run the Prose Docker Container
+
+Next, to run the newly built image, run the following command:
+
+```bash
+docker run -d \
+ -e PROSE_DISCOURSE_HOST=https://discourse.example.com \
+ -e PROSE_APP_PORT=4000 \
+ --name prose \
+ -p 5000:4000 \
+ kodefox/prose:latest
+```
+
+:::note
+If you built the image by hand, you'll want to substitute `kodefox/prose:latest` with the image name and tag you used, such as `prose:latest`.
+:::
+
+To recap, let's briefly break down that command line-by-line
+
+**Run in Detached Mode**
+
+```bash
+docker run -d
+```
+
+The first line lets Docker know to run the container in **detached mode**.
+
+This means that the command will run in the background, will not be tied to your current session, and will keep running even if you log out.
+
+If you omitted the `-d` flag, Docker would run the container in the foreground, and exiting the process in the foreground would stop the container.
+
+**Set Environment Variables**
+
+```bash
+-e PROSE_DISCOURSE_HOST=https://discourse.example.com
+-e PROSE_APP_PORT=4000
+```
+
+These lines instruct Docker to pass the environment variables of `PROSE_DISCOURSE_HOST` and `PROSE_APP_PORT` to the container when running it.
+
+These are both application-level environment variables that Prose itself will leverage to run properly.
+
+The Docker image expects these values to be set and passes them to the container's environment, which Prose then accesses via `process.env`.
+
+**Name the Container**
+
+```bash
+--name prose
+```
+
+This line tells Docker to give the running container a name. This makes it easier to identify and interact with via commands, such as:
+
+```bash
+docker stop prose
+```
+
+**Configure a Port Mapping between the Host and the Container**
+
+```bash
+-p 5000:4000
+```
+
+Next, we configure Docker with a port mapping, which tells Docker to listen to map the host port of `5000` to the container port of `4000`.
+
+Because we previously set `PROSE_APP_PORT=4000`, this means that all requests to the host at port `5000` will be forwarded to Prose inside of its container on port `4000`.
+
+```bash
+kodefox/prose:latest
+```
+
+The last line of the command tells Docker which image to use for the container.
+
+Above, if you built the Prose image by hand, it was tagged as `prose:latest`.
+
+If you chose to pull from Docker Hub, this is simply instructing Docker to pull that image if necessary, and then start the container with it.
+
+#### Next Steps
+
+At this point, you should have a Docker container running the Prose server on your host.
+
+However, in terms of preparing your Prose host for production, you aren't quite there yet.
+
+Below, we'll guide you through the last steps, finalizing your deployment of the Prose GraphQL Server.
+
+#### Setup SSL (IMPORTANT)
+
+:::danger
+Deploying Prose without SSL in a way that is publicly accessible is **extremely risky**.
+
+Doing so could provide an attacker with full access to your Discourse site and all of its data.
+:::
+
+The **most important next-step** to take at this point is to configure an SSL certificate for your Prose host.
+
+The reason this is so important is that, without SSL, Prose's traffic between your users' devices and Discourse is not encrypted.
+
+And this means that attackers can snoop on your users' requests to Prose and Discourseโincluding, importantly, their authentication information.
+
+To put it bluntly, deploying Prose without configuring SSL is irresponsible and compromises the security of your Discourse instance.
+
+An attacker could even steal your authentication token and use it to access, and potentially destroy, your Discourse site.
+
+##### How to Setup SSL
+
+There are a variety of methods to obtain SSL certificates. Some are free, and some are paid.
+
+The free route involves using [Let's Encrypt](https://letsencrypt.org/), which is very useful, but can require more technical knowledge to setup correctlyโdepending on your configuration. A key difference is that you need to renew the certificates more frequently.
+
+The paid route involves using a provider like [DigiCert](https://www.digicert.com/) to obtain certificates that take longer to expire.
+
+Either way, you'll end up with certificate files that you can configure and launch your webserver with.
+
+Ideally, at this point, you've already purchased a domain. If you haven't, we'd recommend using a domain provider to get a low-cost domain name.
+
+You could host Prose at a subdomain of your existing Discourse site, like `prose.mydiscoursesite.com`.
+
+Or, you could just get a cheap, nonsense domain, like `purplemonkeydishwasher.tech`โsince your users won't typically see it anyway.
+
+Regardless, to emphasize it again, it is **critical** that you don't deploy Prose into production until you have prepared your host to encrypt the traffic from Prose.
+
+#### Determine how you'll expose Prose on the host
+
+When someone navigates to your host which is running Prose, how will their request get routed to Prose?
+
+If you had exposed Prose directly on port 80โNOT recommendedโand your host's domain name was `myproseserver.com`, then a user would navigate to `http://myproseserver.com` and be greeted with the [GraphiQL interface](https://www.graphql-yoga.com/docs/features/graphiql).
+
+However, a more common approach is to use a dedicated webserver, such as Nginx or Apache, that acts as a reverse-proxy.
+
+With this approach, the websever listens for all requests on the ports you tell it to, and is configured to route traffic to Prose, which is listening on a non-privileged port, like 8080.
+
+We recommend this approach more highly for the following reasons:
+
+- Existing webservers are generally more reliable and performant
+- It allows configuration of an SSL certificate, which is necessary for protecting your users' data
+
+Upon configuring the webserver, you'll need to instruct it to forward traffic to the running Prose server.
+
+Your setup might look something like this:
+
+- Nginx is configured to listen on port 80 and port 443 on your domain, `purplemonkeydishwasher.tech`
+- Nginx has located and loaded your SSL certificate files for `purplemonkeydishwasher.tech`
+- Nginx is configured to upgrade all requests on port 80 to port 443
+- Your Prose server is running inside of Docker on a container port of 80, and exposed to the host on port 8080.
+- Your Nginx configuration specifies that requests to `purplemonkeydishwasher.tech` should be forwarded to port 8080.
+- Requests come in for `purplemonkeydishwasher.tech`, Nginx routes it to the container running Prose, which handles the requests, and responds.
+
+#### Configure your Cloud Provider's Firewall, if one exists
+
+Ideally, you've configured Prose to be exposed on the open internet with the traffic encrypted over port 443.
+
+Depending on your cloud provider, you may need to go into its settings and expose that port on the firewall.
+
+For example, in DigitalOcean, this involves going to the Networking section, and creating a new firewall rule.
+
+From there, it is fairly simple to add common ports, like 80 and 443, to the firewall.
+
+After that, you simply apply the firewall to your particular instance, and traffic should be allowed through.
+
+#### Configure DNS Settings for your Domain
+
+Provided that you've already registered a domain name, you'll need to configure it so that the domain name points to your host which is running Prose.
+
+Depending on your setup, this will either be done in your domain provider's settings panel, or perhaps within your cloud provider.
+
+Continuing with the DigitalOcean example from above, you can configure your domain provider to point at DigitalOcean's name servers.
+
+This effectively tells your domain provider that DigitalOcean will handle everything for you, and allows you to make adjustments to your domain from within DigitalOcean.
+
+In that case, DigitalOcean makes it seamless to map the domain name to your instance's IP address, and it should then be accessible from the domain name.
+
+Otherwise, you'll want to get the IP address of your host, go into your domain provider, and instruct it that requests to your domain should be direct to your host's IP address.
+
+#### Ready to Go
+
+At this point, your deployed host should be running Prose correctly. When you navigate to the domain name that you configured it with, you should see [GraphiQL](https://www.graphql-yoga.com/docs/features/graphiql), which will allow you to make GraphQL queries against your Discourse instance.
+
+We understand that the details of your deployment can vary quite a bit depending on how you chose to do it.
+
+If you run into any issues with this stepโas alwaysโdon't hesitate to reach out to us for support.
diff --git a/documentation/versioned_docs/version-1.0.0/deployment.md b/documentation/versioned_docs/version-1.0.0/deployment.md
new file mode 100644
index 00000000..b46ab73b
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/deployment.md
@@ -0,0 +1,86 @@
+---
+title: Overview
+---
+
+As covered in [Concepts and Architecture](concepts#prose-discourse-through-graphql), Prose is Lexicon's GraphQL API layer on top of the traditional RESTful API provided by Discourse.
+
+## Getting Started with Deployment
+
+At this point, you're likely to be digging into this section of the documentation for two reasons:
+
+- You've been developing against a local instance (or container) running Prose, and you're ready to actually deploy your entire Lexicon project to production.
+
+- You want to simplify your development process by pointing the Lexicon Mobile App at a deployed instance of Prose.
+
+In either scenario, the end goal of this section is to have a working Prose server accessible on the open internet.
+
+### ๐ Note about Access Control
+
+As a brief aside, please note that Prose cannot expose any information from Discourse that Discourse is not already exposing on its own.
+
+If your Discourse instance requires authentication, then Prose will be unable to retrieve most queries unless the required authentication information is provided by the user accessing Prose.
+
+### ๐งฑ Alternative Deployment Strategies
+
+Initially, we wanted to provide instructions for an integrated deployment strategy. This would have involved deploying Prose on the same host as your Discourse instance, and ideally finding a way to deploy and expose it within the running Docker host that Discourse uses itself.
+
+This is still achieveable. But for now, we have opted to focus solely on deploying Prose as a dedicated instance.
+
+However, should you find yourself preferring a custom deployment of Prose, we would encourage you to do so.
+
+If you do, and you have some questions or challenges you're encountering, please reach out to us.
+
+Ideally we can help you sort things out and work your approach into our documentation so that everyone will benefit going forward.
+
+## Deploying as Dedicated Instance
+
+As mentioned above, the official deployment strategy for Prose is to host it as a dedicated instance.
+
+Like anything, this comes with both benefits and trade-offs, which we have outlined for you below.
+
+### ๐ Benefits
+
+A dedicated host for Prose will have better performance and reliability because its only resource usage comes from running Prose. i.e., it has exclusive usage of CPU, RAM, disk space, etc.
+
+If, on the other hand, you had managed to deploy Prose on the same host as your Discourse instance, this would mean that both Prose and Discourse need to share the host's allocated resources. If your Discourse instance is already running on a fairly light host, running Prose on it might mean that you would need to upgrade to a host with more resources.
+
+### โ ๏ธ Possible Trade-offs
+
+#### Increased Cost
+
+Naturally, if you're setting up a dedicated host to run Prose, then that involves additional costs on top of what you're already paying to host Discourse.
+
+Having said that, for most deployments, it is unlikely that you will need to allocate an expensive amount of resources to Prose.
+
+For example, on Digital Ocean, the $5 Shared CPU node is often sufficient.
+
+#### Potential for Increased Latency
+
+By nature, when deploying Prose on a different host from your running Discourse instance, the latency between the mobile app and Discourse increases.
+
+This is because each request has to make two hops:
+
+- The first request is from the client (your Lexicon-powered mobile app) to the Prose GraphQL API
+- The second request is from Prose to Discourse
+
+However, the only important questions regarding this point are:
+
+- How much measurable latency is there?
+- Is it noticeably slow to myself or my users?
+
+This, of course, can depend on several factors:
+
+- Where your Discourse server is deployed
+- Where your Prose server is deployed
+- Where your users tend to be
+- If the amount of traffic (load) is too much for the system to optimally run both Prose and Discourse.
+
+If you are observing noticeable latency, we would recommend looking into these factors.
+
+Ideally, you'll want to deploy Prose in the same region as your Discourse instance; and it is even better if you can deploy Prose in the same datacenter as your Discourse instance.
+
+## Up Next
+
+With this overview out of the way, we'll start by introducing you to the list of all possible [environment variables](env-prose) that may be necessary or useful when deploying Prose.
+
+Lastly, we'll get into the heart of it, by [preparing your host and deploying Prose](dedicated).
diff --git a/documentation/versioned_docs/version-1.0.0/discourse-features.md b/documentation/versioned_docs/version-1.0.0/discourse-features.md
new file mode 100644
index 00000000..3183014a
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/discourse-features.md
@@ -0,0 +1,52 @@
+---
+title: Discourse Features Support
+---
+
+Below is a table of Discourse features which provides the details and current status about the support for a given feature in the **Lexicon Mobile App**.
+
+If we missed one, or anything looks out of date here, don't hesitate to submit a Pull Request which updates the table.
+
+Is the feature you love not supported? [Reach out to us](mailto:support@kodefox.com) to discuss how we can bring it to life for you.
+
+#### Our General Approach to Feature Support
+
+Much of our initial focus was on using-facing features, rather than administrative features.
+
+This is why, for example, users can select categories for their topics, but administrators are unable to create new categories from within the mobile app.
+
+For this reason, most admin tasks are still best accomplished using the Discourse web app on a larger device.
+
+### Lexicon Mobile App Features
+
+| Feature | Description | Supported | Notes |
+| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------- |
+| 2FA Login | Allow users with 2FA enabled to be prompted for their 2FA code when logging in | โ
| Managing 2FA, such as enabling it or disabling it from within the app, is not currently supported |
+| Ability to Tag Topics | Create and tag topics to provide relevant metadata for your users | โ
๐ง | Configuration required: see [Optimal Experience](optimal#enable-topic-tagging) |
+| Topic Previews (Excerpts) | Show an excerpt of the first post in a topic from the Home screen | โ
๐ง | Configuration required: see [Optimal Experience](optimal#enable-topic-excerpts) |
+| View User Activity | View a user's recent activityโsuch as topics, posts, and likesโin a single feed from their profile | โ
| The ability to filter by activity is not currently supported |
+| Topic Metrics | Likes, Views, Replies, and Frequent Posters | โ
| |
+| Topic & Post Actions | Ability to like and edit topics and posts | โ
| |
+| View Top & Latest Topics | A Tab View at the top of the main feed provides the ability to switch between Latest and Top activity | โ
| |
+| Search | Search the current Discourse instance for topics and posts based on keywords, categories, and tags | โ
| |
+| Categories | View the category of a topic and filter topics by a given category | โ
| Categories cannot be created, updated, or deleted |
+| Attaching Media to Posts | Users can attach media to a post from the app | โ
๐ง | Configuration recommended for supported file extensions-see [Optimal Experience](optimal#configure-upload-extensions) |
+| Standard Markdown | Standard Markdown is supported in the editor and rendered correctly in the mobile app | โ
| Light, incomplete support exists for some of Discourse's custom markup, such as dates |
+| Sign Up | Allow users to sign up for an account directly through the mobile app, depending on whether your Discourse instance allows new user registration or not | โ
| |
+| Browsing Public Instances | Allow users to immediately access and browse your Discourse instance from the mobile app if it is not private | โ
| Users will be prompted to login upon attempting an authenticated action |
+| User Profiles | Ability to view users' profiles and edit your own | โ
| Partial support: displays the user's photo, username, Markdown bio on a single line, and recent activity |
+| Post Flagging | Allow users to flag posts for admins to review | โ
| Admins are not able to review posts in the app, though they will see in-app notifications for flags |
+| In-App Notifications | Allow users to see new notifications from the profile screen of the mobile app and mark all notifications as read | โ
| Some notifications from Discourse are not tappable in the mobile app, such as badge notifications |
+| Private messaging | Allow users to start private or group messages with one another | โ
| |
+| Mentions | Allow users to mention a user when creating or editing posts and messages | โ
|
+| Color Scheme | Provides light and dark mode support for users | โ
| Specify color scheme (light mode, dark mode, or system) from within the app (only local to the user's mobile device) |
+| Badges | The ability to see and interact with badges that have been awarded to users on the Discourse instance | โ | |
+| Post Drafts | Enable users to start composing a draft of a post and return to it later | โ | |
+| Groups | Enable users to create and participate in private groups of which only group members can view certain topics | โ | |
+| Admin Features | Discourse admin features generally not available in Lexiconโbetter suited to a desktop environment | โ | Editing posts is supported |
+| Post Quotes, Polls, Toggles, and Task Lists | Custom text formatting that enables Discourse-specific features | โ | |
+| Discourse Emojis | Utilize emojis when creating a topic, making a post, or sending a reply | โ | Unicode-based emojis are of course supported |
+| Post Bookmarks | Allow users to bookmark certain posts or topics | โ | |
+| DiscourseConnect (SSO) | Replace Discourse authentication with a Custom Provider | โ | |
+| Custom Authentication Plugins | Login via OAuth2 or other protocols using custom Discourse Plugins | โ | |
+| Real-time Chat | Enable users to initiate conversations using the chat feature, either in a channel or through private messaging | โ | |
+| User Status | Allow other user in community to see user message status | โ | |
diff --git a/documentation/versioned_docs/version-1.0.0/env-mobile.md b/documentation/versioned_docs/version-1.0.0/env-mobile.md
new file mode 100644
index 00000000..79af9933
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/env-mobile.md
@@ -0,0 +1,119 @@
+---
+title: Configuration Values
+---
+
+You can check and set the configuration values in `frontend/Config.ts`.
+
+The table below describes the configuration values for the Lexicon Mobile App.
+
+If there is a default value indicated, you do not need to set it.
+
+| Variable | Required | Notes | Default Value | Example Value(s) |
+| -------------------- | -------- | -------------------------------------------------------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
+| proseUrl | Yes | The url of the Prose Server (must start with http or https) | - | https://prose.myserver.com https://prose.myserver.com:8080 https://prose.myserver.com/subpath https://prose.myserver.com:8080/subpath |
+| inferDevelopmentHost | No | The flag (true / false) to override localhost with the host of the development machine | (empty) | true |
+
+## The `config` object
+
+In the `Config.ts` file, you'll find a `config` object that allows you to specify configuration values by scenario.
+
+The two primary scenarios are:
+
+- `localDevelopment`: when developing against the app locally. This configuration is also used as a fallback for an unknown build channel.
+- `buildChannels`: used to define configuration by build channel when building the app with the EAS CLI.
+
+Primarily, you'll only be concerned with configuring `proseUrl` for each of these sections.
+
+## `proseUrl`
+
+:::caution
+`proseUrl` must always be specified, with or without a port number, and must always start with either `http://` or `https://`.
+:::
+
+`proseUrl` is used to specify the URL of the Prose GraphQL API.
+
+The Prose GraphQL API acts a middleman between the Lexicon Mobile App and your Discourse instance. Without it, the mobile app cannot interact with your Discourse instance.
+
+### Example
+
+```ts
+const config = {
+ localDevelopment: {
+ proseUrl: 'http://localhost:8929',
+ },
+ buildChannels: {
+ preview: {
+ proseUrl: 'https://preview.myserver.com',
+ },
+ production: {
+ proseUrl: 'https://prose.myserver.com',
+ },
+ },
+};
+```
+
+With this configuration above, the app will:
+
+- point at `http://localhost:8929` when you run the app using `npm run start`
+- point at `https://preview.myserver.com` when you build the app using `eas build --profile preview`
+- point at `https://prose.myserver.com` when you build the app using `eas build`
+
+`proseUrl` also can include a subpath if desired:
+
+```ts
+const config = {
+ localDevelopment: {
+ proseUrl: 'http://localhost:8929',
+ },
+ buildChannels: {
+ preview: {
+ proseUrl: 'https://preview.myserver.com:8080/subpath',
+ },
+ production: {
+ proseUrl: 'https://myserver.com/api/prose',
+ },
+ },
+};
+```
+
+**Different Behavior in Development**
+
+When running the app locally, if `proseUrl` is set to `http://localhost` or `http://127.0.0.1`, it will replace `proseUrl` with the IP address of your development machine. It does this by using Expo's `debuggerHost` constant.
+
+_Note: this does not apply when building the app._
+
+This addresses multiple issues:
+
+- Accessing `localhost` from within the Android simulator does not map to your development machine
+- Accessing `localhost` from a device running Expo Go does not map to your development machine
+
+Both of these scenarios would otherwise require you to manually identify and specify your development machine's IP address with `proseUrl`. This is bothersome since your machine's IP address can change over time.
+
+If you are interested in more details about this, the implementation of this behavior is available in `frontend/constants/app.ts`.
+
+This behavior of automatically overriding those values can be disabled, with `inferDevelopmentHost`, which is covered below.
+
+## `inferDevelopmentHost`
+
+:::info
+This flag is only valid under `localDevelopment`. It has no effect when used as part of `buildChannels`.
+:::
+
+When in development, by default, the Lexicon Mobile App will check to see if `proseUrl` is set to either `http://localhost` or `http://127.0.0.1`.
+
+When detected, either of those values will be overwritten with the IP address of your development machine.
+
+This is a very useful feature that makes on-device testing simply work out of the box without needing to manually specify your IP address (or update it when it changes).
+
+For scenarios where this behavior is not desirable, `inferDevelopmentHost` can be used as a flag to disable this behavior. It can be disabled by specifying the value as `false`.
+
+When set to `false`, this behavior of overriding `proseUrl` with the development machine's IP address will no longer occur, and the original value will be passed through as-is.
+
+```ts
+const config = {
+ localDevelopment: {
+ proseUrl: 'http://localhost:8929',
+ inferDevelopmentHost: false,
+ },
+};
+```
diff --git a/documentation/versioned_docs/version-1.0.0/env-prose.md b/documentation/versioned_docs/version-1.0.0/env-prose.md
new file mode 100644
index 00000000..59901fd5
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/env-prose.md
@@ -0,0 +1,15 @@
+---
+title: Prose Environment Variables
+---
+
+The table below lays out environment variables for the Prose GraphQL API.
+
+If there is a default value indicated, you do not need to set it.
+
+| Environment Variable | Required | Notes | Default Value | Example Value |
+| --------------------------- | -------- | ----------------------------------------------------------------------------------- | ---------------------- | ------------------------------------ |
+| PROSE_DISCOURSE_HOST | Yes | The specific location of your Discourse instance. | - | https://discourse.example.com |
+| PROSE_DISCOURSE_UPLOAD_HOST | No | Instruct Prose to use a different host for file uploads to Discourse. | | https://upload.discourse.example.com |
+| PROSE_APP_HOSTNAME | No | The **application-level** hostname that Prose will listen on. | localhost | 0.0.0.0 |
+| PROSE_APP_PORT | No | The **application-level** port that Prose will listen on. | 80 | 8080 |
+| SKIP_CHECK_DISCOURSE | No | Bypass the startup process of checking the provided Discourse host for reachability | false | true |
diff --git a/documentation/versioned_docs/version-1.0.0/intro.md b/documentation/versioned_docs/version-1.0.0/intro.md
new file mode 100644
index 00000000..66a89182
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/intro.md
@@ -0,0 +1,148 @@
+---
+id: intro
+title: Introduction
+slug: /
+---
+
+
+ --- iOS Auth
+
+
+
+ --- iOS Dark Mode
+
+
+
+ --- iOS Comment
+
+
+
+ --- iOS Message
+
+ --- Android Auth
+
+
+
+ --- Android Dark Mode
+
+
+
+ --- Android Comment
+
+
+
+ --- Android Message
+
+
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+import Carousel from 'react-bootstrap/Carousel';
+
+---
+
+:::info
+Coming Soon!
+
+Lexicon v2.0.0 is currently in beta, and includes support for push notifications along with other features.
+
+See the [v2 documentation](../version-2.0.0-beta/intro.md) for more details.
+:::
+
+Lexicon is a customizable, pre-built mobile app that provides an elegant mobile discussions experience. Built on top of [Discourse](#what-is-discourse).
+
+## Features
+
+- Topics, Private Messaging, User Signups, Profile Management, and more.
+- Straightforward process to [**customize**](white-labeling) the app for your brand
+- Rapidly build Android and iPhone apps for your existing Discourse site
+- Backed by a [GraphQL](https://graphql.org/) API
+- Free and open source!
+- [Commercial support](commercial-support) available
+
+## Benefits
+
+- Launch a custom mobile discussions app
+- Increase engagement with your users by adding a mobile-first Discourse experienceโno more [WebViews](https://www.kirupa.com/apps/webview.htm).
+- Built with [React Native](https://reactnative.dev/) and [Expo](https://expo.io), delivering a native look-and-feel on both iOS and Android.
+- Includes an auto-documented [GraphQL](https://graphql.org/) [interface](concepts#prose-discourse-through-graphql) over the Discourse API, which you can build on top of.
+
+## Screenshots
+
+### iOS
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+### Android
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## How does Lexicon work?
+
+Lexicon delivers a native mobile Discourse experience with **two key components**:
+
+- The [**Lexicon Mobile App**](#the-lexicon-mobile-app) - a modern mobile app built with [Expo](https://expo.io) & [React Native](https://reactnative.dev/)
+- [**Prose**](#prose-discourse-through-graphql), our GraphQL API on top of the Discourse API
+
+### The Lexicon Mobile App
+
+The Lexicon Mobile App is built with [Expo](https://expo.io), which allows us to maintain both the iOS and Android apps with a single codebase.
+
+For those unfamiliar, Expo provides a superior development and deployment experience on top of [React Native](https://reactnative.dev/).
+
+### Prose: Discourse through GraphQL
+
+Prose is Lexicon's [GraphQL](https://graphql.org/) layer built on top of Discourse's API.
+
+This enables developers to quickly build apps on top of a live Discourse instance while leveraging the [benefits of GraphQL](https://www.apollographql.com/docs/intro/benefits/).
+
+### What is Discourse?
+
+Discourse is open-source **discussion software** that is thoughtfully designed, simple to setup, and well-maintained.
+
+You can learn more about it on the [Discourse website](https://www.discourse.org/).
+
+### Further Details
+
+You can learn about the technical details of our approach in [Concepts & Architecture](concepts).
+
+## License
+
+MIT. Copyright (c) [Lexicon](https://github.com/lexiconhq)
diff --git a/documentation/versioned_docs/version-1.0.0/lexicon-updates.md b/documentation/versioned_docs/version-1.0.0/lexicon-updates.md
new file mode 100644
index 00000000..43d95945
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/lexicon-updates.md
@@ -0,0 +1,17 @@
+---
+title: Receiving Updates from Lexicon
+---
+
+Due to the nature of this project, the best way to synchronize bugfixes, updates, and other changes to the Lexicon Mobile App is to treat your app like a fork of our repository.
+
+In the process of customizing the Lexicon Mobile App for your needs, you might make any number of changes to the theme or assets.
+
+However, the underlying codebase should beโfor the most partโuntouched.
+
+When we release a bugfix or new feature on the `master` branch, you'll be able to pull down our changes, resolve any conflicts with your changes, and have an updated version of your app ready to republish.
+
+It is worth acknowledging that this approach, which effectively uses Git to solve this problem in a fairly simple way, could be improved.
+
+Provided that there's enough interest, we might later decide to shape Lexicon into more of a standalone SDK package that you can import and receive updates to via npm.
+
+If you're interested in making that a reality, please reach out to us!
diff --git a/documentation/versioned_docs/version-1.0.0/optimal.md b/documentation/versioned_docs/version-1.0.0/optimal.md
new file mode 100644
index 00000000..a06199e7
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/optimal.md
@@ -0,0 +1,89 @@
+---
+title: 'Optimal Experience'
+---
+
+If you're planning to make use of the Lexicon Mobile App, there are a few settings you should tweak on your Discourse instance to provide the best in-app experience to your users.
+
+## Enable Topic Excerpts
+
+We have designed the Mobile App so that users can easily see the first few sentences of a topic as they scroll through the topics list.
+
+However, by default, Discourse does not return excerpts when listing topics.
+
+Fortunately, there is a secret setting that enables this.
+
+It just takes a bit of additional configuration to enable.
+
+While Discourse does enable opting into this behavior as part of a [Theme Component](https://meta.discourse.org/t/topic-list-excerpts-theme-component/151520), we wanted to guide you through the option of toggling the setting itself.
+
+Should you prefer to enable it using the above theme component, you're free to do so.
+
+Enabling this setting involves gaining access to the server and changing a setting.
+
+### Instructions
+
+The original instructions can be found [here](https://meta.discourse.org/t/discourse-as-a-simple-personal-blog-engine/138244/4).
+
+Once you've gained access to your server, enter into the running Discourse app.
+
+```sh
+$ /var/discourse/launcher enter app
+```
+
+Next, enter the Rails CLI:
+
+```sh
+$ rails c
+```
+
+Finally, set the setting to true:
+
+```sh
+$ SiteSetting.always_include_topic_excerpts = true
+```
+
+After that, you can exit, and excerpts should now be displaying in the app.
+
+## Enable Topic Tagging
+
+The Lexicon Mobile App was designed with the ability to tag topics in mind.
+
+This allows users to view and manage tags on topics, which is a popular feature on many Discourse servers.
+
+Unfortunately, this is not enabled by default.
+
+### Instructions
+
+In order to enable it, you can take the following steps:
+
+- Navigate to the Admin Site Settings page at `/admin/site_settings`
+- Use the search bar to search for the setting `tagging enabled`
+- Ensure that it is checked
+- If you made a change, click the green checkbox button to apply it
+
+Topics should now be taggable, and viewable in the app.
+
+## Configure Upload Extensions
+
+Discourse provides a security feature that allows Discourse admins to specify a whitelist of file extensions that their users can upload.
+For example, most admins would choose to restrict uploading of `.exe` files.
+In order to be compatible with the settings of your Discourse instance, the Lexicon Mobile App simply requests the list of allowed extensions and uses it to enforce allowed extensions in the app.
+Out of the box, most Discourse instances support this default list of extensions:
+
+- `.jpg`
+- `.jpeg`
+- `.png`
+- `.gif`
+- `.heic`
+- `.heif`
+
+If you'd like to adjust the list of extensions in your Discourse instance, you can do so by following the instructions below.
+
+### Adjusting Allowed Extensions in Discourse
+
+- Navigate to the Admin Site Settings page at `/admin/site_settings`
+- Use the search bar to search for the setting `extensions`
+- Find the setting labeled `authorized extensions`.
+- Adjust the list as you see fit to include the file extensions you'd like your users to be able to upload.
+- When you are done making changes, click the green checkbox to apply them.
+- The Lexicon Mobile App will receive the updated list of extensions from your site settings and begin enforcing it for your users.
diff --git a/documentation/versioned_docs/version-1.0.0/play-store.md b/documentation/versioned_docs/version-1.0.0/play-store.md
new file mode 100644
index 00000000..dacdfa8c
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/play-store.md
@@ -0,0 +1,162 @@
+---
+title: Publishing to the Play Store
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+## Prerequisites
+
+:::note
+If you don't already have a Google Developer account, note that there is a fee to create one.
+:::
+
+- A [Google Developer Account](https://play.google.com/console/signup) to access the [Google Play Console](https://play.google.com/console)
+- An Expo account
+- EAS CLI 2.6.0 or newer
+
+## Google Play Console
+
+The [Google Play Console](https://play.google.com/console) enables you to setup your app, invite beta testers, and publish your app to the [Google Play Store](https://play.google.com/store).
+
+Because you're publishing an app that was built using Expo, it is **very important** that you follow [Expo's instructions](https://github.com/expo/fyi/blob/master/first-android-submission.md) for submitting an app to the Google Play store correctly.
+
+## App Configuration
+
+After setting up your app in the Google Play Console, there are some other adjustments you'll need to make.
+
+### Build Config
+
+Similar to the approach for [Publishing to the App Store](app-store), if you havenโt already, you'll need to set your app name and slug in `frontend/app.json`. The [slug](https://docs.expo.dev/workflow/glossary-of-terms/#slug) is used as part of the URL for your app on Expo's web services, so it is recommended to use kebab-case (e.g., `my-lexicon-app`).
+
+Replace these placeholders with your desired values:
+
+```json
+ "name": "",
+ "slug": "",
+```
+
+Then, you need to configure EAS Build by running the following command, or skip to the next [step](play-store#setup-config-values):
+
+```bash
+eas build:configure
+```
+
+The EAS CLI will prompt you to specify `android.package` and `ios.bundleIdentifier` if those values are not already provided in `app.json`.
+
+Next, verify that the `package` name and other details specific to your app are included in the `android` section of `app.json`. Note that the `versionCode` will be automatically updated when you build the app with the `production` profile, so you don't need to increment the version manually.
+
+Also, there's one further detail that you might want to add, depending on your app's permissions.
+
+In the example below, we're providing our app with the ability to read and write to external storage.
+
+```json
+ "android": {
+ "package": "",
+ "permissions": [ "READ_EXTERNAL_STORAGE" , "WRITE_EXTERNAL_STORAGE" ]
+ "versionCode": 1,
+ },
+```
+
+If your app requires further permissions, be sure to specify them as needed in this part of the configuration.
+
+If you don't quite understand how permissions work yet, it's best to check out the [Expo documentation](https://docs.expo.io/versions/latest/sdk/permissions) on this topic in order to get a full understanding.
+
+### Setup Config Values
+
+:::info
+When publishing your app, it is necessary to deploy Prose somewhere publicly accessible, perhaps on a cloud hosting provider like AWS or DigitalOcean. If Prose is only running on your local machine, users that download your app won't be able to use it.
+Check [the documentation](deployment) to deploy Prose if you haven't already.
+:::
+
+Next, set the **Prose URL** for your builds in `Config.ts`. You can set a different URL for each build channel.
+
+:::note
+In the original release of Lexicon, the **Prose URL** was specified in `frontend/.env`. However, as part of migrating to Expo's EAS feature, we centralized the configuration into `frontend/Config.ts` to save you the trouble of needing to maintain it in more than one place, as suggested in the [Expo documentation](https://docs.expo.dev/build-reference/variables/#can-i-share-environment-variables-defined-in-easjson-with-expo-start-and-eas-update)
+:::
+
+```ts
+const config = {
+ // ...
+ buildChannels: {
+ preview: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ production: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ },
+};
+```
+
+### Add the Play Store Secret File
+
+For the last step, you'll need to provide a `.json` file containing a private key in order to interact with the Play Store. Follow [this guide](https://github.com/expo/fyi/blob/main/creating-google-service-account.md) to generate one. Then, copy the JSON file to your `lexicon/frontend` directory, and rename the file as `playstore_secret.json`.
+
+The JSON file looks like this:
+
+```json
+{
+ "type": "service_account",
+ "project_id": "",
+ "private_key_id": "",
+ "private_key": "-----BEGIN PRIVATE KEY----------END PRIVATE KEY-----\n",
+ "client_email": "",
+ "client_id": "",
+ "auth_uri": "",
+ "token_uri": "",
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
+ "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/lexicon%40api.iam.gserviceaccount.com"
+}
+```
+
+## Build your App for Android
+
+Because we're working with Expo and React Native, this step isn't too different from building your app for iOS.
+
+From the `frontend/` directory, you can run this command to check the app before publishing:
+
+```bash
+eas build --platform android --profile preview
+```
+
+Running `eas build` with the `preview` profile will build the app as an APK. This allows you to quickly load it onto your Android device or emulator. After the build is done, navigate to your project in the [Expo web console](https://expo.dev), then click on the **Builds** menu located on the left-hand side of the screen.
+
+- Click on the project you want to install.
+
+
+
+- Download the app by pressing the `Install` button in the `Build Artifact` section.
+
+
+
+You can download and launch the app on your real device, or drag the downloaded APK file to your emulator.
+
+Once you have verified that the app runs as expected, you can proceed to build it for release:
+
+```bash
+eas build --platform android --profile production
+```
+
+The approach for a production build is similar to the one used for generating a preview build. However, unlike a preview build, you won't be able to launch the production build in Android emulatorโit is intended solely for publishing to the Play Store.
+
+Once this process is completed, you can proceed with submitting it to the Play Store.
+
+## Publish to the Play Store
+
+At this point, you can take your app live on the Google Play Store, or you can proceed with internal testing on the Google Play Console.
+
+To proceed with internal testing, run this command:
+
+```bash
+eas submit --platform android --profile staging
+```
+
+To release your app publicly, run this command:
+
+```bash
+eas submit --platform android --profile production
+```
+
+You can read more about build profiles [here](tutorial/publishing).
+
+At this point, provided that you've completed all the steps, congratulations! Your Lexicon-powered mobile app is now live and ready to be downloaded by your users.
diff --git a/documentation/versioned_docs/version-1.0.0/publish-app.md b/documentation/versioned_docs/version-1.0.0/publish-app.md
new file mode 100644
index 00000000..267f3e1a
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/publish-app.md
@@ -0,0 +1,11 @@
+---
+title: Publishing your App
+---
+
+:::danger Progress
+This page has not been started yet or needs a lot more work.
+:::
+
+Expo workflow, benefits of, etc.
+
+Over the air updates?
diff --git a/documentation/versioned_docs/version-1.0.0/quick-start.md b/documentation/versioned_docs/version-1.0.0/quick-start.md
new file mode 100644
index 00000000..c72f310c
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/quick-start.md
@@ -0,0 +1,66 @@
+---
+title: Quick Start
+---
+
+## Prerequisites
+
+- Node.js 16.14 or newer
+- The latest version of NPM or Yarn, compatible with Node 16.14 or newer
+- Expo CLI 6.0.6 or newer
+- EAS CLI 2.6.0 or newer to build and publish the App
+- An active Discourse site
+ - If you donโt have one, please follow the instructions in [Development Setup](setup#discourse-host)
+
+:::note
+Follow the instructions in [Setup Guidance](tutorial/setup) to install the prerequisite depedencies, such as NPM, the Expo CLI, and the EAS CLI.
+:::
+
+## Installation
+
+Clone the repository and navigate into it:
+
+```
+git clone git@github.com:lexiconhq/lexicon.git
+cd lexicon
+```
+
+Next, install the project's dependencies and generate its GraphQL schema:
+
+```
+$ npm install && npm run generate
+```
+
+Note that `npm run generate` involves two steps.
+
+- First, it will generate a [GraphQL schema](https://nexusjs.org/docs/guides/schema) in the `api` directory.
+
+- Then, using the generated schema, it will create a new folder called `generated` in the `frontend` directory, containing the resulting query and mutation types.
+
+- This allows the frontend codebase to stay in sync with, and not duplicate the code for, the types from the `api` directory.
+
+The code shared from the API is then used by [Apollo](https://github.com/apollographql/apollo-tooling), the GraphQL library we use on the frontend, which enables the Mobile App to query the API correctly.
+
+## Launch the Mobile App
+
+You can run the app and test it out by running this command from the project root:
+
+```
+$ npm run quickstart
+```
+
+This will simultaneously launch two processes:
+
+- The Prose GraphQL API Server
+- The local Expo dev server, which will enable you to launch the React Native app from your device
+
+**Please note that this takes some configuration to setup properly**.
+
+- The `quickstart` command configures the Mobile App and the Prose GraphQL API to point at https://meta.discourse.org, as an example.
+
+- You'll need to make adjustments to point at a site of your choice.
+
+- The Lexicon Mobile App (via Expo) must be configured to point at the Prose GraphQL Server
+
+- The Prose GraphQL Server must be configured to point at an active Discourse instance
+
+More details are available in the [Development Setup](setup) section
diff --git a/documentation/versioned_docs/version-1.0.0/rationale.md b/documentation/versioned_docs/version-1.0.0/rationale.md
new file mode 100644
index 00000000..bfb62fa4
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/rationale.md
@@ -0,0 +1,73 @@
+---
+title: Background & Motivation
+---
+
+### Discourse's Approach to a Mobile Experience
+
+Discourse is a phenomenal, battle-tested piece of software that facilitates thoughtful discussions in countless communities around the globe. It's no secret that we are big fans of it.
+
+The Discourse core team's strategy for mobile devices was to implement their product as a responsive website, and optimize for mobile use cases. This allowed mobile users to simply go to the same Discourse site as they would have on devices with larger screensโ enabling them to view and write posts from their mobile devices.
+
+However, over time, interest in a dedicated Discourse mobile app grew. The core team addressed this need by building a native mobile app. They chose to reuse their existing work by having the app simply wrap a webview containing the mobile site.
+
+This was a nice improvement, as it allowed the mobile app to integrate with native SDKs and provide some additional features to Discourse mobile users.
+
+Overall, their approach to solving this problem was both efficient and well-done.
+
+However, it is still evident to many users that they're interacting with an embedded web browser, and it's clear that it's not a mobile-_first_ experience.
+
+For many users and site-owners, what the Discourse team has provided is more than enough, and it solves all of their problems.
+
+In our case, we were looking for a very specific type of experience.
+
+### Who We Are
+
+The Lexicon Team is part of [KodeFox](https://www.kodefox.com/), a software studio comprised of passionate software engineers, designers, and product managers who regularly build world-class software for our customers.
+
+Interested in custom software development with a personal touch? Drop us a line at [hello@kodefox.com](mailto:hello@kodefox.com).
+
+### Enter Lexicon
+
+Lexicon was formed out of the desire to further leverage many of the great features that the Discourse team had worked hard to build.
+
+In our consulting projects, we found that many of our clients were regularly asking for solutions that Discourse already provides out of the box.
+
+However, our clients wanted a seamless, native mobile experience, tailored to the brand that their users were already familiar with.
+
+After digging into the Discourse API documentation, we felt that it was worthy investment to build a mobile-first Discourse experience which also faciliated customizability.
+
+We were already fluent with the elegant development process provided by React Native and Expo, so it was a natural fit for us to build the mobile app with these technologies.
+
+This allowed us to achieve a high ratio of code reuse across iOS and Android, making feature implementations and bug fixes a much simpler process in most cases.
+
+In integrating with Discourse's API, we also noticed that the API documentation contains a disclaimer which encourages reverse-engineering to understand it.
+
+While we can appreciate the sentiment of figuring things out yourself, we wanted to provide an API experience that makes it easy for developers to dig into interactive documentation and quickly grasp the concepts.
+
+For this reason, we also chose to build Prose, our GraphQL API layer on top of the Discourse RESTful API. Another motivating factor was our existing fluency with GraphQL.
+
+This allowed us to quickly implement the mobile app with an intuitive API paradigm that we were already very familiar with.
+
+#### How Lexicon can help you
+
+If you already run an existing Discourse site and want a native mobile experience for your users, you can very quickly point Lexicon at your site and browse it in real-time from your device.
+
+Check out the [Quick Start](quick-start) page to see a rapid example of spinning up a mobile app for Discourse's own [Meta site](https://meta.discourse.org).
+
+But beyond that, Lexicon is an open source pre-built mobile app. This means that you can customize it to fit your brand.
+
+You can think of it like a template that you can use to build your own mobile app for your community.
+
+If you're interested in customizing the Lexicon Mobile app, you can learn more about that in the [White Labeling](white-labeling) section.
+
+And when you're finished, you can publish it to the Apple App Store or Google Play Store, which we cover in [Publishing your App](app-store).
+
+### FOSS Mindset
+
+Finally, while this project will benefit us and our clients in the future, we also wanted it to be a gift to the community.
+
+We recognize and support the culture of free and open-source software. That's why we're delighted to give back to the community in this way, just as the Discourse team originally did when they chose to open-source their hard work.
+
+So please engage with us on Github, and don't be shy about opening a new issue or even a PR.
+
+We look forward to working with you!
diff --git a/documentation/versioned_docs/version-1.0.0/setup.md b/documentation/versioned_docs/version-1.0.0/setup.md
new file mode 100644
index 00000000..7ef46648
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/setup.md
@@ -0,0 +1,362 @@
+---
+title: Development Setup
+---
+
+### Clone the Lexicon Repository
+
+If you haven't already, make sure you [clone the Lexicon repository](quick-start#installation) from Github.
+
+### Setup a Discourse Instance, if necessary
+
+In order to get started developing against the Lexicon Stack, you'll need a running Discourse instance.
+
+To recap, the Lexicon Stack consists of:
+
+- The Lexicon Mobile App
+- The Lexicon Prose GraphQL API
+- A running Discourse instance
+
+Without a Discourse instance, the Prose GraphQL API has nowhere to retrieve data from. And when the Prose GraphQL API can't retrieve any data, the Lexicon Mobile App won't be able to receive anything either.
+
+For detailed instructions on setting up a local development instance of Discourse, head over to the [tutorial](./tutorial/setup-discourse), which will walk you through the process.
+
+However, if you already have a deployed instance of Discourse, we'd recommend using that instead.
+
+### Configuration
+
+The [Lexicon Stack](concepts#architecture-of-the-lexicon-stack) requires some configuration in order to properly interact with your Discourse server.
+
+This involves configuring both the backend GraphQL API, which interacts with your Discourse instance; as well as the frontend Mobile App, which interacts with the GraphQL API.
+
+The architecture of this setup is depicted in [Architecture of the Lexicon Stack](concepts#architecture-of-the-lexicon-stack).
+
+#### Backend GraphQL API Configuration
+
+The [Prose GraphQL API](concepts#prose-discourse-through-graphql) is fairly simple in terms of configuration. In the simplest case, it only needs to know where your Discourse instance is accessible at.
+
+It receives its configuration via a [`.env` file](https://www.codementor.io/@parthibakumarmurugesan/what-is-env-how-to-set-up-and-run-a-env-file-in-node-1pnyxw9yxj) in the root of the `api/` directory.
+
+Here is the simplest configuration of the `api/.env` file:
+
+```
+PROSE_DISCOURSE_HOST=https://meta.discourse.org
+```
+
+It is also worth noting that you can optionally configure the **Hostname** and **Port Number** that the Prose API server listens on, both of which default to **localhost** and **port 80**, respectively.
+
+```
+PROSE_DISCOURSE_HOST=https://meta.discourse.org
+
+# Instruct Prose to broadcast publicly instead of on localhost
+PROSE_APP_HOSTNAME=0.0.0.0
+
+# Instruct Prose to listen on port 8929 instead of the default port 80
+PROSE_APP_PORT=8929
+```
+
+For a comprehensive list of all environment variables that can be used to configure Prose, check out [Prose Environment Variables](env-prose).
+
+#### Frontend Mobile App Configuration
+
+:::note
+In the original release of Lexicon, the **Prose URL** was specified in `frontend/.env`. However, as part of migrating to Expo's EAS feature, we centralized the configuration into `frontend/Config.ts` to save you the trouble of needing to maintain it in more than one place, as suggested in the [Expo documentation](https://docs.expo.dev/build-reference/variables/#can-i-share-environment-variables-defined-in-easjson-with-expo-start-and-eas-update)
+:::
+
+To configure the frontend mobile app, you'll first need to set your app name and slug in `frontend/app.json`. The [slug](https://docs.expo.dev/workflow/glossary-of-terms/#slug) is used as part of the URL for your app on Expo's web services, so it is recommended to use kebab-case (e.g., `my-lexicon-app`).
+
+Replace these placeholders with your desired values:
+
+```json
+ "name": "",
+ "slug": "",
+```
+
+Next, change the value of `proseUrl` in `frontend/Config.ts` to the URL of your Prose GraphQL APIโwhether local or already deployed somewhere.
+
+```ts
+const config = {
+ localDevelopment: {
+ proseUrl: 'http://localhost:8929',
+ },
+ buildChannels: {
+ preview: {
+ proseUrl: 'https://preview.myserver.com:8080/subpath',
+ },
+ production: {
+ proseUrl: 'https://myserver.com/api/prose',
+ },
+ },
+};
+```
+
+`localDevelopment.proseUrl` will be used during development when you run the app using `npm run start` or `expo start`, whereas the specific value within `buildChannels` (e.g., `production.proseUrl`) will be used when actually building the app.
+
+#### Development Scenarios
+
+When developing locally, there are at least three scenarios that you may find yourself in.
+
+Depending on which one applies to you, the config values across `frontend/Config.ts` and `api/.env` may need to be set differently.
+
+##### Scenario 1: Existing Prose Deployment
+
+If you've already deployed the Prose GraphQL API to a host that is publicly reachable, you will have already setup `api/.env` with the proper values.
+
+In that case, `frontend/Config.ts` only needs updated to point at the deployed GraphQL API.
+
+For example:
+
+```ts
+const config = {
+ localDevelopment: {
+ proseUrl: 'https://my-deployed-graphql.api',
+ },
+ buildChannels: {
+ preview: {
+ proseUrl: 'https://my-deployed-graphql.api',
+ },
+ production: {
+ proseUrl: 'https://my-deployed-graphql.api',
+ },
+ },
+};
+```
+
+In the example above, we have configured the app to point at `https://my-deployed-graphql.api` in all scenarios, including during development when running with `npm run start`.
+
+##### Scenario 2: Run Prose Locally & Access from a Simulator
+
+This approach involves running both the Lexicon Mobile App and the Prose GraphQL API on your development machine. It is accomplished by instructing Expo to launch the Mobile App in the Android or iOS simulator.
+
+When developing this way, you can simply set `localDevelopment.proseUrl` to `http://localhost` in `frontend/Config.ts`. And then in `api/.env`, you can set `PROSE_APP_HOSTNAME` to `0.0.0.0`.
+
+Note that if you want to run Prose locally on a specific port, you would need to make sure that the configuration in both `api/.env` and `frontend/Config.ts` reflect that correctly.
+
+:::caution
+If you configure `PROSE_APP_HOSTNAME` in `api/.env` to only listen on `localhost` or `127.0.0.1` (rather than `0.0.0.0`), it prevents others on the same network as your development machine from accessing it. This includes both your mobile device and the Android simulator, which can lead to connectivity issues when developing locally.
+:::
+
+##### Scenario 3: Run Prose Locally & Access from your Mobile Device
+
+It can be very useful to develop and debug against the app using your actual mobile device with the [Expo Go app](https://expo.dev/client).
+
+In order to do this, you'll need to have your development machine reachable from your mobile device.
+
+A simple way to make it reachable is to ensure that your mobile device and development machine are on the same network, and then, in `api/.env`, set `PROSE_APP_HOSTNAME` to `0.0.0.0`.
+
+In a regular Expo project, you would be required to update the `localDevelopment.proseUrl` value in `frontend/Config.ts` to contain the hardcoded IP address of your development machine on your network.
+
+However, by setting the value to `http://localhost`, we handle this **automatically** by default, so you don't have to worry about it. Read more about it [here](env-mobile#infer_development_host).
+
+###### Hardcoding your local IP Address
+
+:::info
+This approach is not ideal. If your local IP address ever changes, you'll need to locate it again, and update `Config.ts` to reflect that. For this reason, it's preferable to just use `http://localhost`.
+:::
+
+To manually instruct the Mobile App how to locate your development machine, you'll need to find out what the **local IP address** of your development machine is on your current network.
+
+Note that your local IP address is different from your public IP Address.
+
+If you are not sure how to get your local IP address, you can go to [What Is My Browser: Detect Local IP Address](https://www.whatismybrowser.com/detect/what-is-my-local-ip-address) and follow the instructions.
+
+The website itself may not be able to automatically detect your local IP address, but it will give you instructions on how to locate it within your specific operating system.
+
+You will be given an IP address like `10.0.12.121` or `192.168.17.69`.
+
+You can then update the value in `frontend/Config.ts` to your local IP address.
+
+This will allow the app running on your mobile device to properly locate the GraphQL API running on your development machine.
+
+## Configure your Discourse Host
+
+As mentioned above, you'll need to have setup a Discourse host for the GraphQL API to interact with.
+
+We'd like to briefly cover the different approaches to setting up a Discourse Host for development before continuing.
+
+**1. Run a Discourse Instance Locally**
+
+:::note
+Ensure that you are managing all of your ports correctly.
+
+The development setup of Discourse with Docker makes use of multiple ports, one of which being **port 3000** by default. You'll want to double-check that none of the environment variables are pointing at the ports Discourse is using.
+:::
+
+If you'd like to run a Discourse site for development locally, the recommended way to do this to use **[Docker](https://www.docker.com/)**, so make sure you have it installed.
+
+Then, as we mentioned above, you can follow [these steps in the tutorial](tutorial/setup-discourse) to install and run a development instance of Discourse in Docker.
+
+**2. Use try.discourse.org or another popular Discourse site**
+:::info
+Feel free to use existing public Discourse sitesโsuch as the [Docker Community Forum](https://forums.docker.com/) or the [Rust Programming Language Forum](https://users.rust-lang.org/)โin order to test out the Lexicon Mobile App.
+
+Just be mindful of how you're contributing to those sites if you do.
+:::
+
+[Try Discourse](https://try.discourse.org/) is a publicly accessible Discourse instance which is intended for testing. As such, it resets every day.
+
+The only drawback of this approach is that you can only register as a normal user, and therefore cannot modify the site's admin settings.
+
+With this approach, you'd simply configure Prose in `api/.env` to point `PROSE_DISCOURSE_HOST` at one of these instances.
+
+```bash
+PROSE_DISCOURSE_HOST=https://try.discourse.org
+```
+
+## Working with the Codebase
+
+Now that you've prepared everything for development, you can start digging in on the Lexicon codebase.
+
+### Run the Lexicon Mobile App & Prose GraphQL Server
+
+You can run the Mobile App and test it out with a local Prose server by running this command **from the project root**:
+
+```
+$ npm run dev
+```
+
+This will simultaneously launch two processes:
+
+- The GraphQL API Server
+- The local Expo dev server, which will enable you to launch the React Native app from your device
+
+However, if you wish to run the frontend and backend seperately, execute the following command in a terminal to run the frontend
+
+```
+$ npm run --prefix frontend start
+```
+
+Then execute the following line in another terminal to run the backend
+
+```
+$ npm run --prefix api dev
+```
+
+### Debugging
+
+- Use [Expo Developer Menu](https://docs.expo.io/workflow/debugging/#developer-menu) to make the debugging process easier.
+
+Opening the Expo Developer Menu depends on your device:
+
+- On an iOS Device: Shake the device, or touch 3 fingers to the screen.
+- On the iOS Simulator: Hit `โ + ctrl + Z` on a Mac in the emulator.
+- On an Android Device: Shake the device vertically, or run `adb shell input keyevent 82` in the terminal window if the device is connected via USB.
+- On the Android Emulator: Hit `โ + M`, or run `adb shell input keyevent 82` in your terminal window.
+
+- If your changes don't show up, it could involve a cache issue. In this case, you should try restarting Expo.
+ - To do so, quit the process by hitting `Ctrl + C` in the Terminal where it is running.
+ - Then run `npm run start` again.
+ - If the issue persists, you should look for the latest guidance from Expo on how to clear the cache, as it has been known to change.
+
+### Running the Test Suites
+
+Before running tests, double-check that your changes don't contain any errors.
+
+You can run tests across both the frontend and backend codebases sequentially by running the following command from the project root:
+
+```
+$ npm run test
+```
+
+On top of ensuring that all tests have passed, the command will also notify you if there are any Typescript errors or issues from Prettier or ESLint.
+
+Also note that the process of running `npm run test` triggers an additional action in the frontend to take place before running the tests.
+
+A new folder, `frontend/generated`, is created and populated with all the GraphQL Query and Mutation types for use in the codebase.
+
+If we did not run this before the tests, they would fail due to type errors.
+
+### Build & Publish the Lexicon Mobile App
+
+:::note
+An Expo account is required in order to use Expo's services. You can create one here: https://expo.io/signup.
+Once you have created your Expo account, please ensure that you are signed in with your current shell session, via `expo login` or `eas login`.
+:::
+
+You are required to configure EAS build first by running:
+
+```bash
+eas build:configure
+```
+
+You will then get a prompt from the EAS CLI related to the EAS project IDs: `android.package` and `ios.bundleIdentifier`. EAS will provide you with an existing project ID if you have one or ask you to create a new one. As for `android.package` and `ios.bundleIdentifier`, you can specify those values with `com.companyname.appname`, or any other patterns you might prefer.
+
+Once you're done, verify the `proseUrl` value you will use for the actual build of the app in `Config.ts`.
+
+:::info
+When publishing your app, it is necessary to deploy Prose somewhere publicly accessible, perhaps on a cloud hosting provider like AWS or DigitalOcean. If Prose is only running on your local machine, users that download your app won't be able to use it.
+Check [the documentation](deployment) to deploy Prose if you haven't already.
+:::
+
+Now you can build the Mobile App via Expo (EAS) with the preview build profile by running command below:
+
+```bash
+eas build โplatform all โprofile preview
+```
+
+When you do this, the packager will minify all your code and generate two versions of your codeโone for iOS, and one for Androidโand then upload them both to the Expo CDN.
+
+Additionally, if you haven't yet optimized the app's assets, Expo will ask you if you'd like to do so.
+
+This has the same effect as manually running `npx expo-optimize` beforehand. It simply compresses all of the image assets in your project to reduce the size of your build.
+
+When the process is complete, you'll be presented with a shareable QR Code and a URL resembling https://exp.host/@ccheever/an-example, which directs you to the build details in Expo's web console.
+
+At this point, anyone can then use that link to load your project.
+
+For Android, you can install the app on an emulator or on your physical device. However, for iOS, you can only install it on the iOS simulator. To run the app on a real iOS device, follow the steps in [this part](tutorial/building#1-preview) of the tutorial.
+
+When building your app, it is recommended to build it as a preview build first, and make sure everything runs well before building it for release with the production profile.
+
+To build the app with the production build profile, run this command:
+
+```bash
+eas build โplatform all โprofile production
+```
+
+You will also be presented with links directing you to the build details in Expo.
+
+However, unlike the preview build, the release build cannot be installed directly on your physical device or in an emulator / simulator. You'll need to publish the app and then install it from either the Play Store or App Store.
+
+You can read a more detailed explanation of this process in [this section](tutorial/building) of the tutorial.
+
+#### Updates
+
+If you later want to deploy an update to your version of the Lexicon Mobile App, you can use the EAS update command.
+
+First, make sure to configure EAS update by running the following command:
+
+```bash
+eas update:configure
+```
+
+This command will automatically add the `expo.runtimeVersion` field to your `app.json` file.
+You'll see a warning in your terminal telling you to add `expo.updates.url` to `app.json`.
+
+Then run this command to update your project:
+
+```bash
+eas update -โbranch
+```
+
+:::note
+The channel name is the same as the build profile, so for the preview builds, you can run:
+
+```bash
+eas update -โbranch preview
+```
+
+:::
+
+Read more about updating your app [here](tutorial/updating).
+
+Once published, the new version will be available to your users the next time they open it.
+
+For more details on this processโincluding publishing to the App Store and Google Play Storeโfollow the instructions in [Publishing your App](tutorial/publishing).
+
+#### Configure the GraphQL API with your Discourse Server
+
+In order for a published version of the app to be able to contact your Discourse server, you'll need to ensure that:
+
+- The GraphQL API is deployed and running properly on a host that is reachable from the app itself.
+- The GraphQL API is configured to point at the correct host and port of your Discourse server
+- Your Discourse server is reachable by the GraphQL API
diff --git a/documentation/versioned_docs/version-1.0.0/supported-devices.md b/documentation/versioned_docs/version-1.0.0/supported-devices.md
new file mode 100644
index 00000000..148acbb7
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/supported-devices.md
@@ -0,0 +1,29 @@
+---
+title: Supported Devices
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+## iPhone and Android Phones
+
+Once you've published to the App Store and Google Play Store, your published app will work out of the box for your users on both iPhone and Android devices with the following specifications:
+
+| Device | Minimum OS |
+| --------------- | ------------------- |
+| iPhone | iOS 6 and above |
+| Android Devices | Android 5 and above |
+
+| Android | iOS |
+| -------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
+| | |
+| | |
+| | |
+| | |
+
+## Support for Other Devices
+
+At this time, **tablets - including iPads** - and other mobile devices are **not supported**.
+
+We may consider developing support for this in the future.
+
+If this is critical for you, please drop us a line at support@kodefox.io and let us know.
diff --git a/documentation/versioned_docs/version-1.0.0/technologies.md b/documentation/versioned_docs/version-1.0.0/technologies.md
new file mode 100644
index 00000000..c4180c4f
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/technologies.md
@@ -0,0 +1,23 @@
+---
+title: Technologies
+---
+
+### 100% React Native and TypeScript built on Expo
+
+Lexicon was built, and is maintained, with a single code baseโmeaning that bug fixes, improvements, and new features will (in most cases) automatically apply to both iOS and Android.
+
+### GraphQL-based API
+
+Developers who wish to contribute to (or fork) Lexicon can do so with all the benefits of GraphQL. For more information, check out [Concepts and Architecture](concepts#prose-discourse-through-graphql).
+
+### White Labeling Support
+
+White Label the Lexicon Mobile App to give your users the familiar look and feel of your brand. Learn more in [White Labeling](white-labeling).
+
+### Painless integration with existing Discourse instances
+
+Getting started is as easy as spinning up a new server for the Prose GraphQL API, and pointing it at your Discourse instance. No changes are required on your Discourse instance itself.
+
+However, to provide an [optimal experience](optimal) with features like Tagging and Topic Excerpts, you will need to make some light adjustments.
+
+This is covered in detail in [Deploying Prose](deployment).
diff --git a/documentation/versioned_docs/version-1.0.0/theming.md b/documentation/versioned_docs/version-1.0.0/theming.md
new file mode 100644
index 00000000..04dbc172
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/theming.md
@@ -0,0 +1,247 @@
+---
+title: Theming
+---
+
+:::note
+This section will involve reading and modifying Typescript. If you get stuck, reach out to us.
+:::
+
+Lexicon allows you to customize the default theme that the Mobile App provides.
+
+You can accomplish this by modifying the values in `frontend/src/constants/theme`, or in `frontend/src/theme`.
+
+There is a difference between the two, and they work in conjunction with one another.
+
+`frontend/src/constants/theme` defines the underlying base values of the theme.
+
+`frontend/src/theme` then imports those values, and uses them to compose the actual theme object used throughout the rest of the Mobile App.
+
+## Colors
+
+### Adjusting Base & Functional Colors
+
+There are 2 types of colors in the Mobile App: base colors and functional colors.
+
+Base colors are the underlying palette of the theme, whereas functional colors define specific use-cases of the base colors.
+
+For example, you might have noticed that the Mobile App features a nice, eye-catching Royal Blue color as its primary color.
+
+This is defined in the base colors as:
+
+```ts
+// ...
+royalBlue: '#2B6AFF',
+// ...
+```
+
+Then, the functional colors make use of this for particular components in the app.
+
+To continue with the example, the `royalBlue` base color is referenced in the functional colors as:
+
+```ts
+// ...
+activeTab: BASE_COLORS.royalBlue,
+// ...
+primary: BASE_COLORS.royalBlue,
+// ...
+```
+
+Now, any component can reference the functional colors' `primary` value, and it will be `royalBlue`.
+
+However, if you wanted a different theme with a new color, such as, `BASE_COLORS.lightningYellow`, then you could adjust it to:
+
+```ts
+// ...
+activeTab: BASE_COLORS.lightningYellow,
+// ...
+primary: BASE_COLORS.lightningYellow,
+// ...
+```
+
+And the Mobile App would replace the Royal Blue with the value you've defined for Lightning Yellow.
+
+For this reason, if you want to add more colors, you'll need to add base color values first, and then access them within the functional colors.
+
+This approach keeps a clean separation of concerns, which allows theme changes to seamlessly propagate throughout the Mobile App.
+
+### Color Scheme (Dark Mode and Light Mode)
+
+The theme allows you to control how the user can adjust the app's color scheme, if at all.
+
+There are three choices for this: `dark`, `light`, `no-preference`.
+
+- Dark: force the color scheme to remain dark
+- Light: force the color scheme to remain light
+- No Preference (default): allow your users to specify a preference for color scheme
+
+Note that if you specify `dark` or `light`, your users **will not** have the option of selecting a preference for color scheme.
+
+This manifests in the Mobile App by hiding the Dark Mode button which normally appears in the Preferences Scene.
+
+## Fonts
+
+The theme's fonts are declared in `frontend/src/constants/theme/fonts`.
+
+Inside of that file, you'll find multiple aspects of the fonts that can be adjusted:
+
+- Font Variants
+- Font Sizes
+- Heading Font Sizes
+
+### Font Variants
+
+Used to classify multiple font weights into named variants. It supports the following values:
+
+| Variants | Default font weight |
+| -------- | ------------------- |
+| bold | 700 |
+| semiBold | 600 |
+| normal | 400 |
+
+### Font Sizes
+
+Used to set a font size scale that is consistent throughout the app. It supports the following values:
+
+| Variants | Default size |
+| ---------------- | ------------ |
+| xl (extra large) | 24 |
+| l (large) | 18 |
+| m (medium) | 16 |
+| s (small) | 14 |
+| xs (extra small) | 12 |
+
+### Heading Font Sizes
+
+Used to classify multiple font sizes for heading elements, such as `h1`, `h2`, etc.
+
+These values are primarily used for rendering the content of posts and messages from Discourse.
+
+This is because Discourse posts are written in Markdown, and users will often leverage heading elements to format their posts.
+
+| Variants | Default size |
+| -------------- | ------------ |
+| h1 (Heading 1) | 32 |
+| h2 (Heading 2) | 24 |
+| h3 (Heading 3) | 22 |
+| h4 (Heading 4) | 20 |
+| h5 (Heading 5) | 18 |
+| h6 (Heading 6) | 17 |
+
+## Icons
+
+The `icons` theme file is used to store icon-related constants.
+
+Currently, the โiconsโ file only contains a constant which declares the icon sizes scale.
+
+| Variants | Default size |
+| ---------------- | ------------ |
+| xl (extra large) | 28 |
+| l (large) | 24 |
+| m (medium) | 20 |
+| s (small) | 18 |
+| xs (extra small) | 16 |
+
+## Images
+
+The `images` theme file is used to store theme constants used in rendering images.
+
+Currently, this file declares the following theme values:
+
+- Avatar Icon Size
+- Avatar Letter Size
+- Avatar Image Size
+
+Avatars are used throughout the app to display relevant info about a post or message.
+
+As such, it is typically the user's photo.
+
+However, when a photo is not provided, we also compose a letter-based avatar based on the user's initials.
+
+### Avatar Icon Size
+
+| Variants | Default size |
+| ---------------- | ------------ |
+| l (large) | 96 |
+| m (medium) | 52 |
+| s (small) | 40 |
+| xs (extra small) | 28 |
+
+### Avatar Letter Size
+
+| Variants | Default size |
+| ---------------- | ------------ |
+| l (large) | 72 |
+| m (medium) | 36 |
+| s (small) | 28 |
+| xs (extra small) | 16 |
+
+### Avatar Image Size
+
+This defines the quality of the image used for avatars.
+
+| Variants | Default size |
+| ---------------- | ------------ |
+| xl (extra large) | 450 |
+| l (large) | 150 |
+| m (medium) | 100 |
+| s (small) | 50 |
+
+## Spacing
+
+The `spacing` theme file defines spacing constants used throughout the Mobile App for padding and margins.
+
+| Variants | Default size |
+| ------------------------- | ------------ |
+| xxxl (triple extra large) | 36 |
+| xxl (double extra large) | 24 |
+| xl (extra large) | 16 |
+| l (large) | 12 |
+| m (medium) | 8 |
+| s (small) | 4 |
+| xs (extra small) | 2 |
+
+## Advanced Customization
+
+While the above adjustments are generally fairly simple, you can really customize the Mobile App to your heart's content (based on your skill level).
+
+Here are some additional aexamples.
+
+### Custom Fonts
+
+#### Create a folder for the Custom Fonts
+
+To keep the codebase organized, create a folder named `fonts` inside of `frontend/assets`.
+
+You can then move your custom font assets into this folder.
+
+#### Install & Use the `expo-font` Package
+
+This package eases the process of adding custom fonts into an Expo-based app.
+
+In particular, you'll want to use the `loadAsync` function from it, which will map your font assets to their variant names throughout the Mobile App.
+
+While we won't get into too much technical detail here, their [documentation](https://docs.expo.dev/versions/latest/sdk/font/) can guide you through the process.
+
+### Error Messages
+
+It is possible to customize both the error messages and the means through which they are presented to the user.
+
+In order to do this, you should first be aware of two files.
+
+#### `frontend/src/helpers/errorMessage.ts`
+
+The Prose GraphQL API forwards on error messages from Discourse.
+
+This file declares the specific text of those messages as constants so that they can easily be compared in `errorHandler.ts`.
+
+If you observe any additional error messages that are not being caught, you'll want to add them to this file, and then adjust `errorHandler.ts` below accordingly.
+
+#### `frontend/src/helpers/errorHandler.ts`
+
+This file imports from the above `errorMessage.ts`.
+
+It then defines exactly how errors should be handled, including the above messages, when they are encountered.
+
+Currently, the default approach is to display the errors using an Alert to the user.
+
+However, if you wanted to integrate snackbars, you would adjust the code in `errorHandler.ts` to replace the invocations of `Alert.alert`.
diff --git a/documentation/versioned_docs/version-1.0.0/troubleshooting-build.md b/documentation/versioned_docs/version-1.0.0/troubleshooting-build.md
new file mode 100644
index 00000000..68d75dad
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/troubleshooting-build.md
@@ -0,0 +1,128 @@
+---
+title: Troubleshooting when trying out the app
+---
+
+
+
+
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+## Troubleshooting Connection and Configuration Issues with URL
+
+
+
+
+
+If you are encountering issues related to the URL, resulting in an error message saying "please connect to network" as shown in the screenshot, it is likely due to incorrect settings. Specifically, if you are attempting to test builds locally on your mobile device and the channel field is not properly configured, the app may continuously fallback to the localDevelopment channel, even if you have set it to something else like "preview."
+
+Here some steps and notes to help resolve this:
+
+- Open the `frontend/Config.ts` file in your project.
+- Locate the `config` object within the file.
+- In the `localDevelopment` section of the `config` object, you can add the Prose URL specific to the channel you are trying to test. This section is used for local development and as a fallback configuration for unknown build channels in EAS Build. Here's an example:
+
+ ```ts
+ const config: Config = {
+ localDevelopment: {
+ proseUrl: 'http://localhost:8929',
+ },
+ buildChannels: {
+ preview: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ production: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ },
+ };
+ ```
+
+- The example above shows that the config consists of two main sections: localDevelopment, which specifies the URL during localDevelopment, and buildChannels, which includes configurations for different channels such as preview and production. For local development, it will hit the Prose API with the URL `http://localhost:8929`. If the buildChannel is unknown or not found, it will always default to localDevelopment.
+- Update the `proseUrl` value within the desired build channel, such as `preview` or `production`, with the valid and reachable URL of your Prose server.
+- Once you have made the necessary changes, save the `frontend/Config.ts` file.
+
+Now, when you run eas build for a specific build channel, such as `eas build --profile=production`, it will utilize the Prose URL specified in the production configuration.
+
+:::note
+It is important to include the URL in the `frontend/app.json` file, which expo-updates will use to fetch update manifests. Failing to set the URL in the `frontend/app.json` file will result in the expo-update constant always returning undefined for the channel, causing the app to consistently utilize the localDevelopment URL after building. You can specify this URL in the expo and updates sections of the app.json file. For more detailed information on how to configure this, please refer to the [expo documentation](https://docs.expo.dev/versions/latest/config/app/#url) for more detail on this.
+
+```json
+"expo": {
+ "updates": {
+ ...,
+ "url": "https://u.expo.dev/"
+ }
+}
+```
+
+This configuration is essential for seamless integration with Config.ts in your project.
+:::
+
+In certain cases, you may encounter an issue related to Prose API URLs when the channel name specified in the `frontend/eas.json` file does not match the corresponding key name defined in the `config` variable in `frontend/Config.ts`. This discrepancy can lead to problems because the channel name from `eas.json` is used to determine the URL that will be utilized. If the names do not match, the default `localDevelopment` URL will be used instead.
+
+To ensure smooth functioning, it is important to use the same channel name in both the `frontend/eas.json` file and the `frontend/Config.ts` file. This will ensure proper mapping of the channel name to the corresponding URL.
+
+Here is an example to illustrate this:
+
+```json
+// frontend/eas.json
+
+"build": {
+ "staging": {
+ "android": {
+ "buildType": "apk"
+ },
+ "channel": "staging"
+ }
+}
+```
+
+```ts
+// frontend/Config.ts;
+
+const config: Config = {
+ localDevelopment: {
+ proseUrl: 'http://localhost:8929',
+ inferDevelopmentHost: true,
+ },
+
+ buildChannels: {
+ preview: {
+ proseUrl: '',
+ },
+ production: {
+ proseUrl: '',
+ },
+ staging: {
+ proseUrl: '',
+ },
+ },
+};
+```
+
+## The app closes abruptly after the splash screen
+
+If you encounter a situation where your app closes abruptly after the splash screen, it is likely that there are missing configurations in your `app.json` file. One common cause is the absence of a scheme definition in `app.json`, which is essential during the app build process.
+
+To resolve this issue, follow these steps:
+
+1. Open your project's `frontend/app.json` file.
+2. Look for the `"expo"` section.
+3. If a scheme is not present add this part in `"expo"` section
+
+```json
+"expo":{
+ "name": "",
+ "slug": "",
+ "scheme": "",
+ "version": "1.0.0"
+}
+```
+
+Replace `""` with the desired scheme name for your app.
+
+4. Save the changes to the `app.json` file.
+5. Rebuild your app and test it again.
+
+By ensuring that the scheme is correctly defined in `app.json`, you should be able to resolve the issue of the app closing after the splash screen.
diff --git a/documentation/versioned_docs/version-1.0.0/tutorial/building.md b/documentation/versioned_docs/version-1.0.0/tutorial/building.md
new file mode 100644
index 00000000..3e261343
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/tutorial/building.md
@@ -0,0 +1,152 @@
+---
+title: Build your App
+---
+
+## EAS Build
+
+EAS Build is the upgraded version of `expo build`. This service helps to build app binaries for your Expo and React Native projects. Read more about it in the Expo documentation [here](https://docs.expo.dev/build/introduction/).
+
+### Configuration
+
+Let's get started by configuring EAS build. Check [here](https://docs.expo.dev/build-reference/build-configuration/) to see the complete guide from Expo.
+
+#### Build Setup
+
+Run this command in `/frontend` directory:
+
+```bash
+eas build:configure
+```
+
+When running that command, the EAS CLI will typically do the following:
+
+1. It will prompt you for the EAS project ID, either to use an existing ID if you have one, or create a new one. Then it will automatically add the `expo.extra.eas.projectId` field in `app.json`.
+2. It will create a new `eas.json` file if one doesnโt already exist. However, we have that set up for you, so you don't need to worry about creating one. ๐
+3. It will prompt you to specify `android.package` and `ios.bundleIdentifier` if those values are not already provided in `app.json`. Note that those two values don't have to be the identical.
+
+You can see that the values in `app.json` are updated after running the command.
+
+#### Configuration Values
+
+:::info
+When publishing your app, it is necessary to deploy Prose somewhere publicly accessible, perhaps on a cloud hosting provider like AWS or DigitalOcean. If Prose is only running on your local machine, users that download your app won't be able to use it.
+Check [the documentation](../deployment.md) to deploy Prose if you haven't already.
+
+In the original release of Lexicon, the **Prose URL** was specified in `frontend/.env`. However, as part of migrating to Expo's EAS feature, we centralized the configuration into `frontend/Config.ts` to save you the trouble of needing to maintain it in more than one place, as suggested in the [Expo documentation](https://docs.expo.dev/build-reference/variables/#can-i-share-environment-variables-defined-in-easjson-with-expo-start-and-eas-update)
+:::
+
+Next, open `Config.ts` and overwrite the placeholder values with the Prose URL you want to use for the build version. You can either set the same values or a different one for each channel. You don't need to adjust the values in `localDevelopment` since that is only used in development, and not when building the app.
+
+```ts
+const config = {
+ // ...
+ buildChannels: {
+ preview: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ production: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ },
+};
+```
+
+### Run a Build
+
+#### Build for Both Platforms
+
+To build on both platforms, you can use either of the commands below:
+
+```bash
+eas build --platform all
+```
+
+```bash
+eas build -p all
+```
+
+#### iOS only
+
+```bash
+eas build --platform ios
+```
+
+#### Android only
+
+```bash
+eas build --platform android
+```
+
+#### Run a build with a specific profile
+
+```bash
+eas build --platform all โ-profile
+```
+
+```bash
+eas build -p all โe
+```
+
+:::note
+Without --profile, the EAS CLI will default to the `production` profile.
+:::
+
+### Build Profiles
+
+Build profiles serve as a way of grouping configuration values for different scenarios when building the mobile app.
+
+You can find more details [here](https://docs.expo.dev/build/eas-json/).
+
+The `eas.json` file can contain multiple build profiles. However, it typically has 3 profiles: **preview**, **development**, and **production**.
+
+#### 1. Preview
+
+Purpose: to internally test the app in production-like circumstances.
+
+It is recommended to try building with the preview profile **_first_** before building your app with the production profile. That way, you can ensure the app runs as expected before itโs ready to be published.
+
+The build type for Android will be an **APK** file, whereas the iOS build will output a format that can be installed on the simulator.
+
+This is because the `ios.simulator` option was specified in `eas.json`:
+
+```json
+ "ios": {
+ "simulator": true
+ },
+```
+
+If you want to run the preview build on a real device, you'll need have an Apple account with Apple Developer Enterprise Program membership, then add the `ios.enterpriseProvisioning` value in `eas.json`:
+
+```json
+ "ios": {
+ "enterpriseProvisioning": "universal"
+ }
+```
+
+For the `preview` build profile, we have already set the distribution mode to [internal](https://docs.expo.dev/build/internal-distribution/). This ensures that EAS build provides shareable URLs for builds, with instructions on how to get them running.
+
+This approach then allows us to test the app without submitting to the App Store or Play Store.
+
+#### 2. Development
+
+Purpose: to make debugging easier. Expo will automatically include developer tools in the build. As you may have figured, this build should never be published to either of the app stores.
+
+Development builds depend on [expo-dev-client](https://docs.expo.dev/development/introduction/), so Expo will prompt us to install the library if needed.
+
+Similar to preview builds, you can add the iOS options mentioned above to run them on a simulator or real device.
+
+#### 3. Production
+
+Purpose: for submission to the App Store and Play Storeโas a public release, or as part of testing in each respective ecosystem.
+
+In order to use builds like this, they must be installed through the respective app stores.
+
+After running builds with this profile, you'll see that the iOS and Android versions have automatically been incremented. As you might expect, this is because `autoIncrement` has been set to `true`.
+
+It is worth noting, however, that this behavior only applies to TestFlight and Internal Testing, so you'll need to be sure to also manually increment the `expo.version` in `app.json` for public release. Expo provides further [documentation](https://docs.expo.dev/build-reference/app-versions/) on this topic.
+
+## The App is Built
+
+Great work! You can now share the installation link with your peers so they can try out the app.
+
+In the next section, you'll learn how to [publish](publishing) your app to the App Store and Play Store! ๐
diff --git a/documentation/versioned_docs/version-1.0.0/tutorial/install-prose.md b/documentation/versioned_docs/version-1.0.0/tutorial/install-prose.md
new file mode 100644
index 00000000..d6ecec67
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/tutorial/install-prose.md
@@ -0,0 +1,360 @@
+---
+title: Setup the Prose GraphQL API
+---
+
+Now that we have a running Discourse instance to interact with, we can move onto setting up the Prose GraphQL Server.
+
+To recap, Prose is a part of the Lexicon stack.
+
+It is responsible for providing a [GraphQL](https://graphql.org/) interface on top of Discourse, which the Lexicon Mobile App can then interact with.
+
+For more information about this, check out [Concepts & Architecture](../concepts).
+
+## Approaches for Setting Up Prose
+
+If your Discourse instance is running locally, it is natural that you should also setup your Prose server locally.
+
+Otherwise, it would be unnecessary extra work to get a remote Prose server communicating with your local Discourse server.
+
+However, if you've setup your Discourse instance in the cloud, it is up to you if you want to run your Prose server locally or in the cloud as well.
+
+If you'd like to install it in the cloud, you'll want to setup an additional server - similar to how you would set one up for Discourse. If you're not yet comfortable with this, feel free to jump back to the page, [Setup a Cloud Server (Optional)](setup-cloud-server).
+
+Bearing all of that in mind, once you have identified where you'd like to host Prose, you should also consider how you'd like to install it onto that machine.
+
+The first way, which we recommend, is to use **[Docker](https://www.docker.com/)**.
+
+And of course, the second way is to install it manually, rather than using containers.
+
+## Install Prose using Docker
+
+The reason we recommend using Docker is because you won't have to worry about setting up Prose's on your machine.
+
+We have already published Prose to [Docker Hub](https://hub.docker.com/), which means you can easily pull it down and run it. We'll guide you through that below.
+
+### Install Docker
+
+First, just as was necessary for setting up Discourse, you'll want to make sure Docker is installed on your machine.
+
+You can follow the instructions on the [Docker installation page](https://www.docker.com/get-started) if you are unsure of how to do this.
+
+### Pull and Run the Prose GraphQL API Image
+
+After successfully installing Docker, you can use the command below to run the Prose GraphQL image.
+
+Just bear in mind that you'll want to adjust some of the **environment variables** to your situation before you run the command.
+
+```
+$ docker run -d \
+ -e PROSE_DISCOURSE_HOST=https://meta.discourse.org \
+ -e PROSE_APP_PORT=80 \
+ -p 5000:80 \
+ --name prose-graphql \
+ kodefox/prose
+```
+
+The above command will take care of pulling the Prose GraphQL Docker Image, building it, and running it in a container.
+
+To help understand everything that's going on there, let's break it down line by line.
+
+```bash
+docker run -d
+```
+
+This instructs Docker to run our image as a container in **detached mode**. This is similar to backgrounding a process.
+
+```bash
+-e PROSE_DISCOURSE_HOST=https://meta.discourse.org
+-e PROSE_APP_PORT=80
+```
+
+The `-e` flag instructs Docker that we want to set or override certain environment variables in the container with the values we provided.
+
+In this case, we're telling Prose to interact with the Discourse instance is running at `https://meta.discourse.org`, and that Prose should run itself _inside of the container_ on a port of `80`.
+
+```
+-p 5000:80
+```
+
+Next, we're telling Docker what ports we want to map from our host machine into the container.
+
+In the previous step, we established that Prose will run internally on port 80. With the above command, we're telling Docker to expose the container's port 80 as port 5000 on our host.
+
+This means that Prose will be reachable on port 5000 of the host.
+
+So, if you're running this locally, you'll be able to interact with Prose at `http://localhost:5000`.
+
+And if you're running it in the cloud on a domain like `https://prose.mydiscussions.com`, you'd likely want it to be listening on port 443 so the user doesn't have to enter a port number as part of the URL.
+
+### Configure Prose
+
+As suggested above, you can configure Prose through the use of environment variables.
+
+You can find a comprehensive list of all environment variables on the Prose [Environment Variables](../env-prose) page.
+
+In this case, you really only need to set a value for `PROSE_DISCOURSE_HOST`, which will instruct Prose which Discourse instance you'd like it to interact with.
+
+Additionally, if you'd like to set a different port mapping, you can adjust the `-p` flag of the `docker run` command to something else, such as:
+
+```bash
+-p 8080:80
+```
+
+## Install Manually
+
+This section, whether being done locally or remotely on a cloud provider, will require you to install and configure the necessary dependencies to build and run Prose from scratch.
+
+### Setup Development Machine
+
+If you haven't already, setup your machine for Prose development. You can do so by following the guide at [Setup your Development Machine](setup).
+
+By the time you're done with this step, you should have a local copy of the Lexicon repository on your desired machine.
+
+### Configure Environment Variables
+
+The Prose GraphQL API, at a bare minimum, requires you to provide a URL to an accessible Discourse instance in order to run properly.
+
+Because we're doing this manually, you'll need to specify this in a different way than you would for Docker.
+
+Later on, once you've built Prose, one way you can specify this is to simply provide it inline as you launch the server.
+
+```bash
+PROSE_DISCOURSE_HOST=https://discourse.mysite.com node lib/index.js
+```
+
+However, you might find it more ergonomic to leverage the support we've setup for `.env` files.
+
+The entire Prose codebase lives in the `api/` directory of the repository, so get started by navigating there from the project root.
+
+```
+$ cd api/
+```
+
+Next, you'll need to create a `.env` file. Simply copy the template file, `.env.example` into the `.env` file using the following command.
+
+```
+$ cp .env.example .env
+```
+
+After that, as you'd expect, you want to adjust the `.env` file so that it contains the values specific to your project.
+
+```bash
+PROSE_DISCOURSE_HOST=
+PROSE_APP_PORT=
+```
+
+As was covered in the Docker section above, you can find a comprehensive list of all environment variables on the Prose [Environment Variables](../env-prose) page.
+
+### Launch the Prose GraphQL API
+
+:::info
+At this point, you should already have all the project's dependencies installed.
+
+If you encounter any errors about missing packages, go back to the guide at [Setup your Development Machine](setup).
+:::
+
+If you'd just like to launch Prose to check it out quickly, you can simply run (from the `api/` directory):
+
+```bash
+$ npm run dev
+```
+
+This will prepare and spin up Prose in a way that isn't ideal for production.
+
+If you wish to run the Prose GraphQL API in the background as a process, there are multiple solutions.
+
+One method is to use **[Tmux](https://github.com/tmux/tmux)**, which will detach the process from the terminal, allowing you to close it and keep Prose running.
+
+Another method is to use **[PM2](https://pm2.keymetrics.io/)**, which is a sophisticated toolset for running Node processes in production.
+
+#### Using Tmux
+
+**Tmux** can be used to detach processes from their controlling terminals, allowing sessions to remain active without being visible.
+
+To get started, install `tmux` on your machine.
+
+If you are unsure of how to install tmux, you can follow the instructions on [this page](https://github.com/tmux/tmux#installation).
+
+Once it's installed, launch it as follows:
+
+```bash
+$ tmux
+```
+
+Then you can run Prose in the same way as before.
+
+```bash
+$ npm run dev
+```
+
+If you want to detach from your current session, press `Ctrl + B` then press `d` on your keyboard. The session will remain active in the background.
+
+And if you wish to re-attach to your last session, run the following command.
+
+```
+$ tmux a
+```
+
+If you want to learn more about the tmux command, check out [this cheat sheet](https://tmuxcheatsheet.com/).
+
+#### Using PM2
+
+Another way to run Prose in the background is to use **pm2** (process manager for NodeJS).
+
+First, as you'd expect, you'll need to install `pm2` on your machine.
+
+```
+$ npm install -g pm2
+```
+
+Once it's installed, you'll also need to use `pm2` to install [Typescript](https://typescriptlang.org/).
+
+This is because Prose is written in Typescript, and this allows PM2 to run the Typescript files directly for us (as opposed to transpiling them and outputting them as JS first).
+
+To do this, simply run the following command:
+
+```
+$ pm2 install typescript
+```
+
+After that, you can now launch the Prose GraphQL API in the background with:
+
+```
+$ pm2 start src/index.ts
+```
+
+To list all running applications, run the following command.
+
+```
+$ pm2 list
+```
+
+These are some of the frequently used commands.
+
+```
+$ pm2 stop # To stop a process
+$ pm2 restart # To restart a process
+$ pm2 delete # To delete a process
+```
+
+## Test the GraphQL API
+
+Now that you've successfully launched Prose, you can actually interact with it in your web browser.
+
+Because of the libraries that we leveraged in building Prose, it automatically comes with [GraphiQL](https://www.graphql-yoga.com/docs/features/graphiql).
+
+This is an in-browser GraphQL IDE that makes it easy to explore the documentation and the schema of the GraphQL API.
+
+In order to access it, you'll need to make note of the host and port number that you configured the API with.
+
+For example, if you launched Prose from your local machine on port 5000, you'd navigate to [http://localhost:5000](http://localhost:5000).
+
+Similarly, if you set it up in the cloud, and all you have is an IP address with Prose listening on port 80, you would navigate to something like [http://174.31.92.1](http://174.31.92.1).
+
+Once the [GraphiQL](https://www.graphql-yoga.com/docs/features/graphiql) interface loads, you can test out some example queries and mutations, including logging into Discourse through Prose.
+
+### Login
+
+:::info
+If you're accessing a private Discourse site, you'll need to make note of the token that is returned to make other requests. See below.
+:::
+
+```
+mutation Login {
+ login(email: "user@lexicon.com", password: "user_password") {
+ ... on LoginOutput {
+ token
+ user {
+ id
+ name
+ username
+ avatarTemplate
+ }
+ }
+ }
+}
+```
+
+As mentioned in the notice, if you're interacting with a private Discourse site, you'll need to provide a token for other GraphQL requests.
+
+As part of the response for the above mutation, you'll notice a "token" field which contains your authentication token in Base64.
+
+You use this token in other queries and mutations by opening the HTTP Headers section on the bottom left-hand side of the page.
+
+This section expects JSON, with which you'll want to add an Authorization header that contains your token.
+
+```json
+{
+ "Authorization": ""
+}
+```
+
+Once you have done that, you can make authenticated GraphQL queries and mutations as the user you logged in with.
+
+### User Profile
+
+```
+ query UserProfile {
+ userProfile(username: "john_doe") {
+ user {
+ ... on UserDetail {
+ id
+ avatarTemplate
+ username
+ name
+ websiteName
+ bioRaw
+ location
+ dateOfBirth
+ email
+ }
+ }
+ }
+ }
+```
+
+### Topic Detail
+
+```
+query TopicDetail {
+ topicDetail(topicId: 1) {
+ id
+ title
+ views
+ likeCount
+ postsCount
+ liked
+ categoryId
+ tags
+ createdAt
+ postStream {
+ posts {
+ id
+ topicId
+ userId
+ name
+ username
+ avatarTemplate
+ raw
+ createdAt
+ }
+ stream
+ }
+ details {
+ participants {
+ id
+ username
+ avatarTemplate
+ }
+ }
+ }
+}
+```
+
+### Logout
+
+```
+ mutation Logout {
+ logout (username: "john_doe")
+ }
+```
diff --git a/documentation/versioned_docs/version-1.0.0/tutorial/intro.md b/documentation/versioned_docs/version-1.0.0/tutorial/intro.md
new file mode 100644
index 00000000..54e0d630
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/tutorial/intro.md
@@ -0,0 +1,45 @@
+---
+title: Overview
+slug: /tutorial
+---
+
+## Welcome to the Lexicon Tutorial
+
+We're really excited to help you dig in with the Lexicon Stack and learn how to deploy it in a way that benefits you and your users.
+
+## Target Audience & Prerequisites
+
+In order to complete this tutorial, you should have familiarity with:
+
+- The command-line
+- Git and Github
+- Setting up a Discourse instance
+- Setting up servers in general
+
+In terms of prepararation, you will need:
+
+- NodeJS installed on your development machine
+ - Use the latest version of Node that is compatible with the project's version of Expo (i.e. `expo-cli`).
+- An editor to edit config files
+
+#### Have some concerns?
+
+Interested in Lexicon but lacking in technical abilities? We completely understand.
+
+Reach out to us at support@kodefox.com to chat about how we can help bring your idea to life.
+
+## Next Steps
+
+This tutorial will guide you through the process of getting the entire Lexicon Stack up and running **locally** with your Discourse site.
+
+At the end of the tutorial, you will be able to interact with your Discourse site in the Lexicon Mobile App on your local device or simulator.
+
+You will also have an understanding of:
+
+- How to configure and run the Prose GraphQL API locally or on a server you own
+- How to configure and run the Lexicon Mobile app on your device or in a simulator
+- The next steps needed to make full use of Lexicon
+
+Please note that this tutorial will not cover the process of actually launching the app, as well as certain details about deploying to production. For support with those tasks, please refer to the documentation.
+
+Let's get started!
diff --git a/documentation/versioned_docs/version-1.0.0/tutorial/publishing.md b/documentation/versioned_docs/version-1.0.0/tutorial/publishing.md
new file mode 100644
index 00000000..66005bdd
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/tutorial/publishing.md
@@ -0,0 +1,97 @@
+---
+title: Publish your App
+---
+
+## EAS Submit
+
+EAS Submit is a service for uploading and submitting your application binaries to App Store and/or Play Store.
+Check [here](https://docs.expo.dev/submit/introduction/) to learn more about EAS Submit.
+
+### Prerequisites:
+
+- Registered app in App Store Connect, see the guide [here](../app-store#register-a-new-bundle-id).
+- Registered app in Play Store, see the guide [here](../play-store).
+
+### Configuration
+
+Before submitting, you are required to specify the credentials to publish your app.
+
+#### iOS
+
+For iOS, fill in your account information for `appleId`, `ascAppId`, and `appleTeamId`:
+
+```json
+ "base": {
+ "ios": {
+ "appleId": "",
+ "ascAppId": "",
+ "appleTeamId": ""
+ },
+ ...
+ },
+```
+
+- **appleId**: your apple ID (e.g., `john@gmail.com`).
+- **ascAppId**: your App Store Connect app ID. Find your ascAppID by following [this guide](https://github.com/expo/fyi/blob/main/asc-app-id.md) (e.g., `1234567890`).
+- **appleTeamId**: You can check your apple team ID [here](https://developer.apple.com/account/) (e.g., `12LE34XI45`).
+
+#### Android
+
+For Android, you will need to add a `.json` key file to authenticate with the Google Play Store. Please follow [this guide](https://github.com/expo/fyi/blob/main/creating-google-service-account.md) to generate one. Then, copy the JSON file to your `lexicon/frontend` directory, and rename the file as `playstore_secret.json`.
+
+The JSON file looks like this:
+
+```json
+{
+ "type": "service_account",
+ "project_id": "",
+ "private_key_id": "",
+ "private_key": "-----BEGIN PRIVATE KEY----------END PRIVATE KEY-----\n",
+ "client_email": "",
+ "client_id": "",
+ "auth_uri": "",
+ "token_uri": "",
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
+ "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/lexicon%40api.iam.gserviceaccount.com"
+}
+```
+
+Now that the configuration is done, you can start submitting your app.
+
+### Submitting
+
+Use this command to submit the build:
+
+```bash
+eas submit --platform ios --profile
+```
+
+Then you will see the EAS CLI prompt asking which app you would like to submit.
+
+There are 4 possible options:
+
+- Selecting a build from EAS
+- Providing the URL of an app archive
+- Providing the local path to an app binary file
+- Providing the build ID of an existing build on EAS
+
+If you have built your app using EAS Build or have been following the tutorial from [Build your App](building), then please choose the first option, and select the version you want.
+
+### Submit Profiles
+
+By default, `eas.json` has been configured with two submit profiles, which are **staging** and **production**.
+
+The configuration is mostly the same, the only difference lies in the Android track options.
+
+- Staging infers the track as `internal`. This means submitting with the staging profile will submit the build for internal testing in the Play Store.
+- Production infers the track as `production`, which will submit the build for Public Release in the Play Store.
+
+With iOS, on the other hand, both profiles will be submitted to TestFlight before you can release them publicly.
+
+You can reference the Expo documentation to learn more about [Android-specific](https://docs.expo.dev/submit/eas-json/#android-specific-options) and [iOS-specific](https://docs.expo.dev/submit/eas-json/#ios-specific-options) options.
+
+## Congratulations!
+
+Your app is now available for users to download from both the Play Store and the App Store! ๐ฅณ
+
+To learn more about how to update your published app in the case of a bug, as well as OTA updates, check out the [next and final section](updating) of the tutorial.
diff --git a/documentation/versioned_docs/version-1.0.0/tutorial/setup-cloud-server.md b/documentation/versioned_docs/version-1.0.0/tutorial/setup-cloud-server.md
new file mode 100644
index 00000000..b69659a4
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/tutorial/setup-cloud-server.md
@@ -0,0 +1,27 @@
+---
+title: Setup a Cloud Server (Optional)
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+:::info
+This is an optional section for users that don't feel as confident spinning up a new server with a cloud provider.
+
+If you are already adept at this, you can skip to the next section.
+:::
+
+## DigitalOcean Guide
+
+### How To Set Up an Ubuntu 20.04 Server on a DigitalOcean Droplet
+
+For our users that aren't as familiar with setting up servers in the cloud, we wanted to provide you with a solid resource to learn more about it and accomplish something in the process.
+
+DigitalOcean has already provided an excellent guide to walk you through this, so we're going to link you over to them.
+
+In this guide, you will create an Ubuntu server through DigitalOceanโs administrative panel and configure it to work with your SSH keys.
+
+Once you have a solid understanding of how to setup servers in the cloud, you'll be much more capable of deploying the Lexicon Stack for your users.
+
+You can dig in on the article below.
+
+[Read: How To Set Up an Ubuntu 20.04 Server on a DigitalOcean Droplet](https://www.digitalocean.com/community/tutorials/how-to-set-up-an-ubuntu-20-04-server-on-a-digitalocean-droplet)
diff --git a/documentation/versioned_docs/version-1.0.0/tutorial/setup-discourse.md b/documentation/versioned_docs/version-1.0.0/tutorial/setup-discourse.md
new file mode 100644
index 00000000..9b5bf97a
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/tutorial/setup-discourse.md
@@ -0,0 +1,306 @@
+---
+title: Prepare a Discourse Instance
+---
+
+Before you can properly setup Lexicon, you'll need to have a running **[Discourse](https://www.discourse.org/)** instance for Lexicon to interact with.
+
+For this step, you actually have a few options:
+
+#### Option 1: Setup a Local Discourse Instance
+
+The first option is to [setup a development instance](#setup-discourse-locally) of Discourse locally on your development machine. This takes a bit of time and can get a bit technical.
+
+#### Option 2: Buy a Discourse Instance or Use your Existing One
+
+The second option is to pay to [setup a Discourse instance in the cloud](#setup-discourse-in-the-cloud) as a live, reachable production verison. This is much simpler, but has the obvious tradeoff of costing money.
+
+And perhaps it goes without saying, but if you already have a Discourse site, feel free to just use that.
+
+#### Option 3: Use a Public Discourse Site
+
+The third option is to use an existing Discourse site just to test things out.
+
+As you'll see later on, Lexicon allows you to configure which Discourse site it is pointing at. As such, you can instruct it to point at at a publically accessible Discourse site that you don't personally own.
+
+There are countless examples of active Discourse communities out there. Here are a few examples to choose from:
+
+##### Discourse Meta
+
+[https://meta.discourse.org/](https://meta.discourse.org/)
+
+##### Expo
+
+[https://forums.expo.dev/](https://forums.expo.dev/)
+
+##### The Rust Programming Language
+
+[https://users.rust-lang.org/](https://users.rust-lang.org/)
+
+##### FreeCodeCamp Forums
+
+[https://forum.freecodecamp.org/](https://forum.freecodecamp.org/)
+
+## Setup Discourse Locally
+
+:::note
+This section can take a long time. Depending on the specs of your machine, it could take between 10 - 30 minutes to complete.
+:::
+
+This section of the tutorial is based on the following post on Discourse: [Beginners Guide to Install Discourse for Development using Docker](https://meta.discourse.org/t/beginners-guide-to-install-discourse-for-development-using-docker/102009).
+
+If you run into any issues, feel free to reference the original post and subsequent discussion.
+
+### Install Docker
+
+**[Docker](https://www.docker.com/)** is a containerization framework that makes it easy to build, manage, and deploy your application stack in a way that is safer, more reliable, and repeatable across multiple platforms.
+
+When developing, building, and testing applications locally, it is an invaluable tool that greatly simplifies the entire process.
+
+The main way that Docker helps us in this tutorial is that it won't require any modifications to our machine's environment other than installing Docker itself.
+
+This is as-opposed to needing to install all of Discourse's dependencies on your physical machine, in a way that may take a lot of effort to undo later.
+
+If you are unsure of how to install Docker, you can follow the instructions on their [website](https://www.docker.com/get-started).
+
+### Clone Discourse
+
+Once Docker is up and running, we can get started with setting up Discourse locally.
+
+The first step is to clone the Discourse repository to your local machine and `cd` into it.
+
+```
+git clone https://github.com/discourse/discourse.git
+cd discourse
+```
+
+Note the repository is on the larger side (nearly 400mb), so this step may take a while depending on your connection.
+
+### Pull, Build, and Start the Discourse Dev Container
+
+:::caution
+Make sure that the **host ports** listed below are not already in use on your device.
+:::
+
+Discourse already contains a script to help spin up its entire infrastructure using Docker.
+
+During this process, the script will do the following:
+
+- Pull down the necessary "dev" Docker image to bootstrap Discourse
+- Build the aforementioned image
+- Run the image as a container with multiple ports mapped from your host into the container
+ - 127.0.0.1:**1080**->1080/tcp
+ - 127.0.0.1:**3000**->3000/tcp
+ - 127.0.0.1:**4200**->4200/tcp
+ - 127.0.0.1:**9292**->9292/tcp
+ - 127.0.0.1:**9405**->9405/tcp
+- Prompt you for an admin email address and password
+
+To get started, simply run the following command:
+
+```
+$ d/boot_dev --init
+```
+
+Note that all of the Docker images add up to about 1GB of disk space usage on your device.
+
+The command will pause when it needs information from you. As shown below, it will prompt you for an administrator email address and password.
+
+```bash
+# Output omitted
+== 20200804144550 AddTitleToPolls: migrating ==================================
+-- add_column(:polls, :title, :string)
+ -> 0.0014s
+== 20200804144550 AddTitleToPolls: migrated (0.0021s) =========================
+
+Creating admin user...
+Email: me@me.com
+Password:
+Repeat password:
+
+Ensuring account is active!
+
+Account created successfully with username me
+```
+
+Next, it will ask you if you want to make this account an admin account. You do.
+
+```bash
+Do you want to grant Admin privileges to this account? (Y/n) y
+
+Your account now has Admin privileges!
+```
+
+Please be aware, as suggested above, that the ports mentioned above are not currently in use by other processes.
+
+### If something unexpected happened
+
+It's possible that something strange may have happened at this step.
+
+Perhaps there was a weird error message, or the process just never displayed the output shown above.
+
+What we'd recommend doing is the following:
+
+#### Check if a Docker container named `discourse_dev` is running
+
+```bash
+$ docker ps | grep discourse_dev
+CONTAINER ID IMAGE ... NAMES
+dc72a4ead10f discourse/discourse_dev:release ... discourse_dev
+```
+
+If it is, stop and remove the container.
+
+```bash
+$ docker stop discourse_dev
+discourse_dev
+$ docker rm discourse_dev
+discourse_dev
+```
+
+#### Exit or Kill the Existing Process
+
+If the existing process (`d/boot_dev --init`) is still occupying your terminal session, attempt to exit it via `Ctrl + C`.
+
+If the process is not responding to `Ctrl + C` after some time, locate its PID and use `kill -9` to kill it
+
+```bash
+$ ps aux | grep rails
+user 81254 0.0 0.1 discourse_dev bin/rails s
+
+$ kill -9 81254
+```
+
+#### Restart Docker or your Machine
+
+Using the command or interface appropriate for your machine, you should restart all of Docker.
+
+On Docker for Mac, this is as simple as going into the tray icon and clicking Restart.
+
+#### Try running the command again
+
+Sometimes things just go a little haywire with this setup. Try running the command again to see if it works better this time.
+
+#### If you're absolutely stuck, reach out.
+
+Don't hestitate to contact us if you're just stuck with this one.
+
+### Optional: Run the Next Two Commands in the Background
+
+You can read on to get an understanding of what the two commands are, but it's worth mentioning that you want them to run simultaneously.
+
+You can do this by _backgrounding_ both processes.
+
+This means that they won't occupy your current session, requiring you to quit them in order to enter other commands.
+
+When you run this command, it will show you the process IDs (PIDs) of the processes that were backgrounded.
+
+To bring them back into the foreground, you can run the `fg` command, and then use `Ctrl + C` or a similar signal to stop them.
+
+```bash
+d/rails s & d/ember-cli &
+[2] 59786
+[3] 59787
+
+fg
+```
+
+Just **note** that you won't see the output of the commands, and so you may need to be patient for several minutes until Discourse is reachable at its local address.
+
+Alternatively, you can use the PIDs to kill the processes outright in another session:
+
+```bash
+kill -9 59786 59787
+```
+
+### Start the Rails Server within the Container
+
+If you hadn't already noticed, Discourse is built in [Ruby](https://www.ruby-lang.org/en/) using the very popular web framework, [Ruby on Rails](https://rubyonrails.org/).
+
+By running the command below, you will be starting the Rails server, which will take some time, and will produce a tremendous amount of output.
+
+In particular, you'll see the database being initialized as the dev container bootstraps the Discourse server.
+
+To get started, simply run the following command.
+
+```
+d/rails s
+```
+
+#### If you later can't quit the process
+
+**Note** that this command can sometimes hang when you're trying to kill it with `Ctrl + C`.
+
+If that happens, it's recommended that you first stop the Docker container:
+
+```bash
+docker stop docker_dev
+```
+
+Then, bring the process to the foreground with `fg` if necessary.
+
+Last, either exit your session if possible - such as by closing the Terminal - or find out the PID of the Rails process and kill it directly.
+
+```bash
+$ ps aux | grep rails
+user 81254 0.0 0.1 discourse_dev bin/rails s
+
+$ kill -9 81254
+```
+
+### Run the Ember CLI
+
+The above section mentioned Ruby on Rails, which handles the backend aspects of the Discourse application.
+
+However, the Discourse frontend is build in [EmberJS](https://emberjs.com/), which is a batteries-included frontend web framework used by multiple major companies.
+
+Run the command below to instruct the Ember CLI to start the Discourse frontend.
+
+```
+d/ember-cli
+```
+
+Once you have done this, you'll be able to access Disourse at [http://localhost:4200](http://localhost:4200).
+
+Please note that the output of this command can be a bit confusing. And at times, it can seem like nothing is happening.
+
+You may see several progress indicators, as well as blank output, for several minutes before the server is ready.
+
+The output you're looking for will resemble the following:
+
+```bash
+Build successful (72475ms) โ Serving on http://localhost:4200/
+
+Slowest Nodes (totalTime >= 5%) | Total (avg)
+----------------------------------------------------------------------+------------------
+Babel: discourse (2) | 31501ms (15750 ms)
+ember-auto-import-analyzer (11) | 10418ms (947 ms)
+Bundler (1) | 6119ms
+Babel: @ember/test-helpers (2) | 5075ms (2537 ms)
+broccoli-persistent-filter:TemplateCompiler (3) | 4596ms (1532 ms)
+```
+
+## Setup Discourse in the Cloud
+
+There are several guides with instructions on how to setup Discourse in the Cloud.
+
+Rather than writing another one, we have found our favorite one and would like to send you over to them to give you a proper walkthrough of the process.
+
+### Guide by SSDNodes
+
+The guide is provided by the [SSDNodes](https://www.ssdnodes.com/?e=blog&q=more-about-ssdnodes) Blog, [Serverwise](https://blog.ssdnodes.com/blog/).
+
+If you aren't familiar, [SSDNodes](https://www.ssdnodes.com) is an excellent, cost-effective VPS hosting provider.
+
+While we are most familiar with Digital Ocean, we'd strongly encourage you to check them out as an alternative for hosting Discourse.
+
+The post, titled [How To Install Discourse On Ubuntu](https://blog.ssdnodes.com/blog/install-discourse/), is written by [Joel Hans](https://blog.ssdnodes.com/blog/author/joel/).
+
+Joel has written an excellent guide. He'll take you through the entire process, including making update to your Discourse instance.
+
+If you find yourself stuck, or have any questions, feel free to reach out to us.
+
+## Use a Public Discourse Site
+
+If you've chosen this option, there's not much to do other than to note the URL of the Discourse site you'll be using.
+
+Once you have that written down somewhere, you're ready for the next section.
diff --git a/documentation/versioned_docs/version-1.0.0/tutorial/setup-mobile.md b/documentation/versioned_docs/version-1.0.0/tutorial/setup-mobile.md
new file mode 100644
index 00000000..62ab943a
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/tutorial/setup-mobile.md
@@ -0,0 +1,120 @@
+---
+title: Configure & Launch the Mobile App
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+After following the **[Setup the Prose GraphQL API](install-prose)** section, your GraphQL API should now be connected to your Discourse site.
+
+Next, we'll guide you through the process of connecting the Lexicon Mobile App to your Discourse site via Prose.
+
+### Mobile App Configuration
+
+:::note
+In the original release of Lexicon, the **Prose URL** was specified in `frontend/.env`. However, as part of migrating to Expo's EAS feature, we centralized the configuration into `frontend/Config.ts` to save you the trouble of needing to maintain it in more than one place, as suggested in the [Expo documentation](https://docs.expo.dev/build-reference/variables/#can-i-share-environment-variables-defined-in-easjson-with-expo-start-and-eas-update)
+:::
+
+Before launching your local version of the Lexicon Mobile App, you'll need to configure it with at least one piece of information.
+
+The Lexicon Mobile app relies exclusively on a running instance of the Prose GraphQL API in order to retrieve data from your Discourse instance.
+
+Therefore, you'll need to instruct it on how to locate your running Prose server.
+
+In development, it is common to have it running locally. However, if you have already deployed Prose
+somewhere, feel free to use that.
+
+#### Configuring `proseUrl` via `config`
+
+:::caution
+
+##### `proseUrl` requirements
+
+It is worth noting that `proseUrl` **must** start with either `http://` or `https://`.
+
+If it does not, the Mobile App will throw an error when launching.
+:::
+
+`Config.ts` contains the `config` object, which allows you to specify the Prose URL for each scenario encountered when developing and building the Mobile App.
+
+The specific configuration value which enables this is `proseUrl`, and it is contained within each scenario expressed by the `config` object.
+
+```ts
+const config = {
+ localDevelopment: {
+ proseUrl: 'http://localhost:8929',
+ },
+ buildChannels: {
+ preview: {
+ proseUrl: 'https://preview.myserver.com:8080/subpath',
+ },
+ production: {
+ proseUrl: 'https://myserver.com/api/prose',
+ },
+ },
+};
+```
+
+As mentioned earlierโabove, the `config` object allows us to express configuration values for multiple scenarios, which are:
+
+- `localDevelopment`: when developing against the app locally. This configuration is also used as a fallback for an unknown build channel.
+- `buildChannels`: used to define configuration by build channel when building the app with the EAS CLI.
+
+`buildChannels` makes use of Expo's build channels (typically `preview` and `production`) as its keys.
+
+Each key within `buildChannels` maps to a specific Prose URL, which will be used for the build version based on which channel you build for.
+
+From the example above, when we create a `preview` build, the app will be built and configured to contact a Prose server located at `https://preview.myserver.com:8080/subpath`.
+
+The example above expresses a setup in which each build has its own deployed Prose server. However, it is also common to use one server for all scenarios, including development.
+
+```ts
+const config = {
+ localDevelopment: {
+ proseUrl: 'https://myserver.com/api/prose',
+ },
+ buildChannels: {
+ preview: {
+ proseUrl: 'https://myserver.com/api/prose',
+ },
+ production: {
+ proseUrl: 'https://myserver.com/api/prose',
+ },
+ },
+};
+```
+
+##### Port Number
+
+Bear in mind that if your Prose server is not running on port 80 or 443, you also need to specify the **port number** via `proseUrl`.
+
+For example, if you've started a Prose server **locally** on port `8929` and try to run it using `expo start`, your `Config.ts` file would contain `http://myserver.com:8929/api/prose` under `localDevelopment.proseUrl`.
+
+### Launch the Mobile App
+
+Once you have configured everything, you'll want to launch the Mobile App to test that it is speaking to the right Prose server.
+
+To do this, you can simply run the following from the project root:
+
+```bash
+npm run --prefix frontend start
+```
+
+The Expo development server should launch, and you can follow the instructions to run the app in a simulator or on your actual device.
+
+#### Troubleshooting
+
+If the app throws an error upon loading, you should double-check the configuration values you specified, according to the message you've received.
+
+If the app loads, but you're unable to actually connect, you should verify the following:
+
+- Your Prose Server is up and running at the location you provided to the Lexicon Mobile App
+- Your Prose Server is configured to point at an accessible Discourse instance
+- Your Discourse instance is up and running correctly
+
+## Nice Work!
+
+At this point, you've already accomplished a lot.
+
+The Discourse server you started off with is now accessible in a new way from a sleek native mobile app, and you're free to customize it to your heart's content.
+
+In the next part of the tutorial, we'll briefly get into that very topic: customizing the Mobile App to [white label](white-label) it for your brand.
diff --git a/documentation/versioned_docs/version-1.0.0/tutorial/setup.md b/documentation/versioned_docs/version-1.0.0/tutorial/setup.md
new file mode 100644
index 00000000..20505940
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/tutorial/setup.md
@@ -0,0 +1,98 @@
+---
+title: Setup your Development Machine
+---
+
+## Install NodeJS
+
+If you haven't already, install NodeJS on your machine.
+
+The tooling needed to setup Lexicon relies heavily on Node and npm.
+
+If you are unsure of how to install NodeJS, you can follow the instructions on the [NodeJS Website](https://nodejs.org/en/download/).
+
+#### Supported Node Versions
+
+It is recommended that you perform this tutorial using the latest version of Node that is compatible with the the project's version of Expo.
+
+You can always confirm this by viewing the dependencies in [frontend/package.json](https://github.com/lexiconhq/lexicon/blob/master/frontend/package.json).
+
+If your setup doesn't allow you to easily change your current Node version, we would recommend making use of [`nvm`](https://github.com/nvm-sh/nvm) to quickly switch between Node versions.
+
+### Install yarn, if you prefer
+
+Lexicon doesn't leverage any special features of [Yarn](https://yarnpkg.com/) - the alternative package manager for Node. If you prefer it, it will work the same as running `npm install`.
+
+For the purposes of this tutorial, we will demonstrate all commands using `npm`.
+
+### Clone the Lexicon Repository
+
+In a desirable location on your development machine, clone the Lexicon repository and `cd` into it.
+
+```sh
+git clone git@github.com:lexiconhq/lexicon.git
+cd lexicon
+```
+
+### Install Dependencies
+
+Next, install Lexicon's dependencies:
+
+```sh
+npm install
+```
+
+This will install dependencies for both the Mobile App and the backend GraphQL API, Prose.
+
+### Install the Expo CLI
+
+[Expo](https://expo.io/) is the phenomenal toolchain that Lexicon uses to develop and build the Mobile App.
+
+We will later use the Expo CLI to launch the Mobile App - either on your device or in a simulator.
+
+You can install the Expo CLI with the following command:
+
+```sh
+npm install --global expo-cli
+```
+
+Further information is available in the [Expo docs](https://docs.expo.io/).
+
+Then, verify that Expo is available in your `PATH` with the following:
+
+```sh
+$ expo --version
+
+```
+
+### Install the EAS CLI
+
+[Expo Application Services (EAS)](https://expo.dev/eas/) is an integrated set of cloud services for Expo and React Native apps.
+
+We will use the EAS CLI to build and publish the Mobile App.
+
+You can install the EAS CLI with the following command:
+
+```sh
+npm install --global eas-cli
+```
+
+Further information is available in the [Expo docs](https://docs.expo.dev/eas/).
+
+Then, verify that EAS is available in your `PATH` with the following:
+
+```sh
+$ eas --version
+eas-cli/
+```
+
+### Ready to Go!
+
+That's all we need for this step.
+
+Next, there is an optional guide to help you if you're not too familiar with setting up a server on a cloud provider.
+
+You're free to skip this if you're already adept at this process.
+
+After that, we'll look into how we can prepare Discourse to connect with the Lexicon Mobile App.
+
+If you don't already have a Discourse server setup, we'll get into that as well.
diff --git a/documentation/versioned_docs/version-1.0.0/tutorial/updating.md b/documentation/versioned_docs/version-1.0.0/tutorial/updating.md
new file mode 100644
index 00000000..46fcfdd1
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/tutorial/updating.md
@@ -0,0 +1,68 @@
+---
+title: Update your App
+---
+
+## EAS Update
+
+EAS Update is the successor to `expo publish`. This service helps to update projects using the `expo-updates` library.
+
+In particular, it enables you to push quick fixes to your users in between full-fledged app store submissions.
+
+With EAS Update, there is no need to recompile the app with its non-native parts, such as TypeScript code, styling, or image assets. [Click here](https://docs.expo.dev/eas-update/introduction/) to learn more about EAS Update.
+:::note
+You are required to build the app with [EAS Build](building) before using the EAS Update.
+:::
+
+### Configuration
+
+Let's get started by configuring EAS update. Feel free to check out the [complete guide](https://docs.expo.dev/build-reference/build-configuration/) from Expo for further details.
+
+```bash
+eas update:configure
+```
+
+Running this command will add `expo.updates.url` and `runtimeVersion.policy` in `app.json`.
+
+:::caution
+
+As mentioned in the [Expo documentation](https://docs.expo.dev/build/updates/#previewing-updates-in-development-builds), you can no longer launch your app in Expo Go (using `expo start`) after adding the `runtimeVersion` field in `app.json`. It is recommended to use `expo-dev-client` instead to create a development build.
+
+```bash
+eas -p all -e development
+```
+
+or if you still wish to use Expo Go, please remove `runtimeVersion` field from `app.json` before running `expo start`.
+:::
+
+### Updating
+
+After making the necessary changes, you can push updates using this command:
+
+```bash
+eas update โ-branch โ-message โโ
+```
+
+The branch name here is the same as the build profile name when building the app.
+For example, if you had previously built the app with this command:
+
+```bash
+eas build โp all โe preview
+```
+
+Then you can later update it using:
+
+```bash
+eas update โ-branch preview โ-message โFixing typosโ
+```
+
+Once the update is complete, force close and reopen the installed app twice to view the update.
+
+## All Done! ๐
+
+That's it for the tutorial. Great work.
+
+We hope that this has served as an informative guide to help familiarize you with Lexicon and how you can make use of it.
+
+If you haven't already, check out the [Lexicon Documentation](../) to get a deeper understanding of the project and how it all works.
+
+If you have any questions, comments, feedback, or want to contribute, please reach out to us on Github!
diff --git a/documentation/versioned_docs/version-1.0.0/tutorial/white-label.md b/documentation/versioned_docs/version-1.0.0/tutorial/white-label.md
new file mode 100644
index 00000000..f0192667
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/tutorial/white-label.md
@@ -0,0 +1,82 @@
+---
+title: White Label your App
+---
+
+## Customize the Splash Screen and App Icon
+
+In order to customize the app for your own brand, you will likely want to provide your own assets for the **Splash Screen** and the **App Icon**.
+
+The **Splash Screen** - sometimes also referred to as the Launch Screen - is what appears while the app is launching. Some apps also display this to help conceal private information when the app is put into background mode.
+
+The **App Icon** is what is used to represent the app on the user's device, such as on the home screen and when listing it in the device's settings.
+
+Both of these assets often contain your logo in one form or another. For example, the App Icon for the Gmail app is the multi-colored outline of an envelope. Then, when launching the Gmail app, you will notice that the Splash Screen includes a larger version of the App Icon.
+
+### Customizing the Splash Screen
+
+:::info
+Expo does not currently support dark mode for splash screens.
+:::
+
+The assets used for the splash screen in the Mobile App are located at `frontend/assets/images/splash.png` and `frontend/assets/images/splashDark.png`.
+
+Above, we mention splash screen assets for both Dark Mode and Light Mode.
+
+However, unfortunately at this time, Expo does not support Dark Mode for Splash Screens. We have only included both so that they're ready when Expo finally does support this.
+
+In the meantime, you're free to adjust `splash.png` to influce what asset appears.
+
+In order to change it, you can simply replace the existing file with your own `splash.png`.
+
+To find out more about the Splash Screen image size and other details, please see the [Expo Splash Screen Guide](https://docs.expo.io/guides/splash-screens/).
+
+#### Futher Configuration
+
+To resize the Splash Screen image and change its background color, first open `frontend/app.json` and locate the `"splash"` field within it.
+
+As illustrated by the excerpt below, there are multiple fields that can be used to further adjust the Splash Screen:
+
+```json
+"splash": {
+ "image": "./assets/splash.png",
+ "resizeMode": "contain",
+ "backgroundColor": "#FFFFFF"
+},
+```
+
+**image**
+
+The `image` field is fairly self-explanatory - it allows you to adjust what path will be used to locate the Splash Screen image.
+
+**resizeMode**
+
+The `resizeMode` field allows you to manage how the Splash Screen image will be resized to maintain its aspect ratio:
+
+- `contain` - Resize the image to make sure the whole image is visible. This is the default setting.
+- `cover` - Resize the image to cover the entire container (in this case the whole screen) by either stretching or cropping the image as needed.
+
+Further details of how `contain` and `cover` behave are covered in the previously mentioned [Expo Splash Screen guide](https://docs.expo.io/guides/splash-screens/). For an even more detailed explanation, you can read [this post](http://blog.vjeux.com/2013/image/css-container-and-cover.html).
+
+**backgroundColor**
+
+The `backgroundColor` field enables you to specify the color of the background behind the Splash Screen image. Removing this value will result in usage of the default value, which is a white background color.
+
+### Customizing the App Icon
+
+Customizing the App Icon in Lexicon is nearly the same process as customizing the Splash Screen.
+
+The image asset for the Mobile App's icon is located at `frontend/assets/icon.png`. To customize it, simply overwrite that file with your own `icon.png`.
+
+## Further Customization
+
+We get into more detail about how to white label your app in the [White Labeling](../white-labeling) section of the documentation.
+
+In particular, this includes customizing and extending the theme's color palette, icons, and even fonts.
+
+Should you wish to customize anything not covered in that section, get in touch with us, and we'll see how we can help you make it a reality.
+
+## Awesome Work
+
+Your app looks cool now ๐. However, it's only accessible to you.
+
+Next, we'll cover how you can actually [build your app](building), so you can share it with the world.
diff --git a/documentation/versioned_docs/version-1.0.0/white-labeling.md b/documentation/versioned_docs/version-1.0.0/white-labeling.md
new file mode 100644
index 00000000..be413831
--- /dev/null
+++ b/documentation/versioned_docs/version-1.0.0/white-labeling.md
@@ -0,0 +1,13 @@
+---
+title: Overview
+---
+
+The Lexicon Mobile App allows you to customize its appearance through a process known as **White Labeling**.
+
+If you're unfamiliar with this term, it's essentially the process of branding an existing application specifically for your users.
+
+White Labeling allows you to configure the app with your own logo, app icon, color theme, fonts, and so on.
+
+The idea is that your users won't know that the Lexicon team built this app. Its appearance will be completely customized to your brand.
+
+To learn more about White Labeling the Lexicon Mobile App, continue to the next section.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/app-store.md b/documentation/versioned_docs/version-2.0.0-beta/app-store.md
new file mode 100644
index 00000000..f91b5fa0
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/app-store.md
@@ -0,0 +1,282 @@
+---
+title: Publishing to the App Store
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+At this point, you've at least made some minor adjustments to the Lexicon Mobile App, and are ready to publish it so that your users can download it.
+
+In this page, we'll cover the process of publishing it on iOS.
+
+## Prerequisites
+
+- An Apple Developer account
+- An Expo account
+- XCode is installed on your development machine
+- EAS CLI 2.6.0 or newer
+- The [Lexicon Discourse plugin](./discourse-plugin.md) is already installed on your Discourse instance
+
+To get started with TestFlight and publishing your app, you'll need an **Apple Developer account**.
+
+This will enable you to interact with Apple as you go through the process of submitting to TestFlight and, eventually, the App Store.
+
+You'll also need an [Expo account](https://expo.dev/signup) so you can build your app, download it, and upload it to Apple's servers.
+
+Finally, you'll want to have already downloaded and installed [Xcode](https://developer.apple.com/xcode/), which is what you'll use to upload your built app to Apple's servers.
+
+:::note
+If you don't yet have an account with Apple, you'll need to enroll in the [Apple Developer Program](https://developer.apple.com/programs/enroll/) first. Note that there is an annual cost associated with this.
+
+Additionally, you'll want to make sure you have an account with [Expo](https://expo.dev/signup) so you can use features like [EAS Submit](https://docs.expo.dev/submit/introduction/).
+:::
+
+## Register a new Bundle ID
+
+Each app in Apple's App Store has a unique **Bundle Identifier**, or Bundle ID.
+
+In order to publish the app anywhere, including to TestFlight, you'll need to have a Bundle ID registered for your app with Apple.
+
+Typically, this uses the format of `com..`.
+
+For example, if your company is named Expo, and your app is named Expo Go, your Bundle ID could be:
+
+```
+com.expo.expogo
+```
+
+You can follow these instructions to get one.
+
+- Go to [Certificates, Identifiers & Profiles](https://developer.apple.com/account/resources/identifiers/bundleId/add/bundle).
+- Fill in the following fields, and then click `Continue`
+
+
+ - **Description**: You can insert the app name as its description.
+
+ - **Bundle ID**: Select `Explicit`, and then insert then insert your bundle ID in the input field.
+
+- Capabilities
+
+ - You can leave this section empty.
+
+## Add a New App in App Store Connect
+
+Steps:
+
+- Sign in to your [App Store Connect](https://appstoreconnect.apple.com/) account.
+- Click on `My Apps`.
+
+- Click on the `+` button to add new app.
+
+- Fill out the requested information about your app, and then click `Create`.
+
+
+ - **Platforms**: Select `iOS`.
+ - **Name**: The name of your app, as it will appear on the App Store and user's devices.
+ - **Primary Language**: The primary language that will be used if localized app information is not available.
+ - **Bundle ID**: Choose the Bundle ID you created above.
+ - **Note**: double-check that it's correct, because you can not change it afterwards.
+ - **SKU (Stock Keeping Unit)**: A unique ID to differentiate your app from the others, similar to a product ID.
+ - **User Access**: Full access means all users will have access to the app, while limited access means that the app can only be accessed by certain roles defined within App Store Connect.
+
+## Configuration
+
+After creating the app in App Store Connect, you'll want to jump back over to the codebase and make some adjustments.
+
+### Build Config
+
+:::note
+If you haven't yet installed the EAS CLI, follow the instructions in the [tutorial](tutorial/setup#install-the-eas-cli).
+:::
+
+First, you'll need to ensure you've set your app name and slug in `frontend/app.json`. The [slug](https://docs.expo.dev/workflow/glossary-of-terms/#slug) is used as part of the URL for your app on Expo's web services, so it is recommended to use kebab-case (e.g., `my-lexicon-app`).
+
+Replace these placeholders with your desired values:
+
+:::info
+Note below that `scheme` is included. If you want [email deep linking](./email-deep-linking/intro.md) support in your app, **you must specify a scheme**, and then configure the Lexicon Discourse plugin with the same scheme.
+:::
+
+```json
+"name": "",
+"slug": "",
+"scheme": "",
+```
+
+Next, configure EAS Build by running this command from the `frontend/` directory:
+
+```bash
+eas build:configure
+```
+
+The EAS CLI will prompt you to specify `android.package` and `ios.bundleIdentifier` if those values are not already provided in `app.json`. You'll want to add the bundle ID you just registered in App Store Connect as the `bundleIdentifier`.
+
+Then you can see that the value has been updated in the `ios` section of `frontend/app.json` file.
+
+```json
+ "ios": {
+ "supportsTablet": false,
+ "buildNumber": "1.0.0",
+ "bundleIdentifier": "",
+ "config": {
+ "usesNonExemptEncryption" : false
+ }
+ },
+```
+
+:::note
+We set `usesNonExemptEncryption` to `false` because Lexicon doesn't leverage that feature.
+
+For further details, please take a look at [this link](https://developer.apple.com/documentation/bundleresources/information_property_list/itsappusesnonexemptencryption) from Apple's documentation.
+:::
+
+### Setup Config Values
+
+:::info
+When publishing your app, it is necessary to deploy Prose somewhere publicly accessible, perhaps on a cloud hosting provider like AWS or DigitalOcean. If Prose is only running on your local machine, users that download your app won't be able to use it.
+Check [the documentation](deployment) to deploy Prose if you haven't already.
+:::
+
+Next, configure the **Prose URL** for your build in `Config.ts`. You can set a different URL for each build channel.
+
+:::note
+In the original release of Lexicon, the **Prose URL** was specified in `frontend/.env`. However, as part of migrating to Expo's EAS feature, we centralized the configuration into `frontend/Config.ts` to save you the trouble of needing to maintain it in more than one place, as suggested in the [Expo documentation](https://docs.expo.dev/build-reference/variables/#can-i-share-environment-variables-defined-in-easjson-with-expo-start-and-eas-update)
+:::
+
+```ts
+const config = {
+ // ...
+ buildChannels: {
+ preview: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ production: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ },
+};
+```
+
+### Setup Apple Dveloper Account
+
+Lastly, please adjust these fields in `eas.json` with your account information to submit the app:
+
+```json
+ "base": {
+ "ios": {
+ "appleId": "",
+ "ascAppId": "",
+ "appleTeamId": ""
+ },
+ ...
+ },
+```
+
+- **appleId**: your apple ID (e.g., `john@gmail.com`).
+- **ascAppId**: your App Store Connect app ID. Find your ascAppID by following [this guide](https://github.com/expo/fyi/blob/main/asc-app-id.md) (e.g., `1234567890`).
+- **appleTeamId**: You can check your apple team ID [here](https://developer.apple.com/account/) (e.g., `12LE34XI45`).
+
+## Build your App for iOS
+
+Before publishing, you'll need to build your app by instructing Expo to generate an iOS build.
+
+It is recommended to build your app with the `preview` profile before releasing to verify that it works as expected. See [this tutorial](tutorial/building) to learn more about build profiles.
+
+Run this command:
+
+```bash
+eas build --platform ios --profile preview
+```
+
+When you run the above command, Expo will prompt you for your Apple ID and password.
+
+Once the above step has been completed, login to your account on [Expo](https://expo.dev) and download your newly built app.
+
+Navigate to your project in the [Expo web console](https://expo.dev), then click on the **Builds** menu located on the left-hand side of the screen.
+
+- Click on the project you want to install.
+
+
+- Download the iOS build by pressing the `Download` button in the `Build Artifact` section.
+
+
+This will download a tar file containing your app. Extract the file, then drag it to your simulator to install it. See [this section](tutorial/building#1-preview) of the tutorial to learn about running the app on real devices.
+
+Once you have verified that the app runs as expected, you can proceed to build it for release:
+
+```bash
+eas build --platform ios --profile production
+```
+
+The approach for a production build is similar to the one used for generating a preview build. However, unlike a preview build, you won't be able to launch the production build in the iOS simulatorโit is intended solely for publishing to the App Store.
+
+Once this process is completed, you can proceed with submitting it to Apple. This process typically involves Apple's TestFlight service.
+
+## Submit to TestFlight
+
+TestFlight is a key aspect of Apple's Developer Program, which enables developers to provide beta users with access to their app under less restrictive review requirements.
+
+With TestFlight, you're able to invite users to test your app and collect their feedback before releasing it to the public on the App Store. You can learn more about TestFlight [here](https://developer.apple.com/testflight/).
+
+Submitting an iOS app is much easier with EAS Submit. This is covered in more detail in the [tutorial](tutorial/publishing).
+
+Run the following command to start publishing the app to TestFlight:
+
+```bash
+eas submit --platform ios --profile production
+```
+
+Once the process has completed successfully, we can check the build in App Store Connect.
+
+In App Store Connect, click on the TestFlight Tab.
+
+You'll see the [status](https://help.apple.com/app-store-connect/#/dev3d6869aff) of your built version.
+
+- **Red** indicates that you need to perform some action.
+- **Yellow** indicates that some aspect of the process is pendingโeither from you, or from Apple.
+- **Green** indicates that the build is being tested in TestFlight, or is ready to be submitted for review.
+
+You won't be able to begin beta testing with TestFlight until an official tester from Apple verifies your app.
+
+In order to allow Apple to properly test your Lexicon-powered app, they'll need to have credentials to login your Discourse site.
+
+Before submitting your app, you'll need to create those credentials in Discourse and specify them in App Store Connect.
+
+- In App Store Connect, click on your app.
+- Click on TestFlight App.
+- Click on Test Information in the sidebar on the left-hand side.
+- Fill the required fields, then check the `Sign in required` checkbox, and enter the credentials.
+
+- Please also provide information for a person to contact if the review team needs additional information.
+
+
+### Specify Users for Beta Testing
+
+Beta Test Users can belong to an Internal Group or an External Group.
+
+You can specify internal users by going to the Internal Group section, and clicking on **App Store Connect Users**.
+
+Similarly, you can specify external users by selecting External Groups, and clicking on **Add External Testers**.
+
+#### More Information
+
+TestFlight and App Store Connect are sophisticated tools to help with the process of submitting, testing, and publishing your app.
+
+If you have further questions or just want to learn more, we'd recommend that you make use of Apple's documentation, which is very high quality.
+
+For more information about TestFlight in general, read the [documentation](https://developer.apple.com/testflight/).
+
+Similarly, for specific information about beta testing with TestFlight, check out [Testing Apps with TestFlight](https://testflight.apple.com/).
+
+## Publish to the App Store
+
+Once you've successfully passed Apple's review process and have received enough feedback from your beta testers, you're ready to publish to the App Store and go live! :tada:
+
+As a few final reminders, double-check that...
+
+- Your Discourse instance is online, reachable, and functioning correctly.
+- The built version of your app is configured to point at the correct Prose server.
+- Your Prose server is online, reachable and healthy.
+- Your Prose server is deployed with the [recommended guidlines](dedicated#configure--deploy-prose) for production.
+ - In particular, ensure that its traffic is encrypted using an SSL certificate.
+
+Next, we'll guide you through the process of publishing your app for Android devices on the Google Play Store.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/assets.md b/documentation/versioned_docs/version-2.0.0-beta/assets.md
new file mode 100644
index 00000000..a24dcad0
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/assets.md
@@ -0,0 +1,47 @@
+---
+title: App Icon & Other Assets
+---
+
+The Lexicon Mobile App contains multiple assets that can be replaced in order to White Label it.
+
+The assets that can be modified are as follows:
+
+## App Logo
+
+Used to show the app logo in the application, such as on the Login, Register, and 2FA Scenes.
+
+The assets are located at `frontend/assets/images/logo.png` and `frontend/assets/images/logoDark.png`. The `logo.png` is used in light color scheme and `logoDark.png` is used in dark color scheme. To customize it, simply replace the existing file with your own `logo.png` and `logoDark.png`.
+
+## Favicon
+
+Used to show the app logo.
+
+The asset is located at `frontend/assets/favicon.png`. To customize it, simply replace the existing file with your own `favicon.png`.
+
+## Image Placeholder
+
+Used to temporarily take an image place when it is loading.
+
+The asset is located at `frontend/assets/images/imagePlaceholder.png`. To customize it, simply replace the existing file with your own `imagePlaceholder.png`.
+
+## Icons
+
+Used to display icons inside the application.
+
+The assets are located in the `frontend/assets/icons` folder. If you want to add more or edit the remaining icons, you need to insert the icons to the `frontend/assets/icons/` folder and import them in `frontend/src/icons.ts`.
+
+There are some standards applied to the icons, such as:
+
+#### Uniform Icon Size to Maintain Visual Consistency
+
+The UI is designed around the default base dimensions of 28x28px for icons.
+
+If you adjust this, you may need to modify other aspects of the theme or fonts in order to maintain a clean appearance.
+
+Similarly, if you provide a new icon that does not conform to these dimensions, you may run into visual inconsistencies.
+
+#### SVG Icons have their Fill Color Controlled via `currentColor`
+
+If you are adding a new icon that you expect to interact with theme's colors, ensure that its color is not hard-coded, and is instead set to `currentColor`.
+
+If you are unfamiliar with this concept, take a look at the [MDN Specification on SVG color values](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/color).
diff --git a/documentation/versioned_docs/version-2.0.0-beta/commercial-support.md b/documentation/versioned_docs/version-2.0.0-beta/commercial-support.md
new file mode 100644
index 00000000..9d164810
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/commercial-support.md
@@ -0,0 +1,9 @@
+---
+title: Commercial Support
+---
+
+With official support, you get expert help straight from the core team. We provide app customization, dedicated support, prioritize feature requests, deployment strategies, advice on best practices, design decisions, and team augmentation.
+
+Additionally, we are open to engagements for non-technical site owners looking to customize, deploy, and launch a mobile app for their Discourse users.
+
+Reach out to us for consulting at support@kodefox.com.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/concepts.md b/documentation/versioned_docs/version-2.0.0-beta/concepts.md
new file mode 100644
index 00000000..e1d3f780
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/concepts.md
@@ -0,0 +1,68 @@
+---
+title: Concepts and Architecture
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+## Prose: Discourse through GraphQL
+
+It is worth acknowledging upfront that Discourse already provides a traditional, RESTful API for developers out of the box.
+
+However, [the official documentation](https://docs.discourse.org/) for this API points out that it is incomplete, effectively serving as a starting point.
+
+> Note: For any endpoints not listed you can follow the reverse engineer the Discourse API guide to figure out how to use an API endpoint.
+>
+> โ**Discourse API Documentation**
+
+The core team, as well as members of the [support forum](https://meta.discourse.org), regularly respond to questions about the API by [encouraging developers to reverse-engineer the API](https://meta.discourse.org/t/how-to-reverse-engineer-the-discourse-api/20576). As of this writing, the topic for how to reverse engineer the API has been linked to from nearly 200 other topics on the support forum.
+
+To help you simplify the process for you, Prose strives to normalize a subset of the API. We have done so with the hope that it will save you some time as you develop against Discourse.
+
+#### GraphiQL
+
+Prose's GraphQL implementation includes an [in-browser GraphQL IDE](https://www.graphql-yoga.com/docs/features/graphiql), known as [GraphiQL](https://github.com/graphql/graphiql), which allows developers to easily reference the entire documentation and schema and make queries against a running Discourse instance.
+
+
+
+This means you can rapidly get a clear understanding of how a method behavesโand what parameters it requiresโwithout digging through support posts or reverse-engineering the REST API.
+
+#### Why GraphQL?
+
+There is no shortage of articles about both the [benefits](https://www.howtographql.com/basics/1-graphql-is-the-better-rest) and [tradeoffs](https://lwhorton.github.io/2019/08/24/graphql-tradeoffs.html) of GraphQL.
+
+We're well aware that GraphQL isn't some magical solution that solves all the problems of other API paradigms.
+
+Having said that, we chose to build Lexicon with it for two primary reasons.
+
+1. Our team is familiar and fluent with GraphQL, and deeply enjoys working with it.
+
+2. The tooling, libraries, and auto-generated documentation provide out-of-the box benefits which we can pass onto others with no additional effort.
+
+#### Why Expo?
+
+[Expo](https://docs.expo.io/) is both a framework and a platform for building universal React applications. In particular, it provides a superior development experience when building mobile apps with React Native.
+
+We find that Expo makes us much more effective as developers, and also provides excellent services to facilitate the entire process of building and publishing React Native apps.
+
+In particular, Discourse sites that leverage the [Lexicon Discourse Plugin](./discourse-plugin.md) get the benefit of [push notifications](./push-notifications) through Expo's [push notifications service](https://docs.expo.dev/push-notifications/overview/), which abstracts away Google and Apple's push services into a simple interface.
+
+## Lexicon Architecture
+
+The Lexicon Stack is fairly simple, and only consists of 3 major pieces:
+
+- The Lexicon Mobile App
+- The Prose GraphQL API
+- A running, accessible Discourse instance
+ - Optionally, you can install our [Discourse Plugin](./discourse-plugin.md) to enable additional features.
+
+Below is a diagram illustrating the typical architecture for a Lexicon-powered mobile app.
+
+
+
+As indicated above, the mobile app makes requests to a deployed Prose GraphQL server.
+
+The Prose server has been configured to point at an active Discourse instance of the developer's choice.
+
+If the [Lexicon Discourse Plugin](./discourse-plugin.md) is installed, additional endpoints will be exposed which Prose already knows how to communicate with.
+
+Traffic then flows back from Discourse, through Prose, and returns to the mobile app over a GraphQL interface.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/contributing.md b/documentation/versioned_docs/version-2.0.0-beta/contributing.md
new file mode 100644
index 00000000..0fe6fbe9
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/contributing.md
@@ -0,0 +1,131 @@
+---
+title: Contributing
+---
+
+Thank you for your interest in contributing! :sparkles:
+
+We greatly appreciate the time and effort you're willing to put forth to make Lexicon even better.
+
+There are several ways to help out.
+
+## Reporting Bugs
+
+The best way to let us know about a bug is by [creating a new issue](https://github.com/lexiconhq/lexicon/issues/new) on [Github](https://github.com/lexiconhq/lexicon).
+
+As always, we recommend searching the existing open and closed issues before opening a new one.
+
+When you create the issue, please be sure to include the following:
+
+- A detailed description of the bug and its behavior
+
+- The behavior you expected instead of the bug
+
+- A list of steps for how to reproduce the bug
+
+- Details about the device(s) and version(s) you're observing the bug on
+
+- Screenshots and screen recordings, while not necessary, are very welcome!
+
+Once we've received your bug report, we will triage it and label it accordingly.
+
+## Contribute to the Project
+
+Want the honor of being listed in our contributors section :clap:?
+
+We'd love to get a PR from you addressing an existing issue, adding a feature, or even just improving the documentation.
+
+To get started contributing, follow the instructions below.
+
+### Instructions
+
+**1. Fork the [official Lexicon repository](https://github.com/lexiconhq/lexicon)**
+
+You probably already know the drill - click on **Fork** button on the upper-right corner.
+
+**2. Clone your Fork of Lexicon**
+
+Be sure to clone **_your_** fork to your development machine (as opposed to cloning the main Lexicon repository).
+
+```
+$ git clone https://github.com/YOUR_USERNAME/lexicon.git
+```
+
+If you need further guidance with cloning, head over to our [Quick Start](quick-start#installation) section.
+
+Just bear in mind that the Quick Start section walks you through cloning the Lexicon repository. So make sure you change the URL to your username as referenced above.
+
+**3. Run and connect the app with Prose and a Discourse Host**
+
+For a comprehensive walk-through of this step, follow the instructions in the [**Setup**](setup#discourse-host) section.
+
+If you already have a deployed Prose instance that is pointing at a Discourse instance, you can simply configure the Lexicon Mobile App to point at the address of your Prose deployment.
+
+However, if you don't have that, or if you're planning on making adjustments to the Prose server itself, you'll want to ensure the Lexicon Mobile App is configured to point at a Prose server that you have running locally.
+
+**4. Get Started with your Contribution**
+
+At this point, you should be setup to dig in on the main work of your feature, bugfix, or other contribution.
+
+Remember that it's necessary to have the [**ESLint**](https://eslint.org/docs/user-guide/getting-started) and [**Prettier**](https://prettier.io/) plugins installed in your IDE, as those are required in order for the Pull Request checks to pass.
+
+We would recommend working in [VSCode](https://code.visualstudio.com/), since that is what we used to develop Lexicon. However, it is up to you, you only need to ensure that ESLint and Prettier are functioning properly within your IDE.
+
+**5. Run the Test Suite**
+
+Follow these [**steps**](setup#run-the-test-suite) to run the Lexicon test suite.
+
+In order to speed up the feedback cycle, it is recommended that you ensure that all tests are passing locally before pushing, especially if you already have an open PR.
+
+This is primarily because we have configured our Github project to block PRs from being merged if any of the build steps fail.
+
+If the reviewers see that tests are failing, they aren't able to review it as quickly, and will likely request that you resolve any build issues before requesting review again.
+
+**6. Stage, Commit, and Push your Local Changes**
+
+If you're unfamiliar with this process, please take a look at this [great article](https://github.com/git-guides/#learning--mastering-git-commands) from Github to bring you up to speed.
+
+**7. Create a New Pull Request**
+
+Your code is ready to submit! :tada:
+
+Go to the Lexicon [Pull Requests tab](https://github.com/lexiconhq/lexicon/pulls), and compare the changes between your branch and the master branch.
+
+Double-check and make sure you didn't push anything you don't want included in your PR.
+
+Then, go ahead and create a new Pull Request from your forked repository.
+
+Please be sure to follow the Pull Request template, add related labels, and please mention the issue you are addressing to help us keep track of what's being worked on.
+
+## Share Your Thoughts with Us
+
+We'd love to hear your new ideas! Drop them in the [Issues tab](https://github.com/lexiconhq/lexicon/issues).
+
+## Spread the Word
+
+Let others know about your awesome experience using Lexicon on social media, and tag us on Twitter [@GetLexicon](https://twitter.com/GetLexicon).
+
+And if you build your app using Lexicon, please let us know. We'd love to help you spread the word about what you've built!
+
+## Improve the Documentation
+
+As a closing thought, if you find any issues with the Lexicon documentation, or just think you could make it better, you can get started with these brief instructions below.
+
+To generate and run the documentation locally, from the project root, run:
+
+```sh
+npm run docs:start
+```
+
+Similarly, you can build the documentation using:
+
+```sh
+npm run docs:build
+```
+
+All documentation is in the `documentation/` directory, and the Markdown pages used to generate this site are under `documentation/docs`.
+
+If you end up making a PR to improve the documentation, please be sure to label your PR with the `Documentation` label.
+
+:::note
+Don't hesitate to ask if you have any further questions. We're always happy to help. :smile:
+:::
diff --git a/documentation/versioned_docs/version-2.0.0-beta/customize.md b/documentation/versioned_docs/version-2.0.0-beta/customize.md
new file mode 100644
index 00000000..6797d756
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/customize.md
@@ -0,0 +1,28 @@
+---
+title: Customization
+---
+
+## Theming
+
+As part of its [White Labeling Support](white-labeling), Lexicon allows you to customize the theme of the mobile app.
+You can configure the base and functional colors according to a color scheme of your choosing.
+You're also able to customize icons, fonts, and even the error messages that appear inside of the mobile app.
+To get started with this, check out the [Theming page](theming) under the [White Labeling](white-labeling) section.
+
+## White Labeling the Mobile App Assets
+
+To provide your users with a unique experience that matches your brand, you can customize the splash screen and app icon on their device.
+
+This will replace all Lexicon branding with your own.
+
+Further details can be found in both the [Tutorial](tutorial/white-label) and the [White Labeling Section](white-labeling) of this documentation.
+
+## Enabling Additional Discourse features
+
+As you might already be aware, Discourse is a highly customizable piece of software. Much of it is customizable from the Admin Site Settings page on your Discourse instance.
+
+Some of these settings will translate automatically into the Lexicon Mobile App, such as `authorized extensions`.
+
+In general, we have done our best to get out of the way and use Discourse as the source of truth for how the Lexicon Mobile App should appear and behave.
+
+If you find any settings that Lexicon is not responding to, but you feel it should, please open an issue and let us know.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/dedicated.md b/documentation/versioned_docs/version-2.0.0-beta/dedicated.md
new file mode 100644
index 00000000..75fe8afe
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/dedicated.md
@@ -0,0 +1,300 @@
+---
+title: Hosting & Configuration
+---
+
+As mentioned in the [Overview](deployment), this section is meant to guide you through configuring and deploying Prose on a dedicated instance.
+
+## Decide on Where to Host
+
+First, you'll need to answer the following question. Where would you like to host Prose?
+
+While there are many options that vary by project and developer preferences, the simplest way is often to use a cloud provider of your choice.
+
+In the [Lexicon tutorial](tutorial/setup-cloud-server), we walk you through this process using Digital Ocean.
+
+If you're confused about this step, or don't have a preference, you should take some time to work through it.
+
+However, if you already know what you're doing, feel free to use any cloud provider or hosting solution of your choice.
+
+### Hosting Checklist
+
+Once you've decided on a host, go through the checklist below to verify that everything is setup as expected.
+
+#### โ
Ensure Access & Permissions on the Host
+
+At a minimum, you will need to be able to login to the host. Some cloud providers offer a virtual, web-based terminal, but ideally you can get credentials to login directly.
+
+If your host is in a UNIX-based environment, you should also have permissions to run commands as `sudo`.
+
+A quick way to check this is to simply attempt to run a command with `sudo`:
+
+```sh
+$ sudo ls
+```
+
+However, if you have a restrictive hosting environment, you will just need a way to place the Lexicon source onto the host, install its dependencies, and expose it on a port.
+
+Bear in mind that a restrictive hosting environment is not ideal, especially since the recommended setup makes use of Docker.
+
+#### โ
Ensure the Host is reachable in the way you need it
+
+Typically, this means that your host is accessible on the open internet.
+
+However, you might have different constraints, such as only needing the host to be accessible from within a VPN or a local network.
+
+
+
+Once you have setup a host which is reachable in the way you need it to be, you can begin configuring Prose on it.
+
+## Configure & Deploy Prose
+
+### Without Docker
+
+Naturally, setting up Prose without Docker involves more manual steps and can be platform-specific.
+
+We have already covered this approach well in the tutorial. In particular, you can dig in with it on the page, [Setup the Prose GraphQL API](tutorial/install-prose#install-manually)
+
+### With Docker
+
+The Prose Docker image comes preconfigured to run Prose using **[PM2](https://pm2.keymetrics.io/)**, which is a sophisticated toolset for running Node processes in production.
+
+This is typically a reasonable setup, with which you can even expose the PM2 server directly to requests on the host.
+
+However, if you'd prefer a different setup, perhaps using Nginx as a reverse proxy to the Docker container, feel free to modify the Dockerfile to match your requirements.
+
+#### Install Docker
+
+**[Docker](https://www.docker.com/)** is a containerization framework that makes it easy to build, manage, and deploy your application stack in a way that is safer, more reliable, and reproducible across multiple platforms.
+
+There are countless guides available for installing Docker on a given operating system.
+
+Ubuntu is one of the more common operating systems avaiable through most cloud providers.
+
+Docker provides a [full tutorial](https://docs.docker.com/engine/install/ubuntu/) for this, and even provides a convenience script that you can run in two lines:
+
+```sh
+curl -fsSL https://get.docker.com -o get-docker.sh
+sudo sh get-docker.sh
+```
+
+Whichever path you need to take, just make sure that Docker is up and running on your host before continuing.
+
+#### Configure Environment Variables
+
+A comprehensive list of all Prose environment variables can be found on the [Environment Variables](env-prose) page.
+
+In brief, at a minimum, you'll want to ensure that `PROSE_DISCOURSE_HOST` is set.
+
+Another variable to pay attention to is `PROSE_APP_PORT`. This defaults to port 80, which instructs Prose to listen on that port.
+
+Depending on your setup, you might want it to listen on a different port.
+
+
+
+#### Build Prose from the Dockerfile
+
+If you'd like to use Docker to manually build Prose, run the following command from the **project root**.
+
+This might be of interest to you if you'd like to make some adjustments to the Dockerfile itself.
+
+Alternatively, if you simply wish to pull the latest Prose build from Docker Hub, you can [skip to the next step](#pulling-the-prose-docker-image).
+
+Unless you've made modifications to the Dockerfile and have it stored elsewhere, you can get started building by running:
+
+```bash
+docker build -t prose:latest -f api/deploy/Dockerfile api/
+```
+
+The command searches for the `Dockerfile` at `api/deploy/Dockerfile` because we instructed it to look there with the `-f` flag.
+
+Then, it uses `api/` as the context for the build, which allows the references in the `Dockerfile` to resolve correctly.
+
+By passing the `-t prose:latest` tag, it tags the locally built image as the latest build. This can be useful for identifying and managing the images in a Docker environment over time.
+
+#### Pull the Prose Docker Image
+
+If you'd rather just use the latest release of the Prose image, you can simply run:
+
+```
+docker pull kodefox/prose:latest
+```
+
+#### Run the Prose Docker Container
+
+Next, to run the newly built image, run the following command:
+
+```bash
+docker run -d \
+ -e PROSE_DISCOURSE_HOST=https://discourse.example.com \
+ -e PROSE_APP_PORT=4000 \
+ --name prose \
+ -p 5000:4000 \
+ kodefox/prose:latest
+```
+
+:::note
+If you built the image by hand, you'll want to substitute `kodefox/prose:latest` with the image name and tag you used, such as `prose:latest`.
+:::
+
+To recap, let's briefly break down that command line-by-line
+
+**Run in Detached Mode**
+
+```bash
+docker run -d
+```
+
+The first line lets Docker know to run the container in **detached mode**.
+
+This means that the command will run in the background, will not be tied to your current session, and will keep running even if you log out.
+
+If you omitted the `-d` flag, Docker would run the container in the foreground, and exiting the process in the foreground would stop the container.
+
+**Set Environment Variables**
+
+```bash
+-e PROSE_DISCOURSE_HOST=https://discourse.example.com
+-e PROSE_APP_PORT=4000
+```
+
+These lines instruct Docker to pass the environment variables of `PROSE_DISCOURSE_HOST` and `PROSE_APP_PORT` to the container when running it.
+
+These are both application-level environment variables that Prose itself will leverage to run properly.
+
+The Docker image expects these values to be set and passes them to the container's environment, which Prose then accesses via `process.env`.
+
+**Name the Container**
+
+```bash
+--name prose
+```
+
+This line tells Docker to give the running container a name. This makes it easier to identify and interact with via commands, such as:
+
+```bash
+docker stop prose
+```
+
+**Configure a Port Mapping between the Host and the Container**
+
+```bash
+-p 5000:4000
+```
+
+Next, we configure Docker with a port mapping, which tells Docker to listen to map the host port of `5000` to the container port of `4000`.
+
+Because we previously set `PROSE_APP_PORT=4000`, this means that all requests to the host at port `5000` will be forwarded to Prose inside of its container on port `4000`.
+
+```bash
+kodefox/prose:latest
+```
+
+The last line of the command tells Docker which image to use for the container.
+
+Above, if you built the Prose image by hand, it was tagged as `prose:latest`.
+
+If you chose to pull from Docker Hub, this is simply instructing Docker to pull that image if necessary, and then start the container with it.
+
+#### Next Steps
+
+At this point, you should have a Docker container running the Prose server on your host.
+
+However, in terms of preparing your Prose host for production, you aren't quite there yet.
+
+Below, we'll guide you through the last steps, finalizing your deployment of the Prose GraphQL Server.
+
+#### Setup SSL (IMPORTANT)
+
+:::danger
+Deploying Prose without SSL in a way that is publicly accessible is **extremely risky**.
+
+Doing so could provide an attacker with full access to your Discourse site and all of its data.
+:::
+
+The **most important next-step** to take at this point is to configure an SSL certificate for your Prose host.
+
+The reason this is so important is that, without SSL, Prose's traffic between your users' devices and Discourse is not encrypted.
+
+And this means that attackers can snoop on your users' requests to Prose and Discourseโincluding, importantly, their authentication information.
+
+To put it bluntly, deploying Prose without configuring SSL is irresponsible and compromises the security of your Discourse instance.
+
+An attacker could even steal your authentication token and use it to access, and potentially destroy, your Discourse site.
+
+##### How to Setup SSL
+
+There are a variety of methods to obtain SSL certificates. Some are free, and some are paid.
+
+The free route involves using [Let's Encrypt](https://letsencrypt.org/), which is very useful, but can require more technical knowledge to setup correctlyโdepending on your configuration. A key difference is that you need to renew the certificates more frequently.
+
+The paid route involves using a provider like [DigiCert](https://www.digicert.com/) to obtain certificates that take longer to expire.
+
+Either way, you'll end up with certificate files that you can configure and launch your webserver with.
+
+Ideally, at this point, you've already purchased a domain. If you haven't, we'd recommend using a domain provider to get a low-cost domain name.
+
+You could host Prose at a subdomain of your existing Discourse site, like `prose.mydiscoursesite.com`.
+
+Or, you could just get a cheap, nonsense domain, like `purplemonkeydishwasher.tech`โsince your users won't typically see it anyway.
+
+Regardless, to emphasize it again, it is **critical** that you don't deploy Prose into production until you have prepared your host to encrypt the traffic from Prose.
+
+#### Determine how you'll expose Prose on the host
+
+When someone navigates to your host which is running Prose, how will their request get routed to Prose?
+
+If you had exposed Prose directly on port 80โNOT recommendedโand your host's domain name was `myproseserver.com`, then a user would navigate to `http://myproseserver.com` and be greeted with the [GraphiQL interface](https://www.graphql-yoga.com/docs/features/graphiql).
+
+However, a more common approach is to use a dedicated webserver, such as Nginx or Apache, that acts as a reverse-proxy.
+
+With this approach, the websever listens for all requests on the ports you tell it to, and is configured to route traffic to Prose, which is listening on a non-privileged port, like 8080.
+
+We recommend this approach more highly for the following reasons:
+
+- Existing webservers are generally more reliable and performant
+- It allows configuration of an SSL certificate, which is necessary for protecting your users' data
+
+Upon configuring the webserver, you'll need to instruct it to forward traffic to the running Prose server.
+
+Your setup might look something like this:
+
+- Nginx is configured to listen on port 80 and port 443 on your domain, `purplemonkeydishwasher.tech`
+- Nginx has located and loaded your SSL certificate files for `purplemonkeydishwasher.tech`
+- Nginx is configured to upgrade all requests on port 80 to port 443
+- Your Prose server is running inside of Docker on a container port of 80, and exposed to the host on port 8080.
+- Your Nginx configuration specifies that requests to `purplemonkeydishwasher.tech` should be forwarded to port 8080.
+- Requests come in for `purplemonkeydishwasher.tech`, Nginx routes it to the container running Prose, which handles the requests, and responds.
+
+#### Configure your Cloud Provider's Firewall, if one exists
+
+Ideally, you've configured Prose to be exposed on the open internet with the traffic encrypted over port 443.
+
+Depending on your cloud provider, you may need to go into its settings and expose that port on the firewall.
+
+For example, in DigitalOcean, this involves going to the Networking section, and creating a new firewall rule.
+
+From there, it is fairly simple to add common ports, like 80 and 443, to the firewall.
+
+After that, you simply apply the firewall to your particular instance, and traffic should be allowed through.
+
+#### Configure DNS Settings for your Domain
+
+Provided that you've already registered a domain name, you'll need to configure it so that the domain name points to your host which is running Prose.
+
+Depending on your setup, this will either be done in your domain provider's settings panel, or perhaps within your cloud provider.
+
+Continuing with the DigitalOcean example from above, you can configure your domain provider to point at DigitalOcean's name servers.
+
+This effectively tells your domain provider that DigitalOcean will handle everything for you, and allows you to make adjustments to your domain from within DigitalOcean.
+
+In that case, DigitalOcean makes it seamless to map the domain name to your instance's IP address, and it should then be accessible from the domain name.
+
+Otherwise, you'll want to get the IP address of your host, go into your domain provider, and instruct it that requests to your domain should be direct to your host's IP address.
+
+#### Ready to Go
+
+At this point, your deployed host should be running Prose correctly. When you navigate to the domain name that you configured it with, you should see [GraphiQL](https://www.graphql-yoga.com/docs/features/graphiql), which will allow you to make GraphQL queries against your Discourse instance.
+
+We understand that the details of your deployment can vary quite a bit depending on how you chose to do it.
+
+If you run into any issues with this stepโas alwaysโdon't hesitate to reach out to us for support.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/deployment.md b/documentation/versioned_docs/version-2.0.0-beta/deployment.md
new file mode 100644
index 00000000..b46ab73b
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/deployment.md
@@ -0,0 +1,86 @@
+---
+title: Overview
+---
+
+As covered in [Concepts and Architecture](concepts#prose-discourse-through-graphql), Prose is Lexicon's GraphQL API layer on top of the traditional RESTful API provided by Discourse.
+
+## Getting Started with Deployment
+
+At this point, you're likely to be digging into this section of the documentation for two reasons:
+
+- You've been developing against a local instance (or container) running Prose, and you're ready to actually deploy your entire Lexicon project to production.
+
+- You want to simplify your development process by pointing the Lexicon Mobile App at a deployed instance of Prose.
+
+In either scenario, the end goal of this section is to have a working Prose server accessible on the open internet.
+
+### ๐ Note about Access Control
+
+As a brief aside, please note that Prose cannot expose any information from Discourse that Discourse is not already exposing on its own.
+
+If your Discourse instance requires authentication, then Prose will be unable to retrieve most queries unless the required authentication information is provided by the user accessing Prose.
+
+### ๐งฑ Alternative Deployment Strategies
+
+Initially, we wanted to provide instructions for an integrated deployment strategy. This would have involved deploying Prose on the same host as your Discourse instance, and ideally finding a way to deploy and expose it within the running Docker host that Discourse uses itself.
+
+This is still achieveable. But for now, we have opted to focus solely on deploying Prose as a dedicated instance.
+
+However, should you find yourself preferring a custom deployment of Prose, we would encourage you to do so.
+
+If you do, and you have some questions or challenges you're encountering, please reach out to us.
+
+Ideally we can help you sort things out and work your approach into our documentation so that everyone will benefit going forward.
+
+## Deploying as Dedicated Instance
+
+As mentioned above, the official deployment strategy for Prose is to host it as a dedicated instance.
+
+Like anything, this comes with both benefits and trade-offs, which we have outlined for you below.
+
+### ๐ Benefits
+
+A dedicated host for Prose will have better performance and reliability because its only resource usage comes from running Prose. i.e., it has exclusive usage of CPU, RAM, disk space, etc.
+
+If, on the other hand, you had managed to deploy Prose on the same host as your Discourse instance, this would mean that both Prose and Discourse need to share the host's allocated resources. If your Discourse instance is already running on a fairly light host, running Prose on it might mean that you would need to upgrade to a host with more resources.
+
+### โ ๏ธ Possible Trade-offs
+
+#### Increased Cost
+
+Naturally, if you're setting up a dedicated host to run Prose, then that involves additional costs on top of what you're already paying to host Discourse.
+
+Having said that, for most deployments, it is unlikely that you will need to allocate an expensive amount of resources to Prose.
+
+For example, on Digital Ocean, the $5 Shared CPU node is often sufficient.
+
+#### Potential for Increased Latency
+
+By nature, when deploying Prose on a different host from your running Discourse instance, the latency between the mobile app and Discourse increases.
+
+This is because each request has to make two hops:
+
+- The first request is from the client (your Lexicon-powered mobile app) to the Prose GraphQL API
+- The second request is from Prose to Discourse
+
+However, the only important questions regarding this point are:
+
+- How much measurable latency is there?
+- Is it noticeably slow to myself or my users?
+
+This, of course, can depend on several factors:
+
+- Where your Discourse server is deployed
+- Where your Prose server is deployed
+- Where your users tend to be
+- If the amount of traffic (load) is too much for the system to optimally run both Prose and Discourse.
+
+If you are observing noticeable latency, we would recommend looking into these factors.
+
+Ideally, you'll want to deploy Prose in the same region as your Discourse instance; and it is even better if you can deploy Prose in the same datacenter as your Discourse instance.
+
+## Up Next
+
+With this overview out of the way, we'll start by introducing you to the list of all possible [environment variables](env-prose) that may be necessary or useful when deploying Prose.
+
+Lastly, we'll get into the heart of it, by [preparing your host and deploying Prose](dedicated).
diff --git a/documentation/versioned_docs/version-2.0.0-beta/discourse-features.md b/documentation/versioned_docs/version-2.0.0-beta/discourse-features.md
new file mode 100644
index 00000000..2de3d0ec
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/discourse-features.md
@@ -0,0 +1,54 @@
+---
+title: Discourse Features Support
+---
+
+Below is a table of Discourse features which provides the details and current status about the support for a given feature in the **Lexicon Mobile App**.
+
+If we missed one, or anything looks out of date here, don't hesitate to submit a Pull Request which updates the table.
+
+Is the feature you love not supported? [Reach out to us](mailto:support@kodefox.com) to discuss how we can bring it to life for you.
+
+#### Our General Approach to Feature Support
+
+Much of our initial focus was on using-facing features, rather than administrative features.
+
+This is why, for example, users can select categories for their topics, but administrators are unable to create new categories from within the mobile app.
+
+For this reason, most admin tasks are still best accomplished using the Discourse web app on a larger device.
+
+### Lexicon Mobile App Features
+
+| Feature | Description | Supported | Notes |
+| -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------- |
+| Push Notifications Lexicon version 2 | Receive push notifications for new replies, mentions, likes, and more | โ
๐ง | Must have the [Lexicon Discourse Plugin](./discourse-plugin.md) installed and configured |
+| Email Deep Linking Lexicon version 2 | Open the mobile app from a Discourse email link to a topic or post | โ
๐ง | Must have the [Lexicon Discourse Plugin](./discourse-plugin.md) installed and configured |
+| 2FA Login | Allow users with 2FA enabled to be prompted for their 2FA code when logging in | โ
| Managing 2FA, such as enabling it or disabling it from within the app, is not currently supported |
+| Ability to Tag Topics | Create and tag topics to provide relevant metadata for your users | โ
๐ง | Configuration required: see [Optimal Experience](optimal#enable-topic-tagging) |
+| Topic Previews (Excerpts) | Show an excerpt of the first post in a topic from the Home screen | โ
๐ง | Configuration required: see [Optimal Experience](optimal#enable-topic-excerpts) |
+| View User Activity | View a user's recent activityโsuch as topics, posts, and likesโin a single feed from their profile | โ
| The ability to filter by activity is not currently supported |
+| Topic Metrics | Likes, Views, Replies, and Frequent Posters | โ
| |
+| Topic & Post Actions | Ability to like and edit topics and posts | โ
| |
+| View Top & Latest Topics | A Tab View at the top of the main feed provides the ability to switch between Latest and Top activity | โ
| |
+| Search | Search the current Discourse instance for topics and posts based on keywords, categories, and tags | โ
| |
+| Categories | View the category of a topic and filter topics by a given category | โ
| Categories cannot be created, updated, or deleted |
+| Attaching Media to Posts | Users can attach media to a post from the app | โ
๐ง | Configuration recommended for supported file extensions-see [Optimal Experience](optimal#configure-upload-extensions) |
+| Standard Markdown | Standard Markdown is supported in the editor and rendered correctly in the mobile app | โ
| Light, incomplete support exists for some of Discourse's custom markup, such as dates |
+| Sign Up | Allow users to sign up for an account directly through the mobile app, depending on whether your Discourse instance allows new user registration or not | โ
| |
+| Browsing Public Instances | Allow users to immediately access and browse your Discourse instance from the mobile app if it is not private | โ
| Users will be prompted to login upon attempting an authenticated action |
+| User Profiles | Ability to view users' profiles and edit your own | โ
| Partial support: displays the user's photo, username, Markdown bio on a single line, and recent activity |
+| Post Flagging | Allow users to flag posts for admins to review | โ
| Admins are not able to review posts in the app, though they will see in-app notifications for flags |
+| In-App Notifications | Allow users to see new notifications from the profile screen of the mobile app and mark all notifications as read | โ
| Some notifications from Discourse are not tappable in the mobile app, such as badge notifications |
+| Private messaging | Allow users to start private or group messages with one another | โ
| |
+| Mentions | Allow users to mention a user when creating or editing posts and messages | โ
|
+| Color Scheme | Provides light and dark mode support for users | โ
| Specify color scheme (light mode, dark mode, or system) from within the app (only local to the user's mobile device) |
+| Badges | The ability to see and interact with badges that have been awarded to users on the Discourse instance | โ | |
+| Post Drafts | Enable users to start composing a draft of a post and return to it later | โ | |
+| Groups | Enable users to create and participate in private groups of which only group members can view certain topics | โ | |
+| Admin Features | Discourse admin features generally not available in Lexiconโbetter suited to a desktop environment | โ | Editing posts is supported |
+| Post Quotes, Polls, Toggles, and Task Lists | Custom text formatting that enables Discourse-specific features | โ | |
+| Discourse Emojis | Utilize emojis when creating a topic, making a post, or sending a reply | โ | Standard unicode-based emojis are supported |
+| Post Bookmarks | Allow users to bookmark certain posts or topics | โ | |
+| DiscourseConnect (SSO) | Replace Discourse authentication with a Custom Provider | โ | |
+| Custom Authentication Plugins | Login via OAuth2 or other protocols using custom Discourse Plugins | โ | |
+| Real-time Chat | Enable users to initiate conversations using the chat feature, either in a channel or through private messaging | โ | |
+| User Status | Allow other user in community to see user message status | โ | |
diff --git a/documentation/versioned_docs/version-2.0.0-beta/discourse-plugin-enable.md b/documentation/versioned_docs/version-2.0.0-beta/discourse-plugin-enable.md
new file mode 100644
index 00000000..e33e202a
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/discourse-plugin-enable.md
@@ -0,0 +1,34 @@
+---
+title: Enable the Lexicon Plugin
+slug: discourse-plugin/enable
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+---
+
+After you have confirmed the plugin has been installed and your Discourse instance is running again, you can follow these steps to enable the plugin:
+
+1. As an admin user, access your Discourse admin dashboard.
+
+2. Navigate to the `Plugins` tab.
+
+You'll notice that the `discourse-lexicon-plugin` is not enabled yet.
+
+
+
+3. Click on the `Settings` button for the `discourse-lexicon-plugin` entry.
+
+4. Select the feature you want to enable and turn it on.
+
+##### Push Notifications
+
+For push notifications, all you need to do is check the box for `lexicon push notifications enabled`. This is covered in [Enable Push Notifications](./push-notifications/setup/enable-push-notifications.md).
+
+##### Email Deep Linking
+
+For email deep linking, you need to fill in your app scheme first before enabling it.
+
+
+
+This is covered in detail in [Enable Email Deep Linking](./email-deep-linking/setup/enable-email-deep-linking.md).
diff --git a/documentation/versioned_docs/version-2.0.0-beta/discourse-plugin-installation.md b/documentation/versioned_docs/version-2.0.0-beta/discourse-plugin-installation.md
new file mode 100644
index 00000000..911770b1
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/discourse-plugin-installation.md
@@ -0,0 +1,82 @@
+---
+title: Plugin Installation
+slug: discourse-plugin/setup
+---
+
+Before you can start using the Lexicon Discourse Plugin, there are a few prerequisites and installation steps you need to follow. This documentation will guide you through the process, ensuring a smooth setup of the plugin on your site.
+
+## Prerequisites
+
+In order to use this plugin, you must have access to your Discourse server in a way which allows you to modify the server's `app.yml`. If a hosting provider is managing Discourse for you, you will have to contact them to request that they install the plugin on your behalf.
+
+Specifically, you will need the ability to install plugins, which means directly modifying `/var/discourse/containers/app.yml` to include the [Lexicon Discourse plugin](https://github.com/lexiconhq/discourse-lexicon-plugin.git), and then rebuilding your site.
+
+## Plugin Installation Steps
+
+### Access your Server
+
+Login to your underlying Discourse host server via SSH.
+
+This is specific to each hosting setup, but typically you will need to use a terminal application such as Terminal on macOS or PuTTY on Windows.
+
+### Open the Discourse `app.yml` file
+
+Feel free to use your terminal editor of choice (vim, emacs, nano, etc.).
+
+:::note
+You may need `sudo` access to edit the file, but it depends on how the server was configured.
+:::
+
+```bash
+vim /var/discourse/containers/app.yml
+```
+
+### Get the Pluginโs Git Clone URL
+
+Discourse plugins are referenced by their reachable Git clone URLs, which typically end with `.git`.
+
+The Git clone URL for the [Lexicon Discourse plugin](https://github.com/lexiconhq/discourse-lexicon-plugin) can be found below:
+
+```
+https://github.com/lexiconhq/discourse-lexicon-plugin.git
+```
+
+Copy it to your clipboard for use in the next step.
+
+### Add the pluginโs repository URL to your containerโs `app.yml` file:
+
+Add the pluginโs Git clone url to the section below.
+
+```
+hooks:
+ after_code:
+ - exec:
+ cd: $home/plugins
+ cmd:
+ - git clone https://github.com/lexiconhq/discourse-lexicon-plugin.git
+```
+
+### Rebuild the container, with caution
+
+:::caution
+Please be aware that rebuilding your site will result in your site going offline for a period of time, typically between 5 to 30 minutes. We advise proceeding carefully and taking precautions outlined below.
+:::
+
+#### Precautionary Measures
+
+1. Before installing the plugin or performing any site rebuild, it is highly recommended to create a backup of your Discourse site.
+1. It is advisable to upgrade your Discourse installation and all existing plugins to their latest versions before attempting to install this plugin.
+1. Although rare, there may be situations where the site does not come back online after the rebuilding process, and requires further troubleshooting to revive.
+ - This is always a risk when installing a plugin or performing any task that requires rebuilding the app.
+ - We recommend that you perform these changes at a time that minimizes the users affected and that you have a well-defined contingency plan in place if something goes wrong.
+
+#### Run Rebuild Command
+
+```bash
+cd /var/discourse
+./launcher rebuild app
+```
+
+### How to Uninstall the Plugin
+
+To remove the plugin, simply remove the Git clone URL line from your `app.yml` file and rebuild your site. Please keep in mind that rebuilding your site will will result in your site going offline for a period of time, and poses the same risks that come with rebuilding the app.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/discourse-plugin.md b/documentation/versioned_docs/version-2.0.0-beta/discourse-plugin.md
new file mode 100644
index 00000000..adf100d2
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/discourse-plugin.md
@@ -0,0 +1,15 @@
+---
+title: Introduction
+slug: discourse-plugin/
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+---
+
+As of Lexicon version 2.0.0, a custom Discourse plugin is available to provide a more seamless mobile integration between Discourse and your Lexicon-powered mobile app.
+
+The plugin currently offers two key features:
+
+- **Push notifications**: support for native push notifications on user's mobile devices, according to relevant activity on your Discourse site. Powered by Expo's [push notifications service](https://docs.expo.dev/push-notifications/overview/).
+- **Email deep linking**: custom deep links in emails from Discourse, allowing users to seamlessly launch your Lexicon-powered mobile app directly from their mobile email client.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/email-deep-linking/intro.md b/documentation/versioned_docs/version-2.0.0-beta/email-deep-linking/intro.md
new file mode 100644
index 00000000..ca863368
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/email-deep-linking/intro.md
@@ -0,0 +1,9 @@
+---
+id: intro
+title: Introduction
+slug: discourse-plugin/email-deep-linking
+---
+
+The Lexicon Discourse plugin provides support for integrating Discourse's email notifications with your Lexicon-powered mobile app. Our plugin modifies links in specific Discourse emails so that when a relevant link is tapped and the user has your Lexicon-powered mobile app installed, it will open the app to the relevant topic or post. Otherwise, it will fall back to opening the topic in the device's web browser as it normally would.
+
+This section of the documentation offers step-by-step instructions to integrate email deep linking into your Discourse site so that your users have a more seamless experience with your Lexicon-powered mobile app.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/email-deep-linking/setup/enable-email-deep-linking.md b/documentation/versioned_docs/version-2.0.0-beta/email-deep-linking/setup/enable-email-deep-linking.md
new file mode 100644
index 00000000..60d0d6bd
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/email-deep-linking/setup/enable-email-deep-linking.md
@@ -0,0 +1,33 @@
+---
+title: Enable Email Deep Linking
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+This guide will walk you through the necessary steps to activate email deep linking on your Discourse site.
+
+## Steps
+
+1. Ensure the [Lexicon Discourse plugin](../../discourse-plugin-installation.md) is installed and activated.
+
+1. Access your Discourse admin dashboard.
+
+1. Navigate to the `Plugins` section.
+
+
+
+4. Locate the `discourse-lexicon-plugin` and click on the `Settings` button.
+
+5. Fill in the `lexicon app scheme` setting with your app scheme. The app scheme is required to enable email deep linking.
+
+6. Check the `lexicon email deep linking enabled` box in the Lexicon settings section and save your changes.
+
+
+
+Once the email deep linking feature is enabled, you will be able to utilize its functionality in your Discourse instance.
+
+Specifically, when your users receive email notifications for a new message or post, the link will have been overwritten to redirect to a custom endpoint within the Lexicon Discourse plugin.
+
+If the user is on mobile and has already installed your Lexicon mobile app (according to the app scheme you specified), the page will attempt to open the app and redirect to the appropriate message or post.
+
+Otherwise, the page will fallback to the default behavior of redirecting to the message or post within the Discourse web app.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/email-deep-linking/setup/verify-email-deep-linking.md b/documentation/versioned_docs/version-2.0.0-beta/email-deep-linking/setup/verify-email-deep-linking.md
new file mode 100644
index 00000000..06f51678
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/email-deep-linking/setup/verify-email-deep-linking.md
@@ -0,0 +1,51 @@
+---
+title: Verify Email Deep Linking
+slug: verify-email-deep-linking
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+:::note
+The steps below assume that **you have already published your Lexicon-powered mobile app** to the App Store and/or Google Play Store **with the correct app scheme**. If you are running the app on your machine locally through Expo, you should not expect the steps to work.
+:::
+
+This guide will provide you with step-by-step instructions to help you validate the functionality of email deep linking within your Lexicon mobile app.
+
+## Pre-requisites
+
+:::note
+If you have not yet fulfilled all of the pre-requisites below, this test will not work as expected.
+:::
+
+In order to test email deep linking properly:
+
+1. You **must** have already published your Lexicon-powered mobile app to the App Store and/or Google Play Store.
+1. You have already installed and configured the Lexicon Discourse plugin on your Discourse site.
+1. You have enabled email deep linking within the Lexicon Discourse plugin settings, and the app scheme matches what you published your app with.
+1. You have at least 1 mobile device with your Lexicon-powered mobile app already installed, with the correct app scheme as it was configured in Discourse.
+1. You have at least 2 separate Discourse accounts to test with.
+1. Ensure your Discourse site allows **mailing list mode**, and that it is turned on for the accounts you are testing with.
+ - If you do not do this, you will have to wait for Discourse to send its next digest email, which could take a while.
+
+## Steps
+
+To test email deep linking within your **published** Lexicon-powered mobile app, follow these steps:
+
+1. Ensure you have access to at least 2 separate accounts on your Discourse instance.
+1. On your mobile device, open your Lexicon-powered mobile app and login using one of your accounts.
+ - We'll refer to this as the **first** account.
+ - **Note**: ensure that your email client on your mobile device will receive emails for this account.
+1. Open your Discourse site in a web browser on your laptop or desktop computer.
+1. Login to your **second** Discourse account in your web browser.
+1. On your mobile device, using the **first** account, create a new post.
+1. Now, on your laptop or desktop computer, using the **second** account, find the post you created on the mobile app and reply to it.
+1. Back on your mobile device, you should receive an email notification from Discourse about the reply from the second account.
+1. Click on the button that says `Visit Message` or `Visit Topic`.
+ - The label depends on what activity generated the email (see screenshot below).
+1. The link will first open in your mobile web browser. Provided that the Lexicon-powered mobile app is installed and matches the configured app scheme, it should automatically open your app to the relevant topic or message scene.
+
+
+
+
+
+And that's it! You have successfully completed the steps to enable and test email deep linking in your app.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/env-mobile.md b/documentation/versioned_docs/version-2.0.0-beta/env-mobile.md
new file mode 100644
index 00000000..79af9933
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/env-mobile.md
@@ -0,0 +1,119 @@
+---
+title: Configuration Values
+---
+
+You can check and set the configuration values in `frontend/Config.ts`.
+
+The table below describes the configuration values for the Lexicon Mobile App.
+
+If there is a default value indicated, you do not need to set it.
+
+| Variable | Required | Notes | Default Value | Example Value(s) |
+| -------------------- | -------- | -------------------------------------------------------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
+| proseUrl | Yes | The url of the Prose Server (must start with http or https) | - | https://prose.myserver.com https://prose.myserver.com:8080 https://prose.myserver.com/subpath https://prose.myserver.com:8080/subpath |
+| inferDevelopmentHost | No | The flag (true / false) to override localhost with the host of the development machine | (empty) | true |
+
+## The `config` object
+
+In the `Config.ts` file, you'll find a `config` object that allows you to specify configuration values by scenario.
+
+The two primary scenarios are:
+
+- `localDevelopment`: when developing against the app locally. This configuration is also used as a fallback for an unknown build channel.
+- `buildChannels`: used to define configuration by build channel when building the app with the EAS CLI.
+
+Primarily, you'll only be concerned with configuring `proseUrl` for each of these sections.
+
+## `proseUrl`
+
+:::caution
+`proseUrl` must always be specified, with or without a port number, and must always start with either `http://` or `https://`.
+:::
+
+`proseUrl` is used to specify the URL of the Prose GraphQL API.
+
+The Prose GraphQL API acts a middleman between the Lexicon Mobile App and your Discourse instance. Without it, the mobile app cannot interact with your Discourse instance.
+
+### Example
+
+```ts
+const config = {
+ localDevelopment: {
+ proseUrl: 'http://localhost:8929',
+ },
+ buildChannels: {
+ preview: {
+ proseUrl: 'https://preview.myserver.com',
+ },
+ production: {
+ proseUrl: 'https://prose.myserver.com',
+ },
+ },
+};
+```
+
+With this configuration above, the app will:
+
+- point at `http://localhost:8929` when you run the app using `npm run start`
+- point at `https://preview.myserver.com` when you build the app using `eas build --profile preview`
+- point at `https://prose.myserver.com` when you build the app using `eas build`
+
+`proseUrl` also can include a subpath if desired:
+
+```ts
+const config = {
+ localDevelopment: {
+ proseUrl: 'http://localhost:8929',
+ },
+ buildChannels: {
+ preview: {
+ proseUrl: 'https://preview.myserver.com:8080/subpath',
+ },
+ production: {
+ proseUrl: 'https://myserver.com/api/prose',
+ },
+ },
+};
+```
+
+**Different Behavior in Development**
+
+When running the app locally, if `proseUrl` is set to `http://localhost` or `http://127.0.0.1`, it will replace `proseUrl` with the IP address of your development machine. It does this by using Expo's `debuggerHost` constant.
+
+_Note: this does not apply when building the app._
+
+This addresses multiple issues:
+
+- Accessing `localhost` from within the Android simulator does not map to your development machine
+- Accessing `localhost` from a device running Expo Go does not map to your development machine
+
+Both of these scenarios would otherwise require you to manually identify and specify your development machine's IP address with `proseUrl`. This is bothersome since your machine's IP address can change over time.
+
+If you are interested in more details about this, the implementation of this behavior is available in `frontend/constants/app.ts`.
+
+This behavior of automatically overriding those values can be disabled, with `inferDevelopmentHost`, which is covered below.
+
+## `inferDevelopmentHost`
+
+:::info
+This flag is only valid under `localDevelopment`. It has no effect when used as part of `buildChannels`.
+:::
+
+When in development, by default, the Lexicon Mobile App will check to see if `proseUrl` is set to either `http://localhost` or `http://127.0.0.1`.
+
+When detected, either of those values will be overwritten with the IP address of your development machine.
+
+This is a very useful feature that makes on-device testing simply work out of the box without needing to manually specify your IP address (or update it when it changes).
+
+For scenarios where this behavior is not desirable, `inferDevelopmentHost` can be used as a flag to disable this behavior. It can be disabled by specifying the value as `false`.
+
+When set to `false`, this behavior of overriding `proseUrl` with the development machine's IP address will no longer occur, and the original value will be passed through as-is.
+
+```ts
+const config = {
+ localDevelopment: {
+ proseUrl: 'http://localhost:8929',
+ inferDevelopmentHost: false,
+ },
+};
+```
diff --git a/documentation/versioned_docs/version-2.0.0-beta/env-prose.md b/documentation/versioned_docs/version-2.0.0-beta/env-prose.md
new file mode 100644
index 00000000..59901fd5
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/env-prose.md
@@ -0,0 +1,15 @@
+---
+title: Prose Environment Variables
+---
+
+The table below lays out environment variables for the Prose GraphQL API.
+
+If there is a default value indicated, you do not need to set it.
+
+| Environment Variable | Required | Notes | Default Value | Example Value |
+| --------------------------- | -------- | ----------------------------------------------------------------------------------- | ---------------------- | ------------------------------------ |
+| PROSE_DISCOURSE_HOST | Yes | The specific location of your Discourse instance. | - | https://discourse.example.com |
+| PROSE_DISCOURSE_UPLOAD_HOST | No | Instruct Prose to use a different host for file uploads to Discourse. | | https://upload.discourse.example.com |
+| PROSE_APP_HOSTNAME | No | The **application-level** hostname that Prose will listen on. | localhost | 0.0.0.0 |
+| PROSE_APP_PORT | No | The **application-level** port that Prose will listen on. | 80 | 8080 |
+| SKIP_CHECK_DISCOURSE | No | Bypass the startup process of checking the provided Discourse host for reachability | false | true |
diff --git a/documentation/versioned_docs/version-2.0.0-beta/intro.md b/documentation/versioned_docs/version-2.0.0-beta/intro.md
new file mode 100644
index 00000000..f358899d
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/intro.md
@@ -0,0 +1,142 @@
+---
+id: intro
+title: Introduction
+slug: /
+---
+
+
+ --- iOS Auth
+
+
+
+ --- iOS Dark Mode
+
+
+
+ --- iOS Comment
+
+
+
+ --- iOS Message
+
+ --- Android Auth
+
+
+
+ --- Android Dark Mode
+
+
+
+ --- Android Comment
+
+
+
+ --- Android Message
+
+
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+import Carousel from 'react-bootstrap/Carousel';
+
+---
+
+Lexicon is a customizable, pre-built mobile app that provides an elegant mobile discussions experience. Built on top of [Discourse](#what-is-discourse).
+
+## Features
+
+- Topics, Private Messaging, User Signups, Profile Management, and more
+- Rapidly build Android and iPhone apps for your existing Discourse site
+- [Push Notifications](./push-notifications/introduction.md) direct to your users' mobile devices
+- More seamless native Discourse experience [with Email Deep Linking](./email-deep-linking/intro.md)
+- Straightforward process to [**customize**](white-labeling) the app for your brand
+- Backed by a [GraphQL](https://graphql.org/) API
+- Free and open source!
+- [Commercial support](commercial-support) available
+
+## Benefits
+
+- Launch a custom mobile discussions app
+- Increase engagement with your users by adding a mobile-first Discourse experienceโno more [WebViews](https://www.kirupa.com/apps/webview.htm).
+- Built with [React Native](https://reactnative.dev/) and [Expo](https://expo.io), delivering a native look-and-feel on both iOS and Android.
+- Includes an auto-documented [GraphQL](https://graphql.org/) [interface](concepts#prose-discourse-through-graphql) over the Discourse API, which you can build on top of.
+
+## Screenshots
+
+### iOS
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+### Android
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## How does Lexicon work?
+
+Lexicon delivers a native mobile Discourse experience with **two key components**:
+
+- The [**Lexicon Mobile App**](#the-lexicon-mobile-app) - a modern mobile app built with [Expo](https://expo.io) & [React Native](https://reactnative.dev/)
+- [**Prose**](#prose-discourse-through-graphql), our GraphQL API on top of the Discourse API
+
+### The Lexicon Mobile App
+
+The Lexicon Mobile App is built with [Expo](https://expo.io), which allows us to maintain both the iOS and Android apps with a single codebase.
+
+For those unfamiliar, Expo provides a superior development and deployment experience on top of [React Native](https://reactnative.dev/).
+
+### Prose: Discourse through GraphQL
+
+Prose is Lexicon's [GraphQL](https://graphql.org/) layer built on top of Discourse's API.
+
+This enables developers to quickly build apps on top of a live Discourse instance while leveraging the [benefits of GraphQL](https://www.apollographql.com/docs/intro/benefits/).
+
+### What is Discourse?
+
+Discourse is open-source **discussion software** that is thoughtfully designed, simple to setup, and well-maintained.
+
+You can learn more about it on the [Discourse website](https://www.discourse.org/).
+
+### Further Details
+
+You can learn about the technical details of our approach in [Concepts & Architecture](concepts).
+
+## License
+
+MIT. Copyright (c) [Lexicon](https://github.com/lexiconhq)
diff --git a/documentation/versioned_docs/version-2.0.0-beta/lexicon-updates.md b/documentation/versioned_docs/version-2.0.0-beta/lexicon-updates.md
new file mode 100644
index 00000000..43d95945
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/lexicon-updates.md
@@ -0,0 +1,17 @@
+---
+title: Receiving Updates from Lexicon
+---
+
+Due to the nature of this project, the best way to synchronize bugfixes, updates, and other changes to the Lexicon Mobile App is to treat your app like a fork of our repository.
+
+In the process of customizing the Lexicon Mobile App for your needs, you might make any number of changes to the theme or assets.
+
+However, the underlying codebase should beโfor the most partโuntouched.
+
+When we release a bugfix or new feature on the `master` branch, you'll be able to pull down our changes, resolve any conflicts with your changes, and have an updated version of your app ready to republish.
+
+It is worth acknowledging that this approach, which effectively uses Git to solve this problem in a fairly simple way, could be improved.
+
+Provided that there's enough interest, we might later decide to shape Lexicon into more of a standalone SDK package that you can import and receive updates to via npm.
+
+If you're interested in making that a reality, please reach out to us!
diff --git a/documentation/versioned_docs/version-2.0.0-beta/optimal.md b/documentation/versioned_docs/version-2.0.0-beta/optimal.md
new file mode 100644
index 00000000..789e1674
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/optimal.md
@@ -0,0 +1,98 @@
+---
+title: 'Optimal Experience'
+---
+
+If you're planning to make use of the Lexicon Mobile App, there are a few adjustments you should make to your Discourse instance to provide the best in-app experience to your users.
+
+## Install the Lexicon Discourse Plugin
+
+The Lexicon Discourse plugin enhances the native mobile experience for your users in two key ways:
+
+- Adds support for push notifications
+- Adds support for email deep linking.
+
+You can read more about the plugin and how to set it up [here](./discourse-plugin.md).
+
+## Enable Topic Excerpts
+
+We have designed the Mobile App so that users can easily see the first few sentences of a topic as they scroll through the topics list.
+
+However, by default, Discourse does not return excerpts when listing topics.
+
+Fortunately, there is a secret setting that enables this.
+
+It just takes a bit of additional configuration to enable.
+
+While Discourse does enable opting into this behavior as part of a [Theme Component](https://meta.discourse.org/t/topic-list-excerpts-theme-component/151520), we wanted to guide you through the option of toggling the setting itself.
+
+Should you prefer to enable it using the above theme component, you're free to do so.
+
+Enabling this setting involves gaining access to the server and changing a setting.
+
+### Instructions
+
+The original instructions can be found [here](https://meta.discourse.org/t/discourse-as-a-simple-personal-blog-engine/138244/4).
+
+Once you've gained access to your server, enter into the running Discourse app.
+
+```sh
+$ /var/discourse/launcher enter app
+```
+
+Next, enter the Rails CLI:
+
+```sh
+$ rails c
+```
+
+Finally, set the setting to true:
+
+```sh
+$ SiteSetting.always_include_topic_excerpts = true
+```
+
+After that, you can exit, and excerpts should now be displaying in the app.
+
+## Enable Topic Tagging
+
+The Lexicon Mobile App was designed with the ability to tag topics in mind.
+
+This allows users to view and manage tags on topics, which is a popular feature on many Discourse servers.
+
+Unfortunately, this is not enabled by default.
+
+### Instructions
+
+In order to enable it, you can take the following steps:
+
+- Navigate to the Admin Site Settings page at `/admin/site_settings`
+- Use the search bar to search for the setting `tagging enabled`
+- Ensure that it is checked
+- If you made a change, click the green checkbox button to apply it
+
+Topics should now be taggable, and viewable in the app.
+
+## Configure Upload Extensions
+
+Discourse provides a security feature that allows Discourse admins to specify a whitelist of file extensions that their users can upload.
+For example, most admins would choose to restrict uploading of `.exe` files.
+In order to be compatible with the settings of your Discourse instance, the Lexicon Mobile App simply requests the list of allowed extensions and uses it to enforce allowed extensions in the app.
+Out of the box, most Discourse instances support this default list of extensions:
+
+- `.jpg`
+- `.jpeg`
+- `.png`
+- `.gif`
+- `.heic`
+- `.heif`
+
+If you'd like to adjust the list of extensions in your Discourse instance, you can do so by following the instructions below.
+
+### Adjusting Allowed Extensions in Discourse
+
+- Navigate to the Admin Site Settings page at `/admin/site_settings`
+- Use the search bar to search for the setting `extensions`
+- Find the setting labeled `authorized extensions`.
+- Adjust the list as you see fit to include the file extensions you'd like your users to be able to upload.
+- When you are done making changes, click the green checkbox to apply them.
+- The Lexicon Mobile App will receive the updated list of extensions from your site settings and begin enforcing it for your users.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/play-store.md b/documentation/versioned_docs/version-2.0.0-beta/play-store.md
new file mode 100644
index 00000000..9781ea20
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/play-store.md
@@ -0,0 +1,166 @@
+---
+title: Publishing to the Play Store
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+## Prerequisites
+
+:::note
+If you don't already have a Google Developer account, note that there is a fee to create one.
+:::
+
+- A [Google Developer Account](https://play.google.com/console/signup) to access the [Google Play Console](https://play.google.com/console)
+- An Expo account
+- EAS CLI 2.6.0 or newer
+- The [Lexicon Discourse plugin](./discourse-plugin.md) is already installed on your Discourse instance
+
+## Google Play Console
+
+The [Google Play Console](https://play.google.com/console) enables you to setup your app, invite beta testers, and publish your app to the [Google Play Store](https://play.google.com/store).
+
+Because you're publishing an app that was built using Expo, it is **very important** that you follow [Expo's instructions](https://github.com/expo/fyi/blob/master/first-android-submission.md) for submitting an app to the Google Play store correctly.
+
+## App Configuration
+
+After setting up your app in the Google Play Console, there are some other adjustments you'll need to make.
+
+### Build Config
+
+Similar to the approach for [Publishing to the App Store](app-store), if you havenโt already, you'll need to set your app name and slug in `frontend/app.json`. The [slug](https://docs.expo.dev/workflow/glossary-of-terms/#slug) is used as part of the URL for your app on Expo's web services, so it is recommended to use kebab-case (e.g., `my-lexicon-app`).
+
+:::info
+Note below that `scheme` is included. If you want [email deep linking](./email-deep-linking/intro.md) support in your app, **you must specify a scheme**, and then configure the Lexicon Discourse plugin with the same scheme.
+:::
+
+```json
+"name": "",
+"slug": "",
+"scheme": "",
+```
+
+Then, you need to configure EAS Build by running the following command, or skip to the next [step](play-store#setup-config-values):
+
+```bash
+eas build:configure
+```
+
+The EAS CLI will prompt you to specify `android.package` and `ios.bundleIdentifier` if those values are not already provided in `app.json`.
+
+Next, verify that the `package` name and other details specific to your app are included in the `android` section of `app.json`. Note that the `versionCode` will be automatically updated when you build the app with the `production` profile, so you don't need to increment the version manually.
+
+Also, there's one further detail that you might want to add, depending on your app's permissions.
+
+In the example below, we're providing our app with the ability to read and write to external storage.
+
+```json
+ "android": {
+ "package": "",
+ "permissions": [ "READ_EXTERNAL_STORAGE" , "WRITE_EXTERNAL_STORAGE" ]
+ "versionCode": 1,
+ },
+```
+
+If your app requires further permissions, be sure to specify them as needed in this part of the configuration.
+
+If you don't quite understand how permissions work yet, it's best to check out the [Expo documentation](https://docs.expo.io/versions/latest/sdk/permissions) on this topic in order to get a full understanding.
+
+### Setup Config Values
+
+:::info
+When publishing your app, it is necessary to deploy Prose somewhere publicly accessible, perhaps on a cloud hosting provider like AWS or DigitalOcean. If Prose is only running on your local machine, users that download your app won't be able to use it.
+Check [the documentation](deployment) to deploy Prose if you haven't already.
+:::
+
+Next, set the **Prose URL** for your builds in `Config.ts`. You can set a different URL for each build channel.
+
+:::note
+In the original release of Lexicon, the **Prose URL** was specified in `frontend/.env`. However, as part of migrating to Expo's EAS feature, we centralized the configuration into `frontend/Config.ts` to save you the trouble of needing to maintain it in more than one place, as suggested in the [Expo documentation](https://docs.expo.dev/build-reference/variables/#can-i-share-environment-variables-defined-in-easjson-with-expo-start-and-eas-update)
+:::
+
+```ts
+const config = {
+ // ...
+ buildChannels: {
+ preview: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ production: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ },
+};
+```
+
+### Add the Play Store Secret File
+
+For the last step, you'll need to provide a `.json` file containing a private key in order to interact with the Play Store. Follow [this guide](https://github.com/expo/fyi/blob/main/creating-google-service-account.md) to generate one. Then, copy the JSON file to your `lexicon/frontend` directory, and rename the file as `playstore_secret.json`.
+
+The JSON file looks like this:
+
+```json
+{
+ "type": "service_account",
+ "project_id": "",
+ "private_key_id": "",
+ "private_key": "-----BEGIN PRIVATE KEY----------END PRIVATE KEY-----\n",
+ "client_email": "",
+ "client_id": "",
+ "auth_uri": "",
+ "token_uri": "",
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
+ "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/lexicon%40api.iam.gserviceaccount.com"
+}
+```
+
+## Build your App for Android
+
+Because we're working with Expo and React Native, this step isn't too different from building your app for iOS.
+
+From the `frontend/` directory, you can run this command to check the app before publishing:
+
+```bash
+eas build --platform android --profile preview
+```
+
+Running `eas build` with the `preview` profile will build the app as an APK. This allows you to quickly load it onto your Android device or emulator. After the build is done, navigate to your project in the [Expo web console](https://expo.dev), then click on the **Builds** menu located on the left-hand side of the screen.
+
+- Click on the project you want to install.
+
+
+
+- Download the app by pressing the `Install` button in the `Build Artifact` section.
+
+
+
+You can download and launch the app on your real device, or drag the downloaded APK file to your emulator.
+
+Once you have verified that the app runs as expected, you can proceed to build it for release:
+
+```bash
+eas build --platform android --profile production
+```
+
+The approach for a production build is similar to the one used for generating a preview build. However, unlike a preview build, you won't be able to launch the production build in Android emulatorโit is intended solely for publishing to the Play Store.
+
+Once this process is completed, you can proceed with submitting it to the Play Store.
+
+## Publish to the Play Store
+
+At this point, you can take your app live on the Google Play Store, or you can proceed with internal testing on the Google Play Console.
+
+To proceed with internal testing, run this command:
+
+```bash
+eas submit --platform android --profile staging
+```
+
+To release your app publicly, run this command:
+
+```bash
+eas submit --platform android --profile production
+```
+
+You can read more about build profiles [here](tutorial/publishing).
+
+At this point, provided that you've completed all the steps, congratulations! Your Lexicon-powered mobile app is now live and ready to be downloaded by your users.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/publish-app.md b/documentation/versioned_docs/version-2.0.0-beta/publish-app.md
new file mode 100644
index 00000000..267f3e1a
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/publish-app.md
@@ -0,0 +1,11 @@
+---
+title: Publishing your App
+---
+
+:::danger Progress
+This page has not been started yet or needs a lot more work.
+:::
+
+Expo workflow, benefits of, etc.
+
+Over the air updates?
diff --git a/documentation/versioned_docs/version-2.0.0-beta/push-notifications/introduction.md b/documentation/versioned_docs/version-2.0.0-beta/push-notifications/introduction.md
new file mode 100644
index 00000000..619429c6
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/push-notifications/introduction.md
@@ -0,0 +1,8 @@
+---
+title: Introduction
+slug: /push-notifications
+---
+
+The Lexicon Discourse plugin provides support for native push notifications for your Lexicon-powered mobile app. This works for both Android and iOS, and is handled by Expo's [push notifications service](https://docs.expo.dev/push-notifications/overview/).
+
+This documentation offers step-by-step instructions to seamlessly integrate push notifications into your Discourse site so that your users receive them in your Lexicon-powered mobile app. By following this guide, you will be able to enhance the UX of your users by ensuring they receive timely and engaging notifications about activity on your Discourse site.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/push-notifications/plugin-interaction.md b/documentation/versioned_docs/version-2.0.0-beta/push-notifications/plugin-interaction.md
new file mode 100644
index 00000000..5a424ac4
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/push-notifications/plugin-interaction.md
@@ -0,0 +1,31 @@
+---
+title: How Push Notifications work with Lexicon
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+Below, we outline the interaction between the Lexicon mobile app, Prose, and the Discourse Plugin regarding the implementation of push notifications.
+
+## The Lexicon mobile app
+
+The Lexicon mobile app plays a crucial role in enabling push notifications for your users. When a user logs into their account using the app, a unique token is generated using the [`expo-notifications`](https://docs.expo.dev/versions/latest/sdk/notifications/) library. This token serves as a unique identifier for the user's device. The app then sends this token to the Prose GraphQL API, which makes a separate request to the Lexicon Discourse plugin. The plugin then inserts a record into your Discourse site's databaseโensuring any relevant activity on Discourse triggers a push notification to the user's mobile device.
+
+## Prose
+
+As mentioned elsewhere in the documentation, Prose is an intermediary component that facilitates communication between the Lexicon mobile app and your Discourse site. It serves the key role of providing a GraphQL interface over Discourse, which allows the mobile app to communicate with Discourse via GraphQL.
+
+The latest Prose API exposes a new GraphQL mutation, `pushNotifications`, to receive the unique Expo push token from the mobile app when the user logs in.
+
+Once Prose receives the token from the app, it forwards the token to the Discourse Plugin running on your site.
+
+## Discourse Plugin
+
+The Lexicon Discourse Plugin provides several features. In terms of enabling push notifications, it is responsible for integrating with Expo's [push notifications service](https://docs.expo.dev/push-notifications/overview/). When the Discourse Plugin receives a push token from Prose, it saves the token in your Discourse site's database, associating it with the corresponding user.
+
+Since the Lexicon Discourse plugin has been configured to respond to events within your Discourse site, it is able to dispatch push notifications based on your users' activity.
+
+When a relevant event triggers the need for a push notification, such as a new message or reply, the Discourse Plugin retrieves the associated user's token from your Discourse site's database. Using this token, the plugin sends a push notification request to Expo's push notification service, triggering the delivery of the push notification to the user's device.
+
+## Flowchart
+
+
diff --git a/documentation/versioned_docs/version-2.0.0-beta/push-notifications/setup/enable-push-notifications.md b/documentation/versioned_docs/version-2.0.0-beta/push-notifications/setup/enable-push-notifications.md
new file mode 100644
index 00000000..adcac398
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/push-notifications/setup/enable-push-notifications.md
@@ -0,0 +1,32 @@
+---
+title: Enable Push Notifications
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+
+
+
+
+
+Below, we'll walk you through the necessary steps to activate push notifications for your Discourse site.
+
+## Steps
+
+1. Ensure the [Lexicon Discourse plugin](../../discourse-plugin-installation.md) is installed and activated.
+
+1. As an admin user, access your Discourse admin dashboard.
+
+1. Navigate to the Plugins section.
+
+
+
+4. Click on the `Settings` button for the `discourse-lexicon-plugin` entry.
+
+5. Check the `enable Push Notifications` box in the Lexicon settings section and save your changes.
+
+
+
+Once the push notifications setting is enabled, your users will be able to login through the mobile app and start receiving push notifications.
+
+It is important to remember that push notifications are setup specifically when the user logs in through the mobile app. If users are not receiving push notifications, you should instruct them to log out and log back in before attempting any further troubleshooting.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/push-notifications/setup/verify-push-notifications.md b/documentation/versioned_docs/version-2.0.0-beta/push-notifications/setup/verify-push-notifications.md
new file mode 100644
index 00000000..26679ffb
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/push-notifications/setup/verify-push-notifications.md
@@ -0,0 +1,33 @@
+---
+title: Verify Push Notifications
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+
+
+
+
+Below, we'll walk you through how you can validate the functionality of push notifications within your Lexicon-powered mobile app.
+
+:::info
+In order to properly test push notifications, **you will need two separate accounts** on your Discourse site (to generate notifications).
+
+Additionally, **you will need at least one mobile device** for testing purposes.
+:::
+
+## Step
+
+To test push notifications within your Lexicon-powered mobile app, follow these steps:
+
+1. Ensure that you have completed the [Getting Started](../../quick-start) steps for Lexicon.
+1. Start the Lexicon Expo app by navigating to `frontend/` and running `yarn start` from your terminal.
+1. Using the Expo link or QR Code, launch the app on a real mobile device.
+1. Login to the app using one of your accounts.
+1. Using that account, create a post within your Discourse site
+1. Using a separate account, reply to the post to trigger a notification for the first account.
+1. You should receive a push notification on your phone with the reply content from the other account.
+
+
+
+And that's it! The Lexicon Discourse plugin is properly sending push notifications through your Discourse site.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/quick-start.md b/documentation/versioned_docs/version-2.0.0-beta/quick-start.md
new file mode 100644
index 00000000..89f4c8da
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/quick-start.md
@@ -0,0 +1,65 @@
+---
+title: Quick Start
+---
+
+## Prerequisites
+
+- Node.js 16.14 or newer
+- The latest version of NPM or Yarn, compatible with Node 16.14 or newer
+- EAS CLI 3.7.2 or newer to build and publish the app
+- An active Discourse site
+ - If you donโt have one, please follow the instructions in [Development Setup](setup#discourse-host)
+
+:::note
+Follow the instructions in [Setup Guidance](tutorial/setup) to install the prerequisite depedencies, such as NPM and the EAS CLI.
+:::
+
+## Installation
+
+Clone the repository and navigate into it:
+
+```
+git clone git@github.com:lexiconhq/lexicon.git
+cd lexicon
+```
+
+Next, install the project's dependencies and generate its GraphQL schema:
+
+```
+$ npm install && npm run generate
+```
+
+Note that `npm run generate` involves two steps.
+
+- First, it will generate a [GraphQL schema](https://nexusjs.org/docs/guides/schema) in the `api` directory.
+
+- Then, using the generated schema, it will create a new folder called `generated` in the `frontend` directory, containing the resulting query and mutation types.
+
+- This allows the frontend codebase to stay in sync with, and not duplicate the code for, the types from the `api` directory.
+
+The code shared from the API is then used by [Apollo](https://github.com/apollographql/apollo-tooling), the GraphQL library we use on the frontend, which enables the Mobile App to query the API correctly.
+
+## Launch the Mobile App
+
+You can run the app and test it out by running this command from the project root:
+
+```
+$ npm run quickstart
+```
+
+This will simultaneously launch two processes:
+
+- The Prose GraphQL API Server
+- The local Expo dev server, which will enable you to launch the React Native app from your device
+
+**Please note that this takes some configuration to setup properly**.
+
+- The `quickstart` command configures the Mobile App and the Prose GraphQL API to point at https://meta.discourse.org, as an example.
+
+- You'll need to make adjustments to point at a site of your choice.
+
+- The Lexicon Mobile App (via Expo) must be configured to point at the Prose GraphQL Server
+
+- The Prose GraphQL Server must be configured to point at an active Discourse instance
+
+More details are available in the [Development Setup](setup) section
diff --git a/documentation/versioned_docs/version-2.0.0-beta/rationale.md b/documentation/versioned_docs/version-2.0.0-beta/rationale.md
new file mode 100644
index 00000000..bfb62fa4
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/rationale.md
@@ -0,0 +1,73 @@
+---
+title: Background & Motivation
+---
+
+### Discourse's Approach to a Mobile Experience
+
+Discourse is a phenomenal, battle-tested piece of software that facilitates thoughtful discussions in countless communities around the globe. It's no secret that we are big fans of it.
+
+The Discourse core team's strategy for mobile devices was to implement their product as a responsive website, and optimize for mobile use cases. This allowed mobile users to simply go to the same Discourse site as they would have on devices with larger screensโ enabling them to view and write posts from their mobile devices.
+
+However, over time, interest in a dedicated Discourse mobile app grew. The core team addressed this need by building a native mobile app. They chose to reuse their existing work by having the app simply wrap a webview containing the mobile site.
+
+This was a nice improvement, as it allowed the mobile app to integrate with native SDKs and provide some additional features to Discourse mobile users.
+
+Overall, their approach to solving this problem was both efficient and well-done.
+
+However, it is still evident to many users that they're interacting with an embedded web browser, and it's clear that it's not a mobile-_first_ experience.
+
+For many users and site-owners, what the Discourse team has provided is more than enough, and it solves all of their problems.
+
+In our case, we were looking for a very specific type of experience.
+
+### Who We Are
+
+The Lexicon Team is part of [KodeFox](https://www.kodefox.com/), a software studio comprised of passionate software engineers, designers, and product managers who regularly build world-class software for our customers.
+
+Interested in custom software development with a personal touch? Drop us a line at [hello@kodefox.com](mailto:hello@kodefox.com).
+
+### Enter Lexicon
+
+Lexicon was formed out of the desire to further leverage many of the great features that the Discourse team had worked hard to build.
+
+In our consulting projects, we found that many of our clients were regularly asking for solutions that Discourse already provides out of the box.
+
+However, our clients wanted a seamless, native mobile experience, tailored to the brand that their users were already familiar with.
+
+After digging into the Discourse API documentation, we felt that it was worthy investment to build a mobile-first Discourse experience which also faciliated customizability.
+
+We were already fluent with the elegant development process provided by React Native and Expo, so it was a natural fit for us to build the mobile app with these technologies.
+
+This allowed us to achieve a high ratio of code reuse across iOS and Android, making feature implementations and bug fixes a much simpler process in most cases.
+
+In integrating with Discourse's API, we also noticed that the API documentation contains a disclaimer which encourages reverse-engineering to understand it.
+
+While we can appreciate the sentiment of figuring things out yourself, we wanted to provide an API experience that makes it easy for developers to dig into interactive documentation and quickly grasp the concepts.
+
+For this reason, we also chose to build Prose, our GraphQL API layer on top of the Discourse RESTful API. Another motivating factor was our existing fluency with GraphQL.
+
+This allowed us to quickly implement the mobile app with an intuitive API paradigm that we were already very familiar with.
+
+#### How Lexicon can help you
+
+If you already run an existing Discourse site and want a native mobile experience for your users, you can very quickly point Lexicon at your site and browse it in real-time from your device.
+
+Check out the [Quick Start](quick-start) page to see a rapid example of spinning up a mobile app for Discourse's own [Meta site](https://meta.discourse.org).
+
+But beyond that, Lexicon is an open source pre-built mobile app. This means that you can customize it to fit your brand.
+
+You can think of it like a template that you can use to build your own mobile app for your community.
+
+If you're interested in customizing the Lexicon Mobile app, you can learn more about that in the [White Labeling](white-labeling) section.
+
+And when you're finished, you can publish it to the Apple App Store or Google Play Store, which we cover in [Publishing your App](app-store).
+
+### FOSS Mindset
+
+Finally, while this project will benefit us and our clients in the future, we also wanted it to be a gift to the community.
+
+We recognize and support the culture of free and open-source software. That's why we're delighted to give back to the community in this way, just as the Discourse team originally did when they chose to open-source their hard work.
+
+So please engage with us on Github, and don't be shy about opening a new issue or even a PR.
+
+We look forward to working with you!
diff --git a/documentation/versioned_docs/version-2.0.0-beta/setup.md b/documentation/versioned_docs/version-2.0.0-beta/setup.md
new file mode 100644
index 00000000..99305a33
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/setup.md
@@ -0,0 +1,376 @@
+---
+title: Development Setup
+---
+
+### Clone the Lexicon Repository
+
+If you haven't already, make sure you [clone the Lexicon repository](quick-start#installation) from Github.
+
+### Setup a Discourse Instance, if necessary
+
+In order to get started developing against the Lexicon Stack, you'll need a running Discourse instance.
+
+To recap, the Lexicon Stack consists of:
+
+- The Lexicon Mobile App
+- The Lexicon Prose GraphQL API
+- A running Discourse instance
+
+Without a Discourse instance, the Prose GraphQL API has nowhere to retrieve data from. And when the Prose GraphQL API can't retrieve any data, the Lexicon Mobile App won't be able to receive anything either.
+
+For detailed instructions on setting up a local development instance of Discourse, head over to the [tutorial](./tutorial/setup-discourse), which will walk you through the process.
+
+However, if you already have a deployed instance of Discourse, we'd recommend using that instead.
+
+### Install the Lexicon Discourse Plugin
+
+The Lexicon Discourse Plugin is a Discourse plugin that adds support for [push notifications](./push-notifications/introduction.md) and [email deep linking](./email-deep-linking/intro.md).
+
+You can install the plugin in your Discourse instance by following the instructions in the [Discourse plugin documentation](./discourse-plugin.md).
+
+For local development, you're only able to test out push notifications, as email deep linking requires a published app with a [valid app scheme](https://docs.expo.dev/versions/latest/config/app/#scheme).
+
+If you wish to develop against the plugin itself, you can clone the codebase [here](https://github.com/lexiconhq/discourse-lexicon-plugin.git).
+
+### Configuration
+
+The [Lexicon Stack](concepts#architecture-of-the-lexicon-stack) requires some configuration in order to properly interact with your Discourse server.
+
+This involves configuring both the backend GraphQL API, which interacts with your Discourse instance; as well as the frontend Mobile App, which interacts with the GraphQL API.
+
+The architecture of this setup is depicted in [Architecture of the Lexicon Stack](concepts#architecture-of-the-lexicon-stack).
+
+#### Backend GraphQL API Configuration
+
+The [Prose GraphQL API](concepts#prose-discourse-through-graphql) is fairly simple in terms of configuration. In the simplest case, it only needs to know where your Discourse instance is accessible at.
+
+It receives its configuration via a [`.env` file](https://www.codementor.io/@parthibakumarmurugesan/what-is-env-how-to-set-up-and-run-a-env-file-in-node-1pnyxw9yxj) in the root of the `api/` directory.
+
+Here is the simplest configuration of the `api/.env` file:
+
+```
+PROSE_DISCOURSE_HOST=https://meta.discourse.org
+```
+
+It is also worth noting that you can optionally configure the **Hostname** and **Port Number** that the Prose API server listens on, both of which default to **localhost** and **port 80**, respectively.
+
+```
+PROSE_DISCOURSE_HOST=https://meta.discourse.org
+
+# Instruct Prose to broadcast publicly instead of on localhost
+PROSE_APP_HOSTNAME=0.0.0.0
+
+# Instruct Prose to listen on port 8929 instead of the default port 80
+PROSE_APP_PORT=8929
+```
+
+For a comprehensive list of all environment variables that can be used to configure Prose, check out [Prose Environment Variables](env-prose).
+
+#### Frontend Mobile App Configuration
+
+:::note
+In the original release of Lexicon, the **Prose URL** was specified in `frontend/.env`. However, as part of migrating to Expo's EAS feature, we centralized the configuration into `frontend/Config.ts` to save you the trouble of needing to maintain it in more than one place, as suggested in the [Expo documentation](https://docs.expo.dev/build-reference/variables/#can-i-share-environment-variables-defined-in-easjson-with-expo-start-and-eas-update)
+:::
+
+To configure the frontend mobile app, you'll first need to set your app name and slug in `frontend/app.json`. The [slug](https://docs.expo.dev/workflow/glossary-of-terms/#slug) is used as part of the URL for your app on Expo's web services, so it is recommended to use kebab-case (e.g., `my-lexicon-app`).
+
+Replace these placeholders with your desired values:
+
+```json
+ "name": "",
+ "slug": "",
+```
+
+Next, change the value of `proseUrl` in `frontend/Config.ts` to the URL of your Prose GraphQL APIโwhether local or already deployed somewhere.
+
+```ts
+const config = {
+ localDevelopment: {
+ proseUrl: 'http://localhost:8929',
+ },
+ buildChannels: {
+ preview: {
+ proseUrl: 'https://preview.myserver.com:8080/subpath',
+ },
+ production: {
+ proseUrl: 'https://myserver.com/api/prose',
+ },
+ },
+};
+```
+
+`localDevelopment.proseUrl` will be used during development when you run the app using `npm run start` or `expo start`, whereas the specific value within `buildChannels` (e.g., `production.proseUrl`) will be used when actually building the app.
+
+#### Development Scenarios
+
+When developing locally, there are at least three scenarios that you may find yourself in.
+
+Depending on which one applies to you, the config values across `frontend/Config.ts` and `api/.env` may need to be set differently.
+
+##### Scenario 1: Existing Prose Deployment
+
+If you've already deployed the Prose GraphQL API to a host that is publicly reachable, you will have already setup `api/.env` with the proper values.
+
+In that case, `frontend/Config.ts` only needs updated to point at the deployed GraphQL API.
+
+For example:
+
+```ts
+const config = {
+ localDevelopment: {
+ proseUrl: 'https://my-deployed-graphql.api',
+ },
+ buildChannels: {
+ preview: {
+ proseUrl: 'https://my-deployed-graphql.api',
+ },
+ production: {
+ proseUrl: 'https://my-deployed-graphql.api',
+ },
+ },
+};
+```
+
+In the example above, we have configured the app to point at `https://my-deployed-graphql.api` in all scenarios, including during development when running with `npm run start`.
+
+##### Scenario 2: Run Prose Locally & Access from a Simulator
+
+:::info
+If you are running the Prose server locally, you should not expect that the mobile app will continue to function if you turn off your development machine. You must **deploy** the server before attempting to use the mobile app without depending on your development machine.
+:::
+
+This approach involves running both the Lexicon Mobile App and the Prose GraphQL API on your development machine. It is accomplished by instructing Expo to launch the Mobile App in the Android or iOS simulator.
+
+When developing this way, you can simply set `localDevelopment.proseUrl` to `http://localhost` in `frontend/Config.ts`. And then in `api/.env`, you can set `PROSE_APP_HOSTNAME` to `0.0.0.0`.
+
+Note that if you want to run Prose locally on a specific port, you would need to make sure that the configuration in both `api/.env` and `frontend/Config.ts` reflect that correctly.
+
+:::caution
+If you configure `PROSE_APP_HOSTNAME` in `api/.env` to only listen on `localhost` or `127.0.0.1` (rather than `0.0.0.0`), it prevents others on the same network as your development machine from accessing it. This includes both your mobile device and the Android simulator, which can lead to connectivity issues when developing locally.
+:::
+
+##### Scenario 3: Run Prose Locally & Access from your Mobile Device
+
+It can be very useful to develop and debug against the app using your actual mobile device with the [Expo Go app](https://expo.dev/client).
+
+In order to do this, you'll need to have your development machine reachable from your mobile device.
+
+A simple way to make it reachable is to ensure that your mobile device and development machine are on the same network, and then, in `api/.env`, set `PROSE_APP_HOSTNAME` to `0.0.0.0`.
+
+In a regular Expo project, you would be required to update the `localDevelopment.proseUrl` value in `frontend/Config.ts` to contain the hardcoded IP address of your development machine on your network.
+
+However, by setting the value to `http://localhost`, we handle this **automatically** by default, so you don't have to worry about it. Read more about it [here](env-mobile#infer_development_host).
+
+###### Hardcoding your local IP Address
+
+:::info
+This approach is not ideal. If your local IP address ever changes, you'll need to locate it again, and update `Config.ts` to reflect that. For this reason, it's preferable to just use `http://localhost`.
+:::
+
+To manually instruct the Mobile App how to locate your development machine, you'll need to find out what the **local IP address** of your development machine is on your current network.
+
+Note that your local IP address is different from your public IP Address.
+
+If you are not sure how to get your local IP address, you can go to [What Is My Browser: Detect Local IP Address](https://www.whatismybrowser.com/detect/what-is-my-local-ip-address) and follow the instructions.
+
+The website itself may not be able to automatically detect your local IP address, but it will give you instructions on how to locate it within your specific operating system.
+
+You will be given an IP address like `10.0.12.121` or `192.168.17.69`.
+
+You can then update the value in `frontend/Config.ts` to your local IP address.
+
+This will allow the app running on your mobile device to properly locate the GraphQL API running on your development machine.
+
+## Configure your Discourse Host
+
+As mentioned above, you'll need to have setup a Discourse host for the GraphQL API to interact with.
+
+We'd like to briefly cover the different approaches to setting up a Discourse Host for development before continuing.
+
+**1. Run a Discourse Instance Locally**
+
+:::note
+Ensure that you are managing all of your ports correctly.
+
+The development setup of Discourse with Docker makes use of multiple ports, one of which being **port 3000** by default. You'll want to double-check that none of the environment variables are pointing at the ports Discourse is using.
+:::
+
+If you'd like to run a Discourse site for development locally, the recommended way to do this to use **[Docker](https://www.docker.com/)**, so make sure you have it installed.
+
+Then, as we mentioned above, you can follow [these steps in the tutorial](tutorial/setup-discourse) to install and run a development instance of Discourse in Docker.
+
+**2. Use try.discourse.org or another popular Discourse site**
+:::info
+Feel free to use existing public Discourse sitesโsuch as the [Docker Community Forum](https://forums.docker.com/) or the [Rust Programming Language Forum](https://users.rust-lang.org/)โin order to test out the Lexicon Mobile App.
+
+Just be mindful of how you're contributing to those sites if you do.
+:::
+
+[Try Discourse](https://try.discourse.org/) is a publicly accessible Discourse instance which is intended for testing. As such, it resets every day.
+
+The only drawback of this approach is that you can only register as a normal user, and therefore cannot modify the site's admin settings.
+
+With this approach, you'd simply configure Prose in `api/.env` to point `PROSE_DISCOURSE_HOST` at one of these instances.
+
+```bash
+PROSE_DISCOURSE_HOST=https://try.discourse.org
+```
+
+## Working with the Codebase
+
+Now that you've prepared everything for development, you can start digging in on the Lexicon codebase.
+
+### Run the Lexicon Mobile App & Prose GraphQL Server
+
+You can run the Mobile App and test it out with a local Prose server by running this command **from the project root**:
+
+```
+$ npm run dev
+```
+
+This will simultaneously launch two processes:
+
+- The GraphQL API Server
+- The local Expo dev server, which will enable you to launch the React Native app from your device
+
+However, if you wish to run the frontend and backend seperately, execute the following command in a terminal to run the frontend
+
+```
+$ npm run --prefix frontend start
+```
+
+Then execute the following line in another terminal to run the backend
+
+```
+$ npm run --prefix api dev
+```
+
+### Debugging
+
+- Use [Expo Developer Menu](https://docs.expo.io/workflow/debugging/#developer-menu) to make the debugging process easier.
+
+Opening the Expo Developer Menu depends on your device:
+
+- On an iOS Device: Shake the device, or touch 3 fingers to the screen.
+- On the iOS Simulator: Hit `โ + ctrl + Z` on a Mac in the emulator.
+- On an Android Device: Shake the device vertically, or run `adb shell input keyevent 82` in the terminal window if the device is connected via USB.
+- On the Android Emulator: Hit `โ + M`, or run `adb shell input keyevent 82` in your terminal window.
+
+- If your changes don't show up, it could involve a cache issue. In this case, you should try restarting Expo.
+ - To do so, quit the process by hitting `Ctrl + C` in the Terminal where it is running.
+ - Then run `npm run start` again.
+ - If the issue persists, you should look for the latest guidance from Expo on how to clear the cache, as it has been known to change.
+
+### Running the Test Suites
+
+Before running tests, double-check that your changes don't contain any errors.
+
+You can run tests across both the frontend and backend codebases sequentially by running the following command from the project root:
+
+```
+$ npm run test
+```
+
+On top of ensuring that all tests have passed, the command will also notify you if there are any Typescript errors or issues from Prettier or ESLint.
+
+Also note that the process of running `npm run test` triggers an additional action in the frontend to take place before running the tests.
+
+A new folder, `frontend/generated`, is created and populated with all the GraphQL Query and Mutation types for use in the codebase.
+
+If we did not run this before the tests, they would fail due to type errors.
+
+### Build & Publish the Lexicon Mobile App
+
+:::note
+An Expo account is required in order to use Expo's services. You can create one here: https://expo.io/signup.
+Once you have created your Expo account, please ensure that you are signed in with your current shell session, via `expo login` or `eas login`.
+:::
+
+You are required to configure EAS build first by running:
+
+```bash
+eas build:configure
+```
+
+You will then get a prompt from the EAS CLI related to the EAS project IDs: `android.package` and `ios.bundleIdentifier`. EAS will provide you with an existing project ID if you have one or ask you to create a new one. As for `android.package` and `ios.bundleIdentifier`, you can specify those values with `com.companyname.appname`, or any other patterns you might prefer.
+
+Once you're done, verify the `proseUrl` value you will use for the actual build of the app in `Config.ts`.
+
+:::info
+When publishing your app, it is necessary to deploy Prose somewhere publicly accessible, perhaps on a cloud hosting provider like AWS or DigitalOcean. If Prose is only running on your local machine, users that download your app won't be able to use it.
+Check [the documentation](deployment) to deploy Prose if you haven't already.
+:::
+
+Now you can build the Mobile App via Expo (EAS) with the preview build profile by running command below:
+
+```bash
+eas build โplatform all โprofile preview
+```
+
+When you do this, the packager will minify all your code and generate two versions of your codeโone for iOS, and one for Androidโand then upload them both to the Expo CDN.
+
+Additionally, if you haven't yet optimized the app's assets, Expo will ask you if you'd like to do so.
+
+This has the same effect as manually running `npx expo-optimize` beforehand. It simply compresses all of the image assets in your project to reduce the size of your build.
+
+When the process is complete, you'll be presented with a shareable QR Code and a URL resembling https://exp.host/@ccheever/an-example, which directs you to the build details in Expo's web console.
+
+At this point, anyone can then use that link to load your project.
+
+For Android, you can install the app on an emulator or on your physical device. However, for iOS, you can only install it on the iOS simulator. To run the app on a real iOS device, follow the steps in [this part](tutorial/building#1-preview) of the tutorial.
+
+When building your app, it is recommended to build it as a preview build first, and make sure everything runs well before building it for release with the production profile.
+
+To build the app with the production build profile, run this command:
+
+```bash
+eas build โplatform all โprofile production
+```
+
+You will also be presented with links directing you to the build details in Expo.
+
+However, unlike the preview build, the release build cannot be installed directly on your physical device or in an emulator / simulator. You'll need to publish the app and then install it from either the Play Store or App Store.
+
+You can read a more detailed explanation of this process in [this section](tutorial/building) of the tutorial.
+
+#### Updates
+
+If you later want to deploy an update to your version of the Lexicon Mobile App, you can use the EAS update command.
+
+First, make sure to configure EAS update by running the following command:
+
+```bash
+eas update:configure
+```
+
+This command will automatically add the `expo.runtimeVersion` field to your `app.json` file.
+You'll see a warning in your terminal telling you to add `expo.updates.url` to `app.json`.
+
+Then run this command to update your project:
+
+```bash
+eas update -โbranch
+```
+
+:::note
+The channel name is the same as the build profile, so for the preview builds, you can run:
+
+```bash
+eas update -โbranch preview
+```
+
+:::
+
+Read more about updating your app [here](tutorial/updating).
+
+Once published, the new version will be available to your users the next time they open it.
+
+For more details on this processโincluding publishing to the App Store and Google Play Storeโfollow the instructions in [Publishing your App](tutorial/publishing).
+
+#### Configure the GraphQL API with your Discourse Server
+
+In order for a published version of the app to be able to contact your Discourse server, you'll need to ensure that:
+
+- The GraphQL API is deployed and running properly on a host that is reachable from the app itself.
+- The GraphQL API is configured to point at the correct host and port of your Discourse server
+- Your Discourse server is reachable by the GraphQL API
diff --git a/documentation/versioned_docs/version-2.0.0-beta/supported-devices.md b/documentation/versioned_docs/version-2.0.0-beta/supported-devices.md
new file mode 100644
index 00000000..84e6b1bb
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/supported-devices.md
@@ -0,0 +1,33 @@
+---
+title: Supported Devices
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+## iPhone and Android Phones
+
+:::info
+Older versions of iOS and Android may work, but are not officially supported.
+:::
+
+Once you've published to the App Store and Google Play Store, your published app will work out of the box for your users on both iPhone and Android devices with the following specifications:
+
+| Device | Minimum OS |
+| --------------- | -------------------- |
+| iPhone | iOS 16 and above |
+| Android Devices | Android 13 and above |
+
+| Android | iOS |
+| -------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
+| | |
+| | |
+| | |
+| | |
+
+## Support for Other Devices
+
+At this time, **tablets - including iPads** - and other mobile devices are **not supported**.
+
+We may consider developing support for this in the future.
+
+If this is critical for you, please drop us a line at support@kodefox.io and let us know.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/technologies.md b/documentation/versioned_docs/version-2.0.0-beta/technologies.md
new file mode 100644
index 00000000..8657288a
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/technologies.md
@@ -0,0 +1,21 @@
+---
+title: Technologies
+---
+
+### 100% React Native and TypeScript built on Expo
+
+Lexicon was built, and is maintained, with a single code baseโmeaning that bug fixes, improvements, and new features will (in most cases) automatically apply to both iOS and Android.
+
+### GraphQL-based API
+
+Developers who wish to contribute to (or fork) Lexicon can do so with all the benefits of GraphQL. For more information, check out [Concepts and Architecture](concepts#prose-discourse-through-graphql).
+
+### White Labeling Support
+
+White Label the Lexicon Mobile App to give your users the familiar look and feel of your brand. Learn more in [White Labeling](white-labeling).
+
+### Painless integration with existing Discourse instances
+
+Getting started is as easy as spinning up a new server for the Prose GraphQL API, and pointing it at your Discourse instance. No changes are required on your Discourse instance itself.
+
+Note: to enable features like [Push Notifications](./push-notifications) and [Email Deep Linking](./email-deep-linking/intro.md), you can install our [Discourse Plugin](./discourse-plugin.md).
diff --git a/documentation/versioned_docs/version-2.0.0-beta/theming.md b/documentation/versioned_docs/version-2.0.0-beta/theming.md
new file mode 100644
index 00000000..04dbc172
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/theming.md
@@ -0,0 +1,247 @@
+---
+title: Theming
+---
+
+:::note
+This section will involve reading and modifying Typescript. If you get stuck, reach out to us.
+:::
+
+Lexicon allows you to customize the default theme that the Mobile App provides.
+
+You can accomplish this by modifying the values in `frontend/src/constants/theme`, or in `frontend/src/theme`.
+
+There is a difference between the two, and they work in conjunction with one another.
+
+`frontend/src/constants/theme` defines the underlying base values of the theme.
+
+`frontend/src/theme` then imports those values, and uses them to compose the actual theme object used throughout the rest of the Mobile App.
+
+## Colors
+
+### Adjusting Base & Functional Colors
+
+There are 2 types of colors in the Mobile App: base colors and functional colors.
+
+Base colors are the underlying palette of the theme, whereas functional colors define specific use-cases of the base colors.
+
+For example, you might have noticed that the Mobile App features a nice, eye-catching Royal Blue color as its primary color.
+
+This is defined in the base colors as:
+
+```ts
+// ...
+royalBlue: '#2B6AFF',
+// ...
+```
+
+Then, the functional colors make use of this for particular components in the app.
+
+To continue with the example, the `royalBlue` base color is referenced in the functional colors as:
+
+```ts
+// ...
+activeTab: BASE_COLORS.royalBlue,
+// ...
+primary: BASE_COLORS.royalBlue,
+// ...
+```
+
+Now, any component can reference the functional colors' `primary` value, and it will be `royalBlue`.
+
+However, if you wanted a different theme with a new color, such as, `BASE_COLORS.lightningYellow`, then you could adjust it to:
+
+```ts
+// ...
+activeTab: BASE_COLORS.lightningYellow,
+// ...
+primary: BASE_COLORS.lightningYellow,
+// ...
+```
+
+And the Mobile App would replace the Royal Blue with the value you've defined for Lightning Yellow.
+
+For this reason, if you want to add more colors, you'll need to add base color values first, and then access them within the functional colors.
+
+This approach keeps a clean separation of concerns, which allows theme changes to seamlessly propagate throughout the Mobile App.
+
+### Color Scheme (Dark Mode and Light Mode)
+
+The theme allows you to control how the user can adjust the app's color scheme, if at all.
+
+There are three choices for this: `dark`, `light`, `no-preference`.
+
+- Dark: force the color scheme to remain dark
+- Light: force the color scheme to remain light
+- No Preference (default): allow your users to specify a preference for color scheme
+
+Note that if you specify `dark` or `light`, your users **will not** have the option of selecting a preference for color scheme.
+
+This manifests in the Mobile App by hiding the Dark Mode button which normally appears in the Preferences Scene.
+
+## Fonts
+
+The theme's fonts are declared in `frontend/src/constants/theme/fonts`.
+
+Inside of that file, you'll find multiple aspects of the fonts that can be adjusted:
+
+- Font Variants
+- Font Sizes
+- Heading Font Sizes
+
+### Font Variants
+
+Used to classify multiple font weights into named variants. It supports the following values:
+
+| Variants | Default font weight |
+| -------- | ------------------- |
+| bold | 700 |
+| semiBold | 600 |
+| normal | 400 |
+
+### Font Sizes
+
+Used to set a font size scale that is consistent throughout the app. It supports the following values:
+
+| Variants | Default size |
+| ---------------- | ------------ |
+| xl (extra large) | 24 |
+| l (large) | 18 |
+| m (medium) | 16 |
+| s (small) | 14 |
+| xs (extra small) | 12 |
+
+### Heading Font Sizes
+
+Used to classify multiple font sizes for heading elements, such as `h1`, `h2`, etc.
+
+These values are primarily used for rendering the content of posts and messages from Discourse.
+
+This is because Discourse posts are written in Markdown, and users will often leverage heading elements to format their posts.
+
+| Variants | Default size |
+| -------------- | ------------ |
+| h1 (Heading 1) | 32 |
+| h2 (Heading 2) | 24 |
+| h3 (Heading 3) | 22 |
+| h4 (Heading 4) | 20 |
+| h5 (Heading 5) | 18 |
+| h6 (Heading 6) | 17 |
+
+## Icons
+
+The `icons` theme file is used to store icon-related constants.
+
+Currently, the โiconsโ file only contains a constant which declares the icon sizes scale.
+
+| Variants | Default size |
+| ---------------- | ------------ |
+| xl (extra large) | 28 |
+| l (large) | 24 |
+| m (medium) | 20 |
+| s (small) | 18 |
+| xs (extra small) | 16 |
+
+## Images
+
+The `images` theme file is used to store theme constants used in rendering images.
+
+Currently, this file declares the following theme values:
+
+- Avatar Icon Size
+- Avatar Letter Size
+- Avatar Image Size
+
+Avatars are used throughout the app to display relevant info about a post or message.
+
+As such, it is typically the user's photo.
+
+However, when a photo is not provided, we also compose a letter-based avatar based on the user's initials.
+
+### Avatar Icon Size
+
+| Variants | Default size |
+| ---------------- | ------------ |
+| l (large) | 96 |
+| m (medium) | 52 |
+| s (small) | 40 |
+| xs (extra small) | 28 |
+
+### Avatar Letter Size
+
+| Variants | Default size |
+| ---------------- | ------------ |
+| l (large) | 72 |
+| m (medium) | 36 |
+| s (small) | 28 |
+| xs (extra small) | 16 |
+
+### Avatar Image Size
+
+This defines the quality of the image used for avatars.
+
+| Variants | Default size |
+| ---------------- | ------------ |
+| xl (extra large) | 450 |
+| l (large) | 150 |
+| m (medium) | 100 |
+| s (small) | 50 |
+
+## Spacing
+
+The `spacing` theme file defines spacing constants used throughout the Mobile App for padding and margins.
+
+| Variants | Default size |
+| ------------------------- | ------------ |
+| xxxl (triple extra large) | 36 |
+| xxl (double extra large) | 24 |
+| xl (extra large) | 16 |
+| l (large) | 12 |
+| m (medium) | 8 |
+| s (small) | 4 |
+| xs (extra small) | 2 |
+
+## Advanced Customization
+
+While the above adjustments are generally fairly simple, you can really customize the Mobile App to your heart's content (based on your skill level).
+
+Here are some additional aexamples.
+
+### Custom Fonts
+
+#### Create a folder for the Custom Fonts
+
+To keep the codebase organized, create a folder named `fonts` inside of `frontend/assets`.
+
+You can then move your custom font assets into this folder.
+
+#### Install & Use the `expo-font` Package
+
+This package eases the process of adding custom fonts into an Expo-based app.
+
+In particular, you'll want to use the `loadAsync` function from it, which will map your font assets to their variant names throughout the Mobile App.
+
+While we won't get into too much technical detail here, their [documentation](https://docs.expo.dev/versions/latest/sdk/font/) can guide you through the process.
+
+### Error Messages
+
+It is possible to customize both the error messages and the means through which they are presented to the user.
+
+In order to do this, you should first be aware of two files.
+
+#### `frontend/src/helpers/errorMessage.ts`
+
+The Prose GraphQL API forwards on error messages from Discourse.
+
+This file declares the specific text of those messages as constants so that they can easily be compared in `errorHandler.ts`.
+
+If you observe any additional error messages that are not being caught, you'll want to add them to this file, and then adjust `errorHandler.ts` below accordingly.
+
+#### `frontend/src/helpers/errorHandler.ts`
+
+This file imports from the above `errorMessage.ts`.
+
+It then defines exactly how errors should be handled, including the above messages, when they are encountered.
+
+Currently, the default approach is to display the errors using an Alert to the user.
+
+However, if you wanted to integrate snackbars, you would adjust the code in `errorHandler.ts` to replace the invocations of `Alert.alert`.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/troubleshooting-build.md b/documentation/versioned_docs/version-2.0.0-beta/troubleshooting-build.md
new file mode 100644
index 00000000..68d75dad
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/troubleshooting-build.md
@@ -0,0 +1,128 @@
+---
+title: Troubleshooting when trying out the app
+---
+
+
+
+
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+## Troubleshooting Connection and Configuration Issues with URL
+
+
+
+
+
+If you are encountering issues related to the URL, resulting in an error message saying "please connect to network" as shown in the screenshot, it is likely due to incorrect settings. Specifically, if you are attempting to test builds locally on your mobile device and the channel field is not properly configured, the app may continuously fallback to the localDevelopment channel, even if you have set it to something else like "preview."
+
+Here some steps and notes to help resolve this:
+
+- Open the `frontend/Config.ts` file in your project.
+- Locate the `config` object within the file.
+- In the `localDevelopment` section of the `config` object, you can add the Prose URL specific to the channel you are trying to test. This section is used for local development and as a fallback configuration for unknown build channels in EAS Build. Here's an example:
+
+ ```ts
+ const config: Config = {
+ localDevelopment: {
+ proseUrl: 'http://localhost:8929',
+ },
+ buildChannels: {
+ preview: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ production: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ },
+ };
+ ```
+
+- The example above shows that the config consists of two main sections: localDevelopment, which specifies the URL during localDevelopment, and buildChannels, which includes configurations for different channels such as preview and production. For local development, it will hit the Prose API with the URL `http://localhost:8929`. If the buildChannel is unknown or not found, it will always default to localDevelopment.
+- Update the `proseUrl` value within the desired build channel, such as `preview` or `production`, with the valid and reachable URL of your Prose server.
+- Once you have made the necessary changes, save the `frontend/Config.ts` file.
+
+Now, when you run eas build for a specific build channel, such as `eas build --profile=production`, it will utilize the Prose URL specified in the production configuration.
+
+:::note
+It is important to include the URL in the `frontend/app.json` file, which expo-updates will use to fetch update manifests. Failing to set the URL in the `frontend/app.json` file will result in the expo-update constant always returning undefined for the channel, causing the app to consistently utilize the localDevelopment URL after building. You can specify this URL in the expo and updates sections of the app.json file. For more detailed information on how to configure this, please refer to the [expo documentation](https://docs.expo.dev/versions/latest/config/app/#url) for more detail on this.
+
+```json
+"expo": {
+ "updates": {
+ ...,
+ "url": "https://u.expo.dev/"
+ }
+}
+```
+
+This configuration is essential for seamless integration with Config.ts in your project.
+:::
+
+In certain cases, you may encounter an issue related to Prose API URLs when the channel name specified in the `frontend/eas.json` file does not match the corresponding key name defined in the `config` variable in `frontend/Config.ts`. This discrepancy can lead to problems because the channel name from `eas.json` is used to determine the URL that will be utilized. If the names do not match, the default `localDevelopment` URL will be used instead.
+
+To ensure smooth functioning, it is important to use the same channel name in both the `frontend/eas.json` file and the `frontend/Config.ts` file. This will ensure proper mapping of the channel name to the corresponding URL.
+
+Here is an example to illustrate this:
+
+```json
+// frontend/eas.json
+
+"build": {
+ "staging": {
+ "android": {
+ "buildType": "apk"
+ },
+ "channel": "staging"
+ }
+}
+```
+
+```ts
+// frontend/Config.ts;
+
+const config: Config = {
+ localDevelopment: {
+ proseUrl: 'http://localhost:8929',
+ inferDevelopmentHost: true,
+ },
+
+ buildChannels: {
+ preview: {
+ proseUrl: '',
+ },
+ production: {
+ proseUrl: '',
+ },
+ staging: {
+ proseUrl: '',
+ },
+ },
+};
+```
+
+## The app closes abruptly after the splash screen
+
+If you encounter a situation where your app closes abruptly after the splash screen, it is likely that there are missing configurations in your `app.json` file. One common cause is the absence of a scheme definition in `app.json`, which is essential during the app build process.
+
+To resolve this issue, follow these steps:
+
+1. Open your project's `frontend/app.json` file.
+2. Look for the `"expo"` section.
+3. If a scheme is not present add this part in `"expo"` section
+
+```json
+"expo":{
+ "name": "",
+ "slug": "",
+ "scheme": "",
+ "version": "1.0.0"
+}
+```
+
+Replace `""` with the desired scheme name for your app.
+
+4. Save the changes to the `app.json` file.
+5. Rebuild your app and test it again.
+
+By ensuring that the scheme is correctly defined in `app.json`, you should be able to resolve the issue of the app closing after the splash screen.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/tutorial/building.md b/documentation/versioned_docs/version-2.0.0-beta/tutorial/building.md
new file mode 100644
index 00000000..3e261343
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/tutorial/building.md
@@ -0,0 +1,152 @@
+---
+title: Build your App
+---
+
+## EAS Build
+
+EAS Build is the upgraded version of `expo build`. This service helps to build app binaries for your Expo and React Native projects. Read more about it in the Expo documentation [here](https://docs.expo.dev/build/introduction/).
+
+### Configuration
+
+Let's get started by configuring EAS build. Check [here](https://docs.expo.dev/build-reference/build-configuration/) to see the complete guide from Expo.
+
+#### Build Setup
+
+Run this command in `/frontend` directory:
+
+```bash
+eas build:configure
+```
+
+When running that command, the EAS CLI will typically do the following:
+
+1. It will prompt you for the EAS project ID, either to use an existing ID if you have one, or create a new one. Then it will automatically add the `expo.extra.eas.projectId` field in `app.json`.
+2. It will create a new `eas.json` file if one doesnโt already exist. However, we have that set up for you, so you don't need to worry about creating one. ๐
+3. It will prompt you to specify `android.package` and `ios.bundleIdentifier` if those values are not already provided in `app.json`. Note that those two values don't have to be the identical.
+
+You can see that the values in `app.json` are updated after running the command.
+
+#### Configuration Values
+
+:::info
+When publishing your app, it is necessary to deploy Prose somewhere publicly accessible, perhaps on a cloud hosting provider like AWS or DigitalOcean. If Prose is only running on your local machine, users that download your app won't be able to use it.
+Check [the documentation](../deployment.md) to deploy Prose if you haven't already.
+
+In the original release of Lexicon, the **Prose URL** was specified in `frontend/.env`. However, as part of migrating to Expo's EAS feature, we centralized the configuration into `frontend/Config.ts` to save you the trouble of needing to maintain it in more than one place, as suggested in the [Expo documentation](https://docs.expo.dev/build-reference/variables/#can-i-share-environment-variables-defined-in-easjson-with-expo-start-and-eas-update)
+:::
+
+Next, open `Config.ts` and overwrite the placeholder values with the Prose URL you want to use for the build version. You can either set the same values or a different one for each channel. You don't need to adjust the values in `localDevelopment` since that is only used in development, and not when building the app.
+
+```ts
+const config = {
+ // ...
+ buildChannels: {
+ preview: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ production: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ },
+};
+```
+
+### Run a Build
+
+#### Build for Both Platforms
+
+To build on both platforms, you can use either of the commands below:
+
+```bash
+eas build --platform all
+```
+
+```bash
+eas build -p all
+```
+
+#### iOS only
+
+```bash
+eas build --platform ios
+```
+
+#### Android only
+
+```bash
+eas build --platform android
+```
+
+#### Run a build with a specific profile
+
+```bash
+eas build --platform all โ-profile
+```
+
+```bash
+eas build -p all โe
+```
+
+:::note
+Without --profile, the EAS CLI will default to the `production` profile.
+:::
+
+### Build Profiles
+
+Build profiles serve as a way of grouping configuration values for different scenarios when building the mobile app.
+
+You can find more details [here](https://docs.expo.dev/build/eas-json/).
+
+The `eas.json` file can contain multiple build profiles. However, it typically has 3 profiles: **preview**, **development**, and **production**.
+
+#### 1. Preview
+
+Purpose: to internally test the app in production-like circumstances.
+
+It is recommended to try building with the preview profile **_first_** before building your app with the production profile. That way, you can ensure the app runs as expected before itโs ready to be published.
+
+The build type for Android will be an **APK** file, whereas the iOS build will output a format that can be installed on the simulator.
+
+This is because the `ios.simulator` option was specified in `eas.json`:
+
+```json
+ "ios": {
+ "simulator": true
+ },
+```
+
+If you want to run the preview build on a real device, you'll need have an Apple account with Apple Developer Enterprise Program membership, then add the `ios.enterpriseProvisioning` value in `eas.json`:
+
+```json
+ "ios": {
+ "enterpriseProvisioning": "universal"
+ }
+```
+
+For the `preview` build profile, we have already set the distribution mode to [internal](https://docs.expo.dev/build/internal-distribution/). This ensures that EAS build provides shareable URLs for builds, with instructions on how to get them running.
+
+This approach then allows us to test the app without submitting to the App Store or Play Store.
+
+#### 2. Development
+
+Purpose: to make debugging easier. Expo will automatically include developer tools in the build. As you may have figured, this build should never be published to either of the app stores.
+
+Development builds depend on [expo-dev-client](https://docs.expo.dev/development/introduction/), so Expo will prompt us to install the library if needed.
+
+Similar to preview builds, you can add the iOS options mentioned above to run them on a simulator or real device.
+
+#### 3. Production
+
+Purpose: for submission to the App Store and Play Storeโas a public release, or as part of testing in each respective ecosystem.
+
+In order to use builds like this, they must be installed through the respective app stores.
+
+After running builds with this profile, you'll see that the iOS and Android versions have automatically been incremented. As you might expect, this is because `autoIncrement` has been set to `true`.
+
+It is worth noting, however, that this behavior only applies to TestFlight and Internal Testing, so you'll need to be sure to also manually increment the `expo.version` in `app.json` for public release. Expo provides further [documentation](https://docs.expo.dev/build-reference/app-versions/) on this topic.
+
+## The App is Built
+
+Great work! You can now share the installation link with your peers so they can try out the app.
+
+In the next section, you'll learn how to [publish](publishing) your app to the App Store and Play Store! ๐
diff --git a/documentation/versioned_docs/version-2.0.0-beta/tutorial/install-prose.md b/documentation/versioned_docs/version-2.0.0-beta/tutorial/install-prose.md
new file mode 100644
index 00000000..d6ecec67
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/tutorial/install-prose.md
@@ -0,0 +1,360 @@
+---
+title: Setup the Prose GraphQL API
+---
+
+Now that we have a running Discourse instance to interact with, we can move onto setting up the Prose GraphQL Server.
+
+To recap, Prose is a part of the Lexicon stack.
+
+It is responsible for providing a [GraphQL](https://graphql.org/) interface on top of Discourse, which the Lexicon Mobile App can then interact with.
+
+For more information about this, check out [Concepts & Architecture](../concepts).
+
+## Approaches for Setting Up Prose
+
+If your Discourse instance is running locally, it is natural that you should also setup your Prose server locally.
+
+Otherwise, it would be unnecessary extra work to get a remote Prose server communicating with your local Discourse server.
+
+However, if you've setup your Discourse instance in the cloud, it is up to you if you want to run your Prose server locally or in the cloud as well.
+
+If you'd like to install it in the cloud, you'll want to setup an additional server - similar to how you would set one up for Discourse. If you're not yet comfortable with this, feel free to jump back to the page, [Setup a Cloud Server (Optional)](setup-cloud-server).
+
+Bearing all of that in mind, once you have identified where you'd like to host Prose, you should also consider how you'd like to install it onto that machine.
+
+The first way, which we recommend, is to use **[Docker](https://www.docker.com/)**.
+
+And of course, the second way is to install it manually, rather than using containers.
+
+## Install Prose using Docker
+
+The reason we recommend using Docker is because you won't have to worry about setting up Prose's on your machine.
+
+We have already published Prose to [Docker Hub](https://hub.docker.com/), which means you can easily pull it down and run it. We'll guide you through that below.
+
+### Install Docker
+
+First, just as was necessary for setting up Discourse, you'll want to make sure Docker is installed on your machine.
+
+You can follow the instructions on the [Docker installation page](https://www.docker.com/get-started) if you are unsure of how to do this.
+
+### Pull and Run the Prose GraphQL API Image
+
+After successfully installing Docker, you can use the command below to run the Prose GraphQL image.
+
+Just bear in mind that you'll want to adjust some of the **environment variables** to your situation before you run the command.
+
+```
+$ docker run -d \
+ -e PROSE_DISCOURSE_HOST=https://meta.discourse.org \
+ -e PROSE_APP_PORT=80 \
+ -p 5000:80 \
+ --name prose-graphql \
+ kodefox/prose
+```
+
+The above command will take care of pulling the Prose GraphQL Docker Image, building it, and running it in a container.
+
+To help understand everything that's going on there, let's break it down line by line.
+
+```bash
+docker run -d
+```
+
+This instructs Docker to run our image as a container in **detached mode**. This is similar to backgrounding a process.
+
+```bash
+-e PROSE_DISCOURSE_HOST=https://meta.discourse.org
+-e PROSE_APP_PORT=80
+```
+
+The `-e` flag instructs Docker that we want to set or override certain environment variables in the container with the values we provided.
+
+In this case, we're telling Prose to interact with the Discourse instance is running at `https://meta.discourse.org`, and that Prose should run itself _inside of the container_ on a port of `80`.
+
+```
+-p 5000:80
+```
+
+Next, we're telling Docker what ports we want to map from our host machine into the container.
+
+In the previous step, we established that Prose will run internally on port 80. With the above command, we're telling Docker to expose the container's port 80 as port 5000 on our host.
+
+This means that Prose will be reachable on port 5000 of the host.
+
+So, if you're running this locally, you'll be able to interact with Prose at `http://localhost:5000`.
+
+And if you're running it in the cloud on a domain like `https://prose.mydiscussions.com`, you'd likely want it to be listening on port 443 so the user doesn't have to enter a port number as part of the URL.
+
+### Configure Prose
+
+As suggested above, you can configure Prose through the use of environment variables.
+
+You can find a comprehensive list of all environment variables on the Prose [Environment Variables](../env-prose) page.
+
+In this case, you really only need to set a value for `PROSE_DISCOURSE_HOST`, which will instruct Prose which Discourse instance you'd like it to interact with.
+
+Additionally, if you'd like to set a different port mapping, you can adjust the `-p` flag of the `docker run` command to something else, such as:
+
+```bash
+-p 8080:80
+```
+
+## Install Manually
+
+This section, whether being done locally or remotely on a cloud provider, will require you to install and configure the necessary dependencies to build and run Prose from scratch.
+
+### Setup Development Machine
+
+If you haven't already, setup your machine for Prose development. You can do so by following the guide at [Setup your Development Machine](setup).
+
+By the time you're done with this step, you should have a local copy of the Lexicon repository on your desired machine.
+
+### Configure Environment Variables
+
+The Prose GraphQL API, at a bare minimum, requires you to provide a URL to an accessible Discourse instance in order to run properly.
+
+Because we're doing this manually, you'll need to specify this in a different way than you would for Docker.
+
+Later on, once you've built Prose, one way you can specify this is to simply provide it inline as you launch the server.
+
+```bash
+PROSE_DISCOURSE_HOST=https://discourse.mysite.com node lib/index.js
+```
+
+However, you might find it more ergonomic to leverage the support we've setup for `.env` files.
+
+The entire Prose codebase lives in the `api/` directory of the repository, so get started by navigating there from the project root.
+
+```
+$ cd api/
+```
+
+Next, you'll need to create a `.env` file. Simply copy the template file, `.env.example` into the `.env` file using the following command.
+
+```
+$ cp .env.example .env
+```
+
+After that, as you'd expect, you want to adjust the `.env` file so that it contains the values specific to your project.
+
+```bash
+PROSE_DISCOURSE_HOST=
+PROSE_APP_PORT=
+```
+
+As was covered in the Docker section above, you can find a comprehensive list of all environment variables on the Prose [Environment Variables](../env-prose) page.
+
+### Launch the Prose GraphQL API
+
+:::info
+At this point, you should already have all the project's dependencies installed.
+
+If you encounter any errors about missing packages, go back to the guide at [Setup your Development Machine](setup).
+:::
+
+If you'd just like to launch Prose to check it out quickly, you can simply run (from the `api/` directory):
+
+```bash
+$ npm run dev
+```
+
+This will prepare and spin up Prose in a way that isn't ideal for production.
+
+If you wish to run the Prose GraphQL API in the background as a process, there are multiple solutions.
+
+One method is to use **[Tmux](https://github.com/tmux/tmux)**, which will detach the process from the terminal, allowing you to close it and keep Prose running.
+
+Another method is to use **[PM2](https://pm2.keymetrics.io/)**, which is a sophisticated toolset for running Node processes in production.
+
+#### Using Tmux
+
+**Tmux** can be used to detach processes from their controlling terminals, allowing sessions to remain active without being visible.
+
+To get started, install `tmux` on your machine.
+
+If you are unsure of how to install tmux, you can follow the instructions on [this page](https://github.com/tmux/tmux#installation).
+
+Once it's installed, launch it as follows:
+
+```bash
+$ tmux
+```
+
+Then you can run Prose in the same way as before.
+
+```bash
+$ npm run dev
+```
+
+If you want to detach from your current session, press `Ctrl + B` then press `d` on your keyboard. The session will remain active in the background.
+
+And if you wish to re-attach to your last session, run the following command.
+
+```
+$ tmux a
+```
+
+If you want to learn more about the tmux command, check out [this cheat sheet](https://tmuxcheatsheet.com/).
+
+#### Using PM2
+
+Another way to run Prose in the background is to use **pm2** (process manager for NodeJS).
+
+First, as you'd expect, you'll need to install `pm2` on your machine.
+
+```
+$ npm install -g pm2
+```
+
+Once it's installed, you'll also need to use `pm2` to install [Typescript](https://typescriptlang.org/).
+
+This is because Prose is written in Typescript, and this allows PM2 to run the Typescript files directly for us (as opposed to transpiling them and outputting them as JS first).
+
+To do this, simply run the following command:
+
+```
+$ pm2 install typescript
+```
+
+After that, you can now launch the Prose GraphQL API in the background with:
+
+```
+$ pm2 start src/index.ts
+```
+
+To list all running applications, run the following command.
+
+```
+$ pm2 list
+```
+
+These are some of the frequently used commands.
+
+```
+$ pm2 stop # To stop a process
+$ pm2 restart # To restart a process
+$ pm2 delete # To delete a process
+```
+
+## Test the GraphQL API
+
+Now that you've successfully launched Prose, you can actually interact with it in your web browser.
+
+Because of the libraries that we leveraged in building Prose, it automatically comes with [GraphiQL](https://www.graphql-yoga.com/docs/features/graphiql).
+
+This is an in-browser GraphQL IDE that makes it easy to explore the documentation and the schema of the GraphQL API.
+
+In order to access it, you'll need to make note of the host and port number that you configured the API with.
+
+For example, if you launched Prose from your local machine on port 5000, you'd navigate to [http://localhost:5000](http://localhost:5000).
+
+Similarly, if you set it up in the cloud, and all you have is an IP address with Prose listening on port 80, you would navigate to something like [http://174.31.92.1](http://174.31.92.1).
+
+Once the [GraphiQL](https://www.graphql-yoga.com/docs/features/graphiql) interface loads, you can test out some example queries and mutations, including logging into Discourse through Prose.
+
+### Login
+
+:::info
+If you're accessing a private Discourse site, you'll need to make note of the token that is returned to make other requests. See below.
+:::
+
+```
+mutation Login {
+ login(email: "user@lexicon.com", password: "user_password") {
+ ... on LoginOutput {
+ token
+ user {
+ id
+ name
+ username
+ avatarTemplate
+ }
+ }
+ }
+}
+```
+
+As mentioned in the notice, if you're interacting with a private Discourse site, you'll need to provide a token for other GraphQL requests.
+
+As part of the response for the above mutation, you'll notice a "token" field which contains your authentication token in Base64.
+
+You use this token in other queries and mutations by opening the HTTP Headers section on the bottom left-hand side of the page.
+
+This section expects JSON, with which you'll want to add an Authorization header that contains your token.
+
+```json
+{
+ "Authorization": ""
+}
+```
+
+Once you have done that, you can make authenticated GraphQL queries and mutations as the user you logged in with.
+
+### User Profile
+
+```
+ query UserProfile {
+ userProfile(username: "john_doe") {
+ user {
+ ... on UserDetail {
+ id
+ avatarTemplate
+ username
+ name
+ websiteName
+ bioRaw
+ location
+ dateOfBirth
+ email
+ }
+ }
+ }
+ }
+```
+
+### Topic Detail
+
+```
+query TopicDetail {
+ topicDetail(topicId: 1) {
+ id
+ title
+ views
+ likeCount
+ postsCount
+ liked
+ categoryId
+ tags
+ createdAt
+ postStream {
+ posts {
+ id
+ topicId
+ userId
+ name
+ username
+ avatarTemplate
+ raw
+ createdAt
+ }
+ stream
+ }
+ details {
+ participants {
+ id
+ username
+ avatarTemplate
+ }
+ }
+ }
+}
+```
+
+### Logout
+
+```
+ mutation Logout {
+ logout (username: "john_doe")
+ }
+```
diff --git a/documentation/versioned_docs/version-2.0.0-beta/tutorial/intro.md b/documentation/versioned_docs/version-2.0.0-beta/tutorial/intro.md
new file mode 100644
index 00000000..0098344d
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/tutorial/intro.md
@@ -0,0 +1,47 @@
+---
+title: Overview
+slug: /tutorial
+---
+
+:::info
+This tutorial **does not** cover the process of actually launching the app, as well as certain details about deploying to production. For support with those tasks, please refer to the documentation.
+:::
+
+## Welcome to the Lexicon Tutorial
+
+We're really excited to help you dig in with the Lexicon Stack and learn how to deploy it in a way that benefits you and your users.
+
+## Target Audience & Prerequisites
+
+In order to complete this tutorial, you should have familiarity with:
+
+- The command-line
+- Git and Github
+- Setting up a Discourse instance
+- Setting up servers in general
+
+In terms of prepararation, you will need:
+
+- NodeJS installed on your development machine
+ - Use the latest version of Node that is compatible with the project's version of Expo (i.e. `expo-cli`).
+- An editor to edit config files
+
+#### Have some concerns?
+
+Interested in Lexicon but lacking in technical abilities? We completely understand.
+
+Reach out to us at support@kodefox.com to chat about how we can help bring your idea to life.
+
+## Next Steps
+
+This tutorial will guide you through the process of getting the entire Lexicon Stack up and running **locally** with your Discourse site.
+
+At the end of the tutorial, you will be able to interact with your Discourse site in the Lexicon Mobile App on your local device or simulator.
+
+You will also have an understanding of:
+
+- How to configure and run the Prose GraphQL API locally or on a server you own
+- How to configure and run the Lexicon Mobile app on your device or in a simulator
+- The next steps needed to make full use of Lexicon
+
+Let's get started!
diff --git a/documentation/versioned_docs/version-2.0.0-beta/tutorial/publishing.md b/documentation/versioned_docs/version-2.0.0-beta/tutorial/publishing.md
new file mode 100644
index 00000000..66005bdd
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/tutorial/publishing.md
@@ -0,0 +1,97 @@
+---
+title: Publish your App
+---
+
+## EAS Submit
+
+EAS Submit is a service for uploading and submitting your application binaries to App Store and/or Play Store.
+Check [here](https://docs.expo.dev/submit/introduction/) to learn more about EAS Submit.
+
+### Prerequisites:
+
+- Registered app in App Store Connect, see the guide [here](../app-store#register-a-new-bundle-id).
+- Registered app in Play Store, see the guide [here](../play-store).
+
+### Configuration
+
+Before submitting, you are required to specify the credentials to publish your app.
+
+#### iOS
+
+For iOS, fill in your account information for `appleId`, `ascAppId`, and `appleTeamId`:
+
+```json
+ "base": {
+ "ios": {
+ "appleId": "",
+ "ascAppId": "",
+ "appleTeamId": ""
+ },
+ ...
+ },
+```
+
+- **appleId**: your apple ID (e.g., `john@gmail.com`).
+- **ascAppId**: your App Store Connect app ID. Find your ascAppID by following [this guide](https://github.com/expo/fyi/blob/main/asc-app-id.md) (e.g., `1234567890`).
+- **appleTeamId**: You can check your apple team ID [here](https://developer.apple.com/account/) (e.g., `12LE34XI45`).
+
+#### Android
+
+For Android, you will need to add a `.json` key file to authenticate with the Google Play Store. Please follow [this guide](https://github.com/expo/fyi/blob/main/creating-google-service-account.md) to generate one. Then, copy the JSON file to your `lexicon/frontend` directory, and rename the file as `playstore_secret.json`.
+
+The JSON file looks like this:
+
+```json
+{
+ "type": "service_account",
+ "project_id": "",
+ "private_key_id": "",
+ "private_key": "-----BEGIN PRIVATE KEY----------END PRIVATE KEY-----\n",
+ "client_email": "",
+ "client_id": "",
+ "auth_uri": "",
+ "token_uri": "",
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
+ "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/lexicon%40api.iam.gserviceaccount.com"
+}
+```
+
+Now that the configuration is done, you can start submitting your app.
+
+### Submitting
+
+Use this command to submit the build:
+
+```bash
+eas submit --platform ios --profile
+```
+
+Then you will see the EAS CLI prompt asking which app you would like to submit.
+
+There are 4 possible options:
+
+- Selecting a build from EAS
+- Providing the URL of an app archive
+- Providing the local path to an app binary file
+- Providing the build ID of an existing build on EAS
+
+If you have built your app using EAS Build or have been following the tutorial from [Build your App](building), then please choose the first option, and select the version you want.
+
+### Submit Profiles
+
+By default, `eas.json` has been configured with two submit profiles, which are **staging** and **production**.
+
+The configuration is mostly the same, the only difference lies in the Android track options.
+
+- Staging infers the track as `internal`. This means submitting with the staging profile will submit the build for internal testing in the Play Store.
+- Production infers the track as `production`, which will submit the build for Public Release in the Play Store.
+
+With iOS, on the other hand, both profiles will be submitted to TestFlight before you can release them publicly.
+
+You can reference the Expo documentation to learn more about [Android-specific](https://docs.expo.dev/submit/eas-json/#android-specific-options) and [iOS-specific](https://docs.expo.dev/submit/eas-json/#ios-specific-options) options.
+
+## Congratulations!
+
+Your app is now available for users to download from both the Play Store and the App Store! ๐ฅณ
+
+To learn more about how to update your published app in the case of a bug, as well as OTA updates, check out the [next and final section](updating) of the tutorial.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/tutorial/setup-cloud-server.md b/documentation/versioned_docs/version-2.0.0-beta/tutorial/setup-cloud-server.md
new file mode 100644
index 00000000..b69659a4
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/tutorial/setup-cloud-server.md
@@ -0,0 +1,27 @@
+---
+title: Setup a Cloud Server (Optional)
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+:::info
+This is an optional section for users that don't feel as confident spinning up a new server with a cloud provider.
+
+If you are already adept at this, you can skip to the next section.
+:::
+
+## DigitalOcean Guide
+
+### How To Set Up an Ubuntu 20.04 Server on a DigitalOcean Droplet
+
+For our users that aren't as familiar with setting up servers in the cloud, we wanted to provide you with a solid resource to learn more about it and accomplish something in the process.
+
+DigitalOcean has already provided an excellent guide to walk you through this, so we're going to link you over to them.
+
+In this guide, you will create an Ubuntu server through DigitalOceanโs administrative panel and configure it to work with your SSH keys.
+
+Once you have a solid understanding of how to setup servers in the cloud, you'll be much more capable of deploying the Lexicon Stack for your users.
+
+You can dig in on the article below.
+
+[Read: How To Set Up an Ubuntu 20.04 Server on a DigitalOcean Droplet](https://www.digitalocean.com/community/tutorials/how-to-set-up-an-ubuntu-20-04-server-on-a-digitalocean-droplet)
diff --git a/documentation/versioned_docs/version-2.0.0-beta/tutorial/setup-discourse.md b/documentation/versioned_docs/version-2.0.0-beta/tutorial/setup-discourse.md
new file mode 100644
index 00000000..9b5bf97a
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/tutorial/setup-discourse.md
@@ -0,0 +1,306 @@
+---
+title: Prepare a Discourse Instance
+---
+
+Before you can properly setup Lexicon, you'll need to have a running **[Discourse](https://www.discourse.org/)** instance for Lexicon to interact with.
+
+For this step, you actually have a few options:
+
+#### Option 1: Setup a Local Discourse Instance
+
+The first option is to [setup a development instance](#setup-discourse-locally) of Discourse locally on your development machine. This takes a bit of time and can get a bit technical.
+
+#### Option 2: Buy a Discourse Instance or Use your Existing One
+
+The second option is to pay to [setup a Discourse instance in the cloud](#setup-discourse-in-the-cloud) as a live, reachable production verison. This is much simpler, but has the obvious tradeoff of costing money.
+
+And perhaps it goes without saying, but if you already have a Discourse site, feel free to just use that.
+
+#### Option 3: Use a Public Discourse Site
+
+The third option is to use an existing Discourse site just to test things out.
+
+As you'll see later on, Lexicon allows you to configure which Discourse site it is pointing at. As such, you can instruct it to point at at a publically accessible Discourse site that you don't personally own.
+
+There are countless examples of active Discourse communities out there. Here are a few examples to choose from:
+
+##### Discourse Meta
+
+[https://meta.discourse.org/](https://meta.discourse.org/)
+
+##### Expo
+
+[https://forums.expo.dev/](https://forums.expo.dev/)
+
+##### The Rust Programming Language
+
+[https://users.rust-lang.org/](https://users.rust-lang.org/)
+
+##### FreeCodeCamp Forums
+
+[https://forum.freecodecamp.org/](https://forum.freecodecamp.org/)
+
+## Setup Discourse Locally
+
+:::note
+This section can take a long time. Depending on the specs of your machine, it could take between 10 - 30 minutes to complete.
+:::
+
+This section of the tutorial is based on the following post on Discourse: [Beginners Guide to Install Discourse for Development using Docker](https://meta.discourse.org/t/beginners-guide-to-install-discourse-for-development-using-docker/102009).
+
+If you run into any issues, feel free to reference the original post and subsequent discussion.
+
+### Install Docker
+
+**[Docker](https://www.docker.com/)** is a containerization framework that makes it easy to build, manage, and deploy your application stack in a way that is safer, more reliable, and repeatable across multiple platforms.
+
+When developing, building, and testing applications locally, it is an invaluable tool that greatly simplifies the entire process.
+
+The main way that Docker helps us in this tutorial is that it won't require any modifications to our machine's environment other than installing Docker itself.
+
+This is as-opposed to needing to install all of Discourse's dependencies on your physical machine, in a way that may take a lot of effort to undo later.
+
+If you are unsure of how to install Docker, you can follow the instructions on their [website](https://www.docker.com/get-started).
+
+### Clone Discourse
+
+Once Docker is up and running, we can get started with setting up Discourse locally.
+
+The first step is to clone the Discourse repository to your local machine and `cd` into it.
+
+```
+git clone https://github.com/discourse/discourse.git
+cd discourse
+```
+
+Note the repository is on the larger side (nearly 400mb), so this step may take a while depending on your connection.
+
+### Pull, Build, and Start the Discourse Dev Container
+
+:::caution
+Make sure that the **host ports** listed below are not already in use on your device.
+:::
+
+Discourse already contains a script to help spin up its entire infrastructure using Docker.
+
+During this process, the script will do the following:
+
+- Pull down the necessary "dev" Docker image to bootstrap Discourse
+- Build the aforementioned image
+- Run the image as a container with multiple ports mapped from your host into the container
+ - 127.0.0.1:**1080**->1080/tcp
+ - 127.0.0.1:**3000**->3000/tcp
+ - 127.0.0.1:**4200**->4200/tcp
+ - 127.0.0.1:**9292**->9292/tcp
+ - 127.0.0.1:**9405**->9405/tcp
+- Prompt you for an admin email address and password
+
+To get started, simply run the following command:
+
+```
+$ d/boot_dev --init
+```
+
+Note that all of the Docker images add up to about 1GB of disk space usage on your device.
+
+The command will pause when it needs information from you. As shown below, it will prompt you for an administrator email address and password.
+
+```bash
+# Output omitted
+== 20200804144550 AddTitleToPolls: migrating ==================================
+-- add_column(:polls, :title, :string)
+ -> 0.0014s
+== 20200804144550 AddTitleToPolls: migrated (0.0021s) =========================
+
+Creating admin user...
+Email: me@me.com
+Password:
+Repeat password:
+
+Ensuring account is active!
+
+Account created successfully with username me
+```
+
+Next, it will ask you if you want to make this account an admin account. You do.
+
+```bash
+Do you want to grant Admin privileges to this account? (Y/n) y
+
+Your account now has Admin privileges!
+```
+
+Please be aware, as suggested above, that the ports mentioned above are not currently in use by other processes.
+
+### If something unexpected happened
+
+It's possible that something strange may have happened at this step.
+
+Perhaps there was a weird error message, or the process just never displayed the output shown above.
+
+What we'd recommend doing is the following:
+
+#### Check if a Docker container named `discourse_dev` is running
+
+```bash
+$ docker ps | grep discourse_dev
+CONTAINER ID IMAGE ... NAMES
+dc72a4ead10f discourse/discourse_dev:release ... discourse_dev
+```
+
+If it is, stop and remove the container.
+
+```bash
+$ docker stop discourse_dev
+discourse_dev
+$ docker rm discourse_dev
+discourse_dev
+```
+
+#### Exit or Kill the Existing Process
+
+If the existing process (`d/boot_dev --init`) is still occupying your terminal session, attempt to exit it via `Ctrl + C`.
+
+If the process is not responding to `Ctrl + C` after some time, locate its PID and use `kill -9` to kill it
+
+```bash
+$ ps aux | grep rails
+user 81254 0.0 0.1 discourse_dev bin/rails s
+
+$ kill -9 81254
+```
+
+#### Restart Docker or your Machine
+
+Using the command or interface appropriate for your machine, you should restart all of Docker.
+
+On Docker for Mac, this is as simple as going into the tray icon and clicking Restart.
+
+#### Try running the command again
+
+Sometimes things just go a little haywire with this setup. Try running the command again to see if it works better this time.
+
+#### If you're absolutely stuck, reach out.
+
+Don't hestitate to contact us if you're just stuck with this one.
+
+### Optional: Run the Next Two Commands in the Background
+
+You can read on to get an understanding of what the two commands are, but it's worth mentioning that you want them to run simultaneously.
+
+You can do this by _backgrounding_ both processes.
+
+This means that they won't occupy your current session, requiring you to quit them in order to enter other commands.
+
+When you run this command, it will show you the process IDs (PIDs) of the processes that were backgrounded.
+
+To bring them back into the foreground, you can run the `fg` command, and then use `Ctrl + C` or a similar signal to stop them.
+
+```bash
+d/rails s & d/ember-cli &
+[2] 59786
+[3] 59787
+
+fg
+```
+
+Just **note** that you won't see the output of the commands, and so you may need to be patient for several minutes until Discourse is reachable at its local address.
+
+Alternatively, you can use the PIDs to kill the processes outright in another session:
+
+```bash
+kill -9 59786 59787
+```
+
+### Start the Rails Server within the Container
+
+If you hadn't already noticed, Discourse is built in [Ruby](https://www.ruby-lang.org/en/) using the very popular web framework, [Ruby on Rails](https://rubyonrails.org/).
+
+By running the command below, you will be starting the Rails server, which will take some time, and will produce a tremendous amount of output.
+
+In particular, you'll see the database being initialized as the dev container bootstraps the Discourse server.
+
+To get started, simply run the following command.
+
+```
+d/rails s
+```
+
+#### If you later can't quit the process
+
+**Note** that this command can sometimes hang when you're trying to kill it with `Ctrl + C`.
+
+If that happens, it's recommended that you first stop the Docker container:
+
+```bash
+docker stop docker_dev
+```
+
+Then, bring the process to the foreground with `fg` if necessary.
+
+Last, either exit your session if possible - such as by closing the Terminal - or find out the PID of the Rails process and kill it directly.
+
+```bash
+$ ps aux | grep rails
+user 81254 0.0 0.1 discourse_dev bin/rails s
+
+$ kill -9 81254
+```
+
+### Run the Ember CLI
+
+The above section mentioned Ruby on Rails, which handles the backend aspects of the Discourse application.
+
+However, the Discourse frontend is build in [EmberJS](https://emberjs.com/), which is a batteries-included frontend web framework used by multiple major companies.
+
+Run the command below to instruct the Ember CLI to start the Discourse frontend.
+
+```
+d/ember-cli
+```
+
+Once you have done this, you'll be able to access Disourse at [http://localhost:4200](http://localhost:4200).
+
+Please note that the output of this command can be a bit confusing. And at times, it can seem like nothing is happening.
+
+You may see several progress indicators, as well as blank output, for several minutes before the server is ready.
+
+The output you're looking for will resemble the following:
+
+```bash
+Build successful (72475ms) โ Serving on http://localhost:4200/
+
+Slowest Nodes (totalTime >= 5%) | Total (avg)
+----------------------------------------------------------------------+------------------
+Babel: discourse (2) | 31501ms (15750 ms)
+ember-auto-import-analyzer (11) | 10418ms (947 ms)
+Bundler (1) | 6119ms
+Babel: @ember/test-helpers (2) | 5075ms (2537 ms)
+broccoli-persistent-filter:TemplateCompiler (3) | 4596ms (1532 ms)
+```
+
+## Setup Discourse in the Cloud
+
+There are several guides with instructions on how to setup Discourse in the Cloud.
+
+Rather than writing another one, we have found our favorite one and would like to send you over to them to give you a proper walkthrough of the process.
+
+### Guide by SSDNodes
+
+The guide is provided by the [SSDNodes](https://www.ssdnodes.com/?e=blog&q=more-about-ssdnodes) Blog, [Serverwise](https://blog.ssdnodes.com/blog/).
+
+If you aren't familiar, [SSDNodes](https://www.ssdnodes.com) is an excellent, cost-effective VPS hosting provider.
+
+While we are most familiar with Digital Ocean, we'd strongly encourage you to check them out as an alternative for hosting Discourse.
+
+The post, titled [How To Install Discourse On Ubuntu](https://blog.ssdnodes.com/blog/install-discourse/), is written by [Joel Hans](https://blog.ssdnodes.com/blog/author/joel/).
+
+Joel has written an excellent guide. He'll take you through the entire process, including making update to your Discourse instance.
+
+If you find yourself stuck, or have any questions, feel free to reach out to us.
+
+## Use a Public Discourse Site
+
+If you've chosen this option, there's not much to do other than to note the URL of the Discourse site you'll be using.
+
+Once you have that written down somewhere, you're ready for the next section.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/tutorial/setup-mobile.md b/documentation/versioned_docs/version-2.0.0-beta/tutorial/setup-mobile.md
new file mode 100644
index 00000000..62ab943a
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/tutorial/setup-mobile.md
@@ -0,0 +1,120 @@
+---
+title: Configure & Launch the Mobile App
+---
+
+import useBaseUrl from '@docusaurus/useBaseUrl';
+
+After following the **[Setup the Prose GraphQL API](install-prose)** section, your GraphQL API should now be connected to your Discourse site.
+
+Next, we'll guide you through the process of connecting the Lexicon Mobile App to your Discourse site via Prose.
+
+### Mobile App Configuration
+
+:::note
+In the original release of Lexicon, the **Prose URL** was specified in `frontend/.env`. However, as part of migrating to Expo's EAS feature, we centralized the configuration into `frontend/Config.ts` to save you the trouble of needing to maintain it in more than one place, as suggested in the [Expo documentation](https://docs.expo.dev/build-reference/variables/#can-i-share-environment-variables-defined-in-easjson-with-expo-start-and-eas-update)
+:::
+
+Before launching your local version of the Lexicon Mobile App, you'll need to configure it with at least one piece of information.
+
+The Lexicon Mobile app relies exclusively on a running instance of the Prose GraphQL API in order to retrieve data from your Discourse instance.
+
+Therefore, you'll need to instruct it on how to locate your running Prose server.
+
+In development, it is common to have it running locally. However, if you have already deployed Prose
+somewhere, feel free to use that.
+
+#### Configuring `proseUrl` via `config`
+
+:::caution
+
+##### `proseUrl` requirements
+
+It is worth noting that `proseUrl` **must** start with either `http://` or `https://`.
+
+If it does not, the Mobile App will throw an error when launching.
+:::
+
+`Config.ts` contains the `config` object, which allows you to specify the Prose URL for each scenario encountered when developing and building the Mobile App.
+
+The specific configuration value which enables this is `proseUrl`, and it is contained within each scenario expressed by the `config` object.
+
+```ts
+const config = {
+ localDevelopment: {
+ proseUrl: 'http://localhost:8929',
+ },
+ buildChannels: {
+ preview: {
+ proseUrl: 'https://preview.myserver.com:8080/subpath',
+ },
+ production: {
+ proseUrl: 'https://myserver.com/api/prose',
+ },
+ },
+};
+```
+
+As mentioned earlierโabove, the `config` object allows us to express configuration values for multiple scenarios, which are:
+
+- `localDevelopment`: when developing against the app locally. This configuration is also used as a fallback for an unknown build channel.
+- `buildChannels`: used to define configuration by build channel when building the app with the EAS CLI.
+
+`buildChannels` makes use of Expo's build channels (typically `preview` and `production`) as its keys.
+
+Each key within `buildChannels` maps to a specific Prose URL, which will be used for the build version based on which channel you build for.
+
+From the example above, when we create a `preview` build, the app will be built and configured to contact a Prose server located at `https://preview.myserver.com:8080/subpath`.
+
+The example above expresses a setup in which each build has its own deployed Prose server. However, it is also common to use one server for all scenarios, including development.
+
+```ts
+const config = {
+ localDevelopment: {
+ proseUrl: 'https://myserver.com/api/prose',
+ },
+ buildChannels: {
+ preview: {
+ proseUrl: 'https://myserver.com/api/prose',
+ },
+ production: {
+ proseUrl: 'https://myserver.com/api/prose',
+ },
+ },
+};
+```
+
+##### Port Number
+
+Bear in mind that if your Prose server is not running on port 80 or 443, you also need to specify the **port number** via `proseUrl`.
+
+For example, if you've started a Prose server **locally** on port `8929` and try to run it using `expo start`, your `Config.ts` file would contain `http://myserver.com:8929/api/prose` under `localDevelopment.proseUrl`.
+
+### Launch the Mobile App
+
+Once you have configured everything, you'll want to launch the Mobile App to test that it is speaking to the right Prose server.
+
+To do this, you can simply run the following from the project root:
+
+```bash
+npm run --prefix frontend start
+```
+
+The Expo development server should launch, and you can follow the instructions to run the app in a simulator or on your actual device.
+
+#### Troubleshooting
+
+If the app throws an error upon loading, you should double-check the configuration values you specified, according to the message you've received.
+
+If the app loads, but you're unable to actually connect, you should verify the following:
+
+- Your Prose Server is up and running at the location you provided to the Lexicon Mobile App
+- Your Prose Server is configured to point at an accessible Discourse instance
+- Your Discourse instance is up and running correctly
+
+## Nice Work!
+
+At this point, you've already accomplished a lot.
+
+The Discourse server you started off with is now accessible in a new way from a sleek native mobile app, and you're free to customize it to your heart's content.
+
+In the next part of the tutorial, we'll briefly get into that very topic: customizing the Mobile App to [white label](white-label) it for your brand.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/tutorial/setup.md b/documentation/versioned_docs/version-2.0.0-beta/tutorial/setup.md
new file mode 100644
index 00000000..20505940
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/tutorial/setup.md
@@ -0,0 +1,98 @@
+---
+title: Setup your Development Machine
+---
+
+## Install NodeJS
+
+If you haven't already, install NodeJS on your machine.
+
+The tooling needed to setup Lexicon relies heavily on Node and npm.
+
+If you are unsure of how to install NodeJS, you can follow the instructions on the [NodeJS Website](https://nodejs.org/en/download/).
+
+#### Supported Node Versions
+
+It is recommended that you perform this tutorial using the latest version of Node that is compatible with the the project's version of Expo.
+
+You can always confirm this by viewing the dependencies in [frontend/package.json](https://github.com/lexiconhq/lexicon/blob/master/frontend/package.json).
+
+If your setup doesn't allow you to easily change your current Node version, we would recommend making use of [`nvm`](https://github.com/nvm-sh/nvm) to quickly switch between Node versions.
+
+### Install yarn, if you prefer
+
+Lexicon doesn't leverage any special features of [Yarn](https://yarnpkg.com/) - the alternative package manager for Node. If you prefer it, it will work the same as running `npm install`.
+
+For the purposes of this tutorial, we will demonstrate all commands using `npm`.
+
+### Clone the Lexicon Repository
+
+In a desirable location on your development machine, clone the Lexicon repository and `cd` into it.
+
+```sh
+git clone git@github.com:lexiconhq/lexicon.git
+cd lexicon
+```
+
+### Install Dependencies
+
+Next, install Lexicon's dependencies:
+
+```sh
+npm install
+```
+
+This will install dependencies for both the Mobile App and the backend GraphQL API, Prose.
+
+### Install the Expo CLI
+
+[Expo](https://expo.io/) is the phenomenal toolchain that Lexicon uses to develop and build the Mobile App.
+
+We will later use the Expo CLI to launch the Mobile App - either on your device or in a simulator.
+
+You can install the Expo CLI with the following command:
+
+```sh
+npm install --global expo-cli
+```
+
+Further information is available in the [Expo docs](https://docs.expo.io/).
+
+Then, verify that Expo is available in your `PATH` with the following:
+
+```sh
+$ expo --version
+
+```
+
+### Install the EAS CLI
+
+[Expo Application Services (EAS)](https://expo.dev/eas/) is an integrated set of cloud services for Expo and React Native apps.
+
+We will use the EAS CLI to build and publish the Mobile App.
+
+You can install the EAS CLI with the following command:
+
+```sh
+npm install --global eas-cli
+```
+
+Further information is available in the [Expo docs](https://docs.expo.dev/eas/).
+
+Then, verify that EAS is available in your `PATH` with the following:
+
+```sh
+$ eas --version
+eas-cli/
+```
+
+### Ready to Go!
+
+That's all we need for this step.
+
+Next, there is an optional guide to help you if you're not too familiar with setting up a server on a cloud provider.
+
+You're free to skip this if you're already adept at this process.
+
+After that, we'll look into how we can prepare Discourse to connect with the Lexicon Mobile App.
+
+If you don't already have a Discourse server setup, we'll get into that as well.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/tutorial/updating.md b/documentation/versioned_docs/version-2.0.0-beta/tutorial/updating.md
new file mode 100644
index 00000000..46fcfdd1
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/tutorial/updating.md
@@ -0,0 +1,68 @@
+---
+title: Update your App
+---
+
+## EAS Update
+
+EAS Update is the successor to `expo publish`. This service helps to update projects using the `expo-updates` library.
+
+In particular, it enables you to push quick fixes to your users in between full-fledged app store submissions.
+
+With EAS Update, there is no need to recompile the app with its non-native parts, such as TypeScript code, styling, or image assets. [Click here](https://docs.expo.dev/eas-update/introduction/) to learn more about EAS Update.
+:::note
+You are required to build the app with [EAS Build](building) before using the EAS Update.
+:::
+
+### Configuration
+
+Let's get started by configuring EAS update. Feel free to check out the [complete guide](https://docs.expo.dev/build-reference/build-configuration/) from Expo for further details.
+
+```bash
+eas update:configure
+```
+
+Running this command will add `expo.updates.url` and `runtimeVersion.policy` in `app.json`.
+
+:::caution
+
+As mentioned in the [Expo documentation](https://docs.expo.dev/build/updates/#previewing-updates-in-development-builds), you can no longer launch your app in Expo Go (using `expo start`) after adding the `runtimeVersion` field in `app.json`. It is recommended to use `expo-dev-client` instead to create a development build.
+
+```bash
+eas -p all -e development
+```
+
+or if you still wish to use Expo Go, please remove `runtimeVersion` field from `app.json` before running `expo start`.
+:::
+
+### Updating
+
+After making the necessary changes, you can push updates using this command:
+
+```bash
+eas update โ-branch โ-message โโ
+```
+
+The branch name here is the same as the build profile name when building the app.
+For example, if you had previously built the app with this command:
+
+```bash
+eas build โp all โe preview
+```
+
+Then you can later update it using:
+
+```bash
+eas update โ-branch preview โ-message โFixing typosโ
+```
+
+Once the update is complete, force close and reopen the installed app twice to view the update.
+
+## All Done! ๐
+
+That's it for the tutorial. Great work.
+
+We hope that this has served as an informative guide to help familiarize you with Lexicon and how you can make use of it.
+
+If you haven't already, check out the [Lexicon Documentation](../) to get a deeper understanding of the project and how it all works.
+
+If you have any questions, comments, feedback, or want to contribute, please reach out to us on Github!
diff --git a/documentation/versioned_docs/version-2.0.0-beta/tutorial/white-label.md b/documentation/versioned_docs/version-2.0.0-beta/tutorial/white-label.md
new file mode 100644
index 00000000..f0192667
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/tutorial/white-label.md
@@ -0,0 +1,82 @@
+---
+title: White Label your App
+---
+
+## Customize the Splash Screen and App Icon
+
+In order to customize the app for your own brand, you will likely want to provide your own assets for the **Splash Screen** and the **App Icon**.
+
+The **Splash Screen** - sometimes also referred to as the Launch Screen - is what appears while the app is launching. Some apps also display this to help conceal private information when the app is put into background mode.
+
+The **App Icon** is what is used to represent the app on the user's device, such as on the home screen and when listing it in the device's settings.
+
+Both of these assets often contain your logo in one form or another. For example, the App Icon for the Gmail app is the multi-colored outline of an envelope. Then, when launching the Gmail app, you will notice that the Splash Screen includes a larger version of the App Icon.
+
+### Customizing the Splash Screen
+
+:::info
+Expo does not currently support dark mode for splash screens.
+:::
+
+The assets used for the splash screen in the Mobile App are located at `frontend/assets/images/splash.png` and `frontend/assets/images/splashDark.png`.
+
+Above, we mention splash screen assets for both Dark Mode and Light Mode.
+
+However, unfortunately at this time, Expo does not support Dark Mode for Splash Screens. We have only included both so that they're ready when Expo finally does support this.
+
+In the meantime, you're free to adjust `splash.png` to influce what asset appears.
+
+In order to change it, you can simply replace the existing file with your own `splash.png`.
+
+To find out more about the Splash Screen image size and other details, please see the [Expo Splash Screen Guide](https://docs.expo.io/guides/splash-screens/).
+
+#### Futher Configuration
+
+To resize the Splash Screen image and change its background color, first open `frontend/app.json` and locate the `"splash"` field within it.
+
+As illustrated by the excerpt below, there are multiple fields that can be used to further adjust the Splash Screen:
+
+```json
+"splash": {
+ "image": "./assets/splash.png",
+ "resizeMode": "contain",
+ "backgroundColor": "#FFFFFF"
+},
+```
+
+**image**
+
+The `image` field is fairly self-explanatory - it allows you to adjust what path will be used to locate the Splash Screen image.
+
+**resizeMode**
+
+The `resizeMode` field allows you to manage how the Splash Screen image will be resized to maintain its aspect ratio:
+
+- `contain` - Resize the image to make sure the whole image is visible. This is the default setting.
+- `cover` - Resize the image to cover the entire container (in this case the whole screen) by either stretching or cropping the image as needed.
+
+Further details of how `contain` and `cover` behave are covered in the previously mentioned [Expo Splash Screen guide](https://docs.expo.io/guides/splash-screens/). For an even more detailed explanation, you can read [this post](http://blog.vjeux.com/2013/image/css-container-and-cover.html).
+
+**backgroundColor**
+
+The `backgroundColor` field enables you to specify the color of the background behind the Splash Screen image. Removing this value will result in usage of the default value, which is a white background color.
+
+### Customizing the App Icon
+
+Customizing the App Icon in Lexicon is nearly the same process as customizing the Splash Screen.
+
+The image asset for the Mobile App's icon is located at `frontend/assets/icon.png`. To customize it, simply overwrite that file with your own `icon.png`.
+
+## Further Customization
+
+We get into more detail about how to white label your app in the [White Labeling](../white-labeling) section of the documentation.
+
+In particular, this includes customizing and extending the theme's color palette, icons, and even fonts.
+
+Should you wish to customize anything not covered in that section, get in touch with us, and we'll see how we can help you make it a reality.
+
+## Awesome Work
+
+Your app looks cool now ๐. However, it's only accessible to you.
+
+Next, we'll cover how you can actually [build your app](building), so you can share it with the world.
diff --git a/documentation/versioned_docs/version-2.0.0-beta/white-labeling.md b/documentation/versioned_docs/version-2.0.0-beta/white-labeling.md
new file mode 100644
index 00000000..be413831
--- /dev/null
+++ b/documentation/versioned_docs/version-2.0.0-beta/white-labeling.md
@@ -0,0 +1,13 @@
+---
+title: Overview
+---
+
+The Lexicon Mobile App allows you to customize its appearance through a process known as **White Labeling**.
+
+If you're unfamiliar with this term, it's essentially the process of branding an existing application specifically for your users.
+
+White Labeling allows you to configure the app with your own logo, app icon, color theme, fonts, and so on.
+
+The idea is that your users won't know that the Lexicon team built this app. Its appearance will be completely customized to your brand.
+
+To learn more about White Labeling the Lexicon Mobile App, continue to the next section.
diff --git a/documentation/versioned_sidebars/version-1.0.0-sidebars.json b/documentation/versioned_sidebars/version-1.0.0-sidebars.json
new file mode 100644
index 00000000..511494c1
--- /dev/null
+++ b/documentation/versioned_sidebars/version-1.0.0-sidebars.json
@@ -0,0 +1,39 @@
+{
+ "docs": {
+ "Lexicon": [
+ "intro",
+ "rationale",
+ "technologies",
+ "concepts",
+ "discourse-features",
+ "supported-devices",
+ "contributing",
+ "commercial-support"
+ ],
+ "Getting Started": ["quick-start", "setup", "customize"],
+ "Configuring the Mobile App": ["env-mobile"],
+ "White Labeling": ["white-labeling", "assets", "theming"],
+ "Deploying Prose": ["deployment", "env-prose", "dedicated"],
+ "Configuring Discourse": ["optimal"],
+ "Publishing your App": [
+ "app-store",
+ "play-store",
+ "lexicon-updates",
+ "troubleshooting-build"
+ ]
+ },
+ "tutorial": {
+ "Tutorial": [
+ "tutorial/intro",
+ "tutorial/setup",
+ "tutorial/setup-cloud-server",
+ "tutorial/setup-discourse",
+ "tutorial/install-prose",
+ "tutorial/setup-mobile",
+ "tutorial/white-label",
+ "tutorial/building",
+ "tutorial/publishing",
+ "tutorial/updating"
+ ]
+ }
+}
diff --git a/documentation/versioned_sidebars/version-2.0.0-beta-sidebars.json b/documentation/versioned_sidebars/version-2.0.0-beta-sidebars.json
new file mode 100644
index 00000000..36d1e847
--- /dev/null
+++ b/documentation/versioned_sidebars/version-2.0.0-beta-sidebars.json
@@ -0,0 +1,57 @@
+{
+ "docs": {
+ "Lexicon": [
+ "intro",
+ "rationale",
+ "technologies",
+ "concepts",
+ "discourse-features",
+ "supported-devices",
+ "contributing",
+ "commercial-support"
+ ],
+ "Getting Started": ["quick-start", "setup", "customize"],
+ "Configuring the Mobile App": ["env-mobile"],
+ "White Labeling": ["white-labeling", "assets", "theming"],
+ "Deploying Prose": ["deployment", "env-prose", "dedicated"],
+ "Configuring Discourse": ["optimal"],
+ "Discourse Plugin": [
+ "discourse-plugin",
+ "discourse-plugin-installation",
+ "discourse-plugin-enable",
+ {
+ "Push Notifications": [
+ "push-notifications/introduction",
+ "push-notifications/plugin-interaction",
+ "push-notifications/setup/enable-push-notifications",
+ "push-notifications/setup/verify-push-notifications"
+ ],
+ "Email Deep Linking": [
+ "email-deep-linking/intro",
+ "email-deep-linking/setup/enable-email-deep-linking",
+ "email-deep-linking/setup/verify-email-deep-linking"
+ ]
+ }
+ ],
+ "Publishing your App": [
+ "app-store",
+ "play-store",
+ "lexicon-updates",
+ "troubleshooting-build"
+ ]
+ },
+ "tutorial": {
+ "Tutorial": [
+ "tutorial/intro",
+ "tutorial/setup",
+ "tutorial/setup-cloud-server",
+ "tutorial/setup-discourse",
+ "tutorial/install-prose",
+ "tutorial/setup-mobile",
+ "tutorial/white-label",
+ "tutorial/building",
+ "tutorial/publishing",
+ "tutorial/updating"
+ ]
+ }
+}
diff --git a/documentation/versions.json b/documentation/versions.json
new file mode 100644
index 00000000..f103ef9d
--- /dev/null
+++ b/documentation/versions.json
@@ -0,0 +1 @@
+["2.0.0-beta", "1.0.0"]
diff --git a/documentation/yarn.lock b/documentation/yarn.lock
index 14de2301..81b30277 100644
--- a/documentation/yarn.lock
+++ b/documentation/yarn.lock
@@ -1959,9 +1959,9 @@
"@hapi/hoek" "^9.0.0"
"@sideway/formula@^3.0.0":
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.0.tgz#fe158aee32e6bd5de85044be615bc08478a0a13c"
- integrity sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.1.tgz#80fcbcbaf7ce031e0ef2dd29b1bfc7c3f583611f"
+ integrity sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==
"@sideway/pinpoint@^2.0.0":
version "2.0.0"
@@ -4547,9 +4547,9 @@ htmlparser2@^8.0.1:
entities "^4.3.0"
http-cache-semantics@^4.0.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390"
- integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a"
+ integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==
http-deceiver@^1.2.7:
version "1.2.7"
@@ -4988,9 +4988,9 @@ json-schema-traverse@^1.0.0:
integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
json5@^2.1.2, json5@^2.2.1:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c"
- integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==
+ version "2.2.3"
+ resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
+ integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
jsonfile@^6.0.1:
version "6.1.0"
@@ -5051,9 +5051,9 @@ loader-runner@^4.2.0:
integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==
loader-utils@^2.0.0:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.2.tgz#d6e3b4fb81870721ae4e0868ab11dd638368c129"
- integrity sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c"
+ integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==
dependencies:
big.js "^5.2.2"
emojis-list "^3.0.0"
@@ -6751,19 +6751,19 @@ semver@7.0.0:
integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
semver@^5.4.1:
- version "5.7.1"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
- integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
+ version "5.7.2"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"
+ integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0:
- version "6.3.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
- integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
+ version "6.3.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
+ integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7:
- version "7.3.7"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
- integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
+ version "7.5.4"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
+ integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
dependencies:
lru-cache "^6.0.0"
@@ -7299,9 +7299,9 @@ typedarray-to-buffer@^3.1.5:
is-typedarray "^1.0.0"
ua-parser-js@^0.7.18:
- version "0.7.31"
- resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz#649a656b191dffab4f21d5e053e27ca17cbff5c6"
- integrity sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==
+ version "0.7.33"
+ resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.33.tgz#1d04acb4ccef9293df6f70f2c3d22f3030d8b532"
+ integrity sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw==
uncontrollable@^7.2.1:
version "7.2.1"
@@ -7690,9 +7690,9 @@ webpack-sources@^3.2.2, webpack-sources@^3.2.3:
integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
webpack@^5.73.0:
- version "5.74.0"
- resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.74.0.tgz#02a5dac19a17e0bb47093f2be67c695102a55980"
- integrity sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==
+ version "5.78.0"
+ resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.78.0.tgz#836452a12416af2a7beae906b31644cb2562f9e6"
+ integrity sha512-gT5DP72KInmE/3azEaQrISjTvLYlSM0j1Ezhht/KLVkrqtv10JoP/RXhwmX/frrutOPuSq3o5Vq0ehR/4Vmd1g==
dependencies:
"@types/eslint-scope" "^3.7.3"
"@types/estree" "^0.0.51"
diff --git a/frontend/.env.example b/frontend/.env.example
deleted file mode 100644
index 9accc364..00000000
--- a/frontend/.env.example
+++ /dev/null
@@ -1,2 +0,0 @@
-MOBILE_PROSE_HOST=http://127.0.0.1
-MOBILE_PROSE_PORT=80
\ No newline at end of file
diff --git a/frontend/.gitignore b/frontend/.gitignore
index d513d4bf..4906d099 100644
--- a/frontend/.gitignore
+++ b/frontend/.gitignore
@@ -11,7 +11,12 @@ web-build/
src/generated/**/*.ts
src/graphql/schema.json
.env
+playstore_secret.json
+dist/
# macOS
.DS_Store
/coverage
+
+#firebase
+google-services.json
diff --git a/frontend/Config.ts b/frontend/Config.ts
new file mode 100644
index 00000000..09e46c4b
--- /dev/null
+++ b/frontend/Config.ts
@@ -0,0 +1,70 @@
+/**
+ * This configuration file allows you to specify the configuration for developing against,
+ * as well as building and releasing the Lexicon Mobile App.
+ * Currently, there is only one important config value, which is `proseUrl`.
+ */
+
+import * as Updates from 'expo-updates';
+
+/**
+ * Modify this `config` object to specify the configuration for the Lexicon Mobile App by scenario.
+ */
+const config: Config = {
+ /*
+ * `localDevelopment` is used in local development. It has one extra key, `inferDevelopmentHost`,
+ * which you can read about in the documentation.
+ * `localDevelopment` is also used as a fallback configuration if an unknown build channel is provided
+ * to EAS Build.
+ */
+ localDevelopment: {
+ proseUrl: 'http://localhost:8929',
+ inferDevelopmentHost: true, // Specific to local development with Expo Go & the Android simulator. See docs.
+ },
+ /**
+ * `buildChannels` refers to channels within Expo's EAS Build service, which are defined in
+ * `eas.json`. These can be named anything you'd like, but the conventional channel names are
+ * `preview` and `production`.
+ *
+ * Make sure you specify the valid, reachable URL of your Prose server before running `eas build`
+ * for a particular build channel.
+ * By default, running `eas build` will attempt to use the values in `buildChannels.production`.
+ *
+ * If you create a new build profile / channel, be sure to add an entry for it here in `buildChannels`.
+ */
+ buildChannels: {
+ preview: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ production: {
+ proseUrl: 'http://PLACEHOLDER.change.this.to.your.prose.url',
+ },
+ },
+};
+
+/** `getConfig` contains the minimal business logic for retrieving the config for a given channel,
+ * and otherwise falling back to the `localDevelopment` config.
+ */
+function getConfig(): RequiredConfig | LocalConfig {
+ if (!Updates.channel) {
+ return config.localDevelopment;
+ }
+
+ const matchedConfig = config.buildChannels[Updates.channel];
+ if (!matchedConfig) {
+ return config.localDevelopment;
+ }
+
+ return matchedConfig;
+}
+
+/* Type definitions for the `config` object */
+type RequiredConfig = { proseUrl: `${'http' | 'https'}://${string}` };
+type LocalConfig = RequiredConfig & {
+ inferDevelopmentHost?: boolean;
+};
+type Config = {
+ localDevelopment: LocalConfig;
+ buildChannels: Record;
+};
+
+export default getConfig();
diff --git a/frontend/apollo.config.js b/frontend/apollo.config.js
new file mode 100644
index 00000000..3695bc85
--- /dev/null
+++ b/frontend/apollo.config.js
@@ -0,0 +1,9 @@
+module.exports = {
+ client: {
+ service: {
+ name: 'prose-api-schema',
+ localSchemaFile: '../api/src/generated/schema.graphql',
+ },
+ excludes: ['**/generated/**/*'],
+ },
+};
diff --git a/frontend/app.json b/frontend/app.json
index 3e2dcdf6..aabfcd9d 100644
--- a/frontend/app.json
+++ b/frontend/app.json
@@ -1,7 +1,9 @@
{
"expo": {
- "name": "Lexicon",
- "slug": "lexicon",
+ "name": "",
+ "slug": "",
+ "scheme": "",
+ "currentFullName": "@/",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
@@ -32,10 +34,19 @@
]
},
"ios": {
- "supportsTablet": false
+ "supportsTablet": false,
+ "buildNumber": "1.0.0",
+ "config": {
+ "usesNonExemptEncryption": false
+ }
+ },
+ "android": {
+ "permissions": [],
+ "versionCode": 1
},
"web": {
"favicon": "./assets/favicon.png"
- }
+ },
+ "plugins": ["expo-localization"]
}
}
diff --git a/frontend/assets/icons/adminPanel.svg b/frontend/assets/icons/AdminPanel.svg
similarity index 100%
rename from frontend/assets/icons/adminPanel.svg
rename to frontend/assets/icons/AdminPanel.svg
diff --git a/frontend/assets/icons/NoConnection.svg b/frontend/assets/icons/NoConnection.svg
new file mode 100644
index 00000000..3a6ac4e6
--- /dev/null
+++ b/frontend/assets/icons/NoConnection.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/frontend/assets/icons/NotificationActive.svg b/frontend/assets/icons/NotificationActive.svg
new file mode 100644
index 00000000..0700a1b5
--- /dev/null
+++ b/frontend/assets/icons/NotificationActive.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/frontend/assets/icons/Online.svg b/frontend/assets/icons/Online.svg
new file mode 100644
index 00000000..d71aa7c3
--- /dev/null
+++ b/frontend/assets/icons/Online.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/frontend/assets/icons/settings.svg b/frontend/assets/icons/Settings.svg
similarity index 100%
rename from frontend/assets/icons/settings.svg
rename to frontend/assets/icons/Settings.svg
diff --git a/frontend/assets/icons/Unreachable.svg b/frontend/assets/icons/Unreachable.svg
new file mode 100644
index 00000000..2e3778fc
--- /dev/null
+++ b/frontend/assets/icons/Unreachable.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/frontend/babel.config.js b/frontend/babel.config.js
index d53bc5f9..1befd4c0 100644
--- a/frontend/babel.config.js
+++ b/frontend/babel.config.js
@@ -1,9 +1,17 @@
-module.exports = function(api) {
+module.exports = function (api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
- plugins: [["module:react-native-dotenv",{
- "allowUndefined": true
- }]],
+ plugins: [
+ ['module:react-native-dotenv', { allowUndefined: true }],
+ /**
+ * Reanimated plugin has to be listed last
+ * Added to avoid this error
+ * `Export namespace should be first transformed by @babel/plugin-proposal-export-namespace-from`
+ * and as suggested in the docs
+ * https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/installation/#babel-plugin
+ */
+ 'react-native-reanimated/plugin',
+ ],
};
};
diff --git a/frontend/codegen.ts b/frontend/codegen.ts
new file mode 100644
index 00000000..1c62b59b
--- /dev/null
+++ b/frontend/codegen.ts
@@ -0,0 +1,34 @@
+import { CodegenConfig } from '@graphql-codegen/cli';
+
+const config: CodegenConfig = {
+ schema: '../api/src/generated',
+ documents: ['src/graphql/server/*.{ts,tsx}'],
+ config: {
+ namingConvention: {
+ fileName: 'change-case-all#pascalCase',
+ },
+ },
+ generates: {
+ './src/generated/server.ts': {
+ config: {
+ withHooks: true,
+ dedupeOperationSuffix: true,
+ },
+ plugins: [
+ {
+ add: {
+ content: '// THIS FILE IS GENERATED, DO NOT EDIT!',
+ },
+ },
+ 'typescript',
+ 'typescript-operations',
+ 'typescript-react-apollo',
+ ],
+ },
+ },
+ hooks: {
+ afterAllFileWrite: [`prettier --write "src/generated/**/*.{ts,tsx}"`],
+ },
+};
+
+export default config;
diff --git a/frontend/codegen.yml b/frontend/codegen.yml
deleted file mode 100644
index 176b155d..00000000
--- a/frontend/codegen.yml
+++ /dev/null
@@ -1,24 +0,0 @@
-overwrite: true
-schema: '../api/src/generated'
-documents: src/graphql/server/*.{ts,tsx}
-
-generates:
- src/generated/server/types.ts:
- - typescript
- src/generated/server:
- config:
- omitOperationSuffix: true
- preset: near-operation-file
- presetConfig:
- extension: .ts
- baseTypesPath: types.ts
- folder: ../../generated/server
- plugins:
- - add:
- content: '// THIS FILE IS GENERATED, DO NOT EDIT!'
- - typescript-operations
- - typescript-react-apollo
-hooks:
- afterAllFileWrite:
- - prettier --write "src/generated/**/*.{ts,tsx}"
- - node ./scripts/rename-generated-files.js
diff --git a/frontend/docs/DeepLinkRedirect.md b/frontend/docs/DeepLinkRedirect.md
new file mode 100644
index 00000000..1a60a944
--- /dev/null
+++ b/frontend/docs/DeepLinkRedirect.md
@@ -0,0 +1,76 @@
+# Deep Link
+
+## Overview
+
+Lexicon supports deep linking with our plugin discourse-lexicon-plugin. Currently, we have two types of deep links: post and message.
+
+A post deep link will contain information such as the post title and post number. For example: {baseDeepLinkUrl}/post-detail/t/welcome-to-our-community/7.
+
+On the other hand, a message deep link will include the title and message ID. For instance: {baseDeepLinkUrl}/message-detail/t/test/55/1.
+
+## Flow Navigate DeepLink in lexicon app
+
+### Post Detail
+
+This is a flow of diagram of post detail deep link
+
+```mermaid
+flowchart TD
+ UserClick[/Click DeepLink /] --> conditionDiscourse{Is Public Discourse?}
+
+ conditionDiscourse -- yes --> yesPublicCondition(Redirect To Post Detail Scene)
+ yesPublicCondition --> conditionPublicError403{Is GetError 403}
+
+ conditionPublicError403 -- yes --> yes403PublicCondition{Is Already Login}
+ conditionPublicError403 -- no --> no403PublicCondition{is Get Other Error}
+
+ no403PublicCondition -- yes --> resultGetOtherErrorPost(show error message `some thing wrong`)
+ no403PublicCondition -- no --> resultPost(show the post)
+
+
+ yes403PublicCondition -- yes --> yesPublicIsLoginCondition(Redirect To Home Scene and Show Alert Private Post)
+ yes403PublicCondition -- no --> noPublicIsLoginCondition(Redirect To Login Scene)
+
+
+ conditionDiscourse -- no --> privateCondition{is Already Login}
+
+ privateCondition -- yes --> yesPublicCondition
+
+ privateCondition -- no --> noPublicIsLoginCondition
+
+ noPublicIsLoginCondition --> afterLogin[\Input Login Account\]
+
+ afterLogin --> yesPublicCondition
+```
+
+### Message Detail
+
+This is a flow diagram of message detail deep link
+
+```mermaid
+flowchart TD
+ UserClick[/Click DeepLink /] --> conditionDiscourse{Is Public Discourse?}
+
+ conditionDiscourse -- yes --> yesPublicCondition(Redirect To Message Detail Scene)
+
+ yesPublicCondition --> ErrorCondition{is Get Error}
+
+ ErrorCondition -- yes --> resultGetOtherErrorPost(show error message `sorry we can't get the message`)
+ ErrorCondition -- no --> resultPost(show the message)
+
+
+ conditionDiscourse -- no --> privateCondition{is Already Login}
+
+ privateCondition -- yes --> yesPublicCondition
+ privateCondition -- no --> noPrivateConditionLogin(Redirect To Login Scene)
+
+ noPrivateConditionLogin --> afterLogin[\Input Login Account\]
+
+ afterLogin --> yesPublicCondition
+```
+
+## Note
+
+1. We will encounter a 403 error when attempting to make a request to the topicDetail query for private posts. To provide more details on this issue, please refer to PR [#1100](https://github.com/kodefox/lexicon/pull/1100), which offers a more comprehensive description.
+
+2. In our code, we store the deep link path in a hook, which can be found in the file `AppNavigator.tsx`. The code checks if the user is not logged in and then saves the path of the deep link, for example, `t/welcome-to-our-community/7`. This path is handled in the login process, where the user is automatically redirected to the specific route, either the message or post detail scene.
diff --git a/frontend/docs/authentication.md b/frontend/docs/authentication.md
new file mode 100644
index 00000000..46b65372
--- /dev/null
+++ b/frontend/docs/authentication.md
@@ -0,0 +1,28 @@
+# Authentication
+
+## Overview
+Lexicon have few different cases of different state of authentication that need to be handled. This document will explain how to handle each case.
+
+## Ingredients
+### Session Token
+We save session token in async storage. When booting our app, we will load the token from async storage to state. We also use token state to determine whether user is logged in or not. We currently implement this in `AuthProvider` component. The token are in the form of a apollo ReactiveVar because we need to update it in our apollo client and it be hard to update React state from apollo client.
+
+### SiteSettings Query
+SiteSettings query are utilized to determine whether a discourse instance is a private instance where we cannot register new user freely ora public instance where we can register new user freely. In case of public discourse this endpoint should be able to be accessed without authentication.
+
+## Authentication flow
+
+1. Load token from async storage to state (inside auth provider)
+2. Hit SiteSettings endpoint, several result also depending on token availability would determine where we redirect our user to
+3. Redirect user to a page based on combination of token availability and SiteSettings result
+
+| Token | SiteSettings | Result |
+| --- | --- | --- |
+| No | Error | Redirect to login |
+| No | Success | Redirect to Home|
+| Yes | Error | Clean session |
+| Yes | Success | Redirect to Home |
+
+
+
+
diff --git a/frontend/docs/expoExperienceId.md b/frontend/docs/expoExperienceId.md
new file mode 100644
index 00000000..6b0d22a4
--- /dev/null
+++ b/frontend/docs/expoExperienceId.md
@@ -0,0 +1,392 @@
+# Expo Experience Id Push notifications
+
+## Overview
+
+In our integration with the Discourse Lexicon plugin, the Expo experience ID is required to support push notifications. We obtain this from Expo in the mobile app by making use of the [`expo-constants`](https://docs.expo.dev/versions/latest/sdk/constants/) package. According to the documentation, we can access the `expoConfig.originalFullName` or `expoConfig.currentFullName` properties to obtain the desired value.
+
+## Why Experience Id Require
+
+The requirement for the experience ID in the Discourse Lexicon Plugin arises from the need to handle the error known as `PUSH_TOO_MANY_EXPERIENCE_IDS`. This error occurs when attempting to send push notifications, and it can be further understood and managed by referring to the [documentation here](https://docs.expo.dev/push-notifications/sending-notifications/#request-errors).
+
+## Result From Researching Experience Id
+
+The experience ID used for push notifications follows the format `@username/project`. According to the Expo documentation and research conducted within the Lexicon project, we can obtain the experience ID by utilizing `expoConfig.originalFullName` or `expoConfig.currentFullName`. To achieve this, it's necessary to include these values within the `app.json` file of the Lexicon project. Here the example of value
+
+```json
+{
+ "name": "",
+ "slug": "",
+ "scheme": "",
+ "currentFullName": "@/",
+ "originalFullName": "@/"
+}
+```
+
+If we haven't configured these values in the `app.json` file, running the app locally in development mode, building it, or performing an EAS update will result in `undefined` values being returned from the `expo-constants` package.
+
+Here is the distinction between `currentFullName` and `originalFullName` based on the Expo documentation:
+
+- `originalFullName`: This constant represents the initial name of your Expo project as defined when the project was created. Even if the project is transferred between accounts or renamed, this value will remain unchanged.
+
+- `currentFullName`: In contrast, this constant reflects the current name of your app. It might change if you decide to rename your app in the future. When a project is transferred between accounts or renamed, this value may be updated to match the latest name.
+
+In summary, while "originalFullName" retains the app's original name, "currentFullName" keeps track of the app's current name, which can change due to renaming or transfers.
+
+Another constant that can be utilized is `manifest2.extra.scopeKey`, which provides the experience ID value. This value can be obtained from `manifest2` when running the APK in local development mode and after performing an EAS update to build the APK. However, it will return null if the APK is built without utilizing an EAS update.
+
+The value from `manifest2.extra.scopeKey` will be auto-generated based on the `projectId` in `app.json`. If no `projectId` value is set, it will return the value `anonymous` for the user, such as `@anonymous/-2339463f-0c9d-4d59-9898-55d6adf8f37b`. Where UUID will be add in scopeKey if there are no project id to make unique identifier.
+
+#### Table Constants Experience Id in Lexicon
+
+| Name | Value | Development | Build | Update |
+| -------------------------------- | ------------------- | ----------- | ----- | ------ |
+| manifest.extra.scopeKey | @kfox/kf-lounge | โ
| โ | โ
|
+| currentFullName/OriginalFullName | | โ
| โ
| โ
|
+
+Here Result of expoConfig and manifest2 value in app
+
+### Local Development
+
+```json
+{
+ "expoConfig": {
+ "name": "KF Lounge",
+ "slug": "kf-lounge",
+ "scheme": "kf-lounge",
+ "version": "1.1.7",
+ "orientation": "portrait",
+ "icon": "./assets/icon.png",
+ "splash": {
+ "image": "./assets/images/splash.png",
+ "resizeMode": "contain",
+ "backgroundColor": "#ffffff",
+ "imageUrl": "http://192.168.1.4:8081/assets/./assets/images/splash.png"
+ },
+ "userInterfaceStyle": "automatic",
+ "updates": {
+ "fallbackToCacheTimeout": 0
+ },
+ "assetBundlePatterns": ["**/*"],
+ "packagerOpts": {
+ "config": "metro.config.js",
+ "sourceExts": [
+ "expo.ts",
+ "expo.tsx",
+ "expo.js",
+ "expo.jsx",
+ "ts",
+ "tsx",
+ "js",
+ "jsx",
+ "json",
+ "wasm",
+ "svg"
+ ]
+ },
+ "ios": {
+ "supportsTablet": false,
+ "buildNumber": "1.0.0",
+ "config": {
+ "usesNonExemptEncryption": false
+ }
+ },
+ "android": {
+ "package": "com.kodefox.kflounge",
+ "permissions": ["READ_EXTERNAL_STORAGE", "WRITE_EXTERNAL_STORAGE"],
+ "googleServicesFile": "",
+ "versionCode": 29
+ },
+ "web": {
+ "favicon": "./assets/favicon.png"
+ },
+ "plugins": ["expo-localization"],
+ "_internal": {
+ "isDebug": false,
+ "projectRoot": "/Users/switzer/Desktop/lexicon/frontend",
+ "dynamicConfigPath": {},
+ "staticConfigPath": "/Users/switzer/Desktop/lexicon/frontend/app.json",
+ "packageJsonPath": "/Users/switzer/Desktop/lexicon/frontend/package.json"
+ },
+ "sdkVersion": "49.0.0",
+ "platforms": ["ios", "android"],
+ "iconUrl": "http://192.168.1.4:8081/assets/./assets/icon.png",
+ "hostUri": "192.168.1.4:8081"
+ },
+ "manifest2": {
+ "id": "fe70a46f-547c-4389-ad96-8dfb9e910dd0",
+ "createdAt": "2023-08-09T07:55:27.551Z",
+ "runtimeVersion": "exposdk:49.0.0",
+ "launchAsset": {
+ "key": "bundle",
+ "contentType": "application/javascript",
+ "url": "http://192.168.1.4:8081/index.bundle?platform=android&dev=true&hot=false&lazy=true"
+ },
+ "assets": [],
+ "metadata": {},
+ "extra": {
+ "expoClient": {
+ "name": "KF Lounge",
+ "slug": "kf-lounge",
+ "scheme": "kf-lounge",
+ "version": "1.1.7",
+ "orientation": "portrait",
+ "icon": "./assets/icon.png",
+ "splash": {
+ "image": "./assets/images/splash.png",
+ "resizeMode": "contain",
+ "backgroundColor": "#ffffff",
+ "imageUrl": "http://192.168.1.4:8081/assets/./assets/images/splash.png"
+ },
+ "userInterfaceStyle": "automatic",
+ "updates": {
+ "fallbackToCacheTimeout": 0,
+ "url": "https://u.expo.dev/74846d43-b313-4543-9590-71704cc3a568"
+ },
+ "assetBundlePatterns": ["**/*"],
+ "packagerOpts": {
+ "config": "metro.config.js",
+ "sourceExts": [
+ "expo.ts",
+ "expo.tsx",
+ "expo.js",
+ "expo.jsx",
+ "ts",
+ "tsx",
+ "js",
+ "jsx",
+ "json",
+ "wasm",
+ "svg"
+ ]
+ },
+ "ios": {
+ "supportsTablet": false,
+ "buildNumber": "1.0.0",
+ "config": {
+ "usesNonExemptEncryption": false
+ }
+ },
+ "android": {
+ "package": "com.kodefox.kflounge",
+ "permissions": ["READ_EXTERNAL_STORAGE", "WRITE_EXTERNAL_STORAGE"],
+ "googleServicesFile": "{\n \"project_info\": {\n \"project_number\": \"301575653646\",\n \"project_id\": \"kflounge-aa9d1\",\n \"storage_bucket\": \"kflounge-aa9d1.appspot.com\"\n },\n \"client\": [\n {\n \"client_info\": {\n \"mobilesdk_app_id\": \"1:301575653646:android:2860ef5ec5c5ceceb02f5f\",\n \"android_client_info\": {\n \"package_name\": \"com.kodefox.kflounge\"\n }\n },\n \"oauth_client\": [\n {\n \"client_id\": \"301575653646-gg3u22vdrmir0aa38uirlvbv433m4c8c.apps.googleusercontent.com\",\n \"client_type\": 3\n }\n ],\n \"api_key\": [\n {\n \"current_key\": \"AIzaSyDV8j1qkZdCdKlvSRvyOI2566cVXGfAnLs\"\n }\n ],\n \"services\": {\n \"appinvite_service\": {\n \"other_platform_oauth_client\": [\n {\n \"client_id\": \"301575653646-gg3u22vdrmir0aa38uirlvbv433m4c8c.apps.googleusercontent.com\",\n \"client_type\": 3\n }\n ]\n }\n }\n }\n ],\n \"configuration_version\": \"1\"\n}\n",
+ "versionCode": 29
+ },
+ "web": {
+ "favicon": "./assets/favicon.png"
+ },
+ "plugins": ["expo-localization"],
+ "_internal": {
+ "isDebug": false,
+ "projectRoot": "/Users/switzer/Desktop/lexicon/frontend",
+ "dynamicConfigPath": {},
+ "staticConfigPath": "/Users/switzer/Desktop/lexicon/frontend/app.json",
+ "packageJsonPath": "/Users/switzer/Desktop/lexicon/frontend/package.json"
+ },
+ "sdkVersion": "49.0.0",
+ "platforms": ["ios", "android"],
+ "iconUrl": "http://192.168.1.4:8081/assets/./assets/icon.png",
+ "hostUri": "192.168.1.4:8081"
+ },
+ "expoGo": {
+ "debuggerHost": "192.168.1.4:8081",
+ "logUrl": "http://192.168.1.4:8081/logs",
+ "developer": {
+ "tool": "expo-cli",
+ "projectRoot": "/Users/switzer/Desktop/lexicon/frontend"
+ },
+ "packagerOpts": {
+ "dev": true
+ },
+ "mainModuleName": "index",
+ "__flipperHack": "React Native packager is running"
+ },
+ "scopeKey": "@kfox/kf-lounge"
+ },
+ "isVerified": true,
+ "name": "My New Experience",
+ "primaryColor": "#023C69",
+ "iconUrl": "https://d3lwq5rlu14cro.cloudfront.net/ExponentEmptyManifest_192.png",
+ "orientation": "default"
+ }
+}
+```
+
+### Build APK
+
+```json
+{
+ "expoConfig": {
+ "name": "KF Lounge",
+ "slug": "kf-lounge",
+ "scheme": "kf-lounge",
+ "version": "1.1.7",
+ "orientation": "portrait",
+ "icon": "./assets/icon.png",
+ "splash": {
+ "image": "./assets/images/splash.png",
+ "resizeMode": "contain",
+ "backgroundColor": "#ffffff"
+ },
+ "userInterfaceStyle": "automatic",
+ "updates": {
+ "fallbackToCacheTimeout": 0,
+ "url": "https://u.expo.dev/74846d43-b313-4543-9590-71704cc3a568"
+ },
+ "assetBundlePatterns": ["**/*"],
+ "packagerOpts": {
+ "config": "metro.config.js",
+ "sourceExts": [
+ "expo.ts",
+ "expo.tsx",
+ "expo.js",
+ "expo.jsx",
+ "ts",
+ "tsx",
+ "js",
+ "jsx",
+ "json",
+ "wasm",
+ "svg"
+ ]
+ },
+ "ios": {
+ "supportsTablet": false,
+ "buildNumber": "1.0.0"
+ },
+ "android": {
+ "package": "com.kodefox.kflounge",
+ "permissions": ["READ_EXTERNAL_STORAGE", "WRITE_EXTERNAL_STORAGE"],
+ "googleServicesFile": "./google-services.json",
+ "versionCode": 29
+ },
+ "web": {
+ "favicon": "./assets/favicon.png"
+ },
+ "plugins": ["expo-localization"],
+ "sdkVersion": "49.0.0",
+ "platforms": ["ios", "android"]
+ },
+ "manifest2": null
+}
+```
+
+### After Eas Update
+
+> **Note:** for manifest2 value is already inside extra or `manifest2.extra`
+
+```json
+{
+ "expoConfig": {
+ "ios": {
+ "buildNumber": "31",
+ "supportsTablet": false,
+ "bundleIdentifier": "com.kodefox.kflounge"
+ },
+ "web": {
+ "favicon": "./assets/favicon.png"
+ },
+ "icon": "./assets/icon.png",
+ "name": "KF Lounge",
+ "slug": "kf-lounge",
+ "scheme": "kf-lounge",
+ "splash": {
+ "image": "./assets/images/splash.png",
+ "resizeMode": "contain",
+ "backgroundColor": "#ffffff"
+ },
+ "android": {
+ "package": "com.kodefox.kflounge",
+ "permissions": ["READ_EXTERNAL_STORAGE", "WRITE_EXTERNAL_STORAGE"],
+ "versionCode": 31,
+ "googleServicesFile": "./google-services.json"
+ },
+ "updates": {
+ "url": "https://u.expo.dev/74846d43-b313-4543-9590-71704cc3a568",
+ "fallbackToCacheTimeout": 0
+ },
+ "version": "1.1.9",
+ "platforms": ["ios", "android"],
+ "sdkVersion": "49.0.0",
+ "orientation": "portrait",
+ "packagerOpts": {
+ "config": "metro.config.js",
+ "sourceExts": [
+ "expo.ts",
+ "expo.tsx",
+ "expo.js",
+ "expo.jsx",
+ "ts",
+ "tsx",
+ "js",
+ "jsx",
+ "json",
+ "wasm",
+ "svg"
+ ]
+ },
+ "runtimeVersion": {
+ "policy": "sdkVersion"
+ },
+ "userInterfaceStyle": "automatic",
+ "assetBundlePatterns": ["**/*"]
+ },
+ "manifest2": {
+ "expoClient": {
+ "ios": {
+ "buildNumber": "31",
+ "supportsTablet": false,
+ "bundleIdentifier": "com.kodefox.kflounge"
+ },
+ "web": {
+ "favicon": "./assets/favicon.png"
+ },
+ "icon": "./assets/icon.png",
+ "name": "KF Lounge",
+ "slug": "kf-lounge",
+ "scheme": "kf-lounge",
+ "splash": {
+ "image": "./assets/images/splash.png",
+ "resizeMode": "contain",
+ "backgroundColor": "#ffffff"
+ },
+ "android": {
+ "package": "com.kodefox.kflounge",
+ "permissions": ["READ_EXTERNAL_STORAGE", "WRITE_EXTERNAL_STORAGE"],
+ "versionCode": 31,
+ "googleServicesFile": "./google-services.json"
+ },
+ "updates": {
+ "url": "https://u.expo.dev/74846d43-b313-4543-9590-71704cc3a568",
+ "fallbackToCacheTimeout": 0
+ },
+ "version": "1.1.9",
+ "platforms": ["ios", "android"],
+ "sdkVersion": "49.0.0",
+ "orientation": "portrait",
+ "packagerOpts": {
+ "config": "metro.config.js",
+ "sourceExts": [
+ "expo.ts",
+ "expo.tsx",
+ "expo.js",
+ "expo.jsx",
+ "ts",
+ "tsx",
+ "js",
+ "jsx",
+ "json",
+ "wasm",
+ "svg"
+ ]
+ },
+ "runtimeVersion": {
+ "policy": "sdkVersion"
+ },
+ "userInterfaceStyle": "automatic",
+ "assetBundlePatterns": ["**/*"]
+ },
+ "scopeKey": "@kfox/kf-lounge"
+ }
+}
+```
diff --git a/frontend/eas.json b/frontend/eas.json
new file mode 100644
index 00000000..42f2c146
--- /dev/null
+++ b/frontend/eas.json
@@ -0,0 +1,51 @@
+{
+ "cli": {
+ "version": ">= 2.6.0",
+ "appVersionSource": "local"
+ },
+ "build": {
+ "development": {
+ "developmentClient": true,
+ "distribution": "internal",
+ "channel": "development"
+ },
+ "preview": {
+ "distribution": "internal",
+ "channel": "preview",
+ "ios": {
+ "simulator": true
+ },
+ "android": {
+ "buildType": "apk"
+ }
+ },
+ "production": {
+ "autoIncrement": true,
+ "channel": "production"
+ }
+ },
+ "submit": {
+ "base": {
+ "ios": {
+ "appleId": "",
+ "ascAppId": "",
+ "appleTeamId": ""
+ },
+ "android": {
+ "serviceAccountKeyPath": "./playstore_secret.json"
+ }
+ },
+ "staging": {
+ "extends": "base",
+ "android": {
+ "track": "internal"
+ }
+ },
+ "production": {
+ "extends": "base",
+ "android": {
+ "track": "production"
+ }
+ }
+ }
+}
diff --git a/frontend/index.js b/frontend/index.js
new file mode 100644
index 00000000..ce8f2073
--- /dev/null
+++ b/frontend/index.js
@@ -0,0 +1,5 @@
+import { registerRootComponent } from 'expo';
+
+import App from './App';
+
+registerRootComponent(App);
diff --git a/frontend/metro.config.js b/frontend/metro.config.js
index 963e0bab..70b5bbe1 100644
--- a/frontend/metro.config.js
+++ b/frontend/metro.config.js
@@ -1,17 +1,16 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
-const { getDefaultConfig } = require('metro-config');
+const { getDefaultConfig } = require('expo/metro-config');
-module.exports = (async () => {
- const {
- resolver: { sourceExts, assetExts },
- } = await getDefaultConfig();
- return {
- transformer: {
- babelTransformerPath: require.resolve('react-native-svg-transformer'),
- },
- resolver: {
- assetExts: assetExts.filter((ext) => ext !== 'svg'),
- sourceExts: [...sourceExts, 'svg'],
- },
- };
-})();
+const defaultConfig = getDefaultConfig(__dirname);
+const {
+ transformer,
+ resolver: { assetExts },
+} = defaultConfig;
+
+defaultConfig.transformer = {
+ ...transformer,
+ babelTransformerPath: require.resolve('react-native-svg-transformer'),
+};
+defaultConfig.resolver.assetExts = assetExts.filter((ext) => ext !== 'svg');
+defaultConfig.resolver.sourceExts.push('svg');
+module.exports = defaultConfig;
diff --git a/frontend/package.json b/frontend/package.json
index d6a5a8c3..8b35a2cf 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,104 +1,130 @@
{
- "main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
- "quickstart": "MOBILE_PROSE_HOST=http://127.0.0.1 MOBILE_PROSE_PORT=8929 expo -c",
+ "quickstart": "expo -c",
"typecheck": "tsc --noEmit -p .",
"format": "prettier --write \"src/**/*.{ts,tsx}\"",
"format:check": "prettier --check \"src/**/*.{ts,tsx}\"",
"lint": "eslint --max-warnings 0 \"src/**/*.{ts,tsx}\"",
- "jest": "MOBILE_PROSE_HOST=http://localhost jest --coverage --passWithNoTests",
- "test": "yarn graphql:generate && yarn lint && yarn typecheck && yarn format:check && yarn jest",
+ "jestTest": "jest --coverage --passWithNoTests",
+ "test": "yarn graphql:generate && yarn lint && yarn typecheck && yarn format:check && yarn jestTest",
"eject": "expo eject",
- "graphql:generate": "graphql-codegen --config codegen.yml"
+ "graphql:generate": "graphql-codegen --config codegen.ts",
+ "postinstall": "patch-package",
+ "eas-build-post-install": "yarn --cwd ../ && yarn --cwd ../ generate",
+ "android:push:encrypt": "openssl enc -aes-256-cbc -salt -md sha512 -pbkdf2 -in ./google-services.json -out ./google-services.json.enc -k",
+ "dec-google-services": "openssl enc -aes-256-cbc -d -md sha512 -pbkdf2 -in ./google-services.json.enc -out ./google-services.json -k"
},
"dependencies": {
- "@apollo/client": "^3.6.9",
+ "@apollo/client": "^3.7.1",
"@expo-google-fonts/courier-prime": "^0.2.2",
- "@react-native-async-storage/async-storage": "~1.17.3",
- "@react-native-community/datetimepicker": "6.5.2",
- "@react-native-community/masked-view": "^0.1.11",
+ "@react-native-async-storage/async-storage": "1.18.2",
+ "@react-native-community/datetimepicker": "7.2.0",
+ "@react-native-masked-view/masked-view": "0.2.9",
"@react-navigation/bottom-tabs": "^6.3.2",
"@react-navigation/elements": "^1.3.4",
"@react-navigation/native": "^6.0.11",
"@react-navigation/stack": "^6.2.2",
"apollo-upload-client": "^17.0.0",
- "expo": "^47.0.0",
- "expo-constants": "~14.0.2",
- "expo-crypto": "~12.0.0",
- "expo-file-system": "~15.1.1",
- "expo-image-picker": "~14.0.2",
- "expo-localization": "~14.0.0",
- "expo-permissions": "~14.0.0",
- "expo-status-bar": "~1.4.2",
+ "expo": "^49.0.6",
+ "expo-constants": "~14.4.2",
+ "expo-crypto": "~12.4.1",
+ "expo-device": "^5.4.0",
+ "expo-file-system": "~15.4.3",
+ "expo-image-picker": "~14.3.2",
+ "expo-linear-gradient": "~12.3.0",
+ "expo-linking": "~5.0.2",
+ "expo-localization": "~14.3.0",
+ "expo-network": "~5.4.0",
+ "expo-notifications": "~0.20.1",
+ "expo-permissions": "~14.2.1",
+ "expo-splash-screen": "~0.20.5",
+ "expo-status-bar": "~1.6.0",
+ "expo-system-ui": "~2.4.0",
+ "expo-updates": "~0.18.12",
"graphql": "^16.5.0",
"intl": "^1.2.5",
"markdown-it-flowdock": "^0.3.8",
- "react": "18.1.0",
- "react-dom": "18.1.0",
- "react-hook-form": "^6",
- "react-native": "0.70.8",
+ "react": "18.2.0",
+ "react-dom": "18.2.0",
+ "react-hook-form": "^7.43.9",
+ "react-native": "0.72.4",
"react-native-auto-grow-textinput": "^1.2.1",
"react-native-dotenv": "^3.3.1",
- "react-native-gesture-handler": "~2.8.0",
+ "react-native-gesture-handler": "~2.12.0",
"react-native-image-viewing": "^0.2.2",
"react-native-image-zoom-viewer": "^3.0.1",
"react-native-keyboard-accessory": "^0.1.16",
"react-native-keyboard-aware-scroll-view": "0.9.5",
"react-native-markdown-display": "^7.0.0-alpha.2",
"react-native-parsed-text": "^0.0.22",
- "react-native-reanimated": "~2.12.0",
- "react-native-safe-area-context": "4.4.1",
- "react-native-screens": "~3.18.0",
- "react-native-svg": "13.4.0",
- "react-native-web": "~0.18.7",
- "use-debounce": "^8.0.3"
+ "react-native-reanimated": "~3.3.0",
+ "react-native-safe-area-context": "4.6.3",
+ "react-native-screens": "~3.22.0",
+ "react-native-skeleton-placeholder": "^5.2.4",
+ "react-native-svg": "13.9.0",
+ "react-native-toast-message": "^2.1.5",
+ "use-debounce": "^8.0.4"
},
"devDependencies": {
"@babel/core": "^7.19.3",
- "@graphql-codegen/cli": "2.10.0",
+ "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
+ "@babel/plugin-proposal-optional-chaining": "^7.21.0",
+ "@graphql-codegen/add": "^3.2.1",
+ "@graphql-codegen/cli": "^3.3.0",
"@graphql-codegen/near-operation-file-preset": "^2.4.0",
"@graphql-codegen/typescript": "2.7.2",
- "@graphql-codegen/typescript-operations": "2.5.2",
+ "@graphql-codegen/typescript-operations": "^3.0.3",
"@graphql-codegen/typescript-react-apollo": "3.3.2",
- "@graphql-codegen/typescript-resolvers": "^2.7.2",
- "@types/apollo-upload-client": "^14.1.0",
+ "@types/apollo-upload-client": "^17.0.2",
"@types/jest": "^26.0.9",
- "@types/react": "~18.0.24",
+ "@types/react": "~18.2.14",
"@types/react-native": "~0.70.6",
"@types/react-native-dotenv": "^0.2.0",
- "@types/react-test-renderer": "^16.9.2",
- "@typescript-eslint/eslint-plugin": "^5.58.0",
- "@typescript-eslint/parser": "^5.58.0",
- "apollo": "2.34.0",
- "eslint": "^8.38.0",
- "eslint-config-prettier": "^8.8.0",
- "eslint-plugin-eslint-comments": "^3.2.0",
- "eslint-plugin-prettier": "^4.2.1",
- "eslint-plugin-react": "^7.32.2",
- "eslint-plugin-react-hooks": "^4.6.0",
- "eslint-plugin-react-native": "^4.0.0",
- "eslint-plugin-styles": "^1.0.0",
- "eslint-plugin-t": "^1.6.0",
- "jest": "^26.6.3",
- "jest-expo": "^47.0.0",
+ "@types/react-test-renderer": "^18.0.0",
+ "cross-env": "^7.0.3",
+ "eslint": "^7.6.0",
+ "eslint-config-kodefox": "^1.2.0",
+ "eslint-plugin-styles": "^0.1.0",
+ "eslint-plugin-t": "^1.2.1",
+ "jest": "^29.2.1",
+ "jest-expo": "^49.0.0",
+ "patch-package": "^6.4.7",
+ "postinstall-postinstall": "^2.1.0",
"prettier": "^2.0.5",
+ "react-native-console-time-polyfill": "^1.2.3",
"react-native-svg-transformer": "^0.14.3",
"react-native-testing-library": "^6.0.0",
- "react-test-renderer": "^16.13.1",
+ "react-test-renderer": "18.0.0",
"runtypes": "^5.0.1",
"ts-jest": "^26.1.4",
- "typescript": "^4.9.5"
+ "typescript": "^5.1.3"
},
"jest": {
"preset": "jest-expo",
"setupFiles": [
- "/src/__mocks__/setup.js"
+ "/src/__mocks__/setup.js",
+ "/src/__mocks__/setupLinking.ts"
],
"moduleNameMapper": {
"\\.svg$": "/src/__mocks__/svgMock.js"
}
},
+ "eslintConfig": {
+ "extends": "kodefox/react-native",
+ "plugins": [
+ "t",
+ "styles"
+ ],
+ "rules": {
+ "t/string-literal": 1,
+ "styles/style-maker-no-unused": 1,
+ "operator-assignment": [
+ "warn",
+ "always"
+ ]
+ }
+ },
"prettier": {
"singleQuote": true,
"trailingComma": "all",
diff --git a/frontend/patches/@react-navigation+stack+6.2.2.patch b/frontend/patches/@react-navigation+stack+6.2.2.patch
new file mode 100644
index 00000000..b1b4d332
--- /dev/null
+++ b/frontend/patches/@react-navigation+stack+6.2.2.patch
@@ -0,0 +1,20 @@
+diff --git a/node_modules/@react-navigation/stack/src/views/Stack/Card.tsx b/node_modules/@react-navigation/stack/src/views/Stack/Card.tsx
+index 4ce3b31..b239b40 100755
+--- a/node_modules/@react-navigation/stack/src/views/Stack/Card.tsx
++++ b/node_modules/@react-navigation/stack/src/views/Stack/Card.tsx
+@@ -107,6 +107,7 @@ export default class Card extends React.Component {
+ componentDidMount() {
+ this.animate({ closing: this.props.closing });
+ this.isCurrentlyMounted = true;
++ this.props.gesture.addListener(()=>{return});
+ }
+
+ componentDidUpdate(prevProps: Props) {
+@@ -144,6 +145,7 @@ export default class Card extends React.Component {
+ this.props.gesture.stopAnimation();
+ this.isCurrentlyMounted = false;
+ this.handleEndInteraction();
++ this.props.gesture.removeAllListeners();
+ }
+
+ private isCurrentlyMounted = false;
diff --git a/frontend/patches/react-native-markdown-display+7.0.0-alpha.2.patch b/frontend/patches/react-native-markdown-display+7.0.0-alpha.2.patch
new file mode 100644
index 00000000..007aafb9
--- /dev/null
+++ b/frontend/patches/react-native-markdown-display+7.0.0-alpha.2.patch
@@ -0,0 +1,46 @@
+diff --git a/node_modules/react-native-markdown-display/package.json b/node_modules/react-native-markdown-display/package.json
+index 0670296..93bc4b5 100644
+--- a/node_modules/react-native-markdown-display/package.json
++++ b/node_modules/react-native-markdown-display/package.json
+@@ -35,7 +35,7 @@
+ "react-native-fit-image": "^1.5.5"
+ },
+ "peerDependencies": {
+- "react": "^16.2.0",
++ "react": ">=16.2.0",
+ "react-native": ">=0.50.4"
+ },
+ "devDependencies": {
+diff --git a/node_modules/react-native-markdown-display/src/index.d.ts b/node_modules/react-native-markdown-display/src/index.d.ts
+index f0daf4a..0e46a73 100644
+--- a/node_modules/react-native-markdown-display/src/index.d.ts
++++ b/node_modules/react-native-markdown-display/src/index.d.ts
+@@ -1,7 +1,7 @@
+ // tslint:disable:max-classes-per-file
+ import MarkdownIt from 'markdown-it';
+ import Token from 'markdown-it/lib/token';
+-import {ComponentType, ReactNode} from 'react';
++import React, {ComponentType, ReactNode} from 'react';
+ import {StyleSheet, View} from 'react-native';
+
+ export function getUniqueID(): string;
+@@ -82,6 +82,7 @@ export function stringToTokens(
+ export function tokensToAST(tokens: ReadonlyArray): ASTNode[];
+
+ export interface MarkdownProps {
++ children?: React.ReactNode;
+ rules?: RenderRules;
+ style?: StyleSheet.NamedStyles;
+ renderer?: AstRenderer;
+diff --git a/node_modules/react-native-markdown-display/src/lib/util/tokensToAST.js b/node_modules/react-native-markdown-display/src/lib/util/tokensToAST.js
+index b0ed265..4b6a6a1 100644
+--- a/node_modules/react-native-markdown-display/src/lib/util/tokensToAST.js
++++ b/node_modules/react-native-markdown-display/src/lib/util/tokensToAST.js
+@@ -61,6 +61,7 @@ export default function tokensToAST(tokens) {
+ )
+ ) {
+ astNode.index = children.length;
++ astNode.key= `${astNode.type}-${astNode.index}`
+
+ if (token.nesting === 1) {
+ children.push(astNode);
diff --git a/frontend/patches/react-native-skeleton-placeholder+5.2.4.patch b/frontend/patches/react-native-skeleton-placeholder+5.2.4.patch
new file mode 100644
index 00000000..cc805224
--- /dev/null
+++ b/frontend/patches/react-native-skeleton-placeholder+5.2.4.patch
@@ -0,0 +1,58 @@
+diff --git a/node_modules/react-native-skeleton-placeholder/lib/skeleton-placeholder.js b/node_modules/react-native-skeleton-placeholder/lib/skeleton-placeholder.js
+index 353abb6..6370a37 100644
+--- a/node_modules/react-native-skeleton-placeholder/lib/skeleton-placeholder.js
++++ b/node_modules/react-native-skeleton-placeholder/lib/skeleton-placeholder.js
+@@ -36,7 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
+ const masked_view_1 = __importDefault(require("@react-native-masked-view/masked-view"));
+ const React = __importStar(require("react"));
+ const react_native_1 = require("react-native");
+-const react_native_linear_gradient_1 = __importDefault(require("react-native-linear-gradient"));
++const LinearGradient = require('expo-linear-gradient').LinearGradient;
+ const WINDOW_WIDTH = react_native_1.Dimensions.get('window').width;
+ const logEnabled = false;
+ const SkeletonPlaceholder = ({ children, enabled = true, backgroundColor = '#E1E9EE', highlightColor = '#F2F8FC', speed = 800, direction = 'right', borderRadius, shimmerWidth, }) => {
+@@ -56,18 +56,23 @@ const SkeletonPlaceholder = ({ children, enabled = true, backgroundColor = '#E1E
+ return () => loop.stop();
+ }, [isAnimationReady, speed]);
+ const animatedGradientStyle = React.useMemo(() => {
+- const animationWidth = WINDOW_WIDTH + (shimmerWidth !== null && shimmerWidth !== void 0 ? shimmerWidth : 0);
+- return Object.assign(Object.assign({}, react_native_1.StyleSheet.absoluteFillObject), { flexDirection: 'row', transform: [
+- {
+- translateX: animatedValueRef.current.interpolate({
+- inputRange: [0, 1],
+- outputRange: direction === 'right'
+- ? [-animationWidth, animationWidth]
+- : [animationWidth, -animationWidth],
+- }),
+- },
+- ] });
+- }, [direction, WINDOW_WIDTH, shimmerWidth]);
++ const animationWidth = (layout?.width || 0) + (shimmerWidth !== null && shimmerWidth !== undefined ? shimmerWidth : 0);
++ return {
++ ...react_native_1.StyleSheet.absoluteFillObject,
++ flexDirection: 'row',
++ transform: [
++ {
++ translateX: animatedValueRef.current.interpolate({
++ inputRange: [0, 1],
++ outputRange: direction === 'right'
++ ? [-animationWidth, animationWidth]
++ : [animationWidth, -animationWidth],
++ }),
++ },
++ ],
++ width: animationWidth,
++ };
++ }, [direction, layout?.width, shimmerWidth]);
+ const placeholders = React.useMemo(() => {
+ if (!enabled)
+ return null;
+@@ -86,7 +91,7 @@ const SkeletonPlaceholder = ({ children, enabled = true, backgroundColor = '#E1E
+
+
+ {isAnimationReady && highlightColor !== undefined && transparentColor !== undefined && (
+-
++
+ )}
+ );
+ };
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 63b2841c..4b28a6f1 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -2,35 +2,82 @@ import React from 'react';
import { Platform } from 'react-native';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { ApolloProvider } from '@apollo/client';
+import { FormProvider, useForm } from 'react-hook-form';
import { client } from './graphql/client';
import { StorageProvider } from './helpers';
import AppNavigator from './navigation/AppNavigator';
import { AppearanceProvider, ThemeProvider } from './theme';
-import { ModalProvider, PostProvider, UserEventProvider } from './utils';
+import { RequestError, Toast } from './components';
+import {
+ ModalProvider,
+ OngoingLikedTopicProvider,
+ PushNotificationsProvider,
+ RedirectProvider,
+} from './utils';
+import { AuthProvider } from './utils/AuthProvider';
+import { NewPostForm } from './types';
+import { NO_CHANNEL_FILTER_ID } from './constants';
if (Platform.OS === 'android') {
require('intl');
require('intl/locale-data/jsonp/en-US');
+ // required by https://github.com/andyearnshaw/Intl.js/issues/231
+
+ if (Platform.OS === 'android') {
+ // See https://github.com/expo/expo/issues/6536 for this issue.
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, no-underscore-dangle
+ if (typeof (Intl as any).__disableRegExpRestore === 'function') {
+ // eslint-disable-next-line no-underscore-dangle, @typescript-eslint/no-explicit-any
+ (Intl as any).__disableRegExpRestore();
+ }
+ }
+}
+if (__DEV__) {
+ require('react-native-console-time-polyfill');
}
export default function App() {
+ const newPostMethods = useForm({
+ mode: 'onChange',
+ reValidateMode: 'onChange',
+ defaultValues: {
+ title: '',
+ raw: '',
+ tags: [],
+ channelId: NO_CHANNEL_FILTER_ID,
+ editPostId: undefined,
+ editTopicId: undefined,
+ },
+ });
+
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+
+
+
+
);
diff --git a/frontend/src/__mocks__/mockData.ts b/frontend/src/__mocks__/mockData.ts
index 44710e86..4e525431 100644
--- a/frontend/src/__mocks__/mockData.ts
+++ b/frontend/src/__mocks__/mockData.ts
@@ -1,4 +1,4 @@
-import { EmailAddress, Message, Notification, Post } from '../types';
+import { EmailAddress, Notification, Post } from '../types';
const MOCK_IMG = 'https://dummyimage.com/600x400/000/fff';
@@ -86,7 +86,6 @@ const MOCK_POSTS: Array = [
title: 'Example',
content: MOCK_CONTENT,
hidden: false,
- images: [MOCK_IMG],
username: MOCK_USERS[0].username,
avatar: MOCK_IMG,
replyCount: 3010,
@@ -138,7 +137,6 @@ const MOCK_POSTS: Array = [
title: 'KodeFox',
content: MOCK_CONTENT,
hidden: false,
- images: [MOCK_IMG, MOCK_IMG, MOCK_IMG],
username: MOCK_USERS[1].username,
avatar: MOCK_IMG,
replyCount: 3,
@@ -227,47 +225,6 @@ const MOCK_MESSAGES = [
},
];
-const MOCK_MESSAGES2: Message = {
- members: [
- { id: 1, username: 'Natasha William', avatar: MOCK_IMG },
- { id: 2, username: 'Jacob Alexander', avatar: MOCK_IMG },
- { id: 3, username: 'Me', avatar: MOCK_IMG },
- { id: 4, username: 'NotMe', avatar: MOCK_IMG },
- ],
- contents: [
- {
- id: 1,
- userId: 1,
- time: '2020-08-28T22:45:15.634Z',
- message: 'Test',
- },
- {
- id: 2,
- userId: 1,
- time: '2020-08-28T23:02:15.634Z',
- message: 'Hello, Internet Citizens! Welcome to this multi-chat!',
- },
- {
- id: 3,
- userId: 1,
- time: '2020-08-28T23:07:15.634Z',
- message: 'Here we can talk about anything that is happening in our life!',
- },
- {
- id: 4,
- userId: 2,
- time: '2020-08-28T23:12:15.634Z',
- message: 'Hello Nat! Nice to meet you',
- },
- {
- id: 5,
- userId: 3,
- time: '2020-08-28T23:17:15.634Z',
- message: 'Hey guys, nice to meet you all on this platform!',
- },
- ],
-};
-
export default {
posts: MOCK_POSTS,
channels: MOCK_CHANNELS,
@@ -278,5 +235,4 @@ export default {
notifications: MOCK_NOTIFICATIONS,
emailAddress: MOCK_EMAIL_ADDRESS,
messages: MOCK_MESSAGES,
- messages2: MOCK_MESSAGES2,
};
diff --git a/frontend/src/__mocks__/setupLinking.ts b/frontend/src/__mocks__/setupLinking.ts
new file mode 100644
index 00000000..4453ccfa
--- /dev/null
+++ b/frontend/src/__mocks__/setupLinking.ts
@@ -0,0 +1,8 @@
+jest.mock('expo-linking', () => {
+ const module: typeof import('expo-linking') = {
+ ...jest.requireActual('expo-linking'),
+ createURL: jest.fn(),
+ };
+
+ return module;
+});
diff --git a/frontend/src/components/Author.tsx b/frontend/src/components/Author.tsx
index b907b50a..df6aa219 100644
--- a/frontend/src/components/Author.tsx
+++ b/frontend/src/components/Author.tsx
@@ -24,7 +24,6 @@ type Props = TouchableOpacityProps &
imageStyle?: StyleProp;
onPressAuthor?: (username: string) => void;
onPressEmptySpaceInPost?: () => void;
- postList?: boolean;
};
export function Author(props: Props) {
@@ -44,7 +43,6 @@ export function Author(props: Props) {
children,
onPressAuthor,
onPressEmptySpaceInPost,
- postList,
...otherProps
} = props;
@@ -68,7 +66,7 @@ export function Author(props: Props) {
)}
- {onPressEmptySpaceInPost && postList && (
+ {onPressEmptySpaceInPost && (
(
+ render: (props: P, ref: React.Ref) => React.ReactElement | null,
+ ): (props: P & React.RefAttributes) => React.ReactElement | null;
+}
+
+export type RenderItemCustomOption = {
+ isItemLoading: boolean;
+ onLayout: (params: { event: LayoutChangeEvent }) => void;
+};
+
+type Props = Omit<
+ FlatListProps,
+ 'renderItem' | 'refreshControl'
+> & {
+ renderItem: (
+ info: ListRenderItemInfo,
+ customOption: RenderItemCustomOption,
+ ) => ReactElement;
+ refreshControlTintColor?: string;
+ paginationSize?: number;
+ data: Array; // This change was made because in React Native version 0.72, the type of the FlatList component's data prop was changed to ArrayLike, which does not have the slice method available. Therefore, we cannot use the slice method directly on the data prop.
+};
+
+type CustomFlatlistRefType = {
+ scrollToIndex: FlatList['scrollToIndex'];
+ scrollToEnd: FlatList['scrollToEnd'];
+};
+
+type ScrollToIndexParams = Parameters[0];
+
+const DEFAULT_INITIAL_NUM_TO_RENDER = 10;
+const DEFAULT_WINDOW_SIZE = 21;
+
+const DEFAULT_PAGINATION_SIZE = 5;
+
+/**
+ * Custom flatlist to support scroll to any index
+ * It will internally manage pagination and show correct data on scroll
+ *
+ * Notes:
+ * - Required to put onLayout for items rendered as the scroll depend
+ * on items layout finished
+ * - To make illusion of scrolling we wrapped the child in loading state
+ * it's not required but suggested to do as otherwise it will feel janky
+ * - Currently to load earlier data in the list we need to pull to refresh
+ * this limitation is design decision as automatically
+ * adding data to start of the list (ex: using onStartReached)
+ * would scroll the list to top on android(https://github.com/facebook/react-native/pull/29466)
+ *
+ * TODO:
+ * - Refactor to auto load earlier data once RN fix mvcp for android (https://github.com/kodefox/lexicon/issues/793)
+ */
+
+function BaseCustomFlatList(
+ props: Props,
+ ref: ForwardedRef,
+) {
+ const {
+ data: propsItemData = [],
+ initialNumToRender,
+ windowSize,
+ renderItem,
+ onEndReached,
+ onScroll,
+ onRefresh,
+ refreshing = false,
+ refreshControlTintColor,
+ paginationSize = DEFAULT_PAGINATION_SIZE,
+ ...flatListProps
+ } = props;
+ const safePropsItemData = useMemo(() => {
+ return propsItemData ?? [];
+ }, [propsItemData]);
+ const [startIndex, setStartIndex] = useState();
+ const [lastIndex, setLastIndex] = useState();
+
+ // use to show loading on all items
+ const [itemsLoading, setItemsLoading] = useState(false);
+
+ const baseFlatListRef = useRef>(null);
+
+ const scrollToIndexParam = useRef();
+ const shouldInternalScroll = useRef();
+ const itemRenderCount = useRef(0);
+
+ const internalOnEndReached = () => {
+ /**
+ * Compare our internal latestIndex with data props length
+ * if less load rest of our data from props
+ * if equal means our props runs out of data, trigger onEndReach
+ */
+ if (
+ lastIndex !== undefined &&
+ safePropsItemData &&
+ lastIndex !== safePropsItemData.length
+ ) {
+ setLastIndex(safePropsItemData.length);
+ }
+ };
+
+ useImperativeHandle(
+ ref,
+ () => {
+ return {
+ scrollToIndex: (params) => {
+ const initialWindow = Math.max(
+ initialNumToRender || DEFAULT_INITIAL_NUM_TO_RENDER,
+ windowSize || DEFAULT_WINDOW_SIZE,
+ );
+ const halfInitialWindow = Math.floor(initialWindow / 2);
+
+ // Handle default behavior
+ if (params.index < initialWindow) {
+ return baseFlatListRef.current?.scrollToIndex(params);
+ }
+
+ /**
+ * Scroll illusion
+ * 1. turned on loading for all item
+ * 2. replace with sliced item
+ * 3. scroll to specific item
+ */
+ setItemsLoading(true);
+ const newStartIndex = params.index - halfInitialWindow;
+ const newLastIndex = params.index + halfInitialWindow;
+ setStartIndex(newStartIndex);
+ setLastIndex(newLastIndex);
+ // set param for the scrollToIndex called
+ itemRenderCount.current = 0;
+ scrollToIndexParam.current = {
+ ...params,
+ index: halfInitialWindow,
+ };
+ shouldInternalScroll.current = true;
+ },
+ scrollToEnd: (params) => {
+ baseFlatListRef.current?.scrollToEnd(params);
+ },
+ };
+ },
+ [initialNumToRender, windowSize],
+ );
+
+ // debounced scroll to happened after new data layout finished
+ const internalScroll = () => {
+ itemRenderCount.current += 1;
+ if (!shouldInternalScroll.current) {
+ return;
+ }
+ if (!scrollToIndexParam.current) {
+ return;
+ }
+ if (itemRenderCount.current < scrollToIndexParam.current.index + 1) {
+ return;
+ }
+
+ shouldInternalScroll.current = false;
+ // This setTimeout call is an imperfect fix that makes the scrolling transition smoother. We might need to adjust this later after we improve the render latency.
+ setTimeout(() => {
+ setItemsLoading(false);
+ }, 500);
+ // SetTimeout below needed because even after last item onLayout the scrollToIndex still using old calculation
+ setTimeout(() => {
+ scrollToIndexParam.current &&
+ baseFlatListRef.current?.scrollToIndex(scrollToIndexParam.current);
+ });
+ };
+
+ const internalOnRefresh = () => {
+ if (propsItemData && startIndex) {
+ const newStartIndex = Math.max(startIndex - paginationSize, 0);
+ setStartIndex(newStartIndex);
+ } else {
+ onRefresh && onRefresh();
+ // removing internal window on true refresh to just pass all data
+ setStartIndex(undefined);
+ setLastIndex(undefined);
+ }
+ };
+
+ const slicedFlatListData = safePropsItemData.slice(
+ startIndex !== undefined ? startIndex : 0,
+ lastIndex !== undefined ? lastIndex : safePropsItemData.length,
+ );
+
+ return (
+ {
+ const customOptions: RenderItemCustomOption = {
+ isItemLoading: itemsLoading,
+ onLayout: internalScroll,
+ };
+ return renderItem({ ...params }, customOptions);
+ }}
+ refreshControl={
+
+ }
+ onEndReached={(info) => {
+ internalOnEndReached();
+ if (
+ (lastIndex === safePropsItemData.length || lastIndex === undefined) &&
+ onEndReached
+ ) {
+ onEndReached(info);
+ /**
+ * removing internal window on true on end reach
+ * to get all data from current start to the end
+ */
+ setLastIndex(undefined);
+ }
+ }}
+ {...flatListProps}
+ />
+ );
+}
+const CustomFlatList = forwardRef(BaseCustomFlatList);
+
+export { CustomFlatlistRefType, CustomFlatList };
diff --git a/frontend/src/components/CustomFlatList/index.ts b/frontend/src/components/CustomFlatList/index.ts
new file mode 100644
index 00000000..74aabdf4
--- /dev/null
+++ b/frontend/src/components/CustomFlatList/index.ts
@@ -0,0 +1 @@
+export * from './CustomFlatList';
diff --git a/frontend/src/components/LoadingOrError.tsx b/frontend/src/components/LoadingOrError.tsx
index 98bda6b5..6cf8d121 100644
--- a/frontend/src/components/LoadingOrError.tsx
+++ b/frontend/src/components/LoadingOrError.tsx
@@ -1,11 +1,13 @@
-import React from 'react';
+import React, { useEffect } from 'react';
import { View } from 'react-native';
import { useNavigation } from '@react-navigation/native';
import { ActivityIndicator, Text } from '../core-ui';
-import { removeToken, showLogoutAlert, useStorage } from '../helpers';
+import { showLogoutAlert } from '../helpers';
import { makeStyles } from '../theme';
import { StackNavProp } from '../types';
+import { useAuth } from '../utils/AuthProvider';
+import { ERROR_NOT_FOUND } from '../constants';
type Props = {
message?: string;
@@ -14,9 +16,26 @@ type Props = {
export function LoadingOrError(props: Props) {
const { reset } = useNavigation>();
- const storage = useStorage();
- const styles = useStyles();
+ const { cleanSession } = useAuth();
+ const { message } = props;
+ useEffect(() => {
+ if (message === ERROR_NOT_FOUND) {
+ /**
+ * This is a legacy implementation that should be refactored
+ * We don't want to mixed this view layer with Auth logic
+ * https://github.com/kodefox/lexicon/issues/1097
+ */
+ cleanSession();
+ reset({ index: 0, routes: [{ name: 'Login' }] });
+ showLogoutAlert();
+ }
+ }, [message, reset, cleanSession]);
+
+ return ;
+}
+export function LoadingOrErrorView(props: Props) {
+ const styles = useStyles();
const {
loading = false,
message = loading
@@ -24,13 +43,6 @@ export function LoadingOrError(props: Props) {
: t('Something unexpected happened. Please try again'),
} = props;
- if (message === 'Not found or private') {
- removeToken();
- storage.removeItem('user');
- reset({ index: 0, routes: [{ name: 'Login' }] });
- showLogoutAlert();
- }
-
return (
{loading ? : null}
diff --git a/frontend/src/components/Markdown.tsx b/frontend/src/components/Markdown.tsx
index c5652f7e..d1556ab4 100644
--- a/frontend/src/components/Markdown.tsx
+++ b/frontend/src/components/Markdown.tsx
@@ -1,50 +1,52 @@
/* eslint-disable styles/style-maker-no-unused */
import React from 'react';
-import { Alert, Platform, StyleProp, View, ViewStyle } from 'react-native';
+import { Platform, StyleProp, View, ViewStyle } from 'react-native';
import BaseMarkdown, {
ASTNode,
- getUniqueID,
MarkdownIt,
MarkdownProps,
} from 'react-native-markdown-display';
import { useNavigation } from '@react-navigation/core';
import mentionFlowDock from 'markdown-it-flowdock';
+import * as Linking from 'expo-linking';
+import { useReactiveVar } from '@apollo/client';
-import { NO_USERNAME_ALERT, NO_USERNAME_SUB_ALERT } from '../constants';
import { CustomImage } from '../core-ui/CustomImage';
import { Text } from '../core-ui/Text';
import { makeStyles } from '../theme';
import { StackNavProp } from '../types';
+import CachedImage from '../core-ui/CachedImage';
+import { isEmojiImage } from '../helpers/emojiHandler';
+import { extractPathname, getValidDetailParams } from '../helpers';
+import { discourseHostVar } from '../constants';
type Props = Omit & {
content: string;
fontColor?: string;
style?: StyleProp;
- imageUrls?: Array;
mentionColor?: string;
- listOfMention?: Array;
+ mentions?: Array;
nonClickable?: boolean;
};
const ios = Platform.OS === 'ios';
export function Markdown(props: Props) {
- const { navigate } = useNavigation>();
+ const { navigate, push } = useNavigation>();
let styles = useStyles();
+ let discourseHost = useReactiveVar(discourseHostVar);
let {
content,
fontColor,
mentionColor,
style,
- listOfMention,
+ mentions,
nonClickable,
- imageUrls = [],
...otherProps
} = props;
content = content || '';
- let image = 0;
styles = fontColor
? { ...styles, ...{ body: { ...styles.body, color: fontColor } } }
@@ -52,27 +54,24 @@ export function Markdown(props: Props) {
const markdownItInstance = MarkdownIt({ typographer: true }).use(
mentionFlowDock,
- {
- containerClassName: 'mention',
- },
+ { containerClassName: 'mention' },
);
const onPressMention = (username: string) => {
- if (listOfMention?.includes(username)) {
- navigate('UserInformation', { username });
- } else {
- Alert.alert(NO_USERNAME_ALERT, NO_USERNAME_SUB_ALERT, [
- { text: t('Got it') },
- ]);
- }
+ navigate('UserInformation', { username });
};
- const renderImage = (node: ASTNode) => {
- let { src } = node.attributes;
- const uploadRegex = /upload:\/\//g;
- src = uploadRegex.test(src) ? imageUrls[image] || '' : src;
- image += 1;
- return ;
+ const renderImage = ({ attributes: { src }, key, content }: ASTNode) => {
+ if (isEmojiImage(content)) {
+ return (
+
+ );
+ }
+ return ;
};
const renderMention = ({ key, content }: ASTNode) => (
@@ -92,6 +91,47 @@ export function Markdown(props: Props) {
{t('#{content}', { content })}
);
+ const renderLink = ({ key, attributes }: ASTNode) => {
+ if (typeof attributes.href !== 'string') {
+ return;
+ }
+
+ let url = attributes.href;
+ const isSameHost = url.startsWith(discourseHost);
+ const pathname = isSameHost ? extractPathname(url) : '';
+
+ if (isSameHost && pathname) {
+ url = `/${pathname.replace(/t\//, 'topics/')}`;
+ }
+
+ const onLinkPress = () => {
+ const detailParams = getValidDetailParams(pathname.split('/'));
+
+ if (!detailParams) {
+ Linking.openURL(url);
+ return;
+ }
+
+ const { topicId, postNumber } = detailParams;
+ push('PostDetail', { topicId, postNumber });
+ };
+
+ const handleLinkPress = () => {
+ if (!isSameHost || !pathname) {
+ Linking.openURL(url);
+ return;
+ }
+
+ onLinkPress();
+ };
+
+ return (
+
+ {url}
+
+ );
+ };
+
return (
;
setRawText?: (value: string) => void;
- setMentionValue?: UseFormMethods['setValue'];
setShowUserList: (value: boolean) => void;
viewStyle?: StyleProp;
fontStyle?: StyleProp;
+ setMentionValue?: (text: string) => void;
};
export function MentionList(props: Props) {
@@ -48,8 +47,9 @@ export function MentionList(props: Props) {
const onPressUser = (username: string) => {
const replacedText = rawText.replace(/@[A-Za-z0-9._-]*$/, `@${username}`);
textRef.current?.focus();
+
if (setMentionValue) {
- setMentionValue('raw', replacedText);
+ setMentionValue(replacedText);
} else if (setRawText) {
setRawText(replacedText);
}
diff --git a/frontend/src/components/Metrics/Metrics.tsx b/frontend/src/components/Metrics/Metrics.tsx
index e32bbaca..9110d02c 100644
--- a/frontend/src/components/Metrics/Metrics.tsx
+++ b/frontend/src/components/Metrics/Metrics.tsx
@@ -1,121 +1,213 @@
-import React, { useEffect, useState } from 'react';
+import React, { useState, useEffect, useCallback, memo } from 'react';
import { View, ViewProps } from 'react-native';
+import { useDebouncedCallback } from 'use-debounce';
+import { FIRST_POST_NUMBER } from '../../constants';
import { ActivityIndicator, Divider } from '../../core-ui';
-import { useLikePost } from '../../hooks';
+import { getUpdatedLikeCount } from '../../helpers';
+import { useLikeTopicOrPost } from '../../hooks';
import { makeStyles, useTheme } from '../../theme';
-import { usePost, useUserEvent } from '../../utils';
+import { useOngoingLikedTopic } from '../../utils';
import { MetricItem } from './MetricItem';
-type Props = ViewProps & {
- postId: number;
- topicId: number;
- postList?: boolean;
- viewCount?: number;
- baseLikeCount: number;
- replyCount: number;
- onPressReply?: (postId: number) => void;
- isCreator?: boolean;
- baseIsLiked: boolean;
- onPressView?: () => void;
+type Props = {
title?: string;
- likedTopic?: Array;
- nestedComment?: boolean;
-};
+ postNumber?: number;
+ likePerformedFrom?: 'home-scene' | 'topic-detail';
+} & MetricViewProps;
export { Props as MetricsProp };
+const DEBOUNCE_WAIT_TIME = 500;
+
export function Metrics(props: Props) {
- const { onLikedStatusChanged, likedTopic } = usePost();
- const styles = useStyles();
- const { colors } = useTheme();
- const { isScrolled } = useUserEvent();
+ const { likedTopics } = useOngoingLikedTopic();
const {
postId,
topicId,
- postList = false,
viewCount,
replyCount,
- baseLikeCount,
- baseIsLiked,
- onPressReply,
+ likeCount: likeCountProps = 0,
+ postNumber,
+ isLiked,
isCreator,
- style,
- onPressView,
title,
- nestedComment = false,
+ likePerformedFrom = 'topic-detail',
+ onPressReply,
+ onPressView,
...otherProps
} = props;
- const [isLiked, setIsLiked] = useState(baseIsLiked);
- const [pastRequest, setPastRequest] = useState(baseIsLiked);
- const [likeCount, setLikeCount] = useState(0);
- const [counter, setCounter] = useState(baseLikeCount);
- const [tempLiked, setTempLiked] = useState>([]);
- const [tempLikedShadow, setTempLikedShadow] = useState>([]);
+ const [likeData, setLikeData] = useState({
+ liked: isLiked,
+ likeCount: likeCountProps,
+ });
+ const isFromHomeScene = likePerformedFrom === 'home-scene';
+ const performDebouncedLike = useDebouncedCallback((liked: boolean) => {
+ if (liked === isLiked) {
+ return;
+ }
+ like({
+ variables: {
+ unlike: isLiked,
+ ...(isFromHomeScene ? { topicId } : { postId }),
+ likeCount: likeCountProps,
+ },
+ });
+ }, DEBOUNCE_WAIT_TIME);
+
+ /**
+ * Update like count and liked value for topic replies
+ * This is separated from the other useEffect to prevent
+ * updating like data for topic replies when ongoing
+ * likedTopics value changes
+ */
useEffect(() => {
- if (likedTopic) {
- setTempLiked(likedTopic);
- setTempLikedShadow(likedTopic);
+ const isFirstPost = postNumber === FIRST_POST_NUMBER;
+ // Skip updating like count and liked value for topic and first post of topics
+ if (isFromHomeScene || isFirstPost) {
+ return;
}
- }, [likedTopic, postId]);
+ setLikeData({ likeCount: likeCountProps, liked: isLiked });
+ }, [isFromHomeScene, isLiked, likeCountProps, likePerformedFrom, postNumber]);
+ /**
+ * Update like count and liked value for topic and first post of topics
+ * if isFromHomeScene is true, then it's a topic
+ * if isFirstPost is true, then it's the first post of topics
+ */
useEffect(() => {
- setLikeCount(baseLikeCount);
- }, [baseLikeCount]);
+ const isFirstPost = postNumber === FIRST_POST_NUMBER;
+ if (!isFromHomeScene && !isFirstPost) {
+ return;
+ }
- const { like, loading } = useLikePost(
- likeCount,
- setLikeCount,
- postList,
- postId,
- tempLiked,
- setTempLiked,
- tempLikedShadow,
- setTempLikedShadow,
- counter,
- setCounter,
- );
+ const { liked: likedTopic, likeCount: topicLikeCount } =
+ likedTopics[topicId] ?? {};
+ let liked = likedTopic ?? isLiked;
+ let likeCount = topicLikeCount ?? likeCountProps;
- const onPressLike = () => {
- if (!isScrolled && !nestedComment) {
- if (!likedTopic.includes(topicId)) {
- setPastRequest(false);
- onLikedStatusChanged(topicId, true);
- } else {
- setPastRequest(true);
- onLikedStatusChanged(topicId, false);
- }
+ if (!isFirstPost) {
+ setLikeData({ likeCount, liked });
+ return;
}
- if (!postList) {
- let currentLikeStatus = nestedComment
- ? isLiked
- : likedTopic.includes(topicId);
- if (currentLikeStatus) {
- setLikeCount(likeCount - 1);
- setIsLiked(false);
- } else {
- setLikeCount(likeCount + 1);
- setIsLiked(true);
- }
- like({
- variables: {
- postId,
- unlike: currentLikeStatus,
- },
+
+ /**
+ * Revert post like count to not use topic like count
+ * Liked value of the topic resembles the liked value of the first post.
+ * However, the like counts are different because topic likeCount
+ * represents the total of likes within that topic, while post
+ * likeCount only represents the number of likes for that post
+ */
+
+ likeCount = likeCountProps;
+
+ /**
+ * Update post likeCount if topic liked and post liked values are different
+ * This means there's an ongoing like action related to this post, so
+ * post likeCount should get recalculated
+ */
+ if (liked !== isLiked) {
+ const updatedLikeCount = getUpdatedLikeCount({
+ liked,
+ previousCount: likeCountProps,
});
+ likeCount = updatedLikeCount;
}
- };
+
+ setLikeData({ likeCount, liked });
+ }, [
+ isFromHomeScene,
+ isLiked,
+ likeCountProps,
+ likedTopics,
+ postNumber,
+ topicId,
+ ]);
+
+ // Ensuring debounced callback is called if it hasn't fired when component unmount
+ useEffect(() => {
+ return () => {
+ performDebouncedLike.flush();
+ };
+ }, [performDebouncedLike]);
+
+ // TODO: Add navigation #800
+ const [like] = useLikeTopicOrPost();
+
+ const onPressLike = useCallback(() => {
+ setLikeData(({ liked: prevLiked, likeCount: previousCount }) => {
+ const liked = !prevLiked;
+ const likeCount = getUpdatedLikeCount({
+ liked,
+ previousCount,
+ });
+ performDebouncedLike(liked);
+ return { liked, likeCount };
+ });
+ }, [performDebouncedLike]);
+
+ return (
+