import { createContext, useCallback, useContext, useMemo } from 'react'; import type { IServerInfo } from '../../../definition/IServerInfo'; import type { Serialized } from '../../../definition/Serialized'; import type { Method, PathFor, OperationParams, MatchPathPattern, OperationResult, PathPattern } from '../../../definition/rest'; import { ServerMethodFunction, ServerMethodName, ServerMethodParameters, ServerMethodReturn, ServerMethods } from './methods'; type ServerContextValue = { info?: IServerInfo; absoluteUrl: (path: string) => string; callMethod?: ( methodName: MethodName, ...args: ServerMethodParameters ) => Promise>; callEndpoint: >( method: TMethod, path: TPath, params: Serialized>>, ) => Promise>>>; uploadToEndpoint: (endpoint: string, params: any, formData: any) => Promise; getStream: (streamName: string, options?: {}) => (eventName: string, callback: (data: T) => void) => () => void; }; export const ServerContext = createContext({ info: undefined, absoluteUrl: (path) => path, callEndpoint: () => { throw new Error('not implemented'); }, uploadToEndpoint: async () => undefined, getStream: () => () => (): void => undefined, }); export const useServerInformation = (): IServerInfo => { const { info } = useContext(ServerContext); if (!info) { throw new Error('useServerInformation: no info available'); } return info; }; export const useAbsoluteUrl = (): ((path: string) => string) => useContext(ServerContext).absoluteUrl; export const useMethod = (methodName: MethodName): ServerMethodFunction => { const { callMethod } = useContext(ServerContext); return useCallback( (...args: ServerMethodParameters) => { if (!callMethod) { throw new Error(`cannot use useMethod(${methodName}) hook without a wrapping ServerContext`); } return callMethod(methodName, ...args); }, [callMethod, methodName], ); }; type EndpointFunction = ( params: void extends OperationParams ? void : Serialized>, ) => Promise>>; export const useEndpoint = >( method: TMethod, path: TPath, ): EndpointFunction> => { const { callEndpoint } = useContext(ServerContext); return useCallback((params) => callEndpoint(method, path, params), [callEndpoint, path, method]); }; export const useUpload = (endpoint: string): ((params: any, formData: any) => Promise) => { const { uploadToEndpoint } = useContext(ServerContext); return useCallback((params, formData: any) => uploadToEndpoint(endpoint, params, formData), [endpoint, uploadToEndpoint]); }; export const useStream = (streamName: string, options?: {}): ((eventName: string, callback: (data: T) => void) => () => void) => { const { getStream } = useContext(ServerContext); return useMemo(() => getStream(streamName, options), [getStream, streamName, options]); };