@dsh-workbench/shared 0.3.11 → 1.0.0-beta.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 (371) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +97 -0
  3. package/dist/api/blocker-table.d.ts +3 -3
  4. package/dist/api/blocker-table.js +47 -23
  5. package/dist/api/dsh.d.ts +1 -1
  6. package/dist/api/workbench-client.js +2 -1
  7. package/dist/components/Activity.css +0 -1
  8. package/dist/components/ApprovalDetail.css +1 -2
  9. package/dist/components/ApprovalDetail.d.ts +1 -1
  10. package/dist/components/ApprovalPlan.css +0 -1
  11. package/dist/components/Card.css +0 -1
  12. package/dist/components/Card.d.ts +1 -1
  13. package/dist/components/CardBoundary.d.ts +1 -1
  14. package/dist/components/CardHead.css +0 -1
  15. package/dist/components/CardHead.d.ts +1 -1
  16. package/dist/components/ChoiceGroup.css +1 -2
  17. package/dist/components/ConfirmBar.d.ts +1 -1
  18. package/dist/components/ConfirmBar.js +1 -1
  19. package/dist/components/Form.css +1 -1
  20. package/dist/components/FormActions.js +1 -1
  21. package/dist/components/LongTaskRow.css +1 -2
  22. package/dist/components/LongTaskRow.d.ts +1 -1
  23. package/dist/components/LongTaskRow.js +1 -1
  24. package/dist/components/Note.css +0 -1
  25. package/dist/components/ResourceStates.css +0 -1
  26. package/dist/components/SettingsSection.css +0 -1
  27. package/dist/components/Spinner.css +0 -1
  28. package/dist/components/Stack.css +0 -1
  29. package/dist/components/StateBlock.css +0 -1
  30. package/dist/components/board-module.d.ts +3 -3
  31. package/dist/components/icons.d.ts +1 -1
  32. package/dist/components/icons.js +11 -4
  33. package/dist/config/constants.d.ts +2 -2
  34. package/dist/config/constants.js +2 -2
  35. package/dist/contract/adapters.d.ts +10 -0
  36. package/dist/contract/cli.d.ts +3 -0
  37. package/dist/contract/data.d.ts +126 -0
  38. package/dist/{api → contract}/facts.d.ts +12 -3
  39. package/dist/{api → contract}/facts.js +19 -1
  40. package/dist/contract/needs.d.ts +132 -0
  41. package/dist/contract/needs.js +232 -0
  42. package/dist/contract/plugin-source.d.ts +1 -0
  43. package/dist/contract/protocol/bundle-install.d.ts +136 -0
  44. package/dist/contract/protocol/bundle-install.js +12 -0
  45. package/dist/contract/protocol/config-sync.d.ts +55 -0
  46. package/dist/contract/protocol/config-sync.js +2 -0
  47. package/dist/contract/protocol/diy.d.ts +4 -0
  48. package/dist/contract/protocol/diy.js +4 -0
  49. package/dist/contract/protocol/dsh-plugins.d.ts +11 -0
  50. package/dist/contract/protocol/dsh-plugins.js +1 -0
  51. package/dist/contract/protocol/long-tasks.d.ts +13 -0
  52. package/dist/contract/protocol/long-tasks.js +1 -0
  53. package/dist/contract/protocol/market-index.d.ts +195 -0
  54. package/dist/contract/protocol/market-index.js +7 -0
  55. package/dist/contract/protocol/platform.d.ts +44 -0
  56. package/dist/contract/protocol/platform.js +1 -0
  57. package/dist/contract/protocol/preflight-wake.d.ts +7 -0
  58. package/dist/contract/protocol/preflight-wake.js +1 -0
  59. package/dist/contract/protocol/profile-create.d.ts +30 -0
  60. package/dist/contract/protocol/profile-create.js +2 -0
  61. package/dist/contract/protocol/sidebar-edition.d.ts +14 -0
  62. package/dist/contract/protocol/sidebar-edition.js +2 -0
  63. package/dist/contract/protocol/unit-manifests.d.ts +6 -0
  64. package/dist/contract/protocol/unit-manifests.js +1 -0
  65. package/dist/contract/unit-board.js +1 -0
  66. package/dist/contract/unit-capability.d.ts +34 -0
  67. package/dist/contract/unit-capability.js +1 -0
  68. package/dist/{host → contract}/unit-declaration.d.ts +7 -5
  69. package/dist/{api → contract}/unit-declaration.js +19 -13
  70. package/dist/contract/unit.d.ts +57 -0
  71. package/dist/contract/unit.js +24 -0
  72. package/dist/contract/workbench-contract.d.ts +15 -0
  73. package/dist/contract/workbench-contract.js +1 -0
  74. package/dist/host/adapter-set.d.ts +26 -0
  75. package/dist/host/adapter-set.js +243 -0
  76. package/dist/host/adapter-types.d.ts +79 -0
  77. package/dist/host/adapter-types.js +23 -0
  78. package/dist/host/adapters.d.ts +22 -0
  79. package/dist/host/adapters.js +9 -0
  80. package/dist/host/browser.d.ts +3 -0
  81. package/dist/host/browser.js +3 -0
  82. package/dist/host/changelog.d.ts +21 -0
  83. package/dist/host/changelog.js +188 -0
  84. package/dist/host/channel-plugin.d.ts +15 -0
  85. package/dist/host/channel-plugin.js +42 -0
  86. package/dist/host/cli.d.ts +4 -0
  87. package/dist/host/cli.js +7 -0
  88. package/dist/host/command-name.d.ts +1 -0
  89. package/dist/host/command-name.js +14 -0
  90. package/dist/host/data-error.d.ts +13 -0
  91. package/dist/host/data-error.js +20 -0
  92. package/dist/host/data-root.js +3 -0
  93. package/dist/host/diy-debug.js +2 -1
  94. package/dist/host/diy-record.js +2 -1
  95. package/dist/host/facts.d.ts +1 -1
  96. package/dist/host/facts.js +3 -2
  97. package/dist/host/git.js +2 -2
  98. package/dist/host/http.js +1 -1
  99. package/dist/host/lib-capabilities.d.ts +22 -0
  100. package/dist/host/lib-capabilities.js +37 -0
  101. package/dist/host/lib-install.d.ts +9 -0
  102. package/dist/host/lib-install.js +10 -0
  103. package/dist/host/long-task.d.ts +1 -1
  104. package/dist/host/long-task.js +4 -3
  105. package/dist/host/market-index.d.ts +22 -0
  106. package/dist/host/market-index.js +420 -0
  107. package/dist/host/needs.d.ts +4 -0
  108. package/dist/host/needs.js +2 -0
  109. package/dist/host/patch.d.ts +9 -0
  110. package/dist/host/patch.js +78 -0
  111. package/dist/host/paths.d.ts +12 -0
  112. package/dist/host/paths.js +28 -0
  113. package/dist/host/platform.d.ts +14 -0
  114. package/dist/host/platform.js +40 -0
  115. package/dist/host/plugin-source.d.ts +8 -6
  116. package/dist/host/plugin-source.js +43 -33
  117. package/dist/host/plugin.d.ts +4 -0
  118. package/dist/host/plugin.js +39 -0
  119. package/dist/host/port-types.d.ts +191 -0
  120. package/dist/host/port-types.js +1 -0
  121. package/dist/host/preflight.d.ts +28 -0
  122. package/dist/host/preflight.js +1 -0
  123. package/dist/host/profile-port.d.ts +4 -0
  124. package/dist/host/profile-port.js +4 -0
  125. package/dist/host/provision.d.ts +2 -2
  126. package/dist/host/provision.js +5 -3
  127. package/dist/host/recipe-rules.d.ts +5 -0
  128. package/dist/host/recipe-rules.js +382 -0
  129. package/dist/host/recipe.d.ts +14 -0
  130. package/dist/host/recipe.js +283 -0
  131. package/dist/host/shell-text.d.ts +9 -2
  132. package/dist/host/shell-text.js +15 -3
  133. package/dist/host/shell.d.ts +2 -0
  134. package/dist/host/shell.js +7 -0
  135. package/dist/host/spec.d.ts +8 -0
  136. package/dist/host/spec.js +24 -0
  137. package/dist/host/supply-index.d.ts +34 -0
  138. package/dist/host/supply-index.js +202 -0
  139. package/dist/host/supply-port.d.ts +5 -0
  140. package/dist/host/supply-port.js +39 -0
  141. package/dist/host/time.d.ts +12 -0
  142. package/dist/host/time.js +19 -0
  143. package/dist/host/tokens.d.ts +26 -0
  144. package/dist/host/tokens.js +154 -0
  145. package/dist/host/tool-kit.js +1 -1
  146. package/dist/host/unit-face.d.ts +5 -4
  147. package/dist/host/version-range.d.ts +2 -0
  148. package/dist/host/version-range.js +73 -0
  149. package/dist/host/version.d.ts +3 -0
  150. package/dist/host/version.js +29 -0
  151. package/dist/host.d.ts +47 -16
  152. package/dist/host.js +47 -16
  153. package/dist/i18n/en.js +224 -71
  154. package/dist/i18n/index.d.ts +298 -73
  155. package/dist/i18n/merge.js +1 -1
  156. package/dist/i18n/need-text.d.ts +26 -0
  157. package/dist/i18n/need-text.js +26 -0
  158. package/dist/i18n/settings.d.ts +70 -0
  159. package/dist/i18n/settings.js +136 -0
  160. package/dist/i18n/zh.d.ts +297 -72
  161. package/dist/i18n/zh.js +226 -73
  162. package/dist/index.d.ts +23 -7
  163. package/dist/index.js +23 -7
  164. package/dist/{api → lib}/dsh-client.d.ts +11 -1
  165. package/dist/lib/dsh-client.js +1 -0
  166. package/dist/lib/market-index.d.ts +7 -0
  167. package/dist/lib/market-index.js +25 -0
  168. package/dist/lib/react.d.ts +0 -40
  169. package/dist/lib/react.js +0 -36
  170. package/dist/lib/ui.js +3 -9
  171. package/dist/testing/data.d.ts +13 -0
  172. package/dist/testing/data.js +46 -0
  173. package/dist/testing/declaration.d.ts +1 -1
  174. package/dist/testing/declaration.js +1 -1
  175. package/dist/testing/host-fakes.d.ts +0 -13
  176. package/dist/testing/host-fakes.js +0 -24
  177. package/dist/testing/needs.d.ts +16 -0
  178. package/dist/testing/needs.js +46 -0
  179. package/dist/testing.d.ts +2 -0
  180. package/dist/testing.js +2 -0
  181. package/package.json +18 -2
  182. package/src/api/__tests__/blocker-table.test.ts +135 -86
  183. package/src/api/blocker-table.ts +52 -26
  184. package/src/api/dsh.ts +1 -1
  185. package/src/api/host-write.ts +0 -1
  186. package/src/api/workbench-client.test.ts +2 -2
  187. package/src/api/workbench-client.ts +2 -1
  188. package/src/components/Activity.css +0 -1
  189. package/src/components/ApprovalDetail.css +1 -2
  190. package/src/components/ApprovalDetail.tsx +1 -1
  191. package/src/components/ApprovalPlan.css +0 -1
  192. package/src/components/Card.css +0 -1
  193. package/src/components/Card.tsx +1 -1
  194. package/src/components/CardAnchor.test.tsx +1 -1
  195. package/src/components/CardBoundary.tsx +1 -1
  196. package/src/components/CardHead.css +0 -1
  197. package/src/components/CardHead.tsx +1 -1
  198. package/src/components/ChoiceGroup.css +1 -2
  199. package/src/components/ConfirmBar.tsx +1 -1
  200. package/src/components/Form.css +1 -1
  201. package/src/components/Form.tsx +1 -1
  202. package/src/components/FormActions.tsx +1 -1
  203. package/src/components/LongTaskRow.css +1 -2
  204. package/src/components/LongTaskRow.tsx +1 -1
  205. package/src/components/Note.css +0 -1
  206. package/src/components/ResourceStates.css +0 -1
  207. package/src/components/SelectFieldNodes.tsx +0 -1
  208. package/src/components/SettingsSection.css +0 -1
  209. package/src/components/Spinner.css +0 -1
  210. package/src/components/Stack.css +0 -1
  211. package/src/components/StateBlock.css +0 -1
  212. package/src/components/__tests__/long-task-row.test.ts +1 -1
  213. package/src/components/board-module.ts +3 -3
  214. package/src/components/icons.tsx +16 -8
  215. package/src/config/constants.ts +2 -2
  216. package/src/{api → contract}/__tests__/facts.test.ts +73 -25
  217. package/src/{api → contract}/__tests__/long-task.test.ts +3 -3
  218. package/src/contract/__tests__/needs.test.ts +74 -0
  219. package/src/{host → contract}/__tests__/unit-declaration.test.ts +1 -1
  220. package/src/contract/__tests__/unit.test.ts +43 -0
  221. package/src/contract/adapters.ts +9 -0
  222. package/src/contract/cli.ts +3 -0
  223. package/src/contract/data.ts +145 -0
  224. package/src/{api → contract}/facts.ts +34 -4
  225. package/src/contract/needs.ts +331 -0
  226. package/src/contract/plugin-source.ts +1 -0
  227. package/src/contract/protocol/bundle-install.ts +198 -0
  228. package/src/contract/protocol/config-sync.ts +65 -0
  229. package/src/contract/protocol/diy.ts +4 -0
  230. package/src/contract/protocol/dsh-plugins.ts +13 -0
  231. package/src/contract/protocol/long-tasks.ts +16 -0
  232. package/src/contract/protocol/market-index.ts +246 -0
  233. package/src/contract/protocol/platform.ts +47 -0
  234. package/src/contract/protocol/preflight-wake.ts +17 -0
  235. package/src/contract/protocol/profile-create.ts +36 -0
  236. package/src/contract/protocol/sidebar-edition.ts +19 -0
  237. package/src/contract/protocol/unit-manifests.ts +8 -0
  238. package/src/{api → contract}/unit-board.ts +0 -1
  239. package/src/contract/unit-capability.ts +37 -0
  240. package/src/{host → contract}/unit-declaration.ts +22 -18
  241. package/src/contract/unit.ts +76 -0
  242. package/src/contract/workbench-contract.ts +30 -0
  243. package/src/host/__tests__/adapter-set.test.ts +228 -0
  244. package/src/host/__tests__/adapters.test.ts +27 -0
  245. package/src/host/__tests__/changelog.test.ts +102 -0
  246. package/src/host/__tests__/command-name.test.ts +16 -0
  247. package/src/host/__tests__/diy-record.test.ts +3 -3
  248. package/src/host/__tests__/facts.test.ts +5 -5
  249. package/src/host/__tests__/long-task.test.ts +1 -1
  250. package/src/host/__tests__/market-index.test.ts +179 -0
  251. package/src/host/__tests__/plugin-ledger.test.ts +10 -10
  252. package/src/host/__tests__/provision.test.ts +7 -6
  253. package/src/host/__tests__/shell-text.test.ts +16 -1
  254. package/src/host/__tests__/supply-index.test.ts +137 -0
  255. package/src/host/__tests__/tokens.test.ts +110 -0
  256. package/src/host/__tests__/version-range.test.ts +21 -0
  257. package/src/host/adapter-set.ts +298 -0
  258. package/src/host/adapter-types.ts +105 -0
  259. package/src/host/adapters.ts +44 -0
  260. package/src/host/browser.ts +3 -0
  261. package/src/host/changelog.ts +212 -0
  262. package/src/host/channel-plugin.ts +55 -0
  263. package/src/host/cli.ts +11 -0
  264. package/src/host/command-name.ts +15 -0
  265. package/src/host/data-error.ts +21 -0
  266. package/src/host/data-root.ts +2 -0
  267. package/src/host/diy-debug.ts +2 -1
  268. package/src/host/diy-record.ts +2 -1
  269. package/src/host/facts.ts +4 -3
  270. package/src/host/git.ts +2 -2
  271. package/src/host/http.ts +1 -1
  272. package/src/host/lib-capabilities.ts +52 -0
  273. package/src/host/lib-install.ts +18 -0
  274. package/src/host/long-task.ts +4 -3
  275. package/src/host/market-index.ts +413 -0
  276. package/src/host/needs.ts +6 -0
  277. package/src/host/patch.ts +93 -0
  278. package/src/host/paths.ts +37 -0
  279. package/src/host/platform.ts +48 -0
  280. package/src/host/plugin-source.ts +48 -56
  281. package/src/host/plugin.ts +39 -0
  282. package/src/host/port-types.ts +222 -0
  283. package/src/host/preflight.ts +31 -0
  284. package/src/host/profile-port.ts +9 -0
  285. package/src/host/provision.ts +7 -4
  286. package/src/host/recipe-rules.ts +330 -0
  287. package/src/host/recipe.test.ts +334 -0
  288. package/src/host/recipe.ts +323 -0
  289. package/src/host/shell-text.ts +15 -3
  290. package/src/host/shell.ts +9 -0
  291. package/src/host/spec.ts +32 -0
  292. package/src/host/supply-index.ts +256 -0
  293. package/src/host/supply-port.ts +45 -0
  294. package/src/host/time.ts +22 -0
  295. package/src/host/tokens.ts +186 -0
  296. package/src/host/tool-kit.ts +1 -1
  297. package/src/host/unit-face.ts +5 -4
  298. package/src/host/version-range.ts +71 -0
  299. package/src/host/version.ts +30 -0
  300. package/src/host.ts +47 -16
  301. package/src/i18n/en.ts +224 -71
  302. package/src/i18n/merge.test.ts +6 -6
  303. package/src/i18n/merge.ts +1 -1
  304. package/src/i18n/need-text.ts +27 -0
  305. package/src/i18n/settings.ts +141 -0
  306. package/src/i18n/zh.ts +227 -73
  307. package/src/index.ts +23 -7
  308. package/src/lib/blocker-action.ts +0 -1
  309. package/src/{api → lib}/dsh-client.ts +12 -1
  310. package/src/lib/market-index.ts +36 -0
  311. package/src/lib/react.ts +0 -40
  312. package/src/lib/text.test.ts +2 -2
  313. package/src/lib/ui.test.ts +6 -5
  314. package/src/lib/ui.ts +3 -9
  315. package/src/testing/__tests__/declaration.test.ts +1 -1
  316. package/src/testing/data.ts +66 -0
  317. package/src/testing/declaration.ts +2 -2
  318. package/src/testing/host-fakes.ts +0 -38
  319. package/src/testing/needs.ts +80 -0
  320. package/src/testing.ts +2 -0
  321. package/dist/api/unit-declaration.d.ts +0 -65
  322. package/dist/api/unit.d.ts +0 -85
  323. package/dist/api/unit.js +0 -8
  324. package/dist/api/workbench-contract.d.ts +0 -44
  325. package/dist/components/MockStrip.css +0 -39
  326. package/dist/components/MockStrip.d.ts +0 -15
  327. package/dist/components/MockStrip.js +0 -8
  328. package/dist/components/SaveBar.css +0 -7
  329. package/dist/host/browser-find.d.ts +0 -38
  330. package/dist/host/browser-find.js +0 -242
  331. package/dist/host/browser-read.d.ts +0 -28
  332. package/dist/host/browser-read.js +0 -243
  333. package/dist/host/opencli-runtime.d.ts +0 -25
  334. package/dist/host/opencli-runtime.js +0 -56
  335. package/dist/host/opencli-window.d.ts +0 -2
  336. package/dist/host/opencli-window.js +0 -8
  337. package/dist/host/opencli.d.ts +0 -37
  338. package/dist/host/opencli.js +0 -155
  339. package/dist/host/unit-declaration.js +0 -213
  340. package/dist/host/unit-libs.d.ts +0 -37
  341. package/dist/lib/diy-debug.d.ts +0 -80
  342. package/dist/lib/diy-debug.js +0 -88
  343. package/dist/lib/diy-record.d.ts +0 -135
  344. package/dist/lib/diy-record.js +0 -162
  345. package/dist/lib/lint-probe.d.ts +0 -1
  346. package/dist/lib/lint-probe.js +0 -6
  347. package/dist/lib/panel-state.d.ts +0 -120
  348. package/dist/lib/panel-state.js +0 -176
  349. package/src/api/__tests__/unit.test.ts +0 -38
  350. package/src/api/unit.ts +0 -93
  351. package/src/api/workbench-contract.ts +0 -59
  352. package/src/host/__tests__/browser-find.test.ts +0 -330
  353. package/src/host/__tests__/browser-read.test.ts +0 -228
  354. package/src/host/__tests__/opencli-runtime.test.ts +0 -46
  355. package/src/host/browser-find.ts +0 -311
  356. package/src/host/browser-read.ts +0 -311
  357. package/src/host/opencli-runtime.ts +0 -79
  358. package/src/host/opencli-window.ts +0 -11
  359. package/src/host/opencli.ts +0 -213
  360. package/src/host/unit-libs.ts +0 -41
  361. /package/dist/{api/blocker.js → contract/adapters.js} +0 -0
  362. /package/dist/{api → contract}/blocker.d.ts +0 -0
  363. /package/dist/{api/dsh-client.js → contract/blocker.js} +0 -0
  364. /package/dist/{api/unit-board.js → contract/cli.js} +0 -0
  365. /package/dist/{api/workbench-contract.js → contract/data.js} +0 -0
  366. /package/dist/{api → contract}/long-task.d.ts +0 -0
  367. /package/dist/{api → contract}/long-task.js +0 -0
  368. /package/dist/{host/unit-libs.js → contract/plugin-source.js} +0 -0
  369. /package/dist/{api → contract}/unit-board.d.ts +0 -0
  370. /package/src/{api → contract}/blocker.ts +0 -0
  371. /package/src/{api → contract}/long-task.ts +0 -0
@@ -1,4 +1,3 @@
1
-
2
1
  .wb-note {
3
2
  margin: 0;
4
3
  font-size: var(--dsw-font-xxs-12-font-size);
@@ -1,4 +1,3 @@
1
-
2
1
  .wb-centered.wb-centeredCompact {
3
2
  flex: none;
4
3
  min-height: 0;
@@ -98,4 +98,3 @@ export function selectLoadingNode(args: {
98
98
  </button>
99
99
  );
100
100
  }
101
-
@@ -1,4 +1,3 @@
1
-
2
1
  section.wb-settings {
3
2
  display: flex;
4
3
  flex-direction: column;
@@ -1,4 +1,3 @@
1
-
2
1
  .wb-spinner {
3
2
  display: inline-flex;
4
3
  align-items: center;
@@ -1,4 +1,3 @@
1
-
2
1
  .wb-stack {
3
2
  display: flex;
4
3
  flex-direction: column;
@@ -1,4 +1,3 @@
1
-
2
1
  .wb-stateBlock {
3
2
  display: flex;
4
3
  flex-direction: column;
@@ -43,7 +43,7 @@ describe('两按停止钮:接线(这仓的组件测试是 node 环境,读
43
43
  });
44
44
 
45
45
  it('★★ 上膛后 3 秒自己落膛:用 LONG_TASK_STOP_ARM_MS,卸载 / 落膛都清掉计时器', () => {
46
- expect(ROW).toContain("from '../api/long-task.js'");
46
+ expect(ROW).toContain("from '../contract/long-task.js'");
47
47
  expect(ROW).toContain('setTimeout(() => setArmed(false), LONG_TASK_STOP_ARM_MS)');
48
48
  expect(ROW).toContain('clearTimeout(timer)');
49
49
  expect(ROW).toContain('}, [armed]);');
@@ -1,7 +1,7 @@
1
1
  import type { ReactNode } from 'react';
2
- import type { SessionsSnapshot, Translate, WorkspaceSnapshot, WorkspaceView } from '../api/dsh-client.js';
3
- import type { UnitManifest } from '../api/unit.js';
4
- import type { CapabilityPayload } from '../api/workbench-contract.js';
2
+ import type { SessionsSnapshot, Translate, WorkspaceSnapshot, WorkspaceView } from '../lib/dsh-client.js';
3
+ import type { UnitManifest } from '../contract/unit.js';
4
+ import type { CapabilityPayload } from '../contract/workbench-contract.js';
5
5
  import type { Dictionaries } from '../i18n/index.js';
6
6
 
7
7
  /**
@@ -51,20 +51,28 @@ export function IconConversation({ size = 16 }: IconProps) {
51
51
  );
52
52
  }
53
53
 
54
+ const BRAND_FRAME = 'M10 6H54A5 5 0 0 1 59 11V43A5 5 0 0 1 54 48H10A5 5 0 0 1 5 43V11A5 5 0 0 1 10 6Z M12 10H52A3 3 0 0 1 55 13V41A3 3 0 0 1 52 44H12A3 3 0 0 1 9 41V13A3 3 0 0 1 12 10Z';
55
+
56
+ const BRAND_TAIL =
57
+ 'M8.844 13.742C8.967 12.328 8.45 10.4 8.45 9.65C8.45 8.94 8.88 8.43 9.6 8.43C11.285 8.43 12.106 8.281 12.685 8.104C13.71 7.791 14.585 6.768 15.055 5.945C15.137 5.803 14.99 5.641 14.829 5.671C13.829 5.86 12.828 5.376 11.827 4.978C10.659 4.514 9.491 4.707 8.935 4.876C8.805 4.915 8.658 4.819 8.636 4.686C8.468 3.643 7.405 2.615 5.498 2.238C4.54 2.048 3.748 1.574 3.347 1.202C3.252 1.113 3.088 1.125 3.03 1.242C2.628 2.059 2.168 3.82 5.248 6.115C5.82 6.494 6.31 6.785 6.574 7.637C6.72 8.104 6.157 9.168 6.061 9.368C5.157 11.27 5.089 12.19 4.926 13.742Z';
58
+
59
+ const BRAND_TAIL_TRANSFORM = 'translate(14.6263 10.5853) scale(1.95)';
60
+
54
61
  /**
55
- * 品牌标:侧栏顶上那枚工作台方块标;默认 24px(它是品牌物,别拿它当通用图标)。
62
+ * 品牌标:一台显示器里放着 dsh 的鲸鱼尾巴;默认 24px(它是品牌物,别拿它当通用图标)。
56
63
  * @param props.size - 边长像素,同时给 `width` 与 `height`。
57
64
  * @returns 一枚 `aria-hidden` 的 svg。
58
65
  */
59
66
  export function IconBrandMark({ size = 24 }: IconProps) {
60
67
  return (
61
- <Shell size={size} strokeWidth={1.6} viewBox="0 0 24 24">
62
- <rect x={3} y={3} width={18} height={18} rx={5} stroke="currentColor" />
63
- <path
64
- d="M8 9.5h8M8 12.5h8M8 15.5h5"
65
- stroke="currentColor"
66
- strokeLinecap="round"
67
- />
68
+ <Shell size={size} viewBox="0 0 64 64">
69
+ <path d={BRAND_FRAME} fill="currentColor" fillRule="evenodd" />
70
+ <rect x={27.5} y={48} width={9} height={4.75} fill="currentColor" />
71
+ <rect x={19} y={52.75} width={26} height={4.75} rx={2.375} fill="currentColor" />
72
+ <g transform={BRAND_TAIL_TRANSFORM}>
73
+ <path d={BRAND_TAIL} fill="currentColor" />
74
+ <circle cx={6.885} cy={13.742} r={1.95} fill="currentColor" />
75
+ </g>
68
76
  </Shell>
69
77
  );
70
78
  }
@@ -40,8 +40,8 @@ export const PANEL_STATE_PREFIX = `${API_PREFIX}/${PANEL_STATE_PATH}`;
40
40
  /** 钉住的 opencli 插件版本:`opencli-runtime` 按它校验、取那一份。 */
41
41
  export const OPENCLI_PIN = "1.8.8";
42
42
 
43
- /** 缺陷看板套件的 dsh 服务名(`workbenchCodingIssues`):套件照它登记自己那份服务。 */
44
- export const CODING_ISSUES_SERVICE = "workbenchCodingIssues";
43
+ /** 缺陷看板套件的 dsh 服务名(`workbenchIssues`):套件照它登记自己那份服务。 */
44
+ export const ISSUES_SERVICE = "workbenchIssues";
45
45
 
46
46
  /** 面板套件的 dsh 服务名(`workbenchPanels`):宿主经它取套件公布的清单与订阅。 */
47
47
  export const PANELS_SERVICE = "workbenchPanels";
@@ -5,6 +5,7 @@ import {
5
5
  parseFactFrame,
6
6
  type FactFrame,
7
7
  type FactTransport,
8
+ type FactTransportMode,
8
9
  } from '../facts.js';
9
10
 
10
11
  function fakeTransport(): {
@@ -52,17 +53,17 @@ describe('createFactChannel', () => {
52
53
  it('★ 之后的帧只惊动它点名的事实(别的读者不该白跑一次)', () => {
53
54
  const wire = fakeTransport();
54
55
  const channel = createFactChannel({ transport: wire.transport });
55
- const cmdb = vi.fn();
56
+ const inventory = vi.fn();
56
57
  const issues = vi.fn();
57
- channel.subscribe('cmdb/summary', cmdb);
58
+ channel.subscribe('inventory/summary', inventory);
58
59
  channel.subscribe('issues', issues);
59
60
  channel.applyFrame({ epoch: 'e1', rev: 1, facts: [] });
60
61
 
61
- channel.applyFrame({ epoch: 'e1', rev: 2, facts: ['cmdb/summary'] });
62
+ channel.applyFrame({ epoch: 'e1', rev: 2, facts: ['inventory/summary'] });
62
63
 
63
- expect(cmdb).toHaveBeenCalledTimes(1);
64
+ expect(inventory).toHaveBeenCalledTimes(1);
64
65
  expect(issues).not.toHaveBeenCalled();
65
- expect(channel.revisionOf('cmdb/summary')).toBe(2);
66
+ expect(channel.revisionOf('inventory/summary')).toBe(2);
66
67
  expect(channel.revisionOf('issues')).toBe(0);
67
68
  });
68
69
 
@@ -132,33 +133,33 @@ describe('createFactChannel', () => {
132
133
  const summary = vi.fn();
133
134
  const builds = vi.fn();
134
135
  const issues = vi.fn();
135
- channel.subscribe('cmdb/summary', summary);
136
- channel.subscribe('cmdb/builds?env=innettest', builds);
137
- channel.subscribe('coding-issues/list', issues);
136
+ channel.subscribe('inventory/summary', summary);
137
+ channel.subscribe('inventory/builds?env=innettest', builds);
138
+ channel.subscribe('issues/list', issues);
138
139
  channel.applyFrame({ epoch: 'e1', rev: 1, facts: [] });
139
140
 
140
- channel.applyFrame({ epoch: 'e1', rev: 2, facts: ['capability', 'panels', 'cmdb*'] });
141
+ channel.applyFrame({ epoch: 'e1', rev: 2, facts: ['capability', 'panels', 'inventory*'] });
141
142
 
142
143
  expect(summary).toHaveBeenCalledTimes(1);
143
144
  expect(builds).toHaveBeenCalledTimes(1);
144
145
  expect(issues).not.toHaveBeenCalled();
145
- expect(channel.revisionOf('cmdb/summary')).toBeGreaterThan(1);
146
+ expect(channel.revisionOf('inventory/summary')).toBeGreaterThan(1);
146
147
  });
147
148
 
148
149
  it('命名空间不许凭空造出订阅(订阅表只由读者写),也不许越界到别的模块', () => {
149
150
  const wire = fakeTransport();
150
151
  const channel = createFactChannel({ transport: wire.transport });
151
- const codingAnalysis = vi.fn();
152
+ const demoAnalysis = vi.fn();
152
153
  const lookalike = vi.fn();
153
- channel.subscribe('coding-analysis/summary', codingAnalysis);
154
- channel.subscribe('cmdb-extra/summary', lookalike);
154
+ channel.subscribe('analysis/summary', demoAnalysis);
155
+ channel.subscribe('inventory-extra/summary', lookalike);
155
156
  channel.applyFrame({ epoch: 'e1', rev: 1, facts: [] });
156
157
 
157
- channel.applyFrame({ epoch: 'e1', rev: 2, facts: ['cmdb*'] });
158
+ channel.applyFrame({ epoch: 'e1', rev: 2, facts: ['inventory*'] });
158
159
 
159
- expect(codingAnalysis).not.toHaveBeenCalled();
160
+ expect(demoAnalysis).not.toHaveBeenCalled();
160
161
  expect(lookalike).not.toHaveBeenCalled();
161
- expect(channel.revisionOf('cmdb/never-subscribed')).toBe(0);
162
+ expect(channel.revisionOf('inventory/never-subscribed')).toBe(0);
162
163
  expect(channel.subscriberCount()).toBe(2);
163
164
  });
164
165
 
@@ -166,26 +167,26 @@ describe('createFactChannel', () => {
166
167
  const wire = fakeTransport();
167
168
  const channel = createFactChannel({ transport: wire.transport });
168
169
  const listener = vi.fn();
169
- channel.subscribe('cmdb/builds?env=innettest', listener);
170
+ channel.subscribe('inventory/builds?env=innettest', listener);
170
171
 
171
- channel.applyFrame({ epoch: 'e1', rev: 4, facts: ['cmdb*'] });
172
+ channel.applyFrame({ epoch: 'e1', rev: 4, facts: ['inventory*'] });
172
173
 
173
174
  expect(listener).not.toHaveBeenCalled();
174
- expect(channel.revisionOf('cmdb/builds?env=innettest')).toBeGreaterThan(0);
175
+ expect(channel.revisionOf('inventory/builds?env=innettest')).toBeGreaterThan(0);
175
176
  });
176
177
 
177
178
  it('refresh(命名空间) 只惊动它下面的事实(本地失效也按模块点名,不是一律全量)', () => {
178
179
  const wire = fakeTransport();
179
180
  const channel = createFactChannel({ transport: wire.transport });
180
- const cmdb = vi.fn();
181
+ const inventory = vi.fn();
181
182
  const issues = vi.fn();
182
- channel.subscribe('cmdb/summary', cmdb);
183
- channel.subscribe('coding-issues/list', issues);
183
+ channel.subscribe('inventory/summary', inventory);
184
+ channel.subscribe('issues/list', issues);
184
185
  channel.applyFrame({ epoch: 'e1', rev: 1, facts: [] });
185
186
 
186
- channel.refresh('cmdb*');
187
+ channel.refresh('inventory*');
187
188
 
188
- expect(cmdb).toHaveBeenCalledTimes(1);
189
+ expect(inventory).toHaveBeenCalledTimes(1);
189
190
  expect(issues).not.toHaveBeenCalled();
190
191
  });
191
192
 
@@ -204,6 +205,53 @@ describe('createFactChannel', () => {
204
205
 
205
206
  expect(seen).toEqual([4]);
206
207
  });
208
+
209
+ it('★ 传输来路:没建连是 null,报上来就换档,同一档不重复惊动', () => {
210
+ const wire: { report: ((mode: FactTransportMode) => void) | null } = { report: null };
211
+ const channel = createFactChannel({
212
+ transport: {
213
+ start(handlers) {
214
+ wire.report = handlers.onMode ?? null;
215
+ return () => {};
216
+ },
217
+ },
218
+ });
219
+ const listener = vi.fn();
220
+ expect(channel.mode()).toBeNull();
221
+ channel.subscribeMode(listener);
222
+ channel.subscribe('panels', vi.fn());
223
+
224
+ wire.report?.('polling');
225
+ expect(channel.mode()).toBe('polling');
226
+ wire.report?.('polling');
227
+ expect(listener).toHaveBeenCalledTimes(1);
228
+
229
+ wire.report?.('sse');
230
+ expect(channel.mode()).toBe('sse');
231
+ expect(listener).toHaveBeenCalledTimes(2);
232
+ });
233
+
234
+ it('★ 最后一个订阅走掉、传输停了,来路回到没建连', () => {
235
+ const wire: { report: ((mode: FactTransportMode) => void) | null } = { report: null };
236
+ const channel = createFactChannel({
237
+ transport: {
238
+ start(handlers) {
239
+ wire.report = handlers.onMode ?? null;
240
+ return () => {};
241
+ },
242
+ },
243
+ });
244
+ const listener = vi.fn();
245
+ channel.subscribeMode(listener);
246
+ const off = channel.subscribe('panels', vi.fn());
247
+ wire.report?.('sse');
248
+ listener.mockClear();
249
+
250
+ off();
251
+
252
+ expect(channel.mode()).toBeNull();
253
+ expect(listener).toHaveBeenCalledTimes(1);
254
+ });
207
255
  });
208
256
 
209
257
  describe('parseFactFrame', () => {
@@ -255,7 +303,7 @@ describe('parseFactFrame', () => {
255
303
 
256
304
  describe('factOfRoute', () => {
257
305
  it('事实名就是路由名(不另起一套词汇,读与订阅不可能各说各话)', () => {
258
- expect(factOfRoute('cmdb/summary')).toBe('cmdb/summary');
306
+ expect(factOfRoute('inventory/summary')).toBe('inventory/summary');
259
307
  expect(factOfRoute('capability')).toBe('capability');
260
308
  });
261
309
  });
@@ -13,16 +13,16 @@ import {
13
13
 
14
14
  describe('runsRouteOf', () => {
15
15
  it('★ 事实名 = 路由名(三处同一个来源,改一处不可能漏另一处)', () => {
16
- expect(runsRouteOf('cmdb')).toBe('cmdb/runs');
16
+ expect(runsRouteOf('inventory')).toBe('inventory/runs');
17
17
  expect(runsRouteOf('issues')).toBe('issues/runs');
18
18
  });
19
19
  });
20
20
 
21
21
  describe('stopRouteOf(停止那条写路由)', () => {
22
22
  it('★ 就是读路由 + `/stop`(读口与写口同一个单元名,不另造一套命名)', () => {
23
- expect(stopRouteOf('cmdb')).toBe('cmdb/runs/stop');
23
+ expect(stopRouteOf('inventory')).toBe('inventory/runs/stop');
24
24
  expect(stopRouteOf('issues')).toBe('issues/runs/stop');
25
- expect(stopRouteOf('cmdb')).toBe(`${runsRouteOf('cmdb')}/stop`);
25
+ expect(stopRouteOf('inventory')).toBe(`${runsRouteOf('inventory')}/stop`);
26
26
  });
27
27
  });
28
28
 
@@ -0,0 +1,74 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import {
3
+ NEED_KINDS,
4
+ NEED_KIND_SPECS,
5
+ SUPPLY_SOURCE_KINDS,
6
+ needProblemsOf,
7
+ needsProblemsOf,
8
+ } from '../needs.js';
9
+
10
+ const npm = { kind: 'npm', package: '@acme/plugin-demo', registryDefault: 'https://registry.test/' };
11
+ const base = { kind: 'lib', name: 'demo', purpose: '测试', sources: [npm] };
12
+
13
+ function errorsOf(need: unknown): readonly string[] {
14
+ return needProblemsOf('demo', need, 0).errors;
15
+ }
16
+
17
+ describe('needs 校验矩阵', () => {
18
+ it('★ 四种 kind 的最小声明都过;注册表与 NEED_KINDS 一一对应', () => {
19
+ expect(
20
+ needsProblemsOf('demo', [
21
+ { kind: 'bin', name: 'gitops', purpose: '部署' },
22
+ { kind: 'extension', runtime: 'opencli', name: 'demo', purpose: '面板', sources: [npm] },
23
+ base,
24
+ { kind: 'env', name: 'DSH_TOKEN', secret: true, purpose: '只读接口' },
25
+ ]).errors,
26
+ ).toEqual([]);
27
+ expect(Object.keys(NEED_KIND_SPECS).sort()).toEqual([...NEED_KINDS].sort());
28
+ });
29
+
30
+ it('未知 kind / 未知 source.kind → 红,并点名', () => {
31
+ const unknownKind = errorsOf({ kind: 'mcp', name: 'x', purpose: '测试' });
32
+ expect(unknownKind.join(' ')).toContain('needs[0].kind 不认识');
33
+ const unknownSource = errorsOf({ ...base, sources: [{ kind: 'tarball', url: 'x' }] });
34
+ expect(unknownSource.join(' ')).toContain('sources[0].kind 不认识');
35
+ expect(new Set(Object.values(NEED_KIND_SPECS).flatMap((spec) => spec.sources))).toEqual(
36
+ new Set(SUPPLY_SOURCE_KINDS),
37
+ );
38
+ });
39
+
40
+ it('bin / env 写了 sources → 红(没有安装路径)', () => {
41
+ expect(errorsOf({ kind: 'bin', name: 'x', purpose: '测试', sources: [npm] }).join(' ')).toContain(
42
+ '不支持 sources',
43
+ );
44
+ expect(errorsOf({ kind: 'env', name: 'X', purpose: '测试', sources: [npm] }).join(' ')).toContain(
45
+ '不支持 sources',
46
+ );
47
+ });
48
+
49
+ it('lib 只认 npm 源;sources 空数组 → 红(不代装就整条删掉)', () => {
50
+ expect(errorsOf({ ...base, sources: [{ kind: 'git', url: 'github:acme/demo' }] }).join(' ')).toContain(
51
+ '只支持 npm',
52
+ );
53
+ expect(errorsOf({ ...base, sources: [] }).join(' ')).toContain('空数组');
54
+ });
55
+
56
+ it('必填项:purpose、extension.runtime、name、required 类型、id 空串', () => {
57
+ expect(errorsOf({ ...base, purpose: '' }).join(' ')).toContain('purpose 没写');
58
+ expect(errorsOf({ kind: 'extension', name: 'x', purpose: '测试' }).join(' ')).toContain('runtime 没写');
59
+ expect(errorsOf({ ...base, name: '' }).join(' ')).toContain('name 没写');
60
+ expect(errorsOf({ ...base, required: 'yes' }).join(' ')).toContain('required 要是布尔');
61
+ expect(errorsOf({ ...base, id: '' }).join(' ')).toContain('id 是空串');
62
+ });
63
+
64
+ it('★ need 内未知字段只是警告;x- 前缀直接忽略(不为可选字段升协议版本)', () => {
65
+ const read = needProblemsOf('demo', { ...base, future: 1, 'x-vendor': true }, 0);
66
+ expect(read.errors).toEqual([]);
67
+ expect(read.warnings.join(' ')).toContain('不认识的字段 future');
68
+ expect(read.warnings.join(' ')).not.toContain('x-vendor');
69
+ });
70
+
71
+ it('没写 needs → 空表不报', () => {
72
+ expect(needsProblemsOf('demo', undefined)).toEqual({ errors: [], warnings: [] });
73
+ });
74
+ });
@@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest';
2
2
  import { declarationProblemsOf, readDeclaration } from '../unit-declaration.js';
3
3
 
4
4
  const declared = (tools: unknown) => ({
5
- apiVersion: 1,
5
+ apiVersion: 2,
6
6
  unit: 'demo',
7
7
  card: null,
8
8
  tools,
@@ -0,0 +1,43 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import type { Need } from '../needs.js';
3
+ import { needsOf, provisionableNeedsOf, type UnitManifest } from '../unit.js';
4
+
5
+ function manifest(needs?: readonly Need[]): UnitManifest {
6
+ return {
7
+ id: 'issues',
8
+ card: { titleKey: 'issues.mine', order: 10 },
9
+ tools: [],
10
+ host: { inject: [] },
11
+ ...(needs === undefined ? {} : { needs }),
12
+ };
13
+ }
14
+
15
+ const npm = { kind: 'npm' as const, registryEnv: 'WB_NPM', registryDefault: 'https://registry.example/' };
16
+
17
+ describe('provisionableNeedsOf(缺来源时那条回退口径,宿主与浏览器共用一份)', () => {
18
+ it('写了 sources 的 extension / lib → 宿主可代装', () => {
19
+ const needs: Need[] = [
20
+ { kind: 'extension', runtime: 'opencli', name: 'demo', purpose: '测试', sources: [npm] },
21
+ { kind: 'lib', name: 'opencli-workflow', purpose: '测试', sources: [npm] },
22
+ ];
23
+ expect(provisionableNeedsOf(manifest(needs)).map((need) => need.name)).toEqual([
24
+ 'demo',
25
+ 'opencli-workflow',
26
+ ]);
27
+ });
28
+
29
+ it('★ 没写 sources 的 extension、bin、env 都不算供给 —— 它们不是市场门槛,只是「我自己装,你帮我判」', () => {
30
+ const needs: Need[] = [
31
+ { kind: 'extension', runtime: 'opencli', name: 'demo', purpose: '测试' },
32
+ { kind: 'bin', name: 'gitops', purpose: '测试' },
33
+ { kind: 'env', name: 'DSH_TOKEN', purpose: '测试' },
34
+ ];
35
+ expect(provisionableNeedsOf(manifest(needs))).toEqual([]);
36
+ expect(provisionableNeedsOf(manifest([]))).toEqual([]);
37
+ expect(provisionableNeedsOf(manifest())).toEqual([]);
38
+ });
39
+
40
+ it('needsOf 没写就是空表', () => {
41
+ expect(needsOf(manifest())).toEqual([]);
42
+ });
43
+ });
@@ -0,0 +1,9 @@
1
+ export interface BrowserPort {
2
+ read(input: unknown): Promise<unknown>;
3
+ find(input: unknown): Promise<unknown>;
4
+ }
5
+
6
+ export interface PreflightPort {
7
+ run(options?: { readonly hard?: boolean }): Promise<unknown>;
8
+ snapshot(): unknown;
9
+ }
@@ -0,0 +1,3 @@
1
+ export interface CliPort {
2
+ readonly command: string;
3
+ }
@@ -0,0 +1,145 @@
1
+ export interface DataRequestBase {
2
+ readonly timeoutMs?: number;
3
+ }
4
+
5
+ export interface HttpDataRequest extends DataRequestBase {
6
+ readonly kind: 'http';
7
+ readonly url: string;
8
+ readonly headers?: Readonly<Record<string, string>>;
9
+ }
10
+
11
+ export interface BrowserDataRequest extends DataRequestBase {
12
+ readonly kind: 'browser';
13
+ readonly script: string;
14
+ readonly url?: string;
15
+ readonly loginUrl?: string;
16
+ readonly session?: string;
17
+ readonly open?: boolean;
18
+ }
19
+
20
+ export interface CommandDataRequest extends DataRequestBase {
21
+ readonly kind: 'command';
22
+ readonly command: string;
23
+ }
24
+
25
+ export type DataRequest = HttpDataRequest | BrowserDataRequest | CommandDataRequest;
26
+
27
+ export type DataErrorCode = 'invalid-request' | 'http' | 'auth' | 'timeout' | 'parse' | 'command' | 'browser';
28
+
29
+ export interface DataError {
30
+ readonly code: DataErrorCode;
31
+ readonly message: string;
32
+ readonly status?: number;
33
+ readonly detail?: string;
34
+ readonly hint?: string;
35
+ readonly helpUrl?: string;
36
+ readonly pageCode?: string;
37
+ }
38
+
39
+ export interface DataSuccess<T = unknown> {
40
+ readonly ok: true;
41
+ readonly data: T;
42
+ }
43
+
44
+ export interface DataFailure {
45
+ readonly ok: false;
46
+ readonly error: DataError;
47
+ }
48
+
49
+ export type DataResult<T = unknown> = DataSuccess<T> | DataFailure;
50
+
51
+ export interface CredentialSourceCookie {
52
+ readonly kind: 'cookie';
53
+ }
54
+
55
+ export interface CredentialSourceCookieValue {
56
+ readonly kind: 'cookieValue';
57
+ readonly name: string;
58
+ }
59
+
60
+ export interface CredentialSourceEndpoint {
61
+ readonly kind: 'endpoint';
62
+ readonly url: string;
63
+ readonly method?: 'GET' | 'POST';
64
+ readonly body?: unknown;
65
+ readonly path: string;
66
+ }
67
+
68
+ export interface CredentialSourceMeta {
69
+ readonly kind: 'meta';
70
+ readonly name: string;
71
+ }
72
+
73
+ export interface CredentialSourceGlobal {
74
+ readonly kind: 'global';
75
+ readonly path: string;
76
+ }
77
+
78
+ export interface CredentialSourceStorage {
79
+ readonly kind: 'storage';
80
+ readonly area: 'local' | 'session';
81
+ readonly key: string;
82
+ readonly path?: string;
83
+ }
84
+
85
+ export type CredentialSource =
86
+ | CredentialSourceCookie
87
+ | CredentialSourceCookieValue
88
+ | CredentialSourceEndpoint
89
+ | CredentialSourceMeta
90
+ | CredentialSourceGlobal
91
+ | CredentialSourceStorage;
92
+
93
+ export type CredentialPlace =
94
+ | { readonly in: 'cookie' }
95
+ | { readonly in: 'header'; readonly name: string; readonly prefix?: string }
96
+ | { readonly in: 'query'; readonly name: string }
97
+ | { readonly in: 'body'; readonly field: string };
98
+
99
+ export type RecipeAuth =
100
+ | { readonly kind: 'none' }
101
+ | { readonly kind?: undefined; readonly source: CredentialSource; readonly place: CredentialPlace };
102
+
103
+ export interface RecipeRequest {
104
+ readonly method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
105
+ readonly path: string;
106
+ readonly query?: Readonly<Record<string, string | number | boolean>>;
107
+ readonly headers?: Readonly<Record<string, string>>;
108
+ readonly body?: unknown;
109
+ readonly contentType?: 'json' | 'form';
110
+ }
111
+
112
+ export interface RecipeResponse {
113
+ readonly kind: 'json' | 'text';
114
+ readonly path?: string;
115
+ readonly maxBytes?: number;
116
+ }
117
+
118
+ export interface RequestRecipe {
119
+ readonly origin: string;
120
+ readonly loginUrl?: string;
121
+ readonly session?: string;
122
+ readonly timeoutMs?: number;
123
+ readonly auth?: RecipeAuth;
124
+ readonly request: RecipeRequest;
125
+ readonly response?: RecipeResponse;
126
+ }
127
+
128
+ export interface CallOverrides {
129
+ readonly path?: string;
130
+ readonly query?: Readonly<Record<string, string | number | boolean>>;
131
+ readonly headers?: Readonly<Record<string, string>>;
132
+ readonly body?: unknown;
133
+ readonly response?: Partial<RecipeResponse>;
134
+ }
135
+
136
+ export type RecipeCalls = Readonly<Record<string, CallOverrides>>;
137
+
138
+ export type RecipeResults<T = unknown> = Readonly<Record<string, DataResult<T>>>;
139
+
140
+ export interface DataReader {
141
+ read<T = unknown>(request: DataRequest): Promise<DataResult<T>>;
142
+ request<T = unknown>(recipe: RequestRecipe, overrides?: CallOverrides): Promise<DataResult<T>>;
143
+ requestMany<T = unknown>(recipe: RequestRecipe, calls: RecipeCalls): Promise<RecipeResults<T>>;
144
+ submit<T = unknown>(recipe: RequestRecipe, overrides?: CallOverrides): Promise<DataResult<T>>;
145
+ }