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

apollo-link

Package Overview
Dependencies
Maintainers
3
Versions
48
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

apollo-link - npm Package Compare versions

Comparing version 0.6.1-beta.1 to 0.6.1-beta.3

CHANGELOG.md

78

package.json
{
"name": "apollo-link",
"version": "0.6.1-beta.1",
"version": "0.6.1-beta.3",
"description": "Flexible, lightweight transport layer for GraphQL",

@@ -13,6 +13,6 @@ "author": "Evans Hauser <evanshauser@gmail.com>",

"license": "MIT",
"main": "./dist/src/bundle.umd.js",
"module": "./dist/src/index.js",
"jsnext:main": "./dist/src/index.js",
"typings": "./dist/src/index.d.ts",
"main": "./lib/bundle.umd.js",
"module": "./lib/index.js",
"jsnext:main": "./lib/index.js",
"typings": "./lib/index.d.ts",
"repository": {

@@ -27,51 +27,43 @@ "type": "git",

"scripts": {
"pretest": "npm run build-test",
"test": "npm run test-only --",
"posttest": "npm run lint",
"test-only": "mocha --reporter spec --full-trace dist/tests/tests.js",
"test-watch":
"mocha --reporter spec --full-trace dist/tests/tests.js --watch",
"coverage":
"istanbul cover ./node_modules/mocha/bin/_mocha -- --reporter dot --full-trace dist/tests/tests.js",
"postcoverage":
"remap-istanbul --input coverage/coverage.json --type lcovonly --output coverage/lcov.info",
"build:browser":
"browserify ./lib/bundle.umd.js -o=./lib/bundle.js --i apollo-utilities --i graphql --i zen-observable-ts && npm run minify:browser",
"build": "tsc -p .",
"bundle": "rollup -c",
"clean": "rimraf lib/* && rimraf coverage/*",
"filesize": "npm run build && npm run build:browser",
"lint":
"tslint --type-check -p tsconfig.test.json src/*.ts && tslint --type-check -p tsconfig.test.json tests/*.ts",
"prebuild": "npm run clean:dist",
"build": "tsc -p .",
"build-test": "tsc -p tsconfig.test.json",
"tslint --type-check -p tsconfig.json -c ../../tslint.json src/*.ts",
"minify:browser":
"uglifyjs -c -m -o ./lib/bundle.min.js -- ./lib/bundle.js",
"postbuild": "npm run bundle",
"postbuild-test": "npm run bundle",
"bundle": "rollup -c",
"watch": "tsc -w -p .",
"clean": "npm run clean:dist && npm run clean:coverage",
"clean:dist": "rimraf dist/*",
"clean:coverage": "rimraf coverage/*",
"prepublishOnly": "npm run clean && npm run build"
"prebuild": "npm run clean",
"prepublishOnly": "npm run clean && npm run build",
"test": "jest",
"watch": "tsc -w -p ."
},
"dependencies": {
"graphql": "^0.10.3",
"graphql-tag": "^2.4.2",
"zen-observable-ts": "^0.4.3-beta.0"
"apollo-utilities": "^0.2.0-beta.0",
"graphql": "^0.11.3",
"zen-observable-ts": "^0.4.3-beta.2"
},
"devDependencies": {
"@types/chai": "4.0.4",
"@types/chai-as-promised": "0.0.31",
"@types/graphql": "0.10.2",
"@types/mocha": "2.2.42",
"@types/sinon": "2.3.3",
"chai": "4.1.1",
"chai-as-promised": "7.1.1",
"fetch-mock": "5.12.2",
"istanbul": "0.4.5",
"lodash": "4.17.4",
"mocha": "3.5.0",
"remap-istanbul": "0.9.5",
"@types/jest": "^20.0.8",
"browserify": "^14.4.0",
"graphql-tag": "^2.4.2",
"jest": "^21.1.0",
"rimraf": "2.6.1",
"rollup": "^0.45.2",
"sinon": "3.2.0",
"source-map-support": "0.4.16",
"ts-jest": "^21.0.1",
"tslint": "5.7.0",
"typescript": "2.5.1"
"typescript": "2.5.1",
"uglify-js": "^3.1.1"
},
"jest": {
"transform": {
".(ts|tsx)": "<rootDir>/node_modules/ts-jest/preprocessor.js"
},
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
"moduleFileExtensions": ["ts", "tsx", "js", "json"]
}
}
export default {
entry: 'dist/src/index.js',
dest: 'dist/src/bundle.umd.js',
entry: './lib/index.js',
dest: './lib/bundle.umd.js',
format: 'umd',

@@ -8,10 +8,7 @@ sourceMap: true,

exports: 'named',
onwarn
onwarn,
};
function onwarn(message) {
const suppressed = [
'UNRESOLVED_IMPORT',
'THIS_IS_UNDEFINED'
];
const suppressed = ['UNRESOLVED_IMPORT', 'THIS_IS_UNDEFINED'];

@@ -18,0 +15,0 @@ if (!suppressed.find(code => message.code === code)) {

@@ -1,2 +0,2 @@

import { execute, ApolloLink } from './link';
export * from './link';
export { makePromise } from './linkUtils';

@@ -8,3 +8,2 @@ export * from './types';

export default ApolloLink;
export { Observable, ApolloLink, execute };
export { Observable };

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

import Observable from 'zen-observable-ts';
import {

@@ -11,106 +13,108 @@ GraphQLRequest,

validateOperation,
toLink,
isTerminating,
LinkError,
transformOperation,
createOperation,
} from './linkUtils';
import gql from 'graphql-tag';
const passthrough = (op, forward) => (forward ? forward(op) : Observable.of());
import Observable from 'zen-observable-ts';
import {
DocumentNode,
DefinitionNode,
OperationDefinitionNode,
} from 'graphql/language/ast';
const toLink = (handler: RequestHandler | ApolloLink) =>
typeof handler === 'function' ? new ApolloLink(handler) : handler;
export abstract class ApolloLink {
public static from(links: (ApolloLink | RequestHandler)[]) {
if (links.length === 0) {
return ApolloLink.empty();
}
export const empty = (): ApolloLink =>
new ApolloLink((op, forward) => Observable.of());
return links.map(toLink).reduce((x, y) => x.concat(y));
export const from = (links: ApolloLink[]): ApolloLink => {
if (links.length === 0) return empty();
return links.map(toLink).reduce((x, y) => x.concat(y));
};
export const split = (
test: (op: Operation) => boolean,
left: ApolloLink | RequestHandler,
right: ApolloLink | RequestHandler = new ApolloLink(passthrough),
): ApolloLink => {
const leftLink = toLink(left);
const rightLink = toLink(right);
if (isTerminating(leftLink) && isTerminating(rightLink)) {
return new ApolloLink(operation => {
return test(operation)
? leftLink.request(operation) || Observable.of()
: rightLink.request(operation) || Observable.of();
});
} else {
return new ApolloLink((operation, forward) => {
return test(operation)
? leftLink.request(operation, forward) || Observable.of()
: rightLink.request(operation, forward) || Observable.of();
});
}
};
public static empty(): ApolloLink {
return new FunctionLink((op, forward) => Observable.of());
// join two Links together
export const concat = (
first: ApolloLink | RequestHandler,
second: ApolloLink | RequestHandler,
) => {
const firstLink = toLink(first);
if (isTerminating(firstLink)) {
console.warn(
new LinkError(
`You are calling concat on a terminating link, which will have no effect`,
firstLink,
),
);
return firstLink;
}
const nextLink = toLink(second);
public static passthrough(): ApolloLink {
return new FunctionLink(
(op, forward) => (forward ? forward(op) : Observable.of()),
if (isTerminating(nextLink)) {
return new ApolloLink(
operation =>
firstLink.request(
operation,
op => nextLink.request(op) || Observable.of(),
) || Observable.of(),
);
} else {
return new ApolloLink((operation, forward) => {
return (
firstLink.request(operation, op => {
return nextLink.request(op, forward) || Observable.of();
}) || Observable.of()
);
});
}
};
// split allows for creating a split point in an execution chain
// like filter, it can be used to direct operations based
// on request information. Instead of dead ending an execution,
// split allows for new chains to be formed.
public static split(
test: (op: Operation) => boolean,
left: ApolloLink | RequestHandler,
right: ApolloLink | RequestHandler = ApolloLink.passthrough(),
): ApolloLink {
const leftLink = toLink(left);
const rightLink = toLink(right);
if (isTerminating(leftLink) && isTerminating(rightLink)) {
return new FunctionLink(operation => {
return test(operation)
? leftLink.request(operation) || Observable.of()
: rightLink.request(operation) || Observable.of();
});
} else {
return new FunctionLink((operation, forward) => {
return test(operation)
? leftLink.request(operation, forward) || Observable.of()
: rightLink.request(operation, forward) || Observable.of();
});
}
export class ApolloLink {
constructor(request?: RequestHandler) {
if (request) this.request = request;
}
public static empty = empty;
public static from = from;
public static split = split;
public split(
test: (op: Operation) => boolean,
left: ApolloLink | RequestHandler,
right: ApolloLink | RequestHandler = ApolloLink.passthrough(),
right: ApolloLink | RequestHandler = new ApolloLink(passthrough),
): ApolloLink {
return this.concat(ApolloLink.split(test, left, right));
return this.concat(split(test, left, right));
}
// join two Links together
public concat(next: ApolloLink | RequestHandler): ApolloLink {
if (isTerminating(this)) {
console.warn(
new LinkError(
`You are calling concat on a terminating link, which will have no effect`,
this,
),
);
return this;
}
const nextLink = toLink(next);
if (isTerminating(nextLink)) {
return new FunctionLink(
operation =>
this.request(
operation,
op => nextLink.request(op) || Observable.of(),
) || Observable.of(),
);
} else {
return new FunctionLink((operation, forward) => {
return (
this.request(operation, op => {
return nextLink.request(op, forward) || Observable.of();
}) || Observable.of()
);
});
}
return concat(this, next);
}
public abstract request(
public request(
operation: Operation,
forward?: NextLink,
): Observable<FetchResult> | null;
): Observable<FetchResult> | null {
throw new Error('request is not implemented');
}
}

@@ -122,67 +126,10 @@

): Observable<FetchResult> {
const copy = { ...operation };
validateOperation(copy);
if (!copy.context) {
copy.context = {};
}
if (!copy.variables) {
copy.variables = {};
}
if (!copy.query) {
console.warn(`query should either be a string or GraphQL AST`);
copy.query = <DocumentNode>{};
}
return link.request(transformOperation(copy)) || Observable.of();
return (
link.request(
createOperation(
operation.context,
transformOperation(validateOperation(operation)),
),
) || Observable.of()
);
}
function getName(node: OperationDefinitionNode) {
return node && node.name && node.name.kind === 'Name' && node.name.value;
}
function transformOperation(operation: GraphQLRequest): Operation {
let transformedOperation: Operation;
if (typeof operation.query === 'string') {
transformedOperation = {
...operation,
query: gql(operation.query),
};
} else {
transformedOperation = {
...operation,
} as Operation;
}
if (transformedOperation.query && transformedOperation.query.definitions) {
if (!transformedOperation.operationName) {
const operationTypes = ['query', 'mutation', 'subscription'];
const definitions = <OperationDefinitionNode[]>transformedOperation.query.definitions.filter(
(x: DefinitionNode) =>
x.kind === 'OperationDefinition' &&
operationTypes.indexOf(x.operation) >= 0,
);
transformedOperation.operationName = getName(definitions[0]) || '';
}
} else if (!transformedOperation.operationName) {
transformedOperation.operationName = '';
}
return transformedOperation;
}
export class FunctionLink extends ApolloLink {
constructor(public f: RequestHandler) {
super();
this.request = f;
}
public request(
operation: Operation,
forward: NextLink,
): Observable<FetchResult> {
throw Error('should be overridden');
}
}

@@ -1,9 +0,17 @@

import { GraphQLRequest, RequestHandler } from './types';
import { getOperationName } from 'apollo-utilities';
import Observable from 'zen-observable-ts';
import { print } from 'graphql/language/printer';
import { ApolloLink, FunctionLink } from './link';
import { GraphQLRequest, Operation } from './types';
import { ApolloLink } from './link';
import Observable from 'zen-observable-ts';
export function validateOperation(operation: GraphQLRequest): GraphQLRequest {
const OPERATION_FIELDS = ['query', 'operationName', 'variables', 'context'];
const OPERATION_FIELDS = [
'query',
'operationName',
'variables',
'extensions',
'context',
];
if (!operation.query) throw new Error('ApolloLink requires a query');
for (let key of Object.keys(operation)) {

@@ -26,10 +34,2 @@ if (OPERATION_FIELDS.indexOf(key) < 0) {

export function toLink(link: ApolloLink | RequestHandler): ApolloLink {
if (typeof link === 'function') {
return new FunctionLink(link);
} else {
return link as ApolloLink;
}
}
export function isTerminating(link: ApolloLink): boolean {

@@ -57,1 +57,60 @@ return link.request.length <= 1;

}
export function transformOperation(operation: GraphQLRequest): GraphQLRequest {
const transformedOperation: GraphQLRequest = {
variables: operation.variables || {},
extensions: operation.extensions || {},
operationName: operation.operationName,
query: operation.query,
};
// best guess at an operation name
if (!transformedOperation.operationName) {
transformedOperation.operationName =
typeof transformedOperation.query !== 'string'
? getOperationName(transformedOperation.query)
: '';
}
return transformedOperation as Operation;
}
export function createOperation(
starting: any,
operation: GraphQLRequest,
): Operation {
let context = { ...starting };
const setContext = next => {
if (typeof next === 'function') {
context = next(context);
} else {
context = { ...next };
}
};
const getContext = () => ({ ...context });
Object.defineProperty(operation, 'setContext', {
enumerable: false,
value: setContext,
});
Object.defineProperty(operation, 'getContext', {
enumerable: false,
value: getContext,
});
Object.defineProperty(operation, 'toKey', {
enumerable: false,
value: () => getKey(operation),
});
return operation as Operation;
}
export function getKey(operation: GraphQLRequest) {
// XXX we're assuming here that variables will be serialized in the same order.
// that might not always be true
return `${print(operation.query)}|${JSON.stringify(
operation.variables,
)}|${operation.operationName}`;
}

@@ -20,8 +20,5 @@ import { Operation, NextLink, FetchResult } from '../types';

): Observable<FetchResult> {
if (!operation.context) {
operation.context = {};
}
operation.context = this.setContext(operation.context);
operation.setContext(this.setContext(operation.getContext()));
return forward(operation);
}
}

@@ -1,23 +0,19 @@

import { assert } from 'chai';
import * as sinon from 'sinon';
import * as Links from '../link';
import gql from 'graphql-tag';
import { execute, ApolloLink } from '../link';
const sampleQuery = `
query SampleQuery {
stub{
id
const sampleQuery = gql`
query SampleQuery {
stub {
id
}
}
}
`;
export function checkCalls<T>(
calls: Array<sinon.SinonSpyCall>,
results: Array<T>,
) {
assert.deepEqual(calls.length, results.length);
calls.map((call, i) => assert.deepEqual(call.args[0].data, results[i]));
export function checkCalls<T>(calls: any[] = [], results: Array<T>) {
expect(calls.length).toBe(results.length);
calls.map((call, i) => expect(call.data).toEqual(results[i]));
}
export interface TestResultType {
link: Links.ApolloLink;
link: ApolloLink;
results?: any[];

@@ -36,8 +32,8 @@ query?: string;

const spy = sinon.spy();
Links.execute(link, { query, context, variables }).subscribe({
const spy = jest.fn();
execute(link, { query, context, variables }).subscribe({
next: spy,
error: error => {
assert(error, results.pop());
checkCalls(spy.getCalls(), results);
expect(error).toEqual(results.pop());
checkCalls(spy.mock.calls[0], results);
if (done) {

@@ -48,3 +44,3 @@ done();

complete: () => {
checkCalls(spy.getCalls(), results);
checkCalls(spy.mock.calls[0], results);
if (done) {

@@ -51,0 +47,0 @@ done();

@@ -5,5 +5,7 @@ import Observable from 'zen-observable-ts';

export interface GraphQLRequest {
query?: string | DocumentNode;
query: DocumentNode;
variables?: Record<string, any>;
operationName?: string;
context?: Record<string, any>;
extensions?: Record<string, any>;
}

@@ -13,5 +15,8 @@

query: DocumentNode;
variables?: Record<string, any>;
operationName?: string;
context?: Record<string, any>;
variables: Record<string, any>;
operationName: string;
extensions: Record<string, any>;
setContext: (context: Record<string, any>) => Record<string, any>;
getContext: () => Record<string, any>;
toKey: () => string;
}

@@ -18,0 +23,0 @@

{
"extends": "../../tsconfig",
"compilerOptions": {
"outDir": "dist",
"rootDir": "."
"rootDir": "./src",
"outDir": "lib"
},
"include": ["src/**/*.ts"]
"include": ["src/**/*.ts"],
"exclude": ["src/**/__tests__/*.ts"]
}
SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc