graphql-modules 2.4.0 → 2.4.1-alpha-20241223144441-674927c3a29a8c57bbdad7eb31576cb88178f815

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.
@@ -3,7 +3,10 @@ import { ResolvedProvider } from '../di/resolution';
3
3
  import type { InternalAppContext, ModulesMap } from './application';
4
4
  export type ExecutionContextBuilder<TContext extends {
5
5
  [key: string]: any;
6
- } = {}> = (context: TContext) => {
6
+ } = {}> = (context: TContext) => ExecutionContextEnv & {
7
+ runWithContext<TReturn = any>(cb: (env: ExecutionContextEnv) => TReturn): TReturn;
8
+ };
9
+ export type ExecutionContextEnv = {
7
10
  context: InternalAppContext;
8
11
  ɵdestroy(): void;
9
12
  ɵinjector: Injector;
package/index.js CHANGED
@@ -4,6 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  const schema = require('@graphql-tools/schema');
6
6
  const graphql = require('graphql');
7
+ const async_hooks = require('async_hooks');
7
8
  const wrap = require('@graphql-tools/wrap');
8
9
  const ramda = require('ramda');
9
10
 
@@ -854,6 +855,7 @@ function duplicatedGlobalTokenError(provider, modules) {
854
855
  */
855
856
  const CONTEXT = new InjectionToken('context');
856
857
 
858
+ const alc = new async_hooks.AsyncLocalStorage();
857
859
  function createContextBuilder({ appInjector, modulesMap, appLevelOperationProviders, singletonGlobalProvidersMap, operationGlobalProvidersMap, }) {
858
860
  // This is very critical. It creates an execution context.
859
861
  // It has to run on every operation.
@@ -882,11 +884,14 @@ function createContextBuilder({ appInjector, modulesMap, appLevelOperationProvid
882
884
  },
883
885
  });
884
886
  appInjector.setExecutionContextGetter(function executionContextGetter() {
885
- return appContext;
887
+ var _a;
888
+ return ((_a = alc.getStore()) === null || _a === void 0 ? void 0 : _a.getApplicationContext()) || appContext;
886
889
  });
887
890
  function createModuleExecutionContextGetter(moduleId) {
888
891
  return function moduleExecutionContextGetter() {
889
- return getModuleContext(moduleId, context);
892
+ var _a;
893
+ return (((_a = alc.getStore()) === null || _a === void 0 ? void 0 : _a.getModuleContext(moduleId)) ||
894
+ getModuleContext(moduleId, context));
890
895
  };
891
896
  }
892
897
  modulesMap.forEach((mod, moduleId) => {
@@ -956,7 +961,7 @@ function createContextBuilder({ appInjector, modulesMap, appLevelOperationProvid
956
961
  return getModuleContext(moduleId, sharedContext).injector;
957
962
  },
958
963
  });
959
- return {
964
+ const env = {
960
965
  ɵdestroy: once(() => {
961
966
  providersToDestroy.forEach(([injector, keyId]) => {
962
967
  // If provider was instantiated
@@ -970,6 +975,19 @@ function createContextBuilder({ appInjector, modulesMap, appLevelOperationProvid
970
975
  ɵinjector: operationAppInjector,
971
976
  context: sharedContext,
972
977
  };
978
+ return {
979
+ ...env,
980
+ runWithContext(cb) {
981
+ return alc.run({
982
+ getApplicationContext() {
983
+ return appContext;
984
+ },
985
+ getModuleContext(moduleId) {
986
+ return getModuleContext(moduleId, context);
987
+ },
988
+ }, () => cb(env));
989
+ },
990
+ };
973
991
  };
974
992
  return contextBuilder;
975
993
  }
@@ -979,31 +997,34 @@ function executionCreator({ contextBuilder, }) {
979
997
  // Custom or original execute function
980
998
  const executeFn = (options === null || options === void 0 ? void 0 : options.execute) || graphql.execute;
981
999
  return (argsOrSchema, document, rootValue, contextValue, variableValues, operationName, fieldResolver, typeResolver) => {
982
- var _a;
983
- // Create an execution context
984
- const { context, ɵdestroy: destroy } = (_a = options === null || options === void 0 ? void 0 : options.controller) !== null && _a !== void 0 ? _a : contextBuilder(isNotSchema(argsOrSchema)
1000
+ function perform({ context, ɵdestroy: destroy, }) {
1001
+ const executionArgs = isNotSchema(argsOrSchema)
1002
+ ? {
1003
+ ...argsOrSchema,
1004
+ contextValue: context,
1005
+ }
1006
+ : {
1007
+ schema: argsOrSchema,
1008
+ document: document,
1009
+ rootValue,
1010
+ contextValue: context,
1011
+ variableValues,
1012
+ operationName,
1013
+ fieldResolver,
1014
+ typeResolver,
1015
+ };
1016
+ // It's important to wrap the executeFn within a promise
1017
+ // so we can easily control the end of execution (with finally)
1018
+ return Promise.resolve()
1019
+ .then(() => executeFn(executionArgs))
1020
+ .finally(destroy);
1021
+ }
1022
+ if (options === null || options === void 0 ? void 0 : options.controller) {
1023
+ return perform(options.controller);
1024
+ }
1025
+ return contextBuilder(isNotSchema(argsOrSchema)
985
1026
  ? argsOrSchema.contextValue
986
- : contextValue);
987
- const executionArgs = isNotSchema(argsOrSchema)
988
- ? {
989
- ...argsOrSchema,
990
- contextValue: context,
991
- }
992
- : {
993
- schema: argsOrSchema,
994
- document: document,
995
- rootValue,
996
- contextValue: context,
997
- variableValues,
998
- operationName,
999
- fieldResolver,
1000
- typeResolver,
1001
- };
1002
- // It's important to wrap the executeFn within a promise
1003
- // so we can easily control the end of execution (with finally)
1004
- return Promise.resolve()
1005
- .then(() => executeFn(executionArgs))
1006
- .finally(destroy);
1027
+ : contextValue).runWithContext(perform);
1007
1028
  };
1008
1029
  };
1009
1030
  return createExecution;
@@ -1014,43 +1035,46 @@ function subscriptionCreator({ contextBuilder, }) {
1014
1035
  // Custom or original subscribe function
1015
1036
  const subscribeFn = (options === null || options === void 0 ? void 0 : options.subscribe) || graphql.subscribe;
1016
1037
  return (argsOrSchema, document, rootValue, contextValue, variableValues, operationName, fieldResolver, subscribeFieldResolver) => {
1017
- var _a;
1018
- // Create an subscription context
1019
- const { context, ɵdestroy: destroy } = (_a = options === null || options === void 0 ? void 0 : options.controller) !== null && _a !== void 0 ? _a : contextBuilder(isNotSchema(argsOrSchema)
1038
+ function perform({ context, ɵdestroy: destroy, }) {
1039
+ const subscriptionArgs = isNotSchema(argsOrSchema)
1040
+ ? {
1041
+ ...argsOrSchema,
1042
+ contextValue: context,
1043
+ }
1044
+ : {
1045
+ schema: argsOrSchema,
1046
+ document: document,
1047
+ rootValue,
1048
+ contextValue: context,
1049
+ variableValues,
1050
+ operationName,
1051
+ fieldResolver,
1052
+ subscribeFieldResolver,
1053
+ };
1054
+ let isIterable = false;
1055
+ // It's important to wrap the subscribeFn within a promise
1056
+ // so we can easily control the end of subscription (with finally)
1057
+ return Promise.resolve()
1058
+ .then(() => subscribeFn(subscriptionArgs))
1059
+ .then((sub) => {
1060
+ if (isAsyncIterable(sub)) {
1061
+ isIterable = true;
1062
+ return tapAsyncIterator(sub, destroy);
1063
+ }
1064
+ return sub;
1065
+ })
1066
+ .finally(() => {
1067
+ if (!isIterable) {
1068
+ destroy();
1069
+ }
1070
+ });
1071
+ }
1072
+ if (options === null || options === void 0 ? void 0 : options.controller) {
1073
+ return perform(options.controller);
1074
+ }
1075
+ return contextBuilder(isNotSchema(argsOrSchema)
1020
1076
  ? argsOrSchema.contextValue
1021
- : contextValue);
1022
- const subscriptionArgs = isNotSchema(argsOrSchema)
1023
- ? {
1024
- ...argsOrSchema,
1025
- contextValue: context,
1026
- }
1027
- : {
1028
- schema: argsOrSchema,
1029
- document: document,
1030
- rootValue,
1031
- contextValue: context,
1032
- variableValues,
1033
- operationName,
1034
- fieldResolver,
1035
- subscribeFieldResolver,
1036
- };
1037
- let isIterable = false;
1038
- // It's important to wrap the subscribeFn within a promise
1039
- // so we can easily control the end of subscription (with finally)
1040
- return Promise.resolve()
1041
- .then(() => subscribeFn(subscriptionArgs))
1042
- .then((sub) => {
1043
- if (isAsyncIterable(sub)) {
1044
- isIterable = true;
1045
- return tapAsyncIterator(sub, destroy);
1046
- }
1047
- return sub;
1048
- })
1049
- .finally(() => {
1050
- if (!isIterable) {
1051
- destroy();
1052
- }
1053
- });
1077
+ : contextValue).runWithContext(perform);
1054
1078
  };
1055
1079
  };
1056
1080
  return createSubscription;
@@ -1075,10 +1099,9 @@ function apolloSchemaCreator({ createSubscription, contextBuilder, schema, }) {
1075
1099
  const createApolloSchema = () => {
1076
1100
  const sessions = {};
1077
1101
  const subscription = createSubscription();
1078
- function getSession(ctx) {
1102
+ function getSession(ctx, { context, ɵdestroy: destroy }) {
1079
1103
  if (!ctx[CONTEXT_ID]) {
1080
1104
  ctx[CONTEXT_ID] = uniqueId((id) => !sessions[id]);
1081
- const { context, ɵdestroy: destroy } = contextBuilder(ctx);
1082
1105
  sessions[ctx[CONTEXT_ID]] = {
1083
1106
  count: 0,
1084
1107
  session: {
@@ -1110,20 +1133,22 @@ function apolloSchemaCreator({ createSubscription, contextBuilder, schema, }) {
1110
1133
  operationName: input.operationName,
1111
1134
  });
1112
1135
  }
1113
- // Create an execution context
1114
- const { context, destroy } = getSession(input.context);
1115
- // It's important to wrap the executeFn within a promise
1116
- // so we can easily control the end of execution (with finally)
1117
- return Promise.resolve()
1118
- .then(() => graphql.execute({
1119
- schema,
1120
- document: input.document,
1121
- contextValue: context,
1122
- variableValues: input.variables,
1123
- rootValue: input.rootValue,
1124
- operationName: input.operationName,
1125
- }))
1126
- .finally(destroy);
1136
+ // Create an execution context and run within it
1137
+ return contextBuilder(input.context).runWithContext((env) => {
1138
+ const { context, destroy } = getSession(input.context, env);
1139
+ // It's important to wrap the executeFn within a promise
1140
+ // so we can easily control the end of execution (with finally)
1141
+ return Promise.resolve()
1142
+ .then(() => graphql.execute({
1143
+ schema,
1144
+ document: input.document,
1145
+ contextValue: context,
1146
+ variableValues: input.variables,
1147
+ rootValue: input.rootValue,
1148
+ operationName: input.operationName,
1149
+ }))
1150
+ .finally(destroy);
1151
+ });
1127
1152
  },
1128
1153
  });
1129
1154
  };
package/index.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  import { makeExecutableSchema } from '@graphql-tools/schema';
2
2
  import { GraphQLSchema, execute as execute$1, subscribe, visit, Kind, GraphQLScalarType, concatAST, defaultFieldResolver, parse } from 'graphql';
3
+ import { AsyncLocalStorage } from 'async_hooks';
3
4
  import { wrapSchema } from '@graphql-tools/wrap';
4
5
  import { mergeDeepWith } from 'ramda';
5
6
 
@@ -851,6 +852,7 @@ function duplicatedGlobalTokenError(provider, modules) {
851
852
  */
852
853
  const CONTEXT = new InjectionToken('context');
853
854
 
855
+ const alc = new AsyncLocalStorage();
854
856
  function createContextBuilder({ appInjector, modulesMap, appLevelOperationProviders, singletonGlobalProvidersMap, operationGlobalProvidersMap, }) {
855
857
  // This is very critical. It creates an execution context.
856
858
  // It has to run on every operation.
@@ -879,11 +881,14 @@ function createContextBuilder({ appInjector, modulesMap, appLevelOperationProvid
879
881
  },
880
882
  });
881
883
  appInjector.setExecutionContextGetter(function executionContextGetter() {
882
- return appContext;
884
+ var _a;
885
+ return ((_a = alc.getStore()) === null || _a === void 0 ? void 0 : _a.getApplicationContext()) || appContext;
883
886
  });
884
887
  function createModuleExecutionContextGetter(moduleId) {
885
888
  return function moduleExecutionContextGetter() {
886
- return getModuleContext(moduleId, context);
889
+ var _a;
890
+ return (((_a = alc.getStore()) === null || _a === void 0 ? void 0 : _a.getModuleContext(moduleId)) ||
891
+ getModuleContext(moduleId, context));
887
892
  };
888
893
  }
889
894
  modulesMap.forEach((mod, moduleId) => {
@@ -953,7 +958,7 @@ function createContextBuilder({ appInjector, modulesMap, appLevelOperationProvid
953
958
  return getModuleContext(moduleId, sharedContext).injector;
954
959
  },
955
960
  });
956
- return {
961
+ const env = {
957
962
  ɵdestroy: once(() => {
958
963
  providersToDestroy.forEach(([injector, keyId]) => {
959
964
  // If provider was instantiated
@@ -967,6 +972,19 @@ function createContextBuilder({ appInjector, modulesMap, appLevelOperationProvid
967
972
  ɵinjector: operationAppInjector,
968
973
  context: sharedContext,
969
974
  };
975
+ return {
976
+ ...env,
977
+ runWithContext(cb) {
978
+ return alc.run({
979
+ getApplicationContext() {
980
+ return appContext;
981
+ },
982
+ getModuleContext(moduleId) {
983
+ return getModuleContext(moduleId, context);
984
+ },
985
+ }, () => cb(env));
986
+ },
987
+ };
970
988
  };
971
989
  return contextBuilder;
972
990
  }
@@ -976,31 +994,34 @@ function executionCreator({ contextBuilder, }) {
976
994
  // Custom or original execute function
977
995
  const executeFn = (options === null || options === void 0 ? void 0 : options.execute) || execute$1;
978
996
  return (argsOrSchema, document, rootValue, contextValue, variableValues, operationName, fieldResolver, typeResolver) => {
979
- var _a;
980
- // Create an execution context
981
- const { context, ɵdestroy: destroy } = (_a = options === null || options === void 0 ? void 0 : options.controller) !== null && _a !== void 0 ? _a : contextBuilder(isNotSchema(argsOrSchema)
997
+ function perform({ context, ɵdestroy: destroy, }) {
998
+ const executionArgs = isNotSchema(argsOrSchema)
999
+ ? {
1000
+ ...argsOrSchema,
1001
+ contextValue: context,
1002
+ }
1003
+ : {
1004
+ schema: argsOrSchema,
1005
+ document: document,
1006
+ rootValue,
1007
+ contextValue: context,
1008
+ variableValues,
1009
+ operationName,
1010
+ fieldResolver,
1011
+ typeResolver,
1012
+ };
1013
+ // It's important to wrap the executeFn within a promise
1014
+ // so we can easily control the end of execution (with finally)
1015
+ return Promise.resolve()
1016
+ .then(() => executeFn(executionArgs))
1017
+ .finally(destroy);
1018
+ }
1019
+ if (options === null || options === void 0 ? void 0 : options.controller) {
1020
+ return perform(options.controller);
1021
+ }
1022
+ return contextBuilder(isNotSchema(argsOrSchema)
982
1023
  ? argsOrSchema.contextValue
983
- : contextValue);
984
- const executionArgs = isNotSchema(argsOrSchema)
985
- ? {
986
- ...argsOrSchema,
987
- contextValue: context,
988
- }
989
- : {
990
- schema: argsOrSchema,
991
- document: document,
992
- rootValue,
993
- contextValue: context,
994
- variableValues,
995
- operationName,
996
- fieldResolver,
997
- typeResolver,
998
- };
999
- // It's important to wrap the executeFn within a promise
1000
- // so we can easily control the end of execution (with finally)
1001
- return Promise.resolve()
1002
- .then(() => executeFn(executionArgs))
1003
- .finally(destroy);
1024
+ : contextValue).runWithContext(perform);
1004
1025
  };
1005
1026
  };
1006
1027
  return createExecution;
@@ -1011,43 +1032,46 @@ function subscriptionCreator({ contextBuilder, }) {
1011
1032
  // Custom or original subscribe function
1012
1033
  const subscribeFn = (options === null || options === void 0 ? void 0 : options.subscribe) || subscribe;
1013
1034
  return (argsOrSchema, document, rootValue, contextValue, variableValues, operationName, fieldResolver, subscribeFieldResolver) => {
1014
- var _a;
1015
- // Create an subscription context
1016
- const { context, ɵdestroy: destroy } = (_a = options === null || options === void 0 ? void 0 : options.controller) !== null && _a !== void 0 ? _a : contextBuilder(isNotSchema(argsOrSchema)
1035
+ function perform({ context, ɵdestroy: destroy, }) {
1036
+ const subscriptionArgs = isNotSchema(argsOrSchema)
1037
+ ? {
1038
+ ...argsOrSchema,
1039
+ contextValue: context,
1040
+ }
1041
+ : {
1042
+ schema: argsOrSchema,
1043
+ document: document,
1044
+ rootValue,
1045
+ contextValue: context,
1046
+ variableValues,
1047
+ operationName,
1048
+ fieldResolver,
1049
+ subscribeFieldResolver,
1050
+ };
1051
+ let isIterable = false;
1052
+ // It's important to wrap the subscribeFn within a promise
1053
+ // so we can easily control the end of subscription (with finally)
1054
+ return Promise.resolve()
1055
+ .then(() => subscribeFn(subscriptionArgs))
1056
+ .then((sub) => {
1057
+ if (isAsyncIterable(sub)) {
1058
+ isIterable = true;
1059
+ return tapAsyncIterator(sub, destroy);
1060
+ }
1061
+ return sub;
1062
+ })
1063
+ .finally(() => {
1064
+ if (!isIterable) {
1065
+ destroy();
1066
+ }
1067
+ });
1068
+ }
1069
+ if (options === null || options === void 0 ? void 0 : options.controller) {
1070
+ return perform(options.controller);
1071
+ }
1072
+ return contextBuilder(isNotSchema(argsOrSchema)
1017
1073
  ? argsOrSchema.contextValue
1018
- : contextValue);
1019
- const subscriptionArgs = isNotSchema(argsOrSchema)
1020
- ? {
1021
- ...argsOrSchema,
1022
- contextValue: context,
1023
- }
1024
- : {
1025
- schema: argsOrSchema,
1026
- document: document,
1027
- rootValue,
1028
- contextValue: context,
1029
- variableValues,
1030
- operationName,
1031
- fieldResolver,
1032
- subscribeFieldResolver,
1033
- };
1034
- let isIterable = false;
1035
- // It's important to wrap the subscribeFn within a promise
1036
- // so we can easily control the end of subscription (with finally)
1037
- return Promise.resolve()
1038
- .then(() => subscribeFn(subscriptionArgs))
1039
- .then((sub) => {
1040
- if (isAsyncIterable(sub)) {
1041
- isIterable = true;
1042
- return tapAsyncIterator(sub, destroy);
1043
- }
1044
- return sub;
1045
- })
1046
- .finally(() => {
1047
- if (!isIterable) {
1048
- destroy();
1049
- }
1050
- });
1074
+ : contextValue).runWithContext(perform);
1051
1075
  };
1052
1076
  };
1053
1077
  return createSubscription;
@@ -1072,10 +1096,9 @@ function apolloSchemaCreator({ createSubscription, contextBuilder, schema, }) {
1072
1096
  const createApolloSchema = () => {
1073
1097
  const sessions = {};
1074
1098
  const subscription = createSubscription();
1075
- function getSession(ctx) {
1099
+ function getSession(ctx, { context, ɵdestroy: destroy }) {
1076
1100
  if (!ctx[CONTEXT_ID]) {
1077
1101
  ctx[CONTEXT_ID] = uniqueId((id) => !sessions[id]);
1078
- const { context, ɵdestroy: destroy } = contextBuilder(ctx);
1079
1102
  sessions[ctx[CONTEXT_ID]] = {
1080
1103
  count: 0,
1081
1104
  session: {
@@ -1107,20 +1130,22 @@ function apolloSchemaCreator({ createSubscription, contextBuilder, schema, }) {
1107
1130
  operationName: input.operationName,
1108
1131
  });
1109
1132
  }
1110
- // Create an execution context
1111
- const { context, destroy } = getSession(input.context);
1112
- // It's important to wrap the executeFn within a promise
1113
- // so we can easily control the end of execution (with finally)
1114
- return Promise.resolve()
1115
- .then(() => execute$1({
1116
- schema,
1117
- document: input.document,
1118
- contextValue: context,
1119
- variableValues: input.variables,
1120
- rootValue: input.rootValue,
1121
- operationName: input.operationName,
1122
- }))
1123
- .finally(destroy);
1133
+ // Create an execution context and run within it
1134
+ return contextBuilder(input.context).runWithContext((env) => {
1135
+ const { context, destroy } = getSession(input.context, env);
1136
+ // It's important to wrap the executeFn within a promise
1137
+ // so we can easily control the end of execution (with finally)
1138
+ return Promise.resolve()
1139
+ .then(() => execute$1({
1140
+ schema,
1141
+ document: input.document,
1142
+ contextValue: context,
1143
+ variableValues: input.variables,
1144
+ rootValue: input.rootValue,
1145
+ operationName: input.operationName,
1146
+ }))
1147
+ .finally(destroy);
1148
+ });
1124
1149
  },
1125
1150
  });
1126
1151
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphql-modules",
3
- "version": "2.4.0",
3
+ "version": "2.4.1-alpha-20241223144441-674927c3a29a8c57bbdad7eb31576cb88178f815",
4
4
  "description": "Create reusable, maintainable, testable and extendable GraphQL modules",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {