@scalar/workspace-store 0.49.1 → 0.49.2
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.
- package/CHANGELOG.md +10 -0
- package/README.md +153 -121
- package/dist/client.d.ts +30 -13
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +151 -76
- package/dist/request-example/builder/helpers/get-example-from-schema.d.ts.map +1 -1
- package/dist/request-example/builder/helpers/get-example-from-schema.js +104 -2
- package/dist/request-example/types.d.ts +6 -7
- package/dist/request-example/types.d.ts.map +1 -1
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @scalar/workspace-store
|
|
2
2
|
|
|
3
|
+
## 0.49.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#8921](https://github.com/scalar/scalar/pull/8921): Prevent infinite recursion when validating defaults on circular composed schemas.
|
|
8
|
+
- [#9083](https://github.com/scalar/scalar/pull/9083): fix: prevent proxy leak into document meta breaking IndexedDB persistence
|
|
9
|
+
- [#9059](https://github.com/scalar/scalar/pull/9059): feat: added the scalar-app back to open source
|
|
10
|
+
- [#8921](https://github.com/scalar/scalar/pull/8921): fix nullable numeric schema defaults so empty-string defaults are normalized to null in generated request body examples.
|
|
11
|
+
- [#9050](https://github.com/scalar/scalar/pull/9050): chore: depricate intermediate document state
|
|
12
|
+
|
|
3
13
|
## 0.49.1
|
|
4
14
|
|
|
5
15
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@ A powerful data store for managing OpenAPI documents. This package provides a fl
|
|
|
7
7
|
Server side data store which enables document chunking to reduce initial loading time specially when working with large openapi documents
|
|
8
8
|
|
|
9
9
|
#### Usage
|
|
10
|
+
|
|
10
11
|
Create a new store in SSR mode
|
|
11
12
|
|
|
12
13
|
```ts
|
|
@@ -44,29 +45,32 @@ const store = await createServerWorkspaceStore({
|
|
|
44
45
|
})
|
|
45
46
|
|
|
46
47
|
// Add a new document to the store
|
|
47
|
-
await store.addDocument(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
48
|
+
await store.addDocument(
|
|
49
|
+
{
|
|
50
|
+
openapi: '3.1.1',
|
|
51
|
+
info: {
|
|
52
|
+
title: 'Hello World',
|
|
53
|
+
version: '1.0.0',
|
|
54
|
+
},
|
|
55
|
+
components: {
|
|
56
|
+
schemas: {
|
|
57
|
+
Person: {
|
|
58
|
+
type: 'object',
|
|
59
|
+
properties: {
|
|
60
|
+
name: { type: 'string' },
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
User: {
|
|
64
|
+
$ref: '#/components/schemas/Person',
|
|
59
65
|
},
|
|
60
|
-
},
|
|
61
|
-
User: {
|
|
62
|
-
$ref: '#/components/schemas/Person',
|
|
63
66
|
},
|
|
64
67
|
},
|
|
65
68
|
},
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
69
|
+
{
|
|
70
|
+
'name': 'document-2',
|
|
71
|
+
'x-scalar-selected-server': 'server1',
|
|
72
|
+
},
|
|
73
|
+
)
|
|
70
74
|
|
|
71
75
|
// Get the workspace
|
|
72
76
|
// Workspace is going to keep all the sparse documents
|
|
@@ -74,10 +78,8 @@ const workspace = store.getWorkspace()
|
|
|
74
78
|
|
|
75
79
|
// Get chucks using json pointers
|
|
76
80
|
const chunk = store.get('#/document-name/components/schemas/Person')
|
|
77
|
-
|
|
78
81
|
```
|
|
79
82
|
|
|
80
|
-
|
|
81
83
|
Create a new store in static mode
|
|
82
84
|
|
|
83
85
|
```ts
|
|
@@ -115,29 +117,32 @@ const store = await createServerWorkspaceStore({
|
|
|
115
117
|
})
|
|
116
118
|
|
|
117
119
|
// Add a new document to the store
|
|
118
|
-
await store.addDocument(
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
120
|
+
await store.addDocument(
|
|
121
|
+
{
|
|
122
|
+
openapi: '3.1.1',
|
|
123
|
+
info: {
|
|
124
|
+
title: 'Hello World',
|
|
125
|
+
version: '1.0.0',
|
|
126
|
+
},
|
|
127
|
+
components: {
|
|
128
|
+
schemas: {
|
|
129
|
+
Person: {
|
|
130
|
+
type: 'object',
|
|
131
|
+
properties: {
|
|
132
|
+
name: { type: 'string' },
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
User: {
|
|
136
|
+
$ref: '#/components/schemas/Person',
|
|
130
137
|
},
|
|
131
|
-
},
|
|
132
|
-
User: {
|
|
133
|
-
$ref: '#/components/schemas/Person',
|
|
134
138
|
},
|
|
135
139
|
},
|
|
136
140
|
},
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
141
|
+
{
|
|
142
|
+
'name': 'document-2',
|
|
143
|
+
'x-scalar-selected-server': 'server1',
|
|
144
|
+
},
|
|
145
|
+
)
|
|
141
146
|
|
|
142
147
|
// Generate the workspace file system
|
|
143
148
|
// This will write in the filesystem the workspace and all the chucks
|
|
@@ -146,6 +151,7 @@ const workspace = await store.generateWorkspaceChunks()
|
|
|
146
151
|
```
|
|
147
152
|
|
|
148
153
|
### Load documents from external sources
|
|
154
|
+
|
|
149
155
|
```ts
|
|
150
156
|
// Initialize the store with documents from external sources
|
|
151
157
|
const store = await createServerWorkspaceStore({
|
|
@@ -153,13 +159,13 @@ const store = await createServerWorkspaceStore({
|
|
|
153
159
|
documents: [
|
|
154
160
|
{
|
|
155
161
|
name: 'remoteFile',
|
|
156
|
-
url: 'http://localhost/document.json'
|
|
162
|
+
url: 'http://localhost/document.json',
|
|
157
163
|
},
|
|
158
164
|
{
|
|
159
165
|
name: 'fsFile',
|
|
160
|
-
path: './document.json'
|
|
161
|
-
}
|
|
162
|
-
]
|
|
166
|
+
path: './document.json',
|
|
167
|
+
},
|
|
168
|
+
],
|
|
163
169
|
})
|
|
164
170
|
|
|
165
171
|
// Output: { openapi: 'x.x.x', ... }
|
|
@@ -175,35 +181,38 @@ A reactive workspace store for managing OpenAPI documents with automatic referen
|
|
|
175
181
|
|
|
176
182
|
#### Usage
|
|
177
183
|
|
|
178
|
-
|
|
184
|
+
The client-side store starts empty and exposes `addDocument` for loading documents in. Workspace metadata, plugins, fetch overrides, and a file loader plugin can be supplied at construction time.
|
|
179
185
|
|
|
180
|
-
|
|
186
|
+
```ts
|
|
187
|
+
// Initialize a new (empty) workspace store
|
|
181
188
|
const store = createWorkspaceStore({
|
|
182
|
-
documents: [
|
|
183
|
-
{
|
|
184
|
-
name: 'default',
|
|
185
|
-
document: {
|
|
186
|
-
info: {
|
|
187
|
-
title: 'OpenApi document',
|
|
188
|
-
version: '1.0.0',
|
|
189
|
-
},
|
|
190
|
-
},
|
|
191
|
-
},
|
|
192
|
-
],
|
|
193
189
|
meta: {
|
|
194
190
|
'x-scalar-active-document': 'default',
|
|
195
191
|
},
|
|
196
192
|
})
|
|
197
193
|
|
|
198
|
-
// Add
|
|
194
|
+
// Add the default document
|
|
199
195
|
await store.addDocument({
|
|
196
|
+
name: 'default',
|
|
200
197
|
document: {
|
|
198
|
+
openapi: '3.1.0',
|
|
201
199
|
info: {
|
|
202
200
|
title: 'OpenApi document',
|
|
203
201
|
version: '1.0.0',
|
|
204
202
|
},
|
|
205
203
|
},
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
// Add another OpenAPI document to the workspace
|
|
207
|
+
await store.addDocument({
|
|
206
208
|
name: 'document',
|
|
209
|
+
document: {
|
|
210
|
+
openapi: '3.1.0',
|
|
211
|
+
info: {
|
|
212
|
+
title: 'Another document',
|
|
213
|
+
version: '1.0.0',
|
|
214
|
+
},
|
|
215
|
+
},
|
|
207
216
|
})
|
|
208
217
|
|
|
209
218
|
// Get the currently active document
|
|
@@ -216,7 +225,7 @@ store.workspace.documents['document']
|
|
|
216
225
|
store.update('x-scalar-color-mode', true)
|
|
217
226
|
|
|
218
227
|
// Update settings for the active document
|
|
219
|
-
store.updateDocument('active',
|
|
228
|
+
store.updateDocument('active', 'x-scalar-selected-server', 'production')
|
|
220
229
|
|
|
221
230
|
// Resolve and load document chunks including any $ref references
|
|
222
231
|
await store.resolve(['paths', '/users', 'get'])
|
|
@@ -224,7 +233,7 @@ await store.resolve(['paths', '/users', 'get'])
|
|
|
224
233
|
|
|
225
234
|
#### Load documents from external sources
|
|
226
235
|
|
|
227
|
-
|
|
236
|
+
The store can also load documents from a URL or, when a file loader plugin is configured, from the local filesystem. Each call returns a boolean indicating whether the document was added successfully.
|
|
228
237
|
|
|
229
238
|
```ts
|
|
230
239
|
const store = createWorkspaceStore()
|
|
@@ -232,7 +241,7 @@ const store = createWorkspaceStore()
|
|
|
232
241
|
// Load a document into the store from a remote url
|
|
233
242
|
await store.addDocument({
|
|
234
243
|
name: 'default',
|
|
235
|
-
url: 'http://localhost/document.json'
|
|
244
|
+
url: 'http://localhost/document.json',
|
|
236
245
|
})
|
|
237
246
|
|
|
238
247
|
// Output: { openapi: 'x.x.x', ... }
|
|
@@ -241,11 +250,13 @@ console.log(store.workspace.documents.default)
|
|
|
241
250
|
|
|
242
251
|
#### Document Persistence and Export
|
|
243
252
|
|
|
244
|
-
The workspace store
|
|
253
|
+
The workspace store keeps two snapshots per document at runtime: the **original** (the last saved baseline that the user committed to with `saveDocument`) and the **active** document (the reactive in-memory state, which may include unsaved edits). Most persistence methods are anchored on those two snapshots.
|
|
254
|
+
|
|
255
|
+
> **Deprecated:** an additional `intermediateDocuments` map and the helper methods `getIntermediateDocument` / `promoteIntermediateToOriginal` still exist for backward compatibility but are no longer authoritative. New code should rely on `getOriginalDocument` and the active document instead. The intermediate map is kept in sync on save / revert / rebase so existing consumers keep working until the layer is removed.
|
|
245
256
|
|
|
246
257
|
##### Export Document
|
|
247
258
|
|
|
248
|
-
Export the specified document in JSON or YAML format
|
|
259
|
+
Export the specified document in JSON or YAML format. The export reads from the saved baseline (the same content `revertDocumentChanges` would restore), so it always reflects the user's last save rather than any unsaved edits.
|
|
249
260
|
|
|
250
261
|
```ts
|
|
251
262
|
// Export the specified document as JSON
|
|
@@ -253,60 +264,57 @@ const jsonString = store.exportDocument('documentName', 'json')
|
|
|
253
264
|
|
|
254
265
|
// Export the specified document as YAML
|
|
255
266
|
const yamlString = store.exportDocument('documentName', 'yaml')
|
|
256
|
-
```
|
|
257
267
|
|
|
258
|
-
|
|
268
|
+
// Or export the currently active document directly
|
|
269
|
+
const activeJson = store.exportActiveDocument('json')
|
|
270
|
+
```
|
|
259
271
|
|
|
260
272
|
##### Save Document Changes
|
|
261
273
|
|
|
262
|
-
|
|
274
|
+
`saveDocument` promotes the current in-memory document to the new saved baseline. It serialises the reactive workspace document back into a plain shape (with bundler-internal keys stripped), writes it into the original-document map, and clears the document's `x-scalar-is-dirty` flag.
|
|
263
275
|
|
|
264
276
|
```ts
|
|
265
277
|
// Save the specified document state
|
|
266
|
-
const
|
|
278
|
+
const ok = await store.saveDocument('documentName')
|
|
267
279
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
console.log('Some changes were excluded:', excludedDiffs)
|
|
280
|
+
if (!ok) {
|
|
281
|
+
console.warn('Document does not exist or could not be serialised')
|
|
271
282
|
}
|
|
272
283
|
```
|
|
273
284
|
|
|
274
|
-
|
|
285
|
+
`saveDocument` returns `true` on success and `false` when the document does not exist or cannot be serialised back into the original map.
|
|
275
286
|
|
|
276
287
|
##### Revert Document Changes
|
|
277
288
|
|
|
278
|
-
Revert the specified document to its most recent
|
|
289
|
+
Revert the specified document to its most recent saved baseline, discarding all unsaved in-memory changes.
|
|
279
290
|
|
|
280
291
|
```ts
|
|
281
|
-
// Revert the specified document to its
|
|
282
|
-
store.revertDocumentChanges('documentName')
|
|
292
|
+
// Revert the specified document to its last saved state
|
|
293
|
+
await store.revertDocumentChanges('documentName')
|
|
283
294
|
```
|
|
284
295
|
|
|
285
|
-
The `revertDocumentChanges` method restores the
|
|
296
|
+
The `revertDocumentChanges` method restores the active document from the original-document map, which is whatever `saveDocument` last wrote (or the document as it was first loaded into the workspace if it has never been saved).
|
|
286
297
|
|
|
287
298
|
**Warning:** This operation will discard all unsaved changes to the specified document.
|
|
288
299
|
|
|
289
300
|
##### Complete Example
|
|
290
301
|
|
|
291
302
|
```ts
|
|
292
|
-
const store = createWorkspaceStore(
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
},
|
|
301
|
-
},
|
|
302
|
-
],
|
|
303
|
+
const store = createWorkspaceStore()
|
|
304
|
+
await store.addDocument({
|
|
305
|
+
name: 'api',
|
|
306
|
+
document: {
|
|
307
|
+
openapi: '3.0.0',
|
|
308
|
+
info: { title: 'My API', version: '1.0.0' },
|
|
309
|
+
paths: {},
|
|
310
|
+
},
|
|
303
311
|
})
|
|
304
312
|
|
|
305
313
|
// Make some changes to the document
|
|
306
314
|
store.workspace.documents['api'].info.title = 'Updated API Title'
|
|
307
315
|
|
|
308
|
-
//
|
|
309
|
-
store.revertDocumentChanges()
|
|
316
|
+
// Restore the saved baseline since the changes were never saved
|
|
317
|
+
await store.revertDocumentChanges('api')
|
|
310
318
|
```
|
|
311
319
|
|
|
312
320
|
### Workspace State Persistence
|
|
@@ -329,28 +337,25 @@ client.loadWorkspace(currentWorkspaceState)
|
|
|
329
337
|
When you have a new or updated OpenAPI document and want to overwrite the existing one—regardless of which parts have changed—you can use the `replaceDocument` method. This method efficiently and atomically updates the entire document in place, ensuring that only the necessary changes are applied for optimal performance.
|
|
330
338
|
|
|
331
339
|
```ts
|
|
332
|
-
const client = createWorkspaceStore(
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
version: '1.0.0',
|
|
341
|
-
},
|
|
342
|
-
paths: {},
|
|
343
|
-
components: {
|
|
344
|
-
schemas: {},
|
|
345
|
-
},
|
|
346
|
-
servers: [],
|
|
347
|
-
},
|
|
340
|
+
const client = createWorkspaceStore()
|
|
341
|
+
await client.addDocument({
|
|
342
|
+
name: 'document-name',
|
|
343
|
+
document: {
|
|
344
|
+
openapi: '3.1.0',
|
|
345
|
+
info: {
|
|
346
|
+
title: 'Document Title',
|
|
347
|
+
version: '1.0.0',
|
|
348
348
|
},
|
|
349
|
-
|
|
349
|
+
paths: {},
|
|
350
|
+
components: {
|
|
351
|
+
schemas: {},
|
|
352
|
+
},
|
|
353
|
+
servers: [],
|
|
354
|
+
},
|
|
350
355
|
})
|
|
351
356
|
|
|
352
357
|
// Update the document with the new changes
|
|
353
|
-
client.replaceDocument('document-name', {
|
|
358
|
+
await client.replaceDocument('document-name', {
|
|
354
359
|
openapi: '3.1.0',
|
|
355
360
|
info: {
|
|
356
361
|
title: 'Updated Document',
|
|
@@ -370,13 +375,13 @@ Create the workspace from a specification object
|
|
|
370
375
|
|
|
371
376
|
```ts
|
|
372
377
|
await store.importWorkspaceFromSpecification({
|
|
373
|
-
workspace: 'draft',
|
|
374
|
-
info: { title: 'My Workspace' },
|
|
375
|
-
documents: {
|
|
378
|
+
'workspace': 'draft',
|
|
379
|
+
'info': { title: 'My Workspace' },
|
|
380
|
+
'documents': {
|
|
376
381
|
api: { $ref: '/examples/api.yaml' },
|
|
377
382
|
petstore: { $ref: '/examples/petstore.yaml' },
|
|
378
383
|
},
|
|
379
|
-
overrides: {
|
|
384
|
+
'overrides': {
|
|
380
385
|
api: {
|
|
381
386
|
servers: [
|
|
382
387
|
{
|
|
@@ -414,10 +419,10 @@ await store.addDocument({
|
|
|
414
419
|
servers: [
|
|
415
420
|
{
|
|
416
421
|
url: 'http://localhost:8080',
|
|
417
|
-
description: 'Default dev server'
|
|
418
|
-
}
|
|
419
|
-
]
|
|
420
|
-
}
|
|
422
|
+
description: 'Default dev server',
|
|
423
|
+
},
|
|
424
|
+
],
|
|
425
|
+
},
|
|
421
426
|
})
|
|
422
427
|
```
|
|
423
428
|
|
|
@@ -425,13 +430,40 @@ When you override specific fields, those changes are applied only in-memory and
|
|
|
425
430
|
|
|
426
431
|
### Rebase document origin with the updated remote origin
|
|
427
432
|
|
|
428
|
-
|
|
433
|
+
`rebaseDocument` reconciles a workspace document with a new upstream origin. It performs a two-way merge between:
|
|
434
|
+
|
|
435
|
+
- the **incoming changes** — `diff(originalDocument, newOrigin)`
|
|
436
|
+
- the **local changes** — `diff(originalDocument, activeDocument)`
|
|
437
|
+
|
|
438
|
+
The call returns a discriminated result. On `ok: false` the `type` field describes why the rebase did not run (`CORRUPTED_STATE`, `FETCH_FAILED`, or `NO_CHANGES_DETECTED`). On `ok: true` it exposes the auto-mergeable `changes`, the `conflicts` that need user input, and an `applyChanges` callback that writes the merged result back into the workspace.
|
|
429
439
|
|
|
430
440
|
```ts
|
|
431
|
-
//
|
|
432
|
-
const
|
|
433
|
-
|
|
434
|
-
//
|
|
435
|
-
|
|
441
|
+
// Fetch the latest origin and start a rebase
|
|
442
|
+
const result = await store.rebaseDocument({
|
|
443
|
+
name: 'api',
|
|
444
|
+
// Any `WorkspaceDocumentInput` is accepted - inline document, url, or path
|
|
445
|
+
url: 'https://example.com/api/openapi.json',
|
|
446
|
+
})
|
|
447
|
+
|
|
448
|
+
if (!result.ok) {
|
|
449
|
+
console.warn(`Rebase did not run: ${result.type}`)
|
|
450
|
+
return
|
|
436
451
|
}
|
|
437
|
-
|
|
452
|
+
|
|
453
|
+
if (result.conflicts.length === 0) {
|
|
454
|
+
// No conflicts - just apply with an empty resolution set
|
|
455
|
+
await result.applyChanges({ resolvedConflicts: [] })
|
|
456
|
+
return
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Surface the conflicts to the user. Each conflict is a tuple of
|
|
460
|
+
// [incomingDiffs, localDiffs] - resolve by picking either side, or by
|
|
461
|
+
// providing a fully resolved document.
|
|
462
|
+
const resolvedConflicts = result.conflicts.flatMap(([incoming]) => incoming)
|
|
463
|
+
await result.applyChanges({ resolvedConflicts })
|
|
464
|
+
|
|
465
|
+
// Or, pass a complete document to use as-is (overrides the merge result):
|
|
466
|
+
await result.applyChanges({ resolvedDocument: newDocument })
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
After `applyChanges` returns, the merged document becomes both the new active document and the new saved baseline, so a subsequent `revertDocumentChanges` rolls back to the post-rebase state rather than the pre-rebase original.
|
package/dist/client.d.ts
CHANGED
|
@@ -249,26 +249,36 @@ export type WorkspaceStore = {
|
|
|
249
249
|
*
|
|
250
250
|
* @param documentName - The name of the document to get the intermediate version of.
|
|
251
251
|
* @returns The intermediate version of the document, or undefined if the document does not exist.
|
|
252
|
+
*
|
|
253
|
+
* @deprecated The intermediate document layer is being phased out. The
|
|
254
|
+
* workspace store now keeps only two snapshots per document: the original
|
|
255
|
+
* (last saved / loaded baseline) and the active in-memory state. Use
|
|
256
|
+
* `getOriginalDocument` to read the saved baseline. The `intermediateDocuments`
|
|
257
|
+
* map is no longer updated by `saveDocument` or `rebaseDocument` and only
|
|
258
|
+
* reflects the document as it was first loaded into the workspace.
|
|
252
259
|
*/
|
|
253
260
|
getIntermediateDocument(documentName: string): Record<string, unknown> | null;
|
|
254
261
|
/**
|
|
255
|
-
* Saves the current state of the specified document
|
|
262
|
+
* Saves the current state of the specified document as the new baseline.
|
|
256
263
|
*
|
|
257
|
-
* This function captures the latest (reactive) state of the document from
|
|
258
|
-
*
|
|
259
|
-
*
|
|
260
|
-
*
|
|
264
|
+
* This function captures the latest (reactive) state of the document from
|
|
265
|
+
* the workspace and writes a deep clone of it back into the
|
|
266
|
+
* `originalDocuments` map - effectively promoting the in-memory state to
|
|
267
|
+
* the new "last saved" snapshot. After saving, `getOriginalDocument`
|
|
268
|
+
* returns the persisted edits and `revertDocumentChanges` rolls back to
|
|
269
|
+
* exactly this state.
|
|
261
270
|
*
|
|
262
271
|
* The update is performed in-place. A deep clone of the current document
|
|
263
|
-
* state is used to avoid mutating the reactive object directly.
|
|
272
|
+
* state is used to avoid mutating the reactive object directly. The
|
|
273
|
+
* dirty flag (`x-scalar-is-dirty`) is cleared on success.
|
|
264
274
|
*
|
|
265
275
|
* @param documentName - The name of the document to save.
|
|
266
|
-
* @returns
|
|
267
|
-
*
|
|
276
|
+
* @returns `true` when the save succeeded, `false` if the document does
|
|
277
|
+
* not exist or cannot be serialised back into the original map.
|
|
268
278
|
*
|
|
269
279
|
* @example
|
|
270
280
|
* // Save the current state of the document named 'api'
|
|
271
|
-
* const isSuccess = store.saveDocument('api')
|
|
281
|
+
* const isSuccess = await store.saveDocument('api')
|
|
272
282
|
* if (isSuccess) {
|
|
273
283
|
* console.log('Document saved successfully')
|
|
274
284
|
* } else {
|
|
@@ -286,10 +296,11 @@ export type WorkspaceStore = {
|
|
|
286
296
|
/**
|
|
287
297
|
* Restores the specified document to its last locally saved state.
|
|
288
298
|
*
|
|
289
|
-
* This method updates the current reactive document (in the workspace)
|
|
290
|
-
* corresponding
|
|
291
|
-
* any unsaved in-memory
|
|
292
|
-
*
|
|
299
|
+
* This method updates the current reactive document (in the workspace)
|
|
300
|
+
* with the contents of the corresponding original document (from the
|
|
301
|
+
* `originalDocuments` map), effectively discarding any unsaved in-memory
|
|
302
|
+
* changes and reverting to the last saved version. Vue reactivity is
|
|
303
|
+
* preserved by updating the existing reactive object in place.
|
|
293
304
|
*
|
|
294
305
|
* **Warning:** This operation will discard all unsaved (in-memory) changes to the specified document.
|
|
295
306
|
*
|
|
@@ -318,6 +329,12 @@ export type WorkspaceStore = {
|
|
|
318
329
|
* } else {
|
|
319
330
|
* console.log('Intermediate document does not exist')
|
|
320
331
|
* }
|
|
332
|
+
*
|
|
333
|
+
* @deprecated The intermediate document layer is being phased out.
|
|
334
|
+
* `saveDocument` already writes directly to `originalDocuments`, so this
|
|
335
|
+
* method has no remaining responsibility once the intermediate map stops
|
|
336
|
+
* being updated. It is kept for API compatibility and will be removed in
|
|
337
|
+
* a future release.
|
|
321
338
|
*/
|
|
322
339
|
promoteIntermediateToOriginal(documentName: string): boolean;
|
|
323
340
|
/**
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
CHANGED
|
@@ -101,6 +101,40 @@ const METADATA_ONLY_DOCUMENT_KEYS = new Set([
|
|
|
101
101
|
// conflict cache).
|
|
102
102
|
'x-scalar-registry-meta',
|
|
103
103
|
]);
|
|
104
|
+
/**
|
|
105
|
+
* Removes internal and metadata keys from the provided document object.
|
|
106
|
+
*
|
|
107
|
+
* This function deletes a list of known internal keys that are only meant for
|
|
108
|
+
* in-memory/document processing use and should not be present in the final bundled document.
|
|
109
|
+
* Most of these keys are injected by the bundler or used for Scalar OpenAPI document state tracking.
|
|
110
|
+
*
|
|
111
|
+
* Note: Nested internal keys are handled elsewhere in the bundler pipeline.
|
|
112
|
+
*
|
|
113
|
+
* @param document - The OpenAPI document object to be sanitized in-place.
|
|
114
|
+
*/
|
|
115
|
+
const purgeInternalDocumentKeys = (input) => {
|
|
116
|
+
const result = deepClone(input);
|
|
117
|
+
// Top level keys that need to be excluded from the original document
|
|
118
|
+
// Nested keys are removed during the previous step of the bundler process
|
|
119
|
+
const EXCLUDE_KEYS = [
|
|
120
|
+
// Bundler metadata fields added temporarily during document processing
|
|
121
|
+
'x-ext',
|
|
122
|
+
'x-ext-urls',
|
|
123
|
+
// Scalar internal/external metadata fields
|
|
124
|
+
'x-scalar-navigation',
|
|
125
|
+
'x-scalar-is-dirty',
|
|
126
|
+
'x-original-oas-version',
|
|
127
|
+
'x-scalar-original-document-hash',
|
|
128
|
+
'x-scalar-original-source-url',
|
|
129
|
+
'x-scalar-registry-meta',
|
|
130
|
+
];
|
|
131
|
+
// Remove top-level properties that should only exist temporarily or for internal usage
|
|
132
|
+
// These properties are used for internal purposes and are not needed in the final bundled document
|
|
133
|
+
for (const property of EXCLUDE_KEYS) {
|
|
134
|
+
delete result[property];
|
|
135
|
+
}
|
|
136
|
+
return result;
|
|
137
|
+
};
|
|
104
138
|
/**
|
|
105
139
|
* Creates a reactive workspace store that manages documents and their metadata.
|
|
106
140
|
* The store provides functionality for accessing, updating, and resolving document references.
|
|
@@ -351,20 +385,27 @@ export const createWorkspaceStore = (workspaceProps) => {
|
|
|
351
385
|
return workspace[extensions.workspace.activeDocument] ?? Object.keys(workspace.documents)[0] ?? '';
|
|
352
386
|
}
|
|
353
387
|
function exportDocument(documentName, format, minify) {
|
|
354
|
-
|
|
355
|
-
|
|
388
|
+
// The original document map now holds the most recently saved state of
|
|
389
|
+
// the document - `saveDocument` writes directly into it and
|
|
390
|
+
// `revertDocumentChanges` reads from it. Exporting therefore mirrors
|
|
391
|
+
// exactly what the user would get if they reverted to the last save.
|
|
392
|
+
const savedDocument = originalDocuments[documentName];
|
|
393
|
+
if (!savedDocument) {
|
|
356
394
|
return;
|
|
357
395
|
}
|
|
358
396
|
if (format === 'json') {
|
|
359
|
-
return minify ? JSON.stringify(
|
|
397
|
+
return minify ? JSON.stringify(savedDocument) : JSON.stringify(savedDocument, null, 2);
|
|
360
398
|
}
|
|
361
|
-
return YAML.stringify(
|
|
399
|
+
return YAML.stringify(savedDocument);
|
|
362
400
|
}
|
|
363
|
-
// Save the current state of the specified document
|
|
364
|
-
//
|
|
365
|
-
//
|
|
366
|
-
//
|
|
367
|
-
//
|
|
401
|
+
// Save the current state of the specified document as the new baseline.
|
|
402
|
+
// The reactive workspace document is serialised back into a plain shape
|
|
403
|
+
// (with bundler-internal keys stripped) and stored under
|
|
404
|
+
// `originalDocuments[documentName]` - the original map is now the single
|
|
405
|
+
// source of truth for "what the user has saved". The intermediate map is
|
|
406
|
+
// deprecated, but we keep mirroring writes into it so any consumer still
|
|
407
|
+
// reading from `getIntermediateDocument` observes fresh content while
|
|
408
|
+
// the layer is being phased out.
|
|
368
409
|
const saveDocument = async (documentName) => {
|
|
369
410
|
const activeDocument = workspace.documents[documentName];
|
|
370
411
|
const newDocument = await getEditableDocument(documentName);
|
|
@@ -372,15 +413,19 @@ export const createWorkspaceStore = (workspaceProps) => {
|
|
|
372
413
|
console.warn('Failed to save document, active document is missing');
|
|
373
414
|
return false;
|
|
374
415
|
}
|
|
375
|
-
//
|
|
376
|
-
|
|
416
|
+
// Promote the in-memory edits to the new saved baseline. Two stores
|
|
417
|
+
// get a deep clone each so subsequent mutations on either one stay
|
|
418
|
+
// isolated.
|
|
419
|
+
originalDocuments[documentName] = newDocument;
|
|
420
|
+
intermediateDocuments[documentName] = deepClone(newDocument);
|
|
377
421
|
// Mark the document as not dirty since we are saving it
|
|
378
422
|
activeDocument['x-scalar-is-dirty'] = false;
|
|
379
423
|
return true;
|
|
380
424
|
};
|
|
381
425
|
// Add a document to the store synchronously from an in-memory OpenAPI document
|
|
382
426
|
async function addInMemoryDocument(input, navigationOptions) {
|
|
383
|
-
const { name
|
|
427
|
+
const { name } = input;
|
|
428
|
+
const meta = deepClone(input.meta);
|
|
384
429
|
const clonedRawInputDocument = withMeasurementSync('deepClone', () => deepClone(input.document));
|
|
385
430
|
withMeasurementSync('initialize', () => {
|
|
386
431
|
if (input.initialize !== false) {
|
|
@@ -524,17 +569,18 @@ export const createWorkspaceStore = (workspaceProps) => {
|
|
|
524
569
|
return rawDocument;
|
|
525
570
|
};
|
|
526
571
|
/**
|
|
527
|
-
* Promotes the intermediate document to the original document so the
|
|
528
|
-
* intermediate becomes the new baseline.
|
|
572
|
+
* Promotes the intermediate document to the original document so the
|
|
573
|
+
* current intermediate becomes the new baseline.
|
|
574
|
+
*
|
|
575
|
+
* The intermediate layer is deprecated: `saveDocument` now writes
|
|
576
|
+
* directly into `originalDocuments`, so by the time anyone could call
|
|
577
|
+
* this method the original map already holds the latest saved baseline.
|
|
578
|
+
* Copying the (now stale) intermediate over the original would clobber
|
|
579
|
+
* the user's save, so this is a no-op for existing documents and only
|
|
580
|
+
* reports `false` when the document does not exist at all.
|
|
529
581
|
*/
|
|
530
582
|
const promoteIntermediateToOriginal = (documentName) => {
|
|
531
|
-
|
|
532
|
-
if (!intermediate) {
|
|
533
|
-
return false;
|
|
534
|
-
}
|
|
535
|
-
const cloned = deepClone(unpackProxyObject(intermediate, { depth: 1 }));
|
|
536
|
-
originalDocuments[documentName] = cloned;
|
|
537
|
-
return true;
|
|
583
|
+
return Boolean(intermediateDocuments[documentName]);
|
|
538
584
|
};
|
|
539
585
|
/**
|
|
540
586
|
* Retrieves an editable clone of a workspace document.
|
|
@@ -558,25 +604,7 @@ export const createWorkspaceStore = (workspaceProps) => {
|
|
|
558
604
|
treeShake: false,
|
|
559
605
|
urlMap: true,
|
|
560
606
|
}));
|
|
561
|
-
|
|
562
|
-
// Nested keys are removed buring the previous step of the bundler process
|
|
563
|
-
const EXCLUDE_KEYS = [
|
|
564
|
-
// Bundler metadata fields added temporarily during document processing
|
|
565
|
-
'x-ext',
|
|
566
|
-
'x-ext-urls',
|
|
567
|
-
// Scalar internal/external metadata fields
|
|
568
|
-
'x-scalar-navigation',
|
|
569
|
-
'x-scalar-is-dirty',
|
|
570
|
-
'x-original-oas-version',
|
|
571
|
-
'x-scalar-original-document-hash',
|
|
572
|
-
'x-scalar-original-source-url',
|
|
573
|
-
];
|
|
574
|
-
// Remove top level properties that should only exist in memory for the original document
|
|
575
|
-
// These properties are used for internal purposes and are not needed in the final bundled document
|
|
576
|
-
for (const property of EXCLUDE_KEYS) {
|
|
577
|
-
delete original[property];
|
|
578
|
-
}
|
|
579
|
-
return original;
|
|
607
|
+
return purgeInternalDocumentKeys(original);
|
|
580
608
|
};
|
|
581
609
|
/**
|
|
582
610
|
* Builds (or updates) the navigation sidebar for the specified document.
|
|
@@ -634,7 +662,8 @@ export const createWorkspaceStore = (workspaceProps) => {
|
|
|
634
662
|
return true;
|
|
635
663
|
},
|
|
636
664
|
async replaceDocument(documentName, input) {
|
|
637
|
-
|
|
665
|
+
// Used to preserve the original metadata of the document (we need to unpack so we don't store a proxy object)
|
|
666
|
+
const currentDocument = unpackProxyObject(workspace.documents[documentName], { depth: 1 });
|
|
638
667
|
if (!currentDocument) {
|
|
639
668
|
return console.error(`Document '${documentName}' does not exist in the workspace.`);
|
|
640
669
|
}
|
|
@@ -646,6 +675,8 @@ export const createWorkspaceStore = (workspaceProps) => {
|
|
|
646
675
|
documentSource: currentDocument['x-scalar-original-source-url'],
|
|
647
676
|
documentHash: currentDocument['x-scalar-original-document-hash'],
|
|
648
677
|
meta: {
|
|
678
|
+
// Preserve the registry meta
|
|
679
|
+
'x-scalar-registry-meta': currentDocument['x-scalar-registry-meta'],
|
|
649
680
|
// Set the document as dirty
|
|
650
681
|
'x-scalar-is-dirty': true,
|
|
651
682
|
// Clear the navigation to trigger a rebuild
|
|
@@ -711,17 +742,30 @@ export const createWorkspaceStore = (workspaceProps) => {
|
|
|
711
742
|
saveDocument,
|
|
712
743
|
promoteIntermediateToOriginal,
|
|
713
744
|
async revertDocumentChanges(documentName) {
|
|
714
|
-
|
|
715
|
-
const
|
|
716
|
-
|
|
745
|
+
// Used to preserve the original metadata of the document (we need to unpack so we don't store a proxy object)
|
|
746
|
+
const workspaceDocument = unpackProxyObject(workspace.documents[documentName], { depth: 1 });
|
|
747
|
+
// Restore from the original (last saved) snapshot. `saveDocument`
|
|
748
|
+
// writes here, so this reliably rolls back to whatever the user
|
|
749
|
+
// last persisted - matching the soft-deprecation path away from the
|
|
750
|
+
// intermediate document layer.
|
|
751
|
+
const baseline = unpackProxyObject(originalDocuments[documentName], { depth: 1 });
|
|
752
|
+
if (!workspaceDocument || !baseline) {
|
|
717
753
|
return;
|
|
718
754
|
}
|
|
755
|
+
// Keep the deprecated intermediate map aligned with the original so
|
|
756
|
+
// any consumer still reading from `getIntermediateDocument` sees the
|
|
757
|
+
// post-revert state instead of the pre-revert one.
|
|
758
|
+
intermediateDocuments[documentName] = deepClone(baseline);
|
|
719
759
|
await addInMemoryDocument({
|
|
720
760
|
name: documentName,
|
|
721
|
-
document:
|
|
761
|
+
document: baseline,
|
|
722
762
|
documentSource: workspaceDocument['x-scalar-original-source-url'],
|
|
723
763
|
documentHash: workspaceDocument['x-scalar-original-document-hash'],
|
|
724
764
|
initialize: false,
|
|
765
|
+
meta: {
|
|
766
|
+
// Preserve the registry meta
|
|
767
|
+
'x-scalar-registry-meta': workspaceDocument['x-scalar-registry-meta'],
|
|
768
|
+
},
|
|
725
769
|
});
|
|
726
770
|
},
|
|
727
771
|
commitDocument(documentName) {
|
|
@@ -770,18 +814,21 @@ export const createWorkspaceStore = (workspaceProps) => {
|
|
|
770
814
|
rebaseDocument: async (input) => {
|
|
771
815
|
const { name } = input;
|
|
772
816
|
// ---- Get the current documents
|
|
817
|
+
// The intermediate snapshot has been deprecated. Rebase now reasons
|
|
818
|
+
// about exactly two local snapshots: the original (last saved
|
|
819
|
+
// baseline, written by `saveDocument`) and the active in-memory
|
|
820
|
+
// document (with any unsaved edits on top).
|
|
773
821
|
const originalDocument = unpackProxyObject(originalDocuments[name], { depth: 1 });
|
|
774
|
-
const intermediateDocument = unpackProxyObject(intermediateDocuments[name], { depth: 1 });
|
|
775
822
|
// raw version without any proxies
|
|
776
|
-
const
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
if (!originalDocument || !
|
|
823
|
+
const activeDocumentRaw = unpackProxyObject(workspace.documents[name], { depth: 1 });
|
|
824
|
+
// editable version of the document (reversing bundling and also remove internal metadata)
|
|
825
|
+
const activeDocument = await getEditableDocument(name);
|
|
826
|
+
if (!originalDocument || !activeDocument || !activeDocumentRaw) {
|
|
780
827
|
// If any required document state is missing, do nothing
|
|
781
828
|
return {
|
|
782
829
|
ok: false,
|
|
783
830
|
type: 'CORRUPTED_STATE',
|
|
784
|
-
message: `Cannot rebase document '${name}': missing original
|
|
831
|
+
message: `Cannot rebase document '${name}': missing original or active document state`,
|
|
785
832
|
};
|
|
786
833
|
}
|
|
787
834
|
// ---- Resolve input document
|
|
@@ -800,7 +847,7 @@ export const createWorkspaceStore = (workspaceProps) => {
|
|
|
800
847
|
// Compare document hashes to see if the document has changed
|
|
801
848
|
// When the hashes match, we can skip the rebase process
|
|
802
849
|
const newHash = generateHash(resolve.raw);
|
|
803
|
-
if (
|
|
850
|
+
if (activeDocumentRaw['x-scalar-original-document-hash'] === newHash) {
|
|
804
851
|
return {
|
|
805
852
|
ok: false,
|
|
806
853
|
type: 'NO_CHANGES_DETECTED',
|
|
@@ -811,46 +858,67 @@ export const createWorkspaceStore = (workspaceProps) => {
|
|
|
811
858
|
// ---- Override the configurations and metadata
|
|
812
859
|
overrides[name] = input.overrides ?? {};
|
|
813
860
|
extraDocumentConfigurations[name] = { fetch: input.fetch };
|
|
814
|
-
// ----
|
|
815
|
-
|
|
861
|
+
// ---- Compute the merge between upstream and local edits
|
|
862
|
+
// Two-way merge anchored on the original (last saved) snapshot:
|
|
863
|
+
// - changelogIncoming: changes the registry made on top of the
|
|
864
|
+
// original (what we want to pull in)
|
|
865
|
+
// - changelogLocal: changes the user has made on top of the
|
|
866
|
+
// original since the last save (what we want to keep)
|
|
867
|
+
const changelogIncoming = diff(originalDocument, newDocumentOrigin);
|
|
816
868
|
// When there are no changes, we can return early since we don't need to do anything
|
|
817
869
|
// This is not supposed to happen due to the hash check above, but just in case
|
|
818
|
-
if (
|
|
870
|
+
if (changelogIncoming.length === 0) {
|
|
819
871
|
return {
|
|
820
872
|
ok: false,
|
|
821
873
|
type: 'NO_CHANGES_DETECTED',
|
|
822
874
|
message: `No changes detected for document '${name}' after fetching the latest version.`,
|
|
823
875
|
};
|
|
824
876
|
}
|
|
825
|
-
const
|
|
826
|
-
const
|
|
877
|
+
const changelogLocal = diff(originalDocument, activeDocument);
|
|
878
|
+
const merged = merge(changelogIncoming, changelogLocal);
|
|
827
879
|
return {
|
|
828
880
|
ok: true,
|
|
829
|
-
conflicts:
|
|
830
|
-
changes:
|
|
881
|
+
conflicts: merged.conflicts,
|
|
882
|
+
changes: merged.diffs,
|
|
831
883
|
applyChanges: async (applyChangesInput) => {
|
|
832
|
-
// Helper function to compute the new
|
|
833
|
-
|
|
884
|
+
// Helper function to compute the new active document based on
|
|
885
|
+
// resolved conflicts or a resolved document. With the
|
|
886
|
+
// intermediate layer gone, the merged result *is* the new
|
|
887
|
+
// active document - there is no longer an intermediate hop.
|
|
888
|
+
const getNewActiveDocument = () => {
|
|
834
889
|
if ('resolvedConflicts' in applyChangesInput) {
|
|
835
|
-
const
|
|
890
|
+
const changeset = merged.diffs.concat(applyChangesInput.resolvedConflicts);
|
|
836
891
|
// Apply the merged changes (diffs + resolved conflicts) to the original document
|
|
837
|
-
return apply(deepClone(originalDocument),
|
|
892
|
+
return apply(deepClone(originalDocument), changeset);
|
|
838
893
|
}
|
|
839
|
-
// If
|
|
894
|
+
// If the caller provided a fully resolved document, use it as-is.
|
|
840
895
|
return applyChangesInput.resolvedDocument;
|
|
841
896
|
};
|
|
842
|
-
const
|
|
843
|
-
|
|
844
|
-
//
|
|
845
|
-
|
|
846
|
-
//
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
//
|
|
851
|
-
//
|
|
852
|
-
|
|
853
|
-
|
|
897
|
+
const mergedDocument = getNewActiveDocument();
|
|
898
|
+
const newActiveDocument = coerceValue(OpenAPIDocumentSchemaStrict, mergedDocument);
|
|
899
|
+
// Detect whether the rebase folded in any local edits. When the
|
|
900
|
+
// merged result matches the upstream snapshot the pull was
|
|
901
|
+
// effectively a fast-forward (no unsaved local work to carry
|
|
902
|
+
// over), so the document is clean relative to the registry.
|
|
903
|
+
// When it differs we still hold unpushed changes locally - flag
|
|
904
|
+
// the document as dirty so the push flow can surface them, the
|
|
905
|
+
// same way `git pull --rebase` leaves you "ahead of origin"
|
|
906
|
+
// once your local commits get replayed on top.
|
|
907
|
+
//
|
|
908
|
+
// We compare the pre-coerce merged document against upstream
|
|
909
|
+
// because `coerceValue` normalises the merged result against
|
|
910
|
+
// the strict schema and that normalisation can introduce diffs
|
|
911
|
+
// even for pure fast-forwards. The merged document is what the
|
|
912
|
+
// two-way merge actually produced, so its byte-for-byte equality
|
|
913
|
+
// with upstream is the real fast-forward signal.
|
|
914
|
+
const hasLocalChangesAgainstUpstream = diff(newDocumentOrigin, mergedDocument).length > 0;
|
|
915
|
+
// The merged result becomes the new saved baseline so a subsequent
|
|
916
|
+
// revert restores to the post-rebase state, not to the
|
|
917
|
+
// pre-rebase original. Mirror the same content into the
|
|
918
|
+
// deprecated intermediate map so any lingering consumer reads
|
|
919
|
+
// the post-rebase state too.
|
|
920
|
+
originalDocuments[name] = newActiveDocument;
|
|
921
|
+
intermediateDocuments[name] = deepClone(newActiveDocument);
|
|
854
922
|
// add the new active document to the workspace but don't re-initialize
|
|
855
923
|
await addInMemoryDocument({
|
|
856
924
|
...input,
|
|
@@ -864,6 +932,13 @@ export const createWorkspaceStore = (workspaceProps) => {
|
|
|
864
932
|
// Update the original document hash
|
|
865
933
|
documentHash: generateHash(resolve.raw),
|
|
866
934
|
initialize: false,
|
|
935
|
+
meta: {
|
|
936
|
+
...input.meta,
|
|
937
|
+
// Preserve the registry meta
|
|
938
|
+
'x-scalar-registry-meta': activeDocumentRaw['x-scalar-registry-meta'],
|
|
939
|
+
// Flag local edits that need pushing - see note above.
|
|
940
|
+
'x-scalar-is-dirty': hasLocalChangesAgainstUpstream,
|
|
941
|
+
},
|
|
867
942
|
});
|
|
868
943
|
},
|
|
869
944
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-example-from-schema.d.ts","sourceRoot":"","sources":["../../../../src/request-example/builder/helpers/get-example-from-schema.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wCAAwC,CAAA;
|
|
1
|
+
{"version":3,"file":"get-example-from-schema.d.ts","sourceRoot":"","sources":["../../../../src/request-example/builder/helpers/get-example-from-schema.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wCAAwC,CAAA;AAsnB1E,KAAK,2BAA2B,GAAG;IACjC,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,4CAA4C;IAC5C,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IACvB,iEAAiE;IACjE,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACnC,qDAAqD;IACrD,8BAA8B,CAAC,EAAE,OAAO,CAAA;IACxC,0DAA0D;IAC1D,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC9C,CAAA;AAeD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,oBAAoB,GAC/B,QAAQ,YAAY,EACpB,UAAU,2BAA2B,EACrC,mDAMG,OAAO,CAAC;IACT,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,YAAY,CAAA;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;IACrB,6EAA6E;IAC7E,UAAU,EAAE,MAAM,EAAE,CAAA;CACrB,CAAM,KACN,OAqKF,CAAA"}
|
|
@@ -172,6 +172,105 @@ const mergeExamples = (baseValue, newValue) => {
|
|
|
172
172
|
}
|
|
173
173
|
return newValue;
|
|
174
174
|
};
|
|
175
|
+
const MAX_SCHEMA_VALIDATION_DEPTH = MAX_LEVELS_DEEP * 5;
|
|
176
|
+
/** Cache composed schema resolution to preserve identity across recursion checks. */
|
|
177
|
+
const composedSchemaResolutionCache = new WeakMap();
|
|
178
|
+
const isValueOfType = (value, targetType) => {
|
|
179
|
+
switch (targetType) {
|
|
180
|
+
case 'string':
|
|
181
|
+
return typeof value === 'string';
|
|
182
|
+
case 'number':
|
|
183
|
+
return typeof value === 'number' && !Number.isNaN(value);
|
|
184
|
+
case 'integer':
|
|
185
|
+
return typeof value === 'number' && Number.isInteger(value);
|
|
186
|
+
case 'boolean':
|
|
187
|
+
return typeof value === 'boolean';
|
|
188
|
+
case 'object':
|
|
189
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
190
|
+
case 'array':
|
|
191
|
+
return Array.isArray(value);
|
|
192
|
+
case 'null':
|
|
193
|
+
return value === null;
|
|
194
|
+
default:
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
const resolveComposedSchemaMember = (schema) => {
|
|
199
|
+
const rawSchema = getSchemaCacheTarget(schema);
|
|
200
|
+
if (composedSchemaResolutionCache.has(rawSchema)) {
|
|
201
|
+
return composedSchemaResolutionCache.get(rawSchema);
|
|
202
|
+
}
|
|
203
|
+
const resolved = '$ref' in schema ? resolve.schema(schema) : schema;
|
|
204
|
+
composedSchemaResolutionCache.set(rawSchema, resolved);
|
|
205
|
+
return resolved;
|
|
206
|
+
};
|
|
207
|
+
const schemaAllowsValue = (schema, value, seen = new Set(), level = 0) => {
|
|
208
|
+
// Depth guard prevents stack overflows when composed schemas loop through wrapped resolver objects.
|
|
209
|
+
if (level > MAX_SCHEMA_VALIDATION_DEPTH) {
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
const rawSchema = getSchemaCacheTarget(schema);
|
|
213
|
+
if (seen.has(rawSchema)) {
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
seen.add(rawSchema);
|
|
217
|
+
if ('type' in schema && schema.type) {
|
|
218
|
+
const types = Array.isArray(schema.type) ? schema.type : [schema.type];
|
|
219
|
+
const matchesType = types.some((targetType) => {
|
|
220
|
+
if (targetType === 'number' && isValueOfType(value, 'integer')) {
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
return isValueOfType(value, targetType);
|
|
224
|
+
});
|
|
225
|
+
if (!matchesType) {
|
|
226
|
+
seen.delete(rawSchema);
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
const anyOf = schema.anyOf;
|
|
231
|
+
if (Array.isArray(anyOf) && anyOf.length > 0) {
|
|
232
|
+
const matchesAnyOf = anyOf.some((item) => {
|
|
233
|
+
const resolved = resolveComposedSchemaMember(item);
|
|
234
|
+
return !!resolved && schemaAllowsValue(resolved, value, seen, level + 1);
|
|
235
|
+
});
|
|
236
|
+
if (!matchesAnyOf) {
|
|
237
|
+
seen.delete(rawSchema);
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
const oneOf = schema.oneOf;
|
|
242
|
+
if (Array.isArray(oneOf) && oneOf.length > 0) {
|
|
243
|
+
const matchesOneOf = oneOf.some((item) => {
|
|
244
|
+
const resolved = resolveComposedSchemaMember(item);
|
|
245
|
+
return !!resolved && schemaAllowsValue(resolved, value, seen, level + 1);
|
|
246
|
+
});
|
|
247
|
+
if (!matchesOneOf) {
|
|
248
|
+
seen.delete(rawSchema);
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
const allOf = schema.allOf;
|
|
253
|
+
if (Array.isArray(allOf) && allOf.length > 0) {
|
|
254
|
+
const matchesAllOf = allOf.every((item) => {
|
|
255
|
+
const resolved = resolveComposedSchemaMember(item);
|
|
256
|
+
return !resolved || schemaAllowsValue(resolved, value, seen, level + 1);
|
|
257
|
+
});
|
|
258
|
+
if (!matchesAllOf) {
|
|
259
|
+
seen.delete(rawSchema);
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
seen.delete(rawSchema);
|
|
264
|
+
return true;
|
|
265
|
+
};
|
|
266
|
+
const INVALID_DEFAULT = Symbol('INVALID_DEFAULT');
|
|
267
|
+
const normalizeSchemaDefault = (schema) => {
|
|
268
|
+
const defaultValue = schema.default;
|
|
269
|
+
if (schemaAllowsValue(schema, defaultValue)) {
|
|
270
|
+
return defaultValue;
|
|
271
|
+
}
|
|
272
|
+
return INVALID_DEFAULT;
|
|
273
|
+
};
|
|
175
274
|
const getCompositionSelectionKey = (schemaPath, composition) => [...schemaPath, composition].join('.');
|
|
176
275
|
const getCompositionSelectionIndex = (schemaPath, composition, options, length) => {
|
|
177
276
|
const rawIndex = options?.compositionSelection?.[getCompositionSelectionKey(schemaPath, composition)];
|
|
@@ -477,8 +576,11 @@ export const getExampleFromSchema = (schema, options, { level = 0, parentSchema,
|
|
|
477
576
|
return cache(_schema, _schema.example, cacheKey);
|
|
478
577
|
}
|
|
479
578
|
if (_schema.default !== undefined) {
|
|
480
|
-
|
|
481
|
-
|
|
579
|
+
const normalizedDefault = normalizeSchemaDefault(_schema);
|
|
580
|
+
if (normalizedDefault !== INVALID_DEFAULT) {
|
|
581
|
+
seen.delete(targetValue);
|
|
582
|
+
return cache(_schema, normalizedDefault, cacheKey);
|
|
583
|
+
}
|
|
482
584
|
}
|
|
483
585
|
if (_schema.const !== undefined) {
|
|
484
586
|
seen.delete(targetValue);
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import type { HttpMethod } from '@scalar/helpers/http/http-methods';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
};
|
|
2
|
+
/**
|
|
3
|
+
* Re-exported from `@scalar/helpers/types/result` so the rest of the
|
|
4
|
+
* workspace-store codebase keeps importing `Result` from a colocated
|
|
5
|
+
* module while the canonical definition lives in helpers.
|
|
6
|
+
*/
|
|
7
|
+
export type { Result } from '@scalar/helpers/types/result';
|
|
9
8
|
export type RequestExampleMeta = {
|
|
10
9
|
path: string;
|
|
11
10
|
method: HttpMethod;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/request-example/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAEnE
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/request-example/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAEnE;;;;GAIG;AACH,YAAY,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAA;AAE1D,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,UAAU,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA"}
|
package/package.json
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"openapi",
|
|
17
17
|
"scalar"
|
|
18
18
|
],
|
|
19
|
-
"version": "0.49.
|
|
19
|
+
"version": "0.49.2",
|
|
20
20
|
"engines": {
|
|
21
21
|
"node": ">=22"
|
|
22
22
|
},
|
|
@@ -143,12 +143,12 @@
|
|
|
143
143
|
"type-fest": "^5.3.1",
|
|
144
144
|
"vue": "^3.5.30",
|
|
145
145
|
"yaml": "^2.8.3",
|
|
146
|
-
"@scalar/
|
|
147
|
-
"@scalar/
|
|
148
|
-
"@scalar/
|
|
146
|
+
"@scalar/helpers": "0.6.0",
|
|
147
|
+
"@scalar/json-magic": "0.12.12",
|
|
148
|
+
"@scalar/snippetz": "0.9.6",
|
|
149
149
|
"@scalar/validation": "0.3.2",
|
|
150
|
-
"@scalar/types": "0.9.
|
|
151
|
-
"@scalar/
|
|
150
|
+
"@scalar/types": "0.9.6",
|
|
151
|
+
"@scalar/openapi-upgrader": "0.2.7"
|
|
152
152
|
},
|
|
153
153
|
"devDependencies": {
|
|
154
154
|
"@google-cloud/storage": "7.16.0",
|