mirror of
https://github.com/jwinterm/rarity-analyser.git
synced 2026-10-17 05:41:40 +02:00
Create app
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
MONGODB = mongodb://localhost:27017/rarity-analyser
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
node_modules
|
||||||
|
# Keep environment variables out of version control
|
||||||
|
.env
|
||||||
|
dist
|
||||||
|
src/data/
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
/* eslint-disable no-undef */
|
||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
plugins: ['@typescript-eslint'],
|
||||||
|
extends: [
|
||||||
|
'eslint:recommended',
|
||||||
|
'plugin:@typescript-eslint/recommended',
|
||||||
|
'prettier',
|
||||||
|
],
|
||||||
|
}
|
||||||
+5
-1
@@ -1,5 +1,9 @@
|
|||||||
|
.DS_Store
|
||||||
|
|
||||||
node_modules
|
node_modules
|
||||||
# Keep environment variables out of version control
|
# Keep environment variables out of version control
|
||||||
.env
|
.env
|
||||||
|
|
||||||
src/data/
|
src/data/*
|
||||||
|
|
||||||
|
dist
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
dist
|
||||||
|
src/data/*
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
# Rarity analyser
|
||||||
|
|
||||||
|
Creates rarity data for an NFT collection and provides a GraphQL API for making queries.
|
||||||
|
|
||||||
|
Creates both classic and normalized rarity scores.
|
||||||
|
|
||||||
|
User interface at [rarity-interface](https://github.com/mikko-o/rarity-interface).
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
### Create a MongoDB instance
|
||||||
|
|
||||||
|
1. Create a free [MongoDB Atlas instance](https://www.mongodb.com/) or use a [local MongoDB](https://docs.mongodb.com/manual/administration/install-community/).
|
||||||
|
|
||||||
|
2. Add the [connection string](https://docs.mongodb.com/manual/reference/connection-string/) for MongoDB into a .env file:
|
||||||
|
|
||||||
|
```
|
||||||
|
# .env
|
||||||
|
MONGODB=mongodb://localhost:27017/rarity
|
||||||
|
```
|
||||||
|
|
||||||
|
### Analyse metadata
|
||||||
|
|
||||||
|
Analyse collection [metadata](https://docs.opensea.io/docs/metadata-standards) with
|
||||||
|
`yarn analyse --json <path_to_metadata_json_file>`.
|
||||||
|
|
||||||
|
### Start the GraphQL server
|
||||||
|
Start the server with `yarn dev`
|
||||||
|
|
||||||
|
### Deployment
|
||||||
|
#### Heroku
|
||||||
|
```
|
||||||
|
heroku create
|
||||||
|
heroku config:set MONGODB=mongodb+srv://<user>:<password>@db.b5lu1.mongodb.net/db
|
||||||
|
git push heroku main
|
||||||
|
```
|
||||||
|
## Configuration
|
||||||
|
Following options can be applied in the rarityConfig.ts file.
|
||||||
|
### weights
|
||||||
|
Add weights to scale rarity scores up or down.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
# rarityConfig.ts
|
||||||
|
{
|
||||||
|
weights: {
|
||||||
|
"Trait A": 1.2,
|
||||||
|
"Trait B": 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### getMissingTraitIdentifier
|
||||||
|
`(trait_type?: string) => string | undefined`
|
||||||
|
|
||||||
|
By default it is assumed that the missing traits are completely missing from the attribute list. Some collections however use other values for missing traits, for example "No Hat" for the trait type "Hat".
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```typescript
|
||||||
|
# rarityConfig.ts
|
||||||
|
{
|
||||||
|
getMissingTraitIdentifier: (traittype?: string) => "No " + traitType
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### attributesFieldName
|
||||||
|
|
||||||
|
The default name is `attributes`, define a custom name here.
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
### analyse
|
||||||
|
`yarn analyse --json <collection.json> --saveJson --db <true>`
|
||||||
|
Analyses rarity data form existing metadata
|
||||||
|
|
||||||
|
Cli options:
|
||||||
|
|
||||||
|
#### --json
|
||||||
|
Default: `src/data/collection.json`
|
||||||
|
Path to the token attribute file
|
||||||
|
|
||||||
|
#### --saveJson
|
||||||
|
Default: `false`
|
||||||
|
Saves rarity data into a json file
|
||||||
|
|
||||||
|
#### --db
|
||||||
|
Default: `true`
|
||||||
|
Skips saving to database if false
|
||||||
|
|
||||||
|
### Interfaces
|
||||||
|
|
||||||
|
##### Token
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Token {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
attributes: Attribute[] // Attribute field name can be configured in rarityConfig.ts
|
||||||
|
image?: string
|
||||||
|
description?: string
|
||||||
|
image_data?: string
|
||||||
|
external_url?: string
|
||||||
|
animation_url?: string
|
||||||
|
background_color?: string
|
||||||
|
|
||||||
|
// The following fields are included in the analysed data
|
||||||
|
rarity_score: number
|
||||||
|
rank: number
|
||||||
|
rarity_score_normalized: number
|
||||||
|
rank_normalized: number
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Attribute
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Attribute {
|
||||||
|
trait_type: number
|
||||||
|
value: string
|
||||||
|
|
||||||
|
// The following fields are included in the analysed data
|
||||||
|
rarity_score: number
|
||||||
|
rarity_score_normalized: number
|
||||||
|
percentile: number
|
||||||
|
count: number // Count of how many tokens have the value of this attribute
|
||||||
|
}
|
||||||
|
```
|
||||||
+19
-10
@@ -1,31 +1,40 @@
|
|||||||
{
|
{
|
||||||
"name": "rarity-graphql",
|
"name": "rarity-graphql",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"main": "index.js",
|
"main": "src/index.ts",
|
||||||
"author": "mikkoo.eth",
|
"author": "mikkoo.eth",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"private": false,
|
"private": false,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "yarn tsc",
|
"build": "yarn tsc",
|
||||||
"start": "node dist/index.js",
|
"start": "node dist/src/index.js",
|
||||||
"dev": "yarn ts-node src/index.ts",
|
"dev": "yarn ts-node-dev src/index.ts",
|
||||||
"analyse": "yarn ts-node src/scripts/analyse.ts",
|
"analyse": "yarn ts-node src/scripts/analyse.ts",
|
||||||
"seed": "yarn ts-node src/scripts/seed.ts"
|
"seed": "yarn ts-node src/scripts/seed.ts",
|
||||||
|
"lint": "yarn eslint . --ext .js,.ts",
|
||||||
|
"format": "yarn prettier --write . --no-semi --single-quote"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@graphql-tools/schema": "^8.2.0",
|
||||||
"apollo-server": "^3.3.0",
|
"apollo-server": "^3.3.0",
|
||||||
"axios": "^0.21.4",
|
"dotenv": "^10.0.0",
|
||||||
"graphql": "^15.5.3",
|
"graphql": "^15.5.3",
|
||||||
"mongoose": "^6.0.5"
|
"lodash.orderby": "^4.6.0",
|
||||||
|
"micro": "^9.3.4",
|
||||||
|
"mongoose": "^6.0.5",
|
||||||
|
"typescript": "^4.4.3",
|
||||||
|
"yargs": "^17.1.1-candidate.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/lodash.orderby": "^4.6.6",
|
"@types/lodash.orderby": "^4.6.6",
|
||||||
"@types/node": "^16.7.13",
|
"@types/node": "^16.7.13",
|
||||||
"@types/yargs": "^17.0.2",
|
"@types/yargs": "^17.0.2",
|
||||||
"lodash.orderby": "^4.6.0",
|
"@typescript-eslint/eslint-plugin": "^4.31.1",
|
||||||
|
"@typescript-eslint/parser": "^4.31.1",
|
||||||
|
"eslint": "^7.32.0",
|
||||||
|
"eslint-config-prettier": "^8.3.0",
|
||||||
|
"prettier": "^2.4.1",
|
||||||
"ts-node": "^10.2.1",
|
"ts-node": "^10.2.1",
|
||||||
"ts-node-dev": "^1.1.8",
|
"ts-node-dev": "^1.1.8"
|
||||||
"typescript": "^4.4.2",
|
|
||||||
"yargs": "^17.1.1-candidate.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { Config } from './src/types'
|
||||||
|
|
||||||
|
const config: Config = {
|
||||||
|
// weights: {},
|
||||||
|
// getMissingTraitIdentifier: (trait_type?: string) => undefined,
|
||||||
|
// attributesFieldName: 'attributes',
|
||||||
|
}
|
||||||
|
|
||||||
|
export default config
|
||||||
+515
@@ -0,0 +1,515 @@
|
|||||||
|
import { orderBy } from 'lodash'
|
||||||
|
import {
|
||||||
|
Token,
|
||||||
|
TokenWithRarity,
|
||||||
|
Collection,
|
||||||
|
IsMissing,
|
||||||
|
GetIsMissing,
|
||||||
|
GetMissingTraitIdentifier,
|
||||||
|
Weights,
|
||||||
|
Attribute,
|
||||||
|
TraitsMeta,
|
||||||
|
} from './types'
|
||||||
|
import config from '../rarityConfig'
|
||||||
|
import { defaultMissingTraitIdentifier } from './utils'
|
||||||
|
|
||||||
|
const getMissingTraitIdentifier =
|
||||||
|
config.getMissingTraitIdentifier ?? defaultMissingTraitIdentifier
|
||||||
|
|
||||||
|
const weights: Weights = config.weights ?? {}
|
||||||
|
const getWeight = (traitType: string) => weights[traitType] ?? 1
|
||||||
|
|
||||||
|
const MISSING = 'none'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param missingTraitIdentifier Value of the trait type that indicates that it is missing. `undefined` (default) if there is no specific identifier and the {trait_type: string, value: string} entry is simply omitted.
|
||||||
|
* @returns A function, which given traitType and token returns true if the trait type is missing (as specified by missingTraitIdentifier). Returns true also if the given traitType is completely missing from the tokens attributes
|
||||||
|
*/
|
||||||
|
const getIsMissing: GetIsMissing =
|
||||||
|
(getMissingTraitIdentifier) => (traitType, token) => {
|
||||||
|
const attribute = token.attributes.find(
|
||||||
|
(att) => att.trait_type === traitType
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
!attribute || attribute.value === getMissingTraitIdentifier(traitType)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const traitIsMissingFn = getIsMissing(getMissingTraitIdentifier)
|
||||||
|
|
||||||
|
type Counts = {
|
||||||
|
[trait_type: string]: {
|
||||||
|
[value: string]: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns Collection with rarity data
|
||||||
|
*/
|
||||||
|
export const analyse = (
|
||||||
|
t: Array<Record<string, string | number | Attribute[]>>
|
||||||
|
): Collection => {
|
||||||
|
const tokens: Token[] = preprocess(t)
|
||||||
|
const n = tokens.length
|
||||||
|
let traitTypes = getTraitTypeSet(tokens)
|
||||||
|
|
||||||
|
const tokensWithMissingTraits = addMissingTraits(
|
||||||
|
tokens,
|
||||||
|
traitIsMissingFn,
|
||||||
|
traitTypes,
|
||||||
|
getMissingTraitIdentifier
|
||||||
|
)
|
||||||
|
|
||||||
|
const tokensWithTraitCount = addTraitCounts(
|
||||||
|
tokensWithMissingTraits,
|
||||||
|
getMissingTraitIdentifier
|
||||||
|
)
|
||||||
|
|
||||||
|
traitTypes = getTraitTypeSet(tokensWithTraitCount)
|
||||||
|
|
||||||
|
const counts = count(tokensWithTraitCount)
|
||||||
|
|
||||||
|
const tokensWithAttributeRarity = addAttributeRarities(
|
||||||
|
tokensWithTraitCount,
|
||||||
|
counts
|
||||||
|
)
|
||||||
|
|
||||||
|
// Sort attributes by rarity_score
|
||||||
|
const tokensWithOrderedAttributes = tokensWithAttributeRarity.map(
|
||||||
|
(token) => ({
|
||||||
|
...token,
|
||||||
|
attributes: orderBy(token.attributes, (a) => a.rarity_score, 'desc'),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
const tokensWithTotalRarityScore = getTotalRarityScore(
|
||||||
|
tokensWithOrderedAttributes
|
||||||
|
)
|
||||||
|
|
||||||
|
const tokensWithRankings = getRankings(tokensWithTotalRarityScore)
|
||||||
|
|
||||||
|
const traitTypeData = getTraitRarityScores(tokensWithRankings, [...traitTypes])
|
||||||
|
const [traitTypeDataWithStats, collectionStats] = getStats(traitTypeData)
|
||||||
|
const traitTypeDataWithNormalizedRarities = addNormalizedRarities(traitTypeDataWithStats, collectionStats.mean)
|
||||||
|
|
||||||
|
const tokensWithNormalizedRarities = addTokenNormalizedRarities(tokensWithRankings, traitTypeDataWithNormalizedRarities)
|
||||||
|
|
||||||
|
const tokensWithTotalNormalizedRarity = getTotalNormalizedRarityScore(tokensWithNormalizedRarities)
|
||||||
|
|
||||||
|
const tokensWithNormalizedRankings = getNormalizedRankings(tokensWithTotalNormalizedRarity)
|
||||||
|
|
||||||
|
return {
|
||||||
|
tokens: tokensWithNormalizedRankings,
|
||||||
|
numTokens: n,
|
||||||
|
traitTypes: traitTypeDataWithNormalizedRarities,
|
||||||
|
stats: collectionStats,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const preprocess = (
|
||||||
|
tokens: Record<string, string | number | Attribute[]>[]
|
||||||
|
) => {
|
||||||
|
const attributesFieldName = config.attributesFieldName
|
||||||
|
|
||||||
|
// Filter possible empty objects, ie. trait_type and value are missing
|
||||||
|
const filtered: Array<
|
||||||
|
Record<string, string | number | Attribute[]> & {
|
||||||
|
attributes: Attribute[]
|
||||||
|
}
|
||||||
|
> = tokens.map((token) => {
|
||||||
|
const attributes = token[
|
||||||
|
attributesFieldName ?? 'attributes'
|
||||||
|
] as Attribute[]
|
||||||
|
|
||||||
|
if (!('trait_type' in attributes[0]))
|
||||||
|
throw new Error('Attribute trait type missing')
|
||||||
|
|
||||||
|
const filteredAttributes = attributes.filter(
|
||||||
|
(a) => Object.keys(a).length > 0
|
||||||
|
)
|
||||||
|
return { ...token, attributes: filteredAttributes }
|
||||||
|
})
|
||||||
|
|
||||||
|
let t = filtered
|
||||||
|
// If attribute field name is not 'attributes', rename the field
|
||||||
|
if (attributesFieldName && attributesFieldName !== 'attributes') {
|
||||||
|
const mapped = filtered.map((token) => {
|
||||||
|
const attributes = token[attributesFieldName] as Attribute[]
|
||||||
|
|
||||||
|
if (!('trait_type' in attributes[0]))
|
||||||
|
throw new Error('Attribute trait_type missing')
|
||||||
|
|
||||||
|
const newToken: Record<string, string | number | Attribute[]> & {
|
||||||
|
attributes: Attribute[]
|
||||||
|
} = {
|
||||||
|
...token,
|
||||||
|
attributes: attributes,
|
||||||
|
}
|
||||||
|
delete newToken[attributesFieldName]
|
||||||
|
return newToken
|
||||||
|
})
|
||||||
|
t = mapped
|
||||||
|
}
|
||||||
|
|
||||||
|
return t as Token[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tokens
|
||||||
|
* @param traitIsMissingFn Function that given a token and a trait type returns true if the trait type is missing
|
||||||
|
* @param traitTypes A set of trait types
|
||||||
|
* @param missingTraitIdentifier Value of a trait type that is missing or not active on the token. By default (undefined) it is assumed that the trait type is completely missing from the attribute list.
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const addMissingTraits = (
|
||||||
|
tokens: Token[],
|
||||||
|
traitIsMissingFn: IsMissing,
|
||||||
|
traitTypes: Set<string>,
|
||||||
|
getMissingTraitIdentifier: GetMissingTraitIdentifier
|
||||||
|
) =>
|
||||||
|
tokens.map((token) => {
|
||||||
|
const missingAttributes = getMissingTraits(
|
||||||
|
token,
|
||||||
|
traitIsMissingFn,
|
||||||
|
traitTypes,
|
||||||
|
getMissingTraitIdentifier
|
||||||
|
)
|
||||||
|
|
||||||
|
// Delete old missing attributes if exists
|
||||||
|
const missingTraits = new Set(missingAttributes.map((m) => m.trait_type))
|
||||||
|
const filteredAttributes = token.attributes.filter(
|
||||||
|
(a) => !missingTraits.has(a.trait_type)
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
...token,
|
||||||
|
attributes: [...filteredAttributes, ...missingAttributes],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns Set of a tokens missing traits as attributes with placeholder rarity data
|
||||||
|
*/
|
||||||
|
const getMissingTraits = <T extends Token>(
|
||||||
|
token: T,
|
||||||
|
isMissingFn: IsMissing,
|
||||||
|
traitTypes: Set<string>,
|
||||||
|
getMissingTraitIdentifier: GetMissingTraitIdentifier
|
||||||
|
) =>
|
||||||
|
[...traitTypes]
|
||||||
|
.filter((traitType) => isMissingFn(traitType, token))
|
||||||
|
.map((trait_type) => ({
|
||||||
|
trait_type,
|
||||||
|
value: getMissingTraitIdentifier(trait_type) ?? MISSING,
|
||||||
|
rarity_score: 0,
|
||||||
|
count: 0,
|
||||||
|
percentile: 0,
|
||||||
|
}))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns tokens with trait_count attribute (`{trait_type: 'trait_count', value: number}`)
|
||||||
|
*/
|
||||||
|
const addTraitCounts = (
|
||||||
|
tokens: Token[],
|
||||||
|
getMissingTraitIdentifier: GetMissingTraitIdentifier
|
||||||
|
) =>
|
||||||
|
tokens.map((token) => {
|
||||||
|
const count = token.attributes.filter(
|
||||||
|
(a) => a.value !== getMissingTraitIdentifier(a.trait_type) ?? MISSING
|
||||||
|
).length
|
||||||
|
const traitCountAttribute = {
|
||||||
|
trait_type: 'Trait Count',
|
||||||
|
value: String(count),
|
||||||
|
rarity_score: 0,
|
||||||
|
percentile: 0,
|
||||||
|
count: 0,
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...token,
|
||||||
|
attributes: [...token.attributes, traitCountAttribute],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns counts of how many times each different attribute value occurs in the collection
|
||||||
|
*/
|
||||||
|
const count = (tokens: Token[]): Counts => {
|
||||||
|
const counts: Counts = {}
|
||||||
|
tokens.forEach((token) => {
|
||||||
|
token.attributes.forEach(({ trait_type, value }) => {
|
||||||
|
const count = counts[trait_type] ? counts[trait_type][value] ?? 0 : 0
|
||||||
|
if (counts[trait_type]) counts[trait_type][value] = count + 1
|
||||||
|
else counts[trait_type] = { [value]: 1 }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return counts
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns tokens with rarity_score, percentile. Include count (how many tokens have this value)
|
||||||
|
*/
|
||||||
|
const addAttributeRarities = (tokens: Token[], counts: Counts) =>
|
||||||
|
tokens.map((token) => {
|
||||||
|
const updatedAttributes = token.attributes.map((attribute) => {
|
||||||
|
const { trait_type, value } = attribute
|
||||||
|
const count = counts[trait_type][value]
|
||||||
|
const percentile = count / tokens.length
|
||||||
|
const rarity_score = (1 / percentile) * getWeight(trait_type)
|
||||||
|
return { ...attribute, rarity_score, percentile, count }
|
||||||
|
})
|
||||||
|
return { ...token, attributes: updatedAttributes }
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns set of different trait types in the collection
|
||||||
|
*/
|
||||||
|
const getTraitTypeSet = (tokens: Token[]): Set<string> => {
|
||||||
|
const traitTypes = new Set<string>()
|
||||||
|
tokens.forEach((token) => {
|
||||||
|
token.attributes.forEach(({ trait_type }) => {
|
||||||
|
if (!traitTypes.has(trait_type)) traitTypes.add(trait_type)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return traitTypes
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTotalRarityScore = (
|
||||||
|
tokens: Token[]
|
||||||
|
) => {
|
||||||
|
const totalRarityScores = tokens.map((token) => {
|
||||||
|
const rarity_score = token.attributes.reduce(
|
||||||
|
(sum, attribute) => sum + attribute.rarity_score,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
return { ...token, rarity_score }
|
||||||
|
})
|
||||||
|
|
||||||
|
return totalRarityScores
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTotalNormalizedRarityScore = (
|
||||||
|
tokens: Omit<TokenWithRarity, 'rarity_score_normalized' | 'rank_normalized'>[]
|
||||||
|
) => {
|
||||||
|
const totalRarityScores = tokens.map((token) => {
|
||||||
|
const rarity_score_normalized = token.attributes.reduce((sum, attribute) => {
|
||||||
|
if (attribute.rarity_score_normalized === undefined) throw new Error("Normalized rarity score missing")
|
||||||
|
return sum + attribute.rarity_score_normalized
|
||||||
|
}, 0
|
||||||
|
)
|
||||||
|
return { ...token, rarity_score_normalized }
|
||||||
|
})
|
||||||
|
|
||||||
|
return totalRarityScores
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tokens Array of tokens sorted by rarity_score (desc)
|
||||||
|
* @returns Tokens with rankins
|
||||||
|
*/
|
||||||
|
const getRankings = (tokens: Omit<TokenWithRarity, 'rank' | 'rarity_score_normalized' | 'rank_normalized'>[]) => {
|
||||||
|
const sorted = orderBy(tokens, (token) => token.rarity_score, 'desc')
|
||||||
|
|
||||||
|
let currentRank = 0
|
||||||
|
let previousRarityScore = Infinity
|
||||||
|
|
||||||
|
const rankedTokens = sorted.map((token, i) => {
|
||||||
|
if (token.rarity_score < previousRarityScore) {
|
||||||
|
currentRank = i + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
const updated: Omit<TokenWithRarity, 'rarity_score_normalized' | 'rank_normalized'> = { ...token, rank: currentRank }
|
||||||
|
previousRarityScore = updated.rarity_score
|
||||||
|
return updated
|
||||||
|
})
|
||||||
|
|
||||||
|
return rankedTokens
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tokens Array of tokens sorted by rarity_score (desc)
|
||||||
|
* @returns Tokens with rankins
|
||||||
|
*/
|
||||||
|
const getNormalizedRankings = (tokens: Omit<TokenWithRarity, 'rank_normalized'>[]) => {
|
||||||
|
const sorted = orderBy(tokens, (token) => token.rarity_score_normalized, 'desc')
|
||||||
|
|
||||||
|
let currentRank = 0
|
||||||
|
let previous = Infinity
|
||||||
|
|
||||||
|
const rankedTokens = sorted.map((token, i) => {
|
||||||
|
if (token.rarity_score_normalized < previous) {
|
||||||
|
currentRank = i + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
const updated = { ...token, rank_normalized: currentRank }
|
||||||
|
previous = updated.rarity_score_normalized
|
||||||
|
return updated
|
||||||
|
})
|
||||||
|
|
||||||
|
return rankedTokens
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTraitRarityScores = (tokens: Token[], traitTypes: string[]) => {
|
||||||
|
const temp: Record<string, Record<string, Attribute>> = {}
|
||||||
|
traitTypes.forEach((t) => (temp[t] = {}))
|
||||||
|
|
||||||
|
tokens.forEach((token) => {
|
||||||
|
token.attributes.forEach((attribute) => {
|
||||||
|
const { trait_type, rarity_score, value } = attribute
|
||||||
|
const attributes = temp[trait_type]
|
||||||
|
if (!attributes) return
|
||||||
|
const current = attributes[value]
|
||||||
|
if (!current || rarity_score > current.rarity_score) {
|
||||||
|
temp[trait_type][value] = attribute
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const result = Object.entries(temp).map(([key, val]) => ({
|
||||||
|
trait_type: key,
|
||||||
|
attributes: orderBy(
|
||||||
|
Object.entries(val).map((val) => val[1]),
|
||||||
|
x => x.count
|
||||||
|
),
|
||||||
|
}))
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
const getStats = (
|
||||||
|
traitRarities: { trait_type: string; attributes: Attribute[] }[]
|
||||||
|
) => {
|
||||||
|
const dataWithStats = traitRarities.map((trait) => {
|
||||||
|
const [sum, min, max] = trait.attributes
|
||||||
|
.map((a) => a.rarity_score)
|
||||||
|
.reduce(
|
||||||
|
([sum, min, max], rarity_score) => [
|
||||||
|
sum + rarity_score,
|
||||||
|
Math.min(min, rarity_score),
|
||||||
|
Math.max(max, rarity_score),
|
||||||
|
],
|
||||||
|
[0, Number.MAX_VALUE, 0]
|
||||||
|
)
|
||||||
|
const mean = sum / trait.attributes.length
|
||||||
|
const temp = trait.attributes
|
||||||
|
.map((a) => a.rarity_score)
|
||||||
|
.reduce((acc, rarity) => acc + Math.pow(rarity - mean, 2))
|
||||||
|
const std = Math.sqrt(temp / trait.attributes.length)
|
||||||
|
return {
|
||||||
|
...trait,
|
||||||
|
stats: { mean, std, min, max },
|
||||||
|
numValues: trait.attributes.length,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const [sum, min, max] = dataWithStats.reduce(
|
||||||
|
([sum, min, max], trait) => {
|
||||||
|
const s = trait.attributes.reduce(
|
||||||
|
(sum, attribute) => sum + attribute.rarity_score,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
return [s, Math.min(min, trait.stats.min), Math.max(max, trait.stats.max)]
|
||||||
|
},
|
||||||
|
[0, Number.MAX_VALUE, 0]
|
||||||
|
)
|
||||||
|
const mean = sum / dataWithStats.length
|
||||||
|
const temp = dataWithStats.reduce(
|
||||||
|
(acc, rarity) =>
|
||||||
|
acc +
|
||||||
|
rarity.attributes.reduce(
|
||||||
|
(sum, a) => sum + Math.pow(a.rarity_score - mean, 2),
|
||||||
|
0
|
||||||
|
),
|
||||||
|
0
|
||||||
|
)
|
||||||
|
const std = Math.sqrt(
|
||||||
|
temp /
|
||||||
|
dataWithStats.reduce((count, trait) => count + trait.attributes.length, 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
return [dataWithStats, { mean, std, min, max }] as const
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The idea with normalization is the following:
|
||||||
|
* If a trait type has more possible values than an average type,it will generally get higher rarity scores only for that reason.
|
||||||
|
* Example:
|
||||||
|
* If four values are equally distributed among 800 tokens, this trait will be add a rarity score of 4 to the token's total rarity.
|
||||||
|
* If there are 5 values, each trait will add 5.
|
||||||
|
* Therefore the trait types with more values need to be scaled down.
|
||||||
|
* However some traits types include rarer values than others
|
||||||
|
* We will take into account by checking whether the average rarity of the trait type
|
||||||
|
* is higher than the average rarity of the whole collection.
|
||||||
|
* Example:
|
||||||
|
* Trait has 30% more traits than the average, but 40% higher average rarity
|
||||||
|
* -> 10% of the higher rarity is due to actual rarity and scaling down 30% would remove some of that
|
||||||
|
* Solution is to 1. remove and store 10%, 2. remove 30%, 3. add 10% back.
|
||||||
|
*/
|
||||||
|
const addNormalizedRarities = (
|
||||||
|
traitTypes: TraitsMeta[],
|
||||||
|
meanRarity: number
|
||||||
|
) => {
|
||||||
|
const tempSum = traitTypes.reduce((sum, type) => sum + type.numValues, 0)
|
||||||
|
const meanValueCount = tempSum / traitTypes.length
|
||||||
|
const attributesWithNormalizedRarities = traitTypes.map(
|
||||||
|
metaTrait => {
|
||||||
|
const { stats, numValues, attributes } = metaTrait
|
||||||
|
let a: number
|
||||||
|
if (stats.mean >= meanRarity)
|
||||||
|
a = (stats.mean - meanRarity) / stats.mean
|
||||||
|
else
|
||||||
|
a = (meanRarity - stats.mean) / meanRarity
|
||||||
|
|
||||||
|
let b: number
|
||||||
|
if (numValues >= meanValueCount)
|
||||||
|
b = (numValues - meanValueCount) / numValues
|
||||||
|
else
|
||||||
|
b = (meanValueCount - numValues) / meanValueCount
|
||||||
|
|
||||||
|
const c = numValues >= meanValueCount ? 1 - b : 1 + b
|
||||||
|
|
||||||
|
const updated = attributes.map(attribute => {
|
||||||
|
const r = attribute.rarity_score
|
||||||
|
let rarity_score_normalized
|
||||||
|
if (a >= b && ((stats.mean > meanRarity && numValues > meanValueCount) || (stats.mean < meanRarity && numValues < meanValueCount)))
|
||||||
|
rarity_score_normalized = (r - (a - b) * r) * c + (a - b) * r
|
||||||
|
else
|
||||||
|
rarity_score_normalized = (r - a * r) * c + a * r
|
||||||
|
return {
|
||||||
|
...attribute,
|
||||||
|
rarity_score_normalized
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
...metaTrait,
|
||||||
|
attributes: updated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return attributesWithNormalizedRarities
|
||||||
|
}
|
||||||
|
|
||||||
|
const addTokenNormalizedRarities = (tokens: Omit<TokenWithRarity, 'rarity_score_normalized' | 'rank_normalized'>[], traitTypes: TraitsMeta[]) => {
|
||||||
|
const normalizedMap = {} as { [traitType: string]: { [value: string]: number } }
|
||||||
|
|
||||||
|
traitTypes.forEach(type => {
|
||||||
|
type.attributes.forEach(({ trait_type, value, rarity_score_normalized }) => {
|
||||||
|
if (rarity_score_normalized === undefined) throw new Error('Normalized rarity score missing')
|
||||||
|
if (!normalizedMap[trait_type])
|
||||||
|
normalizedMap[trait_type] = {}
|
||||||
|
|
||||||
|
normalizedMap[trait_type][value] = rarity_score_normalized
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return tokens.map(token => ({
|
||||||
|
...token,
|
||||||
|
attributes: token.attributes.map(attribute => ({
|
||||||
|
...attribute,
|
||||||
|
rarity_score_normalized: normalizedMap[attribute.trait_type][attribute.value]
|
||||||
|
}))
|
||||||
|
}))
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import mongoose from 'mongoose'
|
||||||
|
import dotenv from 'dotenv'
|
||||||
|
|
||||||
|
dotenv.config()
|
||||||
|
|
||||||
|
const connect = (uri?: string) => {
|
||||||
|
const s = uri ?? process.env.MONGODB
|
||||||
|
if (!s) throw new Error('Connection URI not found')
|
||||||
|
mongoose.connect(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import mongoose from 'mongoose'
|
||||||
|
import { metaSchema, tokenSchema } from './schema'
|
||||||
|
|
||||||
|
export const Token = mongoose.model('Token', tokenSchema)
|
||||||
|
|
||||||
|
export const Meta = mongoose.model('Meta', metaSchema)
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
import mongoose from 'mongoose'
|
||||||
|
import {
|
||||||
|
AttributeWithRarity,
|
||||||
|
Meta,
|
||||||
|
Stats,
|
||||||
|
TokenWithRarity,
|
||||||
|
TraitsMeta,
|
||||||
|
} from '../types'
|
||||||
|
|
||||||
|
const { Schema } = mongoose
|
||||||
|
|
||||||
|
const attributeSchema = new Schema<AttributeWithRarity>({
|
||||||
|
trait_type: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
index: true,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
index: true,
|
||||||
|
},
|
||||||
|
rarity_score: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
index: true,
|
||||||
|
},
|
||||||
|
rarity_score_normalized: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
index: true,
|
||||||
|
},
|
||||||
|
percentile: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
count: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export const tokenSchema = new Schema<TokenWithRarity>({
|
||||||
|
id: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
unique: true,
|
||||||
|
index: true,
|
||||||
|
},
|
||||||
|
name: String,
|
||||||
|
attributes: [attributeSchema],
|
||||||
|
description: String,
|
||||||
|
image: String,
|
||||||
|
image_data: String,
|
||||||
|
external_url: String,
|
||||||
|
animation_url: String,
|
||||||
|
background_color: String,
|
||||||
|
rank: {
|
||||||
|
type: Number,
|
||||||
|
index: true,
|
||||||
|
},
|
||||||
|
rarity_score: {
|
||||||
|
type: Number,
|
||||||
|
index: true,
|
||||||
|
},
|
||||||
|
rarity_score_normalized: {
|
||||||
|
type: Number,
|
||||||
|
index: true,
|
||||||
|
},
|
||||||
|
rank_normalized: {
|
||||||
|
type: Number,
|
||||||
|
index: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const statsSchema = new Schema<Stats>({
|
||||||
|
mean: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
std: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
min: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
max: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const traitTypeMetaSchema = new Schema<TraitsMeta>({
|
||||||
|
trait_type: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
attributes: {
|
||||||
|
type: [attributeSchema],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
stats: statsSchema,
|
||||||
|
numValues: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export const metaSchema = new Schema<Meta>({
|
||||||
|
numTokens: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
traitTypes: {
|
||||||
|
type: [traitTypeMetaSchema],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
stats: statsSchema,
|
||||||
|
})
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import mongoose from 'mongoose'
|
||||||
|
import { Token, Meta } from './models'
|
||||||
|
import { Collection } from '../types'
|
||||||
|
import connect from './connection'
|
||||||
|
|
||||||
|
const seed = async (collection: Collection) => {
|
||||||
|
connect()
|
||||||
|
|
||||||
|
await Promise.all([Token.deleteMany({}), Meta.deleteMany({})])
|
||||||
|
|
||||||
|
const { tokens, ...metadata } = collection
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
Token.insertMany(tokens).catch(console.error),
|
||||||
|
Meta.create(metadata),
|
||||||
|
])
|
||||||
|
|
||||||
|
mongoose.disconnect()
|
||||||
|
}
|
||||||
|
|
||||||
|
export default seed
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import { Token, Meta } from '../db/models'
|
||||||
|
|
||||||
|
interface TokensArgs {
|
||||||
|
first: number
|
||||||
|
skip: number
|
||||||
|
orderBy: string
|
||||||
|
orderDirection: string
|
||||||
|
trait_count: number
|
||||||
|
traits: Array<{
|
||||||
|
trait_type: string
|
||||||
|
value: string
|
||||||
|
}>
|
||||||
|
id: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolvers = {
|
||||||
|
Query: {
|
||||||
|
tokens(parent: any, args: TokensArgs) {
|
||||||
|
const { first, skip, orderBy, orderDirection, traits, id } = args
|
||||||
|
|
||||||
|
const [trait_types, values] = traits
|
||||||
|
? traits.reduce(
|
||||||
|
([trait_types, values], trait) => [
|
||||||
|
[...trait_types, trait.trait_type],
|
||||||
|
[...values, trait.value],
|
||||||
|
],
|
||||||
|
[[] as string[], [] as string[]]
|
||||||
|
)
|
||||||
|
: []
|
||||||
|
|
||||||
|
return Token.find({
|
||||||
|
...(id ? { id } : {}),
|
||||||
|
...(traits
|
||||||
|
? {
|
||||||
|
'attributes.trait_type': { $in: trait_types },
|
||||||
|
'attributes.value': { $in: values },
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
|
})
|
||||||
|
.sort({ [orderBy ?? 'rarity_score']: orderDirection ?? 'desc' })
|
||||||
|
.skip(skip)
|
||||||
|
.limit(first)
|
||||||
|
.catch(console.log)
|
||||||
|
},
|
||||||
|
token(parent: any, args: { id?: number; rank?: number }) {
|
||||||
|
const { id, rank } = args
|
||||||
|
return Token.findOne({
|
||||||
|
...(rank ? { rank } : {}),
|
||||||
|
...(id ? { id } : {}),
|
||||||
|
}).catch(console.log)
|
||||||
|
},
|
||||||
|
meta: () => Meta.findOne({}).catch(console.log),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default resolvers
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import { gql } from 'apollo-server-core'
|
||||||
|
|
||||||
|
const typeDefs = gql`
|
||||||
|
type Attribute {
|
||||||
|
id: Int!
|
||||||
|
trait_type: String!
|
||||||
|
value: String
|
||||||
|
rarity_score: Float!
|
||||||
|
rarity_score_normalized: Float!
|
||||||
|
percentile: Float!
|
||||||
|
count: Float!
|
||||||
|
tokenId: Int!
|
||||||
|
}
|
||||||
|
type TraitCount {
|
||||||
|
count: Int!
|
||||||
|
percentile: Float!
|
||||||
|
rarity_score: Float!
|
||||||
|
tokenId: Int!
|
||||||
|
}
|
||||||
|
type Token {
|
||||||
|
id: Int!
|
||||||
|
name: String!
|
||||||
|
attributes: [Attribute!]!
|
||||||
|
metadataUrl: String!
|
||||||
|
trait_count: TraitCount!
|
||||||
|
description: String
|
||||||
|
image: String
|
||||||
|
image_data: String
|
||||||
|
external_url: String
|
||||||
|
animation_url: String
|
||||||
|
background_color: String
|
||||||
|
rank: Float!
|
||||||
|
rarity_score: Float!
|
||||||
|
rarity_score_normalized: Float!
|
||||||
|
rank_normalized: Float!
|
||||||
|
}
|
||||||
|
type AttributeMeta {
|
||||||
|
trait_type: String!
|
||||||
|
rarity_score: Float!
|
||||||
|
rarity_score_normalized: Float!
|
||||||
|
value: String
|
||||||
|
percentile: Float!
|
||||||
|
count: Float!
|
||||||
|
}
|
||||||
|
type Stats {
|
||||||
|
mean: Float!
|
||||||
|
std: Float!
|
||||||
|
min: Float!
|
||||||
|
max: Float!
|
||||||
|
}
|
||||||
|
type TraitTypeMeta {
|
||||||
|
trait_type: String!
|
||||||
|
attributes: [AttributeMeta!]!
|
||||||
|
stats: Stats!
|
||||||
|
numValues: Int!
|
||||||
|
}
|
||||||
|
type Meta {
|
||||||
|
numTokens: Int!
|
||||||
|
traitTypes: [TraitTypeMeta!]!
|
||||||
|
stats: Stats!
|
||||||
|
}
|
||||||
|
|
||||||
|
input Trait {
|
||||||
|
trait_type: String
|
||||||
|
value: String
|
||||||
|
}
|
||||||
|
|
||||||
|
type Query {
|
||||||
|
tokens(
|
||||||
|
first: Int
|
||||||
|
skip: Int
|
||||||
|
orderBy: String
|
||||||
|
orderDirection: String
|
||||||
|
traits: [Trait]
|
||||||
|
id: Int
|
||||||
|
): [Token]
|
||||||
|
token(id: Int, rank: Int): Token
|
||||||
|
meta: Meta
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export default typeDefs
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { ApolloServer } from 'apollo-server'
|
||||||
|
import connect from './db/connection'
|
||||||
|
import typeDefs from './graphql/typeDefs'
|
||||||
|
import resolvers from './graphql/resolvers'
|
||||||
|
import {
|
||||||
|
ApolloServerPluginLandingPageGraphQLPlayground
|
||||||
|
} from "apollo-server-core";
|
||||||
|
import dotenv from 'dotenv'
|
||||||
|
|
||||||
|
dotenv.config()
|
||||||
|
|
||||||
|
connect()
|
||||||
|
|
||||||
|
const server = new ApolloServer({
|
||||||
|
typeDefs,
|
||||||
|
resolvers,
|
||||||
|
plugins: [
|
||||||
|
ApolloServerPluginLandingPageGraphQLPlayground
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
server.listen({ port: process.env.PORT ?? 4000 }).then(({ url }) => {
|
||||||
|
console.log(`🚀 Server ready at ${url}`)
|
||||||
|
})
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import { readFileSync, writeFileSync } from 'fs'
|
||||||
|
import yargs from 'yargs'
|
||||||
|
import { analyse } from '../analysis'
|
||||||
|
import seed from '../db/seed'
|
||||||
|
import { Token } from '../types'
|
||||||
|
|
||||||
|
const argv = yargs(process.argv.slice(2)).options({
|
||||||
|
json: {
|
||||||
|
type: 'string',
|
||||||
|
default: 'src/data/collection.json',
|
||||||
|
describe: 'Path to the token attribute file',
|
||||||
|
},
|
||||||
|
saveJson: {
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
describe: 'Use this flag to save data into a json file',
|
||||||
|
},
|
||||||
|
db: {
|
||||||
|
type: 'boolean',
|
||||||
|
default: true,
|
||||||
|
describe: 'If true, adds data to database',
|
||||||
|
}
|
||||||
|
}).argv
|
||||||
|
|
||||||
|
if ('json' in argv) {
|
||||||
|
console.log('Analysing data...')
|
||||||
|
const rawData = readFileSync(argv.json, { encoding: 'utf-8' })
|
||||||
|
const tokens: Token[] = JSON.parse(rawData)
|
||||||
|
const collection = analyse(tokens)
|
||||||
|
|
||||||
|
if (argv.saveJson) {
|
||||||
|
writeFileSync(
|
||||||
|
'src/data/' + 'collection-rarities.json',
|
||||||
|
JSON.stringify(collection)
|
||||||
|
)
|
||||||
|
console.log(`\nRarity data written in src/data/collection-rarities.json\n`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argv.db) {
|
||||||
|
console.log('\nInitializing database.')
|
||||||
|
|
||||||
|
seed(collection).then(() => {
|
||||||
|
console.log(`\nDatabase initialized.`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
export interface Meta {
|
||||||
|
numTokens: number
|
||||||
|
traitTypes: TraitsMeta[]
|
||||||
|
stats: Stats
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TraitsMeta {
|
||||||
|
trait_type: string
|
||||||
|
attributes: Attribute[]
|
||||||
|
stats: Stats
|
||||||
|
numValues: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Stats {
|
||||||
|
max: number
|
||||||
|
min: number
|
||||||
|
mean: number
|
||||||
|
std: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Collection extends Meta {
|
||||||
|
tokens: TokenWithRarity[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Token = {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
image?: string
|
||||||
|
image_data?: string
|
||||||
|
description?: string
|
||||||
|
attributes: Attribute[]
|
||||||
|
external_url?: string
|
||||||
|
animation_url?: string
|
||||||
|
background_color?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Attribute {
|
||||||
|
trait_type: string
|
||||||
|
value: string
|
||||||
|
rarity_score: number
|
||||||
|
rarity_score_normalized?: number
|
||||||
|
percentile: number
|
||||||
|
count: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RarityFields {
|
||||||
|
rarity_score?: number
|
||||||
|
percentile?: number
|
||||||
|
count?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MissingTrait {
|
||||||
|
trait_type: string
|
||||||
|
rarity_score: number
|
||||||
|
percentile: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TokenWithRarity extends Token {
|
||||||
|
rank: number
|
||||||
|
rarity_score: number
|
||||||
|
rarity_score_normalized: number
|
||||||
|
rank_normalized: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GetMissingTraitIdentifier = (
|
||||||
|
traitType?: string
|
||||||
|
) => string | undefined
|
||||||
|
|
||||||
|
export type Weights = { [traitType: string]: number }
|
||||||
|
|
||||||
|
export interface Config {
|
||||||
|
weights?: Weights
|
||||||
|
getMissingTraitIdentifier?: GetMissingTraitIdentifier
|
||||||
|
attributesFieldName?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AttributeWithRarity = Attribute & RarityFields
|
||||||
|
|
||||||
|
export type IsMissing = <T extends Token = Token>(
|
||||||
|
trait_type: string,
|
||||||
|
token: T
|
||||||
|
) => boolean
|
||||||
|
|
||||||
|
export type GetIsMissing = (
|
||||||
|
getMissingTraitIdentifier: GetMissingTraitIdentifier
|
||||||
|
) => IsMissing
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { GetIsMissing } from './types'
|
||||||
|
|
||||||
|
export const getFileName = (
|
||||||
|
collectionName: string | undefined,
|
||||||
|
postfix?: string
|
||||||
|
) => {
|
||||||
|
return (
|
||||||
|
(collectionName ?? 'collection').split(' ').join('') +
|
||||||
|
(postfix ?? '') +
|
||||||
|
'.json'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param traitType
|
||||||
|
* @param token
|
||||||
|
* @param missingTraitIdentifier Value of the trait type that indicates that it is missing. `undefined` (default) if there is no specific identifier and the {trait_type: string, value: string} entry is simply omitted.
|
||||||
|
* @returns true if the attribute is not found or if the value of the attribute is equal to the missingTraitIdentifier
|
||||||
|
*/
|
||||||
|
export const getIsMissing: GetIsMissing =
|
||||||
|
(missingTraitIdentifierFn) => (traitType, token) => {
|
||||||
|
const attribute = token.attributes.find(
|
||||||
|
(att) => att.trait_type === traitType
|
||||||
|
)
|
||||||
|
return !attribute || attribute.value === missingTraitIdentifierFn(traitType)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const defaultMissingTraitIdentifier = () => undefined
|
||||||
+3
-3
@@ -9,11 +9,11 @@
|
|||||||
"ES6",
|
"ES6",
|
||||||
"ES2020",
|
"ES2020",
|
||||||
"esnext"
|
"esnext"
|
||||||
], /* Specify library files to be included in the compilation. */
|
] /* Specify library files to be included in the compilation. */,
|
||||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||||
// "checkJs": true, /* Report errors in .js files. */
|
// "checkJs": true, /* Report errors in .js files. */
|
||||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
|
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
|
||||||
"declaration": true, /* Generates corresponding '.d.ts' file. */
|
"declaration": true /* Generates corresponding '.d.ts' file. */,
|
||||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */
|
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */
|
||||||
// "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
|
// "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
|
||||||
/* Module Resolution Options */
|
/* Module Resolution Options */
|
||||||
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
"moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
|
||||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||||
|
|||||||
+643
@@ -0,0 +1,643 @@
|
|||||||
|
Arguments:
|
||||||
|
/Users/mikko/.nvm/versions/node/v14.17.0/bin/node /Users/mikko/.nvm/versions/node/v14.17.0/bin/yarn add @graphql-tools
|
||||||
|
|
||||||
|
PATH:
|
||||||
|
/Users/mikko/google-cloud-sdk/bin:/Users/mikko/.nvm/versions/node/v14.17.0/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/mikko/.cargo/bin
|
||||||
|
|
||||||
|
Yarn version:
|
||||||
|
1.22.10
|
||||||
|
|
||||||
|
Node version:
|
||||||
|
14.17.0
|
||||||
|
|
||||||
|
Platform:
|
||||||
|
darwin x64
|
||||||
|
|
||||||
|
Trace:
|
||||||
|
Error: https://registry.yarnpkg.com/@graphql-tools: Request "https://registry.yarnpkg.com/@graphql-tools" returned a 405
|
||||||
|
at Request.params.callback [as _callback] (/Users/mikko/.nvm/versions/node/v14.17.0/lib/node_modules/yarn/lib/cli.js:66997:18)
|
||||||
|
at Request.self.callback (/Users/mikko/.nvm/versions/node/v14.17.0/lib/node_modules/yarn/lib/cli.js:140662:22)
|
||||||
|
at Request.emit (events.js:376:20)
|
||||||
|
at Request.<anonymous> (/Users/mikko/.nvm/versions/node/v14.17.0/lib/node_modules/yarn/lib/cli.js:141634:10)
|
||||||
|
at Request.emit (events.js:376:20)
|
||||||
|
at IncomingMessage.<anonymous> (/Users/mikko/.nvm/versions/node/v14.17.0/lib/node_modules/yarn/lib/cli.js:141556:12)
|
||||||
|
at Object.onceWrapper (events.js:482:28)
|
||||||
|
at IncomingMessage.emit (events.js:388:22)
|
||||||
|
at endReadableNT (internal/streams/readable.js:1336:12)
|
||||||
|
at processTicksAndRejections (internal/process/task_queues.js:82:21)
|
||||||
|
|
||||||
|
npm manifest:
|
||||||
|
{
|
||||||
|
"name": "rarity-analyser",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"author": "mikkoo.eth",
|
||||||
|
"license": "MIT",
|
||||||
|
"private": false,
|
||||||
|
"scripts": {
|
||||||
|
"seed": "npx prisma db seed"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@prisma/client": "^3.0.2",
|
||||||
|
"@types/express": "^4.17.13",
|
||||||
|
"@types/node": "^16.7.13",
|
||||||
|
"express": "^4.17.1",
|
||||||
|
"express-graphql": "^0.12.0",
|
||||||
|
"prisma": "3.0.1",
|
||||||
|
"ts-node": "^10.2.1",
|
||||||
|
"typescript": "^4.4.2"
|
||||||
|
},
|
||||||
|
"prisma": {
|
||||||
|
"seed": "ts-node prisma/seed.ts"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
yarn manifest:
|
||||||
|
No manifest
|
||||||
|
|
||||||
|
Lockfile:
|
||||||
|
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||||
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
"@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.6.1":
|
||||||
|
version "0.6.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.6.1.tgz#118511f316e2e87ee4294761868e254d3da47960"
|
||||||
|
integrity sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg==
|
||||||
|
dependencies:
|
||||||
|
"@cspotcode/source-map-consumer" "0.8.0"
|
||||||
|
|
||||||
|
"@prisma/client@^3.0.2":
|
||||||
|
version "3.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.0.2.tgz#f04d9b252f3d0c6918df43ad228eac27d03f6db1"
|
||||||
|
integrity sha512-6SrDYY2Yr5AmYpVB3XAXFqfzxKMdDTemXR7FmfXthnxWhQHoBwRLNZ3B3GyI/MmWa5tr+kaaGDJjp1LU0vuYvQ==
|
||||||
|
dependencies:
|
||||||
|
"@prisma/engines-version" "2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db"
|
||||||
|
|
||||||
|
"@prisma/engines-version@2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db":
|
||||||
|
version "2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db"
|
||||||
|
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db.tgz#c45323e420f47dd950b22c873bdcf38f75e65779"
|
||||||
|
integrity sha512-iArSApZZImVmT9oC/rGOjzvpG2AOqlIeqYcVnop9poA3FxD4zfVPbNPH9DTgOWhc06OkBHujJZeAcsNddVabIQ==
|
||||||
|
|
||||||
|
"@prisma/engines@2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db":
|
||||||
|
version "2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db"
|
||||||
|
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db.tgz#b6cf70bc05dd2a62168a16f3ea58a1b011074621"
|
||||||
|
integrity sha512-Q9CwN6e5E5Abso7J3A1fHbcF4NXGRINyMnf7WQ07fXaebxTTARY5BNUzy2Mo5uH82eRVO5v7ImNuR044KTjLJg==
|
||||||
|
|
||||||
|
"@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/body-parser@*":
|
||||||
|
version "1.19.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.1.tgz#0c0174c42a7d017b818303d4b5d969cb0b75929c"
|
||||||
|
integrity sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg==
|
||||||
|
dependencies:
|
||||||
|
"@types/connect" "*"
|
||||||
|
"@types/node" "*"
|
||||||
|
|
||||||
|
"@types/connect@*":
|
||||||
|
version "3.4.35"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1"
|
||||||
|
integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
|
||||||
|
"@types/express-serve-static-core@^4.17.18":
|
||||||
|
version "4.17.24"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz#ea41f93bf7e0d59cd5a76665068ed6aab6815c07"
|
||||||
|
integrity sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA==
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
"@types/qs" "*"
|
||||||
|
"@types/range-parser" "*"
|
||||||
|
|
||||||
|
"@types/express@^4.17.13":
|
||||||
|
version "4.17.13"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034"
|
||||||
|
integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==
|
||||||
|
dependencies:
|
||||||
|
"@types/body-parser" "*"
|
||||||
|
"@types/express-serve-static-core" "^4.17.18"
|
||||||
|
"@types/qs" "*"
|
||||||
|
"@types/serve-static" "*"
|
||||||
|
|
||||||
|
"@types/mime@^1":
|
||||||
|
version "1.3.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a"
|
||||||
|
integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==
|
||||||
|
|
||||||
|
"@types/node@*":
|
||||||
|
version "16.9.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.1.tgz#0611b37db4246c937feef529ddcc018cf8e35708"
|
||||||
|
integrity sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==
|
||||||
|
|
||||||
|
"@types/node@^16.7.13":
|
||||||
|
version "16.7.13"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.13.tgz#86fae356b03b5a12f2506c6cf6cd9287b205973f"
|
||||||
|
integrity sha512-pLUPDn+YG3FYEt/pHI74HmnJOWzeR+tOIQzUx93pi9M7D8OE7PSLr97HboXwk5F+JS+TLtWuzCOW97AHjmOXXA==
|
||||||
|
|
||||||
|
"@types/qs@*":
|
||||||
|
version "6.9.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb"
|
||||||
|
integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==
|
||||||
|
|
||||||
|
"@types/range-parser@*":
|
||||||
|
version "1.2.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc"
|
||||||
|
integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==
|
||||||
|
|
||||||
|
"@types/serve-static@*":
|
||||||
|
version "1.13.10"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9"
|
||||||
|
integrity sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==
|
||||||
|
dependencies:
|
||||||
|
"@types/mime" "^1"
|
||||||
|
"@types/node" "*"
|
||||||
|
|
||||||
|
accepts@^1.3.7, 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==
|
||||||
|
dependencies:
|
||||||
|
mime-types "~2.1.24"
|
||||||
|
negotiator "0.6.2"
|
||||||
|
|
||||||
|
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@^8.4.1:
|
||||||
|
version "8.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2"
|
||||||
|
integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==
|
||||||
|
|
||||||
|
arg@^4.1.0:
|
||||||
|
version "4.1.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
|
||||||
|
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
|
||||||
|
|
||||||
|
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=
|
||||||
|
|
||||||
|
body-parser@1.19.0:
|
||||||
|
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"
|
||||||
|
|
||||||
|
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==
|
||||||
|
|
||||||
|
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, 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==
|
||||||
|
|
||||||
|
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==
|
||||||
|
|
||||||
|
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==
|
||||||
|
|
||||||
|
debug@2.6.9:
|
||||||
|
version "2.6.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||||
|
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
|
||||||
|
dependencies:
|
||||||
|
ms "2.0.0"
|
||||||
|
|
||||||
|
depd@~1.1.2:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
|
||||||
|
integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
|
||||||
|
|
||||||
|
destroy@~1.0.4:
|
||||||
|
version "1.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
|
||||||
|
integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
|
||||||
|
|
||||||
|
diff@^4.0.1:
|
||||||
|
version "4.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
|
||||||
|
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
|
||||||
|
|
||||||
|
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=
|
||||||
|
|
||||||
|
encodeurl@~1.0.2:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
|
||||||
|
integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
|
||||||
|
|
||||||
|
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=
|
||||||
|
|
||||||
|
etag@~1.8.1:
|
||||||
|
version "1.8.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
|
||||||
|
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
|
||||||
|
|
||||||
|
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@^4.17.1:
|
||||||
|
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"
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
forwarded@0.2.0:
|
||||||
|
version "0.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
|
||||||
|
integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
|
||||||
|
|
||||||
|
fresh@0.5.2:
|
||||||
|
version "0.5.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
|
||||||
|
integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
|
||||||
|
|
||||||
|
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.3, 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-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"
|
||||||
|
|
||||||
|
iconv-lite@0.4.24:
|
||||||
|
version "0.4.24"
|
||||||
|
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||||
|
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
|
||||||
|
dependencies:
|
||||||
|
safer-buffer ">= 2.1.2 < 3"
|
||||||
|
|
||||||
|
inherits@2.0.3:
|
||||||
|
version "2.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||||
|
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
||||||
|
|
||||||
|
inherits@2.0.4:
|
||||||
|
version "2.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||||
|
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||||
|
|
||||||
|
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==
|
||||||
|
|
||||||
|
make-error@^1.1.1:
|
||||||
|
version "1.3.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
|
||||||
|
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
|
||||||
|
|
||||||
|
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=
|
||||||
|
|
||||||
|
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=
|
||||||
|
|
||||||
|
methods@~1.1.2:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
|
||||||
|
integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
|
||||||
|
|
||||||
|
mime-db@1.49.0:
|
||||||
|
version "1.49.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.49.0.tgz#f3dfde60c99e9cf3bc9701d687778f537001cbed"
|
||||||
|
integrity sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==
|
||||||
|
|
||||||
|
mime-types@~2.1.24:
|
||||||
|
version "2.1.32"
|
||||||
|
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.32.tgz#1d00e89e7de7fe02008db61001d9e02852670fd5"
|
||||||
|
integrity sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==
|
||||||
|
dependencies:
|
||||||
|
mime-db "1.49.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==
|
||||||
|
|
||||||
|
ms@2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||||
|
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
|
||||||
|
|
||||||
|
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==
|
||||||
|
|
||||||
|
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==
|
||||||
|
|
||||||
|
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=
|
||||||
|
dependencies:
|
||||||
|
ee-first "1.1.1"
|
||||||
|
|
||||||
|
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==
|
||||||
|
|
||||||
|
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=
|
||||||
|
|
||||||
|
prisma@3.0.1:
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.0.1.tgz#7f52b6533b562d0bb32e1b74403b146ee6d89029"
|
||||||
|
integrity sha512-ENmYAopd56nkds5/IOSTGixbkbUN2QdEzB4cp/mtaGB/G0OArbP6cnbA/9u02Pe29RdErbNOoIdCGASjpItJwQ==
|
||||||
|
dependencies:
|
||||||
|
"@prisma/engines" "2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db"
|
||||||
|
|
||||||
|
proxy-addr@~2.0.5:
|
||||||
|
version "2.0.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
|
||||||
|
integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
|
||||||
|
dependencies:
|
||||||
|
forwarded "0.2.0"
|
||||||
|
ipaddr.js "1.9.1"
|
||||||
|
|
||||||
|
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==
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
raw-body@^2.4.1:
|
||||||
|
version "2.4.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.1.tgz#30ac82f98bb5ae8c152e67149dac8d55153b168c"
|
||||||
|
integrity sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==
|
||||||
|
dependencies:
|
||||||
|
bytes "3.1.0"
|
||||||
|
http-errors "1.7.3"
|
||||||
|
iconv-lite "0.4.24"
|
||||||
|
unpipe "1.0.0"
|
||||||
|
|
||||||
|
safe-buffer@5.1.2:
|
||||||
|
version "5.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||||
|
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||||
|
|
||||||
|
"safer-buffer@>= 2.1.2 < 3":
|
||||||
|
version "2.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||||
|
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
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==
|
||||||
|
|
||||||
|
"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=
|
||||||
|
|
||||||
|
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==
|
||||||
|
|
||||||
|
ts-node@^10.2.1:
|
||||||
|
version "10.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.2.1.tgz#4cc93bea0a7aba2179497e65bb08ddfc198b3ab5"
|
||||||
|
integrity sha512-hCnyOyuGmD5wHleOQX6NIjJtYVIO8bPP8F2acWkB4W06wdlkgyvJtubO/I9NkI88hCFECbsEgoLc0VNkYmcSfw==
|
||||||
|
dependencies:
|
||||||
|
"@cspotcode/source-map-support" "0.6.1"
|
||||||
|
"@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"
|
||||||
|
yn "3.1.1"
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
typescript@^4.4.2:
|
||||||
|
version "4.4.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.2.tgz#6d618640d430e3569a1dfb44f7d7e600ced3ee86"
|
||||||
|
integrity sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==
|
||||||
|
|
||||||
|
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=
|
||||||
|
|
||||||
|
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=
|
||||||
|
|
||||||
|
vary@~1.1.2:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||||
|
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
|
||||||
|
|
||||||
|
yn@3.1.1:
|
||||||
|
version "3.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
|
||||||
|
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
|
||||||
Reference in New Issue
Block a user