@3dn-builder/builder

中文文档
0.713.0发布于 2026/11/07MITTypeScriptES Module零依赖近 30 天下载 1万

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

中文使用文档
文档目录11 节
  1. 安装
  2. 创建、挂载、销毁
  3. 会议
  4. 登录
  5. 保存
  6. 命令
  7. 特征
  8. 错误
  9. 角质
  10. 测试您的整合
  11. 开发此软件包

@ 3dn- 建设者/ 建设者

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

安装

npm install @3dn-builder/builder

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

创建、挂载、销毁

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() 已经返回.

会议

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() 拒绝任何看起来像一个, 和任何选项 命名建设者加载从.

登录

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) 说明是否在这个设备上保留了草稿 .

保存

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不拥有的产品,因此复制件取代了开放设计.

命令

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

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开关,动画滑行器,相机角度和下载打印文件,没有编辑工具),在没有登录的情况下下载其打印文件,例如用于打印行. 没有任何东西可以通过它保存或复制.

特征

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_BROWSERload() 或者说 mount() 在安全部门改革期间.
LOAD_FAILED建造者没有加载; 下一次调用重试 .
VERSION_CONFLICT另一个构建器版本已经在页面上运行.
SESSION_FAILEDsession.get() 失败或返回无效会话.
LICENSE_ERROR该许可证被拒绝。 使登山者死亡; onLicenseError 名为.
LOGIN_CANCELLED直升机没有登录.
SAVE_FAILED保存失败, 或 customization.record() 失败( e)reason: 'customization') (中文(简体) ).
SAVE_TIMEOUT内部无结果 saveTimeoutMs。 。 。 .
EXPORT_FAILED, (中文(简体) ), EXPORT_TIMEOUTexternalExport.run() 失败或超时 .
DESTROYEDdestroy() 在电话待发时跑掉了.

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' 当建设者自己的部分代码无法下载时, 也会开火; 然后, 建设者会显示一个 重新装入页面 按钮.

角质

@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();
  }
}

测试您的整合

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() 自己派一个.

开发此软件包

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 共发布 77 个版本,首次发布于 2026/10/10;过去 12 个月发布了 77 个版本。

版本发布日期距今
0.713.0latest2026/11/07今天
0.712.02026/11/07今天
0.711.02026/11/071 天前
0.709.02026/11/061 天前
0.708.02026/11/052 天前
0.707.02026/11/052 天前

关于 @3dn-builder/builder 的常见问题

@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 和提交记录判断。