@scalar/workspace-store 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (256) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/client.d.ts +57 -30900
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +39 -23
  5. package/dist/client.js.map +2 -2
  6. package/dist/navigation/helpers/get-tag.d.ts +13 -0
  7. package/dist/navigation/helpers/get-tag.d.ts.map +1 -0
  8. package/dist/navigation/helpers/get-tag.js +10 -0
  9. package/dist/navigation/helpers/get-tag.js.map +7 -0
  10. package/dist/navigation/helpers/traverse-description.d.ts +19 -0
  11. package/dist/navigation/helpers/traverse-description.d.ts.map +1 -0
  12. package/dist/navigation/helpers/traverse-description.js +50 -0
  13. package/dist/navigation/helpers/traverse-description.js.map +7 -0
  14. package/dist/navigation/helpers/traverse-document.d.ts +16 -0
  15. package/dist/navigation/helpers/traverse-document.d.ts.map +1 -0
  16. package/dist/navigation/helpers/traverse-document.js +53 -0
  17. package/dist/navigation/helpers/traverse-document.js.map +7 -0
  18. package/dist/navigation/helpers/traverse-paths.d.ts +21 -0
  19. package/dist/navigation/helpers/traverse-paths.d.ts.map +1 -0
  20. package/dist/navigation/helpers/traverse-paths.js +39 -0
  21. package/dist/navigation/helpers/traverse-paths.js.map +7 -0
  22. package/dist/navigation/helpers/traverse-schemas.d.ts +16 -0
  23. package/dist/navigation/helpers/traverse-schemas.d.ts.map +1 -0
  24. package/dist/navigation/helpers/traverse-schemas.js +35 -0
  25. package/dist/navigation/helpers/traverse-schemas.js.map +7 -0
  26. package/dist/navigation/helpers/traverse-tags.d.ts +15 -0
  27. package/dist/navigation/helpers/traverse-tags.d.ts.map +1 -0
  28. package/dist/navigation/helpers/traverse-tags.js +77 -0
  29. package/dist/navigation/helpers/traverse-tags.js.map +7 -0
  30. package/dist/navigation/helpers/traverse-webhooks.d.ts +19 -0
  31. package/dist/navigation/helpers/traverse-webhooks.d.ts.map +1 -0
  32. package/dist/navigation/helpers/traverse-webhooks.js +40 -0
  33. package/dist/navigation/helpers/traverse-webhooks.js.map +7 -0
  34. package/dist/navigation/helpers/utils.d.ts +39 -0
  35. package/dist/navigation/helpers/utils.d.ts.map +1 -0
  36. package/dist/navigation/helpers/utils.js +25 -0
  37. package/dist/navigation/helpers/utils.js.map +7 -0
  38. package/dist/navigation/index.d.ts +3 -0
  39. package/dist/navigation/index.d.ts.map +1 -0
  40. package/dist/navigation/index.js +5 -0
  41. package/dist/navigation/index.js.map +7 -0
  42. package/dist/navigation/types.d.ts +94 -0
  43. package/dist/navigation/types.d.ts.map +1 -0
  44. package/dist/navigation/types.js +1 -0
  45. package/dist/navigation/types.js.map +7 -0
  46. package/dist/schemas/extensions.d.ts +14 -0
  47. package/dist/schemas/extensions.d.ts.map +1 -0
  48. package/dist/schemas/extensions.js +17 -0
  49. package/dist/schemas/extensions.js.map +7 -0
  50. package/dist/schemas/{callback.d.ts.map → openapi-v3/callback.d.ts.map} +1 -1
  51. package/dist/schemas/{callback.js.map → openapi-v3/callback.js.map} +1 -1
  52. package/dist/schemas/{components.d.ts.map → openapi-v3/components.d.ts.map} +1 -1
  53. package/dist/schemas/{components.js.map → openapi-v3/components.js.map} +1 -1
  54. package/dist/schemas/openapi-v3/contact.d.ts.map +1 -0
  55. package/dist/schemas/{contact.js.map → openapi-v3/contact.js.map} +1 -1
  56. package/dist/schemas/openapi-v3/discriminator.d.ts.map +1 -0
  57. package/dist/schemas/{discriminator.js.map → openapi-v3/discriminator.js.map} +1 -1
  58. package/dist/schemas/openapi-v3/encoding.d.ts.map +1 -0
  59. package/dist/schemas/{encoding.js.map → openapi-v3/encoding.js.map} +1 -1
  60. package/dist/schemas/openapi-v3/example.d.ts.map +1 -0
  61. package/dist/schemas/{example.js.map → openapi-v3/example.js.map} +1 -1
  62. package/dist/schemas/openapi-v3/external-documentation.d.ts.map +1 -0
  63. package/dist/schemas/{external-documentation.js.map → openapi-v3/external-documentation.js.map} +1 -1
  64. package/dist/schemas/openapi-v3/header.d.ts.map +1 -0
  65. package/dist/schemas/{header.js.map → openapi-v3/header.js.map} +1 -1
  66. package/dist/schemas/openapi-v3/info.d.ts.map +1 -0
  67. package/dist/schemas/{info.js.map → openapi-v3/info.js.map} +1 -1
  68. package/dist/schemas/openapi-v3/license.d.ts.map +1 -0
  69. package/dist/schemas/{license.js.map → openapi-v3/license.js.map} +1 -1
  70. package/dist/schemas/openapi-v3/link.d.ts.map +1 -0
  71. package/dist/schemas/{link.js.map → openapi-v3/link.js.map} +1 -1
  72. package/dist/schemas/openapi-v3/media-type.d.ts.map +1 -0
  73. package/dist/schemas/{media-type.js.map → openapi-v3/media-type.js.map} +1 -1
  74. package/dist/schemas/openapi-v3/oauth-flow.d.ts.map +1 -0
  75. package/dist/schemas/{oauth-flow.js.map → openapi-v3/oauth-flow.js.map} +1 -1
  76. package/dist/schemas/openapi-v3/oauthflows.d.ts.map +1 -0
  77. package/dist/schemas/{oauthflows.js.map → openapi-v3/oauthflows.js.map} +1 -1
  78. package/dist/schemas/{openapi-document.d.ts.map → openapi-v3/openapi-document.d.ts.map} +1 -1
  79. package/dist/schemas/{openapi-document.js.map → openapi-v3/openapi-document.js.map} +1 -1
  80. package/dist/schemas/openapi-v3/operation-without-callback.d.ts.map +1 -0
  81. package/dist/schemas/{operation-without-callback.js.map → openapi-v3/operation-without-callback.js.map} +1 -1
  82. package/dist/schemas/openapi-v3/parameter.d.ts.map +1 -0
  83. package/dist/schemas/{parameter.js.map → openapi-v3/parameter.js.map} +1 -1
  84. package/dist/schemas/{path-item.d.ts.map → openapi-v3/path-item.d.ts.map} +1 -1
  85. package/dist/schemas/{path-item.js.map → openapi-v3/path-item.js.map} +1 -1
  86. package/dist/schemas/{paths.d.ts.map → openapi-v3/paths.d.ts.map} +1 -1
  87. package/dist/schemas/{paths.js.map → openapi-v3/paths.js.map} +1 -1
  88. package/dist/schemas/openapi-v3/reference.d.ts.map +1 -0
  89. package/dist/schemas/{reference.js.map → openapi-v3/reference.js.map} +1 -1
  90. package/dist/schemas/openapi-v3/request-body.d.ts.map +1 -0
  91. package/dist/schemas/{request-body.js.map → openapi-v3/request-body.js.map} +1 -1
  92. package/dist/schemas/openapi-v3/response.d.ts.map +1 -0
  93. package/dist/schemas/{response.js.map → openapi-v3/response.js.map} +1 -1
  94. package/dist/schemas/openapi-v3/responses.d.ts.map +1 -0
  95. package/dist/schemas/{responses.js.map → openapi-v3/responses.js.map} +1 -1
  96. package/dist/schemas/openapi-v3/schema.d.ts.map +1 -0
  97. package/dist/schemas/{schema.js.map → openapi-v3/schema.js.map} +1 -1
  98. package/dist/schemas/openapi-v3/security-requirement.d.ts.map +1 -0
  99. package/dist/schemas/{security-requirement.js.map → openapi-v3/security-requirement.js.map} +1 -1
  100. package/dist/schemas/openapi-v3/security-scheme.d.ts.map +1 -0
  101. package/dist/schemas/{security-scheme.js.map → openapi-v3/security-scheme.js.map} +1 -1
  102. package/dist/schemas/openapi-v3/server-variable.d.ts.map +1 -0
  103. package/dist/schemas/{server-variable.js.map → openapi-v3/server-variable.js.map} +1 -1
  104. package/dist/schemas/openapi-v3/server.d.ts.map +1 -0
  105. package/dist/schemas/{server.js.map → openapi-v3/server.js.map} +1 -1
  106. package/dist/schemas/openapi-v3/tag.d.ts.map +1 -0
  107. package/dist/schemas/{tag.js.map → openapi-v3/tag.js.map} +1 -1
  108. package/dist/schemas/openapi-v3/xml.d.ts.map +1 -0
  109. package/dist/schemas/{xml.js.map → openapi-v3/xml.js.map} +1 -1
  110. package/dist/schemas/{server-workspace.d.ts → workspace.d.ts} +20 -19
  111. package/dist/schemas/{server-workspace.d.ts.map → workspace.d.ts.map} +1 -1
  112. package/dist/schemas/workspace.js +31 -0
  113. package/dist/schemas/workspace.js.map +7 -0
  114. package/dist/schemas.d.ts +1 -1
  115. package/dist/schemas.d.ts.map +1 -1
  116. package/dist/schemas.js +1 -1
  117. package/dist/schemas.js.map +1 -1
  118. package/dist/server.d.ts +14 -16
  119. package/dist/server.d.ts.map +1 -1
  120. package/dist/server.js +12 -2
  121. package/dist/server.js.map +2 -2
  122. package/package.json +11 -4
  123. package/.turbo/turbo-build.log +0 -13
  124. package/dist/schemas/contact.d.ts.map +0 -1
  125. package/dist/schemas/discriminator.d.ts.map +0 -1
  126. package/dist/schemas/encoding.d.ts.map +0 -1
  127. package/dist/schemas/example.d.ts.map +0 -1
  128. package/dist/schemas/external-documentation.d.ts.map +0 -1
  129. package/dist/schemas/header.d.ts.map +0 -1
  130. package/dist/schemas/info.d.ts.map +0 -1
  131. package/dist/schemas/license.d.ts.map +0 -1
  132. package/dist/schemas/link.d.ts.map +0 -1
  133. package/dist/schemas/media-type.d.ts.map +0 -1
  134. package/dist/schemas/oauth-flow.d.ts.map +0 -1
  135. package/dist/schemas/oauthflows.d.ts.map +0 -1
  136. package/dist/schemas/operation-without-callback.d.ts.map +0 -1
  137. package/dist/schemas/parameter.d.ts.map +0 -1
  138. package/dist/schemas/reference.d.ts.map +0 -1
  139. package/dist/schemas/request-body.d.ts.map +0 -1
  140. package/dist/schemas/response.d.ts.map +0 -1
  141. package/dist/schemas/responses.d.ts.map +0 -1
  142. package/dist/schemas/schema.d.ts.map +0 -1
  143. package/dist/schemas/security-requirement.d.ts.map +0 -1
  144. package/dist/schemas/security-scheme.d.ts.map +0 -1
  145. package/dist/schemas/server-variable.d.ts.map +0 -1
  146. package/dist/schemas/server-workspace.js +0 -29
  147. package/dist/schemas/server-workspace.js.map +0 -7
  148. package/dist/schemas/server.d.ts.map +0 -1
  149. package/dist/schemas/tag.d.ts.map +0 -1
  150. package/dist/schemas/xml.d.ts.map +0 -1
  151. package/esbuild.ts +0 -8
  152. package/src/client.test.ts +0 -409
  153. package/src/client.ts +0 -254
  154. package/src/helpers/general.ts +0 -30
  155. package/src/helpers/json-path-utils.test.ts +0 -13
  156. package/src/helpers/json-path-utils.ts +0 -38
  157. package/src/helpers/proxy.test.ts +0 -61
  158. package/src/helpers/proxy.ts +0 -213
  159. package/src/schemas/callback.ts +0 -13
  160. package/src/schemas/components.ts +0 -36
  161. package/src/schemas/contact.ts +0 -11
  162. package/src/schemas/discriminator.ts +0 -13
  163. package/src/schemas/encoding.ts +0 -17
  164. package/src/schemas/example.ts +0 -17
  165. package/src/schemas/external-documentation.ts +0 -9
  166. package/src/schemas/header.ts +0 -19
  167. package/src/schemas/info.ts +0 -23
  168. package/src/schemas/license.ts +0 -11
  169. package/src/schemas/link.ts +0 -24
  170. package/src/schemas/media-type.ts +0 -21
  171. package/src/schemas/oauth-flow.ts +0 -13
  172. package/src/schemas/oauthflows.ts +0 -16
  173. package/src/schemas/openapi-document.ts +0 -34
  174. package/src/schemas/operation-without-callback.ts +0 -37
  175. package/src/schemas/parameter.ts +0 -26
  176. package/src/schemas/path-item.ts +0 -35
  177. package/src/schemas/paths.ts +0 -11
  178. package/src/schemas/reference.ts +0 -20
  179. package/src/schemas/request-body.ts +0 -12
  180. package/src/schemas/response.ts +0 -16
  181. package/src/schemas/responses.ts +0 -14
  182. package/src/schemas/schema.ts +0 -26
  183. package/src/schemas/security-requirement.ts +0 -16
  184. package/src/schemas/security-scheme.ts +0 -58
  185. package/src/schemas/server-variable.ts +0 -11
  186. package/src/schemas/server-workspace.ts +0 -36
  187. package/src/schemas/server.ts +0 -12
  188. package/src/schemas/tag.ts +0 -12
  189. package/src/schemas/xml.ts +0 -19
  190. package/src/schemas.ts +0 -6
  191. package/src/server.test.ts +0 -470
  192. package/src/server.ts +0 -341
  193. package/test/helpers.ts +0 -16
  194. package/tsconfig.build.json +0 -12
  195. package/tsconfig.json +0 -8
  196. package/vite.config.ts +0 -9
  197. /package/dist/schemas/{callback.d.ts → openapi-v3/callback.d.ts} +0 -0
  198. /package/dist/schemas/{callback.js → openapi-v3/callback.js} +0 -0
  199. /package/dist/schemas/{components.d.ts → openapi-v3/components.d.ts} +0 -0
  200. /package/dist/schemas/{components.js → openapi-v3/components.js} +0 -0
  201. /package/dist/schemas/{contact.d.ts → openapi-v3/contact.d.ts} +0 -0
  202. /package/dist/schemas/{contact.js → openapi-v3/contact.js} +0 -0
  203. /package/dist/schemas/{discriminator.d.ts → openapi-v3/discriminator.d.ts} +0 -0
  204. /package/dist/schemas/{discriminator.js → openapi-v3/discriminator.js} +0 -0
  205. /package/dist/schemas/{encoding.d.ts → openapi-v3/encoding.d.ts} +0 -0
  206. /package/dist/schemas/{encoding.js → openapi-v3/encoding.js} +0 -0
  207. /package/dist/schemas/{example.d.ts → openapi-v3/example.d.ts} +0 -0
  208. /package/dist/schemas/{example.js → openapi-v3/example.js} +0 -0
  209. /package/dist/schemas/{external-documentation.d.ts → openapi-v3/external-documentation.d.ts} +0 -0
  210. /package/dist/schemas/{external-documentation.js → openapi-v3/external-documentation.js} +0 -0
  211. /package/dist/schemas/{header.d.ts → openapi-v3/header.d.ts} +0 -0
  212. /package/dist/schemas/{header.js → openapi-v3/header.js} +0 -0
  213. /package/dist/schemas/{info.d.ts → openapi-v3/info.d.ts} +0 -0
  214. /package/dist/schemas/{info.js → openapi-v3/info.js} +0 -0
  215. /package/dist/schemas/{license.d.ts → openapi-v3/license.d.ts} +0 -0
  216. /package/dist/schemas/{license.js → openapi-v3/license.js} +0 -0
  217. /package/dist/schemas/{link.d.ts → openapi-v3/link.d.ts} +0 -0
  218. /package/dist/schemas/{link.js → openapi-v3/link.js} +0 -0
  219. /package/dist/schemas/{media-type.d.ts → openapi-v3/media-type.d.ts} +0 -0
  220. /package/dist/schemas/{media-type.js → openapi-v3/media-type.js} +0 -0
  221. /package/dist/schemas/{oauth-flow.d.ts → openapi-v3/oauth-flow.d.ts} +0 -0
  222. /package/dist/schemas/{oauth-flow.js → openapi-v3/oauth-flow.js} +0 -0
  223. /package/dist/schemas/{oauthflows.d.ts → openapi-v3/oauthflows.d.ts} +0 -0
  224. /package/dist/schemas/{oauthflows.js → openapi-v3/oauthflows.js} +0 -0
  225. /package/dist/schemas/{openapi-document.d.ts → openapi-v3/openapi-document.d.ts} +0 -0
  226. /package/dist/schemas/{openapi-document.js → openapi-v3/openapi-document.js} +0 -0
  227. /package/dist/schemas/{operation-without-callback.d.ts → openapi-v3/operation-without-callback.d.ts} +0 -0
  228. /package/dist/schemas/{operation-without-callback.js → openapi-v3/operation-without-callback.js} +0 -0
  229. /package/dist/schemas/{parameter.d.ts → openapi-v3/parameter.d.ts} +0 -0
  230. /package/dist/schemas/{parameter.js → openapi-v3/parameter.js} +0 -0
  231. /package/dist/schemas/{path-item.d.ts → openapi-v3/path-item.d.ts} +0 -0
  232. /package/dist/schemas/{path-item.js → openapi-v3/path-item.js} +0 -0
  233. /package/dist/schemas/{paths.d.ts → openapi-v3/paths.d.ts} +0 -0
  234. /package/dist/schemas/{paths.js → openapi-v3/paths.js} +0 -0
  235. /package/dist/schemas/{reference.d.ts → openapi-v3/reference.d.ts} +0 -0
  236. /package/dist/schemas/{reference.js → openapi-v3/reference.js} +0 -0
  237. /package/dist/schemas/{request-body.d.ts → openapi-v3/request-body.d.ts} +0 -0
  238. /package/dist/schemas/{request-body.js → openapi-v3/request-body.js} +0 -0
  239. /package/dist/schemas/{response.d.ts → openapi-v3/response.d.ts} +0 -0
  240. /package/dist/schemas/{response.js → openapi-v3/response.js} +0 -0
  241. /package/dist/schemas/{responses.d.ts → openapi-v3/responses.d.ts} +0 -0
  242. /package/dist/schemas/{responses.js → openapi-v3/responses.js} +0 -0
  243. /package/dist/schemas/{schema.d.ts → openapi-v3/schema.d.ts} +0 -0
  244. /package/dist/schemas/{schema.js → openapi-v3/schema.js} +0 -0
  245. /package/dist/schemas/{security-requirement.d.ts → openapi-v3/security-requirement.d.ts} +0 -0
  246. /package/dist/schemas/{security-requirement.js → openapi-v3/security-requirement.js} +0 -0
  247. /package/dist/schemas/{security-scheme.d.ts → openapi-v3/security-scheme.d.ts} +0 -0
  248. /package/dist/schemas/{security-scheme.js → openapi-v3/security-scheme.js} +0 -0
  249. /package/dist/schemas/{server-variable.d.ts → openapi-v3/server-variable.d.ts} +0 -0
  250. /package/dist/schemas/{server-variable.js → openapi-v3/server-variable.js} +0 -0
  251. /package/dist/schemas/{server.d.ts → openapi-v3/server.d.ts} +0 -0
  252. /package/dist/schemas/{server.js → openapi-v3/server.js} +0 -0
  253. /package/dist/schemas/{tag.d.ts → openapi-v3/tag.d.ts} +0 -0
  254. /package/dist/schemas/{tag.js → openapi-v3/tag.js} +0 -0
  255. /package/dist/schemas/{xml.d.ts → openapi-v3/xml.d.ts} +0 -0
  256. /package/dist/schemas/{xml.js → openapi-v3/xml.js} +0 -0
@@ -1,409 +0,0 @@
1
- import { createServerWorkspaceStore } from '@/server'
2
- import { createWorkspaceStore } from '@/client'
3
- import { beforeEach, describe, expect, test } from 'vitest'
4
- import fastify, { type FastifyInstance } from 'fastify'
5
- import { afterEach } from 'node:test'
6
-
7
- // Test document
8
- const document = {
9
- openapi: '3.0.0',
10
- info: { title: 'My API' },
11
- components: {
12
- schemas: {
13
- User: {
14
- type: 'object',
15
- properties: {
16
- id: {
17
- type: 'string',
18
- description: 'The user ID',
19
- },
20
- name: {
21
- type: 'string',
22
- description: 'The user name',
23
- },
24
- email: {
25
- type: 'string',
26
- format: 'email',
27
- description: 'The user email',
28
- },
29
- },
30
- },
31
- },
32
- },
33
- paths: {
34
- '/users': {
35
- get: {
36
- summary: 'Get all users',
37
- responses: {
38
- '200': {
39
- description: 'Successful response',
40
- content: {
41
- 'application/json': {
42
- schema: {
43
- type: 'array',
44
- items: {
45
- $ref: '#/components/schemas/User',
46
- },
47
- },
48
- },
49
- },
50
- },
51
- },
52
- },
53
- },
54
- },
55
- }
56
-
57
- describe('create-workspace-store', () => {
58
- let server: FastifyInstance
59
-
60
- beforeEach(() => {
61
- server = fastify({ logger: false })
62
- })
63
-
64
- afterEach(async () => {
65
- await server.close()
66
- })
67
-
68
- test('should correctly update workspace metadata', async () => {
69
- const store = await createWorkspaceStore({
70
- meta: {
71
- 'x-scalar-theme': 'default',
72
- 'x-scalar-dark-mode': false,
73
- },
74
- })
75
-
76
- store.update('x-scalar-dark-mode', true)
77
- store.update('x-scalar-theme', 'saturn')
78
-
79
- expect(store.rawWorkspace['x-scalar-dark-mode']).toBe(true)
80
- expect(store.rawWorkspace['x-scalar-theme']).toBe('saturn')
81
- })
82
-
83
- test('should correctly update document metadata', async () => {
84
- const store = await createWorkspaceStore({
85
- documents: [
86
- {
87
- name: 'default',
88
- document: {
89
- openapi: '3.0.0',
90
- info: { title: 'My API' },
91
- },
92
- meta: {
93
- 'x-scalar-active-auth': 'Bearer',
94
- 'x-scalar-active-server': 'server-1',
95
- },
96
- },
97
- ],
98
- })
99
-
100
- // Should update the active document
101
- store.updateDocument('active', 'x-scalar-active-server', 'server-2')
102
- store.updateDocument('active', 'x-scalar-active-auth', undefined)
103
- expect(store.rawWorkspace.documents['default']['x-scalar-active-auth']).toBe(undefined)
104
- expect(store.rawWorkspace.documents['default']['x-scalar-active-server']).toBe('server-2')
105
-
106
- // Should update a specific document
107
- store.updateDocument('default', 'x-scalar-active-server', 'server-3')
108
- store.updateDocument('default', 'x-scalar-active-auth', 'Bearer')
109
- expect(store.rawWorkspace.documents['default']['x-scalar-active-auth']).toBe('Bearer')
110
- expect(store.rawWorkspace.documents['default']['x-scalar-active-server']).toBe('server-3')
111
- })
112
-
113
- test('should correctly get the correct document', async () => {
114
- const store = await createWorkspaceStore({
115
- documents: [
116
- {
117
- name: 'default',
118
- document: {
119
- openapi: '3.0.0',
120
- info: { title: 'My API' },
121
- },
122
- meta: {
123
- 'x-scalar-active-auth': 'Bearer',
124
- 'x-scalar-active-server': 'server-1',
125
- },
126
- },
127
- {
128
- name: 'document2',
129
- document: {
130
- openapi: '3.0.0',
131
- info: { title: 'Second API' },
132
- },
133
- meta: {
134
- 'x-scalar-active-auth': 'Bearer',
135
- 'x-scalar-active-server': 'server-1',
136
- },
137
- },
138
- ],
139
- meta: {
140
- 'x-scalar-active-document': 'default',
141
- },
142
- })
143
-
144
- // Correctly gets the active document
145
- expect(store.workspace.activeDocument?.info?.title).toBe('My API')
146
-
147
- store.update('x-scalar-active-document', 'document2')
148
- expect(store.workspace.activeDocument?.info?.title).toBe('Second API')
149
-
150
- // Correctly get a specific document
151
- expect(store.workspace.documents['default'].info?.title).toBe('My API')
152
- })
153
-
154
- test('should correctly add new documents', async () => {
155
- const store = await createWorkspaceStore({
156
- documents: [],
157
- })
158
-
159
- await store.addDocument({
160
- document: {
161
- openapi: '3.0.0',
162
- info: { title: 'My API' },
163
- },
164
- name: 'default',
165
- })
166
-
167
- store.update('x-scalar-active-document', 'default')
168
- expect(store.workspace.activeDocument?.info?.title).toBe('My API')
169
- })
170
-
171
- test('should correctly resolve refs on the fly', async () => {
172
- const store = await createWorkspaceStore({
173
- documents: [
174
- {
175
- name: 'default',
176
- document: {
177
- openapi: '3.0.0',
178
- info: { title: 'My API' },
179
- components: {
180
- schemas: {
181
- User: {
182
- type: 'object',
183
- properties: {
184
- id: {
185
- type: 'string',
186
- description: 'The user ID',
187
- },
188
- name: {
189
- type: 'string',
190
- description: 'The user name',
191
- },
192
- email: {
193
- type: 'string',
194
- format: 'email',
195
- description: 'The user email',
196
- },
197
- },
198
- },
199
- },
200
- },
201
- paths: {
202
- '/users': {
203
- get: {
204
- summary: 'Get all users',
205
- responses: {
206
- '200': {
207
- description: 'Successful response',
208
- content: {
209
- 'application/json': {
210
- schema: {
211
- type: 'array',
212
- items: {
213
- $ref: '#/components/schemas/User',
214
- },
215
- },
216
- },
217
- },
218
- },
219
- },
220
- },
221
- },
222
- },
223
- },
224
- },
225
- ],
226
- })
227
-
228
- expect(
229
- (store.workspace.activeDocument?.paths?.['/users'].get as any)?.responses?.[200].content['application/json']
230
- .schema.items.properties.name,
231
- ).toEqual({
232
- type: 'string',
233
- description: 'The user name',
234
- })
235
- })
236
-
237
- test('should correctly resolve chunks from the remote server', async () => {
238
- server.get('/*', (req, res) => {
239
- const path = req.url
240
- const contents = serverStore.get(path)
241
-
242
- res.send(contents)
243
- })
244
-
245
- const PORT = 9988
246
- await server.listen({ port: PORT })
247
-
248
- const serverStore = createServerWorkspaceStore({
249
- mode: 'ssr',
250
- baseUrl: `http://localhost:${PORT}`,
251
- documents: [
252
- {
253
- name: 'default',
254
- document,
255
- },
256
- ],
257
- })
258
-
259
- const store = await createWorkspaceStore({
260
- documents: [
261
- {
262
- name: 'default',
263
- document: serverStore.getWorkspace().documents['default'],
264
- },
265
- ],
266
- })
267
-
268
- // The operation should not be resolved on the fly
269
- expect(store.workspace.activeDocument?.paths?.['/users'].get).toEqual({
270
- '$ref': 'http://localhost:9988/default/operations/~1users/get#',
271
- $global: true,
272
- })
273
-
274
- // We resolve the ref
275
- await store.resolve(['paths', '/users', 'get'])
276
-
277
- // We expect the ref to have been resolved with the correct contents
278
- expect(store.workspace.activeDocument?.paths?.['/users'].get?.summary).toEqual(document.paths['/users'].get.summary)
279
-
280
- expect(
281
- (store.workspace.activeDocument?.paths?.['/users'].get as any).responses[200].content['application/json'].schema
282
- .items,
283
- ).toEqual(document.components.schemas.User)
284
- })
285
-
286
- test('should load files form the remote url', async () => {
287
- const PORT = 9989
288
- const url = `http://localhost:${PORT}`
289
-
290
- // Send the default document
291
- server.get('/', (_, reply) => {
292
- reply.send(document)
293
- })
294
-
295
- await server.listen({ port: PORT })
296
-
297
- const store = await createWorkspaceStore({
298
- documents: [
299
- {
300
- url: url,
301
- name: 'default',
302
- },
303
- ],
304
- })
305
-
306
- expect(Object.keys(store.workspace.documents)).toEqual(['default'])
307
- expect(store.workspace.documents['default'].info?.title).toEqual(document.info.title)
308
-
309
- // Add a new remote file
310
- await store.addDocument({ name: 'new', url: url })
311
-
312
- expect(Object.keys(store.workspace.documents)).toEqual(['default', 'new'])
313
- expect(store.workspace.documents['new'].info?.title).toEqual(document.info.title)
314
- })
315
-
316
- test('should handle circular references when we try to resolve all remote chunks recursively', async () => {
317
- const document = {
318
- openapi: '3.0.0',
319
- info: { title: 'My API' },
320
- components: {
321
- schemas: {
322
- User: {
323
- type: 'object',
324
- properties: {
325
- id: {
326
- type: 'string',
327
- description: 'The user ID',
328
- },
329
- name: {
330
- $ref: '#/components/schemas/Rec',
331
- },
332
- },
333
- },
334
- Rec: {
335
- type: 'object',
336
- properties: {
337
- id: {
338
- $ref: '#/components/schemas/User',
339
- },
340
- },
341
- },
342
- },
343
- },
344
- paths: {
345
- '/users': {
346
- get: {
347
- summary: 'Get all users',
348
- responses: {
349
- '200': {
350
- description: 'Successful response',
351
- content: {
352
- 'application/json': {
353
- schema: {
354
- type: 'array',
355
- items: {
356
- $ref: '#/components/schemas/User',
357
- },
358
- },
359
- },
360
- },
361
- },
362
- },
363
- },
364
- },
365
- },
366
- }
367
-
368
- server.get('/*', (req, res) => {
369
- const path = req.url
370
- const contents = serverStore.get(path)
371
-
372
- res.send(contents)
373
- })
374
-
375
- const PORT = 6672
376
- await server.listen({ port: PORT })
377
-
378
- const serverStore = createServerWorkspaceStore({
379
- mode: 'ssr',
380
- baseUrl: `http://localhost:${PORT}`,
381
- documents: [
382
- {
383
- name: 'default',
384
- document,
385
- },
386
- ],
387
- })
388
-
389
- const store = await createWorkspaceStore({
390
- documents: [
391
- {
392
- name: 'default',
393
- document: serverStore.getWorkspace().documents['default'],
394
- },
395
- ],
396
- })
397
-
398
- // The operation should not be resolved on the fly
399
- expect(store.workspace.activeDocument?.paths?.['/users'].get).toEqual({
400
- '$ref': `http://localhost:${PORT}/default/operations/~1users/get#`,
401
- $global: true,
402
- })
403
-
404
- // We resolve the ref
405
- await store.resolve(['paths', '/users', 'get'])
406
-
407
- expect((store.workspace.activeDocument?.components?.schemas?.['User'] as any)?.type).toBe('object')
408
- })
409
- })
package/src/client.ts DELETED
@@ -1,254 +0,0 @@
1
- import { reactive, toRaw } from 'vue'
2
- import type { WorkspaceMeta, WorkspaceDocumentMeta, Workspace } from './schemas/server-workspace'
3
- import { createMagicProxy } from './helpers/proxy'
4
- import { isObject } from '@/helpers/general'
5
- import { getValueByPath } from '@/helpers/json-path-utils'
6
- import { bundle } from '@scalar/openapi-parser'
7
- import { fetchUrls } from '@scalar/openapi-parser/utils/bundle/plugins/fetch-urls'
8
-
9
- type WorkspaceDocumentMetaInput = { meta?: WorkspaceDocumentMeta; name: string }
10
- type WorkspaceDocumentInput =
11
- | ({ document: Record<string, unknown> } & WorkspaceDocumentMetaInput)
12
- | ({ url: string } & WorkspaceDocumentMetaInput)
13
-
14
- /**
15
- * Resolves a workspace document from various input sources (URL, local file, or direct document object).
16
- *
17
- * @param workspaceDocument - The document input to resolve, which can be:
18
- * - A URL to fetch the document from
19
- * - A local file path to read the document from
20
- * - A direct document object
21
- * @returns A promise that resolves to an object containing:
22
- * - ok: boolean indicating if the resolution was successful
23
- * - data: The resolved document data
24
- *
25
- * @example
26
- * // Resolve from URL
27
- * const urlDoc = await loadDocument({ name: 'api', url: 'https://api.example.com/openapi.json' })
28
- *
29
- * // Resolve from local file
30
- * const fileDoc = await loadDocument({ name: 'local', path: './openapi.json' })
31
- *
32
- * // Resolve direct document
33
- * const directDoc = await loadDocument({
34
- * name: 'inline',
35
- * document: { openapi: '3.0.0', paths: {} }
36
- * })
37
- */
38
- async function loadDocument(workspaceDocument: WorkspaceDocumentInput) {
39
- if ('url' in workspaceDocument) {
40
- return fetchUrls().exec(workspaceDocument.url)
41
- }
42
-
43
- return {
44
- ok: true as const,
45
- data: workspaceDocument.document,
46
- }
47
- }
48
-
49
- /**
50
- * Creates a reactive workspace store that manages documents and their metadata.
51
- * The store provides functionality for accessing, updating, and resolving document references.
52
- *
53
- * @param workspaceProps - Configuration object for the workspace
54
- * @param workspaceProps.meta - Optional metadata for the workspace
55
- * @param workspaceProps.documents - Optional record of documents to initialize the workspace with
56
- * @returns An object containing methods and getters for managing the workspace
57
- * @deprecated Use `createWorkspaceStore` instead.
58
- */
59
- export function createWorkspaceStoreSync(workspaceProps?: {
60
- meta?: WorkspaceMeta
61
- }) {
62
- // Create a reactive workspace object with proxied documents
63
- // Each document is wrapped in a proxy to enable reactive updates and reference resolution
64
- const workspace = reactive({
65
- ...workspaceProps?.meta,
66
- documents: {},
67
- /**
68
- * Returns the currently active document from the workspace.
69
- * The active document is determined by the 'x-scalar-active-document' metadata field,
70
- * falling back to the first document in the workspace if no active document is specified.
71
- *
72
- * @returns The active document or undefined if no document is found
73
- */
74
- get activeDocument(): (typeof workspace.documents)[number] | undefined {
75
- const activeDocumentKey = workspace['x-scalar-active-document'] ?? Object.keys(workspace.documents)[0] ?? ''
76
- return workspace.documents[activeDocumentKey]
77
- },
78
- }) as Workspace
79
-
80
- // Cache to track visited nodes during reference resolution to prevent bundling the same subtree multiple times
81
- // This is needed because we are doing partial bundle operations
82
- const visitedNodesCache = new Set()
83
-
84
- return {
85
- /**
86
- * Returns the raw (non-reactive) workspace object
87
- */
88
- get rawWorkspace() {
89
- return toRaw(workspace)
90
- },
91
- /**
92
- * Returns the reactive workspace object with an additional activeDocument getter
93
- */
94
- get workspace() {
95
- return workspace
96
- },
97
- /**
98
- * Updates a specific metadata field in the workspace
99
- * @param key - The metadata field to update
100
- * @param value - The new value for the field
101
- * @example
102
- * // Update the workspace title
103
- * update('x-scalar-active-document', 'document-name')
104
- */
105
- update<K extends keyof WorkspaceMeta>(key: K, value: WorkspaceMeta[K]) {
106
- // @ts-ignore
107
- if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
108
- throw new Error('Invalid key: cannot modify prototype')
109
- }
110
- Object.assign(workspace, { [key]: value })
111
- },
112
- /**
113
- * Updates a specific metadata field in a document
114
- * @param name - The name of the document to update ('active' or a specific document name)
115
- * @param key - The metadata field to update
116
- * @param value - The new value for the field
117
- * @throws Error if the specified document doesn't exist
118
- * @example
119
- * // Update the auth of the active document
120
- * updateDocument('active', 'x-scalar-active-auth', 'Bearer')
121
- * // Update the auth of a specific document
122
- * updateDocument('document-name', 'x-scalar-active-auth', 'Bearer')
123
- */
124
- updateDocument<K extends keyof WorkspaceDocumentMeta>(
125
- name: 'active' | (string & {}),
126
- key: K,
127
- value: WorkspaceDocumentMeta[K],
128
- ) {
129
- const currentDocument =
130
- workspace.documents[
131
- name === 'active'
132
- ? (workspace['x-scalar-active-document'] ?? Object.keys(workspace.documents)[0] ?? '')
133
- : name
134
- ]
135
-
136
- if (!currentDocument) {
137
- throw 'Please select a valid document'
138
- }
139
-
140
- Object.assign(currentDocument, { [key]: value })
141
- },
142
- /**
143
- * Resolves a reference in the active document by following the provided path and resolving any external $ref references.
144
- * This method traverses the document structure following the given path and resolves any $ref references it encounters.
145
- * During resolution, it sets a loading status and updates the reference with the resolved content.
146
- *
147
- * @param path - Array of strings representing the path to the reference (e.g. ['paths', '/users', 'get', 'responses', '200'])
148
- * @throws Error if the path is invalid or empty
149
- * @example
150
- * // Resolve a reference in the active document
151
- * resolve(['paths', '/users', 'get', 'responses', '200'])
152
- */
153
- resolve: async (path: string[]) => {
154
- const activeDocument = workspace.activeDocument
155
-
156
- const target = getValueByPath(activeDocument, path)
157
-
158
- if (!isObject(target)) {
159
- console.error(
160
- `Invalid path provided for resolution. Path: [${path.join(', ')}]. Found value of type: ${typeof target}. Expected an object.`,
161
- )
162
- return
163
- }
164
-
165
- // Bundle the target document with the active document as root, resolving any external references
166
- // and tracking resolution status through hooks
167
- return bundle(target, {
168
- root: activeDocument,
169
- treeShake: false,
170
- plugins: [fetchUrls()],
171
- urlMap: false,
172
- hooks: {
173
- onResolveStart: (node) => {
174
- node['$status'] = 'loading'
175
- },
176
- onResolveError: (node) => {
177
- node['$status'] = 'error'
178
- },
179
- },
180
- visitedNodes: visitedNodesCache,
181
- })
182
- },
183
- /**
184
- * Adds a new document to the workspace
185
- * @param document - The document content to add. This should be a valid OpenAPI/Swagger document or other supported format
186
- * @param meta - Metadata for the document, including its name and other properties defined in WorkspaceDocumentMeta
187
- * @example
188
- * // Add a new OpenAPI document to the workspace
189
- * store.addDocument({
190
- * name: 'name',
191
- * document: {
192
- * openapi: '3.0.0',
193
- * info: { title: 'title' },
194
- * },
195
- * meta: {
196
- * 'x-scalar-active-auth': 'Bearer',
197
- * 'x-scalar-active-server': 'production'
198
- * }
199
- * })
200
- */
201
- addDocument: async (input: WorkspaceDocumentInput) => {
202
- const { name, meta } = input
203
-
204
- const resolve = await loadDocument(input)
205
-
206
- if (!resolve.ok || !isObject(resolve.data)) {
207
- console.error(`Can not load the document '${name}'`)
208
- workspace.documents[name] = {
209
- ...meta,
210
- }
211
- return
212
- }
213
-
214
- workspace.documents[name] = createMagicProxy({ ...(resolve.data as Record<string, unknown>), ...meta })
215
- },
216
- }
217
- }
218
-
219
- /**
220
- * Creates a reactive workspace store that manages documents and their metadata.
221
- * The store provides functionality for accessing, updating, and resolving document references.
222
- *
223
- * @param workspaceProps - Configuration object for the workspace
224
- * @param workspaceProps.meta - Optional metadata for the workspace
225
- * @param workspaceProps.documents - Optional record of documents to initialize the workspace with
226
- * @returns An object containing methods and getters for managing the workspace
227
- * @example
228
- * // Create a workspace store with metadata and documents
229
- * const store = await createWorkspaceStore({
230
- * meta: {
231
- * name: 'My Workspace',
232
- * description: 'A workspace for my API'
233
- * },
234
- * documents: [
235
- * {
236
- * name: 'petstore',
237
- * document: {
238
- * openapi: '3.0.0',
239
- * info: { title: 'Petstore API' }
240
- * }
241
- * }
242
- * ]
243
- * })
244
- */
245
- export async function createWorkspaceStore(workspaceProps?: {
246
- meta?: WorkspaceMeta
247
- documents?: WorkspaceDocumentInput[]
248
- }) {
249
- const store = createWorkspaceStoreSync({ meta: workspaceProps?.meta })
250
-
251
- await Promise.all(workspaceProps?.documents?.map((it) => store.addDocument(it)) ?? [])
252
-
253
- return store
254
- }
@@ -1,30 +0,0 @@
1
- export type UnknownObject = Record<string, unknown>
2
-
3
- /**
4
- * Returns true if the value is a non-null object (but not an array).
5
- *
6
- * @example
7
- * ```ts
8
- * isObject({}) // true
9
- * isObject([]) // false
10
- * isObject(null) // false
11
- * ```
12
- */
13
- export function isObject(value: unknown): value is UnknownObject {
14
- return typeof value === 'object' && value !== null && !Array.isArray(value)
15
- }
16
-
17
- /**
18
- * Checks if a string is a local reference (starts with #)
19
- * @param value - The reference string to check
20
- * @returns true if the string is a local reference, false otherwise
21
- * @example
22
- * ```ts
23
- * isLocalRef('#/components/schemas/User') // true
24
- * isLocalRef('https://example.com/schema.json') // false
25
- * isLocalRef('./local-schema.json') // false
26
- * ```
27
- */
28
- export function isLocalRef(value: string): boolean {
29
- return value.startsWith('#')
30
- }
@@ -1,13 +0,0 @@
1
- import { parseJsonPointer } from '@/helpers/json-path-utils'
2
- import { describe, expect, test } from 'vitest'
3
-
4
- describe('parseJsonPointer', () => {
5
- test.each([
6
- ['#/users/name', ['users', 'name']],
7
- ['#/', []],
8
- ['', []],
9
- ['users/name', ['users', 'name']],
10
- ])('should correctly parse json pointers', (a, b) => {
11
- expect(parseJsonPointer(a)).toEqual(b)
12
- })
13
- })