@imgly/codesign-mcp 0.1.6 → 0.1.8

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 (448) hide show
  1. package/README.md +5 -10
  2. package/assets/docs/api/index.d.ts +9 -3
  3. package/assets/docs/guide/SKILL.md +2 -2
  4. package/assets/docs/guide/api/node/classes/creativeengine.md +13 -13
  5. package/assets/docs/guide/edit-image/transform/scale.md +1 -3
  6. package/assets/docs/guide/filters-and-effects/duotone.md +1 -1
  7. package/assets/docs/guide/get-started/bun.md +0 -2
  8. package/assets/docs/guide/get-started/deno.md +0 -1
  9. package/assets/docs/guide/get-started/vanilla.md +0 -2
  10. package/assets/docs/guide/import-media/default-assets.md +20 -24
  11. package/assets/docs/guide/plugins/print-ready-pdf.md +0 -2
  12. package/assets/docs/guide/serve-assets.md +80 -23
  13. package/assets/docs/handbook/SKILL.md +6 -7
  14. package/dist/assets/inline.generated.js +12 -12
  15. package/dist/assets/inline.generated.js.map +1 -1
  16. package/dist/cli/http.d.ts.map +1 -1
  17. package/dist/cli/http.js +29 -5
  18. package/dist/cli/http.js.map +1 -1
  19. package/dist/cli/stdio.d.ts.map +1 -1
  20. package/dist/cli/stdio.js +145 -48
  21. package/dist/cli/stdio.js.map +1 -1
  22. package/dist/cli/trial-license.generated.d.ts +1 -1
  23. package/dist/cli/trial-license.generated.js +1 -1
  24. package/dist/cli/trial-license.generated.js.map +1 -1
  25. package/dist/config.d.ts +17 -2
  26. package/dist/config.d.ts.map +1 -1
  27. package/dist/config.js +20 -1
  28. package/dist/config.js.map +1 -1
  29. package/dist/diagnostics/bundle.d.ts +3 -0
  30. package/dist/diagnostics/bundle.d.ts.map +1 -1
  31. package/dist/diagnostics/bundle.js +25 -22
  32. package/dist/diagnostics/bundle.js.map +1 -1
  33. package/dist/diagnostics/events.d.ts +6 -0
  34. package/dist/diagnostics/events.d.ts.map +1 -1
  35. package/dist/diagnostics/events.js.map +1 -1
  36. package/dist/diagnostics/prompt.d.ts +3 -0
  37. package/dist/diagnostics/prompt.d.ts.map +1 -0
  38. package/dist/diagnostics/prompt.js +21 -0
  39. package/dist/diagnostics/prompt.js.map +1 -0
  40. package/dist/diagnostics/router.d.ts +12 -0
  41. package/dist/diagnostics/router.d.ts.map +1 -0
  42. package/dist/diagnostics/router.js +64 -0
  43. package/dist/diagnostics/router.js.map +1 -0
  44. package/dist/diagnostics/spa-assets.generated.d.ts.map +1 -0
  45. package/dist/diagnostics/spa-assets.generated.js +1231 -0
  46. package/dist/diagnostics/spa-assets.generated.js.map +1 -0
  47. package/dist/diagnostics/status.d.ts +38 -0
  48. package/dist/diagnostics/status.d.ts.map +1 -0
  49. package/dist/diagnostics/status.js +53 -0
  50. package/dist/diagnostics/status.js.map +1 -0
  51. package/dist/diagnostics/summary.d.ts +48 -0
  52. package/dist/diagnostics/summary.d.ts.map +1 -0
  53. package/dist/diagnostics/summary.js +116 -0
  54. package/dist/diagnostics/summary.js.map +1 -0
  55. package/dist/diagnostics/tool.d.ts +16 -0
  56. package/dist/diagnostics/tool.d.ts.map +1 -0
  57. package/dist/diagnostics/tool.js +90 -0
  58. package/dist/diagnostics/tool.js.map +1 -0
  59. package/dist/engine/asset-sources.d.ts +8 -0
  60. package/dist/engine/asset-sources.d.ts.map +1 -1
  61. package/dist/engine/asset-sources.js +9 -2
  62. package/dist/engine/asset-sources.js.map +1 -1
  63. package/dist/engine/cesdk-adapter.d.ts +5 -1
  64. package/dist/engine/cesdk-adapter.d.ts.map +1 -1
  65. package/dist/engine/cesdk-adapter.js +8 -1
  66. package/dist/engine/cesdk-adapter.js.map +1 -1
  67. package/dist/engine/engine-capacity.d.ts +16 -0
  68. package/dist/engine/engine-capacity.d.ts.map +1 -0
  69. package/dist/engine/engine-capacity.js +48 -0
  70. package/dist/engine/engine-capacity.js.map +1 -0
  71. package/dist/engine/engine-slots.d.ts +48 -0
  72. package/dist/engine/engine-slots.d.ts.map +1 -0
  73. package/dist/engine/engine-slots.js +182 -0
  74. package/dist/engine/engine-slots.js.map +1 -0
  75. package/dist/engine/uri-resolver.js.map +1 -1
  76. package/dist/server.d.ts +25 -0
  77. package/dist/server.d.ts.map +1 -1
  78. package/dist/server.js +24 -4
  79. package/dist/server.js.map +1 -1
  80. package/dist/tools/engine.d.ts +92 -14
  81. package/dist/tools/engine.d.ts.map +1 -1
  82. package/dist/tools/engine.js +147 -20
  83. package/dist/tools/engine.js.map +1 -1
  84. package/dist/tools/export.d.ts.map +1 -1
  85. package/dist/tools/export.js +34 -4
  86. package/dist/tools/export.js.map +1 -1
  87. package/dist/tools/index.js +2 -2
  88. package/dist/tools/index.js.map +1 -1
  89. package/dist/tools/load.d.ts.map +1 -1
  90. package/dist/tools/load.js +26 -19
  91. package/dist/tools/load.js.map +1 -1
  92. package/dist/tools/preview.d.ts.map +1 -1
  93. package/dist/tools/preview.js +60 -40
  94. package/dist/tools/preview.js.map +1 -1
  95. package/dist/tools/{open-editor.d.ts → view.d.ts} +3 -3
  96. package/dist/tools/view.d.ts.map +1 -0
  97. package/dist/tools/{open-editor.js → view.js} +20 -18
  98. package/dist/tools/view.js.map +1 -0
  99. package/dist/viewer/listener.d.ts +2 -0
  100. package/dist/viewer/listener.d.ts.map +1 -1
  101. package/dist/viewer/listener.js +2 -0
  102. package/dist/viewer/listener.js.map +1 -1
  103. package/dist/viewer/presigned-r2-url-builder.d.ts +1 -1
  104. package/dist/viewer/presigned-r2-url-builder.js +1 -1
  105. package/dist/viewer/presigned-r2-url-builder.js.map +1 -1
  106. package/dist/viewer/router.d.ts.map +1 -1
  107. package/dist/viewer/router.js +8 -17
  108. package/dist/viewer/router.js.map +1 -1
  109. package/dist/viewer/session-mount.js.map +1 -1
  110. package/dist/viewer/spa-assets.generated.d.ts.map +1 -1
  111. package/dist/viewer/spa-assets.generated.js +750 -869
  112. package/dist/viewer/spa-assets.generated.js.map +1 -1
  113. package/dist/viewer/url-builder.d.ts +4 -3
  114. package/dist/viewer/url-builder.d.ts.map +1 -1
  115. package/dist/viewer/url-builder.js +4 -4
  116. package/dist/viewer/url-builder.js.map +1 -1
  117. package/package.json +7 -6
  118. package/dist/dashboard/router.d.ts +0 -3
  119. package/dist/dashboard/router.d.ts.map +0 -1
  120. package/dist/dashboard/router.js +0 -19
  121. package/dist/dashboard/router.js.map +0 -1
  122. package/dist/dashboard/spa-assets.generated.d.ts.map +0 -1
  123. package/dist/dashboard/spa-assets.generated.js +0 -220
  124. package/dist/dashboard/spa-assets.generated.js.map +0 -1
  125. package/dist/metrics/mount.d.ts +0 -11
  126. package/dist/metrics/mount.d.ts.map +0 -1
  127. package/dist/metrics/mount.js +0 -13
  128. package/dist/metrics/mount.js.map +0 -1
  129. package/dist/metrics/recorder.d.ts +0 -55
  130. package/dist/metrics/recorder.d.ts.map +0 -1
  131. package/dist/metrics/recorder.js +0 -97
  132. package/dist/metrics/recorder.js.map +0 -1
  133. package/dist/test/scripts/changelog-add.d.ts +0 -8
  134. package/dist/test/scripts/changelog-add.d.ts.map +0 -1
  135. package/dist/test/scripts/changelog-add.js +0 -50
  136. package/dist/test/scripts/changelog-add.js.map +0 -1
  137. package/dist/test/scripts/changelog-collate.d.ts +0 -38
  138. package/dist/test/scripts/changelog-collate.d.ts.map +0 -1
  139. package/dist/test/scripts/changelog-collate.js +0 -171
  140. package/dist/test/scripts/changelog-collate.js.map +0 -1
  141. package/dist/test/test/changelog.test.d.ts +0 -2
  142. package/dist/test/test/changelog.test.d.ts.map +0 -1
  143. package/dist/test/test/changelog.test.js +0 -293
  144. package/dist/test/test/changelog.test.js.map +0 -1
  145. package/dist/test/test/cli/dispatcher.test.d.ts +0 -2
  146. package/dist/test/test/cli/dispatcher.test.d.ts.map +0 -1
  147. package/dist/test/test/cli/dispatcher.test.js +0 -54
  148. package/dist/test/test/cli/dispatcher.test.js.map +0 -1
  149. package/dist/test/test/cli/redirect-console.test.d.ts +0 -2
  150. package/dist/test/test/cli/redirect-console.test.d.ts.map +0 -1
  151. package/dist/test/test/cli/redirect-console.test.js +0 -78
  152. package/dist/test/test/cli/redirect-console.test.js.map +0 -1
  153. package/dist/test/test/cli/resolve-license.test.d.ts +0 -2
  154. package/dist/test/test/cli/resolve-license.test.d.ts.map +0 -1
  155. package/dist/test/test/cli/resolve-license.test.js +0 -29
  156. package/dist/test/test/cli/resolve-license.test.js.map +0 -1
  157. package/dist/test/test/cli/stdio-diagnostics.test.d.ts +0 -2
  158. package/dist/test/test/cli/stdio-diagnostics.test.d.ts.map +0 -1
  159. package/dist/test/test/cli/stdio-diagnostics.test.js +0 -31
  160. package/dist/test/test/cli/stdio-diagnostics.test.js.map +0 -1
  161. package/dist/test/test/cli/stdio-license.test.d.ts +0 -2
  162. package/dist/test/test/cli/stdio-license.test.d.ts.map +0 -1
  163. package/dist/test/test/cli/stdio-license.test.js +0 -19
  164. package/dist/test/test/cli/stdio-license.test.js.map +0 -1
  165. package/dist/test/test/config.test.d.ts +0 -2
  166. package/dist/test/test/config.test.d.ts.map +0 -1
  167. package/dist/test/test/config.test.js +0 -95
  168. package/dist/test/test/config.test.js.map +0 -1
  169. package/dist/test/test/cross-ref.test.d.ts +0 -2
  170. package/dist/test/test/cross-ref.test.d.ts.map +0 -1
  171. package/dist/test/test/cross-ref.test.js +0 -39
  172. package/dist/test/test/cross-ref.test.js.map +0 -1
  173. package/dist/test/test/diagnostics/bundle.test.d.ts +0 -2
  174. package/dist/test/test/diagnostics/bundle.test.d.ts.map +0 -1
  175. package/dist/test/test/diagnostics/bundle.test.js +0 -53
  176. package/dist/test/test/diagnostics/bundle.test.js.map +0 -1
  177. package/dist/test/test/diagnostics/compose.test.d.ts +0 -2
  178. package/dist/test/test/diagnostics/compose.test.d.ts.map +0 -1
  179. package/dist/test/test/diagnostics/compose.test.js +0 -31
  180. package/dist/test/test/diagnostics/compose.test.js.map +0 -1
  181. package/dist/test/test/diagnostics/file-sink.test.d.ts +0 -2
  182. package/dist/test/test/diagnostics/file-sink.test.d.ts.map +0 -1
  183. package/dist/test/test/diagnostics/file-sink.test.js +0 -113
  184. package/dist/test/test/diagnostics/file-sink.test.js.map +0 -1
  185. package/dist/test/test/diagnostics/redact.test.d.ts +0 -2
  186. package/dist/test/test/diagnostics/redact.test.d.ts.map +0 -1
  187. package/dist/test/test/diagnostics/redact.test.js +0 -59
  188. package/dist/test/test/diagnostics/redact.test.js.map +0 -1
  189. package/dist/test/test/diagnostics/tool-call-adapter.test.d.ts +0 -2
  190. package/dist/test/test/diagnostics/tool-call-adapter.test.d.ts.map +0 -1
  191. package/dist/test/test/diagnostics/tool-call-adapter.test.js +0 -34
  192. package/dist/test/test/diagnostics/tool-call-adapter.test.js.map +0 -1
  193. package/dist/test/test/engine/asset-sources.test.d.ts +0 -2
  194. package/dist/test/test/engine/asset-sources.test.d.ts.map +0 -1
  195. package/dist/test/test/engine/asset-sources.test.js +0 -100
  196. package/dist/test/test/engine/asset-sources.test.js.map +0 -1
  197. package/dist/test/test/engine/cesdk-adapter.test.d.ts +0 -2
  198. package/dist/test/test/engine/cesdk-adapter.test.d.ts.map +0 -1
  199. package/dist/test/test/engine/cesdk-adapter.test.js +0 -32
  200. package/dist/test/test/engine/cesdk-adapter.test.js.map +0 -1
  201. package/dist/test/test/engine/mutex.test.d.ts +0 -2
  202. package/dist/test/test/engine/mutex.test.d.ts.map +0 -1
  203. package/dist/test/test/engine/mutex.test.js +0 -63
  204. package/dist/test/test/engine/mutex.test.js.map +0 -1
  205. package/dist/test/test/engine/session.test.d.ts +0 -2
  206. package/dist/test/test/engine/session.test.d.ts.map +0 -1
  207. package/dist/test/test/engine/session.test.js +0 -159
  208. package/dist/test/test/engine/session.test.js.map +0 -1
  209. package/dist/test/test/engine/unsplash-source.test.d.ts +0 -2
  210. package/dist/test/test/engine/unsplash-source.test.d.ts.map +0 -1
  211. package/dist/test/test/engine/unsplash-source.test.js +0 -129
  212. package/dist/test/test/engine/unsplash-source.test.js.map +0 -1
  213. package/dist/test/test/engine/uri-resolver.test.d.ts +0 -2
  214. package/dist/test/test/engine/uri-resolver.test.d.ts.map +0 -1
  215. package/dist/test/test/engine/uri-resolver.test.js +0 -38
  216. package/dist/test/test/engine/uri-resolver.test.js.map +0 -1
  217. package/dist/test/test/gateway/hosted-stub.test.d.ts +0 -2
  218. package/dist/test/test/gateway/hosted-stub.test.d.ts.map +0 -1
  219. package/dist/test/test/gateway/hosted-stub.test.js +0 -11
  220. package/dist/test/test/gateway/hosted-stub.test.js.map +0 -1
  221. package/dist/test/test/gateway/local.test.d.ts +0 -2
  222. package/dist/test/test/gateway/local.test.d.ts.map +0 -1
  223. package/dist/test/test/gateway/local.test.js +0 -29
  224. package/dist/test/test/gateway/local.test.js.map +0 -1
  225. package/dist/test/test/handbook-contract.test.d.ts +0 -2
  226. package/dist/test/test/handbook-contract.test.d.ts.map +0 -1
  227. package/dist/test/test/handbook-contract.test.js +0 -79
  228. package/dist/test/test/handbook-contract.test.js.map +0 -1
  229. package/dist/test/test/http/server.test.d.ts +0 -2
  230. package/dist/test/test/http/server.test.d.ts.map +0 -1
  231. package/dist/test/test/http/server.test.js +0 -338
  232. package/dist/test/test/http/server.test.js.map +0 -1
  233. package/dist/test/test/http/session-id-header.test.d.ts +0 -2
  234. package/dist/test/test/http/session-id-header.test.d.ts.map +0 -1
  235. package/dist/test/test/http/session-id-header.test.js +0 -76
  236. package/dist/test/test/http/session-id-header.test.js.map +0 -1
  237. package/dist/test/test/http/session-manager.test.d.ts +0 -2
  238. package/dist/test/test/http/session-manager.test.d.ts.map +0 -1
  239. package/dist/test/test/http/session-manager.test.js +0 -97
  240. package/dist/test/test/http/session-manager.test.js.map +0 -1
  241. package/dist/test/test/http/workspace-auth.test.d.ts +0 -2
  242. package/dist/test/test/http/workspace-auth.test.d.ts.map +0 -1
  243. package/dist/test/test/http/workspace-auth.test.js +0 -40
  244. package/dist/test/test/http/workspace-auth.test.js.map +0 -1
  245. package/dist/test/test/metrics/mount.test.d.ts +0 -2
  246. package/dist/test/test/metrics/mount.test.d.ts.map +0 -1
  247. package/dist/test/test/metrics/mount.test.js +0 -59
  248. package/dist/test/test/metrics/mount.test.js.map +0 -1
  249. package/dist/test/test/metrics/recorder.test.d.ts +0 -2
  250. package/dist/test/test/metrics/recorder.test.d.ts.map +0 -1
  251. package/dist/test/test/metrics/recorder.test.js +0 -118
  252. package/dist/test/test/metrics/recorder.test.js.map +0 -1
  253. package/dist/test/test/revisions/hash.test.d.ts +0 -2
  254. package/dist/test/test/revisions/hash.test.d.ts.map +0 -1
  255. package/dist/test/test/revisions/hash.test.js +0 -33
  256. package/dist/test/test/revisions/hash.test.js.map +0 -1
  257. package/dist/test/test/revisions/store.test.d.ts +0 -2
  258. package/dist/test/test/revisions/store.test.d.ts.map +0 -1
  259. package/dist/test/test/revisions/store.test.js +0 -315
  260. package/dist/test/test/revisions/store.test.js.map +0 -1
  261. package/dist/test/test/server.metrics.test.d.ts +0 -2
  262. package/dist/test/test/server.metrics.test.d.ts.map +0 -1
  263. package/dist/test/test/server.metrics.test.js +0 -87
  264. package/dist/test/test/server.metrics.test.js.map +0 -1
  265. package/dist/test/test/server.test.d.ts +0 -2
  266. package/dist/test/test/server.test.d.ts.map +0 -1
  267. package/dist/test/test/server.test.js +0 -146
  268. package/dist/test/test/server.test.js.map +0 -1
  269. package/dist/test/test/skill-tools.test.d.ts +0 -2
  270. package/dist/test/test/skill-tools.test.d.ts.map +0 -1
  271. package/dist/test/test/skill-tools.test.js +0 -84
  272. package/dist/test/test/skill-tools.test.js.map +0 -1
  273. package/dist/test/test/smoke.test.d.ts +0 -2
  274. package/dist/test/test/smoke.test.d.ts.map +0 -1
  275. package/dist/test/test/smoke.test.js +0 -8
  276. package/dist/test/test/smoke.test.js.map +0 -1
  277. package/dist/test/test/tools/asset-generate.test.d.ts +0 -2
  278. package/dist/test/test/tools/asset-generate.test.d.ts.map +0 -1
  279. package/dist/test/test/tools/asset-generate.test.js +0 -66
  280. package/dist/test/test/tools/asset-generate.test.js.map +0 -1
  281. package/dist/test/test/tools/asset-search.test.d.ts +0 -2
  282. package/dist/test/test/tools/asset-search.test.d.ts.map +0 -1
  283. package/dist/test/test/tools/asset-search.test.js +0 -121
  284. package/dist/test/test/tools/asset-search.test.js.map +0 -1
  285. package/dist/test/test/tools/edit-harness.d.ts +0 -14
  286. package/dist/test/test/tools/edit-harness.d.ts.map +0 -1
  287. package/dist/test/test/tools/edit-harness.js +0 -30
  288. package/dist/test/test/tools/edit-harness.js.map +0 -1
  289. package/dist/test/test/tools/edit.telemetry.test.d.ts +0 -2
  290. package/dist/test/test/tools/edit.telemetry.test.d.ts.map +0 -1
  291. package/dist/test/test/tools/edit.telemetry.test.js +0 -46
  292. package/dist/test/test/tools/edit.telemetry.test.js.map +0 -1
  293. package/dist/test/test/tools/edit.test.d.ts +0 -2
  294. package/dist/test/test/tools/edit.test.d.ts.map +0 -1
  295. package/dist/test/test/tools/edit.test.js +0 -267
  296. package/dist/test/test/tools/edit.test.js.map +0 -1
  297. package/dist/test/test/tools/export-harness.d.ts +0 -13
  298. package/dist/test/test/tools/export-harness.d.ts.map +0 -1
  299. package/dist/test/test/tools/export-harness.js +0 -27
  300. package/dist/test/test/tools/export-harness.js.map +0 -1
  301. package/dist/test/test/tools/export.telemetry.test.d.ts +0 -2
  302. package/dist/test/test/tools/export.telemetry.test.d.ts.map +0 -1
  303. package/dist/test/test/tools/export.telemetry.test.js +0 -65
  304. package/dist/test/test/tools/export.telemetry.test.js.map +0 -1
  305. package/dist/test/test/tools/export.test.d.ts +0 -2
  306. package/dist/test/test/tools/export.test.d.ts.map +0 -1
  307. package/dist/test/test/tools/export.test.js +0 -174
  308. package/dist/test/test/tools/export.test.js.map +0 -1
  309. package/dist/test/test/tools/history.test.d.ts +0 -2
  310. package/dist/test/test/tools/history.test.d.ts.map +0 -1
  311. package/dist/test/test/tools/history.test.js +0 -29
  312. package/dist/test/test/tools/history.test.js.map +0 -1
  313. package/dist/test/test/tools/import.test.d.ts +0 -2
  314. package/dist/test/test/tools/import.test.d.ts.map +0 -1
  315. package/dist/test/test/tools/import.test.js +0 -122
  316. package/dist/test/test/tools/import.test.js.map +0 -1
  317. package/dist/test/test/tools/index.test.d.ts +0 -2
  318. package/dist/test/test/tools/index.test.d.ts.map +0 -1
  319. package/dist/test/test/tools/index.test.js +0 -117
  320. package/dist/test/test/tools/index.test.js.map +0 -1
  321. package/dist/test/test/tools/inspect.test.d.ts +0 -2
  322. package/dist/test/test/tools/inspect.test.d.ts.map +0 -1
  323. package/dist/test/test/tools/inspect.test.js +0 -62
  324. package/dist/test/test/tools/inspect.test.js.map +0 -1
  325. package/dist/test/test/tools/list.test.d.ts +0 -2
  326. package/dist/test/test/tools/list.test.d.ts.map +0 -1
  327. package/dist/test/test/tools/list.test.js +0 -23
  328. package/dist/test/test/tools/list.test.js.map +0 -1
  329. package/dist/test/test/tools/load.integration.test.d.ts +0 -2
  330. package/dist/test/test/tools/load.integration.test.d.ts.map +0 -1
  331. package/dist/test/test/tools/load.integration.test.js +0 -165
  332. package/dist/test/test/tools/load.integration.test.js.map +0 -1
  333. package/dist/test/test/tools/load.test.d.ts +0 -2
  334. package/dist/test/test/tools/load.test.d.ts.map +0 -1
  335. package/dist/test/test/tools/load.test.js +0 -387
  336. package/dist/test/test/tools/load.test.js.map +0 -1
  337. package/dist/test/test/tools/metrics.test.d.ts +0 -2
  338. package/dist/test/test/tools/metrics.test.d.ts.map +0 -1
  339. package/dist/test/test/tools/metrics.test.js +0 -29
  340. package/dist/test/test/tools/metrics.test.js.map +0 -1
  341. package/dist/test/test/tools/open-editor.test.d.ts +0 -2
  342. package/dist/test/test/tools/open-editor.test.d.ts.map +0 -1
  343. package/dist/test/test/tools/open-editor.test.js +0 -53
  344. package/dist/test/test/tools/open-editor.test.js.map +0 -1
  345. package/dist/test/test/tools/preview-harness.d.ts +0 -9
  346. package/dist/test/test/tools/preview-harness.d.ts.map +0 -1
  347. package/dist/test/test/tools/preview-harness.js +0 -23
  348. package/dist/test/test/tools/preview-harness.js.map +0 -1
  349. package/dist/test/test/tools/preview.telemetry.test.d.ts +0 -2
  350. package/dist/test/test/tools/preview.telemetry.test.d.ts.map +0 -1
  351. package/dist/test/test/tools/preview.telemetry.test.js +0 -36
  352. package/dist/test/test/tools/preview.telemetry.test.js.map +0 -1
  353. package/dist/test/test/tools/preview.test.d.ts +0 -2
  354. package/dist/test/test/tools/preview.test.d.ts.map +0 -1
  355. package/dist/test/test/tools/preview.test.js +0 -75
  356. package/dist/test/test/tools/preview.test.js.map +0 -1
  357. package/dist/test/test/tools/rename.test.d.ts +0 -2
  358. package/dist/test/test/tools/rename.test.d.ts.map +0 -1
  359. package/dist/test/test/tools/rename.test.js +0 -16
  360. package/dist/test/test/tools/rename.test.js.map +0 -1
  361. package/dist/test/test/tools/save.test.d.ts +0 -2
  362. package/dist/test/test/tools/save.test.d.ts.map +0 -1
  363. package/dist/test/test/tools/save.test.js +0 -137
  364. package/dist/test/test/tools/save.test.js.map +0 -1
  365. package/dist/test/test/tools/schema-best-practices.d.ts +0 -13
  366. package/dist/test/test/tools/schema-best-practices.d.ts.map +0 -1
  367. package/dist/test/test/tools/schema-best-practices.js +0 -169
  368. package/dist/test/test/tools/schema-best-practices.js.map +0 -1
  369. package/dist/test/test/tools/schema-best-practices.test.d.ts +0 -3
  370. package/dist/test/test/tools/schema-best-practices.test.d.ts.map +0 -1
  371. package/dist/test/test/tools/schema-best-practices.test.js +0 -194
  372. package/dist/test/test/tools/schema-best-practices.test.js.map +0 -1
  373. package/dist/test/test/tools/spans.test.d.ts +0 -2
  374. package/dist/test/test/tools/spans.test.d.ts.map +0 -1
  375. package/dist/test/test/tools/spans.test.js +0 -84
  376. package/dist/test/test/tools/spans.test.js.map +0 -1
  377. package/dist/test/test/viewer/broadcaster.test.d.ts +0 -2
  378. package/dist/test/test/viewer/broadcaster.test.d.ts.map +0 -1
  379. package/dist/test/test/viewer/broadcaster.test.js +0 -53
  380. package/dist/test/test/viewer/broadcaster.test.js.map +0 -1
  381. package/dist/test/test/viewer/cesdk-cdn.test.d.ts +0 -2
  382. package/dist/test/test/viewer/cesdk-cdn.test.d.ts.map +0 -1
  383. package/dist/test/test/viewer/cesdk-cdn.test.js +0 -19
  384. package/dist/test/test/viewer/cesdk-cdn.test.js.map +0 -1
  385. package/dist/test/test/viewer/config-route.test.d.ts +0 -2
  386. package/dist/test/test/viewer/config-route.test.d.ts.map +0 -1
  387. package/dist/test/test/viewer/config-route.test.js +0 -28
  388. package/dist/test/test/viewer/config-route.test.js.map +0 -1
  389. package/dist/test/test/viewer/resource-route.test.d.ts +0 -2
  390. package/dist/test/test/viewer/resource-route.test.d.ts.map +0 -1
  391. package/dist/test/test/viewer/resource-route.test.js +0 -70
  392. package/dist/test/test/viewer/resource-route.test.js.map +0 -1
  393. package/dist/test/test/viewer/router.test.d.ts +0 -2
  394. package/dist/test/test/viewer/router.test.d.ts.map +0 -1
  395. package/dist/test/test/viewer/router.test.js +0 -227
  396. package/dist/test/test/viewer/router.test.js.map +0 -1
  397. package/dist/test/test/viewer/session-mount.test.d.ts +0 -2
  398. package/dist/test/test/viewer/session-mount.test.d.ts.map +0 -1
  399. package/dist/test/test/viewer/session-mount.test.js +0 -52
  400. package/dist/test/test/viewer/session-mount.test.js.map +0 -1
  401. package/dist/test/test/viewer/spa-version.test.d.ts +0 -2
  402. package/dist/test/test/viewer/spa-version.test.d.ts.map +0 -1
  403. package/dist/test/test/viewer/spa-version.test.js +0 -14
  404. package/dist/test/test/viewer/spa-version.test.js.map +0 -1
  405. package/dist/test/test/viewer/url-builder.test.d.ts +0 -2
  406. package/dist/test/test/viewer/url-builder.test.d.ts.map +0 -1
  407. package/dist/test/test/viewer/url-builder.test.js +0 -98
  408. package/dist/test/test/viewer/url-builder.test.js.map +0 -1
  409. package/dist/test/test/workspace/content-hash.test.d.ts +0 -2
  410. package/dist/test/test/workspace/content-hash.test.d.ts.map +0 -1
  411. package/dist/test/test/workspace/content-hash.test.js +0 -17
  412. package/dist/test/test/workspace/content-hash.test.js.map +0 -1
  413. package/dist/test/test/workspace/hosted-stub.test.d.ts +0 -2
  414. package/dist/test/test/workspace/hosted-stub.test.d.ts.map +0 -1
  415. package/dist/test/test/workspace/hosted-stub.test.js +0 -30
  416. package/dist/test/test/workspace/hosted-stub.test.js.map +0 -1
  417. package/dist/test/test/workspace/in-memory.test.d.ts +0 -2
  418. package/dist/test/test/workspace/in-memory.test.d.ts.map +0 -1
  419. package/dist/test/test/workspace/in-memory.test.js +0 -4
  420. package/dist/test/test/workspace/in-memory.test.js.map +0 -1
  421. package/dist/test/test/workspace/node-fs.test.d.ts +0 -2
  422. package/dist/test/test/workspace/node-fs.test.d.ts.map +0 -1
  423. package/dist/test/test/workspace/node-fs.test.js +0 -20
  424. package/dist/test/test/workspace/node-fs.test.js.map +0 -1
  425. package/dist/test/test/workspace/s3.test.d.ts +0 -2
  426. package/dist/test/test/workspace/s3.test.d.ts.map +0 -1
  427. package/dist/test/test/workspace/s3.test.js +0 -153
  428. package/dist/test/test/workspace/s3.test.js.map +0 -1
  429. package/dist/test/test/workspace/scoped.test.d.ts +0 -2
  430. package/dist/test/test/workspace/scoped.test.d.ts.map +0 -1
  431. package/dist/test/test/workspace/scoped.test.js +0 -59
  432. package/dist/test/test/workspace/scoped.test.js.map +0 -1
  433. package/dist/test/test/workspace/shared-contract.d.ts +0 -3
  434. package/dist/test/test/workspace/shared-contract.d.ts.map +0 -1
  435. package/dist/test/test/workspace/shared-contract.js +0 -92
  436. package/dist/test/test/workspace/shared-contract.js.map +0 -1
  437. package/dist/test/tsconfig.test.tsbuildinfo +0 -1
  438. package/dist/test/vitest.config.d.ts +0 -3
  439. package/dist/test/vitest.config.d.ts.map +0 -1
  440. package/dist/test/vitest.config.js +0 -8
  441. package/dist/test/vitest.config.js.map +0 -1
  442. package/dist/tools/metrics.d.ts +0 -11
  443. package/dist/tools/metrics.d.ts.map +0 -1
  444. package/dist/tools/metrics.js +0 -28
  445. package/dist/tools/metrics.js.map +0 -1
  446. package/dist/tools/open-editor.d.ts.map +0 -1
  447. package/dist/tools/open-editor.js.map +0 -1
  448. /package/dist/{dashboard → diagnostics}/spa-assets.generated.d.ts +0 -0
@@ -1,76 +0,0 @@
1
- import request from 'supertest';
2
- import { describe, expect, it } from 'vitest';
3
- import { createCodesignHttpServer } from '../../src/http/server.js';
4
- // The transport echoes the session id it assigned in the `mcp-session-id`
5
- // response header. We assert that, with `trustedSessionIdHeader` configured,
6
- // an inbound header value becomes the session id verbatim — and without it,
7
- // the server still mints its own (a normal uuid, not our injected value).
8
- const INIT_BODY = {
9
- jsonrpc: '2.0',
10
- id: 1,
11
- method: 'initialize',
12
- params: {
13
- protocolVersion: '2024-11-05',
14
- capabilities: {},
15
- clientInfo: { name: 'test', version: '0.0.0' }
16
- }
17
- };
18
- describe('trustedSessionIdHeader', () => {
19
- it('uses the inbound header value as the session id on initialize', async () => {
20
- const app = await createCodesignHttpServer({
21
- assets: {},
22
- maxSessions: 4,
23
- idleTimeoutMs: 60_000,
24
- trustedSessionIdHeader: 'x-mcp-session-id',
25
- resolveWorkspaceId: (_req, sid) => `s/${sid}`,
26
- createSession: async () => ({ engine: {}, tools: [] })
27
- });
28
- const res = await request(app)
29
- .post('/mcp')
30
- .set('accept', 'application/json, text/event-stream')
31
- .set('content-type', 'application/json')
32
- .set('x-mcp-session-id', 'worker-minted-123')
33
- .send(INIT_BODY);
34
- expect(res.headers['mcp-session-id']).toBe('worker-minted-123');
35
- await app.shutdown();
36
- });
37
- it('mints its own id when the header is absent', async () => {
38
- const app = await createCodesignHttpServer({
39
- assets: {},
40
- maxSessions: 4,
41
- idleTimeoutMs: 60_000,
42
- trustedSessionIdHeader: 'x-mcp-session-id',
43
- resolveWorkspaceId: (_req, sid) => `s/${sid}`,
44
- createSession: async () => ({ engine: {}, tools: [] })
45
- });
46
- const res = await request(app)
47
- .post('/mcp')
48
- .set('accept', 'application/json, text/event-stream')
49
- .set('content-type', 'application/json')
50
- .send(INIT_BODY);
51
- expect(res.headers['mcp-session-id']).toBeDefined();
52
- expect(res.headers['mcp-session-id']).not.toBe('worker-minted-123');
53
- expect(res.headers['mcp-session-id']).toMatch(/^[0-9a-f-]{36}$/i);
54
- await app.shutdown();
55
- });
56
- it('mints its own id when the header is present but empty', async () => {
57
- const app = await createCodesignHttpServer({
58
- assets: {},
59
- maxSessions: 4,
60
- idleTimeoutMs: 60_000,
61
- trustedSessionIdHeader: 'x-mcp-session-id',
62
- resolveWorkspaceId: (_req, sid) => `s/${sid}`,
63
- createSession: async () => ({ engine: {}, tools: [] })
64
- });
65
- const res = await request(app)
66
- .post('/mcp')
67
- .set('accept', 'application/json, text/event-stream')
68
- .set('content-type', 'application/json')
69
- .set('x-mcp-session-id', '')
70
- .send(INIT_BODY);
71
- expect(res.headers['mcp-session-id']).toBeDefined();
72
- expect(res.headers['mcp-session-id']).toMatch(/^[0-9a-f-]{36}$/i);
73
- await app.shutdown();
74
- });
75
- });
76
- //# sourceMappingURL=session-id-header.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"session-id-header.test.js","sourceRoot":"","sources":["../../../../test/http/session-id-header.test.ts"],"names":[],"mappings":"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","sourcesContent":["import request from 'supertest';\nimport { describe, expect, it } from 'vitest';\nimport { createCodesignHttpServer } from '../../src/http/server.js';\n\n// The transport echoes the session id it assigned in the `mcp-session-id`\n// response header. We assert that, with `trustedSessionIdHeader` configured,\n// an inbound header value becomes the session id verbatim — and without it,\n// the server still mints its own (a normal uuid, not our injected value).\nconst INIT_BODY = {\n jsonrpc: '2.0',\n id: 1,\n method: 'initialize',\n params: {\n protocolVersion: '2024-11-05',\n capabilities: {},\n clientInfo: { name: 'test', version: '0.0.0' }\n }\n};\n\ndescribe('trustedSessionIdHeader', () => {\n it('uses the inbound header value as the session id on initialize', async () => {\n const app = await createCodesignHttpServer({\n assets: {},\n maxSessions: 4,\n idleTimeoutMs: 60_000,\n trustedSessionIdHeader: 'x-mcp-session-id',\n resolveWorkspaceId: (_req, sid) => `s/${sid}`,\n createSession: async () => ({ engine: {}, tools: [] })\n });\n const res = await request(app)\n .post('/mcp')\n .set('accept', 'application/json, text/event-stream')\n .set('content-type', 'application/json')\n .set('x-mcp-session-id', 'worker-minted-123')\n .send(INIT_BODY);\n expect(res.headers['mcp-session-id']).toBe('worker-minted-123');\n await app.shutdown();\n });\n\n it('mints its own id when the header is absent', async () => {\n const app = await createCodesignHttpServer({\n assets: {},\n maxSessions: 4,\n idleTimeoutMs: 60_000,\n trustedSessionIdHeader: 'x-mcp-session-id',\n resolveWorkspaceId: (_req, sid) => `s/${sid}`,\n createSession: async () => ({ engine: {}, tools: [] })\n });\n const res = await request(app)\n .post('/mcp')\n .set('accept', 'application/json, text/event-stream')\n .set('content-type', 'application/json')\n .send(INIT_BODY);\n expect(res.headers['mcp-session-id']).toBeDefined();\n expect(res.headers['mcp-session-id']).not.toBe('worker-minted-123');\n expect(res.headers['mcp-session-id']).toMatch(/^[0-9a-f-]{36}$/i);\n await app.shutdown();\n });\n\n it('mints its own id when the header is present but empty', async () => {\n const app = await createCodesignHttpServer({\n assets: {},\n maxSessions: 4,\n idleTimeoutMs: 60_000,\n trustedSessionIdHeader: 'x-mcp-session-id',\n resolveWorkspaceId: (_req, sid) => `s/${sid}`,\n createSession: async () => ({ engine: {}, tools: [] })\n });\n const res = await request(app)\n .post('/mcp')\n .set('accept', 'application/json, text/event-stream')\n .set('content-type', 'application/json')\n .set('x-mcp-session-id', '')\n .send(INIT_BODY);\n expect(res.headers['mcp-session-id']).toBeDefined();\n expect(res.headers['mcp-session-id']).toMatch(/^[0-9a-f-]{36}$/i);\n await app.shutdown();\n });\n});\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=session-manager.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"session-manager.test.d.ts","sourceRoot":"","sources":["../../../../test/http/session-manager.test.ts"],"names":[],"mappings":""}
@@ -1,97 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
- import { SessionCapExceededError, SessionManager, SessionNotFoundError } from '../../src/http/session-manager.js';
3
- describe('SessionManager', () => {
4
- let nextEngineId;
5
- let createdEngines;
6
- let mgr;
7
- beforeEach(() => {
8
- vi.useFakeTimers();
9
- vi.setSystemTime(new Date('2026-05-09T00:00:00Z'));
10
- nextEngineId = 0;
11
- createdEngines = [];
12
- mgr = new SessionManager({
13
- maxSessions: 3,
14
- idleTimeoutMs: 60_000,
15
- create: async () => {
16
- const engine = { id: nextEngineId++, disposed: false };
17
- createdEngines.push(engine);
18
- return { id: `s-${engine.id}`, engine };
19
- },
20
- destroy: async (s) => {
21
- s.engine.disposed = true;
22
- }
23
- });
24
- });
25
- afterEach(() => {
26
- vi.useRealTimers();
27
- });
28
- it('create() returns a fresh session and registers it under its id', async () => {
29
- const s = await mgr.create();
30
- expect(s.id).toBe('s-0');
31
- expect(s.engine.id).toBe(0);
32
- expect(mgr.get(s.id)).toBe(s);
33
- });
34
- it('get() returns undefined for unknown ids', () => {
35
- expect(mgr.get('nope')).toBeUndefined();
36
- });
37
- it('touch() updates lastActivityAt so the session survives idle eviction', async () => {
38
- const a = await mgr.create();
39
- vi.advanceTimersByTime(50_000);
40
- mgr.touch(a.id);
41
- vi.advanceTimersByTime(50_000); // total 100s; without touch a would be evicted
42
- await mgr.evictIdle();
43
- expect(mgr.get(a.id)).toBe(a);
44
- expect(a.engine.disposed).toBe(false);
45
- });
46
- it('evictIdle() destroys sessions older than idleTimeoutMs', async () => {
47
- const a = await mgr.create();
48
- const b = await mgr.create();
49
- vi.advanceTimersByTime(30_000);
50
- mgr.touch(b.id); // bump b only
51
- vi.advanceTimersByTime(40_000); // a is now 70s idle, b only 40s
52
- await mgr.evictIdle();
53
- expect(mgr.get(a.id)).toBeUndefined();
54
- expect(a.engine.disposed).toBe(true);
55
- expect(mgr.get(b.id)).toBe(b);
56
- expect(b.engine.disposed).toBe(false);
57
- });
58
- it('create() throws SessionCapExceededError once maxSessions is reached', async () => {
59
- await mgr.create();
60
- await mgr.create();
61
- await mgr.create();
62
- await expect(mgr.create()).rejects.toBeInstanceOf(SessionCapExceededError);
63
- });
64
- it('delete() destroys a session and removes it', async () => {
65
- const a = await mgr.create();
66
- await mgr.delete(a.id);
67
- expect(mgr.get(a.id)).toBeUndefined();
68
- expect(a.engine.disposed).toBe(true);
69
- });
70
- it('delete() of an unknown id throws SessionNotFoundError', async () => {
71
- await expect(mgr.delete('nope')).rejects.toBeInstanceOf(SessionNotFoundError);
72
- });
73
- it('destroyAll() shuts down every active session', async () => {
74
- const a = await mgr.create();
75
- const b = await mgr.create();
76
- await mgr.destroyAll();
77
- expect(mgr.get(a.id)).toBeUndefined();
78
- expect(mgr.get(b.id)).toBeUndefined();
79
- expect(a.engine.disposed).toBe(true);
80
- expect(b.engine.disposed).toBe(true);
81
- });
82
- it('forwards a context object to the create callback', async () => {
83
- const seen = [];
84
- const mgr = new SessionManager({
85
- maxSessions: 10,
86
- idleTimeoutMs: 60_000,
87
- create: (ctx) => {
88
- seen.push(ctx?.workspaceId);
89
- return { id: ctx?.workspaceId ?? 'none' };
90
- },
91
- destroy: () => { }
92
- });
93
- await mgr.create({ workspaceId: 'u/a' });
94
- expect(seen).toEqual(['u/a']);
95
- });
96
- });
97
- //# sourceMappingURL=session-manager.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"session-manager.test.js","sourceRoot":"","sources":["../../../../test/http/session-manager.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\nimport {\n SessionCapExceededError,\n SessionManager,\n SessionNotFoundError\n} from '../../src/http/session-manager.js';\n\ninterface FakeEngine {\n id: number;\n disposed: boolean;\n}\n\ninterface FakeSession {\n id: string;\n engine: FakeEngine;\n}\n\ndescribe('SessionManager', () => {\n let nextEngineId: number;\n let createdEngines: FakeEngine[];\n let mgr: SessionManager<FakeSession>;\n\n beforeEach(() => {\n vi.useFakeTimers();\n vi.setSystemTime(new Date('2026-05-09T00:00:00Z'));\n nextEngineId = 0;\n createdEngines = [];\n mgr = new SessionManager<FakeSession>({\n maxSessions: 3,\n idleTimeoutMs: 60_000,\n create: async () => {\n const engine: FakeEngine = { id: nextEngineId++, disposed: false };\n createdEngines.push(engine);\n return { id: `s-${engine.id}`, engine };\n },\n destroy: async (s) => {\n s.engine.disposed = true;\n }\n });\n });\n\n afterEach(() => {\n vi.useRealTimers();\n });\n\n it('create() returns a fresh session and registers it under its id', async () => {\n const s = await mgr.create();\n expect(s.id).toBe('s-0');\n expect(s.engine.id).toBe(0);\n expect(mgr.get(s.id)).toBe(s);\n });\n\n it('get() returns undefined for unknown ids', () => {\n expect(mgr.get('nope')).toBeUndefined();\n });\n\n it('touch() updates lastActivityAt so the session survives idle eviction', async () => {\n const a = await mgr.create();\n vi.advanceTimersByTime(50_000);\n mgr.touch(a.id);\n vi.advanceTimersByTime(50_000); // total 100s; without touch a would be evicted\n await mgr.evictIdle();\n expect(mgr.get(a.id)).toBe(a);\n expect(a.engine.disposed).toBe(false);\n });\n\n it('evictIdle() destroys sessions older than idleTimeoutMs', async () => {\n const a = await mgr.create();\n const b = await mgr.create();\n vi.advanceTimersByTime(30_000);\n mgr.touch(b.id); // bump b only\n vi.advanceTimersByTime(40_000); // a is now 70s idle, b only 40s\n await mgr.evictIdle();\n expect(mgr.get(a.id)).toBeUndefined();\n expect(a.engine.disposed).toBe(true);\n expect(mgr.get(b.id)).toBe(b);\n expect(b.engine.disposed).toBe(false);\n });\n\n it('create() throws SessionCapExceededError once maxSessions is reached', async () => {\n await mgr.create();\n await mgr.create();\n await mgr.create();\n await expect(mgr.create()).rejects.toBeInstanceOf(SessionCapExceededError);\n });\n\n it('delete() destroys a session and removes it', async () => {\n const a = await mgr.create();\n await mgr.delete(a.id);\n expect(mgr.get(a.id)).toBeUndefined();\n expect(a.engine.disposed).toBe(true);\n });\n\n it('delete() of an unknown id throws SessionNotFoundError', async () => {\n await expect(mgr.delete('nope')).rejects.toBeInstanceOf(\n SessionNotFoundError\n );\n });\n\n it('destroyAll() shuts down every active session', async () => {\n const a = await mgr.create();\n const b = await mgr.create();\n await mgr.destroyAll();\n expect(mgr.get(a.id)).toBeUndefined();\n expect(mgr.get(b.id)).toBeUndefined();\n expect(a.engine.disposed).toBe(true);\n expect(b.engine.disposed).toBe(true);\n });\n\n it('forwards a context object to the create callback', async () => {\n const seen: Array<string | undefined> = [];\n const mgr = new SessionManager<{ id: string }, { workspaceId: string }>({\n maxSessions: 10,\n idleTimeoutMs: 60_000,\n create: (ctx) => {\n seen.push(ctx?.workspaceId);\n return { id: ctx?.workspaceId ?? 'none' };\n },\n destroy: () => {}\n });\n await mgr.create({ workspaceId: 'u/a' });\n expect(seen).toEqual(['u/a']);\n });\n});\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=workspace-auth.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"workspace-auth.test.d.ts","sourceRoot":"","sources":["../../../../test/http/workspace-auth.test.ts"],"names":[],"mappings":""}
@@ -1,40 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { makeWorkspaceResolver, WorkspaceAuthError } from '../../src/http/workspace-auth.js';
3
- function cfg(partial) {
4
- return {
5
- cesdkLicense: 'x',
6
- buildId: 'test',
7
- port: 8080,
8
- maxEngines: 8,
9
- idleTimeoutMs: 900_000,
10
- logLevel: 'info',
11
- workspace: { backend: 'local', dir: '/data' },
12
- auth: { mode: 'header', header: 'X-Workspace-Id', ...partial },
13
- gateway: {}
14
- };
15
- }
16
- function fakeReq(headers) {
17
- return {
18
- header: (name) => headers[name.toLowerCase()]
19
- };
20
- }
21
- describe('makeWorkspaceResolver', () => {
22
- it('header mode returns the trusted header value (opaque, unmodified)', () => {
23
- const resolve = makeWorkspaceResolver(cfg({ mode: 'header', header: 'X-Workspace-Id' }));
24
- const req = fakeReq({ 'x-workspace-id': 'u/usr_8842' });
25
- expect(resolve(req, 'sess-1')).toBe('u/usr_8842');
26
- });
27
- it('header mode throws WorkspaceAuthError when the header is absent', () => {
28
- const resolve = makeWorkspaceResolver(cfg({ mode: 'header' }));
29
- expect(() => resolve(fakeReq({}), 'sess-1')).toThrow(WorkspaceAuthError);
30
- });
31
- it('session mode derives the ephemeral s/<sessionId> id', () => {
32
- const resolve = makeWorkspaceResolver(cfg({ mode: 'session' }));
33
- expect(resolve(fakeReq({}), 'sess-42')).toBe('s/sess-42');
34
- });
35
- it('single mode returns the fixed id', () => {
36
- const resolve = makeWorkspaceResolver(cfg({ mode: 'single', fixedWorkspaceId: 'acme' }));
37
- expect(resolve(fakeReq({}), 'sess-1')).toBe('acme');
38
- });
39
- });
40
- //# sourceMappingURL=workspace-auth.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"workspace-auth.test.js","sourceRoot":"","sources":["../../../../test/http/workspace-auth.test.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EACnB,MAAM,kCAAkC,CAAC;AAE1C,SAAS,GAAG,CAAC,OAAsC;IACjD,OAAO;QACL,YAAY,EAAE,GAAG;QACjB,OAAO,EAAE,MAAM;QACf,IAAI,EAAE,IAAI;QACV,UAAU,EAAE,CAAC;QACb,aAAa,EAAE,OAAO;QACtB,QAAQ,EAAE,MAAM;QAChB,SAAS,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE;QAC7C,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAG,OAAO,EAAE;QAC9D,OAAO,EAAE,EAAE;KACZ,CAAC;AACJ,CAAC;AAED,SAAS,OAAO,CAAC,OAA+B;IAC9C,OAAO;QACL,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;KAChC,CAAC;AAC1B,CAAC;AAED,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,OAAO,GAAG,qBAAqB,CACnC,GAAG,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAClD,CAAC;QACF,MAAM,GAAG,GAAG,OAAO,CAAC,EAAE,gBAAgB,EAAE,YAAY,EAAE,CAAC,CAAC;QACxD,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,MAAM,OAAO,GAAG,qBAAqB,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;QAC/D,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,OAAO,GAAG,qBAAqB,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;QAChE,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,OAAO,GAAG,qBAAqB,CACnC,GAAG,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAC,CAClD,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import type { Request } from 'express';\nimport { describe, expect, it } from 'vitest';\nimport type { ServerConfig } from '../../src/config.js';\nimport {\n makeWorkspaceResolver,\n WorkspaceAuthError\n} from '../../src/http/workspace-auth.js';\n\nfunction cfg(partial: Partial<ServerConfig['auth']>): ServerConfig {\n return {\n cesdkLicense: 'x',\n buildId: 'test',\n port: 8080,\n maxEngines: 8,\n idleTimeoutMs: 900_000,\n logLevel: 'info',\n workspace: { backend: 'local', dir: '/data' },\n auth: { mode: 'header', header: 'X-Workspace-Id', ...partial },\n gateway: {}\n };\n}\n\nfunction fakeReq(headers: Record<string, string>): Request {\n return {\n header: (name: string) => headers[name.toLowerCase()]\n } as unknown as Request;\n}\n\ndescribe('makeWorkspaceResolver', () => {\n it('header mode returns the trusted header value (opaque, unmodified)', () => {\n const resolve = makeWorkspaceResolver(\n cfg({ mode: 'header', header: 'X-Workspace-Id' })\n );\n const req = fakeReq({ 'x-workspace-id': 'u/usr_8842' });\n expect(resolve(req, 'sess-1')).toBe('u/usr_8842');\n });\n\n it('header mode throws WorkspaceAuthError when the header is absent', () => {\n const resolve = makeWorkspaceResolver(cfg({ mode: 'header' }));\n expect(() => resolve(fakeReq({}), 'sess-1')).toThrow(WorkspaceAuthError);\n });\n\n it('session mode derives the ephemeral s/<sessionId> id', () => {\n const resolve = makeWorkspaceResolver(cfg({ mode: 'session' }));\n expect(resolve(fakeReq({}), 'sess-42')).toBe('s/sess-42');\n });\n\n it('single mode returns the fixed id', () => {\n const resolve = makeWorkspaceResolver(\n cfg({ mode: 'single', fixedWorkspaceId: 'acme' })\n );\n expect(resolve(fakeReq({}), 'sess-1')).toBe('acme');\n });\n});\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=mount.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mount.test.d.ts","sourceRoot":"","sources":["../../../../test/metrics/mount.test.ts"],"names":[],"mappings":""}
@@ -1,59 +0,0 @@
1
- import express from 'express';
2
- import request from 'supertest';
3
- import { describe, expect, it } from 'vitest';
4
- import { mountMetricsEndpoints } from '../../src/metrics/mount.js';
5
- import { MetricsRecorder } from '../../src/metrics/recorder.js';
6
- describe('mountMetricsEndpoints', () => {
7
- it('GET /metrics returns the merged snapshot', async () => {
8
- const recorder = new MetricsRecorder();
9
- recorder.record({ tool: 'edit', durationMs: 12, ok: true });
10
- recorder.sampleMemory();
11
- const app = express();
12
- mountMetricsEndpoints(app, {
13
- recorder,
14
- maxSessions: 8,
15
- activeSessions: () => 2
16
- });
17
- const res = await request(app).get('/metrics');
18
- expect(res.status).toBe(200);
19
- expect(res.body.activeSessions).toBe(2);
20
- expect(res.body.maxSessions).toBe(8);
21
- expect(typeof res.body.uptimeMs).toBe('number');
22
- expect(res.body.tools.find((t) => t.tool === 'edit')).toBeDefined();
23
- expect(res.body.memory).not.toBeNull();
24
- expect(Array.isArray(res.body.recent)).toBe(true);
25
- });
26
- it('reads activeSessions live at request time', async () => {
27
- const recorder = new MetricsRecorder();
28
- let live = 0;
29
- const app = express();
30
- mountMetricsEndpoints(app, {
31
- recorder,
32
- maxSessions: 4,
33
- activeSessions: () => live
34
- });
35
- live = 3;
36
- const res = await request(app).get('/metrics');
37
- expect(res.body.activeSessions).toBe(3);
38
- });
39
- it('serves the dashboard SPA at /dashboard/ with the metrics URL injected', async () => {
40
- const recorder = new MetricsRecorder();
41
- const app = express();
42
- mountMetricsEndpoints(app, {
43
- recorder,
44
- maxSessions: 8,
45
- activeSessions: () => 0
46
- });
47
- const res = await request(app).get('/dashboard/');
48
- expect(res.status).toBe(200);
49
- expect(res.type).toBe('text/html');
50
- expect(res.text).toContain('/metrics');
51
- expect(res.text).not.toContain('{{METRICS_URL}}');
52
- });
53
- it('does not mount /metrics when the mounter is not called (gating)', async () => {
54
- const app = express();
55
- const res = await request(app).get('/metrics');
56
- expect(res.status).toBe(404);
57
- });
58
- });
59
- //# sourceMappingURL=mount.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mount.test.js","sourceRoot":"","sources":["../../../../test/metrics/mount.test.ts"],"names":[],"mappings":"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","sourcesContent":["import express from 'express';\nimport request from 'supertest';\nimport { describe, expect, it } from 'vitest';\nimport { mountMetricsEndpoints } from '../../src/metrics/mount.js';\nimport { MetricsRecorder } from '../../src/metrics/recorder.js';\n\ndescribe('mountMetricsEndpoints', () => {\n it('GET /metrics returns the merged snapshot', async () => {\n const recorder = new MetricsRecorder();\n recorder.record({ tool: 'edit', durationMs: 12, ok: true });\n recorder.sampleMemory();\n const app = express();\n mountMetricsEndpoints(app, {\n recorder,\n maxSessions: 8,\n activeSessions: () => 2\n });\n const res = await request(app).get('/metrics');\n expect(res.status).toBe(200);\n expect(res.body.activeSessions).toBe(2);\n expect(res.body.maxSessions).toBe(8);\n expect(typeof res.body.uptimeMs).toBe('number');\n expect(\n res.body.tools.find((t: { tool: string }) => t.tool === 'edit')\n ).toBeDefined();\n expect(res.body.memory).not.toBeNull();\n expect(Array.isArray(res.body.recent)).toBe(true);\n });\n\n it('reads activeSessions live at request time', async () => {\n const recorder = new MetricsRecorder();\n let live = 0;\n const app = express();\n mountMetricsEndpoints(app, {\n recorder,\n maxSessions: 4,\n activeSessions: () => live\n });\n live = 3;\n const res = await request(app).get('/metrics');\n expect(res.body.activeSessions).toBe(3);\n });\n\n it('serves the dashboard SPA at /dashboard/ with the metrics URL injected', async () => {\n const recorder = new MetricsRecorder();\n const app = express();\n mountMetricsEndpoints(app, {\n recorder,\n maxSessions: 8,\n activeSessions: () => 0\n });\n const res = await request(app).get('/dashboard/');\n expect(res.status).toBe(200);\n expect(res.type).toBe('text/html');\n expect(res.text).toContain('/metrics');\n expect(res.text).not.toContain('{{METRICS_URL}}');\n });\n\n it('does not mount /metrics when the mounter is not called (gating)', async () => {\n const app = express();\n const res = await request(app).get('/metrics');\n expect(res.status).toBe(404);\n });\n});\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=recorder.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"recorder.test.d.ts","sourceRoot":"","sources":["../../../../test/metrics/recorder.test.ts"],"names":[],"mappings":""}
@@ -1,118 +0,0 @@
1
- import { afterEach, describe, expect, it, vi } from 'vitest';
2
- import { MetricsRecorder } from '../../src/metrics/recorder.js';
3
- describe('MetricsRecorder.record + snapshot', () => {
4
- it('aggregates count/errorCount and min/max/mean from the sample', () => {
5
- const r = new MetricsRecorder();
6
- r.record({ tool: 'edit', durationMs: 10, ok: true });
7
- r.record({ tool: 'edit', durationMs: 30, ok: false });
8
- r.record({ tool: 'edit', durationMs: 20, ok: true });
9
- const edit = r.snapshot().tools.find((t) => t.tool === 'edit');
10
- expect(edit).toBeDefined();
11
- expect(edit.count).toBe(3);
12
- expect(edit.errorCount).toBe(1);
13
- expect(edit.min).toBe(10);
14
- expect(edit.max).toBe(30);
15
- expect(edit.mean).toBe(20);
16
- });
17
- it('computes p50/p95 via nearest-rank over the sample', () => {
18
- const r = new MetricsRecorder();
19
- for (const d of [10, 20, 30, 40, 50, 60, 70, 80, 90, 100])
20
- r.record({ tool: 'x', durationMs: d, ok: true });
21
- const x = r.snapshot().tools.find((t) => t.tool === 'x');
22
- // nearest-rank: p50 → idx ceil(0.5*10)-1 = 4 → 50; p95 → idx 9 → 100
23
- expect(x.p50).toBe(50);
24
- expect(x.p95).toBe(100);
25
- });
26
- it('separates aggregates by tool name', () => {
27
- const r = new MetricsRecorder();
28
- r.record({ tool: 'edit', durationMs: 5, ok: true });
29
- r.record({ tool: 'export', durationMs: 7, ok: true });
30
- expect(r
31
- .snapshot()
32
- .tools.map((t) => t.tool)
33
- .sort()).toEqual(['edit', 'export']);
34
- });
35
- it('evicts oldest recent records beyond recentLimit', () => {
36
- const r = new MetricsRecorder({ recentLimit: 3 });
37
- for (let i = 0; i < 5; i++)
38
- r.record({ tool: 't', durationMs: i, ok: true });
39
- const recent = r.snapshot().recent;
40
- expect(recent).toHaveLength(3);
41
- // newest-last ring: durations 2,3,4 survive
42
- expect(recent.map((x) => x.durationMs)).toEqual([2, 3, 4]);
43
- });
44
- it('bounds the per-tool duration sample to sampleSize (most-recent wins)', () => {
45
- const r = new MetricsRecorder({ sampleSize: 2 });
46
- r.record({ tool: 't', durationMs: 1000, ok: true });
47
- r.record({ tool: 't', durationMs: 1, ok: true });
48
- r.record({ tool: 't', durationMs: 2, ok: true });
49
- const t = r.snapshot().tools.find((x) => x.tool === 't');
50
- // count still counts every call…
51
- expect(t.count).toBe(3);
52
- // …but min/max/percentiles come from the bounded sample [1, 2]
53
- expect(t.min).toBe(1);
54
- expect(t.max).toBe(2);
55
- expect(t.p95).toBe(2);
56
- expect(t.p50).toBe(1);
57
- });
58
- it('snapshot has the documented shape', () => {
59
- const r = new MetricsRecorder();
60
- r.record({ tool: 't', durationMs: 1, ok: true });
61
- const snap = r.snapshot();
62
- expect(snap).toHaveProperty('tools');
63
- expect(snap).toHaveProperty('recent');
64
- expect(snap).toHaveProperty('memory');
65
- expect(Array.isArray(snap.tools)).toBe(true);
66
- expect(Array.isArray(snap.recent)).toBe(true);
67
- });
68
- it('recent records carry tool, durationMs, ok, ts', () => {
69
- const r = new MetricsRecorder();
70
- r.record({ tool: 'edit', durationMs: 12, ok: false });
71
- const rec = r.snapshot().recent[0];
72
- expect(rec.tool).toBe('edit');
73
- expect(rec.durationMs).toBe(12);
74
- expect(rec.ok).toBe(false);
75
- expect(typeof rec.ts).toBe('number');
76
- });
77
- it('memory is null before any sample, populated after sampleMemory()', () => {
78
- const r = new MetricsRecorder();
79
- expect(r.snapshot().memory).toBeNull();
80
- r.sampleMemory();
81
- const mem = r.snapshot().memory;
82
- expect(mem).not.toBeNull();
83
- expect(typeof mem.rss).toBe('number');
84
- expect(typeof mem.heapUsed).toBe('number');
85
- expect(typeof mem.external).toBe('number');
86
- expect(typeof mem.arrayBuffers).toBe('number');
87
- });
88
- });
89
- describe('MetricsRecorder.start/stop', () => {
90
- afterEach(() => vi.useRealTimers());
91
- it('start() seeds an immediate memory sample', () => {
92
- const r = new MetricsRecorder();
93
- r.start();
94
- expect(r.snapshot().memory).not.toBeNull();
95
- r.stop();
96
- });
97
- it('start() samples memory on the interval', () => {
98
- vi.useFakeTimers();
99
- const r = new MetricsRecorder({ memorySampleMs: 1000 });
100
- const spy = vi.spyOn(r, 'sampleMemory');
101
- r.start(); // one immediate seed
102
- expect(spy).toHaveBeenCalledTimes(1);
103
- vi.advanceTimersByTime(3000);
104
- expect(spy).toHaveBeenCalledTimes(4); // seed + 3 ticks
105
- r.stop();
106
- });
107
- it('stop() is idempotent and clears the timer', () => {
108
- vi.useFakeTimers();
109
- const r = new MetricsRecorder({ memorySampleMs: 1000 });
110
- const spy = vi.spyOn(r, 'sampleMemory');
111
- r.start();
112
- r.stop();
113
- r.stop(); // no throw
114
- vi.advanceTimersByTime(5000);
115
- expect(spy).toHaveBeenCalledTimes(1); // only the seed; no ticks after stop
116
- });
117
- });
118
- //# sourceMappingURL=recorder.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"recorder.test.js","sourceRoot":"","sources":["../../../../test/metrics/recorder.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { afterEach, describe, expect, it, vi } from 'vitest';\nimport { MetricsRecorder } from '../../src/metrics/recorder.js';\n\ndescribe('MetricsRecorder.record + snapshot', () => {\n it('aggregates count/errorCount and min/max/mean from the sample', () => {\n const r = new MetricsRecorder();\n r.record({ tool: 'edit', durationMs: 10, ok: true });\n r.record({ tool: 'edit', durationMs: 30, ok: false });\n r.record({ tool: 'edit', durationMs: 20, ok: true });\n const edit = r.snapshot().tools.find((t) => t.tool === 'edit');\n expect(edit).toBeDefined();\n expect(edit!.count).toBe(3);\n expect(edit!.errorCount).toBe(1);\n expect(edit!.min).toBe(10);\n expect(edit!.max).toBe(30);\n expect(edit!.mean).toBe(20);\n });\n\n it('computes p50/p95 via nearest-rank over the sample', () => {\n const r = new MetricsRecorder();\n for (const d of [10, 20, 30, 40, 50, 60, 70, 80, 90, 100])\n r.record({ tool: 'x', durationMs: d, ok: true });\n const x = r.snapshot().tools.find((t) => t.tool === 'x')!;\n // nearest-rank: p50 → idx ceil(0.5*10)-1 = 4 → 50; p95 → idx 9 → 100\n expect(x.p50).toBe(50);\n expect(x.p95).toBe(100);\n });\n\n it('separates aggregates by tool name', () => {\n const r = new MetricsRecorder();\n r.record({ tool: 'edit', durationMs: 5, ok: true });\n r.record({ tool: 'export', durationMs: 7, ok: true });\n expect(\n r\n .snapshot()\n .tools.map((t) => t.tool)\n .sort()\n ).toEqual(['edit', 'export']);\n });\n\n it('evicts oldest recent records beyond recentLimit', () => {\n const r = new MetricsRecorder({ recentLimit: 3 });\n for (let i = 0; i < 5; i++)\n r.record({ tool: 't', durationMs: i, ok: true });\n const recent = r.snapshot().recent;\n expect(recent).toHaveLength(3);\n // newest-last ring: durations 2,3,4 survive\n expect(recent.map((x) => x.durationMs)).toEqual([2, 3, 4]);\n });\n\n it('bounds the per-tool duration sample to sampleSize (most-recent wins)', () => {\n const r = new MetricsRecorder({ sampleSize: 2 });\n r.record({ tool: 't', durationMs: 1000, ok: true });\n r.record({ tool: 't', durationMs: 1, ok: true });\n r.record({ tool: 't', durationMs: 2, ok: true });\n const t = r.snapshot().tools.find((x) => x.tool === 't')!;\n // count still counts every call…\n expect(t.count).toBe(3);\n // …but min/max/percentiles come from the bounded sample [1, 2]\n expect(t.min).toBe(1);\n expect(t.max).toBe(2);\n expect(t.p95).toBe(2);\n expect(t.p50).toBe(1);\n });\n\n it('snapshot has the documented shape', () => {\n const r = new MetricsRecorder();\n r.record({ tool: 't', durationMs: 1, ok: true });\n const snap = r.snapshot();\n expect(snap).toHaveProperty('tools');\n expect(snap).toHaveProperty('recent');\n expect(snap).toHaveProperty('memory');\n expect(Array.isArray(snap.tools)).toBe(true);\n expect(Array.isArray(snap.recent)).toBe(true);\n });\n\n it('recent records carry tool, durationMs, ok, ts', () => {\n const r = new MetricsRecorder();\n r.record({ tool: 'edit', durationMs: 12, ok: false });\n const rec = r.snapshot().recent[0];\n expect(rec.tool).toBe('edit');\n expect(rec.durationMs).toBe(12);\n expect(rec.ok).toBe(false);\n expect(typeof rec.ts).toBe('number');\n });\n\n it('memory is null before any sample, populated after sampleMemory()', () => {\n const r = new MetricsRecorder();\n expect(r.snapshot().memory).toBeNull();\n r.sampleMemory();\n const mem = r.snapshot().memory;\n expect(mem).not.toBeNull();\n expect(typeof mem!.rss).toBe('number');\n expect(typeof mem!.heapUsed).toBe('number');\n expect(typeof mem!.external).toBe('number');\n expect(typeof mem!.arrayBuffers).toBe('number');\n });\n});\n\ndescribe('MetricsRecorder.start/stop', () => {\n afterEach(() => vi.useRealTimers());\n\n it('start() seeds an immediate memory sample', () => {\n const r = new MetricsRecorder();\n r.start();\n expect(r.snapshot().memory).not.toBeNull();\n r.stop();\n });\n\n it('start() samples memory on the interval', () => {\n vi.useFakeTimers();\n const r = new MetricsRecorder({ memorySampleMs: 1000 });\n const spy = vi.spyOn(r, 'sampleMemory');\n r.start(); // one immediate seed\n expect(spy).toHaveBeenCalledTimes(1);\n vi.advanceTimersByTime(3000);\n expect(spy).toHaveBeenCalledTimes(4); // seed + 3 ticks\n r.stop();\n });\n\n it('stop() is idempotent and clears the timer', () => {\n vi.useFakeTimers();\n const r = new MetricsRecorder({ memorySampleMs: 1000 });\n const spy = vi.spyOn(r, 'sampleMemory');\n r.start();\n r.stop();\n r.stop(); // no throw\n vi.advanceTimersByTime(5000);\n expect(spy).toHaveBeenCalledTimes(1); // only the seed; no ticks after stop\n });\n});\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=hash.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"hash.test.d.ts","sourceRoot":"","sources":["../../../../test/revisions/hash.test.ts"],"names":[],"mappings":""}
@@ -1,33 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { revisionId } from '../../src/revisions/hash.js';
3
- describe('revisionId', () => {
4
- it('derives a 12-hex-char id', async () => {
5
- expect(await revisionId({ scene: 'abc', parent: null })).toMatch(/^[0-9a-f]{12}$/);
6
- });
7
- it('is deterministic', async () => {
8
- const a = await revisionId({
9
- scene: 'abc',
10
- parent: 'deadbeef',
11
- note: 'fix'
12
- });
13
- const b = await revisionId({
14
- scene: 'abc',
15
- parent: 'deadbeef',
16
- note: 'fix'
17
- });
18
- expect(a).toBe(b);
19
- });
20
- it('differs when scene differs', async () => {
21
- expect(await revisionId({ scene: 'abc', parent: null })).not.toBe(await revisionId({ scene: 'abd', parent: null }));
22
- });
23
- it('differs when parent differs', async () => {
24
- expect(await revisionId({ scene: 'abc', parent: null })).not.toBe(await revisionId({ scene: 'abc', parent: '0000' }));
25
- });
26
- it('differs when note differs', async () => {
27
- expect(await revisionId({ scene: 'abc', parent: null, note: 'v1' })).not.toBe(await revisionId({ scene: 'abc', parent: null, note: 'v2' }));
28
- });
29
- it('treats missing note as empty', async () => {
30
- expect(await revisionId({ scene: 'abc', parent: null, note: '' })).toBe(await revisionId({ scene: 'abc', parent: null }));
31
- });
32
- });
33
- //# sourceMappingURL=hash.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"hash.test.js","sourceRoot":"","sources":["../../../../test/revisions/hash.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAEzD,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,EAAE,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,CAAC,MAAM,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAC9D,gBAAgB,CACjB,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,kBAAkB,EAAE,KAAK,IAAI,EAAE;QAChC,MAAM,CAAC,GAAG,MAAM,UAAU,CAAC;YACzB,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,UAAU;YAClB,IAAI,EAAE,KAAK;SACZ,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,UAAU,CAAC;YACzB,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,UAAU;YAClB,IAAI,EAAE,KAAK;SACZ,CAAC,CAAC;QACH,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,CAAC,MAAM,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAC/D,MAAM,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CACjD,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;QAC3C,MAAM,CAAC,MAAM,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAC/D,MAAM,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CACnD,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;QACzC,MAAM,CACJ,MAAM,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAC7D,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;QAC5C,MAAM,CAAC,MAAM,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CACrE,MAAM,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CACjD,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { describe, expect, it } from 'vitest';\nimport { revisionId } from '../../src/revisions/hash.js';\n\ndescribe('revisionId', () => {\n it('derives a 12-hex-char id', async () => {\n expect(await revisionId({ scene: 'abc', parent: null })).toMatch(\n /^[0-9a-f]{12}$/\n );\n });\n it('is deterministic', async () => {\n const a = await revisionId({\n scene: 'abc',\n parent: 'deadbeef',\n note: 'fix'\n });\n const b = await revisionId({\n scene: 'abc',\n parent: 'deadbeef',\n note: 'fix'\n });\n expect(a).toBe(b);\n });\n it('differs when scene differs', async () => {\n expect(await revisionId({ scene: 'abc', parent: null })).not.toBe(\n await revisionId({ scene: 'abd', parent: null })\n );\n });\n it('differs when parent differs', async () => {\n expect(await revisionId({ scene: 'abc', parent: null })).not.toBe(\n await revisionId({ scene: 'abc', parent: '0000' })\n );\n });\n it('differs when note differs', async () => {\n expect(\n await revisionId({ scene: 'abc', parent: null, note: 'v1' })\n ).not.toBe(await revisionId({ scene: 'abc', parent: null, note: 'v2' }));\n });\n it('treats missing note as empty', async () => {\n expect(await revisionId({ scene: 'abc', parent: null, note: '' })).toBe(\n await revisionId({ scene: 'abc', parent: null })\n );\n });\n});\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=store.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"store.test.d.ts","sourceRoot":"","sources":["../../../../test/revisions/store.test.ts"],"names":[],"mappings":""}