@vladimirdev635/gql-client-react 0.0.1

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/.npmignore ADDED
@@ -0,0 +1 @@
1
+ tests
package/context.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { ReactNode } from 'react';
2
+ import { Executor, RequestContext } from './types.js';
3
+ export declare function createProviderAndHook<TRequestContext extends RequestContext>(): {
4
+ useGQLExecutor: () => Executor<TRequestContext>;
5
+ GQLExecutorProvider: ({ children, executor }: {
6
+ children: ReactNode;
7
+ executor: Executor<TRequestContext>;
8
+ }) => import("react").JSX.Element;
9
+ };
package/context.jsx ADDED
@@ -0,0 +1,16 @@
1
+ import { createContext, useContext } from 'react';
2
+ export function createProviderAndHook() {
3
+ const context = createContext(undefined);
4
+ function Provider({ children, executor }) {
5
+ return (<context.Provider value={executor}>
6
+ {children}
7
+ </context.Provider>);
8
+ }
9
+ function useExecutor() {
10
+ return useContext(context);
11
+ }
12
+ return {
13
+ useGQLExecutor: useExecutor,
14
+ GQLExecutorProvider: Provider
15
+ };
16
+ }
package/index.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export { createProviderAndHook } from './context.jsx';
2
+ export { type OperationLoadingState, type OperationSuccessState, type OperationFailureState, type OperationState, loadingState, useOperation, } from './useOperation.jsx';
3
+ export { LazyOperationInitialState, LazyOperationState, lazyInitialState, useLazyOperation } from './useLazyOperation.jsx';
package/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { createProviderAndHook } from './context.jsx';
2
+ export { loadingState, useOperation, } from './useOperation.jsx';
3
+ export { lazyInitialState, useLazyOperation } from './useLazyOperation.jsx';
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@vladimirdev635/gql-client-react",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "main": "./index.js",
6
+ "types": "./index.d.ts",
7
+ "files": [
8
+ "./"
9
+ ],
10
+ "homepage": "https://github.com/Voldemat/graphql-plus-plus#readme",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/Voldemat/graphql-plus-plus.git"
14
+ },
15
+ "scripts": {
16
+ "lint": "eslint .",
17
+ "lint:fix": "eslint --fix .",
18
+ "lint:ci": "npm run lint",
19
+ "test": "vitest",
20
+ "build": "tsc && cp package.json .npmignore ./dist/"
21
+ },
22
+ "keywords": [],
23
+ "author": "",
24
+ "license": "ISC",
25
+ "description": "",
26
+ "devDependencies": {
27
+ "@eslint/compat": "^1.3.0",
28
+ "@testing-library/jest-dom": "^6.6.3",
29
+ "@testing-library/react": "^16.3.0",
30
+ "@testing-library/user-event": "^14.6.1",
31
+ "@types/node": "^24.0.1",
32
+ "@types/react": "^19.1.8",
33
+ "@typescript-eslint/eslint-plugin": "^8.34.0",
34
+ "@vitejs/plugin-react": "^4.6.0",
35
+ "eslint": "^9.28.0",
36
+ "jiti": "^2.4.2",
37
+ "jsdom": "^26.1.0",
38
+ "vitest": "^3.2.4"
39
+ },
40
+ "dependencies": {
41
+ "react": "^19.1.0",
42
+ "zod": "^4.0.5"
43
+ },
44
+ "optionalDependencies": {
45
+ "@rollup/rollup-linux-x64-gnu": "4.9.5"
46
+ }
47
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,49 @@
1
+ import { useLazyOperation } from '../useLazyOperation.jsx';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { renderHook, act } from '@testing-library/react';
4
+ import assert from 'assert';
5
+ import { testOperation } from './utils.js';
6
+ describe('useLazyOperation', () => {
7
+ it('Should preserve initial state if no one calls', async () => {
8
+ const { result } = renderHook(() => useLazyOperation({}, testOperation));
9
+ expect(result.current.state.state).toBe('initial');
10
+ await act(async () => { });
11
+ expect(result.current.state.state).toBe('initial');
12
+ });
13
+ it('Should return loading state after invoking, then success state', async () => {
14
+ const executor = async () => ({
15
+ result: { a: 1 },
16
+ response: new Response()
17
+ });
18
+ const { result } = renderHook(() => useLazyOperation(executor, testOperation));
19
+ let promise;
20
+ act(() => {
21
+ promise = result.current.execute({}, {});
22
+ });
23
+ expect(result.current.state.state).toBe('loading');
24
+ // @ts-expect-error 2454
25
+ const newState = await promise;
26
+ expect(newState.state).toBe('success');
27
+ assert(newState.state === 'success');
28
+ expect(newState.result).toStrictEqual({ a: 1 });
29
+ await act(async () => { });
30
+ expect(result.current.state).toStrictEqual(newState);
31
+ });
32
+ it('Should return loading state after invoking, then failure state', async () => {
33
+ const error = new Error('Network error');
34
+ const executor = async () => { throw error; };
35
+ const { result } = renderHook(() => useLazyOperation(executor, testOperation));
36
+ let promise;
37
+ act(() => {
38
+ promise = result.current.execute({}, {});
39
+ });
40
+ expect(result.current.state.state).toBe('loading');
41
+ // @ts-expect-error 2454
42
+ const newState = await promise;
43
+ expect(newState.state).toBe('failure');
44
+ assert(newState.state === 'failure');
45
+ expect(newState.error).toBe(error);
46
+ await act(async () => { });
47
+ expect(result.current.state).toStrictEqual(newState);
48
+ });
49
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,29 @@
1
+ import { useOperation } from '../useOperation.jsx';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { renderHook, act } from '@testing-library/react';
4
+ import assert from 'assert';
5
+ import { testOperation } from './utils.js';
6
+ describe('useOperation', () => {
7
+ it('Should return loading state and then success state', async () => {
8
+ const executor = async () => ({
9
+ result: { a: 1 },
10
+ response: new Response()
11
+ });
12
+ const { result } = renderHook(() => useOperation(executor, testOperation, {}, {}));
13
+ expect(result.current.state).toBe('loading');
14
+ await act(async () => { });
15
+ expect(result.current.state).toBe('success');
16
+ assert(result.current.state === 'success');
17
+ expect(result.current.result).toStrictEqual({ a: 1 });
18
+ });
19
+ it('Should return loading state and then failure state', async () => {
20
+ const error = new Error('Network error');
21
+ const executor = async () => { throw error; };
22
+ const { result } = renderHook(() => useOperation(executor, testOperation, {}, {}));
23
+ expect(result.current.state).toBe('loading');
24
+ await act(async () => { });
25
+ expect(result.current.state).toBe('failure');
26
+ assert(result.current.state === 'failure');
27
+ expect(result.current.error).toBe(error);
28
+ });
29
+ });
@@ -0,0 +1,8 @@
1
+ import { z } from 'zod/v4';
2
+ export declare const testOperation: {
3
+ readonly document: "";
4
+ readonly name: "";
5
+ readonly type: "QUERY";
6
+ readonly variablesSchema: z.ZodObject<{}, z.core.$strip>;
7
+ readonly resultSchema: z.ZodObject<{}, z.core.$strip>;
8
+ };
package/tests/utils.js ADDED
@@ -0,0 +1,8 @@
1
+ import { z } from 'zod/v4';
2
+ export const testOperation = {
3
+ document: '',
4
+ name: '',
5
+ type: 'QUERY',
6
+ variablesSchema: z.object({}),
7
+ resultSchema: z.object({})
8
+ };
package/types.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ import { z } from 'zod/v4';
2
+ export interface Operation {
3
+ name: string;
4
+ document: string;
5
+ type: 'QUERY' | 'MUTATION' | 'SUBSCRIPTION';
6
+ variablesSchema: z.ZodType;
7
+ resultSchema: z.ZodType;
8
+ }
9
+ export interface ExecuteResult<T extends Operation> {
10
+ result: z.infer<T['resultSchema']>;
11
+ response: Response;
12
+ }
13
+ export interface RequestContext {
14
+ fetchOptions?: RequestInit;
15
+ }
16
+ export type Executor<TRequestContext extends RequestContext> = <T extends Operation>(operation: T, variables: z.infer<T['variablesSchema']>, context: TRequestContext) => Promise<ExecuteResult<T>>;
package/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,17 @@
1
+ import { z } from 'zod/v4';
2
+ import { Executor, Operation, RequestContext } from './types.js';
3
+ import { OperationState } from './useOperation.jsx';
4
+ export interface LazyOperationInitialState {
5
+ state: 'initial';
6
+ }
7
+ export type LazyOperationState<T extends Operation> = OperationState<T> | LazyOperationInitialState;
8
+ export declare const lazyInitialState: Readonly<{
9
+ readonly state: "initial";
10
+ }>;
11
+ interface UseLazyOperationReturnType<T extends Operation, TRequestContext extends RequestContext> {
12
+ execute: (variables: z.infer<T['variablesSchema']>, requestContext: TRequestContext) => Promise<LazyOperationState<T>>;
13
+ state: LazyOperationState<T>;
14
+ reset: () => void;
15
+ }
16
+ export declare function useLazyOperation<T extends Operation, TRequestContext extends RequestContext>(executor: Executor<TRequestContext>, operation: T): UseLazyOperationReturnType<T, TRequestContext>;
17
+ export {};
@@ -0,0 +1,26 @@
1
+ import { loadingState } from './useOperation.jsx';
2
+ import { useState } from 'react';
3
+ export const lazyInitialState = Object.freeze({ state: 'initial' });
4
+ async function execute(executor, operation, variables, requestContext, setState) {
5
+ let newState;
6
+ try {
7
+ const result = await executor(operation, variables, requestContext);
8
+ newState = { state: 'success', ...result };
9
+ }
10
+ catch (error) {
11
+ newState = { state: 'failure', error: error };
12
+ }
13
+ setState(newState);
14
+ return newState;
15
+ }
16
+ export function useLazyOperation(executor, operation) {
17
+ const [state, setState] = useState(lazyInitialState);
18
+ return {
19
+ execute: (variables, requestContext) => {
20
+ setState(loadingState);
21
+ return execute(executor, operation, variables, requestContext, setState);
22
+ },
23
+ state,
24
+ reset: () => setState(lazyInitialState)
25
+ };
26
+ }
@@ -0,0 +1,17 @@
1
+ import { z } from 'zod/v4';
2
+ import { ExecuteResult, Executor, Operation, RequestContext } from './types.js';
3
+ export interface OperationLoadingState {
4
+ state: 'loading';
5
+ }
6
+ export interface OperationSuccessState<T extends Operation> extends ExecuteResult<T> {
7
+ state: 'success';
8
+ }
9
+ export interface OperationFailureState {
10
+ state: 'failure';
11
+ error: Error;
12
+ }
13
+ export type OperationState<T extends Operation> = OperationLoadingState | OperationSuccessState<T> | OperationFailureState;
14
+ export declare const loadingState: Readonly<{
15
+ readonly state: "loading";
16
+ }>;
17
+ export declare function useOperation<T extends Operation, TRequestContext extends RequestContext>(executor: Executor<TRequestContext>, operation: T, variables: z.infer<T['variablesSchema']>, requestContext: TRequestContext): OperationState<T>;
@@ -0,0 +1,12 @@
1
+ import { useEffect, useState } from 'react';
2
+ export const loadingState = Object.freeze({ state: 'loading' });
3
+ export function useOperation(executor, operation, variables, requestContext) {
4
+ const [state, setState] = useState(loadingState);
5
+ useEffect(() => {
6
+ executor(operation, variables, requestContext)
7
+ .then(result => setState({ state: 'success', ...result }))
8
+ .catch(error => setState({ state: 'failure', error }));
9
+ return () => setState(loadingState);
10
+ }, []);
11
+ return state;
12
+ }