rdesign/frontend/node_modules/urql/dist/urql.js

765 lines
25 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Object.defineProperty(exports, '__esModule', { value: true });
var core = require('@urql/core');
var React = require('react');
var wonka = require('wonka');
var OBJ = {};
/** `urql`'s React Context.
*
* @remarks
* The React Context that `urql`s {@link Client} will be provided with.
* You may use the reexported {@link Provider} to provide a `Client` as well.
*/
var Context = React.createContext(OBJ);
/** Provider for `urql`'s {@link Client} to GraphQL hooks.
*
* @remarks
* `Provider` accepts a {@link Client} and provides it to all GraphQL hooks,
* and {@link useClient}.
*
* You should make sure to create a {@link Client} and provide it with the
* `Provider` to parts of your component tree that use GraphQL hooks.
*
* @example
* ```tsx
* import { Provider } from 'urql';
* // All of `@urql/core` is also re-exported by `urql`:
* import { Client, cacheExchange, fetchExchange } from '@urql/core';
*
* const client = new Client({
* url: 'https://API',
* exchanges: [cacheExchange, fetchExchange],
* });
*
* const App = () => (
* <Provider value={client}>
* <Component />
* </Provider>
* );
* ```
*/
var Provider = Context.Provider;
/** React Consumer component, providing the {@link Client} provided on a parent component.
* @remarks
* This is an alias for {@link Context.Consumer}.
*/
var Consumer = Context.Consumer;
Context.displayName = 'UrqlContext';
/** Hook returning a {@link Client} from {@link Context}.
*
* @remarks
* `useClient` is a convenience hook, which accesses `urql`'s {@link Context}
* and returns the {@link Client} defined on it.
*
* This will be the {@link Client} you passed to a {@link Provider}
* you wrapped your elements containing this hook with.
*
* @throws
* In development, if the component you call `useClient()` in is
* not wrapped in a {@link Provider}, an error is thrown.
*/
var useClient = () => {
var client = React.useContext(Context);
if (client === OBJ && process.env.NODE_ENV !== 'production') {
var error = "No client has been specified using urql's Provider. please create a client and add a Provider.";
console.error(error);
throw new Error(error);
}
return client;
};
var initialState = {
fetching: false,
stale: false,
hasNext: false,
error: undefined,
data: undefined,
extensions: undefined,
operation: undefined
};
// Two operations are considered equal if they have the same key
var areOperationsEqual = (a, b) => {
return a === b || !!(a && b && a.key === b.key);
};
/**
* Checks if two objects are shallowly different with a special case for
* 'operation' where it compares the key if they are not the otherwise equal
*/
var isShallowDifferent = (a, b) => {
for (var key in a) if (!(key in b)) return true;
for (var _key in b) {
if (_key === 'operation' ? !areOperationsEqual(a[_key], b[_key]) : a[_key] !== b[_key]) {
return true;
}
}
return false;
};
var computeNextState = (prevState, result) => {
var newState = {
...prevState,
...result,
data: result.data !== undefined || result.error ? result.data : prevState.data,
fetching: !!result.fetching,
stale: !!result.stale
};
return isShallowDifferent(prevState, newState) ? newState : prevState;
};
var hasDepsChanged = (a, b) => {
for (var i = 0, l = b.length; i < l; i++) if (a[i] !== b[i]) return true;
return false;
};
var reactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
function deferDispatch(setState, value) {
if (process.env.NODE_ENV !== 'production' && !!reactSharedInternals && !!reactSharedInternals.ReactCurrentOwner && !!reactSharedInternals.ReactCurrentOwner.current) {
Promise.resolve(value).then(setState);
} else {
setState(value);
}
}
/** State of the last mutation executed by your {@link useMutation} hook.
*
* @remarks
* `UseMutationState` is returned (in a tuple) by {@link useMutation} and
* gives you the {@link OperationResult} of the last mutation executed
* with {@link UseMutationExecute}.
*
* Even if the mutation document passed to {@link useMutation} changes,
* the state isnt reset, so you can keep displaying the previous result.
*/
/** Triggers {@link useMutation} to execute its GraphQL mutation operation.
*
* @param variables - variables using which the mutation will be executed.
* @param context - optionally, context options that will be merged with the hook's
* {@link UseQueryArgs.context} options and the `Client`s options.
* @returns the {@link OperationResult} of the mutation.
*
* @remarks
* When called, {@link useMutation} will start the GraphQL mutation
* it currently holds and use the `variables` passed to it.
*
* Once the mutation response comes back from the API, its
* returned promise will resolve to the mutations {@link OperationResult}
* and the {@link UseMutationState} will be updated with the result.
*
* @example
* ```ts
* const [result, executeMutation] = useMutation(UpdateTodo);
* const start = async ({ id, title }) => {
* const result = await executeMutation({ id, title });
* };
*/
/** Result tuple returned by the {@link useMutation} hook.
*
* @remarks
* Similarly to a `useState` hooks return value,
* the first element is the {@link useMutation}s state, updated
* as mutations are executed with the second value, which is
* used to start mutations and is a {@link UseMutationExecute}
* function.
*/
/** Hook to create a GraphQL mutation, run by passing variables to the returned execute function.
*
* @param query - a GraphQL mutation document which `useMutation` will execute.
* @returns a {@link UseMutationResponse} tuple of a {@link UseMutationState} result,
* and an execute function to start the mutation.
*
* @remarks
* `useMutation` allows GraphQL mutations to be defined and keeps its state
* after the mutation is started with the returned execute function.
*
* Given a GraphQL mutation document it returns state to keep track of the
* mutation state and a {@link UseMutationExecute} function, which accepts
* variables for the mutation to be executed.
* Once called, the mutation executes and the state will be updated with
* the mutations result.
*
* @see {@link https://urql.dev/goto/urql/docs/basics/react-preact/#mutations} for `useMutation` docs.
*
* @example
* ```ts
* import { gql, useMutation } from 'urql';
*
* const UpdateTodo = gql`
* mutation ($id: ID!, $title: String!) {
* updateTodo(id: $id, title: $title) {
* id, title
* }
* }
* `;
*
* const UpdateTodo = () => {
* const [result, executeMutation] = useMutation(UpdateTodo);
* const start = async ({ id, title }) => {
* const result = await executeMutation({ id, title });
* };
* // ...
* };
* ```
*/
function useMutation(query) {
var isMounted = React.useRef(true);
var client = useClient();
var [state, setState] = React.useState(initialState);
var executeMutation = React.useCallback((variables, context) => {
deferDispatch(setState, {
...initialState,
fetching: true
});
return wonka.toPromise(wonka.take(1)(wonka.filter(result => !result.hasNext)(wonka.onPush(result => {
if (isMounted.current) {
deferDispatch(setState, {
fetching: false,
stale: result.stale,
data: result.data,
error: result.error,
extensions: result.extensions,
operation: result.operation,
hasNext: result.hasNext
});
}
})(client.executeMutation(core.createRequest(query, variables), context || {})))));
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[client, query, setState]);
React.useEffect(() => {
isMounted.current = true;
return () => {
isMounted.current = false;
};
}, []);
return [state, executeMutation];
}
/** Creates a request from a query and variables but preserves reference equality if the key isn't changing
* @internal
*/
function useRequest(query, variables) {
var prev = React.useRef(undefined);
return React.useMemo(() => {
var request = core.createRequest(query, variables);
// We manually ensure reference equality if the key hasn't changed
if (prev.current !== undefined && prev.current.key === request.key) {
return prev.current;
} else {
prev.current = request;
return request;
}
}, [query, variables]);
}
var getCacheForClient = client => {
if (!client._react) {
var reclaim = new Set();
var map = new Map();
if (client.operations$ /* not available in mocks */) {
wonka.subscribe(operation => {
if (operation.kind === 'teardown' && reclaim.has(operation.key)) {
reclaim.delete(operation.key);
map.delete(operation.key);
}
})(client.operations$);
}
client._react = {
get(key) {
return map.get(key);
},
set(key, value) {
reclaim.delete(key);
map.set(key, value);
},
dispose(key) {
reclaim.add(key);
}
};
}
return client._react;
};
/* eslint-disable react-hooks/exhaustive-deps */
/** Input arguments for the {@link useQuery} hook.
*
* @param query - The GraphQL query that `useQuery` executes.
* @param variables - The variables for the GraphQL query that `useQuery` executes.
*/
/** State of the current query, your {@link useQuery} hook is executing.
*
* @remarks
* `UseQueryState` is returned (in a tuple) by {@link useQuery} and
* gives you the updating {@link OperationResult} of GraphQL queries.
*
* Even when the query and variables passed to {@link useQuery} change,
* this state preserves the prior state and sets the `fetching` flag to
* `true`.
* This allows you to display the previous state, while implementing
* a separate loading indicator separately.
*/
/** Triggers {@link useQuery} to execute a new GraphQL query operation.
*
* @param opts - optionally, context options that will be merged with the hook's
* {@link UseQueryArgs.context} options and the `Client`s options.
*
* @remarks
* When called, {@link useQuery} will re-execute the GraphQL query operation
* it currently holds, even if {@link UseQueryArgs.pause} is set to `true`.
*
* This is useful for executing a paused query or re-executing a query
* and get a new network result, by passing a new request policy.
*
* ```ts
* const [result, reexecuteQuery] = useQuery({ query });
*
* const refresh = () => {
* // Re-execute the query with a network-only policy, skipping the cache
* reexecuteQuery({ requestPolicy: 'network-only' });
* };
* ```
*/
/** Result tuple returned by the {@link useQuery} hook.
*
* @remarks
* Similarly to a `useState` hooks return value,
* the first element is the {@link useQuery}s result and state,
* a {@link UseQueryState} object,
* and the second is used to imperatively re-execute the query
* via a {@link UseQueryExecute} function.
*/
var isSuspense = (client, context) => context && context.suspense !== undefined ? !!context.suspense : client.suspense;
/** Hook to run a GraphQL query and get updated GraphQL results.
*
* @param args - a {@link UseQueryArgs} object, to pass a `query`, `variables`, and options.
* @returns a {@link UseQueryResponse} tuple of a {@link UseQueryState} result, and re-execute function.
*
* @remarks
* `useQuery` allows GraphQL queries to be defined and executed.
* Given {@link UseQueryArgs.query}, it executes the GraphQL query with the
* contexts {@link Client}.
*
* The returned result updates when the `Client` has new results
* for the query, and changes when your input `args` change.
*
* Additionally, if the `suspense` option is enabled on the `Client`,
* the `useQuery` hook will suspend instead of indicating that its
* waiting for a result via {@link UseQueryState.fetching}.
*
* @see {@link https://urql.dev/goto/urql/docs/basics/react-preact/#queries} for `useQuery` docs.
*
* @example
* ```ts
* import { gql, useQuery } from 'urql';
*
* const TodosQuery = gql`
* query { todos { id, title } }
* `;
*
* const Todos = () => {
* const [result, reexecuteQuery] = useQuery({
* query: TodosQuery,
* variables: {},
* });
* // ...
* };
* ```
*/
function useQuery(args) {
var client = useClient();
var cache = getCacheForClient(client);
var suspense = isSuspense(client, args.context);
var request = useRequest(args.query, args.variables);
var source = React.useMemo(() => {
if (args.pause) return null;
var source = client.executeQuery(request, {
requestPolicy: args.requestPolicy,
...args.context
});
return suspense ? wonka.onPush(result => {
cache.set(request.key, result);
})(source) : source;
}, [cache, client, request, suspense, args.pause, args.requestPolicy, args.context]);
var getSnapshot = React.useCallback((source, suspense) => {
if (!source) return {
fetching: false
};
var result = cache.get(request.key);
if (!result) {
var resolve;
var subscription = wonka.subscribe(_result => {
result = _result;
if (resolve) resolve(result);
})(wonka.takeWhile(() => suspense && !resolve || !result || 'hasNext' in result && result.hasNext)(source));
if (result == null && suspense) {
var promise = new Promise(_resolve => {
resolve = _resolve;
});
cache.set(request.key, promise);
throw promise;
} else {
subscription.unsubscribe();
}
} else if (suspense && result != null && 'then' in result) {
throw result;
}
return result || {
fetching: true
};
}, [cache, request]);
var deps = [client, request, args.requestPolicy, args.context, args.pause];
var [state, setState] = React.useState(() => [source, computeNextState(initialState, getSnapshot(source, suspense)), deps]);
var currentResult = state[1];
if (source !== state[0] && hasDepsChanged(state[2], deps)) {
setState([source, currentResult = computeNextState(state[1], getSnapshot(source, suspense)), deps]);
}
React.useEffect(() => {
var source = state[0];
var request = state[2][1];
var hasResult = false;
var updateResult = result => {
hasResult = true;
deferDispatch(setState, state => {
var nextResult = computeNextState(state[1], result);
return state[1] !== nextResult ? [state[0], nextResult, state[2]] : state;
});
};
if (source) {
var subscription = wonka.subscribe(updateResult)(wonka.onEnd(() => {
updateResult({
fetching: false
});
})(source));
if (!hasResult) updateResult({
fetching: true
});
return () => {
cache.dispose(request.key);
subscription.unsubscribe();
};
} else {
updateResult({
fetching: false
});
}
}, [cache, state[0], state[2][1]]);
var executeQuery = React.useCallback(opts => {
var context = {
requestPolicy: args.requestPolicy,
...args.context,
...opts
};
deferDispatch(setState, state => {
var source = suspense ? wonka.onPush(result => {
cache.set(request.key, result);
})(client.executeQuery(request, context)) : client.executeQuery(request, context);
return [source, state[1], deps];
});
}, [client, cache, request, suspense, args.requestPolicy, args.context, args.pause]);
return [currentResult, executeQuery];
}
/* eslint-disable react-hooks/exhaustive-deps */
/** Input arguments for the {@link useSubscription} hook.
*
* @param query - The GraphQL subscription document that `useSubscription` executes.
* @param variables - The variables for the GraphQL subscription that `useSubscription` executes.
*/
/** Combines previous data with an incoming subscription results data.
*
* @remarks
* A `SubscriptionHandler` may be passed to {@link useSubscription} to
* aggregate subscription results into a combined {@link UseSubscriptionState.data}
* value.
*
* This is useful when a subscription event delivers a single item, while
* youd like to display a list of events.
*
* @example
* ```ts
* const NotificationsSubscription = gql`
* subscription { newNotification { id, text } }
* `;
*
* const combineNotifications = (notifications = [], data) => {
* return [...notifications, data.newNotification];
* };
*
* const [result, executeSubscription] = useSubscription(
* { query: NotificationsSubscription },
* combineNotifications,
* );
* ```
*/
/** State of the current subscription, your {@link useSubscription} hook is executing.
*
* @remarks
* `UseSubscriptionState` is returned (in a tuple) by {@link useSubscription} and
* gives you the updating {@link OperationResult} of GraphQL subscriptions.
*
* If a {@link SubscriptionHandler} has been passed to `useSubscription` then
* {@link UseSubscriptionState.data} is instead the updated data as returned
* by the handler, otherwise its the latest results data.
*
* Hint: Even when the query and variables passed to {@link useSubscription} change,
* this state preserves the prior state.
*/
/** Triggers {@link useSubscription} to reexecute a GraphQL subscription operation.
*
* @param opts - optionally, context options that will be merged with the hook's
* {@link UseSubscriptionArgs.context} options and the `Client`s options.
*
* @remarks
* When called, {@link useSubscription} will restart the GraphQL subscription
* operation it currently holds. If {@link UseSubscriptionArgs.pause} is set
* to `true`, it will start executing the subscription.
*
* ```ts
* const [result, executeSubscription] = useSubscription({
* query,
* pause: true,
* });
*
* const start = () => {
* executeSubscription();
* };
* ```
*/
/** Result tuple returned by the {@link useSubscription} hook.
*
* @remarks
* Similarly to a `useState` hooks return value,
* the first element is the {@link useSubscription}s state,
* a {@link UseSubscriptionState} object,
* and the second is used to imperatively re-execute or start the subscription
* via a {@link UseMutationExecute} function.
*/
/** Hook to run a GraphQL subscription and get updated GraphQL results.
*
* @param args - a {@link UseSubscriptionArgs} object, to pass a `query`, `variables`, and options.
* @param handler - optionally, a {@link SubscriptionHandler} function to combine multiple subscription results.
* @returns a {@link UseSubscriptionResponse} tuple of a {@link UseSubscriptionState} result, and an execute function.
*
* @remarks
* `useSubscription` allows GraphQL subscriptions to be defined and executed.
* Given {@link UseSubscriptionArgs.query}, it executes the GraphQL subscription with the
* contexts {@link Client}.
*
* The returned result updates when the `Client` has new results
* for the subscription, and `data` is updated with the results data
* or with the `data` that a `handler` returns.
*
* @example
* ```ts
* import { gql, useSubscription } from 'urql';
*
* const NotificationsSubscription = gql`
* subscription { newNotification { id, text } }
* `;
*
* const combineNotifications = (notifications = [], data) => {
* return [...notifications, data.newNotification];
* };
*
* const Notifications = () => {
* const [result, executeSubscription] = useSubscription(
* { query: NotificationsSubscription },
* combineNotifications,
* );
* // ...
* };
* ```
*/
function useSubscription(args, handler) {
var client = useClient();
var request = useRequest(args.query, args.variables);
var handlerRef = React.useRef(handler);
handlerRef.current = handler;
var source = React.useMemo(() => !args.pause ? client.executeSubscription(request, args.context) : null, [client, request, args.pause, args.context]);
var deps = [client, request, args.context, args.pause];
var [state, setState] = React.useState(() => [source, {
...initialState,
fetching: !!source
}, deps]);
var currentResult = state[1];
if (source !== state[0] && hasDepsChanged(state[2], deps)) {
setState([source, currentResult = computeNextState(state[1], {
fetching: !!source
}), deps]);
}
React.useEffect(() => {
var updateResult = result => {
deferDispatch(setState, state => {
var nextResult = computeNextState(state[1], result);
if (state[1] === nextResult) return state;
if (handlerRef.current && nextResult.data != null && state[1].data !== nextResult.data) {
nextResult.data = handlerRef.current(state[1].data, nextResult.data);
}
return [state[0], nextResult, state[2]];
});
};
if (state[0]) {
return wonka.subscribe(updateResult)(wonka.onEnd(() => {
updateResult({
fetching: !!source
});
})(state[0])).unsubscribe;
} else {
updateResult({
fetching: false
});
}
}, [state[0]]);
// This is the imperative execute function passed to the user
var executeSubscription = React.useCallback(opts => {
var source = client.executeSubscription(request, {
...args.context,
...opts
});
deferDispatch(setState, state => [source, state[1], deps]);
}, [client, request, args.context, args.pause]);
return [currentResult, executeSubscription];
}
/** Props accepted by {@link Mutation}.
*
* @remarks
* `MutationProps` are the props accepted by the {@link Mutation} component.
*
* The result, the {@link MutationState} object, will be passed to
* a {@link MutationProps.children} function, passed as children
* to the `Mutation` component.
*/
/** Object that {@link MutationProps.children} is called with.
*
* @remarks
* This is an extented {@link UseMutationstate} with an added
* {@link MutationState.executeMutation} method, which is usually
* part of a tuple returned by {@link useMutation}.
*/
/** Component Wrapper around {@link useMutation} to run a GraphQL query.
*
* @remarks
* `Mutation` is a component wrapper around the {@link useMutation} hook
* that calls the {@link MutationProps.children} prop, as a function,
* with the {@link MutationState} object.
*/
function Mutation(props) {
var mutation = useMutation(props.query);
return props.children({
...mutation[0],
executeMutation: mutation[1]
});
}
/** Props accepted by {@link Query}.
*
* @remarks
* `QueryProps` are the props accepted by the {@link Query} component,
* which is identical to {@link UseQueryArgs}.
*
* The result, the {@link QueryState} object, will be passed to
* a {@link QueryProps.children} function, passed as children
* to the `Query` component.
*/
/** Object that {@link QueryProps.children} is called with.
*
* @remarks
* This is an extented {@link UseQueryState} with an added
* {@link QueryState.executeQuery} method, which is usually
* part of a tuple returned by {@link useQuery}.
*/
/** Component Wrapper around {@link useQuery} to run a GraphQL query.
*
* @remarks
* `Query` is a component wrapper around the {@link useQuery} hook
* that calls the {@link QueryProps.children} prop, as a function,
* with the {@link QueryState} object.
*/
function Query(props) {
var query = useQuery(props);
return props.children({
...query[0],
executeQuery: query[1]
});
}
/** Props accepted by {@link Subscription}.
*
* @remarks
* `SubscriptionProps` are the props accepted by the {@link Subscription} component,
* which is identical to {@link UseSubscriptionArgs} with an added
* {@link SubscriptionProps.handler} prop, which {@link useSubscription} usually
* accepts as an additional argument.
*
* The result, the {@link SubscriptionState} object, will be passed to
* a {@link SubscriptionProps.children} function, passed as children
* to the `Subscription` component.
*/
/** Object that {@link SubscriptionProps.children} is called with.
*
* @remarks
* This is an extented {@link UseSubscriptionState} with an added
* {@link SubscriptionState.executeSubscription} method, which is usually
* part of a tuple returned by {@link useSubscription}.
*/
/** Component Wrapper around {@link useSubscription} to run a GraphQL subscription.
*
* @remarks
* `Subscription` is a component wrapper around the {@link useSubscription} hook
* that calls the {@link SubscriptionProps.children} prop, as a function,
* with the {@link SubscriptionState} object.
*/
function Subscription(props) {
var subscription = useSubscription(props, props.handler);
return props.children({
...subscription[0],
executeSubscription: subscription[1]
});
}
exports.Consumer = Consumer;
exports.Context = Context;
exports.Mutation = Mutation;
exports.Provider = Provider;
exports.Query = Query;
exports.Subscription = Subscription;
exports.useClient = useClient;
exports.useMutation = useMutation;
exports.useQuery = useQuery;
exports.useSubscription = useSubscription;
Object.keys(core).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
enumerable: true,
get: function () { return core[k]; }
});
});
//# sourceMappingURL=urql.js.map