npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@uni2c/graphqlapi4mp

v1.0.9

Published

Lightweight GraphQL SDL parser and query builder for TypeScript, Node.js, browsers, and mini programs.

Readme

@uni2c/graphqlapi4mp

一个轻量、零运行时依赖的 GraphQL SDL 解析与查询文本生成工具。它可以从 SDL 中提取 Query、Mutation、对象类型、标量和枚举,并根据配置生成 selection set 与完整的 GraphQL operation。

适合需要在小程序、Node.js 或前端项目中根据既有 GraphQL Schema 动态构造查询,同时希望控制运行时代码体积的场景。

特性

  • 解析 GraphQL SDL 中的 typescalarenum
  • 提取 QueryMutation 根字段及参数类型
  • 自动选择标量和枚举字段
  • 按配置递归展开对象字段
  • 生成 Query 或 Mutation 文本
  • 变量格式化与空值过滤:按 SDL 参数类型自动类型转换(IntFloatBooleanStringJsonString[Type] 等),支持开启/关闭空值('', [], undefined, null)过滤
  • 安全加解密与签名:内置 AES-128-CBC 对称加解密、RSA 非对称公钥加密、MD5 签名与 Base64 编解码,开箱即用兼容微信小程序、uni-app 与 Web 环境
  • 请求参数统一预处理:提供 paramProcess,一键完成变量签名、生产环境数据 AES+RSA 混合加密封装
  • 同时支持 ESM 和 CommonJS
  • 内置 TypeScript 类型声明
  • 零额外网络层包依赖,针对小程序轻量优化

安装

npm install @uni2c/graphqlapi4mp

也可以使用 pnpm 或 yarn:

pnpm add @uni2c/graphqlapi4mp
# 或
yarn add @uni2c/graphqlapi4mp

模块导入

ESM / TypeScript:

import {
  parseSDL,
  buildGraphQLQuery,
  buildSelectionFields,
  formatVariables,
  paramProcess,
  setEnv,
  getSign,
  encodeData,
  decodeData,
  initPassword,
  md5,
  base64encode,
  base64decode,
} from '@uni2c/graphqlapi4mp';

CommonJS:

const {
  parseSDL,
  buildGraphQLQuery,
  buildSelectionFields,
  formatVariables,
  paramProcess,
  setEnv,
  getSign,
  encodeData,
  decodeData,
  initPassword,
  md5,
  base64encode,
  base64decode,
} = require('@uni2c/graphqlapi4mp');

完整示例

假设有以下 SDL:

scalar DateTime

enum UserStatus {
  ACTIVE
  DISABLED
}

type Query {
  user(id: ID!, includeDisabled: Boolean = false): User
}

type User {
  id: ID!
  name: String!
  status: UserStatus!
  createdAt: DateTime!
  profile: Profile
}

type Profile {
  bio: String
  website: String
}

解析 SDL、选择返回字段并生成查询:

import {
  buildGraphQLQuery,
  buildSelectionFields,
  parseSDL,
  type GraphQLOperation,
} from '@uni2c/graphqlapi4mp';

const sdl = `
  scalar DateTime
  enum UserStatus { ACTIVE DISABLED }

  type Query {
    user(id: ID!, includeDisabled: Boolean = false): User
  }

  type User {
    id: ID!
    name: String!
    status: UserStatus!
    createdAt: DateTime!
    profile: Profile
  }

  type Profile {
    bio: String
    website: String
  }
`;

const schema = parseSDL(sdl);
const sourceOperation = schema.query.user;

if (!sourceOperation) {
  throw new Error('Query.user 不存在');
}

const operation: GraphQLOperation = {
  ...sourceOperation,
  fields: buildSelectionFields(schema, sourceOperation, {
    profile: {
      website: false,
    },
  }),
};

const query = buildGraphQLQuery(operation, 'query');
console.log(query);

输出:

query user($id: ID!, $includeDisabled: Boolean) {
  user(
    id: $id
    includeDisabled: $includeDisabled
  ) {
    id
    name
    status
    createdAt
    profile {
      bio
    }
  }
}

请求时将变量单独传给 GraphQL 客户端:

const variables = {
  id: 'user-1',
  includeDisabled: false,
};

await fetch('/graphql', {
  method: 'POST',
  headers: {
    'content-type': 'application/json',
  },
  body: JSON.stringify({ query, variables }),
});

API

parseSDL(sdl)

解析 SDL 字符串并返回 Schema 元数据。

const schema = parseSDL(sdl);

schema.query;    // Query 根字段
schema.mutation; // Mutation 根字段
schema.types;    // 所有已解析的对象类型
schema.scalars;  // 内置标量和自定义标量
schema.enums;    // 枚举名称

返回类型:

interface SchemaMeta {
  query: Record<string, SchemaField>;
  mutation: Record<string, SchemaField>;
  types: Record<string, SchemaType>;
  scalars: Set<string>;
  enums: Set<string>;
}

字段的 type 会保留 GraphQL 类型修饰符,例如 ID![User!]!

buildSelectionFields(schema, operation, config?)

根据 operation 返回类型构造 selection set 字段树。

规则:

  • 标量和枚举字段默认包含
  • 对象字段默认不展开
  • 对象字段配置为 true 时展开,并包含其直接标量/枚举字段
  • 对象字段配置为对象时,按该配置递归展开
  • 任意字段配置为 false 时排除
const fields = buildSelectionFields(schema, schema.query.user, {
  name: false,
  profile: {
    bio: true,
    website: false,
  },
});

返回值类似:

[
  'id',
  'status',
  'createdAt',
  {
    name: 'profile',
    fields: ['bio'],
  },
]

注意:对标量字段设置 true 不会改变行为,因为标量字段本来就会默认包含。

buildGraphQLQuery(operation, operationType?)

将 operation 转换为完整 GraphQL 文本。

const query = buildGraphQLQuery(operation); // 默认为 query
const mutation = buildGraphQLQuery(operation, 'mutation');

operation 的参数定义来自 SDL,生成器会同时生成变量声明和字段参数引用。它只生成查询文本,不负责提供实际变量值或发送网络请求。

buildQuery(operation, operationType?)

buildGraphQLQuery 的兼容别名。新代码建议使用 buildGraphQLQuery

unwrapType(type)

移除 GraphQL 列表和非空修饰符,返回基础类型名称。

unwrapType('User');     // User
unwrapType('User!');    // User
unwrapType('[User!]!'); // User

formatVariables(variables, args, filterEmpty?)

根据 SDL 定义的参数类型(如 Int, Float, Boolean, String, JsonString, [Type] 等)格式化查询变量,并支持过滤无效空值。

  • 参数
    • variables (Record<string, any>): 传入的业务变量对象
    • args (Record<string, string>): 对应 operation 在 SDL 中解析出的 args 参数映射(例如 { user_id: 'Int', user_ids: '[Int]' }
    • filterEmpty (boolean,可选,默认为 true): 是否开启无效空值过滤(过滤 '', [], undefined, null
  • 类型转换规则
    • Int: 转换为整数(parseInt(value, 10)
    • Float: 转换为浮点数(parseFloat(value)
    • Boolean: 'false' / '0' 转换成 false,其余按布尔真值
    • String / ID: 转换为字符串
    • JsonString: 对象自动 JSON.stringify 转换
    • [Type]: 支持数组或逗号分隔字符串转数组,并递归转换每个元素
    • 自动忽略未在 args 中定义的冗余变量字段
const args = {
  user_id: 'Int',
  user_ids: '[Int]',
  keyword: 'String',
  isVip: 'Boolean',
};

// 开启空值过滤(默认)
formatVariables(
  {
    user_id: '123',
    user_ids: '1,2,3',
    keyword: '',
    isVip: 'false',
    extra: 'ignored',
  },
  args,
);
// => { user_id: 123, user_ids: [1, 2, 3], isVip: false }

// 关闭空值过滤
formatVariables({ keyword: '' }, args, false);
// => { keyword: '' }

setEnv(options)

初始化运行环境变量与加密密钥配置。

setEnv({
  PROD: true, // 为 true 时,paramProcess 会对数据进行 AES+RSA 加密
  VITE_SALT_KEY: 'salt_key_string', // 参与 MD5 签名的加盐密钥
  VITE_PUBLIC_KEY: '-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----', // RSA 公钥
});

paramProcess(config, password)

对发起请求的配置对象进行统一预处理:

  1. 自动提取 config.data.variables 进行字典序升序并追加盐值计算 MD5 签名,附加到 variables.sign
  2. env.PROD === true,则使用 password(32 位混合密钥)将 config.data 进行 AES-128-CBC 加密,并将 password 经 RSA 公钥加密存入 key
const pwd = initPassword(); // 生成 32 位随机密钥

const config = {
  url: 'https://api.example.com/graphql',
  data: {
    query,
    variables: formatVariables({ user_id: '1' }, operation.args),
  },
};

const processed = paramProcess(config, pwd);

数据加解密与工具函数

  • encrypt(text, key, iv) / decrypt(cipherText, key, iv):基于 @noble/ciphers/aes 实现的 AES-128-CBC 加解密,输出/输入 Base64 格式,key 与 iv 必须为 16 字节。
  • encodeData(data, password) / decodeData(res, password)
    • encodeData: 传入对象与 32 位字符串密钥(前 16 位为 key,后 16 位为 iv),返回 { value: 'AES加密Base64', key: 'RSA加密密码' }
    • decodeData: 传入 { data: 'AES密文' } 和密钥进行 AES 解密,若内容为 JSON 会自动反序列化。
  • getSign(params):将对象或参数字符串按 key 升序拼接,拼接盐值后生成 32 位小写 MD5 签名。
  • initPassword():生成 32 位基于时间戳和随机字符的 MD5 散列密码。
  • md5(text):轻量级纯 JS MD5 算法实现。
  • base64encode(str) / base64decode(str):跨平台 Base64 编解码,兼容微信小程序(wx.arrayBufferToBase64)、uni-app(uni.arrayBufferToBase64)和标准浏览器。

Mutation 示例

type Mutation {
  updateUser(id: ID!, name: String!): User
}
const sourceOperation = schema.mutation.updateUser;
const mutation = buildGraphQLQuery(
  {
    ...sourceOperation,
    fields: buildSelectionFields(schema, sourceOperation),
  },
  'mutation',
);

输出:

mutation updateUser($id: ID!, $name: String!) {
  updateUser(
    id: $id
    name: $name
  ) {
    id
    name
    status
    createdAt
  }
}

手动指定 selection set

不使用 buildSelectionFields 时,也可以自行构造字段树:

const query = buildGraphQLQuery({
  name: 'user',
  type: 'User',
  args: { id: 'ID!' },
  fields: [
    'id',
    'name',
    {
      name: 'profile',
      fields: ['bio'],
    },
  ],
});

当前解析范围

该库面向查询生成所需的轻量 SDL 元数据提取,并不是完整的 GraphQL 规范验证器。目前应注意:

  • 根类型按常规名称 QueryMutation 识别
  • 解析对象 typescalarenum
  • 支持字段参数、列表类型、非空类型、默认值与指令的跳过处理
  • 不解析 inputinterfaceunion、fragment 或 directive 定义为可查询对象
  • 不验证字段值,也不执行 GraphQL operation

需要完整 Schema 校验、执行或 introspection 时,应配合标准 GraphQL 实现使用。

发布产物

包通过条件导出自动选择模块格式:

  • ESM:dist/index.mjs
  • CommonJS:dist/index.cjs
  • TypeScript 声明:dist/index.d.ts

项目构建时会自动检查产物体积;超过预算或出现未登记文件时构建失败。

开发

npm install
npm run typecheck
npm test

其他命令:

npm run build      # 构建 CJS、ESM 和类型声明,并检查体积
npm run size       # 检查 dist 文件及体积预算
npm run test:demo  # 使用项目内大型 SDL 运行演示脚本

License

ISC