@scalar/workspace-store 0.1.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 (198) hide show
  1. package/.turbo/turbo-build.log +10 -0
  2. package/CHANGELOG.md +13 -0
  3. package/README.md +199 -0
  4. package/dist/create-server-workspace-store.d.ts +151 -0
  5. package/dist/create-server-workspace-store.d.ts.map +1 -0
  6. package/dist/create-server-workspace-store.js +199 -0
  7. package/dist/create-server-workspace-store.js.map +7 -0
  8. package/dist/create-workspace-store.d.ts +19773 -0
  9. package/dist/create-workspace-store.d.ts.map +1 -0
  10. package/dist/create-workspace-store.js +186 -0
  11. package/dist/create-workspace-store.js.map +7 -0
  12. package/dist/helpers/general.d.ts +88 -0
  13. package/dist/helpers/general.d.ts.map +1 -0
  14. package/dist/helpers/general.js +38 -0
  15. package/dist/helpers/general.js.map +7 -0
  16. package/dist/helpers/json-path-utils.d.ts +23 -0
  17. package/dist/helpers/json-path-utils.d.ts.map +1 -0
  18. package/dist/helpers/json-path-utils.js +16 -0
  19. package/dist/helpers/json-path-utils.js.map +7 -0
  20. package/dist/helpers/proxy.d.ts +63 -0
  21. package/dist/helpers/proxy.d.ts.map +1 -0
  22. package/dist/helpers/proxy.js +100 -0
  23. package/dist/helpers/proxy.js.map +7 -0
  24. package/dist/index.d.ts +4 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +13 -0
  27. package/dist/index.js.map +7 -0
  28. package/dist/schemas/callback.d.ts +1095 -0
  29. package/dist/schemas/callback.d.ts.map +1 -0
  30. package/dist/schemas/callback.js +11 -0
  31. package/dist/schemas/callback.js.map +7 -0
  32. package/dist/schemas/components.d.ts +2461 -0
  33. package/dist/schemas/components.d.ts.map +1 -0
  34. package/dist/schemas/components.js +38 -0
  35. package/dist/schemas/components.js.map +7 -0
  36. package/dist/schemas/contact.d.ts +10 -0
  37. package/dist/schemas/contact.d.ts.map +1 -0
  38. package/dist/schemas/contact.js +13 -0
  39. package/dist/schemas/contact.js.map +7 -0
  40. package/dist/schemas/discriminator.d.ts +12 -0
  41. package/dist/schemas/discriminator.d.ts.map +1 -0
  42. package/dist/schemas/discriminator.js +11 -0
  43. package/dist/schemas/discriminator.js.map +7 -0
  44. package/dist/schemas/encoding.d.ts +23 -0
  45. package/dist/schemas/encoding.d.ts.map +1 -0
  46. package/dist/schemas/encoding.js +13 -0
  47. package/dist/schemas/encoding.js.map +7 -0
  48. package/dist/schemas/example.d.ts +16 -0
  49. package/dist/schemas/example.d.ts.map +1 -0
  50. package/dist/schemas/example.js +15 -0
  51. package/dist/schemas/example.js.map +7 -0
  52. package/dist/schemas/external-documentation.d.ts +8 -0
  53. package/dist/schemas/external-documentation.d.ts.map +1 -0
  54. package/dist/schemas/external-documentation.js +11 -0
  55. package/dist/schemas/external-documentation.js.map +7 -0
  56. package/dist/schemas/header.d.ts +18 -0
  57. package/dist/schemas/header.d.ts.map +1 -0
  58. package/dist/schemas/header.js +13 -0
  59. package/dist/schemas/header.js.map +7 -0
  60. package/dist/schemas/info.d.ts +28 -0
  61. package/dist/schemas/info.d.ts.map +1 -0
  62. package/dist/schemas/info.js +23 -0
  63. package/dist/schemas/info.js.map +7 -0
  64. package/dist/schemas/license.d.ts +10 -0
  65. package/dist/schemas/license.d.ts.map +1 -0
  66. package/dist/schemas/license.js +13 -0
  67. package/dist/schemas/license.js.map +7 -0
  68. package/dist/schemas/link.d.ts +30 -0
  69. package/dist/schemas/link.d.ts.map +1 -0
  70. package/dist/schemas/link.js +20 -0
  71. package/dist/schemas/link.js.map +7 -0
  72. package/dist/schemas/media-type.d.ts +55 -0
  73. package/dist/schemas/media-type.d.ts.map +1 -0
  74. package/dist/schemas/media-type.js +19 -0
  75. package/dist/schemas/media-type.js.map +7 -0
  76. package/dist/schemas/oauth-flow.d.ts +12 -0
  77. package/dist/schemas/oauth-flow.d.ts.map +1 -0
  78. package/dist/schemas/oauth-flow.js +15 -0
  79. package/dist/schemas/oauth-flow.js.map +7 -0
  80. package/dist/schemas/oauthflows.d.ts +34 -0
  81. package/dist/schemas/oauthflows.d.ts.map +1 -0
  82. package/dist/schemas/oauthflows.js +16 -0
  83. package/dist/schemas/oauthflows.js.map +7 -0
  84. package/dist/schemas/openapi-document.d.ts +4683 -0
  85. package/dist/schemas/openapi-document.d.ts.map +1 -0
  86. package/dist/schemas/openapi-document.js +35 -0
  87. package/dist/schemas/openapi-document.js.map +7 -0
  88. package/dist/schemas/operation-without-callback.d.ts +190 -0
  89. package/dist/schemas/operation-without-callback.d.ts.map +1 -0
  90. package/dist/schemas/operation-without-callback.js +39 -0
  91. package/dist/schemas/operation-without-callback.js.map +7 -0
  92. package/dist/schemas/parameter.d.ts +25 -0
  93. package/dist/schemas/parameter.d.ts.map +1 -0
  94. package/dist/schemas/parameter.js +22 -0
  95. package/dist/schemas/parameter.js.map +7 -0
  96. package/dist/schemas/path-item.d.ts +1106 -0
  97. package/dist/schemas/path-item.d.ts.map +1 -0
  98. package/dist/schemas/path-item.js +37 -0
  99. package/dist/schemas/path-item.js.map +7 -0
  100. package/dist/schemas/paths.d.ts +1093 -0
  101. package/dist/schemas/paths.d.ts.map +1 -0
  102. package/dist/schemas/paths.js +11 -0
  103. package/dist/schemas/paths.js.map +7 -0
  104. package/dist/schemas/reference.d.ts +17 -0
  105. package/dist/schemas/reference.d.ts.map +1 -0
  106. package/dist/schemas/reference.js +15 -0
  107. package/dist/schemas/reference.js.map +7 -0
  108. package/dist/schemas/request-body.d.ts +54 -0
  109. package/dist/schemas/request-body.d.ts.map +1 -0
  110. package/dist/schemas/request-body.js +14 -0
  111. package/dist/schemas/request-body.js.map +7 -0
  112. package/dist/schemas/response.d.ts +84 -0
  113. package/dist/schemas/response.d.ts.map +1 -0
  114. package/dist/schemas/response.js +19 -0
  115. package/dist/schemas/response.js.map +7 -0
  116. package/dist/schemas/responses.d.ts +94 -0
  117. package/dist/schemas/responses.d.ts.map +1 -0
  118. package/dist/schemas/responses.js +8 -0
  119. package/dist/schemas/responses.js.map +7 -0
  120. package/dist/schemas/schema.d.ts +34 -0
  121. package/dist/schemas/schema.d.ts.map +1 -0
  122. package/dist/schemas/schema.js +22 -0
  123. package/dist/schemas/schema.js.map +7 -0
  124. package/dist/schemas/security-requirement.d.ts +11 -0
  125. package/dist/schemas/security-requirement.d.ts.map +1 -0
  126. package/dist/schemas/security-requirement.js +10 -0
  127. package/dist/schemas/security-requirement.js.map +7 -0
  128. package/dist/schemas/security-scheme.d.ts +137 -0
  129. package/dist/schemas/security-scheme.d.ts.map +1 -0
  130. package/dist/schemas/security-scheme.js +56 -0
  131. package/dist/schemas/security-scheme.js.map +7 -0
  132. package/dist/schemas/server-variable.d.ts +10 -0
  133. package/dist/schemas/server-variable.d.ts.map +1 -0
  134. package/dist/schemas/server-variable.js +13 -0
  135. package/dist/schemas/server-variable.js.map +7 -0
  136. package/dist/schemas/server-workspace.d.ts +14043 -0
  137. package/dist/schemas/server-workspace.d.ts.map +1 -0
  138. package/dist/schemas/server-workspace.js +29 -0
  139. package/dist/schemas/server-workspace.js.map +7 -0
  140. package/dist/schemas/server.d.ts +14 -0
  141. package/dist/schemas/server.d.ts.map +1 -0
  142. package/dist/schemas/server.js +14 -0
  143. package/dist/schemas/server.js.map +7 -0
  144. package/dist/schemas/tag.d.ts +13 -0
  145. package/dist/schemas/tag.d.ts.map +1 -0
  146. package/dist/schemas/tag.js +14 -0
  147. package/dist/schemas/tag.js.map +7 -0
  148. package/dist/schemas/xml.d.ts +18 -0
  149. package/dist/schemas/xml.d.ts.map +1 -0
  150. package/dist/schemas/xml.js +17 -0
  151. package/dist/schemas/xml.js.map +7 -0
  152. package/esbuild.ts +6 -0
  153. package/package.json +54 -0
  154. package/src/create-server-workspace-store.test.ts +429 -0
  155. package/src/create-server-workspace-store.ts +339 -0
  156. package/src/create-workspace-store.test.ts +488 -0
  157. package/src/create-workspace-store.ts +282 -0
  158. package/src/helpers/general.ts +115 -0
  159. package/src/helpers/json-path-utils.test.ts +13 -0
  160. package/src/helpers/json-path-utils.ts +38 -0
  161. package/src/helpers/proxy.test.ts +61 -0
  162. package/src/helpers/proxy.ts +213 -0
  163. package/src/index.ts +8 -0
  164. package/src/schemas/callback.ts +13 -0
  165. package/src/schemas/components.ts +36 -0
  166. package/src/schemas/contact.ts +11 -0
  167. package/src/schemas/discriminator.ts +13 -0
  168. package/src/schemas/encoding.ts +17 -0
  169. package/src/schemas/example.ts +17 -0
  170. package/src/schemas/external-documentation.ts +9 -0
  171. package/src/schemas/header.ts +19 -0
  172. package/src/schemas/info.ts +23 -0
  173. package/src/schemas/license.ts +11 -0
  174. package/src/schemas/link.ts +24 -0
  175. package/src/schemas/media-type.ts +21 -0
  176. package/src/schemas/oauth-flow.ts +13 -0
  177. package/src/schemas/oauthflows.ts +16 -0
  178. package/src/schemas/openapi-document.ts +34 -0
  179. package/src/schemas/operation-without-callback.ts +37 -0
  180. package/src/schemas/parameter.ts +26 -0
  181. package/src/schemas/path-item.ts +35 -0
  182. package/src/schemas/paths.ts +11 -0
  183. package/src/schemas/reference.ts +18 -0
  184. package/src/schemas/request-body.ts +12 -0
  185. package/src/schemas/response.ts +16 -0
  186. package/src/schemas/responses.ts +14 -0
  187. package/src/schemas/schema.ts +26 -0
  188. package/src/schemas/security-requirement.ts +16 -0
  189. package/src/schemas/security-scheme.ts +58 -0
  190. package/src/schemas/server-variable.ts +11 -0
  191. package/src/schemas/server-workspace.ts +36 -0
  192. package/src/schemas/server.ts +12 -0
  193. package/src/schemas/tag.ts +12 -0
  194. package/src/schemas/xml.ts +19 -0
  195. package/test/helpers.ts +16 -0
  196. package/tsconfig.build.json +12 -0
  197. package/tsconfig.json +8 -0
  198. package/vite.config.ts +9 -0
@@ -0,0 +1,488 @@
1
+ import { createServerWorkspaceStore, WORKSPACE_FILE_NAME } from '@/create-server-workspace-store'
2
+ import { createWorkspaceStore } from '@/create-workspace-store'
3
+ import { beforeEach, describe, expect, test } from 'vitest'
4
+ import fastify, { type FastifyInstance } from 'fastify'
5
+ import { afterEach } from 'node:test'
6
+ import { cwd } from 'node:process'
7
+ import fs from 'node:fs/promises'
8
+ import type { Workspace } from '@/schemas/server-workspace'
9
+
10
+ // Test document
11
+ const document = {
12
+ openapi: '3.0.0',
13
+ info: { title: 'My API' },
14
+ components: {
15
+ schemas: {
16
+ User: {
17
+ type: 'object',
18
+ properties: {
19
+ id: {
20
+ type: 'string',
21
+ description: 'The user ID',
22
+ },
23
+ name: {
24
+ type: 'string',
25
+ description: 'The user name',
26
+ },
27
+ email: {
28
+ type: 'string',
29
+ format: 'email',
30
+ description: 'The user email',
31
+ },
32
+ },
33
+ },
34
+ },
35
+ },
36
+ paths: {
37
+ '/users': {
38
+ get: {
39
+ summary: 'Get all users',
40
+ responses: {
41
+ '200': {
42
+ description: 'Successful response',
43
+ content: {
44
+ 'application/json': {
45
+ schema: {
46
+ type: 'array',
47
+ items: {
48
+ $ref: '#/components/schemas/User',
49
+ },
50
+ },
51
+ },
52
+ },
53
+ },
54
+ },
55
+ },
56
+ },
57
+ },
58
+ }
59
+
60
+ describe('create-workspace-store', () => {
61
+ let server: FastifyInstance
62
+
63
+ beforeEach(() => {
64
+ server = fastify({ logger: false })
65
+ })
66
+
67
+ afterEach(async () => {
68
+ await server.close()
69
+ })
70
+
71
+ test('should correctly update workspace metadata', async () => {
72
+ const store = await createWorkspaceStore({
73
+ meta: {
74
+ 'x-scalar-theme': 'default',
75
+ 'x-scalar-dark-mode': false,
76
+ },
77
+ })
78
+
79
+ store.update('x-scalar-dark-mode', true)
80
+ store.update('x-scalar-theme', 'saturn')
81
+
82
+ expect(store.rawWorkspace['x-scalar-dark-mode']).toBe(true)
83
+ expect(store.rawWorkspace['x-scalar-theme']).toBe('saturn')
84
+ })
85
+
86
+ test('should correctly update document metadata', async () => {
87
+ const store = await createWorkspaceStore({
88
+ documents: [
89
+ {
90
+ name: 'default',
91
+ document: {
92
+ openapi: '3.0.0',
93
+ info: { title: 'My API' },
94
+ },
95
+ meta: {
96
+ 'x-scalar-active-auth': 'Bearer',
97
+ 'x-scalar-active-server': 'server-1',
98
+ },
99
+ },
100
+ ],
101
+ })
102
+
103
+ // Should update the active document
104
+ store.updateDocument('active', 'x-scalar-active-server', 'server-2')
105
+ store.updateDocument('active', 'x-scalar-active-auth', undefined)
106
+ expect(store.rawWorkspace.documents['default']['x-scalar-active-auth']).toBe(undefined)
107
+ expect(store.rawWorkspace.documents['default']['x-scalar-active-server']).toBe('server-2')
108
+
109
+ // Should update a specific document
110
+ store.updateDocument('default', 'x-scalar-active-server', 'server-3')
111
+ store.updateDocument('default', 'x-scalar-active-auth', 'Bearer')
112
+ expect(store.rawWorkspace.documents['default']['x-scalar-active-auth']).toBe('Bearer')
113
+ expect(store.rawWorkspace.documents['default']['x-scalar-active-server']).toBe('server-3')
114
+ })
115
+
116
+ test('should correctly get the correct document', async () => {
117
+ const store = await createWorkspaceStore({
118
+ documents: [
119
+ {
120
+ name: 'default',
121
+ document: {
122
+ openapi: '3.0.0',
123
+ info: { title: 'My API' },
124
+ },
125
+ meta: {
126
+ 'x-scalar-active-auth': 'Bearer',
127
+ 'x-scalar-active-server': 'server-1',
128
+ },
129
+ },
130
+ {
131
+ name: 'document2',
132
+ document: {
133
+ openapi: '3.0.0',
134
+ info: { title: 'Second API' },
135
+ },
136
+ meta: {
137
+ 'x-scalar-active-auth': 'Bearer',
138
+ 'x-scalar-active-server': 'server-1',
139
+ },
140
+ },
141
+ ],
142
+ meta: {
143
+ 'x-scalar-active-document': 'default',
144
+ },
145
+ })
146
+
147
+ // Correctly gets the active document
148
+ expect(store.workspace.activeDocument?.info?.title).toBe('My API')
149
+
150
+ store.update('x-scalar-active-document', 'document2')
151
+ expect(store.workspace.activeDocument?.info?.title).toBe('Second API')
152
+
153
+ // Correctly get a specific document
154
+ expect(store.workspace.documents['default'].info?.title).toBe('My API')
155
+ })
156
+
157
+ test('should correctly add new documents', async () => {
158
+ const store = await createWorkspaceStore({
159
+ documents: [],
160
+ })
161
+
162
+ await store.addDocument({
163
+ document: {
164
+ openapi: '3.0.0',
165
+ info: { title: 'My API' },
166
+ },
167
+ name: 'default',
168
+ })
169
+
170
+ store.update('x-scalar-active-document', 'default')
171
+ expect(store.workspace.activeDocument?.info?.title).toBe('My API')
172
+ })
173
+
174
+ test('should correctly resolve refs on the fly', async () => {
175
+ const store = await createWorkspaceStore({
176
+ documents: [
177
+ {
178
+ name: 'default',
179
+ document: {
180
+ openapi: '3.0.0',
181
+ info: { title: 'My API' },
182
+ components: {
183
+ schemas: {
184
+ User: {
185
+ type: 'object',
186
+ properties: {
187
+ id: {
188
+ type: 'string',
189
+ description: 'The user ID',
190
+ },
191
+ name: {
192
+ type: 'string',
193
+ description: 'The user name',
194
+ },
195
+ email: {
196
+ type: 'string',
197
+ format: 'email',
198
+ description: 'The user email',
199
+ },
200
+ },
201
+ },
202
+ },
203
+ },
204
+ paths: {
205
+ '/users': {
206
+ get: {
207
+ summary: 'Get all users',
208
+ responses: {
209
+ '200': {
210
+ description: 'Successful response',
211
+ content: {
212
+ 'application/json': {
213
+ schema: {
214
+ type: 'array',
215
+ items: {
216
+ $ref: '#/components/schemas/User',
217
+ },
218
+ },
219
+ },
220
+ },
221
+ },
222
+ },
223
+ },
224
+ },
225
+ },
226
+ },
227
+ },
228
+ ],
229
+ })
230
+
231
+ expect(
232
+ (store.workspace.activeDocument?.paths?.['/users'].get as any)?.responses?.[200].content['application/json']
233
+ .schema.items.properties.name,
234
+ ).toEqual({
235
+ type: 'string',
236
+ description: 'The user name',
237
+ })
238
+ })
239
+
240
+ test('should correctly resolve chunks from the remote server', async () => {
241
+ server.get('/*', (req, res) => {
242
+ const path = req.url
243
+ const contents = serverStore.get(path)
244
+
245
+ res.send(contents)
246
+ })
247
+
248
+ const PORT = 9988
249
+ await server.listen({ port: PORT })
250
+
251
+ const serverStore = createServerWorkspaceStore({
252
+ mode: 'ssr',
253
+ baseUrl: `http://localhost:${PORT}`,
254
+ documents: [
255
+ {
256
+ name: 'default',
257
+ document,
258
+ },
259
+ ],
260
+ })
261
+
262
+ const store = await createWorkspaceStore({
263
+ documents: [
264
+ {
265
+ name: 'default',
266
+ document: serverStore.getWorkspace().documents['default'],
267
+ },
268
+ ],
269
+ })
270
+
271
+ // The operation should not be resolved on the fly
272
+ expect(store.workspace.activeDocument?.paths?.['/users'].get).toEqual({
273
+ '$ref': 'http://localhost:9988/default/operations/~1users/get#',
274
+ })
275
+
276
+ // We resolve the ref
277
+ await store.resolve(['paths', '/users', 'get'])
278
+
279
+ // We expect the ref to have been resolved with the correct contents
280
+ expect(store.workspace.activeDocument?.paths?.['/users'].get?.summary).toEqual(document.paths['/users'].get.summary)
281
+
282
+ expect(
283
+ (store.workspace.activeDocument?.paths?.['/users'].get as any).responses[200].content['application/json'].schema
284
+ .items,
285
+ ).toEqual(document.components.schemas.User)
286
+ })
287
+
288
+ test('should correctly resolve chunks from the file system', async () => {
289
+ const randomSeed = () => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)
290
+ const path = `temp-${randomSeed()}`
291
+
292
+ const serverStore = createServerWorkspaceStore({
293
+ mode: 'static',
294
+ directory: path,
295
+ documents: [
296
+ {
297
+ name: 'default',
298
+ document: document,
299
+ },
300
+ ],
301
+ })
302
+
303
+ await serverStore.generateWorkspaceChunks()
304
+
305
+ const buildPath = `${cwd()}/${path}`
306
+
307
+ // Read the workspace file to get the sparse document
308
+ const workspace = JSON.parse(
309
+ await fs.readFile(`${buildPath}/${WORKSPACE_FILE_NAME}`, { encoding: 'utf-8' }),
310
+ ) as Workspace
311
+
312
+ const store = await createWorkspaceStore({
313
+ documents: [
314
+ {
315
+ name: 'default',
316
+ document: workspace.documents['default'],
317
+ },
318
+ ],
319
+ })
320
+
321
+ // The operation should not be resolved on the fly
322
+ expect(store.workspace.activeDocument?.paths?.['/users'].get).toEqual({
323
+ '$ref': `${path}/chunks/default/operations/~1users/get.json#`,
324
+ })
325
+
326
+ // We resolve the ref
327
+ await store.resolve(['paths', '/users', 'get'])
328
+ await fs.rm(`${cwd()}/${path}`, { recursive: true })
329
+
330
+ // We expect the ref to have been resolved with the correct contents
331
+ expect(store.workspace.activeDocument?.paths?.['/users'].get?.summary).toEqual(document.paths['/users'].get.summary)
332
+
333
+ expect(
334
+ (store.workspace.activeDocument?.paths?.['/users'].get as any).responses[200].content['application/json'].schema
335
+ .items,
336
+ ).toEqual(document.components.schemas.User)
337
+
338
+ // clean up generated files
339
+ })
340
+
341
+ test('should load files form the remote url', async () => {
342
+ const PORT = 9989
343
+ const url = `http://localhost:${PORT}`
344
+
345
+ // Send the default document
346
+ server.get('/', (_, reply) => {
347
+ reply.send(document)
348
+ })
349
+
350
+ await server.listen({ port: PORT })
351
+
352
+ const store = await createWorkspaceStore({
353
+ documents: [
354
+ {
355
+ url: url,
356
+ name: 'default',
357
+ },
358
+ ],
359
+ })
360
+
361
+ expect(Object.keys(store.workspace.documents)).toEqual(['default'])
362
+ expect(store.workspace.documents['default'].info?.title).toEqual(document.info.title)
363
+
364
+ // Add a new remote file
365
+ await store.addDocument({ name: 'new', url: url })
366
+
367
+ expect(Object.keys(store.workspace.documents)).toEqual(['default', 'new'])
368
+ expect(store.workspace.documents['new'].info?.title).toEqual(document.info.title)
369
+ })
370
+
371
+ test('should load files from the local file system', async () => {
372
+ const fileName = 'temp.json'
373
+
374
+ // write the document to a local file
375
+ await fs.writeFile(fileName, JSON.stringify(document))
376
+
377
+ const store = await createWorkspaceStore({
378
+ documents: [
379
+ {
380
+ path: fileName,
381
+ name: 'default',
382
+ },
383
+ ],
384
+ })
385
+
386
+ expect(Object.keys(store.workspace.documents)).toEqual(['default'])
387
+ expect(store.workspace.documents['default'].info?.title).toEqual(document.info.title)
388
+
389
+ await store.addDocument({ name: 'new', path: fileName })
390
+ await fs.rm(fileName)
391
+
392
+ expect(Object.keys(store.workspace.documents)).toEqual(['default', 'new'])
393
+ expect(store.workspace.documents['new'].info?.title).toEqual(document.info.title)
394
+ })
395
+
396
+ test('should handle circular references when we try to resolve all remote chunks recursively', async () => {
397
+ const document = {
398
+ openapi: '3.0.0',
399
+ info: { title: 'My API' },
400
+ components: {
401
+ schemas: {
402
+ User: {
403
+ type: 'object',
404
+ properties: {
405
+ id: {
406
+ type: 'string',
407
+ description: 'The user ID',
408
+ },
409
+ name: {
410
+ $ref: '#/components/schemas/Rec',
411
+ },
412
+ },
413
+ },
414
+ Rec: {
415
+ type: 'object',
416
+ properties: {
417
+ id: {
418
+ $ref: '#/components/schemas/User',
419
+ },
420
+ },
421
+ },
422
+ },
423
+ },
424
+ paths: {
425
+ '/users': {
426
+ get: {
427
+ summary: 'Get all users',
428
+ responses: {
429
+ '200': {
430
+ description: 'Successful response',
431
+ content: {
432
+ 'application/json': {
433
+ schema: {
434
+ type: 'array',
435
+ items: {
436
+ $ref: '#/components/schemas/User',
437
+ },
438
+ },
439
+ },
440
+ },
441
+ },
442
+ },
443
+ },
444
+ },
445
+ },
446
+ }
447
+
448
+ server.get('/*', (req, res) => {
449
+ const path = req.url
450
+ const contents = serverStore.get(path)
451
+
452
+ res.send(contents)
453
+ })
454
+
455
+ const PORT = 6672
456
+ await server.listen({ port: PORT })
457
+
458
+ const serverStore = createServerWorkspaceStore({
459
+ mode: 'ssr',
460
+ baseUrl: `http://localhost:${PORT}`,
461
+ documents: [
462
+ {
463
+ name: 'default',
464
+ document,
465
+ },
466
+ ],
467
+ })
468
+
469
+ const store = await createWorkspaceStore({
470
+ documents: [
471
+ {
472
+ name: 'default',
473
+ document: serverStore.getWorkspace().documents['default'],
474
+ },
475
+ ],
476
+ })
477
+
478
+ // The operation should not be resolved on the fly
479
+ expect(store.workspace.activeDocument?.paths?.['/users'].get).toEqual({
480
+ '$ref': `http://localhost:${PORT}/default/operations/~1users/get#`,
481
+ })
482
+
483
+ // We resolve the ref
484
+ await store.resolve(['paths', '/users', 'get'])
485
+
486
+ expect((store.workspace.activeDocument?.components?.schemas?.['User'] as any)?.type).toBe('object')
487
+ })
488
+ })