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