mirror of
https://github.com/captbaritone/webamp.git
synced 2026-01-23 18:25:30 +00:00
Add a graphql endpoint
This commit is contained in:
parent
25a88a4ec5
commit
00fef7c7b3
12 changed files with 596 additions and 11 deletions
|
|
@ -1,4 +1,5 @@
|
|||
import router from "./router";
|
||||
import graphql from "./graphql";
|
||||
import fileUpload from "express-fileupload";
|
||||
import cors, { CorsOptions } from "cors";
|
||||
import bodyParser from "body-parser";
|
||||
|
|
@ -23,8 +24,14 @@ export type ApiAction =
|
|||
| { type: "GOT_FEEDBACK"; message: string; email?: string; url?: string }
|
||||
| { type: "SYNCED_TO_ARCHIVE"; successes: number; errors: number }
|
||||
| { type: "STARTED_SYNC_TO_ARCHIVE"; count: number }
|
||||
| { type: "POPULAR_TWEET"; bracket: number; url: string, likes: number, date: Date }
|
||||
| { type: "TWEET_BOT_MILESTONE"; bracket: number; count: number};
|
||||
| {
|
||||
type: "POPULAR_TWEET";
|
||||
bracket: number;
|
||||
url: string;
|
||||
likes: number;
|
||||
date: Date;
|
||||
}
|
||||
| { type: "TWEET_BOT_MILESTONE"; bracket: number; count: number };
|
||||
|
||||
export type EventHandler = (event: ApiAction) => void;
|
||||
export type Logger = {
|
||||
|
|
@ -135,6 +142,7 @@ export function createApp({ eventHandler, extraMiddleware, logger }: Options) {
|
|||
|
||||
// Add routes
|
||||
app.use("/", router);
|
||||
app.use("/graphql", graphql);
|
||||
|
||||
// The error handler must be before any other error middleware and after all controllers
|
||||
if (Sentry) {
|
||||
|
|
@ -143,6 +151,7 @@ export function createApp({ eventHandler, extraMiddleware, logger }: Options) {
|
|||
|
||||
// Optional fallthrough error handler
|
||||
app.use(function onError(err, _req, res, _next) {
|
||||
console.error(err);
|
||||
res.statusCode = 500;
|
||||
res.json({ errorId: res.sentry, message: err.message });
|
||||
});
|
||||
|
|
@ -160,6 +169,7 @@ const allowList = [
|
|||
/https:\/\/skins\.webamp\.org/,
|
||||
/https:\/\/winamp-skin-museum\.pages\.dev/,
|
||||
/http:\/\/localhost:3000/,
|
||||
/http:\/\/localhost:3001/,
|
||||
/netlify.app/,
|
||||
];
|
||||
|
||||
|
|
|
|||
266
packages/skin-database/api/graphql/index.ts
Normal file
266
packages/skin-database/api/graphql/index.ts
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
import { Router } from "express";
|
||||
import { graphqlHTTP } from "express-graphql";
|
||||
|
||||
import { buildSchema } from "graphql";
|
||||
import SkinModel from "../../data/SkinModel";
|
||||
import { knex } from "../../db";
|
||||
import SkinResolver from "./resolvers/SkinResolver";
|
||||
import * as Skins from "../../data/skins";
|
||||
import UserResolver from "./resolvers/UserResolver";
|
||||
|
||||
const router = Router();
|
||||
|
||||
const schema = buildSchema(`
|
||||
|
||||
"""A classic Winamp skin"""
|
||||
type Skin {
|
||||
"""Database ID of the skin"""
|
||||
id: Int,
|
||||
|
||||
"""MD5 hash of the skin's file"""
|
||||
md5: String,
|
||||
|
||||
"""URL of the skin on the Winamp Skin Museum"""
|
||||
museum_url: String,
|
||||
|
||||
"""URL of webamp.org with the skin loaded"""
|
||||
webamp_url: String,
|
||||
|
||||
"""URL of a screenshot of the skin"""
|
||||
screenshot_url: String,
|
||||
|
||||
"""URL to download the skin"""
|
||||
download_url: String,
|
||||
|
||||
"""
|
||||
Filename of skin when uploaded to the Museum. Note: In some cases a skin
|
||||
has been uploaded under multiple names. Here we just pick one.
|
||||
"""
|
||||
filename: String,
|
||||
|
||||
"""Text of the readme file extracted from the skin"""
|
||||
readme_text: String,
|
||||
|
||||
"""Has the skin been flagged as "not safe for wrok"?"""
|
||||
nsfw: Boolean,
|
||||
|
||||
"""String representation (rgb usually) of the skin's average color"""
|
||||
average_color: String,
|
||||
|
||||
"""Has the skin been tweeted?"""
|
||||
tweeted: Boolean
|
||||
|
||||
"""List of @winampskins tweets that mentioned the skin."""
|
||||
tweets: [Tweet]
|
||||
|
||||
"""List of files contained within the skin's .wsz archive"""
|
||||
archive_files: [ArchiveFile]
|
||||
|
||||
"""The skin's "item" at archive.org"""
|
||||
internet_archive_item: InternetArchiveItem
|
||||
|
||||
"""
|
||||
Times that the skin has been reviewed either on the Museum's Tinder-style
|
||||
reivew page, or via the Discord bot.
|
||||
"""
|
||||
reviews: [Review]
|
||||
}
|
||||
|
||||
|
||||
"""The judgement made about a skin by a moderator"""
|
||||
enum Rating {
|
||||
APPROVED
|
||||
REJECTED
|
||||
NSFW
|
||||
}
|
||||
|
||||
"""
|
||||
A review of a skin. Done either on the Museum's Tinder-style
|
||||
reivew page, or via the Discord bot.
|
||||
"""
|
||||
type Review {
|
||||
"""The skin that was reviewed"""
|
||||
skin: Skin
|
||||
|
||||
"""
|
||||
The user who made the review (if known). **Note:** In the early days we didn't
|
||||
track this, so many will be null.
|
||||
"""
|
||||
reviewer: String
|
||||
|
||||
"""The rating that the user gave the skin"""
|
||||
rating: Rating
|
||||
}
|
||||
|
||||
|
||||
"""A file found within a Winamp Skin's .wsz archive"""
|
||||
type ArchiveFile {
|
||||
"""Filename of the file within the archive"""
|
||||
filename: String,
|
||||
}
|
||||
|
||||
"""A tweet made by @winampskins mentioning a Winamp skin"""
|
||||
type Tweet {
|
||||
"""URL of the tweet"""
|
||||
url: String
|
||||
|
||||
"""Number of likes the tweet has received. Updated nightly. (Note: Recent likes on older tweets may not be reflected here)"""
|
||||
likes: Int
|
||||
|
||||
"""Number of retweets the tweet has received. Updated nightly. (Note: Recent retweets on older tweets may not be reflected here)"""
|
||||
retweets: Int
|
||||
skin: Skin
|
||||
}
|
||||
|
||||
type InternetArchiveItem {
|
||||
"""The Internet Archive's unique identifier for this item"""
|
||||
identifier: String
|
||||
|
||||
"""The URL where this item can be viewed on the Internet Archive"""
|
||||
url: String
|
||||
|
||||
"""The skin that this item contains"""
|
||||
skin: Skin
|
||||
}
|
||||
|
||||
"""A collection of classic Winamp skins"""
|
||||
type SkinsConnection {
|
||||
"""The total number of skins"""
|
||||
count: Int
|
||||
|
||||
"""The list of skins"""
|
||||
nodes: [Skin]
|
||||
}
|
||||
|
||||
type User {
|
||||
username: String
|
||||
}
|
||||
|
||||
enum SkinsSortOption {
|
||||
"""
|
||||
the Museum's (https://skins.webamp.org) special sorting rules.
|
||||
|
||||
Roughly speaking, it's:
|
||||
|
||||
1. The four classic default skins
|
||||
2. Tweeted skins first (sorted by the number of likes/retweets)
|
||||
3. Approved, but not tweeted yet, skins
|
||||
4. Unreviwed skins
|
||||
5. Rejected skins
|
||||
6. NSFW skins
|
||||
"""
|
||||
MUSEUM
|
||||
}
|
||||
|
||||
enum SkinsFilterOption {
|
||||
"""All the skins that have been approved for tweeting"""
|
||||
APPROVED
|
||||
}
|
||||
|
||||
type Query {
|
||||
"""The currently authenticated user, if any."""
|
||||
me: User
|
||||
|
||||
"""Get a skin by its MD5 hash"""
|
||||
fetch_skin_by_md5(md5: String!): Skin
|
||||
|
||||
"""
|
||||
All skins in the database
|
||||
|
||||
**Note:** We don't currently support combining sorting and filtering.
|
||||
"""
|
||||
skins(
|
||||
first: Int,
|
||||
offset: Int,
|
||||
sort: SkinsSortOption,
|
||||
filter: SkinsFilterOption
|
||||
): SkinsConnection
|
||||
}`);
|
||||
|
||||
class SkinsConnection {
|
||||
_first: number;
|
||||
_offset: number;
|
||||
_sort: string;
|
||||
_filter: string;
|
||||
constructor(first: number, offset: number, sort: string, filter: string) {
|
||||
this._first = first;
|
||||
this._offset = offset;
|
||||
this._filter = filter;
|
||||
this._sort = sort;
|
||||
}
|
||||
async count() {
|
||||
const count = await knex("skins")
|
||||
.where({ skin_type: 1 })
|
||||
.count("*", { as: "count" });
|
||||
return count[0].count;
|
||||
}
|
||||
async nodes(args, ctx) {
|
||||
if (this._sort === "MUSEUM") {
|
||||
if (this._filter) {
|
||||
throw new Error(
|
||||
"We don't support combining sorting and filtering at the same time."
|
||||
);
|
||||
}
|
||||
const items = await Skins.getMuseumPage({
|
||||
first: this._first,
|
||||
offset: this._offset,
|
||||
});
|
||||
return Promise.all(
|
||||
items.map(async (item) => {
|
||||
const model = await SkinModel.fromMd5Assert(ctx, item.md5);
|
||||
return new SkinResolver(model);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
let query = knex("skins");
|
||||
|
||||
if (this._filter === "APPROVED") {
|
||||
query = query
|
||||
.leftJoin("skin_reviews", "skin_reviews.skin_md5", "=", "skins.md5")
|
||||
.where("review", "APPROVED");
|
||||
}
|
||||
|
||||
const skins = await query
|
||||
.where({ skin_type: 1 })
|
||||
.select()
|
||||
.limit(this._first)
|
||||
.offset(this._offset);
|
||||
return skins.map((skin) => {
|
||||
return new SkinResolver(new SkinModel(ctx, skin));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const root = {
|
||||
async fetch_skin_by_md5({ md5 }, { ctx }) {
|
||||
const skin = await SkinModel.fromMd5(ctx, md5);
|
||||
if (skin == null) {
|
||||
return null;
|
||||
}
|
||||
return new SkinResolver(skin);
|
||||
},
|
||||
async skins({ first, offset, sort, filter }) {
|
||||
if (first > 1000) {
|
||||
throw new Error("Maximum limit is 1000");
|
||||
}
|
||||
return new SkinsConnection(first, offset, sort, filter);
|
||||
},
|
||||
me() {
|
||||
return new UserResolver();
|
||||
},
|
||||
};
|
||||
|
||||
router.use(
|
||||
"/",
|
||||
graphqlHTTP({
|
||||
typeResolver(_type) {
|
||||
throw new Error("We probably need to implement typeResolver");
|
||||
},
|
||||
schema: schema,
|
||||
rootValue: root,
|
||||
graphiql: true,
|
||||
})
|
||||
);
|
||||
|
||||
export default router;
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import ArchiveFileModel from "../../../data/ArchiveFileModel";
|
||||
|
||||
export default class ArchiveFileResolver {
|
||||
_model: ArchiveFileModel;
|
||||
constructor(model: ArchiveFileModel) {
|
||||
this._model = model;
|
||||
}
|
||||
filename() {
|
||||
return this._model.getFileName();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
import IaItemModel from "../../../data/IaItemModel";
|
||||
import SkinResolver from "./SkinResolver";
|
||||
|
||||
export default class InternetArchiveItemResolver {
|
||||
_model: IaItemModel;
|
||||
constructor(model: IaItemModel) {
|
||||
this._model = model;
|
||||
}
|
||||
identifier() {
|
||||
return this._model.getIdentifier();
|
||||
}
|
||||
url() {
|
||||
return this._model.getUrl();
|
||||
}
|
||||
async skin() {
|
||||
const skin = await this._model.getSkin();
|
||||
if (skin == null) {
|
||||
return null;
|
||||
}
|
||||
return new SkinResolver(skin);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
import { ReviewRow } from "../../../types";
|
||||
|
||||
export default class ReviewResolver {
|
||||
_model: ReviewRow;
|
||||
constructor(model: ReviewRow) {
|
||||
this._model = model;
|
||||
}
|
||||
reviewer() {
|
||||
return this._model.reviewer;
|
||||
}
|
||||
rating() {
|
||||
return this._model.review;
|
||||
}
|
||||
}
|
||||
65
packages/skin-database/api/graphql/resolvers/SkinResolver.ts
Normal file
65
packages/skin-database/api/graphql/resolvers/SkinResolver.ts
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import SkinModel from "../../../data/SkinModel";
|
||||
import ArchiveFileResolver from "./ArchiveFileResolver";
|
||||
import InternetArchiveItemResolver from "./InternetArchiveItemResolver";
|
||||
import ReviewResolver from "./ReviewResolver";
|
||||
import TweetResolver from "./TweetResolver";
|
||||
|
||||
export default class SkinResolver {
|
||||
_model: SkinModel;
|
||||
constructor(model: SkinModel) {
|
||||
this._model = model;
|
||||
}
|
||||
id() {
|
||||
return this._model.getId();
|
||||
}
|
||||
md5() {
|
||||
return this._model.getMd5();
|
||||
}
|
||||
filename() {
|
||||
return this._model.getFileName();
|
||||
}
|
||||
museum_url() {
|
||||
return this._model.getMuseumUrl();
|
||||
}
|
||||
webamp_url() {
|
||||
return this._model.getWebampUrl();
|
||||
}
|
||||
screenshot_url() {
|
||||
return this._model.getScreenshotUrl();
|
||||
}
|
||||
download_url() {
|
||||
return this._model.getSkinUrl();
|
||||
}
|
||||
readme_text() {
|
||||
return this._model.getReadme();
|
||||
}
|
||||
nsfw() {
|
||||
return this._model.getIsNsfw();
|
||||
}
|
||||
average_color() {
|
||||
return this._model.getAverageColor();
|
||||
}
|
||||
tweeted() {
|
||||
return this._model.tweeted();
|
||||
}
|
||||
async tweets() {
|
||||
const tweets = await this._model.getTweets();
|
||||
return tweets.map((tweetModel) => new TweetResolver(tweetModel));
|
||||
}
|
||||
async archive_files() {
|
||||
const files = await this._model.getArchiveFiles();
|
||||
return files.map((file) => new ArchiveFileResolver(file));
|
||||
}
|
||||
async internet_archive_item() {
|
||||
const item = await this._model.getIaItem();
|
||||
if (item == null) {
|
||||
return null;
|
||||
}
|
||||
return new InternetArchiveItemResolver(item);
|
||||
}
|
||||
|
||||
async reviews() {
|
||||
const reviews = await this._model.getReviews();
|
||||
return reviews.map((row) => new ReviewResolver(row));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
import TweetModel from "../../../data/TweetModel";
|
||||
import SkinResolver from "./SkinResolver";
|
||||
|
||||
export default class TweetResolver {
|
||||
_model: TweetModel;
|
||||
constructor(model: TweetModel) {
|
||||
this._model = model;
|
||||
}
|
||||
|
||||
url() {
|
||||
return this._model.getUrl();
|
||||
}
|
||||
likes() {
|
||||
return this._model.getLikes();
|
||||
}
|
||||
retweets() {
|
||||
return this._model.getRetweets();
|
||||
}
|
||||
async skin() {
|
||||
const skin = await this._model.getSkin();
|
||||
if (skin == null) {
|
||||
return null;
|
||||
}
|
||||
return new SkinResolver(skin);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
export default class UserResolver {
|
||||
username(_args, ctx) {
|
||||
// For now every user is the current user.
|
||||
return ctx.user.username;
|
||||
}
|
||||
}
|
||||
|
|
@ -35,8 +35,8 @@ export default class SkinModel {
|
|||
md5: string
|
||||
): Promise<SkinModel> {
|
||||
const skin = await SkinModel.fromMd5(ctx, md5);
|
||||
if(skin == null) {
|
||||
throw new Error(`Expected to find skin with md5 "${md5}".`);
|
||||
if (skin == null) {
|
||||
throw new Error(`Expected to find skin with md5 "${md5}".`);
|
||||
}
|
||||
return skin;
|
||||
}
|
||||
|
|
@ -79,6 +79,10 @@ export default class SkinModel {
|
|||
throw new Error(`Unknown skin_type ${this.row.skin_type}`);
|
||||
}
|
||||
|
||||
getId(): number {
|
||||
return this.row.id;
|
||||
}
|
||||
|
||||
async tweeted(): Promise<boolean> {
|
||||
return (await this.getTweet()) != null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,9 @@
|
|||
"express": "^4.17.1",
|
||||
"express-async-handler": "^1.1.4",
|
||||
"express-fileupload": "^1.1.7-alpha.3",
|
||||
"express-graphql": "^0.12.0",
|
||||
"express-sitemap-xml": "^2.0.0",
|
||||
"graphql": "14.7.0",
|
||||
"imagemin": "^7.0.0",
|
||||
"imagemin-optipng": "^7.0.0",
|
||||
"knex": "^0.21.1",
|
||||
|
|
@ -35,7 +37,7 @@
|
|||
"sharp": "^0.28.0",
|
||||
"sqlite3": "^5.0.2",
|
||||
"temp": "^0.9.0",
|
||||
"ts-node": "^8.10.2",
|
||||
"ts-node": "^10.5.0",
|
||||
"twit": "^2.2.11",
|
||||
"winston": "^3.2.1",
|
||||
"yargs": "^13.2.4"
|
||||
|
|
@ -63,5 +65,8 @@
|
|||
"prettier": "^2.3.2",
|
||||
"supertest": "^6.0.1",
|
||||
"typescript": "^3.8.3"
|
||||
},
|
||||
"resolutions": {
|
||||
"graphql": "15.3.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ export type TweetStatus =
|
|||
export type SkinType = "MODERN" | "CLASSIC";
|
||||
|
||||
export type SkinRow = {
|
||||
id: number;
|
||||
md5: string;
|
||||
skin_type: number;
|
||||
emails: string;
|
||||
|
|
|
|||
167
yarn.lock
167
yarn.lock
|
|
@ -2132,6 +2132,18 @@
|
|||
exec-sh "^0.3.2"
|
||||
minimist "^1.2.0"
|
||||
|
||||
"@cspotcode/source-map-consumer@0.8.0":
|
||||
version "0.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b"
|
||||
integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==
|
||||
|
||||
"@cspotcode/source-map-support@0.7.0":
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5"
|
||||
integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==
|
||||
dependencies:
|
||||
"@cspotcode/source-map-consumer" "0.8.0"
|
||||
|
||||
"@discordjs/collection@^0.1.6":
|
||||
version "0.1.6"
|
||||
resolved "https://registry.yarnpkg.com/@discordjs/collection/-/collection-0.1.6.tgz#9e9a7637f4e4e0688fd8b2b5c63133c91607682c"
|
||||
|
|
@ -2948,6 +2960,26 @@
|
|||
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
||||
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
|
||||
|
||||
"@tsconfig/node10@^1.0.7":
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9"
|
||||
integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==
|
||||
|
||||
"@tsconfig/node12@^1.0.7":
|
||||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c"
|
||||
integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==
|
||||
|
||||
"@tsconfig/node14@^1.0.0":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2"
|
||||
integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==
|
||||
|
||||
"@tsconfig/node16@^1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e"
|
||||
integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==
|
||||
|
||||
"@types/anymatch@*":
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a"
|
||||
|
|
@ -3729,6 +3761,14 @@ abort-controller@^3.0.0:
|
|||
dependencies:
|
||||
event-target-shim "^5.0.0"
|
||||
|
||||
accepts@^1.3.7:
|
||||
version "1.3.8"
|
||||
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
|
||||
integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
|
||||
dependencies:
|
||||
mime-types "~2.1.34"
|
||||
negotiator "0.6.3"
|
||||
|
||||
accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
|
||||
version "1.3.7"
|
||||
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
|
||||
|
|
@ -3772,6 +3812,11 @@ acorn-walk@^8.0.0:
|
|||
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.0.0.tgz#56ae4c0f434a45fff4a125e7ea95fa9c98f67a16"
|
||||
integrity sha512-oZRad/3SMOI/pxbbmqyurIx7jHw1wZDcR9G44L8pUVFEomX/0dH89SrM1KaDXuv1NpzAXz6Op/Xu/Qd5XXzdEA==
|
||||
|
||||
acorn-walk@^8.1.1:
|
||||
version "8.2.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
|
||||
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
|
||||
|
||||
acorn@^5.5.3:
|
||||
version "5.7.4"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e"
|
||||
|
|
@ -3793,6 +3838,11 @@ acorn@^8.0.4:
|
|||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.0.4.tgz#7a3ae4191466a6984eee0fe3407a4f3aa9db8354"
|
||||
integrity sha512-XNP0PqF1XD19ZlLKvB7cMmnZswW4C/03pRHgirB30uSJTaS3A3V1/P4sS3HPvFmjoriPCJQs+JDSbm4bL1TxGQ==
|
||||
|
||||
acorn@^8.4.1:
|
||||
version "8.7.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf"
|
||||
integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==
|
||||
|
||||
add-dom-event-listener@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/add-dom-event-listener/-/add-dom-event-listener-1.1.0.tgz#6a92db3a0dd0abc254e095c0f1dc14acbbaae310"
|
||||
|
|
@ -4925,6 +4975,11 @@ bytes@3.1.0:
|
|||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
|
||||
|
||||
bytes@3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
|
||||
integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
|
||||
|
||||
cac@^6.7.2:
|
||||
version "6.7.3"
|
||||
resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.3.tgz#10410b8611677990cc2e3c8b576d471c1d71b768"
|
||||
|
|
@ -5579,7 +5634,7 @@ content-disposition@0.5.3, content-disposition@^0.5.2:
|
|||
dependencies:
|
||||
safe-buffer "5.1.2"
|
||||
|
||||
content-type@~1.0.4:
|
||||
content-type@^1.0.4, content-type@~1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
|
||||
|
||||
|
|
@ -5727,6 +5782,11 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7:
|
|||
safe-buffer "^5.0.1"
|
||||
sha.js "^2.4.8"
|
||||
|
||||
create-require@^1.1.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
|
||||
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
|
||||
|
||||
cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5:
|
||||
version "6.0.5"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
|
||||
|
|
@ -7297,6 +7357,16 @@ express-fileupload@^1.1.7-alpha.3:
|
|||
dependencies:
|
||||
busboy "^0.3.1"
|
||||
|
||||
express-graphql@^0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.yarnpkg.com/express-graphql/-/express-graphql-0.12.0.tgz#58deabc309909ca2c9fe2f83f5fbe94429aa23df"
|
||||
integrity sha512-DwYaJQy0amdy3pgNtiTDuGGM2BLdj+YO2SgbKoLliCfuHv3VVTt7vNG/ZqK2hRYjtYHE2t2KB705EU94mE64zg==
|
||||
dependencies:
|
||||
accepts "^1.3.7"
|
||||
content-type "^1.0.4"
|
||||
http-errors "1.8.0"
|
||||
raw-body "^2.4.1"
|
||||
|
||||
express-sitemap-xml@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/express-sitemap-xml/-/express-sitemap-xml-2.0.0.tgz#190b4993458007a61b4747a66e3a723121a207f6"
|
||||
|
|
@ -8279,6 +8349,13 @@ graceful-fs@^4.2.3:
|
|||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
|
||||
|
||||
graphql@14.7.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"
|
||||
|
||||
growly@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
|
||||
|
|
@ -8588,6 +8665,28 @@ http-errors@1.7.2:
|
|||
statuses ">= 1.5.0 < 2"
|
||||
toidentifier "1.0.0"
|
||||
|
||||
http-errors@1.8.0:
|
||||
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.8.1:
|
||||
version "1.8.1"
|
||||
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c"
|
||||
integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==
|
||||
dependencies:
|
||||
depd "~1.1.2"
|
||||
inherits "2.0.4"
|
||||
setprototypeof "1.2.0"
|
||||
statuses ">= 1.5.0 < 2"
|
||||
toidentifier "1.0.1"
|
||||
|
||||
http-errors@~1.6.2:
|
||||
version "1.6.3"
|
||||
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
|
||||
|
|
@ -9472,6 +9571,11 @@ isurl@^1.0.0-alpha5:
|
|||
has-to-string-tag-x "^1.2.0"
|
||||
is-object "^1.0.1"
|
||||
|
||||
iterall@^1.2.2:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea"
|
||||
integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==
|
||||
|
||||
jest-changed-files@^24.9.0:
|
||||
version "24.9.0"
|
||||
resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-24.9.0.tgz#08d8c15eb79a7fa3fc98269bc14b451ee82f8039"
|
||||
|
|
@ -11375,12 +11479,24 @@ mime-db@1.44.0, "mime-db@>= 1.43.0 < 2", mime-db@^1.28.0:
|
|||
version "1.44.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92"
|
||||
|
||||
mime-db@1.51.0:
|
||||
version "1.51.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c"
|
||||
integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==
|
||||
|
||||
mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24:
|
||||
version "2.1.27"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f"
|
||||
dependencies:
|
||||
mime-db "1.44.0"
|
||||
|
||||
mime-types@~2.1.34:
|
||||
version "2.1.34"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24"
|
||||
integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==
|
||||
dependencies:
|
||||
mime-db "1.51.0"
|
||||
|
||||
mime@1.6.0, mime@^1.3.4, mime@^1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
|
||||
|
|
@ -11689,6 +11805,11 @@ negotiator@0.6.2, negotiator@^0.6.2:
|
|||
version "0.6.2"
|
||||
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
|
||||
|
||||
negotiator@0.6.3:
|
||||
version "0.6.3"
|
||||
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
|
||||
integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
|
||||
|
||||
neo-async@^2.5.0, neo-async@^2.6.1:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c"
|
||||
|
|
@ -13449,6 +13570,16 @@ raw-body@2.4.0:
|
|||
iconv-lite "0.4.24"
|
||||
unpipe "1.0.0"
|
||||
|
||||
raw-body@^2.4.1:
|
||||
version "2.4.3"
|
||||
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.3.tgz#8f80305d11c2a0a545c2d9d89d7a0286fcead43c"
|
||||
integrity sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==
|
||||
dependencies:
|
||||
bytes "3.1.2"
|
||||
http-errors "1.8.1"
|
||||
iconv-lite "0.4.24"
|
||||
unpipe "1.0.0"
|
||||
|
||||
rc-align@^2.4.0:
|
||||
version "2.4.5"
|
||||
resolved "https://registry.yarnpkg.com/rc-align/-/rc-align-2.4.5.tgz#c941a586f59d1017f23a428f0b468663fb7102ab"
|
||||
|
|
@ -14439,6 +14570,11 @@ setprototypeof@1.1.1:
|
|||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
|
||||
|
||||
setprototypeof@1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
|
||||
integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
|
||||
|
||||
sha.js@^2.4.0, sha.js@^2.4.8:
|
||||
version "2.4.11"
|
||||
resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7"
|
||||
|
|
@ -14687,7 +14823,7 @@ source-map-resolve@^0.5.0:
|
|||
source-map-url "^0.4.0"
|
||||
urix "^0.1.0"
|
||||
|
||||
source-map-support@^0.5.16, source-map-support@^0.5.17, source-map-support@^0.5.6, source-map-support@~0.5.12:
|
||||
source-map-support@^0.5.16, source-map-support@^0.5.6, source-map-support@~0.5.12:
|
||||
version "0.5.19"
|
||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
|
||||
dependencies:
|
||||
|
|
@ -15513,6 +15649,11 @@ toidentifier@1.0.0:
|
|||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
|
||||
|
||||
toidentifier@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
|
||||
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
|
||||
|
||||
token-types@^1.0.1:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/token-types/-/token-types-1.3.2.tgz#2cd58386be7e1ff316cd6b8d5aa25ea070deb2f0"
|
||||
|
|
@ -15594,14 +15735,23 @@ ts-interface-checker@^0.1.9:
|
|||
resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699"
|
||||
integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==
|
||||
|
||||
ts-node@^8.10.2:
|
||||
version "8.10.2"
|
||||
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.10.2.tgz#eee03764633b1234ddd37f8db9ec10b75ec7fb8d"
|
||||
ts-node@^10.5.0:
|
||||
version "10.5.0"
|
||||
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.5.0.tgz#618bef5854c1fbbedf5e31465cbb224a1d524ef9"
|
||||
integrity sha512-6kEJKwVxAJ35W4akuiysfKwKmjkbYxwQMTBaAxo9KKAx/Yd26mPUyhGz3ji+EsJoAgrLqVsYHNuuYwQe22lbtw==
|
||||
dependencies:
|
||||
"@cspotcode/source-map-support" "0.7.0"
|
||||
"@tsconfig/node10" "^1.0.7"
|
||||
"@tsconfig/node12" "^1.0.7"
|
||||
"@tsconfig/node14" "^1.0.0"
|
||||
"@tsconfig/node16" "^1.0.2"
|
||||
acorn "^8.4.1"
|
||||
acorn-walk "^8.1.1"
|
||||
arg "^4.1.0"
|
||||
create-require "^1.1.0"
|
||||
diff "^4.0.1"
|
||||
make-error "^1.1.1"
|
||||
source-map-support "^0.5.17"
|
||||
v8-compile-cache-lib "^3.0.0"
|
||||
yn "3.1.1"
|
||||
|
||||
tslib@^1.10.0:
|
||||
|
|
@ -15992,6 +16142,11 @@ uuid@^8.3.0:
|
|||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
|
||||
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
||||
|
||||
v8-compile-cache-lib@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz#0582bcb1c74f3a2ee46487ceecf372e46bce53e8"
|
||||
integrity sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA==
|
||||
|
||||
v8-compile-cache@2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue