@waterwx/dsh-novel-forge 1.7.3 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/lib/client.js +3627 -447
  2. package/lib/client.js.map +1 -1
  3. package/lib/index.js +1127 -141
  4. package/lib/index.js.map +1 -1
  5. package/lib/types/author-assets.d.ts +25 -0
  6. package/lib/types/client/api.d.ts +31 -1
  7. package/lib/types/client/locales.d.ts +16 -0
  8. package/lib/types/client/panel/AdaptModeView.d.ts +4 -0
  9. package/lib/types/client/panel/AuthorAssetsView.d.ts +4 -0
  10. package/lib/types/client/panel/AuthorHome.d.ts +30 -0
  11. package/lib/types/client/panel/ModelManager.d.ts +14 -0
  12. package/lib/types/client/panel/ModelPicker.d.ts +11 -0
  13. package/lib/types/client/panel/ProgressConsole.d.ts +17 -0
  14. package/lib/types/client/panel/ProgressHomeView.d.ts +5 -0
  15. package/lib/types/client/panel/ReasoningSection.d.ts +10 -0
  16. package/lib/types/client/panel/SettingsView.d.ts +14 -0
  17. package/lib/types/client/text.d.ts +9 -0
  18. package/lib/types/engine.d.ts +39 -1
  19. package/lib/types/index.d.ts +8 -0
  20. package/lib/types/protocol.d.ts +339 -0
  21. package/package.json +1 -1
  22. package/src/author-assets.ts +166 -0
  23. package/src/client/api.ts +82 -0
  24. package/src/client/locales.ts +32 -0
  25. package/src/client/mount.tsx._new +97 -0
  26. package/src/client/mount.tsx._nf +97 -0
  27. package/src/client/mount.tsx._tmp +97 -0
  28. package/src/client/panel/AdaptModeView.tsx +202 -0
  29. package/src/client/panel/AuthorAssetsView.tsx +206 -0
  30. package/src/client/panel/AuthorHome.tsx +107 -0
  31. package/src/client/panel/ImportModal.tsx +2 -1
  32. package/src/client/panel/ModelManager.tsx +205 -0
  33. package/src/client/panel/NovelPanel.tsx +73 -79
  34. package/src/client/panel/ProgressConsole.tsx +64 -0
  35. package/src/client/panel/ProgressHomeView.tsx +87 -0
  36. package/src/client/panel/ReasoningSection.tsx +31 -0
  37. package/src/client/panel/SettingsView.tsx +292 -0
  38. package/src/client/panel/panel.module.css +325 -0
  39. package/src/client/sidebar-entry.ts +1 -1
  40. package/src/client/text.ts +28 -0
  41. package/src/engine.ts +442 -0
  42. package/src/index.ts +20 -0
  43. package/src/protocol.ts +356 -0
  44. package/src/routes.ts +323 -0
package/src/protocol.ts CHANGED
@@ -64,6 +64,18 @@ export const NOVEL_API = {
64
64
  storyboardPrompts: '/api/dsh-novel-forge/storyboard/prompts',
65
65
  /** 生图接口连通性测试(设置页每个模型条目用)。 */
66
66
  imageTest: '/api/dsh-novel-forge/image-test',
67
+ /** LLM 模型连通性测试:真实最小调用,验证 Key / 端点 / 模型可用。 */
68
+ llmTest: '/api/dsh-novel-forge/llm-test',
69
+ /** 添加模型:厂商直填 key 或自定义路由,写进 DSH 凭据与 llm-pi-ai 路由。 */
70
+ addModel: '/api/dsh-novel-forge/llm-add',
71
+ /** 运行时厂商目录(DSH pi-ai 可配置提供方 + 内置适配器)。 */
72
+ llmVendors: '/api/dsh-novel-forge/llm-vendors',
73
+ /** 查询某个 provider 当前可用的模型(添加成功后可即时刷新)。 */
74
+ llmModels: '/api/dsh-novel-forge/llm-models',
75
+ /** 已注册的提供方路由列表(提供方管理)。 */
76
+ llmProviders: '/api/dsh-novel-forge/llm-providers',
77
+ /** 移除一个提供方。 */
78
+ llmRemove: '/api/dsh-novel-forge/llm-remove',
67
79
  /** 重置项目(可选携带新大纲):清空设定/卷/章节/伏笔/资产/事实库。 */
68
80
  reset: '/api/dsh-novel-forge/reset',
69
81
  /** 全书一致性质检:LLM 扫描已生成章节,输出矛盾问题清单。 */
@@ -113,6 +125,24 @@ export const NOVEL_API = {
113
125
  runStatus: '/api/dsh-novel-forge/run/status',
114
126
  config: '/api/dsh-novel-forge/config',
115
127
  openFolder: '/api/dsh-novel-forge/open-folder',
128
+ /** 作者资产库/总数据:读取个人跨书资产(笔法/红线/套路/角色模板/世界观模板)。 */
129
+ authorAssets: '/api/dsh-novel-forge/author-assets',
130
+ /** 作者资产库:新增/更新一条资产(upsert by id)。 */
131
+ authorAssetsUpsert: '/api/dsh-novel-forge/author-assets/upsert',
132
+ /** 作者资产库:删除一条资产。 */
133
+ authorAssetsRemove: '/api/dsh-novel-forge/author-assets/remove',
134
+ /** 作者资产库:导入默认(书架书的写作资产/角色 + 内置全局库)批量沉淀。 */
135
+ authorAssetsImportDefault: '/api/dsh-novel-forge/author-assets/import-default',
136
+ /** 改编模式:上传全文 → 分析 → 原文设定卡片/可改范围矩阵。 */
137
+ adaptAnalyze: '/api/dsh-novel-forge/adapt/analyze',
138
+ /** 改编模式:确认要改的维度 → 生成映射表/改编规则/联动影响清单。 */
139
+ adaptPropose: '/api/dsh-novel-forge/adapt/propose',
140
+ /** 改编模式:执行术语替换(全局替换 + 命中统计 + 改编文本预览)。 */
141
+ adaptExecute: '/api/dsh-novel-forge/adapt/execute',
142
+ /** 主题自定义背景:上传图片(POST,存盘并返回服务端 URL)。 */
143
+ themeBackgroundUpload: '/api/dsh-novel-forge/theme/background',
144
+ /** 主题自定义背景:读取已上传文件(GET prefix,/theme/background/<name>)。 */
145
+ themeBackgroundGet: '/api/dsh-novel-forge/theme/background',
116
146
  } as const
117
147
 
118
148
  /** 书架:一本书的条目。 */
@@ -1039,6 +1069,23 @@ export interface ImageTestResponse {
1039
1069
  modelFound?: boolean
1040
1070
  }
1041
1071
 
1072
+ /** POST /llm-test 请求:对选中的提供商/模型发一次最小真实调用。 */
1073
+ export interface LlmTestRequest {
1074
+ provider: string
1075
+ model: string
1076
+ }
1077
+
1078
+ /** POST /llm-test 响应。 */
1079
+ export interface LlmTestResponse {
1080
+ ok: boolean
1081
+ /** 连通延迟(毫秒)。 */
1082
+ ms?: number
1083
+ /** 失败原因(已映射为人话)。 */
1084
+ message?: string
1085
+ /** 稳定错误码(LlmError code),便于排查。 */
1086
+ code?: string
1087
+ }
1088
+
1042
1089
  /** POST /roles 响应。 */
1043
1090
  export interface RolesResponse {
1044
1091
  roles: RoleRecord[]
@@ -1217,6 +1264,133 @@ export interface ImageModelConfig {
1217
1264
  }
1218
1265
 
1219
1266
  /** Runtime config surface exposed to the panel (subset of plugin Config). */
1267
+ /** 手动添加的模型库条目(只存插件内,不改 DSH 全局)。 */
1268
+ export interface SavedModel {
1269
+ /** 唯一 id(前端生成的短 id)。 */
1270
+ id: string
1271
+ /** 展示名(可为空,回退到 model)。 */
1272
+ name: string
1273
+ /** DSH 提供商路由(如 zai-coding-cn)。 */
1274
+ provider: string
1275
+ /** 模型 id(如 glm-5.3-flash)。 */
1276
+ model: string
1277
+ }
1278
+
1279
+ /** DSH 模型添加:厂商预设(选择厂商,直接填 API Key)。 */
1280
+ export interface LlmVendor {
1281
+ id: string
1282
+ name: string
1283
+ /** 该厂商对应的 provider 路由。 */
1284
+ route: string
1285
+ /** DSH 凭据引用名(写入 .credentials.yaml 的 refs)。 */
1286
+ apiKeyEnv: string
1287
+ /** 默认模型 id。 */
1288
+ defaultModel: string
1289
+ /** 建议可选模型 id 列表(下拉 data-list 用)。 */
1290
+ models: string[]
1291
+ /** 内置适配器(如 deepseek-official),无需注册 pi-ai 路由。 */
1292
+ builtin?: boolean
1293
+ }
1294
+
1295
+ /** 预置的常见厂商(id=provider 路由;添加模型下拉兜底用,其余厂商由运行时目录动态补充)。 */
1296
+ export const LLM_VENDORS: LlmVendor[] = [
1297
+ { id: 'deepseek-official', name: 'DeepSeek', route: 'deepseek-official', apiKeyEnv: 'DEEPSEEK_API_KEY', defaultModel: 'deepseek-v4-flash', models: ['deepseek-v4-flash', 'deepseek-v4-pro', 'deepseek-chat', 'deepseek-reasoner'], builtin: true },
1298
+ { id: 'zai-coding-cn', name: '智谱 GLM', route: 'zai-coding-cn', apiKeyEnv: 'ZAI_CODING_CN_API_KEY', defaultModel: 'glm-5.3-flash', models: ['glm-4.5-air', 'glm-4.7', 'glm-5-turbo', 'glm-5.1', 'glm-5.2', 'glm-5.3', 'glm-5.3-flash', 'glm-5v-turbo'] },
1299
+ { id: 'qwen-token-plan-cn', name: '千问百炼', route: 'qwen-token-plan-cn', apiKeyEnv: 'QWEN_TOKEN_PLAN_CN_API_KEY', defaultModel: 'qwen3.7-max', models: ['qwen3.6-flash', 'qwen3.6-plus', 'qwen3.7-max', 'qwen3.7-plus', 'qwen3.8-max', 'qwen3.8-max-preview'] },
1300
+ { id: 'openrouter', name: 'OpenRouter', route: 'openrouter', apiKeyEnv: 'OPENROUTER_API_KEY', defaultModel: 'z-ai/glm-5.3-flash', models: ['z-ai/glm-4.6', 'z-ai/glm-4.7', 'z-ai/glm-5', 'z-ai/glm-5-turbo', 'z-ai/glm-5.1', 'z-ai/glm-5.2', 'z-ai/glm-5.3-flash', 'auto', 'deepseek/deepseek-v4-flash', 'anthropic/claude-sonnet-4.6'] },
1301
+ ]
1302
+
1303
+ /** 运行时厂商目录的一项(添加到模型下拉;由 DSH 的 pi-ai 可配置提供方动态生成)。 */
1304
+ export interface LlmVendorOption {
1305
+ /** provider 路由 id(也是厂商下拉的值)。 */
1306
+ id: string
1307
+ /** 展示名。 */
1308
+ name: string
1309
+ /** 建议模型 id(可为空,用户手填)。 */
1310
+ models: string[]
1311
+ /** 已知 DSH 凭据引用名;为空时 host 生成 `PI_AI_<ID>_API_KEY`。 */
1312
+ apiKeyEnv?: string
1313
+ /** 内置适配器(只写凭据,不注册 pi-ai 路由)。 */
1314
+ builtin?: boolean
1315
+ }
1316
+
1317
+ /** GET /llm-vendors 响应。 */
1318
+ export interface LlmVendorsResponse {
1319
+ vendors: LlmVendorOption[]
1320
+ }
1321
+
1322
+ /** /llm-models 里的一条模型。 */
1323
+ export interface LlmModelOption { id: string; name: string }
1324
+
1325
+ /** GET /llm-models?provider=x 响应。 */
1326
+ export interface LlmModelsResponse {
1327
+ models: LlmModelOption[]
1328
+ }
1329
+
1330
+ /** GET /llm-providers 响应:当前已注册的提供方路由。 */
1331
+ export interface LlmProvidersResponse {
1332
+ providers: { id: string; name: string }[]
1333
+ }
1334
+
1335
+ /** POST /llm-remove 请求:移除一个提供方(unset key + 移除 llm-pi-ai 路由)。 */
1336
+ export interface RemoveProviderRequest {
1337
+ provider: string
1338
+ /** 该提供方对应的 DSH 凭据引用名(用于 unset)。 */
1339
+ apiKeyEnv?: string
1340
+ }
1341
+
1342
+ /** POST /llm-remove 响应。 */
1343
+ export interface RemoveProviderResponse {
1344
+ ok: boolean
1345
+ message?: string
1346
+ }
1347
+
1348
+ /** GET /llm-providers 响应:当前已注册的提供方路由。 */
1349
+ export interface LlmProvidersResponse {
1350
+ providers: { id: string; name: string }[]
1351
+ }
1352
+
1353
+ /** POST /llm-remove 请求:移除一个提供方(unset key + 移除 llm-pi-ai 路由)。 */
1354
+ export interface RemoveProviderRequest {
1355
+ provider: string
1356
+ /** 该提供方对应的 DSH 凭据引用名(用于 unset)。 */
1357
+ apiKeyEnv?: string
1358
+ }
1359
+
1360
+ /** POST /llm-remove 响应。 */
1361
+ export interface RemoveProviderResponse {
1362
+ ok: boolean
1363
+ message?: string
1364
+ }
1365
+
1366
+ /** POST /llm-add 请求:添加一个模型(厂商直填 key,或自定义路由)。 */
1367
+ export interface AddModelRequest {
1368
+ mode: 'vendor' | 'custom'
1369
+ /** 厂商模式用:provider 路由 id(来自 /llm-vendors)。 */
1370
+ vendor?: string
1371
+ /** 厂商已知的 DSH 凭据引用名(可选;为空时 host 生成)。 */
1372
+ apiKeyEnv?: string
1373
+ /** 自定义模式用:provider 路由 id。 */
1374
+ provider?: string
1375
+ /** 模型 id。 */
1376
+ model: string
1377
+ /** API Key。 */
1378
+ apiKey: string
1379
+ /** 展示名(可选)。 */
1380
+ name?: string
1381
+ /** 自定义模式用:OpenAI 兼容 base URL。 */
1382
+ baseURL?: string
1383
+ }
1384
+
1385
+ /** POST /llm-add 响应。 */
1386
+ export interface AddModelResponse {
1387
+ ok: boolean
1388
+ saved: SavedModel
1389
+ provider: string
1390
+ message?: string
1391
+ }
1392
+
1393
+ /** 手动添加的模型库条目(只存插件内,不改 DSH 全局)。 */
1220
1394
  export interface NovelConfig {
1221
1395
  /** Absolute path of the default docx outline to load. */
1222
1396
  outlinePath: string
@@ -1252,6 +1426,16 @@ export interface NovelConfig {
1252
1426
  imageApiModel?: string
1253
1427
  /** 是否启用生图(= 存在启用条目)。 */
1254
1428
  imageApiEnabled?: boolean
1429
+ /** 自定义背景图(URL 或 dataURL 或服务端路径引用;空 = 使用主题默认背景)。 */
1430
+ themeBackground?: string
1431
+ /** 自定义背景遮罩/模糊强度 0-80(0 = 不遮罩)。 */
1432
+ themeBackgroundBlur?: number
1433
+ /** 玻璃透明度 0-100(100=当前原样,越小越透,新拟态/黏土可见背景图)。 */
1434
+ themeOpacity?: number
1435
+ /** 是否启用改编模式(默认关闭;发布后开启)。 */
1436
+ enableAdaptMode?: boolean
1437
+ /** 手动添加的模型库(「我的模型」条目;只存插件内)。 */
1438
+ savedModels?: SavedModel[]
1255
1439
  }
1256
1440
 
1257
1441
  /** GET /status response. */
@@ -1468,8 +1652,17 @@ export interface ConfigPatch {
1468
1652
  imageApiKey?: string
1469
1653
  imageApiModel?: string
1470
1654
  imageApiEnabled?: boolean
1655
+ /** 自定义背景图(URL / dataURL / 服务端路径引用)。 */
1656
+ themeBackground?: string
1657
+ /** 自定义背景遮罩/模糊强度 0-80。 */
1658
+ themeBackgroundBlur?: number
1659
+ /** 玻璃透明度 0-100(100=当前原样)。 */
1660
+ themeOpacity?: number
1661
+ enableAdaptMode?: boolean
1471
1662
  /** 生图模型库(完整替换保存)。 */
1472
1663
  imageModels?: ImageModelConfig[]
1664
+ /** 手动添加的模型库(完整替换保存)。 */
1665
+ savedModels?: SavedModel[]
1473
1666
  }
1474
1667
 
1475
1668
  // ------------------------------------------------------------ assistant
@@ -1633,3 +1826,166 @@ export interface StyleEngineRequest {
1633
1826
  /** 资产名(可选,默认「风格资产 N」)。 */
1634
1827
  name?: string
1635
1828
  }
1829
+
1830
+ // ---------------------------------------------------------- author assets (总数据)
1831
+
1832
+ /** 作者资产库中一条可跨书复用的资产(笔法/红线/套路/角色模板/世界观模板等)。 */
1833
+ export interface AuthorStyleAsset {
1834
+ /** 稳定 id(本地唯一)。 */
1835
+ id: string
1836
+ /** 资产名(如「短句快节奏爽文风」「林越式痞坏角色」)。 */
1837
+ name: string
1838
+ /** 资产类型。 */
1839
+ kind: 'style' | 'antiAi' | 'progression' | 'genre' | 'roleTemplate' | 'worldTemplate' | 'custom'
1840
+ /** 一句话摘要。 */
1841
+ summary: string
1842
+ /** 资产正文内容(按 kind 约定解读的文本/JSON 描述)。 */
1843
+ content: string
1844
+ /** 结构化载荷(角色模板/世界观模板等可结构化字段;缺省为 null)。 */
1845
+ structured?: Record<string, unknown>
1846
+ /** 来源书名(哪本书提炼/收藏而来)。 */
1847
+ sourceBooks: string[]
1848
+ /** 标签。 */
1849
+ tags: string[]
1850
+ /** 来源样本文本(可选)。 */
1851
+ sourceText?: string
1852
+ /** 创建时间。 */
1853
+ createdAt: string
1854
+ /** 更新时间。 */
1855
+ updatedAt: string
1856
+ }
1857
+
1858
+ /** 作者资产库(跨书总数据):按作者维度聚合的可复用资产。 */
1859
+ export interface AuthorAssetLibrary {
1860
+ /** 货架版本,便于未来迁移。 */
1861
+ version: 1
1862
+ items: AuthorStyleAsset[]
1863
+ }
1864
+
1865
+ /** GET /author-assets 响应。 */
1866
+ export interface AuthorAssetsResponse {
1867
+ assets: AuthorAssetLibrary
1868
+ }
1869
+
1870
+ /** POST /author-assets/upsert 请求:新增或按 id 更新一条资产。 */
1871
+ export interface AuthorAssetUpsertRequest {
1872
+ asset: AuthorStyleAsset
1873
+ }
1874
+
1875
+ /** POST /author-assets/remove 请求:删除一条资产。 */
1876
+ export interface AuthorAssetRemoveRequest {
1877
+ id: string
1878
+ }
1879
+
1880
+ // ---------------------------------------------------------- adaptation (改编模式)
1881
+
1882
+ /** 改编可改范围的单个维度(矩阵的一行)。 */
1883
+ export interface AdaptationDimension {
1884
+ /** 维度 key(如 realm/name/goldenFinger…)。 */
1885
+ key: string
1886
+ /** 维度名(如「大世界」「修为体系」「主角名」「金手指」)。 */
1887
+ title: string
1888
+ /** 可改度:保留 / 可改影响大 / 可改影响小 / 可自由改 / 仅视觉包装。 */
1889
+ mutability: 'locked' | 'big' | 'small' | 'free' | 'visual'
1890
+ /** 原文当前值(从正文提炼,附证据)。 */
1891
+ current: string
1892
+ /** 该值在正文中的出现证据(章节/频次,可空)。 */
1893
+ evidence?: string
1894
+ /** AI 建议的候选新值(可空)。 */
1895
+ candidates?: string[]
1896
+ /** 联动影响说明(改了会影响哪些章节/角色/伏笔/术语)。 */
1897
+ impact: string
1898
+ /** 风险评级。 */
1899
+ risk: 'high' | 'medium' | 'low'
1900
+ }
1901
+
1902
+ /** POST /adapt/analyze 请求:上传全文做改编分析。 */
1903
+ export interface AdaptAnalyzeRequest {
1904
+ /** 全文文本(优先)。 */
1905
+ text: string
1906
+ /** 或服务器端全文文件路径。 */
1907
+ filePath?: string
1908
+ }
1909
+
1910
+ /** POST /adapt/analyze 响应。 */
1911
+ export interface AdaptAnalyzeResponse {
1912
+ /** 识别书名(文件名推断或正文首行)。 */
1913
+ bookName: string
1914
+ /** 拆出的章节数。 */
1915
+ chapters: number
1916
+ /** 反推的初始大纲(可空)。 */
1917
+ outline?: string
1918
+ /** 可改范围矩阵。 */
1919
+ dimensions: AdaptationDimension[]
1920
+ /** 分析消耗说明。 */
1921
+ note?: string
1922
+ }
1923
+
1924
+ /** 一条改编映射(原值 → 新值)。 */
1925
+ export interface AdaptationMapping {
1926
+ /** 原值(如「林尘」「练气」「青云宗」)。 */
1927
+ source: string
1928
+ /** 新值(如「楚风」「凝元」「天渊阁」)。 */
1929
+ target: string
1930
+ /** 适用范围。 */
1931
+ scope: 'name' | 'realm' | 'faction' | 'term' | 'other'
1932
+ /** 说明(可空)。 */
1933
+ note?: string
1934
+ }
1935
+
1936
+ /** 改编规则:哪些必须保留、哪些允许改、一致性约束。 */
1937
+ export interface AdaptationRules {
1938
+ /** 必须保留的要素(骨架/人物动机/伏笔逻辑/爽点结构…)。 */
1939
+ preserve: string[]
1940
+ /** 允许改变的要素。 */
1941
+ change: string[]
1942
+ /** 改编红线/一致性要求。 */
1943
+ constraints: string[]
1944
+ }
1945
+
1946
+ /** 一组改编方案(映射表 + 规则 + 联动影响清单)。 */
1947
+ export interface AdaptationProposal {
1948
+ /** 映射表(原→新)。 */
1949
+ mappings: AdaptationMapping[]
1950
+ /** 改编规则。 */
1951
+ rules: AdaptationRules
1952
+ /** 联动影响清单。 */
1953
+ impacts: Array<{ item: string; detail: string; risk: 'high' | 'medium' | 'low'; chapters?: number[] }>
1954
+ }
1955
+
1956
+ /** POST /adapt/propose 请求:由用户勾选的维度 + 新值生成改编方案。 */
1957
+ export interface AdaptProposeRequest {
1958
+ /** 原文全文(复用,便于 LLM 核对联动影响)。 */
1959
+ text: string
1960
+ /** 用户确认要改的维度(含原值与新值)。 */
1961
+ selections: Array<{ key: string; title: string; current: string; target: string; mutability: string }>
1962
+ /** 若已分析过,可携带完整矩阵作为上下文。 */
1963
+ dimensions?: AdaptationDimension[]
1964
+ }
1965
+
1966
+ /** POST /adapt/propose 响应。 */
1967
+ export interface AdaptProposeResponse {
1968
+ proposal: AdaptationProposal
1969
+ }
1970
+
1971
+ /** POST /adapt/execute 请求:执行改编(首版为术语替换)。 */
1972
+ export interface AdaptExecuteRequest {
1973
+ /** 原文全文。 */
1974
+ text: string
1975
+ /** 改编映射表。 */
1976
+ mappings: AdaptationMapping[]
1977
+ /** 改编规则(可选,后续逐章改写使用;替换模式暂不依赖)。 */
1978
+ rules?: AdaptationRules
1979
+ /** 执行模式:首版仅 replace(术语替换)。 */
1980
+ mode?: 'replace' | 'rewrite'
1981
+ }
1982
+
1983
+ /** POST /adapt/execute 响应。 */
1984
+ export interface AdaptExecuteResponse {
1985
+ /** 改编后的全文。 */
1986
+ adaptedText: string
1987
+ /** 执行的映射数。 */
1988
+ mappings: number
1989
+ /** 命中统计:每条映射的替换次数。 */
1990
+ hits: Array<{ source: string; target: string; count: number }>
1991
+ }