@imgly/codesign-mcp 0.1.6 → 0.1.7

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 (360) hide show
  1. package/README.md +5 -10
  2. package/dist/cli/http.d.ts.map +1 -1
  3. package/dist/cli/http.js +12 -2
  4. package/dist/cli/http.js.map +1 -1
  5. package/dist/cli/stdio.d.ts.map +1 -1
  6. package/dist/cli/stdio.js +103 -35
  7. package/dist/cli/stdio.js.map +1 -1
  8. package/dist/config.d.ts +11 -2
  9. package/dist/config.d.ts.map +1 -1
  10. package/dist/config.js +12 -1
  11. package/dist/config.js.map +1 -1
  12. package/dist/diagnostics/events.d.ts +6 -0
  13. package/dist/diagnostics/events.d.ts.map +1 -1
  14. package/dist/diagnostics/events.js.map +1 -1
  15. package/dist/engine/cesdk-adapter.d.ts +5 -1
  16. package/dist/engine/cesdk-adapter.d.ts.map +1 -1
  17. package/dist/engine/cesdk-adapter.js +8 -1
  18. package/dist/engine/cesdk-adapter.js.map +1 -1
  19. package/dist/engine/engine-capacity.d.ts +16 -0
  20. package/dist/engine/engine-capacity.d.ts.map +1 -0
  21. package/dist/engine/engine-capacity.js +48 -0
  22. package/dist/engine/engine-capacity.js.map +1 -0
  23. package/dist/engine/engine-slots.d.ts +48 -0
  24. package/dist/engine/engine-slots.d.ts.map +1 -0
  25. package/dist/engine/engine-slots.js +182 -0
  26. package/dist/engine/engine-slots.js.map +1 -0
  27. package/dist/tools/engine.d.ts +13 -0
  28. package/dist/tools/engine.d.ts.map +1 -1
  29. package/dist/tools/engine.js +28 -0
  30. package/dist/tools/engine.js.map +1 -1
  31. package/package.json +2 -2
  32. package/dist/dashboard/router.d.ts +0 -3
  33. package/dist/dashboard/router.d.ts.map +0 -1
  34. package/dist/dashboard/router.js +0 -19
  35. package/dist/dashboard/router.js.map +0 -1
  36. package/dist/dashboard/spa-assets.generated.d.ts +0 -2
  37. package/dist/dashboard/spa-assets.generated.d.ts.map +0 -1
  38. package/dist/dashboard/spa-assets.generated.js +0 -220
  39. package/dist/dashboard/spa-assets.generated.js.map +0 -1
  40. package/dist/metrics/mount.d.ts +0 -11
  41. package/dist/metrics/mount.d.ts.map +0 -1
  42. package/dist/metrics/mount.js +0 -13
  43. package/dist/metrics/mount.js.map +0 -1
  44. package/dist/metrics/recorder.d.ts +0 -55
  45. package/dist/metrics/recorder.d.ts.map +0 -1
  46. package/dist/metrics/recorder.js +0 -97
  47. package/dist/metrics/recorder.js.map +0 -1
  48. package/dist/test/scripts/changelog-add.d.ts +0 -8
  49. package/dist/test/scripts/changelog-add.d.ts.map +0 -1
  50. package/dist/test/scripts/changelog-add.js +0 -50
  51. package/dist/test/scripts/changelog-add.js.map +0 -1
  52. package/dist/test/scripts/changelog-collate.d.ts +0 -38
  53. package/dist/test/scripts/changelog-collate.d.ts.map +0 -1
  54. package/dist/test/scripts/changelog-collate.js +0 -171
  55. package/dist/test/scripts/changelog-collate.js.map +0 -1
  56. package/dist/test/test/changelog.test.d.ts +0 -2
  57. package/dist/test/test/changelog.test.d.ts.map +0 -1
  58. package/dist/test/test/changelog.test.js +0 -293
  59. package/dist/test/test/changelog.test.js.map +0 -1
  60. package/dist/test/test/cli/dispatcher.test.d.ts +0 -2
  61. package/dist/test/test/cli/dispatcher.test.d.ts.map +0 -1
  62. package/dist/test/test/cli/dispatcher.test.js +0 -54
  63. package/dist/test/test/cli/dispatcher.test.js.map +0 -1
  64. package/dist/test/test/cli/redirect-console.test.d.ts +0 -2
  65. package/dist/test/test/cli/redirect-console.test.d.ts.map +0 -1
  66. package/dist/test/test/cli/redirect-console.test.js +0 -78
  67. package/dist/test/test/cli/redirect-console.test.js.map +0 -1
  68. package/dist/test/test/cli/resolve-license.test.d.ts +0 -2
  69. package/dist/test/test/cli/resolve-license.test.d.ts.map +0 -1
  70. package/dist/test/test/cli/resolve-license.test.js +0 -29
  71. package/dist/test/test/cli/resolve-license.test.js.map +0 -1
  72. package/dist/test/test/cli/stdio-diagnostics.test.d.ts +0 -2
  73. package/dist/test/test/cli/stdio-diagnostics.test.d.ts.map +0 -1
  74. package/dist/test/test/cli/stdio-diagnostics.test.js +0 -31
  75. package/dist/test/test/cli/stdio-diagnostics.test.js.map +0 -1
  76. package/dist/test/test/cli/stdio-license.test.d.ts +0 -2
  77. package/dist/test/test/cli/stdio-license.test.d.ts.map +0 -1
  78. package/dist/test/test/cli/stdio-license.test.js +0 -19
  79. package/dist/test/test/cli/stdio-license.test.js.map +0 -1
  80. package/dist/test/test/config.test.d.ts +0 -2
  81. package/dist/test/test/config.test.d.ts.map +0 -1
  82. package/dist/test/test/config.test.js +0 -95
  83. package/dist/test/test/config.test.js.map +0 -1
  84. package/dist/test/test/cross-ref.test.d.ts +0 -2
  85. package/dist/test/test/cross-ref.test.d.ts.map +0 -1
  86. package/dist/test/test/cross-ref.test.js +0 -39
  87. package/dist/test/test/cross-ref.test.js.map +0 -1
  88. package/dist/test/test/diagnostics/bundle.test.d.ts +0 -2
  89. package/dist/test/test/diagnostics/bundle.test.d.ts.map +0 -1
  90. package/dist/test/test/diagnostics/bundle.test.js +0 -53
  91. package/dist/test/test/diagnostics/bundle.test.js.map +0 -1
  92. package/dist/test/test/diagnostics/compose.test.d.ts +0 -2
  93. package/dist/test/test/diagnostics/compose.test.d.ts.map +0 -1
  94. package/dist/test/test/diagnostics/compose.test.js +0 -31
  95. package/dist/test/test/diagnostics/compose.test.js.map +0 -1
  96. package/dist/test/test/diagnostics/file-sink.test.d.ts +0 -2
  97. package/dist/test/test/diagnostics/file-sink.test.d.ts.map +0 -1
  98. package/dist/test/test/diagnostics/file-sink.test.js +0 -113
  99. package/dist/test/test/diagnostics/file-sink.test.js.map +0 -1
  100. package/dist/test/test/diagnostics/redact.test.d.ts +0 -2
  101. package/dist/test/test/diagnostics/redact.test.d.ts.map +0 -1
  102. package/dist/test/test/diagnostics/redact.test.js +0 -59
  103. package/dist/test/test/diagnostics/redact.test.js.map +0 -1
  104. package/dist/test/test/diagnostics/tool-call-adapter.test.d.ts +0 -2
  105. package/dist/test/test/diagnostics/tool-call-adapter.test.d.ts.map +0 -1
  106. package/dist/test/test/diagnostics/tool-call-adapter.test.js +0 -34
  107. package/dist/test/test/diagnostics/tool-call-adapter.test.js.map +0 -1
  108. package/dist/test/test/engine/asset-sources.test.d.ts +0 -2
  109. package/dist/test/test/engine/asset-sources.test.d.ts.map +0 -1
  110. package/dist/test/test/engine/asset-sources.test.js +0 -100
  111. package/dist/test/test/engine/asset-sources.test.js.map +0 -1
  112. package/dist/test/test/engine/cesdk-adapter.test.d.ts +0 -2
  113. package/dist/test/test/engine/cesdk-adapter.test.d.ts.map +0 -1
  114. package/dist/test/test/engine/cesdk-adapter.test.js +0 -32
  115. package/dist/test/test/engine/cesdk-adapter.test.js.map +0 -1
  116. package/dist/test/test/engine/mutex.test.d.ts +0 -2
  117. package/dist/test/test/engine/mutex.test.d.ts.map +0 -1
  118. package/dist/test/test/engine/mutex.test.js +0 -63
  119. package/dist/test/test/engine/mutex.test.js.map +0 -1
  120. package/dist/test/test/engine/session.test.d.ts +0 -2
  121. package/dist/test/test/engine/session.test.d.ts.map +0 -1
  122. package/dist/test/test/engine/session.test.js +0 -159
  123. package/dist/test/test/engine/session.test.js.map +0 -1
  124. package/dist/test/test/engine/unsplash-source.test.d.ts +0 -2
  125. package/dist/test/test/engine/unsplash-source.test.d.ts.map +0 -1
  126. package/dist/test/test/engine/unsplash-source.test.js +0 -129
  127. package/dist/test/test/engine/unsplash-source.test.js.map +0 -1
  128. package/dist/test/test/engine/uri-resolver.test.d.ts +0 -2
  129. package/dist/test/test/engine/uri-resolver.test.d.ts.map +0 -1
  130. package/dist/test/test/engine/uri-resolver.test.js +0 -38
  131. package/dist/test/test/engine/uri-resolver.test.js.map +0 -1
  132. package/dist/test/test/gateway/hosted-stub.test.d.ts +0 -2
  133. package/dist/test/test/gateway/hosted-stub.test.d.ts.map +0 -1
  134. package/dist/test/test/gateway/hosted-stub.test.js +0 -11
  135. package/dist/test/test/gateway/hosted-stub.test.js.map +0 -1
  136. package/dist/test/test/gateway/local.test.d.ts +0 -2
  137. package/dist/test/test/gateway/local.test.d.ts.map +0 -1
  138. package/dist/test/test/gateway/local.test.js +0 -29
  139. package/dist/test/test/gateway/local.test.js.map +0 -1
  140. package/dist/test/test/handbook-contract.test.d.ts +0 -2
  141. package/dist/test/test/handbook-contract.test.d.ts.map +0 -1
  142. package/dist/test/test/handbook-contract.test.js +0 -79
  143. package/dist/test/test/handbook-contract.test.js.map +0 -1
  144. package/dist/test/test/http/server.test.d.ts +0 -2
  145. package/dist/test/test/http/server.test.d.ts.map +0 -1
  146. package/dist/test/test/http/server.test.js +0 -338
  147. package/dist/test/test/http/server.test.js.map +0 -1
  148. package/dist/test/test/http/session-id-header.test.d.ts +0 -2
  149. package/dist/test/test/http/session-id-header.test.d.ts.map +0 -1
  150. package/dist/test/test/http/session-id-header.test.js +0 -76
  151. package/dist/test/test/http/session-id-header.test.js.map +0 -1
  152. package/dist/test/test/http/session-manager.test.d.ts +0 -2
  153. package/dist/test/test/http/session-manager.test.d.ts.map +0 -1
  154. package/dist/test/test/http/session-manager.test.js +0 -97
  155. package/dist/test/test/http/session-manager.test.js.map +0 -1
  156. package/dist/test/test/http/workspace-auth.test.d.ts +0 -2
  157. package/dist/test/test/http/workspace-auth.test.d.ts.map +0 -1
  158. package/dist/test/test/http/workspace-auth.test.js +0 -40
  159. package/dist/test/test/http/workspace-auth.test.js.map +0 -1
  160. package/dist/test/test/metrics/mount.test.d.ts +0 -2
  161. package/dist/test/test/metrics/mount.test.d.ts.map +0 -1
  162. package/dist/test/test/metrics/mount.test.js +0 -59
  163. package/dist/test/test/metrics/mount.test.js.map +0 -1
  164. package/dist/test/test/metrics/recorder.test.d.ts +0 -2
  165. package/dist/test/test/metrics/recorder.test.d.ts.map +0 -1
  166. package/dist/test/test/metrics/recorder.test.js +0 -118
  167. package/dist/test/test/metrics/recorder.test.js.map +0 -1
  168. package/dist/test/test/revisions/hash.test.d.ts +0 -2
  169. package/dist/test/test/revisions/hash.test.d.ts.map +0 -1
  170. package/dist/test/test/revisions/hash.test.js +0 -33
  171. package/dist/test/test/revisions/hash.test.js.map +0 -1
  172. package/dist/test/test/revisions/store.test.d.ts +0 -2
  173. package/dist/test/test/revisions/store.test.d.ts.map +0 -1
  174. package/dist/test/test/revisions/store.test.js +0 -315
  175. package/dist/test/test/revisions/store.test.js.map +0 -1
  176. package/dist/test/test/server.metrics.test.d.ts +0 -2
  177. package/dist/test/test/server.metrics.test.d.ts.map +0 -1
  178. package/dist/test/test/server.metrics.test.js +0 -87
  179. package/dist/test/test/server.metrics.test.js.map +0 -1
  180. package/dist/test/test/server.test.d.ts +0 -2
  181. package/dist/test/test/server.test.d.ts.map +0 -1
  182. package/dist/test/test/server.test.js +0 -146
  183. package/dist/test/test/server.test.js.map +0 -1
  184. package/dist/test/test/skill-tools.test.d.ts +0 -2
  185. package/dist/test/test/skill-tools.test.d.ts.map +0 -1
  186. package/dist/test/test/skill-tools.test.js +0 -84
  187. package/dist/test/test/skill-tools.test.js.map +0 -1
  188. package/dist/test/test/smoke.test.d.ts +0 -2
  189. package/dist/test/test/smoke.test.d.ts.map +0 -1
  190. package/dist/test/test/smoke.test.js +0 -8
  191. package/dist/test/test/smoke.test.js.map +0 -1
  192. package/dist/test/test/tools/asset-generate.test.d.ts +0 -2
  193. package/dist/test/test/tools/asset-generate.test.d.ts.map +0 -1
  194. package/dist/test/test/tools/asset-generate.test.js +0 -66
  195. package/dist/test/test/tools/asset-generate.test.js.map +0 -1
  196. package/dist/test/test/tools/asset-search.test.d.ts +0 -2
  197. package/dist/test/test/tools/asset-search.test.d.ts.map +0 -1
  198. package/dist/test/test/tools/asset-search.test.js +0 -121
  199. package/dist/test/test/tools/asset-search.test.js.map +0 -1
  200. package/dist/test/test/tools/edit-harness.d.ts +0 -14
  201. package/dist/test/test/tools/edit-harness.d.ts.map +0 -1
  202. package/dist/test/test/tools/edit-harness.js +0 -30
  203. package/dist/test/test/tools/edit-harness.js.map +0 -1
  204. package/dist/test/test/tools/edit.telemetry.test.d.ts +0 -2
  205. package/dist/test/test/tools/edit.telemetry.test.d.ts.map +0 -1
  206. package/dist/test/test/tools/edit.telemetry.test.js +0 -46
  207. package/dist/test/test/tools/edit.telemetry.test.js.map +0 -1
  208. package/dist/test/test/tools/edit.test.d.ts +0 -2
  209. package/dist/test/test/tools/edit.test.d.ts.map +0 -1
  210. package/dist/test/test/tools/edit.test.js +0 -267
  211. package/dist/test/test/tools/edit.test.js.map +0 -1
  212. package/dist/test/test/tools/export-harness.d.ts +0 -13
  213. package/dist/test/test/tools/export-harness.d.ts.map +0 -1
  214. package/dist/test/test/tools/export-harness.js +0 -27
  215. package/dist/test/test/tools/export-harness.js.map +0 -1
  216. package/dist/test/test/tools/export.telemetry.test.d.ts +0 -2
  217. package/dist/test/test/tools/export.telemetry.test.d.ts.map +0 -1
  218. package/dist/test/test/tools/export.telemetry.test.js +0 -65
  219. package/dist/test/test/tools/export.telemetry.test.js.map +0 -1
  220. package/dist/test/test/tools/export.test.d.ts +0 -2
  221. package/dist/test/test/tools/export.test.d.ts.map +0 -1
  222. package/dist/test/test/tools/export.test.js +0 -174
  223. package/dist/test/test/tools/export.test.js.map +0 -1
  224. package/dist/test/test/tools/history.test.d.ts +0 -2
  225. package/dist/test/test/tools/history.test.d.ts.map +0 -1
  226. package/dist/test/test/tools/history.test.js +0 -29
  227. package/dist/test/test/tools/history.test.js.map +0 -1
  228. package/dist/test/test/tools/import.test.d.ts +0 -2
  229. package/dist/test/test/tools/import.test.d.ts.map +0 -1
  230. package/dist/test/test/tools/import.test.js +0 -122
  231. package/dist/test/test/tools/import.test.js.map +0 -1
  232. package/dist/test/test/tools/index.test.d.ts +0 -2
  233. package/dist/test/test/tools/index.test.d.ts.map +0 -1
  234. package/dist/test/test/tools/index.test.js +0 -117
  235. package/dist/test/test/tools/index.test.js.map +0 -1
  236. package/dist/test/test/tools/inspect.test.d.ts +0 -2
  237. package/dist/test/test/tools/inspect.test.d.ts.map +0 -1
  238. package/dist/test/test/tools/inspect.test.js +0 -62
  239. package/dist/test/test/tools/inspect.test.js.map +0 -1
  240. package/dist/test/test/tools/list.test.d.ts +0 -2
  241. package/dist/test/test/tools/list.test.d.ts.map +0 -1
  242. package/dist/test/test/tools/list.test.js +0 -23
  243. package/dist/test/test/tools/list.test.js.map +0 -1
  244. package/dist/test/test/tools/load.integration.test.d.ts +0 -2
  245. package/dist/test/test/tools/load.integration.test.d.ts.map +0 -1
  246. package/dist/test/test/tools/load.integration.test.js +0 -165
  247. package/dist/test/test/tools/load.integration.test.js.map +0 -1
  248. package/dist/test/test/tools/load.test.d.ts +0 -2
  249. package/dist/test/test/tools/load.test.d.ts.map +0 -1
  250. package/dist/test/test/tools/load.test.js +0 -387
  251. package/dist/test/test/tools/load.test.js.map +0 -1
  252. package/dist/test/test/tools/metrics.test.d.ts +0 -2
  253. package/dist/test/test/tools/metrics.test.d.ts.map +0 -1
  254. package/dist/test/test/tools/metrics.test.js +0 -29
  255. package/dist/test/test/tools/metrics.test.js.map +0 -1
  256. package/dist/test/test/tools/open-editor.test.d.ts +0 -2
  257. package/dist/test/test/tools/open-editor.test.d.ts.map +0 -1
  258. package/dist/test/test/tools/open-editor.test.js +0 -53
  259. package/dist/test/test/tools/open-editor.test.js.map +0 -1
  260. package/dist/test/test/tools/preview-harness.d.ts +0 -9
  261. package/dist/test/test/tools/preview-harness.d.ts.map +0 -1
  262. package/dist/test/test/tools/preview-harness.js +0 -23
  263. package/dist/test/test/tools/preview-harness.js.map +0 -1
  264. package/dist/test/test/tools/preview.telemetry.test.d.ts +0 -2
  265. package/dist/test/test/tools/preview.telemetry.test.d.ts.map +0 -1
  266. package/dist/test/test/tools/preview.telemetry.test.js +0 -36
  267. package/dist/test/test/tools/preview.telemetry.test.js.map +0 -1
  268. package/dist/test/test/tools/preview.test.d.ts +0 -2
  269. package/dist/test/test/tools/preview.test.d.ts.map +0 -1
  270. package/dist/test/test/tools/preview.test.js +0 -75
  271. package/dist/test/test/tools/preview.test.js.map +0 -1
  272. package/dist/test/test/tools/rename.test.d.ts +0 -2
  273. package/dist/test/test/tools/rename.test.d.ts.map +0 -1
  274. package/dist/test/test/tools/rename.test.js +0 -16
  275. package/dist/test/test/tools/rename.test.js.map +0 -1
  276. package/dist/test/test/tools/save.test.d.ts +0 -2
  277. package/dist/test/test/tools/save.test.d.ts.map +0 -1
  278. package/dist/test/test/tools/save.test.js +0 -137
  279. package/dist/test/test/tools/save.test.js.map +0 -1
  280. package/dist/test/test/tools/schema-best-practices.d.ts +0 -13
  281. package/dist/test/test/tools/schema-best-practices.d.ts.map +0 -1
  282. package/dist/test/test/tools/schema-best-practices.js +0 -169
  283. package/dist/test/test/tools/schema-best-practices.js.map +0 -1
  284. package/dist/test/test/tools/schema-best-practices.test.d.ts +0 -3
  285. package/dist/test/test/tools/schema-best-practices.test.d.ts.map +0 -1
  286. package/dist/test/test/tools/schema-best-practices.test.js +0 -194
  287. package/dist/test/test/tools/schema-best-practices.test.js.map +0 -1
  288. package/dist/test/test/tools/spans.test.d.ts +0 -2
  289. package/dist/test/test/tools/spans.test.d.ts.map +0 -1
  290. package/dist/test/test/tools/spans.test.js +0 -84
  291. package/dist/test/test/tools/spans.test.js.map +0 -1
  292. package/dist/test/test/viewer/broadcaster.test.d.ts +0 -2
  293. package/dist/test/test/viewer/broadcaster.test.d.ts.map +0 -1
  294. package/dist/test/test/viewer/broadcaster.test.js +0 -53
  295. package/dist/test/test/viewer/broadcaster.test.js.map +0 -1
  296. package/dist/test/test/viewer/cesdk-cdn.test.d.ts +0 -2
  297. package/dist/test/test/viewer/cesdk-cdn.test.d.ts.map +0 -1
  298. package/dist/test/test/viewer/cesdk-cdn.test.js +0 -19
  299. package/dist/test/test/viewer/cesdk-cdn.test.js.map +0 -1
  300. package/dist/test/test/viewer/config-route.test.d.ts +0 -2
  301. package/dist/test/test/viewer/config-route.test.d.ts.map +0 -1
  302. package/dist/test/test/viewer/config-route.test.js +0 -28
  303. package/dist/test/test/viewer/config-route.test.js.map +0 -1
  304. package/dist/test/test/viewer/resource-route.test.d.ts +0 -2
  305. package/dist/test/test/viewer/resource-route.test.d.ts.map +0 -1
  306. package/dist/test/test/viewer/resource-route.test.js +0 -70
  307. package/dist/test/test/viewer/resource-route.test.js.map +0 -1
  308. package/dist/test/test/viewer/router.test.d.ts +0 -2
  309. package/dist/test/test/viewer/router.test.d.ts.map +0 -1
  310. package/dist/test/test/viewer/router.test.js +0 -227
  311. package/dist/test/test/viewer/router.test.js.map +0 -1
  312. package/dist/test/test/viewer/session-mount.test.d.ts +0 -2
  313. package/dist/test/test/viewer/session-mount.test.d.ts.map +0 -1
  314. package/dist/test/test/viewer/session-mount.test.js +0 -52
  315. package/dist/test/test/viewer/session-mount.test.js.map +0 -1
  316. package/dist/test/test/viewer/spa-version.test.d.ts +0 -2
  317. package/dist/test/test/viewer/spa-version.test.d.ts.map +0 -1
  318. package/dist/test/test/viewer/spa-version.test.js +0 -14
  319. package/dist/test/test/viewer/spa-version.test.js.map +0 -1
  320. package/dist/test/test/viewer/url-builder.test.d.ts +0 -2
  321. package/dist/test/test/viewer/url-builder.test.d.ts.map +0 -1
  322. package/dist/test/test/viewer/url-builder.test.js +0 -98
  323. package/dist/test/test/viewer/url-builder.test.js.map +0 -1
  324. package/dist/test/test/workspace/content-hash.test.d.ts +0 -2
  325. package/dist/test/test/workspace/content-hash.test.d.ts.map +0 -1
  326. package/dist/test/test/workspace/content-hash.test.js +0 -17
  327. package/dist/test/test/workspace/content-hash.test.js.map +0 -1
  328. package/dist/test/test/workspace/hosted-stub.test.d.ts +0 -2
  329. package/dist/test/test/workspace/hosted-stub.test.d.ts.map +0 -1
  330. package/dist/test/test/workspace/hosted-stub.test.js +0 -30
  331. package/dist/test/test/workspace/hosted-stub.test.js.map +0 -1
  332. package/dist/test/test/workspace/in-memory.test.d.ts +0 -2
  333. package/dist/test/test/workspace/in-memory.test.d.ts.map +0 -1
  334. package/dist/test/test/workspace/in-memory.test.js +0 -4
  335. package/dist/test/test/workspace/in-memory.test.js.map +0 -1
  336. package/dist/test/test/workspace/node-fs.test.d.ts +0 -2
  337. package/dist/test/test/workspace/node-fs.test.d.ts.map +0 -1
  338. package/dist/test/test/workspace/node-fs.test.js +0 -20
  339. package/dist/test/test/workspace/node-fs.test.js.map +0 -1
  340. package/dist/test/test/workspace/s3.test.d.ts +0 -2
  341. package/dist/test/test/workspace/s3.test.d.ts.map +0 -1
  342. package/dist/test/test/workspace/s3.test.js +0 -153
  343. package/dist/test/test/workspace/s3.test.js.map +0 -1
  344. package/dist/test/test/workspace/scoped.test.d.ts +0 -2
  345. package/dist/test/test/workspace/scoped.test.d.ts.map +0 -1
  346. package/dist/test/test/workspace/scoped.test.js +0 -59
  347. package/dist/test/test/workspace/scoped.test.js.map +0 -1
  348. package/dist/test/test/workspace/shared-contract.d.ts +0 -3
  349. package/dist/test/test/workspace/shared-contract.d.ts.map +0 -1
  350. package/dist/test/test/workspace/shared-contract.js +0 -92
  351. package/dist/test/test/workspace/shared-contract.js.map +0 -1
  352. package/dist/test/tsconfig.test.tsbuildinfo +0 -1
  353. package/dist/test/vitest.config.d.ts +0 -3
  354. package/dist/test/vitest.config.d.ts.map +0 -1
  355. package/dist/test/vitest.config.js +0 -8
  356. package/dist/test/vitest.config.js.map +0 -1
  357. package/dist/tools/metrics.d.ts +0 -11
  358. package/dist/tools/metrics.d.ts.map +0 -1
  359. package/dist/tools/metrics.js +0 -28
  360. package/dist/tools/metrics.js.map +0 -1
@@ -1,194 +0,0 @@
1
- // packages/codesign-mcp/test/tools/schema-best-practices.test.ts
2
- //
3
- // Two layers:
4
- // 1. Unit tests that the linter itself catches / passes the shapes it should.
5
- // 2. The contract: EVERY tool the server advertises must have ZERO hard-error
6
- // findings. Warnings are printed (advisory) but don't fail the suite.
7
- //
8
- // This is the programmatic guard behind the "keep tool schemas simple" best
9
- // practices — it would have caught the `load` `oneOf` that made
10
- // openrouter:xiaomi/mimo-v2.5-pro stringify its arguments on every attempt.
11
- import { describe, expect, it } from 'vitest';
12
- import { buildDesignToolRegistrations } from '../../src/tools/index.js';
13
- import { createAssetGenerateTool } from '../../src/tools/asset-generate.js';
14
- import { errorsOnly, lintToolSchema } from './schema-best-practices.js';
15
- // ---------------------------------------------------------------------------
16
- // 1. Unit tests: the linter catches the constructs it claims to.
17
- // ---------------------------------------------------------------------------
18
- describe('lintToolSchema — rule coverage', () => {
19
- const flatClean = {
20
- type: 'object',
21
- properties: {
22
- source: {
23
- type: 'object',
24
- description: 'the source',
25
- properties: {
26
- url: { type: 'string', description: 'http(s) url' },
27
- path: { type: 'string', description: 'local path' }
28
- },
29
- additionalProperties: false
30
- },
31
- title: { type: 'string', description: 'display name' }
32
- },
33
- required: ['source'],
34
- additionalProperties: false
35
- };
36
- it('passes a flat, closed, described object schema', () => {
37
- expect(errorsOnly(lintToolSchema(flatClean))).toEqual([]);
38
- });
39
- it('flags a `oneOf` union (the load/mimo failure mode)', () => {
40
- const schema = {
41
- type: 'object',
42
- properties: {
43
- source: {
44
- oneOf: [
45
- { type: 'object', properties: { url: { type: 'string' } } },
46
- { type: 'object', properties: { path: { type: 'string' } } }
47
- ]
48
- }
49
- },
50
- additionalProperties: false
51
- };
52
- const rules = errorsOnly(lintToolSchema(schema)).map((f) => f.rule);
53
- expect(rules).toContain('no-oneOf');
54
- });
55
- it('flags `allOf`, `$ref`, and `not`', () => {
56
- for (const key of ['allOf', '$ref', 'not']) {
57
- const schema = {
58
- type: 'object',
59
- properties: { x: { [key]: key === '$ref' ? '#/x' : [] } },
60
- additionalProperties: false
61
- };
62
- const rules = errorsOnly(lintToolSchema(schema)).map((f) => f.rule);
63
- expect(rules).toContain(`no-${key.replace('$', '')}`);
64
- }
65
- });
66
- it('flags a non-object root', () => {
67
- const rules = errorsOnly(lintToolSchema({ type: 'string' })).map((f) => f.rule);
68
- expect(rules).toContain('root-must-be-object');
69
- });
70
- it('flags an object missing additionalProperties:false', () => {
71
- const rules = errorsOnly(lintToolSchema({ type: 'object', properties: {} })).map((f) => f.rule);
72
- expect(rules).toContain('object-additional-properties-false');
73
- });
74
- it('allows the `type: ["string","null"]` nullable idiom', () => {
75
- const schema = {
76
- type: 'object',
77
- properties: {
78
- parent: {
79
- type: ['string', 'null'],
80
- description: 'revision id, or null for a new root'
81
- }
82
- },
83
- required: ['parent'],
84
- additionalProperties: false
85
- };
86
- expect(errorsOnly(lintToolSchema(schema))).toEqual([]);
87
- });
88
- it('allows a scalar `anyOf` but rejects an object arm', () => {
89
- const scalar = {
90
- type: 'object',
91
- properties: {
92
- x: { anyOf: [{ type: 'string' }, { type: 'null' }], description: 'x' }
93
- },
94
- additionalProperties: false
95
- };
96
- expect(errorsOnly(lintToolSchema(scalar))).toEqual([]);
97
- const objectArm = {
98
- type: 'object',
99
- properties: {
100
- x: {
101
- anyOf: [
102
- { type: 'string' },
103
- { type: 'object', properties: {}, additionalProperties: false }
104
- ],
105
- description: 'x'
106
- }
107
- },
108
- additionalProperties: false
109
- };
110
- expect(errorsOnly(lintToolSchema(objectArm)).map((f) => f.rule)).toContain('anyof-scalar-arms-only');
111
- });
112
- it('warns (does not error) on a missing property description', () => {
113
- const findings = lintToolSchema({
114
- type: 'object',
115
- properties: { x: { type: 'string' } },
116
- additionalProperties: false
117
- });
118
- expect(errorsOnly(findings)).toEqual([]);
119
- expect(findings.map((f) => f.rule)).toContain('property-needs-description');
120
- });
121
- });
122
- // ---------------------------------------------------------------------------
123
- // 2. Contract: every advertised tool schema is clean.
124
- // ---------------------------------------------------------------------------
125
- const stub = {};
126
- function gateway() {
127
- return {
128
- available: true,
129
- generateImage: async () => ({
130
- bytes: new Uint8Array(),
131
- mimeType: 'image/png'
132
- })
133
- };
134
- }
135
- // Every tool the server can advertise, across both backends (Local exposes the
136
- // extra `import` tool and `load`/`save`/`export`'s `path`/`outPath` arms), plus
137
- // asset_generate (beta-hidden today, but its schema still ships in source and
138
- // will be exposed when the kill-switch flips). Deduped by tool name.
139
- function allToolSchemas() {
140
- const byName = new Map();
141
- for (const allowOutPath of [true, false]) {
142
- for (const reg of buildDesignToolRegistrations({
143
- fs: stub,
144
- store: stub,
145
- session: stub,
146
- engineLock: stub,
147
- gateway: gateway(),
148
- urlBuilder: stub,
149
- allowOutPath
150
- })) {
151
- byName.set(reg.name, reg.inputSchema);
152
- }
153
- }
154
- const assetGen = createAssetGenerateTool({
155
- gateway: gateway(),
156
- fs: stub,
157
- urlBuilder: stub
158
- });
159
- byName.set(assetGen.name, assetGen.inputSchema);
160
- return [...byName].map(([name, schema]) => ({ name, schema }));
161
- }
162
- describe('tool input schemas follow LLM tool-calling best practices', () => {
163
- const tools = allToolSchemas();
164
- it('advertises a non-trivial set of tools (guards against an empty sweep)', () => {
165
- expect(tools.length).toBeGreaterThanOrEqual(10);
166
- });
167
- it.each(tools)('$name — no hard-error schema findings', ({ schema }) => {
168
- const errors = errorsOnly(lintToolSchema(schema));
169
- // Surface a readable message when this fails.
170
- expect(errors, errors.map((e) => `${e.path}: [${e.rule}] ${e.message}`).join('\n')).toEqual([]);
171
- });
172
- it('reports advisory warnings (non-failing) for visibility', () => {
173
- const warnings = [];
174
- for (const { name, schema } of tools) {
175
- for (const f of lintToolSchema(schema)) {
176
- if (f.severity === 'warn')
177
- warnings.push(`${name} ${f.path}: [${f.rule}] ${f.message}`);
178
- }
179
- }
180
- if (warnings.length > 0) {
181
- // eslint-disable-next-line no-console
182
- console.warn(`\n[tool-schema best-practice warnings]\n${warnings.join('\n')}\n`);
183
- }
184
- // Advisory only — always passes. Kept as a test so the warnings render in
185
- // CI output rather than being silently discarded.
186
- expect(Array.isArray(warnings)).toBe(true);
187
- });
188
- });
189
- // Re-exported so a future consumer (a `check` step, a CI gate) can reuse the
190
- // same sweep without duplicating the wiring.
191
- export function collectSchemaErrors() {
192
- return allToolSchemas().flatMap(({ schema }) => errorsOnly(lintToolSchema(schema)));
193
- }
194
- //# sourceMappingURL=schema-best-practices.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"schema-best-practices.test.js","sourceRoot":"","sources":["../../../../test/tools/schema-best-practices.test.ts"],"names":[],"mappings":"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","sourcesContent":["// packages/codesign-mcp/test/tools/schema-best-practices.test.ts\n//\n// Two layers:\n// 1. Unit tests that the linter itself catches / passes the shapes it should.\n// 2. The contract: EVERY tool the server advertises must have ZERO hard-error\n// findings. Warnings are printed (advisory) but don't fail the suite.\n//\n// This is the programmatic guard behind the \"keep tool schemas simple\" best\n// practices — it would have caught the `load` `oneOf` that made\n// openrouter:xiaomi/mimo-v2.5-pro stringify its arguments on every attempt.\n\nimport { describe, expect, it } from 'vitest';\nimport type { GatewayClient } from '../../src/gateway/types.js';\nimport { buildDesignToolRegistrations } from '../../src/tools/index.js';\nimport { createAssetGenerateTool } from '../../src/tools/asset-generate.js';\nimport {\n errorsOnly,\n lintToolSchema,\n type SchemaFinding\n} from './schema-best-practices.js';\n\n// ---------------------------------------------------------------------------\n// 1. Unit tests: the linter catches the constructs it claims to.\n// ---------------------------------------------------------------------------\n\ndescribe('lintToolSchema — rule coverage', () => {\n const flatClean = {\n type: 'object',\n properties: {\n source: {\n type: 'object',\n description: 'the source',\n properties: {\n url: { type: 'string', description: 'http(s) url' },\n path: { type: 'string', description: 'local path' }\n },\n additionalProperties: false\n },\n title: { type: 'string', description: 'display name' }\n },\n required: ['source'],\n additionalProperties: false\n };\n\n it('passes a flat, closed, described object schema', () => {\n expect(errorsOnly(lintToolSchema(flatClean))).toEqual([]);\n });\n\n it('flags a `oneOf` union (the load/mimo failure mode)', () => {\n const schema = {\n type: 'object',\n properties: {\n source: {\n oneOf: [\n { type: 'object', properties: { url: { type: 'string' } } },\n { type: 'object', properties: { path: { type: 'string' } } }\n ]\n }\n },\n additionalProperties: false\n };\n const rules = errorsOnly(lintToolSchema(schema)).map((f) => f.rule);\n expect(rules).toContain('no-oneOf');\n });\n\n it('flags `allOf`, `$ref`, and `not`', () => {\n for (const key of ['allOf', '$ref', 'not'] as const) {\n const schema = {\n type: 'object',\n properties: { x: { [key]: key === '$ref' ? '#/x' : [] } },\n additionalProperties: false\n };\n const rules = errorsOnly(lintToolSchema(schema)).map((f) => f.rule);\n expect(rules).toContain(`no-${key.replace('$', '')}`);\n }\n });\n\n it('flags a non-object root', () => {\n const rules = errorsOnly(lintToolSchema({ type: 'string' })).map(\n (f) => f.rule\n );\n expect(rules).toContain('root-must-be-object');\n });\n\n it('flags an object missing additionalProperties:false', () => {\n const rules = errorsOnly(\n lintToolSchema({ type: 'object', properties: {} })\n ).map((f) => f.rule);\n expect(rules).toContain('object-additional-properties-false');\n });\n\n it('allows the `type: [\"string\",\"null\"]` nullable idiom', () => {\n const schema = {\n type: 'object',\n properties: {\n parent: {\n type: ['string', 'null'],\n description: 'revision id, or null for a new root'\n }\n },\n required: ['parent'],\n additionalProperties: false\n };\n expect(errorsOnly(lintToolSchema(schema))).toEqual([]);\n });\n\n it('allows a scalar `anyOf` but rejects an object arm', () => {\n const scalar = {\n type: 'object',\n properties: {\n x: { anyOf: [{ type: 'string' }, { type: 'null' }], description: 'x' }\n },\n additionalProperties: false\n };\n expect(errorsOnly(lintToolSchema(scalar))).toEqual([]);\n\n const objectArm = {\n type: 'object',\n properties: {\n x: {\n anyOf: [\n { type: 'string' },\n { type: 'object', properties: {}, additionalProperties: false }\n ],\n description: 'x'\n }\n },\n additionalProperties: false\n };\n expect(errorsOnly(lintToolSchema(objectArm)).map((f) => f.rule)).toContain(\n 'anyof-scalar-arms-only'\n );\n });\n\n it('warns (does not error) on a missing property description', () => {\n const findings = lintToolSchema({\n type: 'object',\n properties: { x: { type: 'string' } },\n additionalProperties: false\n });\n expect(errorsOnly(findings)).toEqual([]);\n expect(findings.map((f) => f.rule)).toContain('property-needs-description');\n });\n});\n\n// ---------------------------------------------------------------------------\n// 2. Contract: every advertised tool schema is clean.\n// ---------------------------------------------------------------------------\n\nconst stub = {} as never;\n\nfunction gateway(): GatewayClient {\n return {\n available: true,\n generateImage: async () => ({\n bytes: new Uint8Array(),\n mimeType: 'image/png'\n })\n };\n}\n\n// Every tool the server can advertise, across both backends (Local exposes the\n// extra `import` tool and `load`/`save`/`export`'s `path`/`outPath` arms), plus\n// asset_generate (beta-hidden today, but its schema still ships in source and\n// will be exposed when the kill-switch flips). Deduped by tool name.\nfunction allToolSchemas(): { name: string; schema: unknown }[] {\n const byName = new Map<string, unknown>();\n for (const allowOutPath of [true, false]) {\n for (const reg of buildDesignToolRegistrations({\n fs: stub,\n store: stub,\n session: stub,\n engineLock: stub,\n gateway: gateway(),\n urlBuilder: stub,\n allowOutPath\n })) {\n byName.set(reg.name, reg.inputSchema);\n }\n }\n const assetGen = createAssetGenerateTool({\n gateway: gateway(),\n fs: stub,\n urlBuilder: stub\n });\n byName.set(assetGen.name, assetGen.inputSchema);\n return [...byName].map(([name, schema]) => ({ name, schema }));\n}\n\ndescribe('tool input schemas follow LLM tool-calling best practices', () => {\n const tools = allToolSchemas();\n\n it('advertises a non-trivial set of tools (guards against an empty sweep)', () => {\n expect(tools.length).toBeGreaterThanOrEqual(10);\n });\n\n it.each(tools)('$name — no hard-error schema findings', ({ schema }) => {\n const errors = errorsOnly(lintToolSchema(schema));\n // Surface a readable message when this fails.\n expect(\n errors,\n errors.map((e) => `${e.path}: [${e.rule}] ${e.message}`).join('\\n')\n ).toEqual([]);\n });\n\n it('reports advisory warnings (non-failing) for visibility', () => {\n const warnings: string[] = [];\n for (const { name, schema } of tools) {\n for (const f of lintToolSchema(schema)) {\n if (f.severity === 'warn')\n warnings.push(`${name} ${f.path}: [${f.rule}] ${f.message}`);\n }\n }\n if (warnings.length > 0) {\n // eslint-disable-next-line no-console\n console.warn(\n `\\n[tool-schema best-practice warnings]\\n${warnings.join('\\n')}\\n`\n );\n }\n // Advisory only — always passes. Kept as a test so the warnings render in\n // CI output rather than being silently discarded.\n expect(Array.isArray(warnings)).toBe(true);\n });\n});\n\n// Re-exported so a future consumer (a `check` step, a CI gate) can reuse the\n// same sweep without duplicating the wiring.\nexport function collectSchemaErrors(): SchemaFinding[] {\n return allToolSchemas().flatMap(({ schema }) =>\n errorsOnly(lintToolSchema(schema))\n );\n}\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=spans.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"spans.test.d.ts","sourceRoot":"","sources":["../../../../test/tools/spans.test.ts"],"names":[],"mappings":""}
@@ -1,84 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { SpanRecorder, NOOP_TELEMETRY_SINK, summarizeResult, toErrorShape } from '../../src/tools/spans.js';
3
- describe('SpanRecorder', () => {
4
- it('records a span per timed phase, in order', async () => {
5
- const rec = new SpanRecorder();
6
- const v = await rec.time('a', async () => 41 + 1);
7
- await rec.time('b', async () => undefined);
8
- expect(v).toBe(42);
9
- const spans = rec.list();
10
- expect(spans.map((s) => s.phase)).toEqual(['a', 'b']);
11
- expect(spans.every((s) => typeof s.ms === 'number' && s.ms >= 0)).toBe(true);
12
- });
13
- it('records a span even when the timed fn throws', async () => {
14
- const rec = new SpanRecorder();
15
- await expect(rec.time('boom', async () => {
16
- throw new Error('x');
17
- })).rejects.toThrow('x');
18
- expect(rec.list().map((s) => s.phase)).toEqual(['boom']);
19
- });
20
- it('add() appends a manual span; list() returns a copy', () => {
21
- const rec = new SpanRecorder();
22
- rec.add('lock_wait', 5);
23
- const first = rec.list();
24
- first.push({ phase: 'mutated', ms: 0 });
25
- expect(rec.list().map((s) => s.phase)).toEqual(['lock_wait']);
26
- });
27
- });
28
- describe('toErrorShape', () => {
29
- it('maps an Error to message + stack', () => {
30
- const shape = toErrorShape(new Error('nope'));
31
- expect(shape.message).toBe('nope');
32
- expect(typeof shape.stack).toBe('string');
33
- });
34
- it('stringifies a non-Error', () => {
35
- expect(toErrorShape('bad').message).toBe('bad');
36
- });
37
- });
38
- describe('summarizeResult', () => {
39
- it('keeps a preview-sized image blob so it can be rendered', () => {
40
- const img = 'A'.repeat(5000); // well under the image cap
41
- const out = summarizeResult({
42
- content: [{ type: 'image', data: img, mimeType: 'image/webp' }]
43
- });
44
- expect(out.content[0].data).toBe(img);
45
- expect(out.content[0].mimeType).toBe('image/webp');
46
- });
47
- it('drops an oversized image blob to a marker', () => {
48
- const huge = 'A'.repeat(200_001);
49
- const out = summarizeResult({
50
- content: [{ type: 'image', data: huge, mimeType: 'image/png' }]
51
- });
52
- expect(out.content[0].data).toBe('<200001 base64 chars omitted>');
53
- });
54
- it('drops a large non-image blob to a marker', () => {
55
- const blob = 'A'.repeat(5000);
56
- const out = summarizeResult({
57
- content: [{ type: 'resource', data: blob, mimeType: 'application/pdf' }]
58
- });
59
- expect(out.content[0].data).toBe('<5000 base64 chars omitted>');
60
- });
61
- it('passes small text content through untouched', () => {
62
- const result = {
63
- content: [{ type: 'text', text: 'https://localhost/r/abc' }]
64
- };
65
- expect(summarizeResult(result)).toEqual(result);
66
- });
67
- it('returns non-result values as-is', () => {
68
- expect(summarizeResult(undefined)).toBeUndefined();
69
- expect(summarizeResult('plain')).toBe('plain');
70
- expect(summarizeResult({ nope: 1 })).toEqual({ nope: 1 });
71
- });
72
- });
73
- describe('NOOP_TELEMETRY_SINK', () => {
74
- it('accepts a report silently', () => {
75
- const report = {
76
- tool: 'edit',
77
- succeeded: true,
78
- totalMs: 1,
79
- spans: []
80
- };
81
- expect(() => NOOP_TELEMETRY_SINK.record(report)).not.toThrow();
82
- });
83
- });
84
- //# sourceMappingURL=spans.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"spans.test.js","sourceRoot":"","sources":["../../../../test/tools/spans.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it, expect } from 'vitest';\nimport {\n SpanRecorder,\n NOOP_TELEMETRY_SINK,\n summarizeResult,\n toErrorShape,\n type ToolCallReport\n} from '../../src/tools/spans.js';\n\ndescribe('SpanRecorder', () => {\n it('records a span per timed phase, in order', async () => {\n const rec = new SpanRecorder();\n const v = await rec.time('a', async () => 41 + 1);\n await rec.time('b', async () => undefined);\n expect(v).toBe(42);\n const spans = rec.list();\n expect(spans.map((s) => s.phase)).toEqual(['a', 'b']);\n expect(spans.every((s) => typeof s.ms === 'number' && s.ms >= 0)).toBe(\n true\n );\n });\n\n it('records a span even when the timed fn throws', async () => {\n const rec = new SpanRecorder();\n await expect(\n rec.time('boom', async () => {\n throw new Error('x');\n })\n ).rejects.toThrow('x');\n expect(rec.list().map((s) => s.phase)).toEqual(['boom']);\n });\n\n it('add() appends a manual span; list() returns a copy', () => {\n const rec = new SpanRecorder();\n rec.add('lock_wait', 5);\n const first = rec.list();\n first.push({ phase: 'mutated', ms: 0 });\n expect(rec.list().map((s) => s.phase)).toEqual(['lock_wait']);\n });\n});\n\ndescribe('toErrorShape', () => {\n it('maps an Error to message + stack', () => {\n const shape = toErrorShape(new Error('nope'));\n expect(shape.message).toBe('nope');\n expect(typeof shape.stack).toBe('string');\n });\n it('stringifies a non-Error', () => {\n expect(toErrorShape('bad').message).toBe('bad');\n });\n});\n\ndescribe('summarizeResult', () => {\n it('keeps a preview-sized image blob so it can be rendered', () => {\n const img = 'A'.repeat(5000); // well under the image cap\n const out = summarizeResult({\n content: [{ type: 'image', data: img, mimeType: 'image/webp' }]\n }) as { content: Array<{ type: string; data: string; mimeType: string }> };\n expect(out.content[0].data).toBe(img);\n expect(out.content[0].mimeType).toBe('image/webp');\n });\n\n it('drops an oversized image blob to a marker', () => {\n const huge = 'A'.repeat(200_001);\n const out = summarizeResult({\n content: [{ type: 'image', data: huge, mimeType: 'image/png' }]\n }) as { content: Array<{ data: string }> };\n expect(out.content[0].data).toBe('<200001 base64 chars omitted>');\n });\n\n it('drops a large non-image blob to a marker', () => {\n const blob = 'A'.repeat(5000);\n const out = summarizeResult({\n content: [{ type: 'resource', data: blob, mimeType: 'application/pdf' }]\n }) as { content: Array<{ data: string }> };\n expect(out.content[0].data).toBe('<5000 base64 chars omitted>');\n });\n\n it('passes small text content through untouched', () => {\n const result = {\n content: [{ type: 'text', text: 'https://localhost/r/abc' }]\n };\n expect(summarizeResult(result)).toEqual(result);\n });\n\n it('returns non-result values as-is', () => {\n expect(summarizeResult(undefined)).toBeUndefined();\n expect(summarizeResult('plain')).toBe('plain');\n expect(summarizeResult({ nope: 1 })).toEqual({ nope: 1 });\n });\n});\n\ndescribe('NOOP_TELEMETRY_SINK', () => {\n it('accepts a report silently', () => {\n const report: ToolCallReport = {\n tool: 'edit',\n succeeded: true,\n totalMs: 1,\n spans: []\n };\n expect(() => NOOP_TELEMETRY_SINK.record(report)).not.toThrow();\n });\n});\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=broadcaster.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"broadcaster.test.d.ts","sourceRoot":"","sources":["../../../../test/viewer/broadcaster.test.ts"],"names":[],"mappings":""}
@@ -1,53 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
- import { SseBroadcaster } from '../../src/viewer/broadcaster.js';
3
- function fakeRes() {
4
- const written = [];
5
- const closeCbs = [];
6
- return {
7
- written,
8
- writeHead: vi.fn(),
9
- write: vi.fn((chunk) => {
10
- written.push(chunk);
11
- return true;
12
- }),
13
- end: vi.fn(() => {
14
- for (const cb of closeCbs)
15
- cb();
16
- }),
17
- on: vi.fn((evt, cb) => {
18
- if (evt === 'close')
19
- closeCbs.push(cb);
20
- })
21
- };
22
- }
23
- describe('SseBroadcaster', () => {
24
- it('subscribe writes SSE headers + initial comment', () => {
25
- const b = new SseBroadcaster();
26
- const res = fakeRes();
27
- b.subscribe('root_abc', res);
28
- expect(res.writeHead).toHaveBeenCalledWith(200, expect.objectContaining({ 'content-type': 'text/event-stream' }));
29
- expect(res.written.some((s) => s.startsWith(':'))).toBe(true); // ping comment
30
- });
31
- it('broadcast sends `data: { revision, rootRevision }\\n\\n` to all subscribers of that root', () => {
32
- const b = new SseBroadcaster();
33
- const r1 = fakeRes();
34
- const r2 = fakeRes();
35
- const r3 = fakeRes();
36
- b.subscribe('root_abc', r1);
37
- b.subscribe('root_abc', r2);
38
- b.subscribe('root_xyz', r3);
39
- b.broadcast({ revision: 'rev_1', rootRevision: 'root_abc' });
40
- expect(r1.written.some((s) => s.includes('rev_1'))).toBe(true);
41
- expect(r2.written.some((s) => s.includes('rev_1'))).toBe(true);
42
- expect(r3.written.some((s) => s.includes('rev_1'))).toBe(false);
43
- });
44
- it('removes subscribers when their response closes', () => {
45
- const b = new SseBroadcaster();
46
- const res = fakeRes();
47
- b.subscribe('root_abc', res);
48
- expect(b.subscriberCount('root_abc')).toBe(1);
49
- res.end(); // triggers "close" callback
50
- expect(b.subscriberCount('root_abc')).toBe(0);
51
- });
52
- });
53
- //# sourceMappingURL=broadcaster.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"broadcaster.test.js","sourceRoot":"","sources":["../../../../test/viewer/broadcaster.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it, vi } from 'vitest';\nimport { SseBroadcaster } from '../../src/viewer/broadcaster.js';\n\ninterface FakeResponse {\n written: string[];\n writeHead: ReturnType<typeof vi.fn>;\n write: ReturnType<typeof vi.fn>;\n end: ReturnType<typeof vi.fn>;\n on: ReturnType<typeof vi.fn>;\n}\n\nfunction fakeRes(): FakeResponse {\n const written: string[] = [];\n const closeCbs: Array<() => void> = [];\n return {\n written,\n writeHead: vi.fn(),\n write: vi.fn((chunk: string) => {\n written.push(chunk);\n return true;\n }),\n end: vi.fn(() => {\n for (const cb of closeCbs) cb();\n }),\n on: vi.fn((evt: string, cb: () => void) => {\n if (evt === 'close') closeCbs.push(cb);\n })\n };\n}\n\ndescribe('SseBroadcaster', () => {\n it('subscribe writes SSE headers + initial comment', () => {\n const b = new SseBroadcaster();\n const res = fakeRes();\n b.subscribe('root_abc', res as never);\n expect(res.writeHead).toHaveBeenCalledWith(\n 200,\n expect.objectContaining({ 'content-type': 'text/event-stream' })\n );\n expect(res.written.some((s) => s.startsWith(':'))).toBe(true); // ping comment\n });\n\n it('broadcast sends `data: { revision, rootRevision }\\\\n\\\\n` to all subscribers of that root', () => {\n const b = new SseBroadcaster();\n const r1 = fakeRes();\n const r2 = fakeRes();\n const r3 = fakeRes();\n b.subscribe('root_abc', r1 as never);\n b.subscribe('root_abc', r2 as never);\n b.subscribe('root_xyz', r3 as never);\n b.broadcast({ revision: 'rev_1', rootRevision: 'root_abc' });\n expect(r1.written.some((s) => s.includes('rev_1'))).toBe(true);\n expect(r2.written.some((s) => s.includes('rev_1'))).toBe(true);\n expect(r3.written.some((s) => s.includes('rev_1'))).toBe(false);\n });\n\n it('removes subscribers when their response closes', () => {\n const b = new SseBroadcaster();\n const res = fakeRes();\n b.subscribe('root_abc', res as never);\n expect(b.subscriberCount('root_abc')).toBe(1);\n res.end(); // triggers \"close\" callback\n expect(b.subscriberCount('root_abc')).toBe(0);\n });\n});\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=cesdk-cdn.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cesdk-cdn.test.d.ts","sourceRoot":"","sources":["../../../../test/viewer/cesdk-cdn.test.ts"],"names":[],"mappings":""}
@@ -1,19 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { cesdkCdnUrl, installedCesdkVersion } from '../../src/viewer/cesdk-cdn.js';
3
- describe('cesdkCdnUrl', () => {
4
- it('uses the plain release path for GA versions', () => {
5
- expect(cesdkCdnUrl('1.77.0')).toBe('https://cdn.img.ly/packages/imgly/cesdk-js/1.77.0/index.js');
6
- });
7
- it('uses the plain release path for rc versions', () => {
8
- expect(cesdkCdnUrl('1.77.0-rc.4')).toBe('https://cdn.img.ly/packages/imgly/cesdk-js/1.77.0-rc.4/index.js');
9
- });
10
- it('uses the /nightlies/ path (version repeated) for nightly versions', () => {
11
- expect(cesdkCdnUrl('1.78.0-nightly.20260703')).toBe('https://cdn.img.ly/nightlies/1.78.0-nightly.20260703/packages/imgly/cesdk-js/1.78.0-nightly.20260703/index.js');
12
- });
13
- });
14
- describe('installedCesdkVersion', () => {
15
- it('returns the exact pinned version of the installed engine', () => {
16
- expect(installedCesdkVersion()).toMatch(/^\d+\.\d+\.\d+(-(rc|nightly)\.\w+)?$/);
17
- });
18
- });
19
- //# sourceMappingURL=cesdk-cdn.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cesdk-cdn.test.js","sourceRoot":"","sources":["../../../../test/viewer/cesdk-cdn.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,WAAW,EACX,qBAAqB,EACtB,MAAM,+BAA+B,CAAC;AAEvC,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAChC,4DAA4D,CAC7D,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CACrC,iEAAiE,CAClE,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,CAAC,WAAW,CAAC,yBAAyB,CAAC,CAAC,CAAC,IAAI,CACjD,+GAA+G,CAChH,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,CAAC,qBAAqB,EAAE,CAAC,CAAC,OAAO,CACrC,sCAAsC,CACvC,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { describe, expect, it } from 'vitest';\nimport {\n cesdkCdnUrl,\n installedCesdkVersion\n} from '../../src/viewer/cesdk-cdn.js';\n\ndescribe('cesdkCdnUrl', () => {\n it('uses the plain release path for GA versions', () => {\n expect(cesdkCdnUrl('1.77.0')).toBe(\n 'https://cdn.img.ly/packages/imgly/cesdk-js/1.77.0/index.js'\n );\n });\n it('uses the plain release path for rc versions', () => {\n expect(cesdkCdnUrl('1.77.0-rc.4')).toBe(\n 'https://cdn.img.ly/packages/imgly/cesdk-js/1.77.0-rc.4/index.js'\n );\n });\n it('uses the /nightlies/ path (version repeated) for nightly versions', () => {\n expect(cesdkCdnUrl('1.78.0-nightly.20260703')).toBe(\n 'https://cdn.img.ly/nightlies/1.78.0-nightly.20260703/packages/imgly/cesdk-js/1.78.0-nightly.20260703/index.js'\n );\n });\n});\n\ndescribe('installedCesdkVersion', () => {\n it('returns the exact pinned version of the installed engine', () => {\n expect(installedCesdkVersion()).toMatch(\n /^\\d+\\.\\d+\\.\\d+(-(rc|nightly)\\.\\w+)?$/\n );\n });\n});\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=config-route.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-route.test.d.ts","sourceRoot":"","sources":["../../../../test/viewer/config-route.test.ts"],"names":[],"mappings":""}
@@ -1,28 +0,0 @@
1
- import express from 'express';
2
- import request from 'supertest';
3
- import { describe, expect, it } from 'vitest';
4
- import { createViewerRouter } from '../../src/viewer/router.js';
5
- function fakeDeps() {
6
- return { store: {}, fs: {}, broadcaster: {} };
7
- }
8
- describe('GET /api/config', () => {
9
- it('serves the explicit cesdkEngineUrl when provided', async () => {
10
- const app = express();
11
- app.use(createViewerRouter({
12
- ...fakeDeps(),
13
- cesdkLicense: 'lic',
14
- cesdkEngineUrl: 'https://cdn.img.ly/packages/imgly/cesdk-js/9.9.9/index.js'
15
- }));
16
- const res = await request(app).get('/api/config');
17
- expect(res.status).toBe(200);
18
- expect(res.body.cesdkEngineUrl).toBe('https://cdn.img.ly/packages/imgly/cesdk-js/9.9.9/index.js');
19
- expect(res.body.license).toBe('lic');
20
- });
21
- it('defaults cesdkEngineUrl to the installed engine version', async () => {
22
- const app = express();
23
- app.use(createViewerRouter({ ...fakeDeps() }));
24
- const res = await request(app).get('/api/config');
25
- expect(res.body.cesdkEngineUrl).toMatch(/^https:\/\/cdn\.img\.ly\/(nightlies\/[^/]+\/)?packages\/imgly\/cesdk-js\/[^/]+\/index\.js$/);
26
- });
27
- });
28
- //# sourceMappingURL=config-route.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-route.test.js","sourceRoot":"","sources":["../../../../test/viewer/config-route.test.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,OAAO,MAAM,WAAW,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEhE,SAAS,QAAQ;IACf,OAAO,EAAE,KAAK,EAAE,EAAW,EAAE,EAAE,EAAE,EAAW,EAAE,WAAW,EAAE,EAAW,EAAE,CAAC;AAC3E,CAAC;AAED,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;QACtB,GAAG,CAAC,GAAG,CACL,kBAAkB,CAAC;YACjB,GAAG,QAAQ,EAAE;YACb,YAAY,EAAE,KAAK;YACnB,cAAc,EACZ,2DAA2D;SAC9D,CAAC,CACH,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAClD,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC7B,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAClC,2DAA2D,CAC5D,CAAC;QACF,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;QACvE,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;QACtB,GAAG,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,GAAG,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC;QAC/C,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAClD,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,OAAO,CACrC,4FAA4F,CAC7F,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import express from 'express';\nimport request from 'supertest';\nimport { describe, expect, it } from 'vitest';\nimport { createViewerRouter } from '../../src/viewer/router.js';\n\nfunction fakeDeps() {\n return { store: {} as never, fs: {} as never, broadcaster: {} as never };\n}\n\ndescribe('GET /api/config', () => {\n it('serves the explicit cesdkEngineUrl when provided', async () => {\n const app = express();\n app.use(\n createViewerRouter({\n ...fakeDeps(),\n cesdkLicense: 'lic',\n cesdkEngineUrl:\n 'https://cdn.img.ly/packages/imgly/cesdk-js/9.9.9/index.js'\n })\n );\n const res = await request(app).get('/api/config');\n expect(res.status).toBe(200);\n expect(res.body.cesdkEngineUrl).toBe(\n 'https://cdn.img.ly/packages/imgly/cesdk-js/9.9.9/index.js'\n );\n expect(res.body.license).toBe('lic');\n });\n\n it('defaults cesdkEngineUrl to the installed engine version', async () => {\n const app = express();\n app.use(createViewerRouter({ ...fakeDeps() }));\n const res = await request(app).get('/api/config');\n expect(res.body.cesdkEngineUrl).toMatch(\n /^https:\\/\\/cdn\\.img\\.ly\\/(nightlies\\/[^/]+\\/)?packages\\/imgly\\/cesdk-js\\/[^/]+\\/index\\.js$/\n );\n });\n});\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=resource-route.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"resource-route.test.d.ts","sourceRoot":"","sources":["../../../../test/viewer/resource-route.test.ts"],"names":[],"mappings":""}
@@ -1,70 +0,0 @@
1
- import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
2
- import { tmpdir } from 'node:os';
3
- import { join } from 'node:path';
4
- import express from 'express';
5
- import request from 'supertest';
6
- import { afterEach, describe, expect, it } from 'vitest';
7
- import { createResourceRoute } from '../../src/viewer/resource-route.js';
8
- import { InMemoryWorkspaceFS } from '../../src/workspace/in-memory.js';
9
- describe('resource route — object-store backend', () => {
10
- function makeApp() {
11
- const fs = new InMemoryWorkspaceFS();
12
- const app = express();
13
- app.use(createResourceRoute({ fs, workspaceRoot: '' }));
14
- return { app, fs };
15
- }
16
- it('serves a file under assets/ with its content type', async () => {
17
- const { app, fs } = makeApp();
18
- await fs.writeFile('assets/9f2a1c.png', new Uint8Array([1, 2, 3, 4]));
19
- const res = await request(app).get('/r/assets/9f2a1c.png');
20
- expect(res.status).toBe(200);
21
- expect(res.headers['content-type']).toBe('image/png');
22
- expect(res.headers['content-length']).toBe('4');
23
- });
24
- it('serves a file under exports/', async () => {
25
- const { app, fs } = makeApp();
26
- await fs.writeFile('exports/ab/cdef012345/pdf.pdf', new Uint8Array([5, 6, 7]));
27
- const res = await request(app).get('/r/exports/ab/cdef012345/pdf.pdf');
28
- expect(res.status).toBe(200);
29
- expect(res.headers['content-type']).toBe('application/pdf');
30
- });
31
- it('404s a missing file', async () => {
32
- const { app } = makeApp();
33
- const res = await request(app).get('/r/assets/missing.png');
34
- expect(res.status).toBe(404);
35
- });
36
- it('404s a path outside the assets/ + exports/ allowlist', async () => {
37
- const { app, fs } = makeApp();
38
- await fs.writeFile('objects/ab/cd.scene', new Uint8Array([9]));
39
- const res = await request(app).get('/r/objects/ab/cd.scene');
40
- expect(res.status).toBe(404);
41
- });
42
- it('404s a traversal attempt', async () => {
43
- const { app } = makeApp();
44
- const res = await request(app).get('/r/assets/%2e%2e/%2e%2e/objects/secret.scene');
45
- expect(res.status).toBe(404);
46
- });
47
- });
48
- describe('resource route — disk backend (range support)', () => {
49
- let dir = '';
50
- afterEach(async () => {
51
- if (dir)
52
- await rm(dir, { recursive: true, force: true });
53
- });
54
- it('streams from disk and honours Range requests', async () => {
55
- dir = await mkdtemp(join(tmpdir(), 'resource-route-'));
56
- await mkdir(join(dir, 'assets'), { recursive: true });
57
- await writeFile(join(dir, 'assets/v.bin'), Buffer.from([10, 11, 12, 13, 14, 15]));
58
- const app = express();
59
- app.use(createResourceRoute({ fs: new InMemoryWorkspaceFS(), workspaceRoot: dir }));
60
- const full = await request(app).get('/r/assets/v.bin');
61
- expect(full.status).toBe(200);
62
- expect(full.headers['accept-ranges']).toBe('bytes');
63
- const partial = await request(app)
64
- .get('/r/assets/v.bin')
65
- .set('Range', 'bytes=0-2');
66
- expect(partial.status).toBe(206);
67
- expect(partial.headers['content-length']).toBe('3');
68
- });
69
- });
70
- //# sourceMappingURL=resource-route.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"resource-route.test.js","sourceRoot":"","sources":["../../../../test/viewer/resource-route.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport express from 'express';\nimport request from 'supertest';\nimport { afterEach, describe, expect, it } from 'vitest';\nimport { createResourceRoute } from '../../src/viewer/resource-route.js';\nimport { InMemoryWorkspaceFS } from '../../src/workspace/in-memory.js';\n\ndescribe('resource route — object-store backend', () => {\n function makeApp() {\n const fs = new InMemoryWorkspaceFS();\n const app = express();\n app.use(createResourceRoute({ fs, workspaceRoot: '' }));\n return { app, fs };\n }\n\n it('serves a file under assets/ with its content type', async () => {\n const { app, fs } = makeApp();\n await fs.writeFile('assets/9f2a1c.png', new Uint8Array([1, 2, 3, 4]));\n const res = await request(app).get('/r/assets/9f2a1c.png');\n expect(res.status).toBe(200);\n expect(res.headers['content-type']).toBe('image/png');\n expect(res.headers['content-length']).toBe('4');\n });\n\n it('serves a file under exports/', async () => {\n const { app, fs } = makeApp();\n await fs.writeFile(\n 'exports/ab/cdef012345/pdf.pdf',\n new Uint8Array([5, 6, 7])\n );\n const res = await request(app).get('/r/exports/ab/cdef012345/pdf.pdf');\n expect(res.status).toBe(200);\n expect(res.headers['content-type']).toBe('application/pdf');\n });\n\n it('404s a missing file', async () => {\n const { app } = makeApp();\n const res = await request(app).get('/r/assets/missing.png');\n expect(res.status).toBe(404);\n });\n\n it('404s a path outside the assets/ + exports/ allowlist', async () => {\n const { app, fs } = makeApp();\n await fs.writeFile('objects/ab/cd.scene', new Uint8Array([9]));\n const res = await request(app).get('/r/objects/ab/cd.scene');\n expect(res.status).toBe(404);\n });\n\n it('404s a traversal attempt', async () => {\n const { app } = makeApp();\n const res = await request(app).get(\n '/r/assets/%2e%2e/%2e%2e/objects/secret.scene'\n );\n expect(res.status).toBe(404);\n });\n});\n\ndescribe('resource route — disk backend (range support)', () => {\n let dir = '';\n afterEach(async () => {\n if (dir) await rm(dir, { recursive: true, force: true });\n });\n\n it('streams from disk and honours Range requests', async () => {\n dir = await mkdtemp(join(tmpdir(), 'resource-route-'));\n await mkdir(join(dir, 'assets'), { recursive: true });\n await writeFile(\n join(dir, 'assets/v.bin'),\n Buffer.from([10, 11, 12, 13, 14, 15])\n );\n const app = express();\n app.use(\n createResourceRoute({ fs: new InMemoryWorkspaceFS(), workspaceRoot: dir })\n );\n\n const full = await request(app).get('/r/assets/v.bin');\n expect(full.status).toBe(200);\n expect(full.headers['accept-ranges']).toBe('bytes');\n\n const partial = await request(app)\n .get('/r/assets/v.bin')\n .set('Range', 'bytes=0-2');\n expect(partial.status).toBe(206);\n expect(partial.headers['content-length']).toBe('3');\n });\n});\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=router.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"router.test.d.ts","sourceRoot":"","sources":["../../../../test/viewer/router.test.ts"],"names":[],"mappings":""}