@scalar/workspace-store 0.63.0 → 0.64.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.
- package/CHANGELOG.md +24 -0
- package/README.md +88 -0
- package/dist/client.d.ts +28 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +216 -139
- package/dist/helpers/chunk-index.d.ts +95 -0
- package/dist/helpers/chunk-index.d.ts.map +1 -0
- package/dist/helpers/chunk-index.js +139 -0
- package/dist/helpers/external-examples.d.ts +17 -0
- package/dist/helpers/external-examples.d.ts.map +1 -0
- package/dist/helpers/external-examples.js +50 -0
- package/dist/helpers/operation-examples.d.ts +6 -0
- package/dist/helpers/operation-examples.d.ts.map +1 -0
- package/dist/helpers/operation-examples.js +45 -0
- package/dist/helpers/use-external-examples.d.ts +15 -0
- package/dist/helpers/use-external-examples.d.ts.map +1 -0
- package/dist/helpers/use-external-examples.js +55 -0
- package/dist/mutators/operation/parameters.d.ts.map +1 -1
- package/dist/mutators/operation/parameters.js +28 -9
- package/dist/plugins/bundler/index.d.ts +5 -2
- package/dist/plugins/bundler/index.d.ts.map +1 -1
- package/dist/plugins/bundler/index.js +12 -3
- package/dist/request-example/builder/header/is-param-disabled.d.ts +2 -2
- package/dist/request-example/builder/header/is-param-disabled.d.ts.map +1 -1
- package/dist/request-example/builder/header/is-param-disabled.js +5 -4
- package/dist/request-example/builder/helpers/get-example.d.ts +2 -0
- package/dist/request-example/builder/helpers/get-example.d.ts.map +1 -1
- package/dist/request-example/builder/helpers/get-example.js +9 -7
- package/dist/request-example/context/headers.d.ts.map +1 -1
- package/dist/request-example/context/headers.js +3 -4
- package/dist/schemas/v3.2/strict/openapi-document.d.ts.map +1 -1
- package/dist/schemas/v3.2/strict/openapi-document.js +17 -1
- package/dist/server.d.ts +16 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +34 -9
- package/package.json +3 -3
package/dist/client.js
CHANGED
|
@@ -16,9 +16,11 @@ import { reactive } from 'vue';
|
|
|
16
16
|
import YAML from 'yaml';
|
|
17
17
|
import { createAuthStore } from './entities/auth/index.js';
|
|
18
18
|
import { createHistoryStore } from './entities/history/index.js';
|
|
19
|
+
import { expandChunkIndex } from './helpers/chunk-index.js';
|
|
19
20
|
import { deepClone } from './helpers/deep-clone.js';
|
|
20
21
|
import { createDetectChangesProxy } from './helpers/detect-changes-proxy.js';
|
|
21
22
|
import { bumpDocumentRevision } from './helpers/document-revision.js';
|
|
23
|
+
import { createExternalExampleResolver } from './helpers/external-examples.js';
|
|
22
24
|
import { safeAssign } from './helpers/general.js';
|
|
23
25
|
import { getFetch } from './helpers/get-fetch.js';
|
|
24
26
|
import { mergeObjects } from './helpers/merge-object.js';
|
|
@@ -156,7 +158,7 @@ const purgeInternalDocumentKeys = (input) => {
|
|
|
156
158
|
* @returns An object containing methods and getters for managing the workspace
|
|
157
159
|
*/
|
|
158
160
|
export const createWorkspaceStore = (workspaceProps) => {
|
|
159
|
-
const { verbose = false } = workspaceProps ?? {};
|
|
161
|
+
const { verbose = false, reactive: isReactiveWorkspace = true } = workspaceProps ?? {};
|
|
160
162
|
const withMeasurementSync = (name, fn) => (verbose ? measureSync(name, fn) : fn());
|
|
161
163
|
const withMeasurementAsync = (name, fn) => verbose ? measureAsync(name, fn) : fn();
|
|
162
164
|
/**
|
|
@@ -165,6 +167,11 @@ export const createWorkspaceStore = (workspaceProps) => {
|
|
|
165
167
|
* This can include settings that can not be persisted between sessions (not JSON serializable)
|
|
166
168
|
*/
|
|
167
169
|
const extraDocumentConfigurations = {};
|
|
170
|
+
const externalExampleResolvers = new WeakMap();
|
|
171
|
+
const fallbackExternalExamples = createExternalExampleResolver({
|
|
172
|
+
fetch: workspaceProps?.fetch,
|
|
173
|
+
fileLoader: workspaceProps?.fileLoader,
|
|
174
|
+
});
|
|
168
175
|
/**
|
|
169
176
|
* Notifies all workspace plugins of a workspace state change event.
|
|
170
177
|
*
|
|
@@ -177,20 +184,9 @@ export const createWorkspaceStore = (workspaceProps) => {
|
|
|
177
184
|
workspaceProps?.plugins?.forEach((plugin) => plugin.hooks?.onWorkspaceStateChanges?.(event));
|
|
178
185
|
};
|
|
179
186
|
/**
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
* Every change to the workspace, is tracked and broadcast to all registered plugins.
|
|
183
|
-
* allowing for change tracking.
|
|
184
|
-
*
|
|
185
|
-
* NOTE:
|
|
186
|
-
* The detect changes proxy is applied separately beacause the vue reactitvity proxy have to be the outer most proxy.
|
|
187
|
-
* If the order is reversed, Vue cannot properly track mutations, leading to lost reactivity and bugs.
|
|
188
|
-
* By wrapping the contents with the detect changes proxy first, and then passing the result to Vue's `reactive`,
|
|
189
|
-
* we ensure that Vue manages its reactivity as expected and our change detection hooks
|
|
190
|
-
* are also triggered reliably.
|
|
191
|
-
* Do not reverse this order‼️
|
|
187
|
+
* The plain workspace state, before any observability wrappers are applied.
|
|
192
188
|
*/
|
|
193
|
-
const
|
|
189
|
+
const workspaceState = {
|
|
194
190
|
...workspaceProps?.meta,
|
|
195
191
|
documents: {},
|
|
196
192
|
/**
|
|
@@ -203,88 +199,105 @@ export const createWorkspaceStore = (workspaceProps) => {
|
|
|
203
199
|
get activeDocument() {
|
|
204
200
|
return workspace.documents[getActiveDocumentName()];
|
|
205
201
|
},
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
202
|
+
};
|
|
203
|
+
/**
|
|
204
|
+
* An object containing the reactive workspace state.
|
|
205
|
+
*
|
|
206
|
+
* Every change to the workspace, is tracked and broadcast to all registered plugins.
|
|
207
|
+
* allowing for change tracking.
|
|
208
|
+
*
|
|
209
|
+
* With `reactive: false` the state is used as-is, so reads cost nothing beyond the plain object and
|
|
210
|
+
* nothing observes a write. See the `reactive` option for the full list of what stops happening.
|
|
211
|
+
*
|
|
212
|
+
* NOTE:
|
|
213
|
+
* The detect changes proxy is applied separately beacause the vue reactitvity proxy have to be the outer most proxy.
|
|
214
|
+
* If the order is reversed, Vue cannot properly track mutations, leading to lost reactivity and bugs.
|
|
215
|
+
* By wrapping the contents with the detect changes proxy first, and then passing the result to Vue's `reactive`,
|
|
216
|
+
* we ensure that Vue manages its reactivity as expected and our change detection hooks
|
|
217
|
+
* are also triggered reliably.
|
|
218
|
+
* Do not reverse this order‼️
|
|
219
|
+
*/
|
|
220
|
+
const workspace = !isReactiveWorkspace
|
|
221
|
+
? workspaceState
|
|
222
|
+
: reactive(createDetectChangesProxy(workspaceState, {
|
|
223
|
+
hooks: {
|
|
224
|
+
onAfterChange(path) {
|
|
225
|
+
const type = path[0];
|
|
226
|
+
/** Document changes */
|
|
227
|
+
if (type === 'documents') {
|
|
228
|
+
// We are overriding the while documents object, ignore. This should not happen
|
|
229
|
+
if (path.length < 2) {
|
|
230
|
+
console.log('[WARN]: Overriding entire documents object is not supported');
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
const documentName = path[1];
|
|
234
|
+
const document = workspace.documents[documentName] ?? {
|
|
235
|
+
openapi: '3.1.0',
|
|
236
|
+
info: { title: '', version: '' },
|
|
237
|
+
'x-scalar-original-document-hash': '',
|
|
238
|
+
};
|
|
239
|
+
// Every write through the store passes here, which is what makes the revision a
|
|
240
|
+
// complete record of the document changing.
|
|
241
|
+
bumpDocumentRevision(document);
|
|
242
|
+
const event = {
|
|
243
|
+
type: 'documents',
|
|
244
|
+
documentName,
|
|
245
|
+
value: unpackProxyObject(document),
|
|
246
|
+
path: path.slice(2),
|
|
247
|
+
};
|
|
248
|
+
// Don't mark as dirty when the document is first created or when
|
|
249
|
+
// only metadata-only fields change. `x-scalar-registry-meta` is
|
|
250
|
+
// updated programmatically (commit hash, conflict cache) and
|
|
251
|
+
// does not represent a user edit.
|
|
252
|
+
if (event.path.length > 0 && !METADATA_ONLY_DOCUMENT_KEYS.has(event.path[0])) {
|
|
253
|
+
// The document has been modified since it was last saved
|
|
254
|
+
document['x-scalar-is-dirty'] = true;
|
|
255
|
+
}
|
|
256
|
+
fireWorkspaceChange(event);
|
|
215
257
|
return;
|
|
216
258
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
259
|
+
/** Active document changes */
|
|
260
|
+
if (type === 'activeDocument') {
|
|
261
|
+
const documentName = getActiveDocumentName();
|
|
262
|
+
const document = workspace.documents[documentName] ?? {
|
|
263
|
+
openapi: '3.1.0',
|
|
264
|
+
info: { title: '', version: '' },
|
|
265
|
+
'x-scalar-original-document-hash': '',
|
|
266
|
+
};
|
|
267
|
+
bumpDocumentRevision(document);
|
|
268
|
+
// Active document changed
|
|
269
|
+
const event = {
|
|
270
|
+
type: 'documents',
|
|
271
|
+
documentName,
|
|
272
|
+
value: unpackProxyObject(document),
|
|
273
|
+
path: path.slice(2),
|
|
274
|
+
};
|
|
275
|
+
// Don't mark as dirty when the document is first created or when
|
|
276
|
+
// only metadata-only fields change. `x-scalar-registry-meta` is
|
|
277
|
+
// updated programmatically (commit hash, conflict cache) and
|
|
278
|
+
// does not represent a user edit.
|
|
279
|
+
if (event.path.length > 0 && !METADATA_ONLY_DOCUMENT_KEYS.has(event.path[0])) {
|
|
280
|
+
// The document has been modified since it was last saved
|
|
281
|
+
document['x-scalar-is-dirty'] = true;
|
|
282
|
+
}
|
|
283
|
+
fireWorkspaceChange(event);
|
|
284
|
+
return;
|
|
239
285
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}
|
|
243
|
-
/** Active document changes */
|
|
244
|
-
if (type === 'activeDocument') {
|
|
245
|
-
const documentName = getActiveDocumentName();
|
|
246
|
-
const document = workspace.documents[documentName] ?? {
|
|
247
|
-
openapi: '3.1.0',
|
|
248
|
-
info: { title: '', version: '' },
|
|
249
|
-
'x-scalar-original-document-hash': '',
|
|
250
|
-
};
|
|
251
|
-
bumpDocumentRevision(document);
|
|
252
|
-
// Active document changed
|
|
286
|
+
/** Workspace meta changes */
|
|
287
|
+
const { activeDocument: _a, documents: _d, ...meta } = workspace;
|
|
253
288
|
const event = {
|
|
254
|
-
type: '
|
|
255
|
-
|
|
256
|
-
value: unpackProxyObject(document),
|
|
257
|
-
path: path.slice(2),
|
|
289
|
+
type: 'meta',
|
|
290
|
+
value: unpackProxyObject(meta, { depth: 1 }),
|
|
258
291
|
};
|
|
259
|
-
// Don't mark as dirty when the document is first created or when
|
|
260
|
-
// only metadata-only fields change. `x-scalar-registry-meta` is
|
|
261
|
-
// updated programmatically (commit hash, conflict cache) and
|
|
262
|
-
// does not represent a user edit.
|
|
263
|
-
if (event.path.length > 0 && !METADATA_ONLY_DOCUMENT_KEYS.has(event.path[0])) {
|
|
264
|
-
// The document has been modified since it was last saved
|
|
265
|
-
document['x-scalar-is-dirty'] = true;
|
|
266
|
-
}
|
|
267
292
|
fireWorkspaceChange(event);
|
|
268
293
|
return;
|
|
269
|
-
}
|
|
270
|
-
/** Workspace meta changes */
|
|
271
|
-
const { activeDocument: _a, documents: _d, ...meta } = workspace;
|
|
272
|
-
const event = {
|
|
273
|
-
type: 'meta',
|
|
274
|
-
value: unpackProxyObject(meta, { depth: 1 }),
|
|
275
|
-
};
|
|
276
|
-
fireWorkspaceChange(event);
|
|
277
|
-
return;
|
|
294
|
+
},
|
|
278
295
|
},
|
|
279
|
-
}
|
|
280
|
-
}));
|
|
296
|
+
}));
|
|
281
297
|
/**
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
* Every change to the workspace state (documents, configs, metadata, etc.) can be detected here,
|
|
285
|
-
* allowing for change tracking.
|
|
298
|
+
* The plain document snapshot maps, before the detect changes proxy is applied.
|
|
286
299
|
*/
|
|
287
|
-
const
|
|
300
|
+
const documentSnapshots = {
|
|
288
301
|
/**
|
|
289
302
|
* Holds the original, unmodified documents as they were initially loaded into the workspace.
|
|
290
303
|
* These documents are stored in their raw form—prior to any reactive wrapping, dereferencing, or bundling.
|
|
@@ -316,46 +329,57 @@ export const createWorkspaceStore = (workspaceProps) => {
|
|
|
316
329
|
* OpenAPI document representing the overridden fields.
|
|
317
330
|
*/
|
|
318
331
|
overrides: {},
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
332
|
+
};
|
|
333
|
+
/**
|
|
334
|
+
* An object containing all the workspace state, wrapped in a detect changes proxy.
|
|
335
|
+
*
|
|
336
|
+
* Every change to the workspace state (documents, configs, metadata, etc.) can be detected here,
|
|
337
|
+
* allowing for change tracking.
|
|
338
|
+
*
|
|
339
|
+
* With `reactive: false` the maps are used as-is and a write to them notifies nobody.
|
|
340
|
+
*/
|
|
341
|
+
const { originalDocuments, intermediateDocuments, overrides } = !isReactiveWorkspace
|
|
342
|
+
? documentSnapshots
|
|
343
|
+
: createDetectChangesProxy(documentSnapshots, {
|
|
344
|
+
hooks: {
|
|
345
|
+
onAfterChange(path) {
|
|
346
|
+
const type = path[0];
|
|
347
|
+
if (!type) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
if (path.length < 2) {
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
const documentName = path[1];
|
|
354
|
+
if (type === 'originalDocuments') {
|
|
355
|
+
const event = {
|
|
356
|
+
type,
|
|
357
|
+
documentName: documentName,
|
|
358
|
+
value: unpackProxyObject(originalDocuments[documentName] ?? {}),
|
|
359
|
+
path: path.splice(2),
|
|
360
|
+
};
|
|
361
|
+
fireWorkspaceChange(event);
|
|
362
|
+
}
|
|
363
|
+
if (type === 'intermediateDocuments') {
|
|
364
|
+
const event = {
|
|
365
|
+
type,
|
|
366
|
+
documentName: documentName,
|
|
367
|
+
value: unpackProxyObject(intermediateDocuments[documentName] ?? {}),
|
|
368
|
+
path: path.splice(2),
|
|
369
|
+
};
|
|
370
|
+
fireWorkspaceChange(event);
|
|
371
|
+
}
|
|
372
|
+
if (type === 'overrides') {
|
|
373
|
+
const event = {
|
|
374
|
+
type,
|
|
375
|
+
documentName: documentName,
|
|
376
|
+
value: unpackProxyObject(overrides[documentName] ?? {}),
|
|
377
|
+
};
|
|
378
|
+
fireWorkspaceChange(event);
|
|
379
|
+
}
|
|
380
|
+
},
|
|
356
381
|
},
|
|
357
|
-
}
|
|
358
|
-
});
|
|
382
|
+
});
|
|
359
383
|
/**
|
|
360
384
|
* This store is used to track the history of requests and responses for documents and operations.
|
|
361
385
|
*/
|
|
@@ -387,6 +411,17 @@ export const createWorkspaceStore = (workspaceProps) => {
|
|
|
387
411
|
},
|
|
388
412
|
},
|
|
389
413
|
});
|
|
414
|
+
/**
|
|
415
|
+
* Whether a document needs to be wrapped in the overrides proxy.
|
|
416
|
+
*
|
|
417
|
+
* A reactive workspace always wraps, so the default mode keeps every document the same shape it has
|
|
418
|
+
* always had. A non-reactive workspace wraps only a document that actually has overrides: with an
|
|
419
|
+
* empty override map the proxy resolves to the target on every read and write anyway, so all it adds
|
|
420
|
+
* is a proxy hop on every nested read. Nothing outside this file reads the proxy's identity, and the
|
|
421
|
+
* store rebuilds the document from the current override map whenever the map changes, so a document
|
|
422
|
+
* that gains overrides later gains the proxy along with them.
|
|
423
|
+
*/
|
|
424
|
+
const needsOverridesProxy = (documentOverrides) => isReactiveWorkspace || (isObject(documentOverrides) && Object.keys(documentOverrides).length > 0);
|
|
390
425
|
/**
|
|
391
426
|
* Returns the name of the currently active document in the workspace.
|
|
392
427
|
* The active document is determined by the 'x-scalar-active-document' metadata field,
|
|
@@ -440,6 +475,10 @@ export const createWorkspaceStore = (workspaceProps) => {
|
|
|
440
475
|
const { name } = input;
|
|
441
476
|
const meta = deepClone(input.meta);
|
|
442
477
|
const clonedRawInputDocument = withMeasurementSync('deepClone', () => deepClone(input.document));
|
|
478
|
+
// A compact sparse document is expanded back into per-node chunk references before anything
|
|
479
|
+
// else reads it, so every step below — including the check for a server-generated navigation —
|
|
480
|
+
// sees the document a non-compact server store would have sent.
|
|
481
|
+
withMeasurementSync('expandChunkIndex', () => expandChunkIndex(clonedRawInputDocument));
|
|
443
482
|
withMeasurementSync('initialize', () => {
|
|
444
483
|
if (input.initialize !== false) {
|
|
445
484
|
// Store the original document in the originalDocuments map
|
|
@@ -502,9 +541,10 @@ export const createWorkspaceStore = (workspaceProps) => {
|
|
|
502
541
|
const navigation = traverseAsyncApiDocument(name, asyncApiDocument, navigationOptions);
|
|
503
542
|
asyncApiDocument[extensions.document.navigation] = navigation;
|
|
504
543
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
544
|
+
const asyncApiOverrides = unpackProxyObject(overrides[name]);
|
|
545
|
+
workspace.documents[name] = needsOverridesProxy(asyncApiOverrides)
|
|
546
|
+
? createOverridesProxy(asyncApiDocument, { overrides: asyncApiOverrides })
|
|
547
|
+
: asyncApiDocument;
|
|
508
548
|
return;
|
|
509
549
|
}
|
|
510
550
|
const inputDocument = withMeasurementSync('upgrade', () => upgrade(deepClone(clonedRawInputDocument), '3.1'));
|
|
@@ -524,7 +564,7 @@ export const createWorkspaceStore = (workspaceProps) => {
|
|
|
524
564
|
plugins: [
|
|
525
565
|
...loaders,
|
|
526
566
|
normalizeRefs(),
|
|
527
|
-
externalValueResolver(),
|
|
567
|
+
externalValueResolver({ lazy: true }),
|
|
528
568
|
refsEverywhere(),
|
|
529
569
|
normalizeAuthSchemes(),
|
|
530
570
|
syncPathParameters(),
|
|
@@ -555,9 +595,11 @@ export const createWorkspaceStore = (workspaceProps) => {
|
|
|
555
595
|
// Create a proxied document with magic proxy and apply any overrides, then store it in the workspace documents map
|
|
556
596
|
// We create a new proxy here in order to hide internal properties after validation and processing
|
|
557
597
|
// This ensures that the workspace document only exposes the intended OpenAPI properties and extensions
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
598
|
+
const documentOverrides = unpackProxyObject(overrides[name]);
|
|
599
|
+
const magicDocument = createMagicProxy(getRaw(strictDocument));
|
|
600
|
+
workspace.documents[name] = needsOverridesProxy(documentOverrides)
|
|
601
|
+
? createOverridesProxy(magicDocument, { overrides: documentOverrides })
|
|
602
|
+
: magicDocument;
|
|
561
603
|
}
|
|
562
604
|
// Asynchronously adds a new document to the workspace by loading and validating the input.
|
|
563
605
|
// If loading fails, a placeholder error document is added instead.
|
|
@@ -692,6 +734,22 @@ export const createWorkspaceStore = (workspaceProps) => {
|
|
|
692
734
|
// This is needed because we are doing partial bundle operations
|
|
693
735
|
const visitedNodesCache = new Set();
|
|
694
736
|
return {
|
|
737
|
+
externalExamples: (documentName) => {
|
|
738
|
+
const name = documentName ?? getActiveDocumentName();
|
|
739
|
+
const document = workspace.documents[name];
|
|
740
|
+
if (!document)
|
|
741
|
+
return fallbackExternalExamples;
|
|
742
|
+
const existing = externalExampleResolvers.get(document);
|
|
743
|
+
if (existing)
|
|
744
|
+
return existing;
|
|
745
|
+
const resolver = createExternalExampleResolver({
|
|
746
|
+
origin: document['x-scalar-original-source-url'],
|
|
747
|
+
fileLoader: workspaceProps?.fileLoader,
|
|
748
|
+
fetch: extraDocumentConfigurations[name]?.fetch ?? workspaceProps?.fetch,
|
|
749
|
+
});
|
|
750
|
+
externalExampleResolvers.set(document, resolver);
|
|
751
|
+
return resolver;
|
|
752
|
+
},
|
|
695
753
|
get workspace() {
|
|
696
754
|
return workspace;
|
|
697
755
|
},
|
|
@@ -761,7 +819,15 @@ export const createWorkspaceStore = (workspaceProps) => {
|
|
|
761
819
|
root: activeDocument,
|
|
762
820
|
origin: activeDocument?.['x-scalar-original-source-url'],
|
|
763
821
|
treeShake: false,
|
|
764
|
-
plugins: [
|
|
822
|
+
plugins: [
|
|
823
|
+
fetchUrls({
|
|
824
|
+
fetch: extraDocumentConfigurations[getActiveDocumentName()]?.fetch ?? workspaceProps?.fetch,
|
|
825
|
+
limit: EXTERNAL_FETCH_CONCURRENCY_LIMIT,
|
|
826
|
+
}),
|
|
827
|
+
...(workspaceProps?.fileLoader ? [workspaceProps.fileLoader] : []),
|
|
828
|
+
loadingStatus(),
|
|
829
|
+
externalValueResolver({ lazy: true }),
|
|
830
|
+
],
|
|
765
831
|
urlMap: true,
|
|
766
832
|
visitedNodes: visitedNodesCache,
|
|
767
833
|
});
|
|
@@ -855,12 +921,23 @@ export const createWorkspaceStore = (workspaceProps) => {
|
|
|
855
921
|
};
|
|
856
922
|
},
|
|
857
923
|
loadWorkspace(input) {
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
])
|
|
924
|
+
// A workspace from a compact server store carries an index rather than per-node chunk
|
|
925
|
+
// references; expanded here for the same reason `addInMemoryDocument` expands.
|
|
926
|
+
for (const document of Object.values(input.documents)) {
|
|
927
|
+
expandChunkIndex(document);
|
|
928
|
+
}
|
|
929
|
+
safeAssign(workspace.documents, Object.fromEntries(Object.entries(input.documents).map(([name, doc]) => {
|
|
930
|
+
// Hydration only rewraps: an exported document has already been upgraded, bundled, coerced
|
|
931
|
+
// and given its navigation, so nothing here re-processes it.
|
|
932
|
+
const magicDocument = createMagicProxy(doc);
|
|
933
|
+
const documentOverrides = input.overrides[name];
|
|
934
|
+
return [
|
|
935
|
+
name,
|
|
936
|
+
needsOverridesProxy(documentOverrides)
|
|
937
|
+
? createOverridesProxy(magicDocument, { overrides: documentOverrides })
|
|
938
|
+
: magicDocument,
|
|
939
|
+
];
|
|
940
|
+
})));
|
|
864
941
|
safeAssign(originalDocuments, input.originalDocuments);
|
|
865
942
|
safeAssign(intermediateDocuments, input.intermediateDocuments);
|
|
866
943
|
safeAssign(overrides, input.overrides);
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The extension key a compact sparse document carries its chunk index under.
|
|
3
|
+
*
|
|
4
|
+
* It exists on the wire only: the client expands the index back into per-node references while the
|
|
5
|
+
* document is ingested and removes the key, so nothing downstream ever sees it.
|
|
6
|
+
*/
|
|
7
|
+
export declare const CHUNK_INDEX_KEY = "x-scalar-chunk-index";
|
|
8
|
+
/** Where a document's chunks live, which decides how each reference to one is spelled. */
|
|
9
|
+
export type ChunkMode = 'static' | 'ssr';
|
|
10
|
+
/** The `$ref` template for each kind of chunk, with `{…}` slots the reader fills in. */
|
|
11
|
+
export type ChunkRefTemplates = {
|
|
12
|
+
/** Slots: `{type}`, `{name}`. */
|
|
13
|
+
components: string;
|
|
14
|
+
/** Slots: `{path}`, `{method}`. */
|
|
15
|
+
operations: string;
|
|
16
|
+
/** No slots. */
|
|
17
|
+
navigation: string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* The compact stand-in for a sparse document's `components` and `paths`.
|
|
21
|
+
*
|
|
22
|
+
* Every reference the non-compact form spells out node by node is derivable from where that node
|
|
23
|
+
* sits, so the index carries the positions and one template per kind instead. What a path item
|
|
24
|
+
* keeps besides its operations is not derivable, so it rides along verbatim.
|
|
25
|
+
*/
|
|
26
|
+
export type ChunkIndex = {
|
|
27
|
+
mode: ChunkMode;
|
|
28
|
+
refs: ChunkRefTemplates;
|
|
29
|
+
/** Component names per component type, in document order. */
|
|
30
|
+
components: Record<string, string[]>;
|
|
31
|
+
/**
|
|
32
|
+
* Each path item with its operations replaced by a placeholder.
|
|
33
|
+
*
|
|
34
|
+
* The whole path item is kept rather than a list of methods so that both its key order and the
|
|
35
|
+
* keys that were never externalized survive: `parameters`, `summary`, `servers` and extensions
|
|
36
|
+
* all stay inline in the non-compact form.
|
|
37
|
+
*/
|
|
38
|
+
paths: Record<string, Record<string, unknown>>;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Fills the `{slot}`s of a chunk-reference template.
|
|
42
|
+
*
|
|
43
|
+
* `{{` and `}}` stand for literal braces, so text the writer inlined into a template — a document
|
|
44
|
+
* name, a base URL — may contain braces without being read back as a slot. An unknown slot is left
|
|
45
|
+
* alone rather than blanked, so a template from a newer writer fails visibly instead of resolving
|
|
46
|
+
* to the wrong chunk.
|
|
47
|
+
*/
|
|
48
|
+
export declare const fillChunkRef: (template: string, values?: Record<string, string>) => string;
|
|
49
|
+
/**
|
|
50
|
+
* Builds the reference templates for one document.
|
|
51
|
+
*
|
|
52
|
+
* Filled, these produce exactly the references `externalizeComponentReferences` and
|
|
53
|
+
* `externalizePathReferences` write, so a client that expands the index lands on the same chunk.
|
|
54
|
+
*/
|
|
55
|
+
export declare const chunkRefTemplates: (meta: {
|
|
56
|
+
mode: "ssr";
|
|
57
|
+
name: string;
|
|
58
|
+
baseUrl: string;
|
|
59
|
+
} | {
|
|
60
|
+
mode: "static";
|
|
61
|
+
name: string;
|
|
62
|
+
}) => ChunkRefTemplates;
|
|
63
|
+
/** The reference a lazily loaded chunk is reached through. */
|
|
64
|
+
export declare const chunkReference: (ref: string) => {
|
|
65
|
+
$ref: string;
|
|
66
|
+
$global: true;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Compacts a sparse document's `components` and `paths` into an index.
|
|
70
|
+
*
|
|
71
|
+
* Takes the sections the externalizers produced rather than the document itself, so the index is
|
|
72
|
+
* built from the very references it replaces and the two cannot come to describe different sets of
|
|
73
|
+
* chunks.
|
|
74
|
+
*/
|
|
75
|
+
export declare const buildChunkIndex: ({ mode, refs, components, paths, }: {
|
|
76
|
+
mode: ChunkMode;
|
|
77
|
+
refs: ChunkRefTemplates;
|
|
78
|
+
components: Record<string, Record<string, unknown>>;
|
|
79
|
+
paths: Record<string, Record<string, unknown>>;
|
|
80
|
+
}) => ChunkIndex;
|
|
81
|
+
/**
|
|
82
|
+
* Expands a compact sparse document into the one a non-compact server store would have sent.
|
|
83
|
+
*
|
|
84
|
+
* Mutates the document in place and drops the index key, so what the rest of the store sees is an
|
|
85
|
+
* ordinary sparse document: `resolve()`, the bundler and anything enumerating `paths` or
|
|
86
|
+
* `components` are looking at the shape they always have.
|
|
87
|
+
*
|
|
88
|
+
* A document without an index is left alone, which is every document a non-compact server store or
|
|
89
|
+
* an author produces.
|
|
90
|
+
*
|
|
91
|
+
* @param document - The document to expand, mutated in place
|
|
92
|
+
* @returns Whether an index was found and expanded
|
|
93
|
+
*/
|
|
94
|
+
export declare const expandChunkIndex: (document: unknown) => boolean;
|
|
95
|
+
//# sourceMappingURL=chunk-index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-index.d.ts","sourceRoot":"","sources":["../../src/helpers/chunk-index.ts"],"names":[],"mappings":"AAMA;;;;;GAKG;AACH,eAAO,MAAM,eAAe,yBAAyB,CAAA;AAKrD,0FAA0F;AAC1F,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,KAAK,CAAA;AAExC,wFAAwF;AACxF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAA;IAClB,mCAAmC;IACnC,UAAU,EAAE,MAAM,CAAA;IAClB,gBAAgB;IAChB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,SAAS,CAAA;IACf,IAAI,EAAE,iBAAiB,CAAA;IACvB,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;IACpC;;;;;;OAMG;IACH,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;CAC/C,CAAA;AAKD;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,GAAI,UAAU,MAAM,EAAE,SAAQ,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,KAAG,MAGlF,CAAA;AAwBH;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAC5B,MAAM;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,KACtF,iBAkBF,CAAA;AAED,8DAA8D;AAC9D,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,KAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,IAAI,CAAA;CAAsC,CAAA;AAEhH;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAAI,oCAK7B;IACD,IAAI,EAAE,SAAS,CAAA;IACf,IAAI,EAAE,iBAAiB,CAAA;IACvB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACnD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;CAC/C,KAAG,UAYF,CAAA;AAUF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,gBAAgB,GAAI,UAAU,OAAO,KAAG,OAqDpD,CAAA"}
|