@jitto/analyze-embed

中文文档
0.4.0发布于 2026/11/01SEE LICENSE IN LICENSETypeScriptES Module零依赖

在你的web应用中嵌入Jitto仪表板,用React或纯JavaScript。

中文使用文档
文档目录13 节
  1. 安装
  2. 快速入门
  3. 反应: <JittoDashboard>
  4. 纯JavaScript: mountJittoDashboard
  5. 令牌
  6. 事件
  7. 大小
  8. 过滤器
  9. 主题
  10. 错误和故障排除
  11. 支持的浏览器和框架
  12. 版本控制
  13. 完整的指南和API参考

@jitto / analyze-embed

导游: GUIDE.md,将您从一无所有变成嵌入式仪表板。

在您自己的web应用程序中为您自己的登录用户显示Jitto仪表板,使用React或纯JavaScript。 每个用户只能看到Jitto的行规则允许的行;您的页面从不包含Jitto密码或秘密。

状态:0.4。 预计在1.0之前会有一些小的变化。每个版本都有哪些变化: CHANGELOG.md.

暂不可用: filterChanged 为你的应用设置的过滤器触发(source: 'host');更改用户 过滤栏中的make还没有报告。本自述文件中的其他所有内容都按照描述工作。

过滤器需要Jitto服务器列出它们。 通过 filters (或称 setFilters)只有一次您的Jitto服务器 返回 filter_bar 在它象征性的回答中。在那之前,每个过滤器都被拒绝了 filters 结尾 failed 仪表板无法加载。在0.2.0中 filters 选项被忽略了。

安装

npm install @jitto/analyze-embed

一个包裹,两个入口 @jitto/analyze-embed (纯JavaScript)和 @jitto/analyze-embed/react (反应)。 两者都运行在相同的核心上,所以相同的选项给出相同的事件。包括TypeScript声明。

快速入门

  1. 从Jitto租户管理员那里获得三样东西: 租户的Jitto主机(例如) https://example-tenant.jittocloud.com; -uat 和 -dev 主机为其他环境),仪表板的id,并确认您的网站的来源(例如 https://portal.client.example)是基于承租人的合法来源。起源是准确的: https://,主机,可选 端口。
  2. 安装: npm install @jitto/analyze-embed.
  3. 写 fetchToken (见 令牌):它要求Jitto使用已登录用户自己的仪表板令牌 从您的登录库访问令牌。
  4. 安装仪表板:
import { JittoDashboard } from '@jitto/analyze-embed/react';

export function DeskOverview() {
  return (
    <JittoDashboard
      dashboardId="3f0c6a52-8d1e-4b7a-9c2f-5e8d71a4b6c0"
      embedOrigin="https://example-tenant.jittocloud.com"
      fetchToken={fetchToken} // see Tokens: it sends the user's own access token
      style={{ height: 600 }}
    />
  );
}

以测试用户身份打开该页。您将看到该用户的行。

反应: <JittoDashboard>

import { useRef } from 'react';
import { JittoDashboard } from '@jitto/analyze-embed/react';
import type { JittoDashboardHandle } from '@jitto/analyze-embed';

export function Report() {
  const dashboard = useRef<JittoDashboardHandle>(null);
  return (
    <JittoDashboard
      ref={dashboard}
      dashboardId="3f0c6a52-8d1e-4b7a-9c2f-5e8d71a4b6c0"
      embedOrigin="https://example-tenant.jittocloud.com"
      fetchToken={fetchToken}
      theme={{ mode: 'light', colorPrimary: '#0b7a75' }}
      onLoaded={({ durationMs }) => console.log(`loaded in ${durationMs} ms`)}
      onFailed={({ reason, message }) => console.warn(reason, message)}
      onSizeChanged={({ height }) => console.log('frame height', height)}
      className="report"
    />
  );
}
道具类型要求它是做什么的
dashboardIdstring是租户管理员提供给您的Jitto仪表板id。
embedOriginstring是您的租户的Jitto主机,作为来源(https://example-tenant.jittocloud.com). SDK帧只有这个原点后面跟着 /embed (API的 embed_url),只对这个起源说话。它不能从其他任何东西中获得宿主。
fetchToken(dashboardId, signal) => Promise<EmbedTokenResponse>是获取具有自己访问令牌的已登录用户的指示板令牌。看到 令牌.
filtersFilters否在第一次渲染之前应用的过滤器,按过滤器名称。被拒绝的人以 failed. 看到 过滤器.
themeThemeTokens否颜色、字体、浅色或深色。看到 主题.
tokenDeadlineMsnumber否一个令牌请求的截止日期。默认的 20000.
loadDeadlineMsnumber否之前框架可以保持沉默多久 failed 理性地燃烧 network。默认的 30000。未显示的挂载(如隐藏选项卡中的挂载)将等待,直到它显示出来。
retryDelaysMsreadonly number[]否在每次重试可重试令牌失败(429,500,502,deadline, network)之前等待。默认的 [2000, 5000, 15000]。在山上, Retry-After 超过60秒没有等待; failed 火灾。
fetchDownload(request, signal) => Promise<Response>否已弃用并被忽略: download() 询问仪表板,仪表板在自己的会话上进行下载。已在下一个小版本中删除。
downloadDeadlineMsnumber否截止日期 download(),包括仪表板等待PDF。默认的 180000.
onLoaded(e) => void否仪表板呈现。看到 事件.
onFailed(e) => void否仪表板无法加载或停止工作。
onFilterChanged(e) => void否应用了应用程序设置的过滤器(source: 'host')。
onFilterRejected(e) => void否仪表板拒绝过滤来自 setFilters 或者改变了 filters 道具。没有任何应用。换道具这是唯一的报告。
onSizeChanged(e) => void否页面上仪表板框架的大小发生了变化。看到 大小.
classNamestring否容器元素的类。
styleRecord<string, string | number>否容器元素的样式。给它一个高度。
refRef<JittoDashboardHandle>否相同的手柄 mountJittoDashboard 的回报。

如何更改道具:

  • 改变为 dashboardId 或者 embedOrigin 重新安装仪表板。
  • theme 是按值比较的。相等的值没有任何作用,因此内联对象是安全的。另一个值是 就地应用,如 setTheme 会。删除 theme 改变不了什么:一个主题可以替换,不能删除,所以 仪表板保持其当前外观。
  • filters 太按值比较了,键序被忽略了,所以呢 filters={{ Ccy: userCcy }} 是安全的内联。一个不同的 值被应用为 setFilters 会;拒绝电话 onFilterRejected 过滤器实际上会保留下来。删除 filters 改变不了什么;通过 {} 清除你的应用设置的每个过滤器。使用道具或手柄 setFilters 对于过滤器,不能两者都用。
  • 回调函数、令牌函数和截止日期在使用时被读取。新函数在下一次使用时生效, 没有重新安装。

该组件仅在浏览器中挂载。在服务器渲染的应用程序中,在客户端渲染它。

纯JavaScript: mountJittoDashboard

import { mountJittoDashboard } from '@jitto/analyze-embed';

const element = document.getElementById('dashboard');
if (!element) throw new Error('no #dashboard element on the page');

const dashboard = mountJittoDashboard(element, {
  dashboardId: '3f0c6a52-8d1e-4b7a-9c2f-5e8d71a4b6c0',
  embedOrigin: 'https://example-tenant.jittocloud.com',
  fetchToken,
  onFailed: ({ reason, message }) => console.warn(reason, message),
});

const stop = dashboard.on('loaded', ({ durationMs }) => console.log(`loaded in ${durationMs} ms`));

// Later, when your app's own controls change:
export function useDarkTheme() {
  dashboard.setTheme({ mode: 'dark' });
}

// When your page or view goes away:
export function teardown() {
  stop();
  dashboard.unmount();
}

mountJittoDashboard(element, options) 使用与React props相同的选项和回调(除了 className, style 和 ref)并返回句柄:

成员它是做什么的
dashboardId仪表盘id显示了这个挂载。
setFilters(filters)替换你的应用设置的过滤器。返回一个承诺,一旦仪表板应用它们就会解析;然后 filterChanged 火灾与 source: 'host'. 看到 过滤器.
setTheme(theme)替换适当的主题标记。帧不会重新加载。
download(format, options)将指示板下载为 pdf,或一个图表作为 csv (与 chartId),就像仪表板自己的下载菜单一样,过滤器在仪表板中生效。SDK询问仪表板,仪表板在自己的会话中下载;你的应用程序不发送请求。行是用户自己的。拒绝。 DownloadError。参见指南 添加下载按钮.
on(event, handler)订阅一个事件。返回一个取消订阅的函数。
unmount()删除指示板并取消挂起的令牌请求和计时器。打两次电话是安全的。

这个 setFilters 承诺总能解决问题。它拒绝了 SetFiltersError 谁的 outcome 是:

  • deadline:内部没有应用过滤器 loadDeadlineMs. failed 理性地燃烧 network 和 安装结束。没有显示的仪表板(在隐藏的选项卡中)得到另一个 loadDeadlineMs 代替。
  • ended山先结束了,或者已经结束了。
  • replaced稍后 setFilters 电话是在这个应用之前打来的。

如果仪表板拒绝输入名称或值, setFilters 拒绝。 FilterError 相反,并没有应用任何东西。 它的 code 是 unknown_filter 或者 invalid_filter_value, filterNames 列出被拒绝的名字和 knownFilterNames 列出仪表板拥有的每个过滤器。 filterRejected 触发同样的错误。之前打过的电话 第一个令牌到达等待它:然后按调用顺序根据令牌的筛选器列表检查名称。

令牌

您的页面向Jitto请求一个带有登录用户自己的访问令牌的短期指示板令牌,即您的 登录库已经成立。该令牌是用户的身份:在后端没有令牌端点,没有 共享帐户,没有秘密,您的代码从不说明用户是谁或他们可能看到什么。

  1. SDK调用您的 fetchToken(dashboardId, signal) 挂载一次,并在令牌生命周期的80%(最多)时再次挂载一次 大约24.8天后,这是浏览器计时器所能保持的最长延迟)。

  2. 你的 fetchToken 从浏览器向Jitto发送用户自己的访问令牌:

    POST /api/v1/embed-tokens HTTP/1.1
    Host: example-tenant.jittocloud.com
    Origin: https://portal.client.example
    Authorization: Bearer <the user's own access token>
    Content-Type: application/json
    
    {"dashboard_id": "3f0c6a52-8d1e-4b7a-9c2f-5e8d71a4b6c0"}
    
  3. Jitto根据您的租户的身份提供程序(发行者、签名、受众、到期)检查令牌,读取 用户组,并应用租户管理员存储在Jitto中的行规则。它检查 Origin 针对您的租户允许的来源,并仅针对这些来源回答浏览器的CORS预飞行。

  4. Jitto用一个能活5分钟的仪表盘代币来回答。答案是 Cache-Control: no-store:

    {
      "token": "<opaque>",
      "dashboard_id": "3f0c6a52-8d1e-4b7a-9c2f-5e8d71a4b6c0",
      "embed_url": "https://example-tenant.jittocloud.com/embed",
      "expires_in": 300
    }
    
  5. 你的 fetchToken 将它与SDK的字段名一起交给SDK (dashboardId, embedUrl, expiresIn, filterBar 当答案 filter_bar(仪表板的过滤器),值不变。SDK将检查答案 它自己,用理智拒绝错误的人 token.

当出现错误时,Jitto用HTTP状态和问题体(code, correlation_id),以及 Retry-After 在429路上。对于其他受众或来自其他发行者的过期令牌,将使用401拒绝 unauthenticated (原因 token);没有行规则读取的组中的用户得到403 no_group (原因 permission)。 您的租户管理员向Jitto注册您的身份提供程序一次。

你的 fetchToken 拒绝带有状态和API的HTTP错误 code。这段代码是用来测试的 401、403、422、429、502和错误的答案。 getAccessToken() 您的登录库是:

async function fetchToken(dashboardId, signal) {
  const r = await fetch('https://example-tenant.jittocloud.com/api/v1/embed-tokens', {
    method: 'POST',
    signal,
    cache: 'no-store',
    headers: {
      Authorization: `Bearer ${await getAccessToken()}`, // the signed-in user's own token, from your sign-in library
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ dashboard_id: dashboardId }), // nothing else: Jitto reads who the user is from the token
  });
  const body = await r.json().catch(() => null);
  if (!r.ok) {
    const retryAfter = Number(r.headers.get('Retry-After'));
    throw Object.assign(new Error(`token request failed with HTTP ${r.status}`), {
      status: r.status,
      code: body?.code,
      correlationId: body?.correlation_id,
      retryAfterSeconds: retryAfter > 0 ? retryAfter : undefined,
    });
  }
  if (!body || typeof body !== 'object') return body; // the SDK refuses it with reason `token`
  const answer = { token: body.token, dashboardId: body.dashboard_id, embedUrl: body.embed_url };
  if ('expires_in' in body) answer.expiresIn = body.expires_in;
  if ('filter_bar' in body) answer.filterBar = body.filter_bar; // the dashboard's filters; without it, filters are refused
  return answer; // the SDK checks it and refuses a wrong answer with reason `token`
}

事件

订阅 on… Props或回调,或with handle.on(name, handler).

事件回调有效载荷当
loadedonLoaded{ dashboardId, durationMs }第一次挂载后渲染的仪表板。
failedonFailed{ dashboardId, reason, message, status?, code?, correlationId? }指示板无法加载,令牌刷新失败,或者 setFilters 重新加载没有及时渲染。每座坐骑最多发一次火;然后挂载完成,SDK在其位置显示一条简短的Jitto消息。重新挂载以重试。
filterChangedonFilterChanged{ dashboardId, filters, source }过滤器的效果改变了:每次应用一次 setFilters 电话或 filters 道具变更 source: 'host'. 'user' (过滤栏的更改)尚未报告。
filterRejectedonFilterRejected{ dashboardId, error }仪表板拒绝过滤来自 setFilters 或者改变了 filters 道具。 error 是 FilterError 电话拒绝了。没有应用任何内容,仪表板也没有重新加载。
sizeChangedonSizeChanged{ dashboardId, width, height }页面上仪表板框架的大小发生了变化。看到 大小.

reason 是其中之一 token, permission, network 和 not_found.

大小

给容器一个高度,比如窗口的高度减去页面的页眉。仪表板框架采用 仪表盘自身的高度:

  • 永远不要比容器高:一个更高的仪表板在框架内滚动,所以它的过滤条,信息和 对话框留在屏幕上;
  • 永远不要短于容器或600px,以较短者为准,这样较短的仪表板可以为它的过滤条保留空间 和对话框。在那下面,框架结束在仪表板做。

sizeChanged 报告页面上框架的大小。您可以调整容器的大小,这样在a下面就没有空间了 短仪表板;这永远不会使框架比容器高。

过滤器

过滤器设置仪表板首先显示的内容,根据其过滤栏使用的名称(例如 Ccy, Trade Date & Time),没错,包括案例在内。

  • 把它们放在mount上 filters,然后是 setFilters (或者是新的 filters 道具)。
  • 名称与令牌一起出现:Jitto的回答列出了仪表板的过滤器 filter_bar,每一个 name 和一个 kind,你呢? fetchToken 将其作为 filterBar。没有它,每个过滤器都被拒绝。
  • 只向具有过滤器的仪表板发送过滤器。指示板缺少的名称将使用 FilterError等等 安装仪表板不加载;它永远不会被忽略,因此仪表板永远不会显示未经过滤的数据。
  • 一个值是一个字符串,数字或布尔值,一个列表(几个值),一个日期范围 { from, to } (两天写好) YYYY-MM-DD,例如 2026-06-30, from 之前或之前 to(两者都包括在内),或者 null 清除过滤器。 过滤器接受的值取决于它的值 kind:多项选择过滤器上的值列表,正好是两个 数字 [min, max] 在数字范围上,日期范围仅在日期范围过滤器上。
  • 列表最多包含1000个值,字符串最多包含256个字符,这是仪表板和Jitto的限制 导出API,因此 download() 从来没有拒绝过他们。超过它们的价值是被拒绝的 invalid_filter_value, 设置超过50个过滤器的调用也是如此。不能设置名称大于255个字符的过滤器。
  • setFilters 替换你的应用设置的每个过滤器:你遗漏的名称会回到仪表板自己的默认值。
  • 过滤器按名称在仪表板的地址中传播,一旦编码,该地址最多容纳4096字节。一个 需要更多的电话(多项选择过滤器上的长列表)被立即拒绝 invalid_filter_value, 单独为过滤器命名太长(名称和值),否则为其列表值过滤器命名,否则为每个过滤器命名。
  • 与任何地址一样,仪表板可以出现在Jitto主机的访问日志中,包括过滤器名称和值。 传递用户选择的值(货币、日期),而不是秘密或个人数据。
  • download() 在仪表板中给出过滤器生效的文件:那些是你的应用程序设置的,以及用户自己的 过滤器条的变化,因为。
  • 过滤器缩小了视图。它们不是安全保障。 用户可以在过滤栏中更改它们。用户可能会看到什么 只能由日本柔道的排位规则来决定。
  • 今天 setFilters 重新加载框架内的仪表板。您的页面保持挂载状态,并且没有请求新的令牌, 但是用户自己的过滤条会改变,滚动条的位置会重置。如果可以的话,在mount上设置过滤器。

主题

主题令牌可以改变颜色、字体和浅色或深色。Jitto保持布局;没有CSS钩子。

令牌它改变了什么
mode'light' 或者 'dark'.
colorPrimary按钮,选择的状态,链接。
colorBackground仪表板的页面背景。
colorSurface图表和过滤卡背景。
colorText正文。
colorBorder边界和分隔物。
fontFamily一个CSS font-family 列表。该字体必须已经可以被仪表板主机加载。

颜色是CSS颜色字符串(#1a73e8, rgb(…)). 其他任何内容都会被控制台警告忽略。 setTheme 永远不要重新加载框架。

错误和故障排除

每一次失败都是一次失败 failed 事件有以下四个原因之一。 status, code 和 correlationId 来自 当API回答时;报价的 correlationId 当你向吉托求助时。

原因常见的原因该怎么做
token用户的令牌被拒绝(401 unauthenticated(过期、受众错误、发行方错误);令牌请求太多(429) rate_limited,重试);里面没有令牌 tokenDeadlineMs;另一个仪表盘的答案或者 embedUrl 那不是你的 embedOrigin 紧随其后的是 /embed.检查用户是否已登录,您的登录库是否返回当前令牌。检查 embedOrigin。每次页面视图请求一个令牌,并让SDK刷新。
permission仪表板不在租户的可嵌入列表中(403) not_embeddable);你的原产地是不允许的 origin_not_allowed);用户不属于任何组,行规则读取(403) no_group);仪表板的数据集没有行规则(422) row_rules_incomplete);嵌入未打开(503) embedding_not_configured)。请您的租户管理员修复设置 code 的名字。
not_found没有这个id的仪表盘(404) unknown_dashboard)。检查 dashboardId.
network没有应答,服务器错误(500,502,重试第一次),拒绝CORS预飞行,或帧保持沉默 loadDeadlineMs。令牌请求上的CORS错误,或者 frame-ancestors 错误,在浏览器控制台中表示不允许页面的起源。检查网络。对于CORS或 frame-ancestors 如果出现错误,则要求按照浏览器显示的方式添加您的原点(localhost 和 127.0.0.1 不同,端口也不同)。

其他症状:

你看到导致修复
仪表板加载时没有行用户组不匹配行规则询问您的租户管理员要读取哪些组的行规则。
没有错误的空白区域容器没有高度把容器(style 或者 className)高度。
您自己的CSP会阻止帧或令牌请求你的 frame-src 或者 connect-src 不允许房客的Jitto主机添加你 embedOrigin (例如 https://example-tenant.jittocloud.com)。 frame-src 和 connect-src.

支持的浏览器和框架

建议1.0.0版本;端到端测试在发布前确认列表。

  • 浏览器: Chrome、Edge、Firefox和Safari当前和以前的主要版本。 页面必须被送达 https://,包括本地发展(例如 https://localhost:5173)。
  • 反应: 18和19,通过 @jitto/analyze-embed/react.
  • 一切 (Angular, Vue,服务器端渲染页面,没有框架):使用 mountJittoDashboard 从 @jitto/analyze-embed。专用的包装器可能遵循相同的核心。
  • 打字稿: 包括声明。每个选项、事件和有效负载都被键入。

版本控制

  • 软件包如下 语义版本控制。对选项、事件、有效负载或 故障原因是新主要版本。
  • 包的主版本与嵌入API的路径版本匹配: @jitto/analyze-embed 1.X与 /api/v1/ 只有。附加的API更改保留在v1中。
  • 已弃用的API版本回答为 Deprecation, Sunset 和 Link 头,至少90天之前,它是 移除。

完整的指南和API参考

  • 嵌入指南, GUIDE.md 在这个包中:整个流程,租户管理员的设置, 还有一份安全检查清单。
  • API引用,由嵌入API的OpenAPI 3.1契约生成。您的Jitto联系人提供了您的 租户。

两者都在1.0.0之前移到Jitto文档站点,然后本节链接到那里。

版本与发布记录

@jitto/analyze-embed 共发布 4 个版本,首次发布于 2026/10/27;过去 12 个月发布了 4 个版本。

版本发布日期距今
0.4.0latest2026/11/011 天前
0.3.02026/10/304 天前
0.2.02026/10/277 天前
0.0.0-stage2026/10/277 天前

关于 @jitto/analyze-embed 的常见问题

@jitto/analyze-embed 是什么?

在你的web应用中嵌入Jitto仪表板,用React或纯JavaScript。

如何安装 @jitto/analyze-embed?

在项目目录运行 npm install @jitto/analyze-embed,或使用 pnpm add / yarn add / bun add。

@jitto/analyze-embed 支持 TypeScript 吗?

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

@jitto/analyze-embed 支持 ESM 还是 CommonJS?

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

@jitto/analyze-embed 可以商用吗?

@jitto/analyze-embed 使用 SEE LICENSE IN LICENSE 许可。许可条款写在包内的独立文件中,请阅读该文件确认可否商用。以上为概括,不构成法律意见,请以许可原文为准。

@jitto/analyze-embed 还在维护吗?

最新版本 0.4.0 发布于 2026/11/01(1 天前);至今共发布 4 个版本,其中过去 12 个月发布了 4 个;首次发布于 2026/10/27。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。