Socket
Socket
Sign inDemoInstall

graphile-build

Package Overview
Dependencies
Maintainers
1
Versions
167
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

graphile-build - npm Package Compare versions

Comparing version 5.0.0-alpha.9 to 5.0.0-alpha.10

87

CHANGELOG.md
# graphile-build
## 5.0.0-alpha.10
### Patch Changes
- [#349](https://github.com/benjie/postgraphile-private/pull/349)
[`a94f11091`](https://github.com/benjie/postgraphile-private/commit/a94f11091520b52d90fd007986760848ed20017b)
Thanks [@benjie](https://github.com/benjie)! - **Overhaul behavior system**
Previously the behavior system worked during the schema building process,
inside the various schema hooks. So looking at the behavior of a `relation`
might have looked like:
```ts
GraphQLObjectType_fields_field(field, build, context) {
const relation = context.scope.pgRelationOrWhatever;
// Establish a default behavior, e.g. you might give it different default behavior
// depending on if the remote table is in the same schema or not
const defaultBehavior = someCondition(relation) ? "behavior_if_true" : "behavior_if_false";
// Now establish the user-specified behavior for the entity, inheriting from all the
// relevant places.
const behavior = getBehavior([
relation.remoteResource.codec.extensions,
relation.remoteResource.extensions,
relation.extensions
]);
// Finally check this behavior string against `behavior_to_test`, being sure to apply
// the "schema-time smart defaulting" that we established in `defaultBehavior` above.
if (build.behavior.matches(behavior, "behavior_to_test", defaultBehavior)) {
doTheThing();
}
```
This meant that each plugin might treat the behavior of the entity different -
for example `postgraphile-plugin-connection-filter` might have a different
`someCondition()` under which the "filter" behavior would apply by default,
whereas the built in `condition` plugin might have a different one.
Moreover, each place needs to know to call `getBehavior` with the same list of
extension sources in the same order, otherwise subtle (or not so subtle)
differences in the schema would occur.
And finally, because each entity doesn't have an established behavior, you
can't ask "what's the final behavior for this entity" because it's dynamic,
depending on which plugin is viewing it.
This update fixes all of this; now each entity has a single behavior that's
established once. Each plugin can register `entityBehaviors` for the various
behavior entity types (or global behaviors which apply to all entity types if
that makes more sense). So the hook code equivalent to the above would now be
more like:
```ts
GraphQLObjectType_fields_field(field, build, context) {
const relation = context.scope.pgRelationOrWhatever;
// Do the thing if the relation has the given behavior. Simples.
if (build.behavior.pgCodecRelationMatches(relation, "behavior_to_test")) {
doTheThing();
}
```
This code is much more to the point, much easier for plugin authors to
implement, and also a lot easier to debug since everything has a single
established behavior now (except `refs`, which aren't really an entity in
their own right, but a combination of entities...).
These changes haven't changed any of the schemas in the test suite, but they
may impact you. This could be a breaking change - so be sure to do a schema
diff before/after this.
- [#361](https://github.com/benjie/postgraphile-private/pull/361)
[`dad4d4aae`](https://github.com/benjie/postgraphile-private/commit/dad4d4aaee499098104841740c9049b1deb6ac5f)
Thanks [@benjie](https://github.com/benjie)! - Instead of passing
resolvedPreset to behaviors, pass Build.
- Updated dependencies
[[`56237691b`](https://github.com/benjie/postgraphile-private/commit/56237691bf3eed321b7159e17f36e3651356946f),
[`ed1982f31`](https://github.com/benjie/postgraphile-private/commit/ed1982f31a845ceb3aafd4b48d667649f06778f5),
[`1fe47a2b0`](https://github.com/benjie/postgraphile-private/commit/1fe47a2b08d6e7153a22dde3a99b7a9bf50c4f84),
[`198ac74d5`](https://github.com/benjie/postgraphile-private/commit/198ac74d52fe1e47d602fe2b7c52f216d5216b25),
[`6878c589c`](https://github.com/benjie/postgraphile-private/commit/6878c589cc9fc8f05a6efd377e1272ae24fbf256),
[`2ac706f18`](https://github.com/benjie/postgraphile-private/commit/2ac706f18660c855fe20f460b50694fdd04a7768)]:
- grafast@0.0.1-alpha.9
- graphile-config@0.0.1-alpha.4
## 5.0.0-alpha.9

@@ -4,0 +91,0 @@

46

dist/behavior.d.ts

@@ -0,12 +1,50 @@

export type BehaviorDynamicMethods = {
[entityType in keyof GraphileBuild.BehaviorEntities as `${entityType}Matches`]: (entity: GraphileBuild.BehaviorEntities[entityType], filter: string) => boolean | undefined;
} & {
[entityType in keyof GraphileBuild.BehaviorEntities as `${entityType}Behavior`]: (entity: GraphileBuild.BehaviorEntities[entityType], applyDefaultBehavior?: boolean) => string;
};
export declare class Behavior {
private globalBehaviorDefaults;
constructor(globalBehaviorDefaults?: string);
addDefaultBehavior(behavior: string): void;
private resolvedPreset;
private build;
private behaviorEntities;
private globalDefaultBehavior;
constructor(resolvedPreset: GraphileConfig.ResolvedPreset, build: GraphileBuild.Build);
/**
* Forbid registration of more global behavior defaults, behavior entity types, etc.
*/
freeze(): Behavior & BehaviorDynamicMethods;
private registerEntity;
private assertEntity;
/**
* @param localBehaviorSpecsString - the behavior of the entity as determined by details on the entity itself and any applicable ancestors
* @param filter - the behavior the plugin specifies
* @param defaultBehavior - allows the plugin to specify a default behavior for this in the event that it's not defined elsewhere (lowest priority)
*/
entityMatches<TEntityType extends keyof GraphileBuild.BehaviorEntities>(entityType: TEntityType, entity: GraphileBuild.BehaviorEntities[TEntityType], filter: string): boolean | undefined;
/**
* Given the entity `rawEntity` of type `entityType`, this function will
* return the final behavior string for this entity, respecting all the
* global and entity-specific behaviors.
*
* This is expensive to compute, so we cache it.
*
* **IMPORTANT**: `rawEntity` should be a fixed value so that the cache can be
* reused. If it is a dynamic value (e.g. it's a combination of multiple
* entities) then you should represent it as a tuple and we'll automatically
* cache that.
*/
getBehaviorForEntity<TEntityType extends keyof GraphileBuild.BehaviorEntities>(entityType: TEntityType, rawEntity: GraphileBuild.BehaviorEntities[TEntityType], applyDefaultBehavior?: boolean): ResolvedBehavior;
/** @deprecated Please use entityMatches or stringMatches instead */
matches(localBehaviorSpecsString: string | string[] | null | undefined, filter: string, defaultBehavior?: string): boolean | undefined;
}
export declare function joinBehaviors(strings: ReadonlyArray<string | null | undefined>): string;
interface StackItem {
source: string;
prefix: string;
suffix: string;
}
interface ResolvedBehavior {
stack: ReadonlyArray<StackItem>;
behaviorString: string;
}
export {};
//# sourceMappingURL=behavior.d.ts.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Behavior = void 0;
exports.joinBehaviors = exports.Behavior = void 0;
const grafast_1 = require("grafast");
const graphile_config_1 = require("graphile-config");
const NULL_BEHAVIOR = Object.freeze({
behaviorString: "",
stack: Object.freeze([]),
});
const getEntityBehaviorHooks = (plugin) => {
const val = plugin.schema?.entityBehavior;
if (!val)
return val;
// These might not all be hooks, some might be strings. We need to convert the strings into hooks.
const entries = Object.entries(val);
let changed = false;
for (const entry of entries) {
const lhs = entry[1];
if (typeof lhs === "string") {
const hook = {
provides: ["default"],
before: ["inferred"],
callback: (behavior) => [lhs, behavior],
};
entry[1] = hook;
changed = true;
}
}
if (changed) {
return Object.fromEntries(entries);
}
else {
return val;
}
};
class Behavior {
constructor(globalBehaviorDefaults = "") {
this.globalBehaviorDefaults = globalBehaviorDefaults;
constructor(resolvedPreset, build) {
this.resolvedPreset = resolvedPreset;
this.build = build;
this.behaviorEntities = Object.create(null);
this.registerEntity("string");
// This will be overwritten in freeze
this.globalDefaultBehavior = NULL_BEHAVIOR;
}
// Should only be called during 'build' phase.
addDefaultBehavior(behavior) {
if (this.globalBehaviorDefaults) {
this.globalBehaviorDefaults += " " + behavior;
/**
* Forbid registration of more global behavior defaults, behavior entity types, etc.
*/
freeze() {
const { resolvedPreset, build } = this;
const plugins = (0, graphile_config_1.sortedPlugins)(resolvedPreset.plugins);
const initialBehavior = resolvedPreset.schema?.defaultBehavior ?? "";
this.globalDefaultBehavior = resolveBehavior(initialBehavior
? {
behaviorString: initialBehavior,
stack: [
{
source: "preset.schema.defaultBehavior",
prefix: initialBehavior,
suffix: "",
},
],
}
: { behaviorString: "", stack: [] }, plugins.map((p) => [
`${p.name}.schema.globalBehavior`,
p.schema?.globalBehavior,
]), build);
(0, graphile_config_1.applyHooks)(resolvedPreset.plugins, getEntityBehaviorHooks, (hookName, hookFn, plugin) => {
const entityType = hookName;
if (!this.behaviorEntities[entityType]) {
this.registerEntity(entityType);
}
const t = this.behaviorEntities[entityType];
t.behaviorCallbacks.push([
`${plugin.name}.schema.entityBehavior.${entityType}`,
hookFn,
]);
});
Object.freeze(this);
Object.freeze(this.behaviorEntities);
for (const key of Object.keys(this.behaviorEntities)) {
Object.freeze(this.behaviorEntities[key]);
}
else {
this.globalBehaviorDefaults = behavior;
return this;
}
registerEntity(entityType) {
if (entityType === "string") {
this.stringMatches = stringMatches;
this.stringBehavior = (str) => str;
return;
}
this.behaviorEntities[entityType] = {
behaviorCallbacks: [],
listCache: new Map(),
cacheWithDefault: new Map(),
cacheWithoutDefault: new Map(),
};
this[`${entityType}Matches`] = (entity, behavior) => this.entityMatches(entityType, entity, behavior);
this[`${entityType}Behavior`] = (entity, applyDefaultBehavior = true) => this.getBehaviorForEntity(entityType, entity, applyDefaultBehavior)
.behaviorString;
}
assertEntity(entityType) {
if (entityType === "string") {
throw new Error(`Runtime behaviors cannot be attached to strings, please use 'behavior.stringMatches' directly.`);
}
if (!this.behaviorEntities[entityType]) {
throw new Error(`Behavior entity type '${entityType}' is not registered; known entity types: ${Object.keys(this.behaviorEntities).join(", ")}`);
}
}
// TODO: would be great if this could return `{deprecationReason: string}` too...

@@ -21,22 +113,54 @@ /**

* @param filter - the behavior the plugin specifies
* @param defaultBehavior - allows the plugin to specify a default behavior for this in the event that it's not defined elsewhere (lowest priority)
*/
entityMatches(entityType, entity, filter) {
const finalString = this.getBehaviorForEntity(entityType, entity).behaviorString;
return stringMatches(finalString, filter);
}
/**
* Given the entity `rawEntity` of type `entityType`, this function will
* return the final behavior string for this entity, respecting all the
* global and entity-specific behaviors.
*
* This is expensive to compute, so we cache it.
*
* **IMPORTANT**: `rawEntity` should be a fixed value so that the cache can be
* reused. If it is a dynamic value (e.g. it's a combination of multiple
* entities) then you should represent it as a tuple and we'll automatically
* cache that.
*/
getBehaviorForEntity(entityType, rawEntity, applyDefaultBehavior = true) {
this.assertEntity(entityType);
const { cacheWithDefault, cacheWithoutDefault, listCache } = this.behaviorEntities[entityType];
const cache = applyDefaultBehavior ? cacheWithDefault : cacheWithoutDefault;
const entity = Array.isArray(rawEntity)
? getCachedEntity(listCache, rawEntity)
: rawEntity;
const existing = cache.get(entity);
if (existing !== undefined) {
return existing;
}
const behaviorEntity = this.behaviorEntities[entityType];
const behavior = resolveBehavior(applyDefaultBehavior ? this.globalDefaultBehavior : NULL_BEHAVIOR, behaviorEntity.behaviorCallbacks, entity, this.build);
cache.set(entity, behavior);
return behavior;
}
/** @deprecated Please use entityMatches or stringMatches instead */
matches(localBehaviorSpecsString, filter, defaultBehavior = "") {
let err;
try {
throw new Error("Deprecated call happened here");
}
catch (e) {
err = e;
}
const stackText = err.stack;
if (!warned.has(stackText)) {
warned.add(stackText);
console.error(`[DEPRECATION WARNING] Something in your application is using build.behavior.matches; it should be using build.behavior.pgCodecMatches / etc instead. This API will be removed before the v5.0.0 release. ${stackText}`);
}
const specString = Array.isArray(localBehaviorSpecsString)
? localBehaviorSpecsString.join(" ")
: localBehaviorSpecsString;
const finalBehaviorSpecsString = `${defaultBehavior} ${this.globalBehaviorDefaults} ${specString ?? ""}`;
const specs = parseSpecs(finalBehaviorSpecsString);
const filterScope = parseScope(filter);
if (filterScope[filterScope.length - 1] === "create") {
throw new Error(`'create' filter scope is forbidden; did you mean 'insert'?`);
}
// Loop backwards through the specs
for (let i = specs.length - 1; i >= 0; i--) {
const { positive, scope } = specs[i];
if (scopeMatches(scope, filterScope, positive)) {
return positive;
}
}
return undefined;
const finalBehaviorSpecsString = `${defaultBehavior} ${this.globalDefaultBehavior} ${specString ?? ""}`;
return stringMatches(finalBehaviorSpecsString, filter);
}

@@ -113,2 +237,93 @@ }

}
function joinBehaviors(strings) {
let str = "";
for (const string of strings) {
if (string != null && string !== "") {
if (str === "") {
str = string;
}
else {
str += " " + string;
}
}
}
return str;
}
exports.joinBehaviors = joinBehaviors;
function resolveBehavior(initialBehavior,
// Misnomer; also allows strings or nothings
callbacks, ...args) {
let behaviorString = initialBehavior.behaviorString;
const stack = [...initialBehavior.stack];
for (const [source, g] of callbacks) {
const oldBehavior = behaviorString;
if (typeof g === "string") {
if (g === "") {
continue;
}
else if (behaviorString === "") {
behaviorString = g;
}
else {
behaviorString = g + " " + behaviorString;
}
}
else if (typeof g === "function") {
const newBehavior = g(oldBehavior, ...args);
if (!newBehavior.includes(oldBehavior)) {
throw new Error(`${source} callback must return a list that contains the current (passed in) behavior in addition to any other behaviors you wish to set.`);
}
if (Array.isArray(newBehavior)) {
behaviorString = joinBehaviors(newBehavior);
}
else {
behaviorString = newBehavior;
}
}
const i = behaviorString.indexOf(oldBehavior);
const prefix = behaviorString.substring(0, i);
const suffix = behaviorString.substring(i + oldBehavior.length);
if (prefix !== "" || suffix !== "") {
stack.push({ source, prefix, suffix });
}
}
return {
stack,
behaviorString,
toString() {
return behaviorString;
},
};
}
function getCachedEntity(listCache, entity) {
const nList = listCache.get(entity.length);
if (!nList) {
const list = [entity];
listCache.set(entity.length, list);
return entity;
}
for (const entry of nList) {
if ((0, grafast_1.arraysMatch)(entry, entity)) {
return entry;
}
}
nList.push(entity);
return entity;
}
const warned = new Set();
function stringMatches(behaviorString, filter) {
const specs = parseSpecs(behaviorString);
const filterScope = parseScope(filter);
if (filterScope[filterScope.length - 1] === "create") {
throw new Error(`'create' filter scope is forbidden; did you mean 'insert'?`);
}
// Loop backwards through the specs
for (let i = specs.length - 1; i >= 0; i--) {
const { positive, scope } = specs[i];
if (scopeMatches(scope, filterScope, positive)) {
return positive;
}
}
return undefined;
}
//# sourceMappingURL=behavior.js.map

28

dist/global.d.ts
import type { BaseGraphQLArguments, ExecutableStep, GrafastArgumentConfig, GrafastFieldConfig, GrafastFieldConfigArgumentMap, GrafastInputFieldConfig, GrafastInputFieldConfigMap, OutputPlanForType } from "grafast";
import type { GraphQLArgumentConfig, GraphQLEnumType, GraphQLEnumTypeConfig, GraphQLEnumValueConfig, GraphQLEnumValueConfigMap, GraphQLFieldConfig, GraphQLFieldConfigArgumentMap, GraphQLFieldConfigMap, GraphQLInputFieldConfigMap, GraphQLInputObjectType, GraphQLInputObjectTypeConfig, GraphQLInputType, GraphQLInterfaceType, GraphQLInterfaceTypeConfig, GraphQLNamedType, GraphQLNonNull, GraphQLObjectType, GraphQLObjectTypeConfig, GraphQLOutputType, GraphQLScalarType, GraphQLScalarTypeConfig, GraphQLSchema, GraphQLSchemaConfig, GraphQLType, GraphQLUnionType, GraphQLUnionTypeConfig } from "graphql";
import type { Behavior } from "./behavior.js";
import type { Behavior, BehaviorDynamicMethods } from "./behavior.js";
import type { InflectionBase } from "./inflection.js";

@@ -14,2 +14,10 @@ import type { stringTypeSpec, wrapDescription } from "./utils.js";

}
interface BehaviorEntities {
string: string;
}
interface PluginBehaviorEntitySpec<TEntityType extends keyof GraphileBuild.BehaviorEntities> {
defaultBehavior?: string;
getEntityDefaultBehavior?: (entity: GraphileBuild.BehaviorEntities[TEntityType]) => string;
getEntityConfiguredBehavior?: (entity: GraphileBuild.BehaviorEntities[TEntityType]) => string;
}
/**

@@ -55,8 +63,2 @@ * Details of a single directive application. We typically store a list of

/**
* - 'only': connections will be avoided, preferring lists
* - 'omit': lists will be avoided, preferring connections
* - 'both': both lists and connections will be generated
*/
simpleCollections?: "only" | "both" | "omit";
/**
* When false (default), Grafserv will exit if it fails to build the

@@ -175,8 +177,2 @@ * initial schema (for example if it cannot connect to the database, or if

/**
* Behavior logic that helps decide whether or not a certain thing
* (typically a field, argument, enum value, input field, or similar)
* goes into the schema.
*/
behavior: Behavior;
/**
* Register a type by name with the system; names must be unique. It's

@@ -291,2 +287,8 @@ * strongly advised that your names come from an inflector so that they

$$isQuery: symbol;
/**
* Behavior logic that helps decide whether or not a certain thing
* (typically a field, argument, enum value, input field, or similar)
* goes into the schema.
*/
behavior: Behavior & BehaviorDynamicMethods;
}

@@ -293,0 +295,0 @@ /**

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

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const getSchemaHooks = (plugin) => plugin.schema?.hooks;
/**

@@ -292,11 +291,3 @@ * Generate 'build.inflection' from the given preset.

const resolvedPreset = (0, graphile_config_1.resolvePresets)([preset]);
const { plugins, schema: options } = resolvedPreset;
const builder = new SchemaBuilder_js_1.default(options || {}, inflection);
if (plugins) {
(0, graphile_config_1.applyHooks)(plugins, getSchemaHooks, (hookName, hookFn, plugin) => {
builder._setPluginName(plugin.name);
builder.hook(hookName, hookFn);
builder._setPluginName(null);
});
}
const builder = new SchemaBuilder_js_1.default(resolvedPreset, inflection);
return builder;

@@ -303,0 +294,0 @@ };

@@ -147,2 +147,14 @@ import type { GrafastArgumentConfig, GrafastFieldConfig, GrafastFieldConfigArgumentMap, PromiseOrDirect } from "grafast";

schema?: {
globalBehavior?: string | ((behavior: string, build: GraphileBuild.Build) => string | string[]);
/**
* You should use `before`, `after` and `provides` to ensure that the entity
* behaviors apply in order. The order should be roughly:
*
* - `default` - default global behaviors like "update"
* - `inferred` - behaviors that are inferred based on the entity, e.g. a plugin might disable filtering _by default_ on a relation if it's unindexed
* - `override` - overrides set explicitly by the user
*/
entityBehavior?: {
[entityType in keyof GraphileBuild.BehaviorEntities]?: string | PluginHook<(behavior: string, entity: GraphileBuild.BehaviorEntities[entityType], build: GraphileBuild.Build) => string | string[]>;
};
hooks?: {

@@ -149,0 +161,0 @@ /**

@@ -10,3 +10,2 @@ "use strict";

const util_1 = require("util");
const behavior_js_1 = require("./behavior.js");
const extend_js_1 = tslib_1.__importStar(require("./extend.js"));

@@ -129,3 +128,2 @@ const utils_js_1 = require("./utils.js");

stringTypeSpec: utils_js_1.stringTypeSpec,
behavior: new behavior_js_1.Behavior(builder.options.defaultBehavior),
registerObjectType(typeName, scope, Step, specGenerator, origin) {

@@ -132,0 +130,0 @@ register.call(this, graphql_1.GraphQLObjectType, typeName, scope, Step, specGenerator, origin);

@@ -11,2 +11,3 @@ /// <reference types="node" />

declare class SchemaBuilder<TBuild extends GraphileBuild.Build = GraphileBuild.Build> extends EventEmitter {
private resolvedPreset;
private inflection;

@@ -22,3 +23,3 @@ options: GraphileBuild.SchemaOptions;

newWithHooks: NewWithHooksFunction;
constructor(options: GraphileBuild.SchemaOptions, inflection: GraphileBuild.Inflection);
constructor(resolvedPreset: GraphileConfig.ResolvedPreset, inflection: GraphileBuild.Inflection);
/**

@@ -25,0 +26,0 @@ * @internal

@@ -7,3 +7,5 @@ "use strict";

const events_1 = require("events");
const graphile_config_1 = require("graphile-config");
const graphql_1 = require("graphql");
const behavior_js_1 = require("./behavior.js");
const makeNewBuild_js_1 = tslib_1.__importDefault(require("./makeNewBuild.js"));

@@ -16,2 +18,3 @@ const index_js_1 = require("./newWithHooks/index.js");

const INDENT = " ";
const getSchemaHooks = (plugin) => plugin.schema?.hooks;
/**

@@ -22,9 +25,7 @@ * The class responsible for building a GraphQL schema from graphile-build

class SchemaBuilder extends events_1.EventEmitter {
constructor(options, inflection) {
constructor(resolvedPreset, inflection) {
super();
this.resolvedPreset = resolvedPreset;
this.inflection = inflection;
if (!options) {
throw new Error("Please pass options to SchemaBuilder");
}
this.options = options;
this.options = resolvedPreset.schema ?? {};
// Because hooks can nest, this keeps track of how deep we are.

@@ -34,2 +35,7 @@ this.depth = -1;

this.newWithHooks = (0, index_js_1.makeNewWithHooks)({ builder: this }).newWithHooks;
(0, graphile_config_1.applyHooks)(resolvedPreset.plugins, getSchemaHooks, (hookName, hookFn, plugin) => {
this._setPluginName(plugin.name);
this.hook(hookName, hookFn);
this._setPluginName(null);
});
}

@@ -134,3 +140,6 @@ /**

(0, utils_js_1.bindAll)(build, Object.keys(build).filter((key) => typeof build[key] === "function"));
const finalBuild = Object.freeze(build);
const finalBuild = build;
finalBuild.behavior = new behavior_js_1.Behavior(this.resolvedPreset, finalBuild);
Object.freeze(finalBuild);
finalBuild.behavior.freeze();
finalBuild.status.isBuildPhaseComplete = true;

@@ -137,0 +146,0 @@ const initContext = {

{
"name": "graphile-build",
"version": "5.0.0-alpha.9",
"version": "5.0.0-alpha.10",
"description": "Build a GraphQL schema from plugins",

@@ -44,4 +44,4 @@ "type": "commonjs",

"debug": "^4.3.3",
"grafast": "^0.0.1-alpha.8",
"graphile-config": "^0.0.1-alpha.3",
"grafast": "^0.0.1-alpha.9",
"graphile-config": "^0.0.1-alpha.4",
"lodash": "^4.17.21",

@@ -65,3 +65,3 @@ "pluralize": "^7.0.0",

"@types/jest": "^27.5.1",
"graphile-export": "^0.0.2-alpha.3",
"graphile-export": "^0.0.2-alpha.4",
"graphql": "16.1.0-experimental-stream-defer.6",

@@ -68,0 +68,0 @@ "jest": "^28.1.3",

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