@ codatum/ 嵌入
嵌入 Codatum 笔记本的核心类型SDK 已签名嵌入:在浏览器中创建iframe,从后端通过一个符号,处理参数和事件. 服务器侧式代币发行范围外.
文档数字 : 已签名嵌入 • 妇女 一体化 • 妇女 使用大小写。 。 。 . 包装器数字 : @codatum/embed-反应, (中文(简体) ), @ codatum/embed-vue。 。 。 .
安装
pnpm add @codatum/embed
# or
npm install @codatum/embed
快开始
import { createEmbed } from '@codatum/embed';
const embed = createEmbed({
container: '#dashboard',
embedUrl: 'https://app.codatum.com/protected/workspace/xxx/notebook/yyy',
tokenProvider: async () => {
// Issue a token in your backend and fetch it here
const res = await fetch('/api/codatum/token', { method: 'POST' });
const data = await res.json();
return { token: data.token };
},
});
await embed.init();
// cleanup
embed.destroy();
嵌入
EmbedOptions
| 财产 | 需求 | 说明 |
|---|---|---|
container | 对 | HTMLElement 插入 Iframe 的 CSS 选择器 |
embedUrl | 对 | 来自 Codatum 的已签名嵌入 URL |
tokenProvider | 对 | 见 提供符号 下级 |
iframeOptions | 没有 | 见 框架选项 下级 |
tokenOptions | 没有 | 见 选项 下级 |
displayOptions | 没有 | 见 显示选项 下级 |
devOptions | 没有 | 见 备选案文 下级 |
tokenProvider
需要从后端发出一个令牌并返回它(可选) params) (中文(简体) ). 来电 init(), (中文(简体) ), reload()当迹象即将到期的时候 tokenOptions.disableRefresh 实值 true) (中文(简体) ).
签署: (context: TokenProviderContext) => Promise<{ token: string; params?: EncodedParam[] }>
context.trigger—— 说'INIT'|'RELOAD'|'REFRESH'。 。 。 .context.markNonRetryable()- 调用未跳过重试( ignores)tokenOptions.retryCount) (中文(简体) ).params- 可选的。 如果返回, 则发送到嵌入符; 使用 参数马普encode()建造.
示例
tokenProvider: async (context) => {
const res = await fetch('/api/codatum/token', {
method: 'POST',
body: JSON.stringify({ tenant_id: currentUser.tenantId }),
});
if (!res.ok) {
if (res.status === 401) context.markNonRetryable();
throw new Error(`Token failed: ${res.status}`);
}
const data = await res.json();
const params = paramMapper.encode({
store_id: currentUser.defaultStoreId,
date_range: ['2025-01-01', '2025-01-31']
});
return { token: data.token, params };
}
IframeOptions
应用到 Iframe 元素并通过 URL/ search params 传递到嵌入式.
| 财产 | 类型 | 默认 | 说明 |
|---|---|---|---|
theme | 'LIGHT' | 'DARK'| 'SYSTEM' | 'SYSTEM' | 嵌入式笔记本的 UI 主题 |
locale | string | 浏览器的语言 | 地语区号( 如. 'en', (中文(简体) ), 'ja'用于嵌入式UI |
className | string | - 说吧 | Iframe 元素应用的 CSS 类名 |
style | object | {display: 'block', width: '100%', height: '100%', border: 'none'} | Iframe 的内置样式; 覆盖默认样式 |
attrs | Record<string, string> | - 说吧 | Iframe 的额外 HTML 属性( 例如 ). { title: 'Dashboard', 'data-testid': 'embed-iframe' }(中文(简体) ) |
TokenOptions
控制符号寿命, 刷新行为, 并加载超时 .
| 财产 | 类型 | 默认 | 说明 |
|---|---|---|---|
disableRefresh | boolean | false | 何时 true,禁用自动令牌在令牌过期前刷新 |
refreshBuffer | number | 60 | 自动重新激活时, 符号过期前秒数 |
retryCount | number | 2 | 令牌获取失败的重试次数; 0 = 没有重试 |
loadingTimeout | number | 30 | 马克思等几秒钟 CONTENT_READY 输入后 INITIALIZING, (中文(简体) ), RELOADING,或 REFRESHING· ; 0 = 没有超时 |
onRefreshError | (error: EmbedError) => void | undefined | 当令牌自动重现失败时( 由于 tokenProvider 失败或加载超时),在所有重试后不恢复 |
DisplayOptions
送入所入所入所入所发相.
| 财产 | 类型 | 默认 | 说明 |
|---|---|---|---|
sqlDisplay | 'SHOW' | 'RESULT_ONLY' | 'HIDE' | 'SHOW' | 是否显示 SQL 块, 只显示结果, 还是隐藏 |
hideParamsForm | boolean | false | 将参数窗体隐藏在嵌入层( 例如当您的应用程序拥有过滤器时) |
expandParamsFormByDefault | boolean | false | 默认是否扩展参数窗体 |
DevOptions
仅限开发与测试. 未打算生产.
| 财产 | 类型 | 默认 | 说明 |
|---|---|---|---|
debug | boolean | false | 何时 true,登录 SDK 生命周期: 后Message ( in/out), sorder Provider calls/refresh/retries,状态过渡. |
disableValidateUrl | boolean | false | 何时 true跳过 embedUrl 格式验证(域/路径)。 用于不符合生产模式的本地或中转 URL . |
mock | boolean | MockOptions | - 说吧 | 启用模拟模式: 没有真正的嵌入负载, 没有网络 。 iframe 用途 srcdoc 有个有风格的占位符. |
模拟选项 (当 mock 是对象 :
| 财产 | 类型 | 默认 | 说明 |
|---|---|---|---|
label | string | embedUrl | 文本显示在模拟 Iframe 占位符中 。 当页面上嵌入多处时有用 . |
callTokenProvider | boolean | false | 何时 true,电话 tokenProvider 打开 init(), (中文(简体) ), reload()和自动更新. |
loadingDelay | number | 0 | 在嵌入器被装入前秒延迟 。 可用于测试加载UI. |
创建嵌入式实例
createEmbed(options: EmbedOptions): EmbedInstance
创建嵌入式实例。 掷出 EmbedError 如果选项无效。 打电话 init() 创建 iframe 并启动符号流.
实例方法
| 方法 | 说明 |
|---|---|
async init() | 创建 Iframe, 等待它准备好, 呼叫 tokenProvider,并给嵌入物发送指示符。 当嵌入器发出时决定 CONTENT_READY拒绝 EmbedError 失败. |
async reload() | 电话 tokenProvider,通过 SET_TOKEN当嵌入地的时候 CONTENT_READY拒绝 EmbedError 失败. |
destroy() | 删除 Iframe, 清除听众和计时器 。 如果已经销毁了,就不要. |
实例属性
| 财产 | 类型 | 说明 |
|---|---|---|
iframe | HTMLIFrameElement | null | 嵌入式 Iframe 元素 . |
status | 'CREATED' | 'INITIALIZING' | 'RELOADING' | 'REFRESHING' | 'READY' | 'DESTROYED' | 当前实例状态 . |
容器属性
SDK设定 data-codatum-embed-status 属性,反映当前状态。 当 init() 调用并删除 destroy()。用于基于 CSS 的样式或 E2E 测试选择器.
| 状态 | 何时 |
|---|---|
INITIALIZING | init() 正在等待内容 |
READY | 内容已装入并可见 |
RELOADING | reload() 正在等待内容 |
REFRESHING | 正在自动更新 |
DESTROYED | (属性已删除) |
示例: 自定义装入 UI
初始化时显示您自己的加载指示器, 同时隐藏 Iframe :
<div id="dashboard" style="position: relative;">
<div class="my-loading">Loading…</div>
</div>
/* Hide iframe and show loading UI while loading */
[data-codatum-embed-status="INITIALIZING"] iframe,
[data-codatum-embed-status="RELOADING"] iframe,
[data-codatum-embed-status="REFRESHING"] iframe {
visibility: hidden;
}
[data-codatum-embed-status="INITIALIZING"] .my-loading,
[data-codatum-embed-status="RELOADING"] .my-loading,
[data-codatum-embed-status="REFRESHING"] .my-loading {
display: flex;
position: absolute;
inset: 0;
align-items: center;
justify-content: center;
}
/* Hide loading UI when ready */
[data-codatum-embed-status="READY"] .my-loading {
display: none;
}
没有自定义的 CSS,嵌入式内置加载屏幕显示为iframe内置.
活动
订阅 on(event, handler) 财务报告和审定财务报表 off(event, handler)。 。 。 .
| 活动 | 说明 | 有效载荷 |
|---|---|---|
statusChanged | 案件情况发生了变化. | { type: 'STATUS_CHANGED', status: EmbedStatus, previousStatus: EmbedStatus } |
paramChanged | 用户更改嵌入式参数 . | { type: 'PARAM_CHANGED', params: EncodedParam[] } |
executeSqlsTriggered | SQL被触发了嵌入式执行. | { type: 'EXECUTE_SQLS_TRIGGERED', params: EncodedParam[] } |
executionSucceeded | SQL 执行成功完成. | { type: 'EXECUTION_SUCCEEDED' } |
executionFailed | SQL 执行失败 . | { type: 'EXECUTION_FAILED', errorMessage: string } |
解码为 ParamMapper.decode(payload.params)。 。 。 . EncodedParam: 见 参数马普。 。 。 .
参数马普
嵌入式使用 param_ids(每个笔记本参数指定的ID). 您的应用程序通常使用有意义的键, 如 store_id 或者说 date_range。 。 。 . 参数马普 您的应用程序的密钥值对和 Codatum 之间的地图 param_id + 键 param_value 两个方向.
基本用途
import { createParamMapper } from '@codatum/embed';
const paramMapper = createParamMapper({
store_id: '67a1b2c3d4e5f6a7b8c9d0e1',
date_range: '67a1b2c3d4e5f6a7b8c9d0e2',
product_category: '67a1b2c3d4e5f6a7b8c9d0e3',
});
const appState = {
store_id: 'store_001',
date_range: ['2025-01-01', '2025-01-31'],
product_category: ['Electronics'],
};
// encode: app key:value → EncodedParam[] (use in tokenProvider return)
paramMapper.encode(appState);
// → [
// { param_id: '67a1b2c3...', param_value: '"store_001"' },
// { param_id: '67a1b2c3...', param_value: '["2025-01-01","2025-01-31"]' },
// { param_id: '67a1b2c3...', param_value: '["Electronics"]' },
// ]
// decode: EncodedParam[] → app key:value (use in paramChanged / executeSqlsTriggered)
paramMapper.decode(payload.params);
// → { store_id: 'store_001', date_range: [...], product_category: ['Electronics'] }
创建映射器
createParamMapper(mapping, meta?)
| 参数 | 类型 | 说明 |
|---|---|---|
mapping | Record<string, string> | 你的应用是钥匙 – Codatum param_id 每个参数. |
meta | Record<key, ParamMeta> (可选) | 与 mapping。按键选项: hidden, (中文(简体) ), required, (中文(简体) ), datatype。 。 。 . |
ParamMeta (可选,按键):
| 财产 | 类型 | 说明 |
|---|---|---|
datatype | ParamDatatype | 启用验证并改进打字。 见 参数数据类型 见下文. |
required | boolean | 若为 true, (中文(简体) ), encode 财务报告和审定财务报表 decode 掷出 MISSING_REQUIRED_PARAM 当参数缺失. |
hidden | boolean | 若为 true,编码参数包括: is_hidden: true 所以嵌入体可以隐藏它们 从参数的形式. |
参数数据类型
何时 meta[key].datatype 已经设定, encode 财务报告和审定财务报表 decode 验证值。 支持的数值 :
ParamDatatype | JS/TS 类型 | 页:1 |
|---|---|---|
'STRING' | string | —— 说 |
'NUMBER' | number | 拒绝 NaN。 。 。 . |
'BOOLEAN' | boolean | —— 说 |
'DATE' | string | 一定是这样 YYYY-MM-DD。 。 。 . |
'STRING[]' | string[] | 串起弦来. |
'[DATE, DATE]' | [string, string] | 日期范围;两个要素必须是 YYYY-MM-DD。 。 。 . |
实例方法
| 方法 | 说明 |
|---|---|
encode(values, options?) | 应用密钥:值 EncodedParam[]. JSON-弦乐价值. 使用 RESET_TO_DEFAULT 作为重置笔记本默认参数的值. |
decode(params, options?) | EncodedParam[] - 应用密钥:价值。 在映射时忽略参数 . |
encode 编号 : decode 选项
这两种方法都接受可选的第二个论点:
| 选项 | 类型 | 说明 |
|---|---|---|
only | (keyof mapping)[] | 仅限于这些密钥 。 当主机只发送子集时有用( 例如服务器发送一些参数; 客户端通过 encode 与 only) (中文(简体) ). |
noValidate | boolean | 何时 true,跳过所需的验证和数据类型. |
第一次使用类型
当定义参数定义(例如: datatype)和想要打入编码/解码,可以使用帮助者类型.
import { createParamMapper, RESET_TO_DEFAULT, type DefineDecodedParams, type EncodedParam } from '@codatum/embed';
const paramDefs = {
store_id: { datatype: 'STRING', required: true },
date_range: { datatype: '[DATE, DATE]' },
product_category: { datatype: 'STRING[]' },
} as const;
type ParamValues = DefineDecodedParams<typeof paramDefs>;
// → { store_id: string, date_range?: [string, string], product_category?: string[] }
const paramValues: ParamValues = {
store_id: 'store_001',
date_range: RESET_TO_DEFAULT,
product_category: ['Electronics']
};
const paramMapper = createParamMapper({
store_id: '67a1b2c3d4e5f6a7b8c9d0e1',
date_range: '67a1b2c3d4e5f6a7b8c9d0e2',
product_category: '67a1b2c3d4e5f6a7b8c9d0e3',
}, paramDefs);
// encode only the date_range and product_category params for client-side params
const clientParams = paramMapper.encode(paramValues, { only: ['date_range', 'product_category'] })
// → [
// { param_id: '67a1b2c3d4e5f6a7b8c9d0e2', param_value: '["2025-01-01","2025-01-31"]' },
// { param_id: '67a1b2c3d4e5f6a7b8c9d0e3', param_value: '["Electronics"]' },
// ]
const onParamChanged = (ev: { params: EncodedParam[] }) => {
const values: ParamValues = paramMapper.decode(ev.params);
console.log('Changed:', values);
};
错误
所有出错均以 EmbedError 带有 code 属性.
| 代码 | 被丢弃 | 说明 |
|---|---|---|
INVALID_OPTIONS | createEmbed | 选项无效 |
CONTAINER_NOT_FOUND | init | 未找到集装箱元素 |
LOADING_TIMEOUT | init 编号 : reload | CONTENT_READY 未收到 tokenOptions.loadingTimeout; 自动更新报告 onRefreshError |
TOKEN_PROVIDER_FAILED | init 编号 : reload | tokenProvider 丢弃 |
MISSING_REQUIRED_PARAM | encode 编号 : decode | 缺少必要的参数 |
INVALID_PARAM_VALUE | encode 编号 : decode | 数值失败验证 |
UNEXPECTED_ERROR | createEmbed 编号 : init 编号 : reload | 意外错误 |
处理错误
init() 财务报告和审定财务报表 reload() 投出失败——尝试/捕获。 自动更新错误通过 tokenOptions.onRefreshError 调用.
import { createEmbed, EmbedError } from '@codatum/embed';
try {
const embed = createEmbed({
container: '#dashboard',
embedUrl: '...',
tokenProvider: async () => { /* ... */ },
tokenOptions: {
onRefreshError: (error) => {
// Token auto-refresh failed after all retries.
// e.g. redirect to login, show a banner, etc.
console.error('Refresh failed:', error);
},
},
});
await embed.init();
// reload() also throws on failure
await embed.reload();
} catch (error) {
if (error instanceof EmbedError) {
// error.cause holds the original error thrown by tokenProvider (if applicable)
console.error(error.code, error.message);
}
}
用法实例
以下模式显示了《公约》概述的共同一体化设想: 已签名的嵌入式使用例。 。 。 .
例A:嵌入层中的参数形式(服务器验证商店,客户端发送过滤器)
嵌入显示笔记本的参数形式. 服务器验证 store_id 并用符号编码;客户端发送电流 store_id 仅针对每个令牌请求和编码 date_range 财务报告和审定财务报表 product_category 作为客户端参数,窗体和主机保持同步.
客户端
import { createEmbed, createParamMapper, RESET_TO_DEFAULT } from '@codatum/embed';
const paramMapper = createParamMapper({...}, {
store_id: { datatype: 'STRING' }, // server-side param
date_range: { datatype: '[DATE, DATE]' }, // client-side param
product_category: { datatype: 'STRING[]' }, // client-side param
});
let paramValues = { store_id: undefined, date_range: RESET_TO_DEFAULT, product_category: [] };
const embed = createEmbed({
container: '#dashboard',
embedUrl: '...',
displayOptions: { expandParamsFormByDefault: true },
tokenProvider: async () => {
const res = await fetch('/api/codatum/token', {
method: 'POST',
body: JSON.stringify({ tokenUserId: userId, params: { store_id: paramValues.store_id } }),
});
const { token } = await res.json();
const params = paramMapper.encode(paramValues, { only: ['date_range', 'product_category'] });
return { token, params };
},
});
await embed.init();
embed.on('paramChanged', (ev) => { paramValues = paramMapper.decode(ev.params); });
embed.on('executeSqlsTriggered', (ev) => { paramValues = paramMapper.decode(ev.params); });
服务器 - 验证 store_id 与房客为敌,并将它写入铭文中:
import { createParamMapper } from '@codatum/embed';
// POST /token body: { tokenUserId, params?: { store_id } }
const paramMapper = createParamMapper({...}, {
tenant_id: { datatype: 'STRING', required: true }, // server-side param
store_id: { datatype: 'STRING', required: true }, // server-side param
});
const tenantId = await getTenantIdByUserId(tokenUserId);
const storeIdsForTenant = await getStoreIdsByTenantId(tenantId);
const storeId = params?.store_id ?? storeIdsForTenant[0];
if (!storeIdsForTenant.includes(storeId)) throw new Error('Invalid storeId');
const encoded = paramMapper.encode({ tenant_id: tenantId, store_id: storeId });
// issue token with encoded params
可运行 : 节点.js
例B:仅客户端参数(SaaS拥有过滤器,隐藏参数表)
所有参数除外 tenant_id 由主机管理;嵌入式的参数窗体被隐藏. 道具只携带租户上下文,因此可以缓存并再用. 当用户在主机 UI 中更改过滤器时,请拨 reload() 因此,符号提供者再次以更新的值运行.
客户端
import { createEmbed, createParamMapper } from '@codatum/embed';
const paramMapper = createParamMapper({...}, {
store_id: { datatype: 'STRING' }, // client-side param
date_range: { datatype: '[DATE, DATE]' }, // client-side param
product_category: { datatype: 'STRING[]' }, // client-side param
});
let paramValues = { store_id: 'store_001', date_range: ['2025-01-01', '2025-01-31'], product_category: [] };
const embed = createEmbed({
container: '#dashboard',
embedUrl: '...',
displayOptions: { hideParamsForm: true },
tokenProvider: async () => {
const res = await fetch('/api/codatum/token', { method: 'POST', body: JSON.stringify({ tokenUserId: userId }) });
const { token } = await res.json();
const params = paramMapper.encode(paramValues);
return { token, params };
},
});
await embed.init();
embed.on('paramChanged', (ev) => { paramValues = paramMapper.decode(ev.params); });
embed.on('executeSqlsTriggered', (ev) => { paramValues = paramMapper.decode(ev.params); });
// When the user changes filters in the host UI, update paramValues and reload the embed
async function onDashboardFilterChange(newValues: ParamValues) {
paramValues = newValues;
await embed.reload();
}
服务器 - Token只需要租房范围(身体没有偏执):
import { createParamMapper } from '@codatum/embed';
// POST /token body: { tokenUserId }
const paramMapper = createParamMapper({...}, {
tenant_id: { datatype: 'STRING', required: true }, // server-side param
});
const tenantId = await getTenantIdByUserId(tokenUserId);
const encoded = paramMapper.encode({ tenant_id: tenantId });
// issue token with encoded params
可运行 : 节点.js
例 C: 服务器侧存储( 存储更改时重发)
store_id 在符号中被固定,并验证服务器侧;更改商店需要一个新的符号。 参数形式可见于 date_range 财务报告和审定财务报表 product_category参数值 paramChanged 通过 store_id 到服务器,在每一个令牌请求中;当用户切换存储时,重新装入,这样就可以为新商店发行一个新的令牌.
客户端
import { createEmbed, createParamMapper, RESET_TO_DEFAULT } from '@codatum/embed';
const paramMapper = createParamMapper({...}, {
store_id: { datatype: 'STRING' }, // server-side param
date_range: { datatype: '[DATE, DATE]' }, // client-side param
product_category: { datatype: 'STRING[]' }, // client-side param
});
let paramValues = { store_id: undefined, date_range: RESET_TO_DEFAULT, product_category: ['Electronics'] };
const embed = createEmbed({
container: '#dashboard',
embedUrl: '...',
displayOptions: { expandParamsFormByDefault: true },
tokenProvider: async () => {
const res = await fetch('/api/codatum/token', {
method: 'POST',
body: JSON.stringify({ tokenUserId: userId, params: { store_id: paramValues.store_id } }),
});
const { token } = await res.json();
const params = paramMapper.encode(paramValues, { only: ['date_range', 'product_category'] });
return { token, params };
},
});
await embed.init();
embed.on('paramChanged', (ev) => { paramValues = paramMapper.decode(ev.params); });
embed.on('executeSqlsTriggered', (ev) => { paramValues = paramMapper.decode(ev.params); });
async function onStoreSwitch(storeId: string) {
paramValues.store_id = storeId;
await embed.reload();
}
服务器 ——与例A相同:接受 params.store_id,验证,编码 tenant_id + 键 store_id 在标志.
可运行 : 节点.js
光盘N
独立国际家庭教育研究所的建筑暴露了单一的全球情况 CodatumEmbed。装入脚本并使用 CodatumEmbed.createEmbed 接下来 embed.init()。 。 。 .
<script src="https://unpkg.com/@codatum/embed/dist/index.global.min.js"></script>
<script>
(async function () {
const embed = CodatumEmbed.createEmbed({ container: '#dashboard', embedUrl: '...', tokenProvider: ... });
await embed.init();
})();
</script>