mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-09-12 04:37:51 +02:00
feat(sdk-js): loading external components (#3689)
- **chore: use prepack hook instead of prepublish** - **feat(sdk-js): add react-ui implementation** - **Add apiUrl, assistantId to props** - **Bump to 0.0.46-experimental.0**
This commit is contained in:
@@ -10,6 +10,14 @@ react.cjs
|
||||
react.js
|
||||
react.d.ts
|
||||
react.d.cts
|
||||
react-ui.cjs
|
||||
react-ui.js
|
||||
react-ui.d.ts
|
||||
react-ui.d.cts
|
||||
react-ui/server.cjs
|
||||
react-ui/server.js
|
||||
react-ui/server.d.ts
|
||||
react-ui/server.d.cts
|
||||
node_modules
|
||||
dist
|
||||
.yarn
|
||||
|
||||
@@ -11,7 +11,13 @@ function abs(relativePath) {
|
||||
|
||||
export const config = {
|
||||
internals: [/react/],
|
||||
entrypoints: { index: "index", client: "client", react: "react/index" },
|
||||
entrypoints: {
|
||||
index: "index",
|
||||
client: "client",
|
||||
react: "react/index",
|
||||
"react-ui": "react-ui/index",
|
||||
"react-ui/server": "react-ui/server/index",
|
||||
},
|
||||
tsConfigPath: resolve("./tsconfig.json"),
|
||||
cjsSource: "./dist-cjs",
|
||||
cjsDestination: "./dist",
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "@langchain/langgraph-sdk",
|
||||
"version": "0.0.46",
|
||||
"version": "0.0.47",
|
||||
"description": "Client library for interacting with the LangGraph API",
|
||||
"type": "module",
|
||||
"packageManager": "yarn@1.22.19",
|
||||
"scripts": {
|
||||
"clean": "rm -rf dist/ dist-cjs/",
|
||||
"build": "yarn clean && yarn lc_build --create-entrypoints --pre --tree-shaking",
|
||||
"prepublish": "yarn run build",
|
||||
"prepack": "yarn run build",
|
||||
"format": "prettier --write src",
|
||||
"lint": "prettier --check src && tsc --noEmit",
|
||||
"test": "NODE_OPTIONS=--experimental-vm-modules jest --testPathIgnorePatterns=\\.int\\.test.ts",
|
||||
@@ -29,7 +29,8 @@
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/node": "^20.12.12",
|
||||
"@types/uuid": "^9.0.1",
|
||||
"@types/react": "18.3.2",
|
||||
"@types/react": "^19.0.8",
|
||||
"@types/react-dom": "^19.0.3",
|
||||
"concat-md": "^0.5.1",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "^3.2.5",
|
||||
@@ -37,7 +38,8 @@
|
||||
"typedoc": "^0.27.7",
|
||||
"typedoc-plugin-markdown": "^4.4.2",
|
||||
"typescript": "^5.4.5",
|
||||
"react": "^18.3.1"
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18 || ^19",
|
||||
@@ -79,6 +81,24 @@
|
||||
"import": "./react.js",
|
||||
"require": "./react.cjs"
|
||||
},
|
||||
"./react-ui": {
|
||||
"types": {
|
||||
"import": "./react-ui.d.ts",
|
||||
"require": "./react-ui.d.cts",
|
||||
"default": "./react-ui.d.ts"
|
||||
},
|
||||
"import": "./react-ui.js",
|
||||
"require": "./react-ui.cjs"
|
||||
},
|
||||
"./react-ui/server": {
|
||||
"types": {
|
||||
"import": "./react-ui/server.d.ts",
|
||||
"require": "./react-ui/server.d.cts",
|
||||
"default": "./react-ui/server.d.ts"
|
||||
},
|
||||
"import": "./react-ui/server.js",
|
||||
"require": "./react-ui/server.cjs"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"files": [
|
||||
@@ -94,6 +114,14 @@
|
||||
"react.cjs",
|
||||
"react.js",
|
||||
"react.d.ts",
|
||||
"react.d.cts"
|
||||
"react.d.cts",
|
||||
"react-ui.cjs",
|
||||
"react-ui.js",
|
||||
"react-ui.d.ts",
|
||||
"react-ui.d.cts",
|
||||
"react-ui/server.cjs",
|
||||
"react-ui/server.js",
|
||||
"react-ui/server.d.ts",
|
||||
"react-ui/server.d.cts"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
import { useStream } from "../react/index.js";
|
||||
import type { UIMessage } from "./types.js";
|
||||
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import * as JsxRuntime from "react/jsx-runtime";
|
||||
import type { UseStream } from "../react/stream.js";
|
||||
|
||||
const UseStreamContext = React.createContext<{
|
||||
stream: ReturnType<typeof useStream>;
|
||||
meta: unknown;
|
||||
}>(null!);
|
||||
|
||||
type BagTemplate = {
|
||||
ConfigurableType?: Record<string, unknown>;
|
||||
InterruptType?: unknown;
|
||||
CustomEventType?: unknown;
|
||||
UpdateType?: unknown;
|
||||
MetaType?: unknown;
|
||||
};
|
||||
|
||||
type GetMetaType<Bag extends BagTemplate> = Bag extends { MetaType: unknown }
|
||||
? Bag["MetaType"]
|
||||
: unknown;
|
||||
|
||||
interface UseStreamContext<
|
||||
StateType extends Record<string, unknown> = Record<string, unknown>,
|
||||
Bag extends BagTemplate = BagTemplate,
|
||||
> extends UseStream<StateType, Bag> {
|
||||
meta?: GetMetaType<Bag>;
|
||||
}
|
||||
|
||||
export function useStreamContext<
|
||||
StateType extends Record<string, unknown> = Record<string, unknown>,
|
||||
Bag extends {
|
||||
ConfigurableType?: Record<string, unknown>;
|
||||
InterruptType?: unknown;
|
||||
CustomEventType?: unknown;
|
||||
UpdateType?: unknown;
|
||||
MetaType?: unknown;
|
||||
} = BagTemplate,
|
||||
>(): UseStreamContext<StateType, Bag> {
|
||||
const ctx = React.useContext(UseStreamContext);
|
||||
if (!ctx) {
|
||||
throw new Error(
|
||||
"useStreamContext must be used within a LoadExternalComponent",
|
||||
);
|
||||
}
|
||||
|
||||
return new Proxy(ctx, {
|
||||
get(target, prop: keyof UseStreamContext<StateType, Bag>) {
|
||||
if (prop === "meta") return target.meta;
|
||||
return target.stream[prop];
|
||||
},
|
||||
}) as unknown as UseStreamContext<StateType, Bag>;
|
||||
}
|
||||
|
||||
interface ComponentTarget {
|
||||
comp: React.FunctionComponent | React.ComponentClass;
|
||||
target: HTMLElement;
|
||||
}
|
||||
|
||||
class ComponentStore {
|
||||
private cache: Record<string, ComponentTarget> = {};
|
||||
private boundCache: Record<
|
||||
string,
|
||||
{
|
||||
subscribe: (onStoreChange: () => void) => () => void;
|
||||
getSnapshot: () => ComponentTarget | undefined;
|
||||
}
|
||||
> = {};
|
||||
private callbacks: Record<
|
||||
string,
|
||||
((
|
||||
comp: React.FunctionComponent | React.ComponentClass,
|
||||
el: HTMLElement,
|
||||
) => void)[]
|
||||
> = {};
|
||||
|
||||
respond(
|
||||
shadowRootId: string,
|
||||
comp: React.FunctionComponent | React.ComponentClass,
|
||||
targetElement: HTMLElement,
|
||||
) {
|
||||
this.cache[shadowRootId] = { comp, target: targetElement };
|
||||
this.callbacks[shadowRootId]?.forEach((c) => c(comp, targetElement));
|
||||
}
|
||||
|
||||
getBoundStore(shadowRootId: string) {
|
||||
this.boundCache[shadowRootId] ??= {
|
||||
subscribe: (onStoreChange: () => void) => {
|
||||
this.callbacks[shadowRootId] ??= [];
|
||||
this.callbacks[shadowRootId].push(onStoreChange);
|
||||
return () => {
|
||||
this.callbacks[shadowRootId] = this.callbacks[shadowRootId].filter(
|
||||
(c) => c !== onStoreChange,
|
||||
);
|
||||
};
|
||||
},
|
||||
getSnapshot: () => this.cache[shadowRootId],
|
||||
};
|
||||
|
||||
return this.boundCache[shadowRootId];
|
||||
}
|
||||
}
|
||||
|
||||
const COMPONENT_STORE = new ComponentStore();
|
||||
const COMPONENT_PROMISE_CACHE: Record<string, Promise<string> | undefined> = {};
|
||||
|
||||
const EXT_STORE_SYMBOL = Symbol.for("LGUI_EXT_STORE");
|
||||
const REQUIRE_SYMBOL = Symbol.for("LGUI_REQUIRE");
|
||||
|
||||
interface LoadExternalComponentProps
|
||||
extends Pick<React.HTMLAttributes<HTMLDivElement>, "style" | "className"> {
|
||||
/** API URL of the LangGraph Platform */
|
||||
apiUrl?: string;
|
||||
|
||||
/** ID of the assistant */
|
||||
assistantId: string;
|
||||
|
||||
/** Stream of the assistant */
|
||||
stream: ReturnType<typeof useStream>;
|
||||
|
||||
/** UI message to be rendered */
|
||||
message: UIMessage;
|
||||
|
||||
/** Additional context to be passed to the child component */
|
||||
meta?: unknown;
|
||||
|
||||
/** Fallback to be rendered when the component is loading */
|
||||
fallback?: React.ReactNode;
|
||||
|
||||
/**
|
||||
* Map of components that can be rendered directly without fetching the UI code
|
||||
* from the server.
|
||||
*/
|
||||
components?: Record<string, React.FunctionComponent | React.ComponentClass>;
|
||||
}
|
||||
|
||||
function fetchComponent(
|
||||
apiUrl: string,
|
||||
assistantId: string,
|
||||
agentName: string,
|
||||
): Promise<string> {
|
||||
const cacheKey = `${apiUrl}-${assistantId}-${agentName}`;
|
||||
if (COMPONENT_PROMISE_CACHE[cacheKey] != null) {
|
||||
return COMPONENT_PROMISE_CACHE[cacheKey] as Promise<string>;
|
||||
}
|
||||
|
||||
const request: Promise<string> = fetch(`${apiUrl}/ui/${assistantId}`, {
|
||||
headers: { Accept: "text/html", "Content-Type": "application/json" },
|
||||
method: "POST",
|
||||
body: JSON.stringify({ name: agentName }),
|
||||
}).then((a) => a.text());
|
||||
|
||||
COMPONENT_PROMISE_CACHE[cacheKey] = request;
|
||||
return request;
|
||||
}
|
||||
|
||||
export function LoadExternalComponent({
|
||||
apiUrl = "http://localhost:2024",
|
||||
assistantId,
|
||||
stream,
|
||||
message,
|
||||
meta,
|
||||
fallback,
|
||||
components,
|
||||
...props
|
||||
}: LoadExternalComponentProps) {
|
||||
const ref = React.useRef<HTMLDivElement>(null);
|
||||
const id = React.useId();
|
||||
const shadowRootId = `child-shadow-${id}`;
|
||||
|
||||
const store = React.useMemo(
|
||||
() => COMPONENT_STORE.getBoundStore(shadowRootId),
|
||||
[shadowRootId],
|
||||
);
|
||||
const state = React.useSyncExternalStore(store.subscribe, store.getSnapshot);
|
||||
|
||||
const clientComponent = components?.[message.name];
|
||||
const hasClientComponent = clientComponent != null;
|
||||
|
||||
React.useEffect(() => {
|
||||
if (hasClientComponent) return;
|
||||
fetchComponent(apiUrl, assistantId, message.name).then((html) => {
|
||||
const dom = ref.current;
|
||||
if (!dom) return;
|
||||
const root = dom.shadowRoot ?? dom.attachShadow({ mode: "open" });
|
||||
const fragment = document
|
||||
.createRange()
|
||||
.createContextualFragment(
|
||||
html.replace("{{shadowRootId}}", shadowRootId),
|
||||
);
|
||||
root.appendChild(fragment);
|
||||
});
|
||||
}, [apiUrl, assistantId, message.name, shadowRootId, hasClientComponent]);
|
||||
|
||||
if (hasClientComponent) {
|
||||
return React.createElement(clientComponent, message.content);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div id={shadowRootId} ref={ref} {...props} />
|
||||
|
||||
<UseStreamContext.Provider value={{ stream, meta }}>
|
||||
{state?.target != null
|
||||
? ReactDOM.createPortal(
|
||||
React.createElement(state.comp, message.content),
|
||||
state.target,
|
||||
)
|
||||
: fallback}
|
||||
</UseStreamContext.Provider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
[EXT_STORE_SYMBOL]: ComponentStore;
|
||||
[REQUIRE_SYMBOL]: (name: string) => unknown;
|
||||
}
|
||||
}
|
||||
|
||||
export function bootstrapUiContext() {
|
||||
if (typeof window === "undefined") {
|
||||
console.warn(
|
||||
"Attempting to bootstrap UI context outside of browser environment. " +
|
||||
"Avoid importing from `@langchain/langgraph-sdk/react-ui` in server context.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
window[EXT_STORE_SYMBOL] = COMPONENT_STORE;
|
||||
window[REQUIRE_SYMBOL] = (name: string) => {
|
||||
if (name === "react") return React;
|
||||
if (name === "react-dom") return ReactDOM;
|
||||
if (name === "react/jsx-runtime") return JsxRuntime;
|
||||
if (name === "@langchain/langgraph-sdk/react") return { useStream };
|
||||
if (name === "@langchain/langgraph-sdk/react-ui") {
|
||||
return {
|
||||
useStreamContext,
|
||||
LoadExternalComponent: () => {
|
||||
throw new Error("Nesting LoadExternalComponent is not supported");
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error(`Unknown module...: ${name}`);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { bootstrapUiContext } from "./client.js";
|
||||
bootstrapUiContext();
|
||||
|
||||
export { useStreamContext, LoadExternalComponent } from "./client.js";
|
||||
export type { UIMessage, RemoveUIMessage } from "./types.js";
|
||||
@@ -0,0 +1,6 @@
|
||||
export { typedUi } from "./server.js";
|
||||
export {
|
||||
uiMessageReducer,
|
||||
type UIMessage,
|
||||
type RemoveUIMessage,
|
||||
} from "../types.js";
|
||||
@@ -0,0 +1,49 @@
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import type { ComponentPropsWithoutRef, ElementType } from "react";
|
||||
import type { RemoveUIMessage, UIMessage } from "../types.js";
|
||||
|
||||
export const typedUi = <Decl extends Record<string, ElementType>>(config: {
|
||||
writer?: (chunk: unknown) => void;
|
||||
runId?: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
tags?: string[];
|
||||
runName?: string;
|
||||
}) => {
|
||||
type PropMap = { [K in keyof Decl]: ComponentPropsWithoutRef<Decl[K]> };
|
||||
let collect: (UIMessage | RemoveUIMessage)[] = [];
|
||||
|
||||
const runId = (config.metadata?.run_id as string | undefined) ?? config.runId;
|
||||
if (!runId) throw new Error("run_id is required");
|
||||
|
||||
const metadata = {
|
||||
...config.metadata,
|
||||
tags: config.tags,
|
||||
name: config.runName,
|
||||
run_id: runId,
|
||||
};
|
||||
|
||||
const create = <K extends keyof PropMap & string>(
|
||||
name: K,
|
||||
props: PropMap[K],
|
||||
): UIMessage => ({
|
||||
type: "ui" as const,
|
||||
id: uuidv4(),
|
||||
name,
|
||||
content: props,
|
||||
additional_kwargs: metadata,
|
||||
});
|
||||
|
||||
const remove = (id: string): RemoveUIMessage => ({ type: "remove-ui", id });
|
||||
|
||||
return {
|
||||
create,
|
||||
remove,
|
||||
|
||||
collect,
|
||||
write: <K extends keyof PropMap & string>(name: K, props: PropMap[K]) => {
|
||||
const evt: UIMessage = create(name, props);
|
||||
collect.push(evt);
|
||||
config.writer?.(evt);
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
export interface UIMessage {
|
||||
type: "ui";
|
||||
|
||||
id: string;
|
||||
name: string;
|
||||
content: Record<string, unknown>;
|
||||
additional_kwargs: {
|
||||
run_id: string;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
}
|
||||
|
||||
export interface RemoveUIMessage {
|
||||
type: "remove-ui";
|
||||
id: string;
|
||||
}
|
||||
|
||||
export function uiMessageReducer(
|
||||
state: UIMessage[],
|
||||
update: UIMessage | RemoveUIMessage | (UIMessage | RemoveUIMessage)[],
|
||||
) {
|
||||
const events = Array.isArray(update) ? update : [update];
|
||||
let newState = state.slice();
|
||||
|
||||
for (const event of events) {
|
||||
if (event.type === "remove-ui") {
|
||||
newState = newState.filter((ui) => ui.id !== event.id);
|
||||
continue;
|
||||
}
|
||||
|
||||
const index = state.findIndex((ui) => ui.id === event.id);
|
||||
if (index !== -1) {
|
||||
newState[index] = event;
|
||||
} else {
|
||||
newState.push(event);
|
||||
}
|
||||
}
|
||||
|
||||
return newState;
|
||||
}
|
||||
@@ -482,7 +482,7 @@ interface UseStreamOptions<
|
||||
onThreadId?: (threadId: string) => void;
|
||||
}
|
||||
|
||||
interface UseStream<
|
||||
export interface UseStream<
|
||||
StateType extends Record<string, unknown> = Record<string, unknown>,
|
||||
Bag extends BagTemplate = BagTemplate,
|
||||
> {
|
||||
|
||||
+25
-23
@@ -1005,17 +1005,16 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901"
|
||||
integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==
|
||||
|
||||
"@types/prop-types@*":
|
||||
version "15.7.14"
|
||||
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.14.tgz#1433419d73b2a7ebfc6918dcefd2ec0d5cd698f2"
|
||||
integrity sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==
|
||||
"@types/react-dom@^19.0.3":
|
||||
version "19.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.0.3.tgz#0804dfd279a165d5a0ad8b53a5b9e65f338050a4"
|
||||
integrity sha512-0Knk+HJiMP/qOZgMyNFamlIjw9OFCsyC2ZbigmEEyXXixgre6IQpm/4V+r3qH4GC1JPvRJKInw+on2rV6YZLeA==
|
||||
|
||||
"@types/react@18.3.2":
|
||||
version "18.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.2.tgz#462ae4904973bc212fa910424d901e3d137dbfcd"
|
||||
integrity sha512-Btgg89dAnqD4vV7R3hlwOxgqobUQKgx3MmrQRi0yYbs/P0ym8XozIAlkqVilPqHQwXs4e9Tf63rrCgl58BcO4w==
|
||||
"@types/react@^19.0.8":
|
||||
version "19.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-19.0.9.tgz#675255eb7d978bdaf71f9d08f6b740d41b0b7f32"
|
||||
integrity sha512-FedNTYgmMwSZmD1Sru/W1gJKuiYCN/3SuBkmZkcxX+FpO5zL76B22A9YNfAKg4HQO3Neh/30AiynP6BELdU0qQ==
|
||||
dependencies:
|
||||
"@types/prop-types" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/retry@0.12.0":
|
||||
@@ -2896,7 +2895,7 @@ js-tiktoken@^1.0.12:
|
||||
dependencies:
|
||||
base64-js "^1.5.1"
|
||||
|
||||
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
|
||||
js-tokens@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
|
||||
@@ -2991,13 +2990,6 @@ longest-streak@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.4.tgz#b8599957da5b5dab64dee3fe316fa774597d90e4"
|
||||
integrity sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==
|
||||
|
||||
loose-envify@^1.1.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||
dependencies:
|
||||
js-tokens "^3.0.0 || ^4.0.0"
|
||||
|
||||
lru-cache@^10.2.0:
|
||||
version "10.4.3"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119"
|
||||
@@ -3640,17 +3632,22 @@ quick-lru@^4.0.1:
|
||||
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f"
|
||||
integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==
|
||||
|
||||
react-dom@^19.0.0:
|
||||
version "19.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.0.0.tgz#43446f1f01c65a4cd7f7588083e686a6726cfb57"
|
||||
integrity sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==
|
||||
dependencies:
|
||||
scheduler "^0.25.0"
|
||||
|
||||
react-is@^18.0.0:
|
||||
version "18.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"
|
||||
integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
|
||||
|
||||
react@^18.3.1:
|
||||
version "18.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891"
|
||||
integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
react@^19.0.0:
|
||||
version "19.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-19.0.0.tgz#6e1969251b9f108870aa4bff37a0ce9ddfaaabdd"
|
||||
integrity sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==
|
||||
|
||||
read-pkg-up@^7.0.1:
|
||||
version "7.0.1"
|
||||
@@ -3840,6 +3837,11 @@ safe-regex-test@^1.0.3:
|
||||
es-errors "^1.3.0"
|
||||
is-regex "^1.1.4"
|
||||
|
||||
scheduler@^0.25.0:
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0.tgz#336cd9768e8cceebf52d3c80e3dcf5de23e7e015"
|
||||
integrity sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==
|
||||
|
||||
"semver@2 || 3 || 4 || 5":
|
||||
version "5.7.2"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"
|
||||
|
||||
Reference in New Issue
Block a user