diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 30e9725..0000000 --- a/.eslintrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": ["eslint:recommended"], - "parserOptions": { - "ecmaVersion": 2018, - "sourceType": "module" - }, - "env": { - "browser": false, - "node": true, - "es6": true - } -} \ No newline at end of file diff --git a/.nycrc b/.nycrc deleted file mode 100644 index 47b8989..0000000 --- a/.nycrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "check-coverage": true, - "statements": 80, - "branches": 80, - "functions": 80, - "lines": 80, - "exclude": [ - "**/__tests__.js" - ], - "reporter": ["html", "text"] -} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c95fc5..857ccfd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +### v6.0.0 + +- Converted to TS +- BREAKING removed `delegateToComponent` +- BREAKING excludes removed as an option in import configuration. Transforms used instead as part of a `SubschemaConfig`. +- BREAKING upgraded to graphql 16.9+ peer + +=== + ### v5.0.1 - Update @graphql-tools/utils dependency and fix samples for Apollo server v3. @@ -179,4 +188,4 @@ - Fixed .npmignore to not include misc files that added to the package size -### v1.0.0 โ€”ย promoted from alpha.23 +### v1.0.0 โ€” promoted from alpha.23 diff --git a/README.md b/README.md index ee7ed50..ad490f9 100644 --- a/README.md +++ b/README.md @@ -1,250 +1,303 @@ -![](https://github.com/ExpediaGroup/graphql-component/workflows/Build/badge.svg) +# GraphQL Component -# GraphQL schema components. +![Build Status](https://github.com/ExpediaGroup/graphql-component/workflows/Build/badge.svg) -This project is designed to facilitate componentized or modularized development of GraphQL schemas. +A library for building modular and composable GraphQL schemas through a component-based architecture. -Read more about the idea [here](https://medium.com/expedia-group-tech/graphql-component-architecture-principles-homeaway-ede8a58d6fde). +## Overview -`graphql-component` lets you build a schema progressively through a tree (facilitated through `imports`) of GraphQLComponent instances. Each GraphQLComponent instance encapsulates an executable GraphQL schema, specifically a `graphql-js` GraphQLSchema object. See the API below, but the encapsulated schema is accessible through a simple `schema` getter on a given `GraphQLComponent` instance. +`graphql-component` enables you to build GraphQL schemas progressively through a tree of components. Each component encapsulates its own schema, resolvers, and data sources, making it easier to build and maintain large GraphQL APIs. -Generally speaking, each instance of `GraphQLComponent` has reference to an instance of [`GraphQLSchema`](https://graphql.org/graphql-js/type/#graphqlschema). This instance of `GraphQLSchema` is built in a several ways, depending on the options passed to a given `GraphQLComponent`'s constructor. +Read more about the architecture principles in our [blog post](https://medium.com/expedia-group-tech/graphql-component-architecture-principles-homeaway-ede8a58d6fde). -* when a `GraphQLComponent` instance has `imports` (ie. other `GraphQLComponent` instances or component configuration objects) [graphql-tools stitchSchemas()](https://www.graphql-tools.com/docs/schema-stitching/) is used to create a "gateway" or aggregate schema that is the combination of the underlying imported schemas, and the typeDefs/resolvers passed to the root or importing `GraphQLComponent` -* when a `GraphQLComponent` has no imports, graphql-tools' `makeExecuteableSchema({typeDefs, resolvers})` is used to generate an executable GraphQL schema using the passed/required inputs. +## Features -It's worth noting that `GraphQLComponent` can also be used to construct componentized Apollo Federated schemas. That is, if you pass the `federation: true` flag to a GraphQLComponent constructor, `@apollo/federation`'s [buildSubgraphSchema()](https://www.apollographql.com/docs/federation/api/apollo-subgraph/) is used in lieu of graphql-tools `makeExecutableSchema({...})` and the above still schema construction rule applies. The general use case here might be to help modularize an individual federated subschema service implementation. +- ๐Ÿ”ง **Modular Schema Design**: Build schemas through composable components +- ๐Ÿ”„ **Schema Stitching**: Merge multiple component schemas seamlessly +- ๐Ÿš€ **Apollo Federation Support**: Build federated subgraphs with component architecture +- ๐Ÿ“ฆ **Data Source Management**: Simplified data source injection and overrides +- ๐Ÿ› ๏ธ **Flexible Configuration**: Extensive options for schema customization -### Running the examples +## Installation -local schema composition: - * can be run with `npm run start-composition` +```bash +npm install graphql-component +``` -federation (2 subschema services implemented via `GraphQLComponent` and a vanilla Apollo Gateway): - * can be run with `npm run start-federation` +## Quick Start -### Repository structure +```javascript +const GraphQLComponent = require('graphql-component'); -- `lib` - the graphql-component code. -- `examples/composition` - a simple example of composition using `graphql-component` -- `examples/federation` - a simple example of building a federated schema using `graphql-component` +const { schema, context } = new GraphQLComponent({ + types, + resolvers +}); +``` -### Running examples: -* composition: `npm run start-composition` -* federation: `npm run start-federation` -* go to `localhost:4000/graphql` - * for composition this will bring up the GraphQL Playground for a plain old Apollo Server - * for the federation example this will bring up the GraphQL Playground for an Apollo Federated Gateway +## Core Concepts -### Debug output +### Schema Construction -`GraphQLComponent` uses [debug]() for local stdout based debug logging. Enable all debug logging with the node environment variable `DEBUG=graphql-component:*`. Generally speaking, most debug output occurs during `GraphQLComponent` construction. +A `GraphQLComponent` instance creates a GraphQL schema in one of two ways: -# API -- `GraphQLComponent(options)` - the component class, which may also be extended. Its options include: - - `types` - a string or array of strings of GraphQL SDL defining the type definitions for this component - - `resolvers` - a resolver map (ie. a two level map whose first level keys are types from the SDL, mapped to objects, whose keys are fields on those types and values are resolver functions) - - `imports` - an optional array of imported components for the schema to be merged with. - - `context` - an optional object { namespace, factory } for contributing to context. - - `directives` - an optional object containing custom schema directives. - - `mocks` - a boolean (to enable default mocks) or an object to pass in custom mocks - - `dataSources` - an array of data sources instances to make available on `context.dataSources` . - - `dataSourceOverrides` - overrides for data sources in the component tree. - - `federation` - make this component's schema an Apollo Federated schema (default: `false`). - - `pruneSchema` - (optional) prune the schema according to [pruneSchema in graphql-tools](https://www.graphql-tools.com/docs/api/modules/utils_src#pruneschema) (default: false) - - `pruneSchemaOptions` - (optional) schema options as per [PruneSchemaOptions in graphql-tools](https://www.graphql-tools.com/docs/api/interfaces/utils_src.PruneSchemaOptions) +1. **With Imports**: Creates a gateway/aggregate schema by combining imported component schemas with local types/resolvers +2. **Without Imports**: Uses `makeExecutableSchema()` to generate a schema from local types/resolvers -- `static GraphQLComponent.delegateToComponent(component, options)` - a wrapper function that utilizes `graphql-tools` `delegateToSchema()` to delegate the calling resolver's selection set to a root type field (`Query`, `Mutuation`) of another `GraphQLComponent`'s schema - - `component` (instance of `GraphQLComponent`) - the component's whose schema will be the target of the delegated operation - - `options` (`object`) - - `operation` (optional, can be inferred from `info`): `query` or `mutation` - - `fieldName` (optional, can be inferred if target field has same name as calling resolver's field): the target root type (`Query`, `Mutation`) field in the target `GraphQLComponent`'s schema - - `context` (required) - the `context` object from resolver that calls `delegateToComponent` - - `info` (required) - the `info` object from the resolver that calls `delegateToComponent` - - `args` (`object`, optional) - an object literal whose keys/values are passed as args to the delegatee's target field resolver. By default, the resolver's args from which `delegateToComponent` is called will be passed if the target field has an argument of the same name. Otherwise, arguments passed via the `args` object will override the calling resolver's args of the same name. - - `transforms` (optional `Array`): Transform being a valid `graphql-tools` transform +### Federation Support - - please see `graphql-tools` [delegateToSchema](https://www.graphql-tools.com/docs/schema-delegation/#delegatetoschema) documentation for more details on available `options` since the delegateToComponent functions is simply an adapter for the `GraphQLComponent` API. +To create Apollo Federation subgraphs, set `federation: true` in the component options: -A GraphQLComponent instance (ie, `new GraphQLComponent({...})`) has the following API: +```javascript +const component = new GraphQLComponent({ + types, + resolvers, + federation: true +}); +``` -- `schema` - getter that this component's `GraphQLSchema` object (ie. the "executable" schema that is constructed as described above) -- `context` - context function that builds context for all components in the tree. -- `types` - this component's types. -- `resolvers` - this component's resolvers. -- `imports` - this component's imported components in the form of import configuration objects -- `mocks` - custom mocks for this component. -- `directives` - this component's directives. -- `dataSources` - this component's data source(s), if any. +This uses `@apollo/federation`'s `buildSubgraphSchema()` instead of `makeExecutableSchema()`. -# General usage +## API Reference -Creating a component using the GraphQLComponent class: +### GraphQLComponent Constructor -```javascript -const GraphQLComponent = require('graphql-component'); +```typescript +new GraphQLComponent(options: IGraphQLComponentOptions) +``` -const { schema, context } = new GraphQLComponent({ types, resolvers }); +#### Options + +- `types`: `string | string[]` - GraphQL SDL type definitions +- `resolvers`: `object` - Resolver map for the schema +- `imports`: `Array` - Components to import +- `context`: `{ namespace: string, factory: Function }` - Context configuration +- `mocks`: `boolean | object` - Enable default or custom mocks +- `dataSources`: `Array` - Data source instances +- `dataSourceOverrides`: `Array` - Override default data sources +- `federation`: `boolean` - Enable Apollo Federation support (default: `false`) +- `pruneSchema`: `boolean` - Enable schema pruning (default: `false`) +- `pruneSchemaOptions`: `object` - Schema pruning options +- `transforms`: `Array` - Schema transformation functions + +### Component Instance Properties + +```typescript +interface IGraphQLComponent { + readonly name: string; + readonly schema: GraphQLSchema; + readonly context: IContextWrapper; + readonly types: TypeSource; + readonly resolvers: IResolvers; + readonly imports?: (IGraphQLComponent | IGraphQLComponentConfigObject)[]; + readonly dataSources?: IDataSource[]; + readonly dataSourceOverrides?: IDataSource[]; + federation?: boolean; +} ``` -### Encapsulating state +## Usage Examples -Typically the best way to make a re-useable component with instance data will be to extend `GraphQLComponent`. +### Component Extension ```javascript -const GraphQLComponent = require('graphql-component'); -const resolvers = require('./resolvers'); -const types = require('./types'); -const mocks = require('./mocks'); - class PropertyComponent extends GraphQLComponent { - constructor({ types, resolvers }) { - super({ types, resolvers }); + constructor(options) { + super({ + types, + resolvers, + ...options + }); } } - -module.exports = PropertyComponent; ``` -### Aggregation - -Example to merge multiple components: +### Schema Aggregation ```javascript const { schema, context } = new GraphQLComponent({ imports: [ - new Property(), - new Reviews() + new PropertyComponent(), + new ReviewsComponent() ] }); -const server = new ApolloServer({ - schema, - context -}); -``` - -### Import configuration - -Imports can be a configuration object supplying the following properties: - -- `component` - the component instance to import. -- `exclude` - fields on types to exclude from the component being imported, if any. - -### Exclude - -You can exclude whole types or individual fields on types. - -```javascript -const { schema, context } = new GraphQLComponent({ - imports: [ - { - component: new Property(), - exclude: ['Mutation.*'] - }, - { - component: new Reviews(), - exclude: ['Mutation.*'] - } - ] -}); +const server = new ApolloServer({ schema, context }); ``` -The excluded types will not appear in the aggregate or gateway schema exposed by the root component, but are still present in the schema encapsulated by the underlying component. This can keep from leaking unintended API surface area, if desired. You can still delegate calls to imported component's schema to utilize the excluded field under the covers. - -### Data Source support - -Data sources in `graphql-component` do not extend `apollo-datasource`'s `DataSource` class. - -Instead, data sources in components will be injected into the context, but wrapped in a proxy such that the global -context will be injected as the first argument of any function implemented in a data source class. +### Data Sources -This allows there to exist one instance of a data source for caching or other statefulness (like circuit breakers), -while still ensuring that a data source will have the current context. +Data sources in `graphql-component` use a proxy-based approach for context injection. The library provides two key types to assist with correct implementation: -For example, a data source should be implemented like: - -```javascript -class PropertyDataSource { - async getPropertyById(context, id) { - //do some work... +```typescript +// When implementing a data source: +class MyDataSource implements DataSourceDefinition { + name = 'MyDataSource'; + + // Context must be the first parameter when implementing + async getUserById(context: ComponentContext, id: string) { + // Use context for auth, config, etc. + return { id, name: 'User Name' }; } } -``` - -This data source would be executed without passing the `context` manually: -```javascript +// In resolvers, context is automatically injected: const resolvers = { Query: { - property(_, { id }, { dataSources }) { - return dataSources.PropertyDataSource.getPropertyById(id); + user(_, { id }, context) { + // Don't need to pass context - it's injected automatically + return context.dataSources.MyDataSource.getUserById(id); } } } -``` - -Setting up a component to use a data source might look like: -```javascript +// Add to component: new GraphQLComponent({ - //... - dataSources: [new PropertyDataSource()] -}) + types, + resolvers, + dataSources: [new MyDataSource()] +}); ``` -### Override data sources - -Since data sources are added to the context based on the constructor name, it is possible to simply override data sources by passing the same class name or overriding the constructor name: +#### Data Source Types + +- `DataSourceDefinition`: Interface for implementing data sources - methods must accept context as first parameter +- `DataSource`: Type representing data sources after proxy wrapping - context is automatically injected + +This type system ensures proper context handling while providing a clean API for resolver usage. + +#### TypeScript Example + +```typescript +import { + GraphQLComponent, + DataSourceDefinition, + ComponentContext +} from 'graphql-component'; + +// Define your data source with proper types +class UsersDataSource implements DataSourceDefinition { + name = 'users'; + + // Static property + defaultRole = 'user'; + + // Context is required as first parameter when implementing + async getUserById(context: ComponentContext, id: string): Promise { + // Access context properties (auth, etc.) + const apiKey = context.config?.apiKey; + + // Implementation details... + return { id, name: 'User Name', role: this.defaultRole }; + } + + async getUsersByRole(context: ComponentContext, role: string): Promise { + // Implementation details... + return [ + { id: '1', name: 'User 1', role }, + { id: '2', name: 'User 2', role } + ]; + } +} -```javascript -const { schema, context } = new GraphQLComponent({ - imports: [ - { - component: new Property(), - exclude: ['Mutation.*'] +// In resolvers, the context is automatically injected +const resolvers = { + Query: { + user: (_, { id }, context) => { + // No need to pass context - it's injected by the proxy + return context.dataSources.users.getUserById(id); }, - { - component: new Reviews(), - exclude: ['Mutation.*'] + usersByRole: (_, { role }, context) => { + // No need to pass context - it's injected by the proxy + return context.dataSources.users.getUsersByRole(role); } - ], - dataSourceOverrides: [ - new class PropertyMock { - static get name() { - return 'PropertyDataSource'; - } - //...etc + } +}; + +// Component configuration +const usersComponent = new GraphQLComponent({ + types: ` + type User { + id: ID! + name: String! + role: String! } - ] + + type Query { + user(id: ID!): User + usersByRole(role: String!): [User] + } + `, + resolvers, + dataSources: [new UsersDataSource()] }); ``` -### Decorating the global context +#### Data Source Overrides -Example context argument: +You can override data sources when needed (for testing or extending functionality). The override must follow the same interface: -```javascript -const context = { - namespace: 'myNamespace', - factory: function ({ req }) { - return 'my value'; +```typescript +// For testing - create a mock data source +class MockUsersDataSource implements DataSourceDefinition { + name = 'users'; + defaultRole = 'admin'; + + async getUserById(context: ComponentContext, id: string) { + return { id, name: 'Mock User', role: this.defaultRole }; } -}; + + async getUsersByRole(context: ComponentContext, role: string) { + return [{ id: 'mock', name: 'Mock User', role }]; + } +} + +// Use the component with overrides +const testComponent = new GraphQLComponent({ + imports: [usersComponent], + dataSourceOverrides: [new MockUsersDataSource()] +}); + +// In tests +const context = await testComponent.context({}); +const mockUser = await context.dataSources.users.getUserById('any-id'); +// mockUser will be { id: 'any-id', name: 'Mock User', role: 'admin' } ``` -After this, resolver `context` will contain `{ ..., myNamespace: 'my value' }`. +## Examples -### Context middleware +The repository includes example implementations: -It may be necessary to transform the context before invoking component context. +### Local Schema Composition +```bash +npm run start-composition +``` -```javascript -const { schema, context } = new GraphQLComponent({types, resolvers, context}); +### Federation Example +```bash +npm run start-federation +``` -context.use('transformRawRequest', ({ request }) => { - return { req: request.raw.req }; -}); +Both examples are accessible at `http://localhost:4000/graphql` + +## Debugging + +Enable debug logging with: +```bash +DEBUG=graphql-component:* node your-app.js ``` -Using `context` now in `apollo-server-hapi` for example, will transform the context to one similar to default `apollo-server`. +## Repository Structure + +- `src/` - Core library code +- `examples/` + - `composition/` - Schema composition example + - `federation/` - Federation implementation example + +## Contributing + +Please read our contributing guidelines (link) for details on our code of conduct and development process. + +## License + +This project is licensed under the MIT License - see the LICENSE file for details. diff --git a/dist/index.d.ts b/dist/index.d.ts new file mode 100644 index 0000000..55579f4 --- /dev/null +++ b/dist/index.d.ts @@ -0,0 +1,118 @@ +import { GraphQLResolveInfo, GraphQLSchema } from 'graphql'; +import { IResolvers, PruneSchemaOptions, TypeSource, SchemaMapper } from '@graphql-tools/utils'; +import { IMocks } from '@graphql-tools/mock'; +import { SubschemaConfig } from '@graphql-tools/delegate'; +export type ResolverFunction = (_: any, args: any, ctx: any, info: GraphQLResolveInfo) => any; +export interface IGraphQLComponentConfigObject { + component: IGraphQLComponent; + configuration?: SubschemaConfig; +} +export interface ComponentContext extends Record { + dataSources: DataSourceMap; +} +export type ContextFunction = ((context: Record) => any); +export interface IDataSource { + name: string; + [key: string | symbol]: any; +} +/** + * Type for implementing data sources + * When defining a data source class, methods should accept context as their first parameter + * @example + * class MyDataSource { + * name = 'MyDataSource'; + * + * // Context is required as first parameter when implementing + * getData(context: ComponentContext, id: string) { + * return { id }; + * } + * } + */ +export type DataSourceDefinition = { + [P in keyof T]: T[P] extends Function ? (context: ComponentContext, ...args: any[]) => any : T[P]; +}; +/** + * Type for consuming data sources in resolvers + * When using a data source method, the context is automatically injected + * @example + * // In a resolver: + * Query: { + * getData(_, { id }, context) { + * // Context is automatically injected, so you don't pass it + * return context.dataSources.MyDataSource.getData(id); + * } + * } + */ +export type DataSource = { + [P in keyof T]: T[P] extends (context: ComponentContext, ...p: infer P) => infer R ? (...p: P) => R : T[P]; +}; +export type DataSourceMap = { + [key: string]: IDataSource; +}; +export type DataSourceInjectionFunction = ((context: Record) => DataSourceMap); +export interface IContextConfig { + namespace: string; + factory: ContextFunction; +} +export interface IContextWrapper extends ContextFunction { + use: (name: string | ContextFunction | null, fn?: ContextFunction | string) => void; +} +export interface IGraphQLComponentOptions { + types?: TypeSource; + resolvers?: IResolvers; + mocks?: boolean | IMocks; + imports?: (IGraphQLComponent | IGraphQLComponentConfigObject)[]; + context?: IContextConfig; + dataSources?: IDataSource[]; + dataSourceOverrides?: IDataSource[]; + pruneSchema?: boolean; + pruneSchemaOptions?: PruneSchemaOptions; + federation?: boolean; + transforms?: SchemaMapper[]; +} +export interface IGraphQLComponent { + readonly name: string; + readonly schema: GraphQLSchema; + readonly context: IContextWrapper; + readonly types: TypeSource; + readonly resolvers: IResolvers; + readonly imports?: (IGraphQLComponent | IGraphQLComponentConfigObject)[]; + readonly dataSources?: IDataSource[]; + readonly dataSourceOverrides?: IDataSource[]; + federation?: boolean; +} +/** + * GraphQLComponent class for building modular GraphQL schemas + * @template TContextType - The type of the context object + * @implements {IGraphQLComponent} + */ +export default class GraphQLComponent implements IGraphQLComponent { + _schema: GraphQLSchema; + _types: TypeSource; + _resolvers: IResolvers; + _mocks: boolean | IMocks; + _imports: IGraphQLComponentConfigObject[]; + _context: ContextFunction; + _dataSources: IDataSource[]; + _dataSourceOverrides: IDataSource[]; + _pruneSchema: boolean; + _pruneSchemaOptions: PruneSchemaOptions; + _federation: boolean; + _dataSourceContextInject: DataSourceInjectionFunction; + _transforms: SchemaMapper[]; + private _transformedSchema; + constructor({ types, resolvers, mocks, imports, context, dataSources, dataSourceOverrides, pruneSchema, pruneSchemaOptions, federation, transforms }: IGraphQLComponentOptions); + get context(): IContextWrapper; + get name(): string; + get schema(): GraphQLSchema; + get types(): TypeSource; + get resolvers(): IResolvers; + get imports(): IGraphQLComponentConfigObject[]; + get dataSources(): IDataSource[]; + get dataSourceOverrides(): IDataSource[]; + set federation(flag: boolean); + get federation(): boolean; + dispose(): void; + private transformSchema; + private validateConfig; +} diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..6eb74a0 --- /dev/null +++ b/dist/index.js @@ -0,0 +1,349 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const debug_1 = __importDefault(require("debug")); +const federation_1 = require("@apollo/federation"); +const graphql_1 = require("graphql"); +const merge_1 = require("@graphql-tools/merge"); +const utils_1 = require("@graphql-tools/utils"); +const schema_1 = require("@graphql-tools/schema"); +const stitch_1 = require("@graphql-tools/stitch"); +const mock_1 = require("@graphql-tools/mock"); +const debug = (0, debug_1.default)('graphql-component'); +/** + * GraphQLComponent class for building modular GraphQL schemas + * @template TContextType - The type of the context object + * @implements {IGraphQLComponent} + */ +class GraphQLComponent { + _schema; + _types; + _resolvers; + _mocks; + _imports; + _context; + _dataSources; + _dataSourceOverrides; + _pruneSchema; + _pruneSchemaOptions; + _federation; + _dataSourceContextInject; + _transforms; + _transformedSchema; + constructor({ types, resolvers, mocks, imports, context, dataSources, dataSourceOverrides, pruneSchema, pruneSchemaOptions, federation, transforms }) { + this._types = Array.isArray(types) ? types : [types]; + this._resolvers = bindResolvers(this, resolvers); + this._mocks = mocks; + this._federation = federation; + this._transforms = transforms; + this._dataSources = dataSources || []; + this._dataSourceOverrides = dataSourceOverrides || []; + this._dataSourceContextInject = createDataSourceContextInjector(this._dataSources, this._dataSourceOverrides); + this._pruneSchema = pruneSchema; + this._pruneSchemaOptions = pruneSchemaOptions; + this._imports = imports && imports.length > 0 ? imports.map((i) => { + if (i instanceof GraphQLComponent) { + if (this._federation === true) { + i.federation = true; + } + return { component: i }; + } + else { + const importConfiguration = i; + if (this._federation === true) { + importConfiguration.component.federation = true; + } + return importConfiguration; + } + }) : []; + this._context = async (globalContext) => { + //TODO: currently the context injected into data sources won't have data sources on it + const ctx = { + dataSources: this._dataSourceContextInject(globalContext) + }; + for (const { component } of this.imports) { + const { dataSources, ...importedContext } = await component.context(globalContext); + Object.assign(ctx.dataSources, dataSources); + Object.assign(ctx, importedContext); + } + if (context) { + debug(`building ${context.namespace} context`); + if (!ctx[context.namespace]) { + ctx[context.namespace] = {}; + } + Object.assign(ctx[context.namespace], await context.factory.call(this, globalContext)); + } + return ctx; + }; + this.validateConfig({ types, imports, mocks, federation }); + } + get context() { + const contextFn = async (context) => { + debug(`building root context`); + const middleware = contextFn._middleware || []; + for (const { name, fn } of middleware) { + debug(`applying ${name} middleware`); + context = await fn(context); + } + const componentContext = await this._context(context); + const globalContext = { + ...context, + ...componentContext + }; + return globalContext; + }; + contextFn._middleware = []; + contextFn.use = function (name, fn) { + if (typeof name === 'function') { + fn = name; + name = 'unknown'; + } + debug(`adding ${name} middleware`); + contextFn._middleware.push({ name, fn }); + return contextFn; + }; + return contextFn; + } + get name() { + return this.constructor.name; + } + get schema() { + try { + if (this._schema) { + return this._schema; + } + let makeSchema; + if (this._federation) { + makeSchema = federation_1.buildFederatedSchema; + } + else { + makeSchema = schema_1.makeExecutableSchema; + } + if (this._imports.length > 0) { + // iterate through the imports and construct subschema configuration objects + const subschemas = this._imports.map((imp) => { + const { component, configuration = {} } = imp; + return { + schema: component.schema, + ...configuration + }; + }); + // construct an aggregate schema from the schemas of imported + // components and this component's types/resolvers (if present) + this._schema = (0, stitch_1.stitchSchemas)({ + subschemas, + typeDefs: this._types, + resolvers: this._resolvers, + mergeDirectives: true + }); + } + else { + const schemaConfig = { + typeDefs: (0, merge_1.mergeTypeDefs)(this._types), + resolvers: this._resolvers + }; + this._schema = makeSchema(schemaConfig); + } + if (this._transforms) { + this._schema = this.transformSchema(this._schema, this._transforms); + } + if (this._mocks !== undefined && typeof this._mocks === 'boolean' && this._mocks === true) { + debug(`adding default mocks to the schema for ${this.name}`); + // if mocks are a boolean support simply applying default mocks + this._schema = (0, mock_1.addMocksToSchema)({ schema: this._schema, preserveResolvers: true }); + } + else if (this._mocks !== undefined && typeof this._mocks === 'object') { + debug(`adding custom mocks to the schema for ${this.name}`); + // else if mocks is an object, that means the user provided + // custom mocks, with which we pass them to addMocksToSchema so they are applied + this._schema = (0, mock_1.addMocksToSchema)({ schema: this._schema, mocks: this._mocks, preserveResolvers: true }); + } + if (this._pruneSchema) { + debug(`pruning the schema for ${this.name}`); + this._schema = (0, utils_1.pruneSchema)(this._schema, this._pruneSchemaOptions); + } + debug(`created schema for ${this.name}`); + return this._schema; + } + catch (error) { + debug(`Error creating schema for ${this.name}: ${error}`); + throw new Error(`Failed to create schema for component ${this.name}: ${error.message}`); + } + } + get types() { + return this._types; + } + get resolvers() { + return this._resolvers; + } + get imports() { + return this._imports; + } + get dataSources() { + return this._dataSources; + } + get dataSourceOverrides() { + return this._dataSourceOverrides; + } + set federation(flag) { + this._federation = flag; + } + get federation() { + return this._federation; + } + dispose() { + this._schema = null; + this._types = null; + this._resolvers = null; + this._imports = null; + this._dataSources = null; + this._dataSourceOverrides = null; + } + transformSchema(schema, transforms) { + if (this._transformedSchema) { + return this._transformedSchema; + } + const functions = {}; + const mapping = {}; + for (const transform of transforms) { + for (const [key, fn] of Object.entries(transform)) { + if (!mapping[key]) { + functions[key] = []; + let result = undefined; + mapping[key] = function (...args) { + while (functions[key].length) { + const mapper = functions[key].shift(); + result = mapper(...args); + if (!result) { + break; + } + } + return result; + }; + } + functions[key].push(fn); + } + } + this._transformedSchema = (0, utils_1.mapSchema)(schema, mapping); + return this._transformedSchema; + } + validateConfig(options) { + if (options.federation && !options.types) { + throw new Error('Federation requires type definitions'); + } + if (options.mocks && typeof options.mocks !== 'boolean' && typeof options.mocks !== 'object') { + throw new Error('mocks must be either boolean or object'); + } + } +} +exports.default = GraphQLComponent; +/** + * Wraps data sources with a proxy that intercepts calls to data source methods and injects the current context + * @param {IDataSource[]} dataSources + * @param {IDataSource[]} dataSourceOverrides + * @returns {DataSourceInjectionFunction} a function that returns a map of data sources with methods that have been intercepted + */ +const createDataSourceContextInjector = (dataSources, dataSourceOverrides) => { + const intercept = (instance, context) => { + debug(`intercepting ${instance.constructor.name}`); + return new Proxy(instance, { + get(target, key) { + if (typeof target[key] !== 'function' || key === instance.constructor.name) { + return target[key]; + } + const original = target[key]; + return function (...args) { + return original.call(instance, context, ...args); + }; + } + }); + }; + return (context = {}) => { + const proxiedDataSources = {}; + // Inject data sources + for (const dataSource of dataSources) { + proxiedDataSources[dataSource.name || dataSource.constructor.name] = intercept(dataSource, context); + } + // Override data sources + for (const dataSourceOverride of dataSourceOverrides) { + proxiedDataSources[dataSourceOverride.name || dataSourceOverride.constructor.name] = intercept(dataSourceOverride, context); + } + return proxiedDataSources; + }; +}; +/** + * memoizes resolver functions such that calls of an identical resolver (args/context/path) within the same request context are avoided + * @param {string} parentType - the type whose field resolver is being + * wrapped/memoized + * @param {string} fieldName - the field on the parentType whose resolver + * function is being wrapped/memoized + * @param {function} resolve - the resolver function that parentType. + * fieldName is mapped to + * @returns {function} a function that wraps the input resolver function and + * whose closure scope contains a WeakMap to achieve memoization of the wrapped + * input resolver function + */ +const memoize = function (parentType, fieldName, resolve) { + const _cache = new WeakMap(); + return function _memoizedResolver(_, args, context, info) { + const path = info && info.path && info.path.key; + const key = `${path}_${JSON.stringify(args)}`; + debug(`executing ${parentType}.${fieldName}`); + let cached = _cache.get(context); + if (cached && cached[key]) { + debug(`return cached result of memoized ${parentType}.${fieldName}`); + return cached[key]; + } + if (!cached) { + cached = {}; + } + const result = resolve(_, args, context, info); + cached[key] = result; + _cache.set(context, cached); + debug(`cached ${parentType}.${fieldName}`); + return result; + }; +}; +/** + * make 'this' in resolver functions equal to the input bindContext + * @param {Object} bind - the object context to bind to resolver functions + * @param {Object} resolvers - the resolver map containing the resolver + * functions to bind + * @returns {Object} - an object identical in structure to the input resolver + * map, except with resolver function bound to the input argument bind + */ +const bindResolvers = function (bindContext, resolvers = {}) { + const boundResolvers = {}; + for (const [type, fields] of Object.entries(resolvers)) { + // dont bind an object that is an instance of a graphql scalar + if (fields instanceof graphql_1.GraphQLScalarType) { + debug(`not binding ${type}'s fields since ${type}'s fields are an instance of GraphQLScalarType`); + boundResolvers[type] = fields; + continue; + } + if (!boundResolvers[type]) { + boundResolvers[type] = {}; + } + for (const [field, resolver] of Object.entries(fields)) { + if (['Query', 'Mutation'].indexOf(type) > -1) { + debug(`memoized ${type}.${field}`); + boundResolvers[type][field] = memoize(type, field, resolver.bind(bindContext)); + } + else { + // only bind resolvers that are functions + if (typeof resolver === 'function') { + debug(`binding ${type}.${field}`); + boundResolvers[type][field] = resolver.bind(bindContext); + } + else { + debug(`not binding ${type}.${field} since ${field} is not mapped to a function`); + boundResolvers[type][field] = resolver; + } + } + } + } + return boundResolvers; +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxrREFBZ0M7QUFDaEMsbURBQTBEO0FBQzFELHFDQUErRTtBQUUvRSxnREFBcUQ7QUFDckQsZ0RBTzhCO0FBQzlCLGtEQUE2RDtBQUM3RCxrREFBc0Q7QUFDdEQsOENBQStEO0FBRy9ELE1BQU0sS0FBSyxHQUFHLElBQUEsZUFBVyxFQUFDLG1CQUFtQixDQUFDLENBQUM7QUE2Ri9DOzs7O0dBSUc7QUFDSCxNQUFxQixnQkFBZ0I7SUFDbkMsT0FBTyxDQUFnQjtJQUN2QixNQUFNLENBQWE7SUFDbkIsVUFBVSxDQUFnQztJQUMxQyxNQUFNLENBQW1CO0lBQ3pCLFFBQVEsQ0FBa0M7SUFDMUMsUUFBUSxDQUFrQjtJQUMxQixZQUFZLENBQWdCO0lBQzVCLG9CQUFvQixDQUFnQjtJQUNwQyxZQUFZLENBQVU7SUFDdEIsbUJBQW1CLENBQW9CO0lBQ3ZDLFdBQVcsQ0FBVTtJQUNyQix3QkFBd0IsQ0FBOEI7SUFDdEQsV0FBVyxDQUFnQjtJQUNuQixrQkFBa0IsQ0FBZ0I7SUFFMUMsWUFBWSxFQUNWLEtBQUssRUFDTCxTQUFTLEVBQ1QsS0FBSyxFQUNMLE9BQU8sRUFDUCxPQUFPLEVBQ1AsV0FBVyxFQUNYLG1CQUFtQixFQUNuQixXQUFXLEVBQ1gsa0JBQWtCLEVBQ2xCLFVBQVUsRUFDVixVQUFVLEVBQ2U7UUFFekIsSUFBSSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFckQsSUFBSSxDQUFDLFVBQVUsR0FBRyxhQUFhLENBQUMsSUFBSSxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBRWpELElBQUksQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDO1FBRXBCLElBQUksQ0FBQyxXQUFXLEdBQUcsVUFBVSxDQUFDO1FBRTlCLElBQUksQ0FBQyxXQUFXLEdBQUcsVUFBVSxDQUFDO1FBRTlCLElBQUksQ0FBQyxZQUFZLEdBQUcsV0FBVyxJQUFJLEVBQUUsQ0FBQztRQUV0QyxJQUFJLENBQUMsb0JBQW9CLEdBQUcsbUJBQW1CLElBQUksRUFBRSxDQUFDO1FBRXRELElBQUksQ0FBQyx3QkFBd0IsR0FBRywrQkFBK0IsQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1FBRTlHLElBQUksQ0FBQyxZQUFZLEdBQUcsV0FBVyxDQUFDO1FBRWhDLElBQUksQ0FBQyxtQkFBbUIsR0FBRyxrQkFBa0IsQ0FBQztRQUU5QyxJQUFJLENBQUMsUUFBUSxHQUFHLE9BQU8sSUFBSSxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQW1ELEVBQUUsRUFBRTtZQUNsSCxJQUFJLENBQUMsWUFBWSxnQkFBZ0IsRUFBRSxDQUFDO2dCQUNsQyxJQUFJLElBQUksQ0FBQyxXQUFXLEtBQUssSUFBSSxFQUFFLENBQUM7b0JBQzlCLENBQUMsQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDO2dCQUN0QixDQUFDO2dCQUNELE9BQU8sRUFBRSxTQUFTLEVBQUUsQ0FBQyxFQUFFLENBQUM7WUFDMUIsQ0FBQztpQkFDSSxDQUFDO2dCQUNKLE1BQU0sbUJBQW1CLEdBQUcsQ0FBa0MsQ0FBQztnQkFDL0QsSUFBSSxJQUFJLENBQUMsV0FBVyxLQUFLLElBQUksRUFBRSxDQUFDO29CQUM5QixtQkFBbUIsQ0FBQyxTQUFTLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQztnQkFDbEQsQ0FBQztnQkFDRCxPQUFPLG1CQUFtQixDQUFDO1lBQzdCLENBQUM7UUFDSCxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBR1IsSUFBSSxDQUFDLFFBQVEsR0FBRyxLQUFLLEVBQUUsYUFBc0MsRUFBeUIsRUFBRTtZQUN0RixzRkFBc0Y7WUFDdEYsTUFBTSxHQUFHLEdBQUc7Z0JBQ1YsV0FBVyxFQUFFLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxhQUFhLENBQUM7YUFDMUQsQ0FBQztZQUVGLEtBQUssTUFBTSxFQUFFLFNBQVMsRUFBRSxJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDekMsTUFBTSxFQUFFLFdBQVcsRUFBRSxHQUFHLGVBQWUsRUFBRSxHQUFHLE1BQU0sU0FBUyxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQztnQkFDbkYsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsV0FBVyxFQUFFLFdBQVcsQ0FBQyxDQUFDO2dCQUM1QyxNQUFNLENBQUMsTUFBTSxDQUFDLEdBQUcsRUFBRSxlQUFlLENBQUMsQ0FBQztZQUN0QyxDQUFDO1lBRUQsSUFBSSxPQUFPLEVBQUUsQ0FBQztnQkFDWixLQUFLLENBQUMsWUFBWSxPQUFPLENBQUMsU0FBUyxVQUFVLENBQUMsQ0FBQztnQkFFL0MsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQztvQkFDNUIsR0FBRyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFLENBQUM7Z0JBQzlCLENBQUM7Z0JBRUQsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFLE1BQU0sT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLGFBQWEsQ0FBQyxDQUFDLENBQUM7WUFDekYsQ0FBQztZQUVELE9BQU8sR0FBbUIsQ0FBQztRQUM3QixDQUFDLENBQUM7UUFFRixJQUFJLENBQUMsY0FBYyxDQUFDLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLENBQUMsQ0FBQztJQUU3RCxDQUFDO0lBRUQsSUFBSSxPQUFPO1FBRVQsTUFBTSxTQUFTLEdBQUcsS0FBSyxFQUFFLE9BQWdDLEVBQTZCLEVBQUU7WUFDdEYsS0FBSyxDQUFDLHVCQUF1QixDQUFDLENBQUM7WUFFL0IsTUFBTSxVQUFVLEdBQXVCLFNBQWlCLENBQUMsV0FBVyxJQUFJLEVBQUUsQ0FBQztZQUUzRSxLQUFLLE1BQU0sRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFLElBQUksVUFBVSxFQUFFLENBQUM7Z0JBQ3RDLEtBQUssQ0FBQyxZQUFZLElBQUksYUFBYSxDQUFDLENBQUM7Z0JBQ3JDLE9BQU8sR0FBRyxNQUFNLEVBQUUsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUM5QixDQUFDO1lBRUQsTUFBTSxnQkFBZ0IsR0FBRyxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUM7WUFFdEQsTUFBTSxhQUFhLEdBQUc7Z0JBQ3BCLEdBQUcsT0FBTztnQkFDVixHQUFHLGdCQUFnQjthQUNwQixDQUFDO1lBRUYsT0FBTyxhQUFhLENBQUM7UUFDdkIsQ0FBQyxDQUFDO1FBRUYsU0FBUyxDQUFDLFdBQVcsR0FBRyxFQUFFLENBQUM7UUFFM0IsU0FBUyxDQUFDLEdBQUcsR0FBRyxVQUFVLElBQVksRUFBRSxFQUFtQjtZQUN6RCxJQUFJLE9BQU8sSUFBSSxLQUFLLFVBQVUsRUFBRSxDQUFDO2dCQUMvQixFQUFFLEdBQUcsSUFBSSxDQUFDO2dCQUNWLElBQUksR0FBRyxTQUFTLENBQUM7WUFDbkIsQ0FBQztZQUNELEtBQUssQ0FBQyxVQUFVLElBQUksYUFBYSxDQUFDLENBQUM7WUFDbkMsU0FBUyxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUV6QyxPQUFPLFNBQVMsQ0FBQztRQUNuQixDQUFDLENBQUM7UUFFRixPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDO0lBRUQsSUFBSSxJQUFJO1FBQ04sT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQztJQUMvQixDQUFDO0lBRUQsSUFBSSxNQUFNO1FBQ1IsSUFBSSxDQUFDO1lBQ0gsSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQ2pCLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQztZQUN0QixDQUFDO1lBRUQsSUFBSSxVQUFnRCxDQUFDO1lBRXJELElBQUksSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO2dCQUNyQixVQUFVLEdBQUcsaUNBQW9CLENBQUM7WUFDcEMsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLFVBQVUsR0FBRyw2QkFBb0IsQ0FBQztZQUNwQyxDQUFDO1lBRUQsSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDN0IsNEVBQTRFO2dCQUM1RSxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFO29CQUMzQyxNQUFNLEVBQUUsU0FBUyxFQUFFLGFBQWEsR0FBRyxFQUFFLEVBQUUsR0FBRyxHQUFHLENBQUM7b0JBRTlDLE9BQU87d0JBQ0wsTUFBTSxFQUFFLFNBQVMsQ0FBQyxNQUFNO3dCQUN4QixHQUFHLGFBQWE7cUJBQ2pCLENBQUM7Z0JBQ0osQ0FBQyxDQUFDLENBQUM7Z0JBRUgsNkRBQTZEO2dCQUM3RCwrREFBK0Q7Z0JBQy9ELElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBQSxzQkFBYSxFQUFDO29CQUMzQixVQUFVO29CQUNWLFFBQVEsRUFBRSxJQUFJLENBQUMsTUFBTTtvQkFDckIsU0FBUyxFQUFFLElBQUksQ0FBQyxVQUFVO29CQUMxQixlQUFlLEVBQUUsSUFBSTtpQkFDdEIsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztpQkFDSSxDQUFDO2dCQUNKLE1BQU0sWUFBWSxHQUFHO29CQUNuQixRQUFRLEVBQUUsSUFBQSxxQkFBYSxFQUFDLElBQUksQ0FBQyxNQUFNLENBQUM7b0JBQ3BDLFNBQVMsRUFBRSxJQUFJLENBQUMsVUFBVTtpQkFDM0IsQ0FBQTtnQkFFRCxJQUFJLENBQUMsT0FBTyxHQUFHLFVBQVUsQ0FBQyxZQUFZLENBQUMsQ0FBQztZQUMxQyxDQUFDO1lBRUQsSUFBSSxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7Z0JBQ3JCLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUN0RSxDQUFDO1lBRUQsSUFBSSxJQUFJLENBQUMsTUFBTSxLQUFLLFNBQVMsSUFBSSxPQUFPLElBQUksQ0FBQyxNQUFNLEtBQUssU0FBUyxJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssSUFBSSxFQUFFLENBQUM7Z0JBQzFGLEtBQUssQ0FBQywwQ0FBMEMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7Z0JBQzdELCtEQUErRDtnQkFDL0QsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFBLHVCQUFnQixFQUFDLEVBQUUsTUFBTSxFQUFFLElBQUksQ0FBQyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztZQUNyRixDQUFDO2lCQUNJLElBQUksSUFBSSxDQUFDLE1BQU0sS0FBSyxTQUFTLElBQUksT0FBTyxJQUFJLENBQUMsTUFBTSxLQUFLLFFBQVEsRUFBRSxDQUFDO2dCQUN0RSxLQUFLLENBQUMseUNBQXlDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO2dCQUM1RCwyREFBMkQ7Z0JBQzNELGdGQUFnRjtnQkFDaEYsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFBLHVCQUFnQixFQUFDLEVBQUUsTUFBTSxFQUFFLElBQUksQ0FBQyxPQUFPLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxNQUFNLEVBQUUsaUJBQWlCLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztZQUN6RyxDQUFDO1lBRUQsSUFBSSxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7Z0JBQ3RCLEtBQUssQ0FBQywwQkFBMEIsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7Z0JBQzdDLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBQSxtQkFBVyxFQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLG1CQUFtQixDQUFDLENBQUM7WUFDckUsQ0FBQztZQUVELEtBQUssQ0FBQyxzQkFBc0IsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7WUFFekMsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDO1FBQ3RCLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsS0FBSyxDQUFDLDZCQUE2QixJQUFJLENBQUMsSUFBSSxLQUFLLEtBQUssRUFBRSxDQUFDLENBQUM7WUFDMUQsTUFBTSxJQUFJLEtBQUssQ0FBQyx5Q0FBeUMsSUFBSSxDQUFDLElBQUksS0FBSyxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUMxRixDQUFDO0lBQ0gsQ0FBQztJQUVELElBQUksS0FBSztRQUNQLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQztJQUNyQixDQUFDO0lBRUQsSUFBSSxTQUFTO1FBQ1gsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDO0lBQ3pCLENBQUM7SUFFRCxJQUFJLE9BQU87UUFDVCxPQUFPLElBQUksQ0FBQyxRQUFRLENBQUM7SUFDdkIsQ0FBQztJQUVELElBQUksV0FBVztRQUNiLE9BQU8sSUFBSSxDQUFDLFlBQVksQ0FBQztJQUMzQixDQUFDO0lBRUQsSUFBSSxtQkFBbUI7UUFDckIsT0FBTyxJQUFJLENBQUMsb0JBQW9CLENBQUM7SUFDbkMsQ0FBQztJQUVELElBQUksVUFBVSxDQUFDLElBQUk7UUFDakIsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUM7SUFDMUIsQ0FBQztJQUVELElBQUksVUFBVTtRQUNaLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQztJQUMxQixDQUFDO0lBRU0sT0FBTztRQUNaLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDO1FBQ3BCLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDO1FBQ25CLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxvQkFBb0IsR0FBRyxJQUFJLENBQUM7SUFDbkMsQ0FBQztJQUVPLGVBQWUsQ0FBQyxNQUFxQixFQUFFLFVBQTBCO1FBQ3ZFLElBQUksSUFBSSxDQUFDLGtCQUFrQixFQUFFLENBQUM7WUFDNUIsT0FBTyxJQUFJLENBQUMsa0JBQWtCLENBQUM7UUFDakMsQ0FBQztRQUVELE1BQU0sU0FBUyxHQUFHLEVBQUUsQ0FBQztRQUNyQixNQUFNLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFFbkIsS0FBSyxNQUFNLFNBQVMsSUFBSSxVQUFVLEVBQUUsQ0FBQztZQUNuQyxLQUFLLE1BQU0sQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO2dCQUNsRCxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7b0JBQ2xCLFNBQVMsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUM7b0JBQ3BCLElBQUksTUFBTSxHQUFHLFNBQVMsQ0FBQztvQkFDdkIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLFVBQVUsR0FBRyxJQUFJO3dCQUM5QixPQUFPLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQzs0QkFDN0IsTUFBTSxNQUFNLEdBQUcsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDOzRCQUN0QyxNQUFNLEdBQUcsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUM7NEJBQ3pCLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztnQ0FDWixNQUFNOzRCQUNSLENBQUM7d0JBQ0gsQ0FBQzt3QkFDRCxPQUFPLE1BQU0sQ0FBQztvQkFDaEIsQ0FBQyxDQUFBO2dCQUNILENBQUM7Z0JBQ0QsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUMxQixDQUFDO1FBQ0gsQ0FBQztRQUVELElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFBLGlCQUFTLEVBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ3JELE9BQU8sSUFBSSxDQUFDLGtCQUFrQixDQUFDO0lBQ2pDLENBQUM7SUFFTyxjQUFjLENBQUMsT0FBaUM7UUFDdEQsSUFBSSxPQUFPLENBQUMsVUFBVSxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ3pDLE1BQU0sSUFBSSxLQUFLLENBQUMsc0NBQXNDLENBQUMsQ0FBQztRQUMxRCxDQUFDO1FBRUQsSUFBSSxPQUFPLENBQUMsS0FBSyxJQUFJLE9BQU8sT0FBTyxDQUFDLEtBQUssS0FBSyxTQUFTLElBQUksT0FBTyxPQUFPLENBQUMsS0FBSyxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQzdGLE1BQU0sSUFBSSxLQUFLLENBQUMsd0NBQXdDLENBQUMsQ0FBQztRQUM1RCxDQUFDO0lBQ0gsQ0FBQztDQUVGO0FBbFNELG1DQWtTQztBQUVEOzs7OztHQUtHO0FBQ0gsTUFBTSwrQkFBK0IsR0FBRyxDQUFDLFdBQTBCLEVBQUUsbUJBQWtDLEVBQStCLEVBQUU7SUFDdEksTUFBTSxTQUFTLEdBQUcsQ0FBQyxRQUFxQixFQUFFLE9BQVksRUFBRSxFQUFFO1FBQ3hELEtBQUssQ0FBQyxnQkFBZ0IsUUFBUSxDQUFDLFdBQVcsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBRW5ELE9BQU8sSUFBSSxLQUFLLENBQUMsUUFBUSxFQUFFO1lBQ3pCLEdBQUcsQ0FBQyxNQUFNLEVBQUUsR0FBRztnQkFDYixJQUFJLE9BQU8sTUFBTSxDQUFDLEdBQUcsQ0FBQyxLQUFLLFVBQVUsSUFBSSxHQUFHLEtBQUssUUFBUSxDQUFDLFdBQVcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztvQkFDM0UsT0FBTyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBQ3JCLENBQUM7Z0JBQ0QsTUFBTSxRQUFRLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUU3QixPQUFPLFVBQVUsR0FBRyxJQUFJO29CQUN0QixPQUFPLFFBQVEsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLE9BQU8sRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDO2dCQUNuRCxDQUFDLENBQUM7WUFDSixDQUFDO1NBQ0YsQ0FBdUMsQ0FBQztJQUMzQyxDQUFDLENBQUM7SUFFRixPQUFPLENBQUMsVUFBZSxFQUFFLEVBQWlCLEVBQUU7UUFDMUMsTUFBTSxrQkFBa0IsR0FBRyxFQUFFLENBQUM7UUFFOUIsc0JBQXNCO1FBQ3RCLEtBQUssTUFBTSxVQUFVLElBQUksV0FBVyxFQUFFLENBQUM7WUFDckMsa0JBQWtCLENBQUMsVUFBVSxDQUFDLElBQUksSUFBSSxVQUFVLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxHQUFHLFNBQVMsQ0FBQyxVQUFVLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDdEcsQ0FBQztRQUVELHdCQUF3QjtRQUN4QixLQUFLLE1BQU0sa0JBQWtCLElBQUksbUJBQW1CLEVBQUUsQ0FBQztZQUNyRCxrQkFBa0IsQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLElBQUksa0JBQWtCLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxHQUFHLFNBQVMsQ0FBQyxrQkFBa0IsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUM5SCxDQUFDO1FBRUQsT0FBTyxrQkFBa0IsQ0FBQztJQUM1QixDQUFDLENBQUM7QUFDSixDQUFDLENBQUM7QUFFRjs7Ozs7Ozs7Ozs7R0FXRztBQUNILE1BQU0sT0FBTyxHQUFHLFVBQVUsVUFBa0IsRUFBRSxTQUFpQixFQUFFLE9BQXlCO0lBQ3hGLE1BQU0sTUFBTSxHQUFHLElBQUksT0FBTyxFQUFFLENBQUM7SUFFN0IsT0FBTyxTQUFTLGlCQUFpQixDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLElBQUk7UUFDdEQsTUFBTSxJQUFJLEdBQUcsSUFBSSxJQUFJLElBQUksQ0FBQyxJQUFJLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUM7UUFDaEQsTUFBTSxHQUFHLEdBQUcsR0FBRyxJQUFJLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1FBRTlDLEtBQUssQ0FBQyxhQUFhLFVBQVUsSUFBSSxTQUFTLEVBQUUsQ0FBQyxDQUFDO1FBRTlDLElBQUksTUFBTSxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFakMsSUFBSSxNQUFNLElBQUksTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDMUIsS0FBSyxDQUFDLG9DQUFvQyxVQUFVLElBQUksU0FBUyxFQUFFLENBQUMsQ0FBQztZQUNyRSxPQUFPLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNyQixDQUFDO1FBRUQsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ1osTUFBTSxHQUFHLEVBQUUsQ0FBQztRQUNkLENBQUM7UUFFRCxNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFFL0MsTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLE1BQU0sQ0FBQztRQUVyQixNQUFNLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMsQ0FBQztRQUU1QixLQUFLLENBQUMsVUFBVSxVQUFVLElBQUksU0FBUyxFQUFFLENBQUMsQ0FBQztRQUUzQyxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDLENBQUM7QUFDSixDQUFDLENBQUM7QUFFRjs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxhQUFhLEdBQUcsVUFBVSxXQUE4QixFQUFFLFlBQXdCLEVBQUU7SUFDeEYsTUFBTSxjQUFjLEdBQUcsRUFBRSxDQUFDO0lBRTFCLEtBQUssTUFBTSxDQUFDLElBQUksRUFBRSxNQUFNLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7UUFDdkQsOERBQThEO1FBQzlELElBQUksTUFBTSxZQUFZLDJCQUFpQixFQUFFLENBQUM7WUFDeEMsS0FBSyxDQUFDLGVBQWUsSUFBSSxtQkFBbUIsSUFBSSxnREFBZ0QsQ0FBQyxDQUFBO1lBQ2pHLGNBQWMsQ0FBQyxJQUFJLENBQUMsR0FBRyxNQUFNLENBQUM7WUFDOUIsU0FBUztRQUNYLENBQUM7UUFFRCxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDMUIsY0FBYyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUM1QixDQUFDO1FBRUQsS0FBSyxNQUFNLENBQUMsS0FBSyxFQUFFLFFBQVEsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztZQUN2RCxJQUFJLENBQUMsT0FBTyxFQUFFLFVBQVUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDO2dCQUM3QyxLQUFLLENBQUMsWUFBWSxJQUFJLElBQUksS0FBSyxFQUFFLENBQUMsQ0FBQztnQkFDbkMsY0FBYyxDQUFDLElBQUksQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLE9BQU8sQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFLFFBQVEsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQztZQUNqRixDQUFDO2lCQUNJLENBQUM7Z0JBQ0oseUNBQXlDO2dCQUN6QyxJQUFJLE9BQU8sUUFBUSxLQUFLLFVBQVUsRUFBRSxDQUFDO29CQUNuQyxLQUFLLENBQUMsV0FBVyxJQUFJLElBQUksS0FBSyxFQUFFLENBQUMsQ0FBQztvQkFDbEMsY0FBYyxDQUFDLElBQUksQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7Z0JBQzNELENBQUM7cUJBQ0ksQ0FBQztvQkFDSixLQUFLLENBQUMsZUFBZSxJQUFJLElBQUksS0FBSyxVQUFVLEtBQUssOEJBQThCLENBQUMsQ0FBQztvQkFDakYsY0FBYyxDQUFDLElBQUksQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLFFBQVEsQ0FBQztnQkFDekMsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVELE9BQU8sY0FBYyxDQUFDO0FBQ3hCLENBQUMsQ0FBQyJ9 \ No newline at end of file diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..ba00bc5 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,16 @@ +import globals from "globals"; +import tseslint from "typescript-eslint"; + + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + {files: ["**/*.{js,mjs,cjs,ts}"]}, + {files: ["**/*.js"], languageOptions: {sourceType: "script"}}, + {languageOptions: { globals: globals.node }}, + ...tseslint.configs.recommended, + { + rules: { + "@typescript-eslint/no-explicit-any": "off" + } +} +]; \ No newline at end of file diff --git a/examples/composition/listing-component/index.js b/examples/composition/listing-component/index.ts similarity index 53% rename from examples/composition/listing-component/index.js rename to examples/composition/listing-component/index.ts index 0a7fe4a..ce8525f 100644 --- a/examples/composition/listing-component/index.js +++ b/examples/composition/listing-component/index.ts @@ -1,12 +1,16 @@ 'use strict'; -const GraphQLComponent = require('../../../lib/index'); -const Property = require('../property-component'); -const Reviews = require('../reviews-component'); -const resolvers = require('./resolvers'); -const types = require('./types'); +import { types } from "./types"; +import { resolvers } from "./resolvers"; +import GraphQLComponent from "../../../src"; +import Property from "../property-component"; +import Reviews from "../reviews-component"; -class ListingComponent extends GraphQLComponent { + +export default class ListingComponent extends GraphQLComponent { + propertyComponent: Property; + reviewsComponent: Reviews; + constructor(options) { const propertyComponent = new Property(); const reviewsComponent = new Reviews(); diff --git a/examples/composition/listing-component/resolvers.js b/examples/composition/listing-component/resolvers.ts similarity index 52% rename from examples/composition/listing-component/resolvers.js rename to examples/composition/listing-component/resolvers.ts index 004c891..3eb84d1 100644 --- a/examples/composition/listing-component/resolvers.js +++ b/examples/composition/listing-component/resolvers.ts @@ -1,8 +1,8 @@ 'use strict'; -const GraphQLComponent = require('../../../lib'); +import { delegateToSchema } from '@graphql-tools/delegate'; -const resolvers = { +export const resolvers = { Query: { async listing(_, { id }) { return { id }; @@ -10,26 +10,26 @@ const resolvers = { }, Listing: { property(root, args, context, info) { - return GraphQLComponent.delegateToComponent(this.propertyComponent, { + return delegateToSchema({ + schema: this.propertyComponent.schema, + fieldName: 'propertyById', args: { id: root.id }, context, info - }) + }); }, - reviews(root, args, context, info) { - return GraphQLComponent.delegateToComponent(this.reviewsComponent, { - operation: 'query', + reviews(root, args, context, info) {; + return delegateToSchema({ + schema: this.reviewsComponent.schema, fieldName: 'reviewsByPropertyId', args: { propertyId: root.id }, context, info - }) + }); } } }; - -module.exports = resolvers; diff --git a/examples/composition/listing-component/types.js b/examples/composition/listing-component/types.js deleted file mode 100644 index fed9e29..0000000 --- a/examples/composition/listing-component/types.js +++ /dev/null @@ -1,8 +0,0 @@ -'use strict'; - -const fs = require('fs'); -const path = require('path'); - -const types = fs.readFileSync(path.resolve(path.join(__dirname, 'schema.graphql')), 'utf-8'); - -module.exports = types; diff --git a/examples/composition/listing-component/types.ts b/examples/composition/listing-component/types.ts new file mode 100644 index 0000000..bb101ca --- /dev/null +++ b/examples/composition/listing-component/types.ts @@ -0,0 +1,7 @@ +'use strict'; + +import fs from 'fs'; +import path from 'path'; + +export const types = fs.readFileSync(path.resolve(path.join(__dirname, 'schema.graphql')), 'utf-8'); + diff --git a/examples/composition/property-component/datasource.js b/examples/composition/property-component/datasource.js deleted file mode 100644 index 0c8ce72..0000000 --- a/examples/composition/property-component/datasource.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -const propertiesDB = { - 1: { id: 1, geo: ['41.40338', '2.17403']}, - 2: { id: 2, geo: ['111.1111', '222.2222']} -} - -class PropertyDataSource { - getPropertyById(context, id) { - return propertiesDB[id]; - } -} - -module.exports = PropertyDataSource; \ No newline at end of file diff --git a/examples/composition/property-component/datasource.ts b/examples/composition/property-component/datasource.ts new file mode 100644 index 0000000..a1c14c1 --- /dev/null +++ b/examples/composition/property-component/datasource.ts @@ -0,0 +1,14 @@ +import { DataSourceDefinition, ComponentContext } from '../../../src'; + +const propertiesDB = { + 1: { id: 1, geo: ['41.40338', '2.17403']}, + 2: { id: 2, geo: ['111.1111', '222.2222']} +} + +export default class PropertyDataSource implements DataSourceDefinition { + name = 'PropertyDataSource'; + + getPropertyById(context: ComponentContext, id: string) { + return propertiesDB[id]; + } +} \ No newline at end of file diff --git a/examples/composition/property-component/index.js b/examples/composition/property-component/index.js deleted file mode 100644 index 45f15e8..0000000 --- a/examples/composition/property-component/index.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -const GraphQLComponent = require('../../../lib/index'); -const PropertyDataSource = require('./datasource'); -const resolvers = require('./resolvers'); -const types = require('./types'); - -class PropertyComponent extends GraphQLComponent { - constructor({ dataSources = [new PropertyDataSource()], ...options } = {}) { - super({ types, resolvers, dataSources, ...options }); - } -} - -module.exports = PropertyComponent; diff --git a/examples/composition/property-component/index.ts b/examples/composition/property-component/index.ts new file mode 100644 index 0000000..bccc28d --- /dev/null +++ b/examples/composition/property-component/index.ts @@ -0,0 +1,13 @@ + + +import { types } from "./types"; +import GraphQLComponent from "../../../src"; +import { resolvers } from "./resolvers"; +import PropertyDataSource from "./datasource"; + +export default class PropertyComponent extends GraphQLComponent { + constructor({ dataSources = [new PropertyDataSource()], ...options } = {}) { + super({ types, resolvers, dataSources, ...options }); + } +} + diff --git a/examples/composition/property-component/resolvers.js b/examples/composition/property-component/resolvers.js deleted file mode 100644 index a1d048b..0000000 --- a/examples/composition/property-component/resolvers.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; - -const resolvers = { - Query: { - property(_, { id }, { dataSources }) { - return dataSources.PropertyDataSource.getPropertyById(id); - } - } -}; - -module.exports = resolvers; diff --git a/examples/composition/property-component/resolvers.ts b/examples/composition/property-component/resolvers.ts new file mode 100644 index 0000000..e3aff87 --- /dev/null +++ b/examples/composition/property-component/resolvers.ts @@ -0,0 +1,9 @@ + + +export const resolvers = { + Query: { + propertyById(_, { id }, { dataSources }) { + return dataSources.PropertyDataSource.getPropertyById(id); + } + } +}; diff --git a/examples/composition/property-component/schema.graphql b/examples/composition/property-component/schema.graphql index b8a8f0b..cc832ec 100644 --- a/examples/composition/property-component/schema.graphql +++ b/examples/composition/property-component/schema.graphql @@ -4,5 +4,5 @@ type Property { } type Query { - property(id: ID!) : Property + propertyById(id: ID!) : Property } diff --git a/examples/composition/property-component/types.js b/examples/composition/property-component/types.js deleted file mode 100644 index fed9e29..0000000 --- a/examples/composition/property-component/types.js +++ /dev/null @@ -1,8 +0,0 @@ -'use strict'; - -const fs = require('fs'); -const path = require('path'); - -const types = fs.readFileSync(path.resolve(path.join(__dirname, 'schema.graphql')), 'utf-8'); - -module.exports = types; diff --git a/examples/composition/property-component/types.ts b/examples/composition/property-component/types.ts new file mode 100644 index 0000000..bb101ca --- /dev/null +++ b/examples/composition/property-component/types.ts @@ -0,0 +1,7 @@ +'use strict'; + +import fs from 'fs'; +import path from 'path'; + +export const types = fs.readFileSync(path.resolve(path.join(__dirname, 'schema.graphql')), 'utf-8'); + diff --git a/examples/composition/reviews-component/datasource.js b/examples/composition/reviews-component/datasource.ts similarity index 63% rename from examples/composition/reviews-component/datasource.js rename to examples/composition/reviews-component/datasource.ts index 45a6951..6234aa6 100644 --- a/examples/composition/reviews-component/datasource.js +++ b/examples/composition/reviews-component/datasource.ts @@ -1,15 +1,17 @@ 'use strict'; +import { ComponentContext, DataSourceDefinition } from "../../../src"; + // reviews indexed by property id const reviewsDB = { 1: [ { id: 'rev-id-1-a', content: 'this property was great'}, { id: 'rev-id-1-b', content: 'this property was terrible'}], 2: [ { id: 'rev-id-2-a', content: 'This property was amazing for our extended family'}, { id: 'rev-id-2-b', content: 'I loved the proximity to the beach'}, { id: 'rev-id-2-c', content: 'The bed was not comfortable at all'}] } -class ReviewsDataSource { - getReviewsByPropertyId(context, propertyId) { +export default class ReviewsDataSource implements DataSourceDefinition { + name = 'ReviewsDataSource'; + + getReviewsByPropertyId(context: ComponentContext, propertyId: string) { return reviewsDB[propertyId] } -}; - -module.exports = ReviewsDataSource; \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/composition/reviews-component/index.js b/examples/composition/reviews-component/index.js deleted file mode 100644 index 74ddea5..0000000 --- a/examples/composition/reviews-component/index.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -const GraphQLComponent = require('../../../lib/index'); -const ReviewsDataSource = require('./datasource'); -const resolvers = require('./resolvers'); -const types = require('./types'); - -class ReviewsComponent extends GraphQLComponent { - constructor({ dataSources = [new ReviewsDataSource()], ...options } = {}) { - super({ types, resolvers, dataSources, ...options }); - } -} - -module.exports = ReviewsComponent; diff --git a/examples/composition/reviews-component/index.ts b/examples/composition/reviews-component/index.ts new file mode 100644 index 0000000..7524075 --- /dev/null +++ b/examples/composition/reviews-component/index.ts @@ -0,0 +1,11 @@ + +import { types } from "./types"; +import GraphQLComponent from "../../../src"; +import { resolvers } from "./resolvers"; +import ReviewsDataSource from "./datasource"; + +export default class ReviewsComponent extends GraphQLComponent { + constructor({ dataSources = [new ReviewsDataSource()], ...options } = {}) { + super({ types, resolvers, dataSources, ...options }); + } +} diff --git a/examples/composition/reviews-component/resolvers.js b/examples/composition/reviews-component/resolvers.ts similarity index 72% rename from examples/composition/reviews-component/resolvers.js rename to examples/composition/reviews-component/resolvers.ts index f346603..cb90584 100644 --- a/examples/composition/reviews-component/resolvers.js +++ b/examples/composition/reviews-component/resolvers.ts @@ -1,11 +1,8 @@ -'use strict'; -const resolvers = { +export const resolvers = { Query: { reviewsByPropertyId(_, { propertyId }, { dataSources }) { return dataSources.ReviewsDataSource.getReviewsByPropertyId(propertyId); } } }; - -module.exports = resolvers; diff --git a/examples/composition/reviews-component/types.js b/examples/composition/reviews-component/types.js deleted file mode 100644 index fed9e29..0000000 --- a/examples/composition/reviews-component/types.js +++ /dev/null @@ -1,8 +0,0 @@ -'use strict'; - -const fs = require('fs'); -const path = require('path'); - -const types = fs.readFileSync(path.resolve(path.join(__dirname, 'schema.graphql')), 'utf-8'); - -module.exports = types; diff --git a/examples/composition/reviews-component/types.ts b/examples/composition/reviews-component/types.ts new file mode 100644 index 0000000..bb101ca --- /dev/null +++ b/examples/composition/reviews-component/types.ts @@ -0,0 +1,7 @@ +'use strict'; + +import fs from 'fs'; +import path from 'path'; + +export const types = fs.readFileSync(path.resolve(path.join(__dirname, 'schema.graphql')), 'utf-8'); + diff --git a/examples/composition/server/index.js b/examples/composition/server/index.ts similarity index 78% rename from examples/composition/server/index.js rename to examples/composition/server/index.ts index f85544c..08c9056 100644 --- a/examples/composition/server/index.js +++ b/examples/composition/server/index.ts @@ -4,7 +4,7 @@ const ListingComponent = require('../listing-component'); const { schema, context } = new ListingComponent(); -const server = new ApolloServer({ schema, context, tracing: true }); +const server = new ApolloServer({ schema, context, tracing: false }); server.listen().then(({ url }) => { console.log(`๐Ÿš€ Server ready at ${url}`) diff --git a/examples/federation/gateway.js b/examples/federation/gateway.ts similarity index 62% rename from examples/federation/gateway.js rename to examples/federation/gateway.ts index 0a3da29..b41b264 100644 --- a/examples/federation/gateway.js +++ b/examples/federation/gateway.ts @@ -1,8 +1,7 @@ -const { ApolloServer } = require('apollo-server'); -const { ApolloGateway } = require('@apollo/gateway'); +import { ApolloServer } from 'apollo-server'; +import { ApolloGateway } from '@apollo/gateway'; - -const run = async function() { +const run = async function(): Promise { const gateway = new ApolloGateway({ serviceList: [ { name: 'property', url: 'http://localhost:4001' }, @@ -11,12 +10,11 @@ const run = async function() { }); const server = new ApolloServer({ - gateway, - subscriptions: false + gateway }); const { url } = await server.listen({port: 4000}); console.log(`๐Ÿš€ Gateway ready at ${url}`); } -module.exports = { run }; \ No newline at end of file +export { run }; \ No newline at end of file diff --git a/examples/federation/gateway/index.js b/examples/federation/gateway/index.ts similarity index 61% rename from examples/federation/gateway/index.js rename to examples/federation/gateway/index.ts index 6930ba2..a34a8c0 100644 --- a/examples/federation/gateway/index.js +++ b/examples/federation/gateway/index.ts @@ -1,8 +1,7 @@ +import { ApolloServer } from 'apollo-server'; +import { ApolloGateway } from '@apollo/gateway'; -const { ApolloServer } = require('apollo-server'); -const { ApolloGateway } = require('@apollo/gateway'); - -const startGateway = async () => { +const startGateway = async (): Promise => { const gateway = new ApolloGateway({ serviceList: [ { name: 'property', url: 'http://localhost:4001' }, @@ -11,13 +10,11 @@ const startGateway = async () => { }); const server = new ApolloServer({ - gateway, - subscriptions: false + gateway }); const { url } = await server.listen({port: 4000}); console.log(`๐Ÿš€ Gateway ready at ${url}`); } -module.exports = startGateway; - +export default startGateway; \ No newline at end of file diff --git a/examples/federation/property-service/datasource.js b/examples/federation/property-service/datasource.js deleted file mode 100644 index 0c8ce72..0000000 --- a/examples/federation/property-service/datasource.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -const propertiesDB = { - 1: { id: 1, geo: ['41.40338', '2.17403']}, - 2: { id: 2, geo: ['111.1111', '222.2222']} -} - -class PropertyDataSource { - getPropertyById(context, id) { - return propertiesDB[id]; - } -} - -module.exports = PropertyDataSource; \ No newline at end of file diff --git a/examples/federation/property-service/datasource.ts b/examples/federation/property-service/datasource.ts new file mode 100644 index 0000000..39433ed --- /dev/null +++ b/examples/federation/property-service/datasource.ts @@ -0,0 +1,23 @@ +'use strict'; + +import { ComponentContext, DataSourceDefinition } from "../../../src"; + +interface Property { + id: number; + geo: string[]; +} + +const propertiesDB: Record = { + 1: { id: 1, geo: ['41.40338', '2.17403']}, + 2: { id: 2, geo: ['111.1111', '222.2222']} +} + +class PropertyDataSource implements DataSourceDefinition { + name = 'PropertyDataSource'; + + getPropertyById(context: ComponentContext, id: string): Property | undefined { + return propertiesDB[id]; + } +} + +export default PropertyDataSource; \ No newline at end of file diff --git a/examples/federation/property-service/index.js b/examples/federation/property-service/index.ts similarity index 51% rename from examples/federation/property-service/index.js rename to examples/federation/property-service/index.ts index a6b7c78..9771489 100644 --- a/examples/federation/property-service/index.js +++ b/examples/federation/property-service/index.ts @@ -1,18 +1,22 @@ 'use strict'; -const { ApolloServer } = require('apollo-server'); -const GraphQLComponent = require('../../../lib'); -const PropertyDataSource = require('./datasource'); -const resolvers = require('./resolvers'); -const types = require('./types'); +import { ApolloServer } from 'apollo-server'; +import GraphQLComponent from '../../../dist'; +import PropertyDataSource from './datasource'; +import resolvers from './resolvers'; +import types from './types'; + +interface PropertyComponentOptions { + [key: string]: any; +} class PropertyComponent extends GraphQLComponent { - constructor(options) { + constructor(options: PropertyComponentOptions) { super(options); } } -const run = async function () { +const run = async function (): Promise { const { schema, context } = new PropertyComponent({ types, resolvers, @@ -22,12 +26,11 @@ const run = async function () { const server = new ApolloServer({ schema, - context, - subscriptions: false, + context }); const { url } = await server.listen({port: 4001}) console.log(`๐Ÿš€ Property service ready at ${url}`) } -module.exports = { run }; \ No newline at end of file +export { run }; \ No newline at end of file diff --git a/examples/federation/property-service/resolvers.js b/examples/federation/property-service/resolvers.js deleted file mode 100644 index 6783afe..0000000 --- a/examples/federation/property-service/resolvers.js +++ /dev/null @@ -1,16 +0,0 @@ -'use strict'; - -const resolvers = { - Query: { - property(_, { id }, { dataSources }) { - return dataSources.PropertyDataSource.getPropertyById(id); - } - }, - Property: { - __resolveReference(ref, { dataSources }) { - return dataSources.PropertyDataSource.getPropertyById(ref.id); - } - } -}; - -module.exports = resolvers; \ No newline at end of file diff --git a/examples/federation/property-service/resolvers.ts b/examples/federation/property-service/resolvers.ts new file mode 100644 index 0000000..76d4d70 --- /dev/null +++ b/examples/federation/property-service/resolvers.ts @@ -0,0 +1,18 @@ +'use strict'; + +import { ComponentContext } from "../../../src"; + +const resolvers = { + Query: { + property(_: any, { id }: { id: string }, { dataSources }: ComponentContext) { + return dataSources.PropertyDataSource.getPropertyById(id); + } + }, + Property: { + __resolveReference(ref: { id: string }, { dataSources }: ComponentContext) { + return dataSources.PropertyDataSource.getPropertyById(ref.id); + } + } +}; + +export default resolvers; \ No newline at end of file diff --git a/examples/federation/reviews-service/types.js b/examples/federation/property-service/types.ts similarity index 58% rename from examples/federation/reviews-service/types.js rename to examples/federation/property-service/types.ts index 46e4320..ad19bcb 100644 --- a/examples/federation/reviews-service/types.js +++ b/examples/federation/property-service/types.ts @@ -1,8 +1,8 @@ 'use strict'; -const fs = require('fs'); -const path = require('path'); +import * as fs from 'fs'; +import * as path from 'path'; const types = fs.readFileSync(path.resolve(path.join(__dirname, 'schema.graphql')), 'utf-8'); -module.exports = types; \ No newline at end of file +export default types; \ No newline at end of file diff --git a/examples/federation/reviews-service/datasource.js b/examples/federation/reviews-service/datasource.ts similarity index 53% rename from examples/federation/reviews-service/datasource.js rename to examples/federation/reviews-service/datasource.ts index 3b63177..4cf17cb 100644 --- a/examples/federation/reviews-service/datasource.js +++ b/examples/federation/reviews-service/datasource.ts @@ -1,15 +1,22 @@ 'use strict'; +import { ComponentContext, DataSourceDefinition } from "../../../src"; + +interface Review { + id: string; + content: string; +} + // reviews indexed by property id -const reviewsDB = { +const reviewsDB: Record = { 1: [ { id: 'rev-id-1-a', content: 'this property was great'}, { id: 'rev-id-1-b', content: 'this property was terrible'}], 2: [ { id: 'rev-id-2-a', content: 'This property was amazing for our extended family'}, { id: 'rev-id-2-b', content: 'I loved the proximity to the beach'}, { id: 'rev-id-2-c', content: 'The bed was not comfortable at all'}] } -class ReviewsDataSource { - getReviewsByPropertyId(context, propertyId) { +class ReviewsDataSource implements DataSourceDefinition { + getReviewsByPropertyId(context: ComponentContext, propertyId: string): Review[] | undefined { return reviewsDB[propertyId]; } } -module.exports = ReviewsDataSource; \ No newline at end of file +export default ReviewsDataSource; \ No newline at end of file diff --git a/examples/federation/reviews-service/index.js b/examples/federation/reviews-service/index.ts similarity index 51% rename from examples/federation/reviews-service/index.js rename to examples/federation/reviews-service/index.ts index 0f58768..3ef35ef 100644 --- a/examples/federation/reviews-service/index.js +++ b/examples/federation/reviews-service/index.ts @@ -1,19 +1,23 @@ 'use strict'; -const { ApolloServer } = require('apollo-server'); -const GraphQLComponent = require('../../../lib'); -const ReviewsDataSource = require('./datasource'); -const resolvers = require('./resolvers'); -const types = require('./types'); -const toUppercaseDirective = require('./toUppercaseDirective') +import { ApolloServer } from 'apollo-server'; +import GraphQLComponent from '../../../dist'; +import ReviewsDataSource from './datasource'; +import resolvers from './resolvers'; +import types from './types'; +import toUppercaseDirective from './toUppercaseDirective'; + +interface ReviewsComponentOptions { + [key: string]: any; +} class ReviewsComponent extends GraphQLComponent { - constructor(options) { + constructor(options: ReviewsComponentOptions) { super(options); } } -const run = async function () { +const run = async function (): Promise { const { schema, context } = new ReviewsComponent({ types, resolvers, @@ -26,13 +30,11 @@ const run = async function () { const server = new ApolloServer({ schema, - context, - subscriptions: false + context }); const { url } = await server.listen({port: 4002}) console.log(`๐Ÿš€ Reviews service ready at ${url}`) - } -module.exports = { run }; \ No newline at end of file +export { run }; \ No newline at end of file diff --git a/examples/federation/reviews-service/resolvers.js b/examples/federation/reviews-service/resolvers.js deleted file mode 100644 index 4527f98..0000000 --- a/examples/federation/reviews-service/resolvers.js +++ /dev/null @@ -1,16 +0,0 @@ -'use strict'; - -const resolvers = { - Query: { - reviewsByPropertyId(_, { propertyId }, { dataSources }) { - return dataSources.ReviewsDataSource.getReviewsByPropertyId(propertyId); - } - }, - Property: { - reviews(root, _args, { dataSources }) { - return dataSources.ReviewsDataSource.getReviewsByPropertyId(root.id); - } - } -}; - -module.exports = resolvers; \ No newline at end of file diff --git a/examples/federation/reviews-service/resolvers.ts b/examples/federation/reviews-service/resolvers.ts new file mode 100644 index 0000000..65837d0 --- /dev/null +++ b/examples/federation/reviews-service/resolvers.ts @@ -0,0 +1,18 @@ +'use strict'; + +import { ComponentContext } from "../../../src"; + +const resolvers = { + Query: { + reviewsByPropertyId(_: any, { propertyId }: { propertyId: string }, { dataSources }: ComponentContext) { + return dataSources.ReviewsDataSource.getReviewsByPropertyId(propertyId); + } + }, + Property: { + reviews(root: { id: string }, _args: any, { dataSources }: ComponentContext) { + return dataSources.ReviewsDataSource.getReviewsByPropertyId(root.id); + } + } +}; + +export default resolvers; \ No newline at end of file diff --git a/examples/federation/reviews-service/toUppercaseDirective.js b/examples/federation/reviews-service/toUppercaseDirective.ts similarity index 62% rename from examples/federation/reviews-service/toUppercaseDirective.js rename to examples/federation/reviews-service/toUppercaseDirective.ts index 532bd33..dd3997c 100644 --- a/examples/federation/reviews-service/toUppercaseDirective.js +++ b/examples/federation/reviews-service/toUppercaseDirective.ts @@ -1,15 +1,15 @@ -const {getDirective, MapperKind, mapSchema} = require("@graphql-tools/utils"); -const {defaultFieldResolver} = require("graphql"); +import { getDirective, MapperKind, mapSchema } from "@graphql-tools/utils"; +import { defaultFieldResolver, GraphQLSchema } from "graphql"; -function toUppercaseDirective(directiveName) { - return (schema) => mapSchema(schema, { +function toUppercaseDirective(directiveName: string) { + return (schema: GraphQLSchema) => mapSchema(schema, { [MapperKind.OBJECT_FIELD]: (fieldConfig) => { const upperDirective = getDirective(schema, fieldConfig, directiveName)?.[0]; if (upperDirective) { const {resolve = defaultFieldResolver} = fieldConfig; return { ...fieldConfig, - resolve: async function (source, args, context, info) { + resolve: async function (source: any, args: any, context: any, info: any) { const result = await resolve(source, args, context, info); if (typeof result === 'string') { return result.toUpperCase(); @@ -22,4 +22,4 @@ function toUppercaseDirective(directiveName) { }) } -module.exports = toUppercaseDirective \ No newline at end of file +export default toUppercaseDirective; \ No newline at end of file diff --git a/examples/federation/property-service/types.js b/examples/federation/reviews-service/types.ts similarity index 58% rename from examples/federation/property-service/types.js rename to examples/federation/reviews-service/types.ts index 46e4320..ad19bcb 100644 --- a/examples/federation/property-service/types.js +++ b/examples/federation/reviews-service/types.ts @@ -1,8 +1,8 @@ 'use strict'; -const fs = require('fs'); -const path = require('path'); +import * as fs from 'fs'; +import * as path from 'path'; const types = fs.readFileSync(path.resolve(path.join(__dirname, 'schema.graphql')), 'utf-8'); -module.exports = types; \ No newline at end of file +export default types; \ No newline at end of file diff --git a/examples/federation/run-federation-example.js b/examples/federation/run-federation-example.js deleted file mode 100644 index 0cf76f1..0000000 --- a/examples/federation/run-federation-example.js +++ /dev/null @@ -1,11 +0,0 @@ -const { run: runReviewsService } = require('./reviews-service'); -const { run: runPropertyService } = require('./property-service'); -const { run: runGateway } = require('./gateway'); - -const start = async () => { - await runReviewsService(); - await runPropertyService(); - await runGateway(); -} - -start(); \ No newline at end of file diff --git a/examples/federation/run-federation-example.ts b/examples/federation/run-federation-example.ts new file mode 100644 index 0000000..3a1dfe5 --- /dev/null +++ b/examples/federation/run-federation-example.ts @@ -0,0 +1,11 @@ +import { run as runReviewsService } from './reviews-service'; +import { run as runPropertyService } from './property-service'; +import { run as runGateway } from './gateway'; + +const start = async (): Promise => { + await runReviewsService(); + await runPropertyService(); + await runGateway(); +} + +start(); \ No newline at end of file diff --git a/lib/__tests__.js b/lib/__tests__.js deleted file mode 100644 index 19ae9a4..0000000 --- a/lib/__tests__.js +++ /dev/null @@ -1,1318 +0,0 @@ -'use strict'; - -const Test = require('tape'); -const graphql = require('graphql'); -const gql = require('graphql-tag'); -const { MapperKind, mapSchema, getDirective} = require('@graphql-tools/utils'); -const GraphQLComponent = require('.'); - -Test('GraphQLComponent instance API (getters/setters)', (t) => { - - t.test('component name (anonymous constructor)', (st) => { - const component = new GraphQLComponent(); - t.equals(component.name, 'GraphQLComponent', `unnamed constructor results in component named 'GraphQLComponent'`); - st.end(); - }) - - t.test('component name (named constructor)', (st) => { - class Named extends GraphQLComponent {} - const component = new Named(); - t.equals(component.name, 'Named', `named constructor results in 'Named'`); - st.end(); - }); - - t.test('component context', (st) => { - const component = new GraphQLComponent(); - const context = component.context; - st.ok(typeof context === 'function', 'context is a function'); - st.ok(typeof context.use === 'function', 'context has a use funtion'); - st.end(); - }); - - t.test('component types', (st) => { - const component = new GraphQLComponent({ - types: `type Query { a: String }`, - imports: [new GraphQLComponent({ - types: `type Query { b: B } type B { someField: String}`} - )] - }); - - st.deepEquals(component.types, [`type Query { a: String }`], `only the component's own types are returned`); - st.end(); - }); - - t.test('component resolvers', (st) => { - const component = new GraphQLComponent({ - resolvers: { - Query: { - a() { return 'hello'} - } - }, - imports: [new GraphQLComponent({ - resolvers: { - Query: { - b() { - return 'goodbye'; - } - } - } - })] - }); - - st.equals(Object.keys(component.resolvers.Query).length, 1, `only the component's own resolvers are returned`); - st.end(); - }); - - t.test('component imports', (st) => { - const childThatAlsoHasImports = new GraphQLComponent({ - types: `type Query { c: String }`, - resolvers: { Query: { c() { return 'hello' }}}, - imports: [new GraphQLComponent()] - }); - const root = new GraphQLComponent({ - imports: [ - childThatAlsoHasImports - ] - }); - st.equals(root.imports.length, 1, `only component's own imports are returned`); - st.end(); - }); - - t.test('component directives', (st) => { - const component = new GraphQLComponent({ - directives: { parentDirective: () => {}}, - imports: [new GraphQLComponent({ - directives: { childDirective: () => {}} - })] - }); - - st.equals(Object.keys(component.directives).length, 1, `only component's own directives are returned`); - st.end(); - }); - - t.test('component datasources', (st) => { - const component = new GraphQLComponent({ - dataSources: ['parentDataSourcePlaceHolder'], - imports: [new GraphQLComponent({ - dataSources: ['childDataSourcePlaceHolder'] - })] - }); - - st.equals(Object.keys(component.dataSources).length, 1, `only component's own dataSources are returned`); - st.end(); - }); -}); - -Test(`graphql-tools accessible from GraphQLComponent resolver 'this'`, async (t) => { - const component = new GraphQLComponent({ - types: ` - type Query { - foo: Foo - } - - type Foo { - name: String - } - `, - resolvers: { - Query: { - foo() { - t.ok(this.graphqlTools, 'graphqlTools is defined on resolver this'); - } - } - } - }); - - const document = gql` - query { - foo { - name - } - } - `; - - await graphql.execute({ - document, - schema: component.schema, - contextValue: {} - }); - t.end(); -}); - -// mocks tests -Test(`default mocks applied to component's schema when mocks passed as boolean`, (t) => { - const mockedSchemaComponent = new GraphQLComponent({ - types: ` - type Query { - foo: Foo - } - - type Foo { - a: Int - b: Float - c: String - d: Boolean - } - `, - mocks: true - }); - - const document = gql` - query { - foo { - a - b - c - d - } - } - `; - - const { data: { foo } } = graphql.execute({ - document, - schema: mockedSchemaComponent.schema, - contextValue: {} - }); - - t.ok(typeof foo.a === 'number', 'Foo.a is random number'); - t.ok(typeof foo.b === 'number', 'Foo.b is random number'); - t.equal(foo.c, 'Hello World', 'Foo.c is Hello World'); - t.ok(typeof foo.d === 'boolean', 'Foo.d is boolean'); - t.end(); -}); - -Test(`default mocks applied only to imported component's schema`, async (t) => { - const mockedSchemaComponent = new GraphQLComponent({ - types: ` - type Query { - foo: Foo - } - - type Foo { - a: Int - b: Float - c: String - d: Boolean - } - `, - mocks: true - }); - - const composite = new GraphQLComponent({ - types: ` - type Query { - bar: Bar - } - - type Bar { - barField: String - f: Foo - } - `, - resolvers: { - Query: { - bar() { - return { - barField: 'barField', - } - } - }, - Bar: { - f(root, args, context, info) { - return GraphQLComponent.delegateToComponent(mockedSchemaComponent, { - operation: 'query', - fieldName: 'foo', - context, - info - }); - } - } - }, - imports: [mockedSchemaComponent] - }); - - const document = gql` - query { - bar { - barField - f { - a - b - c - d - } - } - } - `; - - const { data: { bar: { barField, f }} } = await graphql.execute({ - document, - schema: composite.schema, - contextValue: {} - }); - - t.equals(barField, 'barField', 'non-mocked value in root component is present') - t.ok(typeof f.a === 'number', 'Foo.a is random number'); - t.ok(typeof f.b === 'number', 'Foo.b is random number'); - t.equal(f.c, 'Hello World', 'Foo.c is Hello World'); - t.ok(typeof f.d === 'boolean', 'Foo.d is boolean'); - t.end(); -}); - -Test('default mocks applied to imported and composite component', async (t) => { - const mockedSchemaComponent = new GraphQLComponent({ - types: ` - type Query { - foo: Foo - } - - type Foo { - a: Int - b: Float - c: String - d: Boolean - } - `, - mocks: true - }); - - const composite = new GraphQLComponent({ - types: ` - type Query { - bar: Bar - } - - type Bar { - barField: String - f: Foo - compositeMockedField: String - } - `, - resolvers: { - Query: { - bar() { - return { - barField: 'barField', - } - } - }, - Bar: { - f(root, args, context, info) { - return GraphQLComponent.delegateToComponent(mockedSchemaComponent, { - operation: 'query', - fieldName: 'foo', - context, - info - }); - } - } - }, - imports: [mockedSchemaComponent], - mocks: true - }); - - const document = gql` - query { - bar { - barField - f { - a - b - c - d - } - compositeMockedField - } - } - `; - - const { data: { bar: { barField, f, compositeMockedField }} } = await graphql.execute({ - document, - schema: composite.schema, - contextValue: {} - }); - - t.equals(barField, 'barField', 'non-mocked value in root component is present'); - t.equals(compositeMockedField, 'Hello World', 'compositeMockedField is Hello World'); - t.ok(typeof f.a === 'number', 'Foo.a is random number'); - t.ok(typeof f.b === 'number', 'Foo.b is random number'); - t.equal(f.c, 'Hello World', 'Foo.c is Hello World'); - t.ok(typeof f.d === 'boolean', 'Foo.d is boolean'); - t.end(); -}); - -Test(`custom mocks applied to component's schema when mocks passed as object`, (t) => { - const mockedSchemaComponent = new GraphQLComponent({ - types: ` - type Query { - foo: Foo - } - - type Foo { - a: Int - b: Float - c: String - d: Boolean - } - `, - mocks: { - Int: () => 123456789, - Float: () => 3.1415926, - String: () => 'custom string', - Boolean: () => false - } - }); - - const document = gql` - query { - foo { - a - b - c - d - } - } - `; - - const { data: { foo } } = graphql.execute({ - document, - schema: mockedSchemaComponent.schema, - contextValue: {} - }); - - t.equal(foo.a, 123456789, 'Foo.a is a custom mocked Int'); - t.equal(foo.b, 3.1415926, 'Foo.b is custom mocked Float'); - t.equal(foo.c, 'custom string', 'Foo.c is a custom mocked string'); - t.equal(foo.d, false, 'Foo.d is a custom mocked boolean (false)'); - t.end(); -}); - -// delegate tests -Test('delegate from root-type resolver', async (t) => { - const primitive = new GraphQLComponent({ - types: ` - type Query { - foo: Foo - } - - type Foo { - a: String - } - `, - resolvers: { - Query: { - foo() { - return { a: 'a' }; - } - } - } - }); - - const composite = new GraphQLComponent({ - types: ` - type Query { - bar: Foo - } - - type Foo { - b: Int - } - `, - resolvers: { - Query: { - async bar(root, args, context, info) { - const subFoo = await GraphQLComponent.delegateToComponent(primitive, { - operation: 'query', - fieldName: 'foo', - context, - info - }); - - return { ...subFoo, b: 1 }; - } - } - }, - imports: [primitive] - }); - - const document = gql` - query { - bar { - a - b - } - } - `; - - const { data, errors } = await graphql.execute({ - schema: composite.schema, - document, - contextValue: {} - }); - - t.deepEqual(data, { bar: { a: 'a', b: 1}}, 'expected result'); - t.notOk(errors, 'no errors') - t.end(); -}); - -Test('delegate from non root-type resolver', async (t) => { - const primitive = new GraphQLComponent({ - types: ` - type Query { - foo: Foo - } - - type Foo { - a: String - } - `, - resolvers: { - Query: { - foo() { - return { a: 'a' }; - } - } - } - }); - - const composite = new GraphQLComponent({ - types: ` - type Query { - bar: Bar - } - - type Bar { - barField: String - foo: Foo - } - `, - resolvers: { - Query: { - async bar() { - return { barField: 'barField' }; - } - }, - Bar: { - foo(root, args, context, info) { - return GraphQLComponent.delegateToComponent(primitive, { - operation: 'query', - fieldName: 'foo', - context, - info - }); - } - } - }, - imports: [primitive] - }); - - const document = gql` - query { - bar { - barField - foo { - a - } - } - } - `; - - const { data, errors } = await graphql.execute({ - schema: composite.schema, - document, - contextValue: {} - }); - - t.deepEqual(data, { bar: { barField: 'barField', foo: { a: 'a'}}}, 'expected result'); - t.notOk(errors, 'no errors') - t.end(); -}); - -Test('delegate results in non-root type field resolver running in delegatee', async (t) => { - let fooFieldResolverCallCount = 0; - const primitive = new GraphQLComponent({ - types: ` - type Query { - foo: Foo - } - - type Foo { - a: String - fprime: FooPrime - } - - type FooPrime { - prime: String - } - `, - resolvers: { - Query: { - foo() { - return { a: 'a', somethingToTransform: 'hello' }; - } - }, - Foo: { - fprime(root) { - fooFieldResolverCallCount += 1; - if (root.somethingToTransform) { - return { prime: root.somethingToTransform }; - } - } - } - } - }); - - const composite = new GraphQLComponent({ - types: ` - type Query { - bar: Foo - } - - type Foo { - compositeFooField: String - } - `, - resolvers: { - Query: { - async bar(root, args, context, info) { - const subFoo = await GraphQLComponent.delegateToComponent(primitive, { - operation: 'query', - fieldName: 'foo', - context, - info - }); - return { ...subFoo, compositeFooField: 'compositeFooField' }; - } - } - }, - imports: [primitive] - }); - - const document = gql` - query { - bar { - compositeFooField - a - fprime { - prime - } - } - } - `; - - const { data, errors } = await graphql.execute({ - schema: composite.schema, - document, - contextValue: {} - }); - - t.notOk(errors, 'no errors'); - t.deepEqual(data, { bar: { compositeFooField: 'compositeFooField', a: 'a', fprime: { prime: 'hello'}}}, 'expected result'); - t.equal(fooFieldResolverCallCount, 1, 'non root type field resolver in delegatee only called once'); - t.end(); -}); - -Test('delegation resolves nested abstract type resolved without error', async (t) => { - let resolveTypeCount = 0; - let materialNonRootResolverCount = 0; - const primitive = new GraphQLComponent({ - types: ` - type Query { - thingsById(id: ID): ThingsConnection - } - - type ThingsConnection { - edges: [ThingEdge] - } - - type ThingEdge { - node: Thing - } - - interface Thing { - id: ID - } - - type Book implements Thing { - id: ID - title: String - } - - type Mug implements Thing { - id: ID - material: String - } - `, - resolvers: { - Query: { - thingsById() { - return { - edges: [ - { - node: { - id: 1, - title: 'A tale of two cities' - } - }, - { - node: { - id: 2, - } - } - ] - } - } - }, - Thing: { - __resolveType(result) { - resolveTypeCount += 1; - if (result.title) { - return 'Book'; - } - return 'Mug'; - } - }, - Mug: { - material() { - materialNonRootResolverCount += 1; - return 'ceramic'; - } - } - } - }); - - const composite = new GraphQLComponent({ - types: ` - type Query { - foo: Foo - } - - type Foo { - things: ThingsConnection - } - `, - resolvers: { - Query: { - async foo() { - return {}; - } - }, - Foo: { - things(_root, _args, context, info) { - return GraphQLComponent.delegateToComponent(primitive, { - operation: 'query', - fieldName: 'thingsById', - info, - context - }); - } - } - }, - imports: [primitive] - }); - - const document = gql` - query { - foo { - things { - edges { - node { - id - ... on Book { - title - } - ... on Mug { - material - } - } - } - } - } - } - ` - - const { data, errors } = await graphql.execute({ - document, - schema: composite.schema, - contextValue: {} - }); - const expectedResult = { - foo: { - things: { - edges: [ - { - node: { - id: '1', - title: 'A tale of two cities' - } - }, - { - node: { - id: '2', - material: 'ceramic' - } - } - ] - } - } - } - t.deepEquals(data, expectedResult, 'data is resolved as expected'); - t.equals(resolveTypeCount, 2, '__resolveType called once per item as expected'); - t.equals(materialNonRootResolverCount, 1, 'Mug non-root resolver is only executed 1 time as expected'); - t.notOk(errors, 'no errors'); - t.end(); -}); - -Test('error from delegatee propagated back to delegator and abstracted (looks like it came from resolver that called delegate)', async (t) => { - const primitive = new GraphQLComponent({ - types: ` - type Query { - foo: Foo - } - - type Foo { - b: String - } - `, - resolvers: { - Query: { - foo() { - throw new Error('db retrieval error'); - } - } - } - }); - - const composite = new GraphQLComponent({ - types: ` - - type Query { - bar: Bar - } - - type Bar { - a: String - b: String - } - `, - resolvers: { - Query: { - bar(root, args, context, info) { - return GraphQLComponent.delegateToComponent(primitive, { - query: 'operation', - fieldName: 'foo', - context, - info - }); - } - } - } - }); - - const document = gql` - query { - bar { - a - b - } - } - `; - - const { data, errors } = await graphql.execute({ - schema: composite.schema, - document, - contextValue: {} - }); - - t.notOk(data.bar, 'bar is null as expected'); - t.equals(errors.length, 1, '1 error as expected'); - t.equals(errors[0].message, 'db retrieval error'); - t.deepEqual(errors[0].path, ['bar'], 'error path appears as though error came from delegateToComponent calling resolver'); - t.end(); -}); - -Test('delegateToComponent maintains backwards compatibility for changed option keys (contextValue and targetRootField)', async (t) => { - const primitive = new GraphQLComponent({ - types: ` - type Query { - foo: Foo - } - - type Foo { - a: String - } - `, - resolvers: { - Query: { - foo() { - return { a: 'a' }; - } - } - } - }); - - const composite = new GraphQLComponent({ - types: ` - type Query { - bar: Foo - } - - type Foo { - b: Int - } - `, - resolvers: { - Query: { - async bar(root, args, context, info) { - const subFoo = await GraphQLComponent.delegateToComponent(primitive, { - operation: 'query', - targetRootField: 'foo', - contextValue: context, - info - }); - - return { ...subFoo, b: 1 }; - } - } - }, - imports: [primitive] - }); - - const document = gql` - query { - bar { - a - b - } - } - `; - - const { data, errors } = await graphql.execute({ - schema: composite.schema, - document, - contextValue: {} - }); - - t.deepEqual(data, { bar: { a: 'a', b: 1}}, 'expected result'); - t.notOk(errors, 'no errors') - t.end(); -}); - -Test('component directives imports', (t) => { - - t.test('include all', (st) => { - const component = new GraphQLComponent({ - types: ` - directive @parent_directive on OBJECT - `, - imports: [new GraphQLComponent({ - types: ` - directive @child_directive on OBJECT - ` - })] - }); - - st.ok(component.schema.getDirective('child_directive'), `child component directives exist in merged`); - st.ok(component.schema.getDirective('parent_directive'), `parent component directives exist in merged`); - - st.end(); - }); - -}); - -// federation tests -Test('components with federated schemas can be stitched locally by importing root', (t) => { - const fedComponent1 = new GraphQLComponent({ - types: ` - type Query { - property(id: ID!): Property - } - - type Property @key(fields: "id") { - id: ID! - geo: [String] - } - `, - resolvers: { - Query: { - property(_, {id}) { - return { - id, - geo: ['lat', 'long'] - } - } - } - }, - federation: true - }); - - const fedComponent2 = new GraphQLComponent({ - types: ` - type Query { - reviews(propertyId: ID!): [Review] - } - - type Review @key(fields: "id") { - id: ID! - content: String - } - - type Property { - addedPropertyField: String - } - `, - resolvers: { - Query: { - reviews() { - return { - id: 'rev-id-1', - content: 'some-content' - } - } - }, - }, - federation: true - }); - - const emptyRoot = new GraphQLComponent({ - imports: [fedComponent1, fedComponent2] - }); - - const { schema } = emptyRoot; - - const _serviceType = schema.getType('_Service'); - const _serviceTypeFields = _serviceType.getFields(); - const _entityType = schema.getType('_Entity'); - const _entityTypeTypes = _entityType.getTypes(); - const _anyScalar = schema.getType('_Any'); - const queryFields = schema.getType('Query').getFields(); - const propertyTypeFields = schema.getType('Property').getFields(); - - t.ok(_serviceType, 'federated _Service type exists'); - t.ok(_serviceTypeFields['sdl'], '_Service type sdl field exists'); - t.ok(_entityType, 'federated _Entity type exists'); - t.equals(_entityTypeTypes.length, 2, '2 entities'); - t.deepEqual(_entityTypeTypes.map((e) => e.name), ['Property', 'Review'], 'entities are Property and Review as declared via @keys directive'); - t.ok(_anyScalar, 'scalar _Any exists'); - t.deepEqual(Object.keys(queryFields), ['_entities', '_service', 'property', 'reviews'], 'federated query fields and user declared query fields are present'); - t.deepEqual(Object.keys(propertyTypeFields), ['id', 'geo', 'addedPropertyField'], 'Property type fields is union between imported components (ie. property type is merged)'); - t.end(); -}); - -Test(`importing root specifies 'federation: true' results in all components creating federated schemas`, (t) => { - const fedComponent1 = new GraphQLComponent({ - types: ` - type Query { - property(id: ID!): Property - } - - type Property @key(fields: "id") { - id: ID! - geo: [String] - } - `, - resolvers: { - Query: { - property(_, {id}) { - return { - id, - geo: ['lat', 'long'] - } - } - } - }, - }); - - const fedComponent2 = new GraphQLComponent({ - types: ` - type Query { - reviews(propertyId: ID!): [Review] - } - - type Review @key(fields: "id") { - id: ID! - content: String - } - - type Property { - addedPropertyField: String - } - `, - resolvers: { - Query: { - reviews() { - return { - id: 'rev-id-1', - content: 'some-content' - } - } - }, - }, - }); - - const emptyRoot = new GraphQLComponent({ - imports: [fedComponent1, fedComponent2], - federation: true - }); - - const { schema: fedComponent1Schema } = fedComponent1; - const _serviceTypeFedComponent1 = fedComponent1Schema.getType('_Service'); - const _serviceTypeFieldsFedComponent1 = _serviceTypeFedComponent1.getFields(); - const _entityTypeFedComponent1 = fedComponent1Schema.getType('_Entity'); - const _entityTypeTypesFedComponent1 = _entityTypeFedComponent1.getTypes(); - const _anyScalarFedComponent1 = fedComponent1Schema.getType('_Any'); - const queryFieldsFedComponent1 = fedComponent1Schema.getType('Query').getFields(); - - t.ok(_serviceTypeFedComponent1, `federated _Service type exists in fedComponent1's federated schema`); - t.ok(_serviceTypeFieldsFedComponent1['sdl'], `_Service type sdl field exists in fedComponent1's federated schema`); - t.ok(_entityTypeFedComponent1, `federated _Entity type exists in fedComponent1's federated schema`); - t.equals(_entityTypeTypesFedComponent1.length, 1, `1 entity in fedComponent1's federated schema`); - t.ok(_anyScalarFedComponent1, `scalar _Any exists in fedComponent1's federated schema`); - t.deepEqual(Object.keys(queryFieldsFedComponent1), ['_entities', '_service', 'property'], `federated query fields and user declared query fields are present in fedComponent1's federated schema`); - t.ok(fedComponent1._federation, `federation flag is true in imported component, even though it was not set in imported component's constructor`); - - const { schema: fedComponent2Schema } = fedComponent1; - const _serviceTypeFedComponent2 = fedComponent2Schema.getType('_Service'); - const _serviceTypeFieldsFedComponent2 = _serviceTypeFedComponent2.getFields(); - const _entityTypeFedComponent2 = fedComponent2Schema.getType('_Entity'); - const _entityTypeTypesFedComponent2 = _entityTypeFedComponent2.getTypes(); - const _anyScalarFedComponent2 = fedComponent2Schema.getType('_Any'); - const queryFieldsFedComponent2 = fedComponent2Schema.getType('Query').getFields(); - - t.ok(_serviceTypeFedComponent2, `federated _Service type exists in fedComponent2's federated schema`); - t.ok(_serviceTypeFieldsFedComponent2['sdl'], `_Service type sdl field exists in fedComponent2's federated schema`); - t.ok(_entityTypeFedComponent2, `federated _Entity type exists in fedComponent1's federated schema`); - t.equals(_entityTypeTypesFedComponent2.length, 1, `1 entity in fedComponent2's federated schema`); - t.ok(_anyScalarFedComponent2, `scalar _Any exists in fedComponent1's federated schema`); - t.deepEqual(Object.keys(queryFieldsFedComponent2), ['_entities', '_service', 'property'], `federated query fields and user declared query fields are present in fedComponent2's federated schema`); - t.ok(fedComponent2._federation, `federation flag is true in imported component, even though it was not set in imported component's constructor`); - - const { schema } = emptyRoot; - - const _serviceType = schema.getType('_Service'); - const _serviceTypeFields = _serviceType.getFields(); - const _entityType = schema.getType('_Entity'); - const _entityTypeTypes = _entityType.getTypes(); - const _anyScalar = schema.getType('_Any'); - const queryFields = schema.getType('Query').getFields(); - const propertyTypeFields = schema.getType('Property').getFields(); - - t.ok(_serviceType, 'federated _Service type exists in root federated schema'); - t.ok(_serviceTypeFields['sdl'], '_Service type sdl field exists in root federated schema'); - t.ok(_entityType, 'federated _Entity type exists in root federated schema'); - t.equals(_entityTypeTypes.length, 2, '2 entities in root federated schema'); - t.deepEqual(_entityTypeTypes.map((e) => e.name), ['Property', 'Review'], 'entities are Property and Review as declared via @keys directive in root federated schema in root federated schema'); - t.ok(_anyScalar, 'scalar _Any exists'); - t.deepEqual(Object.keys(queryFields), ['_entities', '_service', 'property', 'reviews'], 'federated query fields and user declared query fields are present in root federated schema'); - t.deepEqual(Object.keys(propertyTypeFields), ['id', 'geo', 'addedPropertyField'], 'Property type fields is union between imported components (ie. property type is merged) in root federated schema'); - t.end(); -}) - -Test('federated schema can include custom directive', (t) => { - function customDirective(directiveName) { - return (schema) => mapSchema(schema, { - [MapperKind.OBJECT_FIELD]: (fieldConfig) => { - const directives = getDirective(schema, fieldConfig, directiveName) - const directive = directives && directives[0] - if (directive) { - return { - ...fieldConfig, - } - } - } - }) - } - - const component = new GraphQLComponent({ - types: ` - directive @custom on FIELD_DEFINITION - - type Query { - property(id: ID!): Property @custom - } - type Property @key(fields: "id") { - id: ID! - geo: [String] - } - extend type Extended @key(fields: "id") { - id: ID! @external - newProp: String - } - `, - resolvers: { - Query: { - property(_, { id }) { - return { - id, - geo: ['lat', 'long'] - } - } - }, - }, - directives: { custom: customDirective }, - federation: true - }); - - t.test('federated schema created without error', (t) => { - t.plan(1); - t.doesNotThrow(() => { - component.schema; - }, 'can return a buildFederatedSchema schema'); - }); - - t.test('custom directive added to federated schema', (t) => { - t.plan(1); - const { schema: { _directives: schemaDirectives } } = component; - t.equals(schemaDirectives.filter((directive) => directive.name === 'custom').length, 1, `federated schema has '@custom' directive`); - }); - - t.test('extended properties maintained after adding custom directive', (t) => { - t.plan(2); - const { schema: { _typeMap: { Extended } } } = component; - t.equals(Extended.extensionASTNodes.length, 1, 'Extension AST Nodes is defined'); - t.equals(Extended.astNode.fields.filter((field) => field.name.value === "id" && field.directives[0].name.value === "external").length, 1, `id field marked external`); - }); -}); - -Test('pruning schema', (t) => { - - t.test('does not prune types used only at root', (t) => { - const component1 = new GraphQLComponent({ - types: ` - type Query { - property(id: ID!): Property - } - - type Property { - id: ID! - geo: [String] - } - `, - resolvers: { - Query: { - property(_, { id }) { - return { - id, - geo: ['lat', 'long'] - } - } - } - } - }); - - const component2 = new GraphQLComponent({ - types: ` - type Query { - reviews(propertyId: ID!): [Review] - } - - type Review { - id: ID! - content: String - } - - type Property { - reviews: [Review] - } - `, - resolvers: { - Query: { - reviews() { - return { - id: 'rev-id-1', - content: 'content' - } - } - }, - } - }); - - const rootComponent = new GraphQLComponent({ - imports: [component1, component2], - pruneSchema: true - }); - - const { schema } = rootComponent; - - t.ok(schema.getType('Property'), 'Property type exists'); - t.ok(schema.getType('Review'), 'Review type exists'); - - t.end(); - }); - - t.test('Unused types not removed if prune is false', (t) => { - - const component = new GraphQLComponent({ - types: ` - type Query { - reviews(propertyId: ID!): [Review] - } - - type Review { - id: ID! - content: String - } - - type Property { - reviews: [Review] - } - `, - resolvers: { - Query: { - reviews() { - return { - id: 'rev-id-1', - content: 'content' - } - } - }, - }, - pruneSchema: false - }); - - const { schema } = component; - - t.ok(schema.getType('Property'), 'Property type exists'); - t.ok(schema.getType('Review'), 'Review type exists'); - - t.end(); - }); - - t.test('prune removed unused types', (t) => { - - const component = new GraphQLComponent({ - types: ` - type Query { - reviews(propertyId: ID!): [Review] - } - - type Review { - id: ID! - content: String - } - - type Property { - reviews: [Review] - } - `, - resolvers: { - Query: { - reviews() { - return { - id: 'rev-id-1', - content: 'content' - } - } - }, - }, - pruneSchema: true - }); - - const { schema } = component; - - t.ok(!schema.getType('Property'), 'Property type was pruned'); - t.ok(schema.getType('Review'), 'Review type exists'); - - t.end(); - }); -}); \ No newline at end of file diff --git a/lib/context/__tests__.js b/lib/context/__tests__.js deleted file mode 100644 index a63e693..0000000 --- a/lib/context/__tests__.js +++ /dev/null @@ -1,128 +0,0 @@ -'use strict'; - -const Test = require('tape'); -const { createContext, wrapContext } = require('./index'); -const GraphQLComponent = require('../index'); - -Test('context builder', async (t) => { - t.plan(3); - - const component = new GraphQLComponent({ - imports: [ - { - component: new GraphQLComponent({ - context: { namespace: 'import', factory: () => true} - }) - } - ] - }); - - const context = createContext(component, { namespace: 'test', factory: () => true }); - - const result = await context({}); - - t.ok(typeof result === 'object', 'returned object'); - t.ok(result.test, 'namespace populated'); - t.ok(result.import, 'import namespace populated'); -}); - -Test('context builder with namespace merge', async (t) => { - t.plan(2); - - const component = new GraphQLComponent({ - imports: [ - { - component: new GraphQLComponent({ - context: { namespace: 'test', factory: () => ({ existing: true })} - }) - } - ] - }); - - const context = createContext(component, { namespace: 'test', factory: () => ({ value: true }) }); - - const result = await context({}); - - t.ok(typeof result === 'object', 'returned object'); - t.ok(result.test.existing && result.test.value, 'namespace merged'); -}); - -Test('component context', async (t) => { - t.plan(2); - - const context = wrapContext({ - _context() {}, - _dataSourceInjection() {} - }); - - const result = await context({ default1: true, default2: true }); - - t.ok(typeof result === 'object', 'returned object'); - t.ok(result.default1 && result.default2, 'default values maintained'); -}); - -Test('component context once', async (t) => { - t.plan(3); - - const { context } = new GraphQLComponent({ - context: { namespace: 'parent', factory: (context) => { - t.equal(context.called, 1, 'import modified global context'); - context.called++; - return Object.assign({}, context); - }}, - imports: [ - { - component: new GraphQLComponent({ - context: { namespace: 'import', factory: (context) => { - t.equal(context.called, 0, 'initial global context'); - context.called++; - return Object.assign({}, context); - }} - }) - } - ] - }); - - const result = await context({ called: 0 }); - - //The global context didn't reset because root wrapper context didn't get called again - t.equal(result.called, 2, 'called root once'); -}); - -Test('context middleware', async (t) => { - t.plan(3); - - const context = wrapContext({ - _context() {}, - _dataSourceInjection() {} - }); - - context.use('test', () => { - return { test: true }; - }); - - const result = await context({ default: true }); - - t.ok(typeof result === 'object', 'returned object'); - t.ok(result.test, 'middleware populated'); - t.ok(!result.default, 'middleware mutated'); -}); - -Test('unnamed context middleware', async (t) => { - t.plan(3); - - const context = wrapContext({ - _context() {}, - _dataSourceInjection() {} - }); - - context.use(() => { - return { test: true }; - }); - - const result = await context({ default: true }); - - t.ok(typeof result === 'object', 'returned object'); - t.ok(result.test, 'middleware populated'); - t.ok(!result.default, 'middleware mutated'); -}); \ No newline at end of file diff --git a/lib/context/index.js b/lib/context/index.js deleted file mode 100644 index 956773a..0000000 --- a/lib/context/index.js +++ /dev/null @@ -1,64 +0,0 @@ -'use strict'; - -const debug = require('debug')('graphql-component:context'); - -const createContext = function (root, ctxConfig) { - return async function (context) { - const ctx = {}; - - for (const { component } of root.imports) { - Object.assign(ctx, await component._context(context)); - } - - if (ctxConfig) { - debug(`building ${ctxConfig.namespace} context`); - - if (!ctx[ctxConfig.namespace]) { - ctx[ctxConfig.namespace] = {}; - } - - Object.assign(ctx[ctxConfig.namespace], await ctxConfig.factory.call(root, context)); - } - - return ctx; - }; -}; - -const wrapContext = function (component) { - const middleware = []; - const contextFunction = component._context; - const dataSourceInject = component._dataSourceInjection; - - const context = async function (context) { - debug(`building ${component._id} root context`); - - for (let { name, fn } of middleware) { - debug(`applying ${name} middleware`); - context = await fn(context); - } - - const componentContext = await contextFunction(context); - - const globalContext = { - ...context, - ...componentContext - }; - - globalContext.dataSources = dataSourceInject(globalContext); - - return globalContext; - }; - - context.use = function (name, fn) { - if (typeof name === 'function') { - fn = name; - name = 'unknown'; - } - debug(`adding ${name} middleware`); - middleware.push({ name, fn }); - }; - - return context; -}; - -module.exports = { createContext, wrapContext }; \ No newline at end of file diff --git a/lib/datasource/__tests__.js b/lib/datasource/__tests__.js deleted file mode 100644 index db95ef5..0000000 --- a/lib/datasource/__tests__.js +++ /dev/null @@ -1,173 +0,0 @@ -'use strict'; - -const Test = require('tape'); -const { intercept, createDataSourceInjection } = require('./index'); -const GraphQLComponent = require('../index'); - -Test('intercepts', (t) => { - - t.test('intercept proxy', (t) => { - t.plan(4); - - const proxy = intercept(new class DataSource { - constructor() { - this.instanceField = 'some instance field value' - } - static get name() { - return 'TestDataSource'; - } - test(...args) { - t.equal(args.length, 2, 'added additional arg'); - t.equal(args[0].data, 'test', 'injected the right data'); - t.equal(args[1], 'test', 'data still passed to original call'); - t.equal(this.instanceField, 'some instance field value', '`this` is correctly bound datasource instance methods') - } - }, { - data: 'test' - }); - - proxy.test('test'); - }); - - t.test('do not intercept proxy fields', (t) => { - t.plan(1); - - const proxy = intercept(new class DataSource { - constructor() { - this.instanceField = 'some instance field value' - } - static get name() { - return 'TestDataSource'; - } - }); - - t.equal(proxy.instanceField, 'some instance field value', 'field ok'); - }); - -}); - -Test('injection', (t) => { - t.test('dataSource injection function empty', (t) => { - t.plan(1); - - const injection = createDataSourceInjection({ - imports: [] - }); - - t.doesNotThrow(() => { - injection(); - }, 'no exception thrown'); - }); - - t.test('dataSource injection function', (t) => { - t.plan(4); - - class DataSource { - static get name() { - return 'TestDataSourceInjection'; - } - test(...args) { - t.equal(args.length, 2, 'added additional arg'); - t.equal(args[0].data, 'test', 'injected the right data'); - t.equal(args[1], 'test', 'data still passed to original call'); - } - } - - const component = { - dataSources: [new DataSource()], - imports: [] - }; - - const injection = createDataSourceInjection(component); - - const globalContext = { data: 'test' }; - - globalContext.dataSources = injection(globalContext); - - t.ok(globalContext.dataSources && globalContext.dataSources.TestDataSourceInjection, 'dataSource added to context'); - - globalContext.dataSources.TestDataSourceInjection.test('test'); - }); - - t.test('dataSource override', (t) => { - t.plan(4); - - class DataSource { - static get name() { - return 'TestDataSourceInjection'; - } - test(...args) { - t.equal(args.length, 2, 'added additional arg'); - t.equal(args[0].data, 'test', 'injected the right data'); - t.equal(args[1], 'test', 'data still passed to original call'); - } - } - - const component = { - dataSources: [new class Default { - static get name() { - return 'TestDataSourceInjection'; - } - }], - imports: [] - }; - - const injection = createDataSourceInjection(component, [new DataSource()]); - - const globalContext = { data: 'test' }; - - globalContext.dataSources = injection(globalContext); - - t.ok(globalContext.dataSources && globalContext.dataSources.TestDataSourceInjection, 'dataSource added to context'); - - globalContext.dataSources.TestDataSourceInjection.test('test'); - }); - - t.test('dataSource injection function imports', (t) => { - t.plan(1); - - const injection = createDataSourceInjection({ - imports: [ - { - component: { - _dataSourceInjection: createDataSourceInjection({ imports: [] }), - imports: [] - } - } - ] - }); - - t.doesNotThrow(() => { - injection({}); - }, 'no exception thrown'); - }); -}); - -Test('integration: data source', (t) => { - - t.test('component and context injection', async (t) => { - t.plan(4); - - class DataSource { - static get name() { - return 'TestDataSource'; - } - test(...args) { - t.equal(args.length, 2, 'added additional arg'); - t.equal(args[0].data, 'test', 'injected the right data'); - t.equal(args[1], 'test', 'data still passed to original call'); - } - } - - const { context } = new GraphQLComponent({ - dataSources: [new DataSource()] - }); - - const globalContext = await context({ data: 'test' }); - - t.ok(globalContext.dataSources && globalContext.dataSources.TestDataSource, 'dataSource added to context'); - - globalContext.dataSources.TestDataSource.test('test'); - }); - -}); \ No newline at end of file diff --git a/lib/datasource/index.js b/lib/datasource/index.js deleted file mode 100644 index 0946096..0000000 --- a/lib/datasource/index.js +++ /dev/null @@ -1,49 +0,0 @@ -'use strict'; - -const debug = require('debug')('graphql-component:datasource'); - -const intercept = function (instance, context) { - debug(`intercepting ${instance.constructor.name}`); - - return new Proxy(instance, { - get(target, key) { - if (typeof target[key] !== 'function' || key === instance.constructor.name) { - return target[key]; - } - const original = target[key]; - - return function (...args) { - return original.call(instance, context, ...args); - }; - } - }); -}; - -const createDataSourceInjection = function (root, dataSourceOverrides = []) { - return function (context = {}) { - const dataSources = {}; - - for (const { component } of root.imports) { - Object.assign(dataSources, component._dataSourceInjection(context)); - } - - for (const override of dataSourceOverrides) { - debug(`overriding datasource ${override.constructor.name}`); - dataSources[override.constructor.name] = intercept(override, context); - } - - if (root.dataSources && root.dataSources.length > 0) { - for (const dataSource of root.dataSources) { - const name = dataSource.constructor.name; - if (!dataSources[name]) { - dataSources[name] = intercept(dataSource, context); - } - } - } - - return dataSources; - }; - -}; - -module.exports = { intercept, createDataSourceInjection }; \ No newline at end of file diff --git a/lib/index.d.ts b/lib/index.d.ts deleted file mode 100644 index eba633d..0000000 --- a/lib/index.d.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { DocumentNode, GraphQLSchema, Source } from 'graphql'; -import { IDelegateToSchemaOptions } from '@graphql-tools/delegate'; -import { IResolvers, PruneSchemaOptions } from '@graphql-tools/utils'; -import { IMocks } from '@graphql-tools/mock'; - -type DirectiveUseMap = { [key: string]: any }; - -interface IGraphQLComponentConfigObject { - component: GraphQLComponent; - excludes?: string[]; -} - -type ContextFunction = ((ctx: any) => any); - -interface IContextMiddleware { - name: string - fn: ContextFunction -} - -interface IContextConfig { - namespace: string - factory: ContextFunction -} - -interface IContextWrapper extends ContextFunction { - use: (name: string|ContextFunction|null, fn?: ContextFunction|string) => void -} - -interface IGraphQLComponentOptions { - types?: (string | Source | DocumentNode | GraphQLSchema)[] | (string | Source | DocumentNode | GraphQLSchema); - resolvers?: IResolvers; - mocks?: boolean | MocksConfigFunction; - directives?: DirectiveUseMap; - federation?: boolean; - imports?: GraphQLComponent[] | IGraphQLComponentConfigObject[]; - context?: IContextConfig; - dataSources?: any[]; - dataSourceOverrides?: any; - pruneSchema?: boolean; - pruneSchemaOptions?: PruneSchemaOptions -} - -type MocksConfigFunction = (IMocks) => IMocks; - -export default class GraphQLComponent { - constructor(options?: IGraphQLComponentOptions); - static delegateToComponent(component: GraphQLComponent, options: IDelegateToSchemaOptions): Promise - readonly name: string; - readonly schema: GraphQLSchema; - readonly context: { - (arg: any): Promise; - use(name: any, fn: any): void; - }; - readonly types: string[]; - readonly resolvers: object; - readonly imports: IGraphQLComponentConfigObject[]; - readonly mocks: any; - readonly directives: any; - readonly dataSources: any[]; -} diff --git a/lib/index.js b/lib/index.js deleted file mode 100644 index c96e3c6..0000000 --- a/lib/index.js +++ /dev/null @@ -1,208 +0,0 @@ -'use strict'; - -const { buildFederatedSchema } = require('@apollo/federation'); -const { stitchSchemas } = require('@graphql-tools/stitch'); -const { mergeTypeDefs } = require('@graphql-tools/merge'); -const { addMocksToSchema } = require('@graphql-tools/mock'); -const { makeExecutableSchema } = require('@graphql-tools/schema'); -const { delegateToSchema } = require('@graphql-tools/delegate'); -const { pruneSchema } = require('@graphql-tools/utils'); - -const { bindResolvers } = require('./resolvers'); -const { wrapContext, createContext } = require('./context'); -const { createDataSourceInjection } = require('./datasource'); -const { exclusions } = require('./transforms'); - -const debug = require('debug')('graphql-component:schema'); - -class GraphQLComponent { - constructor({ - types = [], - resolvers = {}, - mocks = undefined, - directives = {}, - federation = false, - imports = [], - context = undefined, - dataSources = [], - dataSourceOverrides = [], - pruneSchema = false, - pruneSchemaOptions = {} - } = {}) { - debug(`creating a GraphQLComponent instance`); - - this._types = Array.isArray(types) ? types : [types]; - - this._resolvers = bindResolvers(this, resolvers); - - this._mocks = mocks; - - this._directives = directives; - - this._federation = federation; - - this._imports = imports && imports.length > 0 ? imports.map((i) => { - // check for a GraphQLComponent instance to construct a configuration object from it - if (i instanceof GraphQLComponent) { - // if the importing component (ie. this component) has federation set to true - set federation: true - // for all of its imported components - if (this._federation === true) { - i.federation = true; - } - return { component: i, exclude: [] }; - } - // check for a configuration object and simply return it - else if (((typeof i === 'function') || (typeof i === 'object')) && i.component) { - // if the importing component (ie. this component) has federation set to true - set federation: true - // for all of its imported components - if (this._federation === true) { - i.component.federation = true; - } - return i; - } - throw new Error(`import in ${this.name} not an instance of GraphQLComponent or component configuration object: { component: , exclude: [] }`); - }) : []; - - this._context = createContext(this, context); - - this._dataSources = dataSources; - - this._pruneSchema = pruneSchema; - - this._pruneSchemaOptions = pruneSchemaOptions; - - this._schema = undefined; - - this._dataSourceInjection = createDataSourceInjection(this, dataSourceOverrides); - - this.graphqlTools = require('@graphql-tools/schema'); - } - - get name() { - return this.constructor.name; - } - - static delegateToComponent(component, options) { - options.schema = component.schema; - // adapt v2 delegate options to v3 options to maintain backwards compatibility - if (options.contextValue) { - options.context = options.contextValue; - delete options.contextValue; - } - - if (options.targetRootField) { - options.fieldName = options.targetRootField; - delete options.targetRootField; - } - - return delegateToSchema(options); - } - - - _getMakeSchemaFunction() { - if (this._federation) { - return (schemaConfig) => { - let schema = buildFederatedSchema(schemaConfig); - - // allows a federated schema to have custom directives using the old class based directive implementation - if (this._directives) { - for (const name in this._directives) { - schema = this._directives[name](name)(schema) - } - } - - return schema; - }; - } - - return makeExecutableSchema; - } - - get schema() { - if (this._schema) { - return this._schema; - } - - if (this._imports.length > 0) { - // iterate through the imports and construct subschema configuration objects - const subschemas = this._imports.map((imp) => { - const { component, exclude } = imp; - return { - schema: component.schema, - transforms: exclusions(exclude) - } - }); - - // construct an aggregate schema from the schemas of imported - // components and this component's types/resolvers (if present) - this._schema = stitchSchemas({ - subschemas, - typeDefs: this._types, - resolvers: this._resolvers, - schemaDirectives: this._directives, - mergeDirectives: true - }); - } - else { - const schemaConfig = { - typeDefs: mergeTypeDefs(this._types), - resolvers: this._resolvers, - schemaDirectives: this._directives - } - - const makeSchema = this._getMakeSchemaFunction(); - - this._schema = makeSchema(schemaConfig); - } - - if (this._mocks !== undefined && typeof this._mocks === 'boolean' && this._mocks === true) { - debug(`adding default mocks to the schema for ${this.name}`); - // if mocks are a boolean support simply applying default mocks - this._schema = addMocksToSchema({schema: this._schema, preserveResolvers: true}); - } - else if (this._mocks !== undefined && typeof this._mocks === 'object') { - debug(`adding custom mocks to the schema for ${this.name}`); - // else if mocks is an object, that means the user provided - // custom mocks, with which we pass them to addMocksToSchema so they are applied - this._schema = addMocksToSchema({schema: this._schema, mocks: this._mocks, preserveResolvers: true}); - } - - if (this._pruneSchema) { - this._schema = pruneSchema(this._schema, this._pruneSchemaOptions); - } - - debug(`created schema for ${this.name}`); - - return this._schema; - } - - get context() { - return wrapContext(this); - } - - get types() { - return this._types; - } - - get resolvers() { - return this._resolvers; - } - - get imports() { - return this._imports; - } - - get directives() { - return this._directives; - } - - get dataSources() { - return this._dataSources; - } - - set federation(flag) { - this._federation = flag; - } -} - -module.exports = GraphQLComponent; diff --git a/lib/resolvers/__tests__.js b/lib/resolvers/__tests__.js deleted file mode 100644 index 4434789..0000000 --- a/lib/resolvers/__tests__.js +++ /dev/null @@ -1,225 +0,0 @@ -'use strict'; - -const Test = require('tape'); -const { GraphQLScalarType } = require('graphql'); -const { - memoize, - bindResolvers, -} = require('./index'); - -Test('memoize()', (t) => { - t.test('memoize() a resolver function', (st) => { - let resolverRunCount = 0; - - const resolverToMemoize = function () { - resolverRunCount += 1; - return resolverRunCount; - }; - - const memoizedResolver = memoize('Query', 'test', resolverToMemoize); - - const parent = {}; - const args = {}; - const context = {}; - const info = { - path: { - key: 'test' - } - } - - let callCount = memoizedResolver(parent, args, context, info); - - st.equal(callCount, 1, 'first call of memoized resolver returns expected value'); - - callCount = memoizedResolver(parent, args, context, info); - - st.equal(callCount, 1, 'second call of memoizedResolver function doesnt call underlying resolver'); - st.end(); - }); - - t.test('memoize() with different operation aliases', (st) => { - let resolverRunCount = 0; - - const resolverToMemoize = function () { - resolverRunCount += 1; - return resolverRunCount; - }; - - const memoizedResolver = memoize('Query', 'test', resolverToMemoize); - - const parent = {}; - const args = {}; - const context = {}; - const infoWithAlias1 = { path: { key: 'alias1' } }; - const infoWithAlias2 = { path: { key: 'alias2' } }; - - let callCount = memoizedResolver(parent, args, context, infoWithAlias1); - - st.equal(callCount, 1, 'first call returns expected call count of 1'); - - callCount = memoizedResolver(parent, args, context, infoWithAlias2); - - st.equal(callCount, 2, 'second call of same resolver with different alias results in cache miss and call count 2'); - st.end(); - }); - - t.test('memoize() with different context', (st) => { - let resolverRunCount = 0; - - const resolverToMemoize = function () { - resolverRunCount += 1; - return resolverRunCount; - }; - - const memoizedResolver = memoize('Query', 'test', resolverToMemoize); - - const parent = {}; - const args = {}; - let context = {}; - const info = { path: { key: 'test'} }; - - let callCount = memoizedResolver(parent, args, context, info); - - st.equal(callCount, 1, 'first call returns expected call count of 1'); - - callCount = memoizedResolver(parent, args, context, info); - - st.equal(callCount, 1, 'second call with same context returns expected call count of 1'); - - // set context to a new reference - context = {}; - callCount = memoizedResolver(parent, args, context, info); - - st.equal(callCount, 2, 'third call with different context results in cache miss and expected call count 2'); - st.end(); - }); - - t.test('memoize() with different args', (st) => { - let resolverRunCount = 0; - - const resolverToMemoize = function () { - resolverRunCount += 1; - return resolverRunCount; - }; - - const memoizedResolver = memoize('Query', 'test', resolverToMemoize); - - const parent = {}; - const args = {}; - const context = {}; - const info = { path: { key: 'test'} }; - - let callCount = memoizedResolver(parent, args, context, info); - - st.equal(callCount, 1, 'first call returns expected call count of 1'); - - args.foo = 'bar'; - callCount = memoizedResolver(parent, args, context, info); - - st.equal(callCount, 2, 'second call with different args results in cache miss and expected call count 2'); - st.end(); - }); -}); - -Test('bindResolvers()', (t) => { - t.test('bind Query field resolver function', (st) => { - const resolvers = { - Query: { - test() { - return this.id; - } - } - }; - - const bound = bindResolvers({ id: 1 }, resolvers); - - const value = bound.Query.test({}, {}, {}, { parentType: 'Query', path: { key: 'test' } }); - - st.equal(value, 1, 'Query field resolver is bound'); - st.end(); - }); - - t.test('bind Mutation field resolver function', (st) => { - const resolvers = { - Mutation: { - test() { - return this.id; - } - } - }; - - const bound = bindResolvers({ id: 1 }, resolvers); - - const value = bound.Mutation.test({}, {}, {}, { parentType: 'Mutation', path: { key: 'test' } }); - - st.equal(value, 1, 'Mutation field resolver is bound'); - st.end(); - }); - - t.test('bind Subscription field resolver object', (st) => { - - const resolvers = { - Subscription: { - someSub: { - subscribe: () => { st.notOk(this.id, 'subscription subscribe() resolver was not bound')} - } - } - }; - - const bound = bindResolvers({ id: 1 }, resolvers); - // call the wrapped resolver result to assert this test case - bound.Subscription.someSub.subscribe(); - st.end(); - }); - - t.test('bind an enum remap', (st) => { - const resolvers = { - FooBarEnumType: { - FOO: 1, - BAR: 2 - } - } - - const bound = bindResolvers({id: 1}, resolvers); - st.equal(bound.FooBarEnumType.FOO, 1, 'enum remap runs through bindResolvers() without error, left as is'); - st.end(); - }); - - t.test('bind non root type field resolver', (st) => { - const resolvers = { - SomeType: { - test() { - return this.id; - } - } - }; - - const bound = bindResolvers({ id: 1 }, resolvers); - - const value = bound.SomeType.test({}, {}, {}, { parentType: 'SomeType', path: { key: 'test' } }); - - st.equal(value, 1, 'SomeType field resolver is bound'); - st.end(); - }); - - t.test('bind a custom GraphQLScalarType resolver', (st) => { - const CustomScalarType = new GraphQLScalarType({ - name: 'CustomScalarType', - description: 'foo bar custom scalar type', - serialize() {}, - parseValue() {}, - parseLiteral() {} - }) - const resolvers = { - Query: { - foo() {} - }, - CustomScalarType - }; - const bound = bindResolvers({ id: 1}, resolvers); - st.equal(bound.CustomScalarType, CustomScalarType, 'wrapped reference is equal to original reference (returned as is)'); - st.end(); - }); -}); - - diff --git a/lib/resolvers/index.js b/lib/resolvers/index.js deleted file mode 100644 index 329709e..0000000 --- a/lib/resolvers/index.js +++ /dev/null @@ -1,96 +0,0 @@ -'use strict'; - -const debug = require('debug')('graphql-component:resolver'); -const { GraphQLScalarType } = require('graphql'); - -/** - * memoizes resolver functions such that calls of an identical resolver (args/context/path) within the same request context are avoided - * @param {string} parentType - the type whose field resolver is being - * wrapped/memoized - * @param {string} fieldName - the field on the parentType whose resolver - * function is being wrapped/memoized - * @param {function} resolve - the resolver function that parentType. - * fieldName is mapped to - * @returns {function} a function that wraps the input resolver function and - * whose closure scope contains a WeakMap to achieve memoization of the wrapped - * input resolver function - */ - const memoize = function (parentType, fieldName, resolve) { - const _cache = new WeakMap(); - - return function _memoizedResolver(_, args, context, info) { - const path = info && info.path && info.path.key; - const key = `${path}_${JSON.stringify(args)}`; - - debug(`executing ${parentType}.${fieldName}`); - - let cached = _cache.get(context); - - if (cached && cached[key]) { - debug(`return cached result of memoized ${parentType}.${fieldName}`); - return cached[key]; - } - - if (!cached) { - cached = {}; - } - - const result = resolve(_, args, context, info); - - cached[key] = result; - - _cache.set(context, cached); - - debug(`cached ${parentType}.${fieldName}`); - - return result; - }; -}; - -/** - * make 'this' in resolver functions equal to the input bindContext - * @param {Object} bind - the object context to bind to resolver functions - * @param {Object} resolvers - the resolver map containing the resolver - * functions to bind - * @returns {Object} - an object identical in structure to the input resolver - * map, except with resolver function bound to the input argument bind - */ -const bindResolvers = function (bindContext, resolvers = {}) { - const boundResolvers = {}; - - for (const [type, fields] of Object.entries(resolvers)) { - // dont bind an object that is an instance of a graphql scalar - if (fields instanceof GraphQLScalarType) { - debug(`not binding ${type}'s fields since ${type}'s fields are an instance of GraphQLScalarType`) - boundResolvers[type] = fields; - continue; - } - - if (!boundResolvers[type]) { - boundResolvers[type] = {}; - } - - for (const [field, resolver] of Object.entries(fields)) { - if (['Query', 'Mutation'].indexOf(type) > -1) { - debug(`memoized ${type}.${field}`); - boundResolvers[type][field] = memoize(type, field, resolver.bind(bindContext)); - } - else { - // only bind resolvers that are functions - if (typeof resolver === 'function') { - debug(`binding ${type}.${field}`); - boundResolvers[type][field] = resolver.bind(bindContext); - } - else { - debug(`not binding ${type}.${field} since ${field} is not mapped to a function`); - boundResolvers[type][field] = resolver; - } - } - } - } - - return boundResolvers; -} - -module.exports = { bindResolvers, memoize }; - diff --git a/lib/transforms/__tests__.js b/lib/transforms/__tests__.js deleted file mode 100644 index d58eafd..0000000 --- a/lib/transforms/__tests__.js +++ /dev/null @@ -1,51 +0,0 @@ -'use strict'; - -const { exclusions } = require('./index.js'); -const Test = require('tape'); -const { FilterTypes, FilterObjectFields } = require('@graphql-tools/wrap'); - -Test('exclusions() accepts null exclude arg', (t) => { - t.plan(1); - - t.doesNotThrow(() => { - exclusions(); - }, 'does not explode'); -}); - -Test('exclusions() throws an error if passed a malformed exclusion', (t) => { - try { - exclusions(['mal.form.ed']); - } catch (e) { - t.equals(e.message, `'mal.form.ed' is malformed, should be of form 'type[.[field]]'`) - } - t.end(); -}); - -Test('exclusions() simply returns exclusions passed as objects', (t) => { - const filterType = new FilterTypes(); - const result = exclusions([filterType]); - console.log(result); - t.equals(result.length, 1, '1 transform is returned') - t.equals(result[0], filterType, 'transform is returned as is, since it was an object'); - t.end(); -}); - -Test(`exclusions() converts 'Type' only exclusion to FilterTypes transform`, (t) => { - const result = exclusions(['Query']); - t.ok(result[0] instanceof FilterTypes, 'resulting transform is an instance of graphql-tools FilterTypes'); - t.end(); -}); - -Test(`exclusions() converts 'Type.*' exclusion to FilterTypes transform`, (t) => { - const result = exclusions(['Query.*']); - t.ok(result[0] instanceof FilterTypes, 'resulting transform is an instance of graphql-tools FilterTypes'); - t.end(); -}); - -Test(`exclusions() converts 'Type.field' exclusion to FilterObjectFields transform`, (t) => { - const result = exclusions(['Query.foo']); - t.ok(result[0] instanceof FilterObjectFields, 'resulting transform is instance of graphql-tools FilterObjectFields'); - t.end(); -}); - -// TODO: actual type exclusions tests on GraphQLComponent instances here \ No newline at end of file diff --git a/lib/transforms/index.js b/lib/transforms/index.js deleted file mode 100644 index eb9c822..0000000 --- a/lib/transforms/index.js +++ /dev/null @@ -1,47 +0,0 @@ -'use strict'; - -const { FilterTypes, FilterObjectFields } = require('@graphql-tools/wrap'); - -const exclusions = function(exclusions = []) { - return exclusions.map((exclusion) => { - if (typeof exclusion === 'string') { - const parts = exclusion.split('.'); - let type; - let field; - if (parts.length === 1) { - type = parts[0]; - } - else if (parts.length === 2) { - type = parts[0]; - field = parts[1]; - } - else { - throw new Error(`'${exclusion}' is malformed, should be of form 'type[.[field]]'`) - } - - // specific type/field exclusion such as 'Query.foo' - if (type && field && field !== '*') { - return new FilterObjectFields((typeName, fieldName) => { - if (typeName === type && field === fieldName) { - return false; - } - return true; - }) - } - // type only exclusion (such as 'Query') or type and all fields exclusions (such as 'Query.*') - else if (type && !field || (type && field && field === '*')) { - return new FilterTypes(graphqlObjectType => { - if (graphqlObjectType.name === type) { - return false; - } - return true; - }) - } - // assume that someone passed in a valid graphql-tools transform - } else if (typeof exclusion === 'object') { - return exclusion; - } - }); -} - -module.exports = { exclusions }; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 815636a..0000000 --- a/package-lock.json +++ /dev/null @@ -1,5543 +0,0 @@ -{ - "name": "graphql-component", - "version": "3.0.4", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@apollo/client": { - "version": "3.6.9", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@apollo/client/-/client-3.6.9.tgz", - "integrity": "sha1-rQ7i46PJLb7UrNaRe2FYpJJznZQ=", - "optional": true, - "requires": { - "@graphql-typed-document-node/core": "^3.1.1", - "@wry/context": "^0.6.0", - "@wry/equality": "^0.5.0", - "@wry/trie": "^0.3.0", - "graphql-tag": "^2.12.6", - "hoist-non-react-statics": "^3.3.2", - "optimism": "^0.16.1", - "prop-types": "^15.7.2", - "symbol-observable": "^4.0.0", - "ts-invariant": "^0.10.3", - "tslib": "^2.3.0", - "zen-observable-ts": "^1.2.5" - } - }, - "@apollo/federation": { - "version": "0.28.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@apollo/federation/-/federation-0.28.0.tgz", - "integrity": "sha1-u/zePzJ7PsZdz9mMb1LWYjo4slE=", - "requires": { - "apollo-graphql": "^0.9.3", - "apollo-server-types": "^3.0.2", - "lodash.xorby": "^4.7.0" - } - }, - "@apollo/gateway": { - "version": "0.28.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@apollo/gateway/-/gateway-0.28.3.tgz", - "integrity": "sha1-nav8Zq3a3/gSGC/1Jmc8bPZnltc=", - "dev": true, - "requires": { - "@apollo/federation": "^0.25.1", - "@apollo/query-planner": "^0.2.1", - "@types/node-fetch": "2.5.10", - "apollo-graphql": "^0.9.3", - "apollo-reporting-protobuf": "^0.8.0", - "apollo-server-caching": "^0.7.0", - "apollo-server-core": "^2.23.0", - "apollo-server-env": "^3.0.0", - "apollo-server-errors": "^2.5.0", - "apollo-server-types": "^0.9.0", - "loglevel": "^1.6.1", - "make-fetch-happen": "^8.0.0", - "pretty-format": "^26.0.0" - }, - "dependencies": { - "@apollo/federation": { - "version": "0.25.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@apollo/federation/-/federation-0.25.2.tgz", - "integrity": "sha1-ELLiKsIOZHAf1tMdmrv39BGwN2M=", - "dev": true, - "requires": { - "apollo-graphql": "^0.9.3", - "lodash.xorby": "^4.7.0" - } - }, - "@apollo/protobufjs": { - "version": "1.2.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@apollo/protobufjs/-/protobufjs-1.2.2.tgz", - "integrity": "sha1-S9ks13Acyu9tUXzbda8nVfBJ+Hw=", - "dev": true, - "requires": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.0", - "@types/node": "^10.1.0", - "long": "^4.0.0" - } - }, - "apollo-reporting-protobuf": { - "version": "0.8.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-reporting-protobuf/-/apollo-reporting-protobuf-0.8.0.tgz", - "integrity": "sha1-rp2WeTTT2O2Bb8haDYBo70XDcbk=", - "dev": true, - "requires": { - "@apollo/protobufjs": "1.2.2" - } - }, - "apollo-server-env": { - "version": "3.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-server-env/-/apollo-server-env-3.1.0.tgz", - "integrity": "sha1-BzPC71CupZbMkM9ApT9uoq1ALNA=", - "dev": true, - "requires": { - "node-fetch": "^2.6.1", - "util.promisify": "^1.0.0" - } - }, - "apollo-server-types": { - "version": "0.9.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-server-types/-/apollo-server-types-0.9.0.tgz", - "integrity": "sha1-zPVQszsHxIxy8QT74odiMrQEhIs=", - "dev": true, - "requires": { - "apollo-reporting-protobuf": "^0.8.0", - "apollo-server-caching": "^0.7.0", - "apollo-server-env": "^3.1.0" - } - } - } - }, - "@apollo/protobufjs": { - "version": "1.2.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@apollo/protobufjs/-/protobufjs-1.2.4.tgz", - "integrity": "sha1-2RPnYnIQ7F79dYzut1HHdsaLoTM=", - "requires": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.0", - "@types/node": "^10.1.0", - "long": "^4.0.0" - } - }, - "@apollo/query-planner": { - "version": "0.2.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@apollo/query-planner/-/query-planner-0.2.3.tgz", - "integrity": "sha1-gBiuEsJFQYOFQcx7INamKFVpGOU=", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "deep-equal": "^2.0.5", - "pretty-format": "^26.0.0" - } - }, - "@apollo/utils.keyvaluecache": { - "version": "1.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@apollo/utils.keyvaluecache/-/utils.keyvaluecache-1.0.1.tgz", - "integrity": "sha1-RvMQ+FkGfv6foSYVbGlU+DgQgNI=", - "requires": { - "@apollo/utils.logger": "^1.0.0", - "lru-cache": "^7.10.1" - } - }, - "@apollo/utils.logger": { - "version": "1.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@apollo/utils.logger/-/utils.logger-1.0.0.tgz", - "integrity": "sha1-bjRgoiUMLvfCw7C+a14UihWW8Ss=" - }, - "@apollographql/apollo-tools": { - "version": "0.5.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@apollographql/apollo-tools/-/apollo-tools-0.5.4.tgz", - "integrity": "sha1-yzmYxs8S5JS5DHM/RN2ZNeLYGWw=", - "dev": true - }, - "@apollographql/graphql-playground-html": { - "version": "1.6.27", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@apollographql/graphql-playground-html/-/graphql-playground-html-1.6.27.tgz", - "integrity": "sha1-vJq2DpRFqiqIE7TpTxUvpyt1YzU=", - "dev": true, - "requires": { - "xss": "^1.0.8" - } - }, - "@apollographql/graphql-upload-8-fork": { - "version": "8.1.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@apollographql/graphql-upload-8-fork/-/graphql-upload-8-fork-8.1.3.tgz", - "integrity": "sha1-oNTg1c7I4SbXi9kVwmTWuQ9XhLw=", - "dev": true, - "requires": { - "@types/express": "*", - "@types/fs-capacitor": "*", - "@types/koa": "*", - "busboy": "^0.3.1", - "fs-capacitor": "^2.0.4", - "http-errors": "^1.7.3", - "object-path": "^0.11.4" - } - }, - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha1-OyXTjIlgC6otzCGe36iKdOssQno=", - "dev": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@babel/generator": { - "version": "7.18.10", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@babel/generator/-/generator-7.18.10.tgz", - "integrity": "sha1-eU8yi/q9y68Ov5v5G1tXth+neio=", - "dev": true, - "requires": { - "@babel/types": "^7.18.10", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - } - }, - "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha1-DAzumzXSyhkEeHVoZbs1KEIvUb4=", - "dev": true - }, - "@babel/helper-function-name": { - "version": "7.18.9", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz", - "integrity": "sha1-lA5ghKVd7oZ9M7Tkh9omdjZehrA=", - "dev": true, - "requires": { - "@babel/template": "^7.18.6", - "@babel/types": "^7.18.9" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha1-1NLI+0uuqlxouZzIJFxWVU+SZng=", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha1-c2eUm8dbIMbVpdSpe7ooJK6O8HU=", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-string-parser": { - "version": "7.18.10", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", - "integrity": "sha1-GB8i0o6+GzhX+ldfXCkLGq9lm1Y=", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha1-nJfjDTGyuMcqHQiYTyyptXTXoHY=", - "dev": true - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha1-gRWGAek+JWN5Wty/vfXWS+Py7N8=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg=", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/parser": { - "version": "7.18.10", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@babel/parser/-/parser-7.18.10.tgz", - "integrity": "sha1-lLX4UiNW5p6Cdydq32ftKAyQ7ME=", - "dev": true - }, - "@babel/template": { - "version": "7.18.10", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha1-b5E0g1lw0dvwg1wNEAyfON4MXnE=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" - } - }, - "@babel/traverse": { - "version": "7.18.10", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@babel/traverse/-/traverse-7.18.10.tgz", - "integrity": "sha1-N62X0csA76hpuR3V0ZUPimzwywg=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.18.10", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.18.9", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "dependencies": { - "globals": { - "version": "11.12.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/globals/-/globals-11.12.0.tgz", - "integrity": "sha1-q4eVM4hooLq9hSV1gBjCp+uVxC4=", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.18.10", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@babel/types/-/types-7.18.10.tgz", - "integrity": "sha1-SQjoG2sznKfGt6VVpfwpRG8m3eY=", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.18.6", - "to-fast-properties": "^2.0.0" - } - }, - "@gar/promisify": { - "version": "1.1.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha1-VVGTqy47s7atw9VRycAw2ehg2vY=", - "dev": true - }, - "@graphql-tools/merge": { - "version": "8.3.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@graphql-tools/merge/-/merge-8.3.1.tgz", - "integrity": "sha1-BhIZQq0omCoUY128h7XUiKBB1yI=", - "requires": { - "@graphql-tools/utils": "8.9.0", - "tslib": "^2.4.0" - }, - "dependencies": { - "@graphql-tools/utils": { - "version": "8.9.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@graphql-tools/utils/-/utils-8.9.0.tgz", - "integrity": "sha1-xqpfZRycmeGspVUQryG1bsKWzbc=", - "requires": { - "tslib": "^2.4.0" - } - } - } - }, - "@graphql-tools/schema": { - "version": "8.5.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@graphql-tools/schema/-/schema-8.5.1.tgz", - "integrity": "sha1-wvL/FEg4CRmjMDEjmclHHbJYC1g=", - "requires": { - "@graphql-tools/merge": "8.3.1", - "@graphql-tools/utils": "8.9.0", - "tslib": "^2.4.0", - "value-or-promise": "1.0.11" - }, - "dependencies": { - "@graphql-tools/utils": { - "version": "8.9.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@graphql-tools/utils/-/utils-8.9.0.tgz", - "integrity": "sha1-xqpfZRycmeGspVUQryG1bsKWzbc=", - "requires": { - "tslib": "^2.4.0" - } - } - } - }, - "@graphql-tools/utils": { - "version": "8.9.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@graphql-tools/utils/-/utils-8.9.0.tgz", - "integrity": "sha1-xqpfZRycmeGspVUQryG1bsKWzbc=", - "requires": { - "tslib": "^2.4.0" - } - }, - "@graphql-typed-document-node/core": { - "version": "3.1.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@graphql-typed-document-node/core/-/core-3.1.1.tgz", - "integrity": "sha1-B214zpmCIljPgT7MHn+kYPp00FI=", - "optional": true - }, - "@jest/types": { - "version": "26.6.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha1-vvWlMgMOHYii9abZM/hOlyJu1I4=", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@josephg/resolvable": { - "version": "1.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@josephg/resolvable/-/resolvable-1.0.1.tgz", - "integrity": "sha1-abxNt1TXnhovF6ZQ00ZuA42Upes=", - "dev": true - }, - "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha1-wa7cYehT8rufXf5tRELTtWWyU7k=", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha1-IgOxGMFXchrd/mnUe3BGVGMGbXg=", - "dev": true - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha1-fGz5mNbSC5FMClWpGuko/yWWXnI=", - "dev": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha1-rdTJjTQUcqKJGQtCTvvbCWmRuyQ=", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.14", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", - "integrity": "sha1-sjGggdj2Z5bkda1Yih70cxEnAe0=", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@npmcli/fs": { - "version": "1.1.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@npmcli/fs/-/fs-1.1.1.tgz", - "integrity": "sha1-cvcZ/pNeaHxWpPrs88A9BrpZMlc=", - "dev": true, - "requires": { - "@gar/promisify": "^1.0.1", - "semver": "^7.3.5" - } - }, - "@npmcli/move-file": { - "version": "1.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@npmcli/move-file/-/move-file-1.1.2.tgz", - "integrity": "sha1-GoLD43L3yuklPrZtclQ9a4aFxnQ=", - "dev": true, - "requires": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - } - }, - "@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" - }, - "@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha1-TIVzDlm5ofHzSQR9vyQpYDS7JzU=" - }, - "@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha1-fvN/DQEPsCitGtWXIuUG2SYoFcs=" - }, - "@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" - }, - "@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", - "requires": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" - }, - "@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" - }, - "@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" - }, - "@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" - }, - "@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" - }, - "@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha1-OALd0hpQqUm2ch3dcto25n5/Gy0=", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha1-P9wrbLWJNbIb+40WJesTAEhDFuc=", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, - "@sinonjs/samsam": { - "version": "6.1.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@sinonjs/samsam/-/samsam-6.1.1.tgz", - "integrity": "sha1-Yn9/TL21bmQZ+iwaPkdRzk9qALE=", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.6.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" - } - }, - "@sinonjs/text-encoding": { - "version": "0.7.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", - "integrity": "sha1-WYGo2xi1a6OO8O+32ZWxKqe1GRg=", - "dev": true - }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha1-zLkURTYBeaBOf+av94wA/8Hur4I=", - "dev": true - }, - "@types/accepts": { - "version": "1.3.5", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/accepts/-/accepts-1.3.5.tgz", - "integrity": "sha1-w0vsEVz8dG4E/loFnfTOfns5FXU=", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/body-parser": { - "version": "1.19.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha1-rqIFnii3ZYY5CBNHrE+rPeFm5vA=", - "dev": true, - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "@types/connect": { - "version": "3.4.35", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha1-X89q5EXkAh0fwiGaSHPMc6O7KtE=", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/content-disposition": { - "version": "0.5.5", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/content-disposition/-/content-disposition-0.5.5.tgz", - "integrity": "sha1-ZQgg6V3jRuH4TjBmfRaMj9JapuM=", - "dev": true - }, - "@types/cookies": { - "version": "0.7.7", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/cookies/-/cookies-0.7.7.tgz", - "integrity": "sha1-epJFPR0WOJwFpTAe71ZvNJRs/YE=", - "dev": true, - "requires": { - "@types/connect": "*", - "@types/express": "*", - "@types/keygrip": "*", - "@types/node": "*" - } - }, - "@types/cors": { - "version": "2.8.10", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/cors/-/cors-2.8.10.tgz", - "integrity": "sha1-YcyEaYSeW83QxwRBIiZcOc7BDPQ=", - "dev": true - }, - "@types/express": { - "version": "4.17.13", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/express/-/express-4.17.13.tgz", - "integrity": "sha1-p24plXKJmbq1GjP6vOHXBaNwkDQ=", - "dev": true, - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.17.30", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/express-serve-static-core/-/express-serve-static-core-4.17.30.tgz", - "integrity": "sha1-Dy+ZYX+o+WlhcMRhUsz3UAs0rAQ=", - "dev": true, - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "@types/fs-capacitor": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/fs-capacitor/-/fs-capacitor-2.0.0.tgz", - "integrity": "sha1-FxE+JYF/WE9YEA+3oI7tKIuBlW4=", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/http-assert": { - "version": "1.5.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/http-assert/-/http-assert-1.5.3.tgz", - "integrity": "sha1-7449Go1Gw4fwSrDy6KuMsMUHhmE=", - "dev": true - }, - "@types/http-errors": { - "version": "1.8.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/http-errors/-/http-errors-1.8.2.tgz", - "integrity": "sha1-cxW0xMVPgtE/phwijsXC6lzJ4OE=", - "dev": true - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha1-hGfUs8CHgF1jWASAiQeRJ3zjXEQ=", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha1-wUwk8Y6oGQwRjudWK3/5mjZVJoY=", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha1-kVP+mLuivVZaY63ZQ21vDX+EaP8=", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/keygrip": { - "version": "1.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/keygrip/-/keygrip-1.0.2.tgz", - "integrity": "sha1-UTq/0lbXrQvx7hhzYGMXszsbKnI=", - "dev": true - }, - "@types/koa": { - "version": "2.13.5", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/koa/-/koa-2.13.5.tgz", - "integrity": "sha1-ZLPKTVTgjABi6J7GZsn0VEOyGmE=", - "dev": true, - "requires": { - "@types/accepts": "*", - "@types/content-disposition": "*", - "@types/cookies": "*", - "@types/http-assert": "*", - "@types/http-errors": "*", - "@types/keygrip": "*", - "@types/koa-compose": "*", - "@types/node": "*" - } - }, - "@types/koa-compose": { - "version": "3.2.5", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/koa-compose/-/koa-compose-3.2.5.tgz", - "integrity": "sha1-hesugKxQvpXzfM+MQHwJu+NGjp0=", - "dev": true, - "requires": { - "@types/koa": "*" - } - }, - "@types/long": { - "version": "4.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/long/-/long-4.0.2.tgz", - "integrity": "sha1-t0EpcZ/I0RwBhoAQCC1IO3VFWRo=" - }, - "@types/mime": { - "version": "3.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/mime/-/mime-3.0.0.tgz", - "integrity": "sha1-6amQOJRAXGplUfF3TfTmTZgE1pw=", - "dev": true - }, - "@types/node": { - "version": "10.17.60", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/node/-/node-10.17.60.tgz", - "integrity": "sha1-NfPWIT2u2V2n8Pc+dbzGmA6QWXs=" - }, - "@types/node-fetch": { - "version": "2.5.10", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/node-fetch/-/node-fetch-2.5.10.tgz", - "integrity": "sha1-m01KBCVWL5/OpwsSyz/N2UbKgTI=", - "dev": true, - "requires": { - "@types/node": "*", - "form-data": "^3.0.0" - } - }, - "@types/qs": { - "version": "6.9.7", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha1-Y7t9Bn2xB8weRXwwO8JdUR/r9ss=", - "dev": true - }, - "@types/range-parser": { - "version": "1.2.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha1-zWZ7z90CUhOq+3ylkVqTJZCs3Nw=", - "dev": true - }, - "@types/serve-static": { - "version": "1.15.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha1-x5MP9hr7M04SGp2ngKrA2bjzQVU=", - "dev": true, - "requires": { - "@types/mime": "*", - "@types/node": "*" - } - }, - "@types/ws": { - "version": "7.4.7", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/ws/-/ws-7.4.7.tgz", - "integrity": "sha1-98OQo296Bnmqad4tUBMZ9PjZtwI=", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/yargs": { - "version": "15.0.14", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/yargs/-/yargs-15.0.14.tgz", - "integrity": "sha1-Jtgh3biecEkhYLZtEKDrbfj2+wY=", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha1-DGDlN/p5D1+Ucu0ndsK3HsEXNRs=", - "dev": true - }, - "@wry/context": { - "version": "0.6.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@wry/context/-/context-0.6.1.tgz", - "integrity": "sha1-w8KcCtYirbAPalMwPE+WXuBuvrI=", - "optional": true, - "requires": { - "tslib": "^2.3.0" - } - }, - "@wry/equality": { - "version": "0.5.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@wry/equality/-/equality-0.5.2.tgz", - "integrity": "sha1-csinp9iE3/MLYS9PhGTromwIDnM=", - "optional": true, - "requires": { - "tslib": "^2.3.0" - } - }, - "@wry/trie": { - "version": "0.3.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@wry/trie/-/trie-0.3.1.tgz", - "integrity": "sha1-Inm3kPFQMvi86n/JRNJ5iOWzsTk=", - "optional": true, - "requires": { - "tslib": "^2.3.0" - } - }, - "accepts": { - "version": "1.3.8", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha1-C/C+EltnAUrcsLCSHmLbe//hay4=", - "dev": true, - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, - "acorn": { - "version": "7.4.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha1-/q7SVZc9LndVW4PbwIhRpsY1IPo=", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha1-ftW7VZCLOy8bxVxq8WU7rafweTc=", - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha1-Sf/1hXfP7j83F2/qtMIuAPhtf3c=", - "dev": true, - "requires": { - "debug": "4" - } - }, - "agentkeepalive": { - "version": "4.2.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/agentkeepalive/-/agentkeepalive-4.2.1.tgz", - "integrity": "sha1-p5dcu5+Ds2fwbJDMUf8o/n1Jlxc=", - "dev": true, - "requires": { - "debug": "^4.1.0", - "depd": "^1.1.2", - "humanize-ms": "^1.2.1" - } - }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha1-kmcP9Q9TWb23o+DUDQ7DDFc3aHo=", - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha1-uvWmLoArB9l3A0WG+MO69a3ybfQ=", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha1-ayKR0dt9mLZSHV8e+kLQ86n+tl4=", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - }, - "dependencies": { - "type-fest": { - "version": "0.21.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha1-0mCiSwGYQ24TP6JqUkptZfo7Ljc=", - "dev": true - } - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha1-CCyyyJyf6GWaMRpTvWpNxTAdswQ=", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "apollo-cache-control": { - "version": "0.14.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-cache-control/-/apollo-cache-control-0.14.0.tgz", - "integrity": "sha1-lfIMPgPnmU4NG9SMWa6utXXtDOc=", - "dev": true, - "requires": { - "apollo-server-env": "^3.1.0", - "apollo-server-plugin-base": "^0.13.0" - }, - "dependencies": { - "apollo-server-env": { - "version": "3.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-server-env/-/apollo-server-env-3.1.0.tgz", - "integrity": "sha1-BzPC71CupZbMkM9ApT9uoq1ALNA=", - "dev": true, - "requires": { - "node-fetch": "^2.6.1", - "util.promisify": "^1.0.0" - } - } - } - }, - "apollo-datasource": { - "version": "0.9.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-datasource/-/apollo-datasource-0.9.0.tgz", - "integrity": "sha1-sLKRMlemEDpfTAPLVteKMOnYUNs=", - "dev": true, - "requires": { - "apollo-server-caching": "^0.7.0", - "apollo-server-env": "^3.1.0" - }, - "dependencies": { - "apollo-server-env": { - "version": "3.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-server-env/-/apollo-server-env-3.1.0.tgz", - "integrity": "sha1-BzPC71CupZbMkM9ApT9uoq1ALNA=", - "dev": true, - "requires": { - "node-fetch": "^2.6.1", - "util.promisify": "^1.0.0" - } - } - } - }, - "apollo-graphql": { - "version": "0.9.7", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-graphql/-/apollo-graphql-0.9.7.tgz", - "integrity": "sha1-MxhQk7SXpXjy32GrjsxkR9cArmQ=", - "requires": { - "core-js-pure": "^3.10.2", - "lodash.sortby": "^4.7.0", - "sha.js": "^2.4.11" - } - }, - "apollo-link": { - "version": "1.2.14", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-link/-/apollo-link-1.2.14.tgz", - "integrity": "sha1-P+2ktH+eu6f0Fgvvi5d7pyW2hNk=", - "dev": true, - "requires": { - "apollo-utilities": "^1.3.0", - "ts-invariant": "^0.4.0", - "tslib": "^1.9.3", - "zen-observable-ts": "^0.8.21" - }, - "dependencies": { - "ts-invariant": { - "version": "0.4.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ts-invariant/-/ts-invariant-0.4.4.tgz", - "integrity": "sha1-l6UjUYaI+TqvrQGw6A64A+sqvYY=", - "dev": true, - "requires": { - "tslib": "^1.9.3" - } - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha1-zy04vcNKE0vK8QkcQfZhni9nLQA=", - "dev": true - }, - "zen-observable-ts": { - "version": "0.8.21", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/zen-observable-ts/-/zen-observable-ts-0.8.21.tgz", - "integrity": "sha1-hdADH7veHro80H07qQ2iQSFfQh0=", - "dev": true, - "requires": { - "tslib": "^1.9.3", - "zen-observable": "^0.8.0" - } - } - } - }, - "apollo-reporting-protobuf": { - "version": "3.3.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-reporting-protobuf/-/apollo-reporting-protobuf-3.3.2.tgz", - "integrity": "sha1-IHjFPTFAvGIhxgQMUyZiPgwhyNQ=", - "requires": { - "@apollo/protobufjs": "1.2.4" - } - }, - "apollo-server": { - "version": "2.25.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-server/-/apollo-server-2.25.4.tgz", - "integrity": "sha1-2geENA3e/PUItLRXROPGFkDE7x0=", - "dev": true, - "requires": { - "apollo-server-core": "^2.25.4", - "apollo-server-express": "^2.25.4", - "express": "^4.0.0", - "graphql-subscriptions": "^1.0.0", - "graphql-tools": "^4.0.8", - "stoppable": "^1.1.0" - }, - "dependencies": { - "graphql-tools": { - "version": "4.0.8", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/graphql-tools/-/graphql-tools-4.0.8.tgz", - "integrity": "sha1-5/ufDUNAj7CHi6ZrUizocbr+nTA=", - "dev": true, - "requires": { - "apollo-link": "^1.2.14", - "apollo-utilities": "^1.0.1", - "deprecated-decorator": "^0.1.6", - "iterall": "^1.1.3", - "uuid": "^3.1.0" - } - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha1-sj5DWK+oogL+ehAK8fX4g/AgB+4=", - "dev": true - } - } - }, - "apollo-server-caching": { - "version": "0.7.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-server-caching/-/apollo-server-caching-0.7.0.tgz", - "integrity": "sha1-5tHmjju1ccumOmH2C0NPt3HG/zk=", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - } - } - }, - "apollo-server-core": { - "version": "2.25.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-server-core/-/apollo-server-core-2.25.4.tgz", - "integrity": "sha1-pWQ3ZJYBZxPH3OqsPZ5lLHpDMmA=", - "dev": true, - "requires": { - "@apollographql/apollo-tools": "^0.5.0", - "@apollographql/graphql-playground-html": "1.6.27", - "@apollographql/graphql-upload-8-fork": "^8.1.3", - "@josephg/resolvable": "^1.0.0", - "@types/ws": "^7.0.0", - "apollo-cache-control": "^0.14.0", - "apollo-datasource": "^0.9.0", - "apollo-graphql": "^0.9.0", - "apollo-reporting-protobuf": "^0.8.0", - "apollo-server-caching": "^0.7.0", - "apollo-server-env": "^3.1.0", - "apollo-server-errors": "^2.5.0", - "apollo-server-plugin-base": "^0.13.0", - "apollo-server-types": "^0.9.0", - "apollo-tracing": "^0.15.0", - "async-retry": "^1.2.1", - "fast-json-stable-stringify": "^2.0.0", - "graphql-extensions": "^0.15.0", - "graphql-tag": "^2.11.0", - "graphql-tools": "^4.0.8", - "loglevel": "^1.6.7", - "lru-cache": "^6.0.0", - "sha.js": "^2.4.11", - "subscriptions-transport-ws": "^0.9.19", - "uuid": "^8.0.0" - }, - "dependencies": { - "@apollo/protobufjs": { - "version": "1.2.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@apollo/protobufjs/-/protobufjs-1.2.2.tgz", - "integrity": "sha1-S9ks13Acyu9tUXzbda8nVfBJ+Hw=", - "dev": true, - "requires": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.0", - "@types/node": "^10.1.0", - "long": "^4.0.0" - } - }, - "apollo-reporting-protobuf": { - "version": "0.8.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-reporting-protobuf/-/apollo-reporting-protobuf-0.8.0.tgz", - "integrity": "sha1-rp2WeTTT2O2Bb8haDYBo70XDcbk=", - "dev": true, - "requires": { - "@apollo/protobufjs": "1.2.2" - } - }, - "apollo-server-env": { - "version": "3.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-server-env/-/apollo-server-env-3.1.0.tgz", - "integrity": "sha1-BzPC71CupZbMkM9ApT9uoq1ALNA=", - "dev": true, - "requires": { - "node-fetch": "^2.6.1", - "util.promisify": "^1.0.0" - } - }, - "apollo-server-types": { - "version": "0.9.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-server-types/-/apollo-server-types-0.9.0.tgz", - "integrity": "sha1-zPVQszsHxIxy8QT74odiMrQEhIs=", - "dev": true, - "requires": { - "apollo-reporting-protobuf": "^0.8.0", - "apollo-server-caching": "^0.7.0", - "apollo-server-env": "^3.1.0" - } - }, - "graphql-tools": { - "version": "4.0.8", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/graphql-tools/-/graphql-tools-4.0.8.tgz", - "integrity": "sha1-5/ufDUNAj7CHi6ZrUizocbr+nTA=", - "dev": true, - "requires": { - "apollo-link": "^1.2.14", - "apollo-utilities": "^1.0.1", - "deprecated-decorator": "^0.1.6", - "iterall": "^1.1.3", - "uuid": "^3.1.0" - }, - "dependencies": { - "uuid": { - "version": "3.4.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha1-sj5DWK+oogL+ehAK8fX4g/AgB+4=", - "dev": true - } - } - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - } - } - }, - "apollo-server-env": { - "version": "4.2.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-server-env/-/apollo-server-env-4.2.1.tgz", - "integrity": "sha1-6lsZRKzNvboxHxeeTfrspILCAYU=", - "requires": { - "node-fetch": "^2.6.7" - } - }, - "apollo-server-errors": { - "version": "2.5.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-server-errors/-/apollo-server-errors-2.5.0.tgz", - "integrity": "sha1-XRAkEXx0lqKXnj40kItWhf4RK2g=", - "dev": true - }, - "apollo-server-express": { - "version": "2.25.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-server-express/-/apollo-server-express-2.25.4.tgz", - "integrity": "sha1-vTceldj94FFuhn8GcoG3ocPYJgw=", - "dev": true, - "requires": { - "@apollographql/graphql-playground-html": "1.6.27", - "@types/accepts": "^1.3.5", - "@types/body-parser": "1.19.0", - "@types/cors": "2.8.10", - "@types/express": "^4.17.12", - "@types/express-serve-static-core": "^4.17.21", - "accepts": "^1.3.5", - "apollo-server-core": "^2.25.4", - "apollo-server-types": "^0.9.0", - "body-parser": "^1.18.3", - "cors": "^2.8.5", - "express": "^4.17.1", - "graphql-subscriptions": "^1.0.0", - "graphql-tools": "^4.0.8", - "parseurl": "^1.3.2", - "subscriptions-transport-ws": "^0.9.19", - "type-is": "^1.6.16" - }, - "dependencies": { - "@apollo/protobufjs": { - "version": "1.2.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@apollo/protobufjs/-/protobufjs-1.2.2.tgz", - "integrity": "sha1-S9ks13Acyu9tUXzbda8nVfBJ+Hw=", - "dev": true, - "requires": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.0", - "@types/node": "^10.1.0", - "long": "^4.0.0" - } - }, - "@types/body-parser": { - "version": "1.19.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@types/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha1-BoWzxH6zAG/+0RfN1VFkth+AU48=", - "dev": true, - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "apollo-reporting-protobuf": { - "version": "0.8.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-reporting-protobuf/-/apollo-reporting-protobuf-0.8.0.tgz", - "integrity": "sha1-rp2WeTTT2O2Bb8haDYBo70XDcbk=", - "dev": true, - "requires": { - "@apollo/protobufjs": "1.2.2" - } - }, - "apollo-server-env": { - "version": "3.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-server-env/-/apollo-server-env-3.1.0.tgz", - "integrity": "sha1-BzPC71CupZbMkM9ApT9uoq1ALNA=", - "dev": true, - "requires": { - "node-fetch": "^2.6.1", - "util.promisify": "^1.0.0" - } - }, - "apollo-server-types": { - "version": "0.9.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-server-types/-/apollo-server-types-0.9.0.tgz", - "integrity": "sha1-zPVQszsHxIxy8QT74odiMrQEhIs=", - "dev": true, - "requires": { - "apollo-reporting-protobuf": "^0.8.0", - "apollo-server-caching": "^0.7.0", - "apollo-server-env": "^3.1.0" - } - }, - "graphql-tools": { - "version": "4.0.8", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/graphql-tools/-/graphql-tools-4.0.8.tgz", - "integrity": "sha1-5/ufDUNAj7CHi6ZrUizocbr+nTA=", - "dev": true, - "requires": { - "apollo-link": "^1.2.14", - "apollo-utilities": "^1.0.1", - "deprecated-decorator": "^0.1.6", - "iterall": "^1.1.3", - "uuid": "^3.1.0" - } - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha1-sj5DWK+oogL+ehAK8fX4g/AgB+4=", - "dev": true - } - } - }, - "apollo-server-plugin-base": { - "version": "0.13.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-server-plugin-base/-/apollo-server-plugin-base-0.13.0.tgz", - "integrity": "sha1-P4V1GkINPEYlNVtss/vdKsvnHxM=", - "dev": true, - "requires": { - "apollo-server-types": "^0.9.0" - }, - "dependencies": { - "@apollo/protobufjs": { - "version": "1.2.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@apollo/protobufjs/-/protobufjs-1.2.2.tgz", - "integrity": "sha1-S9ks13Acyu9tUXzbda8nVfBJ+Hw=", - "dev": true, - "requires": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.0", - "@types/node": "^10.1.0", - "long": "^4.0.0" - } - }, - "apollo-reporting-protobuf": { - "version": "0.8.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-reporting-protobuf/-/apollo-reporting-protobuf-0.8.0.tgz", - "integrity": "sha1-rp2WeTTT2O2Bb8haDYBo70XDcbk=", - "dev": true, - "requires": { - "@apollo/protobufjs": "1.2.2" - } - }, - "apollo-server-env": { - "version": "3.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-server-env/-/apollo-server-env-3.1.0.tgz", - "integrity": "sha1-BzPC71CupZbMkM9ApT9uoq1ALNA=", - "dev": true, - "requires": { - "node-fetch": "^2.6.1", - "util.promisify": "^1.0.0" - } - }, - "apollo-server-types": { - "version": "0.9.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-server-types/-/apollo-server-types-0.9.0.tgz", - "integrity": "sha1-zPVQszsHxIxy8QT74odiMrQEhIs=", - "dev": true, - "requires": { - "apollo-reporting-protobuf": "^0.8.0", - "apollo-server-caching": "^0.7.0", - "apollo-server-env": "^3.1.0" - } - } - } - }, - "apollo-server-types": { - "version": "3.6.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-server-types/-/apollo-server-types-3.6.2.tgz", - "integrity": "sha1-NLsMM1/M4wV8vfcrO2PaGC3m/IQ=", - "requires": { - "@apollo/utils.keyvaluecache": "^1.0.1", - "@apollo/utils.logger": "^1.0.0", - "apollo-reporting-protobuf": "^3.3.2", - "apollo-server-env": "^4.2.1" - } - }, - "apollo-tracing": { - "version": "0.15.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-tracing/-/apollo-tracing-0.15.0.tgz", - "integrity": "sha1-I3+7v2aa7kNwt+kIG2heq6qM6Eo=", - "dev": true, - "requires": { - "apollo-server-env": "^3.1.0", - "apollo-server-plugin-base": "^0.13.0" - }, - "dependencies": { - "apollo-server-env": { - "version": "3.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-server-env/-/apollo-server-env-3.1.0.tgz", - "integrity": "sha1-BzPC71CupZbMkM9ApT9uoq1ALNA=", - "dev": true, - "requires": { - "node-fetch": "^2.6.1", - "util.promisify": "^1.0.0" - } - } - } - }, - "apollo-utilities": { - "version": "1.3.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-utilities/-/apollo-utilities-1.3.4.tgz", - "integrity": "sha1-YSnkOOi+IBtsVbDxPOSdLHF1yc8=", - "dev": true, - "requires": { - "@wry/equality": "^0.1.2", - "fast-json-stable-stringify": "^2.0.0", - "ts-invariant": "^0.4.0", - "tslib": "^1.10.0" - }, - "dependencies": { - "@wry/equality": { - "version": "0.1.11", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@wry/equality/-/equality-0.1.11.tgz", - "integrity": "sha1-NcsVbkqWaVqoGp7MTQN4e8F/F5A=", - "dev": true, - "requires": { - "tslib": "^1.9.3" - } - }, - "ts-invariant": { - "version": "0.4.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ts-invariant/-/ts-invariant-0.4.4.tgz", - "integrity": "sha1-l6UjUYaI+TqvrQGw6A64A+sqvYY=", - "dev": true, - "requires": { - "tslib": "^1.9.3" - } - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha1-zy04vcNKE0vK8QkcQfZhni9nLQA=", - "dev": true - } - } - }, - "append-transform": { - "version": "1.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/append-transform/-/append-transform-1.0.0.tgz", - "integrity": "sha1-BGpSrlgqIovXL1is++KWfGeHWas=", - "dev": true, - "requires": { - "default-require-extensions": "^2.0.0" - } - }, - "archy": { - "version": "1.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", - "dev": true - }, - "array.prototype.reduce": { - "version": "1.0.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/array.prototype.reduce/-/array.prototype.reduce-1.0.4.tgz", - "integrity": "sha1-gWfoAIn3i/9wqZ4gvUIB1GY7Cm8=", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.2", - "es-array-method-boxes-properly": "^1.0.0", - "is-string": "^1.0.7" - } - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha1-bIw/uCfdQ+45GPJ7gngqt2WKb9k=", - "dev": true - }, - "async-retry": { - "version": "1.3.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/async-retry/-/async-retry-1.3.3.tgz", - "integrity": "sha1-Dn82wE2EeOeli9vtgM7fl3eF8oA=", - "dev": true, - "requires": { - "retry": "0.13.1" - } - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha1-kvlWFlAQadB9EO2y/DfT4cZRI7c=", - "dev": true - }, - "backo2": { - "version": "1.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", - "dev": true - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha1-6D46fj8wCzTLnYf2FfoMvzV2kO4=", - "dev": true - }, - "body-parser": { - "version": "1.20.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/body-parser/-/body-parser-1.20.0.tgz", - "integrity": "sha1-Peab2JARwRVz17/uamTxG2vSfMU=", - "dev": true, - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.10.3", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "depd": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/depd/-/depd-2.0.0.tgz", - "integrity": "sha1-tpYWPMdXVg0JzyLMj60Vcbeedt8=", - "dev": true - }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha1-t3dKFIbvc892Z6ya4IWMASxXudM=", - "dev": true, - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha1-VcsADM8dSHKL0jxoWgY5mM8aG2M=", - "dev": true - } - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "busboy": { - "version": "0.3.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/busboy/-/busboy-0.3.1.tgz", - "integrity": "sha1-FwiZJ0xb84quJ9XGK3EmjNWF/Rs=", - "dev": true, - "requires": { - "dicer": "0.3.0" - } - }, - "bytes": { - "version": "3.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha1-iwvuuYYFrfGxKPpDhkA8AJ4CIaU=", - "dev": true - }, - "cacache": { - "version": "15.3.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/cacache/-/cacache-15.3.0.tgz", - "integrity": "sha1-3IU4D7L1Vv492kxxm/oOyHWn8es=", - "dev": true, - "requires": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - } - } - }, - "caching-transform": { - "version": "3.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/caching-transform/-/caching-transform-3.0.2.tgz", - "integrity": "sha1-YB1GuR7Kh2h6KB5xzvmXkbDvynA=", - "dev": true, - "requires": { - "hasha": "^3.0.0", - "make-dir": "^2.0.0", - "package-hash": "^3.0.0", - "write-file-atomic": "^2.4.2" - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha1-sdTonmiBGcPJqQOtMKuy9qkZvjw=", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha1-s2MKvYlDQy9Us/BRkjjjPNffL3M=", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA=", - "dev": true - }, - "casual": { - "version": "1.6.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/casual/-/casual-1.6.2.tgz", - "integrity": "sha1-9WuHETrpmmu6ReBL36BoykQ/noU=", - "dev": true, - "requires": { - "mersenne-twister": "^1.0.1", - "moment": "^2.15.2" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha1-kAlISfCTfy7twkJdDSip5fDLrZ4=", - "dev": true - }, - "chownr": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha1-Fb++U9LqtM9w8YqM1o6+Wzyx3s4=", - "dev": true - }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha1-7oRy27Ep5yezHooQpCfe6d/kAIs=", - "dev": true - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha1-JkMFp65JDR0Dvwybp8kl0XU68wc=", - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "cli-width": { - "version": "3.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha1-ovSEN6LKqaIkNueUvwceyeYc7fY=", - "dev": true - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha1-3u/P2y6AB4SqNPRvoI4GhRx7u8U=", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha1-kzoEBShgyF6DwSJHnEdIqOTHIVY=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha1-InZ74htirxCBV0MG9prFG2IgOWE=", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - } - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha1-w9RaizT9cwYxoRCoolIGgrMdWn8=", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "2.20.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/commander/-/commander-2.20.3.tgz", - "integrity": "sha1-/UhehMA+tIgcIHIrpIA16FMa6zM=", - "dev": true - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha1-i4K076yCUSoCuwsdzsnSxejrW/4=", - "dev": true, - "requires": { - "safe-buffer": "5.2.1" - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=", - "dev": true - }, - "convert-source-map": { - "version": "1.8.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha1-8zc8MtIbTXgN2ABFFGhPt5HKQ2k=", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=", - "dev": true - } - } - }, - "cookie": { - "version": "0.5.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha1-0fXXGt7GVYxY84mYfDZqpH6ZT4s=", - "dev": true - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", - "dev": true - }, - "core-js-pure": { - "version": "3.24.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/core-js-pure/-/core-js-pure-3.24.1.tgz", - "integrity": "sha1-iDnd5dpUVSG/KC/rfcbQtCXzn9M=" - }, - "cors": { - "version": "2.8.5", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/cors/-/cors-2.8.5.tgz", - "integrity": "sha1-6sEdpRWS3Ya58G9uesKTs9+HXSk=", - "dev": true, - "requires": { - "object-assign": "^4", - "vary": "^1" - } - }, - "cp-file": { - "version": "6.2.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/cp-file/-/cp-file-6.2.0.tgz", - "integrity": "sha1-QNXqSh3vKprN0HulwLAkbvc9wQ0=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "make-dir": "^2.0.0", - "nested-error-stacks": "^2.0.0", - "pify": "^4.0.1", - "safe-buffer": "^5.0.1" - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha1-Sl7Hxk364iw6FBJNus3uhG2Ay8Q=", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/semver/-/semver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", - "dev": true - } - } - }, - "cssfilter": { - "version": "0.0.10", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/cssfilter/-/cssfilter-0.0.10.tgz", - "integrity": "sha1-xtJnJjKi5cg+AT5oZKQs6N79IK4=", - "dev": true - }, - "debug": { - "version": "4.3.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/debug/-/debug-4.3.4.tgz", - "integrity": "sha1-Exn2V5NX8jONMzfSzdSRS7XcyGU=", - "requires": { - "ms": "2.1.2" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "deep-equal": { - "version": "2.0.5", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/deep-equal/-/deep-equal-2.0.5.tgz", - "integrity": "sha1-Vc0v4ybYP5y/cmHvDgYLP3JMXLk=", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "es-get-iterator": "^1.1.1", - "get-intrinsic": "^1.0.1", - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.2", - "is-regex": "^1.1.1", - "isarray": "^2.0.5", - "object-is": "^1.1.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.3.0", - "side-channel": "^1.0.3", - "which-boxed-primitive": "^1.0.1", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.2" - } - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha1-pvLc5hL63S7x9Rm3NVHxfoUZmDE=", - "dev": true - }, - "default-require-extensions": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/default-require-extensions/-/default-require-extensions-2.0.0.tgz", - "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", - "dev": true, - "requires": { - "strip-bom": "^3.0.0" - } - }, - "define-properties": { - "version": "1.1.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha1-CxTXvX++svNXLDp+2oDqXVf7BbE=", - "dev": true, - "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - }, - "defined": { - "version": "1.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/defined/-/defined-1.0.0.tgz", - "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", - "dev": true - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "depd": { - "version": "1.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true - }, - "deprecated-decorator": { - "version": "0.1.6", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/deprecated-decorator/-/deprecated-decorator-0.1.6.tgz", - "integrity": "sha1-AJZjF7ehL+kvPMgx91g68ym4bDc=", - "dev": true - }, - "destroy": { - "version": "1.2.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha1-SANzVQmti+VSk0xn32FPlOZvoBU=", - "dev": true - }, - "dicer": { - "version": "0.3.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/dicer/-/dicer-0.3.0.tgz", - "integrity": "sha1-6s2Ys7+/kuirXC/bcaqsRLsGuHI=", - "dev": true, - "requires": { - "streamsearch": "0.1.2" - } - }, - "diff": { - "version": "5.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/diff/-/diff-5.1.0.tgz", - "integrity": "sha1-vFLSmMXqjfkZSAAiREXtQ//IfkA=", - "dev": true - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha1-rd6+rXKmV023g2OdyHoSF3OXOWE=", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dotignore": { - "version": "0.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/dotignore/-/dotignore-0.1.2.tgz", - "integrity": "sha1-+ULyIA0ow6dvvdbw7p8yV8ii6QU=", - "dev": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc=", - "dev": true - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "dev": true - }, - "encoding": { - "version": "0.1.13", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha1-VldK/deR9UqOmyeFwFgqLSYhD6k=", - "dev": true, - "optional": true, - "requires": { - "iconv-lite": "^0.6.2" - } - }, - "err-code": { - "version": "2.0.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha1-I8Lzt1b/38YI0w4nyalBAkgH5/k=", - "dev": true - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha1-tKxAZIEH/c3PriQvQovqihTU8b8=", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.20.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/es-abstract/-/es-abstract-1.20.1.tgz", - "integrity": "sha1-AnKSzW70S9ErGRO4KBFvVHh9GBQ=", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.4.3", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" - } - }, - "es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha1-hz8+hEGN5O4Zxb51KZCy5EcY0J4=", - "dev": true - }, - "es-get-iterator": { - "version": "1.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/es-get-iterator/-/es-get-iterator-1.1.2.tgz", - "integrity": "sha1-kjTFSrpxNIbX694CIIZK9eKyg/c=", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.0", - "has-symbols": "^1.0.1", - "is-arguments": "^1.1.0", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.5", - "isarray": "^2.0.5" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha1-5VzUyc3BiLzvsDs2bHNjI/xciYo=", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es6-error": { - "version": "4.1.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha1-njr0B0Wd7tR+mpH5uIWoTrBcVh0=", - "dev": true - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "eslint": { - "version": "6.8.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/eslint/-/eslint-6.8.0.tgz", - "integrity": "sha1-YiYtZylzn5J1cjgkMC+yJ8jJP/s=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.10.0", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^1.4.3", - "eslint-visitor-keys": "^1.1.0", - "espree": "^6.1.2", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^7.0.0", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.14", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.3", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^6.1.2", - "strip-ansi": "^5.2.0", - "strip-json-comments": "^3.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg=", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "mkdirp": { - "version": "0.5.6", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha1-fe8D0kMtyuS6HWEURcSDlgYiVfY=", - "dev": true, - "requires": { - "minimist": "^1.2.6" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/semver/-/semver-6.3.0.tgz", - "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha1-54blmmbLkrP2wfsNUIqrF0hI9Iw=", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "1.4.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha1-dP7HxU0Hdrb2fgJRBAtYBlZOmB8=", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha1-MOvR73wv3/AcOk8VEESvJfqwUj4=", - "dev": true - }, - "espree": { - "version": "6.2.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/espree/-/espree-6.2.1.tgz", - "integrity": "sha1-d/xy4f10SiBSwg84pbV1gy6Cc0o=", - "dev": true, - "requires": { - "acorn": "^7.1.1", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.1.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha1-E7BM2z5sXRnfkatph6hpVhmwqnE=", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha1-IUj/w4uC6McFff7UhCWz5h8PJKU=", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha1-LupSkHAvJquP5TcDcP+GyWXSESM=", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha1-eteWTWeauyi+5yzsY3WLHF0smSE=", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha1-LupSkHAvJquP5TcDcP+GyWXSESM=", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha1-OYrT88WiSUi+dyXoPRGn3ijNvR0=", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha1-dNLrTeC42hKTcRkQ1Qd1ubcQ72Q=", - "dev": true - }, - "etag": { - "version": "1.8.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "dev": true - }, - "eventemitter3": { - "version": "3.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/eventemitter3/-/eventemitter3-3.1.2.tgz", - "integrity": "sha1-LT1I+cNGaY/Og6hdfWZOmFNd9uc=", - "dev": true - }, - "express": { - "version": "4.18.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/express/-/express-4.18.1.tgz", - "integrity": "sha1-d5fei5xyyFe5zQ4Upe6oBmYmfK8=", - "dev": true, - "requires": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.0", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.10.3", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "depd": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/depd/-/depd-2.0.0.tgz", - "integrity": "sha1-tpYWPMdXVg0JzyLMj60Vcbeedt8=", - "dev": true - }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha1-t3dKFIbvc892Z6ya4IWMASxXudM=", - "dev": true, - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha1-VcsADM8dSHKL0jxoWgY5mM8aG2M=", - "dev": true - } - } - }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha1-ywP3QL764D6k0oPK7SdBqD8zVJU=", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "dependencies": { - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - } - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha1-h0v2nG9ATCtdmcSBNBOZ/VWJJjM=", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "figures": { - "version": "3.2.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/figures/-/figures-3.2.0.tgz", - "integrity": "sha1-YlwYvSk8YE3EqN2y/r8MiDQXRq8=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha1-yg9u+m3T1WEzP7FFFQZcL6/fQ5w=", - "dev": true, - "requires": { - "flat-cache": "^2.0.1" - } - }, - "finalhandler": { - "version": "1.2.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha1-fSP+VzGyB7RkDk/NAK7B+SB6ezI=", - "dev": true, - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha1-VcsADM8dSHKL0jxoWgY5mM8aG2M=", - "dev": true - } - } - }, - "find-cache-dir": { - "version": "2.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha1-jQ+UzRP+Q8bHwmGg2GEVypGMBfc=", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha1-SRafHXmTQwZG2mHsxa41XCHJe3M=", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "flat-cache": { - "version": "2.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha1-XSltbwS9pEpGMKMBQTvbwuwIXsA=", - "dev": true, - "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - }, - "dependencies": { - "rimraf": { - "version": "2.6.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha1-stEE/g2Psnz54KHNqCYt04M8bKs=", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "flatted": { - "version": "2.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha1-RXWyHivO50NKqb5mL0t7X5wrUTg=", - "dev": true - }, - "for-each": { - "version": "0.3.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha1-abRH6IoKXTLD5whPPxcQA0shN24=", - "dev": true, - "requires": { - "is-callable": "^1.1.3" - } - }, - "foreground-child": { - "version": "1.5.6", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/foreground-child/-/foreground-child-1.5.6.tgz", - "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", - "dev": true, - "requires": { - "cross-spawn": "^4", - "signal-exit": "^3.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "4.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/cross-spawn/-/cross-spawn-4.0.2.tgz", - "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" - } - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha1-i75Q6oW+1ZvJ4z3KuCNe6bz0Q80=", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - } - } - }, - "form-data": { - "version": "3.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha1-69U3kbeDVqma+aMA1CgsTV65dV8=", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha1-ImmTZCiq1MFcfr6XeahL8LKoGBE=", - "dev": true - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true - }, - "fs-capacitor": { - "version": "2.0.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/fs-capacitor/-/fs-capacitor-2.0.4.tgz", - "integrity": "sha1-WiLnLUCuUHi0/mT+TQjA0/yIrTw=", - "dev": true - }, - "fs-minipass": { - "version": "2.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha1-f1A2/b8SxjwWkZDL5BmchSJx+fs=", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", - "dev": true - }, - "function.prototype.name": { - "version": "1.1.5", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha1-zOBQX+H/uAUD5vnkbMZORqEqliE=", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - } - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "functions-have-names": { - "version": "1.2.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha1-BAT+TuK6L2B/Dg7DyAuumUEzuDQ=", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha1-T5RBKoLbMvNuOwuXQfipf+sDH34=", - "dev": true - }, - "get-intrinsic": { - "version": "1.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/get-intrinsic/-/get-intrinsic-1.1.2.tgz", - "integrity": "sha1-M2l1Ej4FrQt7pB8VLuSq2+ps9Zg=", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - } - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha1-f9uByQAQH71WTdXxowr1qtweWNY=", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "glob": { - "version": "7.2.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/glob/-/glob-7.2.3.tgz", - "integrity": "sha1-uN8PuAK7+o6JvR2Ti04WV47UTys=", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha1-hpgyxYA0/mikCTwX3BXoNA2EAcQ=", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "globals": { - "version": "12.4.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/globals/-/globals-12.4.0.tgz", - "integrity": "sha1-oYgTV2pBsAokqX5/gVkYwuGZJfg=", - "dev": true, - "requires": { - "type-fest": "^0.8.1" - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha1-FH06AG2kyjzhRyjHrvwofDZ9emw=", - "dev": true - }, - "graphql": { - "version": "15.8.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/graphql/-/graphql-15.8.0.tgz", - "integrity": "sha1-M0EOlrAS+jvbEJHMmalHadshKzg=", - "dev": true - }, - "graphql-extensions": { - "version": "0.15.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/graphql-extensions/-/graphql-extensions-0.15.0.tgz", - "integrity": "sha1-PykfknSHawwon6QGGQmhJni9mBc=", - "dev": true, - "requires": { - "@apollographql/apollo-tools": "^0.5.0", - "apollo-server-env": "^3.1.0", - "apollo-server-types": "^0.9.0" - }, - "dependencies": { - "@apollo/protobufjs": { - "version": "1.2.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/@apollo/protobufjs/-/protobufjs-1.2.2.tgz", - "integrity": "sha1-S9ks13Acyu9tUXzbda8nVfBJ+Hw=", - "dev": true, - "requires": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.0", - "@types/node": "^10.1.0", - "long": "^4.0.0" - } - }, - "apollo-reporting-protobuf": { - "version": "0.8.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-reporting-protobuf/-/apollo-reporting-protobuf-0.8.0.tgz", - "integrity": "sha1-rp2WeTTT2O2Bb8haDYBo70XDcbk=", - "dev": true, - "requires": { - "@apollo/protobufjs": "1.2.2" - } - }, - "apollo-server-env": { - "version": "3.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-server-env/-/apollo-server-env-3.1.0.tgz", - "integrity": "sha1-BzPC71CupZbMkM9ApT9uoq1ALNA=", - "dev": true, - "requires": { - "node-fetch": "^2.6.1", - "util.promisify": "^1.0.0" - } - }, - "apollo-server-types": { - "version": "0.9.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/apollo-server-types/-/apollo-server-types-0.9.0.tgz", - "integrity": "sha1-zPVQszsHxIxy8QT74odiMrQEhIs=", - "dev": true, - "requires": { - "apollo-reporting-protobuf": "^0.8.0", - "apollo-server-caching": "^0.7.0", - "apollo-server-env": "^3.1.0" - } - } - } - }, - "graphql-subscriptions": { - "version": "1.2.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/graphql-subscriptions/-/graphql-subscriptions-1.2.1.tgz", - "integrity": "sha1-IUKy1ylmHd+We3OI988d1M8uBh0=", - "dev": true, - "requires": { - "iterall": "^1.3.0" - } - }, - "graphql-tag": { - "version": "2.12.6", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/graphql-tag/-/graphql-tag-2.12.6.tgz", - "integrity": "sha1-1EGlacHSU37xDKPRYztIclMptfE=", - "requires": { - "tslib": "^2.1.0" - } - }, - "graphql-tools": { - "version": "8.3.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/graphql-tools/-/graphql-tools-8.3.1.tgz", - "integrity": "sha1-ubTOhm5XR7LbSCjt697k/vEdKEc=", - "requires": { - "@apollo/client": "~3.2.5 || ~3.3.0 || ~3.4.0 || ~3.5.0 || ~3.6.0", - "@graphql-tools/schema": "8.5.1", - "tslib": "^2.4.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/has/-/has-1.0.3.tgz", - "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha1-CHG9Pj1RYm9soJZmaLo11WAtbqo=", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=", - "dev": true - }, - "has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha1-YQcIYAYG02lh7QTBlhk7amB/qGE=", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.1" - } - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha1-u3ssQ0klHc6HsSX3vfh0qnyLOfg=", - "dev": true - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha1-fhM4GKfTlHNPlB5zw9P5KR5liyU=", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "hasha": { - "version": "3.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/hasha/-/hasha-3.0.0.tgz", - "integrity": "sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk=", - "dev": true, - "requires": { - "is-stream": "^1.0.1" - } - }, - "hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha1-7OCsr3HWLClpwuxZ/v9CpLGoW0U=", - "optional": true, - "requires": { - "react-is": "^16.7.0" - } - }, - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha1-3/wL+aIcAiCQkPKqaUKeFBTa8/k=", - "dev": true - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha1-39YAJ9o2o238viNiYsAKWCJoFFM=", - "dev": true - }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha1-SekcXL82yblLz81xwj1SSex045A=", - "dev": true - }, - "http-errors": { - "version": "1.8.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha1-fD8oV3y8iiBziEVdvWIpXtB71ow=", - "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.1" - } - }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha1-ioyO9/WTLM+VPClsqCkblap0qjo=", - "dev": true, - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha1-xZ7yJKBP6LdU89sAY6Jeow0ABdY=", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "humanize-ms": { - "version": "1.2.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", - "dev": true, - "requires": { - "ms": "^2.0.0" - } - }, - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha1-pS+AvzjaGVLrXGgXkHGYcaGnJQE=", - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha1-dQ49tYYgh7RzfrrIIH/9HvJ7Jfw=", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha1-NxYsJfy566oublPVtNiM4X2eDCs=", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha1-Yk+PRJfWGbLZdoUx1Y9BIoVNclE=", - "dev": true - }, - "infer-owner": { - "version": "1.0.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha1-xM78qo5RBRwqQLos6KPScpWvlGc=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w=" - }, - "inquirer": { - "version": "7.3.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/inquirer/-/inquirer-7.3.3.tgz", - "integrity": "sha1-BNF2sq8Er8FXqD/XwQDpjuCq0AM=", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.19", - "mute-stream": "0.0.8", - "run-async": "^2.4.0", - "rxjs": "^6.6.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - }, - "dependencies": { - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha1-nibGPTD1NEPpSJSVshBdN7Z6hdk=", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - } - } - }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha1-c0fjB97uovqsKsYgXUvH00ln9Zw=", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "ip": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ip/-/ip-2.0.0.tgz", - "integrity": "sha1-TPSrGC/uIxTHXt4SdvjIC0eZNto=", - "dev": true - }, - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha1-v/OFQ+64mEglB5/zoqjmy9RngbM=", - "dev": true - }, - "is-arguments": { - "version": "1.1.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha1-FbP4j9oB8ql/7ITKdhpWDxI++ps=", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha1-CBR6GHW8KzIAXUHM2Ckd/8ZpHfM=", - "dev": true, - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha1-XG3CACRt2TIa5LiFoRS7H3X2Nxk=", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha1-RzAdWN0CWUB4ZVR4U99tYf5HGUU=", - "dev": true - }, - "is-core-module": { - "version": "2.9.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-core-module/-/is-core-module-2.9.0.tgz", - "integrity": "sha1-4cNEKc1Rxt2eCeB5njluJ7GanGk=", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha1-CEHVU25yTCVZe/bqYuG9OCmN8x8=", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0=", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha1-ZPYeQsu7LuwgcanawLKLoeZdUIQ=", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-lambda": { - "version": "1.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU=", - "dev": true - }, - "is-map": { - "version": "2.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha1-AJItuMm/c+gbejNYJ7wqQ/K5ESc=", - "dev": true - }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha1-e/bwOigAO4s5Zd46wm9mTXZfMVA=", - "dev": true - }, - "is-number-object": { - "version": "1.0.7", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha1-WdUK2kxFJReE6ZBPUkbHQvB6Qvw=", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha1-7vVmPNWfpMCuM5UFMj32hUuxWVg=", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-set": { - "version": "2.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha1-kHVfpMJWLcHF1AJHYNYRm5TKGOw=", - "dev": true - }, - "is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha1-jyWcVztgtqMtQFihoHQwwKc0THk=", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha1-DdEr8gBvJVu1j2lREO/3SR7rwP0=", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha1-ptrJO2NbBjymhyI23oiRClevE5w=", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typed-array": { - "version": "1.1.9", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-typed-array/-/is-typed-array-1.1.9.tgz", - "integrity": "sha1-JG130ocefZ9a6x1UufUscTKezmc=", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.20.0", - "for-each": "^0.3.3", - "has-tostringtag": "^1.0.0" - } - }, - "is-weakmap": { - "version": "2.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha1-UAi1m9xDtpggHRj2KzeyyiQ+jPI=", - "dev": true - }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha1-lSnzg6kzggXol2XgOS78LxAPBvI=", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-weakset": { - "version": "2.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha1-RWnWenR6HOWplN/U723Op258Ch0=", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "isarray": { - "version": "2.0.5", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha1-ivHkwSISRMxiRZ+vOJQNTmRKVyM=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha1-Z18KtpUD+tSx2En3NrqsqAM0T0k=", - "dev": true - }, - "istanbul-lib-hook": { - "version": "2.0.7", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz", - "integrity": "sha1-yVaV84PU+PYN8fBCUqlVDhW1sTM=", - "dev": true, - "requires": { - "append-transform": "^1.0.0" - } - }, - "istanbul-lib-instrument": { - "version": "3.3.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", - "integrity": "sha1-pfY9kfC7wMPkee9MXeAnM17G1jA=", - "dev": true, - "requires": { - "@babel/generator": "^7.4.0", - "@babel/parser": "^7.4.3", - "@babel/template": "^7.4.0", - "@babel/traverse": "^7.4.3", - "@babel/types": "^7.4.0", - "istanbul-lib-coverage": "^2.0.5", - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/semver/-/semver-6.3.0.tgz", - "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", - "dev": true - } - } - }, - "istanbul-lib-report": { - "version": "2.0.8", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", - "integrity": "sha1-WoETzXRtQ8SInro2qxDn1QybTzM=", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "supports-color": "^6.1.0" - }, - "dependencies": { - "has-flag": { - "version": "3.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha1-B2Srxpxj1ayELdSGfo0CXogN+PM=", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "3.0.6", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha1-KEmXxIIRdS7EhiU9qX44ed77qMg=", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "rimraf": "^2.6.3", - "source-map": "^0.6.1" - }, - "dependencies": { - "rimraf": { - "version": "2.7.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha1-NXl/E6f9rcVmFCwp1PB8ytSD4+w=", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "istanbul-reports": { - "version": "2.2.7", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/istanbul-reports/-/istanbul-reports-2.2.7.tgz", - "integrity": "sha1-XZOfYjfXtIOTzAlZ6rQM1P0FaTE=", - "dev": true, - "requires": { - "html-escaper": "^2.0.0" - } - }, - "iterall": { - "version": "1.3.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/iterall/-/iterall-1.3.0.tgz", - "integrity": "sha1-r8sISS4pFcvYoIhOuTqMlNDXL+o=", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha1-GSA/tZmR35jjoocFDUZHzerzJJk=" - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha1-2ugS/bOCX6MGYJqHFzg8UMNqBTc=", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha1-gFZNLkg9rPbo7yCWUKZ98/DCg6Q=", - "dev": true - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha1-u4Z8+zRQ5pEHwTHRxRS6s9yLyqk=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "just-extend": { - "version": "4.2.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/just-extend/-/just-extend-4.2.1.tgz", - "integrity": "sha1-715Ymvth5dZrJOynSUCaiTmox0Q=", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha1-2+w7OrdZdYBxtY/ln8QYca8hQA4=", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw=", - "dev": true - }, - "lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", - "dev": true - }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", - "dev": true - }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" - }, - "lodash.xorby": { - "version": "4.7.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/lodash.xorby/-/lodash.xorby-4.7.0.tgz", - "integrity": "sha1-nBmm+fBjputT3QPBtocXmYAUY9c=" - }, - "loglevel": { - "version": "1.8.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/loglevel/-/loglevel-1.8.0.tgz", - "integrity": "sha1-5+xzpX4ee0GctsasBr8FC2c1YRQ=", - "dev": true - }, - "long": { - "version": "4.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/long/-/long-4.0.0.tgz", - "integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=" - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha1-ce5R+nvkyuwaY4OffmgtgTLTDK8=", - "optional": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lru-cache": { - "version": "7.13.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/lru-cache/-/lru-cache-7.13.1.tgz", - "integrity": "sha1-JnqB+9CIEyfEaoHFkiYGos/jNsQ=" - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha1-XwMQ4YuL6JjMBwCSlaMK5B6R5vU=", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/semver/-/semver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", - "dev": true - } - } - }, - "make-fetch-happen": { - "version": "8.0.14", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/make-fetch-happen/-/make-fetch-happen-8.0.14.tgz", - "integrity": "sha1-qrpzrgq1WGrY6qaL2DMyZpOT4iI=", - "dev": true, - "requires": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.0.5", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^5.0.0", - "ssri": "^8.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - } - } - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "dev": true - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true - }, - "merge-source-map": { - "version": "1.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/merge-source-map/-/merge-source-map-1.1.0.tgz", - "integrity": "sha1-L93n5gIJOfcJBqaPLXrmheTIxkY=", - "dev": true, - "requires": { - "source-map": "^0.6.1" - } - }, - "mersenne-twister": { - "version": "1.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/mersenne-twister/-/mersenne-twister-1.1.0.tgz", - "integrity": "sha1-+RZhjuQ9cXnvz2Qb7EUx65Zwl4o=", - "dev": true - }, - "methods": { - "version": "1.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "dev": true - }, - "mime": { - "version": "1.6.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/mime/-/mime-1.6.0.tgz", - "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=", - "dev": true - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha1-u6vNwChZ9JhzAchW4zh85exDv3A=", - "dev": true - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha1-OBqHG2KnNEUGYK497uRIE/cNlZo=", - "dev": true, - "requires": { - "mime-db": "1.52.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha1-ftLCzMyvhNP/y3pptXcR/CCDQBs=", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha1-Gc0ZS/0+Qo8EmnCBfAONiatL41s=", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha1-hjelt1nqDW6YcCz7OpKDMjyTr0Q=", - "dev": true - }, - "minipass": { - "version": "3.3.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/minipass/-/minipass-3.3.4.tgz", - "integrity": "sha1-ypn5Xdd8Q8ena/UebSAAJe7g/64=", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "minipass-collect": { - "version": "1.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha1-IrgTv3Rdxu26JXa5QAIq1u3Ixhc=", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minipass-fetch": { - "version": "1.4.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/minipass-fetch/-/minipass-fetch-1.4.1.tgz", - "integrity": "sha1-114AkdqsGw/9fp1BYp+v99DB8bY=", - "dev": true, - "requires": { - "encoding": "^0.1.12", - "minipass": "^3.1.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.0.0" - } - }, - "minipass-flush": { - "version": "1.0.5", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha1-gucTXX6JpQ/+ZGEKeHlTxMTLs3M=", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha1-aEcveXEcCEZXwGfFxq2Tzd6oIUw=", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minipass-sized": { - "version": "1.0.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha1-cO5afFBSBwr6z7wil36nne81O3A=", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minizlib": { - "version": "2.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha1-6Q00Zrogm5MkUVCKEc49NjIUWTE=", - "dev": true, - "requires": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - } - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha1-PrXtYmInVteaXw4qIh3+utdcL34=", - "dev": true - }, - "moment": { - "version": "2.29.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/moment/-/moment-2.29.4.tgz", - "integrity": "sha1-Pb4FKIn+fBsu2Wb8s6dzKJZO8Qg=", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ms/-/ms-2.1.2.tgz", - "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=" - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha1-FjDEKyJR/4HiooPelqVJfqkuXg0=", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "negotiator": { - "version": "0.6.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha1-WOMjpy/twNb5zU0x/kn1FHlZDM0=", - "dev": true - }, - "nested-error-stacks": { - "version": "2.1.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz", - "integrity": "sha1-JsijzubMBfvPHjM80vw+ADMmwLU=", - "dev": true - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha1-ozeKdpbOfSI+iPybdkvX7xCJ42Y=", - "dev": true - }, - "nise": { - "version": "5.1.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/nise/-/nise-5.1.1.tgz", - "integrity": "sha1-rEI34NeF7Py4PiDziRhZddpcMfM=", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.8.3", - "@sinonjs/fake-timers": ">=5", - "@sinonjs/text-encoding": "^0.7.1", - "just-extend": "^4.0.2", - "path-to-regexp": "^1.7.0" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "path-to-regexp": { - "version": "1.8.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha1-iHs7qdhDk+h6CgufTLdWGYtTVIo=", - "dev": true, - "requires": { - "isarray": "0.0.1" - } - } - } - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha1-JN6fuoJ+O0rkTciyAlajeRYAUq0=", - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha1-5m2xg4sgDB38IzIl0SyzZSDiNKg=", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/semver/-/semver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", - "dev": true - } - } - }, - "nyc": { - "version": "14.1.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/nyc/-/nyc-14.1.1.tgz", - "integrity": "sha1-FR1kpqn59ZCKG3MjOTHkoKMHXus=", - "dev": true, - "requires": { - "archy": "^1.0.0", - "caching-transform": "^3.0.2", - "convert-source-map": "^1.6.0", - "cp-file": "^6.2.0", - "find-cache-dir": "^2.1.0", - "find-up": "^3.0.0", - "foreground-child": "^1.5.6", - "glob": "^7.1.3", - "istanbul-lib-coverage": "^2.0.5", - "istanbul-lib-hook": "^2.0.7", - "istanbul-lib-instrument": "^3.3.0", - "istanbul-lib-report": "^2.0.8", - "istanbul-lib-source-maps": "^3.0.6", - "istanbul-reports": "^2.2.4", - "js-yaml": "^3.13.1", - "make-dir": "^2.1.0", - "merge-source-map": "^1.1.0", - "resolve-from": "^4.0.0", - "rimraf": "^2.6.3", - "signal-exit": "^3.0.2", - "spawn-wrap": "^1.4.2", - "test-exclude": "^5.2.3", - "uuid": "^3.3.2", - "yargs": "^13.2.2", - "yargs-parser": "^13.0.0" - }, - "dependencies": { - "rimraf": { - "version": "2.7.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha1-NXl/E6f9rcVmFCwp1PB8ytSD4+w=", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha1-sj5DWK+oogL+ehAK8fX4g/AgB+4=", - "dev": true - } - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "object-inspect": { - "version": "1.12.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha1-wGQfJjlFMvKKuNeWq5VOQ8AJqOo=", - "dev": true - }, - "object-is": { - "version": "1.1.5", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha1-ud7qpfx/GEag+uzc7sE45XePU6w=", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha1-HEfyct8nfzsdrwYWd9nILiMixg4=", - "dev": true - }, - "object-path": { - "version": "0.11.8", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/object-path/-/object-path-0.11.8.tgz", - "integrity": "sha1-7QAsArvdAHC3iidFXorgH8FNR0I=", - "dev": true - }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha1-DtVKNC7Os3s4/3brgxoOeIy2OUA=", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } - }, - "object.getownpropertydescriptors": { - "version": "2.1.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.4.tgz", - "integrity": "sha1-eWXmQ3pXJ4tYc4ODGpuClFWkvDc=", - "dev": true, - "requires": { - "array.prototype.reduce": "^1.0.4", - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.1" - } - }, - "on-finished": { - "version": "2.4.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha1-WMjEQRblSEWtV/FKsQsDUzGErD8=", - "dev": true, - "requires": { - "ee-first": "1.1.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha1-0Oluu1awdHbfHdnEgG5SN5hcpF4=", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "optimism": { - "version": "0.16.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/optimism/-/optimism-0.16.1.tgz", - "integrity": "sha1-fI78HzF58YMHuIfhjBXFtxM/bn0=", - "optional": true, - "requires": { - "@wry/context": "^0.6.0", - "@wry/trie": "^0.3.0" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha1-hPodA2/p08fiHZmIS2ARZ+yPtJU=", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha1-PdM8ZHohT9//2DWTPrCG2g3CHbE=", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha1-Mi1poFwCZLJZl9n0DNiokasAZKQ=", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-map": { - "version": "4.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha1-uy+Vpe2i7BaOySdOBqdHw+KQTSs=", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha1-yyhoVA4xPWHeWPr741zpAE1VQOY=", - "dev": true - }, - "package-hash": { - "version": "3.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/package-hash/-/package-hash-3.0.0.tgz", - "integrity": "sha1-UBg/LTbJ4+Uo6gqGBd/1fOl2+I4=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.15", - "hasha": "^3.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha1-aR0nCeeMefrjoVZiJFLQB2LKqqI=", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha1-+8EUtgykKzDZ2vWFjkvWi77bZzU=", - "dev": true - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", - "dev": true - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha1-zvMdyOCho7sNEFwM2Xzzv0f0428=", - "dev": true, - "requires": { - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } - } - }, - "pify": { - "version": "4.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/pify/-/pify-4.0.1.tgz", - "integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=", - "dev": true - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha1-J0kCDyOe2ZCIGx9xIQ1R62UjvqM=", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "pretty-format": { - "version": "26.6.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha1-41wnBfFMt/4v6U+geDRbREEg/JM=", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "dependencies": { - "react-is": { - "version": "17.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha1-5pHUqOnHiTZWVVOas3J2Kw77VPA=", - "dev": true - } - } - }, - "progress": { - "version": "2.0.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/progress/-/progress-2.0.3.tgz", - "integrity": "sha1-foz42PW48jnBvGi+tOt4Vn1XLvg=", - "dev": true - }, - "promise-inflight": { - "version": "1.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", - "dev": true - }, - "promise-retry": { - "version": "2.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha1-/3R6E2IKtXumiPX8Z4VUEMNw2iI=", - "dev": true, - "requires": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "dependencies": { - "retry": { - "version": "0.12.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", - "dev": true - } - } - }, - "prop-types": { - "version": "15.8.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha1-Z9h78aaU9IQ1zzMsJK8QIUoxQLU=", - "optional": true, - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "proxy-addr": { - "version": "2.0.7", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha1-8Z/mnOqzEe65S0LnDowgcPm6ECU=", - "dev": true, - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - } - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew=", - "dev": true - }, - "qs": { - "version": "6.10.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/qs/-/qs-6.10.3.tgz", - "integrity": "sha1-1s3hsv/Kh7WqV4iYFsX4FTXiLo4=", - "dev": true, - "requires": { - "side-channel": "^1.0.4" - } - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha1-PPNwI9GZ4cJNGlW4SADC8+ZGgDE=", - "dev": true - }, - "raw-body": { - "version": "2.5.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha1-/hsWKLGBtwAhXl/UI4n5i3E5KFc=", - "dev": true, - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "dependencies": { - "depd": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/depd/-/depd-2.0.0.tgz", - "integrity": "sha1-tpYWPMdXVg0JzyLMj60Vcbeedt8=", - "dev": true - }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha1-t3dKFIbvc892Z6ya4IWMASxXudM=", - "dev": true, - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha1-VcsADM8dSHKL0jxoWgY5mM8aG2M=", - "dev": true - } - } - }, - "react-is": { - "version": "16.13.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha1-eJcppNw23imZ3BVt1sHZwYzqVqQ=", - "optional": true - }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - }, - "read-pkg-up": { - "version": "4.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/read-pkg-up/-/read-pkg-up-4.0.0.tgz", - "integrity": "sha1-GyIcYIi6d5lgHICPkRYcZuWPiXg=", - "dev": true, - "requires": { - "find-up": "^3.0.0", - "read-pkg": "^3.0.0" - } - }, - "regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha1-h8qzD4D2ZmAYGju3v1mBqHKzZ6w=", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - } - }, - "regexpp": { - "version": "2.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha1-jRnTHPYySCtYkEn4KB+T28uk0H8=", - "dev": true - }, - "release-zalgo": { - "version": "1.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/release-zalgo/-/release-zalgo-1.0.0.tgz", - "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", - "dev": true, - "requires": { - "es6-error": "^4.0.1" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha1-0LMp7MfMD2Fkn2IhW+aa9UqomJs=", - "dev": true - }, - "resolve": { - "version": "1.22.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha1-J8suu1P5GrtJRwqSi7p1WAZqwXc=", - "dev": true, - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha1-SrzYUq0y3Xuqv+m0DgCjbbXzkuY=", - "dev": true - }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha1-OfZ8VLOnpYzqUjbZXPADQjljH34=", - "dev": true, - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - } - }, - "resumer": { - "version": "0.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/resumer/-/resumer-0.0.0.tgz", - "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=", - "dev": true, - "requires": { - "through": "~2.3.4" - } - }, - "retry": { - "version": "0.13.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/retry/-/retry-0.13.1.tgz", - "integrity": "sha1-GFsVh6z2eRnWOzVzSeA1N7JIRlg=", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha1-8aVAK6YiCtUswSgrrBrjqkn9Bho=", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-async": { - "version": "2.4.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha1-hEDsz5nqPnC9QJ1JqriOEMGJpFU=", - "dev": true - }, - "rxjs": { - "version": "6.6.7", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha1-kKwBisq/SRv2UEQjXVhjxNq4BMk=", - "dev": true, - "requires": { - "tslib": "^1.9.0" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha1-zy04vcNKE0vK8QkcQfZhni9nLQA=", - "dev": true - } - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY=" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=", - "dev": true - }, - "semver": { - "version": "7.3.7", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/semver/-/semver-7.3.7.tgz", - "integrity": "sha1-EsW2Sa/b+QSXB3luIqQCiBTOUj8=", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - } - } - }, - "send": { - "version": "0.18.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/send/-/send-0.18.0.tgz", - "integrity": "sha1-ZwFnzGVLBfWqSnZ/kRO7NxvHBr4=", - "dev": true, - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "depd": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/depd/-/depd-2.0.0.tgz", - "integrity": "sha1-tpYWPMdXVg0JzyLMj60Vcbeedt8=", - "dev": true - }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha1-t3dKFIbvc892Z6ya4IWMASxXudM=", - "dev": true, - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ms/-/ms-2.1.3.tgz", - "integrity": "sha1-V0yBOM4dK1hh8LRFedut1gxmFbI=", - "dev": true - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha1-VcsADM8dSHKL0jxoWgY5mM8aG2M=", - "dev": true - } - } - }, - "serve-static": { - "version": "1.15.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha1-+q7wjP/goaYvYMrQxOUTz/CslUA=", - "dev": true, - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha1-ZsmiSnP5/CjL5msJ/tPTPcrxtCQ=", - "dev": true - }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha1-N6XPC4HsvGlD3hCbopYNGyZYSuc=", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha1-785cj9wQTudRslxY1CkAEfpeos8=", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha1-qaF2f4r4QVURTqq9c/mSc8j1mtk=", - "dev": true - }, - "sinon": { - "version": "12.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/sinon/-/sinon-12.0.1.tgz", - "integrity": "sha1-Mx7vhymHUuG4imYraZ+Y5APIWek=", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.8.3", - "@sinonjs/fake-timers": "^8.1.0", - "@sinonjs/samsam": "^6.0.2", - "diff": "^5.0.0", - "nise": "^5.1.0", - "supports-color": "^7.2.0" - } - }, - "slice-ansi": { - "version": "2.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha1-ys12k0YaY3pXiNkqfdT7oGjoFjY=", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg=", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - } - } - }, - "smart-buffer": { - "version": "4.2.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha1-bh1x+k8YwF99D/IW3RakgdDo2a4=", - "dev": true - }, - "socks": { - "version": "2.7.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/socks/-/socks-2.7.0.tgz", - "integrity": "sha1-+SJazbhB6HTcol+HDpEwmQ85E9A=", - "dev": true, - "requires": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" - } - }, - "socks-proxy-agent": { - "version": "5.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz", - "integrity": "sha1-Ay+1gwSKKev/7C5qc/ygdh9IF34=", - "dev": true, - "requires": { - "agent-base": "^6.0.2", - "debug": "4", - "socks": "^2.3.3" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - }, - "spawn-wrap": { - "version": "1.4.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/spawn-wrap/-/spawn-wrap-1.4.3.tgz", - "integrity": "sha1-gbdnDhcMyiR9gL9frwz7cTvc+Eg=", - "dev": true, - "requires": { - "foreground-child": "^1.5.6", - "mkdirp": "^0.5.0", - "os-homedir": "^1.0.1", - "rimraf": "^2.6.2", - "signal-exit": "^3.0.2", - "which": "^1.3.0" - }, - "dependencies": { - "mkdirp": { - "version": "0.5.6", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha1-fe8D0kMtyuS6HWEURcSDlgYiVfY=", - "dev": true, - "requires": { - "minimist": "^1.2.6" - } - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha1-NXl/E6f9rcVmFCwp1PB8ytSD4+w=", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha1-3s6BrJweZxPl99G28X1Gj6U9iak=", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha1-PyjOGnegA3JoPq3kpDMYNSeiFj0=", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha1-z3D1BILu/cmOPOCmgz5KU87rpnk=", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.11", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", - "integrity": "sha1-UMDYxAoU7Bv0Sbrmmg6kaFqdn5U=", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "ssri": { - "version": "8.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ssri/-/ssri-8.0.1.tgz", - "integrity": "sha1-Y45OQ54v+9LNKJd21cpFfE9Roq8=", - "dev": true, - "requires": { - "minipass": "^3.1.1" - } - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true - }, - "stoppable": { - "version": "1.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/stoppable/-/stoppable-1.1.0.tgz", - "integrity": "sha1-MtpWjoPqSIsI5NfqLDvMnXUBXVs=", - "dev": true - }, - "streamsearch": { - "version": "0.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/streamsearch/-/streamsearch-0.1.2.tgz", - "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=", - "dev": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha1-JpxxF9J7Ba0uU2gwqOyJXvnG0BA=", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha1-nibGPTD1NEPpSJSVshBdN7Z6hdk=", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - } - } - }, - "string.prototype.trim": { - "version": "1.2.6", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/string.prototype.trim/-/string.prototype.trim-1.2.6.tgz", - "integrity": "sha1-gklgeH2zep4kcRgC7QwdHAJU+D4=", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - } - }, - "string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha1-kUpluqqyX73U7ikcp93lfoacuNA=", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - } - }, - "string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha1-VGbZO6WM+iE0g5+B1/QkN+jAH+8=", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha1-Fk2qyHqy1vbbOimHXi0XZlgtq+0=", - "dev": true - } - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha1-MfEoGzgyYwQ0gxwxDAHMzajL4AY=", - "dev": true - }, - "subscriptions-transport-ws": { - "version": "0.9.19", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.19.tgz", - "integrity": "sha1-EMoy9+KR1e6Otyi5wC5DxSYGzc8=", - "dev": true, - "requires": { - "backo2": "^1.0.2", - "eventemitter3": "^3.1.0", - "iterall": "^1.2.1", - "symbol-observable": "^1.0.4", - "ws": "^5.2.0 || ^6.0.0 || ^7.0.0" - }, - "dependencies": { - "symbol-observable": { - "version": "1.2.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha1-wiaIrtTqs83C3+rLtWFmBWCgCAQ=", - "dev": true - } - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo=", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha1-btpL00SjyUrqN21MwxvHcxEDngk=", - "dev": true - }, - "symbol-observable": { - "version": "4.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/symbol-observable/-/symbol-observable-4.0.0.tgz", - "integrity": "sha1-W0JfGSJ56H8vm5N6yFQNGYSzkgU=", - "optional": true - }, - "table": { - "version": "5.4.6", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/table/-/table-5.4.6.tgz", - "integrity": "sha1-EpLRlQDOP4YFOwXw6Ofko7shB54=", - "dev": true, - "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, - "dependencies": { - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha1-kzoEBShgyF6DwSJHnEdIqOTHIVY=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha1-InZ74htirxCBV0MG9prFG2IgOWE=", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - } - } - }, - "tape": { - "version": "4.15.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/tape/-/tape-4.15.1.tgz", - "integrity": "sha1-iPtmKWWhH5vhvdsEwRZi1+zrEp4=", - "dev": true, - "requires": { - "call-bind": "~1.0.2", - "deep-equal": "~1.1.1", - "defined": "~1.0.0", - "dotignore": "~0.1.2", - "for-each": "~0.3.3", - "glob": "~7.2.0", - "has": "~1.0.3", - "inherits": "~2.0.4", - "is-regex": "~1.1.4", - "minimist": "~1.2.6", - "object-inspect": "~1.12.0", - "resolve": "~1.22.0", - "resumer": "~0.0.0", - "string.prototype.trim": "~1.2.5", - "through": "~2.3.8" - }, - "dependencies": { - "deep-equal": { - "version": "1.1.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha1-tcmMlCzv+vfLBR4k4UNKJaLmB2o=", - "dev": true, - "requires": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" - } - } - } - }, - "tar": { - "version": "6.1.11", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/tar/-/tar-6.1.11.tgz", - "integrity": "sha1-Z2CjjwA6+hsv/Q/+npq70Oqz1iE=", - "dev": true, - "requires": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - } - }, - "test-exclude": { - "version": "5.2.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/test-exclude/-/test-exclude-5.2.3.tgz", - "integrity": "sha1-w9Ph4xHrfuQF4JLawQrv0JCR6sA=", - "dev": true, - "requires": { - "glob": "^7.1.3", - "minimatch": "^3.0.4", - "read-pkg-up": "^4.0.0", - "require-main-filename": "^2.0.0" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha1-O+NDIaiKgg7RvYDfqjPkefu43TU=", - "dev": true - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" - }, - "ts-invariant": { - "version": "0.10.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ts-invariant/-/ts-invariant-0.10.3.tgz", - "integrity": "sha1-PgSP+W6RRZ/8oBME28f2HB9kL2w=", - "optional": true, - "requires": { - "tslib": "^2.1.0" - } - }, - "tslib": { - "version": "2.4.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha1-fOyqfwc85oCgWEeqd76UEJjzbcM=" - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha1-dkb7XxiHHPu3dJ5pvTmmOI63RQw=", - "dev": true - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha1-CeJJ696FHTseSNJ8EFREZn8XuD0=", - "dev": true - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=", - "dev": true, - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "unbox-primitive": { - "version": "1.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha1-KQMgIQV9Xmzb0IxRKcIm3/jtb54=", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - } - }, - "unique-filename": { - "version": "1.1.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha1-HWl2k2mtoFgxA6HmrodoG1ZXMjA=", - "dev": true, - "requires": { - "unique-slug": "^2.0.0" - } - }, - "unique-slug": { - "version": "2.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha1-uqvOkQg/xk6UWw861hPiZPfNTmw=", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4" - } - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "dev": true - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha1-mxpSWVIlhZ5V9mnZKPiMbFfyp34=", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "util.promisify": { - "version": "1.1.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/util.promisify/-/util.promisify-1.1.1.tgz", - "integrity": "sha1-d4MvV87SyUeBdBScrpuW6ZGM1Us=", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "for-each": "^0.3.3", - "has-symbols": "^1.0.1", - "object.getownpropertydescriptors": "^2.1.1" - } - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha1-gNW1ztJxu5r2xEXyGhoExgbO++I=", - "dev": true - }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha1-LeGWGMZtwkfc+2+ZM4A12CRaLO4=", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha1-/JH2uce6FchX9MssXe/uw51PQQo=", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "value-or-promise": { - "version": "1.0.11", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/value-or-promise/-/value-or-promise-1.0.11.tgz", - "integrity": "sha1-PpApmvMd0BT+hD/jCc76fB2UsUA=" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "dev": true - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/which/-/which-1.3.1.tgz", - "integrity": "sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha1-E3V7yJsgmwSf5dhkMOIc9AqJqOY=", - "dev": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "which-collection": { - "version": "1.0.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha1-cOq3Hru9Ku+vMvkXCC/GLNy3CQY=", - "dev": true, - "requires": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "which-typed-array": { - "version": "1.1.8", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/which-typed-array/-/which-typed-array-1.1.8.tgz", - "integrity": "sha1-DP1TQBpvM02Q7REldUpC7WY+sB8=", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.20.0", - "for-each": "^0.3.3", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.9" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha1-YQY29rH3A4kb00dxzLF/uTtHB5w=", - "dev": true - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha1-H9H2cjXVttD+54EFYAG/tpTAOwk=", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg=", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha1-kzoEBShgyF6DwSJHnEdIqOTHIVY=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha1-InZ74htirxCBV0MG9prFG2IgOWE=", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "write": { - "version": "1.0.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/write/-/write-1.0.3.tgz", - "integrity": "sha1-CADhRSO5I6OH5BUSPIZWFqrg9cM=", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - }, - "dependencies": { - "mkdirp": { - "version": "0.5.6", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha1-fe8D0kMtyuS6HWEURcSDlgYiVfY=", - "dev": true, - "requires": { - "minimist": "^1.2.6" - } - } - } - }, - "write-file-atomic": { - "version": "2.4.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha1-H9Lprh3z51uNjDZ0Q8aS1MqB9IE=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "ws": { - "version": "7.5.9", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/ws/-/ws-7.5.9.tgz", - "integrity": "sha1-VPp9sp9MfOxosd3TqJ3gmZQrtZE=", - "dev": true - }, - "xss": { - "version": "1.0.13", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/xss/-/xss-1.0.13.tgz", - "integrity": "sha1-bkj2FhKLOfNm363FdBHh61s0HGw=", - "dev": true, - "requires": { - "commander": "^2.20.3", - "cssfilter": "0.0.10" - } - }, - "y18n": { - "version": "4.0.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha1-tfJZyCzW4zaSHv17/Yv1YN6e7t8=", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=", - "dev": true - }, - "yargs": { - "version": "13.3.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha1-rX/+/sGqWVZayRX4Lcyzipwxot0=", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - }, - "dependencies": { - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha1-kzoEBShgyF6DwSJHnEdIqOTHIVY=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha1-InZ74htirxCBV0MG9prFG2IgOWE=", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - } - } - }, - "yargs-parser": { - "version": "13.1.2", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha1-Ew8JcC667vJlDVTObj5XBvek+zg=", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "zen-observable": { - "version": "0.8.15", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/zen-observable/-/zen-observable-0.8.15.tgz", - "integrity": "sha1-lkFcUS2OP/2SCv04iWBOMLnqrBU=" - }, - "zen-observable-ts": { - "version": "1.2.5", - "resolved": "https://artylab.expedia.biz/api/npm/public-npm-virtual/zen-observable-ts/-/zen-observable-ts-1.2.5.tgz", - "integrity": "sha1-bG2eo9OoQoEsbpUZIJNloSK6i1g=", - "optional": true, - "requires": { - "zen-observable": "0.8.15" - } - } - } -} diff --git a/package.json b/package.json index a095316..8b9489b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "graphql-component", - "version": "5.0.1", + "version": "6.0.0", "description": "Build, customize and compose GraphQL schemas in a componentized fashion", "keywords": [ "graphql", @@ -9,40 +9,77 @@ "module", "component" ], - "main": "lib/index.js", + "main": "dist/index.js", "scripts": { - "test": "tape lib/*/**/__tests__.js lib/__tests__.js", - "start-composition": "DEBUG=graphql-component:* node examples/composition/server/index.js", - "start-federation": "DEBUG=graphql-component:* node examples/federation/run-federation-example.js", - "lint": "eslint lib", - "cover": "nyc npm test" + "build": "tsc", + "prepublish": "npm run build", + "test": "tape -r ts-node/register \"test/**/*.ts\"", + "start-composition": "DEBUG=graphql-component ts-node examples/composition/server/index.ts", + "start-federation": "DEBUG=graphql-component ts-node examples/federation/run-federation-example.ts", + "lint": "npx eslint src/index.ts", + "cover": "nyc npm test", + "update-deps": "ncu -u && npm install", + "format": "prettier --write \"src/**/*.ts\"", + "precommit": "npm run lint && npm run test", + "prepare": "husky install" }, "author": "Trevor Livingston ", "repository": "https://github.com/ExpediaGroup/graphql-component", "license": "MIT", "dependencies": { "@apollo/federation": "^0.38.1", - "@graphql-tools/delegate": "^8.8.1", - "@graphql-tools/merge": "^8.3.1", - "@graphql-tools/mock": "^8.7.1", - "@graphql-tools/schema": "^8.5.1", - "@graphql-tools/stitch": "^8.7.1", - "@graphql-tools/utils": "^8.6.10", - "@graphql-tools/wrap": "^8.5.1", - "debug": "^4.3.1" + "@graphql-tools/delegate": "^10.2.0", + "@graphql-tools/merge": "^9.0.9", + "@graphql-tools/mock": "^9.0.6", + "@graphql-tools/schema": "^10.0.8", + "@graphql-tools/stitch": "^9.4.0", + "@graphql-tools/utils": "^10.5.6", + "debug": "^4.3.7" }, "peerDependencies": { "graphql": "^16.0.0" }, "devDependencies": { - "@apollo/gateway": "^2.7.1", + "@apollo/gateway": "^2.9.3", + "@types/graphql": "^14.5.0", + "@types/node": "^22.9.1", + "@typescript-eslint/eslint-plugin": "^8.22.0", + "@typescript-eslint/parser": "^8.22.0", "apollo-server": "^3.13.0", - "casual": "^1.6.0", - "eslint": "^6.5.1", - "graphql": "^16.8.1", - "graphql-tag": "^2.12.4", - "nyc": "^14.1.1", - "sinon": "^12.0.1", - "tape": "^4.9.1" + "casual": "^1.6.2", + "eslint": "^9.19.0", + "globals": "^15.14.0", + "graphql": "^16.9.0", + "graphql-tag": "^2.12.6", + "npm-check-updates": "^17.1.11", + "nyc": "^17.1.0", + "sinon": "^19.0.2", + "tape": "^5.9.0", + "ts-node": "^10.9.2", + "typescript": "^5.6.3", + "typescript-eslint": "^8.22.0", + "husky": "^8.0.0", + "prettier": "^2.8.8" + }, + "nyc": { + "include": [ + "src/**/*.ts" + ], + "extension": [ + ".ts" + ], + "require": [ + "ts-node/register" + ], + "reporter": [ + "text-summary", + "html" + ], + "sourceMap": true, + "instrument": true, + "all": true + }, + "engines": { + "node": ">=18.0.0" } } diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..6063fb9 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,542 @@ +import debugConfig from 'debug'; +import { buildFederatedSchema } from '@apollo/federation'; +import { GraphQLResolveInfo, GraphQLScalarType, GraphQLSchema } from 'graphql'; + +import { mergeTypeDefs } from '@graphql-tools/merge'; +import { + pruneSchema, + IResolvers, + PruneSchemaOptions, + TypeSource, + mapSchema, + SchemaMapper +} from '@graphql-tools/utils'; +import { makeExecutableSchema } from '@graphql-tools/schema'; +import { stitchSchemas } from '@graphql-tools/stitch'; +import { addMocksToSchema, IMocks } from '@graphql-tools/mock'; +import { SubschemaConfig } from '@graphql-tools/delegate'; + +const debug = debugConfig('graphql-component'); + +export type ResolverFunction = (_: any, args: any, ctx: any, info: GraphQLResolveInfo) => any; + +export interface IGraphQLComponentConfigObject { + component: IGraphQLComponent; + configuration?: SubschemaConfig; +} + +export interface ComponentContext extends Record { + dataSources: DataSourceMap; +} + +export type ContextFunction = ((context: Record) => any); + +export interface IDataSource { + name: string; + [key: string | symbol]: any; +} + +/** + * Type for implementing data sources + * When defining a data source class, methods should accept context as their first parameter + * @example + * class MyDataSource { + * name = 'MyDataSource'; + * + * // Context is required as first parameter when implementing + * getData(context: ComponentContext, id: string) { + * return { id }; + * } + * } + */ +export type DataSourceDefinition = { + // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type + [P in keyof T]: T[P] extends Function ? (context: ComponentContext, ...args: any[]) => any : T[P]; +} + +/** + * Type for consuming data sources in resolvers + * When using a data source method, the context is automatically injected + * @example + * // In a resolver: + * Query: { + * getData(_, { id }, context) { + * // Context is automatically injected, so you don't pass it + * return context.dataSources.MyDataSource.getData(id); + * } + * } + */ +export type DataSource = { + [P in keyof T]: T[P] extends (context: ComponentContext, ...p: infer P) => infer R ? (...p: P) => R : T[P]; +} + +export type DataSourceMap = { [key: string]: IDataSource }; + +export type DataSourceInjectionFunction = ((context: Record) => DataSourceMap); + +export interface IContextConfig { + namespace: string; + factory: ContextFunction; +} + +export interface IContextWrapper extends ContextFunction { + use: (name: string | ContextFunction | null, fn?: ContextFunction | string) => void; +} + +export interface IGraphQLComponentOptions { + types?: TypeSource + resolvers?: IResolvers; + mocks?: boolean | IMocks; + imports?: (IGraphQLComponent | IGraphQLComponentConfigObject)[]; + context?: IContextConfig; + dataSources?: IDataSource[]; + dataSourceOverrides?: IDataSource[]; + pruneSchema?: boolean; + pruneSchemaOptions?: PruneSchemaOptions + federation?: boolean; + transforms?: SchemaMapper[] +} + +export interface IGraphQLComponent { + readonly name: string; + readonly schema: GraphQLSchema; + readonly context: IContextWrapper; + readonly types: TypeSource; + readonly resolvers: IResolvers; + readonly imports?: (IGraphQLComponent | IGraphQLComponentConfigObject)[]; + readonly dataSources?: IDataSource[]; + readonly dataSourceOverrides?: IDataSource[]; + federation?: boolean; +} + +/** + * GraphQLComponent class for building modular GraphQL schemas + * @template TContextType - The type of the context object + * @implements {IGraphQLComponent} + */ +export default class GraphQLComponent implements IGraphQLComponent { + _schema: GraphQLSchema; + _types: TypeSource; + _resolvers: IResolvers; + _mocks: boolean | IMocks; + _imports: IGraphQLComponentConfigObject[]; + _context: ContextFunction; + _dataSources: IDataSource[]; + _dataSourceOverrides: IDataSource[]; + _pruneSchema: boolean; + _pruneSchemaOptions: PruneSchemaOptions + _federation: boolean; + _dataSourceContextInject: DataSourceInjectionFunction; + _transforms: SchemaMapper[] + private _transformedSchema: GraphQLSchema; + + constructor({ + types, + resolvers, + mocks, + imports, + context, + dataSources, + dataSourceOverrides, + pruneSchema, + pruneSchemaOptions, + federation, + transforms + }: IGraphQLComponentOptions) { + + this._types = Array.isArray(types) ? types : [types]; + + this._resolvers = bindResolvers(this, resolvers); + + this._mocks = mocks; + + this._federation = federation; + + this._transforms = transforms; + + this._dataSources = dataSources || []; + + this._dataSourceOverrides = dataSourceOverrides || []; + + this._dataSourceContextInject = createDataSourceContextInjector(this._dataSources, this._dataSourceOverrides); + + this._pruneSchema = pruneSchema; + + this._pruneSchemaOptions = pruneSchemaOptions; + + this._imports = imports && imports.length > 0 ? imports.map((i: GraphQLComponent | IGraphQLComponentConfigObject) => { + if (i instanceof GraphQLComponent) { + if (this._federation === true) { + i.federation = true; + } + return { component: i }; + } + else { + const importConfiguration = i as IGraphQLComponentConfigObject; + if (this._federation === true) { + importConfiguration.component.federation = true; + } + return importConfiguration; + } + }) : []; + + + this._context = async (globalContext: Record): Promise => { + //TODO: currently the context injected into data sources won't have data sources on it + const ctx = { + dataSources: this._dataSourceContextInject(globalContext) + }; + + for (const { component } of this.imports) { + const { dataSources, ...importedContext } = await component.context(globalContext); + Object.assign(ctx.dataSources, dataSources); + Object.assign(ctx, importedContext); + } + + if (context) { + debug(`building ${context.namespace} context`); + + if (!ctx[context.namespace]) { + ctx[context.namespace] = {}; + } + + Object.assign(ctx[context.namespace], await context.factory.call(this, globalContext)); + } + + return ctx as TContextType; + }; + + this.validateConfig({ types, imports, mocks, federation }); + + } + + get context(): IContextWrapper { + + const contextFn = async (context: Record): Promise => { + debug(`building root context`); + + const middleware: MiddlewareEntry[] = (contextFn as any)._middleware || []; + + for (const { name, fn } of middleware) { + debug(`applying ${name} middleware`); + context = await fn(context); + } + + const componentContext = await this._context(context); + + const globalContext = { + ...context, + ...componentContext + }; + + return globalContext; + }; + + contextFn._middleware = []; + + contextFn.use = function (name: string, fn: ContextFunction): IContextWrapper { + if (typeof name === 'function') { + fn = name; + name = 'unknown'; + } + debug(`adding ${name} middleware`); + contextFn._middleware.push({ name, fn }); + + return contextFn; + }; + + return contextFn; + } + + get name(): string { + return this.constructor.name; + } + + get schema(): GraphQLSchema { + try { + if (this._schema) { + return this._schema; + } + + let makeSchema: (schemaConfig: any) => GraphQLSchema; + + if (this._federation) { + makeSchema = buildFederatedSchema; + } else { + makeSchema = makeExecutableSchema; + } + + if (this._imports.length > 0) { + // iterate through the imports and construct subschema configuration objects + const subschemas = this._imports.map((imp) => { + const { component, configuration = {} } = imp; + + return { + schema: component.schema, + ...configuration + }; + }); + + // construct an aggregate schema from the schemas of imported + // components and this component's types/resolvers (if present) + this._schema = stitchSchemas({ + subschemas, + typeDefs: this._types, + resolvers: this._resolvers, + mergeDirectives: true + }); + } + else { + const schemaConfig = { + typeDefs: mergeTypeDefs(this._types), + resolvers: this._resolvers + } + + this._schema = makeSchema(schemaConfig); + } + + if (this._transforms) { + this._schema = this.transformSchema(this._schema, this._transforms); + } + + if (this._mocks !== undefined && typeof this._mocks === 'boolean' && this._mocks === true) { + debug(`adding default mocks to the schema for ${this.name}`); + // if mocks are a boolean support simply applying default mocks + this._schema = addMocksToSchema({ schema: this._schema, preserveResolvers: true }); + } + else if (this._mocks !== undefined && typeof this._mocks === 'object') { + debug(`adding custom mocks to the schema for ${this.name}`); + // else if mocks is an object, that means the user provided + // custom mocks, with which we pass them to addMocksToSchema so they are applied + this._schema = addMocksToSchema({ schema: this._schema, mocks: this._mocks, preserveResolvers: true }); + } + + if (this._pruneSchema) { + debug(`pruning the schema for ${this.name}`); + this._schema = pruneSchema(this._schema, this._pruneSchemaOptions); + } + + debug(`created schema for ${this.name}`); + + return this._schema; + } catch (error) { + debug(`Error creating schema for ${this.name}: ${error}`); + throw new Error(`Failed to create schema for component ${this.name}: ${error.message}`); + } + } + + get types(): TypeSource { + return this._types; + } + + get resolvers(): IResolvers { + return this._resolvers; + } + + get imports(): IGraphQLComponentConfigObject[] { + return this._imports; + } + + get dataSources(): IDataSource[] { + return this._dataSources; + } + + get dataSourceOverrides(): IDataSource[] { + return this._dataSourceOverrides; + } + + set federation(flag) { + this._federation = flag; + } + + get federation(): boolean { + return this._federation; + } + + public dispose(): void { + this._schema = null; + this._types = null; + this._resolvers = null; + this._imports = null; + this._dataSources = null; + this._dataSourceOverrides = null; + } + + private transformSchema(schema: GraphQLSchema, transforms: SchemaMapper[]): GraphQLSchema { + if (this._transformedSchema) { + return this._transformedSchema; + } + + const functions = {}; + const mapping = {}; + + for (const transform of transforms) { + for (const [key, fn] of Object.entries(transform)) { + if (!mapping[key]) { + functions[key] = []; + let result = undefined; + mapping[key] = function (...args) { + while (functions[key].length) { + const mapper = functions[key].shift(); + result = mapper(...args); + if (!result) { + break; + } + } + return result; + } + } + functions[key].push(fn); + } + } + + this._transformedSchema = mapSchema(schema, mapping); + return this._transformedSchema; + } + + private validateConfig(options: IGraphQLComponentOptions): void { + if (options.federation && !options.types) { + throw new Error('Federation requires type definitions'); + } + + if (options.mocks && typeof options.mocks !== 'boolean' && typeof options.mocks !== 'object') { + throw new Error('mocks must be either boolean or object'); + } + } + +} + +/** + * Wraps data sources with a proxy that intercepts calls to data source methods and injects the current context + * @param {IDataSource[]} dataSources + * @param {IDataSource[]} dataSourceOverrides + * @returns {DataSourceInjectionFunction} a function that returns a map of data sources with methods that have been intercepted + */ +const createDataSourceContextInjector = (dataSources: IDataSource[], dataSourceOverrides: IDataSource[]): DataSourceInjectionFunction => { + const intercept = (instance: IDataSource, context: any) => { + debug(`intercepting ${instance.constructor.name}`); + + return new Proxy(instance, { + get(target, key) { + if (typeof target[key] !== 'function' || key === instance.constructor.name) { + return target[key]; + } + const original = target[key]; + + return function (...args) { + return original.call(instance, context, ...args); + }; + } + }) as any as DataSource; + }; + + return (context: any = {}): DataSourceMap => { + const proxiedDataSources = {}; + + // Inject data sources + for (const dataSource of dataSources) { + proxiedDataSources[dataSource.name || dataSource.constructor.name] = intercept(dataSource, context); + } + + // Override data sources + for (const dataSourceOverride of dataSourceOverrides) { + proxiedDataSources[dataSourceOverride.name || dataSourceOverride.constructor.name] = intercept(dataSourceOverride, context); + } + + return proxiedDataSources; + }; +}; + +/** + * memoizes resolver functions such that calls of an identical resolver (args/context/path) within the same request context are avoided + * @param {string} parentType - the type whose field resolver is being + * wrapped/memoized + * @param {string} fieldName - the field on the parentType whose resolver + * function is being wrapped/memoized + * @param {function} resolve - the resolver function that parentType. + * fieldName is mapped to + * @returns {function} a function that wraps the input resolver function and + * whose closure scope contains a WeakMap to achieve memoization of the wrapped + * input resolver function + */ +const memoize = function (parentType: string, fieldName: string, resolve: ResolverFunction): ResolverFunction { + const _cache = new WeakMap(); + + return function _memoizedResolver(_, args, context, info) { + const path = info && info.path && info.path.key; + const key = `${path}_${JSON.stringify(args)}`; + + debug(`executing ${parentType}.${fieldName}`); + + let cached = _cache.get(context); + + if (cached && cached[key]) { + debug(`return cached result of memoized ${parentType}.${fieldName}`); + return cached[key]; + } + + if (!cached) { + cached = {}; + } + + const result = resolve(_, args, context, info); + + cached[key] = result; + + _cache.set(context, cached); + + debug(`cached ${parentType}.${fieldName}`); + + return result; + }; +}; + +/** + * make 'this' in resolver functions equal to the input bindContext + * @param {Object} bind - the object context to bind to resolver functions + * @param {Object} resolvers - the resolver map containing the resolver + * functions to bind + * @returns {Object} - an object identical in structure to the input resolver + * map, except with resolver function bound to the input argument bind + */ +const bindResolvers = function (bindContext: IGraphQLComponent, resolvers: IResolvers = {}): IResolvers { + const boundResolvers = {}; + + for (const [type, fields] of Object.entries(resolvers)) { + // dont bind an object that is an instance of a graphql scalar + if (fields instanceof GraphQLScalarType) { + debug(`not binding ${type}'s fields since ${type}'s fields are an instance of GraphQLScalarType`) + boundResolvers[type] = fields; + continue; + } + + if (!boundResolvers[type]) { + boundResolvers[type] = {}; + } + + for (const [field, resolver] of Object.entries(fields)) { + if (['Query', 'Mutation'].indexOf(type) > -1) { + debug(`memoized ${type}.${field}`); + boundResolvers[type][field] = memoize(type, field, resolver.bind(bindContext)); + } + else { + // only bind resolvers that are functions + if (typeof resolver === 'function') { + debug(`binding ${type}.${field}`); + boundResolvers[type][field] = resolver.bind(bindContext); + } + else { + debug(`not binding ${type}.${field} since ${field} is not mapped to a function`); + boundResolvers[type][field] = resolver; + } + } + } + } + + return boundResolvers; +}; + +interface MiddlewareEntry { + name: string; + fn: ContextFunction; +} \ No newline at end of file diff --git a/test/context.ts b/test/context.ts new file mode 100644 index 0000000..79c499a --- /dev/null +++ b/test/context.ts @@ -0,0 +1,42 @@ +import test from 'tape'; +import GraphQLComponent from '../src/index'; + +test('GraphQLComponent Context Tests', (t) => { + t.test('should build context with middleware', async (assert) => { + const component = new GraphQLComponent({ + types: `type Query { test: String }` + }); + + const contextFn = component.context; + contextFn.use('test', async (ctx) => ({ + ...ctx, + testValue: 'test' + })); + + const context = await contextFn({}); + assert.equal(context.testValue, 'test', 'middleware was applied'); + assert.end(); + }); + + t.test('should handle multiple middleware in order', async (assert) => { + const component = new GraphQLComponent({ + types: `type Query { test: String }` + }); + + const contextFn = component.context; + contextFn.use('first', async (ctx) => ({ + ...ctx, + value: 1 + })); + contextFn.use('second', async (ctx) => ({ + ...ctx, + value: (ctx.value as number) + 1 + })); + + const context = await contextFn({}); + assert.equal(context.value, 2, 'middleware executed in order'); + assert.end(); + }); + + t.end(); +}); \ No newline at end of file diff --git a/test/datasources.ts b/test/datasources.ts new file mode 100644 index 0000000..0ec21e7 --- /dev/null +++ b/test/datasources.ts @@ -0,0 +1,182 @@ +import test from 'tape'; +import GraphQLComponent, { DataSourceDefinition, DataSource, ComponentContext } from '../src/index'; +import { IResolvers } from '@graphql-tools/utils'; +import { GraphQLResolveInfo } from 'graphql'; + +test('GraphQLComponent DataSource Tests', (t) => { + t.test('should inject context into data source methods', async (assert) => { + class TestDataSource { + name = 'test'; + getData(context, arg) { + return `${context.value}-${arg}`; + } + } + + const component = new GraphQLComponent({ + types: `type Query { test: String }`, + dataSources: [new TestDataSource()] + }); + + const context = await component.context({ value: 'test' }); + const result = context.dataSources.test.getData('arg'); + + assert.equal(result, 'test-arg', 'context was injected into data source method'); + assert.end(); + }); + + t.test('should allow data source overrides', async (assert) => { + class TestDataSource { + name = 'test'; + getData() { + return 'original'; + } + } + + class OverrideDataSource { + name = 'test'; + getData() { + return 'override'; + } + } + + const component = new GraphQLComponent({ + types: `type Query { test: String }`, + dataSources: [new TestDataSource()], + dataSourceOverrides: [new OverrideDataSource()] + }); + + const context = await component.context({}); + const result = context.dataSources.test.getData(); + + assert.equal(result, 'override', 'data source was overridden'); + assert.end(); + }); + + t.test('should preserve non-function properties', async (assert) => { + class TestDataSource { + name = 'test'; + staticValue = 'static value'; + getData(context) { + return this.staticValue; + } + } + + const component = new GraphQLComponent({ + types: `type Query { test: String }`, + dataSources: [new TestDataSource()] + }); + + const context = await component.context({}); + + assert.equal(context.dataSources.test.staticValue, 'static value', 'static property was preserved'); + assert.equal(context.dataSources.test.getData(), 'static value', 'method can access static property'); + assert.end(); + }); + + t.test('should verify DataSourceDefinition type at compile time', async (assert) => { + // This test doesn't run any assertions, it's just to verify the types compile + + // Explicit typing with DataSourceDefinition to demonstrate proper usage + class TypedDataSource implements DataSourceDefinition<{ + getData: (context: ComponentContext, id: string) => { id: string, extra: string }; + getMultiple: (context: ComponentContext, ids: string[]) => { id: string }[]; + staticProp: string; + }> { + name = 'typed'; + staticProp = 'static value'; + + getData(context: ComponentContext, id: string) { + return { id, extra: context.value as string }; + } + + getMultiple(context: ComponentContext, ids: string[]) { + return ids.map(id => ({ id })); + } + } + + const component = new GraphQLComponent({ + types: `type Query { test: String }`, + dataSources: [new TypedDataSource()] + }); + + const context = await component.context({ value: 'test-value' }); + + // Using DataSource type demonstrates automatic context injection + const typedDS = context.dataSources.typed as DataSource; + + const result1 = typedDS.getData('123'); + const result2 = typedDS.getMultiple(['1', '2', '3']); + + assert.equal(result1.id, '123', 'typed data source returns correct id'); + assert.equal(result1.extra, 'test-value', 'typed data source includes context value'); + assert.equal(result2.length, 3, 'typed data source handles multiple ids'); + assert.equal(typedDS.staticProp, 'static value', 'static property preserved in typed data source'); + assert.end(); + }); + + t.test('should verify DataSource type in resolvers', async (assert) => { + // Define data source with required context parameter + class UserDataSource implements DataSourceDefinition<{ + getUserById: (context: ComponentContext, id: string) => { id: string, name: string }; + getUsersByRole: (context: ComponentContext, role: string) => { id: string, name: string }[]; + }> { + name = 'users'; + + getUserById(context: ComponentContext, id: string) { + // Implementation requires context + return { id, name: `User ${id}` }; + } + + getUsersByRole(context: ComponentContext, role: string) { + // Implementation requires context + return [ + { id: '1', name: 'User 1' }, + { id: '2', name: 'User 2' } + ]; + } + } + + // Define resolvers with explicit Query type + const resolvers = { + Query: { + // In resolvers, we don't need to pass context to data source methods + user: (_: any, { id }: { id: string }, context: ComponentContext, info: GraphQLResolveInfo) => { + // Context is injected automatically - call without passing context + return context.dataSources.users.getUserById(id); + }, + usersByRole: (_: any, { role }: { role: string }, context: ComponentContext, info: GraphQLResolveInfo) => { + // Context is injected automatically - call without passing context + return context.dataSources.users.getUsersByRole(role); + } + } + }; + + const component = new GraphQLComponent({ + types: ` + type User { + id: ID! + name: String! + } + type Query { + user(id: ID!): User + usersByRole(role: String!): [User] + } + `, + resolvers, + dataSources: [new UserDataSource()] + }); + + const context = await component.context({}); + + // Test resolver behavior with null info parameter + const user = await resolvers.Query.user(null, { id: '123' }, context, null as any); + const users = await resolvers.Query.usersByRole(null, { role: 'admin' }, context, null as any); + + assert.equal(user.id, '123', 'resolver correctly called data source'); + assert.equal(user.name, 'User 123', 'data source returned correct user name'); + assert.equal(users.length, 2, 'resolver correctly called multi-user data source'); + assert.end(); + }); + + t.end(); +}); \ No newline at end of file diff --git a/test/schema.ts b/test/schema.ts new file mode 100644 index 0000000..e14928a --- /dev/null +++ b/test/schema.ts @@ -0,0 +1,53 @@ +import test from 'tape'; +import GraphQLComponent from '../src/index'; +import { MapperKind } from '@graphql-tools/utils'; + +test('GraphQLComponent Schema Tests', (t) => { + t.test('should create basic schema', (assert) => { + const types = ` + type Query { + hello: String + } + `; + + const resolvers = { + Query: { + hello: () => 'world' + } + }; + + const component = new GraphQLComponent({ types, resolvers }); + assert.ok(component.schema, 'schema was created'); + assert.end(); + }); + + t.test('should handle schema transforms', (assert) => { + const types = ` + type Query { + hello: String + } + `; + + const transforms = [{ + [MapperKind.OBJECT_FIELD]: (fieldConfig, fieldName) => { + if (fieldName === 'hello') { + return { + ...fieldConfig, + description: 'A hello world field' + }; + } + return fieldConfig; + } + }]; + + const component = new GraphQLComponent({ types, transforms, resolvers: { + Query: { + hello: () => 'world' + } + } }); + assert.ok(component.schema?.getQueryType()?.getFields().hello.description === 'A hello world field', 'transform was applied'); + assert.end(); + }); + + t.end(); +}); \ No newline at end of file diff --git a/test/test.ts b/test/test.ts new file mode 100644 index 0000000..03bdd7c --- /dev/null +++ b/test/test.ts @@ -0,0 +1,633 @@ +import { DirectiveLocation, MapperKind } from '@graphql-tools/utils'; +import { graphql, GraphQLDirective, GraphQLString } from 'graphql'; +import { test } from 'tape'; +import GraphQLComponent, { IDataSource } from '../src'; + +test('component names', (t) => { + + t.test('generic name for anonymous constructor', (t) => { + t.plan(1); + + const component = new GraphQLComponent({}); + + t.equals(component.name, 'GraphQLComponent', `unnamed constructor results in component named 'GraphQLComponent'`); + }); + + t.test('component name (named constructor)', (t) => { + t.plan(1); + + class Named extends GraphQLComponent {} + + const component = new Named({}); + + t.equals(component.name, 'Named', `named constructor reflects class name`); + }); + +}); + +test('component types as array', (t) => { + + t.plan(2); + + const component = new GraphQLComponent({ + types: [ + `type Query { hello: String }` + ] + }); + + t.ok(component.schema, 'component with types as array can be created'); + t.ok(component.schema.getQueryType(), 'component with types as array can be created'); + +}); + +test('getters tests', (t) => { + + t.test('component types', (t) => { + t.plan(1); + + const component = new GraphQLComponent({ + types: `type Query { a: String }`, + imports: [new GraphQLComponent({ + types: `type Query { b: B } type B { someField: String}`} + )] + }); + + t.deepEquals(component.types, [`type Query { a: String }`], `only the component's own types are returned`); + }); + + t.test('component resolvers', (t) => { + t.plan(1); + + const component = new GraphQLComponent({ + resolvers: { + Query: { + a() { return 'hello'} + } + }, + imports: [new GraphQLComponent({ + resolvers: { + Query: { + b() { + return 'goodbye'; + } + } + } + })] + }); + + t.equals(Object.keys(component.resolvers.Query).length, 1, `only the component's own resolvers are returned`); + }); + + t.test('component imports', (t) => { + t.plan(1); + + const childThatAlsoHasImports = new GraphQLComponent({ + types: `type Query { c: String }`, + resolvers: { Query: { c() { return 'hello' }}}, + imports: [new GraphQLComponent({})] + }); + const root = new GraphQLComponent({ + imports: [ + childThatAlsoHasImports + ] + }); + t.equals(root.imports.length, 1, `only component's own imports are returned`); + }); + + t.test('component datasources', (t) => { + t.plan(1); + + const component = new GraphQLComponent({ + dataSources: [new class ParentDataSource { + name: 'ParentDataSource' + }], + imports: [new GraphQLComponent({ + dataSources: [new class ChildDataSource { + name: 'ChildDataSource' + }] + })] + }); + + t.equals(Object.keys(component.dataSources).length, 1, `only component's own dataSources are returned`); + }); + +}); + +test('component directives imports', (t) => { + + t.test('include all', (t) => { + const component = new GraphQLComponent({ + types: ` + directive @parent_directive on OBJECT + `, + imports: [new GraphQLComponent({ + types: ` + directive @child_directive on OBJECT + ` + })] + }); + + t.ok(component.schema.getDirective('parent_directive'), `child component directives exist in merged`); + t.ok(component.schema.getDirective('child_directive'), `parent component directives exist in merged`); + + t.end(); + }); + +}); + +test('federation', (t) => { + + t.test('federated schema can include custom directive', (t) => { + + const component = new GraphQLComponent({ + types: ` + directive @custom on FIELD_DEFINITION + type Query { + property(id: ID!): Property @custom + } + type Property @key(fields: "id") { + id: ID! + geo: [String] + } + extend type Extended @key(fields: "id") { + id: ID! @external + newProp: String + } + `, + resolvers: { + Query: { + property(_, { id }) { + return { + id, + geo: ['lat', 'long'] + } + } + }, + }, + transforms: [{ + [MapperKind.OBJECT_FIELD]: (fieldConfig) => { + return fieldConfig; + } + }], + federation: true + }); + + t.test('federated schema created without error', (t) => { + t.plan(1); + t.doesNotThrow(() => { + component.schema; + }, 'can return a buildFederatedSchema schema'); + }); + + t.test('custom directive added to federated schema', (t) => { + t.plan(1); + const { schema } = component; + + const schemaDirectives = schema.getDirectives(); + + t.equals(schemaDirectives.filter((directive) => directive.name === 'custom').length, 1, `federated schema has '@custom' directive`); + }); + + }); + + t.test('imported federated components will merge correctly', (t) => { + + t.plan(1); + + const component = new GraphQLComponent({ + types: ` + type Outer { + id: ID! + } + `, + federation: true, + pruneSchema: false, + imports: [ + new GraphQLComponent({ + types: ` + type Inner { + id: ID! + } + `, + pruneSchema: false + }) + ] + }); + + t.ok(component.imports[0].component.federation, 'imported federated component types are merged'); + + }); + +}); + +test('imports as configuration', (t) => { + + t.plan(1); + + const component = new GraphQLComponent({ + imports: [ + { + component: new GraphQLComponent({ + types: `type Query { hello: String }` + }) + } + ] + }); + + t.ok(component.schema.getQueryType(), 'component with imports as configuration can be created'); + +}); + +test('context', async (t) => { + t.plan(3); + + const component = new GraphQLComponent({ + context: { + namespace: 'test', + factory: (ctx) => { + t.equals(ctx.globalValue, 'global', 'context factory receives global context'); + return { value: 'local' }; + } + } + }); + + const context = await component.context({ globalValue: 'global' }); + + t.equals(context.test.value, 'local', 'context namespaced value is correct'); + t.equals(context.globalValue, 'global', 'context.globalValue is correct'); + +}); + +test('context with subcontext', async (t) => { + t.plan(1); + + const component = new GraphQLComponent({ + types: `type Query { hello: String }`, + context: { + namespace: 'test', + factory: (ctx) => { + return { value: 'local' }; + } + }, + imports: [ + new GraphQLComponent({ + types: `type Query { subhello: String }`, + context: { + namespace: 'subtest', + factory: (ctx) => { + return { value: 'sublocal' }; + } + } + }) + ] + }); + + const context = await component.context({}); + + t.equals(context.subtest.value, 'sublocal', 'subcontext value is correct'); +}); + +test('middleware', async (t) => { + + t.plan(3); + + const component = new GraphQLComponent({ + types: `type Query { hello: String }`, + resolvers: { + Query: { + hello() { + return 'Hello world!'; + } + } + }, + context: { + namespace: 'componentContext', + factory: (ctx) => { + return { value: 'local' }; + } + } + }); + + const context = component.context; + + context.use((ctx) => { + t.ok(ctx, 'middleware executed'); + return { middlware: 'middleware' }; + }); + + const { componentContext, middlware } = await context({}); + + t.equals(componentContext.value, 'local', 'component context added'); + t.equals(middlware, 'middleware', 'middleware context added'); +}); + +test('data source injection', async (t) => { + t.plan(5); + + const dataSource = new class TestDataSource implements IDataSource { + name = 'TestDataSource'; + value = 'original'; + + getTestValue(ctx, arg) { + t.ok(ctx, 'context is correctly injected'); + t.equal(ctx.globalValue, 'global', 'context is correctly injected'); + t.equal(arg, 1, 'arguments are correctly injected'); + return this.value; + } + }; + + const component = new GraphQLComponent({ + dataSources: [ + dataSource + ] + }); + + const context = await component.context({ globalValue: 'global' }); + + t.ok(context.dataSources.TestDataSource, 'data source is correctly injected'); + t.equal(context.dataSources.TestDataSource.getTestValue(1), 'original', 'data source is correctly injected'); +}); + +test('data source injection', async (t) => { + t.plan(2); + + const dataSource = new class TestDataSource implements IDataSource { + name = 'TestDataSource'; + value = 'original'; + }; + + const dataSourceOverride = new class MockTestDataSource implements IDataSource { + name = 'TestDataSource'; + value = 'override'; + }; + + class MyComponent extends GraphQLComponent { + constructor(options) { + super({ dataSources: [dataSource], ...options }); + } + } + + const component = new MyComponent({ + dataSourceOverrides: [ + dataSourceOverride + ] + }); + + const context = await component.context({ globalValue: 'global' }); + + t.ok(context.dataSources.TestDataSource, 'data source is correctly injected'); + t.equal(context.dataSources.TestDataSource.value, 'override', 'data source is correctly injected'); +}); + +test('transform with custom directive', async (t) => { + t.plan(1); + + const types = ` + directive @customDirective(argName: String) on FIELD_DEFINITION + + type Query { + hello: String @customDirective(argName: "example") + } + `; + + const resolvers = { + Query: { + hello: () => 'Hello world!' + } + }; + + const customDirective = new GraphQLDirective({ + name: 'customDirective', + locations: [DirectiveLocation.FIELD_DEFINITION], + args: { + argName: { type: GraphQLString } + } + }); + + const component = new GraphQLComponent({ + types, + resolvers, + transforms: [ + { + [MapperKind.FIELD]: (fieldConfig) => { + const directives = fieldConfig.astNode?.directives || []; + if (directives.some(directive => directive.name.value === 'customDirective')) { + fieldConfig.description = 'This field has a custom directive'; + } + return fieldConfig; + } + } + ] + }); + + const transformedSchema = component.schema; + + const query = ` + { + __type(name: "Query") { + fields { + name + description + } + } + } + `; + + const result = await graphql({ schema: transformedSchema, source: query }) as any; + + t.equal(result.data?.__type?.fields?.find(field => field.name === 'hello')?.description, 'This field has a custom directive', 'custom directive is correctly applied'); +}); + +test('schema composition', async (t) => { + t.plan(2); + + const component = new GraphQLComponent({ + imports: [ + new GraphQLComponent({ + types: ` + type Property { + id: ID! + name: String + } + ` + }), + new GraphQLComponent({ + types: ` + type Review { + id: ID! + content: String + } + ` + }) + ] + }); + + const schema = component.schema; + + t.ok(schema.getType('Property'), 'Property type is present in the composed schema'); + t.ok(schema.getType('Review'), 'Review type is present in the composed schema'); +}); + +test('schema pruning', async (t) => { + t.plan(2); + + const component = new GraphQLComponent({ + types: ` + type Query { + hello: UsedType + } + type UsedType { + id: ID! + } + type UnusedType { + id: ID! + } + `, + resolvers: { + Query: { + hello: () => 'Hello world!' + } + }, + pruneSchema: true + }); + + const schema = component.schema; + + t.ok(schema.getType('UsedType'), 'UsedType type is present in the composed schema'); + t.ok(!schema.getType('UnusedType'), 'unused type is pruned from the schema'); +}); + +test('resolver binding', async (t) => { + t.plan(1); + + class MyComponent extends GraphQLComponent { + value: string; + + constructor(options) { + super(options); + this.value = 'Hello world!'; + } + }; + + const component = new MyComponent({ + types: ` + type Query { + hello: String + } + `, + resolvers: { + Query: { + hello() { + return this.value; + } + } + } + }); + + const schema = component.schema; + + const query = ` + { + hello + } + `; + + const result = await graphql({ schema, source: query, contextValue: {} }); + + t.equal(result.data?.hello, 'Hello world!', 'resolver correctly binds to context'); +}); + +test('resolve memoization', async (t) => { + t.plan(1); + + let count = 0; + + const component = new GraphQLComponent({ + types: ` + type Query { + hello: String + } + `, + resolvers: { + Query: { + hello: () => { + count++; + return 'Hello world!'; + } + } + } + }); + + const schema = component.schema; + + const query = ` + { + hello + } + `; + + const ctx = { v: 1 }; + + const result1 = await graphql({ schema, source: query, contextValue: ctx }); + const result2 = await graphql({ schema, source: query, contextValue: ctx }); + + t.equal(count, 1, 'resolver is memoized'); +}); + +test('mocks', async (t) => { + + t.test('default mocks', async (t) => { + t.plan(1); + + const component = new GraphQLComponent({ + types: ` + type Query { + hello: String + } + `, + mocks: true + }); + + const schema = component.schema; + + const query = ` + { + hello + } + `; + + const result = await graphql({ schema, source: query }); + + t.ok(result.data?.hello, 'default mocks are used'); + }); + + t.test('custom mocks applied', async (t) => { + t.plan(1); + + const component = new GraphQLComponent({ + types: ` + type Query { + hello: String + } + `, + mocks: { + Query: () => ({ + hello: 'Custom hello world!' + }) + } + }); + + const schema = component.schema; + + const query = ` + { + hello + } + `; + + const result = await graphql({ schema, source: query }); + + t.equal(result.data?.hello, 'Custom hello world!', 'custom mocks are used'); + }); + +}); \ No newline at end of file diff --git a/test/validation.ts b/test/validation.ts new file mode 100644 index 0000000..07b14b3 --- /dev/null +++ b/test/validation.ts @@ -0,0 +1,24 @@ +import test from 'tape'; +import GraphQLComponent from '../src/index'; + +test('GraphQLComponent Configuration Validation', (t) => { + t.test('should throw error when federation enabled without types', (assert) => { + assert.throws( + () => new GraphQLComponent({ federation: true }), + /Federation requires type definitions/, + 'throws error when federation enabled without types' + ); + assert.end(); + }); + + t.test('should throw error for invalid mocks configuration', (assert) => { + assert.throws( + () => new GraphQLComponent({ types: ['type Query { test: String }'], mocks: 'invalid' as any }), + /mocks must be either boolean or object/, + 'throws error for invalid mocks value' + ); + assert.end(); + }); + + t.end(); +}); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..97f5e07 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "experimentalDecorators": true, + "module": "commonjs", + "target": "esnext", + "lib": ["esnext"], + "noImplicitAny": false, + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "inlineSourceMap": true, + "declaration": true, + "esModuleInterop": true, + "types" : ["node", "graphql"], + "outDir": "./dist", + "rootDir": "./src" + }, + "exclude": ["node_modules"], + "include": [ + "./src" + ], + "sourceMap": true +}