UNPKG

@donverduyn/react-runtime

Version:
803 lines (784 loc) 32.4 kB
'use strict'; var jsxRuntime = require('react/jsx-runtime'); var React = require('react'); var uuid = require('uuid'); var effect = require('effect'); function _interopNamespaceDefault(e) { var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React); function isPlainObject(value) { return (typeof value === 'object' && value !== null && Object.getPrototypeOf(value) === Object.prototype); } function deepEqual(objA, objB, options = {}) { if (objA === objB) return true; if (isPlainObject(objA) && isPlainObject(objB)) { const keysA = Object.keys(objA); const keysB = Object.keys(objB); if (keysA.length !== keysB.length) return false; for (const key of keysA) { if (!keysB.includes(key)) return false; const valA = objA[key]; const valB = objB[key]; if (!deepEqual(valA, valB, options)) return false; } return true; } if (Array.isArray(objA) && Array.isArray(objB)) { if (objA.length !== objB.length) return false; for (let i = 0; i < objA.length; i++) { if (!deepEqual(objA[i], objB[i], options)) return false; } return true; } return false; } function isReactContext2(variable) { return (isPlainObject(variable) && React__namespace.isValidElement(variable.Provider) && React__namespace.isValidElement(variable.Consumer)); } const isReactContext = ( // eslint-disable-next-line @typescript-eslint/no-explicit-any variable) => { return (isPlainObject(variable) && // // eslint-disable-next-line @typescript-eslint/ban-ts-comment // // @ts-expect-error $$typeof is a private property variable.$$typeof === React__namespace.createContext(null).$$typeof); }; // eslint-disable-next-line @typescript-eslint/no-explicit-any const getDisplayName = (Component, prefix) => { const extraField = Component?.type?.name; const componentName = (Component && (Component.displayName || Component.name || extraField)) || 'Component'; return prefix ? `${prefix}(${componentName})` : componentName; }; // based on https://github.com/mridgway/hoist-non-react-statics/blob/master/src/index.js const hoistBlackList = { $$typeof: true, compare: true, // Don't redefine `displayName`, // it's defined as getter-setter pair on `memo` (see #3192). displayName: true, render: true, type: true, }; function copyStaticProperties(base, target) { // const properties = Object.entries(base).reduce<Record<string, unknown>>( // (acc, [key, value]) => { // if (!hoistBlackList[key as keyof typeof hoistBlackList]) { // acc[key] = value; // } // return acc; // }, // {} // ); // Object.assign(target, properties); Object.keys(base).forEach(function (key) { if (!hoistBlackList[key]) { Object.defineProperty(target, key, // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error not allowed Object.getOwnPropertyDescriptor(base, key)); } }); } // eslint-disable-next-line @typescript-eslint/no-explicit-any const createElement = (Component, // eslint-disable-next-line @typescript-eslint/no-explicit-any mergedProps) => (Component ? jsxRuntime.jsx(Component, { ...mergedProps }) : null); // eslint-disable-next-line @typescript-eslint/no-explicit-any const extractMeta = (Component) => Object.getOwnPropertyNames(Component) .filter((() => { const skip = Object.getOwnPropertyNames(() => { }); return (key) => !skip.includes(key); })()) .reduce((acc, key) => Object.assign(acc, { [key]: Component[key] }), {}); // eslint-disable-next-line eslint-comments/disable-enable-pair /* eslint-disable @typescript-eslint/no-explicit-any */ const noRuntimeMessage = `No runtime available. Did you forget to wrap your component using WithRuntime? `; const getDeps = (input, deps) => (effect.Effect.isEffect(input) ? deps : Array.isArray(input) ? input : deps); const getRuntime = (input, localContext, instances) => { const result = (isReactContext(input) ? input !== localContext ? React__namespace.use(input) : instances.get(input) : effect.ManagedRuntime.isManagedRuntime(input) ? input : instances.get(localContext)); if (result === undefined) { throw new Error(noRuntimeMessage); } else { return result; } }; const getEffectFn = (input, fnOrDeps) => (!effect.ManagedRuntime.isManagedRuntime(input) && !effect.Effect.isEffect(input) && !isReactContext(input) ? input : typeof fnOrDeps === 'function' ? fnOrDeps : () => effect.Effect.void); const getEffect = (input, effectOrDeps) => (effect.Effect.isEffect(input) && !effect.ManagedRuntime.isManagedRuntime(input) ? input : effect.Effect.isEffect(effectOrDeps) ? effectOrDeps : effect.Effect.void); const createUse = (localContext, // eslint-disable-next-line @typescript-eslint/no-explicit-any instances) => (targetOrEffect, effectOrDeps, deps = []) => { const finalDeps = getDeps(effectOrDeps, deps); const effect = getEffect(targetOrEffect, effectOrDeps); const runtime = getRuntime(targetOrEffect, localContext, instances); return React__namespace.useMemo(() => runtime.runSync(effect), [instances, runtime, ...finalDeps]); }; /* This is converting push based events to a pull based stream, where the consumer has control through the provided effect. */ class EventEmitter { constructor() { this.listeners = []; this.resolvers = new Map(); this.eventQueue = []; this.emit = (...args) => { const eventId = uuid.v4(); let resolver; const promise = new Promise((resolve) => { resolver = resolve; }); this.eventQueue.push({ data: args, eventId }); this.notifyListeners(); this.resolvers.set(eventId, resolver); return promise; }; } subscribe(listener) { this.listeners.push(listener); this.notifyListeners(); } notifyListeners() { while (this.eventQueue.length > 0 && this.listeners.length > 0) { const event = this.eventQueue.shift(); this.listeners.forEach((listener) => listener(event.data, event.eventId)); } } resolve(eventId) { return (result) => { const resolver = this.resolvers.get(eventId); if (resolver) { resolver(result); this.resolvers.delete(eventId); } }; } async waitForEvent() { if (this.eventQueue.length > 0) { return Promise.resolve(this.eventQueue.shift()); } return new Promise((resolve) => { const oneTimeListener = (data, eventId) => { resolve({ data, eventId }); this.listeners = this.listeners.filter((l) => l !== oneTimeListener); }; this.subscribe(oneTimeListener); }); } } async function* createAsyncIterator(emitter) { while (true) { yield await emitter.waitForEvent(); } } // eslint-disable-next-line eslint-comments/disable-enable-pair /* eslint-disable @typescript-eslint/no-explicit-any */ const createFn = (localContext, instances) => (targetOrEffect, fnOrDeps, deps = []) => { const finalDeps = getDeps(fnOrDeps, deps); const effectFn = getEffectFn(targetOrEffect, fnOrDeps); const runtime = getRuntime(targetOrEffect, localContext, instances); const fnRef = React__namespace.useRef(effectFn); React__namespace.useEffect(() => { fnRef.current = effectFn; }, [instances, runtime, effectFn, ...finalDeps]); const emitter = React__namespace.useMemo(() => new EventEmitter(), [instances, runtime, ...finalDeps]); const stream = React__namespace.useMemo(() => effect.pipe(effect.Stream.fromAsyncIterable(createAsyncIterator(emitter), () => { }), effect.Stream.mapEffect(({ data, eventId }) => effect.pipe(fnRef.current(...data), effect.Effect.tap((v) => emitter.resolve(eventId)(v)))), effect.Stream.runDrain), [instances, runtime, ...finalDeps]); React__namespace.useEffect(() => { const scope = effect.Effect.runSync(effect.Scope.make()); runtime.runFork(stream.pipe(effect.Effect.forkScoped, effect.Scope.extend(scope))); return () => { runtime.runFork(effect.Scope.close(scope, effect.Exit.void)); }; }, [instances, runtime, emitter, ...finalDeps]); return emitter.emit; }; /* This hook is used to run an effect in a runtime. It takes a context and an effect and runs the effect in the runtime provided by the context. It is used by useRuntimeFn. Assumes createRuntimeContext is used to create the context, because it expects a Layer when withRuntime is missing. */ const createRun = (localContext, // eslint-disable-next-line @typescript-eslint/no-explicit-any instances) => (targetOrEffect, effectOrDeps, deps = []) => { const finalDeps = getDeps(effectOrDeps, deps); const effect$1 = getEffect(targetOrEffect, effectOrDeps); const runtime = getRuntime(targetOrEffect, localContext, instances); const hasRun = React__namespace.useRef(false); const scope = React__namespace.useRef(null); if (!hasRun.current) { scope.current = effect.Effect.runSync(effect.Scope.make()); runtime.runFork(effect$1.pipe(effect.Effect.forkScoped, effect.Scope.extend(scope.current))); hasRun.current = true; } React__namespace.useEffect(() => { if (!hasRun.current) { scope.current = effect.Effect.runSync(effect.Scope.make()); runtime.runFork(effect$1.pipe(effect.Effect.forkScoped, effect.Scope.extend(scope.current))); } return () => { runtime.runFork(effect.Scope.close(scope.current, effect.Exit.void)); hasRun.current = false; }; }, [instances, runtime, ...finalDeps]); }; // const createRuntime = memoize( // <T,>(layer: Layer.Layer<T>, runtimeId: string, config: Config) => { // printLog(config, `creating runtime ${runtimeId}`); // const instance = ManagedRuntime.make(layer); // return Object.assign(instance, { // id: runtimeId, // config, // }) as RuntimeInstance<T>; // }, // // this prevents a second instantiation in strict mode inside the useState function, which gets disposed immediately, and it since it has no side effects, we are safe. // { isShallowEqual: true, maxAge: 100, maxArgs: 2 } // ); /* This hook creates a runtime and disposes it when the component is unmounted. It is used by withRuntime to create a runtime for the context. This is both compatible with strict mode and fast refresh. 🚀 */ // export const useRuntimeInstance = <T,>( // layer: Layer.Layer<T>, // config: Config // ) => { // // TODO: use useSyncExternalStore to keep track of runtime instances and dispose them based on postUnmountTTL. Rehydrate the runtime instances on mount (maybe we need a component name/id combo here). The idea is that we can control the rotation of runtime instances based on what's in the map. This way we can control how any concurrent mode pecularities affect it. This also means we would no longer need to memoize the factory in useState, because the defensive logic would be in the store, to prevent unwanted half executed rotations. // const layerRef = React.useRef(layer); // const shouldCreate = React.useRef(false); // const runtimeId = React.useRef(uuid()); // const hasMounted = React.useRef(false); // const configRef = React.useRef(config); // const [runtime, setRuntime] = React.useState(() => // createRuntime(layerRef.current, runtimeId.current, config) // ); // React.useEffect(() => { // if (!deepEqual(configRef.current, config)) { // printLog(config, `recreating runtime ${runtimeId.current}`); // const newRuntime = Object.assign(ManagedRuntime.make(layer), { // id: uuid(), // config, // }); // void runtime.dispose().then(() => { // setRuntime(() => newRuntime); // configRef.current = config; // runtimeId.current = newRuntime.id; // }); // } // }, [config]); // if (!hasMounted.current) { // hasMounted.current = true; // } else { // printLog(config, `reusing runtime ${runtimeId.current}`); // } // React.useEffect(() => { // if (shouldCreate.current || layerRef.current !== layer) { // layerRef.current = layer; // shouldCreate.current = false; // printLog(config, `recreating runtime ${runtimeId.current}`); // const newRuntime = Object.assign(ManagedRuntime.make(layer), { // id: uuid(), // config, // }); // runtimeId.current = uuid(); // setRuntime(() => newRuntime); // } // return () => { // printLog(config, `disposing runtime ${runtimeId.current}`); // setTimeout(() => void runtime.dispose(), 0); // shouldCreate.current = true; // }; // }, [layer]); // return runtime; // }; class Store { constructor() { // eslint-disable-next-line @typescript-eslint/no-explicit-any this.instances = new Map(); // eslint-disable-next-line @typescript-eslint/no-explicit-any this.contextToId = new Map(); this.disposalTimeouts = new Map(); this.listeners = new Map(); this.loggers = new Map(); // this.log(null, 'initialized'); console.log('Store initialized'); } static of() { return new Store(); } log(config, message) { if (config.debug) { console.log(`[${config.componentName}] ${message}`); } } // private setLogger(config: Config) { // const logger = config.debug // ? (msg: string) => console.log(`[${config.componentName}] ${msg}`) // : () => {}; // this.loggers.set(config.id, logger); updateTimeout(config) { const timeoutId = this.disposalTimeouts.get(config.id); if (timeoutId) { clearTimeout(timeoutId); this.disposalTimeouts.delete(config.id); this.log(config, `cleared disposal timeout for ${config.id}`); } } createTimeout(config, instance) { const timeoutId = setTimeout(() => { void instance.dispose(); this.disposalTimeouts.delete(config.id); this.log(config, `disposed runtime after TTL for ${config.id}`); }, instance.config.postUnmountTTL); this.disposalTimeouts.set(config.id, timeoutId); } createInstance(layer, config) { this.log(config, `instantiating runtime ${config.id}`); return Object.assign(effect.ManagedRuntime.make(layer), { id: config.id, config, }); } onMount(context, config, options = { notify: true, update: false, }) { const idFromContext = this.contextToId.get(context); this.updateTimeout(config); if (idFromContext && idFromContext !== config.id) { const existingInstance = this.instances.get(idFromContext); if (config.fresh && existingInstance && !existingInstance.isDisposed) { this.log(config, `creating runtime with fresh:true for ${config.id}, replacing ${idFromContext}`); const newInstance = this.createInstance(context.layer, config); if (options.notify) this.notifyById(config.id); if (config.disposeStrategy === 'dispose') { setTimeout(() => { void existingInstance.dispose(); existingInstance.isDisposed = true; }, 0); this.instances.set(config.id, newInstance); this.contextToId.set(context, config.id); this.log(config, `disposed previous instance ${idFromContext}`); } } else if (options.update) { this.log(config, `reused existing runtime for ${idFromContext}`); this.updateInstance(config.id, config); } } if (!this.instances.has(config.id)) { this.log(config, `creating new runtime for ${config.id}`); const instance = this.createInstance(context.layer, config); this.instances.set(config.id, instance); this.contextToId.set(context, config.id); // if (options.notify) this.notifyById(config.id); } } onUnmount(_, config) { const instance = this.instances.get(config.id); if (!instance) return; this.log(config, `scheduled disposal for ${config.id}`); this.createTimeout(config, instance); } updateInstance(id, config) { const instance = this.instances.get(id); if (instance) { instance.config = config; this.log(config, `updated config for ${id}`); } } subscribe(context, config) { const existing = this.instances.get(config.id); if (!existing) this.onMount(context, config, { notify: false }); return (listener) => { this.log(config, `subscribed ${config.id}`); this.listeners.set(config.id, listener); return () => { this.listeners.delete(config.id); this.log(config, `unsubscribed ${config.id}`); }; }; } getSnapshot(id) { return () => { // this.log(id, `snapshot read for ${id}`); return this.instances.get(id); }; } getByInstanceId(id) { // this.log(id, `get instance by id ${id}`); return this.instances.get(id); } // eslint-disable-next-line @typescript-eslint/no-explicit-any getByRuntimeCtx(ctx) { const id = this.contextToId.get(ctx); // if (id) this.log(id, `get instance by context`); return id ? this.instances.get(id) : undefined; } notifyById(id) { const listener = this.listeners.get(id); if (listener) { // this.log(id, `notify listener for ${id}`); listener(); } } notifyAll() { // this.log(null, `notifying all listeners`); this.listeners.forEach((listener) => listener()); } disposeAll() { // this.log(null, `disposing all runtimes`); this.instances.forEach((instance) => { void instance.dispose(); // this.log(null, `disposed ${id}`); }); this.instances.clear(); this.contextToId.clear(); this.listeners.clear(); this.disposalTimeouts.forEach(clearTimeout); this.disposalTimeouts.clear(); } } // considered private const store = Store.of(); const useRuntimeInstance = (context, config) => { const configRef = React__namespace.useRef(config); const shouldUpdateRef = React__namespace.useRef(false); if (!store) { throw new Error(`[useRuntimeInstance] Store is not initialized.`); } React__namespace.useEffect(() => { if (shouldUpdateRef.current) { store.onMount(context, config, { notify: true, update: false }); shouldUpdateRef.current = false; } return () => { store.onUnmount(context, config); shouldUpdateRef.current = true; }; }, [context]); if (!deepEqual(configRef.current, config)) { store.updateInstance(config.id, config); configRef.current = config; } const instance = React__namespace.useSyncExternalStore(store.subscribe(context, configRef.current), store.getSnapshot(configRef.current.id)); if (!instance) { throw new Error(`[useRuntimeInstance] Runtime for ID "${config.id}" could not be initialized.`); } return instance; }; const RUNTIME_PROP = '__runtimes'; const COMPONENT_PROP = '__component'; const PROPS_PROP = '__props'; const UPSTREAM_PROP = '__upstream'; const defaultConfig = { componentName: 'Runtime', debug: false, postUnmountTTL: 1000, env: process.env.NODE_ENV === 'production' ? 'prod' : 'dev', disposeStrategy: 'unmount', // only used with fresh: true fresh: false, id: uuid.v4(), }; const getStaticRegistry = (component) => component[RUNTIME_PROP] ?? []; const getStaticComponent = (component) => component[COMPONENT_PROP]; const hoistOriginalComponent = (Wrapper, target) => { Wrapper[COMPONENT_PROP] = target; }; const hoistUpdatedRegistry = (Wrapper, registry) => { Wrapper[RUNTIME_PROP] = registry; }; function collectRuntimeEntries(component, entry) { const graph = []; const visited = new Set(); function dfs(comp, level) { if (visited.has(comp)) return; visited.add(comp); const registry = getStaticRegistry(comp); const appendedRegistry = comp === component ? registry.concat(entry) : registry; appendedRegistry.forEach((item, index) => { graph.push(Object.assign({}, item, { level, index })); const ref = item.context !== entry.context ? item.context.reference() : undefined; // we currently only support a single reference (assuming a single withRuntime usage for a runtime) if (ref) dfs(ref, level + 1); }); } dfs(component, 0); return graph.sort((a, b) => { if (a.level !== b.level) return b.level - a.level; return a.index - b.index; }); } const createRuntimeEntry = (entry) => entry; const hocFactory = (type, name) => { function hoc(Context, getSource) { return (Component) => { const target = getStaticComponent(Component) ?? Component; const registry = getStaticRegistry(Component); const hocId = uuid.v4(); const entry = createRuntimeEntry({ context: Context, configFn: getSource, id: hocId, type, }); const Wrapper = (props) => { const entries = collectRuntimeEntries(Component, entry); const runtimeInstances = new Map(); const upstreamContexts = new Map(); entries .filter((item) => item.type === 'runtime' && item.level !== 0) .forEach(({ context }) => { const val = React__namespace.use(context.context); if (val) { upstreamContexts.set(context.context, val); runtimeInstances.set(context.context, val); } }); let mergedFromConfigs = {}; let previousLevel = 0; entries .filter((entry) => { return !upstreamContexts.has(entry.context.context); }) .forEach((entry) => { const { context, configFn, type } = entry; if (entry.level < previousLevel) mergedFromConfigs = {}; previousLevel = entry.level; const baseConfig = Object.assign({}, defaultConfig, { ...entry.context.context.config, componentName: getDisplayName(target, 'Runtime'), id: entry.level === 0 ? (props.id ?? entry.id) : entry.id, }); // const { layer } = entry.context.context as unknown as { // layer: Layer.Layer<R>; // }; const factory = (overrides) => { const config = Object.assign({}, baseConfig, overrides ?? {}); const runtime = // eslint-disable-next-line react-hooks/rules-of-hooks useRuntimeInstance(entry.context.context, config); runtimeInstances.set(context.context, runtime); // contextToId.set(context, runtime.id); // Store the context to ID mapping return { runtime, use: createUse(context.context, runtimeInstances), useFn: createFn(context.context, runtimeInstances), useRun: createRun(context.context, runtimeInstances), }; }; if (type === 'upstream' && baseConfig.env !== 'prod') { const upstream = runtimeInstances.get(context.context); if (!upstream) { // Fallback to useRuntimeInstance if not found // eslint-disable-next-line react-hooks/rules-of-hooks const fallbackRuntime = useRuntimeInstance(entry.context.context, baseConfig); runtimeInstances.set(context.context, fallbackRuntime); } } if (configFn) { const proxyArg = new Proxy({}, { get(_, prop) { if (prop === 'configure') return factory; if (prop === 'runtime') return factory(); throw new Error(invalidDestructure(name, prop)); }, }); const currentProps = Object.assign({}, mergedFromConfigs, entry.level === 0 ? props : {}); const propsProxy = new Proxy(currentProps, { get(target, prop) { const value = target[prop]; if (!(prop in currentProps)) { console.warn(noUpstreamMessage(name, prop)); } return value; }, }); const maybeProps = configFn(proxyArg, propsProxy); if (entry.level === 0 && maybeProps) { Object.assign(mergedFromConfigs, maybeProps); } } else if (type === 'runtime') { factory(); // const instance = factory(); // runtimeInstances.set(context.context, instance.runtime); } }); const mergedProps = Object.assign(mergedFromConfigs, props); const children = createElement(target, mergedProps) ?? props.children ?? null; return entries .filter((item) => item.type === 'runtime') .reduceRight((acc, { context: { context: Context } }) => { const value = upstreamContexts.get(Context); if (value) return acc; return (jsxRuntime.jsx(Context.Provider, { value: runtimeInstances.get(Context), children: acc })); }, children); }; const meta = extractMeta(Component); const Memo = React__namespace.memo(Wrapper); Memo.displayName = getDisplayName(Component, name); copyStaticProperties(meta, Memo); hoistOriginalComponent(Memo, target); hoistUpdatedRegistry(Memo, registry.concat(entry)); return Memo; }; } return hoc; }; function noUpstreamMessage(name, prop) { return `[${name}] "${String(prop)}" is undefined, because components are not rendered upstream in portable scenarios. This may cause inconsistent behavior.`; } function invalidDestructure(name, prop) { return `[${name}] Invalid destructure "${String(prop)}". Use "runtime" or "configure".`; } const withRuntimeImpl = hocFactory('runtime', 'withRuntime'); // export function withRuntime<TTarget, C extends React.FC<any>>( // Context: RuntimeContextReference<TTarget>, // getSource?: ( // api: { // configure: (config?: Partial<Config>) => RuntimeApi<TTarget>; // runtime: RuntimeApi<TTarget>; // }, // props: Simplify<Partial<React.ComponentProps<C>>> // ) => void // ): ( // Component: C // ) => React.FC<Simplify<React.ComponentProps<C>>> & Simplify<ExtractMeta<C>>; /** * Injects a **local runtime** into the wrapped component. * * This HOC: * - Instantiates the runtime **locally at the leaf**, if it doesn't exist upstream * - Injects runtime hooks (`use`, `useFn`, `useRun`) and provides values as props * - Ensures proper lifecycle management and disposal based on the config * - Merges props returned from the `getSource` function into the component * - Automatically deduplicates and lifts runtime providers to where they're needed * * @template TProps Props returned from the `getSource` function * @template C The original React component * @template TContext A branded runtime context reference * @template R The effect runtime environment type * * @param Context A runtime context reference with a `.context` and `.reference()` method * @param getSource A function that receives runtime API + configure and returns props * @returns A higher-order component that wraps `C`, injects props, and manages runtime * * @example * ```tsx * export const Child = pipe( * ChildView, * withRuntime(UserRuntime, ({ configure }) => { * const user = configure().runtime.use(UserTags.CurrentUser); * return { user }; * }) * ); * ``` */ function withRuntime(Context, getSource) { return withRuntimeImpl(Context, getSource); } const withUpstreamImpl = hocFactory('upstream', 'withUpstream'); function withUpstream(Context, getSource) { return withUpstreamImpl(Context, getSource); } // eslint-disable-next-line @typescript-eslint/no-explicit-any function withStatic(staticProperties) { return (Component) => { copyStaticProperties(staticProperties, Component); return Component; }; } const createRuntimeContext2 = // eslint-disable-next-line @typescript-eslint/no-explicit-any (fn) => (layer) => { const context = React__namespace.createContext(undefined); return { context, layer, ...fn(layer), }; }; const createRuntimeContext = (config) => (layer) => { const reactCtx = React__namespace.createContext(undefined); const context = Object.assign(reactCtx, { layer, config, }); return context; }; const fromLayer = (layer, cb = effect.identity) => effect.pipe(layer, effect.Effect.andThen(cb)); exports.COMPONENT_PROP = COMPONENT_PROP; exports.PROPS_PROP = PROPS_PROP; exports.RUNTIME_PROP = RUNTIME_PROP; exports.UPSTREAM_PROP = UPSTREAM_PROP; exports.copyStaticProperties = copyStaticProperties; exports.createElement = createElement; exports.createRuntimeContext = createRuntimeContext; exports.createRuntimeContext2 = createRuntimeContext2; exports.extractMeta = extractMeta; exports.fromLayer = fromLayer; exports.getDisplayName = getDisplayName; exports.isReactContext = isReactContext; exports.isReactContext2 = isReactContext2; exports.withRuntime = withRuntime; exports.withStatic = withStatic; exports.withUpstream = withUpstream; //# sourceMappingURL=index.cjs.js.map