UNPKG

modules-pack

Version:

JavaScript Modules for Modern Frontend & Backend Projects

104 lines (93 loc) 3.98 kB
import { GraphQLScalarType } from 'graphql' import JSON from 'graphql-type-json' import { Kind } from 'graphql/language' import { PERMISSION, PHONE } from 'modules-pack/variables' import { isGoodPassword, isId, isPhoneNumber, LANGUAGE, LANGUAGE_LEVEL } from 'utils-pack' import { toRgbaColor } from 'utils-pack/color' import { toTimestamp } from 'utils-pack/time' import isEmail from 'validator/lib/isEmail' import { gqlDynamicObjType, gqlEnumType, gqlTagLevelType, Response } from './resolver' /** * COMMON TYPE RESOLVERS ======================================================= * ============================================================================= */ const Id = new GraphQLScalarType({ name: 'Id', description: 'Case-Sensitive Id based on Timestamp (can be generated by frontend). Use GQL ID instead, for caching.', serialize: value => value, // value sent to the client parseValue (value) {return this._fromClient(value)}, // note that `null` value does not get parsed by GQL parseLiteral (ast) {return this._fromClient(ast.value)}, }) Id._fromClient = function (value) { if (isId(value)) return value throw Response.badRequest(`Invalid ${this.name} ${value}, must be a valid Case-Sensitive ID based on Timestamp`) } const Timestamp = new GraphQLScalarType({ name: 'Timestamp', description: 'Unix timestamp in `milliseconds`', serialize: toTimestamp, // value sent to the client parseValue: toTimestamp, // value from the client (as variables' interpolation) parseLiteral (ast) { // value from the client (as inline arguments) if (ast.kind === Kind.INT || ast.kind === Kind.STRING) { return toTimestamp(ast.value) // ast.value is always in string format } throw Response.badRequest(`Invalid Timestamp input ${ast.value}, must be numeric string or number`) } }) const Email = new GraphQLScalarType({ name: 'Email', description: 'Email address', serialize: value => value, // value sent to the client parseValue (value) {return this._fromClient(value)}, parseLiteral (ast) {return this._fromClient(ast.value)}, }) Email._fromClient = function (value) { if (isEmail(value)) return value throw Response.badRequest(`Invalid ${this.name} ${value}, must be a valid email address`) } const Password = new GraphQLScalarType({ name: 'Password', description: 'Pass phrase with minimum strength requirements to ensure User has strong password', serialize () {throw Response.badRequest(`${this.name} should not leak!`)}, // (never show password) parseValue (value) {return this._fromClient(value)}, parseLiteral (ast) {return this._fromClient(ast.value)}, }) Password._fromClient = function (value) { if (isGoodPassword(String(value))) return String(value) throw Response.badRequest(`${this.name} is too weak`) } const Permissions = gqlDynamicObjType('Permissions', PERMISSION, Boolean) const Phones = gqlDynamicObjType('Phones', PHONE, String, {validate: isPhoneNumber}) const LanguageCode = gqlEnumType('LanguageCode', LANGUAGE) const LanguageLevel = gqlTagLevelType('LanguageLevel', LANGUAGE, LANGUAGE_LEVEL) const LanguageLevelRange = gqlTagLevelType('LanguageLevelRange', LANGUAGE, LANGUAGE_LEVEL, {range: true}) const Color = new GraphQLScalarType({ name: 'Color', description: 'RGB(A) color code. Example input: String `"150,190,220"` or Array `[150,190,220,0.87]`', serialize: (value) => value, // value sent to the client parseValue (value) {return this._fromClient(value)}, parseLiteral (ast) {return this._fromClient(ast.value)}, }) Color._fromClient = function (value) { const color = toRgbaColor(value) if (color) return color throw Response.badRequest(`Invalid ${this.name} ${value}, must be an RGB(A) array of numbers`) } export default { Id, Timestamp, Email, Password, Permissions, Phones, LanguageCode, LanguageLevel, LanguageLevelRange, Color, JSON, Query: { cursor: (_, __, {res}) => { return res.cursor || {} } } }