@postrun/react 1.0.0 → 1.1.0
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 +26 -3
- package/dist/index.cjs +60 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +42 -8
- package/dist/index.d.ts +42 -8
- package/dist/index.js +60 -14
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -100,9 +100,32 @@ function ConnectX({
|
|
|
100
100
|
```
|
|
101
101
|
|
|
102
102
|
Prefer wiring it yourself? `useConnect({ profileId, platform, onConnected })`
|
|
103
|
-
returns the same `{ state, start, select, reset }` — `<Connect>` is just
|
|
104
|
-
render-prop wrapper over it. The hosted `/connect` page remains available
|
|
105
|
-
no-SDK fallback (link to the `hosted_connect_url` from a `POST .../connect`).
|
|
103
|
+
returns the same `{ state, start, prepare, select, reset }` — `<Connect>` is just
|
|
104
|
+
a thin render-prop wrapper over it. The hosted `/connect` page remains available
|
|
105
|
+
as a no-SDK fallback (link to the `hosted_connect_url` from a `POST .../connect`).
|
|
106
|
+
|
|
107
|
+
`onConnected` also auto-refetches your `useConnections` list, so the new account
|
|
108
|
+
shows up with no manual refetch. Pass `onError(reason)` / `onCancelled()` if you'd
|
|
109
|
+
rather react with callbacks than read `state.phase`.
|
|
110
|
+
|
|
111
|
+
**Multi-platform picker?** A session is pre-minted on mount, which is ideal for a
|
|
112
|
+
dedicated button but would mint one per platform in a "pick a network" list. Set
|
|
113
|
+
`prepareOnMount={false}` and call `prepare()` on the button's intent
|
|
114
|
+
(`onPointerEnter`/`onFocus`) so only the platform the user is about to click mints:
|
|
115
|
+
|
|
116
|
+
```tsx
|
|
117
|
+
<Connect profileId={id} platform="meta_ads" prepareOnMount={false} onConnected={refetch}>
|
|
118
|
+
{({ state, start, prepare, select }) =>
|
|
119
|
+
state.phase === 'picking' ? (
|
|
120
|
+
<Picker accounts={state.accounts} onPick={select} />
|
|
121
|
+
) : (
|
|
122
|
+
<button onPointerEnter={prepare} onFocus={prepare} onClick={start}>
|
|
123
|
+
Connect Meta
|
|
124
|
+
</button>
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
</Connect>
|
|
128
|
+
```
|
|
106
129
|
|
|
107
130
|
## License
|
|
108
131
|
|
package/dist/index.cjs
CHANGED
|
@@ -314,19 +314,28 @@ var POLL_TIMEOUT_MS = 15e3;
|
|
|
314
314
|
function useConnect({
|
|
315
315
|
profileId,
|
|
316
316
|
platform,
|
|
317
|
-
onConnected
|
|
317
|
+
onConnected,
|
|
318
|
+
onError,
|
|
319
|
+
onCancelled,
|
|
320
|
+
prepareOnMount = true
|
|
318
321
|
}) {
|
|
319
|
-
const { client } = usePostrun();
|
|
322
|
+
const { client, queryClient } = usePostrun();
|
|
320
323
|
const [state, setState] = react.useState({ phase: "preparing" });
|
|
321
324
|
const [remintNonce, setRemintNonce] = react.useState(0);
|
|
322
325
|
const sessionRef = react.useRef(null);
|
|
323
326
|
const pickRef = react.useRef(null);
|
|
324
327
|
const inFlightRef = react.useRef(false);
|
|
325
328
|
const flowGenRef = react.useRef(0);
|
|
329
|
+
const preparingRef = react.useRef(false);
|
|
330
|
+
const prepareGenRef = react.useRef(0);
|
|
326
331
|
const onConnectedRef = react.useRef(onConnected);
|
|
332
|
+
const onErrorRef = react.useRef(onError);
|
|
333
|
+
const onCancelledRef = react.useRef(onCancelled);
|
|
327
334
|
react.useEffect(() => {
|
|
328
335
|
onConnectedRef.current = onConnected;
|
|
329
|
-
|
|
336
|
+
onErrorRef.current = onError;
|
|
337
|
+
onCancelledRef.current = onCancelled;
|
|
338
|
+
});
|
|
330
339
|
const abandonFlow = react.useCallback(() => {
|
|
331
340
|
flowGenRef.current += 1;
|
|
332
341
|
inFlightRef.current = false;
|
|
@@ -334,12 +343,23 @@ function useConnect({
|
|
|
334
343
|
pickRef.current = null;
|
|
335
344
|
pick?.reject(new Error("connect flow abandoned"));
|
|
336
345
|
}, []);
|
|
337
|
-
react.
|
|
338
|
-
|
|
346
|
+
const prepare = react.useCallback(() => {
|
|
347
|
+
if (sessionRef.current || preparingRef.current) return;
|
|
348
|
+
preparingRef.current = true;
|
|
349
|
+
const gen = prepareGenRef.current;
|
|
339
350
|
setState({ phase: "preparing" });
|
|
340
|
-
|
|
351
|
+
const failPrepare = () => {
|
|
352
|
+
preparingRef.current = false;
|
|
353
|
+
setState({ phase: "error", reason: "prepare_failed" });
|
|
354
|
+
onErrorRef.current?.("prepare_failed");
|
|
355
|
+
};
|
|
341
356
|
js.connectionsConnect({ client, path: { id: profileId }, body: { platform } }).then(({ data }) => {
|
|
342
|
-
if (
|
|
357
|
+
if (prepareGenRef.current !== gen) return;
|
|
358
|
+
if (!data) {
|
|
359
|
+
failPrepare();
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
preparingRef.current = false;
|
|
343
363
|
sessionRef.current = {
|
|
344
364
|
token: data.connect_session_token,
|
|
345
365
|
providerConfigKey: data.provider_config_key,
|
|
@@ -347,16 +367,28 @@ function useConnect({
|
|
|
347
367
|
};
|
|
348
368
|
setState({ phase: "idle" });
|
|
349
369
|
}).catch(() => {
|
|
350
|
-
if (
|
|
370
|
+
if (prepareGenRef.current !== gen) return;
|
|
371
|
+
failPrepare();
|
|
351
372
|
});
|
|
373
|
+
}, [client, profileId, platform]);
|
|
374
|
+
react.useEffect(() => {
|
|
375
|
+
prepareGenRef.current += 1;
|
|
376
|
+
preparingRef.current = false;
|
|
377
|
+
sessionRef.current = null;
|
|
378
|
+
setState({ phase: "preparing" });
|
|
379
|
+
if (prepareOnMount) prepare();
|
|
352
380
|
return () => {
|
|
353
|
-
|
|
381
|
+
prepareGenRef.current += 1;
|
|
354
382
|
abandonFlow();
|
|
355
383
|
};
|
|
356
|
-
}, [
|
|
384
|
+
}, [profileId, platform, remintNonce, prepareOnMount, prepare, abandonFlow]);
|
|
357
385
|
const start = react.useCallback(() => {
|
|
358
386
|
const session = sessionRef.current;
|
|
359
|
-
if (!session
|
|
387
|
+
if (!session) {
|
|
388
|
+
prepare();
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
if (inFlightRef.current) return;
|
|
360
392
|
inFlightRef.current = true;
|
|
361
393
|
const gen = flowGenRef.current;
|
|
362
394
|
const isCurrent = () => flowGenRef.current === gen;
|
|
@@ -421,20 +453,24 @@ function useConnect({
|
|
|
421
453
|
switch (outcome.status) {
|
|
422
454
|
case "active":
|
|
423
455
|
setState({ phase: "active", connection: outcome.connection });
|
|
456
|
+
void queryClient.invalidateQueries({ queryKey: connectionKeys.lists() });
|
|
424
457
|
onConnectedRef.current?.(outcome.connection);
|
|
425
458
|
return;
|
|
426
459
|
case "connected_pending":
|
|
427
460
|
setState({ phase: "connected_pending" });
|
|
461
|
+
void queryClient.invalidateQueries({ queryKey: connectionKeys.lists() });
|
|
428
462
|
return;
|
|
429
463
|
case "cancelled":
|
|
430
464
|
setState({ phase: "cancelled" });
|
|
465
|
+
onCancelledRef.current?.();
|
|
431
466
|
return;
|
|
432
467
|
case "error":
|
|
433
468
|
setState({ phase: "error", reason: outcome.reason });
|
|
469
|
+
onErrorRef.current?.(outcome.reason);
|
|
434
470
|
return;
|
|
435
471
|
}
|
|
436
472
|
});
|
|
437
|
-
}, [client, profileId]);
|
|
473
|
+
}, [client, profileId, prepare, queryClient]);
|
|
438
474
|
const select = react.useCallback((externalAccountId) => {
|
|
439
475
|
const pick = pickRef.current;
|
|
440
476
|
if (!pick) return;
|
|
@@ -445,7 +481,7 @@ function useConnect({
|
|
|
445
481
|
const reset = react.useCallback(() => {
|
|
446
482
|
setRemintNonce((n) => n + 1);
|
|
447
483
|
}, []);
|
|
448
|
-
return { state, start, select, reset };
|
|
484
|
+
return { state, start, prepare, select, reset };
|
|
449
485
|
}
|
|
450
486
|
function useConnections(profileId, filter) {
|
|
451
487
|
const { client, queryClient } = usePostrun();
|
|
@@ -517,9 +553,19 @@ function Connect({
|
|
|
517
553
|
profileId,
|
|
518
554
|
platform,
|
|
519
555
|
onConnected,
|
|
556
|
+
onError,
|
|
557
|
+
onCancelled,
|
|
558
|
+
prepareOnMount,
|
|
520
559
|
children
|
|
521
560
|
}) {
|
|
522
|
-
const api = useConnect({
|
|
561
|
+
const api = useConnect({
|
|
562
|
+
profileId,
|
|
563
|
+
platform,
|
|
564
|
+
onConnected,
|
|
565
|
+
onError,
|
|
566
|
+
onCancelled,
|
|
567
|
+
prepareOnMount
|
|
568
|
+
});
|
|
523
569
|
return children(api);
|
|
524
570
|
}
|
|
525
571
|
var UploadError = class extends Error {
|