@envelop/persisted-operations 5.0.0-alpha-d0d0776.0 → 5.0.0-alpha-5b6bfa8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,26 +15,26 @@ yarn add @envelop/persisted-operations
15
15
  The most basic implementation can use an in-memory JS `Map` wrapper with a `Store` object:
16
16
 
17
17
  ```ts
18
- import { envelop } from '@envelop/core';
19
- import { usePersistedOperations, InMemoryStore } from '@envelop/persisted-operations';
18
+ import { envelop } from '@envelop/core'
19
+ import { usePersistedOperations, InMemoryStore } from '@envelop/persisted-operations'
20
20
 
21
21
  // You can retrieve the store in any way (e.g. from a remote source) and implement it with a simple Map / Key->Value
22
- const myData = new Map();
23
- myData.set('persisted_1', parse(`query { ... }`));
24
- myData.set('persisted_2', 'query { ... }'));
22
+ const myData = new Map()
23
+ myData.set('persisted_1', parse(`query { ... }`))
24
+ myData.set('persisted_2', 'query { ... }')
25
25
 
26
26
  const store = new InMemoryStore({
27
- initialData: myData,
27
+ initialData: myData
28
28
  })
29
29
 
30
30
  const getEnveloped = envelop({
31
31
  plugins: [
32
32
  // ... other plugins ...
33
33
  usePersistedOperations({
34
- store: myStore,
35
- }),
36
- ],
37
- });
34
+ store: myStore
35
+ })
36
+ ]
37
+ })
38
38
  ```
39
39
 
40
40
  Now, when running operations through your GraphQL server, you can use a key instead of a query language:
@@ -58,25 +58,25 @@ usePersistedOperations({
58
58
  ## Usage Example with built-in JsonFileStore
59
59
 
60
60
  ```ts
61
- import { usePersistedOperations, JsonFileStore } from '@envelop/persisted-operations';
61
+ import { usePersistedOperations, JsonFileStore } from '@envelop/persisted-operations'
62
62
 
63
- const persistedOperationsStore = new JsonFilesStore();
64
- const filePath = resolve(process.cwd(), 'assets/client1PersistedOperations.json');
63
+ const persistedOperationsStore = new JsonFilesStore()
64
+ const filePath = resolve(process.cwd(), 'assets/client1PersistedOperations.json')
65
65
 
66
66
  // sync
67
- persistedOperationsStore.loadFromFileSync(filePath); // load and parse persisted-operations files
67
+ persistedOperationsStore.loadFromFileSync(filePath) // load and parse persisted-operations files
68
68
 
69
69
  // or async
70
- await persistedOperationsStore.loadFromFile(filePath); // load and parse persisted-operations files
70
+ await persistedOperationsStore.loadFromFile(filePath) // load and parse persisted-operations files
71
71
 
72
72
  const getEnveloped = envelop({
73
73
  plugins: [
74
74
  // ... other plugins ...
75
75
  usePersistedOperations({
76
- store: persistedOperationsStore,
77
- }),
78
- ],
79
- });
76
+ store: persistedOperationsStore
77
+ })
78
+ ]
79
+ })
80
80
  ```
81
81
 
82
82
  ## Multiple Stores
@@ -90,17 +90,17 @@ const getEnveloped = envelop({
90
90
  usePersistedOperations({
91
91
  store: context => {
92
92
  if (context.req.headers['user-agent'].includes('Android')) {
93
- return mobileClientsStore;
93
+ return mobileClientsStore
94
94
  }
95
95
 
96
- return defaultStore;
97
- },
98
- }),
99
- ],
100
- });
96
+ return defaultStore
97
+ }
98
+ })
99
+ ]
100
+ })
101
101
 
102
102
  // later, pass the initial context
103
- const proxyFns = getEnveloped({ req });
103
+ const proxyFns = getEnveloped({ req })
104
104
  ```
105
105
 
106
106
  ## Additional options
@@ -116,8 +116,8 @@ The function receives the context and operationId as arguments, so you can use i
116
116
 
117
117
  ```js
118
118
  onMissingMatch: (context, operationId) => {
119
- myEventPool.add(`Missing match for operation "${operationId}" from agent "${context.req.headers['user-agent']}"`);
120
- };
119
+ myEventPool.add(`Missing match for operation "${operationId}" from agent "${context.req.headers['user-agent']}"`)
120
+ }
121
121
  ```
122
122
 
123
123
  ## With Relay
package/cjs/index.js ADDED
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./types.js"), exports);
5
+ tslib_1.__exportStar(require("./utils.js"), exports);
6
+ tslib_1.__exportStar(require("./stores/aggregated-store.js"), exports);
7
+ tslib_1.__exportStar(require("./stores/inmemory-store.js"), exports);
8
+ tslib_1.__exportStar(require("./stores/json-file-store.js"), exports);
9
+ tslib_1.__exportStar(require("./plugin.js"), exports);
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
package/cjs/plugin.js ADDED
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.usePersistedOperations = exports.readOperationId = void 0;
4
+ const graphql_1 = require("@graphql-tools/graphql");
5
+ const utils_js_1 = require("./utils.js");
6
+ const DEFAULT_OPTIONS = {
7
+ onlyPersisted: false,
8
+ };
9
+ const contextProperty = Symbol('persistedOperationId');
10
+ function readOperationId(context) {
11
+ return context[contextProperty];
12
+ }
13
+ exports.readOperationId = readOperationId;
14
+ const usePersistedOperations = (rawOptions) => {
15
+ const options = {
16
+ ...DEFAULT_OPTIONS,
17
+ ...rawOptions,
18
+ };
19
+ return {
20
+ onParse({ context, params, extendContext, setParsedDocument }) {
21
+ const operationId = options.extractOperationId
22
+ ? options.extractOperationId(context)
23
+ : (0, utils_js_1.operationIdFromSource)(params.source);
24
+ if (!operationId) {
25
+ if (options.onlyPersisted) {
26
+ throw new graphql_1.GraphQLError('Must provide operation id');
27
+ }
28
+ return;
29
+ }
30
+ const store = typeof options.store === 'function' ? options.store(context) : options.store;
31
+ if (!store) {
32
+ throw new graphql_1.GraphQLError('Must provide store for persisted-operations!');
33
+ }
34
+ const rawResult = store.get(operationId);
35
+ if (rawResult) {
36
+ const document = typeof rawResult === 'string' ? (0, graphql_1.parse)(rawResult) : rawResult;
37
+ extendContext({ [contextProperty]: operationId });
38
+ setParsedDocument(document);
39
+ return;
40
+ }
41
+ if (options.onMissingMatch)
42
+ options.onMissingMatch(context, operationId);
43
+ if (options.onlyPersisted) {
44
+ // we want to throw an error only when "onlyPersisted" is true, otherwise we let execution continue normally
45
+ throw new graphql_1.GraphQLError(`Unable to match operation with id '${operationId}'`);
46
+ }
47
+ // if we reach this stage we could not retrieve a persisted operation and we didn't throw any error as onlyPersisted is false
48
+ // hence we let operation continue assuming consumer is not passing an operation id, but a plain query string, with current request.
49
+ },
50
+ };
51
+ };
52
+ exports.usePersistedOperations = usePersistedOperations;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AggregatedStore = void 0;
4
+ class AggregatedStore {
5
+ constructor(stores) {
6
+ this.stores = stores;
7
+ }
8
+ get(operationId) {
9
+ for (const store of this.stores) {
10
+ const item = store.get(operationId);
11
+ if (item) {
12
+ return item;
13
+ }
14
+ }
15
+ return undefined;
16
+ }
17
+ }
18
+ exports.AggregatedStore = AggregatedStore;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InMemoryStore = void 0;
4
+ class InMemoryStore {
5
+ constructor(options) {
6
+ var _a;
7
+ this.storeData = (_a = options === null || options === void 0 ? void 0 : options.initialData) !== null && _a !== void 0 ? _a : new Map();
8
+ }
9
+ get(operationId) {
10
+ return this.storeData.get(operationId) || undefined;
11
+ }
12
+ prime(operationId, document) {
13
+ this.storeData.set(operationId, document);
14
+ }
15
+ clear(operationId) {
16
+ this.storeData.delete(operationId);
17
+ }
18
+ }
19
+ exports.InMemoryStore = InMemoryStore;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JsonFileStore = void 0;
4
+ const fs_1 = require("fs");
5
+ class JsonFileStore {
6
+ constructor() {
7
+ this.storeData = null;
8
+ }
9
+ get(operationId) {
10
+ if (!this.storeData) {
11
+ return undefined;
12
+ }
13
+ return this.storeData.get(operationId) || undefined;
14
+ }
15
+ loadFromFileSync(path) {
16
+ const data = JSON.parse((0, fs_1.readFileSync)(path, 'utf-8'));
17
+ this.storeData = new Map(Object.entries(data));
18
+ }
19
+ async loadFromFile(path) {
20
+ const data = JSON.parse(await fs_1.promises.readFile(path, 'utf-8'));
21
+ this.storeData = new Map(Object.entries(data));
22
+ }
23
+ }
24
+ exports.JsonFileStore = JsonFileStore;
package/cjs/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/cjs/utils.js ADDED
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.operationIdFromSource = void 0;
4
+ function operationIdFromSource(source) {
5
+ return typeof source === 'string' && source.length && source.indexOf('{') === -1 ? source : undefined;
6
+ }
7
+ exports.operationIdFromSource = operationIdFromSource;
package/esm/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export * from './types.js';
2
+ export * from './utils.js';
3
+ export * from './stores/aggregated-store.js';
4
+ export * from './stores/inmemory-store.js';
5
+ export * from './stores/json-file-store.js';
6
+ export * from './plugin.js';
package/esm/plugin.js ADDED
@@ -0,0 +1,47 @@
1
+ import { GraphQLError, parse } from '@graphql-tools/graphql';
2
+ import { operationIdFromSource } from './utils.js';
3
+ const DEFAULT_OPTIONS = {
4
+ onlyPersisted: false,
5
+ };
6
+ const contextProperty = Symbol('persistedOperationId');
7
+ export function readOperationId(context) {
8
+ return context[contextProperty];
9
+ }
10
+ export const usePersistedOperations = (rawOptions) => {
11
+ const options = {
12
+ ...DEFAULT_OPTIONS,
13
+ ...rawOptions,
14
+ };
15
+ return {
16
+ onParse({ context, params, extendContext, setParsedDocument }) {
17
+ const operationId = options.extractOperationId
18
+ ? options.extractOperationId(context)
19
+ : operationIdFromSource(params.source);
20
+ if (!operationId) {
21
+ if (options.onlyPersisted) {
22
+ throw new GraphQLError('Must provide operation id');
23
+ }
24
+ return;
25
+ }
26
+ const store = typeof options.store === 'function' ? options.store(context) : options.store;
27
+ if (!store) {
28
+ throw new GraphQLError('Must provide store for persisted-operations!');
29
+ }
30
+ const rawResult = store.get(operationId);
31
+ if (rawResult) {
32
+ const document = typeof rawResult === 'string' ? parse(rawResult) : rawResult;
33
+ extendContext({ [contextProperty]: operationId });
34
+ setParsedDocument(document);
35
+ return;
36
+ }
37
+ if (options.onMissingMatch)
38
+ options.onMissingMatch(context, operationId);
39
+ if (options.onlyPersisted) {
40
+ // we want to throw an error only when "onlyPersisted" is true, otherwise we let execution continue normally
41
+ throw new GraphQLError(`Unable to match operation with id '${operationId}'`);
42
+ }
43
+ // if we reach this stage we could not retrieve a persisted operation and we didn't throw any error as onlyPersisted is false
44
+ // hence we let operation continue assuming consumer is not passing an operation id, but a plain query string, with current request.
45
+ },
46
+ };
47
+ };
@@ -0,0 +1,14 @@
1
+ export class AggregatedStore {
2
+ constructor(stores) {
3
+ this.stores = stores;
4
+ }
5
+ get(operationId) {
6
+ for (const store of this.stores) {
7
+ const item = store.get(operationId);
8
+ if (item) {
9
+ return item;
10
+ }
11
+ }
12
+ return undefined;
13
+ }
14
+ }
@@ -0,0 +1,15 @@
1
+ export class InMemoryStore {
2
+ constructor(options) {
3
+ var _a;
4
+ this.storeData = (_a = options === null || options === void 0 ? void 0 : options.initialData) !== null && _a !== void 0 ? _a : new Map();
5
+ }
6
+ get(operationId) {
7
+ return this.storeData.get(operationId) || undefined;
8
+ }
9
+ prime(operationId, document) {
10
+ this.storeData.set(operationId, document);
11
+ }
12
+ clear(operationId) {
13
+ this.storeData.delete(operationId);
14
+ }
15
+ }
@@ -0,0 +1,20 @@
1
+ import { readFileSync, promises } from 'fs';
2
+ export class JsonFileStore {
3
+ constructor() {
4
+ this.storeData = null;
5
+ }
6
+ get(operationId) {
7
+ if (!this.storeData) {
8
+ return undefined;
9
+ }
10
+ return this.storeData.get(operationId) || undefined;
11
+ }
12
+ loadFromFileSync(path) {
13
+ const data = JSON.parse(readFileSync(path, 'utf-8'));
14
+ this.storeData = new Map(Object.entries(data));
15
+ }
16
+ async loadFromFile(path) {
17
+ const data = JSON.parse(await promises.readFile(path, 'utf-8'));
18
+ this.storeData = new Map(Object.entries(data));
19
+ }
20
+ }
package/esm/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/esm/utils.js ADDED
@@ -0,0 +1,3 @@
1
+ export function operationIdFromSource(source) {
2
+ return typeof source === 'string' && source.length && source.indexOf('{') === -1 ? source : undefined;
3
+ }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@envelop/persisted-operations",
3
- "version": "5.0.0-alpha-d0d0776.0",
3
+ "version": "5.0.0-alpha-5b6bfa8.0",
4
4
  "sideEffects": false,
5
5
  "peerDependencies": {
6
- "@envelop/core": "3.0.0-alpha-d0d0776.0",
7
- "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0"
6
+ "@envelop/core": "3.0.0-alpha-5b6bfa8.0",
7
+ "@graphql-tools/graphql": "0.1.0-alpha-33fb2950.0"
8
8
  },
9
9
  "repository": {
10
10
  "type": "git",
@@ -13,33 +13,42 @@
13
13
  },
14
14
  "author": "Dotan Simha <dotansimha@gmail.com>",
15
15
  "license": "MIT",
16
- "main": "index.js",
17
- "module": "index.mjs",
18
- "typings": "index.d.ts",
16
+ "main": "cjs/index.js",
17
+ "module": "esm/index.js",
18
+ "typings": "typings/index.d.ts",
19
19
  "typescript": {
20
- "definition": "index.d.ts"
20
+ "definition": "typings/index.d.ts"
21
21
  },
22
+ "type": "module",
22
23
  "exports": {
23
24
  ".": {
24
25
  "require": {
25
- "default": "./index.js",
26
- "types": "./index.d.ts"
26
+ "types": "./typings/index.d.ts",
27
+ "default": "./cjs/index.js"
27
28
  },
28
29
  "import": {
29
- "default": "./index.mjs",
30
- "types": "./index.d.ts"
30
+ "types": "./typings/index.d.ts",
31
+ "default": "./esm/index.js"
32
+ },
33
+ "default": {
34
+ "types": "./typings/index.d.ts",
35
+ "default": "./esm/index.js"
31
36
  }
32
37
  },
33
38
  "./*": {
34
39
  "require": {
35
- "default": "./*.js",
36
- "types": "./*.d.ts"
40
+ "types": "./typings/*.d.ts",
41
+ "default": "./cjs/*.js"
37
42
  },
38
43
  "import": {
39
- "default": "./*.mjs",
40
- "types": "./*.d.ts"
44
+ "types": "./typings/*.d.ts",
45
+ "default": "./esm/*.js"
46
+ },
47
+ "default": {
48
+ "types": "./typings/*.d.ts",
49
+ "default": "./esm/*.js"
41
50
  }
42
51
  },
43
52
  "./package.json": "./package.json"
44
53
  }
45
- }
54
+ }
@@ -0,0 +1,6 @@
1
+ export * from './types.js';
2
+ export * from './utils.js';
3
+ export * from './stores/aggregated-store.js';
4
+ export * from './stores/inmemory-store.js';
5
+ export * from './stores/json-file-store.js';
6
+ export * from './plugin.js';
@@ -1,5 +1,5 @@
1
1
  import { Plugin, DefaultContext } from '@envelop/core';
2
- import { PersistedOperationsFunctionStore, PersistedOperationsStore } from './types';
2
+ import { PersistedOperationsFunctionStore, PersistedOperationsStore } from './types.js';
3
3
  export declare type UsePersistedOperationsOptions<ContextType = DefaultContext> = {
4
4
  /**
5
5
  * Set to `false` to allow running operations that are not available in the store.
@@ -1,5 +1,5 @@
1
- import { DocumentNode } from 'graphql';
2
- import { PersistedOperationsStore } from '../types';
1
+ import { DocumentNode } from '@graphql-tools/graphql';
2
+ import { PersistedOperationsStore } from '../types.js';
3
3
  export declare class AggregatedStore implements PersistedOperationsStore {
4
4
  private stores;
5
5
  constructor(stores: PersistedOperationsStore[]);
@@ -1,5 +1,5 @@
1
- import { DocumentNode } from 'graphql';
2
- import { PersistedOperationsStore } from '../types';
1
+ import { DocumentNode } from '@graphql-tools/graphql';
2
+ import { PersistedOperationsStore } from '../types.js';
3
3
  export declare type InMemoryStoreDataMap = Map<string, DocumentNode | string>;
4
4
  export declare class InMemoryStore implements PersistedOperationsStore {
5
5
  private storeData;
@@ -1,5 +1,5 @@
1
- import { DocumentNode } from 'graphql';
2
- import { PersistedOperationsStore } from '../types';
1
+ import { DocumentNode } from '@graphql-tools/graphql';
2
+ import { PersistedOperationsStore } from '../types.js';
3
3
  export declare type JsonFileStoreDataMap = Map<string, DocumentNode | string>;
4
4
  export declare class JsonFileStore implements PersistedOperationsStore {
5
5
  private storeData;
@@ -1,5 +1,5 @@
1
1
  import { DefaultContext } from '@envelop/core';
2
- import { DocumentNode } from 'graphql';
2
+ import { DocumentNode } from '@graphql-tools/graphql';
3
3
  export interface PersistedOperationsStore {
4
4
  /**
5
5
  * Transfroms a hash/id into a DocumentNode or SDL string.
@@ -1,2 +1,2 @@
1
- import { Source } from 'graphql';
1
+ import { Source } from '@graphql-tools/graphql';
2
2
  export declare function operationIdFromSource(source: string | Source): string | undefined;
package/index.d.ts DELETED
@@ -1,6 +0,0 @@
1
- export * from './types';
2
- export * from './utils';
3
- export * from './stores/aggregated-store';
4
- export * from './stores/inmemory-store';
5
- export * from './stores/json-file-store';
6
- export * from './plugin';
package/index.js DELETED
@@ -1,111 +0,0 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- const fs = require('fs');
6
- const graphql = require('graphql');
7
-
8
- function operationIdFromSource(source) {
9
- return typeof source === 'string' && source.length && source.indexOf('{') === -1 ? source : undefined;
10
- }
11
-
12
- class AggregatedStore {
13
- constructor(stores) {
14
- this.stores = stores;
15
- }
16
- get(operationId) {
17
- for (const store of this.stores) {
18
- const item = store.get(operationId);
19
- if (item) {
20
- return item;
21
- }
22
- }
23
- return undefined;
24
- }
25
- }
26
-
27
- class InMemoryStore {
28
- constructor(options) {
29
- this.storeData = options?.initialData ?? new Map();
30
- }
31
- get(operationId) {
32
- return this.storeData.get(operationId) || undefined;
33
- }
34
- prime(operationId, document) {
35
- this.storeData.set(operationId, document);
36
- }
37
- clear(operationId) {
38
- this.storeData.delete(operationId);
39
- }
40
- }
41
-
42
- class JsonFileStore {
43
- constructor() {
44
- this.storeData = null;
45
- }
46
- get(operationId) {
47
- if (!this.storeData) {
48
- return undefined;
49
- }
50
- return this.storeData.get(operationId) || undefined;
51
- }
52
- loadFromFileSync(path) {
53
- const data = JSON.parse(fs.readFileSync(path, 'utf-8'));
54
- this.storeData = new Map(Object.entries(data));
55
- }
56
- async loadFromFile(path) {
57
- const data = JSON.parse(await fs.promises.readFile(path, 'utf-8'));
58
- this.storeData = new Map(Object.entries(data));
59
- }
60
- }
61
-
62
- const DEFAULT_OPTIONS = {
63
- onlyPersisted: false,
64
- };
65
- const contextProperty = Symbol('persistedOperationId');
66
- function readOperationId(context) {
67
- return context[contextProperty];
68
- }
69
- const usePersistedOperations = (rawOptions) => {
70
- const options = {
71
- ...DEFAULT_OPTIONS,
72
- ...(rawOptions || {}),
73
- };
74
- return {
75
- onParse({ context, params, extendContext, setParsedDocument }) {
76
- const operationId = options.extractOperationId ? options.extractOperationId(context) : operationIdFromSource(params.source);
77
- if (!operationId) {
78
- if (options.onlyPersisted) {
79
- throw new graphql.GraphQLError('Must provide operation id');
80
- }
81
- return;
82
- }
83
- const store = typeof options.store === 'function' ? options.store(context) : options.store;
84
- if (!store) {
85
- throw new graphql.GraphQLError('Must provide store for persisted-operations!');
86
- }
87
- const rawResult = store.get(operationId);
88
- if (rawResult) {
89
- const document = typeof rawResult === 'string' ? graphql.parse(rawResult) : rawResult;
90
- extendContext({ [contextProperty]: operationId });
91
- setParsedDocument(document);
92
- return;
93
- }
94
- if (options.onMissingMatch)
95
- options.onMissingMatch(context, operationId);
96
- if (options.onlyPersisted) {
97
- // we want to throw an error only when "onlyPersisted" is true, otherwise we let execution continue normally
98
- throw new graphql.GraphQLError(`Unable to match operation with id '${operationId}'`);
99
- }
100
- // if we reach this stage we could not retrieve a persisted operation and we didn't throw any error as onlyPersisted is false
101
- // hence we let operation continue assuming consumer is not passing an operation id, but a plain query string, with current request.
102
- },
103
- };
104
- };
105
-
106
- exports.AggregatedStore = AggregatedStore;
107
- exports.InMemoryStore = InMemoryStore;
108
- exports.JsonFileStore = JsonFileStore;
109
- exports.operationIdFromSource = operationIdFromSource;
110
- exports.readOperationId = readOperationId;
111
- exports.usePersistedOperations = usePersistedOperations;
package/index.mjs DELETED
@@ -1,102 +0,0 @@
1
- import { readFileSync, promises } from 'fs';
2
- import { GraphQLError, parse } from 'graphql';
3
-
4
- function operationIdFromSource(source) {
5
- return typeof source === 'string' && source.length && source.indexOf('{') === -1 ? source : undefined;
6
- }
7
-
8
- class AggregatedStore {
9
- constructor(stores) {
10
- this.stores = stores;
11
- }
12
- get(operationId) {
13
- for (const store of this.stores) {
14
- const item = store.get(operationId);
15
- if (item) {
16
- return item;
17
- }
18
- }
19
- return undefined;
20
- }
21
- }
22
-
23
- class InMemoryStore {
24
- constructor(options) {
25
- this.storeData = options?.initialData ?? new Map();
26
- }
27
- get(operationId) {
28
- return this.storeData.get(operationId) || undefined;
29
- }
30
- prime(operationId, document) {
31
- this.storeData.set(operationId, document);
32
- }
33
- clear(operationId) {
34
- this.storeData.delete(operationId);
35
- }
36
- }
37
-
38
- class JsonFileStore {
39
- constructor() {
40
- this.storeData = null;
41
- }
42
- get(operationId) {
43
- if (!this.storeData) {
44
- return undefined;
45
- }
46
- return this.storeData.get(operationId) || undefined;
47
- }
48
- loadFromFileSync(path) {
49
- const data = JSON.parse(readFileSync(path, 'utf-8'));
50
- this.storeData = new Map(Object.entries(data));
51
- }
52
- async loadFromFile(path) {
53
- const data = JSON.parse(await promises.readFile(path, 'utf-8'));
54
- this.storeData = new Map(Object.entries(data));
55
- }
56
- }
57
-
58
- const DEFAULT_OPTIONS = {
59
- onlyPersisted: false,
60
- };
61
- const contextProperty = Symbol('persistedOperationId');
62
- function readOperationId(context) {
63
- return context[contextProperty];
64
- }
65
- const usePersistedOperations = (rawOptions) => {
66
- const options = {
67
- ...DEFAULT_OPTIONS,
68
- ...(rawOptions || {}),
69
- };
70
- return {
71
- onParse({ context, params, extendContext, setParsedDocument }) {
72
- const operationId = options.extractOperationId ? options.extractOperationId(context) : operationIdFromSource(params.source);
73
- if (!operationId) {
74
- if (options.onlyPersisted) {
75
- throw new GraphQLError('Must provide operation id');
76
- }
77
- return;
78
- }
79
- const store = typeof options.store === 'function' ? options.store(context) : options.store;
80
- if (!store) {
81
- throw new GraphQLError('Must provide store for persisted-operations!');
82
- }
83
- const rawResult = store.get(operationId);
84
- if (rawResult) {
85
- const document = typeof rawResult === 'string' ? parse(rawResult) : rawResult;
86
- extendContext({ [contextProperty]: operationId });
87
- setParsedDocument(document);
88
- return;
89
- }
90
- if (options.onMissingMatch)
91
- options.onMissingMatch(context, operationId);
92
- if (options.onlyPersisted) {
93
- // we want to throw an error only when "onlyPersisted" is true, otherwise we let execution continue normally
94
- throw new GraphQLError(`Unable to match operation with id '${operationId}'`);
95
- }
96
- // if we reach this stage we could not retrieve a persisted operation and we didn't throw any error as onlyPersisted is false
97
- // hence we let operation continue assuming consumer is not passing an operation id, but a plain query string, with current request.
98
- },
99
- };
100
- };
101
-
102
- export { AggregatedStore, InMemoryStore, JsonFileStore, operationIdFromSource, readOperationId, usePersistedOperations };