Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

nexus-prisma

Package Overview
Dependencies
Maintainers
1
Versions
225
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

nexus-prisma - npm Package Compare versions

Comparing version 0.5.0-next.1 to 0.5.0-next.2

dist/mapping.d.ts

13

dist/builder.d.ts

@@ -13,5 +13,7 @@ import * as Nexus from 'nexus';

}
declare type FieldPublisher = (opts?: FieldPublisherConfig) => PublisherMethods;
declare type PublisherMethods = Record<string, FieldPublisher>;
export interface Options {
types: any;
photon?: (ctx: any) => any;
photon?: (ctx: Nexus.core.GetGen<'context'>) => any;
shouldGenerateArtifacts?: boolean;

@@ -88,4 +90,5 @@ inputs?: {

protected buildModel(): DynamicOutputPropertyDef<"model">;
protected buildArgsFromField(prismaModelName: string, graphQLTypeName: string, operationName: keyof DMMF.Data.Mapping | null, field: DMMF.Data.SchemaField, opts: FieldPublisherConfig): Nexus.core.ArgsRecord;
protected argsFromQueryOrModelField(prismaModelName: string, graphQLTypeName: string, dmmfField: DMMF.Data.SchemaField, opts: FieldPublisherConfig): CustomInputArg[];
protected internalBuildModel(typeName: string, t: Nexus.core.OutputDefinitionBlock<any>): Record<string, FieldPublisher>;
protected buildArgsFromField(typeName: string, operationName: keyof DMMF.Data.Mapping | null, field: DMMF.Data.SchemaField, resolvedConfig: FieldPublisherConfig): Nexus.core.ArgsRecord;
protected argsFromQueryOrModelField(typeName: string, dmmfField: DMMF.Data.SchemaField, resolvedConfig: FieldPublisherConfig): CustomInputArg[];
/**

@@ -111,8 +114,4 @@ * This handles "tailored field feature publishing".

protected handleInputObjectCustomization(fieldWhitelist: Record<string, boolean> | boolean, inputTypeName: string, fieldName: string, graphQLTypeName: string): DMMF.Data.InputType;
/**
* Build the properties on a .model for a given prisma model.
*/
protected buildModelDo(prismaModelName: string, graphQLTypeName: string, t: Nexus.core.OutputDefinitionBlock<any>): Record<string, (opts?: FieldPublisherConfig | undefined) => any>;
}
export {};
//# sourceMappingURL=builder.d.ts.map

@@ -14,5 +14,5 @@ "use strict";

const GraphQL = __importStar(require("./graphql"));
const mapping_1 = require("./mapping");
const naming_strategies_1 = require("./naming-strategies");
const publisher_1 = require("./publisher");
const supported_ops_1 = require("./supported-ops");
const Typegen = __importStar(require("./typegen"));

@@ -103,56 +103,29 @@ const utils_1 = require("./utils");

// Nexus should improve the type of typeName to be AllOutputTypes
factory: ({ typeDef: t, typeName: gqlTypeName }) => {
if (gqlTypeName === GraphQL.rootNames.Subscription) {
factory: ({ typeDef: t, typeName }) => {
if (typeName === GraphQL.rootNames.Subscription) {
// TODO Lets put a GitHub issue link in this error message
throw new Error(`t.crud is not yet supported on the 'Subscription' type.`);
}
if (gqlTypeName !== GraphQL.rootNames.Query &&
gqlTypeName !== GraphQL.rootNames.Mutation) {
throw new Error(`t.crud can only be used on GraphQL root types 'Query' & 'Mutation' but was used on '${gqlTypeName}'. Please use 't.model' instead`);
if (typeName !== GraphQL.rootNames.Query &&
typeName !== GraphQL.rootNames.Mutation) {
throw new Error(`t.crud can only be used on GraphQL root types 'Query' & 'Mutation' but was used on '${typeName}'. Please use 't.model' instead`);
}
const mappedFields = gqlTypeName === 'Query'
? this.dmmf.mappings.map(mapping => {
const queriesNames = supported_ops_1.getSupportedQueries(mapping);
return {
fields: this.dmmf.queryObject.fields.filter(query => queriesNames.includes(query.name)),
mapping,
};
})
: gqlTypeName === 'Mutation'
? this.dmmf.mappings.map(mapping => {
const mutationsNames = supported_ops_1.getSupportedMutations(mapping);
return {
fields: this.dmmf.mutationObject.fields.filter(mutation => mutationsNames.includes(mutation.name)),
mapping,
};
})
: undefined;
return mappedFields.reduce((crud, mappedField) => {
const prismaModelName = mappedField.mapping.model;
mappedField.fields.forEach(field => {
const mappedFieldName = utils_1.getCRUDFieldName(prismaModelName, field.name, mappedField.mapping, this.fieldNamingStrategy);
const fieldPublisher = givenConfig => {
const resolvedConfig = Object.assign({ pagination: true, type: field.outputType.type }, givenConfig);
const gqlFieldName = resolvedConfig.alias
? resolvedConfig.alias
: mappedFieldName;
const operationName = Object.keys(mappedField.mapping).find(key => mappedField.mapping[key] === field.name);
if (!operationName) {
throw new Error(`Could not find operation name for field ${field.name}`);
}
t.field(gqlFieldName, {
type: this.publisher.outputType(resolvedConfig.type, field),
list: field.outputType.isList || undefined,
nullable: !field.outputType.isRequired,
args: this.buildArgsFromField(prismaModelName, gqlTypeName, operationName, field, resolvedConfig),
resolve: (_parent, args, ctx) => {
const photon = this.getPhoton(ctx);
utils_1.assertPhotonInContext(photon);
return photon[mappedField.mapping.plural][operationName](args);
},
});
return crud;
};
crud[mappedFieldName] = fieldPublisher;
});
return mapping_1.getCrudMappedFields(typeName, this.dmmf).reduce((crud, mappedField) => {
const fieldPublisher = givenConfig => {
const resolvedConfig = Object.assign({ pagination: true, type: mappedField.field.outputType.type }, givenConfig);
const gqlFieldName = resolvedConfig.alias || mappedField.field.name;
t.field(gqlFieldName, {
type: this.publisher.outputType(resolvedConfig.type, mappedField.field),
list: mappedField.field.outputType.isList || undefined,
nullable: !mappedField.field.outputType.isRequired,
args: this.buildArgsFromField(typeName, mappedField.operation, mappedField.field, resolvedConfig),
resolve: (_parent, args, ctx) => {
const photon = this.getPhoton(ctx);
utils_1.assertPhotonInContext(photon);
return photon[mappedField.photonAccessor][mappedField.operation](args);
},
});
return crud;
};
crud[mappedField.field.name] = fieldPublisher;
return crud;

@@ -215,9 +188,40 @@ }, {});

factory: ({ typeDef, typeName }) => this.dmmf.hasModel(typeName)
? this.buildModelDo(typeName, typeName, typeDef)
: (modelName) => this.buildModelDo(modelName, modelName, typeDef),
? this.internalBuildModel(typeName, typeDef)
: (modelName) => this.internalBuildModel(modelName, typeDef),
});
}
buildArgsFromField(prismaModelName, graphQLTypeName, operationName, field, opts) {
internalBuildModel(typeName, t) {
const model = this.dmmf.getModelOrThrow(typeName);
const outputType = this.dmmf.getOutputType(model.name);
const publishers = outputType.fields.reduce((acc, field) => {
const fieldPublisher = givenConfig => {
const resolvedConfig = Object.assign({ pagination: true, type: field.outputType.type }, givenConfig);
const fieldName = resolvedConfig.alias || field.name;
const type = resolvedConfig.type || field.outputType.type;
const fieldOpts = {
type: this.publisher.outputType(type, field),
list: field.outputType.isList || undefined,
nullable: !field.outputType.isRequired,
args: this.buildArgsFromField(typeName, null, field, resolvedConfig),
};
// Rely on default resolvers for scalars and enums
if (field.outputType.kind === 'object') {
const mapping = this.dmmf.getMapping(typeName);
fieldOpts.resolve = (root, args, ctx) => {
const photon = this.getPhoton(ctx);
utils_1.assertPhotonInContext(photon);
return photon[mapping.plural]['findOne']({ where: { id: root.id } })[field.name](args);
};
}
t.field(fieldName, fieldOpts);
return publishers;
};
acc[field.name] = fieldPublisher;
return acc;
}, {});
return publishers;
}
buildArgsFromField(typeName, operationName, field, resolvedConfig) {
let args = [];
if (graphQLTypeName === 'Mutation' || operationName === 'findOne') {
if (typeName === 'Mutation' || operationName === 'findOne') {
args = field.args.map(arg => ({

@@ -229,3 +233,3 @@ arg,

else {
args = this.argsFromQueryOrModelField(prismaModelName, graphQLTypeName, field, opts);
args = this.argsFromQueryOrModelField(typeName, field, resolvedConfig);
}

@@ -237,31 +241,31 @@ return args.reduce((acc, customArg) => {

}
argsFromQueryOrModelField(prismaModelName, graphQLTypeName, dmmfField, opts) {
argsFromQueryOrModelField(typeName, dmmfField, resolvedConfig) {
let args = [];
if (opts.filtering) {
if (resolvedConfig.filtering) {
const inputObjectTypeDefName = `${dmmfField.outputType.type}WhereInput`;
const whereArg = dmmfField.args.find(arg => arg.inputType.type === inputObjectTypeDefName && arg.name === 'where');
if (!whereArg) {
throw new Error(`Could not find filtering argument for ${prismaModelName}.${dmmfField.name}`);
throw new Error(`Could not find filtering argument for ${typeName}.${dmmfField.name}`);
}
args.push({
arg: whereArg,
type: this.handleInputObjectCustomization(opts.filtering, inputObjectTypeDefName, dmmfField.name, graphQLTypeName),
type: this.handleInputObjectCustomization(resolvedConfig.filtering, inputObjectTypeDefName, dmmfField.name, typeName),
});
}
if (opts.ordering) {
if (resolvedConfig.ordering) {
const orderByTypeName = `${dmmfField.outputType.type}OrderByInput`;
const orderByArg = dmmfField.args.find(arg => arg.inputType.type === orderByTypeName && arg.name === 'orderBy');
if (!orderByArg) {
throw new Error(`Could not find ordering argument for ${prismaModelName}.${dmmfField.name}`);
throw new Error(`Could not find ordering argument for ${typeName}.${dmmfField.name}`);
}
args.push({
arg: orderByArg,
type: this.handleInputObjectCustomization(opts.ordering, orderByTypeName, dmmfField.name, graphQLTypeName),
type: this.handleInputObjectCustomization(resolvedConfig.ordering, orderByTypeName, dmmfField.name, typeName),
});
}
if (opts.pagination) {
if (resolvedConfig.pagination) {
const paginationKeys = ['first', 'last', 'before', 'after', 'skip'];
const paginationsArgs = opts.pagination === true
const paginationsArgs = resolvedConfig.pagination === true
? dmmfField.args.filter(a => paginationKeys.includes(a.name))
: dmmfField.args.filter(arg => opts.pagination[arg.name] === true);
: dmmfField.args.filter(arg => resolvedConfig.pagination[arg.name] === true);
args.push(...paginationsArgs.map(a => ({

@@ -310,38 +314,4 @@ arg: a,

}
/**
* Build the properties on a .model for a given prisma model.
*/
buildModelDo(prismaModelName, graphQLTypeName, t) {
const model = this.dmmf.getModelOrThrow(prismaModelName);
const outputType = this.dmmf.getOutputType(model.name);
const seed = {};
const result = outputType.fields.reduce((acc, graphqlField) => {
acc[graphqlField.name] = opts => {
if (!opts) {
opts = {};
}
if (opts.pagination === undefined) {
opts.pagination = true;
}
const fieldName = opts.alias ? opts.alias : graphqlField.name;
const type = opts.type ? opts.type : graphqlField.outputType.type;
const fieldOpts = Object.assign(Object.assign({}, utils_1.nexusFieldOpts(Object.assign(Object.assign({}, graphqlField.outputType), { type: this.publisher.outputType(type, graphqlField) }))), { args: this.buildArgsFromField(prismaModelName, graphQLTypeName, null, graphqlField, opts) });
// Rely on default resolvers for scalars and enums
if (graphqlField.outputType.kind === 'object') {
const mapping = this.dmmf.getMapping(prismaModelName);
fieldOpts.resolve = (root, args, ctx) => {
const photon = this.getPhoton(ctx);
utils_1.assertPhotonInContext(photon);
return photon[mapping.plural]['findOne']({ where: { id: root.id } })[graphqlField.name](args);
};
}
t.field(fieldName, fieldOpts);
return result;
};
return acc;
}, seed);
return result;
}
}
exports.SchemaBuilder = SchemaBuilder;
//# sourceMappingURL=builder.js.map

@@ -7,6 +7,7 @@ import { ExternalDMMF as DMMF } from './transformer';

mappings: DMMF.Mapping[];
queryObject: DMMF.OutputType;
mutationObject: DMMF.OutputType;
queryObject: OutputType;
mutationObject: OutputType;
outputTypesIndex: Index<DMMF.OutputType>;
inputTypesIndex: Index<DMMF.InputType>;
mappingsIndex: Index<DMMF.Mapping>;
enumsIndex: Index<DMMF.Enum>;

@@ -16,3 +17,3 @@ modelsIndex: Index<DMMF.Model>;

getInputType(inputTypeName: string): DMMF.InputType;
getOutputType(outputTypeName: string): DMMF.OutputType;
getOutputType(outputTypeName: string): OutputType;
hasOutputType(outputTypeName: string): boolean;

@@ -25,2 +26,10 @@ getEnumType(enumTypeName: string): DMMF.Enum;

}
export declare class OutputType {
protected outputType: DMMF.OutputType;
name: string;
fields: DMMF.SchemaField[];
isEmbedded?: boolean;
constructor(outputType: DMMF.OutputType);
getField(fieldName: string): DMMF.SchemaField;
}
//# sourceMappingURL=DMMFClass.d.ts.map

@@ -11,5 +11,2 @@ "use strict";

this.mappings = mappings;
// Entrypoints
this.queryObject = schema.outputTypes.find(t => t.name === 'Query');
this.mutationObject = schema.outputTypes.find(t => t.name === 'Mutation');
// Indices

@@ -20,2 +17,6 @@ this.modelsIndex = utils_1.indexBy('name', datamodel.models);

this.outputTypesIndex = utils_1.indexBy('name', schema.outputTypes);
this.mappingsIndex = utils_1.indexBy('model', mappings);
// Entrypoints
this.queryObject = this.getOutputType('Query');
this.mutationObject = this.getOutputType('Mutation');
}

@@ -34,3 +35,3 @@ getInputType(inputTypeName) {

}
return outputType;
return new OutputType(outputType);
}

@@ -73,3 +74,3 @@ hasOutputType(outputTypeName) {

getMapping(modelName) {
const mapping = this.mappings.find(m => m.model === modelName);
const mapping = this.mappingsIndex[modelName];
if (!mapping) {

@@ -82,2 +83,18 @@ throw new Error('Could not find mapping for model: ' + modelName);

exports.DMMFClass = DMMFClass;
class OutputType {
constructor(outputType) {
this.outputType = outputType;
this.name = outputType.name;
this.fields = outputType.fields;
this.isEmbedded = outputType.isEmbedded;
}
getField(fieldName) {
const field = this.outputType.fields.find(f => f.name === fieldName);
if (!field) {
throw new Error(`Could not find field field '${fieldName}' on type ${this.outputType.name}`);
}
return field;
}
}
exports.OutputType = OutputType;
//# sourceMappingURL=DMMFClass.js.map

@@ -87,11 +87,11 @@ import * as Nexus from 'nexus';

model: string;
plural?: string;
findOne?: string;
findMany?: string;
create?: string;
update?: string;
updateMany?: string;
upsert?: string;
delete?: string;
deleteMany?: string;
plural: string;
findOne: string;
findMany: string;
create: string;
update: string;
updateMany: string;
upsert: string;
delete: string;
deleteMany: string;
}

@@ -98,0 +98,0 @@ enum ModelAction {

@@ -10,6 +10,9 @@ import * as Nexus from 'nexus';

outputType(outputTypeName: string, field: DMMF.Data.SchemaField): any;
protected publishObject(name: string): Nexus.core.NexusObjectTypeDef<string>;
protected publishScalar(typeName: string): string | Nexus.core.NexusScalarTypeDef<string>;
protected publishEnum(typeName: string): Nexus.core.NexusEnumTypeDef<string>;
protected publishInputObjectType(inputType: DMMF.Data.InputType): Nexus.core.NexusInputObjectTypeDef<string>;
protected getTypeFromArg(arg: DMMF.Data.SchemaArg): DMMF.Data.Enum | DMMF.Data.InputType | DMMF.Data.OutputType;
protected getTypeFromArg(arg: DMMF.Data.SchemaArg): {
name: string;
};
protected isPublished(typeName: string): boolean;

@@ -16,0 +19,0 @@ protected markTypeAsPublished(typeName: string): void;

@@ -22,3 +22,3 @@ "use strict";

if (this.isPublished(typeName)) {
return Nexus.arg(utils_1.nexusFieldOpts(Object.assign(Object.assign({}, customArg.arg.inputType), { type: customArg.type.name })));
return Nexus.arg(utils_1.dmmfFieldToNexusFieldConfig(Object.assign(Object.assign({}, customArg.arg.inputType), { type: customArg.type.name })));
}

@@ -42,3 +42,3 @@ if (customArg.arg.inputType.kind === 'scalar') {

if (field.outputType.kind === 'object') {
return outputTypeName;
return this.publishObject(outputTypeName);
}

@@ -53,2 +53,14 @@ if (this.dmmf.hasEnumType(outputTypeName)) {

}
publishObject(name) {
this.markTypeAsPublished(name);
const dmmfObject = this.dmmf.getOutputType(name);
return Nexus.objectType({
name,
definition: t => {
for (const field of dmmfObject.fields) {
t.field(field.name, utils_1.dmmfFieldToNexusFieldConfig(field.outputType));
}
},
});
}
publishScalar(typeName) {

@@ -67,7 +79,7 @@ if (graphql_1.scalarsNameValues.includes(typeName)) {

publishEnum(typeName) {
const eType = this.dmmf.getEnumType(typeName);
const dmmfEnum = this.dmmf.getEnumType(typeName);
this.markTypeAsPublished(typeName);
return Nexus.enumType({
name: typeName,
members: eType.values,
members: dmmfEnum.values,
});

@@ -89,3 +101,3 @@ }

[...scalarFields, ...remappedObjectFields].forEach(field => {
t.field(field.name, utils_1.nexusFieldOpts(field.inputType));
t.field(field.name, utils_1.dmmfFieldToNexusFieldConfig(field.inputType));
});

@@ -97,3 +109,5 @@ },

const kindToType = {
scalar: (typeName) => this.dmmf.getOutputType(typeName),
scalar: (typeName) => ({
name: this.dmmf.getOutputType(typeName).name,
}),
enum: (typeName) => this.dmmf.getEnumType(typeName),

@@ -100,0 +114,0 @@ object: (typeName) => this.dmmf.getInputType(typeName),

@@ -10,8 +10,7 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
const supported_ops_1 = require("./supported-ops");
const utils_1 = require("./utils");
const naming_strategies_1 = require("./naming-strategies");
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const DMMF = __importStar(require("./dmmf"));
const mapping_1 = require("./mapping");
const naming_strategies_1 = require("./naming-strategies");
function generateSync(options) {

@@ -69,24 +68,10 @@ doGenerate(true, options);

function renderNexusPrismaTypes(dmmf) {
const queryFieldsWithMapping = dmmf.mappings.map(mapping => {
const queriesNames = supported_ops_1.getSupportedQueries(mapping);
return {
fields: dmmf.queryObject.fields.filter(query => queriesNames.includes(query.name)),
mapping,
};
});
const queriesByType = utils_1.flatMap(queryFieldsWithMapping, ({ fields, mapping }) => fields.map(field => ({
fieldName: utils_1.getCRUDFieldName(mapping.model, field.name, mapping, naming_strategies_1.defaultFieldNamingStrategy),
returnType: field.outputType.type,
})));
const mutationsFieldsWithMapping = dmmf.mappings.map(mapping => {
const mutationsNames = supported_ops_1.getSupportedMutations(mapping);
return {
fields: dmmf.mutationObject.fields.filter(mutation => mutationsNames.includes(mutation.name)),
mapping,
};
});
const mutationsByType = utils_1.flatMap(mutationsFieldsWithMapping, ({ fields, mapping }) => fields.map(field => ({
fieldName: utils_1.getCRUDFieldName(mapping.model, field.name, mapping, naming_strategies_1.defaultFieldNamingStrategy),
returnType: field.outputType.type,
})));
const queriesByType = mapping_1.getCrudMappedFields('Query', dmmf).map(mappedfield => ({
fieldName: mappedfield.field.name,
returnType: mappedfield.field.outputType.type,
}));
const mutationsByType = mapping_1.getCrudMappedFields('Mutation', dmmf).map(mappedField => ({
fieldName: mappedField.field.name,
returnType: mappedField.field.outputType.type,
}));
const fieldsByType = dmmf.datamodel.models.reduce((acc, m) => {

@@ -118,24 +103,18 @@ acc[m.name] = m.fields.map(f => ({

function renderNexusPrismaInputs(dmmf) {
const queryFieldsWithMapping = dmmf.mappings.map(mapping => {
const queriesNames = supported_ops_1.getSupportedQueries(mapping);
return {
fields: dmmf.queryObject.fields
.filter(query => queriesNames.includes(query.name))
.filter(q => q.outputType.isList && q.outputType.kind === 'object'),
mapping,
};
});
const queriesFields = utils_1.flatMap(queryFieldsWithMapping, ({ fields, mapping }) => fields.map(field => {
const whereArg = field.args.find(a => a.name === 'where');
const orderByArg = field.args.find(a => a.name === 'orderBy');
const queriesFields = mapping_1.getCrudMappedFields('Query', dmmf)
.filter(mappedField => mappedField.field.outputType.isList &&
mappedField.field.outputType.kind === 'object')
.map(mappedField => {
const whereArg = mappedField.field.args.find(a => a.name === 'where');
const orderByArg = mappedField.field.args.find(a => a.name === 'orderBy');
const whereInput = dmmf.schema.inputTypes.find(i => i.name === whereArg.inputType.type);
const orderByInput = dmmf.schema.inputTypes.find(i => i.name === orderByArg.inputType.type);
return {
fieldName: utils_1.getCRUDFieldName(mapping.model, field.name, mapping, naming_strategies_1.defaultFieldNamingStrategy),
fieldName: naming_strategies_1.defaultFieldNamingStrategy[mappedField.operation](mappedField.field.name, mappedField.model),
filtering: whereInput,
ordering: orderByInput,
};
}));
});
const fieldsByType = dmmf.datamodel.models
.map(m => dmmf.schema.outputTypes.find(o => o.name === m.name))
.map(m => dmmf.getOutputType(m.name))
.reduce((acc, type) => {

@@ -190,3 +169,3 @@ acc[type.name] = type.fields

return `\
type ModelNameExistsInGraphQLType<
type IsModelNameExistsInGraphQLTypes<
ReturnType extends any

@@ -212,2 +191,5 @@ > = ReturnType extends core.GetGen<'objectNames'> ? true : false;

/**
* Determine if \`B\` is a subset (or equivalent to) of \`A\`.
*/
type IsSubset<A, B> = keyof A extends never

@@ -241,3 +223,3 @@ ? false

type DynamicRequiredType<ReturnType extends any> = ModelNameExistsInGraphQLType<
type DynamicRequiredType<ReturnType extends any> = IsModelNameExistsInGraphQLTypes<
ReturnType

@@ -313,3 +295,3 @@ > extends true

? (opts?: NexusPrismaScalarOpts) => NexusPrismaFields<ModelName> // Return optional scalar opts
: ModelNameExistsInGraphQLType<ReturnType> extends true // If model name has a mapped graphql types
: IsModelNameExistsInGraphQLTypes<ReturnType> extends true // If model name has a mapped graphql types
? (

@@ -316,0 +298,0 @@ opts?: NexusPrismaRelationOpts<ModelName, MethodName, ReturnType>

@@ -1,3 +0,1 @@

import * as DMMF from './dmmf';
import { FieldNamingStrategy } from './naming-strategies';
/**

@@ -10,3 +8,3 @@ * TODO

export declare function flatMap<T, U>(array: T[], callbackfn: (value: T, index: number, array: T[]) => U[]): U[];
export declare function nexusFieldOpts(param: {
export declare function dmmfFieldToNexusFieldConfig(param: {
type: string | object;

@@ -23,3 +21,2 @@ isList: boolean;

export declare function getImportPathRelativeToOutput(from: string, to: string): string;
export declare function getCRUDFieldName(modelName: string, fieldName: string, mapping: DMMF.Data.Mapping, namingStrategy: FieldNamingStrategy): string;
/**

@@ -26,0 +23,0 @@ * Unwrap nexus user-defined types and convert them to a map<TypeName, boolean>

@@ -46,3 +46,3 @@ "use strict";

exports.flatMap = flatMap;
function nexusFieldOpts(param) {
function dmmfFieldToNexusFieldConfig(param) {
return {

@@ -54,3 +54,3 @@ type: param.type,

}
exports.nexusFieldOpts = nexusFieldOpts;
exports.dmmfFieldToNexusFieldConfig = dmmfFieldToNexusFieldConfig;
function assertPhotonInContext(photon) {

@@ -86,10 +86,2 @@ if (!photon) {

exports.getImportPathRelativeToOutput = getImportPathRelativeToOutput;
function getCRUDFieldName(modelName, fieldName, mapping, namingStrategy) {
const operationName = Object.keys(mapping).find(key => mapping[key] === fieldName);
if (!operationName || !namingStrategy[operationName]) {
throw new Error(`Could not find mapping for field ${fieldName}`);
}
return namingStrategy[operationName](fieldName, modelName);
}
exports.getCRUDFieldName = getCRUDFieldName;
/**

@@ -96,0 +88,0 @@ * Unwrap nexus user-defined types and convert them to a map<TypeName, boolean>

{
"name": "nexus-prisma",
"version": "0.5.0-next.1",
"version": "0.5.0-next.2",
"main": "dist/index.js",

@@ -17,3 +17,3 @@ "types": "dist/index.d.ts",

"prepublishOnly": "yarn -s build",
"style": "prettier --write src/**/*.ts test/**/*.ts example/**/*.ts",
"style": "prettier --write 'src/**/*.ts' 'test/**/*.ts' 'example/**/*.ts'",
"test": "jest"

@@ -20,0 +20,0 @@ },

@@ -6,17 +6,12 @@ import * as Nexus from 'nexus'

import * as GraphQL from './graphql'
import { getCrudMappedFields } from './mapping'
import {
ArgsNamingStrategy,
defaultArgsNamingStrategy,
defaultFieldNamingStrategy,
ArgsNamingStrategy,
FieldNamingStrategy,
} from './naming-strategies'
import { Publisher } from './publisher'
import { getSupportedMutations, getSupportedQueries } from './supported-ops'
import * as Typegen from './typegen'
import {
assertPhotonInContext,
getCRUDFieldName,
nexusFieldOpts,
unwrapTypes,
} from './utils'
import { assertPhotonInContext, unwrapTypes } from './utils'

@@ -31,5 +26,8 @@ interface FieldPublisherConfig {

type FieldPublisher = (opts?: FieldPublisherConfig) => PublisherMethods // Fluent API
type PublisherMethods = Record<string, FieldPublisher>
export interface Options {
types: any
photon?: (ctx: any) => any
photon?: (ctx: Nexus.core.GetGen<'context'>) => any
shouldGenerateArtifacts?: boolean

@@ -155,4 +153,4 @@ inputs?: {

// Nexus should improve the type of typeName to be AllOutputTypes
factory: ({ typeDef: t, typeName: gqlTypeName }) => {
if (gqlTypeName === GraphQL.rootNames.Subscription) {
factory: ({ typeDef: t, typeName }) => {
if (typeName === GraphQL.rootNames.Subscription) {
// TODO Lets put a GitHub issue link in this error message

@@ -165,90 +163,47 @@ throw new Error(

if (
gqlTypeName !== GraphQL.rootNames.Query &&
gqlTypeName !== GraphQL.rootNames.Mutation
typeName !== GraphQL.rootNames.Query &&
typeName !== GraphQL.rootNames.Mutation
) {
throw new Error(
`t.crud can only be used on GraphQL root types 'Query' & 'Mutation' but was used on '${gqlTypeName}'. Please use 't.model' instead`,
`t.crud can only be used on GraphQL root types 'Query' & 'Mutation' but was used on '${typeName}'. Please use 't.model' instead`,
)
}
return getCrudMappedFields(typeName, this.dmmf).reduce<
PublisherMethods
>((crud, mappedField) => {
const fieldPublisher: FieldPublisher = givenConfig => {
const resolvedConfig: FieldPublisherConfig = {
pagination: true,
type: mappedField.field.outputType.type,
...givenConfig,
}
const gqlFieldName = resolvedConfig.alias || mappedField.field.name
const mappedFields =
gqlTypeName === 'Query'
? this.dmmf.mappings.map(mapping => {
const queriesNames = getSupportedQueries(mapping)
return {
fields: this.dmmf.queryObject.fields.filter(query =>
queriesNames.includes(query.name),
),
mapping,
}
})
: gqlTypeName === 'Mutation'
? this.dmmf.mappings.map(mapping => {
const mutationsNames = getSupportedMutations(mapping)
return {
fields: this.dmmf.mutationObject.fields.filter(mutation =>
mutationsNames.includes(mutation.name),
),
mapping,
}
})
: (undefined as never)
t.field(gqlFieldName, {
type: this.publisher.outputType(
resolvedConfig.type!,
mappedField.field,
),
list: mappedField.field.outputType.isList || undefined,
nullable: !mappedField.field.outputType.isRequired,
args: this.buildArgsFromField(
typeName,
mappedField.operation,
mappedField.field,
resolvedConfig,
),
resolve: (_parent, args, ctx) => {
const photon = this.getPhoton(ctx)
assertPhotonInContext(photon)
return photon[mappedField.photonAccessor][
mappedField.operation
](args)
},
})
type FieldPublisher = (opts?: FieldPublisherConfig) => CRUDMethods // Fluent API
type CRUDMethods = Record<string, FieldPublisher>
return crud
}
return mappedFields.reduce<CRUDMethods>((crud, mappedField) => {
const prismaModelName = mappedField.mapping.model
crud[mappedField.field.name] = fieldPublisher
mappedField.fields.forEach(field => {
const mappedFieldName = getCRUDFieldName(
prismaModelName,
field.name,
mappedField.mapping,
this.fieldNamingStrategy,
)
const fieldPublisher: FieldPublisher = givenConfig => {
const resolvedConfig: FieldPublisherConfig = {
pagination: true,
type: field.outputType.type,
...givenConfig,
}
const gqlFieldName = resolvedConfig.alias
? resolvedConfig.alias
: mappedFieldName
const operationName = Object.keys(mappedField.mapping).find(
key => (mappedField.mapping as any)[key] === field.name,
) as keyof DMMF.Data.Mapping | undefined
if (!operationName) {
throw new Error(
`Could not find operation name for field ${field.name}`,
)
}
t.field(gqlFieldName, {
type: this.publisher.outputType(resolvedConfig.type!, field),
list: field.outputType.isList || undefined,
nullable: !field.outputType.isRequired,
args: this.buildArgsFromField(
prismaModelName,
gqlTypeName,
operationName,
field,
resolvedConfig,
),
resolve: (_parent, args, ctx) => {
const photon = this.getPhoton(ctx)
assertPhotonInContext(photon)
return photon[mappedField.mapping.plural!][operationName](
args,
)
},
})
return crud
}
crud[mappedFieldName] = fieldPublisher
})
return crud

@@ -313,18 +268,73 @@ }, {})

this.dmmf.hasModel(typeName)
? this.buildModelDo(typeName, typeName, typeDef)
: (modelName: string) =>
this.buildModelDo(modelName, modelName, typeDef),
? this.internalBuildModel(typeName, typeDef)
: (modelName: string) => this.internalBuildModel(modelName, typeDef),
})
}
protected internalBuildModel(
typeName: string,
t: Nexus.core.OutputDefinitionBlock<any>,
) {
const model = this.dmmf.getModelOrThrow(typeName)
const outputType = this.dmmf.getOutputType(model.name)
const publishers = outputType.fields.reduce<PublisherMethods>(
(acc, field) => {
const fieldPublisher: FieldPublisher = givenConfig => {
const resolvedConfig: FieldPublisherConfig = {
pagination: true,
type: field.outputType.type,
...givenConfig,
}
const fieldName = resolvedConfig.alias || field.name
const type = resolvedConfig.type || field.outputType.type
const fieldOpts: Nexus.core.NexusOutputFieldConfig<any, string> = {
type: this.publisher.outputType(type, field),
list: field.outputType.isList || undefined,
nullable: !field.outputType.isRequired,
args: this.buildArgsFromField(
typeName,
null,
field,
resolvedConfig,
),
}
// Rely on default resolvers for scalars and enums
if (field.outputType.kind === 'object') {
const mapping = this.dmmf.getMapping(typeName)
fieldOpts.resolve = (root, args, ctx) => {
const photon = this.getPhoton(ctx)
assertPhotonInContext(photon)
return photon[mapping.plural!]
['findOne']({ where: { id: root.id } })
[field.name](args)
}
}
t.field(fieldName, fieldOpts)
return publishers
}
acc[field.name] = fieldPublisher
return acc
},
{},
)
return publishers
}
protected buildArgsFromField(
prismaModelName: string,
graphQLTypeName: string,
typeName: string,
operationName: keyof DMMF.Data.Mapping | null,
field: DMMF.Data.SchemaField,
opts: FieldPublisherConfig,
resolvedConfig: FieldPublisherConfig,
): Nexus.core.ArgsRecord {
let args: CustomInputArg[] = []
if (graphQLTypeName === 'Mutation' || operationName === 'findOne') {
if (typeName === 'Mutation' || operationName === 'findOne') {
args = field.args.map(arg => ({

@@ -335,8 +345,3 @@ arg,

} else {
args = this.argsFromQueryOrModelField(
prismaModelName,
graphQLTypeName,
field,
opts,
)
args = this.argsFromQueryOrModelField(typeName, field, resolvedConfig)
}

@@ -346,2 +351,3 @@

acc[customArg.arg.name] = this.publisher.inputType(customArg) as any //FIXME
return acc

@@ -352,10 +358,9 @@ }, {})

protected argsFromQueryOrModelField(
prismaModelName: string,
graphQLTypeName: string,
typeName: string,
dmmfField: DMMF.Data.SchemaField,
opts: FieldPublisherConfig,
resolvedConfig: FieldPublisherConfig,
) {
let args: CustomInputArg[] = []
if (opts.filtering) {
if (resolvedConfig.filtering) {
const inputObjectTypeDefName = `${dmmfField.outputType.type}WhereInput`

@@ -369,3 +374,3 @@ const whereArg = dmmfField.args.find(

throw new Error(
`Could not find filtering argument for ${prismaModelName}.${dmmfField.name}`,
`Could not find filtering argument for ${typeName}.${dmmfField.name}`,
)

@@ -377,6 +382,6 @@ }

type: this.handleInputObjectCustomization(
opts.filtering,
resolvedConfig.filtering,
inputObjectTypeDefName,
dmmfField.name,
graphQLTypeName,
typeName,
),

@@ -386,3 +391,3 @@ })

if (opts.ordering) {
if (resolvedConfig.ordering) {
const orderByTypeName = `${dmmfField.outputType.type}OrderByInput`

@@ -395,3 +400,3 @@ const orderByArg = dmmfField.args.find(

throw new Error(
`Could not find ordering argument for ${prismaModelName}.${dmmfField.name}`,
`Could not find ordering argument for ${typeName}.${dmmfField.name}`,
)

@@ -403,6 +408,6 @@ }

type: this.handleInputObjectCustomization(
opts.ordering,
resolvedConfig.ordering,
orderByTypeName,
dmmfField.name,
graphQLTypeName,
typeName,
),

@@ -412,9 +417,9 @@ })

if (opts.pagination) {
if (resolvedConfig.pagination) {
const paginationKeys = ['first', 'last', 'before', 'after', 'skip']
const paginationsArgs =
opts.pagination === true
resolvedConfig.pagination === true
? dmmfField.args.filter(a => paginationKeys.includes(a.name))
: dmmfField.args.filter(
arg => (opts.pagination as any)[arg.name] === true,
arg => (resolvedConfig.pagination as any)[arg.name] === true,
)

@@ -484,62 +489,2 @@

}
/**
* Build the properties on a .model for a given prisma model.
*/
protected buildModelDo(
prismaModelName: string,
graphQLTypeName: string,
t: Nexus.core.OutputDefinitionBlock<any>,
) {
const model = this.dmmf.getModelOrThrow(prismaModelName)
const outputType = this.dmmf.getOutputType(model.name)
const seed: Record<string, (opts?: FieldPublisherConfig) => any> = {}
const result = outputType.fields.reduce((acc, graphqlField) => {
acc[graphqlField.name] = opts => {
if (!opts) {
opts = {}
}
if (opts.pagination === undefined) {
opts.pagination = true
}
const fieldName = opts.alias ? opts.alias : graphqlField.name
const type = opts.type ? opts.type : graphqlField.outputType.type
const fieldOpts: Nexus.core.NexusOutputFieldConfig<any, string> = {
...nexusFieldOpts({
...graphqlField.outputType,
type: this.publisher.outputType(type, graphqlField),
}),
args: this.buildArgsFromField(
prismaModelName,
graphQLTypeName,
null,
graphqlField,
opts,
),
}
// Rely on default resolvers for scalars and enums
if (graphqlField.outputType.kind === 'object') {
const mapping = this.dmmf.getMapping(prismaModelName)
fieldOpts.resolve = (root, args, ctx) => {
const photon = this.getPhoton(ctx)
assertPhotonInContext(photon)
return photon[mapping.plural!]
['findOne']({ where: { id: root.id } })
[graphqlField.name](args)
}
}
t.field(fieldName, fieldOpts)
return result
}
return acc
}, seed)
return result
}
}

@@ -8,6 +8,7 @@ import { ExternalDMMF as DMMF } from './transformer'

public mappings: DMMF.Mapping[]
public queryObject: DMMF.OutputType
public mutationObject: DMMF.OutputType
public queryObject: OutputType
public mutationObject: OutputType
public outputTypesIndex: Index<DMMF.OutputType> = {}
public inputTypesIndex: Index<DMMF.InputType>
public mappingsIndex: Index<DMMF.Mapping>
public enumsIndex: Index<DMMF.Enum>

@@ -22,6 +23,2 @@ public modelsIndex: Index<DMMF.Model>

// Entrypoints
this.queryObject = schema.outputTypes.find(t => t.name === 'Query')!
this.mutationObject = schema.outputTypes.find(t => t.name === 'Mutation')!
// Indices

@@ -32,2 +29,7 @@ this.modelsIndex = indexBy('name', datamodel.models)

this.outputTypesIndex = indexBy('name', schema.outputTypes)
this.mappingsIndex = indexBy('model', mappings)
// Entrypoints
this.queryObject = this.getOutputType('Query')
this.mutationObject = this.getOutputType('Mutation')
}

@@ -52,3 +54,3 @@

return outputType
return new OutputType(outputType)
}

@@ -107,3 +109,3 @@

getMapping(modelName: string) {
const mapping = this.mappings.find(m => m.model === modelName)
const mapping = this.mappingsIndex[modelName]

@@ -117,1 +119,25 @@ if (!mapping) {

}
export class OutputType {
public name: string
public fields: DMMF.SchemaField[]
public isEmbedded?: boolean
constructor(protected outputType: DMMF.OutputType) {
this.name = outputType.name
this.fields = outputType.fields
this.isEmbedded = outputType.isEmbedded
}
getField(fieldName: string) {
const field = this.outputType.fields.find(f => f.name === fieldName)
if (!field) {
throw new Error(
`Could not find field field '${fieldName}' on type ${this.outputType.name}`,
)
}
return field
}
}

@@ -179,11 +179,11 @@ import * as Nexus from 'nexus'

model: string
plural?: string
findOne?: string
findMany?: string
create?: string
update?: string
updateMany?: string
upsert?: string
delete?: string
deleteMany?: string
plural: string
findOne: string
findMany: string
create: string
update: string
updateMany: string
upsert: string
delete: string
deleteMany: string
}

@@ -190,0 +190,0 @@ enum ModelAction {

import * as Nexus from 'nexus'
import * as DMMF from './dmmf'
import { nexusFieldOpts, partition } from './utils'
import { dmmfFieldToNexusFieldConfig, partition } from './utils'
import { CustomInputArg } from './builder'

@@ -26,3 +26,3 @@ import { scalarsNameValues } from './graphql'

return Nexus.arg(
nexusFieldOpts({
dmmfFieldToNexusFieldConfig({
...customArg.arg.inputType,

@@ -56,3 +56,3 @@ type: customArg.type.name,

if (field.outputType.kind === 'object') {
return outputTypeName
return this.publishObject(outputTypeName)
}

@@ -71,2 +71,15 @@

protected publishObject(name: string) {
this.markTypeAsPublished(name)
const dmmfObject = this.dmmf.getOutputType(name)
return Nexus.objectType({
name,
definition: t => {
for (const field of dmmfObject.fields) {
t.field(field.name, dmmfFieldToNexusFieldConfig(field.outputType))
}
},
})
}
protected publishScalar(typeName: string) {

@@ -88,3 +101,3 @@ if (scalarsNameValues.includes(typeName as any)) {

protected publishEnum(typeName: string) {
const eType = this.dmmf.getEnumType(typeName)
const dmmfEnum = this.dmmf.getEnumType(typeName)

@@ -95,3 +108,3 @@ this.markTypeAsPublished(typeName)

name: typeName,
members: eType.values,
members: dmmfEnum.values,
})

@@ -125,3 +138,3 @@ }

;[...scalarFields, ...remappedObjectFields].forEach(field => {
t.field(field.name, nexusFieldOpts(field.inputType))
t.field(field.name, dmmfFieldToNexusFieldConfig(field.inputType))
})

@@ -134,3 +147,5 @@ },

const kindToType = {
scalar: (typeName: string) => this.dmmf.getOutputType(typeName),
scalar: (typeName: string) => ({
name: this.dmmf.getOutputType(typeName).name,
}),
enum: (typeName: string) => this.dmmf.getEnumType(typeName),

@@ -137,0 +152,0 @@ object: (typeName: string) => this.dmmf.getInputType(typeName),

@@ -1,7 +0,6 @@

import { getSupportedQueries, getSupportedMutations } from './supported-ops'
import { flatMap, getCRUDFieldName } from './utils'
import { defaultFieldNamingStrategy } from './naming-strategies'
import * as fs from 'fs-extra'
import * as path from 'path'
import * as DMMF from './dmmf'
import { getCrudMappedFields } from './mapping'
import { defaultFieldNamingStrategy } from './naming-strategies'

@@ -70,45 +69,12 @@ type Options = {

function renderNexusPrismaTypes(dmmf: DMMF.DMMF) {
const queryFieldsWithMapping = dmmf.mappings.map(mapping => {
const queriesNames = getSupportedQueries(mapping)
return {
fields: dmmf.queryObject.fields.filter(query =>
queriesNames.includes(query.name),
),
mapping,
}
})
const queriesByType = flatMap(queryFieldsWithMapping, ({ fields, mapping }) =>
fields.map(field => ({
fieldName: getCRUDFieldName(
mapping.model,
field.name,
mapping,
defaultFieldNamingStrategy,
),
returnType: field.outputType.type,
})),
const queriesByType = getCrudMappedFields('Query', dmmf).map(mappedfield => ({
fieldName: mappedfield.field.name,
returnType: mappedfield.field.outputType.type,
}))
const mutationsByType = getCrudMappedFields('Mutation', dmmf).map(
mappedField => ({
fieldName: mappedField.field.name,
returnType: mappedField.field.outputType.type,
}),
)
const mutationsFieldsWithMapping = dmmf.mappings.map(mapping => {
const mutationsNames = getSupportedMutations(mapping)
return {
fields: dmmf.mutationObject.fields.filter(mutation =>
mutationsNames.includes(mutation.name),
),
mapping,
}
})
const mutationsByType = flatMap(
mutationsFieldsWithMapping,
({ fields, mapping }) =>
fields.map(field => ({
fieldName: getCRUDFieldName(
mapping.model,
field.name,
mapping,
defaultFieldNamingStrategy,
),
returnType: field.outputType.type,
})),
)
const fieldsByType = dmmf.datamodel.models.reduce<

@@ -153,15 +119,11 @@ Record<string, { fieldName: string; returnType: string }[]>

function renderNexusPrismaInputs(dmmf: DMMF.DMMF) {
const queryFieldsWithMapping = dmmf.mappings.map(mapping => {
const queriesNames = getSupportedQueries(mapping)
return {
fields: dmmf.queryObject.fields
.filter(query => queriesNames.includes(query.name))
.filter(q => q.outputType.isList && q.outputType.kind === 'object'),
mapping,
}
})
const queriesFields = flatMap(queryFieldsWithMapping, ({ fields, mapping }) =>
fields.map(field => {
const whereArg = field.args.find(a => a.name === 'where')!
const orderByArg = field.args.find(a => a.name === 'orderBy')!
const queriesFields = getCrudMappedFields('Query', dmmf)
.filter(
mappedField =>
mappedField.field.outputType.isList &&
mappedField.field.outputType.kind === 'object',
)
.map(mappedField => {
const whereArg = mappedField.field.args.find(a => a.name === 'where')!
const orderByArg = mappedField.field.args.find(a => a.name === 'orderBy')!
const whereInput = dmmf.schema.inputTypes.find(

@@ -175,7 +137,5 @@ i => i.name === whereArg.inputType.type,

return {
fieldName: getCRUDFieldName(
mapping.model,
field.name,
mapping,
defaultFieldNamingStrategy,
fieldName: defaultFieldNamingStrategy[mappedField.operation](
mappedField.field.name,
mappedField.model,
),

@@ -185,7 +145,6 @@ filtering: whereInput,

}
}),
)
})
const fieldsByType = dmmf.datamodel.models
.map(m => dmmf.schema.outputTypes.find(o => o.name === m.name)!)
.map(m => dmmf.getOutputType(m.name))
.reduce<

@@ -270,3 +229,3 @@ Record<

return `\
type ModelNameExistsInGraphQLType<
type IsModelNameExistsInGraphQLTypes<
ReturnType extends any

@@ -292,2 +251,5 @@ > = ReturnType extends core.GetGen<'objectNames'> ? true : false;

/**
* Determine if \`B\` is a subset (or equivalent to) of \`A\`.
*/
type IsSubset<A, B> = keyof A extends never

@@ -321,3 +283,3 @@ ? false

type DynamicRequiredType<ReturnType extends any> = ModelNameExistsInGraphQLType<
type DynamicRequiredType<ReturnType extends any> = IsModelNameExistsInGraphQLTypes<
ReturnType

@@ -393,3 +355,3 @@ > extends true

? (opts?: NexusPrismaScalarOpts) => NexusPrismaFields<ModelName> // Return optional scalar opts
: ModelNameExistsInGraphQLType<ReturnType> extends true // If model name has a mapped graphql types
: IsModelNameExistsInGraphQLTypes<ReturnType> extends true // If model name has a mapped graphql types
? (

@@ -396,0 +358,0 @@ opts?: NexusPrismaRelationOpts<ModelName, MethodName, ReturnType>

import { isNamedType } from 'graphql'
import { core } from 'nexus'
import { relative } from 'path'
import * as DMMF from './dmmf'
import { OperationName, FieldNamingStrategy } from './naming-strategies'

@@ -60,3 +58,3 @@ // TODO `any` should be `unknown` but there is a bug (?)

export function nexusFieldOpts(param: {
export function dmmfFieldToNexusFieldConfig(param: {
type: string | object

@@ -119,19 +117,2 @@ isList: boolean

export function getCRUDFieldName(
modelName: string,
fieldName: string,
mapping: DMMF.Data.Mapping,
namingStrategy: FieldNamingStrategy,
) {
const operationName = Object.keys(mapping).find(
key => (mapping as any)[key] === fieldName,
) as OperationName | undefined
if (!operationName || !namingStrategy[operationName]) {
throw new Error(`Could not find mapping for field ${fieldName}`)
}
return namingStrategy[operationName](fieldName, modelName)
}
/**

@@ -138,0 +119,0 @@ * Unwrap nexus user-defined types and convert them to a map<TypeName, boolean>

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc