@scalar/workspace-store 0.40.2 → 0.40.4

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 (368) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/client.d.ts +7 -2
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +820 -681
  5. package/dist/entities/auth/index.js +96 -101
  6. package/dist/entities/auth/schema.d.ts +10 -0
  7. package/dist/entities/auth/schema.d.ts.map +1 -1
  8. package/dist/entities/auth/schema.js +42 -116
  9. package/dist/entities/history/index.js +80 -60
  10. package/dist/entities/history/schema.js +94 -88
  11. package/dist/events/bus.js +146 -93
  12. package/dist/events/definitions/analytics.js +1 -1
  13. package/dist/events/definitions/auth.js +1 -1
  14. package/dist/events/definitions/common.js +1 -1
  15. package/dist/events/definitions/cookie.js +1 -1
  16. package/dist/events/definitions/document.js +1 -1
  17. package/dist/events/definitions/environment.js +1 -1
  18. package/dist/events/definitions/hooks.js +1 -1
  19. package/dist/events/definitions/index.js +1 -1
  20. package/dist/events/definitions/meta.js +1 -1
  21. package/dist/events/definitions/operation.js +1 -1
  22. package/dist/events/definitions/server.js +1 -1
  23. package/dist/events/definitions/tabs.js +1 -1
  24. package/dist/events/definitions/tag.js +1 -1
  25. package/dist/events/definitions/ui.js +1 -1
  26. package/dist/events/definitions/workspace.js +1 -1
  27. package/dist/events/index.js +3 -9
  28. package/dist/events/listeners.js +20 -22
  29. package/dist/events/old-definitions.js +15 -12
  30. package/dist/helpers/deep-clone.js +33 -17
  31. package/dist/helpers/detect-changes-proxy.js +95 -57
  32. package/dist/helpers/general.js +78 -23
  33. package/dist/helpers/generate-unique-value.js +77 -45
  34. package/dist/helpers/get-fetch.js +12 -10
  35. package/dist/helpers/get-resolved-ref.js +11 -10
  36. package/dist/helpers/is-non-optional-security-requirement.js +3 -6
  37. package/dist/helpers/merge-object.js +71 -30
  38. package/dist/helpers/overrides-proxy.js +98 -58
  39. package/dist/helpers/unpack-proxy.js +60 -58
  40. package/dist/mutators/auth.js +358 -230
  41. package/dist/mutators/cookie.js +59 -42
  42. package/dist/mutators/document.js +104 -66
  43. package/dist/mutators/environment.js +97 -72
  44. package/dist/mutators/helpers.js +9 -13
  45. package/dist/mutators/index.js +62 -49
  46. package/dist/mutators/operation/body.js +88 -57
  47. package/dist/mutators/operation/extensions.js +20 -12
  48. package/dist/mutators/operation/helpers/fetch-request-to-har.js +144 -107
  49. package/dist/mutators/operation/helpers/fetch-response-to-har.js +143 -95
  50. package/dist/mutators/operation/helpers/get-parameter-position.js +12 -12
  51. package/dist/mutators/operation/helpers/har-to-operation.js +169 -132
  52. package/dist/mutators/operation/helpers/sync-path-parameters.js +109 -60
  53. package/dist/mutators/operation/history.js +60 -64
  54. package/dist/mutators/operation/index.js +25 -49
  55. package/dist/mutators/operation/operation.js +349 -240
  56. package/dist/mutators/operation/parameters.js +157 -93
  57. package/dist/mutators/server.js +213 -152
  58. package/dist/mutators/tabs.js +173 -130
  59. package/dist/mutators/tag.js +131 -97
  60. package/dist/mutators/workspace.js +72 -42
  61. package/dist/navigation/get-navigation-options.js +97 -84
  62. package/dist/navigation/helpers/get-openapi-object.js +46 -29
  63. package/dist/navigation/helpers/get-operation-entries.js +72 -32
  64. package/dist/navigation/helpers/get-parent-entry.js +16 -12
  65. package/dist/navigation/helpers/get-tag-entries.js +56 -29
  66. package/dist/navigation/helpers/get-tag.js +22 -23
  67. package/dist/navigation/helpers/get-x-keys.js +13 -9
  68. package/dist/navigation/helpers/traverse-description.js +90 -72
  69. package/dist/navigation/helpers/traverse-document.js +111 -98
  70. package/dist/navigation/helpers/traverse-examples.js +35 -31
  71. package/dist/navigation/helpers/traverse-paths.js +118 -106
  72. package/dist/navigation/helpers/traverse-schemas.js +65 -64
  73. package/dist/navigation/helpers/traverse-tags.js +158 -129
  74. package/dist/navigation/helpers/traverse-webhooks.js +96 -90
  75. package/dist/navigation/helpers/update-order-ids.js +59 -51
  76. package/dist/navigation/helpers/utils.js +71 -21
  77. package/dist/navigation/index.js +5 -13
  78. package/dist/navigation/types.js +1 -1
  79. package/dist/persistence/index.js +283 -285
  80. package/dist/persistence/indexdb.js +263 -126
  81. package/dist/plugins/bundler/helpers.js +21 -12
  82. package/dist/plugins/bundler/index.d.ts +7 -0
  83. package/dist/plugins/bundler/index.d.ts.map +1 -1
  84. package/dist/plugins/bundler/index.js +305 -171
  85. package/dist/plugins/client/index.js +1 -5
  86. package/dist/plugins/client/persistence.js +95 -90
  87. package/dist/resolve.js +18 -25
  88. package/dist/schemas/compose.js +6 -7
  89. package/dist/schemas/extensions/document/x-internal.js +3 -7
  90. package/dist/schemas/extensions/document/x-scalar-environments.js +16 -22
  91. package/dist/schemas/extensions/document/x-scalar-icon.js +3 -7
  92. package/dist/schemas/extensions/document/x-scalar-ignore.js +3 -7
  93. package/dist/schemas/extensions/document/x-scalar-is-dirty.js +21 -8
  94. package/dist/schemas/extensions/document/x-scalar-original-document-hash.js +17 -8
  95. package/dist/schemas/extensions/document/x-scalar-registry-meta.js +15 -21
  96. package/dist/schemas/extensions/document/x-scalar-sdk-installation.js +5 -13
  97. package/dist/schemas/extensions/document/x-scalar-watch-mode.js +4 -8
  98. package/dist/schemas/extensions/document/x-tags.js +3 -7
  99. package/dist/schemas/extensions/example/x-disabled.js +17 -7
  100. package/dist/schemas/extensions/general/x-scalar-active-environment.js +4 -7
  101. package/dist/schemas/extensions/general/x-scalar-cookies.js +9 -14
  102. package/dist/schemas/extensions/general/x-scalar-order.js +8 -7
  103. package/dist/schemas/extensions/operation/index.js +4 -23
  104. package/dist/schemas/extensions/operation/x-badge.js +42 -50
  105. package/dist/schemas/extensions/operation/x-code-samples.js +8 -12
  106. package/dist/schemas/extensions/operation/x-draft-examples.js +3 -7
  107. package/dist/schemas/extensions/operation/x-post-response.js +18 -7
  108. package/dist/schemas/extensions/operation/x-scalar-disable-parameters.js +57 -13
  109. package/dist/schemas/extensions/operation/x-scalar-selected-content-type.js +9 -7
  110. package/dist/schemas/extensions/operation/x-scalar-stability.js +15 -14
  111. package/dist/schemas/extensions/parameter/x-global.js +12 -7
  112. package/dist/schemas/extensions/schema/x-additional-properties-name.js +10 -7
  113. package/dist/schemas/extensions/schema/x-enum-descriptions.js +17 -12
  114. package/dist/schemas/extensions/schema/x-enum-varnames.js +21 -8
  115. package/dist/schemas/extensions/schema/x-examples.js +3 -7
  116. package/dist/schemas/extensions/schema/x-variable.js +3 -7
  117. package/dist/schemas/extensions/security/index.js +1 -1
  118. package/dist/schemas/extensions/security/x-default-scopes.js +16 -7
  119. package/dist/schemas/extensions/security/x-scalar-credentials-location.js +16 -7
  120. package/dist/schemas/extensions/security/x-scalar-security-body.js +14 -7
  121. package/dist/schemas/extensions/security/x-scalar-security-query.js +14 -7
  122. package/dist/schemas/extensions/security/x-scalar-security-secrets.js +66 -37
  123. package/dist/schemas/extensions/security/x-tokenName.js +11 -7
  124. package/dist/schemas/extensions/security/x-use-pkce.js +6 -10
  125. package/dist/schemas/extensions/server/x-scalar-selected-server.js +3 -7
  126. package/dist/schemas/extensions/tag/index.js +1 -1
  127. package/dist/schemas/extensions/tag/x-display-name.js +11 -7
  128. package/dist/schemas/extensions/tag/x-tag-groups.js +13 -15
  129. package/dist/schemas/extensions/workspace/index.js +2 -11
  130. package/dist/schemas/extensions/workspace/x-scalar-active-proxy.js +13 -7
  131. package/dist/schemas/extensions/workspace/x-scalar-tabs.js +15 -13
  132. package/dist/schemas/extensions.js +11 -15
  133. package/dist/schemas/inmemory-workspace.d.ts +6 -0
  134. package/dist/schemas/inmemory-workspace.d.ts.map +1 -1
  135. package/dist/schemas/inmemory-workspace.js +13 -21
  136. package/dist/schemas/navigation.js +48 -85
  137. package/dist/schemas/reference-config/appearance.js +15 -22
  138. package/dist/schemas/reference-config/features.js +14 -21
  139. package/dist/schemas/reference-config/index.d.ts +2 -0
  140. package/dist/schemas/reference-config/index.d.ts.map +1 -1
  141. package/dist/schemas/reference-config/index.js +42 -44
  142. package/dist/schemas/reference-config/meta.js +11 -18
  143. package/dist/schemas/reference-config/routing.js +7 -14
  144. package/dist/schemas/reference-config/settings.d.ts +2 -0
  145. package/dist/schemas/reference-config/settings.d.ts.map +1 -1
  146. package/dist/schemas/reference-config/settings.js +10 -17
  147. package/dist/schemas/typebox-coerce.js +23 -6
  148. package/dist/schemas/v3.1/strict/callback.js +6 -12
  149. package/dist/schemas/v3.1/strict/components.js +26 -48
  150. package/dist/schemas/v3.1/strict/contact.js +9 -12
  151. package/dist/schemas/v3.1/strict/discriminator.js +11 -10
  152. package/dist/schemas/v3.1/strict/encoding.js +15 -12
  153. package/dist/schemas/v3.1/strict/example.js +11 -13
  154. package/dist/schemas/v3.1/strict/external-documentation.js +7 -10
  155. package/dist/schemas/v3.1/strict/header.js +27 -28
  156. package/dist/schemas/v3.1/strict/info.js +10 -16
  157. package/dist/schemas/v3.1/strict/license.js +9 -12
  158. package/dist/schemas/v3.1/strict/link.js +22 -19
  159. package/dist/schemas/v3.1/strict/media-type.js +17 -16
  160. package/dist/schemas/v3.1/strict/oauth-flow.js +28 -62
  161. package/dist/schemas/v3.1/strict/oauthflows.js +14 -20
  162. package/dist/schemas/v3.1/strict/openapi-document.d.ts +70 -0
  163. package/dist/schemas/v3.1/strict/openapi-document.d.ts.map +1 -1
  164. package/dist/schemas/v3.1/strict/openapi-document.js +126 -210
  165. package/dist/schemas/v3.1/strict/operation.js +16 -43
  166. package/dist/schemas/v3.1/strict/parameter.d.ts +6 -0
  167. package/dist/schemas/v3.1/strict/parameter.d.ts.map +1 -1
  168. package/dist/schemas/v3.1/strict/parameter.js +29 -35
  169. package/dist/schemas/v3.1/strict/path-item.js +36 -40
  170. package/dist/schemas/v3.1/strict/paths.js +8 -11
  171. package/dist/schemas/v3.1/strict/ref-definitions.js +76 -100
  172. package/dist/schemas/v3.1/strict/reference.js +18 -21
  173. package/dist/schemas/v3.1/strict/request-body.js +8 -16
  174. package/dist/schemas/v3.1/strict/response.js +12 -16
  175. package/dist/schemas/v3.1/strict/responses.js +13 -11
  176. package/dist/schemas/v3.1/strict/schema.js +149 -157
  177. package/dist/schemas/v3.1/strict/security-requirement.js +13 -12
  178. package/dist/schemas/v3.1/strict/security-scheme.js +29 -41
  179. package/dist/schemas/v3.1/strict/server-variable.js +9 -12
  180. package/dist/schemas/v3.1/strict/server.js +10 -13
  181. package/dist/schemas/v3.1/strict/tag.js +11 -20
  182. package/dist/schemas/v3.1/strict/type-guards.js +20 -20
  183. package/dist/schemas/v3.1/strict/xml.js +17 -16
  184. package/dist/schemas/workspace-specification/index.js +11 -23
  185. package/dist/schemas/workspace-specification/info.js +4 -8
  186. package/dist/schemas/workspace.d.ts +6 -0
  187. package/dist/schemas/workspace.d.ts.map +1 -1
  188. package/dist/schemas/workspace.js +25 -51
  189. package/dist/schemas.js +2 -6
  190. package/dist/server.js +286 -176
  191. package/dist/workspace-plugin.js +1 -1
  192. package/package.json +13 -19
  193. package/dist/client.js.map +0 -7
  194. package/dist/entities/auth/index.js.map +0 -7
  195. package/dist/entities/auth/schema.js.map +0 -7
  196. package/dist/entities/history/index.js.map +0 -7
  197. package/dist/entities/history/schema.js.map +0 -7
  198. package/dist/events/bus.js.map +0 -7
  199. package/dist/events/definitions/analytics.js.map +0 -7
  200. package/dist/events/definitions/auth.js.map +0 -7
  201. package/dist/events/definitions/common.js.map +0 -7
  202. package/dist/events/definitions/cookie.js.map +0 -7
  203. package/dist/events/definitions/document.js.map +0 -7
  204. package/dist/events/definitions/environment.js.map +0 -7
  205. package/dist/events/definitions/hooks.js.map +0 -7
  206. package/dist/events/definitions/index.js.map +0 -7
  207. package/dist/events/definitions/meta.js.map +0 -7
  208. package/dist/events/definitions/operation.js.map +0 -7
  209. package/dist/events/definitions/server.js.map +0 -7
  210. package/dist/events/definitions/tabs.js.map +0 -7
  211. package/dist/events/definitions/tag.js.map +0 -7
  212. package/dist/events/definitions/ui.js.map +0 -7
  213. package/dist/events/definitions/workspace.js.map +0 -7
  214. package/dist/events/index.js.map +0 -7
  215. package/dist/events/listeners.js.map +0 -7
  216. package/dist/events/old-definitions.js.map +0 -7
  217. package/dist/helpers/apply-selective-updates.d.ts +0 -19
  218. package/dist/helpers/apply-selective-updates.d.ts.map +0 -1
  219. package/dist/helpers/apply-selective-updates.js +0 -37
  220. package/dist/helpers/apply-selective-updates.js.map +0 -7
  221. package/dist/helpers/deep-clone.js.map +0 -7
  222. package/dist/helpers/detect-changes-proxy.js.map +0 -7
  223. package/dist/helpers/general.js.map +0 -7
  224. package/dist/helpers/generate-unique-value.js.map +0 -7
  225. package/dist/helpers/get-fetch.js.map +0 -7
  226. package/dist/helpers/get-resolved-ref.js.map +0 -7
  227. package/dist/helpers/is-non-optional-security-requirement.js.map +0 -7
  228. package/dist/helpers/merge-object.js.map +0 -7
  229. package/dist/helpers/overrides-proxy.js.map +0 -7
  230. package/dist/helpers/unpack-proxy.js.map +0 -7
  231. package/dist/mutators/auth.js.map +0 -7
  232. package/dist/mutators/cookie.js.map +0 -7
  233. package/dist/mutators/document.js.map +0 -7
  234. package/dist/mutators/environment.js.map +0 -7
  235. package/dist/mutators/helpers.js.map +0 -7
  236. package/dist/mutators/index.js.map +0 -7
  237. package/dist/mutators/operation/body.js.map +0 -7
  238. package/dist/mutators/operation/extensions.js.map +0 -7
  239. package/dist/mutators/operation/helpers/fetch-request-to-har.js.map +0 -7
  240. package/dist/mutators/operation/helpers/fetch-response-to-har.js.map +0 -7
  241. package/dist/mutators/operation/helpers/get-parameter-position.js.map +0 -7
  242. package/dist/mutators/operation/helpers/har-to-operation.js.map +0 -7
  243. package/dist/mutators/operation/helpers/sync-path-parameters.js.map +0 -7
  244. package/dist/mutators/operation/history.js.map +0 -7
  245. package/dist/mutators/operation/index.js.map +0 -7
  246. package/dist/mutators/operation/operation.js.map +0 -7
  247. package/dist/mutators/operation/parameters.js.map +0 -7
  248. package/dist/mutators/server.js.map +0 -7
  249. package/dist/mutators/tabs.js.map +0 -7
  250. package/dist/mutators/tag.js.map +0 -7
  251. package/dist/mutators/workspace.js.map +0 -7
  252. package/dist/navigation/get-navigation-options.js.map +0 -7
  253. package/dist/navigation/helpers/get-openapi-object.js.map +0 -7
  254. package/dist/navigation/helpers/get-operation-entries.js.map +0 -7
  255. package/dist/navigation/helpers/get-parent-entry.js.map +0 -7
  256. package/dist/navigation/helpers/get-tag-entries.js.map +0 -7
  257. package/dist/navigation/helpers/get-tag.js.map +0 -7
  258. package/dist/navigation/helpers/get-x-keys.js.map +0 -7
  259. package/dist/navigation/helpers/traverse-description.js.map +0 -7
  260. package/dist/navigation/helpers/traverse-document.js.map +0 -7
  261. package/dist/navigation/helpers/traverse-examples.js.map +0 -7
  262. package/dist/navigation/helpers/traverse-paths.js.map +0 -7
  263. package/dist/navigation/helpers/traverse-schemas.js.map +0 -7
  264. package/dist/navigation/helpers/traverse-tags.js.map +0 -7
  265. package/dist/navigation/helpers/traverse-webhooks.js.map +0 -7
  266. package/dist/navigation/helpers/update-order-ids.js.map +0 -7
  267. package/dist/navigation/helpers/utils.js.map +0 -7
  268. package/dist/navigation/index.js.map +0 -7
  269. package/dist/navigation/types.js.map +0 -7
  270. package/dist/persistence/index.js.map +0 -7
  271. package/dist/persistence/indexdb.js.map +0 -7
  272. package/dist/plugins/bundler/helpers.js.map +0 -7
  273. package/dist/plugins/bundler/index.js.map +0 -7
  274. package/dist/plugins/client/index.js.map +0 -7
  275. package/dist/plugins/client/persistence.js.map +0 -7
  276. package/dist/resolve.js.map +0 -7
  277. package/dist/schemas/compose.js.map +0 -7
  278. package/dist/schemas/extensions/document/x-internal.js.map +0 -7
  279. package/dist/schemas/extensions/document/x-scalar-environments.js.map +0 -7
  280. package/dist/schemas/extensions/document/x-scalar-icon.js.map +0 -7
  281. package/dist/schemas/extensions/document/x-scalar-ignore.js.map +0 -7
  282. package/dist/schemas/extensions/document/x-scalar-is-dirty.js.map +0 -7
  283. package/dist/schemas/extensions/document/x-scalar-original-document-hash.js.map +0 -7
  284. package/dist/schemas/extensions/document/x-scalar-registry-meta.js.map +0 -7
  285. package/dist/schemas/extensions/document/x-scalar-sdk-installation.js.map +0 -7
  286. package/dist/schemas/extensions/document/x-scalar-watch-mode.js.map +0 -7
  287. package/dist/schemas/extensions/document/x-tags.js.map +0 -7
  288. package/dist/schemas/extensions/example/x-disabled.js.map +0 -7
  289. package/dist/schemas/extensions/general/x-scalar-active-environment.js.map +0 -7
  290. package/dist/schemas/extensions/general/x-scalar-cookies.js.map +0 -7
  291. package/dist/schemas/extensions/general/x-scalar-order.js.map +0 -7
  292. package/dist/schemas/extensions/operation/index.js.map +0 -7
  293. package/dist/schemas/extensions/operation/x-badge.js.map +0 -7
  294. package/dist/schemas/extensions/operation/x-code-samples.js.map +0 -7
  295. package/dist/schemas/extensions/operation/x-draft-examples.js.map +0 -7
  296. package/dist/schemas/extensions/operation/x-post-response.js.map +0 -7
  297. package/dist/schemas/extensions/operation/x-scalar-disable-parameters.js.map +0 -7
  298. package/dist/schemas/extensions/operation/x-scalar-selected-content-type.js.map +0 -7
  299. package/dist/schemas/extensions/operation/x-scalar-stability.js.map +0 -7
  300. package/dist/schemas/extensions/parameter/x-global.js.map +0 -7
  301. package/dist/schemas/extensions/schema/x-additional-properties-name.js.map +0 -7
  302. package/dist/schemas/extensions/schema/x-enum-descriptions.js.map +0 -7
  303. package/dist/schemas/extensions/schema/x-enum-varnames.js.map +0 -7
  304. package/dist/schemas/extensions/schema/x-examples.js.map +0 -7
  305. package/dist/schemas/extensions/schema/x-variable.js.map +0 -7
  306. package/dist/schemas/extensions/security/index.js.map +0 -7
  307. package/dist/schemas/extensions/security/x-default-scopes.js.map +0 -7
  308. package/dist/schemas/extensions/security/x-scalar-credentials-location.js.map +0 -7
  309. package/dist/schemas/extensions/security/x-scalar-security-body.js.map +0 -7
  310. package/dist/schemas/extensions/security/x-scalar-security-query.js.map +0 -7
  311. package/dist/schemas/extensions/security/x-scalar-security-secrets.js.map +0 -7
  312. package/dist/schemas/extensions/security/x-tokenName.js.map +0 -7
  313. package/dist/schemas/extensions/security/x-use-pkce.js.map +0 -7
  314. package/dist/schemas/extensions/server/x-scalar-selected-server.js.map +0 -7
  315. package/dist/schemas/extensions/tag/index.js.map +0 -7
  316. package/dist/schemas/extensions/tag/x-display-name.js.map +0 -7
  317. package/dist/schemas/extensions/tag/x-tag-groups.js.map +0 -7
  318. package/dist/schemas/extensions/workspace/index.js.map +0 -7
  319. package/dist/schemas/extensions/workspace/x-scalar-active-proxy.js.map +0 -7
  320. package/dist/schemas/extensions/workspace/x-scalar-tabs.js.map +0 -7
  321. package/dist/schemas/extensions.js.map +0 -7
  322. package/dist/schemas/inmemory-workspace.js.map +0 -7
  323. package/dist/schemas/navigation.js.map +0 -7
  324. package/dist/schemas/reference-config/appearance.js.map +0 -7
  325. package/dist/schemas/reference-config/features.js.map +0 -7
  326. package/dist/schemas/reference-config/index.js.map +0 -7
  327. package/dist/schemas/reference-config/meta.js.map +0 -7
  328. package/dist/schemas/reference-config/routing.js.map +0 -7
  329. package/dist/schemas/reference-config/settings.js.map +0 -7
  330. package/dist/schemas/typebox-coerce.js.map +0 -7
  331. package/dist/schemas/v3.1/strict/callback.js.map +0 -7
  332. package/dist/schemas/v3.1/strict/components.js.map +0 -7
  333. package/dist/schemas/v3.1/strict/contact.js.map +0 -7
  334. package/dist/schemas/v3.1/strict/discriminator.js.map +0 -7
  335. package/dist/schemas/v3.1/strict/encoding.js.map +0 -7
  336. package/dist/schemas/v3.1/strict/example.js.map +0 -7
  337. package/dist/schemas/v3.1/strict/external-documentation.js.map +0 -7
  338. package/dist/schemas/v3.1/strict/header.js.map +0 -7
  339. package/dist/schemas/v3.1/strict/info.js.map +0 -7
  340. package/dist/schemas/v3.1/strict/license.js.map +0 -7
  341. package/dist/schemas/v3.1/strict/link.js.map +0 -7
  342. package/dist/schemas/v3.1/strict/media-type.js.map +0 -7
  343. package/dist/schemas/v3.1/strict/oauth-flow.js.map +0 -7
  344. package/dist/schemas/v3.1/strict/oauthflows.js.map +0 -7
  345. package/dist/schemas/v3.1/strict/openapi-document.js.map +0 -7
  346. package/dist/schemas/v3.1/strict/operation.js.map +0 -7
  347. package/dist/schemas/v3.1/strict/parameter.js.map +0 -7
  348. package/dist/schemas/v3.1/strict/path-item.js.map +0 -7
  349. package/dist/schemas/v3.1/strict/paths.js.map +0 -7
  350. package/dist/schemas/v3.1/strict/ref-definitions.js.map +0 -7
  351. package/dist/schemas/v3.1/strict/reference.js.map +0 -7
  352. package/dist/schemas/v3.1/strict/request-body.js.map +0 -7
  353. package/dist/schemas/v3.1/strict/response.js.map +0 -7
  354. package/dist/schemas/v3.1/strict/responses.js.map +0 -7
  355. package/dist/schemas/v3.1/strict/schema.js.map +0 -7
  356. package/dist/schemas/v3.1/strict/security-requirement.js.map +0 -7
  357. package/dist/schemas/v3.1/strict/security-scheme.js.map +0 -7
  358. package/dist/schemas/v3.1/strict/server-variable.js.map +0 -7
  359. package/dist/schemas/v3.1/strict/server.js.map +0 -7
  360. package/dist/schemas/v3.1/strict/tag.js.map +0 -7
  361. package/dist/schemas/v3.1/strict/type-guards.js.map +0 -7
  362. package/dist/schemas/v3.1/strict/xml.js.map +0 -7
  363. package/dist/schemas/workspace-specification/index.js.map +0 -7
  364. package/dist/schemas/workspace-specification/info.js.map +0 -7
  365. package/dist/schemas/workspace.js.map +0 -7
  366. package/dist/schemas.js.map +0 -7
  367. package/dist/server.js.map +0 -7
  368. package/dist/workspace-plugin.js.map +0 -7
package/dist/client.js CHANGED
@@ -1,82 +1,136 @@
1
- import { getValueAtPath } from "@scalar/helpers/object/get-value-at-path";
2
- import { isObject } from "@scalar/helpers/object/is-object";
3
- import { preventPollution } from "@scalar/helpers/object/prevent-pollution";
4
- import { generateHash } from "@scalar/helpers/string/generate-hash";
5
- import { measureAsync, measureSync } from "@scalar/helpers/testing/measure";
6
- import { bundle } from "@scalar/json-magic/bundle";
7
- import { fetchUrls } from "@scalar/json-magic/bundle/plugins/browser";
8
- import { apply, diff, merge } from "@scalar/json-magic/diff";
9
- import { createMagicProxy, getRaw } from "@scalar/json-magic/magic-proxy";
10
- import { upgrade } from "@scalar/openapi-upgrader";
11
- import { Value } from "@scalar/typebox/value";
12
- import { reactive } from "vue";
13
- import YAML from "yaml";
14
- import { createAuthStore } from "./entities/auth/index.js";
15
- import { createHistoryStore } from "./entities/history/index.js";
16
- import { EXCLUDE_KEYS, applySelectiveUpdates } from "./helpers/apply-selective-updates.js";
17
- import { deepClone } from "./helpers/deep-clone.js";
18
- import { createDetectChangesProxy } from "./helpers/detect-changes-proxy.js";
19
- import { safeAssign } from "./helpers/general.js";
20
- import { getFetch } from "./helpers/get-fetch.js";
21
- import { mergeObjects } from "./helpers/merge-object.js";
22
- import { createOverridesProxy } from "./helpers/overrides-proxy.js";
23
- import { unpackProxyObject } from "./helpers/unpack-proxy.js";
24
- import { createNavigation } from "./navigation/index.js";
25
- import {
26
- externalValueResolver,
27
- loadingStatus,
28
- normalizeAuthSchemes,
29
- normalizeRefs,
30
- refsEverywhere,
31
- restoreOriginalRefs,
32
- syncPathParameters
33
- } from "./plugins/bundler/index.js";
34
- import { extensions } from "./schemas/extensions.js";
35
- import { coerceValue } from "./schemas/typebox-coerce.js";
36
- import {
37
- OpenAPIDocumentSchema as OpenAPIDocumentSchemaStrict
38
- } from "./schemas/v3.1/strict/openapi-document.js";
1
+ import { getValueAtPath } from '@scalar/helpers/object/get-value-at-path';
2
+ import { isObject } from '@scalar/helpers/object/is-object';
3
+ import { preventPollution } from '@scalar/helpers/object/prevent-pollution';
4
+ import { generateHash } from '@scalar/helpers/string/generate-hash';
5
+ import { measureAsync, measureSync } from '@scalar/helpers/testing/measure';
6
+ import { bundle } from '@scalar/json-magic/bundle';
7
+ import { fetchUrls } from '@scalar/json-magic/bundle/plugins/browser';
8
+ import { apply, diff, merge } from '@scalar/json-magic/diff';
9
+ import { createMagicProxy, getRaw } from '@scalar/json-magic/magic-proxy';
10
+ import { upgrade } from '@scalar/openapi-upgrader';
11
+ import { Value } from '@scalar/typebox/value';
12
+ import { reactive } from 'vue';
13
+ import YAML from 'yaml';
14
+ import { createAuthStore } from './entities/auth/index.js';
15
+ import { createHistoryStore } from './entities/history/index.js';
16
+ import { deepClone } from './helpers/deep-clone.js';
17
+ import { createDetectChangesProxy } from './helpers/detect-changes-proxy.js';
18
+ import { safeAssign } from './helpers/general.js';
19
+ import { getFetch } from './helpers/get-fetch.js';
20
+ import { mergeObjects } from './helpers/merge-object.js';
21
+ import { createOverridesProxy } from './helpers/overrides-proxy.js';
22
+ import { unpackProxyObject } from './helpers/unpack-proxy.js';
23
+ import { createNavigation } from './navigation/index.js';
24
+ import { externalValueResolver, loadingStatus, normalizeAuthSchemes, normalizeRefs, refsEverywhere, removeExtraScalarKeys, restoreOriginalRefs, syncPathParameters, } from './plugins/bundler/index.js';
25
+ import { extensions } from './schemas/extensions.js';
26
+ import { coerceValue } from './schemas/typebox-coerce.js';
27
+ import { OpenAPIDocumentSchema as OpenAPIDocumentSchemaStrict, } from './schemas/v3.1/strict/openapi-document.js';
28
+ /**
29
+ * Resolves a workspace document from various input sources (URL, local file, or direct document object).
30
+ *
31
+ * @param workspaceDocument - The document input to resolve, which can be:
32
+ * - A URL to fetch the document from
33
+ * - A direct document object
34
+ * @returns A promise that resolves to an object containing:
35
+ * - ok: boolean indicating if the resolution was successful
36
+ * - data: The resolved document data
37
+ *
38
+ * @example
39
+ * // Resolve from URL
40
+ * const urlDoc = await loadDocument({ name: 'api', url: 'https://api.example.com/openapi.json' })
41
+ *
42
+ * // Resolve direct document
43
+ * const directDoc = await loadDocument({
44
+ * name: 'inline',
45
+ * document: { openapi: '3.0.0', paths: {} }
46
+ * })
47
+ */
39
48
  function loadDocument(workspaceDocument) {
40
- if ("url" in workspaceDocument) {
41
- return fetchUrls({ fetch: workspaceDocument.fetch }).exec(workspaceDocument.url);
42
- }
43
- if ("path" in workspaceDocument) {
44
- const loader = workspaceDocument.fileLoader;
45
- if (!loader) {
46
- console.error("No loader provided for loading files");
47
- return Promise.resolve({
48
- ok: false
49
- });
49
+ if ('url' in workspaceDocument) {
50
+ return fetchUrls({ fetch: workspaceDocument.fetch }).exec(workspaceDocument.url);
50
51
  }
51
- return loader.exec(workspaceDocument.path);
52
- }
53
- return Promise.resolve({
54
- ok: true,
55
- data: workspaceDocument.document,
56
- // string version of the raw document for hashing purposes
57
- raw: JSON.stringify(workspaceDocument.document)
58
- });
52
+ if ('path' in workspaceDocument) {
53
+ const loader = workspaceDocument.fileLoader;
54
+ if (!loader) {
55
+ console.error('No loader provided for loading files');
56
+ return Promise.resolve({
57
+ ok: false,
58
+ });
59
+ }
60
+ return loader.exec(workspaceDocument.path);
61
+ }
62
+ return Promise.resolve({
63
+ ok: true,
64
+ data: workspaceDocument.document,
65
+ // string version of the raw document for hashing purposes
66
+ raw: JSON.stringify(workspaceDocument.document),
67
+ });
59
68
  }
69
+ /**
70
+ * Returns the base source of a workspace document if it was loaded from a URL or file.
71
+ * If the document was loaded from a file, returns the path to the file.
72
+ * If the document was provided directly as an object, returns undefined.
73
+ * Which can be used to resolve relative references in the document.
74
+ *
75
+ * @param input - The workspace document input (either UrlDoc or ObjectDoc)
76
+ * @returns The URL string if present, otherwise undefined
77
+ */
60
78
  const getDocumentSource = (input) => {
61
- if ("url" in input) {
62
- return input.url;
63
- }
64
- if ("path" in input) {
65
- return input.path;
66
- }
67
- return void 0;
79
+ if ('url' in input) {
80
+ return input.url;
81
+ }
82
+ if ('path' in input) {
83
+ return input.path;
84
+ }
85
+ return undefined;
68
86
  };
69
- const createWorkspaceStore = (workspaceProps) => {
70
- const { verbose = false } = workspaceProps ?? {};
71
- const withMeasurementSync = (name, fn) => verbose ? measureSync(name, fn) : fn();
72
- const withMeasurementAsync = (name, fn) => verbose ? measureAsync(name, fn) : fn();
73
- const extraDocumentConfigurations = {};
74
- const fireWorkspaceChange = (event) => {
75
- workspaceProps?.plugins?.forEach((plugin) => plugin.hooks?.onWorkspaceStateChanges?.(event));
76
- };
77
- const workspace = reactive(
78
- createDetectChangesProxy(
79
- {
87
+ /**
88
+ * Creates a reactive workspace store that manages documents and their metadata.
89
+ * The store provides functionality for accessing, updating, and resolving document references.
90
+ *
91
+ * @param workspaceProps - Configuration object for the workspace
92
+ * @param workspaceProps.meta - Optional metadata for the workspace
93
+ * @param workspaceProps.documents - Optional record of documents to initialize the workspace with
94
+ * Documents that require asynchronous loading must be added using `1` after the store is created
95
+ * this allows atomic awaiting and does not block page load for the store initialization
96
+ * @returns An object containing methods and getters for managing the workspace
97
+ */
98
+ export const createWorkspaceStore = (workspaceProps) => {
99
+ const { verbose = false } = workspaceProps ?? {};
100
+ const withMeasurementSync = (name, fn) => (verbose ? measureSync(name, fn) : fn());
101
+ const withMeasurementAsync = (name, fn) => verbose ? measureAsync(name, fn) : fn();
102
+ /**
103
+ * Holds additional configuration options for each document in the workspace.
104
+ *
105
+ * This can include settings that can not be persisted between sessions (not JSON serializable)
106
+ */
107
+ const extraDocumentConfigurations = {};
108
+ /**
109
+ * Notifies all workspace plugins of a workspace state change event.
110
+ *
111
+ * This function iterates through all registered plugins (if any) and invokes
112
+ * their onWorkspaceStateChanges hook with the given event object.
113
+ *
114
+ * @param event - The workspace state change event to broadcast to plugins
115
+ */
116
+ const fireWorkspaceChange = (event) => {
117
+ workspaceProps?.plugins?.forEach((plugin) => plugin.hooks?.onWorkspaceStateChanges?.(event));
118
+ };
119
+ /**
120
+ * An object containing the reactive workspace state.
121
+ *
122
+ * Every change to the workspace, is tracked and broadcast to all registered plugins.
123
+ * allowing for change tracking.
124
+ *
125
+ * NOTE:
126
+ * The detect changes proxy is applied separately beacause the vue reactitvity proxy have to be the outer most proxy.
127
+ * If the order is reversed, Vue cannot properly track mutations, leading to lost reactivity and bugs.
128
+ * By wrapping the contents with the detect changes proxy first, and then passing the result to Vue's `reactive`,
129
+ * we ensure that Vue manages its reactivity as expected and our change detection hooks
130
+ * are also triggered reliably.
131
+ * Do not reverse this order‼️
132
+ */
133
+ const workspace = reactive(createDetectChangesProxy({
80
134
  ...workspaceProps?.meta,
81
135
  documents: {},
82
136
  /**
@@ -87,626 +141,711 @@ const createWorkspaceStore = (workspaceProps) => {
87
141
  * @returns The active document or undefined if no document is found
88
142
  */
89
143
  get activeDocument() {
90
- return workspace.documents[getActiveDocumentName()];
91
- }
92
- },
93
- {
144
+ return workspace.documents[getActiveDocumentName()];
145
+ },
146
+ }, {
94
147
  hooks: {
95
- onAfterChange(path) {
96
- const type = path[0];
97
- if (type === "documents") {
98
- if (path.length < 2) {
99
- console.log("[WARN]: Overriding entire documents object is not supported");
148
+ onAfterChange(path) {
149
+ const type = path[0];
150
+ /** Document changes */
151
+ if (type === 'documents') {
152
+ // We are overriding the while documents object, ignore. This should not happen
153
+ if (path.length < 2) {
154
+ console.log('[WARN]: Overriding entire documents object is not supported');
155
+ return;
156
+ }
157
+ const documentName = path[1];
158
+ const document = workspace.documents[documentName] ?? {
159
+ openapi: '3.1.0',
160
+ info: { title: '', version: '' },
161
+ 'x-scalar-original-document-hash': '',
162
+ };
163
+ const event = {
164
+ type: 'documents',
165
+ documentName,
166
+ value: unpackProxyObject(document),
167
+ path: path.slice(2),
168
+ };
169
+ // Don't mark as dirty when the document is first created
170
+ if (event.path.length > 0 && event.path[0] !== 'x-scalar-is-dirty') {
171
+ // The document has been modified since it was last saved
172
+ document['x-scalar-is-dirty'] = true;
173
+ }
174
+ fireWorkspaceChange(event);
175
+ return;
176
+ }
177
+ /** Active document changes */
178
+ if (type === 'activeDocument') {
179
+ const documentName = getActiveDocumentName();
180
+ const document = workspace.documents[documentName] ?? {
181
+ openapi: '3.1.0',
182
+ info: { title: '', version: '' },
183
+ 'x-scalar-original-document-hash': '',
184
+ };
185
+ // Active document changed
186
+ const event = {
187
+ type: 'documents',
188
+ documentName,
189
+ value: unpackProxyObject(document),
190
+ path: path.slice(2),
191
+ };
192
+ // Don't mark as dirty when the document is first created
193
+ if (event.path.length > 0 && event.path[0] !== 'x-scalar-is-dirty') {
194
+ // The document has been modified since it was last saved
195
+ document['x-scalar-is-dirty'] = true;
196
+ }
197
+ fireWorkspaceChange(event);
198
+ return;
199
+ }
200
+ /** Workspace meta changes */
201
+ const { activeDocument: _a, documents: _d, ...meta } = workspace;
202
+ const event = {
203
+ type: 'meta',
204
+ value: unpackProxyObject(meta, { depth: 1 }),
205
+ };
206
+ fireWorkspaceChange(event);
100
207
  return;
101
- }
102
- const documentName = path[1];
103
- const document = workspace.documents[documentName] ?? {
104
- openapi: "3.1.0",
105
- info: { title: "", version: "" },
106
- "x-scalar-original-document-hash": ""
107
- };
108
- const event2 = {
109
- type: "documents",
110
- documentName,
111
- value: unpackProxyObject(document),
112
- path: path.slice(2)
113
- };
114
- if (event2.path.length > 0 && event2.path[0] !== "x-scalar-is-dirty") {
115
- document["x-scalar-is-dirty"] = true;
116
- }
117
- fireWorkspaceChange(event2);
118
- return;
119
- }
120
- if (type === "activeDocument") {
121
- const documentName = getActiveDocumentName();
122
- const document = workspace.documents[documentName] ?? {
123
- openapi: "3.1.0",
124
- info: { title: "", version: "" },
125
- "x-scalar-original-document-hash": ""
126
- };
127
- const event2 = {
128
- type: "documents",
129
- documentName,
130
- value: unpackProxyObject(document),
131
- path: path.slice(2)
132
- };
133
- if (event2.path.length > 0 && event2.path[0] !== "x-scalar-is-dirty") {
134
- document["x-scalar-is-dirty"] = true;
135
- }
136
- fireWorkspaceChange(event2);
137
- return;
138
- }
139
- const { activeDocument: _a, documents: _d, ...meta } = workspace;
140
- const event = {
141
- type: "meta",
142
- value: unpackProxyObject(meta, { depth: 1 })
143
- };
144
- fireWorkspaceChange(event);
145
- return;
146
- }
147
- }
148
- }
149
- )
150
- );
151
- const { originalDocuments, intermediateDocuments, overrides } = createDetectChangesProxy(
152
- {
153
- /**
154
- * Holds the original, unmodified documents as they were initially loaded into the workspace.
155
- * These documents are stored in their raw form—prior to any reactive wrapping, dereferencing, or bundling.
156
- * This map preserves the pristine structure of each document, using deep clones to ensure that
157
- * subsequent mutations in the workspace do not affect the originals.
158
- * The originals are retained so that we can restore, compare, or sync with the remote registry as needed.
159
- */
160
- originalDocuments: {},
161
- /**
162
- * Stores the intermediate state of documents after local edits but before syncing with the remote registry.
163
- *
164
- * This map acts as a local "saved" version of the document, reflecting the user's changes after they hit "save".
165
- * The `originalDocuments` map, by contrast, always mirrors the document as it exists in the remote registry.
166
- *
167
- * Use this map to stage local changes that are ready to be propagated back to the remote registry.
168
- * This separation allows us to distinguish between:
169
- * - The last known remote version (`originalDocuments`)
170
- * - The latest locally saved version (`intermediateDocuments`)
171
- * - The current in-memory (possibly unsaved) workspace document (`workspace.documents`)
172
- */
173
- intermediateDocuments: {},
174
- /**
175
- * Stores per-document overrides for OpenAPI documents.
176
- * This object is used to override specific fields of a document
177
- * when you cannot (or should not) modify the source document directly.
178
- * For example, this enables UI-driven or temporary changes to be applied
179
- * on top of the original document, without mutating the source.
180
- * The key is the document name, and the value is a deep partial
181
- * OpenAPI document representing the overridden fields.
182
- */
183
- overrides: {}
184
- },
185
- {
186
- hooks: {
187
- onAfterChange(path) {
188
- const type = path[0];
189
- if (!type) {
190
- return;
191
- }
192
- if (path.length < 2) {
193
- return;
194
- }
195
- const documentName = path[1];
196
- if (type === "originalDocuments") {
197
- const event = {
198
- type,
199
- documentName,
200
- value: unpackProxyObject(originalDocuments[documentName] ?? {}),
201
- path: path.splice(2)
202
- };
203
- fireWorkspaceChange(event);
204
- }
205
- if (type === "intermediateDocuments") {
206
- const event = {
207
- type,
208
- documentName,
209
- value: unpackProxyObject(intermediateDocuments[documentName] ?? {}),
210
- path: path.splice(2)
211
- };
212
- fireWorkspaceChange(event);
213
- }
214
- if (type === "overrides") {
215
- const event = {
216
- type,
217
- documentName,
218
- value: unpackProxyObject(overrides[documentName] ?? {})
219
- };
220
- fireWorkspaceChange(event);
221
- }
222
- }
223
- }
224
- }
225
- );
226
- const history = createHistoryStore({
227
- hooks: {
228
- onHistoryChange: (documentName) => {
229
- fireWorkspaceChange({
230
- type: "history",
231
- documentName,
232
- value: history.export()[documentName] ?? {}
233
- });
234
- }
235
- }
236
- });
237
- const auth = createAuthStore({
238
- hooks: {
239
- onAuthChange: (documentName) => {
240
- fireWorkspaceChange({
241
- type: "auth",
242
- documentName,
243
- value: auth.export()[documentName] ?? {
244
- secrets: {},
245
- selected: { document: { selectedIndex: 0, selectedSchemes: [] }, path: {} }
246
- }
247
- });
248
- }
249
- }
250
- });
251
- function getActiveDocumentName() {
252
- return workspace[extensions.workspace.activeDocument] ?? Object.keys(workspace.documents)[0] ?? "";
253
- }
254
- function exportDocument(documentName, format, minify) {
255
- const intermediateDocument = intermediateDocuments[documentName];
256
- if (!intermediateDocument) {
257
- return;
258
- }
259
- if (format === "json") {
260
- return minify ? JSON.stringify(intermediateDocument) : JSON.stringify(intermediateDocument, null, 2);
261
- }
262
- return YAML.stringify(intermediateDocument);
263
- }
264
- async function saveDocument(documentName) {
265
- const intermediateDocument = intermediateDocuments[documentName];
266
- const workspaceDocument = workspace.documents[documentName];
267
- if (!workspaceDocument) {
268
- return;
269
- }
270
- const activeDocumentRaw = unpackProxyObject(workspaceDocument);
271
- if (!intermediateDocument || !activeDocumentRaw) {
272
- console.warn("Failed to save document, intermediate document and/or active document is missing");
273
- return;
274
- }
275
- const updatedWithOriginalRefs = await bundle(deepClone(activeDocumentRaw), {
276
- plugins: [restoreOriginalRefs()],
277
- treeShake: false,
278
- urlMap: true
279
- });
280
- const excludedDiffs = applySelectiveUpdates(intermediateDocument, updatedWithOriginalRefs);
281
- workspaceDocument["x-scalar-is-dirty"] = false;
282
- return excludedDiffs;
283
- }
284
- async function addInMemoryDocument(input, navigationOptions) {
285
- const { name, meta } = input;
286
- const clonedRawInputDocument = withMeasurementSync("deepClone", () => deepClone(input.document));
287
- withMeasurementSync("initialize", () => {
288
- if (input.initialize !== false) {
289
- originalDocuments[name] = deepClone(clonedRawInputDocument);
290
- intermediateDocuments[name] = deepClone(clonedRawInputDocument);
291
- overrides[name] = input.overrides ?? {};
292
- extraDocumentConfigurations[name] = { fetch: input.fetch };
293
- }
294
- });
295
- const inputDocument = withMeasurementSync("upgrade", () => upgrade(deepClone(clonedRawInputDocument), "3.1"));
296
- const strictDocument = createMagicProxy(
297
- {
298
- ...inputDocument,
299
- ...meta,
300
- "x-original-oas-version": originalDocuments[name]?.openapi ?? originalDocuments[name]?.swagger,
301
- "x-scalar-original-document-hash": input.documentHash,
302
- "x-scalar-original-source-url": input.documentSource
303
- },
304
- { showInternal: true }
305
- );
306
- if (strictDocument[extensions.document.navigation] === void 0) {
307
- const loaders = [
308
- fetchUrls({
309
- fetch: extraDocumentConfigurations[name]?.fetch ?? workspaceProps?.fetch
310
- })
311
- ];
312
- if (workspaceProps?.fileLoader) {
313
- loaders.push(workspaceProps.fileLoader);
314
- }
315
- await withMeasurementAsync(
316
- "bundle",
317
- async () => await bundle(getRaw(strictDocument), {
318
- treeShake: false,
319
- plugins: [
320
- ...loaders,
321
- normalizeRefs(),
322
- externalValueResolver(),
323
- refsEverywhere(),
324
- normalizeAuthSchemes(),
325
- syncPathParameters()
326
- ],
327
- urlMap: true,
328
- origin: input.documentSource
329
- // use the document origin (if provided) as the base URL for resolution
330
- })
331
- );
332
- const coerced = withMeasurementSync(
333
- "coerceValue",
334
- () => coerceValue(OpenAPIDocumentSchemaStrict, deepClone(strictDocument))
335
- );
336
- withMeasurementSync("mergeObjects", () => mergeObjects(strictDocument, coerced));
337
- }
338
- const isValid = Value.Check(OpenAPIDocumentSchemaStrict, strictDocument);
339
- if (!isValid) {
340
- const validationErrors = Array.from(Value.Errors(OpenAPIDocumentSchemaStrict, strictDocument));
341
- console.warn("document validation errors: ");
342
- console.warn(
343
- validationErrors.map((error) => ({
344
- message: error.message,
345
- path: error.path,
346
- schema: error.schema,
347
- value: error.value
348
- }))
349
- );
350
- }
351
- if (strictDocument[extensions.document.navigation] === void 0) {
352
- const navigation = createNavigation(name, strictDocument, navigationOptions);
353
- strictDocument[extensions.document.navigation] = navigation;
354
- }
355
- workspace.documents[name] = createOverridesProxy(createMagicProxy(getRaw(strictDocument)), {
356
- overrides: unpackProxyObject(overrides[name])
208
+ },
209
+ },
210
+ }));
211
+ /**
212
+ * An object containing all the workspace state, wrapped in a detect changes proxy.
213
+ *
214
+ * Every change to the workspace state (documents, configs, metadata, etc.) can be detected here,
215
+ * allowing for change tracking.
216
+ */
217
+ const { originalDocuments, intermediateDocuments, overrides } = createDetectChangesProxy({
218
+ /**
219
+ * Holds the original, unmodified documents as they were initially loaded into the workspace.
220
+ * These documents are stored in their raw form—prior to any reactive wrapping, dereferencing, or bundling.
221
+ * This map preserves the pristine structure of each document, using deep clones to ensure that
222
+ * subsequent mutations in the workspace do not affect the originals.
223
+ * The originals are retained so that we can restore, compare, or sync with the remote registry as needed.
224
+ */
225
+ originalDocuments: {},
226
+ /**
227
+ * Stores the intermediate state of documents after local edits but before syncing with the remote registry.
228
+ *
229
+ * This map acts as a local "saved" version of the document, reflecting the user's changes after they hit "save".
230
+ * The `originalDocuments` map, by contrast, always mirrors the document as it exists in the remote registry.
231
+ *
232
+ * Use this map to stage local changes that are ready to be propagated back to the remote registry.
233
+ * This separation allows us to distinguish between:
234
+ * - The last known remote version (`originalDocuments`)
235
+ * - The latest locally saved version (`intermediateDocuments`)
236
+ * - The current in-memory (possibly unsaved) workspace document (`workspace.documents`)
237
+ */
238
+ intermediateDocuments: {},
239
+ /**
240
+ * Stores per-document overrides for OpenAPI documents.
241
+ * This object is used to override specific fields of a document
242
+ * when you cannot (or should not) modify the source document directly.
243
+ * For example, this enables UI-driven or temporary changes to be applied
244
+ * on top of the original document, without mutating the source.
245
+ * The key is the document name, and the value is a deep partial
246
+ * OpenAPI document representing the overridden fields.
247
+ */
248
+ overrides: {},
249
+ }, {
250
+ hooks: {
251
+ onAfterChange(path) {
252
+ const type = path[0];
253
+ if (!type) {
254
+ return;
255
+ }
256
+ if (path.length < 2) {
257
+ return;
258
+ }
259
+ const documentName = path[1];
260
+ if (type === 'originalDocuments') {
261
+ const event = {
262
+ type,
263
+ documentName: documentName,
264
+ value: unpackProxyObject(originalDocuments[documentName] ?? {}),
265
+ path: path.splice(2),
266
+ };
267
+ fireWorkspaceChange(event);
268
+ }
269
+ if (type === 'intermediateDocuments') {
270
+ const event = {
271
+ type,
272
+ documentName: documentName,
273
+ value: unpackProxyObject(intermediateDocuments[documentName] ?? {}),
274
+ path: path.splice(2),
275
+ };
276
+ fireWorkspaceChange(event);
277
+ }
278
+ if (type === 'overrides') {
279
+ const event = {
280
+ type,
281
+ documentName: documentName,
282
+ value: unpackProxyObject(overrides[documentName] ?? {}),
283
+ };
284
+ fireWorkspaceChange(event);
285
+ }
286
+ },
287
+ },
357
288
  });
358
- }
359
- async function addDocument(input, navigationOptions) {
360
- const { name, meta } = input;
361
- const fetch = getFetch({
362
- fetch: input.fetch ?? workspaceProps?.fetch,
363
- proxyUrl: workspace["x-scalar-active-proxy"] ?? void 0
289
+ /**
290
+ * This store is used to track the history of requests and responses for documents and operations.
291
+ */
292
+ const history = createHistoryStore({
293
+ hooks: {
294
+ onHistoryChange: (documentName) => {
295
+ fireWorkspaceChange({
296
+ type: 'history',
297
+ documentName,
298
+ value: history.export()[documentName] ?? {},
299
+ });
300
+ },
301
+ },
364
302
  });
365
- const resolve = await withMeasurementAsync(
366
- "loadDocument",
367
- async () => await loadDocument({ ...input, fetch, fileLoader: workspaceProps?.fileLoader })
368
- );
369
- return await withMeasurementAsync("addDocument", async () => {
370
- if (!resolve.ok) {
371
- console.error(`Failed to fetch document '${name}': request was not successful`);
372
- workspace.documents[name] = {
373
- ...meta,
374
- openapi: "3.1.0",
375
- info: {
376
- title: `Document '${name}' could not be loaded`,
377
- version: "unknown"
378
- },
379
- "x-scalar-original-document-hash": "not-a-hash"
380
- };
381
- return false;
382
- }
383
- if (!isObject(resolve.data)) {
384
- console.error(`Failed to load document '${name}': response data is not a valid object`);
385
- workspace.documents[name] = {
386
- ...meta,
387
- openapi: "3.1.0",
388
- info: {
389
- title: `Document '${name}' could not be loaded`,
390
- version: "unknown"
391
- },
392
- "x-scalar-original-document-hash": "not-a-hash"
393
- };
394
- return false;
395
- }
396
- await addInMemoryDocument(
397
- {
398
- ...input,
399
- document: resolve.data,
400
- documentSource: getDocumentSource(input),
401
- documentHash: generateHash(resolve.raw)
303
+ /**
304
+ * The auth store for the workspace
305
+ */
306
+ const auth = createAuthStore({
307
+ hooks: {
308
+ onAuthChange: (documentName) => {
309
+ fireWorkspaceChange({
310
+ type: 'auth',
311
+ documentName,
312
+ value: auth.export()[documentName] ?? {
313
+ secrets: {},
314
+ selected: { document: { selectedIndex: 0, selectedSchemes: [] }, path: {} },
315
+ },
316
+ });
317
+ },
402
318
  },
403
- navigationOptions
404
- );
405
- return true;
406
319
  });
407
- }
408
- const getOriginalDocument = (documentName) => {
409
- const rawDocument = unpackProxyObject(originalDocuments[documentName], { depth: 1 });
410
- if (!rawDocument) {
411
- return null;
412
- }
413
- return rawDocument;
414
- };
415
- const getIntermediateDocument = (documentName) => {
416
- const rawDocument = unpackProxyObject(intermediateDocuments[documentName], { depth: 1 });
417
- if (!rawDocument) {
418
- return null;
419
- }
420
- return rawDocument;
421
- };
422
- const promoteIntermediateToOriginal = (documentName) => {
423
- const intermediate = intermediateDocuments[documentName];
424
- if (!intermediate) {
425
- return false;
320
+ /**
321
+ * Returns the name of the currently active document in the workspace.
322
+ * The active document is determined by the 'x-scalar-active-document' metadata field,
323
+ * falling back to the first document in the workspace if no active document is specified.
324
+ *
325
+ * @returns The name of the active document or an empty string if no document is found
326
+ */
327
+ function getActiveDocumentName() {
328
+ return workspace[extensions.workspace.activeDocument] ?? Object.keys(workspace.documents)[0] ?? '';
426
329
  }
427
- const cloned = deepClone(unpackProxyObject(intermediate, { depth: 1 }));
428
- originalDocuments[documentName] = cloned;
429
- return true;
430
- };
431
- const getEditableDocument = async (documentName) => {
432
- const rawDocument = unpackProxyObject(workspace.documents[documentName], { depth: 1 });
433
- if (!rawDocument) {
434
- return null;
330
+ function exportDocument(documentName, format, minify) {
331
+ const intermediateDocument = intermediateDocuments[documentName];
332
+ if (!intermediateDocument) {
333
+ return;
334
+ }
335
+ if (format === 'json') {
336
+ return minify ? JSON.stringify(intermediateDocument) : JSON.stringify(intermediateDocument, null, 2);
337
+ }
338
+ return YAML.stringify(intermediateDocument);
435
339
  }
436
- const original = await bundle(deepClone(rawDocument), {
437
- plugins: [restoreOriginalRefs()],
438
- treeShake: false,
439
- urlMap: true
440
- });
441
- for (const property of EXCLUDE_KEYS) {
442
- delete original[property];
340
+ // Save the current state of the specified document to the intermediate documents map.
341
+ // This function captures the latest (reactive) state of the document from the workspace and
342
+ // applies its changes to the corresponding entry in the `intermediateDocuments` map.
343
+ // The `intermediateDocuments` map represents the most recently "saved" local version of the document,
344
+ // which may include edits not yet synced to the remote registry.
345
+ const saveDocument = async (documentName) => {
346
+ const activeDocument = workspace.documents[documentName];
347
+ const newDocument = await getEditableDocument(documentName);
348
+ if (!activeDocument || !newDocument) {
349
+ console.warn('Failed to save document, active document is missing');
350
+ return false;
351
+ }
352
+ // Store the new document in the intermediate documents map
353
+ intermediateDocuments[documentName] = newDocument;
354
+ // Mark the document as not dirty since we are saving it
355
+ activeDocument['x-scalar-is-dirty'] = false;
356
+ return true;
357
+ };
358
+ // Add a document to the store synchronously from an in-memory OpenAPI document
359
+ async function addInMemoryDocument(input, navigationOptions) {
360
+ const { name, meta } = input;
361
+ const clonedRawInputDocument = withMeasurementSync('deepClone', () => deepClone(input.document));
362
+ withMeasurementSync('initialize', () => {
363
+ if (input.initialize !== false) {
364
+ // Store the original document in the originalDocuments map
365
+ // This is used to track the original state of the document as it was loaded into the workspace
366
+ originalDocuments[name] = deepClone(clonedRawInputDocument);
367
+ // Store the intermediate document state for local edits
368
+ // This is used to track the last saved state of the document
369
+ // It allows us to differentiate between the original document and the latest saved version
370
+ // This is important for local edits that are not yet synced with the remote registry
371
+ // The intermediate document is used to store the latest saved state of the document
372
+ // This allows us to track changes and revert to the last saved state if needed
373
+ intermediateDocuments[name] = deepClone(clonedRawInputDocument);
374
+ // Store the overrides for this document, or an empty object if none are provided
375
+ overrides[name] = input.overrides ?? {};
376
+ // Store extra document configurations that can not be persisted
377
+ extraDocumentConfigurations[name] = { fetch: input.fetch };
378
+ }
379
+ });
380
+ const inputDocument = withMeasurementSync('upgrade', () => upgrade(deepClone(clonedRawInputDocument), '3.1'));
381
+ const strictDocument = createMagicProxy({
382
+ ...inputDocument,
383
+ ...meta,
384
+ 'x-original-oas-version': originalDocuments[name]?.openapi ?? originalDocuments[name]?.swagger,
385
+ 'x-scalar-original-document-hash': input.documentHash,
386
+ 'x-scalar-original-source-url': input.documentSource,
387
+ }, { showInternal: true });
388
+ // If the document navigation is not already present, bundle the entire document to resolve all references.
389
+ // This typically applies when the document is not preprocessed by the server and needs local reference resolution.
390
+ // We need to bundle document first before we validate, so we can also validate the external references
391
+ if (strictDocument[extensions.document.navigation] === undefined) {
392
+ const loaders = [
393
+ fetchUrls({
394
+ fetch: extraDocumentConfigurations[name]?.fetch ?? workspaceProps?.fetch,
395
+ }),
396
+ ];
397
+ // If a file loader plugin is provided, use it to resolve local file references
398
+ // This is useful for non browser environments
399
+ if (workspaceProps?.fileLoader) {
400
+ loaders.push(workspaceProps.fileLoader);
401
+ }
402
+ await withMeasurementAsync('bundle', async () => await bundle(getRaw(strictDocument), {
403
+ treeShake: false,
404
+ plugins: [
405
+ ...loaders,
406
+ normalizeRefs(),
407
+ externalValueResolver(),
408
+ refsEverywhere(),
409
+ normalizeAuthSchemes(),
410
+ syncPathParameters(),
411
+ ],
412
+ urlMap: true,
413
+ origin: input.documentSource, // use the document origin (if provided) as the base URL for resolution
414
+ }));
415
+ // We coerce the values only when the document is not preprocessed by the server-side-store
416
+ const coerced = withMeasurementSync('coerceValue', () => coerceValue(OpenAPIDocumentSchemaStrict, deepClone(strictDocument)));
417
+ withMeasurementSync('mergeObjects', () => mergeObjects(strictDocument, coerced));
418
+ }
419
+ const isValid = Value.Check(OpenAPIDocumentSchemaStrict, strictDocument);
420
+ if (!isValid) {
421
+ const validationErrors = Array.from(Value.Errors(OpenAPIDocumentSchemaStrict, strictDocument));
422
+ console.warn('document validation errors: ');
423
+ console.warn(validationErrors.map((error) => ({
424
+ message: error.message,
425
+ path: error.path,
426
+ schema: error.schema,
427
+ value: error.value,
428
+ })));
429
+ }
430
+ // Skip navigation generation if the document already has a server-side generated navigation structure
431
+ if (strictDocument[extensions.document.navigation] === undefined) {
432
+ const navigation = createNavigation(name, strictDocument, navigationOptions);
433
+ strictDocument[extensions.document.navigation] = navigation;
434
+ }
435
+ // Create a proxied document with magic proxy and apply any overrides, then store it in the workspace documents map
436
+ // We create a new proxy here in order to hide internal properties after validation and processing
437
+ // This ensures that the workspace document only exposes the intended OpenAPI properties and extensions
438
+ workspace.documents[name] = createOverridesProxy(createMagicProxy(getRaw(strictDocument)), {
439
+ overrides: unpackProxyObject(overrides[name]),
440
+ });
443
441
  }
444
- return original;
445
- };
446
- const buildSidebar = (documentName) => {
447
- const document = workspace.documents[documentName];
448
- if (!document) {
449
- console.error(`Document '${documentName}' does not exist in the workspace.`);
450
- return false;
442
+ // Asynchronously adds a new document to the workspace by loading and validating the input.
443
+ // If loading fails, a placeholder error document is added instead.
444
+ async function addDocument(input, navigationOptions) {
445
+ const { name, meta } = input;
446
+ /** Ensure we use the active proxy to fetch documents unless we have a custom fetch override */
447
+ const fetch = getFetch({
448
+ fetch: input.fetch ?? workspaceProps?.fetch,
449
+ proxyUrl: workspace['x-scalar-active-proxy'] ?? undefined,
450
+ });
451
+ const resolve = await withMeasurementAsync('loadDocument', async () => await loadDocument({ ...input, fetch, fileLoader: workspaceProps?.fileLoader }));
452
+ // Log the time taken to add a document
453
+ return await withMeasurementAsync('addDocument', async () => {
454
+ if (!resolve.ok) {
455
+ console.error(`Failed to fetch document '${name}': request was not successful`);
456
+ workspace.documents[name] = {
457
+ ...meta,
458
+ openapi: '3.1.0',
459
+ info: {
460
+ title: `Document '${name}' could not be loaded`,
461
+ version: 'unknown',
462
+ },
463
+ 'x-scalar-original-document-hash': 'not-a-hash',
464
+ };
465
+ return false;
466
+ }
467
+ if (!isObject(resolve.data)) {
468
+ console.error(`Failed to load document '${name}': response data is not a valid object`);
469
+ workspace.documents[name] = {
470
+ ...meta,
471
+ openapi: '3.1.0',
472
+ info: {
473
+ title: `Document '${name}' could not be loaded`,
474
+ version: 'unknown',
475
+ },
476
+ 'x-scalar-original-document-hash': 'not-a-hash',
477
+ };
478
+ return false;
479
+ }
480
+ await addInMemoryDocument({
481
+ ...input,
482
+ document: resolve.data,
483
+ documentSource: getDocumentSource(input),
484
+ documentHash: generateHash(resolve.raw),
485
+ }, navigationOptions);
486
+ return true;
487
+ });
451
488
  }
452
- const navigation = createNavigation(documentName, document);
453
- document[extensions.document.navigation] = navigation;
454
- return true;
455
- };
456
- const visitedNodesCache = /* @__PURE__ */ new Set();
457
- return {
458
- get workspace() {
459
- return workspace;
460
- },
461
- get history() {
462
- return history;
463
- },
464
- get auth() {
465
- return auth;
466
- },
467
- update(key, value) {
468
- preventPollution(key);
469
- Object.assign(workspace, { [key]: value });
470
- },
471
- getEditableDocument,
472
- getOriginalDocument,
473
- getIntermediateDocument,
474
- updateDocument(name, key, value) {
475
- const currentDocument = workspace.documents[name === "active" ? getActiveDocumentName() : name];
476
- if (!currentDocument) {
477
- return false;
478
- }
479
- preventPollution(key);
480
- Object.assign(currentDocument, { [key]: value });
481
- return true;
482
- },
483
- async replaceDocument(documentName, input) {
484
- const currentDocument = workspace.documents[documentName];
485
- if (!currentDocument) {
486
- return console.error(`Document '${documentName}' does not exist in the workspace.`);
487
- }
488
- await addInMemoryDocument({
489
- name: documentName,
490
- document: input,
491
- // Preserve the current metadata
492
- documentSource: currentDocument["x-scalar-original-source-url"],
493
- documentHash: currentDocument["x-scalar-original-document-hash"],
494
- meta: {
495
- // Set the document as dirty
496
- "x-scalar-is-dirty": true,
497
- // Clear the navigation to trigger a rebuild
498
- "x-scalar-navigation": void 0
499
- },
500
- initialize: false
501
- });
502
- },
503
- resolve: (path) => {
504
- const activeDocument = workspace.activeDocument;
505
- const target = getValueAtPath(activeDocument, path);
506
- if (!isObject(target)) {
507
- console.error(
508
- `Invalid path provided for resolution. Path: [${path.join(", ")}]. Found value of type: ${typeof target}. Expected an object.`
509
- );
510
- return Promise.resolve();
511
- }
512
- return bundle(target, {
513
- root: activeDocument,
514
- treeShake: false,
515
- plugins: [fetchUrls(), loadingStatus(), externalValueResolver()],
516
- urlMap: true,
517
- visitedNodes: visitedNodesCache
518
- });
519
- },
520
- addDocument,
489
+ const getOriginalDocument = (documentName) => {
490
+ const rawDocument = unpackProxyObject(originalDocuments[documentName], { depth: 1 });
491
+ if (!rawDocument) {
492
+ return null;
493
+ }
494
+ return rawDocument;
495
+ };
496
+ const getIntermediateDocument = (documentName) => {
497
+ const rawDocument = unpackProxyObject(intermediateDocuments[documentName], { depth: 1 });
498
+ if (!rawDocument) {
499
+ return null;
500
+ }
501
+ return rawDocument;
502
+ };
503
+ /**
504
+ * Promotes the intermediate document to the original document so the current
505
+ * intermediate becomes the new baseline. Fires workspace change for persistence.
506
+ */
507
+ const promoteIntermediateToOriginal = (documentName) => {
508
+ const intermediate = intermediateDocuments[documentName];
509
+ if (!intermediate) {
510
+ return false;
511
+ }
512
+ const cloned = deepClone(unpackProxyObject(intermediate, { depth: 1 }));
513
+ originalDocuments[documentName] = cloned;
514
+ return true;
515
+ };
521
516
  /**
522
- * Deletes a document from the workspace and all associated data.
517
+ * Retrieves an editable clone of a workspace document.
523
518
  *
524
- * This function removes the document and all related data structures.
525
- * If the deleted document was active, it automatically selects the first remaining document.
519
+ * - Unpacks the proxied document from the workspace.
520
+ * - Reverses all external references, restoring original $refs.
521
+ * - Removes transient/in-memory keys defined in EXCLUDE_KEYS.
522
+ *
523
+ * @param documentName The name of the document to retrieve.
524
+ * @returns The editable document object, or null if not found.
526
525
  */
527
- deleteDocument: (documentName) => {
528
- if (!workspace.documents[documentName]) {
529
- return;
530
- }
531
- delete workspace.documents[documentName];
532
- delete originalDocuments[documentName];
533
- delete intermediateDocuments[documentName];
534
- delete overrides[documentName];
535
- delete extraDocumentConfigurations[documentName];
536
- history.clearDocumentHistory(documentName);
537
- auth.clearDocumentAuth(documentName);
538
- const remainingDocuments = Object.keys(workspace.documents);
539
- const wasActiveDocument = workspace["x-scalar-active-document"] === documentName;
540
- if (wasActiveDocument) {
541
- workspace["x-scalar-active-document"] = remainingDocuments[0] ?? void 0;
542
- }
543
- fireWorkspaceChange({
544
- type: "deleteDocument",
545
- documentName
546
- });
547
- },
548
- exportDocument,
549
- exportActiveDocument: (format, minify) => exportDocument(getActiveDocumentName(), format, minify),
550
- buildSidebar,
551
- saveDocument,
552
- promoteIntermediateToOriginal,
553
- async revertDocumentChanges(documentName) {
554
- const workspaceDocument = workspace.documents[documentName];
555
- const intermediate = intermediateDocuments[documentName];
556
- if (!workspaceDocument || !intermediate) {
557
- return;
558
- }
559
- await addInMemoryDocument({
560
- name: documentName,
561
- document: intermediate,
562
- documentSource: workspaceDocument["x-scalar-original-source-url"],
563
- documentHash: workspaceDocument["x-scalar-original-document-hash"],
564
- initialize: false
565
- });
566
- },
567
- commitDocument(documentName) {
568
- console.warn(`Commit operation for document '${documentName}' is not implemented yet.`);
569
- },
570
- exportWorkspace() {
571
- const { activeDocument: _, documents, ...meta } = unpackProxyObject(workspace);
572
- return {
573
- documents: {
574
- ...Object.fromEntries(
575
- Object.entries(documents).map(([name, doc]) => [
576
- name,
577
- // Get the raw document without any proxies
578
- unpackProxyObject(doc)
579
- ])
580
- )
526
+ const getEditableDocument = async (documentName) => {
527
+ const rawDocument = unpackProxyObject(workspace.documents[documentName], { depth: 1 });
528
+ if (!rawDocument) {
529
+ // If the document does not exist, return null
530
+ return null;
531
+ }
532
+ // Reverse all external references and restore original $refs
533
+ const original = (await bundle(deepClone(rawDocument), {
534
+ plugins: [restoreOriginalRefs(), removeExtraScalarKeys()],
535
+ treeShake: false,
536
+ urlMap: true,
537
+ }));
538
+ // Top level keys that need to be excluded from the original document
539
+ // Nested keys are removed buring the previous step of the bundler process
540
+ const EXCLUDE_KEYS = [
541
+ // Bundler metadata fields added temporarily during document processing
542
+ 'x-ext',
543
+ 'x-ext-urls',
544
+ // Scalar internal/external metadata fields
545
+ 'x-scalar-navigation',
546
+ 'x-scalar-is-dirty',
547
+ 'x-original-oas-version',
548
+ 'x-scalar-original-document-hash',
549
+ 'x-scalar-original-source-url',
550
+ ];
551
+ // Remove top level properties that should only exist in memory for the original document
552
+ // These properties are used for internal purposes and are not needed in the final bundled document
553
+ for (const property of EXCLUDE_KEYS) {
554
+ delete original[property];
555
+ }
556
+ return original;
557
+ };
558
+ /**
559
+ * Builds (or updates) the navigation sidebar for the specified document.
560
+ *
561
+ * This method generates the sidebar navigation structure for a workspace document,
562
+ * and attaches it to the document's metadata under the navigation extension key.
563
+ * The document is unpacked to avoid assigning proxy objects as direct property references.
564
+ *
565
+ * - Only the top-level object is proxied; all child objects should be unproxied.
566
+ * - This approach enables safe unpacking of the proxy object without recursively traversing the full object tree.
567
+ *
568
+ * @param documentName - The name/key of the document whose sidebar should be built.
569
+ * @returns {boolean} True if the sidebar was built successfully, false if the document does not exist.
570
+ */
571
+ const buildSidebar = (documentName) => {
572
+ const document = workspace.documents[documentName];
573
+ if (!document) {
574
+ // Log and exit if the document does not exist in the workspace
575
+ console.error(`Document '${documentName}' does not exist in the workspace.`);
576
+ return false;
577
+ }
578
+ // Generate the navigation structure for the sidebar.
579
+ const navigation = createNavigation(documentName, document);
580
+ // Set the computed navigation structure on the document metadata.
581
+ document[extensions.document.navigation] = navigation;
582
+ return true;
583
+ };
584
+ // Cache to track visited nodes during reference resolution to prevent bundling the same subtree multiple times
585
+ // This is needed because we are doing partial bundle operations
586
+ const visitedNodesCache = new Set();
587
+ return {
588
+ get workspace() {
589
+ return workspace;
581
590
  },
582
- meta: unpackProxyObject(meta) ?? {},
583
- originalDocuments: unpackProxyObject(originalDocuments),
584
- intermediateDocuments: unpackProxyObject(intermediateDocuments),
585
- overrides: unpackProxyObject(overrides),
586
- history: history.export(),
587
- auth: auth.export()
588
- };
589
- },
590
- loadWorkspace(input) {
591
- safeAssign(
592
- workspace.documents,
593
- Object.fromEntries(
594
- Object.entries(input.documents).map(([name, doc]) => [
595
- name,
596
- createOverridesProxy(createMagicProxy(doc), {
597
- overrides: input.overrides[name]
598
- })
599
- ])
600
- )
601
- );
602
- safeAssign(originalDocuments, input.originalDocuments);
603
- safeAssign(intermediateDocuments, input.intermediateDocuments);
604
- safeAssign(overrides, input.overrides);
605
- safeAssign(workspace, input.meta);
606
- history.load(input.history);
607
- auth.load(input.auth);
608
- },
609
- importWorkspaceFromSpecification: (specification) => {
610
- const { documents, overrides: overrides2, info: _info, workspace: _workspaceVersion, ...meta } = specification;
611
- safeAssign(workspace, meta);
612
- return Promise.all(
613
- Object.entries(documents ?? {}).map(
614
- ([name, doc]) => addDocument({ url: doc.$ref, name, overrides: overrides2?.[name] })
615
- )
616
- );
617
- },
618
- rebaseDocument: async (input) => {
619
- const { name } = input;
620
- const originalDocument = unpackProxyObject(originalDocuments[name], { depth: 1 });
621
- const intermediateDocument = unpackProxyObject(intermediateDocuments[name], { depth: 1 });
622
- const activeDocument = workspace.documents[name] ? unpackProxyObject(workspace.documents[name], { depth: 1 }) : void 0;
623
- if (!originalDocument || !intermediateDocument || !activeDocument) {
624
- return {
625
- ok: false,
626
- type: "CORRUPTED_STATE",
627
- message: `Cannot rebase document '${name}': missing original, intermediate, or active document state`
628
- };
629
- }
630
- const resolve = await withMeasurementAsync(
631
- "loadDocument",
632
- async () => await loadDocument({
633
- ...input,
634
- fetch: input.fetch ?? workspaceProps?.fetch,
635
- fileLoader: workspaceProps?.fileLoader
636
- })
637
- );
638
- if (!resolve.ok || !isObject(resolve.data)) {
639
- return {
640
- ok: false,
641
- type: "FETCH_FAILED",
642
- message: `Failed to fetch document '${name}': request was not successful or returned invalid data`
643
- };
644
- }
645
- const newHash = generateHash(resolve.raw);
646
- if (activeDocument["x-scalar-original-document-hash"] === newHash) {
647
- return {
648
- ok: false,
649
- type: "NO_CHANGES_DETECTED",
650
- message: `No changes detected for document '${name}': document hash matches the active document`
651
- };
652
- }
653
- const newDocumentOrigin = resolve.data;
654
- overrides[name] = input.overrides ?? {};
655
- extraDocumentConfigurations[name] = { fetch: input.fetch };
656
- const changelogAA = diff(originalDocument, newDocumentOrigin);
657
- if (changelogAA.length === 0) {
658
- return {
659
- ok: false,
660
- type: "NO_CHANGES_DETECTED",
661
- message: `No changes detected for document '${name}' after fetching the latest version.`
662
- };
663
- }
664
- const changelogAB = diff(originalDocument, intermediateDocument);
665
- const changesA = merge(changelogAA, changelogAB);
666
- return {
667
- ok: true,
668
- conflicts: changesA.conflicts,
669
- changes: changesA.diffs,
670
- applyChanges: async (applyChangesInput) => {
671
- const getNewIntermediateDocument = () => {
672
- if ("resolvedConflicts" in applyChangesInput) {
673
- const changesetA = changesA.diffs.concat(applyChangesInput.resolvedConflicts);
674
- return apply(deepClone(originalDocument), changesetA);
591
+ get history() {
592
+ return history;
593
+ },
594
+ get auth() {
595
+ return auth;
596
+ },
597
+ update(key, value) {
598
+ preventPollution(key);
599
+ Object.assign(workspace, { [key]: value });
600
+ },
601
+ getEditableDocument,
602
+ getOriginalDocument,
603
+ getIntermediateDocument,
604
+ updateDocument(name, key, value) {
605
+ const currentDocument = workspace.documents[name === 'active' ? getActiveDocumentName() : name];
606
+ if (!currentDocument) {
607
+ return false;
675
608
  }
676
- return applyChangesInput.resolvedDocument;
677
- };
678
- const newIntermediateDocument = getNewIntermediateDocument();
679
- intermediateDocuments[name] = newIntermediateDocument;
680
- originalDocuments[name] = newDocumentOrigin;
681
- const changelogBA = diff(intermediateDocument, newIntermediateDocument);
682
- const changelogBB = diff(intermediateDocument, activeDocument);
683
- const changesB = merge(changelogBA, changelogBB);
684
- const changesetB = changesB.diffs.concat(changesB.conflicts.flatMap((it) => it[0]));
685
- const newActiveDocument = coerceValue(
686
- OpenAPIDocumentSchemaStrict,
687
- apply(deepClone(newIntermediateDocument), changesetB)
688
- );
689
- await addInMemoryDocument({
690
- ...input,
691
- document: {
692
- ...newActiveDocument,
693
- // force regeneration of navigation
694
- // when we are rebasing, we want to ensure that the navigation is always up to date
695
- [extensions.document.navigation]: void 0
696
- },
697
- documentSource: getDocumentSource(input),
698
- // Update the original document hash
699
- documentHash: generateHash(resolve.raw),
700
- initialize: false
701
- });
702
- }
703
- };
704
- }
705
- };
706
- };
707
- import { generateClientMutators } from "./mutators/index.js";
708
- export {
709
- createWorkspaceStore,
710
- generateClientMutators
609
+ preventPollution(key);
610
+ Object.assign(currentDocument, { [key]: value });
611
+ return true;
612
+ },
613
+ async replaceDocument(documentName, input) {
614
+ const currentDocument = workspace.documents[documentName];
615
+ if (!currentDocument) {
616
+ return console.error(`Document '${documentName}' does not exist in the workspace.`);
617
+ }
618
+ // Replace the whole document
619
+ await addInMemoryDocument({
620
+ name: documentName,
621
+ document: input,
622
+ // Preserve the current metadata
623
+ documentSource: currentDocument['x-scalar-original-source-url'],
624
+ documentHash: currentDocument['x-scalar-original-document-hash'],
625
+ meta: {
626
+ // Set the document as dirty
627
+ 'x-scalar-is-dirty': true,
628
+ // Clear the navigation to trigger a rebuild
629
+ 'x-scalar-navigation': undefined,
630
+ },
631
+ initialize: false,
632
+ });
633
+ },
634
+ resolve: (path) => {
635
+ const activeDocument = workspace.activeDocument;
636
+ const target = getValueAtPath(activeDocument, path);
637
+ if (!isObject(target)) {
638
+ console.error(`Invalid path provided for resolution. Path: [${path.join(', ')}]. Found value of type: ${typeof target}. Expected an object.`);
639
+ return Promise.resolve();
640
+ }
641
+ // Bundle the target document with the active document as root, resolving any external references
642
+ // and tracking resolution status through hooks
643
+ return bundle(target, {
644
+ root: activeDocument,
645
+ treeShake: false,
646
+ plugins: [fetchUrls(), loadingStatus(), externalValueResolver()],
647
+ urlMap: true,
648
+ visitedNodes: visitedNodesCache,
649
+ });
650
+ },
651
+ addDocument,
652
+ /**
653
+ * Deletes a document from the workspace and all associated data.
654
+ *
655
+ * This function removes the document and all related data structures.
656
+ * If the deleted document was active, it automatically selects the first remaining document.
657
+ */
658
+ deleteDocument: (documentName) => {
659
+ // Check if the document exists before attempting deletion
660
+ if (!workspace.documents[documentName]) {
661
+ return;
662
+ }
663
+ // Delete the document from the workspace (this will trigger change detection events)
664
+ delete workspace.documents[documentName];
665
+ // Clean up all associated data structures
666
+ delete originalDocuments[documentName];
667
+ delete intermediateDocuments[documentName];
668
+ delete overrides[documentName];
669
+ delete extraDocumentConfigurations[documentName];
670
+ history.clearDocumentHistory(documentName);
671
+ auth.clearDocumentAuth(documentName);
672
+ // Get remaining documents before deletion to properly set the active document
673
+ const remainingDocuments = Object.keys(workspace.documents);
674
+ const wasActiveDocument = workspace['x-scalar-active-document'] === documentName;
675
+ // Reset the active document to the first remaining one if the deleted document was the active one
676
+ if (wasActiveDocument) {
677
+ workspace['x-scalar-active-document'] = remainingDocuments[0] ?? undefined;
678
+ }
679
+ // Fire the deleteDocument event
680
+ fireWorkspaceChange({
681
+ type: 'deleteDocument',
682
+ documentName,
683
+ });
684
+ },
685
+ exportDocument,
686
+ exportActiveDocument: (format, minify) => exportDocument(getActiveDocumentName(), format, minify),
687
+ buildSidebar,
688
+ saveDocument,
689
+ promoteIntermediateToOriginal,
690
+ async revertDocumentChanges(documentName) {
691
+ const workspaceDocument = workspace.documents[documentName];
692
+ const intermediate = intermediateDocuments[documentName];
693
+ if (!workspaceDocument || !intermediate) {
694
+ return;
695
+ }
696
+ await addInMemoryDocument({
697
+ name: documentName,
698
+ document: intermediate,
699
+ documentSource: workspaceDocument['x-scalar-original-source-url'],
700
+ documentHash: workspaceDocument['x-scalar-original-document-hash'],
701
+ initialize: false,
702
+ });
703
+ },
704
+ commitDocument(documentName) {
705
+ // TODO: Implement commit logic
706
+ console.warn(`Commit operation for document '${documentName}' is not implemented yet.`);
707
+ },
708
+ exportWorkspace() {
709
+ const { activeDocument: _, documents, ...meta } = unpackProxyObject(workspace);
710
+ return {
711
+ documents: {
712
+ ...Object.fromEntries(Object.entries(documents).map(([name, doc]) => [
713
+ name,
714
+ // Get the raw document without any proxies
715
+ unpackProxyObject(doc),
716
+ ])),
717
+ },
718
+ meta: unpackProxyObject(meta) ?? {},
719
+ originalDocuments: unpackProxyObject(originalDocuments),
720
+ intermediateDocuments: unpackProxyObject(intermediateDocuments),
721
+ overrides: unpackProxyObject(overrides),
722
+ history: history.export(),
723
+ auth: auth.export(),
724
+ };
725
+ },
726
+ loadWorkspace(input) {
727
+ safeAssign(workspace.documents, Object.fromEntries(Object.entries(input.documents).map(([name, doc]) => [
728
+ name,
729
+ createOverridesProxy(createMagicProxy(doc), {
730
+ overrides: input.overrides[name],
731
+ }),
732
+ ])));
733
+ safeAssign(originalDocuments, input.originalDocuments);
734
+ safeAssign(intermediateDocuments, input.intermediateDocuments);
735
+ safeAssign(overrides, input.overrides);
736
+ safeAssign(workspace, input.meta);
737
+ history.load(input.history);
738
+ auth.load(input.auth);
739
+ },
740
+ importWorkspaceFromSpecification: (specification) => {
741
+ const { documents, overrides, info: _info, workspace: _workspaceVersion, ...meta } = specification;
742
+ // Assign workspace metadata
743
+ safeAssign(workspace, meta);
744
+ // Add workspace documents
745
+ return Promise.all(Object.entries(documents ?? {}).map(([name, doc]) => addDocument({ url: doc.$ref, name, overrides: overrides?.[name] })));
746
+ },
747
+ rebaseDocument: async (input) => {
748
+ const { name } = input;
749
+ // ---- Get the current documents
750
+ const originalDocument = unpackProxyObject(originalDocuments[name], { depth: 1 });
751
+ const intermediateDocument = unpackProxyObject(intermediateDocuments[name], { depth: 1 });
752
+ // raw version without any proxies
753
+ const activeDocument = workspace.documents[name]
754
+ ? unpackProxyObject(workspace.documents[name], { depth: 1 })
755
+ : undefined;
756
+ if (!originalDocument || !intermediateDocument || !activeDocument) {
757
+ // If any required document state is missing, do nothing
758
+ return {
759
+ ok: false,
760
+ type: 'CORRUPTED_STATE',
761
+ message: `Cannot rebase document '${name}': missing original, intermediate, or active document state`,
762
+ };
763
+ }
764
+ // ---- Resolve input document
765
+ const resolve = await withMeasurementAsync('loadDocument', async () => await loadDocument({
766
+ ...input,
767
+ fetch: input.fetch ?? workspaceProps?.fetch,
768
+ fileLoader: workspaceProps?.fileLoader,
769
+ }));
770
+ if (!resolve.ok || !isObject(resolve.data)) {
771
+ return {
772
+ ok: false,
773
+ type: 'FETCH_FAILED',
774
+ message: `Failed to fetch document '${name}': request was not successful or returned invalid data`,
775
+ };
776
+ }
777
+ // Compare document hashes to see if the document has changed
778
+ // When the hashes match, we can skip the rebase process
779
+ const newHash = generateHash(resolve.raw);
780
+ if (activeDocument['x-scalar-original-document-hash'] === newHash) {
781
+ return {
782
+ ok: false,
783
+ type: 'NO_CHANGES_DETECTED',
784
+ message: `No changes detected for document '${name}': document hash matches the active document`,
785
+ };
786
+ }
787
+ const newDocumentOrigin = resolve.data;
788
+ // ---- Override the configurations and metadata
789
+ overrides[name] = input.overrides ?? {};
790
+ extraDocumentConfigurations[name] = { fetch: input.fetch };
791
+ // ---- Get the new intermediate document
792
+ const changelogAA = diff(originalDocument, newDocumentOrigin);
793
+ // When there are no changes, we can return early since we don't need to do anything
794
+ // This is not supposed to happen due to the hash check above, but just in case
795
+ if (changelogAA.length === 0) {
796
+ return {
797
+ ok: false,
798
+ type: 'NO_CHANGES_DETECTED',
799
+ message: `No changes detected for document '${name}' after fetching the latest version.`,
800
+ };
801
+ }
802
+ const changelogAB = diff(originalDocument, intermediateDocument);
803
+ const changesA = merge(changelogAA, changelogAB);
804
+ return {
805
+ ok: true,
806
+ conflicts: changesA.conflicts,
807
+ changes: changesA.diffs,
808
+ applyChanges: async (applyChangesInput) => {
809
+ // Helper function to compute the new intermediate document based on resolved conflicts or a resolved document
810
+ const getNewIntermediateDocument = () => {
811
+ if ('resolvedConflicts' in applyChangesInput) {
812
+ const changesetA = changesA.diffs.concat(applyChangesInput.resolvedConflicts);
813
+ // Apply the merged changes (diffs + resolved conflicts) to the original document
814
+ return apply(deepClone(originalDocument), changesetA);
815
+ }
816
+ // If there are no resolved conflicts, use the provided resolved document
817
+ return applyChangesInput.resolvedDocument;
818
+ };
819
+ const newIntermediateDocument = getNewIntermediateDocument();
820
+ intermediateDocuments[name] = newIntermediateDocument;
821
+ // Update the original document
822
+ originalDocuments[name] = newDocumentOrigin;
823
+ // ---- Get the new active document
824
+ const changelogBA = diff(intermediateDocument, newIntermediateDocument);
825
+ const changelogBB = diff(intermediateDocument, activeDocument);
826
+ const changesB = merge(changelogBA, changelogBB);
827
+ // Auto-conflict resolution: pick only the changes from the first changeset
828
+ // TODO: In the future, implement smarter conflict resolution if needed
829
+ const changesetB = changesB.diffs.concat(changesB.conflicts.flatMap((it) => it[0]));
830
+ const newActiveDocument = coerceValue(OpenAPIDocumentSchemaStrict, apply(deepClone(newIntermediateDocument), changesetB));
831
+ // add the new active document to the workspace but don't re-initialize
832
+ await addInMemoryDocument({
833
+ ...input,
834
+ document: {
835
+ ...newActiveDocument,
836
+ // force regeneration of navigation
837
+ // when we are rebasing, we want to ensure that the navigation is always up to date
838
+ [extensions.document.navigation]: undefined,
839
+ },
840
+ documentSource: getDocumentSource(input),
841
+ // Update the original document hash
842
+ documentHash: generateHash(resolve.raw),
843
+ initialize: false,
844
+ });
845
+ },
846
+ };
847
+ },
848
+ };
711
849
  };
712
- //# sourceMappingURL=client.js.map
850
+ // biome-ignore lint/performance/noBarrelFile: It's a package entry point
851
+ export { generateClientMutators } from './mutators/index.js';