async function getExtensionModuleField(manifest, fieldType, handlerLink) {
  if (!handlerLink.type) {
    throw new Error(`Missing type!`);
  }
  if (!manifest.modules.fields) {
    throw new Error(`No definition of fields for extension type "${manifest.type}" and key "${manifest.key}"`);
  }
  if (!manifest.modules.fields[fieldType]) {
    throw new Error(`No definition for field type "${fieldType}" on manifest for extension with type "${manifest.type}" and key "${manifest.key}"`);
  }
  const {
    type
  } = handlerLink;
  const handler = manifest.modules.fields[fieldType][type];
  if (!handler) {
    throw new Error(`No handler of type "${type}" for extension type "${manifest.type}" and key "${manifest.key}"`);
  }
  return handler;
}

/** attempt to get the custom resolver for this field, or throw */
export async function getCustomFieldResolver(manifest, handlerLink) {
  const handler = await getExtensionModuleField(manifest, 'custom', handlerLink);
  return handler.resolver;
}

/** attempt to get the serializer for this field, or throw */
export async function getFieldSerializer(manifest, handlerLink) {
  const handler = await getExtensionModuleField(manifest, 'fieldset', handlerLink);
  return handler.serializer;
}

/** attempt to get the deserializer for this field, or throw */
export async function getFieldDeserializer(manifest, handlerLink) {
  const handler = await getExtensionModuleField(manifest, 'fieldset', handlerLink);
  return handler.deserializer;
}

/** attempt to get the user field context provider for this field, or throw */
export async function getUserFieldContextProvider(manifest, handlerLink) {
  const handler = await getExtensionModuleField(manifest, 'user', handlerLink);
  return handler.provider;
}