@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 +1 -0
- package/context.d.ts +9 -0
- package/context.jsx +16 -0
- package/index.d.ts +3 -0
- package/index.js +3 -0
- package/package.json +47 -0
- package/tests/useLazyOperation.spec.d.ts +1 -0
- package/tests/useLazyOperation.spec.js +49 -0
- package/tests/useOperation.spec.d.ts +1 -0
- package/tests/useOperation.spec.jsx +29 -0
- package/tests/utils.d.ts +8 -0
- package/tests/utils.js +8 -0
- package/types.d.ts +16 -0
- package/types.js +1 -0
- package/useLazyOperation.d.ts +17 -0
- package/useLazyOperation.jsx +26 -0
- package/useOperation.d.ts +17 -0
- package/useOperation.jsx +12 -0
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
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
|
+
});
|
package/tests/utils.d.ts
ADDED
package/tests/utils.js
ADDED
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>;
|
package/useOperation.jsx
ADDED
|
@@ -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
|
+
}
|