@codaco/interview
Network Canvas 采访引擎 — 已打包, 任何反应主机都可以嵌入 参与者与调查进行互动。 拥有 Redux 商店, 舞台 导航, 全部17个接口执行( NameGenerator, Socialgram, 分类Bin 地理空间 对话系统 土司系统 设计标志。 主机拥有网络呼叫( 同步、 完成、 资产) URL分辨率),以及参与者目前在协议中的位置.
预定主机为Fresco(Next.js)和新的建筑师预览 模式(Vite)——但软件包对两者都没有意识.
安装
pnpm add @codaco/interview
同伴依赖关系 (你很可能已经拥有这些):
{
"@codaco/fresco-ui": "^2.5.4",
"@codaco/protocol-validation": "^11.5.0",
"@codaco/shared-consts": "5.0.0",
"@codaco/tailwind-config": "^1.0.0-alpha.11",
"immer": "^11.1.4",
"motion": "^12.38.0",
"react": "^19.2.5",
"react-dom": "^19.2.5",
"tailwindcss": "^4.2.4",
}
尾风
软件包假定主机有一个有线的 Tailwind v4 构建插件
(单位:千美元)@tailwindcss/vite 对于维特, @tailwindcss/postcss 用于下一个.js/ 任意
(原始内容存档于2019-10-29). PostCSS protect. 链条中的每个CSS文件都有一个关切
消费者按下列顺序进口:
/* styles/globals.css */
@import '@codaco/tailwind-config/fresco.css'; /* Tailwind v4 + theme + plugins + fonts */
@import '@codaco/fresco-ui/styles.css'; /* @source glue for fresco-ui's classes */
@import '@codaco/interview/styles.css'; /* @source glue for interview's classes */
也别 @import "tailwindcss" 你自己来. 那个进口活人
内部 @codaco/tailwind-config/fresco.css; 再次加载
尾风运行两次,产生重复/相冲突
公用事业.
每一个 @codaco/fresco-ui/styles.css 财务报告和审定财务报表 @codaco/interview/styles.css
是一个只包含 @source "./**/*.{js,ts,tsx}"
指令范围为软件包自己的模块文件。 光荣的结局
进口地点 styles.css 坐着——包裹
src/ 从源头消耗时的树( 如工作空间主机所做的), 或
镜像 dist/ 复制 npm 安装。 都进口了 尾风
类扫描仪同时行走软件包并发送每个工具类
组件参考。 主机不再需要写入
@source '../node_modules/...' 线条本身.
@codaco/tailwind-config/fresco.css 捆绑默认和
访谈主题变体. 贝壳制造 <main data-theme-interview>
带有传送门容器,所以对话框/接通部分留在单元内
子树——不需要主机侧设置. 见 主题 & DOM 范围 见下文.
阴道/jsdom
节点没有CSS装载器,所以任何从
@codaco/interview (即使是计划) 需要维特处理
包裹,否则你得到
"TypeError:未知的文件扩展名 .css" (中文(简体) )内置软件包
每个使用 jsdom 的项目 :
// vitest.config.ts
export default defineConfig({
test: {
server: {
deps: { inline: ['@codaco/interview'] },
},
},
});
壳牌部分
import {
createDebouncedSyncHandler,
Shell,
type InterviewPayload,
} from '@codaco/interview';
完整的最小主机( TypeScript / Next.js App 路由器样式 – the 形状与任何其他反应框架相同:
'use client';
import {
createDebouncedSyncHandler,
Shell,
type AssetRequestHandler,
type FinishHandler,
type InterviewPayload,
type SyncHandler,
} from '@codaco/interview';
import { useCallback, useMemo, useState } from 'react';
import { useRouter, useSearchParams } from 'next/navigation';
export default function InterviewClient({
payload,
resolveAssetUrl,
}: {
payload: InterviewPayload;
resolveAssetUrl: (assetId: string) => Promise<string>;
}) {
const router = useRouter();
const params = useSearchParams();
// currentStep is HOST state — the package never owns it. Keep it in
// useState, nuqs, a context, the URL, wherever fits the host. The
// package re-renders when the prop changes.
const [currentStep, setCurrentStep] = useState<number>(() =>
Number(params.get('step') ?? payload.session.currentStep),
);
const onStepChange = useCallback(
(step: number) => {
setCurrentStep(step);
const next = new URLSearchParams(params.toString());
next.set('step', String(step));
router.replace(`?${next.toString()}`);
},
[params, router],
);
// Persist state on every reducer commit. Receives the full session
// payload — POST it to your server, write to IndexedDB, anything.
//
// The engine offers every change as it happens and never batches on your
// behalf: only you know what one write costs. A local write can take them
// all; a network request usually should not, so wrap it in
// `createDebouncedSyncHandler` (below) rather than posting per answer.
const onSync: SyncHandler = useMemo(
() =>
createDebouncedSyncHandler(
async (interviewId, session) => {
await fetch(`/interview/${interviewId}/sync`, {
method: 'POST',
body: JSON.stringify(session),
});
},
{ waitMs: 3000 },
),
[],
);
// Called when the participant clicks Finish on the FinishSession
// stage. Receives an AbortSignal so you can cancel any in-flight work
// if the user backs out.
const onFinish: FinishHandler = useCallback(
async (interviewId, signal) => {
await fetch(`/interview/${interviewId}/finish`, {
method: 'POST',
signal,
});
router.push(`/interview/${interviewId}/complete`);
},
[router],
);
// Stages reference protocol assets by ID. The package calls this
// exactly when a stage needs a URL — return a same-origin URL,
// pre-signed S3 URL, blob: URL, whatever your storage uses.
const onRequestAsset: AssetRequestHandler = useCallback(
(assetId) => resolveAssetUrl(assetId),
[resolveAssetUrl],
);
return (
<Shell
payload={payload}
currentStep={currentStep}
onStepChange={onStepChange}
onSync={onSync}
onFinish={onFinish}
onRequestAsset={onRequestAsset}
/>
);
}
为什么 currentStep 主办国?
所以东道主可以驾车 无论它喜欢什么 nuqs URL 参数, 浏览器
历史, 阶梯 UI, 来自电子邮件的深层链接, 服务器发送的初始
立场。 软件包读取 currentStep 发送 onStepChange 页:1
每个导航,它不保存自己的副本.
这也是允许主机挂起的 Shell 一次但让
不重新创建 Redux 商店的不同阶段:
currentStep 中间的道具变化 .
果壳道具
| Prop | 类型 | 需求 | 页:1 |
|---|---|---|---|
payload | InterviewPayload | 对 | { session, protocol } ——见外形类型. 每个商店创建一次 payload.session.id;通过稳定的引用. |
currentStep | number | 对 | 参与者的舞台指数。 宿主拥有. |
onStepChange | (step: number) => void | 对 | 每当参与者导航时就被解雇。 主机应该反射 step 进入自己的状态. |
onSync | (id, session, opts) => Promise | 对 | 在每个 Redux 承诺后呼叫——引擎不批量. 随你喜欢的坚持; 包入 createDebouncedSyncHandler 如果写作昂贵. opts.immediate 刻出不可推迟的标记(退出、完成); opts.unloading 附加标记文件可能无法存活的(隐藏,页码). |
onFinish | (id, AbortSignal) => Promise | 对 | 从会场叫来的 如果用户在飞行中途导航,信号会中止. |
onRequestAsset | (assetId) => Promise<url> | 对 | 将协议资产解决为 URL 。 被称为懒惰的阶段上架. |
analytics | InterviewAnalyticsMetadata | 对 | 主机元数据作为每个事件的超级属性: installationId (匿名主机UUID), hostApp (例如:. "Fresco", (中文(简体) ), hostVersion?。 。 。 . |
posthogClient | 邮购客户端( 需要) capture, (中文(简体) ), captureException, (中文(简体) ), register(中文(简体) ) | 没有 | 已初始化的 PostHog 客户端 。 当提供时,包会通过它发出事件而不修改其配置. 缺席时, 包会懒惰地初始化它自己命名的实例 ph-relay.networkcanvas.com。 。 。 . |
disableAnalytics | boolean | 没有 | 何时 true,所有事件排放均被抑制(否) posthog-js 导入)。 默认 false。用于E2E和合成访问运行. |
finishConfirmationDescription | ReactNode | 没有 | 完成确认对话框中显示的特定主机解释 。 不承诺响应的局部中性引导的默认是不可改变的. 一个已订阅的消息组件可以保持一个主机覆盖,以响应语言变化. |
requestedLocale | string | readonly string[] | null | 没有 | 用户偏好,解决了主机地块,或者命令了地块请求. 该软件包会与其自己支持的界面语言进行谈判;未匹配的请求使用英语. |
localePreference | string | null | 没有 | 可选的控制菜单选择, 配对 onLocaleChange。字符串选择最佳支持的匹配; null 如下 requestedLocale。关闭它以保留菜单选择到软件包的地方. |
onLocaleChange | (locale: string | null) => void | 没有 | 在菜单选择后调用, 这样主机就可以坚持它 . null 表示再次遵循主机请求. |
catalog | InterviewCatalog | 没有 | 界面语言的消息来自 loadInterviewCatalog,基于同样的 requestedLocale 财务报告和审定财务报表 localePreference. 让访谈渲染出水合物,而不等待该语言的下载。 只在符合谈判语言时使用. |
allowLanguageSelection | boolean | 没有 | 在设置菜单中显示界面语言选择器 。 默认为 true。 。 。 . |
flags | { isE2E?, isDevelopment? } | 没有 | isE2E: true 曝光情况 window.__interviewStore 用于 Playwright 固定装置. isDevelopment: true 启用 redux-logger . |
软件包替换前一个 onError 内部调用 posthog.captureException 调用; 通过解析分析客户端报告错误和资产负载故障( 或在 disableAnalytics 实值 true) (中文(简体) ). 主机不需要自导出错误槽 .
界面语言
传递用户的偏好或您的主机已经谈判过的地址为
requestedLocale。软件包拥有其登记册和信件:目前
支持 en, (中文(简体) ), en-GB, (中文(简体) ), es, (中文(简体) ), zh-Hans, (中文(简体) ), zh-Hant, (中文(简体) ), de, (中文(简体) ), nl, (中文(简体) ), pt-BR, (中文(简体) ), it,以及 fr,匹配区域请求
例如 es-MX 改为 es, (中文(简体) ), zh-CN 财务报告和审定财务报表 zh-SG 改为 zh-Hans, (中文(简体) ), zh-TW, (中文(简体) ), zh-HK 财务报告和审定财务报表 zh-MO 改为
zh-Hant, (中文(简体) ), de-AT 改为 de, (中文(简体) ), nl-BE 改为 nl, (中文(简体) ), pt 或者说 pt-PT 改为 pt-BR, (中文(简体) ), it-CH 改为 it,以及 fr-CA 改为 fr,然后掉到 en 对不支持或错误的请求。 一个阵列
以优惠顺序表达请求。 不需要主机提供者或目录 .
每种语言的信息都是单独的块, 第一次采访时会加载
显示语言; 英语不需要。 以语言装入的贝壳
还没有装入 显示一个旋转器 在采访的表面,直到它得到了,
而不是先制作英文,而后开关保持当前
在屏幕上使用语言直到新的语言准备好。 每个离线主机都保留
预留每块建筑的可用语言,作为PWA服务
工人们会的.
一个主机可以把下载 从采访的路径
loadInterviewCatalog(requestedLocale, localePreference) 从
@codaco/interview/catalog,它的谈判方式是 Shell 是否和
决定: { locale, messages }。条目没有反应,所以是一个服务器
可以导入它: 服务器委托主机等待它并传递结果为
catalog,而访谈使该语言水合物没有
旋转而无所求. 一个客户端在不等待的情况下打电话
准备有效载荷;然后壳牌发现已经装入的语言.
设置控制包提供的按钮、菜单、验证、访问 标签、帮助和舞台控制。 协议授权的标题、提示、标签、, 选项、研究值和识别符没有变化。 议定书 内容本地化是一个单独的计划.
菜单可以暂时覆盖主机请求. 它的自动选项清除
此覆盖; 新的主机请求也立即生效 。 一个东道主
可使用的持续菜单更改 onLocaleChange 并通过新解决的地方
恢复为 requestedLocale。以在
菜单,也可以通过 localePreference: 字符串优先并匹配
相对于软件包注册;未匹配或格式不当的偏好下降
通过至 requestedLocale。 。 。 . null 如下 requestedLocale,并省略其内容
保持软件包本地菜单状态。 这样可以自动清除保存的首选项
直接在重新装入后。 软件包本身不读取浏览器偏好或
存储。 语言变化保留挂载的访谈,等待格式输入,
导航和答案。 软件包 lang 财务报告和审定财务报表 dir b. 本区域和本区域
将主机文档的语言留给主机.
主机在外部提供导出控制 Shell,例如内线
ProtocolField 预览,可以使用 InterviewI18nProvider 从 @codaco/interview
同样的 requestedLocale 合同和软件包目录。 与
Shell,它没有带来它自己的悬浮边界:它的首次渲染在
尚未加载的语句暂停,所以将其置于其中。 主办者
已经拥有一个提供者可以添加 interviewCatalogLoaders 从
@codaco/interview/locales 他们的应用程序目录来源。 没有供应商,
独立控件使用他们的英语默认值.
分析
采访包直接显示PostHog事件 onError- 典型的主桥。 三种操作模式:
- 主机提供客户端 - 通过
posthogClient; 软件包通过主机实例发送,并distinct_id每起事件都被否决到采访ID。 主机实例配置(自动捕获,识别,会话记录)是主机的责任. - 亲身经历 ——省略
posthogClient; 软件包懒惰导入posthog-js/dist/module.no-external构建( 没有远程脚本加载器, 因此它运行在script-src 'self'并输入一个已命名的实例'@codaco/interview'反对https://ph-relay.networkcanvas.com。 。 。 . - 已禁用 - 通过
disableAnalytics={true}; 没有发布事件, 没有导入后 hog-js .
PII合同:事件从不包括协议-网络数据,协议-作者内容(阶段标签,即时文本,代码簿标签,资产名称),或参与者输入(形式值,自由文本,更改标签,搜索查询,密码句). 事件只包括结构标识符(阶段类型/索引,即时索引,随机节点/对接UUID),代码簿 内部标识 (例如:. "person", (中文(简体) ), "friend"),计数,持续时间,以及包定义的歧视者.
整个事件分类学生活在 docs/superpowers/specs/2026-05-05-interview-analytics-design.md。 。 。 .
烤箱视图
Shell 将自己的 UI 烤面包供应商和取景器安装在原地,
本地化采访区域。 主办方不需要再访问取景口.
这使得通知文本和可访问姓名能够对访谈作出回应
菜单的语言,包括主机使用不同语言时.
每个壳牌公司保持其验证通知独立于其他挂载 面试。 应用级的土司供应商仍可单独供主机使用 在面谈之外发出通知.
建设 InterviewPayload 服务器侧
软件包从未进入主机数据库. 您的服务器手
彻底解决了 { session, protocol } 对象, 全部
asset:// 已映射到 ID 的 URL onRequestAsset 将会是
与电话.
import {
type InterviewPayload,
type ProtocolPayload,
isValidAssetType,
} from '@codaco/interview';
import { hashProtocol } from '@codaco/protocol-validation';
export async function loadInterviewPayload(
interviewId: string,
): Promise<InterviewPayload> {
const interview = await db.interview.findUniqueOrThrow({
where: { id: interviewId },
include: { protocol: true },
});
// protocol assets come from your DB / object store — flatten to the
// shape the package consumes
const assets = interview.protocol.assets
.filter((a) => isValidAssetType(a.type))
.map((a) => ({
assetId: a.id,
name: a.name,
type: a.type,
...(a.value ? { value: a.value } : {}), // apikey assets only
}));
const protocol: ProtocolPayload = {
...interview.protocol,
// Content hash of { codebook, stages }. Computed at protocol-import time
// by `hashProtocol` from @codaco/protocol-validation; forwarded here as a
// super-property on every analytics event.
hash: interview.protocol.hash ?? hashProtocol(interview.protocol),
importedAt: interview.protocol.importedAt.toISOString(),
assets,
};
return {
session: {
id: interview.id,
// … the rest of SessionPayload — see the type for the full shape
network: interview.network ?? createInitialNetwork(),
currentStep: interview.currentStep ?? 0,
stageMetadata: interview.stageMetadata,
// …
},
protocol,
};
}
createInitialNetwork() 返回带有自负的空洞网络
已关闭的节点——当您创建新访问时拨打一次
记录之后的负载会通过计划验证.
持有有效协议文件本身的主机,而不是
平整数据库记录,用
currentProtocolToPayload(protocol, { id, importedAt }) 从
@codaco/interview/contract。通过相同的 id 财务报告和审定财务报表 importedAt 每一次
同一协议已载入.
Sparse 实体属性流
访谈存储实体属性为稀有记录. 自己的属性密钥
总是有定义 VariableValue; 缺少密钥表示变量是
未设. false, (中文(简体) ), 0, (中文(简体) ), '',以及 [] 答复是明确的,并一直在场.
flowchart LR
Form[Mounted form fields] --> Adapter[Coerce values and build patch]
Direct[Direct participant edit] --> Patch[AttributePatch: set and unset]
Adapter --> Patch
Patch --> Validate[Validate keys and overlap]
Validate --> Apply[Apply attributes and secure metadata]
Protocol[Protocol-derived prompt attributes] --> Apply
Apply --> Network[Sparse session.network]
Network --> Sync[onSync session]
Sync --> Persistence[Host persistence]
Persistence --> HostParse[Host read via NcNetworkSchema]
HostParse --> Payload[Shell payload]
Payload --> Network
Persistence --> ExportParse[Exporter parse via NcNetworkSchema]
ExportParse --> Output[CSV and GraphML]
内部 AttributePatch 合同将设定定义值与
删除属性 :
type AttributePatch = Readonly<{
set: Readonly<Record<string, VariableValue>>;
unset: readonly string[];
}>;
格式提交首先强制其协议变量类型的值。 这个
适配器然后考虑确切的挂载字段名称:每个定义值去
改为 set,每个 undefined 值转到 unset字段
被忽略 。 如果挂载定义值不是 VariableValue转换
整个失败, 没有发送部分补丁 .
创建和编辑时有意使用该结果的不同部分:
- 只创建实体写入
set,所以未解字段被省略. - 编辑两者都适用
set财务报告和审定财务报表unset,所以清除挂载字段删除 键,而表单以外的属性保持不变. - 直接参与者编辑, 如 bin 和布局控件, 生成相同的 补丁形状, 而不是写入无效的哨兵 .
节点、边缘和自我更新 thunks 验证参与者编辑的补丁密钥
属于适用的代码簿定义,并拒绝在
两者 set 财务报告和审定财务报表 unset。节点和边缘创建对它们的
初始属性;可明确控制名册和小类进口
允许外部节点属性。 验证在完成之前完成
减号可以突变会话状态 。 即时会员补丁直接导出
从协议的 additionalAttributes,因此减少者应用信任的
键而不重复补丁验证.
共享应用器为两者制作新的属性和安全元数据地图
验证和协议衍生的补丁 。 一个 unset 删除属性并
它的匹配 _secureAttributes 在同一缩小的过渡中输入;空
安全元数据映射崩溃到 undefined。 。 。 .
网络作曲器撤消历史对存在敏感 。 对于每一个触摸到的钥匙,一个
倒数补丁恢复先前的自身值 set,但恢复先前的缺席
与 unset当定义的空值,例如
[] 被编辑后撤销.
onSync 手握在减员后短短的会话。 主机解析
存储或接收的网络 NcNetworkSchema 在构建下一个之前
Shell 有效载荷;这接受无效的输入项,但输出很少.
@codaco/network-exporters 重复在格式化前分析每个会话,
因此,持久性和导出不会重新产生无效属性值.
公共 API 参考
下面的一切都是从 '@codaco/interview'更多公众
子路径曝光合同,协议的 schema 版本, locate catalogs, the
面试目录加载器(@codaco/interview/catalog)和样式;主机代码
不应进入包件内部.
构成部分
Shell- 运行时间InterviewI18nProvider– 所使用的导出控件的软件包地盘边界 外部Shell
Schemas + 帮助者
StageMetadataSchema- Zod计划session.stageMetadata。使用这个 以校验您数据库中恢复的状态,然后将其递回 进入有效载荷.createInitialNetwork()——自负所生的空网络. 打电话一次 每一次新面试.isValidAssetType(type)- 上游类型ResolvedAsset.type。 。 。 .getNodeLabelAttribute(variables, attributes)选择变量 其值应显示为节点的标签。 给兄弟们用的 软件包(例如).@codaco/network-exporters因此,出口使用相同的 uI 的标签逻辑 .
合成数据
generateNetwork(codebook, stages, options?)——决定性 网络生成器,可以走协议的阶段并产生节点, 边缘 自我属性 和阶段元数据 用来写故事 固定装置,负载测试,以及合成预览模式.GenerateNetworkOptions, (中文(简体) ),GenerateNetworkResult- 伙伴类型.
公共类型
type InterviewPayload = { session: SessionPayload; protocol: ProtocolPayload };
type SessionPayload = SessionState; // the Redux session shape
type ProtocolPayload = Omit<CurrentProtocol, 'assetManifest'> & {
id: string;
importedAt: string; // ISO
assets: ResolvedAsset[];
};
type ResolvedAsset = {
assetId: string;
name: string;
type: 'image' | 'video' | 'audio' | 'network' | 'geojson' | 'apikey';
value?: string; // apikey only
source?: string; // the file's name in the protocol, used for MIME type and CSV/JSON decisions
};
type SyncOptions = {
// Do not defer this write.
immediate: boolean;
// The document is being hidden or unloaded and may never run script again:
// use a transport that outlives it, and do not queue behind a request that
// will die with it. Always accompanied by `immediate`.
unloading: boolean;
};
type SyncHandler = (
interviewId: string,
session: SessionPayload,
options: SyncOptions,
) => Promise<void>;
// Batching is the host's decision. This wraps a handler so ordinary changes
// are rate-limited to one write per `waitMs` carrying the newest state, while
// `immediate` writes go out at once.
function createDebouncedSyncHandler(
write: SyncHandler,
options: { waitMs: number },
): SyncHandler;
type FinishHandler = (
interviewId: string,
signal: AbortSignal,
) => Promise<void>;
type AssetRequestHandler = (assetId: string) => Promise<string>;
type ErrorHandler = (error: Error, ctx?: Record<string, unknown>) => void;
type StepChangeHandler = (step: number) => void;
type InterviewerFlags = {
isE2E?: boolean;
isDevelopment?: boolean;
};
主题 & DOM 范围
Shell 制作单曲 <main data-theme-interview> 键。 这既是测试/e2e固定装置的稳定选择器,也是激活采访主题的包装器:后人拿起深色调色板,努尼托打字机,以及响应的根字体大小自动.
Shell 并提供一个门户容器(通过 <PortalContainerProvider> 从 @codaco/fresco-ui/PortalContainer)所以对话,弹出,倒放,工具提示,土司,选择,以及从采访内部打开的组合框都变成了节点 内部 他们自动继承访谈调色板而不是传送到 document.body。 。 。 .
如果你让访谈主题UI 外部 联 合 国 Shell (例如采访结束后的"谢谢"一页),将UI包装为: <ThemedRegion theme="interview"> 从 @codaco/fresco-ui/ThemedRegion数字 :
import { ThemedRegion } from '@codaco/fresco-ui/ThemedRegion';
<ThemedRegion theme="interview">
<ThankYouPage />
</ThemedRegion>;
<ThemedRegion> 及其祖先,直到 <body> 一定没有 transform, (中文(简体) ), filter, (中文(简体) ), perspective,或 contain 设定——这些为固定位置的后人创建了新的包含区块,并会打破模式/流行定位.
测试整合
单位/组件测试(Vitest + jsdom)
见 阴道/jsdom 页:1 @codaco/interview 内
您的配置使得 CSS 的副作用 解决干净.
端对端( Playwright)
对于 e2e , 您通常想要对主机的数据进行确定性立方
层。 软件包通过 isE2E 旗帜,哪个
曝光 Redux 现场商店 window.__interviewStore 这样固定
可以在不点击数据库的情况下读取网络状态 :
<Shell {...props} flags={{ isE2E: true }} />
软件包自己的e2e套件(在此repo中)使用Vite主机
执行 window.__test 钩子 installProtocol 编号 : createInterview 编号 :
reset,运行在官方 mcr.microsoft.com/playwright 图像
表示反对每阶段截图
e2e/visual-snapshots/{chromium,firefox,webkit}-matrix/。用作参考
用于连接您的 e2e 设置 — 见 e2e/README.md 联 合 国
版式和测试授权模式.
对于交互式调试( 无试跑器) , 运行 pnpm dev:host 到启动
vite 主机 + 资产服务器, 准备仓储协议并打开浏览器
页:1.
什么活在这个包里,什么没有
在:
- redux 商店 + 每个压缩器 / 选择器 / tunk
- 所有17个相位接口和导航铬
- 对话框系统、土司系统和相位错误边界
- 合成网络生成器
- 合同类型和主机序列图
输出 :
- 所有触及数据库、会话饼干或网络的东西
- 协议解析和验证(使用)
@codaco/protocol-validation(中文(简体) ) - 导出为 GraphML / CSV( 使用)
@codaco/network-exporters(中文(简体) ) - 网络过滤/查询DSL(使用)
@codaco/network-query(中文(简体) )
当有疑问时:如果将它嵌入一个 非弗雷斯科主机(Architect的预览模式,一个CLI,一个Electron app), 它 属于这里。 如果它和弗雷斯科的Postgres 或它的认证层说话,它 没有.
许可证
MIT — 见寄存器根.