@scalar/workspace-store 0.5.2 → 0.6.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 +12 -0
- package/README.md +47 -6
- package/dist/helpers/proxy.d.ts.map +1 -1
- package/dist/helpers/proxy.js +5 -2
- package/dist/helpers/proxy.js.map +2 -2
- package/dist/server.d.ts +29 -19
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +52 -49
- package/dist/server.js.map +2 -2
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @scalar/workspace-store
|
|
2
2
|
|
|
3
|
+
## 0.6.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- b97c82a: feat(workspace-store): server store input document from different sources
|
|
8
|
+
- 9f786d5: feat(workspace-store): preserve the original ref information
|
|
9
|
+
|
|
10
|
+
### Patch Changes
|
|
11
|
+
|
|
12
|
+
- @scalar/code-highlight@0.1.4
|
|
13
|
+
- @scalar/openapi-parser@0.18.0
|
|
14
|
+
|
|
3
15
|
## 0.5.2
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ Create a new store in SSR mode
|
|
|
11
11
|
|
|
12
12
|
```ts
|
|
13
13
|
// Create the store
|
|
14
|
-
const store = createServerWorkspaceStore({
|
|
14
|
+
const store = await createServerWorkspaceStore({
|
|
15
15
|
baseUrl: 'example.com',
|
|
16
16
|
mode: 'ssr',
|
|
17
17
|
meta: { 'x-scalar-active-document': 'document-name' },
|
|
@@ -44,7 +44,7 @@ const store = createServerWorkspaceStore({
|
|
|
44
44
|
})
|
|
45
45
|
|
|
46
46
|
// Add a new document to the store
|
|
47
|
-
store.addDocument({
|
|
47
|
+
await store.addDocument({
|
|
48
48
|
openapi: '3.1.1',
|
|
49
49
|
info: {
|
|
50
50
|
title: 'Hello World',
|
|
@@ -82,7 +82,7 @@ Create a new store in static mode
|
|
|
82
82
|
|
|
83
83
|
```ts
|
|
84
84
|
// Create the store
|
|
85
|
-
const store = createServerWorkspaceStore({
|
|
85
|
+
const store = await createServerWorkspaceStore({
|
|
86
86
|
directory: 'assets',
|
|
87
87
|
mode: 'static',
|
|
88
88
|
meta: { 'x-scalar-active-document': 'document-name' },
|
|
@@ -115,7 +115,7 @@ const store = createServerWorkspaceStore({
|
|
|
115
115
|
})
|
|
116
116
|
|
|
117
117
|
// Add a new document to the store
|
|
118
|
-
store.addDocument({
|
|
118
|
+
await store.addDocument({
|
|
119
119
|
openapi: '3.1.1',
|
|
120
120
|
info: {
|
|
121
121
|
title: 'Hello World',
|
|
@@ -145,6 +145,30 @@ store.addDocument({
|
|
|
145
145
|
const workspace = await store.generateWorkspaceChunks()
|
|
146
146
|
```
|
|
147
147
|
|
|
148
|
+
### Load documents from external sources
|
|
149
|
+
```ts
|
|
150
|
+
// Initialize the store with documents from external sources
|
|
151
|
+
const store = await createServerWorkspaceStore({
|
|
152
|
+
mode: 'static',
|
|
153
|
+
documents: [
|
|
154
|
+
{
|
|
155
|
+
name: 'remoteFile',
|
|
156
|
+
url: 'http://localhost/document.json'
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
name: 'fsFile',
|
|
160
|
+
path: './document.json'
|
|
161
|
+
}
|
|
162
|
+
]
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
// Output: { openapi: 'x.x.x', ... }
|
|
166
|
+
console.log(store.getWorkspace().documents.remoteFile)
|
|
167
|
+
|
|
168
|
+
// Output: { openapi: 'x.x.x', ... }
|
|
169
|
+
console.log(store.getWorkspace().documents.fsFile)
|
|
170
|
+
```
|
|
171
|
+
|
|
148
172
|
## Client-Side Workspace Store
|
|
149
173
|
|
|
150
174
|
A reactive workspace store for managing OpenAPI documents with automatic reference resolution and chunked loading capabilities. Works seamlessly with server-side stores to handle large documents efficiently.
|
|
@@ -154,7 +178,7 @@ A reactive workspace store for managing OpenAPI documents with automatic referen
|
|
|
154
178
|
```ts
|
|
155
179
|
|
|
156
180
|
// Initialize a new workspace store with default document
|
|
157
|
-
const store =
|
|
181
|
+
const store = createWorkspaceStore({
|
|
158
182
|
documents: [
|
|
159
183
|
{
|
|
160
184
|
name: 'default',
|
|
@@ -172,7 +196,7 @@ const store = await createWorkspaceStore({
|
|
|
172
196
|
})
|
|
173
197
|
|
|
174
198
|
// Add another OpenAPI document to the workspace
|
|
175
|
-
store.
|
|
199
|
+
store.addDocumentSync({
|
|
176
200
|
document: {
|
|
177
201
|
info: {
|
|
178
202
|
title: 'OpenApi document',
|
|
@@ -196,4 +220,21 @@ store.updateDocument('active', "x-scalar-active-auth", '<value>')
|
|
|
196
220
|
|
|
197
221
|
// Resolve and load document chunks including any $ref references
|
|
198
222
|
await store.resolve(['paths', '/users', 'get'])
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
#### Load documents from external sources
|
|
226
|
+
|
|
227
|
+
You can only initialize the store with object literals but if you want to add documents from external sources you can use the addDocument function
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
const store = createWorkspaceStore()
|
|
231
|
+
|
|
232
|
+
// Load a document into the store from a remote url
|
|
233
|
+
await store.addDocument({
|
|
234
|
+
name: 'default',
|
|
235
|
+
url: 'http://localhost/document.json'
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
// Output: { openapi: 'x.x.x', ... }
|
|
239
|
+
console.log(store.workspace.documents.default)
|
|
199
240
|
```
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/helpers/proxy.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAE9C,eAAO,MAAM,aAAa,eAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/helpers/proxy.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAE9C,eAAO,MAAM,aAAa,eAAmB,CAAA;AAyH7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,aAAa,EACtD,YAAY,EAAE,CAAC,EACf,cAAc,GAAE,CAAgB,EAChC,kBAAkB,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,GACtC,CAAC,CAyBH;AAED;;;;;;;;;GASG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,aAAa,iBAExC"}
|
package/dist/helpers/proxy.js
CHANGED
|
@@ -12,7 +12,7 @@ function createProxyHandler(sourceDocument, resolvedProxyCache) {
|
|
|
12
12
|
return true;
|
|
13
13
|
}
|
|
14
14
|
const value = Reflect.get(target, property, receiver);
|
|
15
|
-
const deepResolveNestedRefs = (value2) => {
|
|
15
|
+
const deepResolveNestedRefs = (value2, originalRef) => {
|
|
16
16
|
if (!isObject(value2)) {
|
|
17
17
|
return value2;
|
|
18
18
|
}
|
|
@@ -21,9 +21,12 @@ function createProxyHandler(sourceDocument, resolvedProxyCache) {
|
|
|
21
21
|
if (isLocalRef(ref)) {
|
|
22
22
|
const referencePath = parseJsonPointer(ref);
|
|
23
23
|
const resolvedValue = getValueByPath(sourceDocument, referencePath);
|
|
24
|
-
return deepResolveNestedRefs(resolvedValue);
|
|
24
|
+
return deepResolveNestedRefs(resolvedValue, originalRef ?? ref);
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
+
if (originalRef) {
|
|
28
|
+
return createMagicProxy({ ...value2, "x-original-ref": originalRef }, sourceDocument, resolvedProxyCache);
|
|
29
|
+
}
|
|
27
30
|
return createMagicProxy(value2, sourceDocument, resolvedProxyCache);
|
|
28
31
|
};
|
|
29
32
|
return deepResolveNestedRefs(value);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/helpers/proxy.ts"],
|
|
4
|
-
"sourcesContent": ["import { isReactive, toRaw } from 'vue'\nimport { getValueByPath, parseJsonPointer } from './json-path-utils'\nimport { isLocalRef, isObject } from './general'\nimport type { UnknownObject } from './general'\n\nexport const TARGET_SYMBOL = Symbol('target')\n\n/**\n * Creates a proxy handler that automatically resolves JSON references ($ref) in an object.\n * The handler intercepts property access, assignment, and property enumeration to automatically\n * resolve any $ref references to their target values in the source document.\n *\n * @param sourceDocument - The source document containing the reference targets\n * @param resolvedProxyCache - Optional cache to store resolved proxies and prevent duplicate proxies\n * @returns A proxy handler that automatically resolves $ref references\n */\nfunction createProxyHandler(\n sourceDocument: UnknownObject,\n resolvedProxyCache?: WeakMap<object, UnknownObject>,\n): ProxyHandler<UnknownObject> {\n return {\n get(target, property, receiver) {\n if (property === TARGET_SYMBOL) {\n return target\n }\n\n if (property === '__isProxy') {\n return true\n }\n\n const value = Reflect.get(target, property, receiver)\n\n /**\n * Recursively resolves nested references in an object.\n * If the value is not an object, returns it as is.\n * If the value has a $ref property:\n * - For local references: resolves the reference and continues resolving nested refs\n * - For all other objects: creates a proxy for lazy resolution\n */\n const deepResolveNestedRefs = (value: unknown) => {\n if (!isObject(value)) {\n return value\n }\n\n if ('$ref' in value) {\n const ref = value.$ref as string\n\n if (isLocalRef(ref)) {\n const referencePath = parseJsonPointer(ref)\n const resolvedValue = getValueByPath(sourceDocument, referencePath)\n\n return deepResolveNestedRefs(resolvedValue)\n }\n }\n\n return createMagicProxy(value, sourceDocument, resolvedProxyCache)\n }\n\n return deepResolveNestedRefs(value)\n },\n\n set(target: UnknownObject, property: string, newValue: unknown, receiver: UnknownObject) {\n const rawTarget = isReactive(target) ? toRaw(target) : target\n const currentValue = rawTarget[property]\n\n if (\n isObject(currentValue) &&\n '$ref' in currentValue &&\n typeof currentValue.$ref === 'string' &&\n isLocalRef(currentValue.$ref)\n ) {\n const referencePath = parseJsonPointer(currentValue.$ref)\n const targetObject = getValueByPath(sourceDocument, referencePath.slice(0, -1)) as UnknownObject\n const lastPathSegment = referencePath[referencePath.length - 1]\n\n if (targetObject && lastPathSegment) {\n targetObject[lastPathSegment] = newValue\n }\n } else {\n Reflect.set(rawTarget, property, newValue, receiver)\n }\n return true\n },\n\n has(target: UnknownObject, key: string) {\n if (typeof key === 'string' && key !== '$ref' && typeof target.$ref === 'string' && isLocalRef(target.$ref)) {\n const referencePath = parseJsonPointer(target['$ref'])\n const resolvedValue = getValueByPath(sourceDocument, referencePath) as UnknownObject\n\n return resolvedValue ? key in resolvedValue : false\n }\n\n return key in target\n },\n\n ownKeys(target: UnknownObject) {\n if ('$ref' in target && typeof target.$ref === 'string' && isLocalRef(target.$ref)) {\n const referencePath = parseJsonPointer(target['$ref'])\n const resolvedValue = getValueByPath(sourceDocument, referencePath)\n\n return resolvedValue ? Reflect.ownKeys(resolvedValue) : []\n }\n\n return Reflect.ownKeys(target)\n },\n\n getOwnPropertyDescriptor(target: UnknownObject, key: string) {\n if ('$ref' in target && key !== '$ref' && typeof target.$ref === 'string' && isLocalRef(target.$ref)) {\n const referencePath = parseJsonPointer(target['$ref'])\n const resolvedValue = getValueByPath(sourceDocument, referencePath)\n\n if (resolvedValue) {\n return Object.getOwnPropertyDescriptor(resolvedValue, key)\n }\n }\n\n return Object.getOwnPropertyDescriptor(target, key)\n },\n }\n}\n\n/**\n * Creates a proxy that automatically resolves JSON references ($ref) in an object.\n * The proxy intercepts property access and automatically resolves any $ref references\n * to their target values in the source document.\n *\n * @param targetObject - The object to create a proxy for\n * @param sourceDocument - The source document containing the reference targets (defaults to targetObject)\n * @param resolvedProxyCache - Optional cache to store resolved proxies and prevent duplicate proxies\n * @returns A proxy that automatically resolves $ref references\n *\n * @example\n * // Basic usage with local references\n * const doc = {\n * components: {\n * schemas: {\n * User: { type: 'object', properties: { name: { type: 'string' } } }\n * }\n * },\n * paths: {\n * '/users': {\n * get: {\n * responses: {\n * 200: {\n * content: {\n * 'application/json': {\n * schema: { $ref: '#/components/schemas/User' }\n * }\n * }\n * }\n * }\n * }\n * }\n * }\n * }\n *\n * const proxy = createMagicProxy(doc)\n * // Accessing the schema will automatically resolve the $ref\n * console.log(proxy.paths['/users'].get.responses[200].content['application/json'].schema)\n * // Output: { type: 'object', properties: { name: { type: 'string' } } }\n *\n * @example\n * // Using with a cache to prevent duplicate proxies\n * const cache = new WeakMap()\n * const proxy1 = createMagicProxy(doc, doc, cache)\n * const proxy2 = createMagicProxy(doc, doc, cache)\n * // proxy1 and proxy2 are the same instance due to caching\n * console.log(proxy1 === proxy2) // true\n */\nexport function createMagicProxy<T extends UnknownObject>(\n targetObject: T,\n sourceDocument: T = targetObject,\n resolvedProxyCache?: WeakMap<object, T>,\n): T {\n if (!isObject(targetObject)) {\n return targetObject\n }\n\n const rawTarget = isReactive(targetObject) ? toRaw(targetObject) : targetObject\n\n // check for cached results\n if (resolvedProxyCache?.has(rawTarget)) {\n const cachedValue = resolvedProxyCache.get(rawTarget)\n\n if (cachedValue) {\n return cachedValue\n }\n }\n\n // Create a handler with the correct context\n const handler = createProxyHandler(sourceDocument, resolvedProxyCache)\n const proxy = new Proxy<T>(rawTarget, handler)\n\n if (resolvedProxyCache) {\n resolvedProxyCache.set(rawTarget, proxy)\n }\n\n return proxy\n}\n\n/**\n * Gets the raw (non-proxied) version of an object created by createMagicProxy.\n * This is useful when you need to access the original object without the magic proxy wrapper.\n *\n * @param obj - The magic proxy object to get the raw version of\n * @returns The raw version of the object\n * @example\n * const proxy = createMagicProxy({ foo: { $ref: '#/bar' } })\n * const raw = getRaw(proxy) // { foo: { $ref: '#/bar' } }\n */\nexport function getRaw(obj: UnknownObject) {\n return (obj as { [TARGET_SYMBOL]: UnknownObject })[TARGET_SYMBOL]\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,YAAY,aAAa;AAClC,SAAS,gBAAgB,wBAAwB;AACjD,SAAS,YAAY,gBAAgB;AAG9B,MAAM,gBAAgB,OAAO,QAAQ;AAW5C,SAAS,mBACP,gBACA,oBAC6B;AAC7B,SAAO;AAAA,IACL,IAAI,QAAQ,UAAU,UAAU;AAC9B,UAAI,aAAa,eAAe;AAC9B,eAAO;AAAA,MACT;AAEA,UAAI,aAAa,aAAa;AAC5B,eAAO;AAAA,MACT;AAEA,YAAM,QAAQ,QAAQ,IAAI,QAAQ,UAAU,QAAQ;AASpD,YAAM,wBAAwB,CAACA,
|
|
4
|
+
"sourcesContent": ["import { isReactive, toRaw } from 'vue'\nimport { getValueByPath, parseJsonPointer } from './json-path-utils'\nimport { isLocalRef, isObject } from './general'\nimport type { UnknownObject } from './general'\n\nexport const TARGET_SYMBOL = Symbol('target')\n\n/**\n * Creates a proxy handler that automatically resolves JSON references ($ref) in an object.\n * The handler intercepts property access, assignment, and property enumeration to automatically\n * resolve any $ref references to their target values in the source document.\n *\n * @param sourceDocument - The source document containing the reference targets\n * @param resolvedProxyCache - Optional cache to store resolved proxies and prevent duplicate proxies\n * @returns A proxy handler that automatically resolves $ref references\n */\nfunction createProxyHandler(\n sourceDocument: UnknownObject,\n resolvedProxyCache?: WeakMap<object, UnknownObject>,\n): ProxyHandler<UnknownObject> {\n return {\n get(target, property, receiver) {\n if (property === TARGET_SYMBOL) {\n return target\n }\n\n if (property === '__isProxy') {\n return true\n }\n\n const value = Reflect.get(target, property, receiver)\n\n /**\n * Recursively resolves nested references in an object.\n * If the value is not an object, returns it as is.\n * If the value has a $ref property:\n * - For local references: resolves the reference and continues resolving nested refs\n * - For all other objects: creates a proxy for lazy resolution\n */\n const deepResolveNestedRefs = (value: unknown, originalRef?: string) => {\n if (!isObject(value)) {\n return value\n }\n\n if ('$ref' in value) {\n const ref = value.$ref as string\n\n if (isLocalRef(ref)) {\n const referencePath = parseJsonPointer(ref)\n const resolvedValue = getValueByPath(sourceDocument, referencePath)\n\n // preserve the first $ref to maintain the original reference\n return deepResolveNestedRefs(resolvedValue, originalRef ?? ref)\n }\n }\n\n if (originalRef) {\n return createMagicProxy({ ...value, 'x-original-ref': originalRef }, sourceDocument, resolvedProxyCache)\n }\n\n return createMagicProxy(value, sourceDocument, resolvedProxyCache)\n }\n\n return deepResolveNestedRefs(value)\n },\n\n set(target: UnknownObject, property: string, newValue: unknown, receiver: UnknownObject) {\n const rawTarget = isReactive(target) ? toRaw(target) : target\n const currentValue = rawTarget[property]\n\n if (\n isObject(currentValue) &&\n '$ref' in currentValue &&\n typeof currentValue.$ref === 'string' &&\n isLocalRef(currentValue.$ref)\n ) {\n const referencePath = parseJsonPointer(currentValue.$ref)\n const targetObject = getValueByPath(sourceDocument, referencePath.slice(0, -1)) as UnknownObject\n const lastPathSegment = referencePath[referencePath.length - 1]\n\n if (targetObject && lastPathSegment) {\n targetObject[lastPathSegment] = newValue\n }\n } else {\n Reflect.set(rawTarget, property, newValue, receiver)\n }\n return true\n },\n\n has(target: UnknownObject, key: string) {\n if (typeof key === 'string' && key !== '$ref' && typeof target.$ref === 'string' && isLocalRef(target.$ref)) {\n const referencePath = parseJsonPointer(target['$ref'])\n const resolvedValue = getValueByPath(sourceDocument, referencePath) as UnknownObject\n\n return resolvedValue ? key in resolvedValue : false\n }\n\n return key in target\n },\n\n ownKeys(target: UnknownObject) {\n if ('$ref' in target && typeof target.$ref === 'string' && isLocalRef(target.$ref)) {\n const referencePath = parseJsonPointer(target['$ref'])\n const resolvedValue = getValueByPath(sourceDocument, referencePath)\n\n return resolvedValue ? Reflect.ownKeys(resolvedValue) : []\n }\n\n return Reflect.ownKeys(target)\n },\n\n getOwnPropertyDescriptor(target: UnknownObject, key: string) {\n if ('$ref' in target && key !== '$ref' && typeof target.$ref === 'string' && isLocalRef(target.$ref)) {\n const referencePath = parseJsonPointer(target['$ref'])\n const resolvedValue = getValueByPath(sourceDocument, referencePath)\n\n if (resolvedValue) {\n return Object.getOwnPropertyDescriptor(resolvedValue, key)\n }\n }\n\n return Object.getOwnPropertyDescriptor(target, key)\n },\n }\n}\n\n/**\n * Creates a proxy that automatically resolves JSON references ($ref) in an object.\n * The proxy intercepts property access and automatically resolves any $ref references\n * to their target values in the source document.\n *\n * @param targetObject - The object to create a proxy for\n * @param sourceDocument - The source document containing the reference targets (defaults to targetObject)\n * @param resolvedProxyCache - Optional cache to store resolved proxies and prevent duplicate proxies\n * @returns A proxy that automatically resolves $ref references\n *\n * @example\n * // Basic usage with local references\n * const doc = {\n * components: {\n * schemas: {\n * User: { type: 'object', properties: { name: { type: 'string' } } }\n * }\n * },\n * paths: {\n * '/users': {\n * get: {\n * responses: {\n * 200: {\n * content: {\n * 'application/json': {\n * schema: { $ref: '#/components/schemas/User' }\n * }\n * }\n * }\n * }\n * }\n * }\n * }\n * }\n *\n * const proxy = createMagicProxy(doc)\n * // Accessing the schema will automatically resolve the $ref\n * console.log(proxy.paths['/users'].get.responses[200].content['application/json'].schema)\n * // Output: { type: 'object', properties: { name: { type: 'string' } } }\n *\n * @example\n * // Using with a cache to prevent duplicate proxies\n * const cache = new WeakMap()\n * const proxy1 = createMagicProxy(doc, doc, cache)\n * const proxy2 = createMagicProxy(doc, doc, cache)\n * // proxy1 and proxy2 are the same instance due to caching\n * console.log(proxy1 === proxy2) // true\n */\nexport function createMagicProxy<T extends UnknownObject>(\n targetObject: T,\n sourceDocument: T = targetObject,\n resolvedProxyCache?: WeakMap<object, T>,\n): T {\n if (!isObject(targetObject)) {\n return targetObject\n }\n\n const rawTarget = isReactive(targetObject) ? toRaw(targetObject) : targetObject\n\n // check for cached results\n if (resolvedProxyCache?.has(rawTarget)) {\n const cachedValue = resolvedProxyCache.get(rawTarget)\n\n if (cachedValue) {\n return cachedValue\n }\n }\n\n // Create a handler with the correct context\n const handler = createProxyHandler(sourceDocument, resolvedProxyCache)\n const proxy = new Proxy<T>(rawTarget, handler)\n\n if (resolvedProxyCache) {\n resolvedProxyCache.set(rawTarget, proxy)\n }\n\n return proxy\n}\n\n/**\n * Gets the raw (non-proxied) version of an object created by createMagicProxy.\n * This is useful when you need to access the original object without the magic proxy wrapper.\n *\n * @param obj - The magic proxy object to get the raw version of\n * @returns The raw version of the object\n * @example\n * const proxy = createMagicProxy({ foo: { $ref: '#/bar' } })\n * const raw = getRaw(proxy) // { foo: { $ref: '#/bar' } }\n */\nexport function getRaw(obj: UnknownObject) {\n return (obj as { [TARGET_SYMBOL]: UnknownObject })[TARGET_SYMBOL]\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["value"]
|
|
7
7
|
}
|
package/dist/server.d.ts
CHANGED
|
@@ -1,15 +1,27 @@
|
|
|
1
1
|
import type { WorkspaceDocumentMeta, WorkspaceMeta } from './schemas/workspace.js';
|
|
2
2
|
import { type createNavigationOptions } from './navigation/index.js';
|
|
3
|
+
import { extensions } from './schemas/extensions.js';
|
|
3
4
|
import { type OpenApiDocument } from './schemas/v3.1/strict/openapi-document.js';
|
|
4
5
|
import type { PathsObject } from './schemas/v3.1/strict/paths.js';
|
|
5
6
|
import type { OperationObject } from './schemas/v3.1/strict/path-operations.js';
|
|
7
|
+
import type { TraversedEntry } from './navigation/types.js';
|
|
6
8
|
export declare const WORKSPACE_FILE_NAME = "scalar-workspace.json";
|
|
9
|
+
type WorkspaceDocumentMetaInput = {
|
|
10
|
+
name: string;
|
|
11
|
+
meta?: WorkspaceDocumentMeta;
|
|
12
|
+
};
|
|
13
|
+
type UrlDoc = {
|
|
14
|
+
url: string;
|
|
15
|
+
} & WorkspaceDocumentMetaInput;
|
|
16
|
+
type FileDoc = {
|
|
17
|
+
path: string;
|
|
18
|
+
} & WorkspaceDocumentMetaInput;
|
|
19
|
+
type ObjectDoc = {
|
|
20
|
+
document: Record<string, unknown>;
|
|
21
|
+
} & WorkspaceDocumentMetaInput;
|
|
22
|
+
type WorkspaceDocumentInput = UrlDoc | ObjectDoc | FileDoc;
|
|
7
23
|
type CreateServerWorkspaceStoreBase = {
|
|
8
|
-
documents:
|
|
9
|
-
name: string;
|
|
10
|
-
document: Record<string, unknown> | string;
|
|
11
|
-
meta?: WorkspaceDocumentMeta;
|
|
12
|
-
}[];
|
|
24
|
+
documents: WorkspaceDocumentInput[];
|
|
13
25
|
meta?: WorkspaceMeta;
|
|
14
26
|
config?: createNavigationOptions;
|
|
15
27
|
};
|
|
@@ -2652,7 +2664,7 @@ export declare function externalizePathReferences(document: OpenApiDocument, met
|
|
|
2652
2664
|
/**
|
|
2653
2665
|
* Create server state workspace store
|
|
2654
2666
|
*/
|
|
2655
|
-
export declare function createServerWorkspaceStore(workspaceProps: CreateServerWorkspaceStore): {
|
|
2667
|
+
export declare function createServerWorkspaceStore(workspaceProps: CreateServerWorkspaceStore): Promise<{
|
|
2656
2668
|
/**
|
|
2657
2669
|
* Generates workspace chunks by writing components and operations to the filesystem.
|
|
2658
2670
|
*
|
|
@@ -2678,7 +2690,9 @@ export declare function createServerWorkspaceStore(workspaceProps: CreateServerW
|
|
|
2678
2690
|
* @returns The complete workspace document
|
|
2679
2691
|
*/
|
|
2680
2692
|
getWorkspace: () => {
|
|
2681
|
-
documents: Record<string,
|
|
2693
|
+
documents: Record<string, OpenApiDocument & {
|
|
2694
|
+
[extensions.document.navigation]: TraversedEntry[];
|
|
2695
|
+
}>;
|
|
2682
2696
|
"x-scalar-dark-mode"?: boolean | undefined;
|
|
2683
2697
|
"x-scalar-default-client"?: string | undefined;
|
|
2684
2698
|
"x-scalar-active-document"?: string | undefined;
|
|
@@ -2704,20 +2718,16 @@ export declare function createServerWorkspaceStore(workspaceProps: CreateServerW
|
|
|
2704
2718
|
*/
|
|
2705
2719
|
get: (pointer: string) => unknown;
|
|
2706
2720
|
/**
|
|
2707
|
-
* Adds a new document to the workspace.
|
|
2721
|
+
* Adds a new document to the workspace asynchronously.
|
|
2708
2722
|
*
|
|
2709
|
-
*
|
|
2710
|
-
*
|
|
2711
|
-
*
|
|
2712
|
-
*
|
|
2713
|
-
* - Added to the workspace with its metadata
|
|
2723
|
+
* This function:
|
|
2724
|
+
* 1. Loads the document using the provided input
|
|
2725
|
+
* 2. Checks if the document loaded successfully
|
|
2726
|
+
* 3. If successful, adds the document to the workspace using addDocumentSync
|
|
2714
2727
|
*
|
|
2715
|
-
* @param
|
|
2716
|
-
* @param meta - Document metadata including required name and optional settings
|
|
2728
|
+
* @param input - The document input containing the document source and metadata
|
|
2717
2729
|
*/
|
|
2718
|
-
addDocument: (
|
|
2719
|
-
|
|
2720
|
-
} & WorkspaceDocumentMeta) => void;
|
|
2721
|
-
};
|
|
2730
|
+
addDocument: (input: WorkspaceDocumentInput) => Promise<void>;
|
|
2731
|
+
}>;
|
|
2722
2732
|
export {};
|
|
2723
2733
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAG/E,OAAO,EAAoB,KAAK,uBAAuB,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAG/E,OAAO,EAAoB,KAAK,uBAAuB,EAAE,MAAM,cAAc,CAAA;AAC7E,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,wCAAwC,CAAA;AACpG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAE9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAA;AAI5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAGxD,eAAO,MAAM,mBAAmB,0BAA0B,CAAA;AAE1D,KAAK,0BAA0B,GAAG;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,qBAAqB,CAAA;CAC7B,CAAA;AAED,KAAK,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,0BAA0B,CAAA;AAC1D,KAAK,OAAO,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,0BAA0B,CAAA;AAC5D,KAAK,SAAS,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,0BAA0B,CAAA;AAEnF,KAAK,sBAAsB,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAA;AAE1D,KAAK,8BAA8B,GAAG;IACpC,SAAS,EAAE,sBAAsB,EAAE,CAAA;IACnC,IAAI,CAAC,EAAE,aAAa,CAAA;IACpB,MAAM,CAAC,EAAE,uBAAuB,CAAA;CACjC,CAAA;AACD,KAAK,0BAA0B,GAC3B,CAAC;IACC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,QAAQ,CAAA;CACf,GAAG,8BAA8B,CAAC,GACnC,CAAC;IACC,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,KAAK,CAAA;CACZ,GAAG,8BAA8B,CAAC,CAAA;AAIvC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
|
package/dist/server.js
CHANGED
|
@@ -4,9 +4,10 @@ import fs from "node:fs/promises";
|
|
|
4
4
|
import { cwd } from "node:process";
|
|
5
5
|
import { createNavigation } from "./navigation/index.js";
|
|
6
6
|
import { extensions } from "./schemas/extensions.js";
|
|
7
|
-
import { coerceValue } from "./schemas/typebox-coerce.js";
|
|
8
7
|
import { OpenAPIDocumentSchema } from "./schemas/v3.1/strict/openapi-document.js";
|
|
9
8
|
import { keyOf } from "./helpers/general.js";
|
|
9
|
+
import { fetchUrls, readFiles } from "@scalar/openapi-parser/plugins";
|
|
10
|
+
import { coerceValue } from "./schemas/typebox-coerce.js";
|
|
10
11
|
const DEFAULT_ASSETS_FOLDER = "assets";
|
|
11
12
|
const WORKSPACE_FILE_NAME = "scalar-workspace.json";
|
|
12
13
|
const httpMethods = /* @__PURE__ */ new Set(["get", "put", "post", "delete", "options", "head", "patch", "trace"]);
|
|
@@ -75,30 +76,52 @@ function externalizePathReferences(document, meta) {
|
|
|
75
76
|
});
|
|
76
77
|
return result;
|
|
77
78
|
}
|
|
78
|
-
function
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
79
|
+
async function loadDocument(workspaceDocument) {
|
|
80
|
+
if ("url" in workspaceDocument) {
|
|
81
|
+
return fetchUrls().exec(workspaceDocument.url);
|
|
82
|
+
}
|
|
83
|
+
if ("path" in workspaceDocument) {
|
|
84
|
+
return readFiles().exec(workspaceDocument.path);
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
ok: true,
|
|
88
|
+
data: workspaceDocument.document
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
async function createServerWorkspaceStore(workspaceProps) {
|
|
91
92
|
const workspace = {
|
|
92
93
|
...workspaceProps.meta,
|
|
93
|
-
documents:
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
94
|
+
documents: {}
|
|
95
|
+
};
|
|
96
|
+
const assets = {};
|
|
97
|
+
const addDocumentSync = (document, meta) => {
|
|
98
|
+
const { name, ...documentMeta } = meta;
|
|
99
|
+
const documentV3 = coerceValue(OpenAPIDocumentSchema, upgrade(document).specification);
|
|
100
|
+
assets[meta.name] = {
|
|
101
|
+
components: documentV3.components,
|
|
102
|
+
operations: documentV3.paths && escapePaths(filterHttpMethodsOnly(documentV3.paths))
|
|
103
|
+
};
|
|
104
|
+
const options = workspaceProps.mode === "ssr" ? { mode: workspaceProps.mode, name, baseUrl: workspaceProps.baseUrl } : { mode: workspaceProps.mode, name, directory: workspaceProps.directory ?? DEFAULT_ASSETS_FOLDER };
|
|
105
|
+
const components = externalizeComponentReferences(documentV3, options);
|
|
106
|
+
const paths = externalizePathReferences(documentV3, options);
|
|
107
|
+
const { entries } = createNavigation(documentV3, workspaceProps.config ?? {});
|
|
108
|
+
workspace.documents[meta.name] = {
|
|
109
|
+
...documentMeta,
|
|
110
|
+
...documentV3,
|
|
111
|
+
components,
|
|
112
|
+
paths,
|
|
113
|
+
[extensions.document.navigation]: entries
|
|
114
|
+
};
|
|
101
115
|
};
|
|
116
|
+
const addDocument = async (input) => {
|
|
117
|
+
const document = await loadDocument(input);
|
|
118
|
+
if (!document.ok) {
|
|
119
|
+
console.warn(`Failed to load document "${input.name}`);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
addDocumentSync(document.data, { name: input.name, ...input.meta });
|
|
123
|
+
};
|
|
124
|
+
await Promise.all(workspaceProps.documents.map(addDocument));
|
|
102
125
|
return {
|
|
103
126
|
/**
|
|
104
127
|
* Generates workspace chunks by writing components and operations to the filesystem.
|
|
@@ -176,36 +199,16 @@ function createServerWorkspaceStore(workspaceProps) {
|
|
|
176
199
|
return getValueByPath(assets, parseJsonPointer(pointer));
|
|
177
200
|
},
|
|
178
201
|
/**
|
|
179
|
-
* Adds a new document to the workspace.
|
|
202
|
+
* Adds a new document to the workspace asynchronously.
|
|
180
203
|
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
* - Added to the workspace with its metadata
|
|
204
|
+
* This function:
|
|
205
|
+
* 1. Loads the document using the provided input
|
|
206
|
+
* 2. Checks if the document loaded successfully
|
|
207
|
+
* 3. If successful, adds the document to the workspace using addDocumentSync
|
|
186
208
|
*
|
|
187
|
-
* @param
|
|
188
|
-
* @param meta - Document metadata including required name and optional settings
|
|
209
|
+
* @param input - The document input containing the document source and metadata
|
|
189
210
|
*/
|
|
190
|
-
addDocument
|
|
191
|
-
const { name, ...documentMeta } = meta;
|
|
192
|
-
const documentV3 = coerceValue(OpenAPIDocumentSchema, upgrade(document).specification);
|
|
193
|
-
assets[meta.name] = {
|
|
194
|
-
components: documentV3.components,
|
|
195
|
-
operations: documentV3.paths && escapePaths(filterHttpMethodsOnly(documentV3.paths))
|
|
196
|
-
};
|
|
197
|
-
const options = workspaceProps.mode === "ssr" ? { mode: workspaceProps.mode, name, baseUrl: workspaceProps.baseUrl } : { mode: workspaceProps.mode, name, directory: workspaceProps.directory ?? DEFAULT_ASSETS_FOLDER };
|
|
198
|
-
const components = externalizeComponentReferences(documentV3, options);
|
|
199
|
-
const paths = externalizePathReferences(documentV3, options);
|
|
200
|
-
const { entries } = createNavigation(documentV3, workspaceProps.config ?? {});
|
|
201
|
-
workspace.documents[meta.name] = {
|
|
202
|
-
...documentMeta,
|
|
203
|
-
...documentV3,
|
|
204
|
-
components,
|
|
205
|
-
paths,
|
|
206
|
-
[extensions.document.navigation]: entries
|
|
207
|
-
};
|
|
208
|
-
}
|
|
211
|
+
addDocument
|
|
209
212
|
};
|
|
210
213
|
}
|
|
211
214
|
export {
|
package/dist/server.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/server.ts"],
|
|
4
|
-
"sourcesContent": ["import { escapeJsonPointer, upgrade } from '@scalar/openapi-parser'\nimport { getValueByPath, parseJsonPointer } from './helpers/json-path-utils'\nimport type { WorkspaceDocumentMeta, WorkspaceMeta } from './schemas/workspace'\nimport fs from 'node:fs/promises'\nimport { cwd } from 'node:process'\nimport { createNavigation, type createNavigationOptions } from '@/navigation'\nimport { extensions } from '@/schemas/extensions'\nimport { coerceValue } from '@/schemas/typebox-coerce'\nimport { OpenAPIDocumentSchema, type OpenApiDocument } from '@/schemas/v3.1/strict/openapi-document'\nimport type { PathsObject } from '@/schemas/v3.1/strict/paths'\nimport { keyOf } from '@/helpers/general'\nimport type { ComponentsObject } from '@/schemas/v3.1/strict/components'\nimport type { OperationObject } from '@/schemas/v3.1/strict/path-operations'\n\nconst DEFAULT_ASSETS_FOLDER = 'assets'\nexport const WORKSPACE_FILE_NAME = 'scalar-workspace.json'\n\n// TODO: support input document from different sources\ntype CreateServerWorkspaceStoreBase = {\n documents: {\n name: string\n document: Record<string, unknown> | string\n meta?: WorkspaceDocumentMeta\n }[]\n meta?: WorkspaceMeta\n config?: createNavigationOptions\n}\ntype CreateServerWorkspaceStore =\n | ({\n directory?: string\n mode: 'static'\n } & CreateServerWorkspaceStoreBase)\n | ({\n baseUrl: string\n mode: 'ssr'\n } & CreateServerWorkspaceStoreBase)\n\nconst httpMethods = new Set(['get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace'])\n\n/**\n * Filters an OpenAPI PathsObject to only include standard HTTP methods.\n * Removes any vendor extensions or other non-HTTP properties.\n *\n * @param paths - The OpenAPI PathsObject to filter\n * @returns A new PathsObject containing only standard HTTP methods\n *\n * @example\n * Input: {\n * \"/users\": {\n * \"get\": {...},\n * \"x-custom\": {...},\n * \"post\": {...}\n * }\n * }\n * Output: {\n * \"/users\": {\n * \"get\": {...},\n * \"post\": {...}\n * }\n * }\n */\nexport function filterHttpMethodsOnly(paths: PathsObject) {\n const result: Record<string, Record<string, OperationObject>> = {}\n\n // Todo: skip extension properties\n for (const [path, methods] of Object.entries(paths)) {\n if (!methods) {\n continue\n }\n\n const filteredMethods: Record<string, any> = {}\n\n for (const [method, operation] of Object.entries(methods)) {\n if (httpMethods.has(method.toLowerCase())) {\n filteredMethods[method] = operation\n }\n }\n\n if (Object.keys(filteredMethods).length > 0) {\n result[path] = filteredMethods\n }\n }\n\n return result\n}\n\n/**\n * Escapes path keys in an OpenAPI PathsObject to be JSON Pointer compatible.\n * This is necessary because OpenAPI paths can contain characters that need to be escaped\n * when used as JSON Pointer references (like '/' and '~').\n *\n * @example\n * Input: { \"/users/{id}\": { ... } }\n * Output: { \"/users~1{id}\": { ... } }\n */\nexport function escapePaths(paths: Record<string, Record<string, OperationObject>>) {\n const result: Record<string, Record<string, OperationObject>> = {}\n Object.keys(paths).forEach((path) => {\n result[escapeJsonPointer(path)] = paths[path]\n })\n\n return result\n}\n\n/**\n * Externalizes components by turning them into refs.\n */\nexport function externalizeComponentReferences(\n document: OpenApiDocument,\n meta: { mode: 'ssr'; name: string; baseUrl: string } | { mode: 'static'; name: string; directory: string },\n) {\n const result: Record<string, any> = {}\n\n if (!document.components) {\n return result\n }\n\n Object.entries(document.components).forEach(([type, component]) => {\n if (!component || typeof component !== 'object') {\n return result\n }\n\n result[type] = {}\n Object.keys(component).forEach((name) => {\n const ref =\n meta.mode === 'ssr'\n ? `${meta.baseUrl}/${meta.name}/components/${type}/${name}#`\n : `./chunks/${meta.name}/components/${type}/${name}.json#`\n\n result[type][name] = { '$ref': ref, $global: true }\n })\n })\n\n return result\n}\n\n/**\n * Externalizes paths operations by turning them into refs.\n */\nexport function externalizePathReferences(\n document: OpenApiDocument,\n meta: { mode: 'ssr'; name: string; baseUrl: string } | { mode: 'static'; name: string; directory: string },\n) {\n const result: Record<string, any> = {}\n\n if (!document.paths) {\n return result\n }\n\n Object.entries(document.paths).forEach(([path, pathItem]) => {\n if (!pathItem || typeof pathItem !== 'object') {\n return result\n }\n\n const pathItemRecord = pathItem as Record<string, unknown>\n\n result[path] = {}\n\n const escapedPath = escapeJsonPointer(path)\n\n keyOf(pathItemRecord).forEach((type) => {\n if (httpMethods.has(type)) {\n const ref =\n meta.mode === 'ssr'\n ? `${meta.baseUrl}/${meta.name}/operations/${escapedPath}/${type}#`\n : `./chunks/${meta.name}/operations/${escapedPath}/${type}.json#`\n\n result[path][type] = { '$ref': ref, $global: true }\n } else {\n result[path][type] = pathItemRecord[type]\n }\n })\n })\n\n return result\n}\n\n/**\n * Create server state workspace store\n */\nexport function createServerWorkspaceStore(workspaceProps: CreateServerWorkspaceStore) {\n const documents = workspaceProps.documents.map((el) => {\n const document = upgrade(el.document).specification\n\n const castedDocument = coerceValue(OpenAPIDocumentSchema, document)\n\n return { ...el, document: castedDocument }\n })\n\n /**\n * A map of document chunks that can be loaded asynchronously by the client.\n * Each document is split into components and operations to enable lazy loading.\n * The keys are document names and values contain the components and operations\n * for that document.\n */\n const assets = documents.reduce<\n Record<string, { components?: ComponentsObject; operations?: Record<string, Record<string, OperationObject>> }>\n >((acc, { name, document }) => {\n acc[name] = {\n components: document.components,\n operations: document.paths && escapePaths(filterHttpMethodsOnly(document.paths)),\n }\n return acc\n }, {})\n\n /**\n * Base workspace document containing essential metadata and document references.\n *\n * This workspace document provides the minimal information needed for initial rendering.\n * All components and path operations are replaced with references to enable lazy loading.\n *\n * In SSR mode, references point to API endpoints.\n * In static mode, references point to filesystem chunks.\n */\n const workspace = {\n ...workspaceProps.meta,\n documents: documents.reduce<Record<string, Record<string, unknown>>>((acc, { name, document, meta }) => {\n const options =\n workspaceProps.mode === 'ssr'\n ? { mode: workspaceProps.mode, name, baseUrl: workspaceProps.baseUrl }\n : { mode: workspaceProps.mode, name, directory: workspaceProps.directory ?? DEFAULT_ASSETS_FOLDER }\n\n // Transform the original document by setting all the components and paths operations on refs\n const components = externalizeComponentReferences(document, options)\n const paths = externalizePathReferences(document, options)\n\n // Here we create the sidebar\n const { entries } = createNavigation(document, workspaceProps.config ?? {})\n\n acc[name] = { ...meta, ...document, components, paths, [extensions.document.navigation]: entries }\n return acc\n }, {}),\n }\n\n return {\n /**\n * Generates workspace chunks by writing components and operations to the filesystem.\n *\n * This method is only available in static mode. It creates a directory structure containing:\n * - A workspace file with metadata and document references\n * - Component chunks split by type (schemas, parameters, etc)\n * - Operation chunks split by path and HTTP method\n *\n * The generated workspace references will be relative file paths pointing to these chunks.\n *\n * @throws {Error} If called when mode is not 'static'\n */\n generateWorkspaceChunks: async () => {\n if (workspaceProps.mode !== 'static') {\n throw 'Mode has to be set to `static` to generate filesystem workspace chunks'\n }\n\n // Write the workspace document\n const basePath = `${cwd()}/${workspaceProps.directory ?? DEFAULT_ASSETS_FOLDER}`\n await fs.mkdir(basePath, { recursive: true })\n\n // Write the workspace contents on the file system\n await fs.writeFile(`${basePath}/${WORKSPACE_FILE_NAME}`, JSON.stringify(workspace))\n\n // Write the chunks\n for (const [name, { components, operations }] of Object.entries(assets)) {\n // Write the components chunks\n if (components) {\n for (const [type, component] of Object.entries(components as Record<string, Record<string, unknown>>)) {\n const componentPath = `${basePath}/chunks/${name}/components/${type}`\n await fs.mkdir(componentPath, { recursive: true })\n\n for (const [key, value] of Object.entries(component)) {\n await fs.writeFile(`${componentPath}/${key}.json`, JSON.stringify(value))\n }\n }\n }\n\n // Write the operations chunks\n if (operations) {\n for (const [path, methods] of Object.entries(operations)) {\n const operationPath = `${basePath}/chunks/${name}/operations/${path}`\n await fs.mkdir(operationPath, { recursive: true })\n\n for (const [method, operation] of Object.entries(methods)) {\n await fs.writeFile(`${operationPath}/${method}.json`, JSON.stringify(operation))\n }\n }\n }\n }\n },\n /**\n * Returns the workspace document containing metadata and all sparse documents.\n *\n * The workspace document includes:\n * - Global workspace metadata (theme, active document, etc)\n * - Document metadata and sparse document\n * - In SSR mode: References point to in-memory chunks\n * - In static mode: References point to filesystem chunks\n *\n * @returns The complete workspace document\n */\n getWorkspace: () => {\n return workspace\n },\n /**\n * Retrieves a chunk of data from the workspace using a JSON Pointer\n *\n * A JSON Pointer is a string that references a specific location in a JSON document.\n * Only components and operations chunks can be retrieved.\n *\n * @example\n * ```ts\n * // Get a component\n * get('#/document-name/components/schemas/User')\n *\n * // Get an operation\n * get('#/document-name/operations/pets/get')\n * ```\n *\n * @param pointer - The JSON Pointer string to locate the chunk\n * @returns The chunk data if found, undefined otherwise\n */\n get: (pointer: string) => {\n return getValueByPath(assets, parseJsonPointer(pointer))\n },\n /**\n * Adds a new document to the workspace.\n *\n * The document will be:\n * - Upgraded to OpenAPI 3.1 if needed\n * - Split into components and operations chunks\n * - Have its references externalized based on the workspace mode\n * - Added to the workspace with its metadata\n *\n * @param document - The OpenAPI document to add\n * @param meta - Document metadata including required name and optional settings\n */\n addDocument: (document: Record<string, unknown>, meta: { name: string } & WorkspaceDocumentMeta) => {\n const { name, ...documentMeta } = meta\n\n const documentV3 = coerceValue(OpenAPIDocumentSchema, upgrade(document).specification)\n\n // add the assets\n assets[meta.name] = {\n components: documentV3.components,\n operations: documentV3.paths && escapePaths(filterHttpMethodsOnly(documentV3.paths)),\n }\n\n const options =\n workspaceProps.mode === 'ssr'\n ? { mode: workspaceProps.mode, name, baseUrl: workspaceProps.baseUrl }\n : { mode: workspaceProps.mode, name, directory: workspaceProps.directory ?? DEFAULT_ASSETS_FOLDER }\n\n const components = externalizeComponentReferences(documentV3, options)\n const paths = externalizePathReferences(documentV3, options)\n\n // Build the sidebar entries\n const { entries } = createNavigation(documentV3, workspaceProps.config ?? {})\n\n // The document is now a minimal version with externalized references to components and operations.\n // These references will be resolved asynchronously when needed through the workspace's get() method.\n workspace.documents[meta.name] = {\n ...documentMeta,\n ...documentV3,\n components,\n paths,\n [extensions.document.navigation]: entries,\n }\n },\n }\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,mBAAmB,eAAe;AAC3C,SAAS,gBAAgB,wBAAwB;AAEjD,OAAO,QAAQ;AACf,SAAS,WAAW;AACpB,SAAS,wBAAsD;AAC/D,SAAS,kBAAkB;AAC3B,SAAS,
|
|
4
|
+
"sourcesContent": ["import { escapeJsonPointer, upgrade } from '@scalar/openapi-parser'\nimport { getValueByPath, parseJsonPointer } from './helpers/json-path-utils'\nimport type { WorkspaceDocumentMeta, WorkspaceMeta } from './schemas/workspace'\nimport fs from 'node:fs/promises'\nimport { cwd } from 'node:process'\nimport { createNavigation, type createNavigationOptions } from '@/navigation'\nimport { extensions } from '@/schemas/extensions'\nimport { OpenAPIDocumentSchema, type OpenApiDocument } from '@/schemas/v3.1/strict/openapi-document'\nimport type { PathsObject } from '@/schemas/v3.1/strict/paths'\nimport { keyOf } from '@/helpers/general'\nimport type { OperationObject } from '@/schemas/v3.1/strict/path-operations'\nimport { fetchUrls, readFiles } from '@scalar/openapi-parser/plugins'\nimport { coerceValue } from '@/schemas/typebox-coerce'\nimport type { ComponentsObject } from '@/schemas/v3.1/strict/components'\nimport type { TraversedEntry } from '@/navigation/types'\n\nconst DEFAULT_ASSETS_FOLDER = 'assets'\nexport const WORKSPACE_FILE_NAME = 'scalar-workspace.json'\n\ntype WorkspaceDocumentMetaInput = {\n name: string\n meta?: WorkspaceDocumentMeta\n}\n\ntype UrlDoc = { url: string } & WorkspaceDocumentMetaInput\ntype FileDoc = { path: string } & WorkspaceDocumentMetaInput\ntype ObjectDoc = { document: Record<string, unknown> } & WorkspaceDocumentMetaInput\n\ntype WorkspaceDocumentInput = UrlDoc | ObjectDoc | FileDoc\n\ntype CreateServerWorkspaceStoreBase = {\n documents: WorkspaceDocumentInput[]\n meta?: WorkspaceMeta\n config?: createNavigationOptions\n}\ntype CreateServerWorkspaceStore =\n | ({\n directory?: string\n mode: 'static'\n } & CreateServerWorkspaceStoreBase)\n | ({\n baseUrl: string\n mode: 'ssr'\n } & CreateServerWorkspaceStoreBase)\n\nconst httpMethods = new Set(['get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace'])\n\n/**\n * Filters an OpenAPI PathsObject to only include standard HTTP methods.\n * Removes any vendor extensions or other non-HTTP properties.\n *\n * @param paths - The OpenAPI PathsObject to filter\n * @returns A new PathsObject containing only standard HTTP methods\n *\n * @example\n * Input: {\n * \"/users\": {\n * \"get\": {...},\n * \"x-custom\": {...},\n * \"post\": {...}\n * }\n * }\n * Output: {\n * \"/users\": {\n * \"get\": {...},\n * \"post\": {...}\n * }\n * }\n */\nexport function filterHttpMethodsOnly(paths: PathsObject) {\n const result: Record<string, Record<string, OperationObject>> = {}\n\n // Todo: skip extension properties\n for (const [path, methods] of Object.entries(paths)) {\n if (!methods) {\n continue\n }\n\n const filteredMethods: Record<string, any> = {}\n\n for (const [method, operation] of Object.entries(methods)) {\n if (httpMethods.has(method.toLowerCase())) {\n filteredMethods[method] = operation\n }\n }\n\n if (Object.keys(filteredMethods).length > 0) {\n result[path] = filteredMethods\n }\n }\n\n return result\n}\n\n/**\n * Escapes path keys in an OpenAPI PathsObject to be JSON Pointer compatible.\n * This is necessary because OpenAPI paths can contain characters that need to be escaped\n * when used as JSON Pointer references (like '/' and '~').\n *\n * @example\n * Input: { \"/users/{id}\": { ... } }\n * Output: { \"/users~1{id}\": { ... } }\n */\nexport function escapePaths(paths: Record<string, Record<string, OperationObject>>) {\n const result: Record<string, Record<string, OperationObject>> = {}\n Object.keys(paths).forEach((path) => {\n result[escapeJsonPointer(path)] = paths[path]\n })\n\n return result\n}\n\n/**\n * Externalizes components by turning them into refs.\n */\nexport function externalizeComponentReferences(\n document: OpenApiDocument,\n meta: { mode: 'ssr'; name: string; baseUrl: string } | { mode: 'static'; name: string; directory: string },\n) {\n const result: Record<string, any> = {}\n\n if (!document.components) {\n return result\n }\n\n Object.entries(document.components).forEach(([type, component]) => {\n if (!component || typeof component !== 'object') {\n return result\n }\n\n result[type] = {}\n Object.keys(component).forEach((name) => {\n const ref =\n meta.mode === 'ssr'\n ? `${meta.baseUrl}/${meta.name}/components/${type}/${name}#`\n : `./chunks/${meta.name}/components/${type}/${name}.json#`\n\n result[type][name] = { '$ref': ref, $global: true }\n })\n })\n\n return result\n}\n\n/**\n * Externalizes paths operations by turning them into refs.\n */\nexport function externalizePathReferences(\n document: OpenApiDocument,\n meta: { mode: 'ssr'; name: string; baseUrl: string } | { mode: 'static'; name: string; directory: string },\n) {\n const result: Record<string, any> = {}\n\n if (!document.paths) {\n return result\n }\n\n Object.entries(document.paths).forEach(([path, pathItem]) => {\n if (!pathItem || typeof pathItem !== 'object') {\n return result\n }\n\n const pathItemRecord = pathItem as Record<string, unknown>\n\n result[path] = {}\n\n const escapedPath = escapeJsonPointer(path)\n\n keyOf(pathItemRecord).forEach((type) => {\n if (httpMethods.has(type)) {\n const ref =\n meta.mode === 'ssr'\n ? `${meta.baseUrl}/${meta.name}/operations/${escapedPath}/${type}#`\n : `./chunks/${meta.name}/operations/${escapedPath}/${type}.json#`\n\n result[path][type] = { '$ref': ref, $global: true }\n } else {\n result[path][type] = pathItemRecord[type]\n }\n })\n })\n\n return result\n}\n\n/**\n * Resolves a workspace document from various input sources (URL, local file, or direct document object).\n *\n * @param workspaceDocument - The document input to resolve, which can be:\n * - A URL to fetch the document from\n * - A local file path to read the document from\n * - A direct document object\n * @returns A promise that resolves to an object containing:\n * - ok: boolean indicating if the resolution was successful\n * - data: The resolved document data\n *\n * @example\n * // Resolve from URL\n * const urlDoc = await loadDocument({ name: 'api', url: 'https://api.example.com/openapi.json' })\n *\n * // Resolve direct document\n * const directDoc = await loadDocument({\n * name: 'inline',\n * document: { openapi: '3.0.0', paths: {} }\n * })\n */\nasync function loadDocument(workspaceDocument: WorkspaceDocumentInput) {\n if ('url' in workspaceDocument) {\n return fetchUrls().exec(workspaceDocument.url)\n }\n\n if ('path' in workspaceDocument) {\n return readFiles().exec(workspaceDocument.path)\n }\n\n return {\n ok: true as const,\n data: workspaceDocument.document,\n }\n}\n\n/**\n * Create server state workspace store\n */\nexport async function createServerWorkspaceStore(workspaceProps: CreateServerWorkspaceStore) {\n /**\n * Base workspace document containing essential metadata and document references.\n *\n * This workspace document provides the minimal information needed for initial rendering.\n * All components and path operations are replaced with references to enable lazy loading.\n *\n * In SSR mode, references point to API endpoints.\n * In static mode, references point to filesystem chunks.\n */\n const workspace = {\n ...workspaceProps.meta,\n documents: {} as Record<string, OpenApiDocument & { [extensions.document.navigation]: TraversedEntry[] }>,\n }\n\n /**\n * A map of document chunks that can be loaded asynchronously by the client.\n * Each document is split into components and operations to enable lazy loading.\n * The keys are document names and values contain the components and operations\n * for that document.\n */\n const assets = {} as Record<\n string,\n { components?: ComponentsObject; operations?: Record<string, Record<string, OperationObject>> }\n >\n\n /**\n * Adds a new document to the workspace.\n *\n * This function processes an OpenAPI document by:\n * 1. Converting it to OpenAPI 3.1 format if needed\n * 2. Separating it into reusable components and path operations\n * 3. Externalizing references based on the workspace mode (SSR or static)\n * 4. Adding the processed document to the workspace with its metadata\n *\n * The resulting document contains minimal information with externalized references\n * that will be resolved on-demand through the workspace's get() method.\n *\n * @param document - The OpenAPI document to process and add\n * @param meta - Document metadata containing the required name and optional settings\n */\n const addDocumentSync = (document: Record<string, unknown>, meta: { name: string } & WorkspaceDocumentMeta) => {\n const { name, ...documentMeta } = meta\n\n const documentV3 = coerceValue(OpenAPIDocumentSchema, upgrade(document).specification)\n\n // add the assets\n assets[meta.name] = {\n components: documentV3.components,\n operations: documentV3.paths && escapePaths(filterHttpMethodsOnly(documentV3.paths)),\n }\n\n const options =\n workspaceProps.mode === 'ssr'\n ? { mode: workspaceProps.mode, name, baseUrl: workspaceProps.baseUrl }\n : { mode: workspaceProps.mode, name, directory: workspaceProps.directory ?? DEFAULT_ASSETS_FOLDER }\n\n const components = externalizeComponentReferences(documentV3, options)\n const paths = externalizePathReferences(documentV3, options)\n\n // Build the sidebar entries\n const { entries } = createNavigation(documentV3, workspaceProps.config ?? {})\n\n // The document is now a minimal version with externalized references to components and operations.\n // These references will be resolved asynchronously when needed through the workspace's get() method.\n workspace.documents[meta.name] = {\n ...documentMeta,\n ...documentV3,\n components,\n paths,\n [extensions.document.navigation]: entries,\n }\n }\n\n /**\n * Adds a new document to the workspace asynchronously.\n *\n * This function:\n * 1. Loads the document using the provided input\n * 2. Checks if the document loaded successfully\n * 3. If successful, adds the document to the workspace using addDocumentSync\n *\n * @param input - The document input containing the document source and metadata\n */\n const addDocument = async (input: WorkspaceDocumentInput) => {\n const document = await loadDocument(input)\n\n if (!document.ok) {\n console.warn(`Failed to load document \"${input.name}`)\n return\n }\n\n addDocumentSync(document.data as Record<string, unknown>, { name: input.name, ...input.meta })\n }\n\n // Load and process all initial documents in parallel\n await Promise.all(workspaceProps.documents.map(addDocument))\n\n return {\n /**\n * Generates workspace chunks by writing components and operations to the filesystem.\n *\n * This method is only available in static mode. It creates a directory structure containing:\n * - A workspace file with metadata and document references\n * - Component chunks split by type (schemas, parameters, etc)\n * - Operation chunks split by path and HTTP method\n *\n * The generated workspace references will be relative file paths pointing to these chunks.\n *\n * @throws {Error} If called when mode is not 'static'\n */\n generateWorkspaceChunks: async () => {\n if (workspaceProps.mode !== 'static') {\n throw 'Mode has to be set to `static` to generate filesystem workspace chunks'\n }\n\n // Write the workspace document\n const basePath = `${cwd()}/${workspaceProps.directory ?? DEFAULT_ASSETS_FOLDER}`\n await fs.mkdir(basePath, { recursive: true })\n\n // Write the workspace contents on the file system\n await fs.writeFile(`${basePath}/${WORKSPACE_FILE_NAME}`, JSON.stringify(workspace))\n\n // Write the chunks\n for (const [name, { components, operations }] of Object.entries(assets)) {\n // Write the components chunks\n if (components) {\n for (const [type, component] of Object.entries(components as Record<string, Record<string, unknown>>)) {\n const componentPath = `${basePath}/chunks/${name}/components/${type}`\n await fs.mkdir(componentPath, { recursive: true })\n\n for (const [key, value] of Object.entries(component)) {\n await fs.writeFile(`${componentPath}/${key}.json`, JSON.stringify(value))\n }\n }\n }\n\n // Write the operations chunks\n if (operations) {\n for (const [path, methods] of Object.entries(operations)) {\n const operationPath = `${basePath}/chunks/${name}/operations/${path}`\n await fs.mkdir(operationPath, { recursive: true })\n\n for (const [method, operation] of Object.entries(methods)) {\n await fs.writeFile(`${operationPath}/${method}.json`, JSON.stringify(operation))\n }\n }\n }\n }\n },\n /**\n * Returns the workspace document containing metadata and all sparse documents.\n *\n * The workspace document includes:\n * - Global workspace metadata (theme, active document, etc)\n * - Document metadata and sparse document\n * - In SSR mode: References point to in-memory chunks\n * - In static mode: References point to filesystem chunks\n *\n * @returns The complete workspace document\n */\n getWorkspace: () => {\n return workspace\n },\n /**\n * Retrieves a chunk of data from the workspace using a JSON Pointer\n *\n * A JSON Pointer is a string that references a specific location in a JSON document.\n * Only components and operations chunks can be retrieved.\n *\n * @example\n * ```ts\n * // Get a component\n * get('#/document-name/components/schemas/User')\n *\n * // Get an operation\n * get('#/document-name/operations/pets/get')\n * ```\n *\n * @param pointer - The JSON Pointer string to locate the chunk\n * @returns The chunk data if found, undefined otherwise\n */\n get: (pointer: string) => {\n return getValueByPath(assets, parseJsonPointer(pointer))\n },\n /**\n * Adds a new document to the workspace asynchronously.\n *\n * This function:\n * 1. Loads the document using the provided input\n * 2. Checks if the document loaded successfully\n * 3. If successful, adds the document to the workspace using addDocumentSync\n *\n * @param input - The document input containing the document source and metadata\n */\n addDocument,\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"openapi",
|
|
17
17
|
"scalar"
|
|
18
18
|
],
|
|
19
|
-
"version": "0.
|
|
19
|
+
"version": "0.6.0",
|
|
20
20
|
"engines": {
|
|
21
21
|
"node": ">=18"
|
|
22
22
|
},
|
|
@@ -46,9 +46,9 @@
|
|
|
46
46
|
"@sinclair/typebox": "0.34.33",
|
|
47
47
|
"github-slugger": "^2.0.0",
|
|
48
48
|
"vue": "^3.5.12",
|
|
49
|
+
"@scalar/code-highlight": "0.1.4",
|
|
49
50
|
"@scalar/helpers": "0.0.4",
|
|
50
51
|
"@scalar/openapi-parser": "0.18.0",
|
|
51
|
-
"@scalar/code-highlight": "0.1.4",
|
|
52
52
|
"@scalar/openapi-types": "0.3.3"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|