zod#SuperRefinement TypeScript Examples

The following examples show how to use zod#SuperRefinement. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: config.ts    From airnode with MIT License 6 votes vote down vote up
validateSecuritySchemesReferences: SuperRefinement<{
  ois: OIS[];
  apiCredentials: ApiCredentials[];
}> = (config, ctx) => {
  config.ois.forEach((ois, index) => {
    Object.keys(ois.apiSpecifications.security).forEach((enabledSecuritySchemeName) => {
      const enabledSecurityScheme = ois.apiSpecifications.components.securitySchemes[enabledSecuritySchemeName];
      if (enabledSecurityScheme && ['apiKey', 'http'].includes(enabledSecurityScheme.type)) {
        const securitySchemeApiCredentials = config.apiCredentials.find(
          (apiCredentials) => apiCredentials.securitySchemeName === enabledSecuritySchemeName
        );
        if (!securitySchemeApiCredentials) {
          ctx.addIssue({
            code: z.ZodIssueCode.custom,
            message: `The security scheme is enabled but no credentials are provided in "apiCredentials"`,
            path: ['ois', index, 'apiSpecifications', 'security', enabledSecuritySchemeName],
          });
        }
      }
    });
  });
}
Example #2
Source File: config.ts    From airnode with MIT License 6 votes vote down vote up
validateTemplateSchemes: SuperRefinement<{
  nodeSettings: NodeSettings;
  templates: Template[];
}> = (config, ctx) => {
  if (config.templates) {
    config.templates.forEach((template: any) => {
      // Verify that a V0/RRP templates are valid by hashing the airnodeAddress,
      // endpointId and encodedParameters
      const airnodeAddress = ethers.Wallet.fromMnemonic(config.nodeSettings.airnodeWalletMnemonic).address;
      const derivedTemplateId = ethers.utils.solidityKeccak256(
        ['address', 'bytes32', 'bytes'],
        [airnodeAddress, template.endpointId, template.encodedParameters]
      );
      if (derivedTemplateId !== template.templateId) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: `Template is invalid`,
          path: [template.templateId],
        });
      }
    });
  }
}
Example #3
Source File: config.ts    From airnode with MIT License 6 votes vote down vote up
validateTriggersReferences: SuperRefinement<{
  ois: OIS[];
  triggers: Triggers;
}> = (config, ctx) => {
  forEach(config.triggers, (triggers, triggerSection) => {
    forEach(triggers, (trigger, index) => {
      const { oisTitle, endpointName } = trigger;

      // Check that the OIS with the "oisTitle" from the trigger exists
      const ois = config.ois.find((ois) => ois.title === oisTitle);
      if (!ois) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: `No matching OIS for trigger with OIS title "${oisTitle}"`,
          path: ['triggers', triggerSection, index, 'oisTitle'],
        });

        return;
      }

      // Check that the OIS contains an endpoint from the trigger
      const endpoint = ois.endpoints.find((endpoint) => endpoint.name === endpointName);
      if (!endpoint) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: `No matching endpoint for trigger with endpoint name "${endpointName}"`,
          path: ['triggers', triggerSection, index, 'endpointName'],
        });
      }
    });
  });
}
Example #4
Source File: ois.ts    From airnode with MIT License 6 votes vote down vote up
ensurePathParametersExist: SuperRefinement<Paths> = (paths, ctx) => {
  forEach(paths, (pathData, rawPath) => {
    forEach(pathData, (paramData, httpMethod) => {
      const parameters = paramData!.parameters;
      // Match on anything in the path that is braces
      // i.e. The path /users/{id}/{action} will match ['{id}', '{action}']
      const regex = /\{([^}]+)\}/g;
      const matches = rawPath.match(regex)?.map(removeBraces) ?? [];

      // Check that all path parameters are defined
      matches.forEach((match) => {
        const parameter = parameters.find((p) => p.in === 'path' && p.name === match);
        if (!parameter) {
          ctx.addIssue({
            code: z.ZodIssueCode.custom,
            message: `Path parameter "${match}" is not found in "parameters"`,
            path: [rawPath, httpMethod, 'parameters'],
          });
        }
      }, rawPath);

      // Check that all parameters are used
      parameters.forEach((p, index) => {
        if (p.in === 'path' && !matches.includes(p.name)) {
          ctx.addIssue({
            code: z.ZodIssueCode.custom,
            message: `Parameter "${p.name}" is not found in the URL path`,
            path: [rawPath, httpMethod, 'parameters', index],
          });
        }
      });
    });
  });
}
Example #5
Source File: ois.ts    From airnode with MIT License 5 votes vote down vote up
ensureSingleParameterUsagePerEndpoint: SuperRefinement<{
  endpoints: Endpoint[];
}> = (ois, ctx) => {
  ois.endpoints.forEach((endpoint, oisIndex) => {
    const params = endpoint.parameters.map((p) => p.operationParameter);
    const fixedParams = endpoint.fixedOperationParameters.map((p) => p.operationParameter);
    const checkUniqueness = (section: 'parameters' | 'fixedOperationParameters') => {
      const paramsToCheck = section === 'parameters' ? params : fixedParams;
      paramsToCheck.forEach((param, paramIndex) => {
        const count = paramsToCheck.filter((p) => p.in === param.in && p.name === param.name).length;
        if (count > 1) {
          ctx.addIssue({
            code: z.ZodIssueCode.custom,
            message: `Parameter "${param.name}" in "${param.in}" is used multiple times`,
            path: ['ois', 'endpoints', oisIndex, section, paramIndex],
          });
        }
      });
    };

    // Check uniqueness in the respective sections
    checkUniqueness('parameters');
    checkUniqueness('fixedOperationParameters');

    // Check uniqueness across "parameters" and "fixedOperationParameters"
    params.forEach((param, paramIndex) => {
      const fixedParam = fixedParams.find((p) => p.in === param.in && p.name === param.name);
      if (fixedParam) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: `Parameter "${param.name}" in "${param.in}" is used in both "parameters" and "fixedOperationParameters"`,
          path: ['ois', 'endpoints', oisIndex, 'parameters', paramIndex],
        });

        // Add also an issue for the fixed parameter. This makes it easier for the user to find the offending parameter
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: `Parameter "${param.name}" in "${param.in}" is used in both "parameters" and "fixedOperationParameters"`,
          path: ['ois', 'endpoints', oisIndex, 'fixedOperationParameters', fixedParams.indexOf(fixedParam)],
        });
      }
    });
  });
}
Example #6
Source File: ois.ts    From airnode with MIT License 4 votes vote down vote up
ensureEndpointAndApiSpecificationParamsMatch: SuperRefinement<{
  endpoints: Endpoint[];
  apiSpecifications: ApiSpecification;
}> = (ois, ctx) => {
  const { apiSpecifications, endpoints } = ois;

  // Ensure every "apiSpecification.paths" parameter is defined in "endpoints"
  forEach(apiSpecifications.paths, (pathData, rawPath) => {
    forEach(pathData, (paramData, httpMethod) => {
      const apiEndpoints = endpoints.filter(
        ({ operation }) => operation.method === httpMethod && operation.path === rawPath
      );
      if (!apiEndpoints.length) return; // Missing endpoint for apiSpecification should only be a warning

      apiEndpoints.forEach((endpoint) => {
        paramData!.parameters.forEach((apiParam) => {
          const allEndpointParams = [...endpoint.parameters, ...endpoint.fixedOperationParameters];
          const endpointParam = allEndpointParams.find(
            ({ operationParameter }) =>
              operationParameter.in === apiParam.in && operationParameter.name === apiParam.name
          );
          if (!endpointParam) {
            ctx.addIssue({
              code: z.ZodIssueCode.custom,
              message: `Parameter "${apiParam.name}" not found in "fixedOperationParameters" or "parameters"`,
              path: ['ois', 'endpoints', endpoints.indexOf(endpoint)],
            });
          }
        });
      });
    });
  });

  // Ensure every endpoint parameter references parameter from "apiSpecification.paths"
  endpoints.forEach((endpoint, endpointIndex) => {
    const { operation, parameters, fixedOperationParameters } = endpoint;

    const apiSpec = find(apiSpecifications.paths, (pathData, path) => {
      if (operation.path !== path) return false;

      return !!find(pathData, (_, httpMethod) => operation.method === httpMethod);
    });
    if (!apiSpec) {
      return ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: `No matching API specification found in "apiSpecifications" section`,
        path: ['ois', 'endpoints', endpointIndex],
      });
    }

    // Ensure every parameter exist in "apiSpecification"
    parameters.forEach((endpointParam, endpointParamIndex) => {
      const { operationParameter } = endpointParam;
      const apiParam = apiSpec[operation.method]!.parameters.find(
        (p) => p.in === operationParameter.in && p.name === operationParameter.name
      );

      if (!apiParam) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: `No matching API specification parameter found in "apiSpecifications" section`,
          path: ['ois', 'endpoints', endpointIndex, 'parameters', endpointParamIndex],
        });
      }
    });

    // Ensure every fixed parameter exist in "apiSpecification"
    fixedOperationParameters.forEach((endpointParam, endpointParamIndex) => {
      const { operationParameter } = endpointParam;
      const apiParam = apiSpec[operation.method]!.parameters.find(
        (p) => p.in === operationParameter.in && p.name === operationParameter.name
      );

      if (!apiParam) {
        if (!apiParam) {
          ctx.addIssue({
            code: z.ZodIssueCode.custom,
            message: `No matching API specification parameter found in "apiSpecifications" section`,
            path: ['ois', 'endpoints', endpointIndex, 'fixedOperationParameters', endpointParamIndex],
          });
        }
      }
    });
  });
}