# @crystallize/js-api-client 中文文档

规范地址：https://npmcn.com/package/%40crystallize/js-api-client/

版本：7\.6\.0
npm 元数据更新时间：2026-10-29T21:51:46.977Z
中文译文更新时间：2026-11-11T03:00:55.994Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40crystallize/js-api-client
原文对照：https://npmcn.com/package/%40crystallize/js-api-client/?lang=original
项目主页：https://github.com/CrystallizeAPI/js-api-client#readme
源码仓库：https://github.com/CrystallizeAPI/js-api-client

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：656 kB，71 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- 运行依赖：5 个
- 首次发布：2022-03-25T21:41:23.848Z
- 最新版本发布：2026-10-29T21:51:46.486Z
- 近 30 天下载量：5526（2026-10-11 至 2026-11-09，npm 官方下载统计）
- 已发布版本数：73（近 12 个月 11 个）

## 中文简介

与Crystallize API合作的助手和打字的公用事业.

## 安装

```sh
npm install @crystallize/js-api-client
```

也可以使用：`pnpm add @crystallize/js-api-client`、`yarn add @crystallize/js-api-client`、`bun add @crystallize/js-api-client`

## README

# JS API 客户端

与Crystallize API合作的助手和打字的公用事业.

> v5是一个主要的更新:更简单的客户端,通过@crystallize/schema输入输入,以及专注于共同任务的管理者(目录,导航,水合,订单,客户,订阅,和推车).

## 安装

```bash
pnpm add @crystallize/js-api-client
# or
npm install @crystallize/js-api-client
# or
yarn add @crystallize/js-api-client
```

## 快开始

```typescript
import { createClient } from '@crystallize/js-api-client';

const api = createClient({
    tenantIdentifier: 'furniture',
    // For protected APIs, provide credentials
    // accessTokenId: '…',
    // accessTokenSecret: '…',
    // staticAuthToken: '…',
    // and more
});

// Call any GraphQL you already have (string query + variables)
const { catalogue } = await api.catalogueApi(
    `query Q($path: String!, $language: String!) {
    catalogue(path: $path, language: $language) { name path }
}`,
    { path: '/shop', language: 'en' },
);

// Don't forget to close when using HTTP/2 option (see below)
api.close();
```

## 快速摘要

-   一个有电话的客户: `catalogueApi`, (中文(简体) ), `discoveryApi`, (中文(简体) ), `pimApi`, (中文(简体) ), `nextPimApi`, (中文(简体) ), `meApi`,和商店API的呼叫器 `shopCartApi`, (中文(简体) ), `shopOrderApi`, (中文(简体) ), `shopCustomerApi`, (中文(简体) ), `shopLockApi`, (中文(简体) ), `shopSubscriptionContractApi`, (中文(简体) ), `shopBookingApi`
-   高级助手: `createCatalogueFetcher`, (中文(简体) ), `createNavigationFetcher`, (中文(简体) ), `createProductHydrater`, (中文(简体) ), `createOrderFetcher`, (中文(简体) ), `createOrderManager`, (中文(简体) ), `createCustomerManager`, (中文(简体) ), `createCustomerGroupManager`, (中文(简体) ), `createSubscriptionContractManager`, (中文(简体) ), `createCartManager`, (中文(简体) ), `createShopOrderManager`, (中文(简体) ), `createShopCustomerManager`, (中文(简体) ), `createShopLock`
-   公用事业: `createSignatureVerifier`, (中文(简体) ), `createPluginPayloadDecrypter`, (中文(简体) ), `createBinaryFileManager`, (中文(简体) ), `pricesForUsageOnTier`,请求 `profiling`
-   使用对象构建图形QL `json-to-graphql-query` (见下文一节)
-   强打字通过 `@crystallize/schema` 投入和产出
-   升级? 见 [升级](https://npmcn.com/package/%40crystallize/js-api-client/UPGRADE.md) v4 – v5 迁移

## 备选办法和环境

`createClient(configuration, options?)`

-   配置
    -   `tenantIdentifier` (必须)
    -   `tenantId` 选项
    -   `accessTokenId` 编号 : `accessTokenSecret` 或者说 `sessionId`
    -   `bearerToken` 用于后端发行的 Bearer 令牌(同意为 `Authorization: Bearer …`(中文(简体) )
    -   `staticAuthToken` 只读目录/发现
    -   `shopApiToken` 选项; 否则自动比对
    -   `shopApiStaging` 使用中转商店 API
    -   `origin` 自定义主机后缀( 默认为 `.crystallize.com`(中文(简体) )
-   选项
    -   `useHttp2` 启用 HTTP/2 运输
    -   `timeout` 请求超时以毫秒计; 需要更长时间的请求将被中止
    -   `http2IdleTimeout` HTTP/2 以毫秒计的空闲超时( 默认) `300000` ——5分钟). 对没有服务器的函数使用更短的值, 对长期运行的服务器使用更长的值
    -   `profiling` 调用
    -   `extraHeaders` 所有呼叫的额外请求信头
    -   `shopApiToken` 自动牵引控制 : `{ doNotFetch?: boolean; scopes?: string[]; expiresIn?: number }`。 。 。 . `scopes` 默认为 `['cart']`;通过您使用的每一端点(例如. `['cart', 'order']`)在前面获得一个单一的指使,否则指使会与外延范围被重置,这是第一次叫另一个商店API终点

`client.close()` 当您允许 HTTP/2 优雅地结束基础会话时, 将会被调用 .

### 可用的 API 呼叫器

-   `catalogueApi` -目录图形QL
-   `discoveryApi` - 发现图QL(取代了旧的搜索 API)
-   `pimApi` - PIM GraphQL(经典/图克快传)
-   `nextPimApi` - PIM 下图QL(适用于租户)
-   `meApi` - 我图QL(`/@me`范围)
-   `shopCartApi` - 商店API `/cart` GraphQL( 为您处理的文件夹)
-   `shopOrderApi`, (中文(简体) ), `shopCustomerApi`, (中文(简体) ), `shopLockApi`, (中文(简体) ), `shopSubscriptionContractApi`, (中文(简体) ), `shopBookingApi` - 其他商店API终点(`/order`, (中文(简体) ), `/customer`, (中文(简体) ), `/lock`, (中文(简体) ), `/subscription-contract`, (中文(简体) ), `/booking`(中文(简体) )

所有的商店API的呼叫者 一个客户共享一个符号。 它在过期前5分钟被刷新,当呼叫者需要一个被缓存的代币不覆盖的端点时,它会与瞄准镜的结合进行回放.

所有呼叫者都拥有相同的签名: `<T>(query: string, variables?: Record<string, unknown>) => Promise<T>`。 。 。 .

### 认证概览

将有关全权证书交给 `createClient`数字 :

-   `staticAuthToken` 对目录/发现只读
-   `accessTokenId` + 键 `accessTokenSecret` (或 `sessionId`用于PIM/Shop操作
-   `bearerToken` 用于后端发行的令牌——作为 `Authorization: Bearer …`; 已接受 `catalogueApi`, (中文(简体) ), `discoveryApi`, (中文(简体) ), `pimApi`, (中文(简体) ), `nextPimApi`,以及 `meApi`在不提供其他证书的情况下,也自动用于获取商店 API 令牌.
-   `shopApiToken` 选项; 如果省略, 将使用您的 PIM 证书在第一个商店 API 呼叫中获取一个符号

认证优先级( 每名呼叫者, 最高第一) : `sessionId` → `bearerToken` → `staticAuthToken` → `accessTokenId`编号 :`accessTokenSecret`。 。 。 .

认证文件见官方文件: [https://crystalize.com/learn/developer-guides/api-overview/ 认证](https://crystallize.com/learn/developer-guides/api-overview/authentication)

### 处理错误

API 调用错误 `JSApiClientCallError` 两者 `code` 财务报告和审定财务报表 `statusCode` hTTP 状态的属性 :

```typescript
import { JSApiClientCallError } from '@crystallize/js-api-client';

try {
    await api.pimApi(`query { … }`);
} catch (e) {
    if (e instanceof JSApiClientCallError) {
        console.error(`HTTP ${e.statusCode}:`, e.message);
        // e.code also works (same value)
    }
}
```

## 分析请求

如果有日志查询,计时和服务器计时.

```typescript
import { createClient } from '@crystallize/js-api-client';

const api = createClient(
    { tenantIdentifier: 'furniture' },
    {
        profiling: {
            onRequest: (q) => console.debug('[CRYSTALLIZE] >', q),
            onRequestResolved: ({ resolutionTimeMs, serverTimeMs }, q) =>
                console.debug('[CRYSTALLIZE] <', resolutionTimeMs, 'ms (server', serverTimeMs, 'ms)'),
        },
    },
);
```

## 图形QL 构建器: json- to- graphql- query

这个图书馆充满了赞美 [json- to- graphql- query (英语)](https://www.npmjs.com/package/json-to-graphql-query) 在引擎盖下 你可以使用简单的JS对象来构建GraphQL查询. 多数帮助者接受一个对象并将其转换成图形QL字符串.

-   仍可用生弦给低级呼叫者打电话.
-   对于与目录有关的助手,我们揭露 `catalogueFetcherGraphqlBuilder` 以组成可重复使用的碎片.

示例对象 — 查询字符串 :

```typescript
import { jsonToGraphQLQuery } from 'json-to-graphql-query';

const query = jsonToGraphQLQuery({
    query: {
        catalogue: {
            __args: { path: '/shop', language: 'en' },
            name: true,
            path: true,
        },
    },
});
```

## 高级助手

这些帮助者构建查询,使用 `@crystallize/schema`,并给你打电话正确的API.

### 目录获取器

```typescript
import { createCatalogueFetcher, catalogueFetcherGraphqlBuilder as b } from '@crystallize/js-api-client';

const fetchCatalogue = createCatalogueFetcher(api);

const data = await fetchCatalogue<{ catalogue: { name: string; path: string } }>({
    catalogue: {
        __args: { path: '/shop', language: 'en' },
        name: true,
        path: true,
        ...b.onProduct({}, { onVariant: { sku: true, name: true } }),
    },
});
```

### 导航获取器

```typescript
import { createNavigationFetcher } from '@crystallize/js-api-client';

const nav = createNavigationFetcher(api);
const tree = await nav.byFolders('/', 'en', 3, /* extra root-level query */ undefined, (level) => {
    if (level === 1) return { shape: { identifier: true } };
    return {};
});
```

### 产品水利机

通过路径或具有可选价格背景的SKU获取产品/变量数据.

```typescript
import { createProductHydrater } from '@crystallize/js-api-client';

const hydrater = createProductHydrater(api, {
    marketIdentifiers: ['eu'],
    priceList: 'b2b',
    priceForEveryone: true,
});

const products = await hydrater.bySkus(
    ['SKU-1', 'SKU-2'],
    'en',
    /* extraQuery */ undefined,
    (sku) => ({ vatType: { name: true, percent: true } }),
    () => ({ priceVariants: { identifier: true, price: true } }),
);
```

### 顺序获取器

```typescript
import { createOrderFetcher } from '@crystallize/js-api-client';

const orders = createOrderFetcher(api);
const order = await orders.byId('order-id', {
    onOrder: { payment: { provider: true } },
    onOrderItem: { subscription: { status: true } },
    onCustomer: { email: true },
});

const list = await orders.byCustomerIdentifier('customer-123', { first: 20 });
```

已键入实例( TypeScript 通用名) :

```typescript
type OrderExtras = { payment: { provider: string }[] };
type OrderItemExtras = { subscription?: { status?: string } };
type CustomerExtras = { email?: string };

const typedOrder = await orders.byId<OrderExtras, OrderItemExtras, CustomerExtras>('order-id', {
    onOrder: { payment: { provider: true } },
    onOrderItem: { subscription: { status: true } },
    onCustomer: { email: true },
});

typedOrder.payment; // typed as array with provider
typedOrder.cart[0].subscription?.status; // typed
typedOrder.customer.email; // typed
```

### 订单管理器

创建/更新订单,设定付款或转入管道阶段. 输入以 `@crystallize/schema`。 。 。 .

```typescript
import { createOrderManager } from '@crystallize/js-api-client';

const om = createOrderManager(api);

// Register (minimal example)
const confirmation = await om.register({
    cart: [{ sku: 'SKU-1', name: 'Product', quantity: 1, price: { gross: 100, net: 80, currency: 'USD' } }],
    customer: { identifier: 'customer-123' },
});

// Update payments only
await om.setPayments('order-id', [
    {
        provider: 'STRIPE',
        amount: { gross: 100, net: 80, currency: 'USD' },
        method: 'card',
    },
]);

// Put in pipeline stage
await om.putInPipelineStage({ id: 'order-id', pipelineId: 'pipeline', stageId: 'stage' });
```

### 客户和客户小组管理员

```typescript
import { createCustomerManager, createCustomerGroupManager } from '@crystallize/js-api-client';

const customers = createCustomerManager(api);
await customers.create({ identifier: 'cust-1', email: 'john@doe.com' });
await customers.update({ identifier: 'cust-1', firstName: 'John' });

const groups = createCustomerGroupManager(api);
await groups.create({ identifier: 'vip', name: 'VIP' });
```

### 订阅合同管理器

创建/更新合同并生成一个变体预填模板.

```typescript
import { createSubscriptionContractManager } from '@crystallize/js-api-client';

const scm = createSubscriptionContractManager(api);

const template = await scm.createTemplateBasedOnVariantIdentity(
    '/shop/my-product',
    'SKU-1',
    'plan-identifier',
    'period-id',
    'default',
    'en',
);

// …tweak template and create
const created = await scm.create({
    customerIdentifier: 'customer-123',
    tenantId: 'tenant-id',
    payment: {
        /* … */
    },
    ...template,
});
```

### 墨盒管理器 (Shop API)

托肯处理是自动的( 除非你通过) `shopApiToken` 设置 `shopApiToken.doNotFetch: true`) (中文(简体) ).

```typescript
import { createCartManager } from '@crystallize/js-api-client';

const cart = createCartManager(api);

// Hydrate a cart from input
const hydrated = await cart.hydrate({
    language: 'en',
    items: [{ sku: 'SKU-1', quantity: 1 }],
});

// Add/remove items, abandon or place and fulfill the cart and assign the orderId
await cart.addSkuItem(hydrated.id, { sku: 'SKU-2', quantity: 2 });
await cart.setCustomer(hydrated.id, { identifier: 'customer-123', email: 'john@doe.com' });
await cart.setMeta(hydrated.id, { merge: true, meta: [{ key: 'source', value: 'web' }] });
await cart.abandon(hydrated.id);
await cart.place(hydrated.id);
await cart.fulfill(hydrated.id, orderId);
```

### 商店API订单

`createShopOrderManager` 与商店API谈话 `/order` 终点:将一推车转换成退货订单,记录付款情况,并通过管线移动订单。 (`createOrderManager` 以上针对核心API.) 输入用来自 `@crystallize/schema/shop`,每个方法返回顺序 `id` 加上您选择的字段.

```typescript
import { createShopOrderManager } from '@crystallize/js-api-client';
import type { Order } from '@crystallize/schema/shop';

const orders = createShopOrderManager(api);

const order = await orders.createFromCart(cartId, {
    type: 'standard',
    paymentStatus: 'paid',
    payments: [{ provider: 'stripe', transactionId: 'pi_123', amount: 100, method: 'card' }],
    pipelines: [{ identifier: 'fulfilment', stage: 'new' }],
});

await orders.addPayments(order.id, [{ provider: 'gift-card', amount: 20, meta: [{ key: 'code', value: 'XMAS' }] }]);
await orders.setPayments(order.id, [{ provider: 'stripe', amount: 120 }]); // replaces all payments
await orders.setMeta(order.id, { meta: [{ key: 'source', value: 'web' }] }); // merge: true by default
await orders.setCustomer(order.id, { isGuest: false, identifier: 'customer-123', type: 'individual', addresses: [] });
await orders.addToStage(order.id, 'fulfilment', 'shipped');
await orders.removeFromPipeline(order.id, 'fulfilment');

const fetched = await orders.fetch<Order>(order.id, { reference: true, payments: { provider: true, meta: true } });
const history = await orders.listByCustomer('customer-123', { limit: 10, skip: 0 }, { reference: true });
```

-   `payments` 接受任何 `provider` 字符串:它们记录了所发生的事情,没有任何指控.
-   `payments[].meta` 以 `[{ key, value }]` 列表,但读回为 JSON 对象(`{ code: 'XMAS' }`) (中文(简体) ).
-   `createFromCart`, (中文(简体) ), `addPayments` 财务报告和审定财务报表 `setPayments` 在回复后继续执行命令:在回复后立即发布的读数仍可返回先前状态.
-   `fetch` 以 `JSApiClientCallError` 当命令不存在时.

### 商店 API 客户和锁

```typescript
import { createShopCustomerManager, createShopLock } from '@crystallize/js-api-client';

// `/customer`: customers keyed by identifier
const customers = createShopCustomerManager(api);
await customers.upsert({ identifier: 'customer-123', email: 'john@doe.com', firstName: 'John' }); // create or update
await customers.addAddress('customer-123', { type: 'delivery', street: 'Main St 1', city: 'Oslo' });
await customers.setAddress('customer-123', 0, { type: 'delivery', street: 'Main St 2', city: 'Oslo' });
await customers.removeAddress('customer-123', 0);
await customers.setMeta('customer-123', { meta: [{ key: 'tier', value: 'gold' }] });
const customer = await customers.fetch('customer-123', { email: true, addresses: { city: true } });

// `/lock`: a distributed lock, e.g. so a webhook and a redirect don't both create the order
const lock = createShopLock(api);
if (await lock.acquire(`cart-${cartId}`, 30)) {
    // ttl in seconds, defaults to 60; resolves false when the lock is already held
    try {
        // …createFromCart
    } finally {
        await lock.release(`cart-${cartId}`);
    }
}
```

## 签字核查

使用 `createSignatureVerifier` 以验证用于webhooks,apps或前端呼叫的 Crystalization 签名. 核查员将HS256 JWT信封与共享的密件解码,并与其匹配 `hmac` sHA-256索赔——全部通过捆绑的 `jose` 和平台的 `crypto.subtle`,所以你不需要通过自己的JWT或散去执行.

```typescript
import { createSignatureVerifier } from '@crystallize/js-api-client';

const verify = createSignatureVerifier({ secret: process.env.CRYSTALLIZE_SIGNATURE_SECRET! });

// POST example
await verify(signatureJwtFromHeader, {
    url: request.url,
    method: 'POST',
    body: rawBodyString, // IMPORTANT: raw body
});

// GET webhook example (must pass the original webhook URL)
await verify(signatureJwtFromHeader, {
    url: request.url, // the received URL including query params
    method: 'GET',
    webhookUrl: 'https://example.com/api/webhook', // the configured webhook URL in Crystallize
});
```

## 插件有效载荷解密

使用 `createPluginPayloadDecrypter` 解密一个 Crystallize 插件 JWE 有效载荷(外部 JWE = 嵌入式 JWS 信封 = 逐地) `encryptedSecrets`),并可选择性地对照JWKS验证内置JWS. 这是CLI的单一切入点,任何供应商方的整合都应依赖此.

工厂取自销售商的私人JWK(如: `crystallize plugin keygen`)和可选 `verify` 设置,并返回可重复使用的函数,每个调用接受JWE紧凑的有效载荷。 私钥和JWKS解析器是一次建造并被再用——因此对于一个处理许多webhook呼叫的服务器,在启动时创建解密器一次.

仅 `RSA-OAEP` 编号 : `RSA-OAEP-256` 与 `A*GCM` 内容加密在外 JWE 上被接受. 当外头带着 `cty: "JWT"`,简文作为紧凑的JWS处理,其索赔构成信封.

签名验证为选入:通过 `verify` 以使之得以实现。 何时 `verify` (a) 删去(或在核查失败时)信封和每个外地的秘密仍被退回,以便打电话者检查; `signature.verified` 编号 : `signature.skipped` 编号 : `signature.reason` 告诉你是否相信结果.

```typescript
import { readFile } from 'node:fs/promises';
import { createPluginPayloadDecrypter } from '@crystallize/js-api-client';

const privateJwk = JSON.parse(await readFile('./private.jwk.json', 'utf8'));

// Decrypt only — no signature check. Good for local dev / smoke tests.
const decrypt = createPluginPayloadDecrypter({ privateJwk });
const decoded = await decrypt(jweCompact);

if (decoded.envelope) {
    console.log('tenant:', decoded.envelope.tenantIdentifier);
    console.log('config:', decoded.envelope.config);
    console.log('secrets:', decoded.secrets); // { StripeApiKey: 'sk_live_…', … }
}
```

以通过方式启用校验 `verify` 至少有一个 `audience` (您的插件标识符). `issuer` 默认为 `https://api.crystallize.com` 财务报告和审定财务报表 `jwksUrl` 默认为 `${issuer}/.well-known/jwks.json`,所以生产用途是单行道:

```typescript
// Production — issuer + JWKS URL default to api.crystallize.com.
const decrypt = createPluginPayloadDecrypter({
    privateJwk,
    verify: { audience: 'com.vendor.plugin' },
});

const verified = await decrypt(jweCompact);
if (!verified.signature.verified) {
    // Signature check skipped or failed — envelope + secrets are still populated but MUST be treated as untrusted.
    console.warn('signature not trusted:', verified.signature.reason);
}
```

其它 `verify` 字段 : `clockTolerance` (秒,默认为 `30`, (中文(简体) ), `verifyBackendToken` (还核查) `envelope.backendToken` 默认为 `false`) (中文(简体) ).

回来的 `DecryptedPluginPayload` 包含:

-   `protectedHeader` 外 JWE 保护头
-   `innerProtectedHeader` 内置JWS保护头,当有效载荷被嵌入时
-   `envelope` 核实(或解码)JWS索赔,或 `null` 用于未记录的有效载荷
-   `plaintext` 当有效载荷不是一窝JWT时,原始外平面文字,否则 `null`
-   `secrets` ——逐字解密的简单文字 `envelope.encryptedSecrets`
-   `signature` —— 说 `{ verified, skipped?, reason?, issuer?, audience?, algorithm? }`
-   `backendToken` —— 说 `{ verified, skipped?, reason?, claims? }` 何时 `envelope.backendToken` 在场,否则 `null`

> 警卫: `secrets` 并解码 `envelope` 索赔要求包含清晰的文字证明。 不日志或将其转入共享汇.

## 为公用事业定价

```typescript
import { pricesForUsageOnTier } from '@crystallize/js-api-client';

const usage = 1200;
const total = pricesForUsageOnTier(
    usage,
    [
        { threshold: 0, price: 0, currency: 'USD' },
        { threshold: 1000, price: 0.02, currency: 'USD' },
    ],
    'graduated',
);
```

## 二进制文件管理器

通过预先签名的请求上传文件( 如图像) 。 仅限服务器侧.

```typescript
import { createBinaryFileManager } from '@crystallize/js-api-client';

const files = createBinaryFileManager(api);
const mediaKey = await files.uploadImage('/absolute/path/to/picture.jpg');
const staticKey = await files.uploadFile('/absolute/path/to/static/file.pdf');
const bulkKey = await files.uploadMassOperationFile('/absolute/path/to/import.zip');
// Use the returned keys in subsequent PIM mutations
```

`uploadImage` 验证文件在创建前为图像 `MEDIA` 上传. 使用 `uploadFile` 适用于应居住在租户静态文件存储中的资产,以及 `uploadMassOperationFile` 由批量业务管道处理的进口货物。 打电话 `uploadToTenant` 需要下级控制(如自定义缓冲或上传类型)时直接.

## 大众呼叫客户端( 已过期)

> **折旧:** 使用成熟的生态系统组合,如 [`p-limit`](https://www.npmjs.com/package/p-limit) 或者说 [`p-queue`](https://www.npmjs.com/package/p-queue) 换句话说 它们提供更好的错误处理,TypeScript支持,并被积极维护.

### 建议使用 p- 限额的替代品

```typescript
import pLimit from 'p-limit';
import { createClient } from '@crystallize/js-api-client';

const api = createClient({ tenantIdentifier: 'my-tenant', accessTokenId: '…', accessTokenSecret: '…' });
const limit = pLimit(5); // max 5 concurrent requests

const mutations = items.map((item) =>
    limit(() =>
        api.pimApi(
            `mutation UpdateItem($id: ID!, $name: String!) { product { update(id: $id, input: { name: $name }) { id } } }`,
            { id: item.id, name: item.name },
        ),
    ),
);

const results = await Promise.allSettled(mutations);
const failed = results.filter((r) => r.status === 'rejected');
console.log(`Done: ${results.length - failed.length} succeeded, ${failed.length} failed`);
```

### 遗产使用

大众呼叫客户端仍然在运行,但会在首次使用时发出去色警告.

有时,当你有很多电话需要处理, 无论是询问还是突变, 你都想能够同步管理它们。 这是大众呼叫客户端的目的. 它将使你成为同步,管理生命周期的起重,再试,增减速度等.

这些是主要特点:

-   运行 _首页_ 请求在批次中同步. _首页_ 默认的批量大小
-   如果批次有超过50%的出错,则会保存出错并延续批次大小为 1
-   如果批次中出现不到50%的出错,则会保存出错并延续当前批次大小倒数 1
-   如果没有出错,它会逐批递增(+1)请求的数量,上限为 _最大缩放_
-   如果错误率是100%,则根据 **费博纳奇** 递增
-   所有批次结束后, 您可以重试失败的请求
-   可选生命周期功能 _打开批次_ (同步)
-   可选生命周期功能 _失败_ (同步) 允许您做一些事情, 并且决定让命令( 返回真实: 默认) 或立即返回虚假和重新执行, 或任何其他行动
-   可选生命周期功能 _在请求前_ (同步)在每次请求前执行. 您可以返回更改的请求/承诺
-   可选生命周期功能 _请求后_ (同步) 每次请求后执行 。 如果需要,你也会得到结果

```javascript
const client = createMassCallClient(api, { initialSpawn: 1 });

async function run() {
    for (let i = 1; i <= 54; i++) {
        client.enqueue.catalogueApi(`query { catalogue { id, key${i}: name } }`);
    }

    const successes = await client.execute();
    console.log('First pass done ', successes);
    console.log('Failed Count: ' + client.failureCount());
    while (client.hasFailed()) {
        console.log('Retrying...');
        const newSuccesses = await client.retry();
        console.log('Retry pass done ', newSuccesses);
    }
    console.log('ALL DONE!');
}
run();
```

## 常见问题

### @crystallize/js-api-client 是什么？

与Crystallize API合作的助手和打字的公用事业\.

### 如何安装 @crystallize/js-api-client？

在项目目录运行 npm install @crystallize/js-api-client，或使用 pnpm add / yarn add / bun add。

### @crystallize/js-api-client 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @crystallize/js-api-client 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @crystallize/js-api-client 可以商用吗？

@crystallize/js-api-client 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @crystallize/js-api-client 的下载量有多少？

根据 npm 官方下载统计，@crystallize/js-api-client 在 2026/10/11 – 2026/11/09 这 30 天内被下载 5,526 次，日均约 184 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @crystallize/js-api-client 还在维护吗？

最新版本 7\.6\.0 发布于 2026/10/30（12 天前）；至今共发布 73 个版本，其中过去 12 个月发布了 11 个；首次发布于 2022/03/26。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

