# @3dn-builder/builder 中文文档

规范地址：https://npmcn.com/package/%403dn-builder/builder/

版本：0\.713\.0
npm 元数据更新时间：2026-11-07T14:10:25.769Z
中文译文更新时间：2026-11-06T06:13:40.379Z
软件包许可：MIT

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

原始 npm 页面：https://www.npmjs.com/package/%403dn-builder/builder
原文对照：https://npmcn.com/package/%403dn-builder/builder/?lang=original
项目主页：https://github.com/harikrishna266/three-dn/tree/develop/libs/builder-host#readme
源码仓库：https://github.com/harikrishna266/three-dn

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

- 包体积（解压后）：222 kB，14 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：0 个
- 首次发布：2026-10-09T18:02:29.490Z
- 最新版本发布：2026-11-07T14:10:25.606Z
- 近 30 天下载量：10123（2026-10-05 至 2026-11-03，npm 官方下载统计）
- 已发布版本数：77（近 12 个月 77 个）

## 中文简介

将3DN产品构建器嵌入到任何商店前端:加载,登录,许可证刷新,保存和定制记录.

## 安装

```sh
npm install @3dn-builder/builder
```

也可以使用：`pnpm add @3dn-builder/builder`、`yarn add @3dn-builder/builder`、`bun add @3dn-builder/builder`

## README

# @ 3dn- 建设者/ 建设者

将3DN产品制造器嵌入任何商店前端. SDK加载了构建者,运行了登录回程,刷新了许可证,保存并报告每个保存. 您的站点提供了会话结束点、 登录到的结束点和它自己的登录 UI .

## 安装

```sh
npm install @3dn-builder/builder
```

无害环境管理,零运行时间依赖。 入口点 : `.`, (中文(简体) ), `./events` (只有类型和常数), `./testing` (一个假的) `<threed-builder>`) (中文(简体) ).

## 创建、挂载、销毁

```ts
import { createBuilder } from '@3dn-builder/builder';

const builder = createBuilder({
  session: {
    get: ({ hostProductId }) => api.getBuilderSession(hostProductId),
    refreshLicense: () => api.refreshBuilderLicense(),
  },
  login: {
    getTokens: () => api.mintBuilderTokens(), // null on 401
    onRequired: (action) => showLogin(action), // 'logged-in' | 'redirected' | 'cancelled'
  },
  onSaved: (saved) => showSavedDesign(saved.productId),
  onImagesSaved: (saved) => refreshGallery(saved.productId),
  onLicenseError: (error) => reportSetupError(error.code),
  onCloseRequested: () => closeModal(), // the builder already asked about unsaved changes
});

const instance = await builder.mount({ target: container, hostProductId: 'alpine-mug' });
const design = await instance.save(); // design.productId goes on the cart line
instance.destroy();
```

`createBuilder()` 触摸页面上的任何内容, 因此在服务器侧渲染时安全; 构建者加载 `load()` 或者说 `mount()`目标需要一个真正的高度.

建造者最迟会加载,除非您通过 `version: '1.2.3'`。每个发布的版本都保持在线状态,所以一个被绑定的版本会不断加载,但是它只在3DN API仍然接受它发送的东西的同时继续工作. 坚持住 `'latest'` 除非你需要等待释放.

| 方法 | 行为 |
| --- | --- |
| `load()` | 可选预装,每页一次. |
| `mount(options)` | `{ target, hostProductId, mode?: 'designer' | 'viewer', designId?, loader?: 'container' | 'page', externalExport?, observabilityContext? }` - 比如说. |
| `open()` | 显示隐藏挂载后的构建器 UI . |
| `save()` | 决定: `{ productId, version }` 保存之后,任何克隆记录, `onSaved` 和图像刷新。 45分超时. |
| `refreshSession()` | 电话 `session.get()` 并应用结果. |
| `refreshLicense()` | 每个挂载的建筑商共享许可证刷新一次 . |
| `logout()` | 移除shopper 令牌, 保留许可证令牌 。 延迟登录结果被删除 . |
| `destroy()` | 删除建构器及其收听器; 待调用 `DESTROYED`。 。 。 . |

`loader` 设定加载和许可屏幕覆盖的内容。 默认, `'container'`,仅覆盖 `target`,所以在建设者加载时,你的其余页面仍然可以使用. 过 `'page'` 以屏蔽整个浏览器窗口,例如当构建器作为全屏模式打开时。 对话框和图像编辑器总是覆盖整个窗口.

`observabilityContext` 是建造者的 `observability-context`:一个 JSON 对象字符串,命名您的应用程序,租户,网站,假名用户和请求,加上您的页面 `sentry-trace` 财务报告和审定财务报表 `baggage`,所以建筑商自己的错误报告 说他们在哪里发生。 在元素连接之前设定; `instance.setObservabilityContext(json)` 稍后替换它,例如一旦你的页面的哨兵有踪迹。 关键及其规则载于综合指南第6.3节.

控制器的方法在最近安装的构建器上起作用. 页面上有多个构建者,请联系实例 `mount()` 已经返回.

## 会议

```ts
session: {
  get(request: { hostProductId: string }): Promise<BuilderSession>;
  refreshLicense(): Promise<{ licenseToken: string }>;
}

interface BuilderSession {
  licenseToken: string;
  productId: string;     // the shopper's saved copy, else the global product
  viewToken?: string;    // required for a private product
  token?: string;        // optional shopper tokens, always together
  refreshToken?: string;
}
```

`hostProductId` 您的后端决定它打开的 3DN 产品 。 在服务器上保留安装密钥 : `createBuilder()` 拒绝任何看起来像一个, 和任何选项 命名建设者加载从.

## 登录

```ts
login: {
  getTokens(): Promise<{ token: string; refreshToken: string } | null>; // null on 401
  onRequired(action: LoginRequiredAction): Promise<'logged-in' | 'redirected' | 'cancelled'>;
  onMintFailed?(): Promise<'retry' | 'cancel'>; // getTokens() threw; default 'cancel'
}
```

通过重定向登录: 发送 sphop 到 `loginReturnPath()` 登录后( 用 `isSafeReturnPath()`页:1 `'redirected'`,然后在 `consumeResumeMarker()` 是真的; 构建者完成待定保存. `hasDraft(productId)` 说明是否在这个设备上保留了草稿 .

## 保存

```ts
onSaved?(saved: { hostProductId: string; productId: string; version: number }): void;
onImagesSaved?(saved: { hostProductId: string; productId: string; version: number }): void;

customization?: {
  record(link: {
    hostProductId: string;
    sourceProductId: string;
    savedProductId: string;
    asCopy: boolean;
  }): Promise<void>;
};
```

`onSaved` 每一次成功救出一次,从 `save()` 或者从建设者自己的保存按钮。 第一次保存 使shopper的复制: `productId` 然后是副本,和 `onSaved` 仅在副本存在后开火 `customization.record()` 解决。 它从不为失败的保存或失败的记录发火;下一次保存的记录再次发火.

`onSaved` 在产品图像(它的缩略图和相机角截图)被刷新之前。 读取图像于 `onImagesSaved`:一旦他们显示设计 `version`,在那之后的储蓄 `onSaved`。当图像无法更新时,它不会起火;产品保留了以前的图像. `save()` 仅在图像被刷新或失败后才解决,所以一个主机会在之后摧毁构建者 `await save()` 从不缩短上传时间。 这需要一个建筑师 发送 `tdn-images-saved`,用这个SDK或稍后释放的; 有更古老的钉子 `version`, (中文(简体) ), `save()` 时间流出.

一个shoper先将复制品在来源后和被保存后的名字保存下来,例如"Mug Grey – 19 October, 14:32",所以可以从一个产品中分解出几个设计.

`asCopy` 说抄本的意思. `true`:shopper要求一个("保存为副本",在保存相冲突后也提供),所以把它作为新的设计来保存原件. `false`:保存必须叉出一个shopper不拥有的产品,因此复制件取代了开放设计.

## 命令

当发布命令时,将命令的设计从后端锁定在安装密钥上:

```http
POST {API_BASE}/plugin/products/{productId}/lock
x-installation-key: {INSTALLATION_KEY}

{ "orderRef": "1042-A", "version": 7 }
```

发送 `productId` 财务报告和审定财务报表 `version` 从 `onSaved` 你储存在车线上。 A 类 `409` 指该版本后再次被shoper所保存,或者已经锁定的另一订单. 锁定的设计无法再更改( 没有解锁): 它只打开可读, 下载并保存为副本, 保存失败 `reason: 'locked'`。要更改命令的设计,请取消命令,让shoper订购副本.

`POST {API_BASE}/plugin/products/{productId}/view-only-link` 返回时 `{ url }`:在裸取取景器中打开设计的一个链接(3D中的模型,有2D / Split / 3D开关,动画滑行器,相机角度和下载打印文件,没有编辑工具),在没有登录的情况下下载其打印文件,例如用于打印行. 没有任何东西可以通过它保存或复制.

## 特征

```ts
features?: {
  download?: boolean; // default true: Download print files (and a design area's SVG)
  share?: boolean;    // default true: Share a link to the design
  save?: boolean;     // default true: Save, Save as copy, version history and the save state
  feedback?: boolean; // default true: Report a problem
};
```

设定 `download: false` 或者说 `share: false` 将动作隐藏在桌面和电话布局中,例如当购买者不应拿走艺术品时。 设定 `save: false` 对于一个不保存任何内容的试运行编辑器:shopper可以设计,在2D和3D之间切换并使用每个工具,但是没有保存,没有保存为副本,没有版本历史和保存状态; `save()` 仍然为主机工作。 设定 `feedback: false` 来隐藏“ 报告一个问题”, shopper 描述出出错之处, 3DN 接收时会话记录 。 全部显示,除非你关掉。 任何其他密钥,或者一个不是布尔的值,是 `CONFIG_INVALID` 错误.

## 错误

每一次失败都是 `BuilderError`数字 : `code`页:1 `message` 安全显示, `retryable`, (中文(简体) ), `fatal`和建筑师的 `reason`。 。 。 .

| 代码 | 何时 |
| --- | --- |
| `CONFIG_INVALID` | 错误的选项, 或者一个秘密或脚本 URL 传入 . |
| `NOT_IN_BROWSER` | `load()` 或者说 `mount()` 在安全部门改革期间. |
| `LOAD_FAILED` | 建造者没有加载; 下一次调用重试 . |
| `VERSION_CONFLICT` | 另一个构建器版本已经在页面上运行. |
| `SESSION_FAILED` | `session.get()` 失败或返回无效会话. |
| `LICENSE_ERROR` | 该许可证被拒绝。 使登山者死亡; `onLicenseError` 名为. |
| `LOGIN_CANCELLED` | 直升机没有登录. |
| `SAVE_FAILED` | 保存失败, 或 `customization.record()` 失败( e)`reason: 'customization'`) (中文(简体) ). |
| `SAVE_TIMEOUT` | 内部无结果 `saveTimeoutMs`。 。 。 . |
| `EXPORT_FAILED`, (中文(简体) ), `EXPORT_TIMEOUT` | `externalExport.run()` 失败或超时 . |
| `DESTROYED` | `destroy()` 在电话待发时跑掉了. |

A 类 `SAVE_FAILED` 与 `reason: 'locked'` 指将设计锁定的命令;不能重试,由构建者提供保存为副本.

A 类 `SAVE_FAILED` 与 `reason: 'outdated'` 指页面上的构建器比服务器更老,服务器不再使用其保存. 它不能重试;构建者向shoper提供一页重载,它加载了最新的构建者,并携带了未保存的设计可以穿过的地方.

构建器仅在被问到时保存:它的保存按钮 Ctrl/Cmd+S,它的近快提示,或者您的 `save()`. 在此之前,未保存的工作作为草稿保存在设备上(每个用户,从不发送到服务器).

`onCloseRequested({ productId?, hasUnsavedChanges, discarded })` 直升机关了建筑工就开火 在未保存的更改中, 构建者首先询问保存 / 不保存 / 取消 : 一旦保存和图像完成, 请保存关闭 `discarded: true` (不要再问了),取消保留打开。 您的页面不需要自己的未保存的更改提示 .

其他回调 : `onStatusChange({ status, step?, message?, error? })` (装入进度,从不保存). `status: 'error'` 当建设者自己的部分代码无法下载时, 也会开火; 然后, 建设者会显示一个 **重新装入页面** 按钮.

## 角质

```ts
@Component({ selector: 'app-designer', template: '<div #target style="height: 100%"></div>' })
export class DesignerComponent implements OnDestroy {
  @Input({ required: true }) productRef!: string;
  @ViewChild('target', { static: true }) target!: ElementRef<HTMLElement>;
  private instance?: BuilderInstance;

  constructor() {
    afterNextRender(async () => {
      const { createBuilder } = await import('@3dn-builder/builder'); // browser only
      const builder = createBuilder({ session, login, onSaved: (s) => this.saved(s) });
      this.instance = await builder.mount({ target: this.target.nativeElement, hostProductId: this.productRef });
    });
  }

  ngOnDestroy() {
    this.instance?.destroy();
  }
}
```

## 测试您的整合

```ts
import { installFakeBuilder, findFakeBuilders } from '@3dn-builder/builder/testing';

installFakeBuilder(); // before mount(): no real builder is loaded
const instance = await builder.mount({ target, hostProductId: 'mug' });
const saving = instance.save();
await findFakeBuilders()[0].emitSavedAsClone('clone-1');
await saving; // customization.record(), onSaved and onImagesSaved have run
```

`emitSaved()` 财务报告和审定财务报表 `emitSavedAsClone()` 发送图像结果与构建者一样; `emitImagesSaved()` 财务报告和审定财务报表 `emitImagesSaveFailed()` 自己派一个.

## 开发此软件包

```sh
npx nx test builder-host
npx nx lint builder-host
npx nx build builder-host   # dist/libs/builder-host
```

事件名称和有效载荷类型来自 `@three-dn/constants` 并捆绑在已公布的文件中。 从根部印出版本 `package.json`; 数据 `publish-sdk` 任务在 `.github/workflows/deploy.yml` 发布每期作品.

## 常见问题

### @3dn-builder/builder 是什么？

将3DN产品构建器嵌入到任何商店前端:加载,登录,许可证刷新,保存和定制记录\.

### 如何安装 @3dn-builder/builder？

在项目目录运行 npm install @3dn-builder/builder，或使用 pnpm add / yarn add / bun add。

### @3dn-builder/builder 支持 TypeScript 吗？

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

### @3dn-builder/builder 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @3dn-builder/builder 可以商用吗？

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

### @3dn-builder/builder 的下载量有多少？

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

### @3dn-builder/builder 还在维护吗？

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

