@scalar/api-client-react 2.0.1 → 2.0.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 CHANGED
@@ -1,5 +1,12 @@
1
1
  # @scalar/api-client-react
2
2
 
3
+ ## 2.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#8840](https://github.com/scalar/scalar/pull/8840): feat: allow updating the proxyUrl and make options reactive in api-client
8
+ - [#8863](https://github.com/scalar/scalar/pull/8863): chore: updated imports to new api client version
9
+
3
10
  ## 2.0.1
4
11
 
5
12
  ## 2.0.0
package/README.md CHANGED
@@ -46,10 +46,20 @@ export const OpenButton = () => {
46
46
 
47
47
  ### Options
48
48
 
49
- | Option | Type | Description |
50
- |---|---|---|
51
- | `configuration.url` | `string` | URL of an OpenAPI document to load |
52
- | `configuration.content` | `Record<string, unknown>` | Inline OpenAPI document object |
49
+ <!-- For the complete list of configuration options, see the [Scalar configuration docs](https://scalar.com/products/api-references/configuration). -->
50
+
51
+ | Option | Description |
52
+ |---|---|
53
+ | `configuration.url` | [Required] Pass the URL of an OpenAPI document (JSON or YAML). |
54
+ | `configuration.proxyUrl` | Use a proxy URL to send requests to other origins when CORS blocks direct browser requests. |
55
+ | `configuration.authentication` | Prefill authentication credentials and default security scheme behavior for users. |
56
+ | `configuration.baseServerURL` | Prefix all relative servers with a base URL. |
57
+ | `configuration.hideClientButton` | Whether to hide the client button from the reference sidebar and modal. |
58
+ | `configuration.hiddenClients` | Control which HTTP code-example clients are shown; pass `[]` to show all clients. |
59
+ | `configuration.oauth2RedirectUri` | Set the default OAuth 2.0 redirect URI for authorization code and implicit flows. |
60
+ | `configuration.servers` | Pass a list of servers to override the servers in your OpenAPI document. |
61
+
62
+ <!-- | `configuration.content` | `Record<string, unknown>` | Inline OpenAPI document object | -->
53
63
 
54
64
  ### Routing to a specific request
55
65
 
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type { RoutePayload } from '@scalar/api-client/v2/features/modal';
1
+ export type { RoutePayload } from '@scalar/api-client/modal';
2
2
  export type { ApiClientConfigurationReact, UseApiClientModalProps } from './use-api-client';
3
3
  export { useApiClient } from './use-api-client';
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAA;AAExE,YAAY,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AAC3F,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAE5D,YAAY,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AAC3F,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA"}
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  "use client";
2
- import { useEffect, useState } from "react";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { isObjectEqual } from "@scalar/helpers/object/is-object-equal";
3
4
  //#region src/lazy-load.ts
4
5
  /**
5
6
  * Creates a lazy singleton getter: the factory runs at most once, caches the resulting promise,
@@ -19,7 +20,7 @@ var makeLazySingleton = (factory) => {
19
20
  };
20
21
  };
21
22
  /** Lazy load the client modal creator */
22
- var getClientModalCreator = makeLazySingleton(() => import("@scalar/api-client/v2/features/modal").then(({ createApiClientModal }) => createApiClientModal));
23
+ var getClientModalCreator = makeLazySingleton(() => import("@scalar/api-client/modal").then(({ createApiClientModal }) => createApiClientModal));
23
24
  /** Module-scoped singleton workspace store (lazy-loaded on first use). */
24
25
  var getWorkspaceStoreSingleton = makeLazySingleton(() => import("@scalar/workspace-store/client").then(({ createWorkspaceStore }) => createWorkspaceStore()));
25
26
  /** Module-scoped singleton workspace event bus (lazy-loaded on first use). */
@@ -28,7 +29,7 @@ var getWorkspaceEventBusSingleton = makeLazySingleton(() => import("@scalar/work
28
29
  * Lazily creates the singleton Vue app, mounts it as the last child of document.body,
29
30
  * and returns the controller. Subsequent calls return the same promise.
30
31
  *
31
- * Only modal-level options (e.g. `proxyUrl`) are accepted here. Document-specific fields
32
+ * Only modal-supported options are accepted here. Document-specific fields
32
33
  * (`url`, `content`) must be registered via `workspaceStore.addDocument` after the client
33
34
  * is ready — they are not part of the modal constructor.
34
35
  */
@@ -62,7 +63,7 @@ globalThis.__VUE_OPTIONS_API__ = true;
62
63
  globalThis.__VUE_PROD_HYDRATION_MISMATCH_DETAILS__ = true;
63
64
  globalThis.__VUE_PROD_DEVTOOLS__ = false;
64
65
  /** Tracks which documents are/have been loaded so we dont duplicate */
65
- var documentDict = {};
66
+ var documentSet = /* @__PURE__ */ new Set();
66
67
  /**
67
68
  * Returns the singleton Api Client
68
69
  *
@@ -73,32 +74,32 @@ var documentDict = {};
73
74
  * Subsequent calls from any component share the same instance of the client but can use the same
74
75
  * or different documents
75
76
  */
76
- var useApiClient = ({ configuration } = {}) => {
77
+ var useApiClient = ({ configuration }) => {
77
78
  const [client, setClient] = useState(void 0);
78
79
  const [workspaceStore, setWorkspaceStore] = useState(void 0);
79
- const [documentSlug, setDocumentSlug] = useState("");
80
+ const documentSlugRef = useRef("");
81
+ const previousModalOptionsRef = useRef(void 0);
80
82
  /** Small wrapper to set the documentSlug */
81
83
  const open = (payload) => client?.open({
82
- documentSlug,
84
+ documentSlug: documentSlugRef.current,
83
85
  ...payload
84
86
  });
85
87
  useEffect(() => {
86
88
  let cancelled = false;
87
- const { url, content, ...modalOptions } = configuration ?? {};
89
+ const { url, ...modalOptions } = configuration;
88
90
  getOrCreateApiClient(modalOptions)?.then((_client) => {
89
91
  if (cancelled || !_client) return;
90
- const slug = url || content?.info?.title || "";
92
+ const slug = url || "";
93
+ _client.apiClient.updateOptions(modalOptions, true);
94
+ previousModalOptionsRef.current = modalOptions;
91
95
  setClient(_client.apiClient);
92
96
  setWorkspaceStore(_client.workspaceStore);
93
- setDocumentSlug(slug);
94
- if (slug && !documentDict[slug]) {
95
- documentDict[slug] = true;
96
- _client.workspaceStore.addDocument(content ? {
97
+ documentSlugRef.current = slug;
98
+ if (slug && !documentSet.has(slug)) {
99
+ documentSet.add(slug);
100
+ _client.workspaceStore.addDocument({
97
101
  name: slug,
98
- document: content
99
- } : {
100
- name: slug,
101
- url: url ?? ""
102
+ url
102
103
  });
103
104
  }
104
105
  });
@@ -107,24 +108,27 @@ var useApiClient = ({ configuration } = {}) => {
107
108
  };
108
109
  }, []);
109
110
  useEffect(() => {
110
- if (!client || !configuration || !workspaceStore) return;
111
- const slug = configuration.url || configuration.content?.info?.title || "default";
112
- setDocumentSlug(slug);
113
- if (documentDict[slug]) return;
114
- documentDict[slug] = true;
115
- workspaceStore.addDocument(configuration.content ? {
116
- name: slug,
117
- document: configuration.content
118
- } : {
111
+ if (!client || !workspaceStore) return;
112
+ const slug = configuration.url || "default";
113
+ documentSlugRef.current = slug;
114
+ if (documentSet.has(slug)) return;
115
+ documentSet.add(slug);
116
+ workspaceStore.addDocument({
119
117
  name: slug,
120
- url: configuration.url ?? ""
118
+ url: configuration.url
121
119
  });
122
120
  }, [
123
121
  client,
124
- configuration?.url,
125
- configuration?.content,
122
+ configuration.url,
126
123
  workspaceStore
127
124
  ]);
125
+ useEffect(() => {
126
+ if (!client || !configuration) return;
127
+ const { url: _, ...modalOptions } = configuration;
128
+ if (isObjectEqual(previousModalOptionsRef.current, modalOptions)) return;
129
+ client.updateOptions(modalOptions, true);
130
+ previousModalOptionsRef.current = modalOptions;
131
+ }, [client, configuration]);
128
132
  return client ? {
129
133
  ...client,
130
134
  open
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/lazy-load.ts","../src/use-api-client.ts"],"sourcesContent":["import type { ApiClientConfiguration } from '@scalar/types/api-reference'\n\n/**\n * Creates a lazy singleton getter: the factory runs at most once, caches the resulting promise,\n * and clears the cache on failure so the next call can retry.\n *\n * Optional args are forwarded to the factory on the first (cache-miss) call only.\n * Subsequent calls return the cached promise regardless of the args passed.\n */\nconst makeLazySingleton = <T, Args extends unknown[] = []>(\n factory: (...args: Args) => Promise<T>,\n): ((...args: Args) => Promise<T>) => {\n let cached: Promise<T> | undefined\n return (...args: Args) => {\n cached ??= factory(...args).catch((error) => {\n cached = undefined\n throw error\n })\n return cached\n }\n}\n\n/** Lazy load the client modal creator */\nexport const getClientModalCreator = makeLazySingleton(() =>\n import('@scalar/api-client/v2/features/modal').then(({ createApiClientModal }) => createApiClientModal),\n)\n\n/** Module-scoped singleton workspace store (lazy-loaded on first use). */\nexport const getWorkspaceStoreSingleton = makeLazySingleton(() =>\n import('@scalar/workspace-store/client').then(({ createWorkspaceStore }) => createWorkspaceStore()),\n)\n\n/** Module-scoped singleton workspace event bus (lazy-loaded on first use). */\nexport const getWorkspaceEventBusSingleton = makeLazySingleton(() =>\n import('@scalar/workspace-store/events').then(({ createWorkspaceEventBus }) => createWorkspaceEventBus()),\n)\n\n/**\n * Lazily creates the singleton Vue app, mounts it as the last child of document.body,\n * and returns the controller. Subsequent calls return the same promise.\n *\n * Only modal-level options (e.g. `proxyUrl`) are accepted here. Document-specific fields\n * (`url`, `content`) must be registered via `workspaceStore.addDocument` after the client\n * is ready — they are not part of the modal constructor.\n */\nexport const getOrCreateApiClient = makeLazySingleton(async (options: Partial<ApiClientConfiguration> = {}) => {\n const el = document.createElement('div')\n el.className = 'scalar-app'\n document.body.appendChild(el)\n\n try {\n const [createModal, workspaceStore, eventBus] = await Promise.all([\n getClientModalCreator(),\n getWorkspaceStoreSingleton(),\n getWorkspaceEventBusSingleton(),\n ])\n\n const apiClient = createModal({\n el,\n eventBus,\n workspaceStore,\n options,\n // TODO: map plugins from configuration when available\n // plugins: mapConfigPlugins(options),\n })\n\n return { apiClient, workspaceStore }\n } catch (error) {\n el.remove()\n throw error\n }\n})\n","'use client'\n\nimport type { ApiClientModal, RoutePayload } from '@scalar/api-client/v2/features/modal'\nimport type { ApiClientConfiguration } from '@scalar/types/api-reference'\nimport { useEffect, useState } from 'react'\n\nimport './style.css'\n\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\n\nimport { getOrCreateApiClient } from './lazy-load'\n\nglobalThis.__VUE_OPTIONS_API__ = true\nglobalThis.__VUE_PROD_HYDRATION_MISMATCH_DETAILS__ = true\nglobalThis.__VUE_PROD_DEVTOOLS__ = false\n\n/** We don't really need all of the content types so we just accept an object instead */\nexport type ApiClientConfigurationReact = Partial<\n Omit<ApiClientConfiguration, 'content' | 'url'> & { content?: Record<string, unknown>; url?: string }\n>\n\nexport type UseApiClientModalProps = {\n /** Configuration for the Api Client (url or inline content) */\n configuration?: ApiClientConfigurationReact\n}\n\n/** Tracks which documents are/have been loaded so we dont duplicate */\nconst documentDict: Record<string, true> = {}\n\n/**\n * Returns the singleton Api Client\n *\n * On first call the Vue app is lazily created and appended to document.body where it\n * lives for the lifetime of the page — it is never unmounted, so it survives client-side\n * navigation without losing state.\n *\n * Subsequent calls from any component share the same instance of the client but can use the same\n * or different documents\n */\nexport const useApiClient = ({\n configuration,\n}: UseApiClientModalProps = {}):\n | (Omit<ApiClientModal, 'open'> & { open: (payload: RoutePayload) => void })\n | undefined => {\n const [client, setClient] = useState<ApiClientModal | undefined>(undefined)\n const [workspaceStore, setWorkspaceStore] = useState<WorkspaceStore | undefined>(undefined)\n const [documentSlug, setDocumentSlug] = useState('')\n\n /** Small wrapper to set the documentSlug */\n const open = (payload: RoutePayload) => client?.open({ documentSlug, ...payload })\n\n useEffect(() => {\n let cancelled = false\n\n // Strip document-specific fields before passing to the modal constructor.\n // `url` and `content` are registered separately via workspaceStore.addDocument.\n const { url, content, ...modalOptions } = configuration ?? {}\n\n void getOrCreateApiClient(modalOptions)?.then((_client) => {\n if (cancelled || !_client) {\n return\n }\n\n // Compute the slug here so we can batch all three state updates into one render,\n // preventing a render where `client` is set but `documentSlug` is still ''.\n const slug = url || (content as { info?: { title?: string } })?.info?.title || ''\n\n setClient(_client.apiClient)\n setWorkspaceStore(_client.workspaceStore)\n setDocumentSlug(slug)\n\n if (slug && !documentDict[slug]) {\n documentDict[slug] = true\n void _client.workspaceStore.addDocument(\n content ? { name: slug, document: content } : { name: slug, url: url ?? '' },\n )\n }\n })\n\n return () => {\n cancelled = true\n }\n\n // Only run once per mount\n }, [])\n\n // When url or content changes after the client is already mounted, register the new document\n useEffect(() => {\n if (!client || !configuration || !workspaceStore) {\n return\n }\n\n const slug = configuration.url || (configuration.content as { info?: { title?: string } })?.info?.title || 'default'\n setDocumentSlug(slug)\n\n if (documentDict[slug]) {\n return\n }\n documentDict[slug] = true\n\n void workspaceStore.addDocument(\n configuration.content\n ? { name: slug, document: configuration.content }\n : { name: slug, url: configuration.url ?? '' },\n )\n }, [client, configuration?.url, configuration?.content, workspaceStore])\n\n return client\n ? {\n ...client,\n open,\n }\n : undefined\n}\n"],"mappings":";;;;;;;;;;AASA,IAAM,qBACJ,YACoC;CACpC,IAAI;AACJ,SAAQ,GAAG,SAAe;AACxB,aAAW,QAAQ,GAAG,KAAK,CAAC,OAAO,UAAU;AAC3C,YAAS,KAAA;AACT,SAAM;IACN;AACF,SAAO;;;;AAKX,IAAa,wBAAwB,wBACnC,OAAO,wCAAwC,MAAM,EAAE,2BAA2B,qBAAqB,CACxG;;AAGD,IAAa,6BAA6B,wBACxC,OAAO,kCAAkC,MAAM,EAAE,2BAA2B,sBAAsB,CAAC,CACpG;;AAGD,IAAa,gCAAgC,wBAC3C,OAAO,kCAAkC,MAAM,EAAE,8BAA8B,yBAAyB,CAAC,CAC1G;;;;;;;;;AAUD,IAAa,uBAAuB,kBAAkB,OAAO,UAA2C,EAAE,KAAK;CAC7G,MAAM,KAAK,SAAS,cAAc,MAAM;AACxC,IAAG,YAAY;AACf,UAAS,KAAK,YAAY,GAAG;AAE7B,KAAI;EACF,MAAM,CAAC,aAAa,gBAAgB,YAAY,MAAM,QAAQ,IAAI;GAChE,uBAAuB;GACvB,4BAA4B;GAC5B,+BAAA;GACD,CAAC;AAWF,SAAO;GAAE,WATS,YAAY;IAC5B;IACA;IACA;IACA;IAGD,CAAC;GAEkB;GAAgB;UAC7B,OAAO;AACd,KAAG,QAAQ;AACX,QAAM;;EAER;;;AC3DF,WAAW,sBAAsB;AACjC,WAAW,0CAA0C;AACrD,WAAW,wBAAwB;;AAanC,IAAM,eAAqC,EAAE;;;;;;;;;;;AAY7C,IAAa,gBAAgB,EAC3B,kBAC0B,EAAE,KAEb;CACf,MAAM,CAAC,QAAQ,aAAa,SAAqC,KAAA,EAAU;CAC3E,MAAM,CAAC,gBAAgB,qBAAqB,SAAqC,KAAA,EAAU;CAC3F,MAAM,CAAC,cAAc,mBAAmB,SAAS,GAAG;;CAGpD,MAAM,QAAQ,YAA0B,QAAQ,KAAK;EAAE;EAAc,GAAG;EAAS,CAAC;AAElF,iBAAgB;EACd,IAAI,YAAY;EAIhB,MAAM,EAAE,KAAK,SAAS,GAAG,iBAAiB,iBAAiB,EAAE;AAExD,uBAAqB,aAAa,EAAE,MAAM,YAAY;AACzD,OAAI,aAAa,CAAC,QAChB;GAKF,MAAM,OAAO,OAAQ,SAA2C,MAAM,SAAS;AAE/E,aAAU,QAAQ,UAAU;AAC5B,qBAAkB,QAAQ,eAAe;AACzC,mBAAgB,KAAK;AAErB,OAAI,QAAQ,CAAC,aAAa,OAAO;AAC/B,iBAAa,QAAQ;AAChB,YAAQ,eAAe,YAC1B,UAAU;KAAE,MAAM;KAAM,UAAU;KAAS,GAAG;KAAE,MAAM;KAAM,KAAK,OAAO;KAAI,CAC7E;;IAEH;AAEF,eAAa;AACX,eAAY;;IAIb,EAAE,CAAC;AAGN,iBAAgB;AACd,MAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,eAChC;EAGF,MAAM,OAAO,cAAc,OAAQ,cAAc,SAA2C,MAAM,SAAS;AAC3G,kBAAgB,KAAK;AAErB,MAAI,aAAa,MACf;AAEF,eAAa,QAAQ;AAEhB,iBAAe,YAClB,cAAc,UACV;GAAE,MAAM;GAAM,UAAU,cAAc;GAAS,GAC/C;GAAE,MAAM;GAAM,KAAK,cAAc,OAAO;GAAI,CACjD;IACA;EAAC;EAAQ,eAAe;EAAK,eAAe;EAAS;EAAe,CAAC;AAExE,QAAO,SACH;EACE,GAAG;EACH;EACD,GACD,KAAA"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/lazy-load.ts","../src/use-api-client.ts"],"sourcesContent":["import type { ApiClientModalOptions } from '@scalar/api-client/modal'\n\n/**\n * Creates a lazy singleton getter: the factory runs at most once, caches the resulting promise,\n * and clears the cache on failure so the next call can retry.\n *\n * Optional args are forwarded to the factory on the first (cache-miss) call only.\n * Subsequent calls return the cached promise regardless of the args passed.\n */\nconst makeLazySingleton = <T, Args extends unknown[] = []>(\n factory: (...args: Args) => Promise<T>,\n): ((...args: Args) => Promise<T>) => {\n let cached: Promise<T> | undefined\n return (...args: Args) => {\n cached ??= factory(...args).catch((error) => {\n cached = undefined\n throw error\n })\n return cached\n }\n}\n\n/** Lazy load the client modal creator */\nexport const getClientModalCreator = makeLazySingleton(() =>\n import('@scalar/api-client/modal').then(({ createApiClientModal }) => createApiClientModal),\n)\n\n/** Module-scoped singleton workspace store (lazy-loaded on first use). */\nexport const getWorkspaceStoreSingleton = makeLazySingleton(() =>\n import('@scalar/workspace-store/client').then(({ createWorkspaceStore }) => createWorkspaceStore()),\n)\n\n/** Module-scoped singleton workspace event bus (lazy-loaded on first use). */\nexport const getWorkspaceEventBusSingleton = makeLazySingleton(() =>\n import('@scalar/workspace-store/events').then(({ createWorkspaceEventBus }) => createWorkspaceEventBus()),\n)\n\n/**\n * Lazily creates the singleton Vue app, mounts it as the last child of document.body,\n * and returns the controller. Subsequent calls return the same promise.\n *\n * Only modal-supported options are accepted here. Document-specific fields\n * (`url`, `content`) must be registered via `workspaceStore.addDocument` after the client\n * is ready — they are not part of the modal constructor.\n */\nexport const getOrCreateApiClient = makeLazySingleton(async (options: ApiClientModalOptions = {}) => {\n const el = document.createElement('div')\n el.className = 'scalar-app'\n document.body.appendChild(el)\n\n try {\n const [createModal, workspaceStore, eventBus] = await Promise.all([\n getClientModalCreator(),\n getWorkspaceStoreSingleton(),\n getWorkspaceEventBusSingleton(),\n ])\n\n const apiClient = createModal({\n el,\n eventBus,\n workspaceStore,\n options,\n // TODO: map plugins from configuration when available\n // plugins: mapConfigPlugins(options),\n })\n\n return { apiClient, workspaceStore }\n } catch (error) {\n el.remove()\n throw error\n }\n})\n","'use client'\n\nimport type { ApiClientModal, ApiClientModalOptions, RoutePayload } from '@scalar/api-client/modal'\nimport { useEffect, useRef, useState } from 'react'\n\nimport './style.css'\n\nimport { isObjectEqual } from '@scalar/helpers/object/is-object-equal'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\n\nimport { getOrCreateApiClient } from './lazy-load'\n\nglobalThis.__VUE_OPTIONS_API__ = true\nglobalThis.__VUE_PROD_HYDRATION_MISMATCH_DETAILS__ = true\nglobalThis.__VUE_PROD_DEVTOOLS__ = false\n\nexport type ApiClientConfigurationReact = ApiClientModalOptions & {\n // content?: Record<string, unknown>\n url: string\n}\n\nexport type UseApiClientModalProps = {\n /** Configuration for the Api Client (url or inline content) */\n configuration: ApiClientConfigurationReact\n}\n\n/** Tracks which documents are/have been loaded so we dont duplicate */\nconst documentSet = new Set<string>()\n\n/**\n * Returns the singleton Api Client\n *\n * On first call the Vue app is lazily created and appended to document.body where it\n * lives for the lifetime of the page — it is never unmounted, so it survives client-side\n * navigation without losing state.\n *\n * Subsequent calls from any component share the same instance of the client but can use the same\n * or different documents\n */\nexport const useApiClient = ({\n configuration,\n}: UseApiClientModalProps): (Omit<ApiClientModal, 'open'> & { open: (payload: RoutePayload) => void }) | undefined => {\n const [client, setClient] = useState<ApiClientModal | undefined>(undefined)\n const [workspaceStore, setWorkspaceStore] = useState<WorkspaceStore | undefined>(undefined)\n const documentSlugRef = useRef('')\n const previousModalOptionsRef = useRef<ApiClientModalOptions | undefined>(undefined)\n\n /** Small wrapper to set the documentSlug */\n const open = (payload: RoutePayload) => client?.open({ documentSlug: documentSlugRef.current, ...payload })\n\n useEffect(() => {\n let cancelled = false\n\n // Strip document-specific fields before passing to the modal constructor.\n const { url, ...modalOptions } = configuration\n\n void getOrCreateApiClient(modalOptions)?.then((_client) => {\n if (cancelled || !_client) {\n return\n }\n\n // Compute the slug here so we can batch all three state updates into one render,\n // preventing a render where `client` is set but `documentSlug` is still ''.\n const slug = url || ''\n\n // React always provides the complete modal option set for this hook instance,\n // so we overwrite to clear options removed by consumers.\n _client.apiClient.updateOptions(modalOptions, true)\n previousModalOptionsRef.current = modalOptions\n\n setClient(_client.apiClient)\n setWorkspaceStore(_client.workspaceStore)\n documentSlugRef.current = slug\n\n if (slug && !documentSet.has(slug)) {\n documentSet.add(slug)\n void _client.workspaceStore.addDocument({ name: slug, url })\n }\n })\n\n return () => {\n cancelled = true\n }\n\n // Only run once per mount\n }, [])\n\n // Register new document when we detect the url has changed\n useEffect(() => {\n if (!client || !workspaceStore) {\n return\n }\n\n const slug = configuration.url || 'default'\n documentSlugRef.current = slug\n\n if (documentSet.has(slug)) {\n return\n }\n documentSet.add(slug)\n\n void workspaceStore.addDocument({ name: slug, url: configuration.url })\n }, [client, configuration.url, workspaceStore])\n\n // Update the modal options when the configuration changes\n useEffect(() => {\n if (!client || !configuration) {\n return\n }\n\n const { url: _, ...modalOptions } = configuration\n if (isObjectEqual(previousModalOptionsRef.current, modalOptions)) {\n return\n }\n\n client.updateOptions(modalOptions, true)\n previousModalOptionsRef.current = modalOptions\n }, [client, configuration])\n\n return client\n ? {\n ...client,\n open,\n }\n : undefined\n}\n"],"mappings":";;;;;;;;;;;AASA,IAAM,qBACJ,YACoC;CACpC,IAAI;AACJ,SAAQ,GAAG,SAAe;AACxB,aAAW,QAAQ,GAAG,KAAK,CAAC,OAAO,UAAU;AAC3C,YAAS,KAAA;AACT,SAAM;IACN;AACF,SAAO;;;;AAKX,IAAa,wBAAwB,wBACnC,OAAO,4BAA4B,MAAM,EAAE,2BAA2B,qBAAqB,CAC5F;;AAGD,IAAa,6BAA6B,wBACxC,OAAO,kCAAkC,MAAM,EAAE,2BAA2B,sBAAsB,CAAC,CACpG;;AAGD,IAAa,gCAAgC,wBAC3C,OAAO,kCAAkC,MAAM,EAAE,8BAA8B,yBAAyB,CAAC,CAC1G;;;;;;;;;AAUD,IAAa,uBAAuB,kBAAkB,OAAO,UAAiC,EAAE,KAAK;CACnG,MAAM,KAAK,SAAS,cAAc,MAAM;AACxC,IAAG,YAAY;AACf,UAAS,KAAK,YAAY,GAAG;AAE7B,KAAI;EACF,MAAM,CAAC,aAAa,gBAAgB,YAAY,MAAM,QAAQ,IAAI;GAChE,uBAAuB;GACvB,4BAA4B;GAC5B,+BAAA;GACD,CAAC;AAWF,SAAO;GAAE,WATS,YAAY;IAC5B;IACA;IACA;IACA;IAGD,CAAC;GAEkB;GAAgB;UAC7B,OAAO;AACd,KAAG,QAAQ;AACX,QAAM;;EAER;;;AC3DF,WAAW,sBAAsB;AACjC,WAAW,0CAA0C;AACrD,WAAW,wBAAwB;;AAanC,IAAM,8BAAc,IAAI,KAAa;;;;;;;;;;;AAYrC,IAAa,gBAAgB,EAC3B,oBACoH;CACpH,MAAM,CAAC,QAAQ,aAAa,SAAqC,KAAA,EAAU;CAC3E,MAAM,CAAC,gBAAgB,qBAAqB,SAAqC,KAAA,EAAU;CAC3F,MAAM,kBAAkB,OAAO,GAAG;CAClC,MAAM,0BAA0B,OAA0C,KAAA,EAAU;;CAGpF,MAAM,QAAQ,YAA0B,QAAQ,KAAK;EAAE,cAAc,gBAAgB;EAAS,GAAG;EAAS,CAAC;AAE3G,iBAAgB;EACd,IAAI,YAAY;EAGhB,MAAM,EAAE,KAAK,GAAG,iBAAiB;AAE5B,uBAAqB,aAAa,EAAE,MAAM,YAAY;AACzD,OAAI,aAAa,CAAC,QAChB;GAKF,MAAM,OAAO,OAAO;AAIpB,WAAQ,UAAU,cAAc,cAAc,KAAK;AACnD,2BAAwB,UAAU;AAElC,aAAU,QAAQ,UAAU;AAC5B,qBAAkB,QAAQ,eAAe;AACzC,mBAAgB,UAAU;AAE1B,OAAI,QAAQ,CAAC,YAAY,IAAI,KAAK,EAAE;AAClC,gBAAY,IAAI,KAAK;AAChB,YAAQ,eAAe,YAAY;KAAE,MAAM;KAAM;KAAK,CAAC;;IAE9D;AAEF,eAAa;AACX,eAAY;;IAIb,EAAE,CAAC;AAGN,iBAAgB;AACd,MAAI,CAAC,UAAU,CAAC,eACd;EAGF,MAAM,OAAO,cAAc,OAAO;AAClC,kBAAgB,UAAU;AAE1B,MAAI,YAAY,IAAI,KAAK,CACvB;AAEF,cAAY,IAAI,KAAK;AAEhB,iBAAe,YAAY;GAAE,MAAM;GAAM,KAAK,cAAc;GAAK,CAAC;IACtE;EAAC;EAAQ,cAAc;EAAK;EAAe,CAAC;AAG/C,iBAAgB;AACd,MAAI,CAAC,UAAU,CAAC,cACd;EAGF,MAAM,EAAE,KAAK,GAAG,GAAG,iBAAiB;AACpC,MAAI,cAAc,wBAAwB,SAAS,aAAa,CAC9D;AAGF,SAAO,cAAc,cAAc,KAAK;AACxC,0BAAwB,UAAU;IACjC,CAAC,QAAQ,cAAc,CAAC;AAE3B,QAAO,SACH;EACE,GAAG;EACH;EACD,GACD,KAAA"}
@@ -1,3 +1,4 @@
1
+ import type { ApiClientModalOptions } from '@scalar/api-client/modal';
1
2
  /** Lazy load the client modal creator */
2
3
  export declare const getClientModalCreator: () => Promise<({ el, eventBus, mountOnInitialize, plugins, workspaceStore, options, }: {
3
4
  el: HTMLElement | null;
@@ -5,8 +6,8 @@ export declare const getClientModalCreator: () => Promise<({ el, eventBus, mount
5
6
  eventBus?: import("@scalar/workspace-store/events").WorkspaceEventBus;
6
7
  workspaceStore: import("@scalar/workspace-store/client").WorkspaceStore;
7
8
  plugins?: import("@scalar/oas-utils/helpers").ClientPlugin[];
8
- options?: import("vue").MaybeRefOrGetter<Partial<Pick<import("@scalar/types/api-reference").ApiReferenceConfigurationRaw, "authentication" | "baseServerURL" | "hideClientButton" | "servers" | "hiddenClients">>>;
9
- }) => import("@scalar/api-client/v2/features/modal").ApiClientModal>;
9
+ options?: import("vue").MaybeRefOrGetter<ApiClientModalOptions>;
10
+ }) => import("@scalar/api-client/modal").ApiClientModal>;
10
11
  /** Module-scoped singleton workspace store (lazy-loaded on first use). */
11
12
  export declare const getWorkspaceStoreSingleton: () => Promise<import("@scalar/workspace-store/client").WorkspaceStore>;
12
13
  /** Module-scoped singleton workspace event bus (lazy-loaded on first use). */
@@ -15,73 +16,12 @@ export declare const getWorkspaceEventBusSingleton: () => Promise<import("@scala
15
16
  * Lazily creates the singleton Vue app, mounts it as the last child of document.body,
16
17
  * and returns the controller. Subsequent calls return the same promise.
17
18
  *
18
- * Only modal-level options (e.g. `proxyUrl`) are accepted here. Document-specific fields
19
+ * Only modal-supported options are accepted here. Document-specific fields
19
20
  * (`url`, `content`) must be registered via `workspaceStore.addDocument` after the client
20
21
  * is ready — they are not part of the modal constructor.
21
22
  */
22
- export declare const getOrCreateApiClient: (options?: Partial<{
23
- hideClientButton: boolean;
24
- showSidebar: boolean;
25
- showDeveloperTools: "never" | "always" | "localhost";
26
- showToolbar: "never" | "always" | "localhost";
27
- operationTitleSource: "summary" | "path";
28
- theme: "default" | "alternate" | "moon" | "purple" | "solarized" | "bluePlanet" | "deepSpace" | "saturn" | "kepler" | "elysiajs" | "fastify" | "mars" | "laserwave" | "none";
29
- persistAuth: boolean;
30
- telemetry: boolean;
31
- externalUrls: {
32
- dashboardUrl: string;
33
- registryUrl: string;
34
- proxyUrl: string;
35
- apiBaseUrl: string;
36
- };
37
- authentication?: any;
38
- baseServerURL?: string | undefined;
39
- proxyUrl?: string | undefined;
40
- oauth2RedirectUri?: string | undefined;
41
- searchHotKey?: "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" | undefined;
42
- servers?: any[] | undefined;
43
- _integration?: "elysiajs" | "fastify" | "adonisjs" | "astro" | "docusaurus" | "dotnet" | "express" | "fastapi" | "go" | "hono" | "html" | "laravel" | "litestar" | "nestjs" | "nextjs" | "nitro" | "nuxt" | "platformatic" | "react" | "rust" | "svelte" | "vue" | null | undefined;
44
- onRequestSent?: import("zod/v4/core").$InferOuterFunctionType<import("zod").ZodTuple<readonly [import("zod").ZodString], null>, import("zod").ZodVoid> | undefined;
45
- plugins?: import("zod/v4/core").$InferOuterFunctionType<import("zod").ZodTuple<readonly [], null>, import("zod").ZodObject<{
46
- name: import("zod").ZodString;
47
- views: import("zod").ZodOptional<import("zod").ZodObject<{
48
- "request.section": import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
49
- title: import("zod").ZodOptional<import("zod").ZodString>;
50
- component: import("zod").ZodUnknown;
51
- props: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodAny>>;
52
- }, import("zod/v4/core").$strip>>>;
53
- "response.section": import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
54
- title: import("zod").ZodOptional<import("zod").ZodString>;
55
- component: import("zod").ZodUnknown;
56
- props: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodAny>>;
57
- }, import("zod/v4/core").$strip>>>;
58
- }, import("zod/v4/core").$strip>>;
59
- hooks: import("zod").ZodOptional<import("zod").ZodObject<{
60
- onBeforeRequest: import("zod").ZodOptional<import("zod").ZodFunction<import("zod").ZodTuple<readonly [import("zod").ZodObject<{
61
- request: import("zod").ZodAny;
62
- }, import("zod/v4/core").$strip>], null>, import("zod/v4/core").$ZodFunctionOut>>;
63
- onResponseReceived: import("zod").ZodOptional<import("zod").ZodFunction<import("zod").ZodTuple<readonly [import("zod").ZodObject<{
64
- response: import("zod").ZodCustom<Response, Response>;
65
- operation: import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodAny>;
66
- }, import("zod/v4/core").$strip>], null>, import("zod/v4/core").$ZodFunctionOut>>;
67
- }, import("zod/v4/core").$strip>>;
68
- }, import("zod/v4/core").$strip>>[] | undefined;
69
- default?: boolean | undefined;
70
- url?: string | undefined;
71
- content?: string | Record<string, any> | import("zod/v4/core").$InferOuterFunctionType<import("zod").ZodTuple<readonly [], null>, import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodAny>> | null | undefined;
72
- title?: string | undefined;
73
- slug?: string | undefined;
74
- spec?: {
75
- url?: string | undefined;
76
- content?: string | Record<string, any> | import("zod/v4/core").$InferOuterFunctionType<import("zod").ZodTuple<readonly [], null>, import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodAny>> | null | undefined;
77
- } | undefined;
78
- agent?: {
79
- key?: string | undefined;
80
- disabled?: boolean | undefined;
81
- hideAddApi?: boolean | undefined;
82
- } | undefined;
83
- }> | undefined) => Promise<{
84
- apiClient: import("@scalar/api-client/v2/features/modal").ApiClientModal;
23
+ export declare const getOrCreateApiClient: (options?: Partial<Pick<import("@scalar/types/api-reference").ApiReferenceConfigurationRaw, "authentication" | "baseServerURL" | "hideClientButton" | "proxyUrl" | "oauth2RedirectUri" | "servers" | "hiddenClients">> | undefined) => Promise<{
24
+ apiClient: import("@scalar/api-client/modal").ApiClientModal;
85
25
  workspaceStore: import("@scalar/workspace-store/client").WorkspaceStore;
86
26
  }>;
87
27
  //# sourceMappingURL=lazy-load.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lazy-load.d.ts","sourceRoot":"","sources":["../src/lazy-load.ts"],"names":[],"mappings":"AAsBA,yCAAyC;AACzC,eAAO,MAAM,qBAAqB;;;;;;;oEAEjC,CAAA;AAED,0EAA0E;AAC1E,eAAO,MAAM,0BAA0B,wEAEtC,CAAA;AAED,8EAA8E;AAC9E,eAAO,MAAM,6BAA6B,2EAEzC,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0B/B,CAAA"}
1
+ {"version":3,"file":"lazy-load.d.ts","sourceRoot":"","sources":["../src/lazy-load.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAA;AAsBrE,yCAAyC;AACzC,eAAO,MAAM,qBAAqB;;;;;;;wDAEjC,CAAA;AAED,0EAA0E;AAC1E,eAAO,MAAM,0BAA0B,wEAEtC,CAAA;AAED,8EAA8E;AAC9E,eAAO,MAAM,6BAA6B,2EAEzC,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB;;;EA0B/B,CAAA"}