diff --git a/tracker/tracker-graphql/README.md b/tracker/tracker-graphql/README.md index 9c68794c5..4cc3a4931 100644 --- a/tracker/tracker-graphql/README.md +++ b/tracker/tracker-graphql/README.md @@ -18,13 +18,13 @@ returns `result` without changes. ```js import Tracker from '@openreplay/tracker'; -import { createGraphqlMiddleware } from '@openreplay/tracker-graphql'; +import trackerGraphQL from '@openreplay/tracker-graphql'; const tracker = new Tracker({ projectKey: YOUR_PROJECT_KEY, }); -export const recordGraphQL = tracker.use(createGraphqlMiddleware()); +export const recordGraphQL = tracker.plugin(trackerGraphQL()); ``` ### Relay @@ -33,28 +33,15 @@ If you're using [Relay network tools](https://github.com/relay-tools/react-relay you can simply [create a middleware](https://github.com/relay-tools/react-relay-network-modern/tree/master?tab=readme-ov-file#example-of-injecting-networklayer-with-middlewares-on-the-client-side) ```js -import { createRelayMiddleware } from '@openreplay/tracker-graphql'; +import { createRelayMiddleware } from '@openreplay/tracker-graphql' -const trackerMiddleware = tracker.use(createRelayMiddleware()); +const trackerMiddleware = createRelayMiddleware(tracker) const network = new RelayNetworkLayer([ // your middleware // , - trackerMiddleware, -]); -``` - -You can pass a Sanitizer function to `createRelayMiddleware` to sanitize the variables and data before sending them to OpenReplay. - -```js -const trackerLink = tracker.use( - createRelayMiddleware((variables) => { - return { - ...variables, - password: '***', - }; - }), -); + trackerMiddleware +]) ``` Or you can manually put `recordGraphQL` call @@ -65,22 +52,22 @@ then you should do something like below import { createGraphqlMiddleware } from '@openreplay/tracker-graphql'; // see above for recordGraphQL definition import { Environment } from 'relay-runtime'; -const handler = tracker.use(createGraphqlMiddleware()); +const handler = createGraphqlMiddleware(tracker) function fetchQuery(operation, variables, cacheConfig, uploadables) { return fetch('www.myapi.com/resource', { // ... }) - .then((response) => response.json()) - .then((result) => - handler( - // op kind, name, variables, response, duration (default 0) - operation.operationKind, - operation.name, - variables, - result, - duration, - ), + .then(response => response.json()) + .then(result => + handler( + // op kind, name, variables, response, duration (default 0) + operation.operationKind, + operation.name, + variables, + result, + duration, + ), ); } @@ -94,23 +81,10 @@ See [Relay Network Layer](https://relay.dev/docs/en/network-layer) for details. For [Apollo](https://www.apollographql.com/) you should create a new `ApolloLink` ```js -import { createTrackerLink } from '@openreplay/tracker-graphql'; +import { createTrackerLink } from '@openreplay/tracker-graphql' -const trackerLink = tracker.use(createTrackerLink()); -const yourLink = new ApolloLink(trackerLink); -``` - -You can pass a Sanitizer function to `createRelayMiddleware` to sanitize the variables and data before sending them to OpenReplay. - -```js -const trackerLink = tracker.use( - createTrackerLink((variables) => { - return { - ...variables, - password: '***', - }; - }), -); +const trackerLink = createTrackerLink(tracker); +const yourLink = new ApolloLink(trackerLink) ``` Alternatively you can use generic graphql handler: @@ -119,21 +93,18 @@ Alternatively you can use generic graphql handler: import { createGraphqlMiddleware } from '@openreplay/tracker-graphql'; // see above for recordGraphQL definition import { ApolloLink } from 'apollo-link'; -const handler = tracker.use(createGraphqlMiddleware()); +const handler = createGraphqlMiddleware(tracker) const trackerApolloLink = new ApolloLink((operation, forward) => { - operation.setContext({ start: performance.now() }); - return forward(operation).map((result) => { - const time = performance.now() - operation.getContext().start; - return handler( + return forward(operation).map(result => + handler( // op kind, name, variables, response, duration (default 0) operation.query.definitions[0].operation, operation.operationName, operation.variables, result, - time, - ); - }); + ), + ); }); const link = ApolloLink.from([ diff --git a/tracker/tracker-graphql/src/apolloMiddleware.ts b/tracker/tracker-graphql/src/apolloMiddleware.ts index 2956b23ef..948186b77 100644 --- a/tracker/tracker-graphql/src/apolloMiddleware.ts +++ b/tracker/tracker-graphql/src/apolloMiddleware.ts @@ -1,6 +1,5 @@ import { App, Messages } from '@openreplay/tracker'; import Observable from 'zen-observable'; -import { Sanitizer } from './types'; type Operation = { query: Record; @@ -10,63 +9,48 @@ type Operation = { }; type NextLink = (operation: Operation) => Observable>; -export const createTrackerLink = ( - sanitizer?: Sanitizer | undefined | null>, -) => { - return (app: App | null) => { - if (!app) { - return (operation: Operation, forward: NextLink) => forward(operation); - } - return (operation: Operation, forward: NextLink) => { - return new Observable((observer) => { - const start = app.timestamp(); - const observable = forward(operation); - const subscription = observable.subscribe({ - next(value) { - const end = app.timestamp(); - const operationDefinition = operation.query.definitions[0]; - app.send( - Messages.GraphQL( - operationDefinition.kind === 'OperationDefinition' - ? operationDefinition.operation - : 'unknown?', - operation.operationName, - JSON.stringify( - sanitizer - ? sanitizer(operation.variables) - : operation.variables, - ), - JSON.stringify(sanitizer ? sanitizer(value.data) : value.data), - end - start, - ), - ); - observer.next(value); - }, - error(error) { - const end = app.timestamp(); - app.send( - Messages.GraphQL( - operation.query.definitions[0].kind, - operation.operationName, - JSON.stringify( - sanitizer - ? sanitizer(operation.variables) - : operation.variables, - ), - JSON.stringify(error), - end - start, - ), - ); - observer.error(error); - }, - complete() { - observer.complete(); - }, - }); - - return () => subscription.unsubscribe(); +export const createTrackerLink = (app: App | null) => { + if (!app) { + return (operation: Operation, forward: NextLink) => forward(operation); + } + return (operation: Operation, forward: NextLink) => { + return new Observable((observer) => { + const start = app.timestamp(); + const observable = forward(operation); + const subscription = observable.subscribe({ + next(value) { + const end = app.timestamp(); + app.send( + Messages.GraphQL( + operation.query.definitions[0].kind, + operation.operationName, + JSON.stringify(operation.variables), + JSON.stringify(value.data), + end - start, + ), + ); + observer.next(value); + }, + error(error) { + const end = app.timestamp(); + app.send( + Messages.GraphQL( + operation.query.definitions[0].kind, + operation.operationName, + JSON.stringify(operation.variables), + JSON.stringify(error), + end - start, + ), + ); + observer.error(error); + }, + complete() { + observer.complete(); + }, }); - }; + + return () => subscription.unsubscribe(); + }); }; }; diff --git a/tracker/tracker-graphql/src/graphqlMiddleware.ts b/tracker/tracker-graphql/src/graphqlMiddleware.ts index 79bb75a94..e5302d232 100644 --- a/tracker/tracker-graphql/src/graphqlMiddleware.ts +++ b/tracker/tracker-graphql/src/graphqlMiddleware.ts @@ -1,4 +1,4 @@ -import { App, Messages } from '@openreplay/tracker'; +import { App, Messages } from "@openreplay/tracker"; function createGraphqlMiddleware() { return (app: App | null) => { @@ -10,7 +10,7 @@ function createGraphqlMiddleware() { operationName: string, variables: any, result: any, - duration = 0, + duration = 0 ) => { try { app.send( @@ -30,4 +30,4 @@ function createGraphqlMiddleware() { }; } -export default createGraphqlMiddleware; +export default createGraphqlMiddleware \ No newline at end of file diff --git a/tracker/tracker-graphql/src/index.ts b/tracker/tracker-graphql/src/index.ts index 5bf81f24c..339836352 100644 --- a/tracker/tracker-graphql/src/index.ts +++ b/tracker/tracker-graphql/src/index.ts @@ -1,11 +1,9 @@ import createTrackerLink from './apolloMiddleware.js'; import createRelayMiddleware from './relayMiddleware.js'; import createGraphqlMiddleware from './graphqlMiddleware.js'; -import { Sanitizer } from './types.js'; export { createTrackerLink, createRelayMiddleware, createGraphqlMiddleware, - Sanitizer, -}; +} \ No newline at end of file diff --git a/tracker/tracker-graphql/src/relayMiddleware.ts b/tracker/tracker-graphql/src/relayMiddleware.ts index c3aac9d98..f1e9cc721 100644 --- a/tracker/tracker-graphql/src/relayMiddleware.ts +++ b/tracker/tracker-graphql/src/relayMiddleware.ts @@ -1,55 +1,37 @@ import { App, Messages } from '@openreplay/tracker'; import type { Middleware, RelayRequest } from './relaytypes'; -import { Sanitizer } from './types'; -const createRelayMiddleware = (sanitizer?: Sanitizer>) => { - return (app: App | null): Middleware => { - if (!app) { - return (next) => async (req) => await next(req); +const createRelayMiddleware = (app: App | null): Middleware => { + if (!app) { + return (next) => async (req) => await next(req); + } + return (next) => async (req) => { + const start = app.timestamp(); + const resp = await next(req) + const end = app.timestamp(); + if ('requests' in req) { + req.requests.forEach((request) => { + app.send(getMessage(request, resp.json as Record, end - start)) + }) + } else { + app.send(getMessage(req, resp.json as Record, end - start)) } - return (next) => async (req) => { - const start = app.timestamp(); - const resp = await next(req); - const end = app.timestamp(); - if ('requests' in req) { - req.requests.forEach((request) => { - app.send( - getMessage( - request, - resp.json as Record, - end - start, - sanitizer, - ), - ); - }); - } else { - app.send( - getMessage( - req, - resp.json as Record, - end - start, - sanitizer, - ), - ); - } - return resp; - }; - }; + return resp; + } }; -function getMessage( - request: RelayRequest, - json: Record, - duration: number, - sanitizer?: Sanitizer>, -) { +function getMessage(request: RelayRequest, json: Record, duration: number) { const opKind = request.operation.kind; const opName = request.operation.name; - const vars = JSON.stringify( - sanitizer ? sanitizer(request.variables) : request.variables, - ); - const opResp = JSON.stringify(sanitizer ? sanitizer(json) : json); - return Messages.GraphQL(opKind, opName, vars, opResp, duration); + const vars = JSON.stringify(request.variables) + const opResp = JSON.stringify(json) + return Messages.GraphQL( + opKind, + opName, + vars, + opResp, + duration + ) } -export default createRelayMiddleware; +export default createRelayMiddleware diff --git a/tracker/tracker-graphql/src/relaytypes.ts b/tracker/tracker-graphql/src/relaytypes.ts index dbd2d200c..4330918d5 100644 --- a/tracker/tracker-graphql/src/relaytypes.ts +++ b/tracker/tracker-graphql/src/relaytypes.ts @@ -1,3 +1,4 @@ + type ConcreteBatch = { kind: 'Batch'; fragment: any; @@ -8,7 +9,7 @@ type ConcreteBatch = { text: string | null; operationKind: string; }; -export type Variables = { [name: string]: any }; +type Variables = { [name: string]: any }; interface FetchOpts { url?: string; method: 'POST' | 'GET'; @@ -16,13 +17,7 @@ interface FetchOpts { body: string | FormData; credentials?: 'same-origin' | 'include' | 'omit'; mode?: 'cors' | 'websocket' | 'navigate' | 'no-cors' | 'same-origin'; - cache?: - | 'default' - | 'no-store' - | 'reload' - | 'no-cache' - | 'force-cache' - | 'only-if-cached'; + cache?: 'default' | 'no-store' | 'reload' | 'no-cache' | 'force-cache' | 'only-if-cached'; redirect?: 'follow' | 'error' | 'manual'; signal?: AbortSignal; [name: string]: any; diff --git a/tracker/tracker-graphql/src/types.ts b/tracker/tracker-graphql/src/types.ts deleted file mode 100644 index 441a215e7..000000000 --- a/tracker/tracker-graphql/src/types.ts +++ /dev/null @@ -1 +0,0 @@ -export type Sanitizer = (values: T) => Partial;