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

@cqsjjb/website-platform-sdk

v1.0.5

Published

Website platform iframe SDK (open auth, SM2 config)

Downloads

616

Readme

@cqsjjb/website-platform-sdk

在业务页面中嵌入建站站点(建站系统页面)的浏览器端 SDK:通过开放账号接口完成用户鉴权(含 SM2 加密 config),并在页面容器内挂载 iframe,加载建站预览页;新用户会先出现授权确认,再继续创建账号。


特性

  • ESM:适用于 Vite、Webpack 5、Create React App(配合配置)等现代打包工具,或原生 <script type="module">
  • TypeScript:提供类型声明,便于在 TS 项目中获得提示。
  • 开放账号流程getUserInfo →(无用户数据则)授权弹窗createUser → 拼接 iframe 地址并挂载。
  • 事件回调:鉴权各阶段、授权确认/取消、挂载/卸载均可订阅。
  • 依赖sm-crypto 会随本包安装,用于对 config 做 SM2 加密,无需再单独引入 CDN 版本。

环境要求

  • 浏览器(需 fetchdocument、iframe 等 DOM API)。
  • 建议使用 HTTPS 或与接口同策略的部署环境;跨域与 Cookie 策略由后端与浏览器共同决定。

安装

npm install @cqsjjb/website-platform-sdk

安装后请确保工程能解析 ESM(主流前端脚手架默认支持)。不要用 file:// 直接打开本地 HTML,否则 ES 模块可能被浏览器拦截;本地预览请使用 dev server(如 npm run dev)或 npx serve 等。


使用示例

以下示例中,platformOriginappkeyconfighost 请替换为与后端约定的实际值(platformOrigin 为建站站点根地址,开放账号接口与嵌入页同源)。

React(函数组件 + Hooks)

import { useEffect, useRef } from 'react';
import { createWebSite } from '@cqsjjb/website-platform-sdk';
import type { Website } from '@cqsjjb/website-platform-sdk';

export function WebsitePlatformEmbed() {
  const containerRef = useRef<HTMLDivElement>(null);
  const websiteRef = useRef<Website | null>(null);

  useEffect(() => {
    const el = containerRef.current;
    if (!el) return;

    const website = createWebSite({
      platformOrigin: 'https://你的建站站点根地址',
      appkey: '你的 appkey',
      sm2PublicKeyDerHex: '基座提供的 SM2 公钥 DER(十六进制)',
      config: {
        username: 'user001',
        tenantId: '租户 ID',
        clientId: '客户端 ID',
        siteId: '站点 ID',
        // 其余字段与后端约定一致
      },
      host: typeof window !== 'undefined' ? window.location.origin : '',
    });

    website.on('mount', () => {
      console.log('iframe 已挂载');
    });
    website.on('getUserInfo:error', (_w, detail) => {
      console.error('获取用户信息失败', detail?.err);
    });

    website.mount(el, {
      width: '100%',
      height: '600px',
      style: { border: 'none' },
    });

    websiteRef.current = website;

    return () => {
      website.unmount();
      websiteRef.current = null;
    };
  }, []);

  return <div ref={containerRef} style={{ width: '100%', minHeight: 400 }} />;
}

要点:

  • ref 拿到挂载容器,在 useEffect 里调用 mount,避免重复创建实例时可把 createWebSite 放进 effect 或配合 useMemo/useRef 存实例。
  • effect 清理函数里调用 website.unmount(),防止路由切换或组件卸载后残留 iframe 与监听。

Vue 3(<script setup>

<template>
  <div ref="containerRef" class="embed-wrap"></div>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { createWebSite } from '@cqsjjb/website-platform-sdk';
import type { Website } from '@cqsjjb/website-platform-sdk';

const containerRef = ref<HTMLDivElement | null>(null);
let website: Website | null = null;

onMounted(() => {
  const el = containerRef.value;
  if (!el) return;

  website = createWebSite({
    platformOrigin: 'https://你的建站站点根地址',
    appkey: '你的 appkey',
    sm2PublicKeyDerHex: '基座提供的 SM2 公钥 DER(十六进制)',
    config: {
      username: 'user001',
      tenantId: '租户 ID',
      clientId: '客户端 ID',
      siteId: '站点 ID',
    },
    host: typeof window !== 'undefined' ? window.location.origin : '',
  });

  website.on('mount', () => {
    console.log('iframe 已挂载');
  });
  website.on('getUserInfo:error', (_w, detail) => {
    console.error('获取用户信息失败', detail?.err);
  });

  website.mount(el, {
    width: '100%',
    height: '600px',
    style: { border: 'none' },
  });
});

onBeforeUnmount(() => {
  website?.unmount();
  website = null;
});
</script>

<style scoped>
.embed-wrap {
  width: 100%;
  min-height: 400px;
}
</style>

要点:

  • onMounted 中执行 mount,此时模板已渲染,ref 已指向 DOM。
  • onBeforeUnmount 中调用 unmount(),与页面或组件生命周期对齐。

传统 HTML(原生 ES Module)

页面需通过 HTTP/HTTPS 访问(本地可用任意静态服务)。在页面中增加容器,并用 type="module" 的脚本从 node_modules 引入(路径按实际安装位置调整,打包到静态资源后也可用相对路径)。

<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8" />
  <title>建站站点嵌入示例</title>
</head>
<body>
  <div id="embed-root" style="width:100%;height:600px;border:1px solid #ccc;"></div>

  <script type="module">
    import { createWebSite } from './node_modules/@cqsjjb/website-platform-sdk/dist/index.js';

    const container = document.getElementById('embed-root');
    if (!container) throw new Error('找不到容器');

    const website = createWebSite({
      platformOrigin: 'https://你的建站站点根地址',
      appkey: '你的 appkey',
      sm2PublicKeyDerHex: '基座提供的 SM2 公钥 DER(十六进制)',
      config: {
        username: 'user001',
        tenantId: '租户 ID',
        clientId: '客户端 ID',
        siteId: '站点 ID',
      },
      host: window.location.origin,
    });

    website.on('mount', () => console.log('iframe 已挂载'));
    website.on('getUserInfo:error', (_w, d) => console.error(d?.err));

    website.mount(container, {
      width: '100%',
      height: '100%',
      style: { border: 'none' },
    });

    // 若需要在离开页面前卸载,可绑定 beforeunload 或你自己的导航逻辑:
    // window.addEventListener('beforeunload', () => website.unmount());
  </script>
</body>
</html>

若使用 Vite / Webpack 等多文件打包,通常不写死 node_modules 路径,而是在入口 JS 里写 import { createWebSite } from '@cqsjjb/website-platform-sdk',由打包器解析,再引入打包后的单文件脚本。


API 说明

createWebSite(options: WebsiteOptions): Website

创建 Website 实例。

| 字段 | 类型 | 说明 | |------|------|------| | platformOrigin | string | 必填。建站站点根地址(与开放账号接口、iframe 嵌入页同源),如 https://platform.example.com。末尾 / 可写可不写,SDK 会规范化。 | | appkey | string | 必填。开放应用 appkey。 | | sm2PublicKeyDerHex | string | 必填。SM2 公钥的 X.509 DER 十六进制串(与后端解密用私钥对应),用于加密 config。 | | config | Record<string, unknown> | 可选。业务配置,将 JSON 序列化后经 SM2 加密 传给开放接口(字段名与后端约定一致)。嵌入建站预览页时还需 siteIdtenantId 等,与 buildPlatformIframeSrc 规则一致。 | | host | string | 可选。请求体中的 host,一般填当前业务站点或后端认可的来源地址。 |


website.mount(container, options?)

将 SDK 挂到 一个 DOM 容器上,内部会异步请求开放接口并在成功后插入 iframe

参数

  • containerHTMLElement | null。一般为 div 等块级容器;为 null 时会在控制台报错并中止。
  • optionsMountOptions,可选:

| 字段 | 类型 | 说明 | |------|------|------| | style | Record<string, string> | 应用到 iframe 的 CSS 行内样式(如 border: 'none')。 | | width | string | iframe 宽度,如 '100%''800px'。 | | height | string | iframe 高度。 | | attrs | Record<string, string> | 额外 HTML 属性(如 idtitle)。 |

流程概要

  1. 展示「正在获取用户信息…」Loading。
  2. 调用 getUserInfo;失败则触发 getUserInfo:error 并结束。
  3. 若返回中 没有用户数据!res.data):关闭 Loading → 展示 授权确认(确认 / 取消)。
    • 确认:触发 auth:confirm,再 Loading「正在创建用户…」,调用 createUser
    • 取消:在容器内展示「您已取消授权」文案,触发 auth:cancel不再创建用户、不挂 iframe。
  4. 若有用户数据或 createUser 成功拿到 data:根据 dataconfig 拼接建站预览页 URL(见 buildPlatformIframeSrc),插入 iframemounted = true,触发 mount

website.unmount()

卸载 iframe 并清空与本次挂载相关的内部状态;触发 unmount 事件。若当前未成功挂载 iframe,会在控制台提示错误。


实例属性(赋值即更新 iframe)

iframe 已存在 时,以下 setter 会同步到 DOM。

| 属性 | 说明 | |------|------| | website.width | 字符串,如 '100%'。 | | website.height | 字符串。 | | website.style | 行内样式对象。 | | website.attrs | HTML 属性对象。 |


buildPlatformIframeSrc(data, platformOrigin, config?): string

根据开放接口返回的 用户态 与创建实例时的 config 生成建站预览页 URL(与 SDK 内部挂载 iframe 时一致)。第二参数可与 createWebSite 时一致,或传 website.platformOrigin;第三参数与 createWebSite({ config }) 一致,可省略(默认 {}),但预览路径需要 config.siteIdconfig.tenantId 等字段。

  • 路径{platformOrigin}/official-website-design/container/Preview/{clientId}/{tenantId}/{siteId}
  • clientIddata.clientIdconfig.clientId 取其一或合并(与实现一致)。
  • 查询参数:附带 token(来自 data.token)。

适用于需要自行打开新窗口或预校验 URL 的场景。

normalizePlatformOrigin(origin): string

去掉首尾空白与末尾 /,与 SDK 内部拼接开放接口、iframe 地址时的规范化规则一致;若你在配置中心存的是带尾斜杠的 URL,可先经此函数再传入 platformOrigin(也可直接传入,构造函数内会再次规范化)。


事件

使用 website.on(eventName, callback) 订阅。回调签名为 (website, detail?)(第一个参数为当前 Website 实例)。

| 事件名 | 触发时机 | detail 大致内容 | |--------|----------|-------------------| | getUserInfo:start | 即将请求 getUserInfo | { authOpts } | | getUserInfo:success | getUserInfo HTTP 成功且已解析 JSON | { res, authOpts } | | getUserInfo:error | getUserInfo 抛错或 HTTP 非 2xx | { err, authOpts } | | auth:confirm | 用户点击「确认授权」后、请求 createUser 前 | { authOpts } | | auth:cancel | 用户点击「取消」 | { authOpts } | | createUser:start | 即将请求 createUser | { authOpts } | | createUser:success | createUser 成功 | { res1, authOpts } | | createUser:error | createUser 失败 | { err, authOpts } | | mount | iframe 已插入容器并完成绑定 | 无额外载荷(回调第一个参数仍为 Website 实例) | | heartbeat:start | iframe 挂载后心跳定时器启动(仅当 token 存在时) | 无额外载荷 | | token:expired | 心跳检测到 token 失效 | 无额外载荷(会同步隐藏 iframe 并弹出「重新授权」对话框) | | unmount | 调用 unmount() 并完成清理 | 无额外载荷 |

使用 website.off(eventName) 可移除对应监听。


TypeScript

包导出类型包括:WebsiteOptionsMountOptionsAuthOptsWebsiteUserDataOpenAccountEnvelope 等。

import {
  createWebSite,
  buildPlatformIframeSrc,
  normalizePlatformOrigin,
  type WebsiteOptions,
} from '@cqsjjb/website-platform-sdk';

const origin = normalizePlatformOrigin('https://platform.example.com/');
const url = buildPlatformIframeSrc(userData, origin, {
  tenantId: '租户 ID',
  siteId: '站点 ID',
  clientId: '客户端 ID',
});

与后端约定

  • platformOrigin 决定开放账号接口与 iframe 的基址,须与当前环境建站站点部署地址一致(测试 / 生产分别配置)。
  • config 字段须与后端解密、验签规则一致(SM2 加密由本包在浏览器侧完成)。
  • 若贵司接口在 HTTP 层之外还有业务错误码约定,请在业务代码中根据返回体自行处理(例如统一提示)。

常见问题

1. 页面里 import 报错 / 模块找不到
请通过 开发服务器或静态站点 访问页面,不要使用 file:// 打开含 ES Module 的 HTML。

2. 安装后没有类型提示
确认已正确安装依赖,且 IDE 使用的是包内的类型入口(由 package.json"types" 字段指定)。

3. 新用户一直停在 Loading
检查网络、开放接口是否可达,以及 platformOrigin / appkey / config / host 是否与当前环境一致。

4. 授权成功但无法显示 这可能是跨域问题导致,需要联系技术人员处理。


开源协议

ISC(见发布包内 package.jsonlicense 字段)。