Skip to content

Commit 76c4213

Browse files
authored
Better websocket effects onData + onComplete, no onCompleted (#164)
* Better websocket effects onData + onComplete, no onCompleted * changeset * fix type * Update .changeset/quiet-rice-decide.md * CI check and update * pnpm 10 * pnpm first * fix prettier
1 parent 1cf4fe8 commit 76c4213

File tree

7 files changed

+155
-51
lines changed

7 files changed

+155
-51
lines changed

.changeset/quiet-rice-decide.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@soundxyz/graphql-react-ws': major
3+
---
4+
5+
Better websocket effects onData + onComplete, no onCompleted renamed to onData

.github/workflows/canary.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ jobs:
2121
- name: Setup PNPM
2222
uses: pnpm/[email protected]
2323
with:
24-
version: 7.19.0
24+
version: 10
2525

2626
- name: Use Node
2727
uses: actions/setup-node@v3
2828
with:
29-
node-version: 18.x
29+
node-version: 22.x
3030
cache: 'pnpm'
3131

3232
- name: Setup NPM credentials

.github/workflows/check.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Lint & Type Check
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches: [main]
7+
8+
jobs:
9+
lint-and-typecheck:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- name: Checkout code
13+
uses: actions/checkout@v4
14+
15+
- name: Install pnpm
16+
uses: pnpm/action-setup@v2
17+
with:
18+
version: 10
19+
20+
- name: Set up Node.js
21+
uses: actions/setup-node@v4
22+
with:
23+
node-version: 22
24+
cache: 'pnpm'
25+
26+
- name: Install dependencies
27+
run: pnpm install
28+
29+
- name: Check Prettier formatting
30+
run: pnpm prettier:check
31+
32+
- name: TypeScript type check
33+
run: pnpm tsc --noEmit

.github/workflows/release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ jobs:
1919
- name: Setup PNPM
2020
uses: pnpm/[email protected]
2121
with:
22-
version: 7.19.0
22+
version: 10
2323

2424
- name: Use Node
2525
uses: actions/setup-node@v3
2626
with:
27-
node-version: 18.x
27+
node-version: 22
2828
cache: 'pnpm'
2929

3030
- name: Install Dependencies

examples/next/src/app/page.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ gql`
1818
`;
1919

2020
export default function Page() {
21-
const { data } = useQuery(TestDocument, {});
21+
const { data } = useQuery(TestDocument, {
22+
staleTime: 0,
23+
});
2224

2325
return (
2426
<div className={styles.container}>

packages/graphql-react-ws/src/client.ts

Lines changed: 68 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export type ExecutionResultWithErrors<Data> = Omit<ExecutionResult<Data, unknown
1313
errors: ExecutionResult['errors'];
1414
};
1515

16-
export type EffectCallback<Result, Variables> = ({
16+
export type OnDataEffectCallback<Result, Variables> = ({
1717
operation,
1818
result,
1919
variables,
@@ -23,6 +23,14 @@ export type EffectCallback<Result, Variables> = ({
2323
variables?: Variables;
2424
}) => void;
2525

26+
export type OnCompleteEffectCallback<Result, Variables> = ({
27+
operation,
28+
variables,
29+
}: {
30+
operation: StringDocumentNode<Result, Variables>;
31+
variables?: Variables;
32+
}) => void;
33+
2634
export function GraphQLReactWS<ConnectionInitPayload extends Record<string, unknown>>({
2735
graphqlWsOptions,
2836
}: {
@@ -204,12 +212,12 @@ export function GraphQLReactWS<ConnectionInitPayload extends Record<string, unkn
204212
next: result => {
205213
generator.resolveNext(result);
206214

207-
const effects = effectsStore[query];
215+
const effects = effectsOnDataStore[query];
208216

209217
if (effects && result.data) {
210218
for (const effect of effects) {
211219
try {
212-
Promise.all([
220+
Promise.resolve(
213221
effect({
214222
operation: query as StringDocumentNode<unknown, unknown>,
215223
result: {
@@ -218,7 +226,7 @@ export function GraphQLReactWS<ConnectionInitPayload extends Record<string, unkn
218226
},
219227
variables,
220228
}),
221-
]).catch(() => null);
229+
).catch(() => null);
222230
} catch (err) {}
223231
}
224232
}
@@ -231,6 +239,21 @@ export function GraphQLReactWS<ConnectionInitPayload extends Record<string, unkn
231239
complete: () => {
232240
generator.resolveCompleted();
233241

242+
const effects = effectsOnCompleteStore[query];
243+
244+
if (effects) {
245+
for (const effect of effects) {
246+
try {
247+
Promise.resolve(
248+
effect({
249+
operation: query as StringDocumentNode<unknown, unknown>,
250+
variables,
251+
}),
252+
).catch(() => null);
253+
} catch (err) {}
254+
}
255+
}
256+
234257
cleanupGenerator();
235258
},
236259
});
@@ -259,7 +282,12 @@ export function GraphQLReactWS<ConnectionInitPayload extends Record<string, unkn
259282
subscriptionsControllers: Set<AbortController>;
260283
};
261284

262-
const effectsStore: Record<string, Set<EffectCallback<unknown, unknown>> | null> = {};
285+
const effectsOnDataStore: Record<string, Set<OnDataEffectCallback<unknown, unknown>> | null> = {};
286+
287+
const effectsOnCompleteStore: Record<
288+
string,
289+
Set<OnCompleteEffectCallback<unknown, unknown>> | null
290+
> = {};
263291

264292
const Effects = {
265293
/**
@@ -268,26 +296,54 @@ export function GraphQLReactWS<ConnectionInitPayload extends Record<string, unkn
268296
* It returns a callback that's going to stop the effect from being called
269297
*
270298
* @example
271-
* Effects.onCompleted(TestQuery, ({ operation, result: { data }, variables }) => {
299+
* Effects.onData(TestQuery, ({ operation, result: { data }, variables }) => {
272300
* console.log({
273301
* operation,
274302
* data,
275303
* variables
276304
* });
277305
* });
278306
*/
279-
onCompleted<Result, Variables>(
307+
onData<Result, Variables>(
308+
operation: StringDocumentNode<Result, Variables>,
309+
callback: OnDataEffectCallback<Result, Variables>,
310+
) {
311+
const effects = (effectsOnDataStore[operation] ||= new Set());
312+
313+
effects.add(callback as OnDataEffectCallback<unknown, unknown>);
314+
315+
return function removeEffect() {
316+
effects.delete(callback as OnDataEffectCallback<unknown, unknown>);
317+
318+
if (effects.size === 0) effectsOnDataStore[operation] = null;
319+
};
320+
},
321+
322+
/**
323+
* Add an effect callback to be called every time the specified operation was flagged as complete or stopped
324+
*
325+
* It returns a callback that's going to stop the effect from being called
326+
*
327+
* @example
328+
* Effects.onComplete(TestQuery, ({ operation, variables }) => {
329+
* console.log({
330+
* operation,
331+
* variables
332+
* });
333+
* });
334+
*/
335+
onComplete<Result, Variables>(
280336
operation: StringDocumentNode<Result, Variables>,
281-
callback: EffectCallback<Result, Variables>,
337+
callback: OnCompleteEffectCallback<Result, Variables>,
282338
) {
283-
const effects = (effectsStore[operation] ||= new Set());
339+
const effects = (effectsOnCompleteStore[operation] ||= new Set());
284340

285-
effects.add(callback as EffectCallback<unknown, unknown>);
341+
effects.add(callback as OnCompleteEffectCallback<unknown, unknown>);
286342

287343
return function removeEffect() {
288-
effects.delete(callback as EffectCallback<unknown, unknown>);
344+
effects.delete(callback as OnCompleteEffectCallback<unknown, unknown>);
289345

290-
if (effects.size === 0) effectsStore[operation] = null;
346+
if (effects.size === 0) effectsOnCompleteStore[operation] = null;
291347
};
292348
},
293349
} as const;

scripts/canary-release.js

Lines changed: 42 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,67 @@
11
/* eslint-disable @typescript-eslint/no-var-requires */
2-
const semver = require('semver')
3-
const cp = require('child_process')
4-
const { basename } = require('path')
2+
const semver = require('semver');
3+
const cp = require('child_process');
4+
const { basename } = require('path');
55

6-
const { read: readConfig } = require('@changesets/config')
7-
const readChangesets = require('@changesets/read').default
8-
const assembleReleasePlan = require('@changesets/assemble-release-plan').default
9-
const applyReleasePlan = require('@changesets/apply-release-plan').default
10-
const { getPackages } = require('@manypkg/get-packages')
6+
const { read: readConfig } = require('@changesets/config');
7+
const readChangesets = require('@changesets/read').default;
8+
const assembleReleasePlan = require('@changesets/assemble-release-plan').default;
9+
const applyReleasePlan = require('@changesets/apply-release-plan').default;
10+
const { getPackages } = require('@manypkg/get-packages');
1111

1212
function getNewVersion(version, type) {
13-
const gitHash = cp.spawnSync('git', ['rev-parse', '--short', 'HEAD']).stdout.toString().trim()
13+
const gitHash = cp.spawnSync('git', ['rev-parse', '--short', 'HEAD']).stdout.toString().trim();
1414

15-
return semver.inc(version, `pre${type}`, true, 'alpha-' + gitHash)
15+
return semver.inc(version, `pre${type}`, true, 'alpha-' + gitHash);
1616
}
1717

1818
function getRelevantChangesets(baseBranch) {
1919
const comparePoint = cp
2020
.spawnSync('git', ['merge-base', `origin/${baseBranch}`, 'HEAD'])
2121
.stdout.toString()
22-
.trim()
23-
console.log('compare point', comparePoint)
22+
.trim();
23+
console.log('compare point', comparePoint);
2424
const listModifiedFiles = cp
2525
.spawnSync('git', ['diff', '--name-only', comparePoint])
2626
.stdout.toString()
2727
.trim()
28-
.split('\n')
29-
console.log('listModifiedFiles', listModifiedFiles)
28+
.split('\n');
29+
console.log('listModifiedFiles', listModifiedFiles);
3030

31-
const items = listModifiedFiles.filter((f) => f.startsWith('.changeset')).map((f) => basename(f, '.md'))
32-
console.log('items', items)
31+
const items = listModifiedFiles
32+
.filter(f => f.startsWith('.changeset'))
33+
.map(f => basename(f, '.md'));
34+
console.log('items', items);
3335

34-
return items
36+
return items;
3537
}
3638

3739
async function updateVersions() {
38-
const cwd = process.cwd()
39-
const packages = await getPackages(cwd)
40-
const config = await readConfig(cwd, packages)
41-
const modifiedChangesets = getRelevantChangesets(config.baseBranch)
42-
const changesets = (await readChangesets(cwd)).filter((change) => modifiedChangesets.includes(change.id))
40+
const cwd = process.cwd();
41+
const packages = await getPackages(cwd);
42+
const config = await readConfig(cwd, packages);
43+
const modifiedChangesets = getRelevantChangesets(config.baseBranch);
44+
const changesets = (await readChangesets(cwd)).filter(change =>
45+
modifiedChangesets.includes(change.id),
46+
);
4347

4448
if (changesets.length === 0) {
45-
console.warn(`Unable to find any relevant package for canary publishing. Please make sure changesets exists!`)
46-
process.exit(1)
49+
console.warn(
50+
`Unable to find any relevant package for canary publishing. Please make sure changesets exists!`,
51+
);
52+
process.exit(1);
4753
} else {
48-
const releasePlan = assembleReleasePlan(changesets, packages, config, undefined, false)
54+
const releasePlan = assembleReleasePlan(changesets, packages, config, undefined, false);
4955

5056
if (releasePlan.releases.length === 0) {
51-
console.warn(`Unable to find any relevant package for canary releasing. Please make sure changesets exists!`)
52-
process.exit(1)
57+
console.warn(
58+
`Unable to find any relevant package for canary releasing. Please make sure changesets exists!`,
59+
);
60+
process.exit(1);
5361
} else {
5462
for (const release of releasePlan.releases) {
5563
if (release.type !== 'none') {
56-
release.newVersion = getNewVersion(release.oldVersion, release.type)
64+
release.newVersion = getNewVersion(release.oldVersion, release.type);
5765
}
5866
}
5967

@@ -66,16 +74,16 @@ async function updateVersions() {
6674
},
6775
false,
6876
true,
69-
)
77+
);
7078
}
7179
}
7280
}
7381

7482
updateVersions()
7583
.then(() => {
76-
console.info(`Done!`)
77-
})
78-
.catch((err) => {
79-
console.error(err)
80-
process.exit(1)
84+
console.info(`Done!`);
8185
})
86+
.catch(err => {
87+
console.error(err);
88+
process.exit(1);
89+
});

0 commit comments

Comments
 (0)