@mearie/react 0.0.1-next.3 → 0.0.1-next.5

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/README.md CHANGED
@@ -2,34 +2,48 @@
2
2
 
3
3
  React bindings for Mearie GraphQL client.
4
4
 
5
- This package provides React hooks and components for using Mearie in React
6
- applications.
5
+ This package provides React hooks, components, and the GraphQL client runtime
6
+ for using Mearie in React applications.
7
7
 
8
8
  ## Installation
9
9
 
10
10
  ```bash
11
- npm install mearie @mearie/react
11
+ npm install -D mearie
12
+ npm install @mearie/react
12
13
  ```
13
14
 
15
+ The `mearie` package provides build-time code generation, while `@mearie/react`
16
+ includes the runtime client and React-specific hooks.
17
+
14
18
  ## Usage
15
19
 
20
+ First, create a client and wrap your app with the provider:
21
+
16
22
  ```tsx
17
- import { createClient, httpLink, cacheLink, graphql } from 'mearie';
18
- import { ClientProvider, useQuery } from '@mearie/react';
23
+ // src/App.tsx
24
+ import { createClient, httpLink, cacheLink, ClientProvider } from '@mearie/react';
19
25
 
20
26
  const client = createClient({
21
27
  links: [cacheLink(), httpLink({ url: 'https://api.example.com/graphql' })],
22
28
  });
23
29
 
24
30
  function App() {
25
- return (
26
- <ClientProvider client={client}>
27
- <UserProfile userId="1" />
28
- </ClientProvider>
29
- );
31
+ return <ClientProvider client={client}>{/* Your app components */}</ClientProvider>;
32
+ }
33
+ ```
34
+
35
+ Then use it in your components:
36
+
37
+ ```tsx
38
+ // src/components/UserProfile.tsx
39
+ import { graphql } from '$mearie';
40
+ import { useQuery } from '@mearie/react';
41
+
42
+ interface UserProfileProps {
43
+ userId: string;
30
44
  }
31
45
 
32
- function UserProfile({ userId }: { userId: string }) {
46
+ function UserProfile({ userId }: UserProfileProps) {
33
47
  const { data, loading } = useQuery(
34
48
  graphql(`
35
49
  query GetUser($id: ID!) {
package/dist/index.cjs CHANGED
@@ -21,10 +21,14 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
21
21
  }) : target, mod));
22
22
 
23
23
  //#endregion
24
+ let __mearie_core = require("@mearie/core");
25
+ __mearie_core = __toESM(__mearie_core);
24
26
  let react = require("react");
25
27
  react = __toESM(react);
26
28
  let react_jsx_runtime = require("react/jsx-runtime");
27
29
  react_jsx_runtime = __toESM(react_jsx_runtime);
30
+ let __mearie_core_stream = require("@mearie/core/stream");
31
+ __mearie_core_stream = __toESM(__mearie_core_stream);
28
32
 
29
33
  //#region src/client-provider.tsx
30
34
  const ClientContext = (0, react.createContext)(null);
@@ -42,39 +46,164 @@ const useClient = () => {
42
46
 
43
47
  //#endregion
44
48
  //#region src/use-query.ts
45
- const useQuery = (document, variables) => {
49
+ const useQuery = (query, ...[variables, options]) => {
50
+ const client = useClient();
51
+ const [data, setData] = (0, react.useState)();
52
+ const [loading, setLoading] = (0, react.useState)(!options?.skip);
53
+ const [error, setError] = (0, react.useState)();
54
+ const unsubscribe = (0, react.useRef)(null);
55
+ const stableVariables = (0, react.useMemo)(() => (0, __mearie_core.stringify)(variables), [variables]);
56
+ const stableOptions = (0, react.useMemo)(() => options, [options?.skip]);
57
+ const execute = (0, react.useCallback)(() => {
58
+ unsubscribe.current?.();
59
+ if (stableOptions?.skip) return;
60
+ setLoading(true);
61
+ setError(void 0);
62
+ unsubscribe.current = (0, __mearie_core_stream.pipe)(client.executeQuery(query, variables, stableOptions), (0, __mearie_core_stream.subscribe)({ next: (result) => {
63
+ if (result.errors && result.errors.length > 0) {
64
+ setError(new __mearie_core.AggregatedError(result.errors));
65
+ setLoading(false);
66
+ } else {
67
+ setData(result.data);
68
+ setLoading(false);
69
+ setError(void 0);
70
+ }
71
+ } }));
72
+ }, [
73
+ client,
74
+ query,
75
+ stableVariables,
76
+ stableOptions
77
+ ]);
78
+ (0, react.useEffect)(() => {
79
+ execute();
80
+ return () => unsubscribe.current?.();
81
+ }, [execute]);
46
82
  return {
47
- data: void 0,
48
- loading: true,
49
- error: void 0,
50
- refetch: () => {}
83
+ data,
84
+ loading,
85
+ error,
86
+ refetch: execute
51
87
  };
52
88
  };
53
89
 
54
90
  //#endregion
55
91
  //#region src/use-subscription.ts
56
- const useSubscription = (document, variables, options) => {
92
+ const useSubscription = (subscription, ...[variables, options]) => {
93
+ const client = useClient();
94
+ const [data, setData] = (0, react.useState)();
95
+ const [loading, setLoading] = (0, react.useState)(!options?.skip);
96
+ const [error, setError] = (0, react.useState)();
97
+ const unsubscribe = (0, react.useRef)(null);
98
+ const stableVariables = (0, react.useMemo)(() => (0, __mearie_core.stringify)(variables), [variables]);
99
+ const stableOptions = (0, react.useMemo)(() => options, [
100
+ options?.skip,
101
+ options?.onData,
102
+ options?.onError
103
+ ]);
104
+ const execute = (0, react.useCallback)(() => {
105
+ unsubscribe.current?.();
106
+ if (stableOptions?.skip) return;
107
+ setLoading(true);
108
+ setError(void 0);
109
+ unsubscribe.current = (0, __mearie_core_stream.pipe)(client.executeSubscription(subscription, variables, stableOptions), (0, __mearie_core_stream.subscribe)({ next: (result) => {
110
+ if (result.errors && result.errors.length > 0) {
111
+ const err = new __mearie_core.AggregatedError(result.errors);
112
+ setError(err);
113
+ setLoading(false);
114
+ stableOptions?.onError?.(err);
115
+ } else {
116
+ const resultData = result.data;
117
+ setData(resultData);
118
+ setLoading(false);
119
+ setError(void 0);
120
+ stableOptions?.onData?.(resultData);
121
+ }
122
+ } }));
123
+ }, [
124
+ client,
125
+ subscription,
126
+ stableVariables,
127
+ stableOptions
128
+ ]);
129
+ (0, react.useEffect)(() => {
130
+ execute();
131
+ return () => unsubscribe.current?.();
132
+ }, [execute]);
57
133
  return {
58
- data: void 0,
59
- loading: true,
60
- error: void 0
134
+ data,
135
+ loading,
136
+ error
61
137
  };
62
138
  };
63
139
 
64
140
  //#endregion
65
141
  //#region src/use-mutation.ts
66
- const useMutation = (document) => {
67
- return [async () => ({}), {
68
- data: void 0,
69
- loading: false,
70
- error: void 0
142
+ const useMutation = (mutation) => {
143
+ const client = useClient();
144
+ const [data, setData] = (0, react.useState)();
145
+ const [loading, setLoading] = (0, react.useState)(false);
146
+ const [error, setError] = (0, react.useState)();
147
+ return [(0, react.useCallback)(async (variables, options) => {
148
+ setLoading(true);
149
+ setError(void 0);
150
+ try {
151
+ const result = await (0, __mearie_core_stream.pipe)(client.executeMutation(mutation, variables, options), __mearie_core_stream.collect);
152
+ if (result.errors && result.errors.length > 0) {
153
+ const err = new __mearie_core.AggregatedError(result.errors);
154
+ setError(err);
155
+ setLoading(false);
156
+ throw err;
157
+ }
158
+ setData(result.data);
159
+ setLoading(false);
160
+ return result.data;
161
+ } catch (err) {
162
+ if (err instanceof __mearie_core.AggregatedError) setError(err);
163
+ setLoading(false);
164
+ throw err;
165
+ }
166
+ }, [client, mutation]), {
167
+ data,
168
+ loading,
169
+ error
71
170
  }];
72
171
  };
73
172
 
74
173
  //#endregion
75
174
  //#region src/use-fragment.ts
76
- const useFragment = (document, fragmentRef) => {
77
- return {};
175
+ const useFragment = (fragment, fragmentRef, options) => {
176
+ const client = useClient();
177
+ const dataRef = (0, react.useRef)(void 0);
178
+ const subscribe_ = (0, react.useCallback)((onChange) => {
179
+ return (0, __mearie_core_stream.pipe)(client.executeFragment(fragment, fragmentRef, options), (0, __mearie_core_stream.subscribe)({ next: (result) => {
180
+ if (result.errors && result.errors.length > 0) throw new __mearie_core.AggregatedError(result.errors);
181
+ dataRef.current = result.data;
182
+ onChange();
183
+ } }));
184
+ }, [
185
+ client,
186
+ fragment,
187
+ fragmentRef,
188
+ options
189
+ ]);
190
+ const snapshot = (0, react.useCallback)(() => {
191
+ if (dataRef.current === void 0) {
192
+ const result = (0, __mearie_core_stream.pipe)(client.executeFragment(fragment, fragmentRef, options), __mearie_core_stream.peek);
193
+ if (result.errors && result.errors.length > 0) throw new __mearie_core.AggregatedError(result.errors);
194
+ dataRef.current = result.data;
195
+ }
196
+ return dataRef.current;
197
+ }, [
198
+ client,
199
+ fragment,
200
+ fragmentRef,
201
+ options
202
+ ]);
203
+ const data = (0, react.useSyncExternalStore)(subscribe_, snapshot, snapshot);
204
+ return { get data() {
205
+ return data;
206
+ } };
78
207
  };
79
208
 
80
209
  //#endregion
@@ -83,4 +212,10 @@ exports.useClient = useClient;
83
212
  exports.useFragment = useFragment;
84
213
  exports.useMutation = useMutation;
85
214
  exports.useQuery = useQuery;
86
- exports.useSubscription = useSubscription;
215
+ exports.useSubscription = useSubscription;
216
+ Object.keys(__mearie_core).forEach(function (k) {
217
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
218
+ enumerable: true,
219
+ get: function () { return __mearie_core[k]; }
220
+ });
221
+ });
package/dist/index.d.cts CHANGED
@@ -1,75 +1,84 @@
1
+ import { AggregatedError, Artifact, Client, DataOf, FragmentOptions, FragmentRefs, MutationOptions, QueryOptions, SchemaMeta, SubscriptionOptions, VariablesOf } from "@mearie/core";
1
2
  import { ReactNode } from "react";
2
- import { Client, DataOf, DocumentNode, FragmentRef, VariablesOf } from "@mearie/core";
3
+ export * from "@mearie/core";
3
4
 
4
5
  //#region src/client-provider.d.ts
5
- type ClientProviderProps = {
6
- client: Client;
6
+ type ClientProviderProps<TMeta extends SchemaMeta = SchemaMeta> = {
7
+ client: Client<TMeta>;
7
8
  children: ReactNode;
8
9
  };
9
- declare const ClientProvider: ({
10
+ declare const ClientProvider: <TMeta extends SchemaMeta = SchemaMeta>({
10
11
  client,
11
12
  children
12
- }: ClientProviderProps) => ReactNode;
13
- declare const useClient: () => Client;
13
+ }: ClientProviderProps<TMeta>) => ReactNode;
14
+ declare const useClient: <TMeta extends SchemaMeta = SchemaMeta>() => Client<TMeta>;
14
15
  //#endregion
15
16
  //#region src/use-query.d.ts
16
- type UseQueryReturn<Document$1 extends DocumentNode> = {
17
+ type Query<T extends Artifact<'query'>> = {
17
18
  data: undefined;
18
19
  loading: true;
19
20
  error: undefined;
20
21
  refetch: () => void;
21
22
  } | {
22
- data: DataOf<Document$1>;
23
+ data: DataOf<T>;
23
24
  loading: false;
24
25
  error: undefined;
25
26
  refetch: () => void;
26
27
  } | {
27
- data: DataOf<Document$1> | undefined;
28
+ data: DataOf<T> | undefined;
28
29
  loading: false;
29
- error: Error;
30
+ error: AggregatedError;
30
31
  refetch: () => void;
31
32
  };
32
- declare const useQuery: <Document extends DocumentNode>(document: Document, variables: VariablesOf<Document>) => UseQueryReturn<Document>;
33
+ type UseQueryOptions = QueryOptions & {
34
+ skip?: boolean;
35
+ };
36
+ declare const useQuery: <T extends Artifact<"query">>(query: T, ...[variables, options]: VariablesOf<T> extends undefined ? [undefined?, UseQueryOptions?] : [VariablesOf<T>, UseQueryOptions?]) => Query<T>;
33
37
  //#endregion
34
38
  //#region src/use-subscription.d.ts
35
- type UseSubscriptionReturn<Document$1 extends DocumentNode> = {
39
+ type Subscription<T extends Artifact<'subscription'>> = {
36
40
  data: undefined;
37
41
  loading: true;
38
42
  error: undefined;
39
43
  } | {
40
- data: DataOf<Document$1>;
44
+ data: DataOf<T> | undefined;
41
45
  loading: false;
42
46
  error: undefined;
43
47
  } | {
44
- data: DataOf<Document$1> | undefined;
48
+ data: DataOf<T> | undefined;
45
49
  loading: false;
46
- error: Error;
50
+ error: AggregatedError;
47
51
  };
48
- type UseSubscriptionOptions<Document$1 extends DocumentNode> = {
49
- onData?: (data: DataOf<Document$1>) => void;
50
- onError?: (error: Error) => void;
52
+ type UseSubscriptionOptions<T extends Artifact<'subscription'>> = SubscriptionOptions & {
53
+ skip?: boolean;
54
+ onData?: (data: DataOf<T>) => void;
55
+ onError?: (error: AggregatedError) => void;
51
56
  };
52
- declare const useSubscription: <Document extends DocumentNode>(document: Document, variables: VariablesOf<Document>, options?: UseSubscriptionOptions<Document>) => UseSubscriptionReturn<Document>;
57
+ declare const useSubscription: <T extends Artifact<"subscription">>(subscription: T, ...[variables, options]: VariablesOf<T> extends undefined ? [undefined?, UseSubscriptionOptions<T>?] : [VariablesOf<T>, UseSubscriptionOptions<T>?]) => Subscription<T>;
53
58
  //#endregion
54
59
  //#region src/use-mutation.d.ts
55
- type UseMutationResult<Document$1 extends DocumentNode> = {
60
+ type MutationResult<T extends Artifact<'mutation'>> = {
56
61
  data: undefined;
57
62
  loading: true;
58
63
  error: undefined;
59
64
  } | {
60
- data: DataOf<Document$1>;
65
+ data: DataOf<T> | undefined;
61
66
  loading: false;
62
67
  error: undefined;
63
68
  } | {
64
- data: DataOf<Document$1> | undefined;
69
+ data: DataOf<T> | undefined;
65
70
  loading: false;
66
- error: Error;
71
+ error: AggregatedError;
67
72
  };
68
- type UseMutationReturn<Document$1 extends DocumentNode> = [(variables: VariablesOf<Document$1>) => Promise<DataOf<Document$1>>, UseMutationResult<Document$1>];
69
- declare const useMutation: <Document extends DocumentNode>(document: Document) => UseMutationReturn<Document>;
73
+ type UseMutationOptions = MutationOptions;
74
+ type Mutation<T extends Artifact<'mutation'>> = [(...[variables, options]: VariablesOf<T> extends undefined ? [undefined?, UseMutationOptions?] : [VariablesOf<T>, UseMutationOptions?]) => Promise<DataOf<T>>, MutationResult<T>];
75
+ declare const useMutation: <T extends Artifact<"mutation">>(mutation: T) => Mutation<T>;
70
76
  //#endregion
71
77
  //#region src/use-fragment.d.ts
72
- type UseFragmentReturn<Document$1 extends DocumentNode> = DataOf<Document$1>;
73
- declare const useFragment: <Document extends DocumentNode>(document: Document, fragmentRef: FragmentRef<Document>) => UseFragmentReturn<Document>;
78
+ type UseFragmentOptions = FragmentOptions;
79
+ type Fragment<T extends Artifact<'fragment'>> = {
80
+ data: DataOf<T>;
81
+ };
82
+ declare const useFragment: <T extends Artifact<"fragment">>(fragment: T, fragmentRef: FragmentRefs<T["name"]>, options?: UseFragmentOptions) => Fragment<T>;
74
83
  //#endregion
75
- export { ClientProvider, type UseFragmentReturn, type UseMutationResult, type UseMutationReturn, type UseQueryReturn, type UseSubscriptionOptions, type UseSubscriptionReturn, useClient, useFragment, useMutation, useQuery, useSubscription };
84
+ export { ClientProvider, type Fragment, type Mutation, type Query, type Subscription, type UseFragmentOptions, type UseMutationOptions, type UseQueryOptions, type UseSubscriptionOptions, useClient, useFragment, useMutation, useQuery, useSubscription };
package/dist/index.d.ts CHANGED
@@ -1,75 +1,84 @@
1
+ import { AggregatedError, Artifact, Client, DataOf, FragmentOptions, FragmentRefs, MutationOptions, QueryOptions, SchemaMeta, SubscriptionOptions, VariablesOf } from "@mearie/core";
1
2
  import { ReactNode } from "react";
2
- import { Client, DataOf, DocumentNode, FragmentRef, VariablesOf } from "@mearie/core";
3
+ export * from "@mearie/core";
3
4
 
4
5
  //#region src/client-provider.d.ts
5
- type ClientProviderProps = {
6
- client: Client;
6
+ type ClientProviderProps<TMeta extends SchemaMeta = SchemaMeta> = {
7
+ client: Client<TMeta>;
7
8
  children: ReactNode;
8
9
  };
9
- declare const ClientProvider: ({
10
+ declare const ClientProvider: <TMeta extends SchemaMeta = SchemaMeta>({
10
11
  client,
11
12
  children
12
- }: ClientProviderProps) => ReactNode;
13
- declare const useClient: () => Client;
13
+ }: ClientProviderProps<TMeta>) => ReactNode;
14
+ declare const useClient: <TMeta extends SchemaMeta = SchemaMeta>() => Client<TMeta>;
14
15
  //#endregion
15
16
  //#region src/use-query.d.ts
16
- type UseQueryReturn<Document$1 extends DocumentNode> = {
17
+ type Query<T extends Artifact<'query'>> = {
17
18
  data: undefined;
18
19
  loading: true;
19
20
  error: undefined;
20
21
  refetch: () => void;
21
22
  } | {
22
- data: DataOf<Document$1>;
23
+ data: DataOf<T>;
23
24
  loading: false;
24
25
  error: undefined;
25
26
  refetch: () => void;
26
27
  } | {
27
- data: DataOf<Document$1> | undefined;
28
+ data: DataOf<T> | undefined;
28
29
  loading: false;
29
- error: Error;
30
+ error: AggregatedError;
30
31
  refetch: () => void;
31
32
  };
32
- declare const useQuery: <Document extends DocumentNode>(document: Document, variables: VariablesOf<Document>) => UseQueryReturn<Document>;
33
+ type UseQueryOptions = QueryOptions & {
34
+ skip?: boolean;
35
+ };
36
+ declare const useQuery: <T extends Artifact<"query">>(query: T, ...[variables, options]: VariablesOf<T> extends undefined ? [undefined?, UseQueryOptions?] : [VariablesOf<T>, UseQueryOptions?]) => Query<T>;
33
37
  //#endregion
34
38
  //#region src/use-subscription.d.ts
35
- type UseSubscriptionReturn<Document$1 extends DocumentNode> = {
39
+ type Subscription<T extends Artifact<'subscription'>> = {
36
40
  data: undefined;
37
41
  loading: true;
38
42
  error: undefined;
39
43
  } | {
40
- data: DataOf<Document$1>;
44
+ data: DataOf<T> | undefined;
41
45
  loading: false;
42
46
  error: undefined;
43
47
  } | {
44
- data: DataOf<Document$1> | undefined;
48
+ data: DataOf<T> | undefined;
45
49
  loading: false;
46
- error: Error;
50
+ error: AggregatedError;
47
51
  };
48
- type UseSubscriptionOptions<Document$1 extends DocumentNode> = {
49
- onData?: (data: DataOf<Document$1>) => void;
50
- onError?: (error: Error) => void;
52
+ type UseSubscriptionOptions<T extends Artifact<'subscription'>> = SubscriptionOptions & {
53
+ skip?: boolean;
54
+ onData?: (data: DataOf<T>) => void;
55
+ onError?: (error: AggregatedError) => void;
51
56
  };
52
- declare const useSubscription: <Document extends DocumentNode>(document: Document, variables: VariablesOf<Document>, options?: UseSubscriptionOptions<Document>) => UseSubscriptionReturn<Document>;
57
+ declare const useSubscription: <T extends Artifact<"subscription">>(subscription: T, ...[variables, options]: VariablesOf<T> extends undefined ? [undefined?, UseSubscriptionOptions<T>?] : [VariablesOf<T>, UseSubscriptionOptions<T>?]) => Subscription<T>;
53
58
  //#endregion
54
59
  //#region src/use-mutation.d.ts
55
- type UseMutationResult<Document$1 extends DocumentNode> = {
60
+ type MutationResult<T extends Artifact<'mutation'>> = {
56
61
  data: undefined;
57
62
  loading: true;
58
63
  error: undefined;
59
64
  } | {
60
- data: DataOf<Document$1>;
65
+ data: DataOf<T> | undefined;
61
66
  loading: false;
62
67
  error: undefined;
63
68
  } | {
64
- data: DataOf<Document$1> | undefined;
69
+ data: DataOf<T> | undefined;
65
70
  loading: false;
66
- error: Error;
71
+ error: AggregatedError;
67
72
  };
68
- type UseMutationReturn<Document$1 extends DocumentNode> = [(variables: VariablesOf<Document$1>) => Promise<DataOf<Document$1>>, UseMutationResult<Document$1>];
69
- declare const useMutation: <Document extends DocumentNode>(document: Document) => UseMutationReturn<Document>;
73
+ type UseMutationOptions = MutationOptions;
74
+ type Mutation<T extends Artifact<'mutation'>> = [(...[variables, options]: VariablesOf<T> extends undefined ? [undefined?, UseMutationOptions?] : [VariablesOf<T>, UseMutationOptions?]) => Promise<DataOf<T>>, MutationResult<T>];
75
+ declare const useMutation: <T extends Artifact<"mutation">>(mutation: T) => Mutation<T>;
70
76
  //#endregion
71
77
  //#region src/use-fragment.d.ts
72
- type UseFragmentReturn<Document$1 extends DocumentNode> = DataOf<Document$1>;
73
- declare const useFragment: <Document extends DocumentNode>(document: Document, fragmentRef: FragmentRef<Document>) => UseFragmentReturn<Document>;
78
+ type UseFragmentOptions = FragmentOptions;
79
+ type Fragment<T extends Artifact<'fragment'>> = {
80
+ data: DataOf<T>;
81
+ };
82
+ declare const useFragment: <T extends Artifact<"fragment">>(fragment: T, fragmentRef: FragmentRefs<T["name"]>, options?: UseFragmentOptions) => Fragment<T>;
74
83
  //#endregion
75
- export { ClientProvider, type UseFragmentReturn, type UseMutationResult, type UseMutationReturn, type UseQueryReturn, type UseSubscriptionOptions, type UseSubscriptionReturn, useClient, useFragment, useMutation, useQuery, useSubscription };
84
+ export { ClientProvider, type Fragment, type Mutation, type Query, type Subscription, type UseFragmentOptions, type UseMutationOptions, type UseQueryOptions, type UseSubscriptionOptions, useClient, useFragment, useMutation, useQuery, useSubscription };
package/dist/index.js CHANGED
@@ -1,5 +1,9 @@
1
- import { createContext, useContext } from "react";
1
+ import { AggregatedError, stringify } from "@mearie/core";
2
+ import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
2
3
  import { jsx } from "react/jsx-runtime";
4
+ import { collect, peek, pipe, subscribe } from "@mearie/core/stream";
5
+
6
+ export * from "@mearie/core"
3
7
 
4
8
  //#region src/client-provider.tsx
5
9
  const ClientContext = createContext(null);
@@ -17,39 +21,164 @@ const useClient = () => {
17
21
 
18
22
  //#endregion
19
23
  //#region src/use-query.ts
20
- const useQuery = (document, variables) => {
24
+ const useQuery = (query, ...[variables, options]) => {
25
+ const client = useClient();
26
+ const [data, setData] = useState();
27
+ const [loading, setLoading] = useState(!options?.skip);
28
+ const [error, setError] = useState();
29
+ const unsubscribe = useRef(null);
30
+ const stableVariables = useMemo(() => stringify(variables), [variables]);
31
+ const stableOptions = useMemo(() => options, [options?.skip]);
32
+ const execute = useCallback(() => {
33
+ unsubscribe.current?.();
34
+ if (stableOptions?.skip) return;
35
+ setLoading(true);
36
+ setError(void 0);
37
+ unsubscribe.current = pipe(client.executeQuery(query, variables, stableOptions), subscribe({ next: (result) => {
38
+ if (result.errors && result.errors.length > 0) {
39
+ setError(new AggregatedError(result.errors));
40
+ setLoading(false);
41
+ } else {
42
+ setData(result.data);
43
+ setLoading(false);
44
+ setError(void 0);
45
+ }
46
+ } }));
47
+ }, [
48
+ client,
49
+ query,
50
+ stableVariables,
51
+ stableOptions
52
+ ]);
53
+ useEffect(() => {
54
+ execute();
55
+ return () => unsubscribe.current?.();
56
+ }, [execute]);
21
57
  return {
22
- data: void 0,
23
- loading: true,
24
- error: void 0,
25
- refetch: () => {}
58
+ data,
59
+ loading,
60
+ error,
61
+ refetch: execute
26
62
  };
27
63
  };
28
64
 
29
65
  //#endregion
30
66
  //#region src/use-subscription.ts
31
- const useSubscription = (document, variables, options) => {
67
+ const useSubscription = (subscription, ...[variables, options]) => {
68
+ const client = useClient();
69
+ const [data, setData] = useState();
70
+ const [loading, setLoading] = useState(!options?.skip);
71
+ const [error, setError] = useState();
72
+ const unsubscribe = useRef(null);
73
+ const stableVariables = useMemo(() => stringify(variables), [variables]);
74
+ const stableOptions = useMemo(() => options, [
75
+ options?.skip,
76
+ options?.onData,
77
+ options?.onError
78
+ ]);
79
+ const execute = useCallback(() => {
80
+ unsubscribe.current?.();
81
+ if (stableOptions?.skip) return;
82
+ setLoading(true);
83
+ setError(void 0);
84
+ unsubscribe.current = pipe(client.executeSubscription(subscription, variables, stableOptions), subscribe({ next: (result) => {
85
+ if (result.errors && result.errors.length > 0) {
86
+ const err = new AggregatedError(result.errors);
87
+ setError(err);
88
+ setLoading(false);
89
+ stableOptions?.onError?.(err);
90
+ } else {
91
+ const resultData = result.data;
92
+ setData(resultData);
93
+ setLoading(false);
94
+ setError(void 0);
95
+ stableOptions?.onData?.(resultData);
96
+ }
97
+ } }));
98
+ }, [
99
+ client,
100
+ subscription,
101
+ stableVariables,
102
+ stableOptions
103
+ ]);
104
+ useEffect(() => {
105
+ execute();
106
+ return () => unsubscribe.current?.();
107
+ }, [execute]);
32
108
  return {
33
- data: void 0,
34
- loading: true,
35
- error: void 0
109
+ data,
110
+ loading,
111
+ error
36
112
  };
37
113
  };
38
114
 
39
115
  //#endregion
40
116
  //#region src/use-mutation.ts
41
- const useMutation = (document) => {
42
- return [async () => ({}), {
43
- data: void 0,
44
- loading: false,
45
- error: void 0
117
+ const useMutation = (mutation) => {
118
+ const client = useClient();
119
+ const [data, setData] = useState();
120
+ const [loading, setLoading] = useState(false);
121
+ const [error, setError] = useState();
122
+ return [useCallback(async (variables, options) => {
123
+ setLoading(true);
124
+ setError(void 0);
125
+ try {
126
+ const result = await pipe(client.executeMutation(mutation, variables, options), collect);
127
+ if (result.errors && result.errors.length > 0) {
128
+ const err = new AggregatedError(result.errors);
129
+ setError(err);
130
+ setLoading(false);
131
+ throw err;
132
+ }
133
+ setData(result.data);
134
+ setLoading(false);
135
+ return result.data;
136
+ } catch (err) {
137
+ if (err instanceof AggregatedError) setError(err);
138
+ setLoading(false);
139
+ throw err;
140
+ }
141
+ }, [client, mutation]), {
142
+ data,
143
+ loading,
144
+ error
46
145
  }];
47
146
  };
48
147
 
49
148
  //#endregion
50
149
  //#region src/use-fragment.ts
51
- const useFragment = (document, fragmentRef) => {
52
- return {};
150
+ const useFragment = (fragment, fragmentRef, options) => {
151
+ const client = useClient();
152
+ const dataRef = useRef(void 0);
153
+ const subscribe_ = useCallback((onChange) => {
154
+ return pipe(client.executeFragment(fragment, fragmentRef, options), subscribe({ next: (result) => {
155
+ if (result.errors && result.errors.length > 0) throw new AggregatedError(result.errors);
156
+ dataRef.current = result.data;
157
+ onChange();
158
+ } }));
159
+ }, [
160
+ client,
161
+ fragment,
162
+ fragmentRef,
163
+ options
164
+ ]);
165
+ const snapshot = useCallback(() => {
166
+ if (dataRef.current === void 0) {
167
+ const result = pipe(client.executeFragment(fragment, fragmentRef, options), peek);
168
+ if (result.errors && result.errors.length > 0) throw new AggregatedError(result.errors);
169
+ dataRef.current = result.data;
170
+ }
171
+ return dataRef.current;
172
+ }, [
173
+ client,
174
+ fragment,
175
+ fragmentRef,
176
+ options
177
+ ]);
178
+ const data = useSyncExternalStore(subscribe_, snapshot, snapshot);
179
+ return { get data() {
180
+ return data;
181
+ } };
53
182
  };
54
183
 
55
184
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mearie/react",
3
- "version": "0.0.1-next.3",
3
+ "version": "0.0.1-next.5",
4
4
  "description": "Type-safe, zero-overhead GraphQL client",
5
5
  "keywords": [
6
6
  "graphql",
@@ -26,19 +26,27 @@
26
26
  "author": "Bae Junehyeon <finn@penxle.io>",
27
27
  "sideEffects": false,
28
28
  "type": "module",
29
- "main": "./dist/index.cjs",
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/index.d.ts",
32
+ "import": "./dist/index.js",
33
+ "require": "./dist/index.cjs"
34
+ },
35
+ "./package.json": "./package.json"
36
+ },
30
37
  "files": [
31
38
  "dist",
32
39
  "package.json",
33
40
  "README.md"
34
41
  ],
35
42
  "dependencies": {
36
- "@mearie/core": "0.0.1-next.3"
43
+ "@mearie/core": "0.0.1-next.5"
37
44
  },
38
45
  "devDependencies": {
39
46
  "@types/react": "^19.2.2",
40
47
  "react": "^19.2.0",
41
- "tsdown": "^0.15.8"
48
+ "tsdown": "^0.15.12",
49
+ "typescript": "^5.9.3"
42
50
  },
43
51
  "peerDependencies": {
44
52
  "react": "^18.0.0 || ^19.0.0"
@@ -52,16 +60,10 @@
52
60
  "access": "public"
53
61
  },
54
62
  "scripts": {
55
- "build": "tsdown"
56
- },
57
- "exports": {
58
- ".": {
59
- "types": "./dist/index.d.ts",
60
- "import": "./dist/index.js",
61
- "require": "./dist/index.cjs"
62
- },
63
- "./package.json": "./package.json"
63
+ "build": "tsdown",
64
+ "typecheck": "tsc"
64
65
  },
66
+ "main": "./dist/index.cjs",
65
67
  "module": "./dist/index.js",
66
68
  "types": "./dist/index.d.ts"
67
69
  }